Index: .hgtags
===================================================================
--- .hgtags	(revision 1351)
+++ .hgtags	(revision 1468)
@@ -12,4 +12,2 @@
 6fce226121140735a51a8f447c80f1dacd2974ea 2.4.4
 514d5121a12586b7ff320924d44028b677a01020 2.4.4
-baf879af43beea9764d920c2facd7226e90c5cf3 2.5.1
-cfad9f2a9f6ec03206ff5db91985208e833a7528 2.5.2
Index: CONTRIBUTING.md
===================================================================
--- CONTRIBUTING.md	(revision 1578)
+++ CONTRIBUTING.md	(revision 1578)
@@ -0,0 +1,9 @@
+# CONTRIBUTING
+
+Dotclear is an open source project. If you'd like to contribute, you can send
+a pull request, or feel free to use any other way you'd prefer.
+
+There are many way to contribute :
+
+ * Report bugs
+ * Add documentation
Index: Makefile
===================================================================
--- Makefile	(revision 1451)
+++ Makefile	(revision 1655)
@@ -11,5 +11,5 @@
 	
 	## Copy needed folders and files
-	cp -pRf ./admin ./inc ./themes ./index.php ./CHANGELOG ./CREDITS ./LICENSE ./README ./$(DC)/
+	cp -pRf ./admin ./inc ./themes ./index.php ./CHANGELOG ./CREDITS ./LICENSE ./README.md ./CONTRIBUTING.md ./$(DC)/
 	
 	## Locales directory
@@ -70,5 +70,4 @@
 	find $(DC)/admin/js/jsToolBar/*.js -exec ./build-tools/min-js.php \{\} \;
 	find $(DC)/admin/js/jsUpload/*.js -exec ./build-tools/min-js.php \{\} \;
-	find $(DC)/admin/js/tool-man/*.js -exec ./build-tools/min-js.php \{\} \;
 	find $(DC)/plugins -name '*.js' -exec ./build-tools/min-js.php \{\} \;
 	find $(DC)/themes/default/js/*.js -exec ./build-tools/min-js.php \{\} \;
@@ -88,5 +87,5 @@
 
 deb:
-	cp ./README debian/README
+	cp ./README.md debian/README
 	dpkg-buildpackage -rfakeroot
 
Index: EADME
===================================================================
--- README	(revision 3)
+++ 	(revision )
@@ -1,22 +1,0 @@
-Welcome to Dotclear
-
-WHAT YOU NEED TO RUN DOTCLEAR
------------------------------
-In order to run Dotclear you need:
-
- * A web server (Apache, Cheerokee, lightHttpd, etc.)
- * PHP 5.2 with the following modules:
-   * mbstring
-   * iconv
-   * simplexml
-   * mysql, postgresql or sqlite
- * A database server (MySQL or PostgreSQL) or SQLite.
-
-
-INSTALLATION
-------------
-Copy inc/config.php.in to inc/config.php and fill in the fields with appropriate
-values.
-
-If you intend to use MySQL or PostgreSQL, you'll have to create a database
-first. With SQLite, db/ folder will have to be writable by your web server.
Index: README.md
===================================================================
--- README.md	(revision 1578)
+++ README.md	(revision 1578)
@@ -0,0 +1,92 @@
+# README
+
+## WHAT IS DOTCLEAR ?
+
+Dotclear is an open-source web publishing software.
+Take control over your blog!
+
+Dotclear project's purpose is to provide a user-friendly
+tool allowing anyone to publish on the web, regardless of
+their technical skills.
+
+### Features:
+ * Easy publication
+ * Fully customizable theme
+ * User-friendly administration
+ * Flexible template system
+ * Media management
+ * Choose from several editing syntax (wiki, markdown, textile or directly in wysiwyg)
+ * Flexible comment system
+ * Built-in antispam
+ * Localization
+ * Presentation widgets
+ * Themes and plugins
+ * Pages
+ * Tags and categories
+ * Automated installation
+ * Support for several database types
+ * Multiblog
+ * Multi-user with permissions
+ * Standards compliant
+ * Accessible
+ * Importing / exporting
+ * Naturally optimized for search engines
+ * Syndication feeds
+ * Complete trackback support
+ * Full Unicode support
+ * XML/RPC client support
+ * Extensible
+ * Performance and scalability
+ * Twice free
+
+
+## REQUIREMENTS
+
+In order to run Dotclear you need:
+
+ * A web server (Apache, Cherokee, Nginx, lighttpd, etc.)
+ * PHP 5.2 with the following modules:
+    * mbstring
+    * iconv
+    * simplexml
+    * mysql, postgresql or sqlite
+ * A database server (MySQL or PostgreSQL) or SQLite.
+
+
+## INSTALLATION
+
+### Automatic installation
+   The easiest way to install the blog engine is automatic installation.
+   Download the [one minute install file][1], upload it to your web space. Then open it in your favorite browser. You'll only have to follow the instructions on screen. See the [documentation][2] for more information.
+
+### Standard installation.
+   You need to download [Dotclear archive][3], extract it then upload your files to your web space using an FTP client.
+   Then open your favorite browser and go to http://your.host.name/dotclear/admin/install/. A message alerts you that you haven't got a configuration file and offers to run the wizard. Click this link.
+
+
+## DOCUMENTATION
+Still unsure if you want to move? A "[guided tour][4]" is what you need.
+
+Dotclear is fully documented:
+
+ * If you have moved in already, the [User Manual][5] is there for you.
+ * The managers will turn to the [Administration Guide][6].
+ * Decorators and craftsmen will surely enjoy reading the [Developer and designer resources][7].
+
+Dotclear documentation uses a wiki. Feel free to contribute.
+
+
+CONTRIBUTING
+------------
+Dotclear is an open source project. If you'd like to contribute, please read the [CONTRIBUTING file](CONTRIBUTING.md).
+You can submit a pull request, or feel free to use any other way you'd prefer.
+
+
+[1]: http://download.dotclear.org/loader/dotclear-loader.php
+[2]: http://dotclear.org/documentation/2.0/admin/install
+[3]: http://dotclear.org/download
+[4]: http://dotclear.org/documentation/2.0/overview/tour
+[5]: http://dotclear.org/documentation/2.0/usage
+[6]: http://dotclear.org/documentation/2.0/admin
+[7]: http://dotclear.org/documentation/2.0/resources
+
Index: admin/auth.php
===================================================================
--- admin/auth.php	(revision 1179)
+++ admin/auth.php	(revision 1558)
@@ -265,4 +265,5 @@
   <meta name="ROBOTS" content="NOARCHIVE,NOINDEX,NOFOLLOW" />
   <meta name="GOOGLEBOT" content="NOSNIPPET" />
+  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
   <title><?php echo html::escapeHTML(DC_VENDOR_NAME); ?></title>
   
@@ -323,5 +324,5 @@
 }
 if ($msg) {
-	echo '<p class="message">'.$msg.'</p>';
+	echo '<p class="success">'.$msg.'</p>';
 }
 
@@ -333,5 +334,5 @@
 {
 	echo
-	'<fieldset><legend>'.__('Request a new password').'</legend>'.
+	'<div class="fieldset"><h2>'.__('Request a new password').'</h2>'.
 	'<p><label for="user_id">'.__('Username:').'</label> '.
 	form::field(array('user_id','user_id'),20,32,html::escapeHTML($user_id)).'</p>'.
@@ -342,13 +343,14 @@
 	'<p><input type="submit" value="'.__('recover').'" />'.
 	form::hidden(array('recover'),1).'</p>'.
-	'</fieldset>'.
+	'</div>'.
 	
 	'<div id="issue">'.
-	'<p><a href="auth.php">'.__('Back to login screen').'</a></p></div>';
+	'<p><a href="auth.php">'.__('Back to login screen').'</a></p>'.
+	'</div>';
 }
 elseif ($change_pwd)
 {
 	echo
-	'<fieldset><legend>'.__('Change your password').'</legend>'.
+	'<div class="fieldset"><h2>'.__('Change your password').'</h2>'.
 	'<p><label for="new_pwd">'.__('New password:').'</label> '.
 	form::password(array('new_pwd','new_pwd'),20,255).'</p>'.
@@ -356,5 +358,5 @@
 	'<p><label for="new_pwd_c">'.__('Confirm password:').'</label> '.
 	form::password(array('new_pwd_c','new_pwd_c'),20,255).'</p>'.
-	'</fielset>'.
+	'</div>'.
 	
 	'<p><input type="submit" value="'.__('change').'" />'.
@@ -370,10 +372,10 @@
 	{
 		if ($safe_mode) {
-			echo '<fieldset>';
-			echo '<legend>'.__('Safe mode login').'</legend>';
+			echo '<div class="fieldset">';
+			echo '<h2>'.__('Safe mode login').'</h2>';
 			echo 
-				'<p class="form-note info">'.
-				__('This mode allows you to login without activating any of your plugins. This may be useful to solve compatibility problems').'&nbsp;<br />'.
-				__('Disable or delete any plugin suspected to cause trouble, then log out and log back in normally.').
+				'<p class="form-note">'.
+				__('This mode allows you to login without activating any of your plugins. This may be useful to solve compatibility problems').'&nbsp;</p>'.
+				'<p class="form-note">'.__('Disable or delete any plugin suspected to cause trouble, then log out and log back in normally.').
 				'</p>';
 		}
@@ -394,5 +396,5 @@
 		__('Remember my ID on this computer').'</label></p>'.
 		
-		'<p><input type="submit" value="'.__('log in').'" /></p>';
+		'<p><input type="submit" value="'.__('log in').'" class="login" /></p>';
 		
 		if (!empty($_REQUEST['blog'])) {
@@ -402,5 +404,5 @@
 			echo 
 			form::hidden('safe_mode',1).
-			'</fieldset>';
+			'</div>';
 		}
 		else {
Index: admin/blog.php
===================================================================
--- admin/blog.php	(revision 1277)
+++ admin/blog.php	(revision 1615)
@@ -67,28 +67,37 @@
 else
 {
-	dcPage::open(__('New blog'),dcPage::jsConfirmClose('blog-form'));
+	dcPage::open(__('New blog'),dcPage::jsConfirmClose('blog-form'),
+		dcPage::breadcrumb(
+			array(
+				__('System') => '',
+				__('Blogs') => 'blogs.php',
+				'<span class="page-title">'.__('New blog').'</span>' => ''
+			))
+	);
 	
 	echo
-	'<h2><a href="blogs.php">'.__('Blogs').'</a> &rsaquo; <span class="page-title">'.__('New blog').'</span></h2>'.
+	'<form action="blog.php" method="post" id="blog-form">'.
 	
-	'<form action="blog.php" method="post" id="blog-form" class="fieldset">'.
+	'<div>'.$core->formNonce().'</div>'.
+	'<p><label class="required" for="blog_id"><abbr title="'.__('Required field').'">*</abbr> '.__('Blog ID:').'</label> '.
+	form::field('blog_id',30,32,html::escapeHTML($blog_id)).'</p>'.
+	'<p class="form-note">'.__('At least 2 characters using letters, numbers or symbols.').'</p> ';
+
+	if ($blog_id) {
+		echo
+		'<p class="form-note warn">'.__('Please note that changing your blog ID may require changes in your public index.php file.').'</p>';
+	}
 	
-	'<p><label class="required"><abbr title="'.__('Required field').'">*</abbr> '.__('Blog ID:').' '.
-	form::field('blog_id',30,32,html::escapeHTML($blog_id)).'</label></p>'.
-	'<p class="form-note">'.__('At least 2 characters using letters, numbers or symbols.').'</p> '.
-	'<p class="form-note warn">'.__('Please note that changing your blog ID may require changes in your public index.php file.').'</p>'.
+	echo
+	'<p><label class="required" for="blog_name"><abbr title="'.__('Required field').'">*</abbr> '.__('Blog name:').'</label> '.
+	form::field('blog_name',30,255,html::escapeHTML($blog_name)).'</p>'.
 	
-	'<p><label class="required"><abbr title="'.__('Required field').'">*</abbr> '.__('Blog name:').' '.
-	form::field('blog_name',30,255,html::escapeHTML($blog_name)).'</label></p>'.
-	
-	'<p><label class="required"><abbr title="'.__('Required field').'">*</abbr> '.__('Blog URL:').' '.
-	form::field('blog_url',30,255,html::escapeHTML($blog_url)).'</label></p>'.
+	'<p><label class="required" for="blog_url"><abbr title="'.__('Required field').'">*</abbr> '.__('Blog URL:').'</label> '.
+	form::field('blog_url',30,255,html::escapeHTML($blog_url)).'</p>'.
 	
 	'<p class="area"><label for="blog_desc">'.__('Blog description:').'</label> '.
 	form::textarea('blog_desc',60,5,html::escapeHTML($blog_desc)).'</p>'.
 	
-	'<p><input type="submit" accesskey="s" value="'.__('Create').'" />'.
-	$core->formNonce().
-	'</p>'.
+	'<p><input type="submit" accesskey="s" value="'.__('Create').'" /></p>'.
 	'</form>';
 
Index: admin/blog_del.php
===================================================================
--- admin/blog_del.php	(revision 1288)
+++ admin/blog_del.php	(revision 1399)
@@ -49,10 +49,16 @@
 }
 
-dcPage::open(__('Delete a blog'));
+dcPage::open(__('Delete a blog'),'',
+	dcPage::breadcrumb(
+		array(
+			__('System') => '',
+			__('Blogs') => 'blogs.php',
+			'<span class="page-title">'.__('Delete a blog').'</span>' => ''
+		))
+);
 
 if (!$core->error->flag())
 {
 	echo
-	'<h2 class="page-title">'.__('Delete a blog').'</h2>'.
 	'<p class="message">'.__('Warning').'</p>'.
 	'<p>'.sprintf(__('You are about to delete the blog %s. Every entry, comment and category will be deleted.'),
@@ -63,6 +69,6 @@
 	'<form action="blog_del.php" method="post">'.
 	'<div>'.$core->formNonce().'</div>'.
-	'<p><label for="pwd">'.__('Your password:').' '.
-	form::password('pwd',20,255).'</label></p>'.
+	'<p><label for="pwd">'.__('Your password:').'</label> '.
+	form::password('pwd',20,255).'</p>'.
 	'<p><input type="submit" class="delete" name="del" value="'.__('Delete this blog').'" />'.
 	form::hidden('blog_id',$blog_id).'</p>'.
Index: admin/blog_pref.php
===================================================================
--- admin/blog_pref.php	(revision 1537)
+++ admin/blog_pref.php	(revision 1636)
@@ -174,5 +174,5 @@
 			
 			if ($rs) {
-				throw new Exception(__('That blog Id is already in use.'));
+				throw new Exception(__('This blog ID is already used.'));
 			}
 		}
@@ -256,4 +256,19 @@
 }
 
+if ($standalone) {
+	$breadcrumb = dcPage::breadcrumb(
+		array(
+			html::escapeHTML($blog_name) => '',
+			'<span class="page-title">'.__('Blog settings').'</span>' => ''
+		));
+} else {
+	$breadcrumb = dcPage::breadcrumb(
+		array(
+			__('System') => '',
+			__('Blogs') => 'blogs.php',
+			'<span class="page-title">'.__('Blog settings').' : '.html::escapeHTML($blog_name).'</span>' => ''
+		));
+}
+
 dcPage::open(__('Blog settings'),
 	'<script type="text/javascript">'."\n".
@@ -272,19 +287,16 @@
 	$core->callBehavior('adminBlogPreferencesHeaders').
 	
-	dcPage::jsPageTabs()
+	dcPage::jsPageTabs(),
+	$breadcrumb
 );
 
 if ($blog_id)
 {
-	echo '<h2>'.(!$standalone ? '<a href="blogs.php">'.__('Blogs').'</a> &rsaquo; ' : '').
-	html::escapeHTML($blog_name).' &rsaquo; <span class="page-title">'.
-	__('Blog settings').'</span></h2>';
-	
 	if (!empty($_GET['add'])) {
-		dcPage::message(__('Blog has been successfully created.'));
+		dcPage::success(__('Blog has been successfully created.'));
 	}
 	
 	if (!empty($_GET['upd'])) {
-		dcPage::message(__('Blog has been successfully updated.'));
+		dcPage::success(__('Blog has been successfully updated.'));
 	}
 	
@@ -295,5 +307,5 @@
 	
 	echo
-	'<fieldset><legend>'.__('Blog details').'</legend>'.
+	'<div class="fieldset"><h4>'.__('Blog details').'</h4>'.
 	$core->formNonce();
 	
@@ -301,6 +313,6 @@
 	{
 		echo
-		'<p><label for="blog_id" class="required"><abbr title="'.__('Required field').'">*</abbr> '.__('Blog ID:').
-		form::field('blog_id',30,32,html::escapeHTML($blog_id)).'</label></p>'.
+		'<p><label for="blog_id" class="required"><abbr title="'.__('Required field').'">*</abbr> '.__('Blog ID:').'</label>'.
+		form::field('blog_id',30,32,html::escapeHTML($blog_id)).'</p>'.
 		'<p class="form-note">'.__('At least 2 characters using letters, numbers or symbols.').'</p> '.
 		'<p class="form-note warn">'.__('Please note that changing your blog ID may require changes in your public index.php file.').'</p>';
@@ -308,18 +320,18 @@
 	
 	echo
-	'<p><label for="blog_name" class="required"><abbr title="'.__('Required field').'">*</abbr> '.__('Blog name:').
-	form::field('blog_name',30,255,html::escapeHTML($blog_name)).'</label></p>';
+	'<p><label for="blog_name" class="required"><abbr title="'.__('Required field').'">*</abbr> '.__('Blog name:').'</label>'.
+	form::field('blog_name',30,255,html::escapeHTML($blog_name)).'</p>';
 	
 	if ($core->auth->isSuperAdmin())
 	{
 		echo
-		'<p><label for="blog_url" class="required"><abbr title="'.__('Required field').'">*</abbr> '.__('Blog URL:').
-		form::field('blog_url',30,255,html::escapeHTML($blog_url)).'</label></p>'.
-		
-		'<p><label for="url_scan">'.__('URL scan method:').
-		form::combo('url_scan',$url_scan_combo,$blog_settings->system->url_scan).'</label></p>'.
-		
-		'<p><label for="blog_status">'.__('Blog status:').
-		form::combo('blog_status',$status_combo,$blog_status).'</label></p>';
+		'<p><label for="blog_url" class="required"><abbr title="'.__('Required field').'">*</abbr> '.__('Blog URL:').'</label>'.
+		form::field('blog_url',30,255,html::escapeHTML($blog_url)).'</p>'.
+		
+		'<p><label for="url_scan">'.__('URL scan method:').'</label>'.
+		form::combo('url_scan',$url_scan_combo,$blog_settings->system->url_scan).'</p>'.
+		
+		'<p><label for="blog_status">'.__('Blog status:').'</label>'.
+		form::combo('blog_status',$status_combo,$blog_status).'</p>';
 	}
 	
@@ -327,40 +339,40 @@
 	'<p class="area"><label for="blog_desc">'.__('Blog description:').'</label>'.
 	form::textarea('blog_desc',60,5,html::escapeHTML($blog_desc)).'</p>'.
-	'</fieldset>';
-	
-	
-	echo
-	'<fieldset><legend>'.__('Blog configuration').'</legend>'.
+	'</div>';
+	
+	
+	echo
+	'<div class="fieldset"><h4>'.__('Blog configuration').'</h4>'.
 	'<div class="two-cols">'.
 	'<div class="col">'.
-	'<p><label for="editor">'.__('Blog editor name:').
+	'<p><label for="editor">'.__('Blog editor name:').'</label>'.
 	form::field('editor',30,255,html::escapeHTML($blog_settings->system->editor)).
-	'</label></p>'.
-	
-	'<p><label for="lang">'.__('Default language:').
+	'</p>'.
+	
+	'<p><label for="lang">'.__('Default language:').'</label>'.
 	form::combo('lang',$lang_combo,$blog_settings->system->lang,'l10n').
-	'</label></p>'.
-	
-	'<p><label for="blog_timezone">'.__('Blog timezone:').
+	'</p>'.
+	
+	'<p><label for="blog_timezone">'.__('Blog timezone:').'</label>'.
 	form::combo('blog_timezone',dt::getZones(true,true),html::escapeHTML($blog_settings->system->blog_timezone)).
-	'</label></p>'.
-
-	'<p><label for="copyright_notice">'.__('Copyright notice:').
+	'</p>'.
+
+	'<p><label for="copyright_notice">'.__('Copyright notice:').'</label>'.
 	form::field('copyright_notice',30,255,html::escapeHTML($blog_settings->system->copyright_notice)).
-	'</label></p>'.
-	'</div>'.
-	
-	'<div class="col">'.
-	'<p><label for="post_url_format">'.__('New post URL format:').
+	'</p>'.
+	'</div>'.
+	
+	'<div class="col">'.
+	'<p><label for="post_url_format">'.__('New post URL format:').'</label>'.
 	form::combo('post_url_format',$post_url_combo,html::escapeHTML($blog_settings->system->post_url_format)).
-	'</label></p>'.
-
-	'<p><label for="note_title_tag">'.__('Note title HTML tag:').
+	'</p>'.
+
+	'<p><label for="note_title_tag">'.__('Note title HTML tag:').'</label>'.
 	form::combo('note_title_tag',$note_title_tag_combo,$blog_settings->system->note_title_tag).
-	'</label></p>'.
-		
-	'<p><label for="enable_xmlrpc" class="classic">'.
+	'</p>'.
+		
+	'<p><label for="enable_xmlrpc" class="classic">'.'</label>'.
 	form::checkbox('enable_xmlrpc','1',$blog_settings->system->enable_xmlrpc).
-	__('Enable XML/RPC interface').'</label></p>';
+	__('Enable XML/RPC interface').'</p>';
 
 	echo
@@ -385,23 +397,22 @@
 	'</div>'.
 	'<br class="clear" />'. //Opera sucks
-	'</fieldset>';
-	
-	echo
-	'<fieldset><legend>'.__('Comments and trackbacks').'</legend>'.
+	'</div>';
+	
+	echo
+	'<div class="fieldset"><h4>'.__('Comments and trackbacks').'</h4>'.
+
 	'<div class="two-cols">'.
+
 	'<div class="col">'.
 	'<p><label for="allow_comments" class="classic">'.
 	form::checkbox('allow_comments','1',$blog_settings->system->allow_comments).
-	__('Accept comments').'</label></p>'.
-	
+	__('Accept comments').'</label></p>'.	
 	'<p><label for="comments_pub" class="classic">'.
 	form::checkbox('comments_pub','1',!$blog_settings->system->comments_pub).
-	__('Moderate comments').'</label></p>'.
-	
+	__('Moderate comments').'</label></p>'.	
 	'<p><label for="comments_ttl" class="classic">'.sprintf(__('Leave comments open for %s days'),
 	form::field('comments_ttl',2,3,$blog_settings->system->comments_ttl)).
 	'</label></p>'.
-	'<p class="form-note">'.__('Leave blank to disable this feature.').'</p>'.
-	
+	'<p class="form-note">'.__('Leave blank to disable this feature.').'</p>'.	
 	'<p><label for="wiki_comments" class="classic">'.
 	form::checkbox('wiki_comments','1',$blog_settings->system->wiki_comments).
@@ -412,33 +423,32 @@
 	'<p><label for="allow_trackbacks" class="classic">'.
 	form::checkbox('allow_trackbacks','1',$blog_settings->system->allow_trackbacks).
-	__('Accept trackbacks').'</label></p>'.
-	
+	__('Accept trackbacks').'</label></p>'.	
 	'<p><label for="trackbacks_pub" class="classic">'.
 	form::checkbox('trackbacks_pub','1',!$blog_settings->system->trackbacks_pub).
-	__('Moderate trackbacks').'</label></p>'.
-	
+	__('Moderate trackbacks').'</label></p>'.	
 	'<p><label for="trackbacks_ttl" class="classic">'.sprintf(__('Leave trackbacks open for %s days'),
 	form::field('trackbacks_ttl',2,3,$blog_settings->system->trackbacks_ttl)).'</label></p>'.
-	'<p class="form-note">'.__('Leave blank to disable this feature.').'</p>'.
-	
+	'<p class="form-note">'.__('Leave blank to disable this feature.').'</p>'.	
 	'<p><label for="comments_nofollow" class="classic">'.
 	form::checkbox('comments_nofollow','1',$blog_settings->system->comments_nofollow).
 	__('Add "nofollow" relation on comments and trackbacks links').'</label></p>'.
 	'</div>'.
-	'</div>'.
 	'<br class="clear" />'. //Opera sucks
-	'</fieldset>';
-	
-	echo
-	'<fieldset><legend>'.__('Blog presentation').'</legend>'.
+
+	'</div>'.
+	'<br class="clear" />'. //Opera sucks
+	'</div>';
+	
+	echo
+	'<div class="fieldset"><h4>'.__('Blog presentation').'</h4>'.
 	'<div class="two-cols">'.
 	'<div class="col">'.
-	'<p><label for="date_format">'.__('Date format:').
+	'<p><label for="date_format">'.__('Date format:').'</label>'.
 	form::field('date_format',30,255,html::escapeHTML($blog_settings->system->date_format)).
-	'</label></p>'.
-	
-	'<p><label for="time_format">'.__('Time format:').
+	'</p>'.
+	
+	'<p><label for="time_format">'.__('Time format:').'</label>'.
 	form::field('time_format',30,255,html::escapeHTML($blog_settings->system->time_format)).
-	'</label></p>'.
+	'</p>'.
 	
 	'<p><label for="use_smilies" class="classic">'.
@@ -466,11 +476,11 @@
     '</div>'.
 	'<br class="clear" />'. //Opera sucks
-	'</fieldset>';
-	
-	echo
-	'<fieldset><legend>'.__('Media and images').'</legend>'.
+	'</div>';
+	
+	echo
+	'<div class="fieldset"><h4>'.__('Media and images').'</h4>'.
 	'<div class="two-cols">'.
 	'<div class="col">'.
-	'<h4>'.__('Generated image sizes (in pixels)').'</h4>'.
+	'<h5>'.__('Generated image sizes (in pixels)').'</h5>'.
 	'<p class="field"><label for="media_img_t_size">'.__('Thumbnails:').' '.
 	form::field('media_img_t_size',3,3,$blog_settings->system->media_img_t_size).'</label></p>'.
@@ -484,5 +494,5 @@
 	
 	'<div class="col">'.
-	'<h4><label for="media_img_title_pattern">'.__('Inserted image title').'</label></h4>'.
+	'<h5><label for="media_img_title_pattern">'.__('Inserted image title').'</label></h5>'.
 	'<p>'.__('This defines image tag title when you insert it in a post from the media manager. It is retrieved from the picture\'s metadata.').'</p>'.
 	'<p>'.form::combo('media_img_title_pattern',$img_title_combo,html::escapeHTML($blog_settings->system->media_img_title_pattern)).'</p>'.
@@ -491,12 +501,12 @@
 	__('Use original media date if possible').'</label></p>'.
 
-	'<h4>'.__('Default image insertion attributes').'</h4>'.
-	'<p><label for="media_img_default_size">'.__('Image size:').
+	'<h5>'.__('Default image insertion attributes').'</h5>'.
+	'<p><label for="media_img_default_size">'.__('Image size:').'</label>'.
 	form::combo('media_img_default_size',$img_default_size_combo,
 		(html::escapeHTML($blog_settings->system->media_img_default_size) != '' ? html::escapeHTML($blog_settings->system->media_img_default_size) : 'm')).
-	'</label></p>'.
-	'<p><label for="media_img_default_alignment">'.__('Image alignment').
+	'</p>'.
+	'<p><label for="media_img_default_alignment">'.__('Image alignment:').'</label>'.
 	form::combo('media_img_default_alignment',$img_default_alignment_combo,html::escapeHTML($blog_settings->system->media_img_default_alignment)).
-	'</label></p>'.
+	'</p>'.
 	'<p><label for="media_img_default_link" class="classic">'.
 	form::checkbox('media_img_default_link','1',$blog_settings->system->media_img_default_link).
@@ -504,9 +514,10 @@
 	'</div>'.
 	'</div>'.
-
-	'</fieldset>';
-	
-	echo
-	'<fieldset><legend>'.__('Search engines robots policy').'</legend>';
+	'<br class="clear" />'. //Opera sucks
+
+	'</div>';
+	
+	echo
+	'<div class="fieldset"><h4>'.__('Search engines robots policy').'</h4>';
 	
 	$i = 0;
@@ -518,5 +529,5 @@
 	}
 	
-	echo '</fieldset>';
+	echo '</div>';
 	
 	
@@ -540,7 +551,7 @@
 	} else {
 		if ($blog_id == $core->blog->id) {
-			echo '<p class="message">'.__('The current blog cannot be deleted').'</p>';
+			echo '<p class="message">'.__('The current blog cannot be deleted.').'</p>';
 		} else {
-			echo '<p class="message">'.__('Only superadmin can delete a blog').'</p>';
+			echo '<p class="message">'.__('Only superadmin can delete a blog.').'</p>';
 		}
 	}
@@ -580,5 +591,5 @@
 				)).')</h4>';
 				
-				echo '<ul>';
+				echo '<ul class="nice">';
 				if ($v['super']) {
 					echo '<li>'.__('Super administrator').'</li>';
Index: admin/blog_theme.php
===================================================================
--- admin/blog_theme.php	(revision 1263)
+++ admin/blog_theme.php	(revision 1553)
@@ -173,7 +173,7 @@
 	'<div class="theme-shot"><img src="'.$screenshot.'" alt="" /></div>'.
 	'<div class="theme-info">'.
-		'<h3>'.form::radio(array('theme',$radio_id),html::escapeHTML($id),$current,'','',($has_parent && !$is_parent_present)).' '.
+		'<h4>'.form::radio(array('theme',$radio_id),html::escapeHTML($id),$current,'','',($has_parent && !$is_parent_present)).' '.
 		'<label class="classic" for="'.$radio_id.'">'.
-		html::escapeHTML($details['name']).'</label></h3>'.
+		html::escapeHTML($details['name']).'</label></h4>'.
 		'<p><span class="theme-desc">'.html::escapeHTML($details['desc']).'</span> '.
 		'<span class="theme-author">'.sprintf(__('by %s'),html::escapeHTML($details['author'])).'</span> '.
@@ -187,5 +187,5 @@
 		}
 		if ($has_css) {
-			$res .= '<a class="theme-css" href="'.$theme_url.'/style.css">'.__('Stylesheet').'</a>';
+			$res .= '<span class="theme-css"><a href="'.$theme_url.'/style.css">'.__('Stylesheet').'</a></span>';
 		}
 		$res .= '</p>';
@@ -207,41 +207,48 @@
 }
 
+if (!$theme_conf_mode)
+{
+	$breadcrumb = dcPage::breadcrumb(
+		array(
+			html::escapeHTML($core->blog->name) => '',
+			'<span class="page-title">'.__('Blog appearance').'</span>' => ''
+		));
+} else {
+	$breadcrumb = dcPage::breadcrumb(
+		array(
+			html::escapeHTML($core->blog->name) => '',
+			__('Blog appearance') => 'blog_theme.php',
+			'<span class="page-title">'.__('Theme configuration').'</span>' => ''
+		));
+}
+
 dcPage::open(__('Blog appearance'),
 	(!$theme_conf_mode ? dcPage::jsLoad('js/_blog_theme.js') : '').
 	dcPage::jsPageTabs($default_tab).
-	dcPage::jsColorPicker()
+	dcPage::jsColorPicker(),
+	$breadcrumb
 );
 
 if (!$theme_conf_mode)
 {
-	echo
-	'<h2>'.html::escapeHTML($core->blog->name).' &rsaquo; <span class="page-title">'.__('Blog appearance').'</span></h2>';
-	
 	if (!empty($_GET['upd'])) {
-		dcPage::message(__('Theme has been successfully changed.'));
+		dcPage::success(__('Theme has been successfully changed.'));
 	}
 	
 	if (!empty($_GET['added'])) {
-		dcPage::message(($_GET['added'] == 2 ? __('Theme has been successfully upgraded') : __('Theme has been successfully installed.')));
+		dcPage::success(($_GET['added'] == 2 ? __('Theme has been successfully upgraded') : __('Theme has been successfully installed.')));
 	}
 	
 	if (!empty($_GET['del'])) {
-		dcPage::message(__('Theme has been successfully deleted.'));
-	}
-	
-	if ($can_install) {
-		echo
-		'<p><strong>'.sprintf(__('You can find additional themes for your blog on %s.'),
-		'<a href="http://themes.dotaddict.org/galerie-dc2/">Dotaddict</a>').'</strong> '.
-		__('To install or upgrade a theme you generally just need to upload it '.
-		'in "Install or upgrade a theme" section.').'</p>';
+		dcPage::success(__('Theme has been successfully deleted.'));
 	}
 	
 	# Themes list
-	echo '<div class="multi-part" id="themes-list" title="'.__('Themes').'">';
+	echo '<div class="multi-part" id="themes-list" title="'.__('Themes').'">'.
+	'<h3>'.__('Available themes in your installation').'</h3>';
 	
 	$themes = $core->themes->getModules();
 	if (isset($themes[$core->blog->settings->system->theme])) {
-		echo '<h3>'.sprintf(__('You are currently using "%s"'),$themes[$core->blog->settings->system->theme]['name']).'</h3>';
+		echo '<p>'.sprintf(__('You are currently using <strong>%s</strong>'),$themes[$core->blog->settings->system->theme]['name']).'.</p>';
 	}
 	
@@ -265,13 +272,12 @@
 	
 	echo
-	'<div class="two-cols clear" id="themes-actions">'.
-	$core->formNonce().
-	'<p class="col"><input type="submit" name="select" value="'.__('Use selected theme').'" /></p>';
-	
+	'<div id="themes-actions">'.
+	
+	'<p>'.$core->formNonce().'<input type="submit" name="select" value="'.__('Use selected theme').'" /> ';	
 	if ($can_install) {
-		echo '<p class="col right"><input type="submit" class="delete" name="remove" value="'.__('Delete selected theme').'" /></p>';
-	}
-	
-	echo
+		echo ' <input type="submit" class="delete" name="remove" value="'.__('Delete selected theme').'" />';
+	}
+	echo '</p>'.
+	
 	'</div>'.
 	'</form>'.
@@ -282,36 +288,35 @@
 	{
 		echo
-		'<div class="multi-part clear" id="add-theme" title="'.__('Install or upgrade a theme').'">';
+		'<div class="multi-part clear" id="add-theme" title="'.__('Install or upgrade a theme').'">'.
+		'<h3>'.__('Add themes to your installation').'</h3>'.
+		'<p class="form-note info">'.sprintf(__('You can find additional themes for your blog on %s.'),
+		'<a href="http://themes.dotaddict.org/galerie-dc2/">Dotaddict</a>').'</p>';
 		
 		if ($is_writable)
 		{
-			echo '<p>'.__('You can install themes by uploading or downloading zip files.').'</p>';
+			echo '<p>'.__('You can also install themes by uploading or downloading zip files.').'</p>';
 			
 			# 'Upload theme' form
 			echo
-			'<form method="post" action="blog_theme.php" id="uploadpkg" enctype="multipart/form-data">'.
-			'<fieldset>'.
-			'<legend>'.__('Upload a zip file').'</legend>'.
-			'<p class="field"><label for="pkg_file" class="classic required"><abbr title="'.__('Required field').'">*</abbr> '.__('Theme zip file:').' '.
-			'<input type="file" name="pkg_file" id="pkg_file" /></label></p>'.
-			'<p class="field"><label for="your_pwd1" class="classic required"><abbr title="'.__('Required field').'">*</abbr> '.__('Your password:').' '.
-			form::password(array('your_pwd','your_pwd1'),20,255).'</label></p>'.
-			'<input type="submit" name="upload_pkg" value="'.__('Upload theme').'" />'.
-			$core->formNonce().
-			'</fieldset>'.
+			'<form method="post" action="blog_theme.php" id="uploadpkg" enctype="multipart/form-data" class="fieldset">'.
+			'<h4>'.__('Upload a zip file').'</h4>'.
+			'<p class="field"><label for="pkg_file" class="classic required"><abbr title="'.__('Required field').'">*</abbr> '.__('Theme zip file:').'</label> '.
+			'<input type="file" name="pkg_file" id="pkg_file" /></p>'.
+			'<p class="field"><label for="your_pwd1" class="classic required"><abbr title="'.__('Required field').'">*</abbr> '.__('Your password:').'</label> '.
+			form::password(array('your_pwd','your_pwd1'),20,255).'</p>'.
+			'<p><input type="submit" name="upload_pkg" value="'.__('Upload theme').'" />'.
+			$core->formNonce().'</p>'.
 			'</form>';
 			
 			# 'Fetch theme' form
 			echo
-			'<form method="post" action="blog_theme.php" id="fetchpkg">'.
-			'<fieldset>'.
-			'<legend>'.__('Download a zip file').'</legend>'.
-			'<p class="field"><label for="pkg_url" class="classic required"><abbr title="'.__('Required field').'">*</abbr> '.__('Theme zip file URL:').' '.
-			form::field(array('pkg_url','pkg_url'),40,255).'</label></p>'.
-			'<p class="field"><label for="your_pwd2" class="classic required"><abbr title="'.__('Required field').'">*</abbr> '.__('Your password:').' '.
-			form::password(array('your_pwd','your_pwd2'),20,255).'</label></p>'.
-			'<input type="submit" name="fetch_pkg" value="'.__('Download theme').'" />'.
-			$core->formNonce().
-			'</fieldset>'.
+			'<form method="post" action="blog_theme.php" id="fetchpkg" class="fieldset">'.
+			'<h4>'.__('Download a zip file').'</h4>'.
+			'<p class="field"><label for="pkg_url" class="classic required"><abbr title="'.__('Required field').'">*</abbr> '.__('Theme zip file URL:').'</label> '.
+			form::field(array('pkg_url','pkg_url'),40,255).'</p>'.
+			'<p class="field"><label for="your_pwd2" class="classic required"><abbr title="'.__('Required field').'">*</abbr> '.__('Your password:').'</label> '.
+			form::password(array('your_pwd','your_pwd2'),20,255).'</p>'.
+			'<p><input type="submit" name="fetch_pkg" value="'.__('Download theme').'" />'.
+			$core->formNonce().'</p>'.
 			'</form>';
 		}
@@ -330,8 +335,7 @@
 	$theme_name = $core->themes->moduleInfo($core->blog->settings->system->theme,'name');
 	$core->themes->loadModuleL10Nresources($core->blog->settings->system->theme,$_lang);
+
 	echo
-	'<h2>'.html::escapeHTML($core->blog->name).
-	' &rsaquo; <a href="blog_theme.php">'.__('Blog appearance').'</a> &rsaquo; <span class="page-title">'.__('Theme configuration').'</span></h2>'.
-	'<p><a class="back" href="blog_theme.php">'.__('back').'</a></p>';
+	'<p><a class="back" href="blog_theme.php">'.__('Back to Blog appearance').'</a></p>';
 	
 	try
Index: admin/blogs.php
===================================================================
--- admin/blogs.php	(revision 1179)
+++ admin/blogs.php	(revision 1668)
@@ -73,11 +73,15 @@
 	$starting_script .= dcPage::jsLoad('js/filter-controls.js');
 }
-dcPage::open(__('List of blogs'),$starting_script);
+dcPage::open(__('List of blogs'),$starting_script,
+	dcPage::breadcrumb(
+		array(
+			__('System') => '',
+			'<span class="page-title">'.__('List of blogs').'</span>' => ''
+		))
+);
 
 if (!empty($_GET['del'])) {
-	dcPage::message(__('Blog has been successfully deleted.'));
+	dcPage::success(__('Blog has been successfully deleted.'));
 }
-
-echo '<h2 class="page-title">'.__('List of blogs').'</h2>';
 
 if (!$core->error->flag())
@@ -88,31 +92,31 @@
 	
 	if (!$show_filters) {
-		echo '<p><a id="filter-control" class="form-control" href="#">'.__('Filters').'</a></p>';
+		echo '<p><a id="filter-control" class="form-control" href="#">'.__('Filter blogs list').'</a></p>';
 	}
 	
 	echo
 	'<form action="blogs.php" method="get" id="filters-form">'.
-	'<fieldset class="two-cols"><legend>'.__('Filters').'</legend>'.
+	'<h3 class="hidden">'.__('Filter blogs list').'</h3>'.
 	
-	'<div class="col">'.
-	'<p><label for="sortby">'.__('Order by:').' '.
-	form::combo('sortby',$sortby_combo,html::escapeHTML($sortby)).
-	'</label> '.
-	'<label for="order">'.__('Sort:').' '.
-	form::combo('order',$order_combo,html::escapeHTML($order)).
-	'</label></p>'.
+	'<div class="table">'.
+	'<div class="cell">'.
+	'<h4>'.__('Filters').'</h4>'.
+	'<p><label for="q" class="ib">'.__('Search:').'</label> '.
+	form::field('q',20,255,html::escapeHTML($q)).'</p>'.
 	'</div>'.
 	
-	'<div class="col">'.
-	'<p><label for="q">'.__('Search:').' '.
-	form::field('q',20,255,html::escapeHTML($q)).
-	'</label></p>'.
-	'<p><label for="nb" class="classic">'.	form::field('nb',3,3,$nb_per_page).' '.
-	__('Blogs per page').'</label> '.
-	'<input type="submit" value="'.__('Apply filters').'" /></p>'.
+	'<div class="cell filters-options">'.
+	'<h4>'.__('Display options').'</h4>'.
+	'<p><label for="sortby" class="ib">'.__('Order by:').'</label> '.
+	form::combo('sortby',$sortby_combo,html::escapeHTML($sortby)).'</p>'.
+	'<p><label for="order" class="ib">'.__('Sort:').'</label> '.
+	form::combo('order',$order_combo,html::escapeHTML($order)).'</p>'.
+	'<p><span class="label ib">'.__('Show').'</span> <label for="nb" class="classic">'.	
+	form::field('nb',3,3,$nb_per_page).' '.__('blogs per page').'</label></p>'.
 	'</div>'.
-	
-	'<br class="clear" />'. //Opera sucks
-	'</fieldset>'.
+	'</div>'.
+
+	'<p><input type="submit" value="'.__('Apply filters and display options').'" />'.
+	'<br class="clear" /></p>'. //Opera sucks
 	'</form>';
 	
@@ -127,14 +131,13 @@
 		$pager->var_page = 'page';
 		
-		echo '<p>'.__('Page(s)').' : '.$pager->getLinks().'</p>';
+		echo '<p class="pagination">'.__('Page(s)').' : '.$pager->getLinks().'</p>';
 		
 		echo
-		'<table class="clear"><tr>'.
-		'<th>'.__('Blog name').'</th>'.
-		'<th class="nowrap">'.__('Last update').'</th>'.
-		'<th class="nowrap">'.__('Entries (all types)').'</th>'.
-		'<th class="nowrap">'.__('Blog ID').'</th>'.
-		'<th>&nbsp;</th>'.
-		'<th class="nowrap">'.__('Status').'</th>'.
+		'<table class="clear"><caption class="hidden">'.__('Blogs list').'</caption><tr>'.
+		'<th scope="col" class="nowrap">'.__('Blog id').'</th>'.
+		'<th scope="col">'.__('Blog name').'</th>'.
+		'<th scope="col" class="nowrap">'.__('Entries (all types)').'</th>'.
+		'<th scope="col" class="nowrap">'.__('Last update').'</th>'.
+		'<th scope="col" class="nowrap">'.__('Status').'</th>'.
 		'</tr>';
 		
@@ -145,5 +148,5 @@
 		echo '</table>';
 		
-		echo '<p>'.__('Page(s)').' : '.$pager->getLinks().'</p>';
+		echo '<p class="pagination">'.__('Page(s)').' : '.$pager->getLinks().'</p>';
 	}
 }
@@ -160,7 +163,6 @@
 	if ($GLOBALS['core']->auth->isSuperAdmin()) {
 		$edit_link = 
-		'<a href="blog.php?id='.$blog_id.'" '.
-		'title="'.sprintf(__('Edit blog %s'),$blog_id).'">'.
-		__('edit').'</a>';
+		'<a href="blog.php?id='.$blog_id.'"  title="'.sprintf(__('Edit blog settings for %s'),$blog_id).'">'.
+		'<img src="images/edit-mini.png" alt="'.__('Edit blog settings').'" /> '.$blog_id.'</a> ';
 	}
 	
@@ -173,11 +175,10 @@
 	return
 	'<tr class="line">'.
+	'<td class="nowrap">'.$edit_link.'</td>'.
 	'<td class="maximal"><a href="index.php?switchblog='.$rs->blog_id.'" '.
 	'title="'.sprintf(__('Switch to blog %s'),$rs->blog_id).'">'.
 	html::escapeHTML($rs->blog_name).'</a></td>'.
-	'<td class="nowrap">'.$blog_upddt.'</td>'.
-	'<td class="nowrap">'.$core->countBlogPosts($rs->blog_id).'</td>'.
-	'<td class="nowrap">'.$blog_id.'</td>'.
-	'<td>'.$edit_link.'</td>'.
+	'<td class="nowrap count">'.$core->countBlogPosts($rs->blog_id).'</td>'.
+	'<td class="nowrap count">'.$blog_upddt.'</td>'.
 	'<td class="status">'.$img_status.'</td>'.
 	'</tr>';
Index: admin/categories.php
===================================================================
--- admin/categories.php	(revision 1421)
+++ admin/categories.php	(revision 1662)
@@ -15,42 +15,55 @@
 dcPage::check('categories');
 
-# Remove a category
-if (!empty($_POST['del_cat']))
-{
-	try
-	{
-		# Check if category to delete exists
-		$c = $core->blog->getCategory((integer) $_POST['del_cat']);
-		if ($c->isEmpty()) {
-			throw new Exception(__('This category does not exist.'));
-		}
-		unset($c);
-		
+# Remove a categories
+if (!empty($_POST['categories']) && !empty($_POST['delete'])) {
+	try {
 		# Check if category where to move posts exists
-		$mov_cat = (integer) $_POST['mov_cat'];
+		$mov_cat = (int) $_POST['mov_cat'];
 		$mov_cat = $mov_cat ? $mov_cat : null;
 		if ($mov_cat !== null) {
-			$c = $core->blog->getCategory((integer) $_POST['mov_cat']);
+			$c = $core->blog->getCategory($mov_cat);
 			if ($c->isEmpty()) {
-				throw new Exception(__('This category does not exist.'));
-			}
-			if ($mov_cat == $_POST['del_cat']) {
+				throw new Exception(__('Category where to move posts does not exist'));
+			}
+			unset($c);
+
+			if (in_array($mov_cat, $_POST['categories'])) {
 				throw new Exception(__('The entries cannot be moved to the category you choose to delete.'));
 			}
+		}
+
+		foreach ($_POST['categories'] as $cat_id) {
+			# Check if category to delete exists
+			$c = $core->blog->getCategory((integer) $cat_id);
+			if ($c->isEmpty()) {
+				continue;
+			}
 			unset($c);
-		}
-		
-		# Move posts
-		$core->blog->changePostsCategory($_POST['del_cat'],$mov_cat);
-		
-		# Delete category
-		$core->blog->delCategory($_POST['del_cat']);
-		
-		http::redirect('categories.php?del=1');
-	}
-	catch (Exception $e)
-	{
+
+			# Move posts
+			if ($mov_cat != $cat_id) {
+			        $core->blog->changePostsCategory($cat_id,$mov_cat);
+			}
+
+			# Delete category
+			$core->blog->delCategory($cat_id);
+		}
+		http::redirect('categories.php?del='.count($_POST['categories']));
+	} catch (Exception $e) {
 		$core->error->add($e->getMessage());
 	}
+}
+
+# Update order
+if (!empty($_POST['save_order']) && !empty($_POST['categories_order'])) {
+	$categories = json_decode($_POST['categories_order']);
+
+	foreach ($categories as $category) {
+		if (!empty($category->item_id)) {
+			$core->blog->updCategoryPosition($category->item_id, $category->left, $category->right);
+		}
+	}
+
+	http::redirect('categories.php?reord=1');
 }
 
@@ -69,75 +82,36 @@
 }
 
+
 /* Display
 -------------------------------------------------------- */
-dcPage::open(__('Categories'),
-	dcPage::jsToolMan()."\n".
-	dcPage::jsLoad('js/_categories.js')
+$rs = $core->blog->getCategories(array('post_type'=>'post'));
+
+$starting_script = "";
+if (!$core->auth->user_prefs->accessibility->nodragdrop
+	&& $core->auth->check('categories',$core->blog->id)
+	&& $rs->count()>1) {
+		$starting_script .= dcPage::jsLoad('js/jquery/jquery-ui.custom.js');
+		$starting_script .= dcPage::jsLoad('js/jquery/jquery.mjs.nestedSortable.js');
+}
+$starting_script .= dcPage::jsLoad('js/_categories.js');
+
+dcPage::open(__('Categories'),$starting_script,
+	dcPage::breadcrumb(
+		array(
+			html::escapeHTML($core->blog->name) => '',
+			'<span class="page-title">'.__('Categories').'</span>' => ''
+		))
 );
 
-if (!empty($_GET['add'])) {
-	dcPage::message(__('The category has been successfully created.'));
-}
 if (!empty($_GET['del'])) {
-	dcPage::message(__('The category has been successfully removed.'));
+        dcPage::success(__('The category has been successfully removed.',
+			   'The categories have been successfully removed.',
+			   (int) $_GET['del']
+			   )
+			);
 }
 if (!empty($_GET['reord'])) {
-	dcPage::message(__('Categories have been successfully reordered.'));
-}
-if (!empty($_GET['moved'])) {
-	dcPage::message(__('The category has been successfully moved.'));
-}
-
-echo '<h2>'.html::escapeHTML($core->blog->name).' &rsaquo; <span class="page-title">'.__('Categories').'</span></h2>';
-
-$rs = $core->blog->getCategories(array('post_type'=>'post'));
-
-echo
-'<div class="two-cols">'.
-'<div class="col">';
-if ($rs->isEmpty())
-{
-	echo '<p>'.__('No category yet.').'</p>';
-}
-else
-{
-	echo
-	'<h3>'.__('Categories list').'</h3>'.
-	'<div id="categories">';
-	
-	$ref_level = $level = $rs->level-1;
-	while ($rs->fetch())
-	{
-		$attr = 'id="cat'.$rs->cat_id.'"';
-		if ($rs->nb_total == 0) {
-			$attr .= ' class="deletable"';
-		}
-		
-		if ($rs->level > $level) {
-			echo str_repeat('<ul><li '.$attr.'>',$rs->level - $level);
-		} elseif ($rs->level < $level) {
-			echo str_repeat('</li></ul>',-($rs->level - $level));
-		}
-		
-		if ($rs->level <= $level) {
-			echo '</li><li '.$attr.'>';
-		}
-		
-		echo
-		'<p><strong><a href="category.php?id='.$rs->cat_id.'">'.html::escapeHTML($rs->cat_title).'</a></strong>'.
-		' (<a href="posts.php?cat_id='.$rs->cat_id.'">'.
-		sprintf(($rs->nb_post > 1 ? __('%d entries') : __('%d entry') ),$rs->nb_post).'</a>'.
-		', '.__('total:').' '.$rs->nb_total.')</p>'.
-		'<p>'.__('URL:').' '.html::escapeHTML($rs->cat_url).'</p>';
-		
-		$level = $rs->level;
-	}
-	
-	if ($ref_level - $level < 0) {
-		echo str_repeat('</li></ul>',-($ref_level - $level));
-	}
-	echo '</div>';
-}
-echo '</div>';
+	dcPage::success(__('Categories have been successfully reordered.'));
+}
 
 $categories_combo = array();
@@ -152,43 +126,86 @@
 }
 
-echo '<div class="col">'.
-
-'<form action="category.php" method="post">'.
-'<fieldset><legend>'.__('Add a new category').'</legend>'.
-'<p><label class="required" for="cat_title"><abbr title="'.__('Required field').'">*</abbr> '.__('Title:').' '.
-form::field('cat_title',30,255,'','maximal').'</label></p>'.
-'<p><label for="new_cat_parent">'.__('Parent:').' '.
-form::combo('new_cat_parent',array_merge(array(__('(No cat)') => 0),$categories_combo),'','maximal').
-'</label></p>'.
-'<p><input type="submit" value="'.__('Create').'" /></p>'.
-$core->formNonce().
-'</fieldset>'.
-'</form>';
-
-if (!$rs->isEmpty())
-{
-	echo
-	'<form action="categories.php" method="post" id="delete-category">'.
-	'<fieldset><legend>'.__('Remove a category').'</legend>'.
-	'<p><label for="del_cat">'.__('Choose a category to remove:').' '.
-	form::combo('del_cat',$categories_combo,'','maximal').'</label></p> '.
-	'<p><label for="mov_cat">'.__('And choose the category which will receive its entries:').' '.
-	form::combo('mov_cat',array_merge(array(__('(No cat)') => ''),$categories_combo),'','maximal').'</label></p> '.
-	'<p><input type="submit" value="'.__('Delete').'" class="delete" /></p>'.
-	$core->formNonce().
-	'</fieldset>'.
+echo
+'<p class="top-add"><a class="button add" href="category.php">'.__('New category').'</a></p>';
+
+echo
+'<div class="col">';
+if ($rs->isEmpty())
+{
+	echo '<p>'.__('No category so far.').'</p>';
+}
+else
+{
+	echo
+	'<form action="categories.php" method="post" id="form-categories">'.
+	'<h3>'.__('List of blog\'s categories').'</h3>'.
+	'<div id="categories">';
+
+	$ref_level = $level = $rs->level-1;
+	while ($rs->fetch())
+	{
+		$attr = 'id="cat_'.$rs->cat_id.'"';
+
+		if ($rs->level > $level) {
+			echo str_repeat('<ul><li '.$attr.'>',$rs->level - $level);
+		} elseif ($rs->level < $level) {
+			echo str_repeat('</li></ul>',-($rs->level - $level));
+		}
+
+		if ($rs->level <= $level) {
+			echo '</li><li '.$attr.'>';
+		}
+
+		echo
+		'<p>'.
+		form::checkbox(array('categories[]','cat-'.$rs->cat_id),$rs->cat_id,null,$rs->nb_total>0?'notempty':'').
+		'<label class="classic" for="cat-'.$rs->cat_id.'"><a href="category.php?id='.$rs->cat_id.'">'.html::escapeHTML($rs->cat_title).'</a></label>'.
+		' (<a href="posts.php?cat_id='.$rs->cat_id.'">'.
+		sprintf(($rs->nb_post > 1 ? __('%d entries') : __('%d entry') ),$rs->nb_post).'</a>'.
+		', '.__('total:').' '.$rs->nb_total.') '.
+		'<span class="cat-url">'.__('URL:').' <code>'.html::escapeHTML($rs->cat_url).'</code></span></p>';
+
+		$level = $rs->level;
+	}
+
+	if ($ref_level - $level < 0) {
+		echo str_repeat('</li></ul>',-($ref_level - $level));
+	}
+	echo
+	'</div>';
+
+	echo
+	'<div class="two-cols">'.
+	'<p class="col checkboxes-helpers"></p>'.
+	'<p class="col right" id="mov-cat">'.
+	'<label for="mov_cat" class="classic">'.__('Category which will receive entries of deleted categories:').'</label> '.
+	form::combo('mov_cat',array_merge(array(__('(No cat)') => ''),$categories_combo),'','').
+	'</p>'.
+	'<p class="right">'.
+	'<input type="submit" class="delete" name="delete" value="'.__('Delete selected categories').'"/>'.
+	'</p>'.
+	'</div>';
+
+	echo '<h3 class="clear hidden-if-no-js">'.__('Categories order').'</h3>';
+
+	if ($core->auth->check('categories',$core->blog->id) && $rs->count()>1) {
+		if (!$core->auth->user_prefs->accessibility->nodragdrop) {
+			echo '<p class="hidden-if-no-js">'.__('To rearrange categories order, move items by drag and drop, then click on “Save categories order” button.').'</p>';
+		}
+		echo
+		'<p class="hidden-if-no-js">'.
+		'<input type="hidden" id="categories_order" name="categories_order" value=""/>'.
+		'<input type="submit" name="save_order" id="save-set-order" value="'.__('Save categories order').'" />'.
+		'</p>';
+	}
+
+	echo
+	'<p class="hidden-if-js right"><input type="submit" name="reset" value="'.__('Reorder all categories on the top level and delete selected categories').'" />'.
+	$core->formNonce().'</p>'.
+	'<p class="hidden-if-no-js"><input type="submit" name="reset" value="'.__('Reorder all categories on the top level').'" />'.
+	$core->formNonce().'</p>'.
 	'</form>';
-	
-	echo
-	'<form action="categories.php" method="post" id="reset-order">'.
-	'<fieldset><legend>'.__('Reorder categories').'</legend>'.
-	'<p>'.__('This will relocate all categories on the top level').'</p> '.
-	'<p><input type="submit" value="'.__('Reorder').'" /></p>'.
-	form::hidden(array('reset'),1).
-	$core->formNonce().
-	'</fieldset>'.
-	'</form>';
-}
-echo '</div>';
+}
+
 echo '</div>';
 
Index: admin/category.php
===================================================================
--- admin/category.php	(revision 1179)
+++ admin/category.php	(revision 1571)
@@ -157,34 +157,32 @@
 $title = $cat_id ? html::escapeHTML($cat_title) : __('New category');
 
+$elements = array(
+	html::escapeHTML($core->blog->name) => '',
+	__('Categories') => 'categories.php'
+	);
+if ($cat_id) {
+	while($parents->fetch()) {
+		$elements[html::escapeHTML($parents->cat_title)] = 'category.php?id='.$parents->cat_id;
+	}
+}
+$elements['<span class="page-title">'.$title.'</span>'] = '';
+
 dcPage::open($title,
 	dcPage::jsConfirmClose('category-form').
 	dcPage::jsToolBar().
-	dcPage::jsLoad('js/_category.js')
+	dcPage::jsLoad('js/_category.js'),
+	dcPage::breadcrumb($elements)
 );
 
 if (!empty($_GET['upd'])) {
-	dcPage::message(__('Category has been successfully updated.'));
-}
-
-echo
-'<h2>'.html::escapeHTML($core->blog->name).' &rsaquo; <a href="categories.php">'.
-__('Categories').'</a> &rsaquo; ';
-
-if ($cat_id)
-{
-	while($parents->fetch()) {
-		echo '<a href="category.php?id='.$parents->cat_id.'">'.html::escapeHTML($parents->cat_title).'</a>';
-		echo " &rsaquo; ";
-	}
-}
-
-echo '<span class="page-title">'.$title.'</span></h2>';
+	dcPage::success(__('Category has been successfully updated.'));
+}
 
 echo
 '<form action="category.php" method="post" id="category-form">'.
-'<fieldset><legend>'.__('Category information').'</legend>'.
-'<p><label class="required" for="cat_title"><abbr title="'.__('Required field').'">*</abbr> '.__('Title:').' '.
+'<h3>'.__('Category information').'</h3>'.
+'<p><label class="required" for="cat_title"><abbr title="'.__('Required field').'">*</abbr> '.__('Title:').'</label> '.
 form::field('cat_title',40,255,html::escapeHTML($cat_title)).
-'</label></p>';
+'</p>';
 if (!$cat_id)
 {
@@ -193,8 +191,8 @@
 	'<p><label for="new_cat_parent">'.__('Parent:').' '.
 	'<select id="new_cat_parent" name="new_cat_parent" >'.
-	'<option value="0">'.__('Top level').'</option>';
+	'<option value="0">'.__('(none)').'</option>';
 	while ($rs->fetch()) {
 		echo '<option value="'.$rs->cat_id.'" '.(!empty($_POST['new_cat_parent']) && $_POST['new_cat_parent'] == $rs->cat_id ? 'selected="selected"' : '').'>'.
-		str_repeat('&nbsp;&nbsp;',$rs->level).html::escapeHTML($rs->cat_title).'</option>';
+		str_repeat('&nbsp;&nbsp;',$rs->level-1).($rs->level-1 == 0 ? '' : '&bull; ').html::escapeHTML($rs->cat_title).'</option>';	
 	}
 	echo
@@ -204,6 +202,7 @@
 echo
 '<div class="lockable">'.
-'<p><label for="cat_url">'.__('URL:').' '.form::field('cat_url',40,255,html::escapeHTML($cat_url)).
-'</label></p>'.
+'<p><label for="cat_url">'.__('URL:').'</label> '
+.form::field('cat_url',40,255,html::escapeHTML($cat_url)).
+'</p>'.
 '<p class="form-note warn" id="note-cat-url">'.
 __('Warning: If you set the URL manually, it may conflict with another category.').'</p>'.
@@ -218,5 +217,4 @@
 $core->formNonce().
 '</p>'.
-'</fieldset>'.
 '</form>';
 
@@ -224,15 +222,14 @@
 {
 	echo
-	'<h3>'.__('Move this category').'</h3>'.
+	'<h3 class="border-top">'.__('Move this category').'</h3>'.
 	'<div class="two-cols">'.
 	'<div class="col">'.
 	
-	'<form action="category.php" method="post">'.
-	'<fieldset><legend>'.__('Category parent').'</legend>'.
-	'<p><label for="cat_parent" class="classic">'.__('Parent:').' '.
-	form::combo('cat_parent',$allowed_parents,$cat_parent).'</label></p>'.
+	'<form action="category.php" method="post" class="fieldset">'.
+	'<h4>'.__('Category parent').'</h4>'.
+	'<p><label for="cat_parent" class="classic">'.__('Parent:').'</label> '.
+	form::combo('cat_parent',$allowed_parents,$cat_parent).'</p>'.
 	'<p><input type="submit" accesskey="s" value="'.__('Save').'" />'.
 	form::hidden(array('id'),$cat_id).$core->formNonce().'</p>'.
-	'</fieldset>'.
 	'</form>'.
 	'</div>';
@@ -241,6 +238,6 @@
 		echo
 		'<div class="col">'.
-		'<form action="category.php" method="post">'.
-		'<fieldset><legend>'.__('Category sibling').'</legend>'.
+		'<form action="category.php" method="post" class="fieldset">'.
+		'<h4>'.__('Category sibling').'</h4>'.
 		'<p><label class="classic" for="cat_sibling">'.__('Move current category').'</label> '.
 		form::combo('cat_move',array(__('before')=>'before',__('after')=>'after'),'','','',false,'title="'.__('position: ').'"').' '.
@@ -248,5 +245,4 @@
 		'<p><input type="submit" accesskey="s" value="'.__('Save').'" />'.
 		form::hidden(array('id'),$cat_id).$core->formNonce().'</p>'.
-		'</fieldset>'.
 		'</form>'.
 		'</div>';
Index: admin/comment.php
===================================================================
--- admin/comment.php	(revision 1179)
+++ admin/comment.php	(revision 1553)
@@ -160,4 +160,20 @@
 /* DISPLAY
 -------------------------------------------------------- */
+if ($comment_id) {
+	$breadcrumb = dcPage::breadcrumb(
+		array(
+			html::escapeHTML($core->blog->name) => '',
+			html::escapeHTML($post_title) => $core->getPostAdminURL($post_type,$post_id).'&amp;co=1#c'.$comment_id,
+			'<span class="page-title">'.__('Edit comment').'</span>' => ''
+		));
+} else {
+	$breadcrumb = dcPage::breadcrumb(
+		array(
+			html::escapeHTML($core->blog->name) => '',
+			html::escapeHTML($post_title) => $core->getPostAdminURL($post_type,$post_id),
+			'<span class="page-title">'.__('Edit comment').'</span>' => ''
+		));
+}
+
 dcPage::open(__('Edit comment'),
 	dcPage::jsConfirmClose('comment-form').
@@ -165,5 +181,6 @@
 	dcPage::jsLoad('js/_comment.js').
 	# --BEHAVIOR-- adminCommentHeaders
-	$core->callBehavior('adminCommentHeaders')
+	$core->callBehavior('adminCommentHeaders'),
+	$breadcrumb
 );
 
@@ -171,5 +188,5 @@
 {
 	if (!empty($_GET['upd'])) {
-		dcPage::message(__('Comment has been successfully updated.'));
+		dcPage::success(__('Comment has been successfully updated.'));
 	}
 	
@@ -183,33 +200,33 @@
 		.'">'.__('Send an e-mail').'</a>';
 	}
-	
-	echo '<h2>'.html::escapeHTML($core->blog->name).' &rsaquo; <a href="'.
-		$core->getPostAdminURL($post_type,$post_id).'&amp;co=1#c'.$comment_id.'"> '.
-		$post_title.'</a> &rsaquo; <span class="page-title">'.__('Edit comment').'</span></h2>';
-		
+
 	echo
 	'<form action="comment.php" method="post" id="comment-form">'.
-	'<p>'.__('IP address:').'<br /> '.
+	'<div class="fieldset">'.
+	'<h3>'.__('Information collected').'</h3>'.
+	'<p>'.__('IP address:').' '.
 	'<a href="comments.php?ip='.$comment_ip.'">'.$comment_ip.'</a></p>'.
 	
-	'<p>'.__('Date:').'<br /> '.
+	'<p>'.__('Date:').' '.
 	dt::dt2str(__('%Y-%m-%d %H:%M'),$comment_dt).'</p>'.
-	
-	'<p><label for="comment_author" class="required"><abbr title="'.__('Required field').'">*</abbr>'.__('Author:').
+	'</div>'.
+
+	'<h3>'.__('Comment submitted').'</h3>'.	
+	'<p><label for="comment_author" class="required"><abbr title="'.__('Required field').'">*</abbr>'.__('Author:').'</label>'.
 	form::field('comment_author',30,255,html::escapeHTML($comment_author)).
-	'</label></p>'.
-	
-	'<p><label for="comment_email">'.__('Email:').
+	'</p>'.
+	
+	'<p><label for="comment_email">'.__('Email:').'</label>'.
 	form::field('comment_email',30,255,html::escapeHTML($comment_email)).
-	$comment_mailto.
-	'</label></p>'.
-	
-	'<p><label for="comment_site">'.__('Web site:').
+	'<span>'.$comment_mailto.'</span>'.
+	'</p>'.
+	
+	'<p><label for="comment_site">'.__('Web site:').'</label>'.
 	form::field('comment_site',30,255,html::escapeHTML($comment_site)).
-	'</label></p>'.
-	
-	'<p><label for="comment_status">'.__('Status:').
+	'</p>'.
+	
+	'<p><label for="comment_status">'.__('Status:').'</label>'.
 	form::combo('comment_status',$status_combo,$comment_status,'','',!$can_publish).
-	'</label></p>'.
+	'</p>'.
 	
 	# --BEHAVIOR-- adminAfterCommentDesc
Index: admin/comments.php
===================================================================
--- admin/comments.php	(revision 1179)
+++ admin/comments.php	(revision 1528)
@@ -37,6 +37,6 @@
 $type_combo = array(
 '-' => '',
-__('comment') => 'co',
-__('trackback') => 'tb'
+__('Comment') => 'co',
+__('Trackback') => 'tb'
 );
 
@@ -134,8 +134,8 @@
 if ($core->auth->check('publish,contentadmin',$core->blog->id))
 {
-	$combo_action[__('publish')] = 'publish';
-	$combo_action[__('unpublish')] = 'unpublish';
-	$combo_action[__('mark as pending')] = 'pending';
-	$combo_action[__('mark as junk')] = 'junk';
+	$combo_action[__('Publish')] = 'publish';
+	$combo_action[__('Unpublish')] = 'unpublish';
+	$combo_action[__('Mark as pending')] = 'pending';
+	$combo_action[__('Mark as junk')] = 'junk';
 }
 if ($core->auth->check('delete,contentadmin',$core->blog->id))
@@ -169,7 +169,11 @@
 $starting_script .= $core->callBehavior('adminCommentsHeaders');
 
-dcPage::open(__('Comments and trackbacks'),$starting_script);
-
-echo '<h2>'.html::escapeHTML($core->blog->name).' &rsaquo; <span class="page-title">'.__('Comments and trackbacks').'</span></h2>';
+dcPage::open(__('Comments and trackbacks'),$starting_script,
+	dcPage::breadcrumb(
+		array(
+			html::escapeHTML($core->blog->name) => '',
+			'<span class="page-title">'.__('Comments and trackbacks').'</span>' => ''
+		))
+);
 
 if (!$core->error->flag())
@@ -179,49 +183,4 @@
 		unset($_SESSION['comments_del_spam']);
 	}
-	
-	# Filters
-	if (!$show_filters) {
-		echo '<p><a id="filter-control" class="form-control" href="#">'.
-		__('Filters').'</a></p>';
-	}
-	
-	echo
-	'<form action="comments.php" method="get" id="filters-form">'.
-	'<fieldset><legend>'.__('Filters').'</legend>'.
-	'<div class="three-cols">'.
-	'<div class="col">'.
-	'<label for="type">'.__('Type:').' '.
-	form::combo('type',$type_combo,$type).
-	'</label> '.
-	'<label for="status">'.__('Status:').' '.
-	form::combo('status',$status_combo,$status).
-	'</label>'.
-	'</div>'.
-	
-	'<div class="col">'.
-	'<p><label for="sortby">'.__('Order by:').' '.
-	form::combo('sortby',$sortby_combo,$sortby).
-	'</label> '.
-	'<label for="order">'.__('Sort:').' '.
-	form::combo('order',$order_combo,$order).
-	'</label></p>'.
-	'<p><label for="nb" class="classic">'.	form::field('nb',3,3,$nb_per_page).' '.
-	__('Comments per page').'</label></p>'.
-	'</div>'.
-	
-	'<div class="col">'.
-	'<p><label for="author">'.__('Comment author:').' '.
-	form::field('author',20,255,html::escapeHTML($author)).
-	'</label>'.
-	'<label for="ip">'.__('IP address:').' '.
-	form::field('ip',20,39,html::escapeHTML($ip)).
-	'</label></p>'.
-	'<p><input type="submit" value="'.__('Apply filters').'" /></p>'.
-	'</div>'.
-	
-	'</div>'.
-	'<br class="clear" />'. //Opera sucks
-	'</fieldset>'.
-	'</form>';
 	
 	$spam_count = $core->blog->getComments(array('comment_status'=>-2),true)->f(0);
@@ -233,13 +192,14 @@
 		if (!$with_spam || ($status != -2)) {
 			if ($spam_count == 1) {
-				echo '<p>'.sprintf(__('You have one spam comments.'),'<strong>'.$spam_count.'</strong>').' '.
-				'<a href="comments.php?status=-2">'.__('Show it.').'</a></p>';
+				echo '<p>'.sprintf(__('You have one spam comment.'),'<strong>'.$spam_count.'</strong>').' '.
+				'<a href="comments.php?status=-2">'.__('Show it.').'</a>.</p>';
 			} elseif ($spam_count > 1) {
 				echo '<p>'.sprintf(__('You have %s spam comments.'),'<strong>'.$spam_count.'</strong>').' '.
-				'<a href="comments.php?status=-2">'.__('Show them.').'</a></p>';
+				'<a href="comments.php?status=-2">'.__('Show them.').'</a>.</p>';
 			}
 		}
 		
 		echo
+			'<p class="no-margin">'.
 			$core->formNonce().
 			'<input name="delete_all_spam" class="delete" type="submit" value="'.__('Delete all spams').'" /></p>';
@@ -250,4 +210,46 @@
 		echo '</form>';
 	}
+
+	# Filters
+	if (!$show_filters) {
+		echo '<p><a id="filter-control" class="form-control" href="#">'.
+		__('Filter comments and trackbacks list').'</a></p>';
+	}
+	
+	echo
+	'<form action="comments.php" method="get" id="filters-form">'.
+	'<h3 class="hidden">'.__('Filter comments and trackbacks list').'</h3>'.
+	'<div class="table">'.
+
+	'<div class="cell">'.
+	'<h4>'.__('Filters').'</h4>'.
+	'<p><label for="type" class="ib">'.__('Type:').'</label> '.
+	form::combo('type',$type_combo,$type).'</p> '.
+	'<p><label for="status" class="ib">'.__('Status:').'</label> '.
+	form::combo('status',$status_combo,$status).'</p>'.
+	'</div>'.
+	
+	'<div class="cell filters-sibling-cell">'.
+	'<p><label for="author" class="ib">'.__('Author:').'</label> '.
+	form::field('author',20,255,html::escapeHTML($author)).'</p>'.
+	'<p><label for="ip" class="ib">'.__('IP address:').'</label> '.
+	form::field('ip',20,39,html::escapeHTML($ip)).'</p>'.
+	'</div>'.
+	
+	'<div class="cell filters-options">'.
+	'<h4>'.__('Display options').'</h4>'.
+	'<p><label for="sortby" class="ib">'.__('Order by:').'</label> '.
+	form::combo('sortby',$sortby_combo,$sortby).'</p>'.
+	'<p><label for="order" class="ib">'.__('Sort:').'</label> '.
+	form::combo('order',$order_combo,$order).'</p>'.
+	'<p><span class="label ib">Afficher</span> <label for="nb" class="classic">'.
+	form::field('nb',3,3,$nb_per_page).' '.
+	__('comments per page').'</label></p>'.
+	'</div>'.
+	
+	'</div>'.
+	'<p><input type="submit" value="'.__('Apply filters and display options').'" />'.
+	'<br class="clear" /></p>'. //Opera sucks
+	'</form>';
 	
 	# Show comments
@@ -261,5 +263,5 @@
 	
 	'<p class="col right"><label for="action" class="classic">'.__('Selected comments action:').'</label> '.
-	form::combo('action',$combo_action,$default,'','','','title="'.__('action: ').'"').
+	form::combo('action',$combo_action,$default,'','','','title="'.__('Actions').'"').
 	$core->formNonce().
 	'<input type="submit" value="'.__('ok').'" /></p>'.
Index: admin/comments_actions.php
===================================================================
--- admin/comments_actions.php	(revision 1179)
+++ admin/comments_actions.php	(revision 1474)
@@ -137,5 +137,5 @@
 $core->callBehavior('adminCommentsActionsContent',$core,$action,$hidden_fields);
 
-echo '<p><a class="back" href="'.str_replace('&','&amp;',$redir).'">'.__('back').'</a></p>';
+echo '<p><a class="back" href="'.str_replace('&','&amp;',$redir).'">'.__('Back to comments list').'</a></p>';
 
 dcPage::close();
Index: admin/index.php
===================================================================
--- admin/index.php	(revision 1591)
+++ admin/index.php	(revision 1620)
@@ -121,20 +121,5 @@
 $__dashboard_items = new ArrayObject(array(new ArrayObject,new ArrayObject));
 
-# Documentation links
 $dashboardItem = 0;
-if ($core->auth->user_prefs->dashboard->doclinks) {
-	if (!empty($__resources['doc']))
-	{
-		$doc_links = '<h3>'.__('Documentation and support').'</h3><ul>';
-	
-		foreach ($__resources['doc'] as $k => $v) {
-			$doc_links .= '<li><a href="'.$v.'" title="'.$k.' '.__('(external link)').'">'.$k.'</a></li>';
-		}
-	
-		$doc_links .= '</ul>';
-		$__dashboard_items[$dashboardItem][] = $doc_links;
-		$dashboardItem++;
-	}
-}
 
 if ($core->auth->user_prefs->dashboard->dcnews) {
@@ -180,4 +165,20 @@
 }
 
+# Documentation links
+if ($core->auth->user_prefs->dashboard->doclinks) {
+	if (!empty($__resources['doc']))
+	{
+		$doc_links = '<h3>'.__('Documentation and support').'</h3><ul>';
+	
+		foreach ($__resources['doc'] as $k => $v) {
+			$doc_links .= '<li><a href="'.$v.'" title="'.$k.' '.__('(external link)').'">'.$k.'</a></li>';
+		}
+	
+		$doc_links .= '</ul>';
+		$__dashboard_items[$dashboardItem][] = $doc_links;
+		$dashboardItem++;
+	}
+}
+
 $core->callBehavior('adminDashboardItems', $core, $__dashboard_items);
 
@@ -193,8 +194,29 @@
 	dcPage::jsLoad('js/_index.js').
 	# --BEHAVIOR-- adminDashboardHeaders
-	$core->callBehavior('adminDashboardHeaders')
+	$core->callBehavior('adminDashboardHeaders'),
+	dcPage::breadcrumb(
+		array(
+		'<span class="page-title">'.__('Dashboard').' : '.html::escapeHTML($core->blog->name).'</span>' => ''
+		),
+		false)
 );
 
-echo '<h2>'.html::escapeHTML($core->blog->name).' &rsaquo; <span class="page-title">'.__('Dashboard').'</span></h2>';
+# Dotclear updates notifications
+if ($core->auth->isSuperAdmin() && is_readable(DC_DIGESTS))
+{
+	$updater = new dcUpdate(DC_UPDATE_URL,'dotclear',DC_UPDATE_VERSION,DC_TPL_CACHE.'/versions');
+	$new_v = $updater->check(DC_VERSION);
+	$version_info = $new_v ? $updater->getInfoURL() : '';
+
+	if ($updater->getNotify() && $new_v) {
+		$message =
+		'<div><p>'.sprintf(__('Dotclear %s is available!'),$new_v).'</p> '.
+		'<ul><li><strong><a href="update.php">'.sprintf(__('Upgrade now'),$new_v).'</a></strong>'.
+		'</li><li><a href="update.php?hide_msg=1">'.__('Remind me later').'</a>'.
+		($version_info ? ' </li><li><a href="'.$version_info.'">'.__('information about this version').'</a>' : '').
+		'</li></ul></div>';
+		dcPage::message($message,false,true);
+	}
+}
 
 if ($core->auth->getInfo('user_default_blog') != $core->blog->id && $core->auth->blog_count > 1) {
@@ -204,7 +226,7 @@
 
 if ($core->blog->status == 0) {
-	echo '<p class="static-msg">'.__('This blog is offline').'</p>';
+	echo '<p class="static-msg">'.__('This blog is offline').'.</p>';
 } elseif ($core->blog->status == -1) {
-	echo '<p class="static-msg">'.__('This blog is removed').'</p>';
+	echo '<p class="static-msg">'.__('This blog is removed').'.</p>';
 }
 
@@ -305,5 +327,5 @@
 	if ($i->count() > 0)
 	{
-		$dashboardItems .= '<div>';
+		$dashboardItems .= '<div class="db-item">';
 		foreach ($i as $v) {
 			$dashboardItems .= $v;
@@ -339,28 +361,28 @@
 			}
 		} catch (Exception $e) { }
-		
+	
 		echo
 		'<div id="quick">'.
 		'<h3>'.__('Quick entry').'</h3>'.
-		'<form id="quick-entry" action="post.php" method="post">'.
-		'<fieldset><legend>'.__('New entry').'</legend>'.
-		'<p class="col"><label for="post_title" class="required"><abbr title="'.__('Required field').'">*</abbr> '.__('Title:').
+		'<form id="quick-entry" action="post.php" method="post" class="fieldset">'.
+		'<h4>'.__('New entry').'</h4>'.
+		'<p class="col"><label for="post_title" class="required"><abbr title="'.__('Required field').'">*</abbr> '.__('Title:').'</label>'.
 		form::field('post_title',20,255,'','maximal').
-		'</label></p>'.
+		'</p>'.
 		'<p class="area"><label class="required" '.
 		'for="post_content"><abbr title="'.__('Required field').'">*</abbr> '.__('Content:').'</label> '.
 		form::textarea('post_content',50,7).
 		'</p>'.
-		'<p><label for="cat_id" class="classic">'.__('Category:').' '.
-		form::combo('cat_id',$categories_combo).'</label></p>'.
+		'<p><label for="cat_id" class="classic">'.__('Category:').'</label> '.
+		form::combo('cat_id',$categories_combo).'</p>'.
 		($core->auth->check('categories', $core->blog->id)
 			? '<div>'.
-			'<p id="new_cat">'.__('Add a new category').'</p>'.
+			'<p id="new_cat" class="q-cat">'.__('Add a new category').'</p>'.
+			'<p class="q-cat"><label for="new_cat_title">'.__('Title:').'</label> '.
+			form::field('new_cat_title',30,255,'','').'</p>'.
+			'<p class="q-cat"><label for="new_cat_parent">'.__('Parent:').'</label> '.
+			form::combo('new_cat_parent',$categories_combo,'','').
+			'</p>'.
 			'<p class="form-note info clear">'.__('This category will be created when you will save your post.').'</p>'.
-			'<p><label for="new_cat_title">'.__('Title:').' '.
-			form::field('new_cat_title',30,255,'','maximal').'</label></p>'.
-			'<p><label for="new_cat_parent">'.__('Parent:').' '.
-			form::combo('new_cat_parent',$categories_combo,'','maximal').
-			'</label></p>'.
 			'</div>'
 			: '').
@@ -376,5 +398,4 @@
 		form::hidden('post_notes','').
 		'</p>'.
-		'</fieldset>'.
 		'</form>'.
 		'</div>';
Index: admin/install/index.php
===================================================================
--- admin/install/index.php	(revision 1583)
+++ admin/install/index.php	(revision 1620)
@@ -190,5 +190,5 @@
 		$core->auth->user_prefs->dashboard->put('doclinks',true,'boolean','',null,true);
 		$core->auth->user_prefs->dashboard->put('dcnews',true,'boolean','',null,true);
-		$core->auth->user_prefs->dashboard->put('quickentry',false,'boolean','',null,true);
+		$core->auth->user_prefs->dashboard->put('quickentry',true,'boolean','',null,true);
 
 		# Add accessibility options
@@ -307,4 +307,8 @@
 '<div id="main">';
 
+if (!is_writable(DC_TPL_CACHE)) {
+	echo '<div class="error"><p>'.sprintf(__('Cache directory %s is not writable.'),DC_TPL_CACHE).'</p></div>';
+}
+
 if ($can_install && !empty($err)) {
 	echo '<div class="error"><p><strong>'.__('Errors:').'</strong></p>'.$err.'</div>';
@@ -312,5 +316,5 @@
 
 if (!empty($_GET['wiz'])) {
-	echo '<p class="message">'.__('Configuration file has been successfully created.').'</p>';
+	echo '<p class="success">'.__('Configuration file has been successfully created.').'</p>';
 }
 
@@ -324,10 +328,10 @@
 	'<form action="index.php" method="post">'.
 	'<fieldset><legend>'.__('User information').'</legend>'.
-	'<p><label for="u_firstname">'.__('First Name:').' '.
-	form::field('u_firstname',30,255,html::escapeHTML($u_firstname)).'</label></p>'.
-	'<p><label for="u_name">'.__('Last Name:').' '.
-	form::field('u_name',30,255,html::escapeHTML($u_name)).'</label></p>'.
-	'<p><label for="u_email">'.__('Email:').' '.
-	form::field('u_email',30,255,html::escapeHTML($u_email)).'</label></p>'.
+	'<p><label for="u_firstname">'.__('First Name:').'</label> '.
+	form::field('u_firstname',30,255,html::escapeHTML($u_firstname)).'</p>'.
+	'<p><label for="u_name">'.__('Last Name:').'</label> '.
+	form::field('u_name',30,255,html::escapeHTML($u_name)).'</p>'.
+	'<p><label for="u_email">'.__('Email:').'</label> '.
+	form::field('u_email',30,255,html::escapeHTML($u_email)).'</p>'.
 	'</fieldset>'.
 	
@@ -378,5 +382,5 @@
 	$plugins_install_result.
 	
-	'<p>'.__('Dotclear has been successfully installed. Here is some useful information you should keep.').'</p>'.
+	'<p class="success">'.__('Dotclear has been successfully installed. Here is some useful information you should keep.').'</p>'.
 	
 	'<h3>'.__('Your account').'</h3>'.
Index: admin/install/wizard.php
===================================================================
--- admin/install/wizard.php	(revision 1179)
+++ admin/install/wizard.php	(revision 1399)
@@ -178,16 +178,16 @@
 
 '<form action="wizard.php" method="post">'.
-'<p><label class="required" for="DBDRIVER"><abbr title="'.__('Required field').'">*</abbr> '.__('Database type:').' '.
-form::combo('DBDRIVER',array('MySQL'=>'mysql','PostgreSQL'=>'pgsql'),$DBDRIVER).'</label></p>'.
-'<p><label for="DBHOST">'.__('Database Host Name:').' '.
-form::field('DBHOST',30,255,html::escapeHTML($DBHOST)).'</label></p>'.
-'<p><label for="DBNAME">'.__('Database Name:').' '.
-form::field('DBNAME',30,255,html::escapeHTML($DBNAME)).'</label></p>'.
-'<p><label for="DBUSER">'.__('Database User Name:').' '.
-form::field('DBUSER',30,255,html::escapeHTML($DBUSER)).'</label></p>'.
-'<p><label for="DBPASSWORD">'.__('Database Password:').' '.
-form::password('DBPASSWORD',30,255).'</label></p>'.
-'<p><label for="DBPREFIX" class="required"><abbr title="'.__('Required field').'">*</abbr> '.__('Database Tables Prefix:').' '.
-form::field('DBPREFIX',30,255,html::escapeHTML($DBPREFIX)).'</label></p>'.
+'<p><label class="required" for="DBDRIVER"><abbr title="'.__('Required field').'">*</abbr> '.__('Database type:').'</label> '.
+form::combo('DBDRIVER',array('MySQL'=>'mysql','PostgreSQL'=>'pgsql'),$DBDRIVER).'</p>'.
+'<p><label for="DBHOST">'.__('Database Host Name:').'</label> '.
+form::field('DBHOST',30,255,html::escapeHTML($DBHOST)).'</p>'.
+'<p><label for="DBNAME">'.__('Database Name:').'</label> '.
+form::field('DBNAME',30,255,html::escapeHTML($DBNAME)).'</p>'.
+'<p><label for="DBUSER">'.__('Database User Name:').'</label> '.
+form::field('DBUSER',30,255,html::escapeHTML($DBUSER)).'</p>'.
+'<p><label for="DBPASSWORD">'.__('Database Password:').'</label> '.
+form::password('DBPASSWORD',30,255).'</p>'.
+'<p><label for="DBPREFIX" class="required"><abbr title="'.__('Required field').'">*</abbr> '.__('Database Tables Prefix:').'</label> '.
+form::field('DBPREFIX',30,255,html::escapeHTML($DBPREFIX)).'</p>'.
 
 '<p><input type="submit" value="'.__('Continue').'" /></p>'.
Index: admin/js/_categories.js
===================================================================
--- admin/js/_categories.js	(revision 0)
+++ admin/js/_categories.js	(revision 1595)
@@ -1,13 +1,31 @@
-/* TODO: Some nice drag and drop on categories */
 $(function() {
-	$('form#delete-category').submit(function() {
-		var c_id = $('#del_cat').val();
-		var c_name = $('#del_cat option[value='+c_id+']').text();
-		return window.confirm(dotclear.msg.confirm_delete_category.replace('%s',c_name));
+	if ($.fn['nestedSortable']!==undefined) {
+		$('#categories ul li').css('cursor','move');
+		$('#save-set-order').prop('disabled',true).addClass('disabled');
+		$('#categories ul').nestedSortable({
+			listType: 'ul',
+			items: 'li',
+			placeholder: 'placeholder',
+			update: function() {
+				$('#categories_order').attr('value',JSON.stringify($('#categories ul').nestedSortable('toArray')));
+				$('#save-set-order').prop('disabled',false).removeClass('disabled');
+			}
+		});
+	}
+
+	$('.checkboxes-helpers').each(function() {
+		dotclear.checkboxesHelpers(this);
 	});
-});
 
-$(function() {
-	$('form#reset-order').submit(function() {
+	$('input[name="delete"]').click(function() {
+		var nb_ckecked = $('input[name="categories[]"]:checked').length;
+		if (nb_ckecked==0) {
+			return false;
+		}
+
+		return window.confirm(dotclear.msg.confirm_delete_categories.replace('%s',nb_ckecked));
+	});
+
+	$('input[name="reset"]').click(function() {
 		return window.confirm(dotclear.msg.confirm_reorder_categories);
 	});
Index: admin/js/_index.js
===================================================================
--- admin/js/_index.js	(revision 1500)
+++ admin/js/_index.js	(revision 1638)
@@ -66,12 +66,13 @@
 			});
 		}
-		$('#new_cat').toggleWithLegend(
-			$('#new_cat').parent().children().not('#new_cat'),
-			{} // no cookie on new category as we don't use this every day
-		);
+		$('#new_cat').toggleWithLegend($('#new_cat').parent().children().not('#new_cat'), {
+			// no cookie on new category as we don't use this every day
+			legend_click: true
+		});
 	}
 
 	// allow to hide quick entry div, and remember choice
 	$('#quick h3').toggleWithLegend($('#quick').children().not('h3'),{
+		legend_click: true,
 		cookie: 'dcx_quick_entry'
 	});
Index: admin/js/_media.js
===================================================================
--- admin/js/_media.js	(revision 1234)
+++ admin/js/_media.js	(revision 1461)
@@ -2,4 +2,25 @@
 	if ($('#fileupload').length==0) {
 		return;
+	}
+
+	function enableButton(button) {
+		button.prop('disabled',false).removeClass('disabled');
+	}
+
+	function disableButton(button) {
+		button.prop('disabled',true).addClass('disabled');
+	}
+
+	function displayMessageInQueue(n) {
+		var msg = '';
+		if (n==1) {
+			msg = dotclear.jsUpload.msg.file_in_queue;
+		} else if (n>1) {
+			msg = dotclear.jsUpload.msg.files_in_queue;
+			msg = msg.replace(/%d/,n);
+		} else {
+			msg = dotclear.jsUpload.msg.no_file_in_queue;
+		}
+		$('.queue-message','#fileupload').html(msg);
 	}
 
@@ -10,6 +31,16 @@
 	});
 
-	$('.button.cancel', '#fileupload').click(function(e) {
-		$('.button.cancel, .button.start','#fileupload .fileupload-buttonbar').hide();
+	$('.button.cancel', '#fileupload .fileupload-buttonbar').click(function(e) {
+		$('.button.cancel','#fileupload .fileupload-buttonbar').hide();
+		disableButton($('.button.start','#fileupload .fileupload-buttonbar'));
+		displayMessageInQueue(0);
+	});
+
+	$('.cancel').live('click', function(e) {
+		if ($('.fileupload-ctrl .files .template-upload', '#fileupload').length==0) {
+			$('.button.cancel','#fileupload .fileupload-buttonbar').hide();
+			disableButton($('.button.start','#fileupload .fileupload-buttonbar'));
+		}
+		displayMessageInQueue($('.files .template-upload','#fileupload').length);
 	});
 
@@ -26,7 +57,13 @@
 		autoUpload: false,
 		sequentialUploads: true,
-		disabled: true
+		uploadTemplateId: null,
+		downloadTemplateId: null,
+		uploadTemplate: template_upload,
+		downloadTemplate: template_download
 	}).bind('fileuploadadd', function(e, data) {
-		$('.button.cancel, .button.start', '#fileupload .fileupload-buttonbar').show();
+		$('.button.cancel','#fileupload .fileupload-buttonbar').show();
+		enableButton($('.button.start','#fileupload .fileupload-buttonbar'));
+	}).bind('fileuploadadded', function(e, data) {
+		displayMessageInQueue($('.files .template-upload','#fileupload').length);
 	}).bind('fileuploaddone', function(e, data) {
 		if (data.result.files[0].html !==undefined) {
@@ -35,10 +72,12 @@
 		$('.button.clean','#fileupload').show();
 	}).bind('fileuploadalways', function(e, data) {
-	    if ($('.fileupload-ctrl .files .template-upload', '#fileupload').length==0) {
-		$('.button.start, .button.cancel','#fileupload .fileupload-buttonbar').hide();
-	    }
+		displayMessageInQueue($('.files .template-upload','#fileupload').length);
+		if ($('.fileupload-ctrl .files .template-upload','#fileupload').length==0) {
+			$('.button.cancel','#fileupload .fileupload-buttonbar').hide();
+			disableButton($('.button.start','#fileupload .fileupload-buttonbar'));
+		}
 	});
 
-	var $container = $('#add-file-f').parent().parent();
+	var $container = $('#fileupload').parent().parent();
 	var $msg,label;
 
@@ -47,4 +86,6 @@
 		label = dotclear.jsUpload.msg.choose_files;
 		$('#fileupload').fileupload({disabled:false});
+		displayMessageInQueue(0);
+		disableButton($('.button.start','#fileupload .fileupload-buttonbar'));
 	} else {
 		$msg = dotclear.msg.enhanced_uploader_activate;
@@ -61,13 +102,17 @@
 			// We must remove files in table
 			$('.files .upload-file', '#fileupload').remove();
-			$('.button.cancel, .button.start','#fileupload .fileupload-buttonbar').hide();
-			$('.button.start','#fileupload').show();
+			$('.button.cancel,.button.clean','#fileupload .fileupload-buttonbar').hide();
 			$('#fileupload').fileupload({disabled:true});
+			$('.queue-message','#fileupload').html('').hide();
 		} else {
 			$msg = dotclear.msg.enhanced_uploader_disable;
 			label = dotclear.jsUpload.msg.choose_files;
 			$('#upfile').attr('multiple', true);
-			$('.button.start','#fileupload').hide();
+			var startButton = $('.button.start','#fileupload .fileupload-buttonbar');
+			disableButton(startButton);
+			startButton.show();
 			$('#fileupload').fileupload({disabled:false});
+			$('.queue-message','#fileupload').show();
+			displayMessageInQueue(0);
 		}
 		$(this).find('a').text($msg);
@@ -75,5 +120,5 @@
 
 		$container.toggleClass('enhanced_uploader');
-	}).appendTo($('#add-file-f'));
+	}).appendTo($('#fileupload'));
 
 	// Replace remove links by a POST on hidden form
Index: admin/js/_post.js
===================================================================
--- admin/js/_post.js	(revision 1515)
+++ admin/js/_post.js	(revision 1638)
@@ -1,5 +1,5 @@
 dotclear.commentExpander = function(line) {
 	var td = line.firstChild;
-	
+
 	var img = document.createElement('img');
 	img.src = dotclear.img_plus_src;
@@ -9,5 +9,5 @@
 	img.line = line;
 	img.onclick = function() { dotclear.viewCommentContent(this,this.line); };
-	
+
 	td.insertBefore(img,td.firstChild);
 };
@@ -15,7 +15,7 @@
 dotclear.viewCommentContent = function(img,line) {
 	var commentId = line.id.substr(1);
-	
+
 	var tr = document.getElementById('ce'+commentId);
-	
+
 	if (!tr) {
 		tr = document.createElement('tr');
@@ -25,15 +25,15 @@
 		td.className = 'expand';
 		tr.appendChild(td);
-		
+
 		img.src = dotclear.img_minus_src;
 		img.alt = dotclear.img_minus_alt;
-		
+
 		// Get comment content
 		$.get('services.php',{f:'getCommentById',id: commentId},function(data) {
 			var rsp = $(data).children('rsp')[0];
-			
+
 			if (rsp.attributes[0].value == 'ok') {
 				var comment = $(rsp).find('comment_display_content').text();
-				
+
 				if (comment) {
 					$(td).append(comment);
@@ -42,5 +42,5 @@
 					var comment_ip = $(rsp).find('comment_ip').text();
 					var comment_spam_disp = $(rsp).find('comment_spam_disp').text();
-					
+
 					$(td).append('<p><strong>' + dotclear.msg.website +
 					'</strong> ' + comment_site + '<br />' +
@@ -52,5 +52,5 @@
 			}
 		});
-		
+
 		$(line).toggleClass('expand');
 		line.parentNode.insertBefore(tr,line.nextSibling);
@@ -74,5 +74,5 @@
 $(function() {
 	if (!document.getElementById) { return; }
-	
+
 	if (document.getElementById('edit-entry'))
 	{
@@ -91,58 +91,81 @@
 			}
 		});
-		
+
 		var excerptTb = new jsToolBar(document.getElementById('post_excerpt'));
 		var contentTb = new jsToolBar(document.getElementById('post_content'));
 		excerptTb.context = contentTb.context = 'post';
 	}
-	
+
 	if (document.getElementById('comment_content')) {
 		var commentTb = new jsToolBar(document.getElementById('comment_content'));
 	}
-	
+
 	// Post preview
 	$('#post-preview').modalWeb($(window).width()-40,$(window).height()-40);
-	
+
 	// Tabs events
 	$('#edit-entry').onetabload(function() {
 		dotclear.hideLockable();
-		
+
 		// Add date picker
 		var post_dtPick = new datePicker($('#post_dt').get(0));
 		post_dtPick.img_top = '1.5em';
 		post_dtPick.draw();
-		
+
 		// Confirm post deletion
 		$('input[name="delete"]').click(function() {
-				return window.confirm(dotclear.msg.confirm_delete_post);
-		});
-		
+			return window.confirm(dotclear.msg.confirm_delete_post);
+		});
+
 		// Hide some fields
 		$('#notes-area label').toggleWithLegend($('#notes-area').children().not('label'),{
 			cookie: 'dcx_post_notes',
+			legend_click:true,
 			hide: $('#post_notes').val() == ''
 		});
-		$('#new_cat').toggleWithLegend(
-			$('#new_cat').parent().children().not('#new_cat'),
-			{} // no cookie on new category as we don't use this every day
-		);
-		$('#post_lang').parent().toggleWithLegend($('#post_lang'),{
-			cookie: 'dcx_post_lang'
-		});
-		$('#post_password').parent().toggleWithLegend($('#post_password'),{
+		$('#create_cat').toggleWithLegend($('#create_cat').parent().children().not('#create_cat'),{
+			// no cookie on new category as we don't use this every day
+			legend_click: true
+		});
+		$('#post_lang').parent().children('label').toggleWithLegend($('#post_lang'),{
+			cookie: 'dcx_post_lang',
+			legend_click: true
+		});
+		$('#post_password').parent().children('label').toggleWithLegend($('#post_password'),{
 			cookie: 'dcx_post_password',
+			legend_click: true,
 			hide: $('#post_password').val() == ''
 		});
-		
+		$('#post_status').parent().children('label').toggleWithLegend($('#post_status'),{
+			cookie: 'dcx_post_status',
+			legend_click: true
+		});
+		$('#post_dt').parent().children('label').toggleWithLegend($('#post_dt').parent().children().not('label'),{
+			cookie: 'dcx_post_dt',
+			legend_click: true
+		});
+		$('#label_format').toggleWithLegend($('#label_format').parent().children().not('#label_format'),{
+			cookie: 'dcx_post_format',
+			legend_click: true
+		});
+		$('#cat_id').parent().children('label').toggleWithLegend($('#cat_id'),{
+			cookie: 'cat_id',
+			legend_click: true
+		});
+		$('#post_url').parent().children('label').toggleWithLegend($('#post_url').parent().children().not('label'),{
+			cookie: 'post_url',
+			legend_click: true
+		});
 		// We load toolbar on excerpt only when it's ready
 		$('#excerpt-area label').toggleWithLegend($('#excerpt-area').children().not('label'),{
 			cookie: 'dcx_post_excerpt',
+			legend_click: true,
 			hide: $('#post_excerpt').val() == ''
 		});
-		
+
 		// Load toolbars
 		contentTb.switchMode(formatField.value);
 		excerptTb.switchMode(formatField.value);
-		
+
 		// Replace attachment remove links by a POST form submit
 		$('a.attachment-remove').click(function() {
@@ -156,9 +179,10 @@
 			return false;
 		});
-		
+
 		// Markup validator
 		var h = document.createElement('h4');
 		var a = document.createElement('a');
 		a.href = '#';
+		a.className = 'button';
 		$(a).click(function() {
 			var params = {
@@ -170,5 +194,5 @@
 				lang: $('#post_lang').get(0).value
 			};
-			
+
 			$.post('services.php',params,function(data) {
 				if ($(data).find('rsp').attr('status') != 'ok') {
@@ -176,13 +200,13 @@
 					return false;
 				}
-				
+
 				if ($(data).find('valid').text() == 1) {
 					var p = document.createElement('p');
 					p.id = 'markup-validator';
-					
+
 					if ($('#markup-validator').length > 0) {
 						$('#markup-validator').remove();
 					}
-					
+
 					$(p).addClass('message');
 					$(p).text(dotclear.msg.xhtml_valid);
@@ -194,27 +218,27 @@
 					var div = document.createElement('div');
 					div.id = 'markup-validator';
-					
+
 					if ($('#markup-validator').length > 0) {
 						$('#markup-validator').remove();
 					}
-					
+
 					$(div).addClass('error');
 					$(div).html('<p><strong>' + dotclear.msg.xhtml_not_valid + '</strong></p>' + $(data).find('errors').text());
 					$(div).insertAfter(h);
-					$(div).backgroundFade({sColor:'#ffffff',eColor:'#ff9999',steps:50},function() {
-							$(this).backgroundFade({sColor:'#ff9999',eColor:'#ffffff'});
+					$(div).backgroundFade({sColor:'#ffffff',eColor:'#FFBABA',steps:50},function() {
+							$(this).backgroundFade({sColor:'#ffbaba',eColor:'#ffffff'});
 					});
 				}
-				
+
 				return false;
 			});
-			
+
 			return false;
 		});
-		
+
 		a.appendChild(document.createTextNode(dotclear.msg.xhtml_validator));
 		h.appendChild(a);
 		$(h).appendTo('#entry-content');
-		
+
 		// Check unsaved changes before XHTML conversion
 		var excerpt = $('#post_excerpt').val();
@@ -223,8 +247,8 @@
 			if (excerpt != $('#post_excerpt').val() || content != $('#post_content').val()) {
 				return window.confirm(dotclear.msg.confirm_change_post_format);
-			}	
+			}
 		});
 	});
-	
+
 	$('#comments').onetabload(function() {
 		$('.comments-list tr.line').each(function() {
@@ -234,8 +258,8 @@
 			dotclear.checkboxesHelpers(this);
 		});
-		
+
 		dotclear.commentsActionsHelper();
 	});
-	
+
 	$('#add-comment').onetabload(function() {
 		commentTb.draw('xhtml');
Index: admin/js/_posts_actions.js
===================================================================
--- admin/js/_posts_actions.js	(revision 1419)
+++ admin/js/_posts_actions.js	(revision 1638)
@@ -1,4 +1,4 @@
 $(function() {
-	$('#new_auth_id').autocomplete(usersList, 
+	$('#new_auth_id').autocomplete(usersList,
 	{
 		delay: 1000,
@@ -6,7 +6,7 @@
 		matchContains: true
 	});
-	$('#new_cat').toggleWithLegend(
-		$('#new_cat').parent().children().not('#new_cat'),
-		{} // no cookie on new category as we don't use this every day
-	);
+	$('#new_cat').toggleWithLegend($('#new_cat').parent().children().not('#new_cat'), {
+		// no cookie on new category as we don't use this every day
+		legend_click: true
+	});
 });
Index: admin/js/_posts_list.js
===================================================================
--- admin/js/_posts_list.js	(revision 1034)
+++ admin/js/_posts_list.js	(revision 1640)
@@ -28,23 +28,30 @@
 
 dotclear.viewPostsContent = function(img,lines) {
-	lines.each(function() {
-		var td = this.firstChild;
-		td.firstChild.click();
-	});
+	
+	action = 'toggle';
 
 	if (img.alt == dotclear.img_plus_alt) {
 		img.src = dotclear.img_minus_src;
 		img.alt = dotclear.img_minus_alt;
+		action = 'open';
 	} else {
 		img.src = dotclear.img_plus_src;
 		img.alt = dotclear.img_plus_alt;
+		action = 'close';
 	}
+	
+	lines.each(function() {
+		var td = this.firstChild;
+		dotclear.viewPostContent(td.firstChild,td.firstChild.line,action);
+	});
 };
 
-dotclear.viewPostContent = function(img,line) {
+dotclear.viewPostContent = function(img,line,action) {
+	
+	var action = action || 'toggle';
 	var postId = line.id.substr(1);
 	var tr = document.getElementById('pe'+postId);
 	
-	if (!tr) {
+	if ( !tr && ( action == 'toggle' || action == 'open' ) ) {
 		tr = document.createElement('tr');
 		tr.id = 'pe'+postId;
@@ -78,21 +85,35 @@
 		});
 		
-		$(line).toggleClass('expand');
+		$(line).addClass('expand');
 		line.parentNode.insertBefore(tr,line.nextSibling);
 	}
-	else if (tr.style.display == 'none')
+	else if (tr && tr.style.display == 'none' && ( action == 'toggle' || action == 'open' ) )
 	{
-		$(tr).toggle();
-		$(line).toggleClass('expand');
+		$(tr).css('display', 'table-row');
+		$(line).addClass('expand');
 		img.src = dotclear.img_minus_src;
 		img.alt = dotclear.img_minus_alt;
 	}
-	else
+	else if (tr && tr.style.display != 'none' && ( action == 'toggle' || action == 'close' ) )
 	{
-		$(tr).toggle();
-		$(line).toggleClass('expand');
+		$(tr).css('display', 'none');
+		$(line).removeClass('expand');
 		img.src = dotclear.img_plus_src;
 		img.alt = dotclear.img_plus_alt;
 	}
+	
+	parentTable = $(line).parents('table');
+	if( parentTable.find('tr.expand').length == parentTable.find('tr.line').length ) {
+		img = parentTable.find('tr:not(.line) th:first img');
+		img.attr('src',dotclear.img_minus_src);
+		img.attr('alt',dotclear.img_minus_alt);
+	}
+	
+	if( parentTable.find('tr.expand').length == 0 ) {
+		img = parentTable.find('tr:not(.line) th:first img');
+		img.attr('src',dotclear.img_plus_src);
+		img.attr('alt',dotclear.img_plus_alt);
+	}
+	
 };
 
Index: admin/js/_preferences.js
===================================================================
--- admin/js/_preferences.js	(revision 160)
+++ admin/js/_preferences.js	(revision 1516)
@@ -13,6 +13,6 @@
 		if ($('#user_email').val() != user_email || $('#new_pwd').val() != '') {
 			e.focus();
-			$(e).backgroundFade({sColor:'#ffffff',eColor:'#ff9999',steps:50},function() {
-				$(this).backgroundFade({sColor:'#ff9999',eColor:'#ffffff'});
+			$(e).backgroundFade({sColor:'#ffffff',eColor:'#ffbaba',steps:50},function() {
+				$(this).backgroundFade({sColor:'#ffbaba',eColor:'#ffffff'});
 			});
 			return false;
Index: admin/js/common.js
===================================================================
--- admin/js/common.js	(revision 1140)
+++ admin/js/common.js	(revision 1635)
@@ -121,4 +121,7 @@
 
 		$(ctarget).css('cursor','pointer');
+		if (p.legend_click) {
+			$(ctarget).find('label').css('cursor','pointer');
+		}
 		$(ctarget).click(function() {
 			toggle(i,p.speed);
@@ -153,4 +156,5 @@
 			}
 		}
+		$('p#help-button span').text($('#content').hasClass('with-help') ? dotclear.msg.help_hide : dotclear.msg.help);
 		sizeBox();
 		return false;
@@ -172,5 +176,5 @@
 		o.click(function() {
 			$(this).nextAll().each(function() {
-				if ($(this).is('h3')) {
+				if ($(this).is('h4')) {
 					return false;
 				}
@@ -192,9 +196,9 @@
 	this.find('>hr').remove();
 
-	this.find('h3').each(function() { textToggler($(this)); });
-	this.find('h3:first').nextAll('*:not(h3)').hide();
+	this.find('h4').each(function() { textToggler($(this)); });
+	this.find('h4:first').nextAll('*:not(h4)').hide();
 	sizeBox();
 
-	var img = $('<span id="help-button">'+dotclear.msg.help+'</span>');
+	var img = $('<p id="help-button"><span>'+dotclear.msg.help+'</span></p>');
 	var select = $();
 	img.click(function() { return toggle(); });
@@ -223,4 +227,5 @@
 				imgE.style.top = '1.7em';
 				imgE.style.left = ($(this).width()+4)+'px';
+				imgE.alt=dotclear.msg.click_to_unlock;
 				$(imgE).css('cursor','pointer');
 
@@ -241,4 +246,7 @@
 
 	checkboxesHelpers: function(e) {
+		$(e).append(document.createTextNode(dotclear.msg.to_select));
+		$(e).append(document.createTextNode(' '));
+
 		var a = document.createElement('a');
 		a.href='#';
@@ -250,5 +258,5 @@
 		$(e).append(a);
 
-		$(e).append(document.createTextNode(' - '));
+		$(e).append(document.createTextNode(' | '));
 
 		a = document.createElement('a');
@@ -319,4 +327,13 @@
 -------------------------------------------------------- */
 $(function() {
+	// remove class no-js from html tag; cf style/default.css for examples
+	$('body').removeClass('no-js');
+
+	$('#wrapper').contents().each(function() {
+		if (this.nodeType==8) {
+			$('#footer a').attr('title', $('#footer a').attr('title') + this.data );
+		}
+	});
+
 	// Blog switcher
 	$('#switchblog').change(function() {
@@ -346,5 +363,6 @@
 
 	$('.message').backgroundFade({sColor:'#cccccc',eColor:'#666666',steps:20});
-	$('.error').backgroundFade({sColor:'#ffeee3',eColor:'#ffdec8',steps:20});
+	$('.error').backgroundFade({sColor:'#ffdec8',eColor:'#ffbaba',steps:20});
+	$('.success').backgroundFade({sColor:'#9BCA1C',eColor:'#bee74b',steps:20});
 
 	$('form:has(input[type=password][name=your_pwd])').submit(function() {
@@ -352,6 +370,6 @@
 		if (e.value == '') {
 			e.focus();
-			$(e).backgroundFade({sColor:'#ffffff',eColor:'#ff9999',steps:50},function() {
-				$(this).backgroundFade({sColor:'#ff9999',eColor:'#ffffff'});
+			$(e).backgroundFade({sColor:'#ffffff',eColor:'#ffbaba',steps:50},function() {
+				$(this).backgroundFade({sColor:'#ffbaba',eColor:'#ffffff'});
 			});
 			return false;
Index: admin/js/ie7/IE9.js
===================================================================
--- admin/js/ie7/IE9.js	(revision 1456)
+++ admin/js/ie7/IE9.js	(revision 1456)
@@ -0,0 +1,2901 @@
+/*
+  IE7/IE8/IE9.js - copyright 2004-2010, Dean Edwards
+  http://code.google.com/p/ie7-js/
+  http://www.opensource.org/licenses/mit-license.php
+*/
+
+/* W3C compliance for Microsoft Internet Explorer */
+
+/* credits/thanks:
+  Shaggy, Martijn Wargers, Jimmy Cerra, Mark D Anderson,
+  Lars Dieckow, Erik Arvidsson, Gellért Gyuris, James Denny,
+  Unknown W Brackets, Benjamin Westfarer, Rob Eberhardt,
+  Bill Edney, Kevin Newman, James Crompton, Matthew Mastracci,
+  Doug Wright, Richard York, Kenneth Kolano, MegaZone,
+  Thomas Verelst, Mark 'Tarquin' Wilton-Jones, Rainer Åhlfors,
+  David Zulaica, Ken Kolano, Kevin Newman, Sjoerd Visscher,
+  Ingo Chao
+*/
+
+// timestamp: Fri, 30 Apr 2010 20:59:18
+
+(function(window, document) {
+
+var IE7 = window.IE7 = {
+  version: "2.1(beta4)",
+  toString: K("[IE7]")
+};
+IE7.compat = 9;
+var appVersion = IE7.appVersion = navigator.appVersion.match(/MSIE (\d\.\d)/)[1] - 0;
+
+if (/ie7_off/.test(top.location.search) || appVersion < 5.5 || appVersion >= IE7.compat) return;
+
+var MSIE5 = appVersion < 6;
+
+var Undefined = K();
+var documentElement = document.documentElement, body, viewport;
+var ANON = "!";
+var HEADER = ":link{ie7-link:link}:visited{ie7-link:visited}";
+
+// -----------------------------------------------------------------------
+// external
+// -----------------------------------------------------------------------
+
+var RELATIVE = /^[\w\.]+[^:]*$/;
+function makePath(href, path) {
+  if (RELATIVE.test(href)) href = (path || "") + href;
+  return href;
+};
+
+function getPath(href, path) {
+  href = makePath(href, path);
+  return href.slice(0, href.lastIndexOf("/") + 1);
+};
+
+// Get the path to this script
+var script = document.scripts[document.scripts.length - 1];
+var path = getPath(script.src);
+
+// Use microsoft's http request object to load external files
+try {
+  var httpRequest = new ActiveXObject("Microsoft.XMLHTTP");
+} catch (ex) {
+  // ActiveX disabled
+}
+
+var fileCache = {};
+function loadFile(href, path) {
+  try {
+    href = makePath(href, path);
+    if (!fileCache[href]) {
+      httpRequest.open("GET", href, false);
+      httpRequest.send();
+      if (httpRequest.status == 0 || httpRequest.status == 200) {
+        fileCache[href] = httpRequest.responseText;
+      }
+    }
+  } catch (ex) {
+    // ignore errors
+  }
+  return fileCache[href] || "";
+};
+
+// -----------------------------------------------------------------------
+// OO support
+// -----------------------------------------------------------------------
+
+
+// This is a cut-down version of base2 (http://code.google.com/p/base2/)
+
+var _slice = Array.prototype.slice;
+
+// private
+var _FORMAT = /%([1-9])/g;
+var _LTRIM = /^\s\s*/;
+var _RTRIM = /\s\s*$/;
+var _RESCAPE = /([\/()[\]{}|*+-.,^$?\\])/g;           // safe regular expressions
+var _BASE = /\bbase\b/;
+var _HIDDEN = ["constructor", "toString"];            // only override these when prototyping
+
+var prototyping;
+
+function Base(){};
+Base.extend = function(_instance, _static) {
+  // Build the prototype.
+  prototyping = true;
+  var _prototype = new this;
+  extend(_prototype, _instance);
+  prototyping = false;
+
+  // Create the wrapper for the constructor function.
+  var _constructor = _prototype.constructor;
+  function klass() {
+    // Don't call the constructor function when prototyping.
+    if (!prototyping) _constructor.apply(this, arguments);
+  };
+  _prototype.constructor = klass;
+
+  // Build the static interface.
+  klass.extend = arguments.callee;
+  extend(klass, _static);
+  klass.prototype = _prototype;
+  return klass;
+};
+Base.prototype.extend = function(source) {
+  return extend(this, source);
+};
+
+
+// A collection of regular expressions and their associated replacement values.
+// A Base class for creating parsers.
+
+var HASH     = "#";
+var ITEMS    = "#";
+var KEYS     = ".";
+var COMPILED = "/";
+
+var REGGRP_BACK_REF        = /\\(\d+)/g,
+    REGGRP_ESCAPE_COUNT    = /\[(\\.|[^\]\\])+\]|\\.|\(\?/g,
+    REGGRP_PAREN           = /\(/g,
+    REGGRP_LOOKUP          = /\$(\d+)/,
+    REGGRP_LOOKUP_SIMPLE   = /^\$\d+$/,
+    REGGRP_LOOKUPS         = /(\[(\\.|[^\]\\])+\]|\\.|\(\?)|\(/g,
+    REGGRP_DICT_ENTRY      = /^<#\w+>$/,
+    REGGRP_DICT_ENTRIES    = /<#(\w+)>/g;
+
+var RegGrp = Base.extend({
+  constructor: function(values) {
+    this[KEYS] = [];
+    this[ITEMS] = {};
+    this.merge(values);
+  },
+
+  //dictionary: null,
+  //ignoreCase: false,
+
+  add: function(expression, replacement) {
+    delete this[COMPILED];
+    if (expression instanceof RegExp) {
+      expression = expression.source;
+    }
+    if (!this[HASH + expression]) this[KEYS].push(String(expression));
+    return this[ITEMS][HASH + expression] = new RegGrp.Item(expression, replacement, this);
+  },
+
+  compile: function(recompile) {
+    if (recompile || !this[COMPILED]) {
+      this[COMPILED] = new RegExp(this, this.ignoreCase ? "gi" : "g");
+    }
+    return this[COMPILED];
+  },
+
+  merge: function(values) {
+    for (var i in values) this.add(i, values[i]);
+  },
+
+  exec: function(string) {
+    var group = this,
+        patterns = group[KEYS],
+        items = group[ITEMS], item;
+    var result = this.compile(true).exec(string);
+    if (result) {
+      // Loop through the RegGrp items.
+      var i = 0, offset = 1;
+      while ((item = items[HASH + patterns[i++]])) {
+        var next = offset + item.length + 1;
+        if (result[offset]) { // do we have a result?
+          if (item.replacement === 0) {
+            return group.exec(string);
+          } else {
+            var args = result.slice(offset, next), j = args.length;
+            while (--j) args[j] = args[j] || ""; // some platforms return null/undefined for non-matching sub-expressions
+            args[0] = {match: args[0], item: item};
+            return args;
+          }
+        }
+        offset = next;
+      }
+    }
+    return null;
+  },
+
+  parse: function(string) {
+    string += ""; // type safe
+    var group = this,
+        patterns = group[KEYS],
+        items = group[ITEMS];
+    return string.replace(this.compile(), function(match) {
+      var args = [], item, offset = 1, i = arguments.length;
+      while (--i) args[i] = arguments[i] || ""; // some platforms return null/undefined for non-matching sub-expressions
+      // Loop through the RegGrp items.
+      while ((item = items[HASH + patterns[i++]])) {
+        var next = offset + item.length + 1;
+        if (args[offset]) { // do we have a result?
+          var replacement = item.replacement;
+          switch (typeof replacement) {
+            case "function":
+              return replacement.apply(group, args.slice(offset, next));
+            case "number":
+              return args[offset + replacement];
+            default:
+              return replacement;
+          }
+        }
+        offset = next;
+      }
+      return match;
+    });
+  },
+
+  toString: function() {
+    var strings = [],
+        keys = this[KEYS],
+        items = this[ITEMS], item;
+    for (var i = 0; item = items[HASH + keys[i]]; i++) {
+      strings[i] = item.source;
+    }
+    return "(" + strings.join(")|(") + ")";
+  }
+}, {
+  IGNORE: null, // a null replacement value means that there is no replacement.
+
+  Item: Base.extend({
+    constructor: function(source, replacement, owner) {
+      var length = source.indexOf("(") === -1 ? 0 : RegGrp.count(source);
+
+      var dictionary = owner.dictionary;
+      if (dictionary && source.indexOf("<#") !== -1) {
+        if (REGGRP_DICT_ENTRY.test(source)) {
+          var entry = dictionary[ITEMS][HASH + source.slice(2, -1)];
+          source = entry.replacement;
+          length = entry._length;
+        } else {
+          source = dictionary.parse(source);
+        }
+      }
+
+      if (typeof replacement == "number") replacement = String(replacement);
+      else if (replacement == null) replacement = 0;
+
+      // Does the expression use sub-expression lookups?
+      if (typeof replacement == "string" && REGGRP_LOOKUP.test(replacement)) {
+        if (REGGRP_LOOKUP_SIMPLE.test(replacement)) { // A simple lookup? (e.g. "$2").
+          // Store the index (used for fast retrieval of matched strings).
+          var index = replacement.slice(1) - 0;
+          if (index && index <= length) replacement = index;
+        } else {
+          // A complicated lookup (e.g. "Hello $2 $1.").
+          var lookup = replacement, regexp;
+          replacement = function(match) {
+            if (!regexp) {
+              regexp = new RegExp(source, "g" + (this.ignoreCase ? "i": ""));
+            }
+            return match.replace(regexp, lookup);
+          };
+        }
+      }
+
+      this.length = length;
+      this.source = String(source);
+      this.replacement = replacement;
+    }
+  }),
+
+  count: function(expression) {
+    return (String(expression).replace(REGGRP_ESCAPE_COUNT, "").match(REGGRP_PAREN) || "").length;
+  }
+});
+
+var Dictionary = RegGrp.extend({
+  parse: function(phrase) {
+    // Prevent sub-expressions in dictionary entries from capturing.
+    var entries = this[ITEMS];
+    return phrase.replace(REGGRP_DICT_ENTRIES, function(match, entry) {
+      entry = entries[HASH + entry];
+      return entry ? entry._nonCapturing : match;
+    });
+  },
+
+  add: function(expression, replacement) {
+    // Get the underlying replacement value.
+    if (replacement instanceof RegExp) {
+      replacement = replacement.source;
+    }
+    // Translate the replacement.
+    // The result is the original replacement recursively parsed by this dictionary.
+    var nonCapturing = replacement.replace(REGGRP_LOOKUPS, _nonCapture);
+    if (replacement.indexOf("(") !== -1) {
+      var realLength = RegGrp.count(replacement);
+    }
+    if (replacement.indexOf("<#") !== -1) {
+      replacement = this.parse(replacement);
+      nonCapturing = this.parse(nonCapturing);
+    }
+    var item = this.base(expression, replacement);
+    item._nonCapturing = nonCapturing;
+    item._length = realLength || item.length; // underlying number of sub-groups
+    return item;
+  },
+
+  toString: function() {
+    return "(<#" + this[PATTERNS].join(">)|(<#") + ">)";
+  }
+});
+
+function _nonCapture(match, escaped) {
+  return escaped || "(?:"; // non-capturing
+};
+
+// =========================================================================
+// lang/extend.js
+// =========================================================================
+
+function extend(object, source) { // or extend(object, key, value)
+  if (object && source) {
+    var proto = (typeof source == "function" ? Function : Object).prototype;
+    // Add constructor, toString etc
+    var i = _HIDDEN.length, key;
+    if (prototyping) while (key = _HIDDEN[--i]) {
+      var value = source[key];
+      if (value != proto[key]) {
+        if (_BASE.test(value)) {
+          _override(object, key, value)
+        } else {
+          object[key] = value;
+        }
+      }
+    }
+    // Copy each of the source object's properties to the target object.
+    for (key in source) if (typeof proto[key] == "undefined") {
+      var value = source[key];
+      // Check for method overriding.
+      if (object[key] && typeof value == "function" && _BASE.test(value)) {
+        _override(object, key, value);
+      } else {
+        object[key] = value;
+      }
+    }
+  }
+  return object;
+};
+
+function _override(object, name, method) {
+  // Override an existing method.
+  var ancestor = object[name];
+  object[name] = function() {
+    var previous = this.base;
+    this.base = ancestor;
+    var returnValue = method.apply(this, arguments);
+    this.base = previous;
+    return returnValue;
+  };
+};
+
+function combine(keys, values) {
+  // Combine two arrays to make a hash.
+  if (!values) values = keys;
+  var hash = {};
+  for (var i in keys) hash[i] = values[i];
+  return hash;
+};
+
+function format(string) {
+  // Replace %n with arguments[n].
+  // e.g. format("%1 %2%3 %2a %1%3", "she", "se", "lls");
+  // ==> "she sells sea shells"
+  // Only %1 - %9 supported.
+  var args = arguments;
+  var _FORMAT = new RegExp("%([1-" + arguments.length + "])", "g");
+  return String(string).replace(_FORMAT, function(match, index) {
+    return index < args.length ? args[index] : match;
+  });
+};
+
+function match(string, expression) {
+  // Same as String.match() except that this function will return an empty
+  // array if there is no match.
+  return String(string).match(expression) || [];
+};
+
+function rescape(string) {
+  // Make a string safe for creating a RegExp.
+  return String(string).replace(_RESCAPE, "\\$1");
+};
+
+// http://blog.stevenlevithan.com/archives/faster-trim-javascript
+function trim(string) {
+  return String(string).replace(_LTRIM, "").replace(_RTRIM, "");
+};
+
+function K(k) {
+  return function() {
+    return k;
+  };
+};
+
+// -----------------------------------------------------------------------
+// parsing
+// -----------------------------------------------------------------------
+
+var Parser = RegGrp.extend({ignoreCase: true});
+
+var SINGLE_QUOTES       = /'/g,
+    ESCAPED             = /'(\d+)'/g,
+    ESCAPE              = /\\/g,
+    UNESCAPE            = /\\([nrtf'"])/g;
+
+var strings = [];
+
+var encoder = new Parser({
+  // comments
+  "<!\\-\\-|\\-\\->": "",
+  "\\/\\*[^*]*\\*+([^\\/][^*]*\\*+)*\\/": "",
+  // get rid
+  "@(namespace|import)[^;\\n]+[;\\n]": "",
+  // strings
+  "'(\\\\.|[^'\\\\])*'": encodeString,
+  '"(\\\\.|[^"\\\\])*"': encodeString,
+  // white space
+  "\\s+": " "
+});
+
+function encode(selector) {
+  return encoder.parse(selector).replace(UNESCAPE, "$1");
+};
+
+function decode(query) {
+  // put string values back
+  return query.replace(ESCAPED, decodeString);
+};
+
+function encodeString(string) {
+  var index = strings.length;
+  strings[index] = string.slice(1, -1)
+    .replace(UNESCAPE, "$1")
+    .replace(SINGLE_QUOTES, "\\'");
+  return "'" + index + "'";
+};
+
+function decodeString(match, index) {
+  var string = strings[index];
+  if (string == null) return match;
+  return "'" + strings[index] + "'";
+};
+
+function getString(value) {
+  return value.indexOf("'") === 0 ? strings[value.slice(1, - 1)] : value;
+};
+
+// clone a "width" function to create a "height" function
+var rotater = new RegGrp({
+  Width: "Height",
+  width: "height",
+  Left:  "Top",
+  left:  "top",
+  Right: "Bottom",
+  right: "bottom",
+  onX:   "onY"
+});
+
+function rotate(fn) {
+  return rotater.parse(fn);
+};
+
+// -----------------------------------------------------------------------
+// event handling
+// -----------------------------------------------------------------------
+
+var eventHandlers = [];
+
+function addResize(handler) {
+  addRecalc(handler);
+  addEventHandler(window, "onresize", handler);
+};
+
+// add an event handler (function) to an element
+function addEventHandler(element, type, handler) {
+  element.attachEvent(type, handler);
+  // store the handler so it can be detached later
+  eventHandlers.push(arguments);
+};
+
+// remove an event handler assigned to an element by IE7
+function removeEventHandler(element, type, handler) {
+  try {
+    element.detachEvent(type, handler);
+  } catch (ex) {
+    // write a letter of complaint to microsoft..
+  }
+};
+
+// remove event handlers (they eat memory)
+addEventHandler(window, "onunload", function() {
+  var handler;
+  while (handler = eventHandlers.pop()) {
+    removeEventHandler(handler[0], handler[1], handler[2]);
+  }
+});
+
+function register(handler, element, condition) { // -@DRE
+  //var set = handler[element.uniqueID];
+  if (!handler.elements) handler.elements = {};
+  if (condition) handler.elements[element.uniqueID] = element;
+  else delete handler.elements[element.uniqueID];
+  //return !set && condition;
+  return condition;
+};
+
+addEventHandler(window, "onbeforeprint", function() {
+  if (!IE7.CSS.print) new StyleSheet("print");
+  IE7.CSS.print.recalc();
+});
+
+// -----------------------------------------------------------------------
+// pixel conversion
+// -----------------------------------------------------------------------
+
+// this is handy because it means that web developers can mix and match
+//  measurement units in their style sheets. it is not uncommon to
+//  express something like padding in "em" units whilst border thickness
+//  is most often expressed in pixels.
+
+var PIXEL = /^\d+(px)?$/i;
+var PERCENT = /^\d+%$/;
+var getPixelValue = function(element, value) {
+  if (PIXEL.test(value)) return parseInt(value);
+  var style = element.style.left;
+  var runtimeStyle = element.runtimeStyle.left;
+  element.runtimeStyle.left = element.currentStyle.left;
+  element.style.left = value || 0;
+  value = element.style.pixelLeft;
+  element.style.left = style;
+  element.runtimeStyle.left = runtimeStyle;
+  return value;
+};
+
+// -----------------------------------------------------------------------
+// generic
+// -----------------------------------------------------------------------
+
+var $IE7 = "ie7-";
+
+var Fix = Base.extend({
+  constructor: function() {
+    this.fixes = [];
+    this.recalcs = [];
+  },
+  init: Undefined
+});
+
+// a store for functions that will be called when refreshing IE7
+var recalcs = [];
+function addRecalc(recalc) {
+  recalcs.push(recalc);
+};
+
+IE7.recalc = function() {
+  IE7.HTML.recalc();
+  // re-apply style sheet rules (re-calculate ie7 classes)
+  IE7.CSS.recalc();
+  // apply global fixes to the document
+  for (var i = 0; i < recalcs.length; i++) recalcs[i]();
+};
+
+function isFixed(element) {
+  return element.currentStyle["ie7-position"] == "fixed";
+};
+
+// original style
+function getDefinedStyle(element, propertyName) {
+  return element.currentStyle[$IE7 + propertyName] || element.currentStyle[propertyName];
+};
+
+function setOverrideStyle(element, propertyName, value) {
+  if (element.currentStyle[$IE7 + propertyName] == null) {
+    element.runtimeStyle[$IE7 + propertyName] = element.currentStyle[propertyName];
+  }
+  element.runtimeStyle[propertyName] = value;
+};
+
+// Create a temporary element which is used to inherit styles
+// from the target element.
+function createTempElement(tagName) {
+  var element = document.createElement(tagName || "object");
+  element.style.cssText = "position:absolute;padding:0;display:block;border:none;clip:rect(0 0 0 0);left:-9999";
+  element.ie7_anon = true;
+  return element;
+};
+
+
+// =========================================================================
+// ie7-css.js
+// =========================================================================
+
+var NEXT_SIBLING        = "(e.nextSibling&&IE7._getElementSibling(e,'next'))",
+    PREVIOUS_SIBLING    = NEXT_SIBLING.replace(/next/g, "previous"),
+    IS_ELEMENT          = "e.nodeName>'@'",
+    IF_ELEMENT          = "if(" + IS_ELEMENT + "){";
+
+var ID_ATTRIBUTE  = "(e.nodeName==='FORM'?IE7._getAttribute(e,'id'):e.id)";
+
+var HYPERLINK = /a(#[\w-]+)?(\.[\w-]+)?:(hover|active)/i;
+var FIRST_LINE_LETTER = /(.*)(:first-(line|letter))/;
+var SPACE = /\s/;
+var RULE = /((?:\\.|[^{\\])+)\{((?:\\.|[^}\\])+)\}/g;
+var SELECTOR = /(?:\\.|[^,\\])+/g;
+
+var styleSheets = document.styleSheets;
+
+var inheritedProperties = [];
+
+IE7.CSS = new (Fix.extend({ // single instance
+  parser: new Parser,
+  screen: "",
+  print: "",
+  styles: [],
+  rules: [],
+  pseudoClasses: appVersion < 7 ? "first\\-child" : "",
+  dynamicPseudoClasses: {
+    toString: function() {
+      var strings = [];
+      for (var pseudoClass in this) strings.push(pseudoClass);
+      return strings.join("|");
+    }
+  },
+  
+  init: function() {
+    var NONE = "^\x01$";
+    var CLASS = "\\[class=?[^\\]]*\\]";
+    var pseudoClasses = [];
+    if (this.pseudoClasses) pseudoClasses.push(this.pseudoClasses);
+    var dynamicPseudoClasses = this.dynamicPseudoClasses.toString(); 
+    if (dynamicPseudoClasses) pseudoClasses.push(dynamicPseudoClasses);
+    pseudoClasses = pseudoClasses.join("|");
+    var unknown = appVersion < 7 ? ["[>+~\\[(]|([:.])[\\w-]+\\1"] : [CLASS];
+    if (pseudoClasses) unknown.push(":(" + pseudoClasses + ")");
+    this.UNKNOWN = new RegExp(unknown.join("|") || NONE, "i");
+    var complex = appVersion < 7 ? ["\\[[^\\]]+\\]|[^\\s(\\[]+\\s*[+~]"] : [CLASS];
+    var complexRule = complex.concat();
+    if (pseudoClasses) complexRule.push(":(" + pseudoClasses + ")");
+    Rule.COMPLEX = new RegExp(complexRule.join("|") || NONE, "ig");
+    if (this.pseudoClasses) complex.push(":(" + this.pseudoClasses + ")");
+    DynamicRule.COMPLEX = new RegExp(complex.join("|") || NONE, "i");
+    dynamicPseudoClasses = "not\\(:" + dynamicPseudoClasses.split("|").join("\\)|not\\(:") + "\\)|" + dynamicPseudoClasses;
+    DynamicRule.MATCH = new RegExp(dynamicPseudoClasses ? "(.*?):(" + dynamicPseudoClasses + ")(.*)" : NONE, "i");
+    
+    this.createStyleSheet();
+    this.refresh();
+  },
+  
+	addEventHandler: function() {
+		addEventHandler.apply(null, arguments);
+	},
+  
+  addFix: function(expression, replacement) {
+    this.parser.add(expression, replacement);
+  },
+  
+  addRecalc: function(propertyName, test, handler, replacement) {
+    // recalcs occur whenever the document is refreshed using document.recalc()
+    propertyName = propertyName.source || propertyName;
+    test = new RegExp("([{;\\s])" + propertyName + "\\s*:\\s*" + test + "[^;}]*");
+    var id = this.recalcs.length;
+    if (typeof replacement == "string") replacement = propertyName + ":" + replacement;
+    this.addFix(test, function(match) {
+      if (typeof replacement == "function") replacement = replacement(match);
+      return (replacement ? replacement : match) + ";ie7-" + match.slice(1) + ";ie7_recalc" + id + ":1";
+    });
+    this.recalcs.push(arguments);
+    return id;
+  },
+  
+  apply: function() {
+    this.getInlineCSS();
+    new StyleSheet("screen");
+    this.trash();
+  },
+  
+  createStyleSheet: function() {
+    // create the IE7 style sheet
+    document.getElementsByTagName("head")[0].appendChild(document.createElement("style"));
+    this.styleSheet = styleSheets[styleSheets.length - 1];
+    // flag it so we can ignore it during parsing
+    this.styleSheet.ie7 = true;
+    this.styleSheet.owningElement.ie7 = true;
+    this.styleSheet.cssText = HEADER;
+  },
+  
+  getInlineCSS: function() {// load inline styles
+    var styleSheets = document.getElementsByTagName("style"), styleSheet;
+    for (var i = styleSheets.length - 1; styleSheet = styleSheets[i]; i--) {
+      if (!styleSheet.disabled && !styleSheet.ie7) {
+        styleSheet._cssText = styleSheet.innerHTML;
+      }
+    }
+  },
+  
+  getText: function(styleSheet, path) {
+    // Internet Explorer will trash unknown selectors (it converts them to "UNKNOWN").
+    // So we must reload external style sheets (internal style sheets can have their text
+    // extracted through the innerHTML property).
+
+    // load the style sheet text from an external file
+    try {
+      var cssText = styleSheet.cssText;
+    } catch (e) {
+      cssText = "";
+    }
+    if (httpRequest) cssText = loadFile(styleSheet.href, path) || cssText;
+    return cssText;
+  },
+  
+  recalc: function() {
+    this.screen.recalc();
+    // we're going to read through all style rules.
+    //  certain rules have had ie7 properties added to them.
+    //   e.g. p{top:0; ie7_recalc2:1; left:0}
+    //  this flags a property in the rule as needing a fix.
+    //  the selector text is then used to query the document.
+    //  we can then loop through the results of the query
+    //  and fix the elements.
+    // we ignore the IE7 rules - so count them in the header
+    var RECALCS = /ie7_recalc\d+/g;
+    var start = HEADER.match(/[{,]/g).length;
+    // only calculate screen fixes. print fixes don't show up anyway
+    var rules = this.styleSheet.rules, rule;
+    var calcs, calc, elements, element, i, j, k, id;
+    // loop through all rules
+    for (i = start; rule = rules[i]; i++) {
+      var cssText = rule.style.cssText;
+      // search for the "ie7_recalc" flag (there may be more than one)
+      if (calcs = cssText.match(RECALCS)) {
+        // use the selector text to query the document
+        elements = cssQuery(rule.selectorText);
+        // if there are matching elements then loop
+        //  through the recalc functions and apply them
+        //  to each element
+        if (elements.length) for (j = 0; j < calcs.length; j++) {
+          // get the matching flag (e.g. ie7_recalc3)
+          id = calcs[j];
+          // extract the numeric id from the end of the flag
+          //  and use it to index the collection of recalc
+          //  functions
+          calc = IE7.CSS.recalcs[id.slice(10)][2];
+          for (k = 0; (element = elements[k]); k++) {
+            // apply the fix
+            if (element.currentStyle[id]) calc(element, cssText);
+          }
+        }
+      }
+    }
+  },
+  
+  refresh: function() {
+    this.styleSheet.cssText = HEADER + this.screen + this.print;
+  },
+  
+  trash: function() {
+    // trash the old style sheets
+    for (var i = 0; i < styleSheets.length; i++) {
+      if (!styleSheets[i].ie7) {
+        try {
+          var cssText = styleSheets[i].cssText;
+        } catch (e) {
+          cssText = "";
+        }
+        if (cssText) styleSheets[i].cssText = "";
+      }
+    }
+  }
+}));
+
+// -----------------------------------------------------------------------
+//  IE7 StyleSheet class
+// -----------------------------------------------------------------------
+
+var StyleSheet = Base.extend({
+  constructor: function(media) {
+    this.media = media;
+    this.load();
+    IE7.CSS[media] = this;
+    IE7.CSS.refresh();
+  },
+  
+  createRule: function(selector, cssText) {
+    var match;
+    if (PseudoElement && (match = selector.match(PseudoElement.MATCH))) {
+      return new PseudoElement(match[1], match[2], cssText);
+    } else if (match = selector.match(DynamicRule.MATCH)) {
+      if (!HYPERLINK.test(match[0]) || DynamicRule.COMPLEX.test(match[0])) {
+        return new DynamicRule(selector, match[1], match[2], match[3], cssText);
+      }
+    } else {
+      return new Rule(selector, cssText);
+    }
+    return selector + " {" + cssText + "}";
+  },
+  
+  getText: function() {
+    // store for style sheet text
+    // parse media decalarations
+    var MEDIA        = /@media\s+([^{]+?)\s*\{([^@]+\})\s*\}/gi;
+    var IMPORTS      = /@import[^;\n]+/gi;
+    var TRIM_IMPORTS = /@import\s+url\s*\(\s*["']?|["']?\s*\)\s*/gi;
+    var URL          = /(url\s*\(\s*['"]?)([\w\.]+[^:\)]*['"]?\))/gi;
+
+    var self = this;
+    
+    // Store loaded cssText URLs
+    var fileCache = {};
+    
+    function getCSSText(styleSheet, path, media, level) {
+      var cssText = "";
+      if (!level) {
+        media = toSimpleMedia(styleSheet.media);
+        level = 0;
+      }
+      if (media === "none") {
+        styleSheet.disabled = true;
+        return "";
+      }
+      if (media === "all" || media === self.media) {
+        // IE only allows importing style sheets three levels deep.
+        // it will crash if you try to access a level below this
+        try {
+          var canAcess = !!styleSheet.cssText;
+        } catch (exe) {}
+        if (level < 3 && canAcess) {
+          var hrefs = styleSheet.cssText.match(IMPORTS);
+          // loop through imported style sheets
+          for (var i = 0, imported; i < styleSheet.imports.length; i++) {
+            var imported = styleSheet.imports[i];
+            var href = styleSheet._href || styleSheet.href;
+            imported._href = hrefs[i].replace(TRIM_IMPORTS, "");
+            // call this function recursively to get all imported style sheets
+            cssText += getCSSText(imported, getPath(href, path), media, level + 1);
+          }
+        }
+        // retrieve inline style or load an external style sheet
+        cssText += encode(styleSheet.href ? loadStyleSheet(styleSheet, path) : styleSheet.owningElement._cssText);
+        cssText = parseMedia(cssText, self.media);
+      }
+      return cssText;
+    };
+
+    // Load all style sheets in the document
+    for (var i = 0; i < styleSheets.length; i++) {
+      var styleSheet = styleSheets[i];
+      if (!styleSheet.disabled && !styleSheet.ie7) this.cssText += getCSSText(styleSheet);
+    }
+    
+    // helper functions
+    function parseMedia(cssText, media) {
+      filterMedia.value = media;
+      return cssText.replace(MEDIA, filterMedia);
+    };
+    
+    function filterMedia(match, media, cssText) {
+      media = toSimpleMedia(media);
+      switch (media) {
+        case "screen":
+        case "print":
+          if (media !== filterMedia.value) return "";
+        case "all":
+          return cssText;
+      }
+      return "";
+    };
+    
+    function toSimpleMedia(media) {
+      if (!media) return "all";
+      var split = media.toLowerCase().split(/\s*,\s*/);
+      media = "none";
+      for (var i = 0; i < split.length; i++) {
+        if (split[i] === "all") return "all";
+        if (split[i] === "screen") {
+          if (media === "print") return "all";
+          media = "screen";
+        } else if (split[i] === "print") {
+          if (media === "screen") return "all";
+          media = "print";
+        }
+      }
+      return media;
+    };
+    
+    // Load an external style sheet
+    function loadStyleSheet(styleSheet, path) {
+      var href = styleSheet._href || styleSheet.href;
+      var url = makePath(href, path);
+      // If the style sheet has already loaded then don't reload it
+      if (fileCache[url]) return "";
+      // Load from source
+      fileCache[url] = styleSheet.disabled ? "" :
+        fixUrls(IE7.CSS.getText(styleSheet, path), getPath(href, path));
+      return fileCache[url];
+    };
+
+    // Fix CSS paths.
+    // We're lumping all css text into one big style sheet so relative
+    // paths have to be fixed. This is necessary anyway because of other
+    // Internet Explorer bugs.
+    function fixUrls(cssText, pathname) {
+      // hack & slash
+      return cssText.replace(URL, "$1" + pathname.slice(0, pathname.lastIndexOf("/") + 1) + "$2");
+    };
+  },
+  
+  load: function() {
+    this.cssText = "";
+    this.getText();
+    this.parse();
+    if (inheritedProperties.length) {
+      this.cssText = parseInherited(this.cssText);
+    }
+    this.cssText = decode(this.cssText);
+    fileCache = {};
+  },
+  
+  parse: function() {
+    var cssText = IE7.CSS.parser.parse(this.cssText);
+    
+    var declarations = "";
+    this.cssText = cssText.replace(/@charset[^;]+;|@font\-face[^\}]+\}/g, function(match) {
+      declarations += match + "\n";
+      return "";
+    });
+    this.declarations = decode(declarations);
+    
+    // Parse the style sheet
+    var offset = IE7.CSS.rules.length;
+    var rules = [], rule;
+    while ((rule = RULE.exec(this.cssText))) {
+      var cssText = rule[2];
+      if (cssText) {
+        var fixDescendants = appVersion < 7 && cssText.indexOf("AlphaImageLoader") !== -1;
+        var selectors = rule[1].match(SELECTOR), selector;
+        for (var i = 0; selector = selectors[i]; i++) {
+          selector = trim(selector);
+          var isUnknown = IE7.CSS.UNKNOWN.test(selector);
+          selectors[i] = isUnknown ? this.createRule(selector, cssText) : selector + "{" + cssText + "}";
+          if (fixDescendants) selectors[i] += this.createRule(selector + ">*", "position:relative");
+        }
+        rules.push(selectors.join("\n"));
+      }
+    }
+    this.cssText = rules.join("\n");
+    this.rules = IE7.CSS.rules.slice(offset);
+  },
+  
+  recalc: function() {
+    var rule, i;
+    for (i = 0; (rule = this.rules[i]); i++) rule.recalc();
+  },
+  
+  toString: function() {
+    return this.declarations + "@media " + this.media + "{" + this.cssText + "}";
+  }
+});
+
+var PseudoElement;
+
+// -----------------------------------------------------------------------
+// IE7 style rules
+// -----------------------------------------------------------------------
+
+var Rule = IE7.Rule = Base.extend({
+  constructor: function(selector, cssText) {
+    this.id = IE7.CSS.rules.length;
+    this.className = Rule.PREFIX + this.id;
+    var pseudoElement = selector.match(FIRST_LINE_LETTER);
+    this.selector = (pseudoElement ? pseudoElement[1] : selector) || "*";
+    this.selectorText = this.parse(this.selector) + (pseudoElement ? pseudoElement[2] : "");
+    this.cssText = cssText;
+    this.MATCH = new RegExp("\\s" + this.className + "(\\s|$)", "g");
+    IE7.CSS.rules.push(this);
+    this.init();
+  },
+  
+  init: Undefined,
+  
+  add: function(element) {
+    // allocate this class
+    element.className += " " + this.className;
+  },
+  
+  recalc: function() {
+    // execute the underlying css query for this class
+    var match = cssQuery(this.selector);
+    // add the class name for all matching elements
+    for (var i = 0; i < match.length; i++) this.add(match[i]);
+  },
+
+  parse: function(selector) {
+    // attempt to preserve specificity for "loose" parsing by
+    //  removing unknown tokens from a css selector but keep as
+    //  much as we can..
+    var simple = selector.replace(Rule.CHILD, " ").replace(Rule.COMPLEX, "");
+    if (appVersion < 7) simple = simple.replace(Rule.MULTI, "");
+    var tags = match(simple, Rule.TAGS).length - match(selector, Rule.TAGS).length;
+    var classes = match(simple, Rule.CLASSES).length - match(selector, Rule.CLASSES).length + 1;
+    while (classes > 0 && Rule.CLASS.test(simple)) {
+      simple = simple.replace(Rule.CLASS, "");
+      classes--;
+    }
+    while (tags > 0 && Rule.TAG.test(simple)) {
+      simple = simple.replace(Rule.TAG, "$1*");
+      tags--;
+    }
+    simple += "." + this.className;
+    classes = Math.min(classes, 2);
+    tags = Math.min(tags, 2);
+    var score = -10 * classes - tags;
+    if (score > 0) {
+      simple = simple + "," + Rule.MAP[score] + " " + simple;
+    }
+    return simple;
+  },
+  
+  remove: function(element) {
+    // deallocate this class
+    element.className = element.className.replace(this.MATCH, "$1");
+  },
+  
+  toString: function() {
+    return format("%1 {%2}", this.selectorText, this.cssText);
+  }
+}, {
+  CHILD: />/g,
+  CLASS: /\.[\w-]+/,
+  CLASSES: /[.:\[]/g,
+  MULTI: /(\.[\w-]+)+/g,
+  PREFIX: "ie7_class",
+  TAG: /^\w+|([\s>+~])\w+/,
+  TAGS: /^\w|[\s>+~]\w/g,
+  MAP: {
+    "1":  "html",
+    "2":  "html body",
+    "10": ".ie7_html",
+    "11": "html.ie7_html",
+    "12": "html.ie7_html body",
+    "20": ".ie7_html .ie7_body",
+    "21": "html.ie7_html .ie7_body",
+    "22": "html.ie7_html body.ie7_body"
+  }
+});
+
+// -----------------------------------------------------------------------
+// IE7 dynamic style
+// -----------------------------------------------------------------------
+
+// object properties:
+// attach: the element that an event handler will be attached to
+// target: the element that will have the IE7 class applied
+
+var DynamicRule = Rule.extend({
+  // properties
+  constructor: function(selector, attach, dynamicPseudoClass, target, cssText) {
+    this.negated = dynamicPseudoClass.indexOf("not") === 0;
+    if (this.negated) dynamicPseudoClass = dynamicPseudoClass.slice(5, -1);
+    // initialise object properties
+    this.attach = attach || "*";
+    this.dynamicPseudoClass = IE7.CSS.dynamicPseudoClasses[dynamicPseudoClass];
+    this.target = target;
+    this.base(selector, cssText);
+  },
+  
+  recalc: function() {
+    // execute the underlying css query for this class
+    var attaches = cssQuery(this.attach), attach;
+    // process results
+    for (var i = 0; attach = attaches[i]; i++) {
+      // retrieve the event handler's target element(s)
+      var target = this.target ? cssQuery(this.target, attach) : [attach];
+      // attach event handlers for dynamic pseudo-classes
+      if (target.length) this.dynamicPseudoClass.apply(attach, target, this);
+    }
+  }
+});
+
+// -----------------------------------------------------------------------
+//  IE7 dynamic pseudo-classes
+// -----------------------------------------------------------------------
+
+var DynamicPseudoClass = Base.extend({
+  constructor: function(name, apply) {
+    this.name = name;
+    this.apply = apply;
+    this.instances = {};
+    IE7.CSS.dynamicPseudoClasses[name] = this;
+  },
+  
+  register: function(instance, negated) {
+    // an "instance" is actually an Arguments object
+    var _class = instance[2];
+    if (!negated && _class.negated) {
+      this.unregister(instance, true);
+    } else {
+      instance.id = _class.id + instance[0].uniqueID;
+      if (!this.instances[instance.id]) {
+        var target = instance[1], j;
+        for (j = 0; j < target.length; j++) _class.add(target[j]);
+        this.instances[instance.id] = instance;
+      }
+    }
+  },
+  
+  unregister: function(instance, negated) {
+    var _class = instance[2];
+    if (!negated && _class.negated) {
+      this.register(instance, true);
+    } else {
+      if (this.instances[instance.id]) {
+        var target = instance[1], j;
+        for (j = 0; j < target.length; j++) _class.remove(target[j]);
+        delete this.instances[instance.id];
+      }
+    }
+  }
+});
+  
+// -----------------------------------------------------------------------
+// dynamic pseudo-classes
+// -----------------------------------------------------------------------
+
+var Hover = new DynamicPseudoClass("hover", function(element) {
+  var instance = arguments;
+  IE7.CSS.addEventHandler(element, "onmouseenter", function() {
+    Hover.register(instance);
+  });
+  IE7.CSS.addEventHandler(element, "onmouseleave", function() {
+    Hover.unregister(instance);
+  });
+});
+
+// globally trap the mouseup event (thanks Martijn!)
+addEventHandler(document, "onmouseup", function() {
+  var instances = Hover.instances;
+  for (var i in instances)
+    if (!instances[i][0].contains(event.srcElement))
+      Hover.unregister(instances[i]);
+});
+
+var ATTR = {
+  "=":  "%1==='%2'",                           // "[@%1='%2']"
+  "~=": "(' '+%1+' ').indexOf(' %2 ')!==-1",   // "[contains(concat(' ',@%1,' '),' %2 ')]",
+  "|=": "%1==='%2'||%1.indexOf('%2-')===0",    // "[@%1='%2' or starts-with(@%1,'%2-')]",
+  "^=": "%1.indexOf('%2')===0",                // "[starts-with(@%1,'%2')]",
+  "$=": "%1.slice(-'%2'.length)==='%2'",       // "[ends-with(@%1,'%2')]",
+  "*=": "%1.indexOf('%2')!==-1"                // "[contains(@%1,'%2')]"
+};
+ATTR[""] = "%1!=null";                         // "[@%1]"
+
+var FILTER = {
+  "<#attr>": function(match, name, operator, value) {
+    var attr = "IE7._getAttribute(e,'" + name + "')";
+    value = getString(value);
+    if (operator.length > 1) {
+      if (!value || operator === "~=" && SPACE.test(value)) {
+        return "false&&";
+      }
+      attr = "(" + attr + "||'')";
+    }
+    return "(" + format(ATTR[operator], attr, value) + ")&&";
+  },
+
+  "<#id>":    ID_ATTRIBUTE + "==='$1'&&",
+
+  "<#class>": "e.className&&(' '+e.className+' ').indexOf(' $1 ')!==-1&&",
+
+  // PSEDUO
+  ":first-child":     "!" + PREVIOUS_SIBLING + "&&",
+  ":link":           "e.currentStyle['ie7-link']=='link'&&",
+  ":visited":        "e.currentStyle['ie7-link']=='visited'&&"
+};
+
+// =========================================================================
+// ie7-html.js
+// =========================================================================
+
+// default font-sizes
+//HEADER += "h1{font-size:2em}h2{font-size:1.5em;}h3{font-size:1.17em;}h4{font-size:1em}h5{font-size:.83em}h6{font-size:.67em}";
+
+IE7.HTML = new (Fix.extend({ // single instance  
+  fixed: {},
+  
+  init: Undefined,
+  
+  addFix: function() {
+    // fixes are a one-off, they are applied when the document is loaded
+    this.fixes.push(arguments);
+  },
+  
+  apply: function() {
+    for (var i = 0; i < this.fixes.length; i++) {
+      var match = cssQuery(this.fixes[i][0]);
+      var fix = this.fixes[i][1];
+      for (var j = 0; j < match.length; j++) fix(match[j]);
+    }
+  },
+  
+  addRecalc: function() {
+    // recalcs occur whenever the document is refreshed using document.recalc()
+    this.recalcs.push(arguments);
+  },
+  
+  recalc: function() {
+    // loop through the fixes
+    for (var i = 0; i < this.recalcs.length; i++) {
+      var match = cssQuery(this.recalcs[i][0]);
+      var recalc = this.recalcs[i][1], element;
+      var key = Math.pow(2, i);
+      for (var j = 0; (element = match[j]); j++) {
+        var uniqueID = element.uniqueID;
+        if ((this.fixed[uniqueID] & key) === 0) {
+          element = recalc(element) || element;
+          this.fixed[uniqueID] |= key;
+        }
+      }
+    }
+  }
+}));
+
+if (appVersion < 7) {  
+  // provide support for the <abbr> tag.
+  document.createElement("abbr");
+  
+  // bind to the first child control
+  IE7.HTML.addRecalc("label", function(label) {
+    if (!label.htmlFor) {
+      var firstChildControl = cssQuery("input,textarea", label, true);
+      if (firstChildControl) {
+        addEventHandler(label, "onclick", function() {
+          firstChildControl.click();
+        });
+      }
+    }
+  });
+}
+
+// =========================================================================
+// ie7-layout.js
+// =========================================================================
+
+var NUMERIC = "[.\\d]";
+
+(function() {
+  var layout = IE7.Layout = {};
+
+  // big, ugly box-model hack + min/max stuff
+
+  // #tantek > #erik > #dean { voice-family: hacker; }
+
+  // -----------------------------------------------------------------------
+  // "layout"
+  // -----------------------------------------------------------------------
+
+  HEADER += "*{boxSizing:content-box}";
+
+  // give an element "layout"
+  layout.boxSizing = function(element) {
+    if (!element.currentStyle.hasLayout) {
+    //#  element.runtimeStyle.fixedHeight =
+      element.style.height = "0cm";
+      if (element.currentStyle.verticalAlign === "auto")
+        element.runtimeStyle.verticalAlign = "top";
+      // when an element acquires "layout", margins no longer collapse correctly
+      collapseMargins(element);
+    }
+  };
+
+  // -----------------------------------------------------------------------
+  // Margin Collapse
+  // -----------------------------------------------------------------------
+
+  function collapseMargins(element) {
+    if (element != viewport && element.currentStyle.position !== "absolute") {
+      collapseMargin(element, "marginTop");
+      collapseMargin(element, "marginBottom");
+    }
+  };
+
+  function collapseMargin(element, type) {
+    if (!element.runtimeStyle[type]) {
+      var parentElement = element.parentElement;
+      var isTopMargin = type === "marginTop";
+      if (parentElement && parentElement.currentStyle.hasLayout && !IE7._getElementSibling(element, isTopMargin ? "previous" : "next")) return;
+      var child = element[isTopMargin ? "firstChild" : "lastChild"];
+      if (child && child.nodeName < "@") child = IE7._getElementSibling(child, isTopMargin ? "next" : "previous");
+      if (child && child.currentStyle.styleFloat === "none" && child.currentStyle.hasLayout) {
+        collapseMargin(child, type);
+        margin = _getMargin(element, element.currentStyle[type]);
+        childMargin = _getMargin(child, child.currentStyle[type]);
+        if (margin < 0 || childMargin < 0) {
+          element.runtimeStyle[type] = margin + childMargin;
+        } else {
+          element.runtimeStyle[type] = Math.max(childMargin, margin);
+        }
+        child.runtimeStyle[type] = "0px";
+      }
+    }
+  };
+
+  function _getMargin(element, value) {
+    return value === "auto" ? 0 : getPixelValue(element, value);
+  };
+
+  // -----------------------------------------------------------------------
+  // box-model
+  // -----------------------------------------------------------------------
+
+  // constants
+  var UNIT = /^[.\d][\w]*$/, AUTO = /^(auto|0cm)$/;
+
+  var apply = {};
+  layout.borderBox = function(element){
+    apply.Width(element);
+    apply.Height(element);
+  };
+
+  var _fixWidth = function(HEIGHT) {
+    apply.Width = function(element) {
+      if (!PERCENT.test(element.currentStyle.width)) _fixWidth(element);
+      if (HEIGHT) collapseMargins(element);
+    };
+
+    function _fixWidth(element, value) {
+      if (!element.runtimeStyle.fixedWidth) {
+        if (!value) value = element.currentStyle.width;
+        element.runtimeStyle.fixedWidth = UNIT.test(value) ? Math.max(0, getFixedWidth(element, value)) + "px" : value;
+        setOverrideStyle(element, "width", element.runtimeStyle.fixedWidth);
+      }
+    };
+
+    function layoutWidth(element) {
+      if (!isFixed(element)) {
+        var layoutParent = element.offsetParent;
+        while (layoutParent && !layoutParent.currentStyle.hasLayout) layoutParent = layoutParent.offsetParent;
+      }
+      return (layoutParent || viewport).clientWidth;
+    };
+
+    function getPixelWidth(element, value) {
+      if (PERCENT.test(value)) return parseInt(parseFloat(value) / 100 * layoutWidth(element));
+      return getPixelValue(element, value);
+    };
+
+    var getFixedWidth = function(element, value) {
+      var borderBox = element.currentStyle["ie7-box-sizing"] === "border-box";
+      var adjustment = 0;
+      if (MSIE5 && !borderBox)
+        adjustment += getBorderWidth(element) + getWidth(element, "padding");
+      else if (!MSIE5 && borderBox)
+        adjustment -= getBorderWidth(element) + getWidth(element, "padding");
+      return getPixelWidth(element, value) + adjustment;
+    };
+
+    // easy way to get border thickness for elements with "layout"
+    function getBorderWidth(element) {
+      return element.offsetWidth - element.clientWidth;
+    };
+
+    // have to do some pixel conversion to get padding/margin thickness :-(
+    function getWidth(element, type) {
+      return getPixelWidth(element, element.currentStyle[type + "Left"]) + getPixelWidth(element, element.currentStyle[type + "Right"]);
+    };
+
+    // -----------------------------------------------------------------------
+    // min/max
+    // -----------------------------------------------------------------------
+
+    HEADER += "*{minWidth:none;maxWidth:none;min-width:none;max-width:none}";
+
+    // handle min-width property
+    layout.minWidth = function(element) {
+      // IE6 supports min-height so we frig it here
+      //#if (element.currentStyle.minHeight === "auto") element.runtimeStyle.minHeight = 0;
+      if (element.currentStyle["min-width"] != null) {
+        element.style.minWidth = element.currentStyle["min-width"];
+      }
+      if (register(arguments.callee, element, element.currentStyle.minWidth !== "none")) {
+        layout.boxSizing(element);
+        _fixWidth(element);
+        resizeWidth(element);
+      }
+    };
+
+    // clone the minWidth function to make a maxWidth function
+    eval("IE7.Layout.maxWidth=" + String(layout.minWidth).replace(/min/g, "max"));
+
+    // apply min/max restrictions
+    function resizeWidth(element) {
+      // check boundaries
+      if (element == document.body) {
+        var width = element.clientWidth;
+      } else {
+        var rect = element.getBoundingClientRect();
+        width = rect.right - rect.left;
+      }
+      if (element.currentStyle.minWidth !== "none" && width < getFixedWidth(element, element.currentStyle.minWidth)) {
+        element.runtimeStyle.width = element.currentStyle.minWidth;
+      } else if (element.currentStyle.maxWidth !== "none" && width >= getFixedWidth(element, element.currentStyle.maxWidth)) {
+        element.runtimeStyle.width = element.currentStyle.maxWidth;
+      } else {
+        element.runtimeStyle.width = element.runtimeStyle.fixedWidth;
+      }
+    };
+
+    // -----------------------------------------------------------------------
+    // right/bottom
+    // -----------------------------------------------------------------------
+
+    function fixRight(element) {
+      if (register(fixRight, element, /^(fixed|absolute)$/.test(element.currentStyle.position) &&
+        getDefinedStyle(element, "left") !== "auto" &&
+        getDefinedStyle(element, "right") !== "auto" &&
+        AUTO.test(getDefinedStyle(element, "width")))) {
+          resizeRight(element);
+          layout.boxSizing(element);
+      }
+    };
+    layout.fixRight = fixRight;
+
+    function resizeRight(element) {
+      var left = getPixelWidth(element, element.runtimeStyle._left || element.currentStyle.left);
+      var width = layoutWidth(element) - getPixelWidth(element, element.currentStyle.right) -  left - getWidth(element, "margin");
+      if (parseInt(element.runtimeStyle.width) === width) return;
+      element.runtimeStyle.width = "";
+      if (isFixed(element) || HEIGHT || element.offsetWidth < width) {
+        if (!MSIE5) width -= getBorderWidth(element) + getWidth(element, "padding");
+        if (width < 0) width = 0;
+        element.runtimeStyle.fixedWidth = width;
+        setOverrideStyle(element, "width", width);
+      }
+    };
+
+  // -----------------------------------------------------------------------
+  // window.onresize
+  // -----------------------------------------------------------------------
+
+    // handle window resize
+    var clientWidth = 0;
+    addResize(function() {
+      if (!viewport) return;
+      var i, wider = (clientWidth < viewport.clientWidth);
+      clientWidth = viewport.clientWidth;
+      // resize elements with "min-width" set
+      var elements = layout.minWidth.elements;
+      for (i in elements) {
+        var element = elements[i];
+        var fixedWidth = (parseInt(element.runtimeStyle.width) === getFixedWidth(element, element.currentStyle.minWidth));
+        if (wider && fixedWidth) element.runtimeStyle.width = "";
+        if (wider == fixedWidth) resizeWidth(element);
+      }
+      // resize elements with "max-width" set
+      var elements = layout.maxWidth.elements;
+      for (i in elements) {
+        var element = elements[i];
+        var fixedWidth = (parseInt(element.runtimeStyle.width) === getFixedWidth(element, element.currentStyle.maxWidth));
+        if (!wider && fixedWidth) element.runtimeStyle.width = "";
+        if (wider !== fixedWidth) resizeWidth(element);
+      }
+      // resize elements with "right" set
+      for (i in fixRight.elements) resizeRight(fixRight.elements[i]);
+    });
+
+  // -----------------------------------------------------------------------
+  // fix CSS
+  // -----------------------------------------------------------------------
+    if (MSIE5) {
+      IE7.CSS.addRecalc("width", NUMERIC, apply.Width);
+    }
+    if (appVersion < 7) {
+      IE7.CSS.addRecalc("max-width", NUMERIC, layout.maxWidth);
+      IE7.CSS.addRecalc("right", NUMERIC, fixRight);
+    } else if (appVersion == 7) {
+      if (HEIGHT) IE7.CSS.addRecalc("height", "[\\d.]+%", function(element) {
+        element.runtimeStyle.pixelHeight = parseInt(layoutWidth(element) * element.currentStyle["ie7-height"].slice(0, -1) / 100);
+      });
+    }
+  };
+
+  eval("var _fixHeight=" + rotate(_fixWidth));
+
+  // apply box-model + min/max fixes
+  _fixWidth();
+  _fixHeight(true);
+  
+  if (appVersion < 7) {
+    IE7.CSS.addRecalc("min-width", NUMERIC, layout.minWidth);
+    IE7.CSS.addFix(/\bmin-height\s*/, "height");
+  }
+})();
+
+// =========================================================================
+// ie7-graphics.js
+// =========================================================================
+
+// a small transparent image used as a placeholder
+var BLANK_GIF = makePath("blank.gif", path);
+
+var ALPHA_IMAGE_LOADER = "DXImageTransform.Microsoft.AlphaImageLoader";
+var PNG_FILTER = "progid:" + ALPHA_IMAGE_LOADER + "(src='%1',sizingMethod='%2')";
+  
+// regular expression version of the above
+var PNG;
+
+var filtered = [];
+
+function fixImage(element) {
+  if (PNG.test(element.src)) {
+    // we have to preserve width and height
+    var image = new Image(element.width, element.height);
+    image.onload = function() {
+      element.width = image.width;
+      element.height = image.height;
+      image = null;
+    };
+    image.src = element.src;
+    // store the original url (we'll put it back when it's printed)
+    element.pngSrc = element.src;
+    // add the AlphaImageLoader thingy
+    addFilter(element);
+  }
+};
+
+if (appVersion < 7) {
+  // ** IE7 VARIABLE
+  // e.g. apply the hack to all files ending in ".png"
+  // IE7_PNG_SUFFIX = ".png";
+  // You can also set it to a RegExp
+  // IE7_PNG_SUFFIX = /\d+\.png$/;
+
+  // replace background(-image): url(..) ..  with background(-image): .. ;filter: ..;
+  IE7.CSS.addFix(/background(-image)?\s*:\s*([^};]*)?url\(([^\)]+)\)([^;}]*)?/, function(match, $1, $2, url, $4) {
+    url = getString(url);
+    return PNG.test(url) ? "filter:" + format(PNG_FILTER, url, $4.indexOf("no-repeat") === -1 ? "scale" : "crop") +
+      ";zoom:1;background" + ($1||"") + ":" + ($2||"") + "none" + ($4||"") : match;
+  });
+
+  // list-style-image
+  IE7.CSS.addRecalc(/list\-style(\-image)?/, "[^};]*url", function(element) {
+    var url = element.currentStyle.listStyleImage.slice(5, -2);
+    if (PNG.test(url)) {
+      if (element.nodeName === "LI") {
+        fixListStyleImage(element, url)
+      } else if (element.nodeName === "UL") {
+        for (var i = 0, li; li = element.childNodes[i]; i++) {
+          if (li.nodeName === "LI") fixListStyleImage(li, url);
+        }
+      }
+    }
+  });
+
+  function fixListStyleImage(element, src) {
+    var style = element.runtimeStyle;
+    var originalHeight = element.offsetHeight;
+    var image = new Image;
+    image.onload = function() {
+      var paddingLeft = element.currentStyle.paddingLeft;
+      paddingLeft = paddingLeft === "0px" ? 0 : getPixelValue(element, paddingLeft);
+      style.paddingLeft = (paddingLeft + this.width) + "px";
+      style.marginLeft = -this.width + "px";
+      style.listStyleType = "none";
+      style.listStyleImage = "none";
+      style.paddingTop = Math.max(originalHeight - element.offsetHeight, 0) + "px";
+      addFilter(element, "crop", src);
+      element.style.zoom = "100%";
+    };
+    image.src = src;
+  };
+  
+  // -----------------------------------------------------------------------
+  //  fix PNG transparency (HTML images)
+  // -----------------------------------------------------------------------
+
+  IE7.HTML.addRecalc("img,input", function(element) {
+    if (element.nodeName === "INPUT" && element.type !== "image") return;
+    fixImage(element);
+    addEventHandler(element, "onpropertychange", function() {
+      if (!printing && event.propertyName === "src" &&
+        element.src.indexOf(BLANK_GIF) === -1) fixImage(element);
+    });
+  });
+
+  // assume that background images should not be printed
+  //  (if they are not transparent then they'll just obscure content)
+  // but we'll put foreground images back...
+  var printing = false;
+  addEventHandler(window, "onbeforeprint", function() {
+    printing = true;
+    for (var i = 0; i < filtered.length; i++) removeFilter(filtered[i]);
+  });
+  addEventHandler(window, "onafterprint", function() {
+    for (var i = 0; i < filtered.length; i++) addFilter(filtered[i]);
+    printing = false;
+  });
+}
+
+// apply a filter
+function addFilter(element, sizingMethod, src) {
+  var filter = element.filters[ALPHA_IMAGE_LOADER];
+  if (filter) {
+    filter.src = src || element.src;
+    filter.enabled = true;
+  } else {
+    element.runtimeStyle.filter = format(PNG_FILTER, src || element.src, sizingMethod || "scale");
+    filtered.push(element);
+  }
+  // remove the real image
+  element.src = BLANK_GIF;
+};
+
+function removeFilter(element) {
+  element.src = element.pngSrc;
+  element.filters[ALPHA_IMAGE_LOADER].enabled = false;
+};
+
+// =========================================================================
+// ie7-fixed.js
+// =========================================================================
+
+(function() {
+  if (appVersion >= 7) return;
+  
+  // some things to consider for this hack.
+  // the document body requires a fixed background. even if
+  //  it is just a blank image.
+  // you have to use setExpression instead of onscroll, this
+  //  together with a fixed body background helps avoid the
+  //  annoying screen flicker of other solutions.
+  
+  IE7.CSS.addRecalc("position", "fixed", _positionFixed, "absolute");
+  IE7.CSS.addRecalc("background(-attachment)?", "[^};]*fixed", _backgroundFixed);
+  
+  // scrolling is relative to the documentElement (HTML tag) when in
+  //  standards mode, otherwise it's relative to the document body
+  var $viewport = MSIE5 ? "body" : "documentElement";
+  
+  function _fixBackground() {
+    // this is required by both position:fixed and background-attachment:fixed.
+    // it is necessary for the document to also have a fixed background image.
+    // we can fake this with a blank image if necessary
+    if (body.currentStyle.backgroundAttachment !== "fixed") {
+      if (body.currentStyle.backgroundImage === "none") {
+        body.runtimeStyle.backgroundRepeat = "no-repeat";
+        body.runtimeStyle.backgroundImage = "url(" + BLANK_GIF + ")"; // dummy
+      }
+      body.runtimeStyle.backgroundAttachment = "fixed";
+    }
+    _fixBackground = Undefined;
+  };
+  
+  var _tmp = createTempElement("img");
+  
+  function _isFixed(element) {
+    return element ? isFixed(element) || _isFixed(element.parentElement) : false;
+  };
+  
+  function _setExpression(element, propertyName, expression) {
+    setTimeout("document.all." + element.uniqueID + ".runtimeStyle.setExpression('" + propertyName + "','" + expression + "')", 0);
+  };
+  
+  // -----------------------------------------------------------------------
+  //  backgroundAttachment: fixed
+  // -----------------------------------------------------------------------
+  
+  function _backgroundFixed(element) {
+    if (register(_backgroundFixed, element, element.currentStyle.backgroundAttachment === "fixed" && !element.contains(body))) {
+      _fixBackground();
+      util.bgLeft(element);
+      util.bgTop(element);
+      _backgroundPosition(element);
+    }
+  };
+  
+  function _backgroundPosition(element) {
+    _tmp.src = element.currentStyle.backgroundImage.slice(5, -2);
+    var parentElement = element.canHaveChildren ? element : element.parentElement;
+    parentElement.appendChild(_tmp);
+    util.setOffsetLeft(element);
+    util.setOffsetTop(element);
+    parentElement.removeChild(_tmp);
+  };
+  
+  // -----------------------------------------------------------------------
+  //  position: fixed
+  // -----------------------------------------------------------------------
+  
+  function _positionFixed(element) {
+    if (register(_positionFixed, element, isFixed(element))) {
+      setOverrideStyle(element, "position",  "absolute");
+      setOverrideStyle(element, "left",  element.currentStyle.left);
+      setOverrideStyle(element, "top",  element.currentStyle.top);
+      _fixBackground();
+      IE7.Layout.fixRight(element);
+      //IE7.Layout.fixBottom(element);
+      _foregroundPosition(element);
+    }
+  };
+  
+  function _foregroundPosition(element, recalc) {
+    document.body.getBoundingClientRect(); // force a reflow
+    util.positionTop(element, recalc);
+    util.positionLeft(element, recalc, true);
+    if (!element.runtimeStyle.autoLeft && element.currentStyle.marginLeft === "auto" &&
+      element.currentStyle.right !== "auto") {
+      var left = viewport.clientWidth - util.getPixelWidth(element, element.currentStyle.right) -
+        util.getPixelWidth(element, element.runtimeStyle._left) - element.clientWidth;
+      if (element.currentStyle.marginRight === "auto") left = parseInt(left / 2);
+      if (_isFixed(element.offsetParent)) element.runtimeStyle.pixelLeft += left;
+      else element.runtimeStyle.shiftLeft = left;
+    }
+    if (!element.runtimeStyle.fixedWidth) util.clipWidth(element);
+    if (!element.runtimeStyle.fixedHeight) util.clipHeight(element);
+  };
+  
+  // -----------------------------------------------------------------------
+  //  capture window resize
+  // -----------------------------------------------------------------------
+  
+  function _resize() {
+    // if the window has been resized then some positions need to be
+    //  recalculated (especially those aligned to "right" or "top"
+    var elements = _backgroundFixed.elements;
+    for (var i in elements) _backgroundPosition(elements[i]);
+    elements = _positionFixed.elements;
+    for (i in elements) {
+      _foregroundPosition(elements[i], true);
+      _foregroundPosition(elements[i], true);
+    }
+    _timer = 0;
+  };
+  
+  // use a timer (sometimes this is a good way to prevent resize loops)
+  var _timer;
+  addResize(function() {
+    if (!_timer) _timer = setTimeout(_resize, 100);
+  });
+
+  // -----------------------------------------------------------------------
+  //  rotated
+  // -----------------------------------------------------------------------
+
+  var util = {};
+  
+  var _horizontal = function(util) {
+    util.bgLeft = function(element) {
+      element.style.backgroundPositionX = element.currentStyle.backgroundPositionX;
+      if (!_isFixed(element)) {
+        _setExpression(element, "backgroundPositionX", "(parseInt(runtimeStyle.offsetLeft)+document." + $viewport + ".scrollLeft)||0");
+      }
+    };
+
+    util.setOffsetLeft = function(element) {
+      var propertyName = _isFixed(element) ? "backgroundPositionX" : "offsetLeft";
+      element.runtimeStyle[propertyName] =
+        util.getOffsetLeft(element, element.style.backgroundPositionX) -
+        element.getBoundingClientRect().left - element.clientLeft + 2;
+    };
+
+    util.getOffsetLeft = function(element, position) {
+      switch (position) {
+        case "left":
+        case "top":
+          return 0;
+        case "right":
+        case "bottom":
+          return viewport.clientWidth - _tmp.offsetWidth;
+        case "center":
+          return (viewport.clientWidth - _tmp.offsetWidth) / 2;
+        default:
+          if (PERCENT.test(position)) {
+            return parseInt((viewport.clientWidth - _tmp.offsetWidth) * parseFloat(position) / 100);
+          }
+          _tmp.style.left = position;
+          return _tmp.offsetLeft;
+      }
+    };
+
+    util.clipWidth = function(element) {
+      var fixWidth = element.runtimeStyle.fixWidth;
+      element.runtimeStyle.borderRightWidth = "";
+      element.runtimeStyle.width = fixWidth ? util.getPixelWidth(element, fixWidth) + "px" : "";
+      if (element.currentStyle.width !== "auto") {
+        var rect = element.getBoundingClientRect();
+        var width = element.offsetWidth - viewport.clientWidth + rect.left - 2;
+        if (width >= 0) {
+          element.runtimeStyle.borderRightWidth = "0px";
+          width = Math.max(getPixelValue(element, element.currentStyle.width) - width, 0);
+          setOverrideStyle(element, "width",  width);
+          return width;
+        }
+      }
+    };
+
+    util.positionLeft = function(element, recalc) {
+      // if the element's width is in % units then it must be recalculated
+      //  with respect to the viewport
+      if (!recalc && PERCENT.test(element.currentStyle.width)) {
+        element.runtimeStyle.fixWidth = element.currentStyle.width;
+      }
+      if (element.runtimeStyle.fixWidth) {
+        element.runtimeStyle.width = util.getPixelWidth(element, element.runtimeStyle.fixWidth);
+      }
+      //if (recalc) {
+      //  // if the element is fixed on the right then no need to recalculate
+      //  if (!element.runtimeStyle.autoLeft) return;
+      //} else {
+        element.runtimeStyle.shiftLeft = 0;
+        element.runtimeStyle._left = element.currentStyle.left;
+        // is the element fixed on the right?
+        element.runtimeStyle.autoLeft = element.currentStyle.right !== "auto" && element.currentStyle.left === "auto";
+      //}
+      // reset the element's "left" value and get it's natural position
+      element.runtimeStyle.left = "";
+      element.runtimeStyle.screenLeft = util.getScreenLeft(element);
+      element.runtimeStyle.pixelLeft = element.runtimeStyle.screenLeft;
+      // if the element is contained by another fixed element then there is no need to
+      //  continually recalculate it's left position
+      if (!recalc && !_isFixed(element.offsetParent)) {
+        // onsrcoll produces jerky movement, so we use an expression
+        _setExpression(element, "pixelLeft", "runtimeStyle.screenLeft+runtimeStyle.shiftLeft+document." + $viewport + ".scrollLeft");
+      }
+    };
+
+    // I've forgotten how this works...
+    util.getScreenLeft = function(element) { // thanks to kevin newman (captainn)
+      var screenLeft = element.offsetLeft, nested = 1;
+      if (element.runtimeStyle.autoLeft) {
+        screenLeft = viewport.clientWidth - element.offsetWidth - util.getPixelWidth(element, element.currentStyle.right);
+      }
+      // accommodate margins
+      if (element.currentStyle.marginLeft !== "auto") {
+        screenLeft -= util.getPixelWidth(element, element.currentStyle.marginLeft);
+      }
+      while (element = element.offsetParent) {
+        if (element.currentStyle.position !== "static") nested = -1;
+        screenLeft += element.offsetLeft * nested;
+      }
+      return screenLeft;
+    };
+
+    util.getPixelWidth = function(element, value) {
+      return PERCENT.test(value) ? parseInt(parseFloat(value) / 100 * viewport.clientWidth) : getPixelValue(element, value);
+    };
+  };
+  eval("var _vertical=" + rotate(_horizontal));
+  _horizontal(util);
+  _vertical(util);
+})();
+
+// =========================================================================
+// ie7-oveflow.js
+// =========================================================================
+
+/* ---------------------------------------------------------------------
+
+  This module alters the structure of the document.
+  It may adversely affect other CSS rules. Be warned.
+
+--------------------------------------------------------------------- */
+
+if (appVersion < 7) {
+  var WRAPPER_STYLE = {
+    backgroundColor: "transparent",
+    backgroundImage: "none",
+    backgroundPositionX: null,
+    backgroundPositionY: null,
+    backgroundRepeat: null,
+    borderTopWidth: 0,
+    borderRightWidth: 0,
+    borderBottomWidth: 0,
+    borderLeftStyle: "none",
+    borderTopStyle: "none",
+    borderRightStyle: "none",
+    borderBottomStyle: "none",
+    borderLeftWidth: 0,
+    borderLeftColor: "#000",
+    borderTopColor: "#000",
+    borderRightColor: "#000",
+    borderBottomColor: "#000",
+    height: null,
+    marginTop: 0,
+    marginBottom: 0,
+    marginRight: 0,
+    marginLeft: 0,
+    width: "100%"
+  };
+
+  IE7.CSS.addRecalc("overflow", "visible", function(element) {
+    if (element.currentStyle.position === "absolute") return;
+    
+    // don't do this again
+    if (element.parentNode.ie7_wrapped) return;
+
+    // if max-height is applied, makes sure it gets applied first
+    if (IE7.Layout && element.currentStyle["max-height"] !== "auto") {
+      IE7.Layout.maxHeight(element);
+    }
+
+    if (element.currentStyle.marginLeft === "auto") element.style.marginLeft = 0;
+    if (element.currentStyle.marginRight === "auto") element.style.marginRight = 0;
+
+    var wrapper = document.createElement(ANON);
+    wrapper.ie7_wrapped = element;
+    for (var propertyName in WRAPPER_STYLE) {
+      wrapper.style[propertyName] = element.currentStyle[propertyName];
+      if (WRAPPER_STYLE[propertyName] != null) {
+        element.runtimeStyle[propertyName] = WRAPPER_STYLE[propertyName];
+      }
+    }
+    wrapper.style.display = "block";
+    wrapper.style.position = "relative";
+    element.runtimeStyle.position = "absolute";
+    element.parentNode.insertBefore(wrapper, element);
+    wrapper.appendChild(element);
+  });
+}
+
+// =========================================================================
+// ie7-quirks.js
+// =========================================================================
+
+function ie7Quirks() {
+  var FONT_SIZES = "xx-small,x-small,small,medium,large,x-large,xx-large".split(",");
+  for (var i = 0; i < FONT_SIZES.length; i++) {
+    FONT_SIZES[FONT_SIZES[i]] = FONT_SIZES[i - 1] || "0.67em";
+  }
+  
+  IE7.CSS.addFix(/(font(-size)?\s*:\s*)([\w.-]+)/, function(match, label, size, value) {
+    return label + (FONT_SIZES[value] || value);
+  });
+  
+  var NEGATIVE = /^\-/, LENGTH = /(em|ex)$/i;
+  var EM = /em$/i, EX = /ex$/i;
+
+  getPixelValue = function(element, value) {
+    if (PIXEL.test(value)) return parseInt(value)||0;
+    var scale = NEGATIVE.test(value)? -1 : 1;
+    if (LENGTH.test(value)) scale *= getFontScale(element);
+    temp.style.width = scale < 0 ? value.slice(1) : value;
+    body.appendChild(temp);
+    // retrieve pixel width
+    value = scale * temp.offsetWidth;
+    // remove the temporary element
+    temp.removeNode();
+    return parseInt(value);
+  };
+
+  var temp = createTempElement();
+  function getFontScale(element) {
+    var scale = 1;
+    temp.style.fontFamily = element.currentStyle.fontFamily;
+    temp.style.lineHeight = element.currentStyle.lineHeight;
+    //temp.style.fontSize = "";
+    while (element != body) {
+      var fontSize = element.currentStyle["ie7-font-size"];
+      if (fontSize) {
+        if (EM.test(fontSize)) scale *= parseFloat(fontSize);
+        else if (PERCENT.test(fontSize)) scale *= (parseFloat(fontSize) / 100);
+        else if (EX.test(fontSize)) scale *= (parseFloat(fontSize) / 2);
+        else {
+          temp.style.fontSize = fontSize;
+          return 1;
+        }
+      }
+      element = element.parentElement;
+    }
+    return scale;
+  };
+
+  // cursor:pointer (IE5.x)
+  IE7.CSS.addFix(/cursor\s*:\s*pointer/, "cursor:hand");
+  // display:list-item (IE5.x)
+  IE7.CSS.addFix(/display\s*:\s*list-item/, "display:block");
+  
+  // -----------------------------------------------------------------------
+  //  margin:auto
+  // -----------------------------------------------------------------------
+  
+  function fixMargin(element) {
+    var parent = element.parentElement;
+    var margin = parent.offsetWidth - element.offsetWidth - getPaddingWidth(parent);
+    var autoRight = (element.currentStyle["ie7-margin"] && element.currentStyle.marginRight === "auto") ||
+      element.currentStyle["ie7-margin-right"] === "auto";
+    switch (parent.currentStyle.textAlign) {
+      case "right":
+        margin = autoRight ? parseInt(margin / 2) : 0;
+        element.runtimeStyle.marginRight = margin + "px";
+        break;
+      case "center":
+        if (autoRight) margin = 0;
+      default:
+        if (autoRight) margin /= 2;
+        element.runtimeStyle.marginLeft = parseInt(margin) + "px";
+    }
+  };
+
+  function getPaddingWidth(element) {
+    return getPixelValue(element, element.currentStyle.paddingLeft) +
+      getPixelValue(element, element.currentStyle.paddingRight);
+  };
+  
+  IE7.CSS.addRecalc("margin(-left|-right)?", "[^};]*auto", function(element) {
+    if (register(fixMargin, element,
+      element.parentElement &&
+      element.currentStyle.display === "block" &&
+      element.currentStyle.marginLeft === "auto" &&
+      element.currentStyle.position !== "absolute")) {
+        fixMargin(element);
+    }
+  });
+  
+  addResize(function() {
+    for (var i in fixMargin.elements) {
+      var element = fixMargin.elements[i];
+      element.runtimeStyle.marginLeft =
+      element.runtimeStyle.marginRight = "";
+      fixMargin(element);
+    }
+  });
+};
+
+
+// =========================================================================
+// ie8-css.js
+// =========================================================================
+
+var BRACKETS = "\\([^)]+\\)";
+
+// pseudo-elements can be declared with a double colon
+encoder.add(/::(before|after)/, ":$1");
+
+if (appVersion < 8) {
+
+  if (IE7.CSS.pseudoClasses) IE7.CSS.pseudoClasses += "|";
+  IE7.CSS.pseudoClasses += "before|after|lang" + BRACKETS;
+
+  // -----------------------------------------------------------------------
+  // propertyName: inherit;
+  // -----------------------------------------------------------------------
+  
+  function parseInherited(cssText) {
+    return cssText.replace(new RegExp("([{;\\s])(" + inheritedProperties.join("|") + ")\\s*:\\s*([^;}]+)", "g"), "$1$2:$3;ie7-$2:$3");
+  };
+
+  var INHERITED = /[\w-]+\s*:\s*inherit/g;
+  var STRIP_IE7_FLAGS = /ie7\-|\s*:\s*inherit/g;
+  var DASH_LOWER = /\-([a-z])/g;
+  function toUpper(match, chr) {return chr.toUpperCase()};
+  
+  IE7.CSS.addRecalc("[\\w-]+", "inherit", function(element, cssText) {
+    if (element.parentElement) {
+      var inherited = cssText.match(INHERITED);
+      for (var i = 0; i < inherited.length; i++) {
+        var propertyName = inherited[i].replace(STRIP_IE7_FLAGS, "");
+        if (element.currentStyle["ie7-" + propertyName] === "inherit") {
+          propertyName = propertyName.replace(DASH_LOWER, toUpper);
+          element.runtimeStyle[propertyName] = element.parentElement.currentStyle[propertyName];
+        }
+      }
+    }
+  }, function(match) {
+    inheritedProperties.push(rescape(match.slice(1).split(":")[0]));
+    return match;
+  });
+
+  // -----------------------------------------------------------------------
+  // dynamic pseudo-classes
+  // -----------------------------------------------------------------------
+
+  var Focus = new DynamicPseudoClass("focus", function(element) {
+    var instance = arguments;
+
+    IE7.CSS.addEventHandler(element, "onfocus", function() {
+      Focus.unregister(instance); // in case it starts with focus
+      Focus.register(instance);
+    });
+
+    IE7.CSS.addEventHandler(element, "onblur", function() {
+      Focus.unregister(instance);
+    });
+
+    // check the active element for initial state
+    if (element == document.activeElement) {
+      Focus.register(instance)
+    }
+  });
+
+  var Active = new DynamicPseudoClass("active", function(element) {
+    var instance = arguments;
+    IE7.CSS.addEventHandler(element, "onmousedown", function() {
+      Active.register(instance);
+    });
+  });
+
+  // globally trap the mouseup event (thanks Martijn!)
+  addEventHandler(document, "onmouseup", function() {
+    var instances = Active.instances;
+    for (var i in instances) Active.unregister(instances[i]);
+  });
+
+  // -----------------------------------------------------------------------
+  // IE7 pseudo elements
+  // -----------------------------------------------------------------------
+
+  // constants
+  var URL = /^url\s*\(\s*([^)]*)\)$/;
+  var POSITION_MAP = {
+    before0: "beforeBegin",
+    before1: "afterBegin",
+    after0: "afterEnd",
+    after1: "beforeEnd"
+  };
+
+  var PseudoElement = IE7.PseudoElement = Rule.extend({
+    constructor: function(selector, position, cssText) {
+      // initialise object properties
+      this.position = position;
+      var content = cssText.match(PseudoElement.CONTENT), match, entity;
+      if (content) {
+        content = content[1];
+        match = content.split(/\s+/);
+        for (var i = 0; (entity = match[i]); i++) {
+          match[i] = /^attr/.test(entity) ? {attr: entity.slice(5, -1)} :
+            entity.charAt(0) === "'" ? getString(entity) : decode(entity);
+        }
+        content = match;
+      }
+      this.content = content;
+      // CSS text needs to be decoded immediately
+      this.base(selector, decode(cssText));
+    },
+
+    init: function() {
+      // execute the underlying css query for this class
+      this.match = cssQuery(this.selector);
+      for (var i = 0; i < this.match.length; i++) {
+        var runtimeStyle = this.match[i].runtimeStyle;
+        if (!runtimeStyle[this.position]) runtimeStyle[this.position] = {cssText:""};
+        runtimeStyle[this.position].cssText += ";" + this.cssText;
+        if (this.content != null) runtimeStyle[this.position].content = this.content;
+      }
+    },
+
+    create: function(target) {
+      var generated = target.runtimeStyle[this.position];
+      if (generated) {
+        // copy the array of values
+        var content = [].concat(generated.content || "");
+        for (var j = 0; j < content.length; j++) {
+          if (typeof content[j] == "object") {
+            content[j] = target.getAttribute(content[j].attr);
+          }
+        }
+        content = content.join("");
+        var url = content.match(URL);
+        var cssText = "overflow:hidden;" + generated.cssText.replace(/'/g, '"');
+        var position = POSITION_MAP[this.position + Number(target.canHaveChildren)];
+        var id = 'ie7_pseudo' + PseudoElement.count++;
+        target.insertAdjacentHTML(position, format(PseudoElement.ANON, this.className, id, cssText, url ? "" : content));
+        if (url) {
+          var src = getString(url[1]);
+          var pseudoElement = document.getElementById(id);
+          pseudoElement.src = src;
+          addFilter(pseudoElement, "crop");
+          var targetIsFloated = target.currentStyle.styleFloat !== "none";
+          if (pseudoElement.currentStyle.display === "inline" || targetIsFloated) {
+            if (appVersion < 7 && targetIsFloated && target.canHaveChildren) {
+              target.runtimeStyle.display = "inline";
+              target.runtimeStyle.position = "relative";
+              pseudoElement.runtimeStyle.position = "absolute";
+            }
+            pseudoElement.style.display = "inline-block";
+            if (target.currentStyle.styleFloat !== "none") {
+              pseudoElement.style.pixelWidth = target.offsetWidth;
+            }
+            var image = new Image;
+            image.onload = function() {
+              pseudoElement.style.pixelWidth = this.width;
+              pseudoElement.style.pixelHeight = Math.max(this.height, pseudoElement.offsetHeight);
+            };
+            image.src = src;
+          }
+        }
+        target.runtimeStyle[this.position] = null;
+      }
+    },
+
+    recalc: function() {
+      if (this.content == null) return;
+      for (var i = 0; i < this.match.length; i++) {
+        this.create(this.match[i]);
+      }
+    },
+
+    toString: function() {
+      return "." + this.className + "{display:inline}";
+    }
+  }, {
+    CONTENT: /content\s*:\s*([^;]*)(;|$)/,
+    ANON: "<ie7:! class='ie7_anon %1' id=%2 style='%3'>%4</ie7:!>",
+    MATCH: /(.*):(before|after).*/,
+
+    count: 0
+  });
+
+  IE7._getLang = function(element) {
+    var lang = "";
+    while (element && element.nodeType === 1) {
+      lang = element.lang || element.getAttribute("lang") || "";
+      if (lang) break;
+      element = element.parentNode;
+    }
+    return lang;
+  };
+
+  FILTER = extend(FILTER, {
+    ":lang\\(([^)]+)\\)":    "((ii=IE7._getLang(e))==='$1'||ii.indexOf('$1-')===0)&&"
+  });
+}
+
+// =========================================================================
+// ie8-html.js
+// =========================================================================
+
+var UNSUCCESSFUL = /^(submit|reset|button)$/;
+
+// -----------------------------------------------------------------------
+// <button>
+// -----------------------------------------------------------------------
+
+// IE bug means that innerText is submitted instead of "value"
+IE7.HTML.addRecalc("button,input", function(button) {
+  if (button.nodeName === "BUTTON") {
+    var match = button.outerHTML.match(/ value="([^"]*)"/i);
+    button.runtimeStyle.value = match ? match[1] : "";
+  }
+  // flag the button/input that was used to submit the form
+  if (button.type === "submit") {
+    addEventHandler(button, "onclick", function() {
+      button.runtimeStyle.clicked = true;
+      setTimeout("document.all." + button.uniqueID + ".runtimeStyle.clicked=false", 1);
+    });
+  }
+});
+
+// -----------------------------------------------------------------------
+// <form>
+// -----------------------------------------------------------------------
+
+// only submit "successful controls
+IE7.HTML.addRecalc("form", function(form) {
+  addEventHandler(form, "onsubmit", function() {
+    for (var element, i = 0; element = form[i]; i++) {
+      if (UNSUCCESSFUL.test(element.type) && !element.disabled && !element.runtimeStyle.clicked) {
+        element.disabled = true;
+        setTimeout("document.all." + element.uniqueID + ".disabled=false", 1);
+      } else if (element.nodeName === "BUTTON" && element.type === "submit") {
+        setTimeout("document.all." + element.uniqueID + ".value='" + element.value + "'", 1);
+        element.value = element.runtimeStyle.value;
+      }
+    }
+  });
+});
+
+// -----------------------------------------------------------------------
+// <img>
+// -----------------------------------------------------------------------
+
+// get rid of the spurious tooltip produced by the alt attribute on images
+IE7.HTML.addRecalc("img", function(img) {
+  if (img.alt && !img.title) img.title = "";
+});
+
+// =========================================================================
+// ie8-layout.js
+// =========================================================================
+
+if (appVersion < 8) {
+  IE7.CSS.addRecalc("border-spacing", NUMERIC, function(element) {
+    if (element.currentStyle.borderCollapse !== "collapse") {
+      element.cellSpacing = getPixelValue(element, element.currentStyle["ie7-border-spacing"].split(" ")[0]);
+    }
+  });
+  IE7.CSS.addRecalc("box-sizing", "content-box", IE7.Layout.boxSizing);
+  IE7.CSS.addRecalc("box-sizing", "border-box", IE7.Layout.borderBox);
+}
+
+// =========================================================================
+// ie8-graphics.js
+// =========================================================================
+
+if (appVersion < 8) {
+  // fix object[type=image/*]
+  var IMAGE = /^image/i;
+  IE7.HTML.addRecalc("object", function(element) {
+    if (IMAGE.test(element.type)) {
+      element.body.style.cssText = "margin:0;padding:0;border:none;overflow:hidden";
+      return element;
+    }
+  });
+}
+
+// =========================================================================
+// ie9-css.js
+// =========================================================================
+
+var NOT_NEXT_BY_TYPE     = "!IE7._getElementSiblingByType(e,'next')&&",
+    NOT_PREVIOUS_BY_TYPE = NOT_NEXT_BY_TYPE.replace("next", "previous");
+
+if (IE7.CSS.pseudoClasses) IE7.CSS.pseudoClasses += "|";
+IE7.CSS.pseudoClasses += "(?:first|last|only)\\-(?:child|of\\-type)|empty|root|target|" +
+  ("not|nth\\-child|nth\\-last\\-child|nth\\-of\\-type|nth\\-last\\-of\\-type".split("|").join(BRACKETS + "|") + BRACKETS);
+  
+// :checked
+var Checked = new DynamicPseudoClass("checked", function(element) {
+  if (typeof element.checked !== "boolean") return;
+  var instance = arguments;
+  IE7.CSS.addEventHandler(element, "onpropertychange", function() {
+    if (event.propertyName === "checked") {
+      if (element.checked === true) Checked.register(instance);
+      else Checked.unregister(instance);
+    }
+  });
+  // check current checked state
+  if (element.checked === true) Checked.register(instance);
+});
+
+// :enabled
+var Enabled = new DynamicPseudoClass("enabled", function(element) {
+  if (typeof element.disabled !== "boolean") return;
+  var instance = arguments;
+  IE7.CSS.addEventHandler(element, "onpropertychange", function() {
+    if (event.propertyName === "disabled") {
+      if (element.disabled === false) Enabled.register(instance);
+      else Enabled.unregister(instance);
+    }
+  });
+  // check current disabled state
+  if (element.disabled === false) Enabled.register(instance);
+});
+
+// :disabled
+var Disabled = new DynamicPseudoClass("disabled", function(element) {
+  if (typeof element.disabled !== "boolean") return;
+  var instance = arguments;
+  IE7.CSS.addEventHandler(element, "onpropertychange", function() {
+    if (event.propertyName === "disabled") {
+      if (element.disabled === true) Disabled.register(instance);
+      else Disabled.unregister(instance);
+    }
+  });
+  // check current disabled state
+  if (element.disabled === true) Disabled.register(instance);
+});
+
+// :indeterminate (Kevin Newman)
+var Indeterminate = new DynamicPseudoClass("indeterminate", function(element) {
+  if (typeof element.indeterminate !== "boolean") return;
+  var instance = arguments;
+  IE7.CSS.addEventHandler(element, "onpropertychange", function() {
+    if (event.propertyName === "indeterminate") {
+      if (element.indeterminate === true) Indeterminate.register(instance);
+      else Indeterminate.unregister(instance);
+    }
+  });
+  IE7.CSS.addEventHandler(element, "onclick", function() {
+    Indeterminate.unregister(instance);
+  });
+  // clever Kev says no need to check this up front
+});
+
+// :target
+var Target = new DynamicPseudoClass("target", function(element) {
+  var instance = arguments;
+  // if an element has a tabIndex then it can become "active".
+  //  The default is zero anyway but it works...
+  if (!element.tabIndex) element.tabIndex = 0;
+  // this doesn't detect the back button. I don't know how to do that without adding an iframe :-(
+  IE7.CSS.addEventHandler(document, "onpropertychange", function() {
+    if (event.propertyName === "activeElement") {
+      if (element.id && element.id === location.hash.slice(1)) Target.register(instance);
+      else Target.unregister(instance);
+    }
+  });
+  // check the current location
+  if (element.id && element.id === location.hash.slice(1)) Target.register(instance);
+});
+
+// Register a node and index its siblings.
+var _currentIndex = 1, // -@DRE
+    allIndexes = {_currentIndex: 1};
+
+IE7._indexOf = function(element, last, ofType) {
+  var parent = element.parentNode;
+  if (!parent || parent.nodeType !== 1) return NaN;
+
+  var tagName = ofType ? element.nodeName : "";
+  if (tagName === "TR" && element.sectionRowIndex >= 0) {
+    var index = element.sectionRowIndex;
+    return last ? element.parentNode.rows.length - index + 1 : index;
+  }
+  if ((tagName === "TD" || tagName === "TH") && element.cellIndex >= 0) {
+    index = element.cellIndex;
+    return last ? element.parentNode.cells.length - index + 1 : index;
+  }
+  if (allIndexes._currentIndex !== _currentIndex) {
+    allIndexes = {_currentIndex: _currentIndex};
+  }
+  var id = (parent.uniqueID) + "-" + tagName,
+      indexes = allIndexes[id];
+  if (!indexes) {
+    indexes = {};
+    var index = 0,
+        child = parent.firstChild;
+    while (child) {
+      if (ofType ? child.nodeName === tagName : child.nodeName > "@") {
+        indexes[child.uniqueID] = ++index;
+      }
+      child = child.nextSibling;
+    }
+    indexes.length = index;
+    allIndexes[id] = indexes;
+  }
+  index = indexes[element.uniqueID];
+  return last ? indexes.length - index + 1 : index;
+};
+
+IE7._isEmpty = function(node) {
+  node = node.firstChild;
+  while (node) {
+    if (node.nodeType === 3 || node.nodeName > "@") return false;
+    node = node.nextSibling;
+  }
+  return true;
+};
+
+IE7._getElementSiblingByType = function(node, direction) {
+  var tagName = node.nodeName;
+  direction += "Sibling";
+  do {
+    node = node[direction];
+    if (node && node.nodeName === tagName) break;
+  } while (node);
+  return node;
+};
+
+var ONE = {"+": 1, "-": -1}, SPACES = / /g;
+
+FILTER = extend(extend({
+  ":nth(-last)?-(?:child|(of-type))\\((<#nth_arg>)\\)(<#filter>)?": function(match, last, ofType, args, filters) { // :nth- pseudo classes
+    args = args.replace(SPACES, "");
+
+    var index = "IE7._indexOf(e," + !!last + "," + !!ofType + ")";
+
+    if (args === "even") args = "2n";
+    else if (args === "odd") args = "2n+1";
+    else if (!isNaN(args)) args = "0n" + ~~args;
+
+    args = args.split("n");
+    var a = ~~(ONE[args[0]] || args[0] || 1),
+        b = ~~args[1];
+    if (a === 0) {
+      var expr = index + "===" + b;
+    } else {
+      expr = "((ii=" + index + ")-(" + b + "))%" + a + "===0&&ii" + (a < 0 ? "<" : ">") + "=" + b;
+    }
+    return this.parse(filters) + expr + "&&";
+  },
+
+  "<#negation>": function(match, simple) {
+    if (/:not/i.test(simple)) throwSelectorError();
+
+    if (/^[#.:\[]/.test(simple)) {
+      simple = "*" + simple;
+    }
+    return "!(" + MATCHER.parse(simple).slice(3, -2) + ")&&";
+  }
+}, FILTER), {
+  ":checked":         "e.checked===true&&",
+  ":disabled":        "e.disabled===true&&",
+  ":enabled":         "e.disabled===false&&",
+  ":last-child":      "!" + NEXT_SIBLING + "&&",
+  ":only-child":      "!" + PREVIOUS_SIBLING + "&&!" + NEXT_SIBLING + "&&",
+  ":first-of-type":   NOT_PREVIOUS_BY_TYPE,
+  ":last-of-type":    NOT_NEXT_BY_TYPE,
+  ":only-of-type":    NOT_PREVIOUS_BY_TYPE + NOT_NEXT_BY_TYPE,
+
+  ":empty":          "IE7._isEmpty(e)&&",
+  ":root":           "e==R&&",
+  ":target":         "H&&" + ID_ATTRIBUTE + "===H&&"
+});
+
+var HTML5 = "article,aside,audio,canvas,details,figcaption,figure,footer,header,hgroup,mark,menu,meter,nav,output,progress,section,summary,time,video".split(",");
+for (var i = 0, tagName; tagName = HTML5[i]; i++) document.createElement(tagName);
+
+HEADER += "datalist{display:none}\
+details{padding-left:40px;display:block;margin:1em 0}\
+meter,progress{vertical-align:-0.2em;width:5em;height:1em;display:inline-block}\
+progress{width:10em;}\
+article,aside,figcaption,footer,header,hgroup,summary,section,nav{display:block;margin:1em 0}\
+figure{margin:1em 40px;display:block}\
+mark{background:yellow}";
+
+// =========================================================================
+// ie9-layout.js
+// =========================================================================
+
+// =========================================================================
+// ie9-graphics.js
+// =========================================================================
+
+IE7.CSS.addFix(/\bopacity\s*:\s*([\d.]+)/, function(match, value) {
+  return "zoom:1;filter:Alpha(opacity=" + ((value * 100) || 1) + ")";
+});
+
+var MATCHER;
+
+var cssQuery = (function() {
+  var CONTEXT = /^[>+~]/;
+  
+  var useContext = false;
+  
+  // This is not a selector engine in the strictest sense. So it's best to silently error.
+  function cssQuery(selector, context, single) {
+    selector = trim(selector);
+    if (!context) context = document;
+    var ref = context;
+    useContext = CONTEXT.test(selector);
+    if (useContext) {
+      context = context.parentNode;
+      selector = "*" + selector;
+    }
+    try {
+      return selectQuery.create(selector, useContext)(context, single ? null : [], ref);
+    } catch (ex) {
+      return single ? null : [];
+    }
+  };
+
+  var VALID_SELECTOR = /^(\\.|[' >+~#.\[\]:*(),\w-\^|$=]|[^\x00-\xa0])+$/;
+
+  var _EVALUATED = /^(href|src)$/;
+  var _ATTRIBUTES = {
+    "class": "className",
+    "for": "htmlFor"
+  };
+
+  var IE7_CLASS_NAMES = /\sie7_\w+/g;
+
+  var USE_IFLAG = /^(action|cite|codebase|data|dynsrc|href|longdesc|lowsrc|src|usemap|url)$/i;
+
+  IE7._getAttribute = function(element, name) {
+    if (element.getAttributeNode) {
+      var attribute = element.getAttributeNode(name);
+    }
+    name = _ATTRIBUTES[name.toLowerCase()] || name;
+    if (!attribute) attribute = element.attributes[name];
+    var specified = attribute && attribute.specified;
+
+    if (element[name] && typeof element[name] == "boolean") return name.toLowerCase();
+    if ((specified && USE_IFLAG.test(name)) || (!attribute && MSIE5) || name === "value" || name === "type") {
+      return element.getAttribute(name, 2);
+    }
+    if (name === "style") return element.style.cssText.toLowerCase() || null;
+
+    return specified ? String(attribute.nodeValue) : null;
+  };
+
+  var names = "colSpan,rowSpan,vAlign,dateTime,accessKey,tabIndex,encType,maxLength,readOnly,longDesc";
+  // Convert the list of strings to a hash, mapping the lowercase name to the camelCase name.
+  extend(_ATTRIBUTES, combine(names.toLowerCase().split(","), names.split(",")));
+
+  IE7._getElementSibling = function(node, direction) {
+    direction += "Sibling";
+    do {
+      node = node[direction];
+      if (node && node.nodeName > "@") break;
+    } while (node);
+    return node;
+  };
+
+  var IMPLIED_ASTERISK    = /(^|[, >+~])([#.:\[])/g,
+      BLOCKS              = /\)\{/g,
+      COMMA               = /,/,
+      QUOTED              = /^['"]/,
+      HEX_ESCAPE          = /\\([\da-f]{2,2})/gi,
+      LAST_CHILD          = /last/i;
+
+  IE7._byId = function(document, id) {
+    var result = document.all[id] || null;
+    // Returns a single element or a collection.
+    if (!result || (result.nodeType && IE7._getAttribute(result, "id") === id)) return result;
+    // document.all has returned a collection of elements with name/id
+    for (var i = 0; i < result.length; i++) {
+      if (IE7._getAttribute(result[i], "id") === id) return result[i];
+    }
+    return null;
+  };
+
+  // =========================================================================
+  // dom/selectors-api/CSSSelectorParser.js
+  // =========================================================================
+
+  // http://www.w3.org/TR/css3-selectors/#w3cselgrammar (kinda)
+  var CSSSelectorParser = RegGrp.extend({
+    dictionary: new Dictionary({
+      ident:           /\-?(\\.|[_a-z]|[^\x00-\xa0])(\\.|[\w-]|[^\x00-\xa0])*/,
+      combinator:      /[\s>+~]/,
+      operator:        /[\^~|$*]?=/,
+      nth_arg:         /[+-]?\d+|[+-]?\d*n(?:\s*[+-]\s*\d+)?|even|odd/,
+      tag:             /\*|<#ident>/,
+      id:              /#(<#ident>)/,
+      'class':         /\.(<#ident>)/,
+      pseudo:          /\:([\w-]+)(?:\(([^)]+)\))?/,
+      attr:            /\[(<#ident>)(?:(<#operator>)((?:\\.|[^\[\]#.:])+))?\]/,
+      negation:        /:not\((<#tag>|<#id>|<#class>|<#attr>|<#pseudo>)\)/,
+      sequence:        /(\\.|[~*]=|\+\d|\+?\d*n\s*\+\s*\d|[^\s>+~,\*])+/,
+      filter:          /[#.:\[]<#sequence>/,
+      selector:        /[^>+~](\\.|[^,])*?/,
+      grammar:         /^(<#selector>)((,<#selector>)*)$/
+    }),
+
+    ignoreCase: true
+  });
+
+  var normalizer = new CSSSelectorParser({
+    "\\\\.|[~*]\\s+=|\\+\\s+\\d": RegGrp.IGNORE,
+    "\\[\\s+": "[",
+    "\\(\\s+": "(",
+    "\\s+\\)": ")",
+    "\\s+\\]": "]",
+    "\\s*([,>+~]|<#operator>)\\s*": "$1",
+    "\\s+$": "",
+    "\\s+": " "
+  });
+
+  function normalize(selector) {
+    selector = normalizer.parse(selector.replace(HEX_ESCAPE, "\\x$1"))
+      .replace(UNESCAPE, "$1")
+      .replace(IMPLIED_ASTERISK, "$1*$2");
+    if (!VALID_SELECTOR.test(selector)) throwSelectorError();
+    return selector;
+  };
+
+  function unescape(query) {
+    // put string values back
+    return query.replace(ESCAPED, unescapeString);
+  };
+
+  function unescapeString(match, index) {
+    return strings[index];
+  };
+
+  var BRACES = /\{/g, BRACES_ESCAPED = /\\{/g;
+
+  function closeBlock(group) {
+    return Array((group.replace(BRACES_ESCAPED, "").match(BRACES) || "").length + 1).join("}");
+  };
+
+  FILTER = new CSSSelectorParser(FILTER);
+
+  var TARGET = /:target/i, ROOT = /:root/i;
+
+  function getConstants(selector) {
+    var constants = "";
+    if (ROOT.test(selector)) constants += ",R=d.documentElement";
+    if (TARGET.test(selector)) constants += ",H=d.location;H=H&&H.hash.replace('#','')";
+    if (constants || selector.indexOf("#") !== -1) {
+      constants = ",t=c.nodeType,d=t===9?c:c.ownerDocument||(c.document||c).parentWindow.document" + constants;
+    }
+    return "var ii" + constants + ";";
+  };
+
+  var COMBINATOR = {
+    " ":   ";while(e!=s&&(e=e.parentNode)&&e.nodeType===1){",
+    ">":   ".parentElement;if(e){",
+    "+":   ";while((e=e.previousSibling)&&!(" + IS_ELEMENT + "))continue;if(e){",
+    "~":   ";while((e=e.previousSibling)){" + IF_ELEMENT
+  };
+
+  var TOKEN = /\be\b/g;
+
+  MATCHER = new CSSSelectorParser({
+    "(?:(<#selector>)(<#combinator>))?(<#tag>)(<#filter>)?$": function(match, before, combinator, tag, filters) {
+      var group = "";
+      if (tag !== "*") {
+        var TAG = tag.toUpperCase();
+        group += "if(e.nodeName==='" + TAG + (TAG === tag ? "" : "'||e.nodeName==='" + tag) + "'){";
+      }
+      if (filters) {
+        group += "if(" + FILTER.parse(filters).slice(0, -2) + "){";
+      }
+      group = group.replace(TOKEN, "e" + this.index);
+      if (combinator) {
+        group += "var e=e" + (this.index++) + COMBINATOR[combinator];
+        group = group.replace(TOKEN, "e" + this.index);
+      }
+      if (before) {
+        group += this.parse(before);
+      }
+      return group;
+    }
+  });
+  
+  var BY_ID       = "e0=IE7._byId(d,'%1');if(e0){",
+      BY_TAG_NAME = "var n=c.getElementsByTagName('%1');",
+      STORE       = "if(r==null)return e0;r[k++]=e0;";
+
+  var TAG_NAME = 1;
+
+  var SELECTOR = new CSSSelectorParser({
+    "^((?:<#selector>)?(?:<#combinator>))(<#tag>)(<#filter>)?$": true
+  });
+
+  var cache = {};
+
+  var selectById = new CSSSelectorParser({
+    "^(<#tag>)#(<#ident>)(<#filter>)?( [^,]*)?$": function(match, tagName, id, filters, after) {
+      var block = format(BY_ID, id), endBlock = "}";
+      if (filters) {
+        block += MATCHER.parse(tagName + filters);
+        endBlock = closeBlock(block);
+      }
+      if (after) {
+        block += "s=c=e0;" + selectQuery.parse("*" + after);
+      } else {
+        block += STORE;
+      }
+      return block + endBlock;
+    },
+
+    "^([^#,]+)#(<#ident>)(<#filter>)?$": function(match, before, id, filters) {
+      var block = format(BY_ID, id);
+      if (before === "*") {
+        block += STORE;
+      } else {
+        block += MATCHER.parse(before + filters) + STORE + "break";
+      }
+      return block + closeBlock(block);
+    },
+
+    "^.*$": ""
+  });
+
+  var selectQuery = new CSSSelectorParser({
+    "<#grammar>": function(match, selector, remainingSelectors) {
+      if (!this.groups) this.groups = [];
+
+      var group = SELECTOR.exec(" " + selector);
+
+      if (!group) throwSelectorError();
+
+      this.groups.push(group.slice(1));
+
+      if (remainingSelectors) {
+        return this.parse(remainingSelectors.replace(COMMA, ""));
+      }
+
+      var groups = this.groups,
+          tagName = groups[0][TAG_NAME]; // first tag name
+
+      for (var i = 1; group = groups[i]; i++) { // search tag names
+        if (tagName !== group[TAG_NAME]) {
+          tagName = "*"; // mixed tag names, so use "*"
+          break;
+        }
+      }
+
+      var matcher = "", store = STORE + "continue filtering;";
+
+      for (var i = 0; group = groups[i]; i++) {
+        MATCHER.index = 0;
+        if (tagName !== "*") group[TAG_NAME] = "*"; // we are already filtering by tagName
+        group = group.join("");
+        if (group === " *") { // select all
+          matcher = store;
+          break;
+        } else {
+          group = MATCHER.parse(group);
+          if (useContext) group += "if(e" + MATCHER.index + "==s){";
+          matcher += group + store + closeBlock(group);
+        }
+      }
+
+      // reduce to a single loop
+      var isWild = tagName === "*";
+      return (isWild ? "var n=c.all;" : format(BY_TAG_NAME, tagName)) +
+        "filtering:while((e0=n[i++]))" +
+        (isWild ? IF_ELEMENT.replace(TOKEN, "e0") : "{") +
+          matcher +
+        "}";
+    },
+
+    "^.*$": throwSelectorError
+  });
+
+  var REDUNDANT_NODETYPE_CHECKS = /\&\&(e\d+)\.nodeType===1(\)\{\s*if\(\1\.nodeName=)/g;
+
+  selectQuery.create = function(selector) {
+    if (!cache[selector]) {
+      selector = normalize(selector);
+      this.groups = null;
+      MATCHER.index = 0;
+      var block = this.parse(selector);
+      this.groups = null;
+      MATCHER.index = 0;
+      if (selector.indexOf("#") !== -1) {
+        var byId  = selectById.parse(selector);
+        if (byId) {
+          block =
+            "if(t===1||t===11|!c.getElementById){" +
+              block +
+            "}else{" +
+              byId +
+            "}";
+        }
+      }
+      // remove redundant nodeType==1 checks
+      block = block.replace(REDUNDANT_NODETYPE_CHECKS, "$2");
+      block = getConstants(selector) + decode(block);
+      cache[selector] = new Function("return function(c,r,s){var i=0,k=0,e0;" + block + "return r}")();
+    }
+    return cache[selector];
+  };
+
+  return cssQuery;
+})();
+
+function throwSelectorError() {
+  throw new SyntaxError("Invalid selector.");
+};
+
+// -----------------------------------------------------------------------
+// initialisation
+// -----------------------------------------------------------------------
+
+IE7.loaded = true;
+
+(function() {
+  try {
+    // http://javascript.nwbox.com/IEContentLoaded/
+    if (!document.body) throw "continue";
+    documentElement.doScroll("left");
+  } catch (ex) {
+    setTimeout(arguments.callee, 1);
+    return;
+  }
+  // execute the inner text of the IE7 script
+  try {
+    eval(script.innerHTML);
+  } catch (ex) {
+    // ignore errors
+  }
+  if (typeof IE7_PNG_SUFFIX == "object") {
+    PNG = IE7_PNG_SUFFIX;
+  } else {
+    PNG = new RegExp(rescape(window.IE7_PNG_SUFFIX || "-trans.png") + "(\\?.*)?$", "i");
+  }
+
+  // frequently used references
+  body = document.body;
+  viewport = MSIE5 ? body : documentElement;
+
+  // classes
+  body.className += " ie7_body";
+  documentElement.className += " ie7_html";
+
+  if (MSIE5) ie7Quirks();
+
+  IE7.CSS.init();
+  IE7.HTML.init();
+
+  IE7.HTML.apply();
+  IE7.CSS.apply();
+
+  IE7.recalc();
+})();
+
+})(this, document);
Index: admin/js/jquery/jquery-ui.custom.js
===================================================================
--- admin/js/jquery/jquery-ui.custom.js	(revision 1048)
+++ admin/js/jquery/jquery-ui.custom.js	(revision 1648)
@@ -1,6 +1,6 @@
-/*! jQuery UI - v1.9.2 - 2012-11-29
+/*! jQuery UI - v1.10.3 - 2013-08-23
 * http://jqueryui.com
-* Includes: jquery.ui.core.js, jquery.ui.widget.js, jquery.ui.mouse.js, jquery.ui.sortable.js, jquery.ui.accordion.js
-* Copyright (c) 2012 jQuery Foundation and other contributors Licensed MIT */
+* Includes: jquery.ui.core.js, jquery.ui.widget.js, jquery.ui.mouse.js, jquery.ui.draggable.js, jquery.ui.sortable.js, jquery.ui.accordion.js
+* Copyright 2013 jQuery Foundation and other contributors Licensed MIT */
 
 (function( $, undefined ) {
@@ -9,14 +9,9 @@
 	runiqueId = /^ui-id-\d+$/;
 
-// prevent duplicate loading
-// this is only a problem because we proxy existing functions
-// and we don't want to double proxy them
+// $.ui might exist from components with no dependencies, e.g., $.ui.position
 $.ui = $.ui || {};
-if ( $.ui.version ) {
-	return;
-}
 
 $.extend( $.ui, {
-	version: "1.9.2",
+	version: "1.10.3",
 
 	keyCode: {
@@ -48,32 +43,33 @@
 // plugins
 $.fn.extend({
-	_focus: $.fn.focus,
-	focus: function( delay, fn ) {
-		return typeof delay === "number" ?
-			this.each(function() {
-				var elem = this;
-				setTimeout(function() {
-					$( elem ).focus();
-					if ( fn ) {
-						fn.call( elem );
-					}
-				}, delay );
-			}) :
-			this._focus.apply( this, arguments );
-	},
+	focus: (function( orig ) {
+		return function( delay, fn ) {
+			return typeof delay === "number" ?
+				this.each(function() {
+					var elem = this;
+					setTimeout(function() {
+						$( elem ).focus();
+						if ( fn ) {
+							fn.call( elem );
+						}
+					}, delay );
+				}) :
+				orig.apply( this, arguments );
+		};
+	})( $.fn.focus ),
 
 	scrollParent: function() {
 		var scrollParent;
-		if (($.ui.ie && (/(static|relative)/).test(this.css('position'))) || (/absolute/).test(this.css('position'))) {
+		if (($.ui.ie && (/(static|relative)/).test(this.css("position"))) || (/absolute/).test(this.css("position"))) {
 			scrollParent = this.parents().filter(function() {
-				return (/(relative|absolute|fixed)/).test($.css(this,'position')) && (/(auto|scroll)/).test($.css(this,'overflow')+$.css(this,'overflow-y')+$.css(this,'overflow-x'));
+				return (/(relative|absolute|fixed)/).test($.css(this,"position")) && (/(auto|scroll)/).test($.css(this,"overflow")+$.css(this,"overflow-y")+$.css(this,"overflow-x"));
 			}).eq(0);
 		} else {
 			scrollParent = this.parents().filter(function() {
-				return (/(auto|scroll)/).test($.css(this,'overflow')+$.css(this,'overflow-y')+$.css(this,'overflow-x'));
+				return (/(auto|scroll)/).test($.css(this,"overflow")+$.css(this,"overflow-y")+$.css(this,"overflow-x"));
 			}).eq(0);
 		}
 
-		return (/fixed/).test(this.css('position')) || !scrollParent.length ? $(document) : scrollParent;
+		return (/fixed/).test(this.css("position")) || !scrollParent.length ? $(document) : scrollParent;
 	},
 
@@ -148,5 +144,5 @@
 function visible( element ) {
 	return $.expr.filters.visible( element ) &&
-		!$( element ).parents().andSelf().filter(function() {
+		!$( element ).parents().addBack().filter(function() {
 			return $.css( this, "visibility" ) === "hidden";
 		}).length;
@@ -176,29 +172,4 @@
 });
 
-// support
-$(function() {
-	var body = document.body,
-		div = body.appendChild( div = document.createElement( "div" ) );
-
-	// access offsetHeight before setting the style to prevent a layout bug
-	// in IE 9 which causes the element to continue to take up space even
-	// after it is removed from the DOM (#8026)
-	div.offsetHeight;
-
-	$.extend( div.style, {
-		minHeight: "100px",
-		height: "auto",
-		padding: 0,
-		borderWidth: 0
-	});
-
-	$.support.minHeight = div.offsetHeight === 100;
-	$.support.selectstart = "onselectstart" in div;
-
-	// set display to none to avoid a layout bug in IE
-	// http://dev.jquery.com/ticket/4014
-	body.removeChild( div ).style.display = "none";
-});
-
 // support: jQuery <1.8
 if ( !$( "<a>" ).outerWidth( 1 ).jquery ) {
@@ -248,4 +219,13 @@
 }
 
+// support: jQuery <1.8
+if ( !$.fn.addBack ) {
+	$.fn.addBack = function( selector ) {
+		return this.add( selector == null ?
+			this.prevObject : this.prevObject.filter( selector )
+		);
+	};
+}
+
 // support: jQuery 1.6.1, 1.6.2 (http://bugs.jquery.com/ticket/9413)
 if ( $( "<a>" ).data( "a-b", "a" ).removeData( "a-b" ).data( "a-b" ) ) {
@@ -266,11 +246,7 @@
 
 // deprecated
-
-(function() {
-	var uaMatch = /msie ([\w.]+)/.exec( navigator.userAgent.toLowerCase() ) || [];
-	$.ui.ie = uaMatch.length ? true : false;
-	$.ui.ie6 = parseFloat( uaMatch[ 1 ], 10 ) === 6;
-})();
-
+$.ui.ie = !!/msie [\w.]+/.exec( navigator.userAgent.toLowerCase() );
+
+$.support.selectstart = "onselectstart" in document.createElement( "div" );
 $.fn.extend({
 	disableSelection: function() {
@@ -287,5 +263,5 @@
 
 $.extend( $.ui, {
-	// $.ui.plugin is deprecated.  Use the proxy pattern instead.
+	// $.ui.plugin is deprecated. Use $.widget() extensions instead.
 	plugin: {
 		add: function( module, option, set ) {
@@ -312,6 +288,4 @@
 	},
 
-	contains: $.contains,
-
 	// only used by resizable
 	hasScroll: function( el, a ) {
@@ -336,14 +310,4 @@
 		el[ scroll ] = 0;
 		return has;
-	},
-
-	// these are odd functions, fix the API or move into individual plugins
-	isOverAxis: function( x, reference, size ) {
-		//Determines when x coordinate is over "b" element axis
-		return ( x > reference ) && ( x < ( reference + size ) );
-	},
-	isOver: function( y, x, top, left, height, width ) {
-		//Determines when x, y coordinates is over "b" element
-		return $.ui.isOverAxis( y, top, height ) && $.ui.isOverAxis( x, left, width );
 	}
 });
@@ -367,4 +331,7 @@
 $.widget = function( name, base, prototype ) {
 	var fullName, existingConstructor, constructor, basePrototype,
+		// proxiedPrototype allows the provided prototype to remain unmodified
+		// so that it can be used as a mixin for multiple widgets (#8876)
+		proxiedPrototype = {},
 		namespace = name.split( "." )[ 0 ];
 
@@ -413,29 +380,31 @@
 	basePrototype.options = $.widget.extend( {}, basePrototype.options );
 	$.each( prototype, function( prop, value ) {
-		if ( $.isFunction( value ) ) {
-			prototype[ prop ] = (function() {
-				var _super = function() {
-						return base.prototype[ prop ].apply( this, arguments );
-					},
-					_superApply = function( args ) {
-						return base.prototype[ prop ].apply( this, args );
-					};
-				return function() {
-					var __super = this._super,
-						__superApply = this._superApply,
-						returnValue;
-
-					this._super = _super;
-					this._superApply = _superApply;
-
-					returnValue = value.apply( this, arguments );
-
-					this._super = __super;
-					this._superApply = __superApply;
-
-					return returnValue;
+		if ( !$.isFunction( value ) ) {
+			proxiedPrototype[ prop ] = value;
+			return;
+		}
+		proxiedPrototype[ prop ] = (function() {
+			var _super = function() {
+					return base.prototype[ prop ].apply( this, arguments );
+				},
+				_superApply = function( args ) {
+					return base.prototype[ prop ].apply( this, args );
 				};
-			})();
-		}
+			return function() {
+				var __super = this._super,
+					__superApply = this._superApply,
+					returnValue;
+
+				this._super = _super;
+				this._superApply = _superApply;
+
+				returnValue = value.apply( this, arguments );
+
+				this._super = __super;
+				this._superApply = __superApply;
+
+				return returnValue;
+			};
+		})();
 	});
 	constructor.prototype = $.widget.extend( basePrototype, {
@@ -444,10 +413,8 @@
 		// don't prefix for widgets that aren't DOM-based
 		widgetEventPrefix: existingConstructor ? basePrototype.widgetEventPrefix : name
-	}, prototype, {
+	}, proxiedPrototype, {
 		constructor: constructor,
 		namespace: namespace,
 		widgetName: name,
-		// TODO remove widgetBaseClass, see #8155
-		widgetBaseClass: fullName,
 		widgetFullName: fullName
 	});
@@ -575,7 +542,4 @@
 
 		if ( element !== this ) {
-			// 1.9 BC for #7810
-			// TODO remove dual storage
-			$.data( element, this.widgetName, this );
 			$.data( element, this.widgetFullName, this );
 			this._on( true, this.element, {
@@ -844,5 +808,5 @@
 			element.delay( options.delay );
 		}
-		if ( hasOptions && $.effects && ( $.effects.effect[ effectName ] || $.uiBackCompat !== false && $.effects[ effectName ] ) ) {
+		if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) {
 			element[ method ]( options );
 		} else if ( effectName !== method && element[ effectName ] ) {
@@ -860,23 +824,16 @@
 });
 
-// DEPRECATED
-if ( $.uiBackCompat !== false ) {
-	$.Widget.prototype._getCreateOptions = function() {
-		return $.metadata && $.metadata.get( this.element[0] )[ this.widgetName ];
-	};
-}
-
 })( jQuery );
 (function( $, undefined ) {
 
 var mouseHandled = false;
-$( document ).mouseup( function( e ) {
+$( document ).mouseup( function() {
 	mouseHandled = false;
 });
 
 $.widget("ui.mouse", {
-	version: "1.9.2",
+	version: "1.10.3",
 	options: {
-		cancel: 'input,textarea,button,select,option',
+		cancel: "input,textarea,button,select,option",
 		distance: 1,
 		delay: 0
@@ -886,10 +843,10 @@
 
 		this.element
-			.bind('mousedown.'+this.widgetName, function(event) {
+			.bind("mousedown."+this.widgetName, function(event) {
 				return that._mouseDown(event);
 			})
-			.bind('click.'+this.widgetName, function(event) {
-				if (true === $.data(event.target, that.widgetName + '.preventClickEvent')) {
-					$.removeData(event.target, that.widgetName + '.preventClickEvent');
+			.bind("click."+this.widgetName, function(event) {
+				if (true === $.data(event.target, that.widgetName + ".preventClickEvent")) {
+					$.removeData(event.target, that.widgetName + ".preventClickEvent");
 					event.stopImmediatePropagation();
 					return false;
@@ -903,9 +860,9 @@
 	// other instances of mouse
 	_mouseDestroy: function() {
-		this.element.unbind('.'+this.widgetName);
+		this.element.unbind("."+this.widgetName);
 		if ( this._mouseMoveDelegate ) {
 			$(document)
-				.unbind('mousemove.'+this.widgetName, this._mouseMoveDelegate)
-				.unbind('mouseup.'+this.widgetName, this._mouseUpDelegate);
+				.unbind("mousemove."+this.widgetName, this._mouseMoveDelegate)
+				.unbind("mouseup."+this.widgetName, this._mouseUpDelegate);
 		}
 	},
@@ -945,6 +902,6 @@
 
 		// Click event may never have fired (Gecko & Opera)
-		if (true === $.data(event.target, this.widgetName + '.preventClickEvent')) {
-			$.removeData(event.target, this.widgetName + '.preventClickEvent');
+		if (true === $.data(event.target, this.widgetName + ".preventClickEvent")) {
+			$.removeData(event.target, this.widgetName + ".preventClickEvent");
 		}
 
@@ -957,6 +914,6 @@
 		};
 		$(document)
-			.bind('mousemove.'+this.widgetName, this._mouseMoveDelegate)
-			.bind('mouseup.'+this.widgetName, this._mouseUpDelegate);
+			.bind("mousemove."+this.widgetName, this._mouseMoveDelegate)
+			.bind("mouseup."+this.widgetName, this._mouseUpDelegate);
 
 		event.preventDefault();
@@ -968,5 +925,5 @@
 	_mouseMove: function(event) {
 		// IE mouseup check - mouseup happened when mouse was out of window
-		if ($.ui.ie && !(document.documentMode >= 9) && !event.button) {
+		if ($.ui.ie && ( !document.documentMode || document.documentMode < 9 ) && !event.button) {
 			return this._mouseUp(event);
 		}
@@ -988,6 +945,6 @@
 	_mouseUp: function(event) {
 		$(document)
-			.unbind('mousemove.'+this.widgetName, this._mouseMoveDelegate)
-			.unbind('mouseup.'+this.widgetName, this._mouseUpDelegate);
+			.unbind("mousemove."+this.widgetName, this._mouseMoveDelegate)
+			.unbind("mouseup."+this.widgetName, this._mouseUpDelegate);
 
 		if (this._mouseStarted) {
@@ -995,5 +952,5 @@
 
 			if (event.target === this._mouseDownEvent.target) {
-				$.data(event.target, this.widgetName + '.preventClickEvent', true);
+				$.data(event.target, this.widgetName + ".preventClickEvent", true);
 			}
 
@@ -1012,13 +969,13 @@
 	},
 
-	_mouseDelayMet: function(event) {
+	_mouseDelayMet: function(/* event */) {
 		return this.mouseDelayMet;
 	},
 
 	// These are placeholder methods, to be overriden by extending plugin
-	_mouseStart: function(event) {},
-	_mouseDrag: function(event) {},
-	_mouseStop: function(event) {},
-	_mouseCapture: function(event) { return true; }
+	_mouseStart: function(/* event */) {},
+	_mouseDrag: function(/* event */) {},
+	_mouseStop: function(/* event */) {},
+	_mouseCapture: function(/* event */) { return true; }
 });
 
@@ -1026,6 +983,959 @@
 (function( $, undefined ) {
 
+$.widget("ui.draggable", $.ui.mouse, {
+	version: "1.10.3",
+	widgetEventPrefix: "drag",
+	options: {
+		addClasses: true,
+		appendTo: "parent",
+		axis: false,
+		connectToSortable: false,
+		containment: false,
+		cursor: "auto",
+		cursorAt: false,
+		grid: false,
+		handle: false,
+		helper: "original",
+		iframeFix: false,
+		opacity: false,
+		refreshPositions: false,
+		revert: false,
+		revertDuration: 500,
+		scope: "default",
+		scroll: true,
+		scrollSensitivity: 20,
+		scrollSpeed: 20,
+		snap: false,
+		snapMode: "both",
+		snapTolerance: 20,
+		stack: false,
+		zIndex: false,
+
+		// callbacks
+		drag: null,
+		start: null,
+		stop: null
+	},
+	_create: function() {
+
+		if (this.options.helper === "original" && !(/^(?:r|a|f)/).test(this.element.css("position"))) {
+			this.element[0].style.position = "relative";
+		}
+		if (this.options.addClasses){
+			this.element.addClass("ui-draggable");
+		}
+		if (this.options.disabled){
+			this.element.addClass("ui-draggable-disabled");
+		}
+
+		this._mouseInit();
+
+	},
+
+	_destroy: function() {
+		this.element.removeClass( "ui-draggable ui-draggable-dragging ui-draggable-disabled" );
+		this._mouseDestroy();
+	},
+
+	_mouseCapture: function(event) {
+
+		var o = this.options;
+
+		// among others, prevent a drag on a resizable-handle
+		if (this.helper || o.disabled || $(event.target).closest(".ui-resizable-handle").length > 0) {
+			return false;
+		}
+
+		//Quit if we're not on a valid handle
+		this.handle = this._getHandle(event);
+		if (!this.handle) {
+			return false;
+		}
+
+		$(o.iframeFix === true ? "iframe" : o.iframeFix).each(function() {
+			$("<div class='ui-draggable-iframeFix' style='background: #fff;'></div>")
+			.css({
+				width: this.offsetWidth+"px", height: this.offsetHeight+"px",
+				position: "absolute", opacity: "0.001", zIndex: 1000
+			})
+			.css($(this).offset())
+			.appendTo("body");
+		});
+
+		return true;
+
+	},
+
+	_mouseStart: function(event) {
+
+		var o = this.options;
+
+		//Create and append the visible helper
+		this.helper = this._createHelper(event);
+
+		this.helper.addClass("ui-draggable-dragging");
+
+		//Cache the helper size
+		this._cacheHelperProportions();
+
+		//If ddmanager is used for droppables, set the global draggable
+		if($.ui.ddmanager) {
+			$.ui.ddmanager.current = this;
+		}
+
+		/*
+		 * - Position generation -
+		 * This block generates everything position related - it's the core of draggables.
+		 */
+
+		//Cache the margins of the original element
+		this._cacheMargins();
+
+		//Store the helper's css position
+		this.cssPosition = this.helper.css( "position" );
+		this.scrollParent = this.helper.scrollParent();
+		this.offsetParent = this.helper.offsetParent();
+		this.offsetParentCssPosition = this.offsetParent.css( "position" );
+
+		//The element's absolute position on the page minus margins
+		this.offset = this.positionAbs = this.element.offset();
+		this.offset = {
+			top: this.offset.top - this.margins.top,
+			left: this.offset.left - this.margins.left
+		};
+
+		//Reset scroll cache
+		this.offset.scroll = false;
+
+		$.extend(this.offset, {
+			click: { //Where the click happened, relative to the element
+				left: event.pageX - this.offset.left,
+				top: event.pageY - this.offset.top
+			},
+			parent: this._getParentOffset(),
+			relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper
+		});
+
+		//Generate the original position
+		this.originalPosition = this.position = this._generatePosition(event);
+		this.originalPageX = event.pageX;
+		this.originalPageY = event.pageY;
+
+		//Adjust the mouse offset relative to the helper if "cursorAt" is supplied
+		(o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt));
+
+		//Set a containment if given in the options
+		this._setContainment();
+
+		//Trigger event + callbacks
+		if(this._trigger("start", event) === false) {
+			this._clear();
+			return false;
+		}
+
+		//Recache the helper size
+		this._cacheHelperProportions();
+
+		//Prepare the droppable offsets
+		if ($.ui.ddmanager && !o.dropBehaviour) {
+			$.ui.ddmanager.prepareOffsets(this, event);
+		}
+
+
+		this._mouseDrag(event, true); //Execute the drag once - this causes the helper not to be visible before getting its correct position
+
+		//If the ddmanager is used for droppables, inform the manager that dragging has started (see #5003)
+		if ( $.ui.ddmanager ) {
+			$.ui.ddmanager.dragStart(this, event);
+		}
+
+		return true;
+	},
+
+	_mouseDrag: function(event, noPropagation) {
+		// reset any necessary cached properties (see #5009)
+		if ( this.offsetParentCssPosition === "fixed" ) {
+			this.offset.parent = this._getParentOffset();
+		}
+
+		//Compute the helpers position
+		this.position = this._generatePosition(event);
+		this.positionAbs = this._convertPositionTo("absolute");
+
+		//Call plugins and callbacks and use the resulting position if something is returned
+		if (!noPropagation) {
+			var ui = this._uiHash();
+			if(this._trigger("drag", event, ui) === false) {
+				this._mouseUp({});
+				return false;
+			}
+			this.position = ui.position;
+		}
+
+		if(!this.options.axis || this.options.axis !== "y") {
+			this.helper[0].style.left = this.position.left+"px";
+		}
+		if(!this.options.axis || this.options.axis !== "x") {
+			this.helper[0].style.top = this.position.top+"px";
+		}
+		if($.ui.ddmanager) {
+			$.ui.ddmanager.drag(this, event);
+		}
+
+		return false;
+	},
+
+	_mouseStop: function(event) {
+
+		//If we are using droppables, inform the manager about the drop
+		var that = this,
+			dropped = false;
+		if ($.ui.ddmanager && !this.options.dropBehaviour) {
+			dropped = $.ui.ddmanager.drop(this, event);
+		}
+
+		//if a drop comes from outside (a sortable)
+		if(this.dropped) {
+			dropped = this.dropped;
+			this.dropped = false;
+		}
+
+		//if the original element is no longer in the DOM don't bother to continue (see #8269)
+		if ( this.options.helper === "original" && !$.contains( this.element[ 0 ].ownerDocument, this.element[ 0 ] ) ) {
+			return false;
+		}
+
+		if((this.options.revert === "invalid" && !dropped) || (this.options.revert === "valid" && dropped) || this.options.revert === true || ($.isFunction(this.options.revert) && this.options.revert.call(this.element, dropped))) {
+			$(this.helper).animate(this.originalPosition, parseInt(this.options.revertDuration, 10), function() {
+				if(that._trigger("stop", event) !== false) {
+					that._clear();
+				}
+			});
+		} else {
+			if(this._trigger("stop", event) !== false) {
+				this._clear();
+			}
+		}
+
+		return false;
+	},
+
+	_mouseUp: function(event) {
+		//Remove frame helpers
+		$("div.ui-draggable-iframeFix").each(function() {
+			this.parentNode.removeChild(this);
+		});
+
+		//If the ddmanager is used for droppables, inform the manager that dragging has stopped (see #5003)
+		if( $.ui.ddmanager ) {
+			$.ui.ddmanager.dragStop(this, event);
+		}
+
+		return $.ui.mouse.prototype._mouseUp.call(this, event);
+	},
+
+	cancel: function() {
+
+		if(this.helper.is(".ui-draggable-dragging")) {
+			this._mouseUp({});
+		} else {
+			this._clear();
+		}
+
+		return this;
+
+	},
+
+	_getHandle: function(event) {
+		return this.options.handle ?
+			!!$( event.target ).closest( this.element.find( this.options.handle ) ).length :
+			true;
+	},
+
+	_createHelper: function(event) {
+
+		var o = this.options,
+			helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event])) : (o.helper === "clone" ? this.element.clone().removeAttr("id") : this.element);
+
+		if(!helper.parents("body").length) {
+			helper.appendTo((o.appendTo === "parent" ? this.element[0].parentNode : o.appendTo));
+		}
+
+		if(helper[0] !== this.element[0] && !(/(fixed|absolute)/).test(helper.css("position"))) {
+			helper.css("position", "absolute");
+		}
+
+		return helper;
+
+	},
+
+	_adjustOffsetFromHelper: function(obj) {
+		if (typeof obj === "string") {
+			obj = obj.split(" ");
+		}
+		if ($.isArray(obj)) {
+			obj = {left: +obj[0], top: +obj[1] || 0};
+		}
+		if ("left" in obj) {
+			this.offset.click.left = obj.left + this.margins.left;
+		}
+		if ("right" in obj) {
+			this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
+		}
+		if ("top" in obj) {
+			this.offset.click.top = obj.top + this.margins.top;
+		}
+		if ("bottom" in obj) {
+			this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
+		}
+	},
+
+	_getParentOffset: function() {
+
+		//Get the offsetParent and cache its position
+		var po = this.offsetParent.offset();
+
+		// This is a special case where we need to modify a offset calculated on start, since the following happened:
+		// 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent
+		// 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that
+		//    the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag
+		if(this.cssPosition === "absolute" && this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) {
+			po.left += this.scrollParent.scrollLeft();
+			po.top += this.scrollParent.scrollTop();
+		}
+
+		//This needs to be actually done for all browsers, since pageX/pageY includes this information
+		//Ugly IE fix
+		if((this.offsetParent[0] === document.body) ||
+			(this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() === "html" && $.ui.ie)) {
+			po = { top: 0, left: 0 };
+		}
+
+		return {
+			top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0),
+			left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0)
+		};
+
+	},
+
+	_getRelativeOffset: function() {
+
+		if(this.cssPosition === "relative") {
+			var p = this.element.position();
+			return {
+				top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(),
+				left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft()
+			};
+		} else {
+			return { top: 0, left: 0 };
+		}
+
+	},
+
+	_cacheMargins: function() {
+		this.margins = {
+			left: (parseInt(this.element.css("marginLeft"),10) || 0),
+			top: (parseInt(this.element.css("marginTop"),10) || 0),
+			right: (parseInt(this.element.css("marginRight"),10) || 0),
+			bottom: (parseInt(this.element.css("marginBottom"),10) || 0)
+		};
+	},
+
+	_cacheHelperProportions: function() {
+		this.helperProportions = {
+			width: this.helper.outerWidth(),
+			height: this.helper.outerHeight()
+		};
+	},
+
+	_setContainment: function() {
+
+		var over, c, ce,
+			o = this.options;
+
+		if ( !o.containment ) {
+			this.containment = null;
+			return;
+		}
+
+		if ( o.containment === "window" ) {
+			this.containment = [
+				$( window ).scrollLeft() - this.offset.relative.left - this.offset.parent.left,
+				$( window ).scrollTop() - this.offset.relative.top - this.offset.parent.top,
+				$( window ).scrollLeft() + $( window ).width() - this.helperProportions.width - this.margins.left,
+				$( window ).scrollTop() + ( $( window ).height() || document.body.parentNode.scrollHeight ) - this.helperProportions.height - this.margins.top
+			];
+			return;
+		}
+
+		if ( o.containment === "document") {
+			this.containment = [
+				0,
+				0,
+				$( document ).width() - this.helperProportions.width - this.margins.left,
+				( $( document ).height() || document.body.parentNode.scrollHeight ) - this.helperProportions.height - this.margins.top
+			];
+			return;
+		}
+
+		if ( o.containment.constructor === Array ) {
+			this.containment = o.containment;
+			return;
+		}
+
+		if ( o.containment === "parent" ) {
+			o.containment = this.helper[ 0 ].parentNode;
+		}
+
+		c = $( o.containment );
+		ce = c[ 0 ];
+
+		if( !ce ) {
+			return;
+		}
+
+		over = c.css( "overflow" ) !== "hidden";
+
+		this.containment = [
+			( parseInt( c.css( "borderLeftWidth" ), 10 ) || 0 ) + ( parseInt( c.css( "paddingLeft" ), 10 ) || 0 ),
+			( parseInt( c.css( "borderTopWidth" ), 10 ) || 0 ) + ( parseInt( c.css( "paddingTop" ), 10 ) || 0 ) ,
+			( over ? Math.max( ce.scrollWidth, ce.offsetWidth ) : ce.offsetWidth ) - ( parseInt( c.css( "borderRightWidth" ), 10 ) || 0 ) - ( parseInt( c.css( "paddingRight" ), 10 ) || 0 ) - this.helperProportions.width - this.margins.left - this.margins.right,
+			( over ? Math.max( ce.scrollHeight, ce.offsetHeight ) : ce.offsetHeight ) - ( parseInt( c.css( "borderBottomWidth" ), 10 ) || 0 ) - ( parseInt( c.css( "paddingBottom" ), 10 ) || 0 ) - this.helperProportions.height - this.margins.top  - this.margins.bottom
+		];
+		this.relative_container = c;
+	},
+
+	_convertPositionTo: function(d, pos) {
+
+		if(!pos) {
+			pos = this.position;
+		}
+
+		var mod = d === "absolute" ? 1 : -1,
+			scroll = this.cssPosition === "absolute" && !( this.scrollParent[ 0 ] !== document && $.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) ? this.offsetParent : this.scrollParent;
+
+		//Cache the scroll
+		if (!this.offset.scroll) {
+			this.offset.scroll = {top : scroll.scrollTop(), left : scroll.scrollLeft()};
+		}
+
+		return {
+			top: (
+				pos.top	+																// The absolute mouse position
+				this.offset.relative.top * mod +										// Only for relative positioned nodes: Relative offset from element to offset parent
+				this.offset.parent.top * mod -										// The offsetParent's offset without borders (offset + border)
+				( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : this.offset.scroll.top ) * mod )
+			),
+			left: (
+				pos.left +																// The absolute mouse position
+				this.offset.relative.left * mod +										// Only for relative positioned nodes: Relative offset from element to offset parent
+				this.offset.parent.left * mod	-										// The offsetParent's offset without borders (offset + border)
+				( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : this.offset.scroll.left ) * mod )
+			)
+		};
+
+	},
+
+	_generatePosition: function(event) {
+
+		var containment, co, top, left,
+			o = this.options,
+			scroll = this.cssPosition === "absolute" && !( this.scrollParent[ 0 ] !== document && $.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) ? this.offsetParent : this.scrollParent,
+			pageX = event.pageX,
+			pageY = event.pageY;
+
+		//Cache the scroll
+		if (!this.offset.scroll) {
+			this.offset.scroll = {top : scroll.scrollTop(), left : scroll.scrollLeft()};
+		}
+
+		/*
+		 * - Position constraining -
+		 * Constrain the position to a mix of grid, containment.
+		 */
+
+		// If we are not dragging yet, we won't check for options
+		if ( this.originalPosition ) {
+			if ( this.containment ) {
+				if ( this.relative_container ){
+					co = this.relative_container.offset();
+					containment = [
+						this.containment[ 0 ] + co.left,
+						this.containment[ 1 ] + co.top,
+						this.containment[ 2 ] + co.left,
+						this.containment[ 3 ] + co.top
+					];
+				}
+				else {
+					containment = this.containment;
+				}
+
+				if(event.pageX - this.offset.click.left < containment[0]) {
+					pageX = containment[0] + this.offset.click.left;
+				}
+				if(event.pageY - this.offset.click.top < containment[1]) {
+					pageY = containment[1] + this.offset.click.top;
+				}
+				if(event.pageX - this.offset.click.left > containment[2]) {
+					pageX = containment[2] + this.offset.click.left;
+				}
+				if(event.pageY - this.offset.click.top > containment[3]) {
+					pageY = containment[3] + this.offset.click.top;
+				}
+			}
+
+			if(o.grid) {
+				//Check for grid elements set to 0 to prevent divide by 0 error causing invalid argument errors in IE (see ticket #6950)
+				top = o.grid[1] ? this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1] : this.originalPageY;
+				pageY = containment ? ((top - this.offset.click.top >= containment[1] || top - this.offset.click.top > containment[3]) ? top : ((top - this.offset.click.top >= containment[1]) ? top - o.grid[1] : top + o.grid[1])) : top;
+
+				left = o.grid[0] ? this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0] : this.originalPageX;
+				pageX = containment ? ((left - this.offset.click.left >= containment[0] || left - this.offset.click.left > containment[2]) ? left : ((left - this.offset.click.left >= containment[0]) ? left - o.grid[0] : left + o.grid[0])) : left;
+			}
+
+		}
+
+		return {
+			top: (
+				pageY -																	// The absolute mouse position
+				this.offset.click.top	-												// Click offset (relative to the element)
+				this.offset.relative.top -												// Only for relative positioned nodes: Relative offset from element to offset parent
+				this.offset.parent.top +												// The offsetParent's offset without borders (offset + border)
+				( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : this.offset.scroll.top )
+			),
+			left: (
+				pageX -																	// The absolute mouse position
+				this.offset.click.left -												// Click offset (relative to the element)
+				this.offset.relative.left -												// Only for relative positioned nodes: Relative offset from element to offset parent
+				this.offset.parent.left +												// The offsetParent's offset without borders (offset + border)
+				( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : this.offset.scroll.left )
+			)
+		};
+
+	},
+
+	_clear: function() {
+		this.helper.removeClass("ui-draggable-dragging");
+		if(this.helper[0] !== this.element[0] && !this.cancelHelperRemoval) {
+			this.helper.remove();
+		}
+		this.helper = null;
+		this.cancelHelperRemoval = false;
+	},
+
+	// From now on bulk stuff - mainly helpers
+
+	_trigger: function(type, event, ui) {
+		ui = ui || this._uiHash();
+		$.ui.plugin.call(this, type, [event, ui]);
+		//The absolute position has to be recalculated after plugins
+		if(type === "drag") {
+			this.positionAbs = this._convertPositionTo("absolute");
+		}
+		return $.Widget.prototype._trigger.call(this, type, event, ui);
+	},
+
+	plugins: {},
+
+	_uiHash: function() {
+		return {
+			helper: this.helper,
+			position: this.position,
+			originalPosition: this.originalPosition,
+			offset: this.positionAbs
+		};
+	}
+
+});
+
+$.ui.plugin.add("draggable", "connectToSortable", {
+	start: function(event, ui) {
+
+		var inst = $(this).data("ui-draggable"), o = inst.options,
+			uiSortable = $.extend({}, ui, { item: inst.element });
+		inst.sortables = [];
+		$(o.connectToSortable).each(function() {
+			var sortable = $.data(this, "ui-sortable");
+			if (sortable && !sortable.options.disabled) {
+				inst.sortables.push({
+					instance: sortable,
+					shouldRevert: sortable.options.revert
+				});
+				sortable.refreshPositions();	// Call the sortable's refreshPositions at drag start to refresh the containerCache since the sortable container cache is used in drag and needs to be up to date (this will ensure it's initialised as well as being kept in step with any changes that might have happened on the page).
+				sortable._trigger("activate", event, uiSortable);
+			}
+		});
+
+	},
+	stop: function(event, ui) {
+
+		//If we are still over the sortable, we fake the stop event of the sortable, but also remove helper
+		var inst = $(this).data("ui-draggable"),
+			uiSortable = $.extend({}, ui, { item: inst.element });
+
+		$.each(inst.sortables, function() {
+			if(this.instance.isOver) {
+
+				this.instance.isOver = 0;
+
+				inst.cancelHelperRemoval = true; //Don't remove the helper in the draggable instance
+				this.instance.cancelHelperRemoval = false; //Remove it in the sortable instance (so sortable plugins like revert still work)
+
+				//The sortable revert is supported, and we have to set a temporary dropped variable on the draggable to support revert: "valid/invalid"
+				if(this.shouldRevert) {
+					this.instance.options.revert = this.shouldRevert;
+				}
+
+				//Trigger the stop of the sortable
+				this.instance._mouseStop(event);
+
+				this.instance.options.helper = this.instance.options._helper;
+
+				//If the helper has been the original item, restore properties in the sortable
+				if(inst.options.helper === "original") {
+					this.instance.currentItem.css({ top: "auto", left: "auto" });
+				}
+
+			} else {
+				this.instance.cancelHelperRemoval = false; //Remove the helper in the sortable instance
+				this.instance._trigger("deactivate", event, uiSortable);
+			}
+
+		});
+
+	},
+	drag: function(event, ui) {
+
+		var inst = $(this).data("ui-draggable"), that = this;
+
+		$.each(inst.sortables, function() {
+
+			var innermostIntersecting = false,
+				thisSortable = this;
+
+			//Copy over some variables to allow calling the sortable's native _intersectsWith
+			this.instance.positionAbs = inst.positionAbs;
+			this.instance.helperProportions = inst.helperProportions;
+			this.instance.offset.click = inst.offset.click;
+
+			if(this.instance._intersectsWith(this.instance.containerCache)) {
+				innermostIntersecting = true;
+				$.each(inst.sortables, function () {
+					this.instance.positionAbs = inst.positionAbs;
+					this.instance.helperProportions = inst.helperProportions;
+					this.instance.offset.click = inst.offset.click;
+					if (this !== thisSortable &&
+						this.instance._intersectsWith(this.instance.containerCache) &&
+						$.contains(thisSortable.instance.element[0], this.instance.element[0])
+					) {
+						innermostIntersecting = false;
+					}
+					return innermostIntersecting;
+				});
+			}
+
+
+			if(innermostIntersecting) {
+				//If it intersects, we use a little isOver variable and set it once, so our move-in stuff gets fired only once
+				if(!this.instance.isOver) {
+
+					this.instance.isOver = 1;
+					//Now we fake the start of dragging for the sortable instance,
+					//by cloning the list group item, appending it to the sortable and using it as inst.currentItem
+					//We can then fire the start event of the sortable with our passed browser event, and our own helper (so it doesn't create a new one)
+					this.instance.currentItem = $(that).clone().removeAttr("id").appendTo(this.instance.element).data("ui-sortable-item", true);
+					this.instance.options._helper = this.instance.options.helper; //Store helper option to later restore it
+					this.instance.options.helper = function() { return ui.helper[0]; };
+
+					event.target = this.instance.currentItem[0];
+					this.instance._mouseCapture(event, true);
+					this.instance._mouseStart(event, true, true);
+
+					//Because the browser event is way off the new appended portlet, we modify a couple of variables to reflect the changes
+					this.instance.offset.click.top = inst.offset.click.top;
+					this.instance.offset.click.left = inst.offset.click.left;
+					this.instance.offset.parent.left -= inst.offset.parent.left - this.instance.offset.parent.left;
+					this.instance.offset.parent.top -= inst.offset.parent.top - this.instance.offset.parent.top;
+
+					inst._trigger("toSortable", event);
+					inst.dropped = this.instance.element; //draggable revert needs that
+					//hack so receive/update callbacks work (mostly)
+					inst.currentItem = inst.element;
+					this.instance.fromOutside = inst;
+
+				}
+
+				//Provided we did all the previous steps, we can fire the drag event of the sortable on every draggable drag, when it intersects with the sortable
+				if(this.instance.currentItem) {
+					this.instance._mouseDrag(event);
+				}
+
+			} else {
+
+				//If it doesn't intersect with the sortable, and it intersected before,
+				//we fake the drag stop of the sortable, but make sure it doesn't remove the helper by using cancelHelperRemoval
+				if(this.instance.isOver) {
+
+					this.instance.isOver = 0;
+					this.instance.cancelHelperRemoval = true;
+
+					//Prevent reverting on this forced stop
+					this.instance.options.revert = false;
+
+					// The out event needs to be triggered independently
+					this.instance._trigger("out", event, this.instance._uiHash(this.instance));
+
+					this.instance._mouseStop(event, true);
+					this.instance.options.helper = this.instance.options._helper;
+
+					//Now we remove our currentItem, the list group clone again, and the placeholder, and animate the helper back to it's original size
+					this.instance.currentItem.remove();
+					if(this.instance.placeholder) {
+						this.instance.placeholder.remove();
+					}
+
+					inst._trigger("fromSortable", event);
+					inst.dropped = false; //draggable revert needs that
+				}
+
+			}
+
+		});
+
+	}
+});
+
+$.ui.plugin.add("draggable", "cursor", {
+	start: function() {
+		var t = $("body"), o = $(this).data("ui-draggable").options;
+		if (t.css("cursor")) {
+			o._cursor = t.css("cursor");
+		}
+		t.css("cursor", o.cursor);
+	},
+	stop: function() {
+		var o = $(this).data("ui-draggable").options;
+		if (o._cursor) {
+			$("body").css("cursor", o._cursor);
+		}
+	}
+});
+
+$.ui.plugin.add("draggable", "opacity", {
+	start: function(event, ui) {
+		var t = $(ui.helper), o = $(this).data("ui-draggable").options;
+		if(t.css("opacity")) {
+			o._opacity = t.css("opacity");
+		}
+		t.css("opacity", o.opacity);
+	},
+	stop: function(event, ui) {
+		var o = $(this).data("ui-draggable").options;
+		if(o._opacity) {
+			$(ui.helper).css("opacity", o._opacity);
+		}
+	}
+});
+
+$.ui.plugin.add("draggable", "scroll", {
+	start: function() {
+		var i = $(this).data("ui-draggable");
+		if(i.scrollParent[0] !== document && i.scrollParent[0].tagName !== "HTML") {
+			i.overflowOffset = i.scrollParent.offset();
+		}
+	},
+	drag: function( event ) {
+
+		var i = $(this).data("ui-draggable"), o = i.options, scrolled = false;
+
+		if(i.scrollParent[0] !== document && i.scrollParent[0].tagName !== "HTML") {
+
+			if(!o.axis || o.axis !== "x") {
+				if((i.overflowOffset.top + i.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity) {
+					i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop + o.scrollSpeed;
+				} else if(event.pageY - i.overflowOffset.top < o.scrollSensitivity) {
+					i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop - o.scrollSpeed;
+				}
+			}
+
+			if(!o.axis || o.axis !== "y") {
+				if((i.overflowOffset.left + i.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity) {
+					i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft + o.scrollSpeed;
+				} else if(event.pageX - i.overflowOffset.left < o.scrollSensitivity) {
+					i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft - o.scrollSpeed;
+				}
+			}
+
+		} else {
+
+			if(!o.axis || o.axis !== "x") {
+				if(event.pageY - $(document).scrollTop() < o.scrollSensitivity) {
+					scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed);
+				} else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity) {
+					scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed);
+				}
+			}
+
+			if(!o.axis || o.axis !== "y") {
+				if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity) {
+					scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed);
+				} else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity) {
+					scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed);
+				}
+			}
+
+		}
+
+		if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) {
+			$.ui.ddmanager.prepareOffsets(i, event);
+		}
+
+	}
+});
+
+$.ui.plugin.add("draggable", "snap", {
+	start: function() {
+
+		var i = $(this).data("ui-draggable"),
+			o = i.options;
+
+		i.snapElements = [];
+
+		$(o.snap.constructor !== String ? ( o.snap.items || ":data(ui-draggable)" ) : o.snap).each(function() {
+			var $t = $(this),
+				$o = $t.offset();
+			if(this !== i.element[0]) {
+				i.snapElements.push({
+					item: this,
+					width: $t.outerWidth(), height: $t.outerHeight(),
+					top: $o.top, left: $o.left
+				});
+			}
+		});
+
+	},
+	drag: function(event, ui) {
+
+		var ts, bs, ls, rs, l, r, t, b, i, first,
+			inst = $(this).data("ui-draggable"),
+			o = inst.options,
+			d = o.snapTolerance,
+			x1 = ui.offset.left, x2 = x1 + inst.helperProportions.width,
+			y1 = ui.offset.top, y2 = y1 + inst.helperProportions.height;
+
+		for (i = inst.snapElements.length - 1; i >= 0; i--){
+
+			l = inst.snapElements[i].left;
+			r = l + inst.snapElements[i].width;
+			t = inst.snapElements[i].top;
+			b = t + inst.snapElements[i].height;
+
+			if ( x2 < l - d || x1 > r + d || y2 < t - d || y1 > b + d || !$.contains( inst.snapElements[ i ].item.ownerDocument, inst.snapElements[ i ].item ) ) {
+				if(inst.snapElements[i].snapping) {
+					(inst.options.snap.release && inst.options.snap.release.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item })));
+				}
+				inst.snapElements[i].snapping = false;
+				continue;
+			}
+
+			if(o.snapMode !== "inner") {
+				ts = Math.abs(t - y2) <= d;
+				bs = Math.abs(b - y1) <= d;
+				ls = Math.abs(l - x2) <= d;
+				rs = Math.abs(r - x1) <= d;
+				if(ts) {
+					ui.position.top = inst._convertPositionTo("relative", { top: t - inst.helperProportions.height, left: 0 }).top - inst.margins.top;
+				}
+				if(bs) {
+					ui.position.top = inst._convertPositionTo("relative", { top: b, left: 0 }).top - inst.margins.top;
+				}
+				if(ls) {
+					ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l - inst.helperProportions.width }).left - inst.margins.left;
+				}
+				if(rs) {
+					ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r }).left - inst.margins.left;
+				}
+			}
+
+			first = (ts || bs || ls || rs);
+
+			if(o.snapMode !== "outer") {
+				ts = Math.abs(t - y1) <= d;
+				bs = Math.abs(b - y2) <= d;
+				ls = Math.abs(l - x1) <= d;
+				rs = Math.abs(r - x2) <= d;
+				if(ts) {
+					ui.position.top = inst._convertPositionTo("relative", { top: t, left: 0 }).top - inst.margins.top;
+				}
+				if(bs) {
+					ui.position.top = inst._convertPositionTo("relative", { top: b - inst.helperProportions.height, left: 0 }).top - inst.margins.top;
+				}
+				if(ls) {
+					ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l }).left - inst.margins.left;
+				}
+				if(rs) {
+					ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r - inst.helperProportions.width }).left - inst.margins.left;
+				}
+			}
+
+			if(!inst.snapElements[i].snapping && (ts || bs || ls || rs || first)) {
+				(inst.options.snap.snap && inst.options.snap.snap.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item })));
+			}
+			inst.snapElements[i].snapping = (ts || bs || ls || rs || first);
+
+		}
+
+	}
+});
+
+$.ui.plugin.add("draggable", "stack", {
+	start: function() {
+		var min,
+			o = this.data("ui-draggable").options,
+			group = $.makeArray($(o.stack)).sort(function(a,b) {
+				return (parseInt($(a).css("zIndex"),10) || 0) - (parseInt($(b).css("zIndex"),10) || 0);
+			});
+
+		if (!group.length) { return; }
+
+		min = parseInt($(group[0]).css("zIndex"), 10) || 0;
+		$(group).each(function(i) {
+			$(this).css("zIndex", min + i);
+		});
+		this.css("zIndex", (min + group.length));
+	}
+});
+
+$.ui.plugin.add("draggable", "zIndex", {
+	start: function(event, ui) {
+		var t = $(ui.helper), o = $(this).data("ui-draggable").options;
+		if(t.css("zIndex")) {
+			o._zIndex = t.css("zIndex");
+		}
+		t.css("zIndex", o.zIndex);
+	},
+	stop: function(event, ui) {
+		var o = $(this).data("ui-draggable").options;
+		if(o._zIndex) {
+			$(ui.helper).css("zIndex", o._zIndex);
+		}
+	}
+});
+
+})(jQuery);
+(function( $, undefined ) {
+
+/*jshint loopfunc: true */
+
+function isOverAxis( x, reference, size ) {
+	return ( x > reference ) && ( x < ( reference + size ) );
+}
+
+function isFloating(item) {
+	return (/left|right/).test(item.css("float")) || (/inline|table-cell/).test(item.css("display"));
+}
+
 $.widget("ui.sortable", $.ui.mouse, {
-	version: "1.9.2",
+	version: "1.10.3",
 	widgetEventPrefix: "sort",
 	ready: false,
@@ -1035,5 +1945,5 @@
 		connectWith: false,
 		containment: false,
-		cursor: 'auto',
+		cursor: "auto",
 		cursorAt: false,
 		dropOnEmpty: true,
@@ -1043,5 +1953,5 @@
 		handle: false,
 		helper: "original",
-		items: '> *',
+		items: "> *",
 		opacity: false,
 		placeholder: false,
@@ -1052,5 +1962,19 @@
 		scope: "default",
 		tolerance: "intersect",
-		zIndex: 1000
+		zIndex: 1000,
+
+		// callbacks
+		activate: null,
+		beforeStop: null,
+		change: null,
+		deactivate: null,
+		out: null,
+		over: null,
+		receive: null,
+		remove: null,
+		sort: null,
+		start: null,
+		stop: null,
+		update: null
 	},
 	_create: function() {
@@ -1064,5 +1988,5 @@
 
 		//Let's determine if the items are being displayed horizontally
-		this.floating = this.items.length ? o.axis === 'x' || (/left|right/).test(this.items[0].item.css('float')) || (/inline|table-cell/).test(this.items[0].item.css('display')) : false;
+		this.floating = this.items.length ? o.axis === "x" || isFloating(this.items[0].item) : false;
 
 		//Let's determine the parent's offset
@@ -1073,5 +1997,5 @@
 
 		//We're ready to go
-		this.ready = true
+		this.ready = true;
 
 	},
@@ -1082,6 +2006,7 @@
 		this._mouseDestroy();
 
-		for ( var i = this.items.length - 1; i >= 0; i-- )
+		for ( var i = this.items.length - 1; i >= 0; i-- ) {
 			this.items[i].item.removeData(this.widgetName + "-item");
+		}
 
 		return this;
@@ -1100,5 +2025,7 @@
 
 	_mouseCapture: function(event, overrideHandle) {
-		var that = this;
+		var currentItem = null,
+			validHandle = false,
+			that = this;
 
 		if (this.reverting) {
@@ -1106,5 +2033,7 @@
 		}
 
-		if(this.options.disabled || this.options.type == 'static') return false;
+		if(this.options.disabled || this.options.type === "static") {
+			return false;
+		}
 
 		//We have to refresh the items data once first
@@ -1112,18 +2041,26 @@
 
 		//Find out if the clicked node (or one of its parents) is a actual item in this.items
-		var currentItem = null, nodes = $(event.target).parents().each(function() {
-			if($.data(this, that.widgetName + '-item') == that) {
+		$(event.target).parents().each(function() {
+			if($.data(this, that.widgetName + "-item") === that) {
 				currentItem = $(this);
 				return false;
 			}
 		});
-		if($.data(event.target, that.widgetName + '-item') == that) currentItem = $(event.target);
-
-		if(!currentItem) return false;
+		if($.data(event.target, that.widgetName + "-item") === that) {
+			currentItem = $(event.target);
+		}
+
+		if(!currentItem) {
+			return false;
+		}
 		if(this.options.handle && !overrideHandle) {
-			var validHandle = false;
-
-			$(this.options.handle, currentItem).find("*").andSelf().each(function() { if(this == event.target) validHandle = true; });
-			if(!validHandle) return false;
+			$(this.options.handle, currentItem).find("*").addBack().each(function() {
+				if(this === event.target) {
+					validHandle = true;
+				}
+			});
+			if(!validHandle) {
+				return false;
+			}
 		}
 
@@ -1136,5 +2073,7 @@
 	_mouseStart: function(event, overrideHandle, noActivation) {
 
-		var o = this.options;
+		var i, body,
+			o = this.options;
+
 		this.currentContainer = this;
 
@@ -1185,5 +2124,5 @@
 		this.originalPageY = event.pageY;
 
-		//Adjust the mouse offset relative to the helper if 'cursorAt' is supplied
+		//Adjust the mouse offset relative to the helper if "cursorAt" is supplied
 		(o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt));
 
@@ -1192,5 +2131,5 @@
 
 		//If the helper is not the original, hide the original so it's not playing any role during the drag, won't cause anything bad this way
-		if(this.helper[0] != this.currentItem[0]) {
+		if(this.helper[0] !== this.currentItem[0]) {
 			this.currentItem.hide();
 		}
@@ -1200,25 +2139,36 @@
 
 		//Set a containment if given in the options
-		if(o.containment)
+		if(o.containment) {
 			this._setContainment();
-
-		if(o.cursor) { // cursor option
-			if ($('body').css("cursor")) this._storedCursor = $('body').css("cursor");
-			$('body').css("cursor", o.cursor);
+		}
+
+		if( o.cursor && o.cursor !== "auto" ) { // cursor option
+			body = this.document.find( "body" );
+
+			// support: IE
+			this.storedCursor = body.css( "cursor" );
+			body.css( "cursor", o.cursor );
+
+			this.storedStylesheet = $( "<style>*{ cursor: "+o.cursor+" !important; }</style>" ).appendTo( body );
 		}
 
 		if(o.opacity) { // opacity option
-			if (this.helper.css("opacity")) this._storedOpacity = this.helper.css("opacity");
+			if (this.helper.css("opacity")) {
+				this._storedOpacity = this.helper.css("opacity");
+			}
 			this.helper.css("opacity", o.opacity);
 		}
 
 		if(o.zIndex) { // zIndex option
-			if (this.helper.css("zIndex")) this._storedZIndex = this.helper.css("zIndex");
+			if (this.helper.css("zIndex")) {
+				this._storedZIndex = this.helper.css("zIndex");
+			}
 			this.helper.css("zIndex", o.zIndex);
 		}
 
 		//Prepare scrolling
-		if(this.scrollParent[0] != document && this.scrollParent[0].tagName != 'HTML')
+		if(this.scrollParent[0] !== document && this.scrollParent[0].tagName !== "HTML") {
 			this.overflowOffset = this.scrollParent.offset();
+		}
 
 		//Call callbacks
@@ -1226,19 +2176,24 @@
 
 		//Recache the helper size
-		if(!this._preserveHelperProportions)
+		if(!this._preserveHelperProportions) {
 			this._cacheHelperProportions();
-
-
-		//Post 'activate' events to possible containers
-		if(!noActivation) {
-			 for (var i = this.containers.length - 1; i >= 0; i--) { this.containers[i]._trigger("activate", event, this._uiHash(this)); }
+		}
+
+
+		//Post "activate" events to possible containers
+		if( !noActivation ) {
+			for ( i = this.containers.length - 1; i >= 0; i-- ) {
+				this.containers[ i ]._trigger( "activate", event, this._uiHash( this ) );
+			}
 		}
 
 		//Prepare possible droppables
-		if($.ui.ddmanager)
+		if($.ui.ddmanager) {
 			$.ui.ddmanager.current = this;
-
-		if ($.ui.ddmanager && !o.dropBehaviour)
+		}
+
+		if ($.ui.ddmanager && !o.dropBehaviour) {
 			$.ui.ddmanager.prepareOffsets(this, event);
+		}
 
 		this.dragging = true;
@@ -1251,4 +2206,7 @@
 
 	_mouseDrag: function(event) {
+		var i, item, itemElement, intersection,
+			o = this.options,
+			scrolled = false;
 
 		//Compute the helpers position
@@ -1262,33 +2220,37 @@
 		//Do scrolling
 		if(this.options.scroll) {
-			var o = this.options, scrolled = false;
-			if(this.scrollParent[0] != document && this.scrollParent[0].tagName != 'HTML') {
-
-				if((this.overflowOffset.top + this.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity)
+			if(this.scrollParent[0] !== document && this.scrollParent[0].tagName !== "HTML") {
+
+				if((this.overflowOffset.top + this.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity) {
 					this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop + o.scrollSpeed;
-				else if(event.pageY - this.overflowOffset.top < o.scrollSensitivity)
+				} else if(event.pageY - this.overflowOffset.top < o.scrollSensitivity) {
 					this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop - o.scrollSpeed;
-
-				if((this.overflowOffset.left + this.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity)
+				}
+
+				if((this.overflowOffset.left + this.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity) {
 					this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft + o.scrollSpeed;
-				else if(event.pageX - this.overflowOffset.left < o.scrollSensitivity)
+				} else if(event.pageX - this.overflowOffset.left < o.scrollSensitivity) {
 					this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft - o.scrollSpeed;
+				}
 
 			} else {
 
-				if(event.pageY - $(document).scrollTop() < o.scrollSensitivity)
+				if(event.pageY - $(document).scrollTop() < o.scrollSensitivity) {
 					scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed);
-				else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity)
+				} else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity) {
 					scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed);
-
-				if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity)
+				}
+
+				if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity) {
 					scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed);
-				else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity)
+				} else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity) {
 					scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed);
-
-			}
-
-			if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour)
+				}
+
+			}
+
+			if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) {
 				$.ui.ddmanager.prepareOffsets(this, event);
+			}
 		}
 
@@ -1297,13 +2259,21 @@
 
 		//Set the helper position
-		if(!this.options.axis || this.options.axis != "y") this.helper[0].style.left = this.position.left+'px';
-		if(!this.options.axis || this.options.axis != "x") this.helper[0].style.top = this.position.top+'px';
+		if(!this.options.axis || this.options.axis !== "y") {
+			this.helper[0].style.left = this.position.left+"px";
+		}
+		if(!this.options.axis || this.options.axis !== "x") {
+			this.helper[0].style.top = this.position.top+"px";
+		}
 
 		//Rearrange
-		for (var i = this.items.length - 1; i >= 0; i--) {
+		for (i = this.items.length - 1; i >= 0; i--) {
 
 			//Cache variables and intersection, continue if no intersection
-			var item = this.items[i], itemElement = item.item[0], intersection = this._intersectsWithPointer(item);
-			if (!intersection) continue;
+			item = this.items[i];
+			itemElement = item.item[0];
+			intersection = this._intersectsWithPointer(item);
+			if (!intersection) {
+				continue;
+			}
 
 			// Only put the placeholder inside the current Container, skip all
@@ -1314,16 +2284,20 @@
 			// Without this moving items in "sub-sortables" can cause the placeholder to jitter
 			// beetween the outer and inner container.
-			if (item.instance !== this.currentContainer) continue;
-
-			if (itemElement != this.currentItem[0] //cannot intersect with itself
-				&&	this.placeholder[intersection == 1 ? "next" : "prev"]()[0] != itemElement //no useless actions that have been done before
-				&&	!$.contains(this.placeholder[0], itemElement) //no action if the item moved is the parent of the item checked
-				&& (this.options.type == 'semi-dynamic' ? !$.contains(this.element[0], itemElement) : true)
-				//&& itemElement.parentNode == this.placeholder[0].parentNode // only rearrange items within the same container
+			if (item.instance !== this.currentContainer) {
+				continue;
+			}
+
+			// cannot intersect with itself
+			// no useless actions that have been done before
+			// no action if the item moved is the parent of the item checked
+			if (itemElement !== this.currentItem[0] &&
+				this.placeholder[intersection === 1 ? "next" : "prev"]()[0] !== itemElement &&
+				!$.contains(this.placeholder[0], itemElement) &&
+				(this.options.type === "semi-dynamic" ? !$.contains(this.element[0], itemElement) : true)
 			) {
 
-				this.direction = intersection == 1 ? "down" : "up";
-
-				if (this.options.tolerance == "pointer" || this._intersectsWithSides(item)) {
+				this.direction = intersection === 1 ? "down" : "up";
+
+				if (this.options.tolerance === "pointer" || this._intersectsWithSides(item)) {
 					this._rearrange(event, item);
 				} else {
@@ -1340,8 +2314,10 @@
 
 		//Interconnect with droppables
-		if($.ui.ddmanager) $.ui.ddmanager.drag(this, event);
+		if($.ui.ddmanager) {
+			$.ui.ddmanager.drag(this, event);
+		}
 
 		//Call callbacks
-		this._trigger('sort', event, this._uiHash());
+		this._trigger("sort", event, this._uiHash());
 
 		this.lastPositionAbs = this.positionAbs;
@@ -1352,20 +2328,27 @@
 	_mouseStop: function(event, noPropagation) {
 
-		if(!event) return;
+		if(!event) {
+			return;
+		}
 
 		//If we are using droppables, inform the manager about the drop
-		if ($.ui.ddmanager && !this.options.dropBehaviour)
+		if ($.ui.ddmanager && !this.options.dropBehaviour) {
 			$.ui.ddmanager.drop(this, event);
+		}
 
 		if(this.options.revert) {
-			var that = this;
-			var cur = this.placeholder.offset();
-
+			var that = this,
+				cur = this.placeholder.offset(),
+				axis = this.options.axis,
+				animation = {};
+
+			if ( !axis || axis === "x" ) {
+				animation.left = cur.left - this.offset.parent.left - this.margins.left + (this.offsetParent[0] === document.body ? 0 : this.offsetParent[0].scrollLeft);
+			}
+			if ( !axis || axis === "y" ) {
+				animation.top = cur.top - this.offset.parent.top - this.margins.top + (this.offsetParent[0] === document.body ? 0 : this.offsetParent[0].scrollTop);
+			}
 			this.reverting = true;
-
-			$(this.helper).animate({
-				left: cur.left - this.offset.parent.left - this.margins.left + (this.offsetParent[0] == document.body ? 0 : this.offsetParent[0].scrollLeft),
-				top: cur.top - this.offset.parent.top - this.margins.top + (this.offsetParent[0] == document.body ? 0 : this.offsetParent[0].scrollTop)
-			}, parseInt(this.options.revert, 10) || 500, function() {
+			$(this.helper).animate( animation, parseInt(this.options.revert, 10) || 500, function() {
 				that._clear(event);
 			});
@@ -1384,8 +2367,9 @@
 			this._mouseUp({ target: null });
 
-			if(this.options.helper == "original")
+			if(this.options.helper === "original") {
 				this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper");
-			else
+			} else {
 				this.currentItem.show();
+			}
 
 			//Post deactivating events to containers
@@ -1402,6 +2386,10 @@
 		if (this.placeholder) {
 			//$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node!
-			if(this.placeholder[0].parentNode) this.placeholder[0].parentNode.removeChild(this.placeholder[0]);
-			if(this.options.helper != "original" && this.helper && this.helper[0].parentNode) this.helper.remove();
+			if(this.placeholder[0].parentNode) {
+				this.placeholder[0].parentNode.removeChild(this.placeholder[0]);
+			}
+			if(this.options.helper !== "original" && this.helper && this.helper[0].parentNode) {
+				this.helper.remove();
+			}
 
 			$.extend(this, {
@@ -1425,17 +2413,20 @@
 	serialize: function(o) {
 
-		var items = this._getItemsAsjQuery(o && o.connected);
-		var str = []; o = o || {};
+		var items = this._getItemsAsjQuery(o && o.connected),
+			str = [];
+		o = o || {};
 
 		$(items).each(function() {
-			var res = ($(o.item || this).attr(o.attribute || 'id') || '').match(o.expression || (/(.+)[-=_](.+)/));
-			if(res) str.push((o.key || res[1]+'[]')+'='+(o.key && o.expression ? res[1] : res[2]));
+			var res = ($(o.item || this).attr(o.attribute || "id") || "").match(o.expression || (/(.+)[\-=_](.+)/));
+			if (res) {
+				str.push((o.key || res[1]+"[]")+"="+(o.key && o.expression ? res[1] : res[2]));
+			}
 		});
 
 		if(!str.length && o.key) {
-			str.push(o.key + '=');
-		}
-
-		return str.join('&');
+			str.push(o.key + "=");
+		}
+
+		return str.join("&");
 
 	},
@@ -1443,8 +2434,10 @@
 	toArray: function(o) {
 
-		var items = this._getItemsAsjQuery(o && o.connected);
-		var ret = []; o = o || {};
-
-		items.each(function() { ret.push($(o.item || this).attr(o.attribute || 'id') || ''); });
+		var items = this._getItemsAsjQuery(o && o.connected),
+			ret = [];
+
+		o = o || {};
+
+		items.each(function() { ret.push($(o.item || this).attr(o.attribute || "id") || ""); });
 		return ret;
 
@@ -1457,27 +2450,26 @@
 			x2 = x1 + this.helperProportions.width,
 			y1 = this.positionAbs.top,
-			y2 = y1 + this.helperProportions.height;
-
-		var l = item.left,
+			y2 = y1 + this.helperProportions.height,
+			l = item.left,
 			r = l + item.width,
 			t = item.top,
-			b = t + item.height;
-
-		var dyClick = this.offset.click.top,
-			dxClick = this.offset.click.left;
-
-		var isOverElement = (y1 + dyClick) > t && (y1 + dyClick) < b && (x1 + dxClick) > l && (x1 + dxClick) < r;
-
-		if(	   this.options.tolerance == "pointer"
-			|| this.options.forcePointerForContainers
-			|| (this.options.tolerance != "pointer" && this.helperProportions[this.floating ? 'width' : 'height'] > item[this.floating ? 'width' : 'height'])
+			b = t + item.height,
+			dyClick = this.offset.click.top,
+			dxClick = this.offset.click.left,
+			isOverElementHeight = ( this.options.axis === "x" ) || ( ( y1 + dyClick ) > t && ( y1 + dyClick ) < b ),
+			isOverElementWidth = ( this.options.axis === "y" ) || ( ( x1 + dxClick ) > l && ( x1 + dxClick ) < r ),
+			isOverElement = isOverElementHeight && isOverElementWidth;
+
+		if ( this.options.tolerance === "pointer" ||
+			this.options.forcePointerForContainers ||
+			(this.options.tolerance !== "pointer" && this.helperProportions[this.floating ? "width" : "height"] > item[this.floating ? "width" : "height"])
 		) {
 			return isOverElement;
 		} else {
 
-			return (l < x1 + (this.helperProportions.width / 2) // Right Half
-				&& x2 - (this.helperProportions.width / 2) < r // Left Half
-				&& t < y1 + (this.helperProportions.height / 2) // Bottom Half
-				&& y2 - (this.helperProportions.height / 2) < b ); // Top Half
+			return (l < x1 + (this.helperProportions.width / 2) && // Right Half
+				x2 - (this.helperProportions.width / 2) < r && // Left Half
+				t < y1 + (this.helperProportions.height / 2) && // Bottom Half
+				y2 - (this.helperProportions.height / 2) < b ); // Top Half
 
 		}
@@ -1486,16 +2478,17 @@
 	_intersectsWithPointer: function(item) {
 
-		var isOverElementHeight = (this.options.axis === 'x') || $.ui.isOverAxis(this.positionAbs.top + this.offset.click.top, item.top, item.height),
-			isOverElementWidth = (this.options.axis === 'y') || $.ui.isOverAxis(this.positionAbs.left + this.offset.click.left, item.left, item.width),
+		var isOverElementHeight = (this.options.axis === "x") || isOverAxis(this.positionAbs.top + this.offset.click.top, item.top, item.height),
+			isOverElementWidth = (this.options.axis === "y") || isOverAxis(this.positionAbs.left + this.offset.click.left, item.left, item.width),
 			isOverElement = isOverElementHeight && isOverElementWidth,
 			verticalDirection = this._getDragVerticalDirection(),
 			horizontalDirection = this._getDragHorizontalDirection();
 
-		if (!isOverElement)
+		if (!isOverElement) {
 			return false;
+		}
 
 		return this.floating ?
-			( ((horizontalDirection && horizontalDirection == "right") || verticalDirection == "down") ? 2 : 1 )
-			: ( verticalDirection && (verticalDirection == "down" ? 2 : 1) );
+			( ((horizontalDirection && horizontalDirection === "right") || verticalDirection === "down") ? 2 : 1 )
+			: ( verticalDirection && (verticalDirection === "down" ? 2 : 1) );
 
 	},
@@ -1503,13 +2496,13 @@
 	_intersectsWithSides: function(item) {
 
-		var isOverBottomHalf = $.ui.isOverAxis(this.positionAbs.top + this.offset.click.top, item.top + (item.height/2), item.height),
-			isOverRightHalf = $.ui.isOverAxis(this.positionAbs.left + this.offset.click.left, item.left + (item.width/2), item.width),
+		var isOverBottomHalf = isOverAxis(this.positionAbs.top + this.offset.click.top, item.top + (item.height/2), item.height),
+			isOverRightHalf = isOverAxis(this.positionAbs.left + this.offset.click.left, item.left + (item.width/2), item.width),
 			verticalDirection = this._getDragVerticalDirection(),
 			horizontalDirection = this._getDragHorizontalDirection();
 
 		if (this.floating && horizontalDirection) {
-			return ((horizontalDirection == "right" && isOverRightHalf) || (horizontalDirection == "left" && !isOverRightHalf));
+			return ((horizontalDirection === "right" && isOverRightHalf) || (horizontalDirection === "left" && !isOverRightHalf));
 		} else {
-			return verticalDirection && ((verticalDirection == "down" && isOverBottomHalf) || (verticalDirection == "up" && !isOverBottomHalf));
+			return verticalDirection && ((verticalDirection === "down" && isOverBottomHalf) || (verticalDirection === "up" && !isOverBottomHalf));
 		}
 
@@ -1518,10 +2511,10 @@
 	_getDragVerticalDirection: function() {
 		var delta = this.positionAbs.top - this.lastPositionAbs.top;
-		return delta != 0 && (delta > 0 ? "down" : "up");
+		return delta !== 0 && (delta > 0 ? "down" : "up");
 	},
 
 	_getDragHorizontalDirection: function() {
 		var delta = this.positionAbs.left - this.lastPositionAbs.left;
-		return delta != 0 && (delta > 0 ? "right" : "left");
+		return delta !== 0 && (delta > 0 ? "right" : "left");
 	},
 
@@ -1534,34 +2527,33 @@
 	_connectWith: function() {
 		var options = this.options;
-		return options.connectWith.constructor == String
-			? [options.connectWith]
-			: options.connectWith;
+		return options.connectWith.constructor === String ? [options.connectWith] : options.connectWith;
 	},
 
 	_getItemsAsjQuery: function(connected) {
 
-		var items = [];
-		var queries = [];
-		var connectWith = this._connectWith();
+		var i, j, cur, inst,
+			items = [],
+			queries = [],
+			connectWith = this._connectWith();
 
 		if(connectWith && connected) {
-			for (var i = connectWith.length - 1; i >= 0; i--){
-				var cur = $(connectWith[i]);
-				for (var j = cur.length - 1; j >= 0; j--){
-					var inst = $.data(cur[j], this.widgetName);
-					if(inst && inst != this && !inst.options.disabled) {
-						queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element) : $(inst.options.items, inst.element).not(".ui-sortable-helper").not('.ui-sortable-placeholder'), inst]);
+			for (i = connectWith.length - 1; i >= 0; i--){
+				cur = $(connectWith[i]);
+				for ( j = cur.length - 1; j >= 0; j--){
+					inst = $.data(cur[j], this.widgetFullName);
+					if(inst && inst !== this && !inst.options.disabled) {
+						queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element) : $(inst.options.items, inst.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"), inst]);
 					}
-				};
-			};
-		}
-
-		queries.push([$.isFunction(this.options.items) ? this.options.items.call(this.element, null, { options: this.options, item: this.currentItem }) : $(this.options.items, this.element).not(".ui-sortable-helper").not('.ui-sortable-placeholder'), this]);
-
-		for (var i = queries.length - 1; i >= 0; i--){
+				}
+			}
+		}
+
+		queries.push([$.isFunction(this.options.items) ? this.options.items.call(this.element, null, { options: this.options, item: this.currentItem }) : $(this.options.items, this.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"), this]);
+
+		for (i = queries.length - 1; i >= 0; i--){
 			queries[i][0].each(function() {
 				items.push(this);
 			});
-		};
+		}
 
 		return $(items);
@@ -1575,7 +2567,8 @@
 		this.items = $.grep(this.items, function (item) {
 			for (var j=0; j < list.length; j++) {
-				if(list[j] == item.item[0])
+				if(list[j] === item.item[0]) {
 					return false;
-			};
+				}
+			}
 			return true;
 		});
@@ -1587,29 +2580,31 @@
 		this.items = [];
 		this.containers = [this];
-		var items = this.items;
-		var queries = [[$.isFunction(this.options.items) ? this.options.items.call(this.element[0], event, { item: this.currentItem }) : $(this.options.items, this.element), this]];
-		var connectWith = this._connectWith();
+
+		var i, j, cur, inst, targetData, _queries, item, queriesLength,
+			items = this.items,
+			queries = [[$.isFunction(this.options.items) ? this.options.items.call(this.element[0], event, { item: this.currentItem }) : $(this.options.items, this.element), this]],
+			connectWith = this._connectWith();
 
 		if(connectWith && this.ready) { //Shouldn't be run the first time through due to massive slow-down
-			for (var i = connectWith.length - 1; i >= 0; i--){
-				var cur = $(connectWith[i]);
-				for (var j = cur.length - 1; j >= 0; j--){
-					var inst = $.data(cur[j], this.widgetName);
-					if(inst && inst != this && !inst.options.disabled) {
+			for (i = connectWith.length - 1; i >= 0; i--){
+				cur = $(connectWith[i]);
+				for (j = cur.length - 1; j >= 0; j--){
+					inst = $.data(cur[j], this.widgetFullName);
+					if(inst && inst !== this && !inst.options.disabled) {
 						queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element[0], event, { item: this.currentItem }) : $(inst.options.items, inst.element), inst]);
 						this.containers.push(inst);
 					}
-				};
-			};
-		}
-
-		for (var i = queries.length - 1; i >= 0; i--) {
-			var targetData = queries[i][1];
-			var _queries = queries[i][0];
-
-			for (var j=0, queriesLength = _queries.length; j < queriesLength; j++) {
-				var item = $(_queries[j]);
-
-				item.data(this.widgetName + '-item', targetData); // Data for target checking (mouse manager)
+				}
+			}
+		}
+
+		for (i = queries.length - 1; i >= 0; i--) {
+			targetData = queries[i][1];
+			_queries = queries[i][0];
+
+			for (j=0, queriesLength = _queries.length; j < queriesLength; j++) {
+				item = $(_queries[j]);
+
+				item.data(this.widgetName + "-item", targetData); // Data for target checking (mouse manager)
 
 				items.push({
@@ -1619,6 +2614,6 @@
 					left: 0, top: 0
 				});
-			};
-		};
+			}
+		}
 
 	},
@@ -1631,12 +2626,15 @@
 		}
 
-		for (var i = this.items.length - 1; i >= 0; i--){
-			var item = this.items[i];
+		var i, item, t, p;
+
+		for (i = this.items.length - 1; i >= 0; i--){
+			item = this.items[i];
 
 			//We ignore calculating positions of all connected containers when we're not over them
-			if(item.instance != this.currentContainer && this.currentContainer && item.item[0] != this.currentItem[0])
+			if(item.instance !== this.currentContainer && this.currentContainer && item.item[0] !== this.currentItem[0]) {
 				continue;
-
-			var t = this.options.toleranceElement ? $(this.options.toleranceElement, item.item) : item.item;
+			}
+
+			t = this.options.toleranceElement ? $(this.options.toleranceElement, item.item) : item.item;
 
 			if (!fast) {
@@ -1645,19 +2643,19 @@
 			}
 
-			var p = t.offset();
+			p = t.offset();
 			item.left = p.left;
 			item.top = p.top;
-		};
+		}
 
 		if(this.options.custom && this.options.custom.refreshContainers) {
 			this.options.custom.refreshContainers.call(this);
 		} else {
-			for (var i = this.containers.length - 1; i >= 0; i--){
-				var p = this.containers[i].element.offset();
+			for (i = this.containers.length - 1; i >= 0; i--){
+				p = this.containers[i].element.offset();
 				this.containers[i].containerCache.left = p.left;
 				this.containers[i].containerCache.top = p.top;
 				this.containers[i].containerCache.width	= this.containers[i].element.outerWidth();
 				this.containers[i].containerCache.height = this.containers[i].element.outerHeight();
-			};
+			}
 		}
 
@@ -1667,19 +2665,32 @@
 	_createPlaceholder: function(that) {
 		that = that || this;
-		var o = that.options;
-
-		if(!o.placeholder || o.placeholder.constructor == String) {
-			var className = o.placeholder;
+		var className,
+			o = that.options;
+
+		if(!o.placeholder || o.placeholder.constructor === String) {
+			className = o.placeholder;
 			o.placeholder = {
 				element: function() {
 
-					var el = $(document.createElement(that.currentItem[0].nodeName))
-						.addClass(className || that.currentItem[0].className+" ui-sortable-placeholder")
-						.removeClass("ui-sortable-helper")[0];
-
-					if(!className)
-						el.style.visibility = "hidden";
-
-					return el;
+					var nodeName = that.currentItem[0].nodeName.toLowerCase(),
+						element = $( "<" + nodeName + ">", that.document[0] )
+							.addClass(className || that.currentItem[0].className+" ui-sortable-placeholder")
+							.removeClass("ui-sortable-helper");
+
+					if ( nodeName === "tr" ) {
+						that.currentItem.children().each(function() {
+							$( "<td>&#160;</td>", that.document[0] )
+								.attr( "colspan", $( this ).attr( "colspan" ) || 1 )
+								.appendTo( element );
+						});
+					} else if ( nodeName === "img" ) {
+						element.attr( "src", that.currentItem.attr( "src" ) );
+					}
+
+					if ( !className ) {
+						element.css( "visibility", "hidden" );
+					}
+
+					return element;
 				},
 				update: function(container, p) {
@@ -1687,9 +2698,11 @@
 					// 1. If a className is set as 'placeholder option, we don't force sizes - the class is responsible for that
 					// 2. The option 'forcePlaceholderSize can be enabled to force it even if a class name is specified
-					if(className && !o.forcePlaceholderSize) return;
+					if(className && !o.forcePlaceholderSize) {
+						return;
+					}
 
 					//If the element doesn't have a actual height by itself (without styles coming from a stylesheet), it receives the inline height from the dragged item
-					if(!p.height()) { p.height(that.currentItem.innerHeight() - parseInt(that.currentItem.css('paddingTop')||0, 10) - parseInt(that.currentItem.css('paddingBottom')||0, 10)); };
-					if(!p.width()) { p.width(that.currentItem.innerWidth() - parseInt(that.currentItem.css('paddingLeft')||0, 10) - parseInt(that.currentItem.css('paddingRight')||0, 10)); };
+					if(!p.height()) { p.height(that.currentItem.innerHeight() - parseInt(that.currentItem.css("paddingTop")||0, 10) - parseInt(that.currentItem.css("paddingBottom")||0, 10)); }
+					if(!p.width()) { p.width(that.currentItem.innerWidth() - parseInt(that.currentItem.css("paddingLeft")||0, 10) - parseInt(that.currentItem.css("paddingRight")||0, 10)); }
 				}
 			};
@@ -1708,20 +2721,22 @@
 
 	_contactContainers: function(event) {
+		var i, j, dist, itemWithLeastDistance, posProperty, sizeProperty, base, cur, nearBottom, floating,
+			innermostContainer = null,
+			innermostIndex = null;
 
 		// get innermost container that intersects with item
-		var innermostContainer = null, innermostIndex = null;
-
-
-		for (var i = this.containers.length - 1; i >= 0; i--){
+		for (i = this.containers.length - 1; i >= 0; i--) {
 
 			// never consider a container that's located within the item itself
-			if($.contains(this.currentItem[0], this.containers[i].element[0]))
+			if($.contains(this.currentItem[0], this.containers[i].element[0])) {
 				continue;
+			}
 
 			if(this._intersectsWith(this.containers[i].containerCache)) {
 
 				// if we've already found a container and it's more "inner" than this, then continue
-				if(innermostContainer && $.contains(this.containers[i].element[0], innermostContainer.element[0]))
+				if(innermostContainer && $.contains(this.containers[i].element[0], innermostContainer.element[0])) {
 					continue;
+				}
 
 				innermostContainer = this.containers[i];
@@ -1739,22 +2754,35 @@
 
 		// if no intersecting containers found, return
-		if(!innermostContainer) return;
+		if(!innermostContainer) {
+			return;
+		}
 
 		// move the item into the container if it's not there already
 		if(this.containers.length === 1) {
-			this.containers[innermostIndex]._trigger("over", event, this._uiHash(this));
-			this.containers[innermostIndex].containerCache.over = 1;
+			if (!this.containers[innermostIndex].containerCache.over) {
+				this.containers[innermostIndex]._trigger("over", event, this._uiHash(this));
+				this.containers[innermostIndex].containerCache.over = 1;
+			}
 		} else {
 
 			//When entering a new container, we will find the item with the least distance and append our item near it
-			var dist = 10000; var itemWithLeastDistance = null;
-			var posProperty = this.containers[innermostIndex].floating ? 'left' : 'top';
-			var sizeProperty = this.containers[innermostIndex].floating ? 'width' : 'height';
-			var base = this.positionAbs[posProperty] + this.offset.click[posProperty];
-			for (var j = this.items.length - 1; j >= 0; j--) {
-				if(!$.contains(this.containers[innermostIndex].element[0], this.items[j].item[0])) continue;
-				if(this.items[j].item[0] == this.currentItem[0]) continue;
-				var cur = this.items[j].item.offset()[posProperty];
-				var nearBottom = false;
+			dist = 10000;
+			itemWithLeastDistance = null;
+			floating = innermostContainer.floating || isFloating(this.currentItem);
+			posProperty = floating ? "left" : "top";
+			sizeProperty = floating ? "width" : "height";
+			base = this.positionAbs[posProperty] + this.offset.click[posProperty];
+			for (j = this.items.length - 1; j >= 0; j--) {
+				if(!$.contains(this.containers[innermostIndex].element[0], this.items[j].item[0])) {
+					continue;
+				}
+				if(this.items[j].item[0] === this.currentItem[0]) {
+					continue;
+				}
+				if (floating && !isOverAxis(this.positionAbs.top + this.offset.click.top, this.items[j].top, this.items[j].height)) {
+					continue;
+				}
+				cur = this.items[j].item.offset()[posProperty];
+				nearBottom = false;
 				if(Math.abs(cur - base) > Math.abs(cur + this.items[j][sizeProperty] - base)){
 					nearBottom = true;
@@ -1768,11 +2796,17 @@
 			}
 
-			if(!itemWithLeastDistance && !this.options.dropOnEmpty) //Check if dropOnEmpty is enabled
+			//Check if dropOnEmpty is enabled
+			if(!itemWithLeastDistance && !this.options.dropOnEmpty) {
 				return;
-
-			this.currentContainer = this.containers[innermostIndex];
+			}
+
+			if(this.currentContainer === this.containers[innermostIndex]) {
+				return;
+			}
+
 			itemWithLeastDistance ? this._rearrange(event, itemWithLeastDistance, null, true) : this._rearrange(event, null, this.containers[innermostIndex].element, true);
 			this._trigger("change", event, this._uiHash());
 			this.containers[innermostIndex]._trigger("change", event, this._uiHash(this));
+			this.currentContainer = this.containers[innermostIndex];
 
 			//Update the placeholder
@@ -1788,15 +2822,22 @@
 	_createHelper: function(event) {
 
-		var o = this.options;
-		var helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event, this.currentItem])) : (o.helper == 'clone' ? this.currentItem.clone() : this.currentItem);
-
-		if(!helper.parents('body').length) //Add the helper to the DOM if that didn't happen already
-			$(o.appendTo != 'parent' ? o.appendTo : this.currentItem[0].parentNode)[0].appendChild(helper[0]);
-
-		if(helper[0] == this.currentItem[0])
+		var o = this.options,
+			helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event, this.currentItem])) : (o.helper === "clone" ? this.currentItem.clone() : this.currentItem);
+
+		//Add the helper to the DOM if that didn't happen already
+		if(!helper.parents("body").length) {
+			$(o.appendTo !== "parent" ? o.appendTo : this.currentItem[0].parentNode)[0].appendChild(helper[0]);
+		}
+
+		if(helper[0] === this.currentItem[0]) {
 			this._storedCSS = { width: this.currentItem[0].style.width, height: this.currentItem[0].style.height, position: this.currentItem.css("position"), top: this.currentItem.css("top"), left: this.currentItem.css("left") };
-
-		if(helper[0].style.width == '' || o.forceHelperSize) helper.width(this.currentItem.width());
-		if(helper[0].style.height == '' || o.forceHelperSize) helper.height(this.currentItem.height());
+		}
+
+		if(!helper[0].style.width || o.forceHelperSize) {
+			helper.width(this.currentItem.width());
+		}
+		if(!helper[0].style.height || o.forceHelperSize) {
+			helper.height(this.currentItem.height());
+		}
 
 		return helper;
@@ -1805,20 +2846,20 @@
 
 	_adjustOffsetFromHelper: function(obj) {
-		if (typeof obj == 'string') {
-			obj = obj.split(' ');
+		if (typeof obj === "string") {
+			obj = obj.split(" ");
 		}
 		if ($.isArray(obj)) {
 			obj = {left: +obj[0], top: +obj[1] || 0};
 		}
-		if ('left' in obj) {
+		if ("left" in obj) {
 			this.offset.click.left = obj.left + this.margins.left;
 		}
-		if ('right' in obj) {
+		if ("right" in obj) {
 			this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
 		}
-		if ('top' in obj) {
+		if ("top" in obj) {
 			this.offset.click.top = obj.top + this.margins.top;
 		}
-		if ('bottom' in obj) {
+		if ("bottom" in obj) {
 			this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
 		}
@@ -1836,12 +2877,14 @@
 		// 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that
 		//    the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag
-		if(this.cssPosition == 'absolute' && this.scrollParent[0] != document && $.contains(this.scrollParent[0], this.offsetParent[0])) {
+		if(this.cssPosition === "absolute" && this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) {
 			po.left += this.scrollParent.scrollLeft();
 			po.top += this.scrollParent.scrollTop();
 		}
 
-		if((this.offsetParent[0] == document.body) //This needs to be actually done for all browsers, since pageX/pageY includes this information
-		|| (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() == 'html' && $.ui.ie)) //Ugly IE fix
+		// This needs to be actually done for all browsers, since pageX/pageY includes this information
+		// with an ugly IE fix
+		if( this.offsetParent[0] === document.body || (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() === "html" && $.ui.ie)) {
 			po = { top: 0, left: 0 };
+		}
 
 		return {
@@ -1854,5 +2897,5 @@
 	_getRelativeOffset: function() {
 
-		if(this.cssPosition == "relative") {
+		if(this.cssPosition === "relative") {
 			var p = this.currentItem.position();
 			return {
@@ -1882,17 +2925,22 @@
 	_setContainment: function() {
 
-		var o = this.options;
-		if(o.containment == 'parent') o.containment = this.helper[0].parentNode;
-		if(o.containment == 'document' || o.containment == 'window') this.containment = [
-			0 - this.offset.relative.left - this.offset.parent.left,
-			0 - this.offset.relative.top - this.offset.parent.top,
-			$(o.containment == 'document' ? document : window).width() - this.helperProportions.width - this.margins.left,
-			($(o.containment == 'document' ? document : window).height() || document.body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top
-		];
+		var ce, co, over,
+			o = this.options;
+		if(o.containment === "parent") {
+			o.containment = this.helper[0].parentNode;
+		}
+		if(o.containment === "document" || o.containment === "window") {
+			this.containment = [
+				0 - this.offset.relative.left - this.offset.parent.left,
+				0 - this.offset.relative.top - this.offset.parent.top,
+				$(o.containment === "document" ? document : window).width() - this.helperProportions.width - this.margins.left,
+				($(o.containment === "document" ? document : window).height() || document.body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top
+			];
+		}
 
 		if(!(/^(document|window|parent)$/).test(o.containment)) {
-			var ce = $(o.containment)[0];
-			var co = $(o.containment).offset();
-			var over = ($(ce).css("overflow") != 'hidden');
+			ce = $(o.containment)[0];
+			co = $(o.containment).offset();
+			over = ($(ce).css("overflow") !== "hidden");
 
 			this.containment = [
@@ -1908,20 +2956,23 @@
 	_convertPositionTo: function(d, pos) {
 
-		if(!pos) pos = this.position;
-		var mod = d == "absolute" ? 1 : -1;
-		var o = this.options, scroll = this.cssPosition == 'absolute' && !(this.scrollParent[0] != document && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName);
+		if(!pos) {
+			pos = this.position;
+		}
+		var mod = d === "absolute" ? 1 : -1,
+			scroll = this.cssPosition === "absolute" && !(this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent,
+			scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName);
 
 		return {
 			top: (
-				pos.top																	// The absolute mouse position
-				+ this.offset.relative.top * mod										// Only for relative positioned nodes: Relative offset from element to offset parent
-				+ this.offset.parent.top * mod											// The offsetParent's offset without borders (offset + border)
-				- ( ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod)
+				pos.top	+																// The absolute mouse position
+				this.offset.relative.top * mod +										// Only for relative positioned nodes: Relative offset from element to offset parent
+				this.offset.parent.top * mod -											// The offsetParent's offset without borders (offset + border)
+				( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod)
 			),
 			left: (
-				pos.left																// The absolute mouse position
-				+ this.offset.relative.left * mod										// Only for relative positioned nodes: Relative offset from element to offset parent
-				+ this.offset.parent.left * mod											// The offsetParent's offset without borders (offset + border)
-				- ( ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) * mod)
+				pos.left +																// The absolute mouse position
+				this.offset.relative.left * mod +										// Only for relative positioned nodes: Relative offset from element to offset parent
+				this.offset.parent.left * mod	-										// The offsetParent's offset without borders (offset + border)
+				( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) * mod)
 			)
 		};
@@ -1931,5 +2982,9 @@
 	_generatePosition: function(event) {
 
-		var o = this.options, scroll = this.cssPosition == 'absolute' && !(this.scrollParent[0] != document && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName);
+		var top, left,
+			o = this.options,
+			pageX = event.pageX,
+			pageY = event.pageY,
+			scroll = this.cssPosition === "absolute" && !(this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName);
 
 		// This is another very weird special case that only happens for relative elements:
@@ -1937,10 +2992,7 @@
 		// 2. and the scroll parent is the document or similar to the offset parent
 		// we have to refresh the relative offset during the scroll so there are no jumps
-		if(this.cssPosition == 'relative' && !(this.scrollParent[0] != document && this.scrollParent[0] != this.offsetParent[0])) {
+		if(this.cssPosition === "relative" && !(this.scrollParent[0] !== document && this.scrollParent[0] !== this.offsetParent[0])) {
 			this.offset.relative = this._getRelativeOffset();
 		}
-
-		var pageX = event.pageX;
-		var pageY = event.pageY;
 
 		/*
@@ -1952,16 +3004,24 @@
 
 			if(this.containment) {
-				if(event.pageX - this.offset.click.left < this.containment[0]) pageX = this.containment[0] + this.offset.click.left;
-				if(event.pageY - this.offset.click.top < this.containment[1]) pageY = this.containment[1] + this.offset.click.top;
-				if(event.pageX - this.offset.click.left > this.containment[2]) pageX = this.containment[2] + this.offset.click.left;
-				if(event.pageY - this.offset.click.top > this.containment[3]) pageY = this.containment[3] + this.offset.click.top;
+				if(event.pageX - this.offset.click.left < this.containment[0]) {
+					pageX = this.containment[0] + this.offset.click.left;
+				}
+				if(event.pageY - this.offset.click.top < this.containment[1]) {
+					pageY = this.containment[1] + this.offset.click.top;
+				}
+				if(event.pageX - this.offset.click.left > this.containment[2]) {
+					pageX = this.containment[2] + this.offset.click.left;
+				}
+				if(event.pageY - this.offset.click.top > this.containment[3]) {
+					pageY = this.containment[3] + this.offset.click.top;
+				}
 			}
 
 			if(o.grid) {
-				var top = this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1];
-				pageY = this.containment ? (!(top - this.offset.click.top < this.containment[1] || top - this.offset.click.top > this.containment[3]) ? top : (!(top - this.offset.click.top < this.containment[1]) ? top - o.grid[1] : top + o.grid[1])) : top;
-
-				var left = this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0];
-				pageX = this.containment ? (!(left - this.offset.click.left < this.containment[0] || left - this.offset.click.left > this.containment[2]) ? left : (!(left - this.offset.click.left < this.containment[0]) ? left - o.grid[0] : left + o.grid[0])) : left;
+				top = this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1];
+				pageY = this.containment ? ( (top - this.offset.click.top >= this.containment[1] && top - this.offset.click.top <= this.containment[3]) ? top : ((top - this.offset.click.top >= this.containment[1]) ? top - o.grid[1] : top + o.grid[1])) : top;
+
+				left = this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0];
+				pageX = this.containment ? ( (left - this.offset.click.left >= this.containment[0] && left - this.offset.click.left <= this.containment[2]) ? left : ((left - this.offset.click.left >= this.containment[0]) ? left - o.grid[0] : left + o.grid[0])) : left;
 			}
 
@@ -1970,16 +3030,16 @@
 		return {
 			top: (
-				pageY																// The absolute mouse position
-				- this.offset.click.top													// Click offset (relative to the element)
-				- this.offset.relative.top												// Only for relative positioned nodes: Relative offset from element to offset parent
-				- this.offset.parent.top												// The offsetParent's offset without borders (offset + border)
-				+ ( ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ))
+				pageY -																// The absolute mouse position
+				this.offset.click.top -													// Click offset (relative to the element)
+				this.offset.relative.top	-											// Only for relative positioned nodes: Relative offset from element to offset parent
+				this.offset.parent.top +												// The offsetParent's offset without borders (offset + border)
+				( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ))
 			),
 			left: (
-				pageX																// The absolute mouse position
-				- this.offset.click.left												// Click offset (relative to the element)
-				- this.offset.relative.left												// Only for relative positioned nodes: Relative offset from element to offset parent
-				- this.offset.parent.left												// The offsetParent's offset without borders (offset + border)
-				+ ( ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ))
+				pageX -																// The absolute mouse position
+				this.offset.click.left -												// Click offset (relative to the element)
+				this.offset.relative.left	-											// Only for relative positioned nodes: Relative offset from element to offset parent
+				this.offset.parent.left +												// The offsetParent's offset without borders (offset + border)
+				( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ))
 			)
 		};
@@ -1989,5 +3049,5 @@
 	_rearrange: function(event, i, a, hardRefresh) {
 
-		a ? a[0].appendChild(this.placeholder[0]) : i.item[0].parentNode.insertBefore(this.placeholder[0], (this.direction == 'down' ? i.item[0] : i.item[0].nextSibling));
+		a ? a[0].appendChild(this.placeholder[0]) : i.item[0].parentNode.insertBefore(this.placeholder[0], (this.direction === "down" ? i.item[0] : i.item[0].nextSibling));
 
 		//Various things done here to improve the performance:
@@ -2000,5 +3060,7 @@
 
 		this._delay(function() {
-			if(counter == this.counter) this.refreshPositions(!hardRefresh); //Precompute after each DOM insertion, NOT on mousemove
+			if(counter === this.counter) {
+				this.refreshPositions(!hardRefresh); //Precompute after each DOM insertion, NOT on mousemove
+			}
 		});
 
@@ -2010,14 +3072,19 @@
 		// We delay all events that have to be triggered to after the point where the placeholder has been removed and
 		// everything else normalized again
-		var delayedTriggers = [];
+		var i,
+			delayedTriggers = [];
 
 		// We first have to update the dom position of the actual currentItem
 		// Note: don't do it if the current item is already removed (by a user), or it gets reappended (see #4088)
-		if(!this._noFinalSort && this.currentItem.parent().length) this.placeholder.before(this.currentItem);
+		if(!this._noFinalSort && this.currentItem.parent().length) {
+			this.placeholder.before(this.currentItem);
+		}
 		this._noFinalSort = null;
 
-		if(this.helper[0] == this.currentItem[0]) {
-			for(var i in this._storedCSS) {
-				if(this._storedCSS[i] == 'auto' || this._storedCSS[i] == 'static') this._storedCSS[i] = '';
+		if(this.helper[0] === this.currentItem[0]) {
+			for(i in this._storedCSS) {
+				if(this._storedCSS[i] === "auto" || this._storedCSS[i] === "static") {
+					this._storedCSS[i] = "";
+				}
 			}
 			this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper");
@@ -2026,6 +3093,10 @@
 		}
 
-		if(this.fromOutside && !noPropagation) delayedTriggers.push(function(event) { this._trigger("receive", event, this._uiHash(this.fromOutside)); });
-		if((this.fromOutside || this.domPosition.prev != this.currentItem.prev().not(".ui-sortable-helper")[0] || this.domPosition.parent != this.currentItem.parent()[0]) && !noPropagation) delayedTriggers.push(function(event) { this._trigger("update", event, this._uiHash()); }); //Trigger update callback if the DOM position has changed
+		if(this.fromOutside && !noPropagation) {
+			delayedTriggers.push(function(event) { this._trigger("receive", event, this._uiHash(this.fromOutside)); });
+		}
+		if((this.fromOutside || this.domPosition.prev !== this.currentItem.prev().not(".ui-sortable-helper")[0] || this.domPosition.parent !== this.currentItem.parent()[0]) && !noPropagation) {
+			delayedTriggers.push(function(event) { this._trigger("update", event, this._uiHash()); }); //Trigger update callback if the DOM position has changed
+		}
 
 		// Check if the items Container has Changed and trigger appropriate
@@ -2041,6 +3112,8 @@
 
 		//Post events to containers
-		for (var i = this.containers.length - 1; i >= 0; i--){
-			if(!noPropagation) delayedTriggers.push((function(c) { return function(event) { c._trigger("deactivate", event, this._uiHash(this)); };  }).call(this, this.containers[i]));
+		for (i = this.containers.length - 1; i >= 0; i--){
+			if(!noPropagation) {
+				delayedTriggers.push((function(c) { return function(event) { c._trigger("deactivate", event, this._uiHash(this)); };  }).call(this, this.containers[i]));
+			}
 			if(this.containers[i].containerCache.over) {
 				delayedTriggers.push((function(c) { return function(event) { c._trigger("out", event, this._uiHash(this)); };  }).call(this, this.containers[i]));
@@ -2050,7 +3123,14 @@
 
 		//Do what was originally in plugins
-		if(this._storedCursor) $('body').css("cursor", this._storedCursor); //Reset cursor
-		if(this._storedOpacity) this.helper.css("opacity", this._storedOpacity); //Reset opacity
-		if(this._storedZIndex) this.helper.css("zIndex", this._storedZIndex == 'auto' ? '' : this._storedZIndex); //Reset z-index
+		if ( this.storedCursor ) {
+			this.document.find( "body" ).css( "cursor", this.storedCursor );
+			this.storedStylesheet.remove();
+		}
+		if(this._storedOpacity) {
+			this.helper.css("opacity", this._storedOpacity);
+		}
+		if(this._storedZIndex) {
+			this.helper.css("zIndex", this._storedZIndex === "auto" ? "" : this._storedZIndex);
+		}
 
 		this.dragging = false;
@@ -2058,5 +3138,7 @@
 			if(!noPropagation) {
 				this._trigger("beforeStop", event, this._uiHash());
-				for (var i=0; i < delayedTriggers.length; i++) { delayedTriggers[i].call(this, event); }; //Trigger all delayed events
+				for (i=0; i < delayedTriggers.length; i++) {
+					delayedTriggers[i].call(this, event);
+				} //Trigger all delayed events
 				this._trigger("stop", event, this._uiHash());
 			}
@@ -2066,13 +3148,20 @@
 		}
 
-		if(!noPropagation) this._trigger("beforeStop", event, this._uiHash());
+		if(!noPropagation) {
+			this._trigger("beforeStop", event, this._uiHash());
+		}
 
 		//$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node!
 		this.placeholder[0].parentNode.removeChild(this.placeholder[0]);
 
-		if(this.helper[0] != this.currentItem[0]) this.helper.remove(); this.helper = null;
+		if(this.helper[0] !== this.currentItem[0]) {
+			this.helper.remove();
+		}
+		this.helper = null;
 
 		if(!noPropagation) {
-			for (var i=0; i < delayedTriggers.length; i++) { delayedTriggers[i].call(this, event); }; //Trigger all delayed events
+			for (i=0; i < delayedTriggers.length; i++) {
+				delayedTriggers[i].call(this, event);
+			} //Trigger all delayed events
 			this._trigger("stop", event, this._uiHash());
 		}
@@ -2117,5 +3206,5 @@
 
 $.widget( "ui.accordion", {
-	version: "1.9.2",
+	version: "1.10.3",
 	options: {
 		active: 0,
@@ -2136,19 +3225,9 @@
 
 	_create: function() {
-		var accordionId = this.accordionId = "ui-accordion-" +
-				(this.element.attr( "id" ) || ++uid),
-			options = this.options;
-
+		var options = this.options;
 		this.prevShow = this.prevHide = $();
-		this.element.addClass( "ui-accordion ui-widget ui-helper-reset" );
-
-		this.headers = this.element.find( options.header )
-			.addClass( "ui-accordion-header ui-helper-reset ui-state-default ui-corner-all" );
-		this._hoverable( this.headers );
-		this._focusable( this.headers );
-
-		this.headers.next()
-			.addClass( "ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom" )
-			.hide();
+		this.element.addClass( "ui-accordion ui-widget ui-helper-reset" )
+			// ARIA
+			.attr( "role", "tablist" );
 
 		// don't allow collapsible: false and active: false / null
@@ -2156,73 +3235,11 @@
 			options.active = 0;
 		}
+
+		this._processPanels();
 		// handle negative values
 		if ( options.active < 0 ) {
 			options.active += this.headers.length;
 		}
-		this.active = this._findActive( options.active )
-			.addClass( "ui-accordion-header-active ui-state-active" )
-			.toggleClass( "ui-corner-all ui-corner-top" );
-		this.active.next()
-			.addClass( "ui-accordion-content-active" )
-			.show();
-
-		this._createIcons();
-		this.refresh();
-
-		// ARIA
-		this.element.attr( "role", "tablist" );
-
-		this.headers
-			.attr( "role", "tab" )
-			.each(function( i ) {
-				var header = $( this ),
-					headerId = header.attr( "id" ),
-					panel = header.next(),
-					panelId = panel.attr( "id" );
-				if ( !headerId ) {
-					headerId = accordionId + "-header-" + i;
-					header.attr( "id", headerId );
-				}
-				if ( !panelId ) {
-					panelId = accordionId + "-panel-" + i;
-					panel.attr( "id", panelId );
-				}
-				header.attr( "aria-controls", panelId );
-				panel.attr( "aria-labelledby", headerId );
-			})
-			.next()
-				.attr( "role", "tabpanel" );
-
-		this.headers
-			.not( this.active )
-			.attr({
-				"aria-selected": "false",
-				tabIndex: -1
-			})
-			.next()
-				.attr({
-					"aria-expanded": "false",
-					"aria-hidden": "true"
-				})
-				.hide();
-
-		// make sure at least one header is in the tab order
-		if ( !this.active.length ) {
-			this.headers.eq( 0 ).attr( "tabIndex", 0 );
-		} else {
-			this.active.attr({
-				"aria-selected": "true",
-				tabIndex: 0
-			})
-			.next()
-				.attr({
-					"aria-expanded": "true",
-					"aria-hidden": "false"
-				});
-		}
-
-		this._on( this.headers, { keydown: "_keydown" });
-		this._on( this.headers.next(), { keydown: "_panelKeyDown" });
-		this._setupEvents( options.event );
+		this._refresh();
 	},
 
@@ -2230,4 +3247,5 @@
 		return {
 			header: this.active,
+			panel: !this.active.length ? $() : this.active.next(),
 			content: !this.active.length ? $() : this.active.next()
 		};
@@ -2331,4 +3349,5 @@
 
 	_keydown: function( event ) {
+		/*jshint maxcomplexity:15*/
 		if ( event.altKey || event.ctrlKey ) {
 			return;
@@ -2376,18 +3395,114 @@
 
 	refresh: function() {
-		var maxHeight, overflow,
-			heightStyle = this.options.heightStyle,
-			parent = this.element.parent();
-
+		var options = this.options;
+		this._processPanels();
+
+		// was collapsed or no panel
+		if ( ( options.active === false && options.collapsible === true ) || !this.headers.length ) {
+			options.active = false;
+			this.active = $();
+		// active false only when collapsible is true
+		} else if ( options.active === false ) {
+			this._activate( 0 );
+		// was active, but active panel is gone
+		} else if ( this.active.length && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) {
+			// all remaining panel are disabled
+			if ( this.headers.length === this.headers.find(".ui-state-disabled").length ) {
+				options.active = false;
+				this.active = $();
+			// activate previous panel
+			} else {
+				this._activate( Math.max( 0, options.active - 1 ) );
+			}
+		// was active, active panel still exists
+		} else {
+			// make sure active index is correct
+			options.active = this.headers.index( this.active );
+		}
+
+		this._destroyIcons();
+
+		this._refresh();
+	},
+
+	_processPanels: function() {
+		this.headers = this.element.find( this.options.header )
+			.addClass( "ui-accordion-header ui-helper-reset ui-state-default ui-corner-all" );
+
+		this.headers.next()
+			.addClass( "ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom" )
+			.filter(":not(.ui-accordion-content-active)")
+			.hide();
+	},
+
+	_refresh: function() {
+		var maxHeight,
+			options = this.options,
+			heightStyle = options.heightStyle,
+			parent = this.element.parent(),
+			accordionId = this.accordionId = "ui-accordion-" +
+				(this.element.attr( "id" ) || ++uid);
+
+		this.active = this._findActive( options.active )
+			.addClass( "ui-accordion-header-active ui-state-active ui-corner-top" )
+			.removeClass( "ui-corner-all" );
+		this.active.next()
+			.addClass( "ui-accordion-content-active" )
+			.show();
+
+		this.headers
+			.attr( "role", "tab" )
+			.each(function( i ) {
+				var header = $( this ),
+					headerId = header.attr( "id" ),
+					panel = header.next(),
+					panelId = panel.attr( "id" );
+				if ( !headerId ) {
+					headerId = accordionId + "-header-" + i;
+					header.attr( "id", headerId );
+				}
+				if ( !panelId ) {
+					panelId = accordionId + "-panel-" + i;
+					panel.attr( "id", panelId );
+				}
+				header.attr( "aria-controls", panelId );
+				panel.attr( "aria-labelledby", headerId );
+			})
+			.next()
+				.attr( "role", "tabpanel" );
+
+		this.headers
+			.not( this.active )
+			.attr({
+				"aria-selected": "false",
+				tabIndex: -1
+			})
+			.next()
+				.attr({
+					"aria-expanded": "false",
+					"aria-hidden": "true"
+				})
+				.hide();
+
+		// make sure at least one header is in the tab order
+		if ( !this.active.length ) {
+			this.headers.eq( 0 ).attr( "tabIndex", 0 );
+		} else {
+			this.active.attr({
+				"aria-selected": "true",
+				tabIndex: 0
+			})
+			.next()
+				.attr({
+					"aria-expanded": "true",
+					"aria-hidden": "false"
+				});
+		}
+
+		this._createIcons();
+
+		this._setupEvents( options.event );
 
 		if ( heightStyle === "fill" ) {
-			// IE 6 treats height like minHeight, so we need to turn off overflow
-			// in order to get a reliable height
-			// we use the minHeight support test because we assume that only
-			// browsers that don't support minHeight will treat height as minHeight
-			if ( !$.support.minHeight ) {
-				overflow = parent.css( "overflow" );
-				parent.css( "overflow", "hidden");
-			}
 			maxHeight = parent.height();
 			this.element.siblings( ":visible" ).each(function() {
@@ -2400,7 +3515,4 @@
 				maxHeight -= elem.outerHeight( true );
 			});
-			if ( overflow ) {
-				parent.css( "overflow", overflow );
-			}
 
 			this.headers.each(function() {
@@ -2447,12 +3559,18 @@
 
 	_setupEvents: function( event ) {
-		var events = {};
-		if ( !event ) {
-			return;
-		}
-		$.each( event.split(" "), function( index, eventName ) {
-			events[ eventName ] = "_eventHandler";
-		});
+		var events = {
+			keydown: "_keydown"
+		};
+		if ( event ) {
+			$.each( event.split(" "), function( index, eventName ) {
+				events[ eventName ] = "_eventHandler";
+			});
+		}
+
+		this._off( this.headers.add( this.headers.next() ) );
 		this._on( this.headers, events );
+		this._on( this.headers.next(), { keydown: "_panelKeyDown" });
+		this._hoverable( this.headers );
+		this._focusable( this.headers );
 	},
 
@@ -2633,191 +3751,3 @@
 });
 
-
-
-// DEPRECATED
-if ( $.uiBackCompat !== false ) {
-	// navigation options
-	(function( $, prototype ) {
-		$.extend( prototype.options, {
-			navigation: false,
-			navigationFilter: function() {
-				return this.href.toLowerCase() === location.href.toLowerCase();
-			}
-		});
-
-		var _create = prototype._create;
-		prototype._create = function() {
-			if ( this.options.navigation ) {
-				var that = this,
-					headers = this.element.find( this.options.header ),
-					content = headers.next(),
-					current = headers.add( content )
-						.find( "a" )
-						.filter( this.options.navigationFilter )
-						[ 0 ];
-				if ( current ) {
-					headers.add( content ).each( function( index ) {
-						if ( $.contains( this, current ) ) {
-							that.options.active = Math.floor( index / 2 );
-							return false;
-						}
-					});
-				}
-			}
-			_create.call( this );
-		};
-	}( jQuery, jQuery.ui.accordion.prototype ) );
-
-	// height options
-	(function( $, prototype ) {
-		$.extend( prototype.options, {
-			heightStyle: null, // remove default so we fall back to old values
-			autoHeight: true, // use heightStyle: "auto"
-			clearStyle: false, // use heightStyle: "content"
-			fillSpace: false // use heightStyle: "fill"
-		});
-
-		var _create = prototype._create,
-			_setOption = prototype._setOption;
-
-		$.extend( prototype, {
-			_create: function() {
-				this.options.heightStyle = this.options.heightStyle ||
-					this._mergeHeightStyle();
-
-				_create.call( this );
-			},
-
-			_setOption: function( key ) {
-				if ( key === "autoHeight" || key === "clearStyle" || key === "fillSpace" ) {
-					this.options.heightStyle = this._mergeHeightStyle();
-				}
-				_setOption.apply( this, arguments );
-			},
-
-			_mergeHeightStyle: function() {
-				var options = this.options;
-
-				if ( options.fillSpace ) {
-					return "fill";
-				}
-
-				if ( options.clearStyle ) {
-					return "content";
-				}
-
-				if ( options.autoHeight ) {
-					return "auto";
-				}
-			}
-		});
-	}( jQuery, jQuery.ui.accordion.prototype ) );
-
-	// icon options
-	(function( $, prototype ) {
-		$.extend( prototype.options.icons, {
-			activeHeader: null, // remove default so we fall back to old values
-			headerSelected: "ui-icon-triangle-1-s"
-		});
-
-		var _createIcons = prototype._createIcons;
-		prototype._createIcons = function() {
-			if ( this.options.icons ) {
-				this.options.icons.activeHeader = this.options.icons.activeHeader ||
-					this.options.icons.headerSelected;
-			}
-			_createIcons.call( this );
-		};
-	}( jQuery, jQuery.ui.accordion.prototype ) );
-
-	// expanded active option, activate method
-	(function( $, prototype ) {
-		prototype.activate = prototype._activate;
-
-		var _findActive = prototype._findActive;
-		prototype._findActive = function( index ) {
-			if ( index === -1 ) {
-				index = false;
-			}
-			if ( index && typeof index !== "number" ) {
-				index = this.headers.index( this.headers.filter( index ) );
-				if ( index === -1 ) {
-					index = false;
-				}
-			}
-			return _findActive.call( this, index );
-		};
-	}( jQuery, jQuery.ui.accordion.prototype ) );
-
-	// resize method
-	jQuery.ui.accordion.prototype.resize = jQuery.ui.accordion.prototype.refresh;
-
-	// change events
-	(function( $, prototype ) {
-		$.extend( prototype.options, {
-			change: null,
-			changestart: null
-		});
-
-		var _trigger = prototype._trigger;
-		prototype._trigger = function( type, event, data ) {
-			var ret = _trigger.apply( this, arguments );
-			if ( !ret ) {
-				return false;
-			}
-
-			if ( type === "beforeActivate" ) {
-				ret = _trigger.call( this, "changestart", event, {
-					oldHeader: data.oldHeader,
-					oldContent: data.oldPanel,
-					newHeader: data.newHeader,
-					newContent: data.newPanel
-				});
-			} else if ( type === "activate" ) {
-				ret = _trigger.call( this, "change", event, {
-					oldHeader: data.oldHeader,
-					oldContent: data.oldPanel,
-					newHeader: data.newHeader,
-					newContent: data.newPanel
-				});
-			}
-			return ret;
-		};
-	}( jQuery, jQuery.ui.accordion.prototype ) );
-
-	// animated option
-	// NOTE: this only provides support for "slide", "bounceslide", and easings
-	// not the full $.ui.accordion.animations API
-	(function( $, prototype ) {
-		$.extend( prototype.options, {
-			animate: null,
-			animated: "slide"
-		});
-
-		var _create = prototype._create;
-		prototype._create = function() {
-			var options = this.options;
-			if ( options.animate === null ) {
-				if ( !options.animated ) {
-					options.animate = false;
-				} else if ( options.animated === "slide" ) {
-					options.animate = 300;
-				} else if ( options.animated === "bounceslide" ) {
-					options.animate = {
-						duration: 200,
-						down: {
-							easing: "easeOutBounce",
-							duration: 1000
-						}
-					};
-				} else {
-					options.animate = options.animated;
-				}
-			}
-
-			_create.call( this );
-		};
-	}( jQuery, jQuery.ui.accordion.prototype ) );
-}
-
 })( jQuery );
Index: admin/js/jquery/jquery.mjs.nestedSortable.js
===================================================================
--- admin/js/jquery/jquery.mjs.nestedSortable.js	(revision 1532)
+++ admin/js/jquery/jquery.mjs.nestedSortable.js	(revision 1532)
@@ -0,0 +1,429 @@
+/*
+ * jQuery UI Nested Sortable
+ * v 1.3.5 / 21 jun 2012
+ * http://mjsarfatti.com/code/nestedSortable
+ *
+ * Depends on:
+ *	 jquery.ui.sortable.js 1.8+
+ *
+ * Copyright (c) 2010-2012 Manuele J Sarfatti
+ * Licensed under the MIT License
+ * http://www.opensource.org/licenses/mit-license.php
+ */
+
+(function($) {
+
+	$.widget("mjs.nestedSortable", $.extend({}, $.ui.sortable.prototype, {
+
+		options: {
+			tabSize: 20,
+			disableNesting: 'mjs-nestedSortable-no-nesting',
+			errorClass: 'mjs-nestedSortable-error',
+			doNotClear: false,
+			listType: 'ol',
+			maxLevels: 0,
+			protectRoot: false,
+			rootID: null,
+			rtl: false,
+			isAllowed: function(item, parent) { return true; }
+		},
+
+		_create: function() {
+			this.element.data('sortable', this.element.data('nestedSortable'));
+
+			if (!this.element.is(this.options.listType))
+				throw new Error('nestedSortable: Please check the listType option is set to your actual list type');
+
+			return $.ui.sortable.prototype._create.apply(this, arguments);
+		},
+
+		destroy: function() {
+			this.element
+				.removeData("nestedSortable")
+				.unbind(".nestedSortable");
+			return $.ui.sortable.prototype.destroy.apply(this, arguments);
+		},
+
+		_mouseDrag: function(event) {
+
+			//Compute the helpers position
+			this.position = this._generatePosition(event);
+			this.positionAbs = this._convertPositionTo("absolute");
+
+			if (!this.lastPositionAbs) {
+				this.lastPositionAbs = this.positionAbs;
+			}
+
+			var o = this.options;
+
+			//Do scrolling
+			if(this.options.scroll) {
+				var scrolled = false;
+				if(this.scrollParent[0] != document && this.scrollParent[0].tagName != 'HTML') {
+
+					if((this.overflowOffset.top + this.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity)
+						this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop + o.scrollSpeed;
+					else if(event.pageY - this.overflowOffset.top < o.scrollSensitivity)
+						this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop - o.scrollSpeed;
+
+					if((this.overflowOffset.left + this.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity)
+						this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft + o.scrollSpeed;
+					else if(event.pageX - this.overflowOffset.left < o.scrollSensitivity)
+						this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft - o.scrollSpeed;
+
+				} else {
+
+					if(event.pageY - $(document).scrollTop() < o.scrollSensitivity)
+						scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed);
+					else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity)
+						scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed);
+
+					if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity)
+						scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed);
+					else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity)
+						scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed);
+
+				}
+
+				if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour)
+					$.ui.ddmanager.prepareOffsets(this, event);
+			}
+
+			//Regenerate the absolute position used for position checks
+			this.positionAbs = this._convertPositionTo("absolute");
+
+      // Find the top offset before rearrangement,
+      var previousTopOffset = this.placeholder.offset().top;
+
+			//Set the helper position
+			if(!this.options.axis || this.options.axis != "y") this.helper[0].style.left = this.position.left+'px';
+			if(!this.options.axis || this.options.axis != "x") this.helper[0].style.top = this.position.top+'px';
+
+			//Rearrange
+			for (var i = this.items.length - 1; i >= 0; i--) {
+
+				//Cache variables and intersection, continue if no intersection
+				var item = this.items[i], itemElement = item.item[0], intersection = this._intersectsWithPointer(item);
+				if (!intersection) continue;
+
+				if(itemElement != this.currentItem[0] //cannot intersect with itself
+					&&	this.placeholder[intersection == 1 ? "next" : "prev"]()[0] != itemElement //no useless actions that have been done before
+					&&	!$.contains(this.placeholder[0], itemElement) //no action if the item moved is the parent of the item checked
+					&& (this.options.type == 'semi-dynamic' ? !$.contains(this.element[0], itemElement) : true)
+					//&& itemElement.parentNode == this.placeholder[0].parentNode // only rearrange items within the same container
+				) {
+
+					$(itemElement).mouseenter();
+
+					this.direction = intersection == 1 ? "down" : "up";
+
+					if (this.options.tolerance == "pointer" || this._intersectsWithSides(item)) {
+						$(itemElement).mouseleave();
+						this._rearrange(event, item);
+					} else {
+						break;
+					}
+
+					// Clear emtpy ul's/ol's
+					this._clearEmpty(itemElement);
+
+					this._trigger("change", event, this._uiHash());
+					break;
+				}
+			}
+
+			var parentItem = (this.placeholder[0].parentNode.parentNode &&
+							 $(this.placeholder[0].parentNode.parentNode).closest('.ui-sortable').length)
+				       			? $(this.placeholder[0].parentNode.parentNode)
+				       			: null,
+			    level = this._getLevel(this.placeholder),
+			    childLevels = this._getChildLevels(this.helper);
+
+      // To find the previous sibling in the list, keep backtracking until we hit a valid list item.
+			var previousItem = this.placeholder[0].previousSibling ? $(this.placeholder[0].previousSibling) : null;
+			if (previousItem != null) {
+				while (previousItem[0].nodeName.toLowerCase() != 'li' || previousItem[0] == this.currentItem[0] || previousItem[0] == this.helper[0]) {
+					if (previousItem[0].previousSibling) {
+						previousItem = $(previousItem[0].previousSibling);
+					} else {
+						previousItem = null;
+						break;
+					}
+				}
+			}
+
+      // To find the next sibling in the list, keep stepping forward until we hit a valid list item.
+      var nextItem = this.placeholder[0].nextSibling ? $(this.placeholder[0].nextSibling) : null;
+      if (nextItem != null) {
+        while (nextItem[0].nodeName.toLowerCase() != 'li' || nextItem[0] == this.currentItem[0] || nextItem[0] == this.helper[0]) {
+          if (nextItem[0].nextSibling) {
+            nextItem = $(nextItem[0].nextSibling);
+          } else {
+            nextItem = null;
+            break;
+          }
+        }
+      }
+
+			var newList = document.createElement(o.listType);
+
+			this.beyondMaxLevels = 0;
+			
+			// If the item is moved to the left, send it to its parent's level unless there are siblings below it.
+			if (parentItem != null && nextItem == null &&
+					(o.rtl && (this.positionAbs.left + this.helper.outerWidth() > parentItem.offset().left + parentItem.outerWidth()) ||
+					!o.rtl && (this.positionAbs.left < parentItem.offset().left))) {
+				parentItem.after(this.placeholder[0]);
+				this._clearEmpty(parentItem[0]);
+				this._trigger("change", event, this._uiHash());
+			}
+			// If the item is below a sibling and is moved to the right, make it a child of that sibling.
+			else if (previousItem != null &&
+						(o.rtl && (this.positionAbs.left + this.helper.outerWidth() < previousItem.offset().left + previousItem.outerWidth() - o.tabSize) ||
+						!o.rtl && (this.positionAbs.left > previousItem.offset().left + o.tabSize))) {
+				this._isAllowed(previousItem, level, level+childLevels+1);
+				if (!previousItem.children(o.listType).length) {
+					previousItem[0].appendChild(newList);
+				}
+        // If this item is being moved from the top, add it to the top of the list.
+        if (previousTopOffset && (previousTopOffset <= previousItem.offset().top)) {
+          previousItem.children(o.listType).prepend(this.placeholder);
+        }
+        // Otherwise, add it to the bottom of the list.
+        else {
+				  previousItem.children(o.listType)[0].appendChild(this.placeholder[0]);
+        }
+				this._trigger("change", event, this._uiHash());
+			}
+			else {
+				this._isAllowed(parentItem, level, level+childLevels);
+			}
+
+			//Post events to containers
+			this._contactContainers(event);
+
+			//Interconnect with droppables
+			if($.ui.ddmanager) $.ui.ddmanager.drag(this, event);
+
+			//Call callbacks
+			this._trigger('sort', event, this._uiHash());
+
+			this.lastPositionAbs = this.positionAbs;
+			return false;
+
+		},
+
+		_mouseStop: function(event, noPropagation) {
+
+			// If the item is in a position not allowed, send it back
+			if (this.beyondMaxLevels) {
+
+				this.placeholder.removeClass(this.options.errorClass);
+
+				if (this.domPosition.prev) {
+					$(this.domPosition.prev).after(this.placeholder);
+				} else {
+					$(this.domPosition.parent).prepend(this.placeholder);
+				}
+
+				this._trigger("revert", event, this._uiHash());
+
+			}
+
+			// Clean last empty ul/ol
+			for (var i = this.items.length - 1; i >= 0; i--) {
+				var item = this.items[i].item[0];
+				this._clearEmpty(item);
+			}
+
+			$.ui.sortable.prototype._mouseStop.apply(this, arguments);
+
+		},
+
+		serialize: function(options) {
+
+			var o = $.extend({}, this.options, options),
+				items = this._getItemsAsjQuery(o && o.connected),
+			    str = [];
+
+			$(items).each(function() {
+				var res = ($(o.item || this).attr(o.attribute || 'id') || '')
+						.match(o.expression || (/(.+)[-=_](.+)/)),
+				    pid = ($(o.item || this).parent(o.listType)
+						.parent(o.items)
+						.attr(o.attribute || 'id') || '')
+						.match(o.expression || (/(.+)[-=_](.+)/));
+
+				if (res) {
+					str.push(((o.key || res[1]) + '[' + (o.key && o.expression ? res[1] : res[2]) + ']')
+						+ '='
+						+ (pid ? (o.key && o.expression ? pid[1] : pid[2]) : o.rootID));
+				}
+			});
+
+			if(!str.length && o.key) {
+				str.push(o.key + '=');
+			}
+
+			return str.join('&');
+
+		},
+
+		toHierarchy: function(options) {
+
+			var o = $.extend({}, this.options, options),
+				sDepth = o.startDepthCount || 0,
+			    ret = [];
+
+			$(this.element).children(o.items).each(function () {
+				var level = _recursiveItems(this);
+				ret.push(level);
+			});
+
+			return ret;
+
+			function _recursiveItems(item) {
+				var id = ($(item).attr(o.attribute || 'id') || '').match(o.expression || (/(.+)[-=_](.+)/));
+				if (id) {
+					var currentItem = {"id" : id[2]};
+					if ($(item).children(o.listType).children(o.items).length > 0) {
+						currentItem.children = [];
+						$(item).children(o.listType).children(o.items).each(function() {
+							var level = _recursiveItems(this);
+							currentItem.children.push(level);
+						});
+					}
+					return currentItem;
+				}
+			}
+		},
+
+		toArray: function(options) {
+
+			var o = $.extend({}, this.options, options),
+				sDepth = o.startDepthCount || 0,
+			    ret = [],
+			    left = 2;
+
+			ret.push({
+				"item_id": o.rootID,
+				"parent_id": 'none',
+				"depth": sDepth,
+				"left": '1',
+				"right": ($(o.items, this.element).length + 1) * 2
+			});
+
+			$(this.element).children(o.items).each(function () {
+				left = _recursiveArray(this, sDepth + 1, left);
+			});
+
+			ret = ret.sort(function(a,b){ return (a.left - b.left); });
+
+			return ret;
+
+			function _recursiveArray(item, depth, left) {
+
+				var right = left + 1,
+				    id,
+				    pid;
+
+				if ($(item).children(o.listType).children(o.items).length > 0) {
+					depth ++;
+					$(item).children(o.listType).children(o.items).each(function () {
+						right = _recursiveArray($(this), depth, right);
+					});
+					depth --;
+				}
+
+				id = ($(item).attr(o.attribute || 'id')).match(o.expression || (/(.+)[-=_](.+)/));
+
+				if (depth === sDepth + 1) {
+					pid = o.rootID;
+				} else {
+					var parentItem = ($(item).parent(o.listType)
+											 .parent(o.items)
+											 .attr(o.attribute || 'id'))
+											 .match(o.expression || (/(.+)[-=_](.+)/));
+					pid = parentItem[2];
+				}
+
+				if (id) {
+						ret.push({"item_id": id[2], "parent_id": pid, "depth": depth, "left": left, "right": right});
+				}
+
+				left = right + 1;
+				return left;
+			}
+
+		},
+
+		_clearEmpty: function(item) {
+
+			var emptyList = $(item).children(this.options.listType);
+			if (emptyList.length && !emptyList.children().length && !this.options.doNotClear) {
+				emptyList.remove();
+			}
+
+		},
+
+		_getLevel: function(item) {
+
+			var level = 1;
+
+			if (this.options.listType) {
+				var list = item.closest(this.options.listType);
+				while (list && list.length > 0 && 
+                    	!list.is('.ui-sortable')) {
+					level++;
+					list = list.parent().closest(this.options.listType);
+				}
+			}
+
+			return level;
+		},
+
+		_getChildLevels: function(parent, depth) {
+			var self = this,
+			    o = this.options,
+			    result = 0;
+			depth = depth || 0;
+
+			$(parent).children(o.listType).children(o.items).each(function (index, child) {
+					result = Math.max(self._getChildLevels(child, depth + 1), result);
+			});
+
+			return depth ? result + 1 : result;
+		},
+
+		_isAllowed: function(parentItem, level, levels) {
+			var o = this.options,
+				isRoot = $(this.domPosition.parent).hasClass('ui-sortable') ? true : false,
+				maxLevels = this.placeholder.closest('.ui-sortable').nestedSortable('option', 'maxLevels'); // this takes into account the maxLevels set to the recipient list
+
+			// Is the root protected?
+			// Are we trying to nest under a no-nest?
+			// Are we nesting too deep?
+			if (!o.isAllowed(this.currentItem, parentItem) ||
+				parentItem && parentItem.hasClass(o.disableNesting) ||
+				o.protectRoot && (parentItem == null && !isRoot || isRoot && level > 1)) {
+					this.placeholder.addClass(o.errorClass);
+					if (maxLevels < levels && maxLevels != 0) {
+						this.beyondMaxLevels = levels - maxLevels;
+					} else {
+						this.beyondMaxLevels = 1;
+					}
+			} else {
+				if (maxLevels < levels && maxLevels != 0) {
+					this.placeholder.addClass(o.errorClass);
+					this.beyondMaxLevels = levels - maxLevels;
+				} else {
+					this.placeholder.removeClass(o.errorClass);
+					this.beyondMaxLevels = 0;
+				}
+			}
+		}
+
+	}));
+
+	$.mjs.nestedSortable.prototype.options = $.extend({}, $.ui.sortable.prototype.options, $.mjs.nestedSortable.prototype.options);
+})(jQuery);
Index: admin/js/jquery/jquery.pageTabs.js
===================================================================
--- admin/js/jquery/jquery.pageTabs.js	(revision 1223)
+++ admin/js/jquery/jquery.pageTabs.js	(revision 1280)
@@ -39,10 +39,9 @@
 				li = document.createElement('li');
 				a = document.createElement('a');
-				$(a).html(this.title);
+				a.appendChild(document.createTextNode(this.title));
 				this.title = '';
 				a.href = '#';
 				a.fn = This.showDiv;
 				a.index = this.id || i;
-				li.id = "part-tabs-"+a.index;
 				a.obj = This;
 				jQuery(a).click(function() { this.fn.call(this.obj,this.index); return false; });
Index: admin/js/jsToolBar/jsToolBar.wysiwyg.js
===================================================================
--- admin/js/jsToolBar/jsToolBar.wysiwyg.js	(revision 925)
+++ admin/js/jsToolBar/jsToolBar.wysiwyg.js	(revision 1626)
@@ -209,5 +209,5 @@
 		
 		This.setSwitcher();
-		setTimeout(function(){This.focusEditor();},1);
+		try { This.iwin.document.designMode = 'on'; } catch (e) {}; // Firefox needs this
 		
 		return true;
Index: admin/js/jsUpload/jquery.fileupload-process.js
===================================================================
--- admin/js/jsUpload/jquery.fileupload-process.js	(revision 1144)
+++ admin/js/jsUpload/jquery.fileupload-process.js	(revision 1320)
@@ -1,4 +1,4 @@
 /*
- * jQuery File Upload Processing Plugin 1.1
+ * jQuery File Upload Processing Plugin 1.2.2
  * https://github.com/blueimp/jQuery-File-Upload
  *
@@ -99,12 +99,18 @@
             var processQueue = [];
             $.each(options.processQueue, function () {
-                var settings = {};
+                var settings = {},
+                    action = this.action,
+                    prefix = this.prefix === true ? action : this.prefix;
                 $.each(this, function (key, value) {
                     if ($.type(value) === 'string' &&
                             value.charAt(0) === '@') {
-                        settings[key] = options[value.slice(1)];
+                        settings[key] = options[
+                            value.slice(1) || (prefix ? prefix +
+                                key.charAt(0).toUpperCase() + key.slice(1) : key)
+                        ];
                     } else {
                         settings[key] = value;
                     }
+
                 });
                 processQueue.push(settings);
@@ -128,5 +134,5 @@
                     this._trigger('processstart');
                 }
-                $.each(data.files, function (index, file) {
+                $.each(data.files, function (index) {
                     var opts = index ? $.extend({}, options) : options,
                         func = function () {
Index: admin/js/jsUpload/jquery.fileupload-ui.js
===================================================================
--- admin/js/jsUpload/jquery.fileupload-ui.js	(revision 1206)
+++ admin/js/jsUpload/jquery.fileupload-ui.js	(revision 1320)
@@ -1,4 +1,4 @@
 /*
- * jQuery File Upload User Interface Plugin 8.2.1
+ * jQuery File Upload User Interface Plugin 8.7.1
  * https://github.com/blueimp/jQuery-File-Upload
  *
@@ -20,5 +20,7 @@
             'jquery',
             'tmpl',
-            './jquery.fileupload-resize',
+            './jquery.fileupload-image',
+            './jquery.fileupload-audio',
+            './jquery.fileupload-video',
             './jquery.fileupload-validate'
         ], factory);
@@ -104,19 +106,7 @@
                     );
                 });
-
-            /*
-             *  
-             *  Activation du bouton si un fichier trouvé
-             */
-                var fileUploadButtonBar = that.element.find('.fileupload-buttonbar');
-                fileUploadButtonBar.find('.start').prop('disabled', false);
-                fileUploadButtonBar.find('.start').removeClass('disabled');
-             /*
-             *
-             */
             },
             // Callback for the start of each file upload request:
             send: function (e, data) {
-                $(this).find('.start').hide();
                 var that = $(this).data('blueimp-fileupload') ||
                         $(this).data('fileupload');
@@ -140,5 +130,4 @@
             // Callback for successful uploads:
             done: function (e, data) {
-
                 var that = $(this).data('blueimp-fileupload') ||
                         $(this).data('fileupload'),
@@ -151,6 +140,6 @@
                     data.context.each(function (index) {
                         var file = files[index] ||
-                                {error: 'Empty file upload result'},
-                            deferred = that._addFinishedDeferreds();
+                                {error: 'Empty file upload result'};
+                        deferred = that._addFinishedDeferreds();
                         that._transition($(this)).done(
                             function () {
@@ -171,6 +160,7 @@
                     });
                 } else {
-                    template = that._renderDownload(files)
-                        .appendTo(that.options.filesContainer);
+                    template = that._renderDownload(files)[
+                        that.options.prependFiles ? 'prependTo' : 'appendTo'
+                    ](that.options.filesContainer);
                     that._forceReflow(template);
                     deferred = that._addFinishedDeferreds();
@@ -227,6 +217,7 @@
                     });
                 } else if (data.errorThrown !== 'abort') {
-                    data.context = that._renderUpload(data.files)
-                        .appendTo(that.options.filesContainer)
+                    data.context = that._renderUpload(data.files)[
+                        that.options.prependFiles ? 'prependTo' : 'appendTo'
+                    ](that.options.filesContainer)
                         .data('data', data);
                     that._forceReflow(data.context);
@@ -281,12 +272,9 @@
             // Callback for uploads start, equivalent to the global ajaxStart event:
             start: function (e) {
-                $(this).find('.start').hide();
                 var that = $(this).data('blueimp-fileupload') ||
-                $(this).data('fileupload');
+                        $(this).data('fileupload');
                 that._resetFinishedDeferreds();
                 that._transition($(this).find('.fileupload-progress')).done(
-
                     function () {
-
                         that._trigger('started', e);
                     }
@@ -295,5 +283,4 @@
             // Callback for uploads stop, equivalent to the global ajaxStop event:
             stop: function (e) {
-                $(this).find('.start').show();
                 var that = $(this).data('blueimp-fileupload') ||
                         $(this).data('fileupload'),
@@ -312,17 +299,4 @@
                     }
                 );
-            /*
-             *  Recherche des fichers restants à uploader
-             *  Désactivation du bouton si plus rien
-             */
-             var filesList = that.options.filesContainer;
-             if(filesList.find('.start').size() == 0) {
-                var fileUploadButtonBar = that.element.find('.fileupload-buttonbar');
-                fileUploadButtonBar.find('.start').prop('disabled', true);
-                fileUploadButtonBar.find('.start').addClass('disabled');
-             }
-            /*
-             *
-             */
             },
             processstart: function () {
@@ -335,7 +309,6 @@
             destroy: function (e, data) {
                 var that = $(this).data('blueimp-fileupload') ||
-                        $(this).data('fileupload');
-                if (data.url) {
-                    $.ajax(data).done(function () {
+                        $(this).data('fileupload'),
+                    removeNode = function () {
                         that._transition(data.context).done(
                             function () {
@@ -344,5 +317,9 @@
                             }
                         );
-                    });
+                    };
+                if (data.url) {
+                    $.ajax(data).done(removeNode);
+                } else {
+                    removeNode();
                 }
             }
@@ -637,4 +614,7 @@
             this._super();
             this._resetFinishedDeferreds();
+            if (!$.support.fileInput) {
+                this._disableFileInputButton();
+            }
         },
 
Index: admin/js/jsUpload/jquery.fileupload.js
===================================================================
--- admin/js/jsUpload/jquery.fileupload.js	(revision 1144)
+++ admin/js/jsUpload/jquery.fileupload.js	(revision 1320)
@@ -1,4 +1,4 @@
 /*
- * jQuery File Upload Plugin 5.31.1
+ * jQuery File Upload Plugin 5.32.2
  * https://github.com/blueimp/jQuery-File-Upload
  *
@@ -11,5 +11,5 @@
 
 /*jslint nomen: true, unparam: true, regexp: true */
-/*global define, window, document, File, Blob, FormData, location */
+/*global define, window, document, location, File, Blob, FormData */
 
 (function (factory) {
@@ -28,4 +28,16 @@
     'use strict';
 
+    // Detect file input support, based on
+    // http://viljamis.com/blog/2012/file-upload-support-on-mobile/
+    $.support.fileInput = !(new RegExp(
+        // Handle devices which give false positives for the feature detection:
+        '(Android (1\\.[0156]|2\\.[01]))' +
+            '|(Windows Phone (OS 7|8\\.0))|(XBLWP)|(ZuneWP)|(WPDesktop)' +
+            '|(w(eb)?OSBrowser)|(webOS)' +
+            '|(Kindle/(1\\.0|2\\.[05]|3\\.0))'
+    ).test(window.navigator.userAgent) ||
+        // Feature detection for all other devices:
+        $('<input type="file">').prop('disabled'));
+
     // The FileReader API is not actually used, but works as feature detection,
     // as e.g. Safari supports XHR file uploads via the FormData API,
@@ -33,4 +45,8 @@
     $.support.xhrFileUpload = !!(window.XMLHttpRequestUpload && window.FileReader);
     $.support.xhrFormDataFileUpload = !!window.FormData;
+
+    // Detect support for Blob slicing (required for chunked uploads):
+    $.support.blobSlice = window.Blob && (Blob.prototype.slice ||
+        Blob.prototype.webkitSlice || Blob.prototype.mozSlice);
 
     // The fileupload widget listens for change events on file input fields defined
@@ -145,11 +161,14 @@
             // widget (via file input selection, drag & drop, paste or add API call).
             // If the singleFileUploads option is enabled, this callback will be
-            // called once for each file in the selection for XHR file uplaods, else
+            // called once for each file in the selection for XHR file uploads, else
             // once for each file selection.
+            //
             // The upload starts when the submit method is invoked on the data parameter.
             // The data object contains a files property holding the added files
-            // and allows to override plugin options as well as define ajax settings.
+            // and allows you to override plugin options as well as define ajax settings.
+            //
             // Listeners for this callback can also be bound the following way:
             // .bind('fileuploadadd', func);
+            //
             // data.submit() returns a Promise object and allows to attach additional
             // handlers using jQuery's Deferred callbacks:
@@ -233,4 +252,9 @@
             'forceIframeTransport'
         ],
+
+        _blobSlice: $.support.blobSlice && function () {
+            var slice = this.slice || this.webkitSlice || this.mozSlice;
+            return slice.apply(this, arguments);
+        },
 
         _BitrateTimer: function () {
@@ -380,7 +404,9 @@
                 options.headers['Content-Range'] = options.contentRange;
             }
-            if (!multipart) {
+            if (!multipart || options.blob || !this._isInstanceOf('File', file)) {
                 options.headers['Content-Disposition'] = 'attachment; filename="' +
                     encodeURI(file.name) + '"';
+            }
+            if (!multipart) {
                 options.contentType = file.type;
                 options.data = options.blob || file;
@@ -415,6 +441,4 @@
                     }
                     if (options.blob) {
-                        options.headers['Content-Disposition'] = 'attachment; filename="' +
-                            encodeURI(file.name) + '"';
                         formData.append(paramName, options.blob, file.name);
                     } else {
@@ -440,4 +464,5 @@
 
         _initIframeSettings: function (options) {
+            var targetHost = $('<a></a>').prop('href', options.url).prop('host');
             // Setting the dataType to iframe enables the iframe transport:
             options.dataType = 'iframe ' + (options.dataType || '');
@@ -445,6 +470,5 @@
             options.formData = this._getFormData(options);
             // Add redirect url to form data on cross-domain uploads:
-            if (options.redirect && $('<a></a>').prop('href', options.url)
-                    .prop('host') !== location.host) {
+            if (options.redirect && targetHost && targetHost !== location.host) {
                 options.formData.push({
                     name: options.redirectParamName || 'redirect',
@@ -628,10 +652,11 @@
         // upload requests:
         _chunkedUpload: function (options, testOnly) {
+            options.uploadedBytes = options.uploadedBytes || 0;
             var that = this,
                 file = options.files[0],
                 fs = file.size,
-                ub = options.uploadedBytes = options.uploadedBytes || 0,
+                ub = options.uploadedBytes,
                 mcs = options.maxChunkSize || fs,
-                slice = file.slice || file.webkitSlice || file.mozSlice,
+                slice = this._blobSlice,
                 dfd = $.Deferred(),
                 promise = dfd.promise(),
@@ -851,5 +876,6 @@
                     pipe = slot.pipe(send);
                 } else {
-                    pipe = (this._sequence = this._sequence.pipe(send, send));
+                    this._sequence = this._sequence.pipe(send, send);
+                    pipe = this._sequence;
                 }
                 // Return the piped Promise object, enhanced with an abort method,
@@ -1101,7 +1127,7 @@
 
         _onDrop: function (e) {
+            e.dataTransfer = e.originalEvent && e.originalEvent.dataTransfer;
             var that = this,
-                dataTransfer = e.dataTransfer = e.originalEvent &&
-                    e.originalEvent.dataTransfer,
+                dataTransfer = e.dataTransfer,
                 data = {};
             if (dataTransfer && dataTransfer.files && dataTransfer.files.length) {
@@ -1117,6 +1143,6 @@
 
         _onDragOver: function (e) {
-            var dataTransfer = e.dataTransfer = e.originalEvent &&
-                e.originalEvent.dataTransfer;
+            e.dataTransfer = e.originalEvent && e.originalEvent.dataTransfer;
+            var dataTransfer = e.dataTransfer;
             if (dataTransfer) {
                 if (this._trigger('dragover', e) === false) {
@@ -1140,7 +1166,9 @@
                 });
             }
-            this._on(this.options.fileInput, {
-                change: this._onChange
-            });
+            if ($.support.fileInput) {
+                this._on(this.options.fileInput, {
+                    change: this._onChange
+                });
+            }
         },
 
@@ -1276,4 +1304,8 @@
                                 return;
                             }
+                            if (!files.length) {
+                                dfd.reject();
+                                return;
+                            }
                             data.files = files;
                             jqXHR = that._onSend(null, data).then(
Index: admin/js/jsUpload/jquery.iframe-transport.js
===================================================================
--- admin/js/jsUpload/jquery.iframe-transport.js	(revision 1144)
+++ admin/js/jsUpload/jquery.iframe-transport.js	(revision 1320)
@@ -1,4 +1,4 @@
 /*
- * jQuery Iframe Transport Plugin 1.6.2
+ * jQuery Iframe Transport Plugin 1.7
  * https://github.com/blueimp/jQuery-File-Upload
  *
@@ -171,5 +171,13 @@
 
     // The iframe transport returns the iframe content document as response.
-    // The following adds converters from iframe to text, json, html, and script:
+    // The following adds converters from iframe to text, json, html, xml
+    // and script.
+    // Please note that the Content-Type for JSON responses has to be text/plain
+    // or text/html, if the browser doesn't include application/json in the
+    // Accept header, else IE will show a download dialog.
+    // The Content-Type for XML responses on the other hand has to be always
+    // application/xml or text/xml, so IE properly parses the XML response.
+    // See also
+    // https://github.com/blueimp/jQuery-File-Upload/wiki/Setup#content-type-negotiation
     $.ajaxSetup({
         converters: {
@@ -182,4 +190,10 @@
             'iframe html': function (iframe) {
                 return iframe && $(iframe[0].body).html();
+            },
+            'iframe xml': function (iframe) {
+                var xmlDoc = iframe && iframe[0];
+                return xmlDoc && $.isXMLDoc(xmlDoc) ? xmlDoc :
+                        $.parseXML((xmlDoc.XMLDocument && xmlDoc.XMLDocument.xml) ||
+                            $(xmlDoc.body).html());
             },
             'iframe script': function (iframe) {
Index: admin/js/jsUpload/template-download.js
===================================================================
--- admin/js/jsUpload/template-download.js	(revision 1461)
+++ admin/js/jsUpload/template-download.js	(revision 1461)
@@ -0,0 +1,1 @@
+var template_download = tmpl('{% for (var i=0, file; file=o.files[i]; i++) { %}<li class="template-download fade"><div class="upload-file"><div class="upload-fileinfo"><span class="upload-filename">{%=file.name%}</span><span class="upload-filesize">({%=o.formatFileSize(file.size)%})</span><span class="upload-filemsg{% if (file.error) { %} upload-error{% } %}">{% if (file.error) { %}'+dotclear.jsUpload.msg.error+' {%=file.error%}{% } else { %}'+dotclear.jsUpload.msg.file_successfully_uploaded+'{% } %}</span></div><div class="upload-progress">{% if (!file.error) { %}<div class="bar" style="width:100%;">100%</div>{% } %}</div></li>{% } %}');
Index: admin/js/jsUpload/template-upload.js
===================================================================
--- admin/js/jsUpload/template-upload.js	(revision 1461)
+++ admin/js/jsUpload/template-upload.js	(revision 1461)
@@ -0,0 +1,1 @@
+var template_upload = tmpl('{% for (var i=0, file; file=o.files[i]; i++) { %}<li class="template-upload fade"><div class="upload-file"><div class="upload-fileinfo"><span class="upload-filename">{%=file.name%}</span><span class="upload-filesize">({%=o.formatFileSize(file.size)%})</span><span class="upload-filecancel cancel">'+dotclear.jsUpload.msg.cancel+'</span>{% if (!o.files.error && !i && !o.options.autoUpload) { %}<input type="submit" class="button start"  value="'+dotclear.jsUpload.msg.send+'"/>{% } %}<span class="upload-filemsg"></span></div>{% if (!o.files.error) { %}<div class="upload-progress progress progress-success progress-striped active"><div class="bar" style="width:0%;"></div></div>{% } %}</li>{% } %}');
Index: admin/js/prelude.js
===================================================================
--- admin/js/prelude.js	(revision 447)
+++ admin/js/prelude.js	(revision 1615)
@@ -6,5 +6,7 @@
 			aElts[i].className="hidden";
 			aElts[i].onfocus=function() {
-				this.className="";
+				$('#prelude a').removeClass('hidden');
+				$('#wrapper').css('padding-top', '1em');
+				$('#help-button').css('top', '4em');
 			}
 		}
@@ -19,2 +21,7 @@
 }
 addLoadEvent(aFocus);
+
+// init
+$(function() {
+	$('#wrapper').css('padding-top', '0');
+});
Index: dmin/js/tool-man/cookies.js
===================================================================
--- admin/js/tool-man/cookies.js	(revision 0)
+++ 	(revision )
@@ -1,34 +1,0 @@
-/* Copyright (c) 2005 Tim Taylor Consulting (see LICENSE.txt)
-
-based on http://www.quirksmode.org/js/cookies.html
-*/
-
-ToolMan._cookieOven = {
-	
-	set : function(name, value, expirationInDays) {
-		if (expirationInDays) {
-			var date = new Date()
-			date.setTime(date.getTime() + (expirationInDays * 24 * 60 * 60 * 1000))
-			var expires = "; expires=" + date.toGMTString()
-		} else {
-			var expires = ""
-		}
-		document.cookie = name + "=" + value + expires + "; path=/"
-	},
-	
-	get : function(name) {
-		var namePattern = name + "="
-		var cookies = document.cookie.split(';')
-		for(var i = 0, n = cookies.length; i < n; i++) {
-			var c = cookies[i]
-			while (c.charAt(0) == ' ') c = c.substring(1, c.length)
-			if (c.indexOf(namePattern) == 0)
-				return c.substring(namePattern.length, c.length)
-		}
-		return null
-	},
-	
-	eraseCookie : function(name) {
-		createCookie(name, "", -1)
-	}
-};
Index: dmin/js/tool-man/coordinates.js
===================================================================
--- admin/js/tool-man/coordinates.js	(revision 0)
+++ 	(revision )
@@ -1,154 +1,0 @@
-/* Copyright (c) 2005 Tim Taylor Consulting (see LICENSE.txt) */
-
-/* FIXME: assumes position styles are specified in 'px' */
-
-ToolMan._coordinatesFactory = {
-	
-	create : function(x, y) {
-		// FIXME: Safari won't parse 'throw' and aborts trying to do anything with this file
-		//if (isNaN(x) || isNaN(y)) throw "invalid x,y: " + x + "," + y
-		return new _ToolManCoordinate(this, x, y)
-	},
-	
-	origin : function() {
-		return this.create(0, 0)
-	},
-	
-	/*
-	 * FIXME: Safari 1.2, returns (0,0) on absolutely positioned elements
-	 */
-	topLeftPosition : function(element) {
-		var left = parseInt(ToolMan.css().readStyle(element, "left"))
-		var left = isNaN(left) ? 0 : left
-		var top = parseInt(ToolMan.css().readStyle(element, "top"))
-		var top = isNaN(top) ? 0 : top
-		
-		return this.create(left, top)
-	},
-	
-	bottomRightPosition : function(element) {
-		return this.topLeftPosition(element).plus(this._size(element))
-	},
-	
-	topLeftOffset : function(element) {
-		var offset = this._offset(element) 
-		
-		var parent = element.offsetParent
-		while (parent) {
-			offset = offset.plus(this._offset(parent))
-			parent = parent.offsetParent
-		}
-		return offset
-	},
-	
-	bottomRightOffset : function(element) {
-		return this.topLeftOffset(element).plus(
-				this.create(element.offsetWidth, element.offsetHeight))
-	},
-	
-	scrollOffset : function() {
-		if (window.pageXOffset) {
-			return this.create(window.pageXOffset, window.pageYOffset)
-		} else if (document.documentElement) {
-			return this.create(
-					document.body.scrollLeft + document.documentElement.scrollLeft, 
-					document.body.scrollTop + document.documentElement.scrollTop)
-		} else if (document.body.scrollLeft >= 0) {
-			return this.create(document.body.scrollLeft, document.body.scrollTop)
-		} else {
-			return this.create(0, 0)
-		}
-	},
-	
-	clientSize : function() {
-		if (window.innerHeight >= 0) {
-			return this.create(window.innerWidth, window.innerHeight)
-		} else if (document.documentElement) {
-			return this.create(document.documentElement.clientWidth,
-					document.documentElement.clientHeight)
-		} else if (document.body.clientHeight >= 0) {
-			return this.create(document.body.clientWidth,
-					document.body.clientHeight)
-		} else {
-			return this.create(0, 0)
-		}
-	},
-	
-	/**
-	 * mouse coordinate relative to the window (technically the
-	 * browser client area) i.e. the part showing your page
-	 *
-	 * NOTE: in Safari the coordinate is relative to the document
-	 */
-	mousePosition : function(event) {
-		event = ToolMan.events().fix(event)
-		return this.create(event.clientX, event.clientY)
-	},
-	
-	/**
-	 * mouse coordinate relative to the document
-	 */
-	mouseOffset : function(event) {
-		event = ToolMan.events().fix(event)
-		if (event.pageX >= 0 || event.pageX < 0) {
-			return this.create(event.pageX, event.pageY)
-		} else if (event.clientX >= 0 || event.clientX < 0) {
-			return this.mousePosition(event).plus(this.scrollOffset())
-		}
-	},
-	
-	_size : function(element) {
-	/* TODO: move to a Dimension class */
-		return this.create(element.offsetWidth, element.offsetHeight)
-	},
-	
-	_offset : function(element) {
-		return this.create(element.offsetLeft, element.offsetTop)
-	}
-}
-
-function _ToolManCoordinate(factory, x, y) {
-	this.factory = factory
-	this.x = isNaN(x) ? 0 : x
-	this.y = isNaN(y) ? 0 : y
-}
-
-_ToolManCoordinate.prototype = {
-	toString : function() {
-		return "(" + this.x + "," + this.y + ")"
-	},
-	
-	plus : function(that) {
-		return this.factory.create(this.x + that.x, this.y + that.y)
-	},
-	
-	minus : function(that) {
-		return this.factory.create(this.x - that.x, this.y - that.y)
-	},
-	
-	min : function(that) {
-		return this.factory.create(
-				Math.min(this.x , that.x), Math.min(this.y , that.y))
-	},
-	
-	max : function(that) {
-		return this.factory.create(
-				Math.max(this.x , that.x), Math.max(this.y , that.y))
-	},
-	
-	constrainTo : function (one, two) {
-		var min = one.min(two)
-		var max = one.max(two)
-		
-		return this.max(min).min(max)
-	},
-	
-	distance : function (that) {
-		return Math.sqrt(Math.pow(this.x - that.x, 2) + Math.pow(this.y - that.y, 2))
-	},
-	
-	reposition : function(element) {
-		element.style["top"] = this.y + "px"
-		element.style["left"] = this.x + "px"
-	}
-}
Index: dmin/js/tool-man/core.js
===================================================================
--- admin/js/tool-man/core.js	(revision 0)
+++ 	(revision )
@@ -1,170 +1,0 @@
-/*
-Copyright (c) 2005 Tim Taylor Consulting <http://tool-man.org/>
-
-Permission is hereby granted, free of charge, to any person obtaining a
-copy of this software and associated documentation files (the "Software"),
-to deal in the Software without restriction, including without limitation
-the rights to use, copy, modify, merge, publish, distribute, sublicense,
-and/or sell copies of the Software, and to permit persons to whom the
-Software is furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included
-in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
-IN THE SOFTWARE.
-*/
-
-var ToolMan = {
-	events : function() {
-		if (!ToolMan._eventsFactory) throw "ToolMan Events module isn't loaded";
-		return ToolMan._eventsFactory
-	},
-	
-	css : function() {
-		if (!ToolMan._cssFactory) throw "ToolMan CSS module isn't loaded";
-		return ToolMan._cssFactory
-	},
-	
-	coordinates : function() {
-		if (!ToolMan._coordinatesFactory) throw "ToolMan Coordinates module isn't loaded";
-		return ToolMan._coordinatesFactory
-	},
-	
-	drag : function() {
-		if (!ToolMan._dragFactory) throw "ToolMan Drag module isn't loaded";
-		return ToolMan._dragFactory
-	},
-	
-	dragsort : function() {
-		if (!ToolMan._dragsortFactory) throw "ToolMan DragSort module isn't loaded";
-		return ToolMan._dragsortFactory
-	},
-	
-	helpers : function() {
-		return ToolMan._helpers
-	},
-	
-	cookies : function() {
-		if (!ToolMan._cookieOven) throw "ToolMan Cookie module isn't loaded";
-		return ToolMan._cookieOven
-	},
-	
-	junkdrawer : function() {
-		return ToolMan._junkdrawer
-	}
-	
-}
-
-ToolMan._helpers = {
-	map : function(array, func) {
-		for (var i = 0, n = array.length; i < n; i++) func(array[i])
-	},
-	
-	nextItem : function(item, nodeName) {
-		if (item == null) return false;
-		var next = item.nextSibling
-		while (next != null) {
-			if (next.nodeName == nodeName) return next
-			next = next.nextSibling
-		}
-		return null
-	},
-	
-	previousItem : function(item, nodeName) {
-		var previous = item.previousSibling
-		while (previous != null) {
-			if (previous.nodeName == nodeName) return previous
-			previous = previous.previousSibling
-		}
-		return null
-	},
-	
-	moveBefore : function(item1, item2) {
-		var parent = item1.parentNode
-		parent.removeChild(item1)
-		parent.insertBefore(item1, item2)
-	},
-	
-	moveAfter : function(item1, item2) {
-		var parent = item1.parentNode
-		parent.removeChild(item1)
-		parent.insertBefore(item1, item2 ? item2.nextSibling : null)
-	}
-}
-
-/** 
- * scripts without a proper home
- *
- * stuff here is subject to change unapologetically and without warning
- */
-ToolMan._junkdrawer = {
-	serializeList : function(list) {
-		var items = list.getElementsByTagName("li")
-		var array = new Array()
-		for (var i = 0, n = items.length; i < n; i++) {
-			var item = items[i]
-			
-			array.push(ToolMan.junkdrawer()._identifier(item))
-		}
-		return array.join('|')
-	},
-	
-	inspectListOrder : function(id) {
-		alert(ToolMan.junkdrawer().serializeList(document.getElementById(id)))
-	},
-	
-	restoreListOrder : function(listID) {
-		var list = document.getElementById(listID)
-		if (list == null) return
-		
-		var cookie = ToolMan.cookies().get("list-" + listID)
-		if (!cookie) return;
-		
-		var IDs = cookie.split('|')
-		var items = ToolMan.junkdrawer()._itemsByID(list)
-		
-		for (var i = 0, n = IDs.length; i < n; i++) {
-			var itemID = IDs[i]
-			if (itemID in items) {
-				var item = items[itemID]
-				list.removeChild(item)
-				list.insertBefore(item, null)
-			}
-		}
-	},
-	
-	_identifier : function(item) {
-		var trim = ToolMan.junkdrawer().trim
-		var identifier
-		
-		identifier = trim(item.getAttribute("id"))
-		if (identifier != null && identifier.length > 0) return identifier;
-		
-		identifier = trim(item.getAttribute("itemID"))
-		if (identifier != null && identifier.length > 0) return identifier;
-		
-		// FIXME: strip out special chars or make this an MD5 hash or something
-		return trim(item.innerHTML)
-	},
-	
-	_itemsByID : function(list) {
-		var array = new Array()
-		var items = list.getElementsByTagName('li')
-		for (var i = 0, n = items.length; i < n; i++) {
-			var item = items[i]
-			array[ToolMan.junkdrawer()._identifier(item)] = item
-		}
-		return array
-	},
-	
-	trim : function(text) {
-		if (text == null) return null
-		return text.replace(/^(\s+)?(.*\S)(\s+)?$/, '$2')
-	}
-}
Index: dmin/js/tool-man/css.js
===================================================================
--- admin/js/tool-man/css.js	(revision 0)
+++ 	(revision )
@@ -1,17 +1,0 @@
-/* Copyright (c) 2005 Tim Taylor Consulting (see LICENSE.txt) */
-
-// TODO: write unit tests
-ToolMan._cssFactory = {
-	readStyle : function(element, property) {
-		if (element.style[property]) {
-			return element.style[property]
-		} else if (element.currentStyle) {
-			return element.currentStyle[property]
-		} else if (document.defaultView && document.defaultView.getComputedStyle) {
-			var style = document.defaultView.getComputedStyle(element, null)
-			return style.getPropertyValue(property)
-		} else {
-			return null
-		}
-	}
-}
Index: dmin/js/tool-man/drag.js
===================================================================
--- admin/js/tool-man/drag.js	(revision 0)
+++ 	(revision )
@@ -1,249 +1,0 @@
-/* Copyright (c) 2005 Tim Taylor Consulting (see LICENSE.txt) */
-
-ToolMan._dragFactory = {
-	createSimpleGroup : function(element, handle) {
-		handle = handle ? handle : element
-		var group = this.createGroup(element)
-		group.setHandle(handle)
-		//group.transparentDrag()
-		group.onTopWhileDragging()
-		return group
-	},
-	
-	createGroup : function(element) {
-		var group = new _ToolManDragGroup(this, element)
-		
-		var position = ToolMan.css().readStyle(element, 'position')
-		if (position == 'static') {
-			element.style["position"] = 'relative'
-		} else if (position == 'absolute') {
-			/* for Safari 1.2 */
-			ToolMan.coordinates().topLeftOffset(element).reposition(element)
-		}
-		
-		// TODO: only if ToolMan.isDebugging()
-		group.register('draginit', this._showDragEventStatus)
-		group.register('dragmove', this._showDragEventStatus)
-		group.register('dragend', this._showDragEventStatus)
-		
-		return group
-	},
-	
-	_showDragEventStatus : function(dragEvent) {
-		window.status = dragEvent.toString()
-	},
-	
-	constraints : function() {
-		return this._constraintFactory
-	},
-	
-	_createEvent : function(type, event, group) {
-		return new _ToolManDragEvent(type, event, group)
-	}
-}
-
-function _ToolManDragGroup(factory, element) {
-	this.factory = factory
-	this.element = element
-	this._handle = null
-	this._thresholdDistance = 0
-	this._transforms = new Array()
-	// TODO: refactor into a helper object, move into events.js
-	this._listeners = new Array()
-	this._listeners['draginit'] = new Array()
-	this._listeners['dragstart'] = new Array()
-	this._listeners['dragmove'] = new Array()
-	this._listeners['dragend'] = new Array()
-}
-
-_ToolManDragGroup.prototype = {
-	/*
-	 * TODO:
-	 *   - unregister(type, func)
-	 *   - move custom event listener stuff into Event library
-	 *   - keyboard nudging of "selected" group
-	 */
-	
-	setHandle : function(handle) {
-		var events = ToolMan.events()
-		
-		handle.toolManDragGroup = this
-		events.register(handle, 'mousedown', this._dragInit)
-		//handle.onmousedown = function() { return false }
-		
-		if (this.element != handle)
-			events.unregister(this.element, 'mousedown', this._dragInit)
-	},
-	
-	register : function(type, func) {
-		this._listeners[type].push(func)
-	},
-	
-	addTransform : function(transformFunc) {
-		this._transforms.push(transformFunc)
-	},
-	
-	verticalOnly : function() {
-		this.addTransform(this.factory.constraints().vertical())
-	},
-	
-	horizontalOnly : function() {
-		this.addTransform(this.factory.constraints().horizontal())
-	},
-	
-	setThreshold : function(thresholdDistance) {
-		this._thresholdDistance = thresholdDistance
-	},
-	
-	transparentDrag : function(opacity) {
-		if (typeof(opacity) == "undefined") {
-			opacity = 0.75;
-		}
-		var originalOpacity = ToolMan.css().readStyle(this.element, "opacity")
-		
-		this.register('dragstart', function(dragEvent) {
-			var element = dragEvent.group.element
-			element.style.opacity = opacity
-			element.style.filter = 'alpha(opacity=' + (opacity * 100) + ')'
-		})
-		this.register('dragend', function(dragEvent) {
-			var element = dragEvent.group.element
-			element.style.opacity = originalOpacity
-			element.style.filter = 'alpha(opacity=100)'
-		})
-	},
-	
-	onTopWhileDragging : function(zIndex) {
-		if (typeof(zIndex) == "undefined") {
-			zIndex = 100000;
-		}
-		
-		var originalZIndex = ToolMan.css().readStyle(this.element, "z-index")
-		
-		this.register('dragstart', function(dragEvent) {
-			dragEvent.group.element.style.zIndex = zIndex
-		})
-		this.register('dragend', function(dragEvent) {
-			if (typeof(originalZIndex) != "undefined") {
-				dragEvent.group.element.style.zIndex = originalZIndex
-			}
-			//dragEvent.group.element.style.backgroundColor = '#f00';
-		})
-	},
-	
-	_dragInit : function(event) {
-		event = ToolMan.events().fix(event)
-		var group = document.toolManDragGroup = this.toolManDragGroup
-		var dragEvent = group.factory._createEvent('draginit', event, group)
-		
-		group._isThresholdExceeded = false
-		group._initialMouseOffset = dragEvent.mouseOffset
-		group._grabOffset = dragEvent.mouseOffset.minus(dragEvent.topLeftOffset)
-		ToolMan.events().register(document, 'mousemove', group._drag)
-		document.onmousemove = function() { return false }
-		ToolMan.events().register(document, 'mouseup', group._dragEnd)
-		
-		ToolMan.events().register(document, 'mousedown',group._drag);
-		document.onmousedown = function() { return false; };
-		
-		group._notifyListeners(dragEvent)
-	},
-	
-	_drag : function(event) {
-		event = ToolMan.events().fix(event)
-		var coordinates = ToolMan.coordinates()
-		var group = this.toolManDragGroup
-		if (!group) return
-		var dragEvent = group.factory._createEvent('dragmove', event, group)
-		
-		var newTopLeftOffset = dragEvent.mouseOffset.minus(group._grabOffset)
-		
-		// TODO: replace with DragThreshold object
-		if (!group._isThresholdExceeded) {
-			var distance = 
-					dragEvent.mouseOffset.distance(group._initialMouseOffset)
-			if (distance < group._thresholdDistance) return
-			group._isThresholdExceeded = true
-			group._notifyListeners(
-					group.factory._createEvent('dragstart', event, group))
-		}
-		
-		for (i in group._transforms) {
-			var transform = group._transforms[i]
-			newTopLeftOffset = transform(newTopLeftOffset, dragEvent)
-		}
-		
-		var dragDelta = newTopLeftOffset.minus(dragEvent.topLeftOffset)
-		var newTopLeftPosition = dragEvent.topLeftPosition.plus(dragDelta)
-		newTopLeftPosition.reposition(group.element)
-		dragEvent.transformedMouseOffset = newTopLeftOffset.plus(group._grabOffset)
-		
-		group._notifyListeners(dragEvent)
-		
-		var errorDelta = newTopLeftOffset.minus(coordinates.topLeftOffset(group.element))
-		if (errorDelta.x != 0 || errorDelta.y != 0) {
-			coordinates.topLeftPosition(group.element).plus(errorDelta).reposition(group.element)
-		}
-	},
-	
-	_dragEnd : function(event) {
-		event = ToolMan.events().fix(event)
-		var group = this.toolManDragGroup
-		var dragEvent = group.factory._createEvent('dragend', event, group)
-		
-		group._notifyListeners(dragEvent)
-		
-		this.toolManDragGroup = null
-		ToolMan.events().unregister(document, 'mousemove', group._drag)
-		document.onmousemove = null
-		ToolMan.events().unregister(document, 'mouseup', group._dragEnd)
-		
-		ToolMan.events().register(document, 'mousedown', group._drag);
-		document.onmousedown = function() { return true };
-	},
-	
-	_notifyListeners : function(dragEvent) {
-		var listeners = this._listeners[dragEvent.type]
-		for (i in listeners) {
-			listeners[i](dragEvent)
-		}
-	}
-}
-
-function _ToolManDragEvent(type, event, group) {
-	this.type = type
-	this.group = group
-	this.mousePosition = ToolMan.coordinates().mousePosition(event)
-	this.mouseOffset = ToolMan.coordinates().mouseOffset(event)
-	this.transformedMouseOffset = this.mouseOffset
-	this.topLeftPosition = ToolMan.coordinates().topLeftPosition(group.element)
-	this.topLeftOffset = ToolMan.coordinates().topLeftOffset(group.element)
-}
-
-_ToolManDragEvent.prototype = {
-	toString : function() {
-		return "mouse: " + this.mousePosition + this.mouseOffset + "    " +
-				"xmouse: " + this.transformedMouseOffset + "    " +
-				"left,top: " + this.topLeftPosition + this.topLeftOffset
-	}
-}
-
-ToolMan._dragFactory._constraintFactory = {
-	vertical : function() {
-		return function(coordinate, dragEvent) {
-			var x = dragEvent.topLeftOffset.x
-			return coordinate.x != x
-					? coordinate.factory.create(x, coordinate.y) 
-					: coordinate
-		}
-	},
-	
-	horizontal : function() {
-		return function(coordinate, dragEvent) {
-			var y = dragEvent.topLeftOffset.y
-			return coordinate.y != y
-					? coordinate.factory.create(coordinate.x, y) 
-					: coordinate
-		}
-	}
-}
Index: dmin/js/tool-man/dragsort.js
===================================================================
--- admin/js/tool-man/dragsort.js	(revision 0)
+++ 	(revision )
@@ -1,87 +1,0 @@
-/* Copyright (c) 2005 Tim Taylor Consulting (see LICENSE.txt) */
-
-ToolMan._dragsortFactory = {
-	makeSortable : function(item) {
-		var group = ToolMan.drag().createSimpleGroup(item)
-		
-		group.register('dragstart', this._onDragStart)
-		group.register('dragmove', this._onDragMove)
-		group.register('dragend', this._onDragEnd)
-		
-		return group
-	},
-	
-	/** 
-	 * Iterates over a list's items, making them sortable, applying
-	 * optional functions to each item.
-	 *
-	 * example: makeListSortable(myList, myFunc1, myFunc2, ... , myFuncN)
-	 */
-	makeListSortable : function(list) {
-		var helpers = ToolMan.helpers()
-		var coordinates = ToolMan.coordinates()
-		var items = list.getElementsByTagName("li")
-		
-		helpers.map(items, function(item) {
-			var dragGroup = dragsort.makeSortable(item)
-			dragGroup.setThreshold(4)
-			var min, max
-			dragGroup.addTransform(function(coordinate, dragEvent) {
-				return coordinate.constrainTo(min, max)
-			})
-			dragGroup.register('dragstart', function() {
-				var items = list.getElementsByTagName("li")
-				min = max = coordinates.topLeftOffset(items[0])
-				for (var i = 1, n = items.length; i < n; i++) {
-					var offset = coordinates.topLeftOffset(items[i])
-					min = min.min(offset)
-					max = max.max(offset)
-				}
-			})
-		})
-		for (var i = 1, n = arguments.length; i < n; i++)
-			helpers.map(items, arguments[i])
-	},
-	
-	_onDragStart : function(dragEvent) {
-	},
-	
-	_onDragMove : function(dragEvent) {
-		var helpers = ToolMan.helpers()
-		var coordinates = ToolMan.coordinates()
-		
-		var item = dragEvent.group.element
-		var xmouse = dragEvent.transformedMouseOffset
-		var moveTo = null
-		
-		var previous = helpers.previousItem(item, item.nodeName)
-		while (previous != null) {
-			var bottomRight = coordinates.bottomRightOffset(previous)
-			if (xmouse.y <= bottomRight.y && xmouse.x <= bottomRight.x) {
-				moveTo = previous
-			}
-			previous = helpers.previousItem(previous, item.nodeName)
-		}
-		if (moveTo != null) {
-			helpers.moveBefore(item, moveTo)
-			return
-		}
-		
-		var next = helpers.nextItem(item, item.nodeName)
-		while (next != null) {
-			var topLeft = coordinates.topLeftOffset(next)
-			if (topLeft.y <= xmouse.y && topLeft.x <= xmouse.x) {
-				moveTo = next
-			}
-			next = helpers.nextItem(next, item.nodeName)
-		}
-		if (moveTo != null) {
-			helpers.moveBefore(item, helpers.nextItem(moveTo, item.nodeName))
-			return
-		}
-	},
-	
-	_onDragEnd : function(dragEvent) {
-		ToolMan.coordinates().create(0, 0).reposition(dragEvent.group.element)
-	}
-}
Index: dmin/js/tool-man/events.js
===================================================================
--- admin/js/tool-man/events.js	(revision 0)
+++ 	(revision )
@@ -1,43 +1,0 @@
-/* Copyright (c) 2005 Tim Taylor Consulting (see LICENSE.txt) */
-
-ToolMan._eventsFactory = {
-	fix : function(event) {
-		if (!event) event = window.event
-		
-		if (event.target) {
-			if (event.target.nodeType == 3) event.target = event.target.parentNode
-		} else if (event.srcElement) {
-			event.target = event.srcElement
-		}
-		
-		return event
-	},
-	
-	register : function(element, type, func) {
-		if (element.addEventListener) {
-			element.addEventListener(type, func, false)
-		} else if (element.attachEvent) {
-			if (!element._listeners) element._listeners = new Array()
-			if (!element._listeners[type]) element._listeners[type] = new Array()
-			var workaroundFunc = function() {
-				func.apply(element, new Array())
-			}
-			element._listeners[type][func] = workaroundFunc
-			element.attachEvent('on' + type, workaroundFunc)
-		}
-	},
-	
-	unregister : function(element, type, func) {
-		if (element.removeEventListener) {
-			element.removeEventListener(type, func, false)
-		} else if (element.detachEvent) {
-			if (element._listeners 
-					&& element._listeners[type] 
-					&& element._listeners[type][func]) {
-						
-				element.detachEvent('on' + type, 
-						element._listeners[type][func])
-			}
-		}
-	}
-}
Index: admin/langs.php
===================================================================
--- admin/langs.php	(revision 1179)
+++ admin/langs.php	(revision 1553)
@@ -129,16 +129,18 @@
 -------------------------------------------------------- */
 dcPage::open(__('Languages management'),
-	dcPage::jsLoad('js/_langs.js')
+	dcPage::jsLoad('js/_langs.js'),
+	dcPage::breadcrumb(
+	array(
+		__('System') => '',
+		'<span class="page-title">'.__('Languages management').'</span>' => ''
+	))
 );
 
-echo
-'<h2 class="page-title">'.__('Languages management').'</h2>';
-
 if (!empty($_GET['removed'])) {
-	dcPage::message(__('Language has been successfully deleted.'));
+	dcPage::success(__('Language has been successfully deleted.'));
 }
 
 if (!empty($_GET['added'])) {
-	dcPage::message(($_GET['added'] == 2 ? __('Language has been successfully upgraded') : __('Language has been successfully installed.')));
+	dcPage::success(($_GET['added'] == 2 ? __('Language has been successfully upgraded') : __('Language has been successfully installed.')));
 }
 
@@ -220,16 +222,15 @@
 	
 	echo
-	'<form method="post" action="langs.php" enctype="multipart/form-data">'.
-	'<fieldset>'.
-	'<legend>'.__('Available languages').'</legend>'.
+	'<form method="post" action="langs.php" enctype="multipart/form-data" class="fieldset">'.
+	'<h4>'.__('Available languages').'</h4>'.
 	'<p>'.sprintf(__('You can download and install a additional language directly from Dotclear.net. '.
 	'Proposed languages are based on your version: %s.'),'<strong>'.DC_VERSION.'</strong>').'</p>'.
-	'<p class="field"><label for="pkg_url" class="classic">'.__('Language:').' '.
-	form::combo(array('pkg_url'),$dc_langs_combo).'</label></p>'.
-	'<p class="field"><label for="your_pwd1" class="classic required"><abbr title="'.__('Required field').'">*</abbr> '.__('Your password:').' '.
-	form::password(array('your_pwd','your_pwd1'),20,255).'</label></p>'.
-	'<input type="submit" value="'.__('Install language').'" />'.
+	'<p class="field"><label for="pkg_url" class="classic">'.__('Language:').'</label> '.
+	form::combo(array('pkg_url'),$dc_langs_combo).'</p>'.
+	'<p class="field"><label for="your_pwd1" class="classic required"><abbr title="'.__('Required field').'">*</abbr> '.__('Your password:').'</label> '.
+	form::password(array('your_pwd','your_pwd1'),20,255).'</p>'.
+	'<p><input type="submit" value="'.__('Install language').'" />'.
 	$core->formNonce().
-	'</fieldset>'.
+	'</p>'.
 	'</form>';
 }
@@ -239,15 +240,14 @@
 	# 'Upload language pack' form
 	echo
-	'<form method="post" action="langs.php" enctype="multipart/form-data">'.
-	'<fieldset>'.
-	'<legend>'.__('Upload a zip file').'</legend>'.
+	'<form method="post" action="langs.php" enctype="multipart/form-data" class="fieldset">'.
+	'<h4>'.__('Upload a zip file').'</h4>'.
 	'<p>'.__('You can install languages by uploading zip files.').'</p>'.
-	'<p class="field"><label for="pkg_file" class="classic required"><abbr title="'.__('Required field').'">*</abbr> '.__('Language zip file:').' '.
-	'<input type="file" id="pkg_file" name="pkg_file" /></label></p>'.
-	'<p class="field"><label for="your_pwd2" class="classic required"><abbr title="'.__('Required field').'">*</abbr> '.__('Your password:').' '.
-	form::password(array('your_pwd','your_pwd2'),20,255).'</label></p>'.
-	'<input type="submit" name="upload_pkg" value="'.__('Upload language').'" />'.
+	'<p class="field"><label for="pkg_file" class="classic required"><abbr title="'.__('Required field').'">*</abbr> '.__('Language zip file:').'</label> '.
+	'<input type="file" id="pkg_file" name="pkg_file" /></p>'.
+	'<p class="field"><label for="your_pwd2" class="classic required"><abbr title="'.__('Required field').'">*</abbr> '.__('Your password:').'</label> '.
+	form::password(array('your_pwd','your_pwd2'),20,255).'</p>'.
+	'<p><input type="submit" name="upload_pkg" value="'.__('Upload language').'" />'.
 	$core->formNonce().
-	'</fieldset>'.
+	'</p>'.
 	'</form>';
 }
Index: admin/media.php
===================================================================
--- admin/media.php	(revision 1234)
+++ admin/media.php	(revision 1678)
@@ -203,7 +203,12 @@
 if ($dir && !empty($_GET['remove']) && empty($_GET['noconfirm']))
 {
-	call_user_func($open_f,__('Media manager'));
-	
-	echo '<h2>'.html::escapeHTML($core->blog->name).' &rsaquo; '.__('Media manager').' &rsaquo; <span class="page-title">'.__('confirm removal').'</span></h2>';
+	call_user_func($open_f,__('Media manager'),'',
+		dcPage::breadcrumb(
+			array(
+				html::escapeHTML($core->blog->name) => '',
+				__('Media manager') => '',
+				'<span class="page-title">'.__('confirm removal').'</span>' => ''
+			),!$popup)
+	);
 	
 	echo
@@ -227,43 +232,57 @@
 $user_ui_enhanceduploader = $core->auth->user_prefs->interface->enhanceduploader;
 
+
+if (!isset($core->media)) {
+	$breadcrumb = dcPage::breadcrumb(
+		array(
+			html::escapeHTML($core->blog->name) => '',
+			'<span class="page-title">'.__('Media manager').'</span>' => ''
+		),!$popup);
+} else {
+	$breadcrumb_media = $core->media->breadCrumb(html::escapeURL($page_url).'&amp;d=%s','<span class="page-title">%s</span>');
+	if ($breadcrumb_media == '') {
+		$breadcrumb = dcPage::breadcrumb(
+			array(
+				html::escapeHTML($core->blog->name) => '',
+				'<span class="page-title">'.__('Media manager').'</span>' => ''
+			),!$popup);
+	} else {
+		$breadcrumb = dcPage::breadcrumb(
+			array(
+				html::escapeHTML($core->blog->name) => '',
+				__('Media manager') => html::escapeURL($page_url.'&d='),
+				$breadcrumb_media => ''
+			),!$popup);
+	}
+}
+
 call_user_func($open_f,__('Media manager'),
 	dcPage::jsLoad('js/_media.js').
-	($core_media_writable ? dcPage::jsUpload(array('d='.$d)) : '')
+	($core_media_writable ? dcPage::jsUpload(array('d='.$d)) : ''),
+	$breadcrumb
 	);
 
 if (!empty($_GET['mkdok'])) {
-	dcPage::message(__('Directory has been successfully created.'));
+	dcPage::success(__('Directory has been successfully created.'));
 }
 
 if (!empty($_GET['upok'])) {
-	dcPage::message(__('Files have been successfully uploaded.'));
+	dcPage::success(__('Files have been successfully uploaded.'));
 }
 
 if (!empty($_GET['rmfok'])) {
-	dcPage::message(__('File has been successfully removed.'));
+	dcPage::success(__('File has been successfully removed.'));
 }
 
 if (!empty($_GET['rmdok'])) {
-	dcPage::message(__('Directory has been successfully removed.'));
+	dcPage::success(__('Directory has been successfully removed.'));
 }
 
 if (!empty($_GET['rebuildok'])) {
-	dcPage::message(__('Directory has been successfully rebuilt.'));
+	dcPage::success(__('Directory has been successfully rebuilt.'));
 }
 
 if (!empty($_GET['unzipok'])) {
-	dcPage::message(__('Zip file has been successfully extracted.'));
-}
-
-echo '<h2>'.html::escapeHTML($core->blog->name).' &rsaquo; ';
-if (!isset($core->media)) {
-	echo '<span class="page-title">'.__('Media manager').'</span></h2>';
-} else {
-	$breadcrumb = $core->media->breadCrumb(html::escapeURL($page_url).'&amp;d=%s','<span class="page-title">%s</span>');
-	if ($breadcrumb == '') {
-		echo '<span class="page-title">'.__('Media manager').'</span></h2>';
-	} else {
-		echo '<a href="'.html::escapeURL($page_url.'&d=').'">'.__('Media manager').'</a>'.' / '.$breadcrumb.'</h2>';
-	}
+	dcPage::success(__('Zip file has been successfully extracted.'));
 }
 
@@ -274,11 +293,11 @@
 
 if ($post_id) {
-	echo '<p><strong>'.sprintf(__('Choose a file to attach to entry %s by clicking on %s.'),
+	echo '<p class="form-note info">'.sprintf(__('Choose a file to attach to entry %s by clicking on %s.'),
 		'<a href="'.$core->getPostAdminURL($post_type,$post_id).'">'.html::escapeHTML($post_title).'</a>',
-		'<img src="images/plus.png" alt="'.__('Attach this file to entry').'" />').'</strong></p>';
+		'<img src="images/plus.png" alt="'.__('Attach this file to entry').'" />').'</p>';
 }
 if ($popup) {
-	echo '<p><strong>'.sprintf(__('Choose a file to insert into entry by clicking on %s.'),
-		'<img src="images/plus.png" alt="'.__('Attach this file to entry').'" />').'</strong></p>';
+	echo '<p class="form-note info">'.sprintf(__('Choose a file to insert into entry by clicking on %s.'),
+		'<img src="images/plus.png" alt="'.__('Attach this file to entry').'" />').'</p>';
 }
 
@@ -288,5 +307,5 @@
 if (count($items) == 0)
 {
-	echo '<p><strong>'.__('No file.').'</strong></p>';
+	echo '<p>'.__('No file.').'</p>';
 }
 else
@@ -298,6 +317,6 @@
 	echo
 	'<form action="media.php" method="get">'.
-	'<p><label for="file_sort" class="classic">'.__('Sort files:').' '.
-	form::combo('file_sort',$sort_combo,$file_sort).'</label>'.
+	'<p><label for="file_sort" class="classic">'.__('Sort files:').'</label> '.
+	form::combo('file_sort',$sort_combo,$file_sort).
 	form::hidden(array('popup'),$popup).
 	form::hidden(array('post_id'),$post_id).
@@ -305,5 +324,5 @@
 	'</form>'.
 	
-	'<p>'.__('Page(s)').' : '.$pager->getLinks().'</p>';
+	'<p class="pagination">'.__('Page(s)').' : '.$pager->getLinks().'</p>';
 	
 	for ($i=$pager->index_start, $j=0; $i<=$pager->index_end; $i++, $j++)
@@ -313,5 +332,5 @@
 	
 	echo
-	'<p class="clear">'.__('Page(s)').' : '.$pager->getLinks().'</p>';
+	'<p class="clear pagination">'.__('Page(s)').' : '.$pager->getLinks().'</p>';
 }
 if (!isset($pager)) {
@@ -335,24 +354,25 @@
 
 	echo
-	'<form id="fileupload" action="'.html::escapeURL($page_url).'" method="POST" enctype="multipart/form-data">'.
-	'<fieldset id="add-file-f"><legend>'.__('Add files').'</legend>'.
+	'<div class="fieldset">'.
+	'<h3>'.__('Add files').'</h3>'.
 	'<p>'.__('Please take care to publish media that you own and that are not protected by copyright.').'</p>'.
-	form::hidden(array('MAX_FILE_SIZE'),DC_MAX_UPLOAD_SIZE).
-	$core->formNonce().
-	'<div class="fileupload-ctrl"><div class="files"></div></div>';
-
-	echo
-	'<div class="fileupload-buttonbar">';
-
-	echo
-	'<p class="max-sier form-note info">&nbsp;'.__('Maximum file size allowed:').' '.files::size(DC_MAX_UPLOAD_SIZE).'</p>'.
-	'<label for="upfile">'.'<span class="add-label one-file">'.__('Choose file').'</span>'.'</label>'.
+	'<p class="max-sizer form-note info">&nbsp;'.__('Maximum file size allowed:').' '.files::size(DC_MAX_UPLOAD_SIZE).'</p>'.
+	'<form id="fileupload" action="'.html::escapeURL($page_url).'" method="post" enctype="multipart/form-data" aria-disabled="false">'.
+	'<p>'.form::hidden(array('MAX_FILE_SIZE'),DC_MAX_UPLOAD_SIZE).
+	$core->formNonce().'</p>'.
+	'<div class="fileupload-ctrl"><p class="queue-message"></p><ul class="files"></ul></div>';
+
+	echo
+	'<div class="fileupload-buttonbar clear">';
+
+	echo
+	'<p><label for="upfile">'.'<span class="add-label one-file">'.__('Choose file').'</span>'.'</label>'.
 	'<button class="button add">'.__('Choose files').'</button>'.
-	'<input type="file" id="upfile" name="upfile[]"'.($user_ui_enhanceduploader?' multiple="mutiple"':'').' data-url="'.html::escapeURL($page_url).'" />';
-
-	echo
-	'<p class="one-file"><label for="upfiletitle">'.__('Title:').form::field(array('upfiletitle','upfiletitle'),35,255).'</label></p>'.
-	'<p class="one-file"><label for="upfilepriv" class="classic">'.form::checkbox(array('upfilepriv','upfilepriv'),1).' '.
-	__('Private').'</label></p>';
+	'<input type="file" id="upfile" name="upfile[]"'.($user_ui_enhanceduploader?' multiple="mutiple"':'').' data-url="'.html::escapeURL($page_url).'" /></p>';
+
+	echo
+	'<p class="one-file"><label for="upfiletitle">'.__('Title:').'</label>'.form::field(array('upfiletitle','upfiletitle'),35,255).'</p>'.
+	'<p class="one-file"><label for="upfilepriv" class="classic">'.__('Private').'</label> '.
+	form::checkbox(array('upfilepriv','upfilepriv'),1).'</p>';
 
 	if (!$user_ui_enhanceduploader) {
@@ -363,26 +383,25 @@
 
 	echo
-	'<button class="button clean">'.__('Refresh').'</button>'.
+	'<p class="clear"><button class="button clean">'.__('Refresh').'</button>'.
 	'<input class="button cancel one-file" type="reset" value="'.__('Clear all').'"/>'.
-	'<input class="button start" type="submit" value="'.__('Upload').'"/>'.
+	'<input class="button start" type="submit" value="'.__('Upload').'"/></p>'.
 	'</div>';
 
 	echo
-	form::hidden(array('d'),$d).
-	'</fieldset>'.
+	'<p style="clear:both;">'.form::hidden(array('d'),$d).'</p>'.
 	'</form>'.
-	'</div>';
-	
+	'</div></div>';
+
 	echo
 	'<div class="col">'.
-	'<form class="clear" action="'.html::escapeURL($page_url).'" method="post">'.
-	'<fieldset id="new-dir-f">'.
-	'<legend>'.__('New directory').'</legend>'.
+	'<form class="clear fieldset" action="'.html::escapeURL($page_url).'" method="post">'.
+	'<div id="new-dir-f">'.
+	'<h3>'.__('New directory').'</h3>'.
 	$core->formNonce().
-	'<p><label for="newdir">'.__('Directory Name:').
-	form::field(array('newdir','newdir'),35,255).'</label></p>'.
+	'<p><label for="newdir">'.__('Directory Name:').'</label>'.
+	form::field(array('newdir','newdir'),35,255).'</p>'.
 	'<p><input type="submit" value="'.__('Create').'" />'.
 	form::hidden(array('d'),html::escapeHTML($d)).'</p>'.
-	'</fieldset>'.
+	'</div>'.
 	'</form></div>';
 	
@@ -403,5 +422,5 @@
 {
 	echo
-	'<p class="zip-dl"><a href="'.html::escapeURL($page_url).'&amp;zipdl=1">'.
+	'<p class="zip-dl"><a class="submit" href="'.html::escapeURL($page_url).'&amp;zipdl=1">'.
 	__('Download this directory as a zip file').'</a></p>';
 }
@@ -428,9 +447,7 @@
 	$class = 'media-item media-col-'.($i%2);
 	
-	$alt = (!$f->d ? sprintf(__('Media details of %s'),$fname) : 
-		sprintf(__('Go to %s folder'),($fname == '..' ? __('parent') : $fname)));
 	$res =
 	'<div class="'.$class.'"><a class="media-icon media-link" href="'.$link.'">'.
-	'<img src="'.$f->media_icon.'" alt="'.$alt.'" /></a>'.
+	'<img src="'.$f->media_icon.'" alt="" /></a>'.
 	'<ul>'.
 	'<li><a class="media-link" href="'.$link.'">'.$fname.'</a></li>';
Index: admin/media_item.php
===================================================================
--- admin/media_item.php	(revision 1179)
+++ admin/media_item.php	(revision 1605)
@@ -175,5 +175,11 @@
 	$starting_scripts.
 	dcPage::jsDatePicker().
-	dcPage::jsPageTabs($tab)
+	dcPage::jsPageTabs($tab),
+	dcPage::breadcrumb(
+		array(
+			html::escapeHTML($core->blog->name) => '',
+			__('Media manager') => html::escapeURL($media_page_url),
+			$core->media->breadCrumb(html::escapeURL($media_page_url).'&amp;d=%s').'<span class="page-title">'.$file->basename.'</span>' => ''
+		),!$popup)
 );
 
@@ -184,13 +190,9 @@
 
 if (!empty($_GET['fupd']) || !empty($_GET['fupl'])) {
-	dcPage::message(__('File has been successfully updated.'));
+	dcPage::success(__('File has been successfully updated.'));
 }
 if (!empty($_GET['thumbupd'])) {
-	dcPage::message(__('Thumbnails have been successfully updated.'));
-}
-
-echo '<h2><a href="'.html::escapeURL($media_page_url).'">'.__('Media manager').'</a>'.
-' / '.$core->media->breadCrumb(html::escapeURL($media_page_url).'&amp;d=%s').
-'<span class="page-title">'.$file->basename.'</span></h2>';
+	dcPage::success(__('Thumbnails have been successfully updated.'));
+}
 
 # Insertion popup
@@ -331,5 +333,5 @@
 	echo
 	'<p><a id="media-insert-cancel" class="button" href="#">'.__('Cancel').'</a> - '.
-	'<strong><a id="media-insert-ok" class="button" href="#">'.__('Insert').'</a></strong>'.
+	'<a id="media-insert-ok" class="button" href="#">'.__('Insert').'</a>'.
 	form::hidden(array('type'),html::escapeHTML($media_type)).
 	form::hidden(array('title'),html::escapeHTML($file->media_title)).
@@ -346,5 +348,6 @@
 
 echo
-'<div id="media-details">';
+'<div id="media-details">'.
+'<div class="near-icon">';
 
 if ($file->media_image)
@@ -355,14 +358,4 @@
 		$thumb_size = 's';
 	}
-	
-	echo '<p>'.__('Available sizes:').' ';
-	foreach (array_reverse($file->media_thumb) as $s => $v)
-	{
-		$strong_link = ($s == $thumb_size) ? '<strong>%s</strong>' : '%s';
-		printf($strong_link,'<a href="'.html::escapeURL($page_url).
-		'&amp;id='.$id.'&amp;size='.$s.'&amp;tab=media-details-tab">'.$core->media->thumb_sizes[$s][2].'</a> | ');
-	}
-	echo '<a href="'.html::escapeURL($page_url).'&amp;id='.$id.'&amp;size=o&amp;tab=media-details-tab">'.__('original').'</a>';
-	echo '</p>';
 	
 	if (isset($file->media_thumb[$thumb_size])) {
@@ -374,4 +367,14 @@
 		echo '<p id="media-original-image"'.$class.'><img src="'.$file->file_url.'?'.time()*rand().'" alt="" /></p>';
 	}
+	
+	echo '<p>'.__('Available sizes:').' ';
+	foreach (array_reverse($file->media_thumb) as $s => $v)
+	{
+		$strong_link = ($s == $thumb_size) ? '<strong>%s</strong>' : '%s';
+		printf($strong_link,'<a href="'.html::escapeURL($page_url).
+		'&amp;id='.$id.'&amp;size='.$s.'&amp;tab=media-details-tab">'.$core->media->thumb_sizes[$s][2].'</a> | ');
+	}
+	echo '<a href="'.html::escapeURL($page_url).'&amp;id='.$id.'&amp;size=o&amp;tab=media-details-tab">'.__('original').'</a>';
+	echo '</p>';
 }
 
@@ -398,6 +401,6 @@
 {
 	echo
-	'<p><strong><a href="'.html::escapeHTML($page_url).'&amp;id='.$id.'&amp;find_posts=1&amp;tab=media-details-tab">'.
-	__('Show entries containing this media').'</a></strong></p>';
+	'<p><a class="button" href="'.html::escapeHTML($page_url).'&amp;id='.$id.'&amp;find_posts=1&amp;tab=media-details-tab">'.
+	__('Show entries containing this media').'</a></p>';
 }
 else
@@ -484,4 +487,8 @@
 }
 
+echo '</div>';
+
+echo '<h3>'.__('Updates and modifications').'</h3>';
+
 if ($file->editable && $core_media_writable)
 {
@@ -489,11 +496,11 @@
 	{
 		echo
-		'<form class="clear" action="'.html::escapeURL($page_url).'" method="post">'.
-		'<fieldset><legend>'.__('Update thumbnails').'</legend>'.
+		'<form class="clear fieldset" action="'.html::escapeURL($page_url).'" method="post">'.
+		'<h4>'.__('Update thumbnails').'</h4>'.
 		'<p>'.__('This will create or update thumbnails for this image.').'</p>'.
 		'<p><input type="submit" name="thumbs" value="'.__('Update thumbnails').'" />'.
 		form::hidden(array('id'),$id).
 		$core->formNonce().'</p>'.
-		'</fieldset></form>';
+		'</form>';
 	}
 	
@@ -506,6 +513,6 @@
 		
 		echo
-		'<form class="clear" id="file-unzip" action="'.html::escapeURL($page_url).'" method="post">'.
-		'<fieldset><legend>'.__('Extract archive').'</legend>'.
+		'<form class="clear fieldset" id="file-unzip" action="'.html::escapeURL($page_url).'" method="post">'.
+		'<h4>'.__('Extract archive').'</h4>'.
 		'<ul>'.
 		'<li><strong>'.__('Extract in a new directory').'</strong> : '.
@@ -514,33 +521,33 @@
 		__('This will extract archive in current directory and will overwrite existing files or directory.').'</li>'.
 		'</ul>'.
-		'<p><label for="inflate_mode" class="classic">'.__('Extract mode:').' '.
-		form::combo('inflate_mode',$inflate_combo,'new').'</label> '.
+		'<p><label for="inflate_mode" class="classic">'.__('Extract mode:').'</label> '.
+		form::combo('inflate_mode',$inflate_combo,'new').
 		'<input type="submit" name="unzip" value="'.__('Extract').'" />'.
 		form::hidden(array('id'),$id).
 		$core->formNonce().'</p>'.
-		'</fieldset></form>';
+		'</form>';
 	}
 	
 	echo
-	'<form class="clear" action="'.html::escapeURL($page_url).'" method="post">'.
-	'<fieldset><legend>'.__('Change media properties').'</legend>'.
-	'<p><label for="media_file">'.__('File name:').
-	form::field('media_file',30,255,html::escapeHTML($file->basename)).'</label></p>'.
-	'<p><label for="media_title">'.__('File title:').
-	form::field('media_title',30,255,html::escapeHTML($file->media_title)).'</label></p>'.
-	'<p><label for="media_dt">'.__('File date:').
-	form::field('media_dt',16,16,html::escapeHTML($file->media_dtstr)).'</label></p>'.
+	'<form class="clear fieldset" action="'.html::escapeURL($page_url).'" method="post">'.
+	'<h4>'.__('Change media properties').'</h4>'.
+	'<p><label for="media_file">'.__('File name:').'</label>'.
+	form::field('media_file',30,255,html::escapeHTML($file->basename)).'</p>'.
+	'<p><label for="media_title">'.__('File title:').'</label>'.
+	form::field('media_title',30,255,html::escapeHTML($file->media_title)).'</p>'.
+	'<p><label for="media_dt">'.__('File date:').'</label>'.
+	form::field('media_dt',16,16,html::escapeHTML($file->media_dtstr)).'</p>'.
 	'<p><label for="media_private" class="classic">'.form::checkbox('media_private',1,$file->media_priv).' '.
 	__('Private').'</label></p>'.
-	'<p><label for="media_path">'.__('New directory:').
-	form::combo('media_path',$dirs_combo,dirname($file->relname)).'</label></p>'.
+	'<p><label for="media_path">'.__('New directory:').'</label>'.
+	form::combo('media_path',$dirs_combo,dirname($file->relname)).'</p>'.
 	'<p><input type="submit" accesskey="s" value="'.__('Save').'" />'.
 	form::hidden(array('id'),$id).
 	$core->formNonce().'</p>'.
-	'</fieldset></form>';
+	'</form>';
 	
 	echo
-	'<form class="clear" action="'.html::escapeURL($page_url).'" method="post" enctype="multipart/form-data">'.
-	'<fieldset><legend>'.__('Change file').'</legend>'.
+	'<form class="clear fieldset" action="'.html::escapeURL($page_url).'" method="post" enctype="multipart/form-data">'.
+	'<h4>'.__('Change file').'</h4>'.
 	'<div>'.form::hidden(array('MAX_FILE_SIZE'),DC_MAX_UPLOAD_SIZE).'</div>'.
 	'<p><label for="upfile">'.__('Choose a file:').
@@ -551,5 +558,5 @@
 	form::hidden(array('id'),$id).
 	$core->formNonce().'</p>'.
-	'</fieldset></form>';
+	'</form>';
 
 	if ($file->del) {
Index: admin/plugin.php
===================================================================
--- admin/plugin.php	(revision 1179)
+++ admin/plugin.php	(revision 1358)
@@ -81,7 +81,11 @@
 else
 {
-	call_user_func($open_f,__('Plugin not found'));
-	
-	echo '<h2 class="page-title">'.__('Plugin not found').'</h2>';
+	call_user_func($open_f,__('Plugin not found'),'',
+		dcPage::breadcrumb(
+			array(
+				__('System') => '',
+				'<span class="page-title">'.__('Plugin not found').'</span>' => ''
+			))
+	);
 	
 	echo '<p>'.__('The plugin you reached does not exist or does not have an admin page.').'</p>';
Index: admin/plugins.php
===================================================================
--- admin/plugins.php	(revision 1271)
+++ admin/plugins.php	(revision 1622)
@@ -191,15 +191,17 @@
 dcPage::open(__('Plugins management'),
 	dcPage::jsLoad('js/_plugins.js').
-	dcPage::jsPageTabs($default_tab)
+	dcPage::jsPageTabs($default_tab),
+	dcPage::breadcrumb(
+		array(
+			__('System') => '',
+			'<span class="page-title">'.__('Plugins management').'</span>' => ''
+		))
 );
 
-echo
-'<h2 class="page-title">'.__('Plugins management').'</h2>';
-
 if (!empty($_GET['removed'])) {
-	dcPage::message(__('Plugin has been successfully deleted.'));
+	dcPage::success(__('Plugin has been successfully deleted.'));
 }
 if (!empty($_GET['added'])) {
-	dcPage::message(($_GET['added'] == 2 ? __('Plugin has been successfully upgraded') : __('Plugin has been successfully installed.')));
+	dcPage::success(($_GET['added'] == 2 ? __('Plugin has been successfully upgraded') : __('Plugin has been successfully installed.')));
 }
 
@@ -233,10 +235,9 @@
 		'<a href="plugin.php?p=daInstaller">'.__('DotAddict.org Installer').'</a>'));
 
-echo '<p>';
 if ($is_writable) {
-	echo __('To install or upgrade a plugin you generally just need to upload it '.
+	echo '<p>'.__('To install or upgrade a plugin you generally just need to upload it '.
 	'in "Install or upgrade a plugin" section.');
 } else {
-	echo __('To install or upgrade a plugin you just need to extract it in your plugins directory.');
+	echo '<p>'.__('To install or upgrade a plugin you just need to extract it in your plugins directory.');
 }
 echo '</p>';
@@ -353,28 +354,25 @@
 	# 'Upload plugin' form
 	echo
-	'<form method="post" action="plugins.php" id="uploadpkg" enctype="multipart/form-data">'.
-	'<fieldset>'.
-	'<legend>'.__('Upload a zip file').'</legend>'.
-	'<p class="field"><label for="pkg_file" class="classic required"><abbr title="'.__('Required field').'">*</abbr> '.__('Plugin zip file:').' '.
-	'<input type="file" id="pkg_file" name="pkg_file" /></label></p>'.
-	'<p class="field"><label for="your_pwd1" class="classic required"><abbr title="'.__('Required field').'">*</abbr> '.__('Your password:').' '.
-	form::password(array('your_pwd','your_pwd1'),20,255).'</label></p>'.
-	'<input type="submit" name="upload_pkg" value="'.__('Upload plugin').'" />'.
+	'<form method="post" action="plugins.php" id="uploadpkg" enctype="multipart/form-data" class="fieldset">'.
+	'<h3>'.__('Upload a zip file').'</h3>'.
+	'<p class="field"><label for="pkg_file" class="classic required"><abbr title="'.__('Required field').'">*</abbr> '.__('Plugin zip file:').'</label> '.
+	'<input type="file" id="pkg_file" name="pkg_file" /></p>'.
+	'<p class="field"><label for="your_pwd1" class="classic required"><abbr title="'.__('Required field').'">*</abbr> '.__('Your password:').'</label> '.
+	form::password(array('your_pwd','your_pwd1'),20,255).'</p>'.
+	'<p><input type="submit" name="upload_pkg" value="'.__('Upload plugin').'" />'.
 	$core->formNonce().
-	'</fieldset>'.
+	'</p>'.
 	'</form>';
 	
 	# 'Fetch plugin' form
 	echo
-	'<form method="post" action="plugins.php" id="fetchpkg">'.
-	'<fieldset>'.
-	'<legend>'.__('Download a zip file').'</legend>'.
-	'<p class="field"><label for="pkg_url" class="classic required"><abbr title="'.__('Required field').'">*</abbr> '.__('Plugin zip file URL:').' '.
-	form::field(array('pkg_url','pkg_url'),40,255).'</label></p>'.
-	'<p class="field"><label for="your_pwd2" class="classic required"><abbr title="'.__('Required field').'">*</abbr> '.__('Your password:').' '.
-	form::password(array('your_pwd','your_pwd2'),20,255).'</label></p>'.
-	'<input type="submit" name="fetch_pkg" value="'.__('Download plugin').'" />'.
-	$core->formNonce().
-	'</fieldset>'.
+	'<form method="post" action="plugins.php" id="fetchpkg" class="fieldset">'.
+	'<h3>'.__('Download a zip file').'</h3>'.
+	'<p class="field"><label for="pkg_url" class="classic required"><abbr title="'.__('Required field').'">*</abbr> '.__('Plugin zip file URL:').'</label> '.
+	form::field(array('pkg_url','pkg_url'),40,255).'</p>'.
+	'<p class="field"><label for="your_pwd2" class="classic required"><abbr title="'.__('Required field').'">*</abbr> '.__('Your password:').'</label> '.
+	form::password(array('your_pwd','your_pwd2'),20,255).'</p>'.
+	'<p><input type="submit" name="fetch_pkg" value="'.__('Download plugin').'" />'.
+	$core->formNonce().'</p>'.
 	'</form>';
 }
@@ -388,9 +386,4 @@
 echo '</div>';
 
-if ($core->plugins->moduleExists('daInstaller')) {
-	echo '<p><a href="plugin.php?p=daInstaller" class="multi-part">'.__('DotAddict.org Installer').'</a></p>';
-}
-
-
 # --BEHAVIOR-- pluginsToolsTabs
 $core->callBehavior('pluginsToolsTabs',$core);
Index: admin/popup_link.php
===================================================================
--- admin/popup_link.php	(revision 1179)
+++ admin/popup_link.php	(revision 1399)
@@ -40,11 +40,11 @@
 echo
 '<form id="link-insert-form" action="#" method="get">'.
-'<p><label class="required"><abbr title="'.__('Required field').'">*</abbr> '.__('Link URL:').' '.
-form::field('href',35,512,html::escapeHTML($href)).'</label></p>'.
-'<p><label>'.__('Link title:').' '. 
-form::field('title',35,512,html::escapeHTML($title)).'</label></p>'. 
-'<p><label>'.__('Link language:').' '.
+'<p><label class="required" for="href"><abbr title="'.__('Required field').'">*</abbr> '.__('Link URL:').'</label> '.
+form::field('href',35,512,html::escapeHTML($href)).'</p>'.
+'<p><label for="title">'.__('Link title:').'</label> '. 
+form::field('title',35,512,html::escapeHTML($title)).'</p>'. 
+'<p><label for="hreflang">'.__('Link language:').'</label> '.
 form::combo('hreflang',$lang_combo,$hreflang).
-'</label></p>'.
+'</p>'.
 
 '</form>'.
Index: admin/popup_posts.php
===================================================================
--- admin/popup_posts.php	(revision 1179)
+++ admin/popup_posts.php	(revision 1399)
@@ -53,14 +53,14 @@
 
 echo '<form action="popup_posts.php" method="post">'.
-	'<p><label for"type" class="classic">'.__('Entry type:').' '.form::combo('type',$type_combo,$type).'</label></p>'.
-	$core->formNonce().
+	'<p><label for"type" class="classic">'.__('Entry type:').'</label> '.form::combo('type',$type_combo,$type).''.
+	$core->formNonce().'</p>'.
 	'<noscript><div><input type="submit" value="'.__('Ok').'" /></div></noscript>'.
 	'</form>';
 
 echo '<form action="popup_posts.php" method="get">'.
-	'<p><label for="q" class="classic">'.__('Search entry:').' '.form::field('q',30,255,html::escapeHTML($q)).'</label> '.
-	' <input type="submit" value="'.__('Search').'" /></p>'.
+	'<p><label for="q" class="classic">'.__('Search entry:').'</label> '.form::field('q',30,255,html::escapeHTML($q)).
+	' <input type="submit" value="'.__('Search').'" />'.
 	form::hidden('type',html::escapeHTML($type)).
-	'</form>';
+	'</p></form>';
 
 try {
Index: admin/post.php
===================================================================
--- admin/post.php	(revision 1537)
+++ admin/post.php	(revision 1625)
@@ -50,4 +50,16 @@
 }
 
+# Getting categories
+$categories_combo = array('&nbsp;' => '');
+try {
+	$categories = $core->blog->getCategories(array('post_type'=>'post'));
+	while ($categories->fetch()) {
+		$categories_combo[] = new formSelectOption(
+			str_repeat('&nbsp;&nbsp;',$categories->level-1).($categories->level-1 == 0 ? '' : '&bull; ').html::escapeHTML($categories->cat_title),
+			$categories->cat_id
+	);
+	}
+} catch (Exception $e) { }
+
 # Status combo
 foreach ($core->blog->getAllPostStatus() as $k => $v) {
@@ -82,4 +94,6 @@
 if (!empty($_REQUEST['id']))
 {
+	$page_title = __('Edit entry');
+	
 	$params['post_id'] = $_REQUEST['id'];
 	
@@ -111,6 +125,4 @@
 		$post_open_tb = (boolean) $post->post_open_tb;
 		
-		$page_title = __('Edit entry');
-		
 		$can_edit_post = $post->isEditable();
 		$can_delete= $post->isDeletable();
@@ -121,5 +133,5 @@
 		if ($next_rs !== null) {
 			$next_link = sprintf($post_link,$next_rs->post_id,
-				html::escapeHTML($next_rs->post_title),__('next entry').'&nbsp;&#187;');
+				html::escapeHTML($next_rs->post_title),__('Next entry').'&nbsp;&#187;');
 			$next_headlink = sprintf($post_headlink,'next',
 				html::escapeHTML($next_rs->post_title),$next_rs->post_id);
@@ -128,5 +140,5 @@
 		if ($prev_rs !== null) {
 			$prev_link = sprintf($post_link,$prev_rs->post_id,
-				html::escapeHTML($prev_rs->post_title),'&#171;&nbsp;'.__('previous entry'));
+				html::escapeHTML($prev_rs->post_title),'&#171;&nbsp;'.__('Previous entry'));
 			$prev_headlink = sprintf($post_headlink,'previous',
 				html::escapeHTML($prev_rs->post_title),$prev_rs->post_id);
@@ -316,4 +328,28 @@
 }
 
+if ($post_id) {
+	switch ($post_status) {
+		case 1:
+			$img_status = sprintf($img_status_pattern,__('Published'),'check-on.png');
+			break;
+		case 0:
+			$img_status = sprintf($img_status_pattern,__('Unpublished'),'check-off.png');
+			break;
+		case -1:
+			$img_status = sprintf($img_status_pattern,__('Scheduled'),'scheduled.png');
+			break;
+		case -2:
+			$img_status = sprintf($img_status_pattern,__('Pending'),'check-wrn.png');
+			break;
+		default:
+			$img_status = '';
+	}
+	$edit_entry_str = __('&ldquo;%s&rdquo;');
+	$page_title_edit = sprintf($edit_entry_str, html::escapeHTML($post_title)).' '.$img_status;
+} else {
+	$img_status = '';
+}
+
+
 dcPage::open($page_title.' - '.__('Entries'),
 	dcPage::jsDatePicker().
@@ -326,22 +362,28 @@
 	$core->callBehavior('adminPostHeaders').
 	dcPage::jsPageTabs($default_tab).
-	$next_headlink."\n".$prev_headlink
+	$next_headlink."\n".$prev_headlink,
+	dcPage::breadcrumb(
+		array(
+			html::escapeHTML($core->blog->name) => '',
+			__('Entries') => 'posts.php',
+			'<span class="page-title">'.($post_id ? $page_title_edit : $page_title).'</span>' => ''
+		))
 );
 
 if (!empty($_GET['upd'])) {
-	dcPage::message(__('Entry has been successfully updated.'));
+	dcPage::success(__('Entry has been successfully updated.'));
 }
 elseif (!empty($_GET['crea'])) {
-	dcPage::message(__('Entry has been successfully created.'));
+	dcPage::success(__('Entry has been successfully created.'));
 }
 elseif (!empty($_GET['attached'])) {
-	dcPage::message(__('File has been successfully attached.'));
+	dcPage::success(__('File has been successfully attached.'));
 }
 elseif (!empty($_GET['rmattach'])) {
-	dcPage::message(__('Attachment has been successfully removed.'));
+	dcPage::success(__('Attachment has been successfully removed.'));
 }
 
 if (!empty($_GET['creaco'])) {
-	dcPage::message(__('Comment has been successfully created.'));
+	dcPage::success(__('Comment has been successfully created.'));
 }
 
@@ -356,37 +398,12 @@
 }
 
-echo '<h2>'.html::escapeHTML($core->blog->name).' &rsaquo; '.'<a href="posts.php">'.__('Entries').'</a> &rsaquo; <span class="page-title">';
-if ($post_id) {
-	switch ($post_status) {
-		case 1:
-			$img_status = sprintf($img_status_pattern,__('published'),'check-on.png');
-			break;
-		case 0:
-			$img_status = sprintf($img_status_pattern,__('unpublished'),'check-off.png');
-			break;
-		case -1:
-			$img_status = sprintf($img_status_pattern,__('scheduled'),'scheduled.png');
-			break;
-		case -2:
-			$img_status = sprintf($img_status_pattern,__('pending'),'check-wrn.png');
-			break;
-		default:
-			$img_status = '';
-	}
-	$edit_entry_str = __('Edit entry &ldquo;%s&rdquo;');
-	echo sprintf($edit_entry_str, html::escapeHTML($post_title)).' '.$img_status;
-} else {
-	echo $page_title;
-}
-echo	'</span></h2>';
-
 if ($post_id && $post->post_status == 1) {
-	echo '<p><a href="'.$post->getURL().'" onclick="window.open(this.href);return false;" title="'.$post_title.' ('.__('new window').')'.'">'.__('Go to this entry on the site').' <img src="images/outgoing-blue.png" alt="" /></a></p>';
+	echo '<p><a class="onblog_link" href="'.$post->getURL().'" onclick="window.open(this.href);return false;" title="'.$post_title.' ('.__('new window').')'.'">'.__('Go to this entry on the site').' <img src="images/outgoing-blue.png" alt="" /></a></p>';
 }
 if ($post_id)
 {
-	echo '<p>';
+	echo '<p class="nav_prevnext">';
 	if ($prev_link) { echo $prev_link; }
-	if ($next_link && $prev_link) { echo ' - '; }
+	if ($next_link && $prev_link) { echo ' | '; }
 	if ($next_link) { echo $next_link; }
 	
@@ -403,37 +420,137 @@
 	exit;
 }
-
 /* Post form if we can edit post
 -------------------------------------------------------- */
 if ($can_edit_post)
 {
-	echo '<div class="multi-part" title="'.__('Edit entry').'" id="edit-entry">';
+	$sidebar_items = new ArrayObject(array(
+		'status-box' => array(
+			'title' => __('Status'),
+			'items' => array(
+				'post_status' => 
+					'<p class="entry-status"><label for="post_status" class="ib">'.__('Entry status').' '.$img_status.'</label>'.
+					form::combo('post_status',$status_combo,$post_status,'maximal','',!$can_publish).
+					'</p>',
+				'post_dt' => 
+					'<p><label for="post_dt" class="ib">'.__('Publication date and hour').'</label>'.
+					form::field('post_dt',16,16,$post_dt,($bad_dt ? 'invalid' : '')).
+					'</p>',
+				'post_lang' =>
+					'<p><label for="post_lang" class="ib">'.__('Entry lang').'</label>'.
+					form::combo('post_lang',$lang_combo,$post_lang).
+					'</p>',
+				'post_format' =>
+					'<div>'.
+					'<h5 id="label_format"><label for="post_format" class="ib">'.__('Text formating').'</label></h5>'.
+					'<p>'.form::combo('post_format',$formaters_combo,$post_format,'maximal').
+					'</p>'.
+					'<p>'.($post_id && $post_format != 'xhtml' ? 
+					'<a id="convert-xhtml" class="button maximal" href="post.php?id='.$post_id.'&amp;xconv=1">'.
+					__('Convert to XHTML').'</a>' : '').'</p></div>')),
+		'metas-box' => array(
+			'title' => __('Ordering'),
+			'items' => array(
+				'post_selected' => 
+					'<p><label for="post_selected" class="classic">'.
+					form::checkbox('post_selected',1,$post_selected).' '.
+					__('Selected entry').'</label></p>',
+				'cat_id' =>
+					'<p><label for="cat_id" class="ib">'.__('Category').'</label>'.
+					form::combo('cat_id',$categories_combo,$cat_id,'maximal').
+					'</p>'.
+					($core->auth->check('categories', $core->blog->id) ?
+						'<div>'.
+						'<h5 id="create_cat">'.__('Add a new category').'</h5>'.
+						'<p><label for="new_cat_title">'.__('Title:').' '.
+						form::field('new_cat_title',30,255,'','maximal').'</label></p>'.
+						'<p><label for="new_cat_parent">'.__('Parent:').' '.
+						form::combo('new_cat_parent',$categories_combo,'','maximal').
+						'</label></p>'.
+						'</div>'
+					: ''))),
+		'options-box' => array(
+			'title' => __('Options'),
+			'items' => array(
+				'post_open_comment' =>
+					'<p><label for="post_open_comment" class="classic">'.
+					form::checkbox('post_open_comment',1,$post_open_comment).' '.
+					__('Accept comments').'</label></p>'.
+					($core->blog->settings->system->allow_comments ? 
+						(isContributionAllowed($post_id,strtotime($post_dt),true) ? 
+							'' :
+							'<p class="form-note warn">'.
+							__('Warning: Comments are not more accepted for this entry.').'</p>') : 
+						'<p class="form-note warn">'.
+						__('Comments are not accepted on this blog so far.').'</p>'),
+				'post_open_tb' =>
+					'<p><label for="post_open_tb" class="classic">'.
+					form::checkbox('post_open_tb',1,$post_open_tb).' '.
+					__('Accept trackbacks').'</label></p>'.
+					($core->blog->settings->system->allow_trackbacks ? 
+						(isContributionAllowed($post_id,strtotime($post_dt),false) ? 
+							'' :
+							'<p class="form-note warn">'.
+							__('Warning: Trackbacks are not more accepted for this entry.').'</p>') : 
+						'<p class="form-note warn">'.__('Trackbacks are not accepted on this blog so far.').'</p>'),
+				'post_password' =>
+					'<p><label for="post_password" class="ib">'.__('Password').'</label>'.
+					form::field('post_password',10,32,html::escapeHTML($post_password),'maximal').
+					'</p>',
+				'post_url' =>
+					'<div class="lockable">'.
+					'<p><label for="post_url" class="ib">'.__('Edit basename').'</label>'.
+					form::field('post_url',10,255,html::escapeHTML($post_url),'maximal').
+					'</p>'.
+					'<p class="form-note warn">'.
+					__('Warning: If you set the URL manually, it may conflict with another entry.').
+					'</p></div>'
+	))));
+
+	$main_items = new ArrayObject(array(
+		"post_title" =>
+			'<p class="col">'.
+			'<label class="required no-margin"><abbr title="'.__('Required field').'">*</abbr> '.__('Title:').'</label>'.
+			form::field('post_title',20,255,html::escapeHTML($post_title),'maximal').
+			'</p>',
+		
+		"post_excerpt" =>
+			'<p class="area" id="excerpt-area"><label for="post_excerpt">'.__('Excerpt:').'<span class="form-note">'.
+			__('Add an introduction to the post.').'</span></label> '.
+			form::textarea('post_excerpt',50,5,html::escapeHTML($post_excerpt)).
+			'</p>',
+		
+		"post_content" =>
+			'<p class="area"><label class="required" '.
+			'for="post_content"><abbr title="'.__('Required field').'">*</abbr> '.__('Content:').'</label> '.
+			form::textarea('post_content',50,$core->auth->getOption('edit_size'),html::escapeHTML($post_content)).
+			'</p>',
+		
+		"post_notes" =>
+			'<p class="area" id="notes-area"><label for="post_notes">'.__('Personal notes:').'<span class="form-note">'.
+			__('Add unpublished notes.').'</span></label>'.
+			form::textarea('post_notes',50,5,html::escapeHTML($post_notes)).
+			'</p>'
+		)
+	);
+	
+	# --BEHAVIOR-- adminPostFormItems
+	$core->callBehavior('adminPostFormItems',$main_items,$sidebar_items, isset($post) ? $post : null);
+
+	echo '<div class="multi-part" title="'.($post_id ? __('Edit entry') : __('New entry')).'" id="edit-entry">';
 	echo '<form action="post.php" method="post" id="entry-form">';
 	echo '<div id="entry-wrapper">';
 	echo '<div id="entry-content"><div class="constrained">';
+
+	echo '<h3 class="hidden">'.__('Edit post').'</h3>';
+	
+	foreach ($main_items as $id => $item) {
+		echo $item;
+	}
+
+	# --BEHAVIOR-- adminPostForm (may be deprecated)
+	$core->callBehavior('adminPostForm',isset($post) ? $post : null);
 	
 	echo
-	'<p class="col"><label class="required"><abbr title="'.__('Required field').'">*</abbr> '.__('Title:').
-	form::field('post_title',20,255,html::escapeHTML($post_title),'maximal').
-	'</label></p>'.
-	
-	'<p class="area" id="excerpt-area"><label for="post_excerpt">'.__('Excerpt:').'</label> '.
-	form::textarea('post_excerpt',50,5,html::escapeHTML($post_excerpt)).
-	'</p>'.
-	
-	'<p class="area"><label class="required" '.
-	'for="post_content"><abbr title="'.__('Required field').'">*</abbr> '.__('Content:').'</label> '.
-	form::textarea('post_content',50,$core->auth->getOption('edit_size'),html::escapeHTML($post_content)).
-	'</p>'.
-	
-	'<p class="area" id="notes-area"><label for="post_notes">'.__('Notes:').'</label>'.
-	form::textarea('post_notes',50,5,html::escapeHTML($post_notes)).
-	'</p>';
-	
-	# --BEHAVIOR-- adminPostForm
-	$core->callBehavior('adminPostForm',isset($post) ? $post : null);
-	
-	echo
-	'<p>'.
+	'<p class="border-top">'.
 	($post_id ? form::hidden('id',$post_id) : '').
 	'<input type="submit" value="'.__('Save').' (s)" '.
@@ -460,74 +577,16 @@
 	echo '<div id="entry-sidebar">';
 	
-	echo
-	'<p><label for="cat_id">'.__('Category:').
-	form::combo('cat_id',$categories_combo,$cat_id,'maximal').
-	'</label></p>'.
-	
-	($core->auth->check('categories', $core->blog->id) ?
-		'<div>'.
-		'<p id="new_cat">'.__('Add a new category').'</p>'.
-		'<p class="form-note info clear">'.__('This category will be created when you will save your post.').'</p>'.
-		'<p><label for="new_cat_title">'.__('Title:').' '.
-		form::field('new_cat_title',30,255,'','maximal').'</label></p>'.
-		'<p><label for="new_cat_parent">'.__('Parent:').' '.
-		form::combo('new_cat_parent',$categories_combo,'','maximal').
-		'</label></p>'.
-		'</div>'
-	: '').
-	
-	'<p><label for="post_status">'.__('Entry status:').
-	form::combo('post_status',$status_combo,$post_status,'','',!$can_publish).
-	'</label></p>'.
-	
-	'<p><label for="post_dt">'.__('Published on:').
-	form::field('post_dt',16,16,$post_dt,($bad_dt ? 'invalid' : '')).
-	'</label></p>'.
-	
-	'<p><label for="post_format">'.__('Text formating:').
-	form::combo('post_format',$formaters_combo,$post_format).
-	'</label>'.
-	'</p>'.
-	'<p>'.($post_id && $post_format != 'xhtml' ? '<a id="convert-xhtml" class="button" href="post.php?id='.$post_id.'&amp;xconv=1">'.__('Convert to XHTML').'</a>' : '').'</p>'.
-	
-	'<p><label for="post_open_comment" class="classic">'.form::checkbox('post_open_comment',1,$post_open_comment).' '.
-	__('Accept comments').'</label></p>'.
-	($core->blog->settings->system->allow_comments ? 
-		(isContributionAllowed($post_id,strtotime($post_dt),true) ? 
-			'' :
-			'<p class="form-note warn">'.__('Warning: Comments are not more accepted for this entry.').'</p>') : 
-		'<p class="form-note warn">'.__('Warning: Comments are not accepted on this blog.').'</p>').
-
-	'<p><label for="post_open_tb" class="classic">'.form::checkbox('post_open_tb',1,$post_open_tb).' '.
-	__('Accept trackbacks').'</label></p>'.
-	($core->blog->settings->system->allow_trackbacks ? 
-		(isContributionAllowed($post_id,strtotime($post_dt),false) ? 
-			'' :
-			'<p class="form-note warn">'.__('Warning: Trackbacks are not more accepted for this entry.').'</p>') : 
-		'<p class="form-note warn">'.__('Warning: Trackbacks are not accepted on this blog.').'</p>').
-
-	'<p><label for="post_selected" class="classic">'.form::checkbox('post_selected',1,$post_selected).' '.
-	__('Selected entry').'</label></p>'.
-	
-	'<p><label for="post_lang">'.__('Entry lang:').
-	form::combo('post_lang',$lang_combo,$post_lang).
-	'</label></p>'.
-	
-	'<p><label for="post_password">'.__('Entry password:').
-	form::field('post_password',10,32,html::escapeHTML($post_password),'maximal').
-	'</label></p>'.
-	
-	'<div class="lockable">'.
-	'<p><label for="post_url">'.__('Basename:').
-	form::field('post_url',10,255,html::escapeHTML($post_url),'maximal').
-	'</label></p>'.
-	'<p class="form-note warn">'.
-	__('Warning: If you set the URL manually, it may conflict with another entry.').
-	'</p>'.
-	'</div>';
-	
-	# --BEHAVIOR-- adminPostFormSidebar
+	foreach ($sidebar_items as $id => $c) {
+		echo '<div id="'.$id.'" class="box">'.
+			'<h4>'.$c['title'].'</h4>';
+		foreach ($c['items'] as $e_name=>$e_content) {
+			echo $e_content;
+		}
+		echo '</div>';
+	}
+	
+	
+	# --BEHAVIOR-- adminPostFormSidebar (may be deprecated)
 	$core->callBehavior('adminPostFormSidebar',isset($post) ? $post : null);
-	
 	echo '</div>';		// End #entry-sidebar
 
@@ -560,8 +619,8 @@
 	if ($can_edit_post && $core->auth->check('publish,contentadmin',$core->blog->id))
 	{
-		$combo_action[__('publish')] = 'publish';
-		$combo_action[__('unpublish')] = 'unpublish';
-		$combo_action[__('mark as pending')] = 'pending';
-		$combo_action[__('mark as junk')] = 'junk';
+		$combo_action[__('Publish')] = 'publish';
+		$combo_action[__('Unpublish')] = 'unpublish';
+		$combo_action[__('Mark as pending')] = 'pending';
+		$combo_action[__('Mark as junk')] = 'junk';
 	}
 	
@@ -571,11 +630,13 @@
 	}
 	
+	echo
+	'<div id="comments" class="multi-part" title="'.__('Comments').'">';
+		
 	# --BEHAVIOR-- adminCommentsActionsCombo
 	$core->callBehavior('adminCommentsActionsCombo',array(&$combo_action));
 	
 	$has_action = !empty($combo_action) && (!$trackbacks->isEmpty() || !$comments->isEmpty());
-	
-	echo
-	'<div id="comments" class="multi-part" title="'.__('Comments').'">';
+	echo 
+	'<p class="top-add"><a class="button add onblog_link" href="#comment-form">'.__('Add a comment').'</a></p>';
 	
 	if ($has_action) {
@@ -611,29 +672,24 @@
 		'</form>';
 	}
-	
-	echo '</div>';
-}
-
-/* Add a comment
--------------------------------------------------------- */
-if ($post_id)
-{
+	/* Add a comment
+	-------------------------------------------------------- */
+
 	echo
-	'<div class="multi-part" id="add-comment" title="'.__('Add a comment').'">'.
+	'<div class="fieldset clear">'.
 	'<h3>'.__('Add a comment').'</h3>'.
 	
 	'<form action="comment.php" method="post" id="comment-form">'.
 	'<div class="constrained">'.
-	'<p><label for="comment_author" class="required"><abbr title="'.__('Required field').'">*</abbr> '.__('Name:').
+	'<p><label for="comment_author" class="required"><abbr title="'.__('Required field').'">*</abbr> '.__('Name:').'</label>'.
 	form::field('comment_author',30,255,html::escapeHTML($core->auth->getInfo('user_cn'))).
-	'</label></p>'.
-	
-	'<p><label for="comment_email">'.__('Email:').
+	'</p>'.
+	
+	'<p><label for="comment_email">'.__('Email:').'</label>'.
 	form::field('comment_email',30,255,html::escapeHTML($core->auth->getInfo('user_email'))).
-	'</label></p>'.
-	
-	'<p><label for="comment_site">'.__('Web site:').
+	'</p>'.
+	
+	'<p><label for="comment_site">'.__('Web site:').'</label>'.
 	form::field('comment_site',30,255,html::escapeHTML($core->auth->getInfo('user_url'))).
-	'</label></p>'.
+	'</p>'.
 	
 	'<p class="area"><label for="comment_content" class="required"><abbr title="'.__('Required field').'">*</abbr> '.
@@ -645,7 +701,9 @@
 	$core->formNonce().
 	'<input type="submit" name="add" value="'.__('Save').'" /></p>'.
-	'</div>'.
+	'</div>'. #constrained
+
 	'</form>'.
-	'</div>';
+	'</div>'. #add comment
+	'</div>'; #comments
 }
 
@@ -677,9 +735,9 @@
 	echo
 	'<table class="comments-list"><tr>'.
-	'<th colspan="2">'.__('Author').'</th>'.
+	'<th colspan="2" class="first">'.__('Author').'</th>'.
 	'<th>'.__('Date').'</th>'.
 	'<th class="nowrap">'.__('IP address').'</th>'.
 	'<th>'.__('Status').'</th>'.
-	'<th>&nbsp;</th>'.
+	'<th>'.__('Edit').'</th>'.
 	'</tr>';
 	
@@ -691,14 +749,14 @@
 		switch ($rs->comment_status) {
 			case 1:
-				$img_status = sprintf($img,__('published'),'check-on.png');
+				$img_status = sprintf($img,__('Published'),'check-on.png');
 				break;
 			case 0:
-				$img_status = sprintf($img,__('unpublished'),'check-off.png');
+				$img_status = sprintf($img,__('Unpublished'),'check-off.png');
 				break;
 			case -1:
-				$img_status = sprintf($img,__('pending'),'check-wrn.png');
+				$img_status = sprintf($img,__('Pending'),'check-wrn.png');
 				break;
 			case -2:
-				$img_status = sprintf($img,__('junk'),'junk.png');
+				$img_status = sprintf($img,__('Junk'),'junk.png');
 				break;
 		}
@@ -715,5 +773,5 @@
 		'<td class="nowrap status">'.$img_status.'</td>'.
 		'<td class="nowrap status"><a href="'.$comment_url.'">'.
-		'<img src="images/edit-mini.png" alt="" title="'.__('Edit this comment').'" /></a></td>'.
+		'<img src="images/edit-mini.png" alt="" title="'.__('Edit this comment').'" /> '.__('Edit').'</a></td>'.
 		
 		'</tr>';
@@ -723,5 +781,5 @@
 }
 
-dcPage::helpBlock('core_post','core_wiki');
+dcPage::helpBlock('core_post','core_trackbacks','core_wiki');
 dcPage::close();
 ?>
Index: admin/posts.php
===================================================================
--- admin/posts.php	(revision 1179)
+++ admin/posts.php	(revision 1596)
@@ -61,5 +61,5 @@
 	}
 	
-	$categories_combo[__('None')] = 'NULL';
+	$categories_combo[__('(No cat)')] = 'NULL';
 	while ($categories->fetch()) {
 		$categories_combo[str_repeat('&nbsp;&nbsp;',$categories->level-1).($categories->level-1 == 0 ? '' : '&bull; ').
@@ -77,6 +77,6 @@
 	$selected_combo = array(
 	'-' => '',
-	__('selected') => '1',
-	__('not selected') => '0'
+	__('Selected') => '1',
+	__('Not selected') => '0'
 	);
 	
@@ -245,51 +245,64 @@
 }
 
-dcPage::open(__('Entries'),$starting_script);
-
+dcPage::open(__('Entries'),$starting_script,
+	dcPage::breadcrumb(
+		array(
+			html::escapeHTML($core->blog->name) => '',
+			'<span class="page-title">'.__('Entries').'</span>' => ''
+		))
+);
+if (!empty($_GET['upd'])) {
+	dcPage::success(__('Selected entries have been successfully updated.'));
+} elseif (!empty($_GET['del'])) {
+	dcPage::success(__('Selected entries have been successfully deleted.'));
+}
 if (!$core->error->flag())
 {
-	echo 
-	'<h2>'.html::escapeHTML($core->blog->name).' &rsaquo; <span class="page-title">'.__('Entries').'</span></h2>'.
+	echo
 	'<p class="top-add"><a class="button add" href="post.php">'.__('New entry').'</a></p>';
 	
 	if (!$show_filters) {
 		echo '<p><a id="filter-control" class="form-control" href="#">'.
-		__('Filters').'</a></p>';
+		__('Filter posts list').'</a></p>';
 	}
 	
 	echo
 	'<form action="posts.php" method="get" id="filters-form">'.
-	'<fieldset><legend>'.__('Filters').'</legend>'.
-	'<div class="three-cols">'.
-	'<div class="col">'.
-	'<label for="user_id">'.__('Author:').
-	form::combo('user_id',$users_combo,$user_id).'</label> '.
-	'<label for="cat_id">'.__('Category:').
-	form::combo('cat_id',$categories_combo,$cat_id).'</label> '.
-	'<label for="status">'.__('Status:').
-	form::combo('status',$status_combo,$status).'</label> '.
-	'</div>'.
-	
-	'<div class="col">'.
-	'<label for="selected">'.__('Selected:').
-	form::combo('selected',$selected_combo,$selected).'</label> '.
-	'<label for="month">'.__('Month:').
-	form::combo('month',$dt_m_combo,$month).'</label> '.
-	'<label for="lang">'.__('Lang:').
-	form::combo('lang',$lang_combo,$lang).'</label> '.
-	'</div>'.
-	
-	'<div class="col">'.
-	'<p><label for="sortby">'.__('Order by:').
-	form::combo('sortby',$sortby_combo,$sortby).'</label> '.
-	'<label for="order">'.__('Sort:').
-	form::combo('order',$order_combo,$order).'</label></p>'.
-	'<p><label for="nb" class="classic">'.	form::field('nb',3,3,$nb_per_page).' '.
-	__('Entries per page').'</label></p> '.
-	'<p><input type="submit" value="'.__('Apply filters').'" /></p>'.
-	'</div>'.
-	'</div>'.
-	'<br class="clear" />'. //Opera sucks
-	'</fieldset>'.
+	'<h3 class="hidden">'.__('Filter posts list').'</h3>'.
+
+	'<div class="table">'.
+	'<div class="cell">'.
+	'<h4>'.__('Filters').'</h4>'.
+	'<p><label for="user_id" class="ib">'.__('Author:').'</label> '.
+	form::combo('user_id',$users_combo,$user_id).'</p>'.
+	'<p><label for="cat_id" class="ib">'.__('Category:').'</label> '.
+	form::combo('cat_id',$categories_combo,$cat_id).'</p>'.
+	'<p><label for="status" class="ib">'.__('Status:').'</label> ' .
+	form::combo('status',$status_combo,$status).'</p> '.
+	'</div>'.
+	
+	'<div class="cell filters-sibling-cell">'.
+	'<p><label for="selected" class="ib">'.__('Selected:').'</label> '.
+	form::combo('selected',$selected_combo,$selected).'</p>'.
+	'<p><label for="month" class="ib">'.__('Month:').'</label> '.
+	form::combo('month',$dt_m_combo,$month).'</p>'.
+	'<p><label for="lang" class="ib">'.__('Lang:').'</label> '.
+	form::combo('lang',$lang_combo,$lang).'</p> '.
+	'</div>'.
+	
+	'<div class="cell filters-options">'.
+	'<h4>'.__('Display options').'</h4>'.
+	'<p><label for="sortby" class="ib">'.__('Order by:').'</label> '.
+	form::combo('sortby',$sortby_combo,$sortby).'</p>'.
+	'<p><label for="order" class="ib">'.__('Sort:').'</label> '.
+	form::combo('order',$order_combo,$order).'</p>'.
+	'<p><span class="label ib">'.__('Show').'</span> <label for="nb" class="classic">'.
+	form::field('nb',3,3,$nb_per_page).' '.
+	__('entries per page').'</label></p>'.
+	'</div>'.
+	'</div>'.
+
+	'<p><input type="submit" value="'.__('Apply filters and display options').'" />'.
+	'<br class="clear" /></p>'. //Opera sucks
 	'</form>';
 	
Index: admin/posts_actions.php
===================================================================
--- admin/posts_actions.php	(revision 1421)
+++ admin/posts_actions.php	(revision 1637)
@@ -16,182 +16,325 @@
 
 $params = array();
-$action = '';
+
+/**
+* FieldsList - Compatibility class for hidden fields & entries[] fields
+*
+*/
+class FieldsList {
+	/** @var array list of hidden fields */
+	protected $hidden;
+	/** @var array list of selected entries */
+	protected $entries;
+
+
+   /**
+     * Class constructor
+	*/
+	public function __construct() {
+		$this->hidden=array();
+		$this->entries =array();
+	}
+
+    /**
+     * addHidden - adds a hidden field
+     * 
+     * @param string $name the field name.
+     * @param mixed $value the field value.
+     *
+     * @access public
+	 * @return the FieldsList instance, enabling to chain requests
+     */	
+	 public function addHidden($name,$value) {
+		$this->hidden[] = form::hidden($name,$value);
+		return $this;
+	}
+
+    /**
+     * addEntry - adds a antry field
+     * 
+     * @param string $id the entry id.
+     * @param mixed $title the entry title.
+     *
+     * @access public
+	 * @return the FieldsList instance, enabling to chain requests
+     */	
+	 public function addEntry($id,$title) {
+		$this->entries[$id]=$title;
+		return $this;
+	}
+
+    /**
+     * getHidden - returns the list of hidden fields, html encoded
+     *
+     * @access public
+	 * @return the list of hidden fields, html encoded
+     */
+	 public function getHidden() {
+		return join('',$this->hidden);
+	}
+	
+    /**
+     * getEntries - returns the list of entry fields, html encoded
+     *
+	 * @param boolean $hidden if set to true, returns entries as a list of hidden field
+	 *                if set to false, returns html code displaying the list of entries
+	 *                with a list of checkboxes to enable to select/deselect entries
+     * @access public
+	 * @return the list of entry fields, html encoded
+     */
+	public function getEntries ($hidden=false) {
+		$ret = '';
+		if ($hidden) {
+			foreach ($this->entries as $id=> $e) {
+				$ret .= form::hidden('entries[]',$id);
+			}
+		} else {
+			$ret = 
+				'<table class="posts-list"><tr>'.
+				'<th colspan="2">'.__('Title').'</th>'.
+				'</tr>';
+			foreach ($this->entries as $id=>$title) {
+				$ret .= 
+					'<tr><td>'.
+					form::checkbox(array('entries[]'),$id,true,'','').'</td>'.
+					'<td>'.	$title.'</td></tr>';
+			}
+			$ret .= '</table>';
+		}
+		return $ret;
+	}
+	
+    /**
+     * getEntriesQS - returns the list of entry fields as query string
+     *
+     * @access public
+	 * @return the list of entry fields, html encoded
+     */
+	public function getEntriesQS() {
+		$ret=array();
+		foreach ($this->entries as $id=>$title) {
+			$ret[] = 'entries[]='.$id;
+		}
+		return join('&',$ret);
+	}
+	
+    /**
+     * __toString - magic method. -- DEPRECATED here
+	 *              This method is only used to preserve compatibility with plugins 
+	 *				relying on previous versions of adminPostsActionsContent behavior, 
+	 *
+     * @access public
+	 * @return the list of hidden fields and entries (as hidden fields too), html encoded
+     */
+	public function __toString() {
+		return join('',$this->hidden).$this->getEntries(true);
+	}
+}
+
+$fields = new FieldsList();
+$posts_ids = array();
+
+if (isset($_POST['redir']) && strpos($_POST['redir'],'://') === false)
+{
+	$redir = $_POST['redir'];
+}
+else
+{
+	$redir =
+	'posts.php?user_id='.$_POST['user_id'].
+	'&cat_id='.$_POST['cat_id'].
+	'&status='.$_POST['status'].
+	'&selected='.$_POST['selected'].
+	'&month='.$_POST['month'].
+	'&lang='.$_POST['lang'].
+	'&sortby='.$_POST['sortby'].
+	'&order='.$_POST['order'].
+	'&page='.$_POST['page'].
+	'&nb='.$_POST['nb'];
+}
+$redir_sel = $redir;
+
+if (!empty($_POST['entries']))
+{
+	$entries = $_POST['entries'];
+	
+	foreach ($entries as $k => $v) {
+		$entries[$k] = (integer) $v;
+	}
+	
+	$params['sql'] = 'AND P.post_id IN('.implode(',',$entries).') ';
+	
+	if (!isset($_POST['full_content']) || empty($_POST['full_content'])) {
+		$params['no_content'] = true;
+	}
+	
+	if (isset($_POST['post_type'])) {
+		$params['post_type'] = $_POST['post_type'];
+	}
+	
+	$posts = $core->blog->getPosts($params);
+	while ($posts->fetch())	{
+		$posts_ids[] = $posts->post_id;
+		$fields->addEntry($posts->post_id,$posts->post_title);
+	}
+	// Redirection including selected entries
+	$redir_sel = $redir.'&'.$fields->getEntriesQS();
+
+} else {
+	$posts = $core->con->select("SELECT blog_id FROM ".$core->prefix."blog WHERE false");;
+}
 
 /* Actions
 -------------------------------------------------------- */
-if (!empty($_POST['action']) && !empty($_POST['entries']))
-{
-	$entries = $_POST['entries'];
+if (!empty($_POST['action']))
+{
 	$action = $_POST['action'];
-	
-	if (isset($_POST['redir']) && strpos($_POST['redir'],'://') === false)
-	{
-		$redir = $_POST['redir'];
-	}
-	else
-	{
-		$redir =
-		'posts.php?user_id='.$_POST['user_id'].
-		'&cat_id='.$_POST['cat_id'].
-		'&status='.$_POST['status'].
-		'&selected='.$_POST['selected'].
-		'&month='.$_POST['month'].
-		'&lang='.$_POST['lang'].
-		'&sortby='.$_POST['sortby'].
-		'&order='.$_POST['order'].
-		'&page='.$_POST['page'].
-		'&nb='.$_POST['nb'];
-	}
-	
-	foreach ($entries as $k => $v) {
-		$entries[$k] = (integer) $v;
-	}
-	
-	$params['sql'] = 'AND P.post_id IN('.implode(',',$entries).') ';
-	
-	if (!isset($_POST['full_content']) || empty($_POST['full_content'])) {
-		$params['no_content'] = true;
-	}
-	
-	if (isset($_POST['post_type'])) {
-		$params['post_type'] = $_POST['post_type'];
-	}
-	
-	$posts = $core->blog->getPosts($params);
-	
-	$posts_ids = array();
-	while ($posts->fetch())	{
-		$posts_ids[] = $posts->post_id;
-	}
-	
-	# --BEHAVIOR-- adminPostsActions
-	$core->callBehavior('adminPostsActions',$core,$posts,$action,$redir);
-	
-	if (preg_match('/^(publish|unpublish|schedule|pending)$/',$action))
-	{
-		switch ($action) {
-			case 'unpublish' : $status = 0; break;
-			case 'schedule' : $status = -1; break;
-			case 'pending' : $status = -2; break;
-			default : $status = 1; break;
-		}
-		
-		try
+} 
+else
+{
+	$core->error->add(__('No action specified.'));
+	dcPage::open(
+		__('Entries'),'',dcPage::breadcrumb(
+		array(
+			html::escapeHTML($core->blog->name) => '',
+			__('Entries') => 'posts.php',
+			'<span class="page-title">'.__('Entries actions').'</span>' => ''
+		))
+	);
+	
+	echo '<p><a class="back" href="'.html::escapeURL($redir_sel).'">'.__('Back to entries list').'</a></p>';
+
+	dcPage::close();
+	exit;
+}
+
+# --BEHAVIOR-- adminPostsActions
+$core->callBehavior('adminPostsActions',$core,$posts,$action,$redir);
+
+if (preg_match('/^(publish|unpublish|schedule|pending)$/',$action))
+{
+	switch ($action) {
+		case 'unpublish' : $status = 0; break;
+		case 'schedule' : $status = -1; break;
+		case 'pending' : $status = -2; break;
+		default : $status = 1; break;
+	}
+	
+	try
+	{
+		$core->blog->updPostsStatus($posts_ids,$status);
+		
+		http::redirect($redir_sel.'&upd=1');
+	}
+	catch (Exception $e)
+	{
+		$core->error->add($e->getMessage());
+	}
+}
+elseif ($action == 'selected' || $action == 'unselected')
+{
+	try
+	{
+		$core->blog->updPostsSelected($posts_ids,$action == 'selected');
+		
+		http::redirect($redir_sel."&upd=1");
+	}
+	catch (Exception $e)
+	{
+		$core->error->add($e->getMessage());
+	}
+}
+elseif ($action == 'delete')
+{
+	try
+	{
+		// Backward compatibility
+		foreach($posts_ids as $post_id)
 		{
-			$core->blog->updPostsStatus($posts_ids,$status);
+			# --BEHAVIOR-- adminBeforePostDelete
+			$core->callBehavior('adminBeforePostDelete',(integer) $post_id);
+		}
+		
+		# --BEHAVIOR-- adminBeforePostsDelete
+		$core->callBehavior('adminBeforePostsDelete',$posts_ids);
+		
+		$core->blog->delPosts($posts_ids);
+		
+		http::redirect($redir."&del=1");
+	}
+	catch (Exception $e)
+	{
+		$core->error->add($e->getMessage());
+	}
+	
+}
+elseif ($action == 'category' && isset($_POST['new_cat_id']))
+{
+	$new_cat_id = $_POST['new_cat_id'];
+	
+	try
+	{
+		if (!empty($_POST['new_cat_title']) && $core->auth->check('categories', $core->blog->id))
+		{
+			$cur_cat = $core->con->openCursor($core->prefix.'category');
+			$cur_cat->cat_title = $_POST['new_cat_title'];
+			$cur_cat->cat_url = '';
 			
-			http::redirect($redir);
-		}
-		catch (Exception $e)
-		{
-			$core->error->add($e->getMessage());
-		}
-	}
-	elseif ($action == 'selected' || $action == 'unselected')
-	{
-		try
-		{
-			$core->blog->updPostsSelected($posts_ids,$action == 'selected');
+			$parent_cat = !empty($_POST['new_cat_parent']) ? $_POST['new_cat_parent'] : '';
 			
-			http::redirect($redir);
-		}
-		catch (Exception $e)
-		{
-			$core->error->add($e->getMessage());
-		}
-	}
-	elseif ($action == 'delete')
-	{
-		try
-		{
-			// Backward compatibility
-			foreach($posts_ids as $post_id)
-			{
-				# --BEHAVIOR-- adminBeforePostDelete
-				$core->callBehavior('adminBeforePostDelete',(integer) $post_id);
-			}
+			# --BEHAVIOR-- adminBeforeCategoryCreate
+			$core->callBehavior('adminBeforeCategoryCreate', $cur_cat);
 			
-			# --BEHAVIOR-- adminBeforePostsDelete
-			$core->callBehavior('adminBeforePostsDelete',$posts_ids);
+			$new_cat_id = $core->blog->addCategory($cur_cat, (integer) $parent_cat);
 			
-			$core->blog->delPosts($posts_ids);
-			
-			http::redirect($redir);
-		}
-		catch (Exception $e)
-		{
-			$core->error->add($e->getMessage());
-		}
-		
-	}
-	elseif ($action == 'category' && isset($_POST['new_cat_id']))
-	{
-		$new_cat_id = $_POST['new_cat_id'];
-		
-		try
-		{
-			if (!empty($_POST['new_cat_title']) && $core->auth->check('categories', $core->blog->id))
-			{
-				$cur_cat = $core->con->openCursor($core->prefix.'category');
-				$cur_cat->cat_title = $_POST['new_cat_title'];
-				$cur_cat->cat_url = '';
-				
-				$parent_cat = !empty($_POST['new_cat_parent']) ? $_POST['new_cat_parent'] : '';
-				
-				# --BEHAVIOR-- adminBeforeCategoryCreate
-				$core->callBehavior('adminBeforeCategoryCreate', $cur_cat);
-				
-				$new_cat_id = $core->blog->addCategory($cur_cat, (integer) $parent_cat);
-				
-				# --BEHAVIOR-- adminAfterCategoryCreate
-				$core->callBehavior('adminAfterCategoryCreate', $cur_cat, $new_cat_id);
-			}
-			
-			$core->blog->updPostsCategory($posts_ids, $new_cat_id);
-			
-			http::redirect($redir);
-		}
-		catch (Exception $e)
-		{
-			$core->error->add($e->getMessage());
-		}
-	}
-	elseif ($action == 'author' && isset($_POST['new_auth_id'])
-	&& $core->auth->check('admin',$core->blog->id))
-	{
-		$new_user_id = $_POST['new_auth_id'];
-		
-		try
-		{
-			if ($core->getUser($new_user_id)->isEmpty()) {
-				throw new Exception(__('This user does not exist'));
-			}
-			
-			$cur = $core->con->openCursor($core->prefix.'post');
-			$cur->user_id = $new_user_id;
-			$cur->update('WHERE post_id '.$core->con->in($posts_ids));
-			
-			http::redirect($redir);
-		}
-		catch (Exception $e)
-		{
-			$core->error->add($e->getMessage());
-		}
-	}
-	elseif ($action == 'lang' && isset($_POST['new_lang']))
-	{
-		$new_lang = $_POST['new_lang'];
-		try
-		{
-			$cur = $core->con->openCursor($core->prefix.'post');
-			$cur->post_lang = $new_lang;
-			$cur->update('WHERE post_id '.$core->con->in($posts_ids));
-			
-			http::redirect($redir);
-		}
-		catch (Exception $e)
-		{
-			$core->error->add($e->getMessages());
-		}
+			# --BEHAVIOR-- adminAfterCategoryCreate
+			$core->callBehavior('adminAfterCategoryCreate', $cur_cat, $new_cat_id);
+		}
+		
+		$core->blog->updPostsCategory($posts_ids, $new_cat_id);
+		
+		http::redirect($redir_sel."&upd=1");
+	}
+	catch (Exception $e)
+	{
+		$core->error->add($e->getMessage());
+	}
+}
+elseif ($action == 'author' && isset($_POST['new_auth_id'])
+&& $core->auth->check('admin',$core->blog->id))
+{
+	$new_user_id = $_POST['new_auth_id'];
+	
+	try
+	{
+		if ($core->getUser($new_user_id)->isEmpty()) {
+			throw new Exception(__('This user does not exist'));
+		}
+		
+		$cur = $core->con->openCursor($core->prefix.'post');
+		$cur->user_id = $new_user_id;
+		$cur->update('WHERE post_id '.$core->con->in($posts_ids));
+		
+		http::redirect($redir_sel."&upd=1");
+	}
+	catch (Exception $e)
+	{
+		$core->error->add($e->getMessage());
+	}
+}
+elseif ($action == 'lang' && isset($_POST['new_lang']))
+{
+	$new_lang = $_POST['new_lang'];
+	try
+	{
+		$cur = $core->con->openCursor($core->prefix.'post');
+		$cur->post_lang = $new_lang;
+		$cur->update('WHERE post_id '.$core->con->in($posts_ids));
+		
+		http::redirect($redir_sel."&upd=1");
+	}
+	catch (Exception $e)
+	{
+		$core->error->add($e->getMessages());
 	}
 }
@@ -231,39 +374,43 @@
 }
 
-$hidden_fields = '';
-while ($posts->fetch()) {
-	$hidden_fields .= form::hidden(array('entries[]'),$posts->post_id);
-}
-
 if (isset($_POST['redir']) && strpos($_POST['redir'],'://') === false)
 {
-	$hidden_fields .= form::hidden(array('redir'),html::escapeURL($_POST['redir']));
+	$fields->addHidden(array('redir'),html::escapeURL($_POST['redir']));
 }
 else
 {
-	$hidden_fields .=
-	form::hidden(array('user_id'),$_POST['user_id']).
-	form::hidden(array('cat_id'),$_POST['cat_id']).
-	form::hidden(array('status'),$_POST['status']).
-	form::hidden(array('selected'),$_POST['selected']).
-	form::hidden(array('month'),$_POST['month']).
-	form::hidden(array('lang'),$_POST['lang']).
-	form::hidden(array('sortby'),$_POST['sortby']).
-	form::hidden(array('order'),$_POST['order']).
-	form::hidden(array('page'),$_POST['page']).
-	form::hidden(array('nb'),$_POST['nb']);
+	$fields
+		->addHidden(array('user_id'),$_POST['user_id'])
+		->addHidden(array('cat_id'),$_POST['cat_id'])
+		->addHidden(array('status'),$_POST['status'])
+		->addHidden(array('selected'),$_POST['selected'])
+		->addHidden(array('month'),$_POST['month'])
+		->addHidden(array('lang'),$_POST['lang'])
+		->addHidden(array('sortby'),$_POST['sortby'])
+		->addHidden(array('order'),$_POST['order'])
+		->addHidden(array('page'),$_POST['page'])
+		->addHidden(array('nb'),$_POST['nb'])
+	;
 }
 
 if (isset($_POST['post_type'])) {
-	$hidden_fields .= form::hidden(array('post_type'),$_POST['post_type']);
+	$fields->addHidden(array('post_type'),$_POST['post_type']);
 }
 
 # --BEHAVIOR-- adminPostsActionsContent
-$core->callBehavior('adminPostsActionsContent',$core,$action,$hidden_fields);
+$core->callBehavior('adminPostsActionsContent',$core,$action,$fields);
 
 if ($action == 'category')
 {
-	echo '<h2 class="page-title">'.__('Change category for entries').'</h2>';
-	
+	echo dcPage::breadcrumb(
+		array(
+			html::escapeHTML($core->blog->name) => '',
+			__('Entries') => 'posts.php',
+			'<span class="page-title">'.__('Change category for this selection').'</span>' => ''
+	));
+	
+	echo '<p><a class="back" href="'.html::escapeURL($redir_sel).'">'.__('Back to entries list').'</a></p>';
+
+	# categories list
 	# Getting categories
 	$categories_combo = array(__('(No cat)') => '');
@@ -271,10 +418,10 @@
 		$categories = $core->blog->getCategories(array('post_type'=>'post'));
 		if (!$categories->isEmpty()) {
-			while ($categories->fetch()) {
+		while ($categories->fetch()) {
 				$catparents_combo[] = $categories_combo[] = new formSelectOption(
 					str_repeat('&nbsp;&nbsp;',$categories->level-1).($categories->level-1 == 0 ? '' : '&bull; ').html::escapeHTML($categories->cat_title),
-					$categories->cat_id
-				);
-			}
+				$categories->cat_id
+			);
+		}
 		}
 	} catch (Exception $e) { }
@@ -282,22 +429,22 @@
 	echo
 	'<form action="posts_actions.php" method="post">'.
-	'<p><label for="new_cat_id" class="classic">'.__('Category:').' '.
-	form::combo('new_cat_id',$categories_combo,'').
-	'</label> ';
+	$fields->getEntries().
+	'<p><label for="new_cat_id" class="classic">'.__('Category:').'</label> '.
+	form::combo('new_cat_id',$categories_combo,'');
 	
 	if ($core->auth->check('categories', $core->blog->id)) {
 		echo 
 		'<div>'.
-		'<p id="new_cat">'.__('Add a new category').'</p>'.
-		'<p><label for="new_cat_title">'.__('Title:').' '.
-		form::field('new_cat_title',30,255,'','maximal').'</label></p>'.
-		'<p><label for="new_cat_parent">'.__('Parent:').' '.
-		form::combo('new_cat_parent',$categories_combo,'','maximal').
-		'</label></p>'.
+		'<p id="new_cat">'.__('Create a new category for the post(s)').'</p>'.
+		'<p><label for="new_cat_title">'.__('Title:').'</label> '.
+		form::field('new_cat_title',30,255,'','').'</p>'.
+		'<p><label for="new_cat_parent">'.__('Parent:').'</label> '.
+		form::combo('new_cat_parent',$categories_combo,'','').
+		'</p>'.
 		'</div>';
 	}
 	
 	echo
-	$hidden_fields.
+	$fields->getHidden().
 	$core->formNonce().
 	form::hidden(array('action'),'category').
@@ -307,6 +454,12 @@
 elseif ($action == 'lang')
 {
-	echo '<h2 class="page-title">'.__('Change language for entries').'</h2>';
-	
+	echo dcPage::breadcrumb(
+		array(
+			html::escapeHTML($core->blog->name) => '',
+			__('Entries') => 'posts.php',
+			'<span class="page-title">'.__('Change language for this selection').'</span>' => ''
+	));
+	echo '<p><a class="back" href="'.html::escapeURL($redir_sel).'">'.__('Back to entries list').'</a></p>';
+
 	# lang list
 	# Languages combo
@@ -327,10 +480,11 @@
 	echo
 	'<form action="posts_actions.php" method="post">'.
-	'<p><label for="new_lang" class="classic">'.__('Entry lang:').' '.
-	form::combo('new_lang',$lang_combo,'').
-	'</label> ';
+	$fields->getEntries().
+	
+	'<p><label for="new_lang" class="classic">'.__('Entry lang:').'</label> '.
+	form::combo('new_lang',$lang_combo,'');
 	
 	echo
-	$hidden_fields.
+	$fields->getHidden().
 	$core->formNonce().
 	form::hidden(array('action'),'lang').
@@ -341,14 +495,20 @@
 elseif ($action == 'author' && $core->auth->check('admin',$core->blog->id))
 {
-	echo '<h2 class="page-title">'.__('Change author for entries').'</h2>';
-	
+	echo dcPage::breadcrumb(
+		array(
+			html::escapeHTML($core->blog->name) => '',
+			__('Entries') => 'posts.php',
+			'<span class="page-title">'.__('Change author for this selection').'</span>' => ''
+	));
+	echo '<p><a class="back" href="'.html::escapeURL($redir_sel).'">'.__('Back to entries list').'</a></p>';
+
 	echo
 	'<form action="posts_actions.php" method="post">'.
-	'<p><label for="new_auth_id" class="classic">'.__('Author ID:').' '.
-	form::field('new_auth_id',20,255).
-	'</label> ';
+	$fields->getEntries().
+	'<p><label for="new_auth_id" class="classic">'.__('New author (author ID):').'</label> '.
+	form::field('new_auth_id',20,255);
 	
 	echo
-	$hidden_fields.
+	$fields->getHidden().
 	$core->formNonce().
 	form::hidden(array('action'),'author').
@@ -357,6 +517,4 @@
 }
 
-echo '<p><a class="back" href="'.html::escapeURL($redir).'">'.__('back').'</a></p>';
-
 dcPage::close();
 ?>
Index: admin/preferences.php
===================================================================
--- admin/preferences.php	(revision 1375)
+++ admin/preferences.php	(revision 1609)
@@ -361,27 +361,31 @@
 	
 	# --BEHAVIOR-- adminPreferencesHeaders
-	$core->callBehavior('adminPreferencesHeaders')
+	$core->callBehavior('adminPreferencesHeaders'),
+
+	dcPage::breadcrumb(
+	array(
+		html::escapeHTML($core->auth->userID()) => '',
+		'<span class="page-title">'.$page_title.'</span>' => ''
+	))
 );
 
 if (!empty($_GET['upd'])) {
-	dcPage::message(__('Personal information has been successfully updated.'));
+	dcPage::success(__('Personal information has been successfully updated.'));
 }
 if (!empty($_GET['updated'])) {
-	dcPage::message(__('Personal options has been successfully updated.'));
+	dcPage::success(__('Personal options has been successfully updated.'));
 }
 if (!empty($_GET['append'])) {
-	dcPage::message(__('Favorites have been successfully added.'));
+	dcPage::success(__('Favorites have been successfully added.'));
 }
 if (!empty($_GET['neworder'])) {
-	dcPage::message(__('Favorites have been successfully updated.'));
+	dcPage::success(__('Favorites have been successfully updated.'));
 }
 if (!empty($_GET['removed'])) {
-	dcPage::message(__('Favorites have been successfully removed.'));
+	dcPage::success(__('Favorites have been successfully removed.'));
 }
 if (!empty($_GET['replaced'])) {
-	dcPage::message(__('Default favorites have been successfully updated.'));
-}
-
-echo '<h2>'.html::escapeHTML($core->blog->name).' &rsaquo; <span class="page-title">'.$page_title.'</span></h2>';
+	dcPage::success(__('Default favorites have been successfully updated.'));
+}
 
 # User profile
@@ -389,69 +393,53 @@
 
 echo
+'<h3 class="hidden-if-js">'.__('My profile').'</h3>'.
 '<form action="preferences.php" method="post" id="user-form">'.
-'<fieldset><legend>'.__('My profile').'</legend>'.
-'<div class="two-cols">'.
-'<div class="col">'.
-'<p><label for="user_name">'.__('Last Name:').
-form::field('user_name',20,255,html::escapeHTML($user_name)).'</label></p>'.
-
-'<p><label for="user_firstname">'.__('First Name:').
-form::field('user_firstname',20,255,html::escapeHTML($user_firstname)).'</label></p>'.
-
-'<p><label for="user_displayname">'.__('Display name:').
-form::field('user_displayname',20,255,html::escapeHTML($user_displayname)).'</label></p>'.
-
-'<p><label for="user_email">'.__('Email:').
-form::field('user_email',20,255,html::escapeHTML($user_email)).'</label></p>'.
-
-'<p><label for="user_url">'.__('URL:').
-form::field('user_url',30,255,html::escapeHTML($user_url)).'</label></p>'.
-
-'</div>'.
-
-'<div class="col">'.
-
-'<p><label for="user_lang">'.__('User language:').
-form::combo('user_lang',$lang_combo,$user_lang,'l10n').'</label></p>'.
-
-'<p><label for="user_tz">'.__('User timezone:').
-form::combo('user_tz',dt::getZones(true,true),$user_tz).'</label></p>'.
-
-'</div>'.
-'</div>'.
-'<br class="clear" />'. //Opera sucks
-'</fieldset>';
+
+'<p><label for="user_name">'.__('Last Name:').'</label>'.
+form::field('user_name',20,255,html::escapeHTML($user_name)).'</p>'.
+
+'<p><label for="user_firstname">'.__('First Name:').'</label>'.
+form::field('user_firstname',20,255,html::escapeHTML($user_firstname)).'</p>'.
+
+'<p><label for="user_displayname">'.__('Display name:').'</label>'.
+form::field('user_displayname',20,255,html::escapeHTML($user_displayname)).'</p>'.
+
+'<p><label for="user_email">'.__('Email:').'</label>'.
+form::field('user_email',20,255,html::escapeHTML($user_email)).'</p>'.
+
+'<p><label for="user_url">'.__('URL:').'</label>'.
+form::field('user_url',30,255,html::escapeHTML($user_url)).'</p>';
 
 if ($core->auth->allowPassChange())
 {
 	echo
-	'<fieldset>'.
-	'<legend>'.__('Change your password').'</legend>'.
+	'<h4 class="vertical-separator">'.__('Change my password').'</h4>'.
 	
 	'<div class="pw-table">'.
 	'<p class="pw-cell"><label for="new_pwd">'.__('New password:').'</label>'.
 	form::password('new_pwd',20,255,'','','',false,' data-indicator="pwindicator" ').'</p>'.
-    '<div id="pwindicator">'.
-    '    <div class="bar"></div>'.
-    '    <p class="label no-margin"></p>'.
-    '</div>'.
-    '</div>'.
+	'<div id="pwindicator">'.
+	'    <div class="bar"></div>'.
+	'    <p class="label no-margin"></p>'.
+	'</div>'.
+	'</div>'.
 	
-	'<p><label for="new_pwd_c">'.__('Confirm password:').'</label>'.
+	'<p><label for="new_pwd_c">'.__('Confirm new password:').'</label>'.
 	form::password('new_pwd_c',20,255).'</p>'.
-	'</fieldset>'.
 	
-	'<p>'.__('If you have changed this user email or password you must provide your current password to save these modifications.').'</p>'.
-	'<p><label for="cur_pwd">'.__('Your password:').'</label>'.
-	form::password('cur_pwd',20,255).'</p>';
-}
-
-echo
-'<p class="clear">'.
+	'<p><label for="cur_pwd">'.__('Your current password:').'</label>'.
+	form::password('cur_pwd',20,255).'</p>'.
+	'<p class="form-note warn">'.
+	__('If you have changed your email or password you must provide your current password to save these modifications.').
+	'</p>';
+}
+
+echo
+'<p class="clear vertical-separator">'.
 $core->formNonce().
-'<input type="submit" accesskey="s" value="'.__('Save').'" /></p>'.
-'</form>';
-
-echo '</div>';
+'<input type="submit" accesskey="s" value="'.__('Update my profile').'" /></p>'.
+'</form>'.
+
+'</div>';
 
 # User options : some from actual user profile, dashboard modules, ...
@@ -460,34 +448,21 @@
 echo
 '<form action="preferences.php" method="post" id="opts-forms">'.
-'<fieldset><legend>'.__('My options').'</legend>'.
-
-'<p><label for="user_post_format">'.__('Preferred format:').
-form::combo('user_post_format',$formaters_combo,$user_options['post_format']).'</label></p>'.
-
-'<p><label for="user_post_status">'.__('Default entry status:').
-form::combo('user_post_status',$status_combo,$user_post_status).'</label></p>'.
-
-'<p><label for="user_edit_size">'.__('Entry edit field height:').
-form::field('user_edit_size',5,4,(integer) $user_options['edit_size']).'</label></p>'.
-
-'<p><label for="user_wysiwyg" class="classic">'.
-form::checkbox('user_wysiwyg',1,$user_options['enable_wysiwyg']).' '.
-__('Enable WYSIWYG mode').'</label></p>'.
+'<h3 class="hidden-if-js">'.__('My options').'</h3>';
+
+echo
+'<div class="two-cols">'.
+
+'<div class="col">'.
+'<h4>'.__('Interface').'</h4>'.
+
+'<p><label for="user_lang">'.__('Language for my interface:').'</label>'.
+form::combo('user_lang',$lang_combo,$user_lang,'l10n').'</p>'.
+
+'<p><label for="user_tz">'.__('My timezone:').'</label>'.
+form::combo('user_tz',dt::getZones(true,true),$user_tz).'</p>'.
 
 '<p><label for="user_ui_enhanceduploader" class="classic">'.
 form::checkbox('user_ui_enhanceduploader',1,$user_ui_enhanceduploader).' '.
-__('Activate enhanced uploader in media manager').'</label></p>'.
-
-'<p><label for="user_ui_nofavmenu" class="classic">'.
-form::checkbox('user_ui_nofavmenu',1,$user_ui_nofavmenu).' '.
-__('Hide My favorites menu').'</label></p>';
-
-if (count($iconsets_combo) > 1) {
-	echo 
-		'<p><label for="user_ui_iconset">'.__('Iconset:').
-		form::combo('user_ui_iconset',$iconsets_combo,$user_ui_iconset).'</label></p>';
-} else {
-	form::hidden('user_ui_iconset','');
-}
+__('Activate enhanced uploader in media manager').'</label></p>';
 
 if ($core->auth->isSuperAdmin()) {
@@ -496,13 +471,10 @@
 	form::checkbox('user_ui_hide_std_favicon',1,$user_ui_hide_std_favicon).' '.
 	__('Do not use standard favicon').'</label></p>'.
-	'<p class="clear form-note info">'.__('This will be applied for all users').'</p>';
-}
-
-echo 
-'<br class="clear" />'. //Opera sucks
-'</fieldset>';
-
-echo
-'<fieldset><legend>'.__('Accessibility options').'</legend>'.
+	'<p class="clear form-note warn">'.__('This will be applied for all users').'.'.
+	'</p>';//Opera sucks;
+}
+
+echo
+'<h5>'.__('Accessibility').'</h5>'.
 
 '<p><label for="user_acc_nodragdrop" class="classic">'.
@@ -510,9 +482,48 @@
 __('Disable javascript powered drag and drop for ordering items').'</label></p>'.
 
-'<p class="clear form-note info">'.__('Numeric fields will allow to type the elements\' ordering number.').'</p>'.
-'</fieldset>';
-
-echo
-'<fieldset><legend>'.__('Dashboard modules').'</legend>'.
+'<p class="clear form-note">'.__('If checked, numeric fields will allow to type the elements\' ordering number.').'</p>';
+
+echo
+'<h4 class="border-top">'.__('Edition').'</h4>'.
+
+'<p><label for="user_post_format">'.__('Preferred format:').'</label>'.
+form::combo('user_post_format',$formaters_combo,$user_options['post_format']).'</p>'.
+
+'<p><label for="user_post_status">'.__('Default entry status:').'</label>'.
+form::combo('user_post_status',$status_combo,$user_post_status).'</p>'.
+
+'<p><label for="user_edit_size">'.__('Entry edit field height:').'</label>'.
+form::field('user_edit_size',5,4,(integer) $user_options['edit_size']).'</p>'.
+
+'<p><label for="user_wysiwyg" class="classic">'.
+form::checkbox('user_wysiwyg',1,$user_options['enable_wysiwyg']).' '.
+__('Enable WYSIWYG mode').'</label></p>';
+
+echo
+'<h4 class="border-top">'.__('Other options').'</h4>';
+
+# --BEHAVIOR-- adminPreferencesForm
+$core->callBehavior('adminPreferencesForm',$core);
+
+echo
+'</div>'.
+
+'<div class="col">'.
+'<h4>'.__('Dashboard and menu').'</h4>'.
+
+'<p><label for="user_ui_nofavmenu" class="classic">'.
+form::checkbox('user_ui_nofavmenu',1,$user_ui_nofavmenu).' '.
+__('Hide My favorites menu').'</label></p>';
+
+if (count($iconsets_combo) > 1) {
+	echo 
+		'<p><label for="user_ui_iconset" class="classic">'.__('Iconset:').'</label> '.
+		form::combo('user_ui_iconset',$iconsets_combo,$user_ui_iconset).'</p>';
+} else {
+	form::hidden('user_ui_iconset','');
+}
+
+echo
+'<h5>'.('Dashboard modules').'</h5>'.
 
 '<p><label for="user_dm_doclinks" class="classic">'.
@@ -526,16 +537,15 @@
 '<p><label for="user_dm_quickentry" class="classic">'.
 form::checkbox('user_dm_quickentry',1,$user_dm_quickentry).' '.
-__('Display quick entry form').'</label></p>'.
-
-'<br class="clear" />'. //Opera sucks
-'</fieldset>';
-
-# --BEHAVIOR-- adminPreferencesForm
-$core->callBehavior('adminPreferencesForm',$core);
-
-echo
-'<p class="clear">'.
+__('Display quick entry form').'</label><br class="clear" />'. //Opera sucks
+'</p>';
+
+echo
+'</div>'.
+'</div>';
+
+echo
+'<p class="clear border-top">'.
 $core->formNonce().
-'<input type="submit" accesskey="s" value="'.__('Save').'" /></p>'.
+'<input type="submit" accesskey="s" value="'.__('Save my options').'" /></p>'.
 '</form>';
 
@@ -547,6 +557,7 @@
 echo '<form action="preferences.php" method="post" id="favs-form">';
 echo '<div class="two-cols">';
+
 echo '<div class="col70">';
-echo '<fieldset id="my-favs"><legend>'.__('My favorites').'</legend>';
+echo '<div id="my-favs" class="fieldset"><h3>'.__('My favorites').'</h3>';
 
 $count = 0;
@@ -592,8 +603,8 @@
 }
 
-echo '</fieldset>';
+echo '</div>';
 
 echo '<div id="default-favs"><h3>'.__('Default favorites').'</h3>';
-echo '<p class="form-note info clear">'.__('Those favorites are displayed when My Favorites list is empty.').'</p>';
+echo '<p>'.__('Those favorites are displayed when My Favorites list is empty.').'</p>';
 $count = 0;
 foreach ($ws->dumpPrefs() as $k => $v) {
@@ -612,7 +623,9 @@
 echo '</div>';
 echo '</div>';
-echo '<div class="col30" id="available-favs">';
+
+
+echo '<div class="col30 fieldset" id="available-favs">';
 # Available favorites
-echo '<fieldset><legend>'.__('Available favorites').'</legend>';
+echo '<h3>'.__('Available favorites').'</h3>';
 $count = 0;
 $array = $_fav;
@@ -640,6 +653,7 @@
 $core->formNonce().
 '<input type="submit" name="appendaction" value="'.__('Add to my favorites').'" /></p>';
-echo '</fieldset>';
 echo '</div>';
+
+
 echo '</div>'; # Two-cols
 echo '</form>';
Index: admin/search.php
===================================================================
--- admin/search.php	(revision 1276)
+++ admin/search.php	(revision 1589)
@@ -15,5 +15,5 @@
 dcPage::check('usage,contentadmin');
 
-$q = !empty($_GET['q']) ? $_GET['q'] : null;
+$q = !empty($_GET['q']) ? $_GET['q'] : (!empty($_GET['qx']) ? $_GET['qx'] : null);
 $qtype = !empty($_GET['qtype']) ? $_GET['qtype'] : 'p';
 if ($qtype != 'c' && $qtype != 'p') {
@@ -70,13 +70,18 @@
 
 
-dcPage::open(__('Search'),$starting_scripts);
+dcPage::open(__('Search'),$starting_scripts,
+	dcPage::breadcrumb(
+		array(
+			html::escapeHTML($core->blog->name) => '',
+			'<span class="page-title">'.__('Search').'</span>' => ''
+		))
+);
 
 echo
-'<h2>'.html::escapeHTML($core->blog->name).' &rsaquo; <span class="page-title">'.__('Search').'</span></h2>'.
 '<form action="search.php" method="get">'.
 '<div class="fieldset"><h3>'.__('Search options').'</h3>'.
 '<p><label for="q">'.__('Query:').' </label>'.form::field('q',30,255,html::escapeHTML($q)).'</p>'.
-'<p><label for="qtype1" class="classic">'.form::radio(array('qtype','qtype1'),'p',$qtype == 'p').' '.__('Search entries').'</label> '.
-'<label for="qtype2" class="classic">'.form::radio(array('qtype','qtype2'),'c',$qtype == 'c').' '.__('Search comments').'</label></p>'.
+'<p><label for="qtype1" class="classic">'.form::radio(array('qtype','qtype1'),'p',$qtype == 'p').' '.__('Search in entries').'</label> '.
+'<label for="qtype2" class="classic">'.form::radio(array('qtype','qtype2'),'c',$qtype == 'c').' '.__('Search in comments').'</label></p>'.
 '<p><input type="submit" value="'.__('Search').'" /></p>'.
 '</div>'.
Index: admin/style/date-picker.css
===================================================================
--- admin/style/date-picker.css	(revision 0)
+++ admin/style/date-picker.css	(revision 1330)
@@ -1,35 +1,35 @@
 .date-picker {
-	border-collapse : collapse;
-	background : #fff;
-	color : #fff;
+	border-collapse: collapse;
+	background: #fff;
+	color: #fff;
 	border: 1px solid #666;
-	border-width : 1px 2px 2px 1px;
+	border-width: 1px 2px 2px 1px;
 }
 .date-picker th {
-	border : none;
-	color : #000;
-	text-align : center;
+	border: none;
+	color: #000;
+	text-align: center;
 }
 .date-picker td {
-	border : 1px solid #666;
-	text-align : center;
+	border: 1px solid #666;
+	text-align: center;
 	padding : 4px 6px;
 }
 th.date-picker-month {
-	text-align : left;
+	text-align: left;
 }
 th.date-picker-year {
-	text-align : right;
+	text-align: right;
 }
 .date-picker-control, th.date-picker-control {
-	color : #06c;
-	cursor : pointer;
+	color: #06c;
+	cursor: pointer;
 }
 .date-picker-day, .date-picker-today {
-	color : #000;
-	background : #eee;
-	cursor : pointer;
+	color: #000;
+	background: #eee;
+	cursor: pointer;
 }
 .date-picker-today {
-	background : #ccc;
+	background: #ccc;
 }
Index: admin/style/default.css
===================================================================
--- admin/style/default.css	(revision 1375)
+++ admin/style/default.css	(revision 1678)
@@ -13,13 +13,16 @@
 
 /* ------------------------------------------------------------------ html */
+html {
+	font-size: 62.5%;
+}
 body {
-	font: 75%/1.5em Helvetica,Arial,sans-serif;
+	font-size: 12px; /* ie < 9 sucks */
+	font-size: 1.2rem;
+	line-height: 1.5;
+	font-family: Arial,Helvetica,sans-serif;
 	color: #333;
-	background: #f5f5f5;
-	margin: 0;
-	padding: 0;
-}
-body.auth {
 	background: #fff;
+	margin: 0;
+	padding: 0;
 }
 
@@ -32,23 +35,58 @@
 	text-decoration: underline;
 }
-a img, a:link img, a:visited img { 
+a img, a:link img, a:visited img {
 	border:none;
 }
-
-h1, h2, h3, h4, h5, h6, p {
+h1, h2, h3, .as_h3, h4, h5, h6, p {
 	margin-top: 0;
-	margin-bottom: 0.6em;
+	margin-bottom: 1em;
 }
 h2 {
 	color: #666;
-	font-size: 1.4em;
-	padding: 4px 0;
+	font-size: 18px; /* ie < 9 sucks */
+	font-size: 1.8rem;
+	padding: 0 0 1.5em;
+	font-weight: normal;
+}
+h2 a:link, h2 a:visited {
+	color: #666;
+	border-color: #000;
 }
 .page-title {
 	color: #d30e60;
 }
-h3 {
+.page-title img {
+	padding-left: .5em;
+	vertical-align: middle;
+}
+#content > h2 {
+	padding: 0 18px 6px; /* ie < 9 sucks */
+	padding: 0 1.8rem .6rem;
+	margin: 0 -18px .5em; /* ie < 9 sucks */
+	margin: 0 -1.8rem 1rem;
+	background: #fff url(bg_h2.png) repeat-x center bottom;
+}
+h3, .as_h3 {
+	color: #575859;
+	font-size: 16px; /* ie < 9 sucks */
+	font-size: 1.6rem;
+}
+h4 {
+	font-size: 14px; /* ie < 9 sucks */
+	font-size: 1.4rem;
+	color: #575859;
+}
+h5 {
+	font-size: 12px; /* ie < 9 sucks */
+	font-size: 1.2rem;
+	color: #575859;
+}
+#entry-sidebar h5 {
+	font-weight: normal;
 	color: #333;
-	font-size: 1.2em;
+}
+.entry-status img.img_select_option {
+	padding-left: 4px;
+	vertical-align: text-top;
 }
 p, div.p {
@@ -57,5 +95,5 @@
 hr {
 	height: 1px;
-	border-width: 1px 0 0 0;
+	border-width: 1px 0 0;
 	border-color: #999;
 	border-style: solid;
@@ -83,29 +121,36 @@
 #header {
 	background: #575859;
-	height: 3em;
 	position: relative;
+	border-bottom: 4px solid #A2CBE9;
+	width: 100%;
 }
 #prelude {
-	background: #575859;
-	line-height: 1.5em;
-	margin: 0;
-	padding: 0 1.7em 0 1em;
+	line-height: 1.5;
+	margin: 0;
+	padding: 0;
 	overflow: hidden;
 	position: absolute;
-	top: 1.2em;
+	top: 3em;
 	left: 0;
+	background: #A2CBE9;
+	width: 100%;
 	}
 #prelude li {
 	list-style-type: none;
-	margin: 0 1em 0 0;
+	margin: 0;
 	background:transparent;
-	}
+	display: inline;
+}
 #prelude li a {
-	color:#fff;
-	}
+	padding: 3px 16px 3px 8px; /* ie < 9 sucks */
+	padding: 3px 1.6rem 3px .8rem;
+	background: #A2CBE9;
+	color: #000;
+	border-bottom-color: #A2CBE9;
+}
 #top {
 	margin: 0;
 	padding: 0;
-	width: 13em;
+	width: 14.5em;
 	float: left;
 }
@@ -113,38 +158,41 @@
 	padding: 0;
 	margin: 0;
-	height: 3em;
+	height: 36px;
 	text-indent: -1000px;
-	background: transparent url(dc_logo.png) no-repeat 0 50%;
 }
 #top h1 a {
 	position: absolute;
-	top: 3px;
+	top: 0;
 	left: 0;
-	width: 130px;
-	height: 60px;
+	width: 174px; /* ie < 9 sucks */
+	width: 17.4rem;
+	height: 36px; /* ie < 9 sucks */
+	height: 3.6rem;
 	border: none;
-	outline: none;
 	color: #fff;
 }
+#top h1 a:link {
+	background: transparent url(dc_logos/b-dotclear120.png) no-repeat 0 6px;
+}
+#top h1 a:hover, #top h1 a:focus {
+	background: transparent url(dc_logos/b-dotclear120.png) no-repeat 0 -94px;
+}
 #info-boxes {
-	background: #575859;
-	font-size: .95em;
-	height: 3em;
+	font-size: 12px; /* ie < 9 sucks */
+	font-size: 1.2rem;
+	line-height: 3em;
 }
 #info-box1 {
 	margin: 0;
-	padding: .5em 3px 4px 0;
+	padding: 0 3px 0 18px;
 	color: #fff;
-	float: left;
-	background: #575859;
+	display: inline-block;
 }
 #info-box2 {
-	margin: .1em 0 0 0;
-	padding: .5em 1.3em 4px 0;
+	margin: 0;
+	padding: 0 18px 0 0;
 	color: #fff;
 	float: right;
 	text-align: right;
-	background: #575859;
-	height: 2em;
 }
 #info-box1 p {
@@ -153,5 +201,6 @@
 }
 #info-box1 select {
-	width: 15em;
+	width: 145px; /* ie < 9 sucks */
+	width: 14.5em;
 }
 #info-box1 a img, #info-box2 a img {
@@ -159,6 +208,5 @@
 	padding-left: .3em;
 	}
-#info-box1 a, #info-box2 a {
-	background: #575859;
+#info-boxes a {
 	font-weight: bold;
 	color: #fff;
@@ -169,34 +217,38 @@
 	font-weight: normal;
 }
+#info-boxes .logout {
+	margin-right: 0;
+}
 #info-box1 a {
 	margin-left: 1.33em;
 }
 #info-box2 a.active {
-	border-bottom-color: #f5f5f5;
+	border-bottom-color: #fff;
 	margin: 0;
 	padding: 1.2em .5em;
-	background-color: #f5f5f5;
+	background-color: #fff;
 	color: #333;
 	font-weight: bold;
 }
 #info-box2 span {
-	color: #575859;
-}
-/* prelude */
+	color: #999;
+}
+/* main blocks */
 #wrapper {
 	width: 100%;
+	padding-top: 1em;
 }
 #main {
 	width: 100%;
 	float: right;
-	margin-left: -13em;
+	margin-left: -14.5em;
 	margin-top: 0;
+	background: #fff url(bg_menu.png);
 }
 #content {
-	margin: 1.5em 1.5em .5em 13em;
-	padding: 1em;
+	margin: 0 0 0 14.5em;
+	padding: 9px 18px 18px; /* ie < 9 sucks */
+	padding: .9rem 1.8rem 1.8rem;
 	background: #fff;
-	border-radius: .5em;
-	border: 1px solid #ddd;
 }
 	/* Micro clearfix thx to Nicolas Gallagher */
@@ -219,26 +271,32 @@
 }
 .two-cols .col {
-	width: 49%;
+	width: 48%;
 	margin-left: 2%;
 	float: left;
 }
-.two-cols .col:first-child {
-	width: 49%;
-	margin-left: 0;
-}
 .two-cols .col70{
-	width: 69%;
+	width: 68%;
 	margin-left: 0;
 	float: left;
 }
-.two-cols .col30 {
+.col30 {
 	width: 28%;
 	margin-left: 2%;
 	float: left;
 }
+.two-cols .col:first-child,
+.two-cols .col30.first-col {
+	margin-left: 0;
+	margin-right: 2%;
+}
+.two-cols .col:last-child,
+.two-cols .col70.last-col {
+	margin-left: 2%;
+	margin-right: 0;
+}
 /* -------------------------------------------------------------- layout - onglets */
 .part-tabs ul {
-	padding: .3em 0 1px 1em;
-	border-bottom: 1px solid #999;
+	padding: .5em 0 .3em 1em;
+	border-bottom: 1px solid #ddd;
 }
 .part-tabs li {
@@ -248,16 +306,11 @@
 }
 .part-tabs li a {
-	padding: .3em 0.5em;
-	margin-right: .5em;
-	border: 1px solid #999;
+	padding: .5em 2em;
+	margin-right: -1px;
+	border: 1px solid #aaa;
 	border-bottom: none;
-	background: #dfdfdf;
 	text-decoration: none;
-	border-top-left-radius: .3em;
-	border-top-right-radius: .3em;
-	color: #000;
-}
-.part-tabs li.part-tabs-link a {
-	background: #ffe;
+	color: #333;
+	background-color:#E4E0EC;
 }
 .part-tabs li a:hover, .part-tabs li a:focus {
@@ -268,25 +321,30 @@
 .part-tabs li.part-tabs-active a {
 	background: #fff;
-	border-bottom: 1px solid #fff;
-	color: #000;
 	font-weight: bold;
+	border-bottom-color: #fff;
+	padding-bottom: 7px; /* ie < 9 sucks */
+	padding-bottom: .7rem;
 }
 /* ------------------------------------------------------------------ main-menu */
 #main-menu {
-	width: 13em;
+	width: 14.5em;
 	float: left;
-	margin-top: 1.2em;
-	margin-bottom: .5em;
+	margin:0;
+	padding-top: .5em;
+	padding-bottom: 1em;
+	background: #f7f7f7;
 }
 #main-menu h3 {
-	margin: 0 0 0.5em;
-	padding: .5em 0 0 .5em;
-	text-transform: uppercase;
+	margin: 0;
+	padding: 10px 0 10px 8px;
 	color: #666;
-	font-size: 1.1em;
+	font-size: 14px; /* ie < 9 sucks */
+	font-size: 1.4rem;
+}
+#main-menu h3 img[alt="cacher"] {
+	vertical-align: top;
 }
 #main-menu ul {
-	font-size: .95em;
-	margin: 0 0 1em 0;
+	margin: 0 0 1.5em 0;
 	padding: 0;
 	list-style: none;
@@ -295,57 +353,101 @@
 	display: block;
 	margin: 0.5em 0 0;
-	padding: .2em 0 0 32px;
+	padding: 3px 0 0 30px;
 	background-repeat: no-repeat;
-	background-position: 12px .4em;
+	background-position: 8px .3em;
+}
+#main-menu ul li:first-child {
+	margin-top: 0;
+}
+#main-menu li.active {
+	background-color: #fff;
 }
 #main-menu a {
-	font-weight: bold;
+	color: #333;
+	border-bottom-color: #ccc;
 }
 #main-menu .active a {
 	border-bottom: none;
-	color: #333;
+	color: #d30e60;
 }
 #main-menu .active {
-	background-color: #fff;
-	padding: .4em 0 .1em 32px;
-	background-position: 12px .4em;
-	border-top: 1px solid #ddd;
-	border-bottom: 1px solid #ddd;
-	margin-right: -1px;
-}
-#favorites-menu {
-	margin: 0 0 2em;
+	font-weight: bold;
+}
+#search-menu {
+	padding: 4px 5px 0;
+	font-size: 100%
+}
+#search-menu * {
+	height: 22px; /* ie < 9 sucks */
+	height: 2.2rem;
+	display: inline-block;
+	vertical-align: top;
+	line-height: 22px;
+}
+#search-menu p {
+	border: 1px solid #999;
+	border-radius: .3em;
+	position: relative;
+	overflow: hidden;
+}
+#qx {
+	width: 124px; /* ie < 9 sucks */
+	width: 12.4rem;
+	border-bottom-left-radius: .3em;
+	border-top-left-radius: .3em;
+	background: transparent url(search.png) no-repeat 4px center;
+	text-indent: 18px;
+	padding: 0;
+	border: none;
+	height: 22px;
+	height: 2.2rem;
+}
+#qx:focus {
+	border: 2px solid #bee74b;
+}
+#search-menu input[type="submit"] {
+	padding: 0 3px;
+	padding: 0 .3rem;
+	margin-left: -4px;
+	background: #dfdfdf;
+	border-color: #999;
+	color: #444;
+	border-bottom-right-radius: .3em;
+	border-top-right-radius: .3em;
+	border-top-left-radius: 0;
+	border-bottom-left-radius: 0;
+	text-shadow: none;
+	border: none;
+	border-left: 1px solid #aaa;
+	font-size: 10px; /* ie < 9 sucks */
+	font-size: 1rem;
+}
+#search-menu input[type="submit"]:hover,
+#search-menu input[type="submit"]:focus {
+	background: #575859;
+	color: #fff;
+}
+#favorites-menu, #blog-menu, #system-menu, #plugins-menu {
+	border-bottom: 1px dashed #A2CBE9;
 }
 #favorites-menu h3 {
-	color: #333;
-	text-transform: none;
-}
-#favorites-menu a {
-	color: #333;
-}
-#favorites-menu .active {
-	background-color: transparent;
-	border: none;
-}
-#favorites-menu .active a {
-	font-weight: bold;
-	color: #666;
+	color: #000;
+	font-variant: small-caps;
+	padding-top: .2em;
 }
 /* ------------------------------------------------------------------ footer */
 #footer {
 	clear: both;
-	padding: .75em .75em 0 0;
+	padding: .5em 1em .5em 0;
 	text-align: right;
+	border-top: 1px solid #ccc;
 }
 #footer p {
 	margin: 0;
 	padding: 0 1em;
-	text-align: center;
-	font-size: 1.1em;
-}
-#footer a {
+	font-size: 1em;
 }
 #footer p span.credit {
-	font-size: .85em;
+	font-size: 1em;
 	font-weight: normal;
 }
@@ -353,41 +455,41 @@
 #login-screen {
 	display: block;
-	width: 18em;
+	width: 20em;
 	margin: 1.5em auto 0;
-	font-size: 1.1em;
+	font-size: 14px; /* ie < 9 sucks */
+	font-size: 1.4rem;
 }
 #login-screen h1 {
 	text-indent: -2000px;
-	background: transparent url(dotclear-logo2.png) no-repeat top left;
-	height: 50px;
+	background: transparent url(dc_logos/w-dotclear240.png) no-repeat top left;
+	height: 66px;
 	margin-bottom: .5em;
-	margin-left: .5em;
-}
-#login-screen fieldset, #login-screen .fieldset {
-	border: 1px solid #999;
+	margin-left: 0;
+}
+#login-screen .fieldset {
+	border: 1px solid #A8DC26;
 	padding: 1em 1em 0 1em;
-	border-radius: 4px;
+	border-radius: 3px;
+	background: #fff;
 }
 #login-screen input[type=text], #login-screen input[type=password], #login-screen input[type=submit] {
 	width: 100%;
 }
+#login-screen input.login {
+	padding-top: 6px;
+	padding-bottom: 6px;
+	font-size: 1em;
+}
 #login-screen #issue {
-	margin-left: 1em;
-	font-size: 1em;
-}
-#login-screen #issue strong {font-weight: normal;}
-
-
+	margin-left: 1.33em;
+	font-size: 12px; /* ie < 9 sucks */
+	font-size: 1.2rem;
+}
+#login-screen #issue strong {
+	font-weight: normal;
+}
 /* ------------------------------------------------------------------ dashboard */
 #dashboard-main {
-	float: left;
-	overflow: hidden;
-	padding: 1em 2% 1em 0;
-	width: 70%;
-}
-#dashboard-main.fullwidth {
-	width: 100%;
 	padding: 1em 0;
-	float: none;
 }
 #icons {
@@ -399,6 +501,8 @@
 	width: 210px;
 	text-align: center;
-	margin: 2em 0 0 0;
+	margin: 1em 0 2em;
+	padding: 1em 0;
 	display:inline-block;
+	vertical-align: top;
 }
 #icons a,
@@ -412,4 +516,23 @@
 #icons a span {
 	border-bottom: 1px dotted #f90;
+	color: #333;
+}
+#icons a img {
+	padding: 2em;
+	-moz-box-shadow: 0px 1px 0px 0px #ffffff;
+	-webkit-box-shadow: 0px 1px 0px 0px #ffffff;
+	box-shadow: 0px 1px 0px 0px #ffffff;
+	background:-webkit-gradient( linear, left top, left bottom, color-stop(0.05, #f9f9f9), color-stop(1, #e9e9e9) );
+	background:-moz-linear-gradient( center top, #f9f9f9 5%, #e9e9e9 100% );
+	filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#f9f9f9', endColorstr='#e9e9e9');
+	background-color:#f9f9f9;
+	-moz-border-radius:1em;
+	-webkit-border-radius:1em;
+	border-radius:1em;
+	border:1px solid #dcdcdc;
+	display:inline-block;
+}
+#icons a:focus img, #icons a:hover img {
+	background: #bee74b;
 }
 #icons a:focus span, #icons a:hover span {
@@ -417,5 +540,4 @@
 }
 #quick {
-	clear: left;
 	margin-top: 2em;
 }
@@ -426,15 +548,36 @@
 #quick p.qinfo {
 	margin: -.7em -1em 1em;
-	background: #eef url(info.png) no-repeat .2em .2em;
+	background: #f3f3ff url(info.png) no-repeat .2em .2em;
 	border: 1px solid #99f;
 	padding: .2em 1em .1em 24px;
 	color: #666;
 }
+#quick #new_cat, .q-cat, .q-cat label {
+	display: inline-block;
+	vertical-align: top;
+	margin-right: 1em;
+	margin-top: 0;
+}
+.q-cat label {
+	margin-right: .3em;
+}
+#quick #new_cat {
+	margin-bottom: 2em;
+}
 #dashboard-items {
-	float: left;
-	width: 27%;
-	overflow: hidden;
-	padding-bottom: 1em;
-	padding-top: 3em;
+	margin: 3em auto;
+	display: table;
+	width: 100%;
+	border-collapse: collapse;
+}
+.db-item {
+	display: table-cell;
+	padding: 1em 3em;
+	vertical-align: top;
+	border: 1px solid #ddd;
+	border-collapse: collapse;
+}
+.db-item h3 {
+	font-weight: normal;
 }
 #dashboard-items img {
@@ -464,5 +607,5 @@
 }
 #upg-notify ul {
-	padding-left: 15px;
+	padding-left: 1.5em;
 }
 #upg-notify li {
@@ -476,5 +619,14 @@
 }
 #entry-content {
-	margin-right: 18em;
+	margin-right: 19em;
+	margin-left: 0;
+}
+.multi-part {
+	padding-left: 1em;
+}
+#entry-content label {
+	text-transform: uppercase;
+	font-weight: bold;
+	margin-top: 2em;
 }
 #entry-sidebar {
@@ -482,10 +634,23 @@
 	float: right;
 }
+#entry-sidebar select {
+	width: 100%;
+}
+#entry-sidebar input#post_position {
+	width: 4em;
+}
+.box {
+	border-bottom: 1px solid #ddd;
+	margin-bottom: 1em;
+}
 #comments {
 	clear: both;
 }
+#trackback-form textarea {
+	width: 98%;
+}
 /* ------------------------------------------------------------------ categories */
 #categories {
-	margin: 1em 0 2em;
+	margin: 1em 0;
 }
 #categories ul {
@@ -496,11 +661,17 @@
 #categories li {
 	margin: .5em 0;
-	padding: .3em 1.5em;
+	padding: .5em 1.2em;
 	border: 1px solid #ccc;
-	border-left: 1em solid #E5E3DA;
-	border-radius: .3em;
+	border-left: 8px solid #E5E3DA;
+	border-radius: 3px;
+}
+#categories input[type="checkbox"] {
+	margin-right: .8em;
 }
 #categories h4 {
 	margin: 0;
+}
+#categories label a {
+	font-weight: bold;
 }
 #categories h4 span {
@@ -509,7 +680,37 @@
 #categories li p {
 	margin: 0;
+	display: inline-block;
+}
+.cat-url {
+	padding-left: 1em;
+}
+.cat-actions {
+	line-height: 2;
 }
 select#del_cat {
 	width: 100%;
+}
+#new_cat {
+	font-weight: bold;
+	margin-top: 2em;
+}
+#categories .placeholder {
+        outline: 1px dashed #4183C4;
+        min-height: 2.5em;
+}
+#categories input.cat-rank {
+  float: right;
+  margin-left: 30px;
+}
+#save-set-order.disabled {
+        text-shadow: none;
+        color: #666;
+        background: #F5F5F5;
+        border: 1px solid #CCCCCC;
+}
+#save-set-order.disabled:hover {
+        color: #666;
+        background: #DFDFDF;
+        border: 1px solid #CCCCCC;
 }
 /* ------------------------------------------------------------------ media */
@@ -518,5 +719,8 @@
 }
 #media-details {
+}
+.near-icon {
 	margin-left: 70px;
+	margin-bottom: 3em;
 }
 #media-details ul {
@@ -549,5 +753,5 @@
 	position: static;
 }
-.media-col-0 {
+/*.media-col-0 {
 	clear: left;
 }
@@ -576,5 +780,5 @@
 	margin: 0 0 0 60px;
 	padding: 0;
-}
+}*/
 li.media-action {
 	display: block;
@@ -593,5 +797,35 @@
 	border: none;
 }
+.media-item {
+	position: relative;
+	border: 1px solid #ccc;
+	margin: 1em;
+	padding: 1em;
+	width: 300px;
+	height: 120px;
+	display: inline-block;
+	vertical-align: top;
+}
+div.media-list .media-item {
+}
+a.media-icon {
+	display: block;
+	border-bottom: none;
+	margin: 0 auto; 
+}
+.media-icon img {
+	display: block;
+}
+.media-item ul {
+	display: block;
+	list-style: none;
+	margin: 0;
+	padding: 0;
+}
 /* ------------------------------------------------------------------ preferences */
+#my-favs {
+	border: 1px solid #A8DC26;
+	padding: 1em 2em
+}
 #my-favs ul {
 	list-style-type: none;
@@ -651,28 +885,53 @@
 	border-radius: .5em;
 }
+#user-options label.ib {
+	display: inline-block;
+	width: 14em;
+	padding-right: 1em;
+}
+.blog-perm {
+	margin-top: 2em;
+	font-weight: bold;
+}
+.ul-perm {
+	list-style-type: square;
+	margin-left: 0;
+	padding-left: 3.5em;
+	margin-bottom: 0
+}
+.add-perm {
+	padding-top: .5em;
+	padding-left: 2.5em;
+	margin-left: 0;
+}
 /* -------------------------------------------------------------------- Themes */
 #themes {
-	border-bottom: 1px solid #ccc;
-	margin: 1em 0;
+	margin: 0;
+	width: 100%;
+	padding: 0;
+}
+#themes h3 {
 }
 #themes div.theme-details {
-	clear: left;
 	border-top: 1px solid #ccc;
-	padding: 1em 0;
+	padding: 12px;
+	display: inline-block;
+	vertical-align: top;
+	width: 284px;
+}
+.current-theme {
+	background: #eef;
 }
 #themes div.theme-details:hover {
-	background: #eee;
+	background: #f0f0f0;
 }
 #themes div.theme-details div.theme-shot {
-	float: left;
 }
 #themes div.theme-details div.theme-shot img {
 	display: block;
-	width: 57px;
-	height: 50px;
 	border: 1px solid #ccc;
+	margin-bottom: 1.5em;
 }
 #themes div.theme-details div.theme-info {
-	margin-left: 67px;
 }
 #themes div.theme-details div.theme-info span.theme-desc {
@@ -683,33 +942,45 @@
 }
 #themes div.theme-details div.theme-actions {
-	margin-left: 67px;
+}
+#themes-actions {
+	border-bottom: 1px solid #999;
+	margin-bottom: 3em;
+}
+.theme-css {
+	display: block;
 }
 /* Themes list, JS version */
 #themes-wrapper {
+	display: table;
+}
+#themes-wrapper #themes {
+	display: table-cell;
+	vertical-align: top;
+	padding-left: 1em;
 }
 #theme-box {
-	border: 1px solid #999;
-	border-left: none;
-	padding: 5px;
-	float: right;
-	height: 420px;
-	width: 320px;
-	overflow: auto;
-}
-#theme-box div.theme-shot img {
-	display: block;
-	margin: 0 0 0 10px;
+	display: table-cell;
+	vertical-align: top;
+	padding: 0;
+	width: 312px;
+	border: 1px solid #ccc;
+	border-radius: 3px;
+}
+#theme-box .theme-shot,
+#theme-box .theme-info,
+#theme-box .theme-actions {
+	background: #eef;
+	padding: 1em 16px;
+	margin: 0;
+}
+#theme-box .theme-shot img {
+	display: block;
 	width: 280px;
 	height: 245px;
 	border: 1px solid #ccc;
 }
-#theme-box div.theme-info {
-	margin: 1em 0 0 10px;
-}
-#theme-box h3 {
-	margin: 0;
-}
-#theme-box div.theme-info span {
-	display: block;
+#theme-box h4 {
+	color: #000;
+	background: #eef;
 }
 #theme-box span.theme-version {
@@ -723,43 +994,34 @@
 	font-weight:bold;
 }
-#theme-box div.theme-actions {
-	margin-left: 10px;
-}
-#themes-wrapper #themes {
-	border: 1px solid #999;
-	overflow: auto;
-	height: 420px;
-	padding: 5px;
-	margin: 0;
-}
-#themes div.theme-details-js {
+#theme-box .theme-actions {
+	border-bottom: 1px solid #ccc;
+}
+#themes .theme-details-js {
 	float: left;
 	width: 120px;
 	height: 150px;
-	margin: 0 10px 20px;
-	padding: 10px 10px 0;
+	margin: 0 12px 24px;
+	padding: 12px 12px 0;
 	text-align: center;
 	background: #f3f3f3;
-	border: 1px solid #f3f3f3;
+	border: 1px solid #ddd;
 	cursor: pointer;
 	border-radius: 4px;
 }
-#themes div.theme-details-js label {
+#themes .theme-details-js label {
 	cursor: pointer;
 }
-#themes div.theme-details-js.theme-selected {
-	background: #E5E3DA;
+#themes .theme-details-js.theme-selected {
+	background: #ddd;
 	border: 1px solid #999;
 }
-#themes div.theme-details-js div.theme-shot img {
+#themes .theme-details-js .theme-shot img {
 	width: 120px;
 	height: 105px;
 	border: 1px solid #fff;
 }
-#themes div.theme-details-js h3 {
-	font-family: inherit;
-	font-weight: normal;
-	margin: 0;
-	padding: 0;
+#themes a:focus div, #themes a:hover div,
+#themes a:focus div.current-theme, #themes a:hover div.current-theme {
+	background: #bee74b;
 }
 /* ----------------------------------------------------------  Plugins list */
@@ -767,5 +1029,4 @@
 	vertical-align: middle;
 }
-
 select.l10n option {
 	padding-left: 16px;
@@ -776,22 +1037,25 @@
 /* ------------------------------------------------------------------ contextual help */
 #help {
-	margin-top: 2em;
+	margin-top: 4em;
 	background: #f5f5f5;
 	z-index: 100;
+	clear: both;
+	padding: 0 1em;
 }
 #help-button {
-	position: fixed;
-	top: 3.2em;
+	background: transparent url(../images/page_help.png) no-repeat 6px center;
+	position: absolute;
+	top: 36px; /* ie < 9 sucks */
+	top: 3.6rem;
 	right: 0px;
+	padding: 0 1.5em 0 30px;
 	cursor: pointer;
-	background: #fc3;
-	border: 1px solid #dde;
-	border-right: none;
-	font-size: 1.1em;
-	font-weight: bold;
-	text-transform: capitalize;
-	padding: .33em .75em .33em 1em;
-	border-radius: 1em 0 0 1em;
-	color: #444;
+	color: #2373A8;
+	line-height: 42px; /* ie < 9 sucks */
+	line-height: 4.2rem;
+}
+#help-button span {
+	padding: .5em 0 .1em 0;
+	border-bottom: 1px solid #2373A8;
 }
 .help-box {
@@ -803,19 +1067,30 @@
 }
 #content.with-help #help-button {
-	right: 282px;
+	right: 282px; /* ie < 9 sucks */
+	right: 28.2rem;
+	background-color: #f5f5f5;
+	position: fixed;
+	border-top: 2px solid #FFD478;
+	border-left: 2px solid #FFD478;
+	border-bottom: 2px solid #FFD478;
+	border-bottom-left-radius: 1em;
+	border-top-left-radius: 1em;
 }
 #content.with-help #help {
 	display: block;
 	position: absolute;
-	top: 40px;
+	top: 36px; /* ie < 9 sucks */
+	top: 3.6rem;
 	right: 0;
-	width: 280px;
-	border-left: 2px solid #fc3;
+	width: 280px; /* ie < 9 sucks */
+	width: 28rem;
+	border-left: 2px solid #FFD478;
+	border-top: 2px solid #FFD478;
 	margin-top: 0;
-	padding: 10px 0 0 0;
+	padding: .5em 0 0 0;
 	overflow: auto;
 }
 #content.with-help .help-content {
-	padding: 0 5px 1em 5px;
+	padding: 0 .5em 1em;
 }
 .help-content dt {
@@ -829,49 +1104,90 @@
 /* ------------------------------------------------------------------ popups */
 body.popup #wrapper, body.popup #top {
-	margin-top: -1.5em;
+	width: 100%;
+	padding: 0;
+}
+body.popup #wrapper {
 	float: none;
-}
-body.popup #top h1 {
-	background: transparent;
+	margin:0;
+	display: block;
+}
+body.popup h1, body.popup #top {
+	margin: 0;
+	border-bottom: 1px solid;
+	font-weight: normal;
+	color: #fff;
+	background: #575859;
+	font-size: 1.5em;
+	text-indent: .5em;
+	line-height: 1.3em;
 }
 body.popup #main {
-	margin-left: -35px;
-	margin-bottom: 1em;
+	margin-bottom: 1em 0;
 }
 body.popup #content {
-	margin-left: 35px;
-	margin-left: 2em;  /* 3.2 */
-}
-body.popup #footer {
-	display: none; /* 3.2 */
+	margin: 0;
+	padding: .5em 0;
+}
+body.popup #content h2 {
+	margin: 0 0 1em;
 }
 body.popup #footer p {
-	margin-left: 35px;
 	border: none;
 }
 /* ------------------------------------------------------------------ messages */
-div.error, p.error, 
-div.message, p.message, 
-div.static-msg, p.static-msg {
-	padding: 0.5em 0.5em 0.5em 48px;
+.error, .message, .static-msg, .static-msg, .success {
+	padding: 1em 0.5em 0.5em 48px;
 	margin-bottom: 1em;
 	border-radius: 8px;
 }
-p.error, p.message, p.static-msg {
+p.error, p.message, p.static-msg, p.success {
 	padding-top: 1em;
 	padding-bottom: 1em;
 }
-div.error, p.error {
-	background: #ffdec8 url(msg-error.png) no-repeat .7em .7em;
+.error {
+	background: #FFBABA url(msg-error.png) no-repeat .7em .7em;
 	color: #000;
 }
-div.message, p.message, 
-div.static-msg, p.static-msg {
+.message, .static-msg {
 	background: #666 url(msg-std.png) no-repeat .7em .7em;
 	color: #fff;
 }
-div.message a, p.message a, 
-div.static-msg a, p.static-msg a {
+.success {
+	background: #bee74b url(msg-success.png) no-repeat .7em .7em;
+	color: #000;
+}
+.message a, .static-msg a {
 	color: #fff;
+}
+.success a {
+	color: #666;
+}
+/* ------------------------------------------------------------------ navigation */
+.anchor-nav {
+	background: #575859;
+	color: #fff;
+	padding: 4px 1em;
+	float: right;
+}
+.nav_prevnext {
+	margin-bottom: 2em;
+	color: #fff;
+}
+.nav_prevnext a, a.back {
+	border: 1px solid #ddd;
+	padding: 2px 1.5em;
+	border-radius: .75em;
+	background-color: #f0f0f0;
+}
+a.back:before {
+	content: "\ab\a0";
+}
+a.onblog_link {
+	color: #333;
+	float: right;
+	border: 1px solid #eee;
+	padding: 2px 1.5em;
+	border-radius: .75em;
+	background-color: #ffe;
 }
 /* ------------------------------------------------------------------ debug */
@@ -897,7 +1213,33 @@
 }
 /* -------------------------------------------------------------------- CLASSES COMMUNES */
-
-.no-margin {
-	margin: 0;
+.no-margin, #entry-content label.no-margin {
+	margin: 0;
+}
+.vertical-separator {
+	margin-top: 2em;
+}
+p.clear.vertical-separator {
+	padding-top: 2em;
+}
+.border-top {
+	border-top: 1px solid #999;
+	padding-top: 1em;
+	margin-top:	1em;
+}
+.fieldset {
+	background: #fff;
+	border: 1px solid #aaa;
+	border-radius: 6px;
+	padding: 1em .7em .5em;
+	margin-bottom: 1em;
+}
+.fieldset h3 {
+	color: #333;
+}
+.table {
+	display: table;
+}
+.cell {
+	display: table-cell;
 }
 /* paragraphe pour bouton Nouveau bidule */
@@ -914,5 +1256,612 @@
 	vertical-align: middle;
 }
-/* Si quelque chose a besoin d'être caché sauf pour les revues d'écran */
+
+.clear {
+	clear: both;
+}
+.lclear {
+	clear: left;
+}
+div.clearer {
+	height: 1px;
+	font-size: 1px;
+}
+.right {
+	text-align: right;
+}
+.txt-center {
+	text-align: center;
+}
+.frame-shrink {
+	border: 1px solid #666;
+	padding: 0.5em;
+	margin-bottom: 1em;
+	height: 120px;
+	overflow: auto;
+}
+.grid {
+	background: transparent repeat url('grid.png') 0 0;
+}
+.line p {
+	margin: 0;
+}
+.offline {
+	color: #666;
+}
+ul.nice {
+	margin: 1em 0;
+	padding: 0 0 0 2em;
+	list-style: square;
+}
+ul.nice li {
+	margin:0;
+	padding: 0;
+}
+.zip-dl {
+	background: transparent url(package.png) no-repeat 0 50%;
+	padding: 5px 0 5px 20px;
+}
+.distrib img {
+	display: block;
+	float: right;
+	margin-top: -1em;
+}
+
+/* TABLES
+-------------------------------------------------------- */
+table {
+	font-size: 12px; /* ie < 9 sucks */
+	font-size: 1.2rem;
+	border-collapse: collapse;
+	margin: 0 0 1em 0;
+}
+table.posts-list {
+	min-width: 50%;
+}
+tr.line:hover {
+	background: #f3f3f3;
+}
+caption {
+	color: #333;
+	font-weight: bold;
+	text-align: left;
+	margin-bottom: .5em;
+}
+
+td {
+	border-width: 0 0 1px 0;
+	border-style: solid;
+	border-color: #e3e3e3;
+	padding: .3em 1em .3em .5em;
+	vertical-align: top;
+}
+th {
+	border-width: 1px 0 1px 0;
+	border-style: solid;
+	border-color: #ccc;
+	background: #f3f3ff;
+	padding: .3em 1em .3em .5em;
+	vertical-align: top;
+	text-align: left;
+}
+th.first img {
+	padding-right: 24px;
+}
+.noborder td, td.noborder, .noborder th, th.noborder {
+	border-width: 0 0 1px 0;
+	border-color: #ddd;
+	line-height: 2em;
+	padding-bottom: 0;
+}
+.noborder p {
+	margin-bottom: 0;
+}
+table .maximal, table.maximal {
+	width: 100%;
+}
+table .minimal {
+	width: 1px;
+}
+table .nowrap {
+	white-space: nowrap;
+	vertical-align: top;
+}
+table .count {
+	text-align: right;
+	padding-right: 1.5em;
+}
+table.settings, table.prefs {
+	width: 80%;
+	border: 1px solid #999;
+	margin-bottom: 3em;
+}
+table.settings th, table.prefs th {
+	background: #f3f3ff;
+}
+table.settings th:first-child, table.prefs th:first-child {
+	width: 20%;
+}
+table.settings th + th, table.prefs th + th {
+	width: 30%;
+}
+table.settings th + th + th, table.prefs th + th + th {
+	width: 10%;
+}
+table.settings th:last-child, table.prefs th:last-child {
+	width: 40%;
+}
+td.status {
+	vertical-align: middle;
+}
+td.status img {
+	margin-bottom: -2px;
+}
+td.status a {
+	border: none;
+}
+tr.line img.expand, th img.expand {
+	margin-right: 6px;
+	margin-bottom: -2px;
+}
+tr.line input {
+	vertical-align: middle;
+}
+tr.expand td {
+	border-bottom: none;
+}
+td.expand {
+	padding: 1em;
+}
+
+.dragable {
+	border-collapse: separate;
+}
+.dragable tbody td {
+
+}
+.handle {
+	padding: 0;
+}
+.handler {
+	cursor: move;
+	background: transparent url(drag.png) no-repeat 0 50%;
+	padding-left: 15px;
+}
+/* ----------------------------------------------------------------- FORMS */
+form {
+	display: block;
+	margin: 0;
+	padding: 0;
+}
+fieldset {
+	display: block;
+	margin: 0 0 1em 0;
+	padding: 1em 0.5em;
+	border-width: 1px 0;
+	border-style: solid;
+	border-color: #ccc;
+	background: #f5f5f5;
+}
+legend {
+	font-weight: bold;
+	padding: 0.2em 0.6em;
+	border-width: 1px;
+	border-style: solid;
+	border-color: #333;
+	background: #fff;
+	margin-bottom: 0.5em;
+	border-radius: 3px;
+}
+optgroup {
+	font-weight: bold;
+	font-style: normal;
+}
+option {
+	font-weight: normal;
+}
+input, textarea, select {
+	background: #f9f9f9;
+	color: #000;
+	border-width: 2px;
+	border-style: solid;
+	border-color: #ccc #ddd #ddd #ccc; 
+}
+select {
+	border-right: 2px solid #fff;
+}
+input.invalid, textarea.invalid, select.invalid {
+	border: 1px solid red;
+	background: #fff;
+	color: red;
+	box-shadow: 0 0 0 1px rgba(218, 62, 90, 0.3)
+}
+input, textarea, select, option {
+	font: 100% "DejaVu Sans","Lucida Grande","Lucida Sans Unicode",Arial,sans-serif;
+}
+input[type=text], input[type=password], textarea {
+	padding: 2px 0;
+	margin-right: .3em;
+}
+textarea {
+	padding: 2px 0;
+}
+input[type=checkbox], input[type=radio], input[type=file] {
+	border: none;
+	margin: 0;
+	padding: 0;
+	background: transparent;
+}
+input[type=file] {
+	margin-top: .3em;
+	margin-bottom: .3em;
+}
+label {
+	display: block;
+}
+label input, label select, label span {
+	display: block;
+}
+p.form-note {
+	font-style:italic;
+	margin-top: -.7em;
+	color: #666;
+}
+span.form-note {
+	font-style:italic;
+	font-weight: normal;
+	text-transform: none;
+	color: #666;
+}
+p.form-note.warn, p.form-note.info, p.warning {
+	font-style: normal;
+	padding: .2em .66em .2em;
+	text-indent: 24px;
+	color: #333;
+	display: inline-block;
+	line-height: 1.5em;
+}
+p.form-note.warn, p.warning {
+	background: #ffd url(msg-warning.png) no-repeat .3em .3em;
+	border: 1px solid #f0c020;
+}
+p.form-note.info {
+	background: #f5eaff url(msg-info.png) no-repeat .3em .3em;
+	border: 1px solid #c484ff;
+}
+.form-note a {border-bottom: 1px solid #ddbaff;}
+
+label.ib {
+	display: inline-block;
+}
+label.classic {
+	display: inline;
+}
+label.classic input, label span input, label.classic select, label span select {
+	display: inline;
+}
+
+label.area, p.area {
+	width: inherit !important;
+}
+.area textarea {
+	display: block;
+	width: 100%;
+	resize: vertical;
+}
+label.required {
+	font-weight: bold;
+}
+label.required abbr {
+	color: #dd0000;
+	font-size: 1.3em;
+}
+label.inline {
+	display: inline;
+}
+p.field {
+	position: relative;
+
+}
+p.field label {
+	display: block;
+	width: 14em;
+}
+p.field input, p.field select {
+	display: inline;
+	position: absolute;
+	left: 14.5em;
+	top: 0;
+}
+label .maximal, textarea.maximal, input.maximal {
+	width: 100%;
+}
+textarea.maximal {
+	resize: vertical;
+}
+
+a.form-control {
+	display: none;
+	background: url(../images/expand.png) no-repeat 4px center;
+	padding-left: 20px;
+	color: #000;
+}
+.constrained {
+	margin: 0;
+	padding: 0;
+	border: none;
+	background: transparent;
+}
+input:focus, textarea:focus, select:focus {
+	-webkit-box-sizing: border-box;
+	-moz-box-sizing: border-box;
+	box-sizing: border-box;
+	border: 2px solid #bee74b;
+}
+/* --------------------------------------------------------------- buttons */
+/* commun */
+input[type=submit],
+input[type=reset],
+input[type=button],
+a.button,
+a.submit {
+	display: inline-block;
+	cursor: pointer;
+	text-align: center;
+	text-decoration: none;
+	padding: .1em .5em;
+	border-radius: .2em;
+	margin-bottom: .1em;
+	font-size: 12px; /* ie < 9 sucks */
+	font-size: 1.2rem;
+ }
+h4 a.button {font-weight: normal;}
+
+/* validation */
+input[type=submit],
+input[type=button],
+a.submit {
+	color: #fff;
+	text-shadow: 0 -1px 1px #1A87B9;
+	background:#25A6E1;
+	background:-moz-linear-gradient(top,#25A6E1 0%,#188BC0 100%);
+	background:-webkit-gradient(linear,left top,left bottom,color-stop(0%,#25A6E1),color-stop(100%,#188BC0));
+	background:linear-gradient(top,#25A6E1 0%,#188BC0 100%);
+	filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#25A6E1',endColorstr='#188BC0',GradientType=0);
+	border:1px solid #2C8FD1;
+
+}
+input[type=submit]:hover,
+input[type=button]:hover,
+a.submit:hover,
+input[type=submit]:focus,
+input[type=button]:focus,
+a.submit:focus {
+	background:#188BC0;
+	background:-moz-linear-gradient(top,#188BC0 0%,#25A6E1 100%);
+	background:-webkit-gradient(linear,left top,left bottom,color-stop(0%,#188BC0),color-stop(100%,#25A6E1));
+	background:linear-gradient(top,#188BC0 0%,#25A6E1 100%);
+	filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#25A6E1',endColorstr='#25A6E1',GradientType=0);
+}
+/* suppression et reset */
+a.button,
+input[type=submit].reset,
+input[type=submit].delete {
+	border: 1px solid #ccc;
+	background: #f5f5f5;
+	color: #000;
+	background: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#dfdfdf));
+	background: -moz-linear-gradient(top,  #f5f5f5,  #dfdfdf);
+	text-shadow:1px 1px 0px #fff;
+	}
+a.button:hover,
+input[type=reset]:hover,
+input[type=submit].reset:hover,
+input[type=submit].delete:hover,
+a.button:focus,
+input[type=reset]:focus,
+input[type=submit].reset:focus,
+input[type=submit].delete:focus {
+	background:-webkit-gradient( linear, left top, left bottom, color-stop(0.05, #e9e9e9), color-stop(1, #f9f9f9) );
+	background:-moz-linear-gradient( center top, #e9e9e9 5%, #f9f9f9 100% );
+	filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#e9e9e9', endColorstr='#f9f9f9');
+	background-color:#e9e9e9;
+	}
+a.delete,
+input.delete,
+input[type=submit].delete {
+	color: #c00;
+	padding-bottom: 2px;
+}
+#entry-content .delete {
+	margin-left: 1em;
+}
+a.delete:hover,
+input.delete:hover,
+input[type=submit].delete:hover,
+a.delete:focus,
+input.delete:focus,
+input[type=submit].delete:focus {
+	border-color: #c00;
+}
+/* finasseries */
+input[type=button] {
+	padding: .1em;
+}
+#info-box a.button {
+	padding: 0 .5em;
+	margin-left: 2em;
+}
+.button.add {
+	background:-webkit-gradient( linear, left top, left bottom, color-stop(0.05, #bee74b), color-stop(1, #9BCA1C) );
+	background:-moz-linear-gradient( center top, #bee74b 5%, #9BCA1C 100% );
+	filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#bee74b', endColorstr='#9BCA1C');
+	background-color:#bee74b;
+	border:1px solid #B2D742;
+	padding:.5em 1.5em;
+	color: #000;
+	text-shadow:1px 1px 0px #98cf40;
+	font-weight: normal;
+	font-size: 14px; /* ie < 9 sucks */
+	font-size: 1.4rem;
+}
+.button.add:hover, .button.add:active, .button.add:focus {
+	background:-webkit-gradient( linear, left top, left bottom, color-stop(0.05, #9BCA1C), color-stop(1, #bee74b) );
+	background:-moz-linear-gradient( center top, #9BCA1C 5%, #bee74b 100% );
+	filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#9BCA1C', endColorstr='#bee74b');
+	background-color:#9BCA1C;
+}
+.button-add:focus {
+	outline: dotted 1px;
+}
+
+/* jQuery Autocomplete plugin */
+.ac_results {
+	padding: 0px;
+	border: 1px dotted #f90;
+	background-color: white;
+	overflow: hidden;
+	z-index: 99999;
+}
+.ac_results ul {
+	width: 100%;
+	list-style-position: outside;
+	list-style: none;
+	padding: 0;
+	margin: 0;
+}
+.ac_results li {
+	margin: 0px;
+	padding: 2px 5px;
+	cursor: default;
+	display: block;
+	font: menu;
+	font-size: 1em;
+	line-height: 16px;
+	overflow: hidden;
+}
+.ac_loading {
+	background: transparent url('loader.gif') right center no-repeat;
+}
+.ac_over {
+	background-color: #06c;
+	color: white;
+}
+
+/* ------------------------------------------------------- Filters */
+#filters-form {
+	border: 1px dashed #999;
+	border-radius: .5em;
+	margin-bottom: 2em;
+	padding: .5em 1em 0;
+}
+#filters-form .table {
+	display: table;
+	width: 100%;
+	padding: 0;
+	margin-bottom: 1em;
+	margin-top: .5em;
+}
+#filters-form .cell {
+	padding: 0 2em 0 0;
+	display: table-cell;
+	vertical-align: top;
+}
+#filters-form .filters-sibling-cell {
+	padding-top: 3.8em;
+}
+#filters-form .filters-options {
+	padding-left: 2em;
+	border-left: 1px solid #ccc;
+}
+#filters-form label.ib, span.ib {
+	width:7em;
+	display: inline-block;
+}
+#filters-form label.ibw, span.ibw {
+	width: 9em;
+	display: inline-block;
+}
+#filters-form select {
+	width: 14em;
+}
+#filters-form h4 {
+	margin-top: 0;
+	margin-bottom: 2em;
+}
+
+/* ---------------------------------------------------- Pagination */
+.pagination {
+	height: 22px;
+	margin-top: 1em;
+	line-height: 22px;
+	padding: 0 .75em;
+	border: 1px solid #ddd;
+	overflow: hidden;
+	background: #e1e1e1;
+	background: -moz-linear-gradient(center top , #f2f2f2, #e1e1e1);
+	background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#f2f2f2), color-stop(100%,#e1e1e1));
+	-moz-border-radius: 4px;
+	-webkit-border-radius: 4px;
+	border-radius: 4px;
+	clear: left;
+}
+.pagination a, .pagination strong {
+	height: 20px;
+	border: none;
+	padding: 2px 6px;
+	background-color : transparent;
+	background-position : 50% 50%;
+	background-repeat: no-repeat;
+}
+.pagination a:hover, .pagination strong {
+	border-color : #ccc;
+	background-color: #fff;
+}
+
+/* --------------------------------------------------------------- password indcator */
+.pw-table {
+	display: table;
+	margin-bottom: 1em;
+}
+.pw-cell {
+	display: table-cell;
+	margin-bottom: 1em;
+}
+#pwindicator {
+	display: table-cell;
+	vertical-align: bottom;
+	padding-left: 1.5em;
+	height: 3.8em;
+}
+#pwindicator .bar {
+	height: 6px;
+	margin-bottom: 4px;
+}
+.pw-very-weak .bar {
+	background: #900;
+	width: 30px;
+}
+.pw-weak .bar {
+	background: #c00;
+	width: 60px;
+}
+.pw-mediocre .bar {
+	background: #f60;
+	width: 90px;
+}
+.pw-strong .bar {
+	background: #060;
+	width: 120px;
+}
+.pw-very-strong .bar {
+	background: #0c0;
+	width: 150px;
+}
+/* ------------------------------------------------------------- cachotteries */
+/* caché pour tout le monde */
+.hide {
+	display: none;
+}
+/* Caché sauf pour les revues d'écran */
 .hidden {
     position: absolute !important;
@@ -925,500 +1874,70 @@
     overflow: hidden;
     }
-.clear {
-	clear: both;
-}
-.lclear {
-	clear: left;
-}
-div.clearer {
-	height: 1px;
-	font-size: 1px;
-}
-.hide {
-	display: none;
-}
-.right {
-	text-align: right;
-}
-.frame-shrink {
-	border: 1px solid #666;
-	padding: 0.5em;
-	margin-bottom: 1em;
-	height: 120px;
-	overflow: auto;
-}
-.grid {
-	background: transparent repeat url('grid.png') 0 0;
-}
-.line p {
-	margin: 0;
-}
-.offline {
-	color: #666;
-}
-ul.nice {
-	margin: 1em 0;
-	padding: 0 0 0 2em;
-	list-style: square;
-}
-ul.nice li {
-	margin:0;
-	padding: 0;
-}
-.zip-dl {
-	background: transparent url(package.png) no-repeat 0 50%;
-	padding: 5px 0 5px 20px;
-}
-/* pas trouvé dans le code */
-.comment {
-	border-top: 2px solid #ccc;
-	margin-bottom: 1em;
-	padding: 2em 0 1em 0;
-	position: relative;
-}
-.comment form p {
-	margin: 0;
-	position: absolute;
-	top: 2px;
-	right: 0;
-}
-.distrib img {
-	display: block;
-	float: right;
-	margin-top: -1em;
-}
-/* TABLES
--------------------------------------------------------- */
-table {
-	font-size: 1em;
-	border-collapse: collapse;
-	margin: 0 0 1em 0;
-}
-tr.line:hover {
-	background: #ddd;
-}
-caption {
-	color: #333;
-	font-size: 1.2em;
-	font-weight: bold;
-	text-align: left;
-	margin-bottom: .5em;
+/* caché si js est inactif */
+.no-js .hidden-if-no-js {
+        display: none;
+}
+/* montré si js est inactif */
+.no-js .hidden-if-js {
+	display: block;
+}
+/* caché si js est actif */
+.hidden-if-js {
+        display: none;
 }
 
-th, td {
-	border-width: 0 0 1px 0;
-	border-style: solid;
-	border-color: #ccc;
-	padding: 3px 5px;
-	vertical-align: top;
-}
-th {
-	text-align: left;
-	border-bottom-color: #666;
-}
-.noborder td, td.noborder, .noborder th, th.noborder {
-	border-width: 0;
-}
-table .maximal, table.maximal {
-	width: 100%;
-}
-table .minimal {
-	width: 1px;
-}
-table .nowrap {
-	white-space: nowrap;
-	vertical-align: top;
-}
-table.settings, table.prefs {
-	width: 80%;
-}
-table.settings th:first-child, table.prefs th:first-child {
-	width: 20%;
-}
-table.settings th + th, table.prefs th + th {
-	width: 30%;
-}
-table.settings th + th + th, table.prefs th + th + th {
-	width: 10%;
-}
-table.settings th:last-child, table.prefs th:last-child {
-	width: 40%;
-}
-
-td.status {
-	vertical-align: middle;
-}
-td.status img {
-	margin-bottom: -2px;
-}
-td.status a {
-	border: none;
-}
-
-tr.line img.expand {
-	margin-right: 10px;
-	margin-bottom: -2px;
-}
-tr.line input {
-	vertical-align: middle;
-}
-tr.expand td {
-	border-bottom: none;
-}
-td.expand {
-	padding: 1em;
-}
-
-.dragable {
-	border-collapse: separate;
-}
-.dragable tbody td {
-
-}
-.handle {
-	padding: 0;
-}
-.handler {
-	cursor: move;
-	background: transparent url(drag.png) no-repeat 0 50%;
-	padding-left: 15px;
-}
-
-/* ----------------------------------------------------------------- FORMS */
-form {
-	display: block;
-	margin: 0;
-	padding: 0;
-}
-fieldset, .fieldset {
-	display: block;
-	margin: 0 0 1em 0;
-	padding: 1em 0.5em;
-	border-width: 1px 0;
-	border-style: solid;
-	border-color: #ccc;
-	background: #f5f5f5;
-}
-legend {
-	font-weight: bold;
-	padding: 0.2em 0.6em;
-	border-width: 1px;
-	border-style: solid;
-	border-color: #ccc;
-	background: #f5f5f5;
-	margin-bottom: 0.5em;
-}
-optgroup {
-	font-weight: bold;
-	font-style: normal;
-}
-option {
-	font-weight: normal;
-}
-input, textarea, select {
-	background: #f9f9f9;
-	color: #000;
-	border-width: 1px;
-	border-style: solid;
-	border-color: #000 #ccc #ccc #000;
-}
-input.invalid, textarea.invalid, select.invalid {
-	border: 1px solid red;
-	background: #fff; 
-	color: red;
-	box-shadow: 0 0 0 1px rgba(218, 62, 90, 0.3)
-}
-input, textarea, select, option {
-	font: 1em "DejaVu Sans","Lucida Grande","Lucida Sans Unicode",Arial,sans-serif;
-}
-input[type=text], input[type=password], textarea {
-	padding: 2px 0;
-	margin-right: .3em;
-}
-input[type=checkbox], input[type=radio] {
-	border: none;
-}
-textarea {
-	padding: 2px 0;
-}
-
-input[type=checkbox], input[type=radio] {
-	margin: 0;
-	padding: 0;
-	background: transparent;
-}
-label {
-	display: block;
-}
-label input, label select, label span {
-	display: block;
-}
-p.form-note {
-	font-style:italic;
-	margin-top: -.7em;
-	color: #666;
-}
-span.form-note {
-	font-style:italic;
-	font-weight: normal;
-	color: #666;
-}
-p.form-note.warn, p.form-note.info, p.warning {
-	font-style: normal;
-	padding: .2em 1em .1em 24px;
-}
-p.form-note.warn, p.warning {
-	background: #ffd url(warning.png) no-repeat .3em .3em;
-	border: 1px solid #f0c020;
-}
-p.form-note.info {
-	background: #eef url(info.png) no-repeat .3em .2em;
-	border: 1px solid #99f;
-}
-.form-note a {border-bottom: 1px solid #99f;}
-
-label.classic {
-	display: inline;
-}
-label.classic input, label span input, label.classic select, label span select {
-	display: inline;
-}
-
-label.area, p.area {
-	width: inherit !important;
-}
-.area textarea {
-	display: block;
-	width: 100%;
-	resize: vertical;
-}
-label.required {
-	font-weight: bold;
-}
-label.required abbr {
-	color: #dd0000;
-	font-size: 1.3em;
-}
-label.inline {
-	display: inline;
-}
-p.field {
-	position: relative;
-	
-}
-p.field label {
-	display: block;
-	width: 14em;
-}
-p.field input, p.field select {
-	display: inline;
-	position: absolute;
-	left: 15em;
-	top: 0;
-}
-label .maximal, textarea.maximal, input.maximal {
-	width: 100%;
-}
-textarea.maximal {
-	resize: vertical;
-}
-
-a.form-control {
-	display: none;
-	font-weight: bold;
-	background: url(magnifier.png) no-repeat 0 0;
-	color: green;
-	padding-left: 20px;
-}
-.constrained {
-	margin: 0;
-	padding: 0;
-	border: none;
-	background: transparent;
-}
-
-/* --------------------------------------------------------------- buttons */
-h2 a.button {
-	color: #333;
-	font-weight: normal;
-	font-size: .75em;
-	vertical-align: middle;
-}
-/* commun */
-input[type=submit],
-input[type=reset],
-input[type=button],
-a.button,
-a.back,
-a.submit {
-	display: inline-block;
-	outline: none;
-	cursor: pointer;
-	text-align: center;
-	text-decoration: none;
-	padding: .1em .5em 0 .5em;
-	text-shadow: 0 1px 1px rgba(0,0,0,.3);
-	border-radius: .2em;
-	margin-bottom: .1em;
-}
-/* validation */
-input[type=submit],
-input[type=button],
-a.submit {
-	color: #fff;
-	border: 1px solid #2373A8;
-	background: #2373A8;
-	background: -webkit-gradient(linear, left top, left bottom, from(#2C8FD1), to(#2373A8));
-	background: -moz-linear-gradient(top,  #2C8FD1,  #2373A8);
-}
-input[type=submit]:hover,
-input[type=button]:hover,
-a.submit:hover,
-input[type=submit]:focus,
-input[type=button]:focus,
-a.submit:focus {
-	background: #2373A8;
-	background: -webkit-gradient(linear, left top, left bottom, from(#2373A8), to(#2C8FD1));
-	background: -moz-linear-gradient(top,  #2373A8,  #2C8FD1);
-	filter:  progid:DXImageTransform.Microsoft.gradient(startColorstr='#2373A8', endColorstr='#2C8FD1');
-	border: 1px solid #2C8FD1;
-}
-/* suppression et reset */
-a.button,
-a.back,
-input[type=submit].reset,
-input[type=submit].delete {
-	border: 1px solid #ccc;
-	background: #f5f5f5;
-	color: #000;
-	background: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#dfdfdf));
-	background: -moz-linear-gradient(top,  #f5f5f5,  #dfdfdf);
-	text-shadow: none;
+/* ---------------------------------------------------------------------------
+	Media queries vite fait en attendant la reprise complète du layout
+---------------------------------------------------------------------------- */
+@media screen and (max-width: 920px) {
+	#top, #top h1 a {width: 42px !important; height:100%; overflow: hidden;
+}
+	#top h1 a:link {
+		background: transparent url(dc_logos/b-dotclear120.png) no-repeat -180px 6px;
+		border-right: 1px solid #ccc;
 	}
-a.button:hover,
-a.back:hover,
-input[type=reset]:hover,
-input[type=submit].reset:hover,
-input[type=submit].delete:hover,
-a.button:focus,
-a.back:focus,
-input[type=reset]:focus,
-input[type=submit].reset:focus,
-input[type=submit].delete:focus {
-	background: #dfdfdf;
-	background: -webkit-gradient(linear, left top, left bottom, from(#dfdfdf), to(#f5f5f5));
-	background: -moz-linear-gradient(top,  #dfdfdf,  #f5f5f5);
-	filter:  progid:DXImageTransform.Microsoft.gradient(startColorstr='#e5e5e5', endColorstr='#f5f5f5');
+	#top h1 a:hover, #top h1 a:focus {
+		background: url(dc_logos/b-dotclear120.png) no-repeat -180px -94px;
+		border-right: 1px solid #A2CBE9;
 	}
-a.delete,
-input.delete,
-input[type=submit].delete {
-	color: #c00;
-	padding-bottom: .1em;
-}
-#entry-content .delete {
-	margin-left: 1em;
-}
-a.delete:hover,
-input.delete:hover,
-input[type=submit].delete:hover,
-a.delete:focus,
-input.delete:focus,
-input[type=submit].delete:focus {
-	border-color: #c00;
-}
-/* finasseries */
-input[type=button] {
-	padding: .1em;
-}
-#info-box a.button {
-	padding: 0 .5em;
-	margin-left: 2em;
-}
-a.back:before {
-	content: "\ab\a0";
-}
-a.button.add {
-	border-radius: .5em;
-	margin-bottom: .1em;	
-	background: #2C8FD1 url(../images/add.png) no-repeat 6px center;
-	color: #fff;
-	padding: .2em 16px .2em 30px;
-	border: 1px solid #2373A8;
-}
-a.button.add:hover, a.button.add:focus {
-	background-color: #2373A8;
-}
-
-/* jQuery Autocomplete plugin */
-.ac_results {
-	padding: 0px;
-	border: 1px dotted #f90;
-	background-color: white;
-	overflow: hidden;
-	z-index: 99999;
-}
-.ac_results ul {
-	width: 100%;
-	list-style-position: outside;
-	list-style: none;
-	padding: 0;
-	margin: 0;
-}
-.ac_results li {
-	margin: 0px;
-	padding: 2px 5px;
-	cursor: default;
-	display: block;
-	font: menu;
-	font-size: 1em;
-	line-height: 16px;
-	overflow: hidden;
-}
-.ac_loading {
-	background: transparent url('loader.gif') right center no-repeat;
-}
-.ac_over {
-	background-color: #06c;
-	color: white;
-}
-
-/* --------------------------------------------------------------- password indcator */
-.pw-table {
-	display: table;
-	margin-bottom: 1em;
-}
-.pw-cell {
-	display: table-cell;
-	margin-bottom: 1em;
-}
-#pwindicator {
-	display: table-cell;
-	vertical-align: bottom;
-	padding-left: 1.5em;
-	height: 3.8em;
-}
-#pwindicator .bar {
-	height: 6px;
-	margin-bottom: 4px;
-}
-.pw-very-weak .bar {
-	background: #900;
-	width: 30px;
-}
-.pw-weak .bar {
-	background: #c00;
-	width: 60px;
-}
-.pw-mediocre .bar {
-	background: #f60;
-	width: 90px;
-}
-.pw-strong .bar {
-	background: #060;
-	width: 120px;
-}
-.pw-very-strong .bar {
-	background: #0c0;
-	width: 150px;
-}
+}
+@media screen and (max-width: 800px) {
+	#top, #info-boxes, #info-box1, #info-box2 {
+		display:inline-block;
+		vertical-align:middle;
+		margin:0;
+		padding:0;
+		line-height: 32px; /* ie < 9 sucks */
+		line-height: 3.2rem;
+	}
+	#info-box1 {margin-left: .75em;}
+	#info-box1 select {width: 140px; width: 14rem;}
+	#main-menu, #main, #content, #content h2, #entry-wrapper, #entry-sidebar, #entry-content, .two-cols .col, .two-cols .col:first-child {
+    	display:block;
+    	width: 98%;
+    	margin:0 auto;
+    	padding:0;
+    	float:none;
+    	text-align: left;
+    	clear: both;
+  	}
+  	#content {
+  		width: 100%;
+  		padding-top: .5em;
+  	}
+}
+@media screen and (max-width: 720px) {
+	.smallscreen {display: none;}
+	#help-button {width:20px; overflow: hidden;}
+	#info-box2 {float:none;}
+	#dashboard-items div {display: block;margin-bottom: 1em; padding: 0 1em;}
+	#help-button {height:26px; width:26px; background-color: #A2CBE9; padding: 0; margin:0;font-size:10px; font-size: 1rem;line-height: 68px}
+}
+@media screen and (max-width: 492px) {
+	#header {height: 36px; height: 3.6rem;}
+	#wrapper {font-size: 16px; font-size: 1.6rem;}
+	.page-title, #info-boxes, .media-item {display: inline-block;}
+	div.media-list .media-item {width: 90%; float: none}
+	#info-box1 select {width: 120px; width: 12rem; margin-right: .6rem;}
+	#info-box1 p.nomobile, label.nomobile {display: none;}
+}
Index: admin/style/install.css
===================================================================
--- admin/style/install.css	(revision 1583)
+++ admin/style/install.css	(revision 1620)
@@ -6,9 +6,13 @@
 	Please see http://dotclear.net/ for more details.
 */
+html {
+	font-size: 62.5%;
+}
 body.install {
-	font: 0.875em Helvetica,Arial,sans-serif;
-	color: #000;
-	background-color: #fff;
-	line-height: 1.5em;
+	font: 1.2rem/1.5 Arial,Helvetica,sans-serif;
+	color: #333;
+	background: #fff;
+	margin: 0;
+	padding: 0;
 }
 body.install #content {
@@ -22,5 +26,5 @@
 }
 body.install h1,h2 {
-	font-family: Helvetica,arial,sans-serif;
+	font-family: arial,Helvetica,sans-serif;
 }
 body.install h1 {
Index: admin/style/jsToolBar/jsToolBar.css
===================================================================
--- admin/style/jsToolBar/jsToolBar.css	(revision 1065)
+++ admin/style/jsToolBar/jsToolBar.css	(revision 1636)
@@ -2,13 +2,16 @@
 	border-width : 0 1px 1px 1px;
 	border-style : solid;
-	border-color : #000 #ccc #ccc #000;
-	padding-left: 5px;
+	border-color : #ccc;
 	background : #f9f9f9;
 }
 .jstEditor textarea, .jstEditor iframe {
-  margin: 0;
-  border: 0;
+	-webkit-box-sizing: border-box;
+	-moz-box-sizing: border-box;
+	box-sizing: border-box;	
+	margin: 0;
+	border: 2px solid #f9f9f9;
+  	width: 100%;
+  	padding: .5em 0 0 0;
 }
-
 .jstHandle {
 	height: 8px;
@@ -20,11 +23,21 @@
 	border-style: solid;
 }
-
+.jstEditor textarea:focus, .jstEditor iframe:focus {
+	border: 2px solid #bee74b;
+}
 .jstElements {
-	padding: 3px 3px;
-	border-width: 1px 1px 0 1px;
-	border-style: solid;
-	border-color: #000 #ccc #ccc #000;
-	background: #dfdfdf;
+	height: 28px;
+	padding: 0 1rem; 
+	border: 1px solid #ccc;
+	overflow: hidden; 
+	background: #e1e1e1; 
+	background: -moz-linear-gradient(center top , #f2f2f2, #e1e1e1); 
+	background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#f2f2f2), color-stop(100%,#e1e1e1)); 
+	-moz-border-radius: 4px 4px 0 0; 
+	-webkit-border-radius: 4px 4px 0 0; 
+	border-radius: 4px 4px 0 0; 
+	-webkit-box-shadow: 0 1px 0 #FFF inset; 
+	-moz-box-shadow: 0 1px 0 #FFF inset; 
+	box-shadow: 0 1px 0 #FFF inset;
 }
 
@@ -34,13 +47,12 @@
 .jstElements select {
 	width: 12em;
+	margin-right: .6rem;
 }
 .jstElements button {
-	margin-right : 2px;
-	width : 20px;
-	height: 20px;
-	padding: 0;
-	border-style: solid;
-	border-width: 1px;
-	border-color: #dfdfdf;
+	width : 30px;
+	height: 28px;
+	border-style: groove;
+	border-width:  0 1px 0 0;
+	border-color: #666;
 	background-color : transparent;
 	background-position : 50% 50%;
@@ -55,11 +67,16 @@
 }
 .jstElements span {
-	display : inline;
+	display : inline-block;
+	vertical-align: top;
+	background: #dfdfdf;
 }
 
 .jstSpacer {
-	width : 0px;
-	font-size: 1px;
-	margin-right: 4px;
+	width : 2px;
+	height: 28px;
+	margin-right: 0;
+	border-style: groove;
+	border-width:  0 1px 0 0;
+	border-color: #666;
 }
 
@@ -67,19 +84,17 @@
 	display: block;
 	list-style: none;
-	margin: 0 0 0 -5px;
+	margin: 0;
 	padding: 0 0 5px 0;
 	background: #dfdfdf;
 	border-top: 1px solid #999;
-	font-size: 90%;
-	font-weight: bold;
 }
 .jstSwitcher li {
 	display: inline;
 	margin: 0 0 0 5px;
-	padding: 2px 4px;
+	padding: 2px 8px;
 }
 .jstSwitcher li.jstSwitcherCurrent {
 	color: #fff;
-	background: #999;
+	background: #575859;
 	border-radius: 0 0 2px 2px;
 }
@@ -143,5 +158,4 @@
 }
 
-
 /* WYSIWYG Iframe */
 .wysiwygIframe {
Index: admin/style/jsUpload/style.css
===================================================================
--- admin/style/jsUpload/style.css	(revision 1209)
+++ admin/style/jsUpload/style.css	(revision 1588)
@@ -20,5 +20,4 @@
 	float: left;
 }
-
 .enhanced_uploader .button:hover {
 	background: #2373A8;
@@ -27,6 +26,6 @@
 	border: 1px solid #2C8FD1;
 }
-
-.enhanced_uploader .add, .enhanced_uploader .clean, .enhanced_uploader .cancel, .enhanced_uploader .disabled {
+.enhanced_uploader .add, .enhanced_uploader .clean, 
+.enhanced_uploader .cancel, .enhanced_uploader .disabled {
 	text-shadow: none;
 	color: #000;
@@ -36,6 +35,6 @@
 	border: 1px solid #CCCCCC;
 }
-
-.enhanced_uploader .button.add:hover, .enhanced_uploader .button.clean:hover, .enhanced_uploader .button.cancel:hover, .enhanced_uploader .disabled:hover {
+.enhanced_uploader .button.add:hover, .enhanced_uploader .button.clean:hover, 
+.enhanced_uploader .button.cancel:hover, .enhanced_uploader .disabled:hover {
 	background: #DFDFDF;
 	background: -webkit-gradient(linear, left top, left bottom, from(#DFDFDF), to(#F5F5F5));
@@ -49,21 +48,14 @@
 	border: 1px solid #CCCCCC;
 }
-
-.enhanced_uploader .fileupload-buttonbar {
+/*.enhanced_uploader .fileupload-buttonbar {
 	margin-top: 2em;
-}
-
+}*/
 .enhanced_uploader .upload-filecancel {
 	border: none;
 }
-
-.enhanced_uploader .add {
-	margin-right: 4em;
+.enhanced_uploader .add, .enhanced_uploader .cancel, 
+.enhanced_uploader .clean, .enhanced_uploader .start {
+	margin-right: .4em;
 }
-
-.enhanced_uploader .cancel, .enhanced_uploader .clean, .enhanced_uploader .start {
-	margin-left: .5em;
-}
-
 .enhanced_uploader #upfile {
 	visibility: hidden;
@@ -75,61 +67,62 @@
 	cursor: pointer;
 }
-
-.button.clean, .button.cancel, .button.add, .enhanced_uploader .fileupload-buttonbar .button.start {
+.button.clean, .button.cancel, .button.add {
 	display: none;
 }
-
 .enhanced_uploader .button.add {
 	display: inline-block;
 }
-
 .enhanced_uploader .max-size {
 	display: block;
 }
-
 .enhanced_uploader .one-file {
 	display: none;
 }
-
 label span.one-file {
 	display: inline;
 }
-
 .enhanced_uploader p.clear {
-	margin-top: 3em;
-	margin-bottom: 0;
+	padding-top: 1em;
+	margin-bottom: 1em;
 }
-
 #add-file-f p.clear {
 	margin-top: 1em;
 	margin-bottom: 0;
+	clear: both;
 }
-
 /* files */
+.files {
+	list-style-type: none;
+	margin-left: 0;
+	padding-left: 0;
+}
+.files li {
+	margin-left: 0;
+	padding-left: 0;
+}
 .upload-msg {
 	font-weight: bold;
 }
-
 .upload-msg.upload-error {
 	color: #c00;
 }
-
 .upload-files {
 	padding: 0 0.5em;
 	margin: 10px 0;
 }
-
 .upload-file {
 	margin: 0 0 8px 0;
 	position: relative;
 }
-
 .upload-fileinfo {
-	margin-left: 16px;
+	margin-left: 8px;
 	margin-bottom: .4em;
 }
-
+.upload-fileinfo span {
+	padding-right: 8px;
+}
 .upload-fileinfo .upload-filecancel {
 	display: block;
+	padding-right: 0;
 	margin-top: 3px;
 	width: 20px;
@@ -140,18 +133,14 @@
 	float: left;
 }
-
 .upload-filemsg {
 	font-weight: bold;
 	color: green;
 }
-
 .upload-filemsg.upload-error {
 	color: #c00;
 }
-
 .upload-progress {
-	padding: 0 1em;
+	padding: 0 8px;
 }
-
 .upload-progress div {
 	width: 0;
@@ -166,6 +155,9 @@
 	border-radius: 2px;
 }
-
 div.template-upload {
 	clear: both;
 }
+.queue-message {
+	font-weight: bold;
+	margin: 0 0 1em 0;
+}
Index: admin/trackbacks.php
===================================================================
--- admin/trackbacks.php	(revision 1179)
+++ admin/trackbacks.php	(revision 1614)
@@ -83,5 +83,15 @@
 /* DISPLAY
 -------------------------------------------------------- */
-dcPage::open($page_title,dcPage::jsLoad('js/_trackbacks.js'));
+if ($can_view_page) {
+	$breadcrumb = dcPage::breadcrumb(
+	array(
+		html::escapeHTML($core->blog->name) => '',
+		html::escapeHTML($post->post_title) => $core->getPostAdminURL($post->post_type,$id),
+		'<span class="page-title">'.$page_title.'</span>' => ''
+	));
+} else {
+	$breadcrumb = '';
+}
+dcPage::open($page_title,dcPage::jsLoad('js/_trackbacks.js'),$breadcrumb);
 
 # Exit if we cannot view page
@@ -94,6 +104,4 @@
 	dcPage::message(__('All pings sent.'));
 }
-
-echo '<h2>'.html::escapeHTML($core->blog->name).' &rsaquo; <span class="page-title">'.$page_title.'</span></h2>';
 
 echo '<p><a class="back" href="'.$core->getPostAdminURL($post->post_type,$id).'">'.
@@ -112,6 +120,6 @@
 	$tb_urls = implode("\n",$TB->discover($post->post_excerpt_xhtml.' '.$post->post_content_xhtml));
 } else {
-	$auto_link = '<strong><a class="button" href="trackbacks.php?id='.$id.'&amp;auto=1">'.
-	__('Auto discover ping URLs').'</a></strong>';
+	$auto_link = '<a class="button" href="trackbacks.php?id='.$id.'&amp;auto=1">'.
+	__('Auto discover ping URLs').'</a>';
 }
 
@@ -119,10 +127,10 @@
 '<h3>'.__('Ping blogs').'</h3>'.
 '<form action="trackbacks.php" id="trackback-form" method="post">'.
-'<p><label for="tb_urls" class="area">'.__('URLs to ping:').
+'<p><label for="tb_urls" class="area">'.__('URLs to ping:').'</label>'.
 form::textarea('tb_urls',60,5,$tb_urls).
-'</label></p>'.
+'</p>'.
 
-'<p><label for="tb_excerpt" class="area">'.__('Send excerpt:').
-form::textarea('tb_excerpt',60,3,$tb_excerpt).'</label></p>'.
+'<p><label for="tb_excerpt" class="area">'.__('Send excerpt:').'</label>'.
+form::textarea('tb_excerpt',60,5,$tb_excerpt).'</p>'.
 
 '<p>'.form::hidden('id',$id).
@@ -147,4 +155,5 @@
 }
 
+dcPage::helpBlock('core_trackbacks');
 dcPage::close();
 ?>
Index: admin/update.php
===================================================================
--- admin/update.php	(revision 1591)
+++ admin/update.php	(revision 1620)
@@ -174,12 +174,15 @@
 		dcPage::jsPageTabs($default_tab).
 		dcPage::jsLoad('js/_update.js')
-	: '')
+		: ''),
+	dcPage::breadcrumb(
+		array(
+			__('System') => '',
+			'<span class="page-title">'.__('Dotclear update').'</span>' => ''
+		))
 );
 
 if (!$core->error->flag()) {
-	echo '<h2>'.__('Dotclear update').'</h2>';
-	
 	if (!empty($_GET['nocache'])) {
-		dcPage::message(__('Manual checking of update done successfully.'));
+		dcPage::success(__('Manual checking of update done successfully.'));
 	}
 }
@@ -200,5 +203,5 @@
 		echo
 			'<p class="static-msg">'.sprintf(__('Dotclear %s is available.'),$new_v).
-				($version_info ? ' ('.sprintf(__('<a href=\"%s\">Information about this version</a>.'),$version_info).')' : '').
+				($version_info ? ' <a href="'.$version_info.'">('.__('Information about this version').')</a>' : '').
 				'</p>'.
 		
Index: admin/user.php
===================================================================
--- admin/user.php	(revision 1583)
+++ admin/user.php	(revision 1621)
@@ -15,5 +15,5 @@
 dcPage::checkSuper();
 
-$page_title = __('new user');
+$page_title = __('New user');
 
 $user_id = '';
@@ -187,16 +187,33 @@
 	
 	# --BEHAVIOR-- adminUserHeaders
-	$core->callBehavior('adminUserHeaders')
+	$core->callBehavior('adminUserHeaders'),
+
+	dcPage::breadcrumb(
+		array(
+			__('System') => '',
+			__('Users') => 'users.php',
+			'<span class="page-title">'.$page_title.'</span>' => ''
+		))
 );
 
 if (!empty($_GET['upd'])) {
-	dcPage::message(__('User has been successfully updated.'));
+	dcPage::success(__('User has been successfully updated.'));
 }
 
 if (!empty($_GET['add'])) {
-	dcPage::message(__('User has been successfully created.'));
-}
-
-echo '<h2><a href="users.php">'.__('Users').'</a> &rsaquo; <span class="page-title">'.$page_title.'</span></h2>';
+	dcPage::success(__('User has been successfully created.'));
+}
+
+echo
+'<form action="user.php" method="post" id="user-form">'.
+'<div class="two-cols">'.
+
+'<div class="col">'.
+'<h3>'.__('User profile').'</h3>'.
+
+'<p><label for="user_id" class="required"><abbr title="'.__('Required field').'">*</abbr> '.__('User ID:').'</label> '.
+form::field('user_id',20,255,html::escapeHTML($user_id)).
+'</p>'.
+'<p class="form-note">'.__('At least 2 characters using letters, numbers or symbols.').'</p>';
 
 if ($user_id == $core->auth->userID()) {
@@ -207,13 +224,4 @@
 
 echo
-'<form action="user.php" method="post" id="user-form">'.
-'<fieldset><legend>'.__('User information').'</legend>'.
-'<div class="two-cols">'.
-'<div class="col">'.
-'<p><label for="user_id" class="required"><abbr title="'.__('Required field').'">*</abbr> '.__('Username:').' '.
-form::field('user_id',20,255,html::escapeHTML($user_id)).
-'</label></p>'.
-'<p class="form-note">'.__('At least 2 characters using letters, numbers or symbols.').'</p>'.
-
 '<div class="pw-table">'.
 	'<p class="pw-cell">'.
@@ -231,49 +239,7 @@
 
 '<p><label for="new_pwd_c" '.($user_id != '' ? '' : 'class="required"').'>'.
-($user_id != '' ? '' : '<abbr title="'.__('Required field').'">*</abbr> ').__('Confirm password:').' '.
+($user_id != '' ? '' : '<abbr title="'.__('Required field').'">*</abbr> ').__('Confirm password:').'</label> '.
 form::password('new_pwd_c',20,255).
-'</label></p>'.
-
-'<p><label for="user_name">'.__('Last Name:').' '.
-form::field('user_name',20,255,html::escapeHTML($user_name)).
-'</label></p>'.
-
-'<p><label for="user_firstname">'.__('First Name:').' '.
-form::field('user_firstname',20,255,html::escapeHTML($user_firstname)).
-'</label></p>'.
-
-'<p><label for="user_displayname">'.__('Display name:').' '.
-form::field('user_displayname',20,255,html::escapeHTML($user_displayname)).
-'</label></p>'.
-
-'<p><label for="user_email">'.__('Email:').' '.
-form::field('user_email',20,255,html::escapeHTML($user_email)).
-'</label></p>'.
-'<p class="form-note">'.__('Mandatory for password recovering procedure.').'</p>'.
-'</div>'.
-
-'<div class="col">'.
-'<p><label for="user_url">'.__('URL:').' '.
-form::field('user_url',30,255,html::escapeHTML($user_url)).
-'</label></p>'.
-'<p><label for="user_post_format">'.__('Preferred format:').' '.
-form::combo('user_post_format',$formaters_combo,$user_options['post_format']).
-'</label></p>'.
-
-'<p><label for="user_post_status">'.__('Default entry status:').' '.
-form::combo('user_post_status',$status_combo,$user_post_status).
-'</label></p>'.
-
-'<p><label for="user_edit_size">'.__('Entry edit field height:').' '.
-form::field('user_edit_size',5,4,(integer) $user_options['edit_size']).
-'</label></p>'.
-
-'<p><label for="user_lang">'.__('User language:').' '.
-form::combo('user_lang',$lang_combo,$user_lang,'l10n').
-'</label></p>'.
-
-'<p><label for="user_tz">'.__('User timezone:').' '.
-form::combo('user_tz',dt::getZones(true,true),$user_tz).
-'</label></p>';
+'</p>';
 
 if ($core->auth->allowPassChange()) {
@@ -285,19 +251,66 @@
 
 $super_disabled = $user_super && $user_id == $core->auth->userID();
-
 echo
 '<p><label for="user_super" class="classic">'.form::checkbox('user_super','1',$user_super,'','',$super_disabled).' '.
 __('Super administrator').'</label></p>'.
+
+'<p><label for="user_name">'.__('Last Name:').'</label> '.
+form::field('user_name',20,255,html::escapeHTML($user_name)).
+'</p>'.
+
+'<p><label for="user_firstname">'.__('First Name:').'</label> '.
+form::field('user_firstname',20,255,html::escapeHTML($user_firstname)).
+'</p>'.
+
+'<p><label for="user_displayname">'.__('Display name:').'</label> '.
+form::field('user_displayname',20,255,html::escapeHTML($user_displayname)).
+'</p>'.
+
+'<p><label for="user_email">'.__('Email:').'</label> '.
+form::field('user_email',20,255,html::escapeHTML($user_email)).
+'</p>'.
+'<p class="form-note">'.__('Mandatory for password recovering procedure.').'</p>'.
+
+'<p><label for="user_url">'.__('URL:').'</label> '.
+form::field('user_url',30,255,html::escapeHTML($user_url)).
+'</p>'.
 '</div>'.
-'</div>'.
-'</fieldset>';
+
+'<div class="col">'.
+'<h3>'.__('Options').'</h3>'.
+'<h4>'.__('Interface').'</h4>'.
+'<p><label for="user_lang">'.__('Language:').'</label> '.
+form::combo('user_lang',$lang_combo,$user_lang,'l10n').
+'</p>'.
+
+'<p><label for="user_tz">'.__('Timezone:').'</label> '.
+form::combo('user_tz',dt::getZones(true,true),$user_tz).
+'</p>'.
+
+'<h4>'.__('Edition').'</h4>'.
+'<p><label for="user_post_format">'.__('Preferred format:').'</label> '.
+form::combo('user_post_format',$formaters_combo,$user_options['post_format']).
+'</p>'.
+
+'<p><label for="user_post_status">'.__('Default entry status:').'</label> '.
+form::combo('user_post_status',$status_combo,$user_post_status).
+'</p>'.
+
+'<p><label for="user_edit_size">'.__('Entry edit field height:').'</label> '.
+form::field('user_edit_size',5,4,(integer) $user_options['edit_size']).
+'</p>';
 
 # --BEHAVIOR-- adminUserForm
 $core->callBehavior('adminUserForm',isset($rs) ? $rs : null);
 
+echo 
+'</div>'.
+'</div>';
+
+
 echo
-'<p><label for="your_pwd" '.($user_id != '' ? '' : 'class="required"').'>'.
-($user_id != '' ? '' : '<abbr title="'.__('Required field').'">*</abbr> ').__('Your password:').
-form::password('your_pwd',20,255).'</label></p>'.
+'<p class="clear vertical-separator"><label for="your_pwd" class="required">'.
+'<abbr title="'.__('Required field').'">*</abbr> '.__('Your password:').'</label>'.
+form::password('your_pwd',20,255).'</p>'.
 '<p class="clear"><input type="submit" name="save" accesskey="s" value="'.__('Save').'" />'.
 ($user_id != '' ? '' : ' <input type="submit" name="saveplus" value="'.__('Save and create another').'" />').
@@ -310,51 +323,61 @@
 if ($user_id)
 {
-	echo '<div class="clear fieldset"><h3>'.__('Permissions').'</h3>'.
-	'<form action="users_actions.php" method="post">'.
-	'<p><input type="submit" value="'.__('Add new permissions').'" />'.
-	form::hidden(array('redir'),'user.php?id='.$user_id).
-	form::hidden(array('action'),'blogs').
-	form::hidden(array('users[]'),$user_id).
-	$core->formNonce().
-	'</p>'.
-	'</form>';
-	
-	$permissions = $core->getUserPermissions($user_id);
-	$perm_types = $core->auth->getPermissionsTypes();
-	
-	if (count($permissions) == 0)
+	echo '<div class="clear fieldset">'.
+	'<h3>'.__('Permissions').'</h3>';
+
+	if (!$user_super)
 	{
-		echo '<p>'.__('No permissions.').'</p>';
-	}
-	else
-	{
-		foreach ($permissions as $k => $v)
+		echo
+		'<form action="users_actions.php" method="post">'.
+		'<p><input type="submit" value="'.__('Add new permissions').'" />'.
+		form::hidden(array('redir'),'user.php?id='.$user_id).
+		form::hidden(array('action'),'blogs').
+		form::hidden(array('users[]'),$user_id).
+		$core->formNonce().
+		'</p>'.
+		'</form>';
+		
+		$permissions = $core->getUserPermissions($user_id);
+		$perm_types = $core->auth->getPermissionsTypes();
+		
+		if (count($permissions) == 0)
 		{
-			if (count($v['p']) > 0)
+			echo '<p>'.__('No permissions so far.').'</p>';
+		}
+		else
+		{
+			foreach ($permissions as $k => $v)
 			{
-				echo 
-				'<form action="users_actions.php" method="post">'.
-				'<h4><a href="blog.php?id='.html::escapeHTML($k).'">'.
-				html::escapeHTML($v['name']).'</a> ('.html::escapeHTML($k).')</h4>';
-				
-				echo '<ul>';
-				foreach ($v['p'] as $p => $V) {
-					if (isset($perm_types[$p])) {
-						echo '<li>'.__($perm_types[$p]).'</li>';
+				if (count($v['p']) > 0)
+				{
+					echo 
+					'<form action="users_actions.php" method="post">'.
+					'<p class="blog-perm">'.__('Blog:').' <a href="blog.php?id='.html::escapeHTML($k).'">'.
+					html::escapeHTML($v['name']).'</a> ('.html::escapeHTML($k).')</p>';
+					
+					echo '<ul class="ul-perm">';
+					foreach ($v['p'] as $p => $V) {
+						if (isset($perm_types[$p])) {
+							echo '<li>'.__($perm_types[$p]).'</li>';
+						}
 					}
+					echo
+					'</ul>'.
+					'<p class="add-perm"><input type="submit" class="reset" value="'.__('Change permissions').'" />'.
+					form::hidden(array('redir'),'user.php?id='.$user_id).
+					form::hidden(array('action'),'perms').
+					form::hidden(array('users[]'),$user_id).
+					form::hidden(array('blogs[]'),$k).
+					$core->formNonce().
+					'</p>'.
+					'</form>';
 				}
-				echo '</ul>'.
-				'<p><input type="submit" value="'.__('Change permissions').'" />'.
-				form::hidden(array('redir'),'user.php?id='.$user_id).
-				form::hidden(array('action'),'perms').
-				form::hidden(array('users[]'),$user_id).
-				form::hidden(array('blogs[]'),$k).
-				$core->formNonce().
-				'</p>'.
-				'</form>';
-			}
-		}
-	}
-	
+			}
+		}	
+
+	} 
+	else {
+		echo '<p>'.sprintf(__('%s is super admin (all rights on all blogs).'),'<strong>'.$user_id.'</strong>').'</p>';
+	}	
 	echo '</div>';
 }
Index: admin/users.php
===================================================================
--- admin/users.php	(revision 1237)
+++ admin/users.php	(revision 1609)
@@ -39,5 +39,5 @@
 
 
-# Get users
+#?Get users
 $page = !empty($_GET['page']) ? $_GET['page'] : 1;
 $nb_per_page =  30;
@@ -94,5 +94,11 @@
 }
 
-dcPage::open(__('Users'),$starting_script);
+dcPage::open(__('Users'),$starting_script,
+	dcPage::breadcrumb(
+		array(
+			__('System') => '',
+			'<span class="page-title">'.__('Users').'</span>' => ''
+		))
+);
 
 if (!$core->error->flag())
@@ -105,36 +111,35 @@
 	}
 	
-	echo 
-	'<h2 class="page-title">'.__('Users').'</h2>'.
-	'<p class="top-add"><strong><a class="button add" href="user.php">'.__('Create a new user').'</a></strong></p>';
+	echo
+	'<p class="top-add"><strong><a class="button add" href="user.php">'.__('New user').'</a></strong></p>';
 	
 	if (!$show_filters) {
-		echo '<p><a id="filter-control" class="form-control" href="#">'.__('Filters').'</a></p>';
+		echo '<p><a id="filter-control" class="form-control" href="#">'.__('Filter users list').'</a></p>';
 	}
 	
 	echo
 	'<form action="users.php" method="get" id="filters-form">'.
-	'<fieldset class="two-cols"><legend>'.__('Filters').'</legend>'.
+	'<h3 class="hidden">'.__('Filter users list').'</h3>'.
 	
-	'<div class="col">'.
-	'<p><label for="sortby">'.__('Order by:').' '.
-	form::combo('sortby',$sortby_combo,$sortby).
-	'</label> '.
-	'<label for="order">'.__('Sort:').' '.
-	form::combo('order',$order_combo,$order).
-	'</label></p>'.
+	'<div class="table">'.
+	'<div class="cell">'.
+	'<h4>'.__('Filters').'</h4>'.
+	'<p><label for="q" class="ib">'.__('Search:').'</label> '.
+	form::field('q',20,255,html::escapeHTML($q)).'</p>'.
 	'</div>'.
-	
-	'<div class="col">'.
-	'<p><label for="q">'.__('Search:').' '.
-	form::field('q',20,255,html::escapeHTML($q)).
-	'</label></p>'.
-	'<p><label for="nb" class="classic">'.	form::field('nb',3,3,$nb_per_page).' '.
-	__('Users per page').'</label> '.
-	'<input type="submit" value="'.__('Apply filters').'" /></p>'.
+
+	'<div class="cell filters-options">'.
+	'<h4>'.__('Display options').'</h4>'.
+	'<p><label for="sortby" class="ib">'.__('Order by:').'</label> '.
+	form::combo('sortby',$sortby_combo,$sortby).'</p> '.
+	'<p><label for="order" class="ib">'.__('Sort:').'</label> '.
+	form::combo('order',$order_combo,$order).'</p>'.
+	'<p><span class="label ib">'.__('Show').'</span> <label for="nb" class="classic">'.	
+	form::field('nb',3,3,$nb_per_page).' '.__('users per page').'</label></p> '.
 	'</div>'.
-	
-	'<br class="clear" />'. //Opera sucks
-	'</fieldset>'.
+	'</div>'.
+
+	'<p><input type="submit" value="'.__('Apply filters and display options').'" />'.	
+	'<br class="clear" /></p>'. //Opera sucks
 	'</form>';
 	
Index: admin/users_actions.php
===================================================================
--- admin/users_actions.php	(revision 1555)
+++ admin/users_actions.php	(revision 1620)
@@ -131,9 +131,26 @@
 /* DISPLAY
 -------------------------------------------------------- */
+if (!empty($users) && empty($blogs) && $action == 'blogs') {
+	$breadcrumb = dcPage::breadcrumb(
+		array(
+			__('System') => '',
+			__('Users') => 'users.php',
+			'<span class="page-title">'.__('Permissions').'</span>' => ''
+		));
+} else {
+	$breadcrumb = dcPage::breadcrumb(
+		array(
+			__('System') => '',
+			__('Users') => 'users.php',
+			'<span class="page-title">'.__('Actions').'</span>' => ''
+		));
+}
+
 dcPage::open(
 	__('Users'),
 	dcPage::jsLoad('js/_users_actions.js').
 	# --BEHAVIOR-- adminUsersActionsHeaders
-	$core->callBehavior('adminUsersActionsHeaders')
+	$core->callBehavior('adminUsersActionsHeaders'),
+	$breadcrumb
 );
 
@@ -162,4 +179,6 @@
 }
 
+echo '<p><a class="back" href="'.html::escapeURL($redir).'">'.__('Back to user profile').'</a></p>';
+
 # --BEHAVIOR-- adminUsersActionsContent
 $core->callBehavior('adminUsersActionsContent',$core,$action,$hidden_fields);
@@ -177,6 +196,5 @@
 	}
 	
-	echo 
-	'<h2><a href="users.php">'.__('Users').'</a> &rsaquo; <span class="page-title">'.__('Permissions').'</span></h2>'.
+	echo
 	'<p>'.sprintf(
 		__('Choose one or more blogs to which you want to give permissions to users %s.'),
@@ -239,5 +257,4 @@
 	
 	echo 
-	'<h2><a href="users.php">'.__('Users').'</a> &rsaquo; <span class="page-title">'.__('Permissions').'</span></h2>'.
 	'<p>'.sprintf(
 		__('You are about to change permissions on the following blogs for users %s.'),
@@ -248,5 +265,5 @@
 	foreach ($blogs as $b)
 	{
-		echo '<h3><a href="blog.php?id='.html::escapeHTML($b).'">'.html::escapeHTML($b).'</a>'.
+		echo '<h3>'.('Blog:').' <a href="blog.php?id='.html::escapeHTML($b).'">'.html::escapeHTML($b).'</a>'.
 		form::hidden(array('blogs[]'),$b).'</h3>';
 		
@@ -268,16 +285,15 @@
 	
 	echo
-	'<fieldset><legend>'.__('Validate permissions').'</legend>'.
-	'<p><label for="your_pwd" class="required"><abbr title="'.__('Required field').'">*</abbr> '.__('Your password:').
-	form::password('your_pwd',20,255).'</label></p>'.
-	'</fieldset>'.
+	'<div class="fieldset">'.
+	'<h3>'.__('Validate permissions').'</h3>'.
+	'<p><label for="your_pwd">'.__('Your password:').'</label>'.
+	form::password('your_pwd',20,255).'</p>'.
 	'<p><input type="submit" accesskey="s" value="'.__('Save').'" />'.
 	$hidden_fields.
 	form::hidden(array('action'),'updateperm').
 	$core->formNonce().'</p>'.
+	'</div>'.
 	'</form>';
 }
-
-echo '<p><a class="back" href="'.html::escapeURL($redir).'">'.__('back').'</a></p>';
 
 dcPage::close();
Index: inc/admin/lib.dc.page.php
===================================================================
--- inc/admin/lib.dc.page.php	(revision 1462)
+++ inc/admin/lib.dc.page.php	(revision 1655)
@@ -49,5 +49,5 @@
 
 	# Top of admin page
-	public static function open($title='', $head='')
+	public static function open($title='',$head='',$breadcrumb='')
 	{
 		global $core;
@@ -73,9 +73,9 @@
 			}
 			$blog_box =
-			'<p><label for="switchblog" class="classic">'.
-			__('Blogs:').' '.
+			'<p><label for="switchblog" class="classic nomobile">'.
+			__('Blogs:').'</label> '.
 			$core->formNonce().
 			form::combo('switchblog',$blogs,$core->blog->id).
-			'</label></p>'.
+			'</p>'.
 			'<noscript><p><input type="submit" value="'.__('ok').'" /></p></noscript>';
 		}
@@ -93,14 +93,15 @@
 		"<head>\n".
 		'  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />'."\n".
-		'  <title>'.$title.' - '.html::escapeHTML($core->blog->name).' - '.html::escapeHTML(DC_VENDOR_NAME).' - '.DC_VERSION.'</title>'."\n".
-
 		'  <meta name="ROBOTS" content="NOARCHIVE,NOINDEX,NOFOLLOW" />'."\n".
 		'  <meta name="GOOGLEBOT" content="NOSNIPPET" />'."\n".
+		'  <meta name="viewport" content="width=device-width, initial-scale=1.0" />'."\n".
+		'  <title>'.$title.' - '.html::escapeHTML($core->blog->name).' - '.html::escapeHTML(DC_VENDOR_NAME).' - '.DC_VERSION.'</title>'."\n".
+
 
 		self::jsLoadIE7().
-		'  	<link rel="stylesheet" href="style/default.css" type="text/css" media="screen" />'."\n";
+		'  <link rel="stylesheet" href="style/default.css" type="text/css" media="screen" />'."\n";
 		if (l10n::getTextDirection($GLOBALS['_lang']) == 'rtl') {
 			echo
-			'  	<link rel="stylesheet" href="style/default-rtl.css" type="text/css" media="screen" />'."\n";
+			'  <link rel="stylesheet" href="style/default-rtl.css" type="text/css" media="screen" />'."\n";
 		}
 
@@ -121,9 +122,12 @@
 		"</head>\n".
 		'<body id="dotclear-admin'.
-		($safe_mode ? ' safe-mode' : '').
-		'">'."\n".
+		($safe_mode ? ' safe-mode' : '').'" class="no-js">'."\n".
 
 		'<div id="header">'.
-		'<ul id="prelude"><li><a href="#content">'.__('Go to the content').'</a></li><li><a href="#main-menu">'.__('Go to the menu').'</a></li></ul>'."\n".
+		'<ul id="prelude">'.
+		'<li><a href="#content">'.__('Go to the content').'</a></li>'.
+		'<li><a href="#main-menu">'.__('Go to the menu').'</a></li>'.
+		'<li><a href="#qx">'.__('Go to search').'</a></li>'.
+		'</ul>'."\n".
 		'<div id="top"><h1><a href="index.php">'.DC_VENDOR_NAME.'</a></h1></div>'."\n";
 
@@ -133,11 +137,11 @@
 		'<form action="index.php" method="post">'.
 		$blog_box.
-		'<p><a href="'.$core->blog->url.'" onclick="window.open(this.href);return false;" title="'.__('Go to site').' ('.__('new window').')'.'">'.__('Go to site').' <img src="images/outgoing.png" alt="" /></a>'.
+		'<p class="nomobile"><a href="'.$core->blog->url.'" onclick="window.open(this.href);return false;" title="'.__('Go to site').' ('.__('new window').')'.'">'.__('Go to site').'<img src="images/outgoing.png" alt="" /></a>'.
 		'</p></form>'.
 		'</div>'.
 		'<div id="info-box2">'.
-		'<a'.(preg_match('/index.php$/',$_SERVER['REQUEST_URI']) ? ' class="active"' : '').' href="index.php">'.__('My dashboard').'</a>'.
-		'<span> | </span><a'.(preg_match('/preferences.php(\?.*)?$/',$_SERVER['REQUEST_URI']) ? ' class="active"' : '').' href="preferences.php">'.__('My preferences').'</a>'.
-		'<span> | </span><a href="index.php?logout=1" class="logout">'.sprintf(__('Logout %s'),$core->auth->userID()).' <img src="images/logout.png" alt="" /></a>'.
+		'<a class="smallscreen'.(preg_match('/index.php$/',$_SERVER['REQUEST_URI']) ? ' active' : '').'" href="index.php">'.__('My dashboard').'</a>'.
+		'<span class="smallscreen"> | </span><a class="smallscreen'.(preg_match('/preferences.php(\?.*)?$/',$_SERVER['REQUEST_URI']) ? ' active' : '').'" href="preferences.php">'.__('My preferences').'</a>'.
+		'<span class="smallscreen"> | </span><a href="index.php?logout=1" class="logout">'.sprintf(__('Logout %s'),$core->auth->userID()).'<img src="images/logout.png" alt="" /></a>'.
 		'</div>'.
 		'</div>'.
@@ -158,4 +162,7 @@
 		}
 
+		// Display breadcrumb (if given) before any error message
+		echo $breadcrumb;
+
 		if ($core->error->flag()) {
 			echo
@@ -176,5 +183,10 @@
 		"</div>\n".		// End of #main
 
-		'<div id="main-menu">'."\n";
+		'<div id="main-menu">'."\n".
+
+		'<form id="search-menu" action="search.php" method="get">'.
+		'<p><label for="qx" class="hidden">'.__('Search:').' </label>'.form::field('qx',30,255,'').
+		'<input type="submit" value="'.__('OK').'" /></p>'.
+		'</form>';
 
 		foreach ($menu as $k => $v) {
@@ -193,5 +205,13 @@
 		echo
 		'</div>'."\n".		// End of #main-menu
-		'<div id="footer"><a href="http://dotclear.org/" title="'.$text.'"><img src="style/dc_logo_footer.png" alt="'.$text.'" /></a></div>'."\n".
+		'<div id="footer"><a href="http://dotclear.org/" title="'.$text.'"><img src="style/dc_logos/w-dotclear90.png" alt="'.$text.'" /></a></div>'."\n".
+		'<!-- '."\n".
+'                  .'."\n".
+'               ,;:\'`\'::'."\n".
+'            __||'."\n".
+'      _____/LLLL\_'."\n".
+'      \__________"|'."\n".
+'    ~^~^~^~^~^~^~^~^~^~'."\n".
+' -->'."\n".
 		"</div>\n";		// End of #wrapper
 
@@ -204,5 +224,5 @@
 	}
 
-	public static function openPopup($title='', $head='')
+	public static function openPopup($title='',$head='',$breadcrumb='')
 	{
 		global $core;
@@ -216,4 +236,5 @@
 		'xml:lang="'.$core->auth->getInfo('user_lang').'" '.
 		'lang="'.$core->auth->getInfo('user_lang').'">'."\n".
+		'<meta name="viewport" content="width=device-width, initial-scale=1.0" />'."\n".
 		"<head>\n".
 		'  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />'."\n".
@@ -241,5 +262,5 @@
 		'<body id="dotclear-admin" class="popup">'."\n".
 
-		'<div id="top"><h1>'.DC_VENDOR_NAME.'</h1></div>'."\n";
+		'<div id="top hidden"><h1>'.DC_VENDOR_NAME.'</h1></div>'."\n";
 
 		echo
@@ -247,4 +268,7 @@
 		'<div id="main">'."\n".
 		'<div id="content">'."\n";
+
+		// display breadcrumb if given
+		echo $breadcrumb;
 
 		if ($core->error->flag()) {
@@ -266,5 +290,24 @@
 	}
 
-	public static function message($msg,$timestamp=true,$div=false,$echo=true)
+	public static function breadcrumb($elements=null,$with_home_link=true,$echo=false)
+	{
+		// First item of array elements should be blog's name, System or Plugins
+		$res = '<h2>'.($with_home_link ?
+			'<a class="go_home" href="index.php"><img src="style/dashboard.png" alt="'.__('Go to dashboard').'" /></a>' :
+			'<img src="style/dashboard-alt.png" alt="" />');
+		$index = 0;
+		foreach ($elements as $element => $url) {
+			$res .= ($with_home_link ? ($index == 1 ? ' : ' : ' &rsaquo; ') : ($index == 0 ? ' ' : ' &rsaquo; ')).
+				($url ? '<a href="'.$url.'">' : '').$element.($url ? '</a>' : '');
+			$index++;
+		}
+		$res .= '</h2>';
+		if ($echo) {
+			echo $res;
+		}
+		return $res;
+	}
+
+	public static function message($msg,$timestamp=true,$div=false,$echo=true,$class='message')
 	{
 		global $core;
@@ -272,5 +315,5 @@
 		$res = '';
 		if ($msg != '') {
-			$res = ($div ? '<div class="message">' : '').'<p'.($div ? '' : ' class="message"').'>'.
+			$res = ($div ? '<div class="'.$class.'">' : '').'<p'.($div ? '' : ' class="'.$class.'"').'>'.
 			($timestamp ? dt::str(__('%H:%M:%S:'),null,$core->auth->getInfo('user_tz')).' ' : '').$msg.
 			'</p>'.($div ? '</div>' : '');
@@ -280,4 +323,9 @@
 		}
 		return $res;
+	}
+
+	public static function success($msg,$timestamp=true,$div=false,$echo=true)
+	{
+		self::message($msg,$timestamp,$div,$echo,"success");
 	}
 
@@ -333,4 +381,10 @@
 	{
 		$args = func_get_args();
+
+		$args = new ArrayObject($args);
+
+		# --BEHAVIOR-- adminPageHelpBlock
+		$GLOBALS['core']->callBehavior('adminPageHelpBlock',$args);
+
 		if (empty($args)) {
 			return;
@@ -371,5 +425,5 @@
 
 		echo
-		'<div id="help"><hr /><div class="help-content clear"><h2>'.__('Help').'</h2>'.
+		'<div id="help"><hr /><div class="help-content clear"><h3>'.__('Help about this page').'</h3>'.
 		$content.
 		'</div></div>';
@@ -411,5 +465,9 @@
 
 		self::jsVar('dotclear.msg.help',
-			__('help')).
+			__('Help about this page')).
+		self::jsVar('dotclear.msg.help_hide',
+			__('Hide')).
+		self::jsVar('dotclear.msg.to_select',
+			__('Select:')).
 		self::jsVar('dotclear.msg.no_selection',
 			__('no selection')).
@@ -417,5 +475,5 @@
 			__('select all')).
 		self::jsVar('dotclear.msg.invert_sel',
-			__('invert selection')).
+			__('Invert selection')).
 		self::jsVar('dotclear.msg.website',
 			__('Web site:')).
@@ -434,6 +492,10 @@
 		self::jsVar('dotclear.msg.confirm_delete_posts',
 			__("Are you sure you want to delete selected entries (%s)?")).
+		self::jsVar('dotclear.msg.confirm_delete_categories',
+			__("Are you sure you want to delete selected categories (%s)?")).
 		self::jsVar('dotclear.msg.confirm_delete_post',
 			__("Are you sure you want to delete this entry?")).
+		self::jsVar('dotclear.msg.click_to_unlock',
+			__("Click here to unlock the field")).
 		self::jsVar('dotclear.msg.confirm_spam_delete',
 			__('Are you sure you want to delete all spams?')).
@@ -489,6 +551,6 @@
 	{
 		return
-		'<!--[if lt IE 8]>'."\n".
-		self::jsLoad('js/ie7/IE8.js').
+		'<!--[if lt IE 9]>'."\n".
+		self::jsLoad('js/ie7/IE9.js').
 		'<link rel="stylesheet" type="text/css" href="style/iesucks.css" />'."\n".
 		'<![endif]-->'."\n";
@@ -692,57 +754,4 @@
 	'<link rel="stylesheet" type="text/css" href="style/jsUpload/style.css" />'."\n".
 
-	'<script id="template-upload" type="text/x-tmpl">
-	{% for (var i=0, file; file=o.files[i]; i++) { %}
-	<div class="template-upload fade">
-	<div class="upload-file">
-	<div class="upload-fileinfo">
-		<span class="upload-filename">{%=file.name%}</span>
-		<span class="upload-filesize">({%=o.formatFileSize(file.size)%})</span>
-		<span class="upload-filecancel cancel">'.__('Cancel').'</span>
-		{% if (!o.files.error && !i && !o.options.autoUpload) { %}
-		<input type="submit" class="button start"  value="'.__('Send').'"/>
-		{% } %}
-		<span class="upload-filemsg"></span>
-	</div>
-	{% if (!o.files.error) { %}
-	<div class="upload-progress progress progress-success progress-striped active"><div class="bar" style="width:0%;"></div></div>
-	{% } %}
-	</div>
-	{% } %}
-	</script>
-	<!-- The template to display files available for download -->
-	<script id="template-download" type="text/x-tmpl">
-	{% for (var i=0, file; file=o.files[i]; i++) { %}
-	<div class="template-download fade">
-	<div class="upload-file">
-	<div class="upload-fileinfo">
-		<span class="upload-filename">{%=file.name%}</span>
-		<span class="upload-filesize">({%=o.formatFileSize(file.size)%})</span>
-		<span class="upload-filemsg{% if (file.error) { %} upload-error{% } %}">
-		{% if (file.error) { %}
-		'.__('Error:').' {%=file.error%}
-		{% } else { %}
-		'.__('File successfully uploaded.').'
-		{% } %}
-		</span>
-	</div>
-	<div class="upload-progress">
-		{% if (!file.error) { %}
-		<div class="bar" style="width:100%;">100%</div>
-		{% } %}
-	</div>
-	</div>
-	{% } %}
-	</script>'.
-
-	self::jsLoad('js/jsUpload/vendor/jquery.ui.widget.js').
-	self::jsLoad('js/jsUpload/tmpl.js').
-	self::jsLoad('js/jsUpload/load-image.js').
-	self::jsLoad('js/jsUpload/jquery.iframe-transport.js').
-	self::jsLoad('js/jsUpload/jquery.fileupload.js').
-	self::jsLoad('js/jsUpload/jquery.fileupload-process.js').
-	self::jsLoad('js/jsUpload/jquery.fileupload-resize.js').
-	self::jsLoad('js/jsUpload/jquery.fileupload-ui.js').
-
 	'<script type="text/javascript">'."\n".
 	"//<![CDATA[\n".
@@ -761,4 +770,6 @@
 	self::jsVar('dotclear.jsUpload.msg.clean',__('Clean')).
 	self::jsVar('dotclear.jsUpload.msg.upload',__('Upload')).
+	self::jsVar('dotclear.jsUpload.msg.send',__('Send')).
+	self::jsVar('dotclear.jsUpload.msg.file_successfully_uploaded',__('File successfully uploaded.')).
 	self::jsVar('dotclear.jsUpload.msg.no_file_in_queue',__('No file in queue.')).
 	self::jsVar('dotclear.jsUpload.msg.file_in_queue',__('1 file in queue.')).
@@ -767,17 +778,16 @@
 	self::jsVar('dotclear.jsUpload.base_url',$base_url).
 	"\n//]]>\n".
-	"</script>\n";
-}
-
-public static function jsToolMan()
-{
-	return
-	'<script type="text/javascript" src="js/tool-man/core.js"></script>'.
-	'<script type="text/javascript" src="js/tool-man/events.js"></script>'.
-	'<script type="text/javascript" src="js/tool-man/css.js"></script>'.
-	'<script type="text/javascript" src="js/tool-man/coordinates.js"></script>'.
-	'<script type="text/javascript" src="js/tool-man/drag.js"></script>'.
-	'<script type="text/javascript" src="js/tool-man/dragsort.js"></script>'.
-	'<script type="text/javascript" src="js/dragsort-tablerows.js"></script>';
+	"</script>\n".
+
+	self::jsLoad('js/jsUpload/vendor/jquery.ui.widget.js').
+	self::jsLoad('js/jsUpload/tmpl.js').
+	self::jsLoad('js/jsUpload/template-upload.js').
+	self::jsLoad('js/jsUpload/template-download.js').
+	self::jsLoad('js/jsUpload/load-image.js').
+	self::jsLoad('js/jsUpload/jquery.iframe-transport.js').
+	self::jsLoad('js/jsUpload/jquery.fileupload.js').
+	self::jsLoad('js/jsUpload/jquery.fileupload-process.js').
+	self::jsLoad('js/jsUpload/jquery.fileupload-resize.js').
+	self::jsLoad('js/jsUpload/jquery.fileupload-ui.js');
 }
 
Index: inc/admin/lib.pager.php
===================================================================
--- inc/admin/lib.pager.php	(revision 1364)
+++ inc/admin/lib.pager.php	(revision 1670)
@@ -23,6 +23,6 @@
 		$this->rs =& $rs;
 		$this->rs_count = $rs_count;
-		$this->html_prev = __('&#171;prev.');
-		$this->html_next = __('next&#187;');
+		$this->html_prev = __('&#171; prev.');
+		$this->html_next = __('next &#187;');
 	}
 }
@@ -42,14 +42,19 @@
 			$pager->html_next = $this->html_next;
 			$pager->var_page = 'page';
-			
+			$entries = array();
+			if (isset($_REQUEST['entries'])) {
+				foreach ($_REQUEST['entries'] as $v) {
+					$entries[(integer)$v]=true;
+				}
+			}
 			$html_block =
-			'<table class="clear"><tr>'.
-			'<th colspan="2">'.__('Title').'</th>'.
-			'<th>'.__('Date').'</th>'.
-			'<th>'.__('Category').'</th>'.
-			'<th>'.__('Author').'</th>'.
-			'<th>'.__('Comments').'</th>'.
-			'<th>'.__('Trackbacks').'</th>'.
-			'<th>'.__('Status').'</th>'.
+			'<table class="clear"><caption class="hidden">'.__('Entries list').'</caption><tr>'.
+			'<th colspan="2" class="first">'.__('Title').'</th>'.
+			'<th scope="col">'.__('Date').'</th>'.
+			'<th scope="col">'.__('Category').'</th>'.
+			'<th scope="col">'.__('Author').'</th>'.
+			'<th scope="col">'.__('Comments').'</th>'.
+			'<th scope="col">'.__('Trackbacks').'</th>'.
+			'<th scope="col">'.__('Status').'</th>'.
 			'</tr>%s</table>';
 			
@@ -58,5 +63,5 @@
 			}
 			
-			echo '<p>'.__('Page(s)').' : '.$pager->getLinks().'</p>';
+			echo '<p class="pagination">'.__('Page(s)').' : '.$pager->getLinks().'</p>';
 			
 			$blocks = explode('%s',$html_block);
@@ -66,14 +71,14 @@
 			while ($this->rs->fetch())
 			{
-				echo $this->postLine();
+				echo $this->postLine(isset($entries[$this->rs->post_id]));
 			}
 			
 			echo $blocks[1];
 			
-			echo '<p>'.__('Page(s)').' : '.$pager->getLinks().'</p>';
+			echo '<p class="pagination">'.__('Page(s)').' : '.$pager->getLinks().'</p>';
 		}
 	}
 	
-	private function postLine()
+	private function postLine($checked)
 	{
 		if ($this->core->auth->check('categories',$this->core->blog->id)) {
@@ -93,14 +98,14 @@
 		switch ($this->rs->post_status) {
 			case 1:
-				$img_status = sprintf($img,__('published'),'check-on.png');
+				$img_status = sprintf($img,__('Published'),'check-on.png');
 				break;
 			case 0:
-				$img_status = sprintf($img,__('unpublished'),'check-off.png');
+				$img_status = sprintf($img,__('Unpublished'),'check-off.png');
 				break;
 			case -1:
-				$img_status = sprintf($img,__('scheduled'),'scheduled.png');
+				$img_status = sprintf($img,__('Scheduled'),'scheduled.png');
 				break;
 			case -2:
-				$img_status = sprintf($img,__('pending'),'check-wrn.png');
+				$img_status = sprintf($img,__('Pending'),'check-wrn.png');
 				break;
 		}
@@ -108,10 +113,10 @@
 		$protected = '';
 		if ($this->rs->post_password) {
-			$protected = sprintf($img,__('protected'),'locker.png');
+			$protected = sprintf($img,__('Protected'),'locker.png');
 		}
 		
 		$selected = '';
 		if ($this->rs->post_selected) {
-			$selected = sprintf($img,__('selected'),'selected.png');
+			$selected = sprintf($img,__('Selected'),'selected.png');
 		}
 		
@@ -128,12 +133,12 @@
 		$res .=
 		'<td class="nowrap">'.
-		form::checkbox(array('entries[]'),$this->rs->post_id,'','','',!$this->rs->isEditable()).'</td>'.
-		'<td class="maximal"><a href="'.$this->core->getPostAdminURL($this->rs->post_type,$this->rs->post_id).'">'.
+		form::checkbox(array('entries[]'),$this->rs->post_id,$checked,'','',!$this->rs->isEditable()).'</td>'.
+		'<td class="maximal" scope="row"><a href="'.$this->core->getPostAdminURL($this->rs->post_type,$this->rs->post_id).'">'.
 		html::escapeHTML($this->rs->post_title).'</a></td>'.
-		'<td class="nowrap">'.dt::dt2str(__('%Y-%m-%d %H:%M'),$this->rs->post_dt).'</td>'.
+		'<td class="nowrap count">'.dt::dt2str(__('%Y-%m-%d %H:%M'),$this->rs->post_dt).'</td>'.
 		'<td class="nowrap">'.$cat_title.'</td>'.
 		'<td class="nowrap">'.html::escapeHTML($this->rs->user_id).'</td>'.
-		'<td class="nowrap">'.$this->rs->nb_comment.'</td>'.
-		'<td class="nowrap">'.$this->rs->nb_trackback.'</td>'.
+		'<td class="nowrap count">'.$this->rs->nb_comment.'</td>'.
+		'<td class="nowrap count">'.$this->rs->nb_trackback.'</td>'.
 		'<td class="nowrap status">'.$img_status.' '.$selected.' '.$protected.' '.$attach.'</td>'.
 		'</tr>';
@@ -159,9 +164,9 @@
 			
 			$html_block =
-			'<table class="clear"><tr>'.
-			'<th>'.__('Title').'</th>'.
-			'<th>'.__('Date').'</th>'.
-			'<th>'.__('Author').'</th>'.
-			'<th>'.__('Status').'</th>'.
+			'<table class="clear"><caption class="hidden">'.__('Entries list').'</caption><tr>'.
+			'<th scope="col">'.__('Title').'</th>'.
+			'<th scope="col">'.__('Date').'</th>'.
+			'<th scope="col">'.__('Author').'</th>'.
+			'<th scope="col">'.__('Status').'</th>'.
 			'</tr>%s</table>';
 			
@@ -170,5 +175,5 @@
 			}
 			
-			echo '<p>'.__('Page(s)').' : '.$pager->getLinks().'</p>';
+			echo '<p class="pagination">'.__('Page(s)').' : '.$pager->getLinks().'</p>';
 			
 			$blocks = explode('%s',$html_block);
@@ -183,5 +188,5 @@
 			echo $blocks[1];
 			
-			echo '<p>'.__('Page(s)').' : '.$pager->getLinks().'</p>';
+			echo '<p class="pagination">'.__('Page(s)').' : '.$pager->getLinks().'</p>';
 		}
 	}
@@ -192,14 +197,14 @@
 		switch ($this->rs->post_status) {
 			case 1:
-				$img_status = sprintf($img,__('published'),'check-on.png');
+				$img_status = sprintf($img,__('Published'),'check-on.png');
 				break;
 			case 0:
-				$img_status = sprintf($img,__('unpublished'),'check-off.png');
+				$img_status = sprintf($img,__('Unpublished'),'check-off.png');
 				break;
 			case -1:
-				$img_status = sprintf($img,__('scheduled'),'scheduled.png');
+				$img_status = sprintf($img,__('Scheduled'),'scheduled.png');
 				break;
 			case -2:
-				$img_status = sprintf($img,__('pending'),'check-wrn.png');
+				$img_status = sprintf($img,__('Pending'),'check-wrn.png');
 				break;
 		}
@@ -207,10 +212,10 @@
 		$protected = '';
 		if ($this->rs->post_password) {
-			$protected = sprintf($img,__('protected'),'locker.png');
+			$protected = sprintf($img,__('Protected'),'locker.png');
 		}
 		
 		$selected = '';
 		if ($this->rs->post_selected) {
-			$selected = sprintf($img,__('selected'),'selected.png');
+			$selected = sprintf($img,__('Selected'),'selected.png');
 		}
 		
@@ -226,8 +231,8 @@
 		
 		$res .=
-		'<td class="maximal"><a href="'.$this->core->getPostAdminURL($this->rs->post_type,$this->rs->post_id).'" '.
+		'<td scope="row" class="maximal"><a href="'.$this->core->getPostAdminURL($this->rs->post_type,$this->rs->post_id).'" '.
 		'title="'.html::escapeHTML($this->rs->getURL()).'">'.
 		html::escapeHTML($this->rs->post_title).'</a></td>'.
-		'<td class="nowrap">'.dt::dt2str(__('%Y-%m-%d %H:%M'),$this->rs->post_dt).'</td>'.
+		'<td class="nowrap count">'.dt::dt2str(__('%Y-%m-%d %H:%M'),$this->rs->post_dt).'</td>'.
 		'<td class="nowrap">'.html::escapeHTML($this->rs->user_id).'</td>'.
 		'<td class="nowrap status">'.$img_status.' '.$selected.' '.$protected.' '.$attach.'</td>'.
@@ -254,18 +259,17 @@
 			
 			$html_block =
-			'<table><tr>'.
-			'<th colspan="2">'.__('Title').'</th>'.
-			'<th>'.__('Date').'</th>'.
-			'<th>'.__('Author').'</th>'.
-			'<th>'.__('Type').'</th>'.
-			'<th>'.__('Status').'</th>'.
-			'<th>&nbsp;</th>'.
+			'<table><caption class="hidden">'.__('Comments and trackbacks list').'</caption><tr>'.
+			'<th colspan="2" scope="col" abbr="comm" class="first">'.__('Type').'</th>'.
+			'<th scope="col">'.__('Author').'</th>'.
+			'<th scope="col">'.__('Date').'</th>'.
+			'<th scope="col" class="txt-center">'.__('Status').'</th>'.
+			'<th scope="col" abbr="entry">'.__('Entry title').'</th>'.
 			'</tr>%s</table>';
-			
+
 			if ($enclose_block) {
 				$html_block = sprintf($enclose_block,$html_block);
 			}
 			
-			echo '<p>'.__('Page(s)').' : '.$pager->getLinks().'</p>';
+			echo '<p class="pagination">'.__('Page(s)').' : '.$pager->getLinks().'</p>';
 			
 			$blocks = explode('%s',$html_block);
@@ -280,5 +284,5 @@
 			echo $blocks[1];
 			
-			echo '<p>'.__('Page(s)').' : '.$pager->getLinks().'</p>';
+			echo '<p class="pagination">'.__('Page(s)').' : '.$pager->getLinks().'</p>';
 		}
 	}
@@ -306,21 +310,24 @@
 		switch ($this->rs->comment_status) {
 			case 1:
-				$img_status = sprintf($img,__('published'),'check-on.png');
+				$img_status = sprintf($img,__('Published'),'check-on.png');
 				break;
 			case 0:
-				$img_status = sprintf($img,__('unpublished'),'check-off.png');
+				$img_status = sprintf($img,__('Unpublished'),'check-off.png');
 				break;
 			case -1:
-				$img_status = sprintf($img,__('pending'),'check-wrn.png');
+				$img_status = sprintf($img,__('Pending'),'check-wrn.png');
 				break;
 			case -2:
-				$img_status = sprintf($img,__('junk'),'junk.png');
-				break;
-		}
-		
-		$comment_author = html::escapeHTML($this->rs->comment_author);
-		if (mb_strlen($comment_author) > 20) {
-			$comment_author = mb_strcut($comment_author,0,17).'...';
-		}
+				$img_status = sprintf($img,__('Junk'),'junk.png');
+				break;
+		}
+		
+		$post_title = html::escapeHTML($this->rs->post_title);
+		if (mb_strlen($post_title) > 60) {
+			$post_title = mb_strcut($post_title,0,57).'...';
+		}
+		$comment_title = sprintf(__('Edit the %1$s from %2$s'),
+			$this->rs->comment_trackback ? __('trackback') : __('comment'),
+			html::escapeHTML($this->rs->comment_author));
 		
 		$res = '<tr class="line'.($this->rs->comment_status != 1 ? ' offline' : '').'"'.
@@ -330,13 +337,14 @@
 		'<td class="nowrap">'.
 		form::checkbox(array('comments[]'),$this->rs->comment_id,'','','',0).'</td>'.
-		'<td class="maximal"><a href="'.$post_url.'">'.
-		html::escapeHTML($this->rs->post_title).'</a>'.
-		($this->rs->post_type != 'post' ? ' ('.html::escapeHTML($this->rs->post_type).')' : '').'</td>'.
-		'<td class="nowrap">'.dt::dt2str(__('%Y-%m-%d %H:%M'),$this->rs->comment_dt).'</td>'.
-		'<td class="nowrap"><a href="'.$author_url.'">'.html::escapeHTML($comment_author).'</a></td>'.
-		'<td class="nowrap">'.($this->rs->comment_trackback ? __('trackback') : __('comment')).'</td>'.
-		'<td class="nowrap status">'.$img_status.'</td>'.
-		'<td class="nowrap status"><a href="'.$comment_url.'">'.
-		'<img src="images/edit-mini.png" alt="" title="'.__('Edit this comment').'" /></a></td>';
+		'<td class="nowrap" abbr="'.__('Type and author').'" scope="raw">'.
+			'<a href="'.$comment_url.'" title="'.$comment_title.'">'.
+			'<img src="images/edit-mini.png" alt="'.__('Edit').'"/> '.
+			($this->rs->comment_trackback ? __('trackback') : __('comment')).' '.'</a></td>'.
+		'<td class="nowrap maximal"><a href="'.$author_url.'">'.html::escapeHTML($this->rs->comment_author).'</a></td>'.
+		'<td class="nowrap count">'.dt::dt2str(__('%Y-%m-%d %H:%M'),$this->rs->comment_dt).'</td>'.
+		'<td class="nowrap status txt-center">'.$img_status.'</td>'.
+		'<td class="nowrap"><a href="'.$post_url.'">'.
+		html::escapeHTML($post_title).'</a>'.
+		($this->rs->post_type != 'post' ? ' ('.html::escapeHTML($this->rs->post_type).')' : '').'</td>';
 		
 		$res .= '</tr>';
@@ -362,10 +370,10 @@
 			
 			$html_block =
-			'<table class="clear"><tr>'.
-			'<th colspan="2">'.__('Username').'</th>'.
-			'<th>'.__('First Name').'</th>'.
-			'<th>'.__('Last Name').'</th>'.
-			'<th>'.__('Display name').'</th>'.
-			'<th class="nowrap">'.__('Entries').'</th>'.
+			'<table class="clear"><caption class="hidden">'.__('Users list').'</caption><tr>'.
+			'<th colspan="2" scope="col" class="first">'.__('Username').'</th>'.
+			'<th scope="col">'.__('First Name').'</th>'.
+			'<th scope="col">'.__('Last Name').'</th>'.
+			'<th scope="col">'.__('Display name').'</th>'.
+			'<th scope="col" class="nowrap">'.__('Entries (all types)').'</th>'.
 			'</tr>%s</table>';
 			
@@ -374,5 +382,5 @@
 			}
 			
-			echo '<p>'.__('Page(s)').' : '.$pager->getLinks().'</p>';
+			echo '<p class="pagination">'.__('Page(s)').' : '.$pager->getLinks().'</p>';
 			
 			$blocks = explode('%s',$html_block);
@@ -387,5 +395,5 @@
 			echo $blocks[1];
 			
-			echo '<p>'.__('Page(s)').' : '.$pager->getLinks().'</p>';
+			echo '<p class="pagination">'.__('Page(s)').' : '.$pager->getLinks().'</p>';
 		}
 	}
@@ -408,10 +416,10 @@
 		'<td class="nowrap">'.form::hidden(array('nb_post[]'),(integer) $this->rs->nb_post).
 		form::checkbox(array('users[]'),$this->rs->user_id).'</td>'.
-		'<td class="maximal"><a href="user.php?id='.$this->rs->user_id.'">'.
+		'<td class="maximal" scope="row"><a href="user.php?id='.$this->rs->user_id.'">'.
 		$this->rs->user_id.'</a>&nbsp;'.$img_status.'</td>'.
 		'<td class="nowrap">'.html::escapeHTML($this->rs->user_firstname).'</td>'.
 		'<td class="nowrap">'.html::escapeHTML($this->rs->user_name).'</td>'.
 		'<td class="nowrap">'.html::escapeHTML($this->rs->user_displayname).'</td>'.
-		'<td class="nowrap"><a href="posts.php?user_id='.$this->rs->user_id.'">'.
+		'<td class="nowrap count"><a href="posts.php?user_id='.$this->rs->user_id.'">'.
 		$this->rs->nb_post.'</a></td>'.
 		'</tr>';
Index: inc/admin/prepend.php
===================================================================
--- inc/admin/prepend.php	(revision 1592)
+++ inc/admin/prepend.php	(revision 1620)
@@ -261,5 +261,5 @@
 		'images/menu/users.png','images/menu/users-b.png',
 		null,null,null));
-	$_fav['plugins'] = new ArrayObject(array('plugins','Plugins','plugins.php',
+	$_fav['plugins'] = new ArrayObject(array('plugins','Plugins management','plugins.php',
 		'images/menu/plugins.png','images/menu/plugins-b.png',
 		null,null,null));
@@ -284,5 +284,5 @@
 	# Set menu titles
 	
-	$_menu['System']->title = __('System');
+	$_menu['System']->title = __('System settings');
 	$_menu['Blog']->title = __('Blog');
 	$_menu['Plugins']->title = __('Plugins');
@@ -328,5 +328,5 @@
 		preg_match('/langs.php(\?.*)?$/',$_SERVER['REQUEST_URI']),
 		$core->auth->isSuperAdmin());
-	$_menu['System']->prependItem(__('Plugins'),'plugins.php','images/menu/plugins.png',
+	$_menu['System']->prependItem(__('Plugins management'),'plugins.php','images/menu/plugins.png',
 		preg_match('/plugins.php(\?.*)?$/',$_SERVER['REQUEST_URI']),
 		$core->auth->isSuperAdmin());
Index: inc/core/class.dc.blog.php
===================================================================
--- inc/core/class.dc.blog.php	(revision 1570)
+++ inc/core/class.dc.blog.php	(revision 1620)
@@ -81,5 +81,5 @@
 			$this->desc = $b->blog_desc;
 			$this->url = $b->blog_url;
-			$this->host = preg_replace('|^([a-z]{3,}://)(.*?)/.*$|','$1$2',$this->url);
+			$this->host = http::getHostFromURL($this->url);
 			$this->creadt = strtotime($b->blog_creadt);
 			$this->upddt = strtotime($b->blog_upddt);
@@ -91,13 +91,13 @@
 			$this->public_path = path::fullFromRoot($this->settings->system->public_path,DC_ROOT);
 			
-			$this->post_status['-2'] = __('pending');
-			$this->post_status['-1'] = __('scheduled');
-			$this->post_status['0'] = __('unpublished');
-			$this->post_status['1'] = __('published');
-			
-			$this->comment_status['-2'] = __('junk');
-			$this->comment_status['-1'] = __('pending');
-			$this->comment_status['0'] = __('unpublished');
-			$this->comment_status['1'] = __('published');
+			$this->post_status['-2'] = __('Pending');
+			$this->post_status['-1'] = __('Scheduled');
+			$this->post_status['0'] = __('Unpublished');
+			$this->post_status['1'] = __('Published');
+			
+			$this->comment_status['-2'] = __('Junk');
+			$this->comment_status['-1'] = __('Pending');
+			$this->comment_status['0'] = __('Unpublished');
+			$this->comment_status['1'] = __('Published');
 			
 			# --BEHAVIOR-- coreBlogConstruct
@@ -300,5 +300,9 @@
 		$counter = $this->getCategoriesCounter($c_params);
 		
-		$without_empty = $this->core->auth->userID() == false; # For public display
+		if (isset($params['without_empty']) && ($params['without_empty'] == false)) {
+			$without_empty = false;
+		} else {
+			$without_empty = $this->core->auth->userID() == false; # Get all categories if in admin display
+		}
 		
 		$start = isset($params['start']) ? (integer) $params['start'] : 0;
@@ -550,4 +554,17 @@
 		$this->triggerBlog();
 	}
+
+        /**
+        Set category position
+
+        @param  id              <b>integer</b>          Category ID
+        @param  left            <b>integer</b>          Category ID before
+        @param  right           <b>integer</b>          Category ID after
+        */
+        public function updCategoryPosition($id,$left,$right)
+        {
+                $this->categories()->updatePosition($id,$left,$right);
+                $this->triggerBlog();
+        }
 	
 	/**
Index: inc/core/class.dc.categories.php
===================================================================
--- inc/core/class.dc.categories.php	(revision 1179)
+++ inc/core/class.dc.categories.php	(revision 1532)
@@ -188,4 +188,22 @@
 	}
 	
+        public function updatePosition($id,$left,$right)
+        {
+                $sql = 'UPDATE '.$this->table.' SET '
+                        .$this->f_left.' = '.$left.', '
+                        .$this->f_right.' = '.$right
+                        .' WHERE '.$this->f_id .' = '.(integer) $id
+                        .$this->getCondition();
+
+                $this->con->begin();
+                try {
+                        $this->con->execute($sql);
+                        $this->con->commit();
+                } catch (Exception $e) {
+                        $this->con->rollback();
+                        throw $e;
+                }
+        }
+
 	public function deleteNode($node,$keep_children=true)
 	{
Index: inc/core/class.dc.media.php
===================================================================
--- inc/core/class.dc.media.php	(revision 1677)
+++ inc/core/class.dc.media.php	(revision 1468)
@@ -299,7 +299,5 @@
 			$f->media_thumb = array();
 			$p = path::info($f->relname);
-
 			$alpha = ($p['extension'] == 'png') || ($p['extension'] == 'PNG');
-
 			$thumb = sprintf(($alpha ? $this->thumb_tp_alpha : $this->thumb_tp),$this->root.'/'.$p['dirname'],$p['base'],'%s');
 			$thumb_url = sprintf(($alpha ? $this->thumb_tp_alpha : $this->thumb_tp),$this->root_url.$p['dirname'],$p['base'],'%s');
@@ -308,18 +306,8 @@
 			$thumb_url = preg_replace('#\./#','/',$thumb_url);
 			$thumb_url = preg_replace('#(?<!:)/+#','/',$thumb_url);
-
-			if ($alpha) {
-				$thumb_alt = sprintf($this->thumb_tp,$this->root.'/'.$p['dirname'],$p['base'],'%s');
-				$thumb_url_alt = sprintf($this->thumb_tp,$this->root_url.$p['dirname'],$p['base'],'%s');
-				# Cleaner URLs
-				$thumb_url_alt = preg_replace('#\./#','/',$thumb_url_alt);
-				$thumb_url_alt = preg_replace('#(?<!:)/+#','/',$thumb_url_alt);
-			}
 			
 			foreach ($this->thumb_sizes as $suffix => $s) {
 				if (file_exists(sprintf($thumb,$suffix))) {
 					$f->media_thumb[$suffix] = sprintf($thumb_url,$suffix);
-				} elseif ($alpha && file_exists(sprintf($thumb_alt,$suffix))) {
-					$f->media_thumb[$suffix] = sprintf($thumb_url_alt,$suffix);
 				}
 			}
@@ -511,8 +499,7 @@
 	@param	post_id	<b>integer</b>		Post ID
 	@param	media_id	<b>integer</b>		Optionnal media ID
-	@param	return_rs	<b>boolean</b>		Whether to return a resultset (true) or an array (false, default value).
-	@return	<b>array</b> Array or ResultSet of fileItems
-	*/
-	public function getPostMedia($post_id,$media_id=null,$return_rs=false)
+	@return	<b>array</b> Array of fileItems
+	*/
+	public function getPostMedia($post_id,$media_id=null)
 	{
 		$params = array(
@@ -530,9 +517,9 @@
 			$f = $this->fileRecord($rs);
 			if ($f !== null) {
-				$res[] = $return_rs ? new ArrayObject($f) : $f;
-			}
-		}
-		
-		return $return_rs ? staticRecord::newFromArray($res) : $res;
+				$res[] = $f;
+			}
+		}
+		
+		return $res;
 	}
 	
Index: inc/core/class.dc.postmedia.php
===================================================================
--- inc/core/class.dc.postmedia.php	(revision 1179)
+++ inc/core/class.dc.postmedia.php	(revision 1505)
Index: inc/core/class.dc.trackback.php
===================================================================
--- inc/core/class.dc.trackback.php	(revision 1179)
+++ inc/core/class.dc.trackback.php	(revision 1674)
@@ -80,36 +80,56 @@
 		}
 		
-		$data = array(
-			'title' => $post_title,
-			'excerpt' => $post_excerpt,
-			'url' => $post_url,
-			'blog_name' => trim(html::escapeHTML(html::clean($this->core->blog->name)))
-			//,'__debug' => false
-		);
-		
-		# Ping
-		try
-		{
-			$http = self::initHttp($url,$path);
-			$http->post($path,$data,'UTF-8');
-			$res = $http->getContent();
-		}
-		catch (Exception $e)
-		{
-			throw new Exception(__('Unable to ping URL'));
-		}
-		
-		$pattern =
-		'|<response>.*<error>(.*)</error>(.*)'.
-		'(<message>(.*)</message>(.*))?'.
-		'</response>|msU';
-		
-		if (!preg_match($pattern,$res,$match))
-		{
-			throw new Exception(sprintf(__('%s is not a ping URL'),$url));
-		}
-		
-		$ping_error = trim($match[1]);
-		$ping_msg = (!empty($match[4])) ? $match[4] : '';
+		$ping_parts = explode('|',$url);
+		
+		# Let's walk by the trackback way
+		if (count($ping_parts) < 2) {
+			$data = array(
+				'title' => $post_title,
+				'excerpt' => $post_excerpt,
+				'url' => $post_url,
+				'blog_name' => trim(html::escapeHTML(html::clean($this->core->blog->name)))
+				//,'__debug' => false
+			);
+			
+			# Ping
+			try
+			{
+				$http = self::initHttp($url,$path);
+				$http->post($path,$data,'UTF-8');
+				$res = $http->getContent();
+			}
+			catch (Exception $e)
+			{
+				throw new Exception(__('Unable to ping URL'));
+			}
+			
+			$pattern =
+			'|<response>.*<error>(.*)</error>(.*)'.
+			'(<message>(.*)</message>(.*))?'.
+			'</response>|msU';
+			
+			if (!preg_match($pattern,$res,$match))
+			{
+				throw new Exception(sprintf(__('%s is not a ping URL'),$url));
+			}
+			
+			$ping_error = trim($match[1]);
+			$ping_msg = (!empty($match[4])) ? $match[4] : '';
+		}
+		# Damnit ! Let's play pingback
+		else {
+			try {
+				$xmlrpc = new xmlrpcClient($ping_parts[0]);
+				$res = $xmlrpc->query('pingback.ping', $post_url, $ping_parts[1]);
+				$ping_error = '0';
+			}
+			catch (xmlrpcException $e) {
+				$ping_error = $e->getCode();
+				$ping_msg = $e->getMessage();	
+			}
+			catch (Exception $e) {
+				throw new Exception(__('Unable to ping URL'));
+			}
+		}
 		
 		if ($ping_error != '0') {
@@ -289,4 +309,147 @@
 	}
 	//@}
+
+	/// @name Receive pingbacks
+	//@{
+	/**
+	Receives a pingback and insert it as a comment of given post.
+	
+	@param	from_url		<b>string</b>		Source URL
+	@param	to_url			<b>string</b>		Target URL
+	*/
+	public function receive_pb($from_url, $to_url)
+	{
+		$reg = '!^'.preg_quote($this->core->blog->url).'(.*)!';
+		$type = $args = $next = '';
+		
+		# Are you dumb?
+		if (!preg_match($reg, $to_url, $m)) {
+			throw new Exception(__('Any chance you ping one of my contents? No? Really?'), 0);
+		}
+		
+		# Does the targeted URL look like a registered post type? 
+		$url_part = $m[1];
+		$p_type = '';
+		$post_types = $this->core->getPostTypes();
+		foreach ($post_types as $k => $v) {
+			$reg = '!^'.preg_quote(str_replace('%s', '', $v['public_url'])).'(.*)!';
+			if (preg_match($reg, $url_part, $n)) {
+				$p_type = $k;
+				$post_url = $n[1];
+				break;
+			}
+		}
+		
+		if (empty($p_type)) {
+			throw new Exception(__('Sorry but you can not ping this type of content.'), 33);
+		}
+
+		# Time to see if we've got a winner...
+		$params = array(
+			'post_type' => $p_type,
+			'post_url' => $post_url,
+		);
+		$posts = $this->core->blog->getPosts($params);
+		
+		# Missed! 
+		if ($posts->isEmpty()) {
+			throw new Exception(__('Oops. Kinda "not found" stuff. Please check the target URL twice.'), 33);
+		}
+		
+		# Nice try. But, sorry, no.
+		if (!$posts->trackbacksActive()) {
+			throw new Exception(__('Sorry, dude. This entry does not accept pingback at the moment.'), 33);
+		}
+
+		# OK. We've found our champion. Time to check the remote part.
+		try {
+			$http = self::initHttp($from_url, $from_path);
+			
+			# First round : just to be sure the ping comes from an acceptable resource type.
+			$http->setHeadersOnly(true);
+			$http->get($from_path);
+			$c_type = explode(';', $http->getHeader('content-type'));
+
+			# Bad luck. Bye, bye...
+			if (!in_array($c_type[0],array('text/html', 'application/xhtml+xml'))) {
+				throw new Exception(__('Your source URL does not look like a supported content type. Sorry. Bye, bye!'), 0);
+			}
+			
+			# Second round : let's go fetch and parse the remote content
+			$http->setHeadersOnly(false);
+			$http->get($from_path);
+			$remote_content = $http->getContent();
+
+			$charset = mb_detect_encoding($remote_content,
+				'UTF-8,ISO-8859-1,ISO-8859-2,ISO-8859-3,'.
+				'ISO-8859-4,ISO-8859-5,ISO-8859-6,ISO-8859-7,ISO-8859-8,'.
+				'ISO-8859-9,ISO-8859-10,ISO-8859-13,ISO-8859-14,ISO-8859-15');
+
+			if (strtolower($charset) != 'utf-8') {
+				$remote_content = iconv($charset,'UTF-8',$remote_content);
+			}
+			
+			# We want a title...
+			if (!preg_match('!<title>([^<].*?)</title>!mis', $remote_content, $m)) {
+				throw new Exception(__('Where\'s your title?'), 0);
+			}
+			$title = trim(html::clean($m[1]));
+			$title = html::decodeEntities($title);
+			$title = html::escapeHTML($title);
+			$title = text::cutString($title,60);
+			
+			preg_match('!<body[^>]*?>(.*)?</body>!msi', $remote_content, $m);
+			$source = $m[1];
+			$source = preg_replace('![\r\n\s]+!ms',' ',$source);
+			$source = preg_replace( "/<\/*(h\d|p|th|td|li|dt|dd|pre|caption|input|textarea|button)[^>]*>/", "\n\n", $source );
+			$source = strip_tags($source, '<a>');
+			$source = explode("\n\n",$source);
+			
+			$excerpt = '';
+			foreach ($source as $line) {
+				if (strpos($line, $to_url) !== false) {
+					if (preg_match("!<a[^>]+?".$to_url."[^>]*>([^>]+?)</a>!", $line, $m)) {
+						$excerpt = strip_tags($line);
+						break;
+					}
+				}
+			}
+			if ($excerpt) {
+				$excerpt = '(&#8230;) '.text::cutString(html::escapeHTML($excerpt),255).' (&#8230;)';
+			}
+			else {
+				$excerpt = '(??)';
+			}
+
+			$comment =
+			"<!-- TB -->\n".
+			'<p><strong>'.$title."</strong></p>\n".
+			'<p>'.$excerpt.'</p>';
+			
+			$cur = $this->core->con->openCursor($this->core->prefix.'comment');
+			$cur->comment_author = 'Anonymous blog';
+			$cur->comment_site = (string) $from_url;
+			$cur->comment_content = (string) $comment;
+			$cur->post_id = $posts->post_id;
+			$cur->comment_trackback = 1;
+			$cur->comment_status = $this->core->blog->settings->system->trackbacks_pub ? 1 : -1;
+			$cur->comment_ip = http::realIP();
+			
+			# --BEHAVIOR-- publicBeforeTrackbackCreate
+			$this->core->callBehavior('publicBeforeTrackbackCreate',$cur);
+			if ($cur->post_id) {
+				$comment_id = $this->core->blog->addComment($cur);
+				
+				# --BEHAVIOR-- publicAfterTrackbackCreate
+				$this->core->callBehavior('publicAfterTrackbackCreate',$cur,$comment_id);
+			}
+		}
+		catch (Exception $e) {
+			throw new Exception(__('Sorry, an internal problem has occured.'), 0);
+		}
+		
+		return __('Thanks, mate. It was a pleasure.');
+	}
+	//@}
 	
 	private static function initHttp($url,&$path)
@@ -346,5 +509,5 @@
 			for ($i = 0; $i<count($match); $i++)
 			{
-				if (preg_match('/href="(http:\/\/[^"]+)"/ms', $match[$i][1], $matches)) {
+				if (preg_match('/href="((https?:\/)?\/[^"]+)"/ms', $match[$i][1], $matches)) {
 					$res[$matches[1]] = 1;
 				}
@@ -358,5 +521,5 @@
 			for ($i = 0; $i<count($match); $i++)
 			{
-				if (preg_match('/cite="(http:\/\/[^"]+)"/ms', $match[$i][2], $matches)) {
+				if (preg_match('/cite="((https?:\/)?\/[^"]+)"/ms', $match[$i][2], $matches)) {
 					$res[$matches[1]] = 1;
 				}
@@ -369,4 +532,8 @@
 	private function getPingURL($url)
 	{
+		if (strpos($url,'/') === 0) {
+			$url = http::getHost().$url;
+		}
+		
 		try
 		{
@@ -374,4 +541,5 @@
 			$http->get($path);
 			$page_content = $http->getContent();
+			$pb_url = $http->getHeader('x-pingback');
 		}
 		catch (Exception $e)
@@ -380,4 +548,20 @@
 		}
 		
+		# If we've got a X-Pingback header and it's a valid URL, it will be enough
+		if ($pb_url && filter_var($pb_url,FILTER_VALIDATE_URL) && preg_match('!^https?:!',$pb_url)) {
+			return $pb_url.'|'.$url;
+		}
+		
+		# No X-Pingback header. A link rel=pingback, maybe ?
+		$pattern_pingback = '!<link rel="pingback" href="(.*?)"( /)?>!msi';
+		
+		if (preg_match($pattern_pingback,$page_content,$m)) {
+			$pb_url = $m[1];
+			if (filter_var($pb_url,FILTER_VALIDATE_URL) && preg_match('!^https?:!',$pb_url)) {
+				return $pb_url.'|'.$url;
+			}
+		}
+
+		# No pingback ? OK, let's check for a trackback data chunk...
 		$pattern_rdf =
 		'/<rdf:RDF.*?>.*?'.
@@ -388,9 +572,12 @@
 		preg_match_all($pattern_rdf,$page_content,$rdf_all,PREG_SET_ORDER);
 		
+		$url_path = parse_url($url, PHP_URL_PATH);
+		$sanitized_url = str_replace($url_path, html::sanitizeURL($url_path), $url);
+		
 		for ($i=0; $i<count($rdf_all); $i++)
 		{
 			$rdf = $rdf_all[$i][1];
-			
-			if (preg_match('/dc:identifier="'.preg_quote($url,'/').'"/msi',$rdf)) {
+			if (preg_match('/dc:identifier="'.preg_quote($url,'/').'"/msi',$rdf) ||
+				preg_match('/dc:identifier="'.preg_quote($sanitized_url,'/').'"/msi',$rdf)) {
 				if (preg_match('/trackback:ping="(.*?)"/msi',$rdf,$tb_link)) {
 					return $tb_link[1];
Index: inc/core/class.dc.update.php
===================================================================
--- inc/core/class.dc.update.php	(revision 1231)
+++ inc/core/class.dc.update.php	(revision 1280)
@@ -32,5 +32,4 @@
 	
 	protected $cache_ttl = '-6 hours';
-	protected $nocache_ttl = '-2 mins';
 	protected $forced_files = array();
 	
@@ -56,10 +55,9 @@
 	 * 
 	 * @param version		string	Current version to compare
-	 * @param nocache		boolean	Force checking
 	 * @return string				Latest version if available
 	 */
-	public function check($version, $nocache=false)
-	{
-		$this->getVersionInfo($nocache);
+	public function check($version)
+	{
+		$this->getVersionInfo();
 		$v = $this->getVersion();
 		if ($v && version_compare($version,$v,'<')) {
@@ -70,13 +68,8 @@
 	}
 	
-	public function getVersionInfo($nocache=false)
-	{
-		# Check minimum time without cache (prevents from server flood)
-		if ($nocache && is_readable($this->cache_file) && filemtime($this->cache_file) > strtotime($this->nocache_ttl)) {
-			$nocache = false;
-		}
-		
+	public function getVersionInfo()
+	{
 		# Check cached file
-		if (is_readable($this->cache_file) && filemtime($this->cache_file) > strtotime($this->cache_ttl) && !$nocache)
+		if (is_readable($this->cache_file) && filemtime($this->cache_file) > strtotime($this->cache_ttl))
 		{
 			$c = @file_get_contents($this->cache_file);
Index: inc/core/class.dc.xmlrpc.php
===================================================================
--- inc/core/class.dc.xmlrpc.php	(revision 1179)
+++ inc/core/class.dc.xmlrpc.php	(revision 1674)
@@ -214,4 +214,9 @@
 			array('array','integer','string','string'),
 			'Retrieve all of the comment statuses.');
+			
+		# Pingback support
+		$this->addCallback('pingback.ping',array($this,'pingback_ping'),
+			array('string', 'string', 'string'),
+			'Notify a link to a post.');
 	}
 	
@@ -270,5 +275,5 @@
 	}
 	
-	private function setBlog()
+	private function setBlog($bypass = false)
 	{
 		if (!$this->blog_id) {
@@ -288,6 +293,7 @@
 		}
 		
-		if (!$this->core->blog->settings->system->enable_xmlrpc ||
-		!$this->core->auth->check('usage,contentadmin',$this->core->blog->id)) {
+		if (!$bypass &&
+			(!$this->core->blog->settings->system->enable_xmlrpc ||
+			!$this->core->auth->check('usage,contentadmin',$this->core->blog->id))) {
 			$this->core->blog = null;
 			throw new Exception('Not enough permissions on this blog.');
@@ -1629,4 +1635,18 @@
 		);
 	}
+
+	/* Pingback support
+	--------------------------------------------------- */
+	public function pingback_ping($from_url, $to_url)
+	{
+		# Come on, buddy! Don't make me waste time with this kind of silliness...
+		if (!(filter_var($from_url, FILTER_VALIDATE_URL) && preg_match('!^https?://!',$from_url))) {
+			throw new Exception(__('No valid source URL provided? Try again!'), 0);
+		}
+		
+		$this->setBlog(true);
+		$tb = new dcTrackback($this->core);
+		return $tb->receive_pb($from_url, $to_url);
+	}
 }
 ?>
Index: inc/dbschema/upgrade.php
===================================================================
--- inc/dbschema/upgrade.php	(revision 1205)
+++ inc/dbschema/upgrade.php	(revision 1581)
@@ -336,8 +336,14 @@
 			}
 
-			if (version_compare($version, '2.5.1', '<='))
+			if (version_compare($version,'2.5.1','<='))
 			{
 				// Flash enhanced upload no longer needed
 				@unlink(DC_ROOT.'/'.'inc/swf/swfupload.swf');
+			}
+
+			if (version_compare($version,'2.6','<='))
+			{
+				// README has been replaced by README.md and CONTRIBUTING.md
+				@unlink(DC_ROOT.'/'.'README');
 			}
 			
Index: inc/load_plugin_file.php
===================================================================
--- inc/load_plugin_file.php	(revision 1241)
+++ inc/load_plugin_file.php	(revision 1280)
@@ -86,5 +86,5 @@
 }
 
-http::$cache_max_age = (!defined('DC_CACHE_MAX_AGE') ? 604800 : DC_CACHE_MAX_AGE);
+http::$cache_max_age = 7200;
 http::cache(array_merge(array($PF),get_included_files()));
 
Index: inc/prepend.php
===================================================================
--- inc/prepend.php	(revision 1352)
+++ inc/prepend.php	(revision 1468)
@@ -123,5 +123,5 @@
 # Constants
 define('DC_ROOT',path::real(dirname(__FILE__).'/..'));
-define('DC_VERSION','2.5.3-dev');
+define('DC_VERSION','2.6-dev');
 define('DC_DIGESTS',dirname(__FILE__).'/digests');
 define('DC_L10N_ROOT',dirname(__FILE__).'/../locales');
Index: inc/public/class.dc.template.php
===================================================================
--- inc/public/class.dc.template.php	(revision 1249)
+++ inc/public/class.dc.template.php	(revision 1674)
@@ -67,8 +67,8 @@
 		$this->addValue('BlogLanguage',array($this,'BlogLanguage'));
 		$this->addValue('BlogThemeURL',array($this,'BlogThemeURL'));
-		$this->addValue('BlogParentThemeURL',array($this,'BlogParentThemeURL'));
 		$this->addValue('BlogUpdateDate',array($this,'BlogUpdateDate'));
 		$this->addValue('BlogID',array($this,'BlogID'));
 		$this->addValue('BlogURL',array($this,'BlogURL'));
+		$this->addValue('BlogXMLRPCURL',array($this,'BlogXMLRPCURL'));
 		$this->addValue('BlogPublicURL',array($this,'BlogPublicURL'));
 		$this->addValue('BlogQmarkURL',array($this,'BlogQmarkURL'));
@@ -840,5 +840,5 @@
 	
 	/*dtd
-	<!ELEMENT tpl:BlogThemeURL - O -- Blog's current Theme URL -->
+	<!ELEMENT tpl:BlogThemeURL - O -- Blog's current Themei URL -->
 	*/
 	public function BlogThemeURL($attr)
@@ -846,14 +846,4 @@
 		$f = $this->getFilters($attr);
 		return '<?php echo '.sprintf($f,'$core->blog->settings->system->themes_url."/".$core->blog->settings->system->theme').'; ?>';
-	}
-	
-	/*dtd
-	<!ELEMENT tpl:BlogParentThemeURL - O -- Blog's current Theme's parent URL -->
-	*/
-	public function BlogParentThemeURL($attr)
-	{
-		$f = $this->getFilters($attr);
-		$parent = '$core->themes->moduleInfo($core->blog->settings->system->theme,\'parent\')';
-		return '<?php echo '.sprintf($f,'$core->blog->settings->system->themes_url."/".('."$parent".' ? '."$parent".' : $core->blog->settings->system->theme)').'; ?>';
 	}
     
@@ -917,4 +907,13 @@
 	
 	/*dtd
+	<!ELEMENT tpl:BlogXMLRPCURL - O -- Blog XML-RPC URL -->
+	*/
+	public function BlogXMLRPCURL($attr)
+	{
+		$f = $this->getFilters($attr);
+		return '<?php echo '.sprintf($f,'$core->blog->url.$core->url->getURLFor(\'xmlrpc\',$core->blog->id)').'; ?>';
+	}
+	
+	/*dtd
 	<!ELEMENT tpl:BlogURL - O -- Blog URL -->
 	*/
@@ -965,4 +964,8 @@
 		if (!empty($attr['level'])) {
 			$p .= "\$params['level'] = ".(integer) $attr['level'].";\n";
+		}
+
+		if (isset($attr['with_empty']) && ((boolean) $attr['with_empty'] == true)) {
+			$p .= '$params[\'without_empty\'] = false;';
 		}
 		
Index: inc/public/default-templates/post.html
===================================================================
--- inc/public/default-templates/post.html	(revision 932)
+++ inc/public/default-templates/post.html	(revision 1674)
@@ -25,4 +25,5 @@
   <link rel="top" href="{{tpl:BlogURL}}" title="{{tpl:lang Home}}" />
   <link rel="contents" href="{{tpl:BlogArchiveURL}}" title="{{tpl:lang Archives}}" />
+  <tpl:EntryIf pings_active="1"><link rel="pingback" href="{{tpl:BlogXMLRPCURL}}" /></tpl:EntryIf>
   
   <tpl:EntryNext><link rel="next" href="{{tpl:EntryURL}}"
Index: inc/public/lib.urlhandlers.php
===================================================================
--- inc/public/lib.urlhandlers.php	(revision 1179)
+++ inc/public/lib.urlhandlers.php	(revision 1674)
@@ -263,5 +263,6 @@
 			$params = new ArrayObject(array(
 				'cat_url' => $args,
-				'post_type' => 'post'));
+				'post_type' => 'post',
+				'without_empty' => false));
 			
 			$core->callBehavior('publicCategoryBeforeGetCategories',$params,$args);
@@ -479,4 +480,7 @@
 				
 				# The entry
+				if ($_ctx->posts->trackbacksActive()) {
+					header('X-Pingback: '.$core->blog->url.$core->url->getURLFor("xmlrpc",$core->blog->id));
+				}
 				self::serveDocument('post.html');
 			}
Index: locales/_pot/main.pot
===================================================================
--- locales/_pot/main.pot	(revision 1039)
+++ locales/_pot/main.pot	(revision 1425)
@@ -1091,5 +1091,5 @@
 
 #: admin/comments.php:214
-msgid "You have one spam comments."
+msgid "You have one spam comment."
 msgstr ""
 
Index: locales/_pot/plugins.pot
===================================================================
--- locales/_pot/plugins.pot	(revision 963)
+++ locales/_pot/plugins.pot	(revision 1354)
@@ -2311,5 +2311,5 @@
 
 #: plugins/widgets/index.php:250
-msgid "Once included in a sidebar, widgets have configuration options that you can reach by clicking on the + sign next to their name."
+msgid "Once included in a sidebar, widgets have configuration options that you can reach by clicking on the arrow next to their name."
 msgstr ""
 
Index: locales/bn/help/blowupConfig.html
===================================================================
--- locales/bn/help/blowupConfig.html	(revision 1264)
+++ locales/bn/help/blowupConfig.html	(revision 1280)
@@ -35,5 +35,5 @@
 <p>You can choose a header image among the list to use in place of the default one.</p>
 
-<p>When you choose "Custom..." in the image list, you will be able to upload your own image. <strong>The image file must be in JPG or PNG format and must be precisely 800px wide.</strong></p>
+<p>When you choose "Custom..." in the image list, you will be able to upload your own image. <strong>The image file must be in JPG or PNG format and must be precisely 800px wide.</strong>
 
 <p>If you upload a JPG image, a border will be added to the image, which is not the case with PNG images (the transparency of which will also be kept).</p>
Index: locales/bn/main.po
===================================================================
--- locales/bn/main.po	(revision 1592)
+++ locales/bn/main.po	(revision 1637)
@@ -215,5 +215,5 @@
 
 #, fuzzy
-msgid "That blog Id is already in use."
+msgid "This blog ID is already used."
 msgstr "Dotclear ইতিমধ্যেই ইন্সটল করা আছে।"
 
@@ -459,5 +459,5 @@
 
 #, php-format
-msgid "You are currently using \"%s\""
+msgid "You are currently using <strong>%s</strong>"
 msgstr "আপনি বর্তমানে ব্যবহার করছেন \"%s\""
 
@@ -586,5 +586,5 @@
 msgstr "ক্যাটাগরিটি সফলভাবে সরানো হয়েছে।"
 
-msgid "No category yet."
+msgid "No category so far."
 msgstr "কোনো ক্যাটাগরি নেই।"
 
@@ -759,5 +759,5 @@
 msgstr "মন্তব্যের লেখক:"
 
-msgid "You have one spam comments."
+msgid "You have one spam comment."
 msgstr "আপনার একটি স্প্যাম মন্তব্য আছে।"
 
@@ -1740,8 +1740,8 @@
 msgstr "এধরণের কোনো ইউজার নেই"
 
-msgid "Change category for entries"
-msgstr ""
-
-msgid "Change author for entries"
+msgid "Change category for this selection"
+msgstr ""
+
+msgid "Change author for this selection"
 msgstr ""
 
@@ -2122,5 +2122,5 @@
 msgstr "সব সিলেক্ট করুন"
 
-msgid "invert selection"
+msgid "Invert selection"
 msgstr ""
 
Index: locales/bn/plugins.po
===================================================================
--- locales/bn/plugins.po	(revision 1126)
+++ locales/bn/plugins.po	(revision 1668)
@@ -838,5 +838,5 @@
 
 #, php-format
-msgid "This will import a single blog backup as new content in the current blog: %s."
+msgid "This will import a single blog backup as new content in the current blog: <strong>%s</strong>."
 msgstr ""
 
@@ -1060,14 +1060,14 @@
 msgstr ""
 
-msgid "Page status:"
-msgstr ""
-
-msgid "Page position:"
-msgstr ""
-
-msgid "Page lang:"
-msgstr ""
-
-msgid "Page password:"
+msgid "Page status"
+msgstr ""
+
+msgid "Page position"
+msgstr ""
+
+msgid "Page lang"
+msgstr ""
+
+msgid "Page password"
 msgstr ""
 
@@ -1239,5 +1239,5 @@
 msgstr ""
 
-msgid "Currently no menu items"
+msgid "No menu items so far."
 msgstr ""
 
@@ -1540,5 +1540,5 @@
 msgstr ""
 
-msgid "Once included in a sidebar, widgets have configuration options that you can reach by clicking on the + sign next to their name."
+msgid "Once included in a sidebar, widgets have configuration options that you can reach by clicking on the arrow next to their name."
 msgstr ""
 
Index: locales/ca/help/blowupConfig.html
===================================================================
--- locales/ca/help/blowupConfig.html	(revision 1264)
+++ locales/ca/help/blowupConfig.html	(revision 1280)
@@ -35,5 +35,5 @@
 <p>You can choose a header image among the list to use in place of the default one.</p>
 
-<p>When you choose "Custom..." in the image list, you will be able to upload your own image. <strong>The image file must be in JPG or PNG format and must be precisely 800px wide.</strong></p>
+<p>When you choose "Custom..." in the image list, you will be able to upload your own image. <strong>The image file must be in JPG or PNG format and must be precisely 800px wide.</strong>
 
 <p>If you upload a JPG image, a border will be added to the image, which is not the case with PNG images (the transparency of which will also be kept).</p>
Index: locales/ca/main.po
===================================================================
--- locales/ca/main.po	(revision 1592)
+++ locales/ca/main.po	(revision 1637)
@@ -219,5 +219,5 @@
 
 #, fuzzy
-msgid "That blog Id is already in use."
+msgid "This blog ID is already used."
 msgstr "DotClear esta instal·lat."
 
@@ -468,5 +468,5 @@
 
 #, php-format
-msgid "You are currently using \"%s\""
+msgid "You are currently using <strong>%s</strong>"
 msgstr ""
 
@@ -601,5 +601,5 @@
 
 #, fuzzy
-msgid "No category yet."
+msgid "No category so far."
 msgstr "Cap categoria."
 
@@ -787,5 +787,5 @@
 msgstr "Autor del comentari:"
 
-msgid "You have one spam comments."
+msgid "You have one spam comment."
 msgstr "Te un comentari no desitjat."
 
@@ -1809,8 +1809,8 @@
 msgstr "Aquest usuari no existeix"
 
-msgid "Change category for entries"
+msgid "Change category for this selection"
 msgstr "Canviar la categoria per les entrades"
 
-msgid "Change author for entries"
+msgid "Change author for this selection"
 msgstr "Canviar l'autor per les entrades"
 
@@ -2200,5 +2200,5 @@
 msgstr "Seleccionar tot"
 
-msgid "invert selection"
+msgid "Invert selection"
 msgstr "invertir la selecció"
 
Index: locales/ca/plugins.po
===================================================================
--- locales/ca/plugins.po	(revision 1126)
+++ locales/ca/plugins.po	(revision 1668)
@@ -835,5 +835,5 @@
 
 #, php-format
-msgid "This will import a single blog backup as new content in the current blog: %s."
+msgid "This will import a single blog backup as new content in the current blog: <strong>%s</strong>."
 msgstr ""
 
@@ -1056,14 +1056,14 @@
 msgstr ""
 
-msgid "Page status:"
-msgstr ""
-
-msgid "Page position:"
-msgstr ""
-
-msgid "Page lang:"
-msgstr ""
-
-msgid "Page password:"
+msgid "Page status"
+msgstr ""
+
+msgid "Page position"
+msgstr ""
+
+msgid "Page lang"
+msgstr ""
+
+msgid "Page password"
 msgstr ""
 
@@ -1230,5 +1230,5 @@
 msgstr ""
 
-msgid "Currently no menu items"
+msgid "No menu items so far."
 msgstr ""
 
@@ -1529,5 +1529,5 @@
 msgstr ""
 
-msgid "Once included in a sidebar, widgets have configuration options that you can reach by clicking on the + sign next to their name."
+msgid "Once included in a sidebar, widgets have configuration options that you can reach by clicking on the arrow next to their name."
 msgstr ""
 
Index: locales/cs/help/blowupConfig.html
===================================================================
--- locales/cs/help/blowupConfig.html	(revision 1264)
+++ locales/cs/help/blowupConfig.html	(revision 1280)
@@ -35,5 +35,5 @@
 <p>You can choose a header image among the list to use in place of the default one.</p>
 
-<p>When you choose "Custom..." in the image list, you will be able to upload your own image. <strong>The image file must be in JPG or PNG format and must be precisely 800px wide.</strong></p>
+<p>When you choose "Custom..." in the image list, you will be able to upload your own image. <strong>The image file must be in JPG or PNG format and must be precisely 800px wide.</strong>
 
 <p>If you upload a JPG image, a border will be added to the image, which is not the case with PNG images (the transparency of which will also be kept).</p>
Index: locales/cs/main.po
===================================================================
--- locales/cs/main.po	(revision 1592)
+++ locales/cs/main.po	(revision 1637)
@@ -214,5 +214,5 @@
 msgstr "Zakázat vyhledavacím enginům indexovat nebo archivovat obsah blogu."
 
-msgid "That blog Id is already in use."
+msgid "This blog ID is already used."
 msgstr "Blog ID je už použito."
 
@@ -457,5 +457,5 @@
 
 #, php-format
-msgid "You are currently using \"%s\""
+msgid "You are currently using <strong>%s</strong>"
 msgstr "Používáte \"%s\" vzhled"
 
@@ -585,5 +585,5 @@
 msgstr "Kategorie byla úspěšně přesunuta."
 
-msgid "No category yet."
+msgid "No category so far."
 msgstr "Zatím žádná kategorie."
 
@@ -764,5 +764,5 @@
 msgstr "Autor komentáře:"
 
-msgid "You have one spam comments."
+msgid "You have one spam comment."
 msgstr "Máte jeden spam komentář."
 
@@ -1741,8 +1741,8 @@
 msgstr "Tento uživatel neexistuje"
 
-msgid "Change category for entries"
+msgid "Change category for this selection"
 msgstr "Změnit kategorii pro články"
 
-msgid "Change author for entries"
+msgid "Change author for this selection"
 msgstr "Změnit autora pro články"
 
@@ -2126,5 +2126,5 @@
 msgstr "vybrat vše"
 
-msgid "invert selection"
+msgid "Invert selection"
 msgstr "obrátit výběr"
 
Index: locales/cs/plugins.po
===================================================================
--- locales/cs/plugins.po	(revision 1126)
+++ locales/cs/plugins.po	(revision 1668)
@@ -843,5 +843,5 @@
 
 #, php-format
-msgid "This will import a single blog backup as new content in the current blog: %s."
+msgid "This will import a single blog backup as new content in the current blog: <strong>%s</strong>."
 msgstr "Tímto naimportujete zálohu jednoho blogu jako nový obsah tohoto blogu: %s."
 
@@ -1065,14 +1065,14 @@
 msgstr ""
 
-msgid "Page status:"
+msgid "Page status"
 msgstr "Stav stránky:"
 
-msgid "Page position:"
+msgid "Page position"
 msgstr "Pozice stránky:"
 
-msgid "Page lang:"
+msgid "Page lang"
 msgstr "Jazyk stránky:"
 
-msgid "Page password:"
+msgid "Page password"
 msgstr "Heslo stránky:"
 
@@ -1256,5 +1256,5 @@
 msgstr "Jste si jisti, že chcete smazat vybrané odkazy?"
 
-msgid "Currently no menu items"
+msgid "No menu items so far."
 msgstr ""
 
@@ -1565,5 +1565,5 @@
 msgstr ""
 
-msgid "Once included in a sidebar, widgets have configuration options that you can reach by clicking on the + sign next to their name."
+msgid "Once included in a sidebar, widgets have configuration options that you can reach by clicking on the arrow next to their name."
 msgstr ""
 
Index: locales/da/help/blowupConfig.html
===================================================================
--- locales/da/help/blowupConfig.html	(revision 1264)
+++ locales/da/help/blowupConfig.html	(revision 1280)
@@ -35,5 +35,5 @@
 <p>You can choose a header image among the list to use in place of the default one.</p>
 
-<p>When you choose "Custom..." in the image list, you will be able to upload your own image. <strong>The image file must be in JPG or PNG format and must be precisely 800px wide.</strong></p>
+<p>When you choose "Custom..." in the image list, you will be able to upload your own image. <strong>The image file must be in JPG or PNG format and must be precisely 800px wide.</strong>
 
 <p>If you upload a JPG image, a border will be added to the image, which is not the case with PNG images (the transparency of which will also be kept).</p>
Index: locales/da/main.po
===================================================================
--- locales/da/main.po	(revision 1592)
+++ locales/da/main.po	(revision 1637)
@@ -215,5 +215,5 @@
 
 #, fuzzy
-msgid "That blog Id is already in use."
+msgid "This blog ID is already used."
 msgstr "Dotclear er allerede installeret."
 
@@ -459,5 +459,5 @@
 
 #, php-format
-msgid "You are currently using \"%s\""
+msgid "You are currently using <strong>%s</strong>"
 msgstr "Du bruger lige nu \"%s\""
 
@@ -587,5 +587,5 @@
 msgstr "Kategorien er flyttet."
 
-msgid "No category yet."
+msgid "No category so far."
 msgstr "Ingen kategori endnu."
 
@@ -765,5 +765,5 @@
 msgstr "Kommentar ejer:"
 
-msgid "You have one spam comments."
+msgid "You have one spam comment."
 msgstr "Du har en spam kommentar."
 
@@ -1752,8 +1752,8 @@
 msgstr ""
 
-msgid "Change category for entries"
-msgstr ""
-
-msgid "Change author for entries"
+msgid "Change category for this selection"
+msgstr ""
+
+msgid "Change author for this selection"
 msgstr ""
 
@@ -2134,5 +2134,5 @@
 msgstr ""
 
-msgid "invert selection"
+msgid "Invert selection"
 msgstr ""
 
Index: locales/da/plugins.po
===================================================================
--- locales/da/plugins.po	(revision 1126)
+++ locales/da/plugins.po	(revision 1668)
@@ -835,5 +835,5 @@
 
 #, php-format
-msgid "This will import a single blog backup as new content in the current blog: %s."
+msgid "This will import a single blog backup as new content in the current blog: <strong>%s</strong>."
 msgstr ""
 
@@ -1056,14 +1056,14 @@
 msgstr ""
 
-msgid "Page status:"
-msgstr ""
-
-msgid "Page position:"
-msgstr ""
-
-msgid "Page lang:"
-msgstr ""
-
-msgid "Page password:"
+msgid "Page status"
+msgstr ""
+
+msgid "Page position"
+msgstr ""
+
+msgid "Page lang"
+msgstr ""
+
+msgid "Page password"
 msgstr ""
 
@@ -1230,5 +1230,5 @@
 msgstr ""
 
-msgid "Currently no menu items"
+msgid "No menu items so far."
 msgstr ""
 
@@ -1529,5 +1529,5 @@
 msgstr ""
 
-msgid "Once included in a sidebar, widgets have configuration options that you can reach by clicking on the + sign next to their name."
+msgid "Once included in a sidebar, widgets have configuration options that you can reach by clicking on the arrow next to their name."
 msgstr ""
 
Index: locales/de/help/blowupConfig.html
===================================================================
--- locales/de/help/blowupConfig.html	(revision 1264)
+++ locales/de/help/blowupConfig.html	(revision 1280)
@@ -35,5 +35,5 @@
 <p>Du kannst ein Bild Deiner Wahl statt des Standardbildes einsetzen.</p>
 
-<p>Wenn Du  "Benutzerdefiniert..." in der Bilderliste ausw&auml;hlst, dann hast Du die M&ouml;glichkeit, Dein eigenes Bild upzuloaden. <strong>Das Dateiformat muss entweder JPG der PNG sein und es muss 800px breit sein.</strong></p>
+<p>Wenn Du  "Benutzerdefiniert..." in der Bilderliste ausw&auml;hlst, dann hast Du die M&ouml;glichkeit, Dein eigenes Bild upzuloaden. <strong>Das Dateiformat muss entweder JPG der PNG sein und es muss 800px breit sein.</strong>
 
 <p>Wenn Du ein JPG-Bild uploadest, dann wird automatisch ein Rahmen um das Bild gesetzt. Dies geschieht nicht bei der Verwendung eines PNG-Bildes und die Transparenz wird ebenfalls beibehalten.</p>
Index: locales/de/main.po
===================================================================
--- locales/de/main.po	(revision 1592)
+++ locales/de/main.po	(revision 1637)
@@ -212,5 +212,5 @@
 msgstr "Erlaube Suchmaschinen weder das Durchsuchen und Archivieren des Inhaltes noch des Archivs dieses Blogs."
 
-msgid "That blog Id is already in use."
+msgid "This blog ID is already used."
 msgstr "Diese Blog-ID wird schon verwendet."
 
@@ -457,5 +457,5 @@
 
 #, php-format
-msgid "You are currently using \"%s\""
+msgid "You are currently using <strong>%s</strong>"
 msgstr "Du verwendest gerade \"%s\""
 
@@ -584,5 +584,5 @@
 msgstr "Die Kategorie wurde erfolgreich verschoben."
 
-msgid "No category yet."
+msgid "No category so far."
 msgstr "Keine Kategorie angelegt."
 
@@ -763,5 +763,5 @@
 msgstr "Autor des Kommentars"
 
-msgid "You have one spam comments."
+msgid "You have one spam comment."
 msgstr "Du hast Spam in deinen Kommentaren."
 
@@ -1740,8 +1740,8 @@
 msgstr "Dieser Benutzer existiert nicht."
 
-msgid "Change category for entries"
+msgid "Change category for this selection"
 msgstr "Kategorie für die Einträge ändern"
 
-msgid "Change author for entries"
+msgid "Change author for this selection"
 msgstr "Autor für die Einträge ändern"
 
@@ -2126,5 +2126,5 @@
 msgstr "alles markieren"
 
-msgid "invert selection"
+msgid "Invert selection"
 msgstr "Auswahl entfernen"
 
Index: locales/de/plugins.po
===================================================================
--- locales/de/plugins.po	(revision 1126)
+++ locales/de/plugins.po	(revision 1668)
@@ -843,5 +843,5 @@
 
 #, php-format
-msgid "This will import a single blog backup as new content in the current blog: %s."
+msgid "This will import a single blog backup as new content in the current blog: <strong>%s</strong>."
 msgstr "Dies wird einen einzelnen Blog als neuen Inhalt in den aktuellen Blog importieren: %s."
 
@@ -1066,14 +1066,14 @@
 msgstr ""
 
-msgid "Page status:"
+msgid "Page status"
 msgstr "Status der Seite:"
 
-msgid "Page position:"
+msgid "Page position"
 msgstr "Position der Seite:"
 
-msgid "Page lang:"
+msgid "Page lang"
 msgstr "Sprache der Seite:"
 
-msgid "Page password:"
+msgid "Page password"
 msgstr "Passwort der Seite:"
 
@@ -1256,5 +1256,5 @@
 msgstr "Ausgewählte Links wirklich löschen?"
 
-msgid "Currently no menu items"
+msgid "No menu items so far."
 msgstr ""
 
@@ -1569,5 +1569,5 @@
 msgstr ""
 
-msgid "Once included in a sidebar, widgets have configuration options that you can reach by clicking on the + sign next to their name."
+msgid "Once included in a sidebar, widgets have configuration options that you can reach by clicking on the arrow next to their name."
 msgstr ""
 
Index: locales/en/help/post.html
===================================================================
--- locales/en/help/post.html	(revision 175)
+++ locales/en/help/post.html	(revision 1459)
@@ -88,24 +88,4 @@
 </dl>
 
-<h3>Trackback</h3>
-<p>To make a trackback, click on the <em>Ping blogs</em> link.
-You will not see this link if your entry's status is not <em>published</em>.</p>
-
-<dl>
-  <dt>URLs to ping</dt>
-  <dd>Paste here the trackback URLs you found in the posts you want to ping.</dd>
-  
-  
-  <dt>Send excerpt</dt>
-  <dd>This field defaults to your entry's first few sentences. That's wht will be
-  sent to the blog you're pinging, along with a link to your post. You can modify
-  the excerpt by editing this field.</dd>
-  
-  
-  <dt>Auto discover ping URLs</dt>
-  <dd>If your entries links specific posts and if the blog carrying those posts
-  is set to allow it, this tool will find the URLs to ping for you.</dd>
-</dl>
-
 <h3>Comments</h3>
 <dl>
Index: locales/en/help/trackbacks.html
===================================================================
--- locales/en/help/trackbacks.html	(revision 1459)
+++ locales/en/help/trackbacks.html	(revision 1459)
@@ -0,0 +1,29 @@
+<html>
+<head>
+  <title>Editing an entry</title>
+</head>
+
+<body>
+
+<h3>Trackback</h3>
+<p>To make a trackback, click on the <em>Ping blogs</em> link.
+You will not see this link if your entry's status is not <em>published</em>.</p>
+
+<dl>
+  <dt>URLs to ping</dt>
+  <dd>Paste here the trackback URLs you found in the posts you want to ping.</dd>
+  
+  
+  <dt>Send excerpt</dt>
+  <dd>This field defaults to your entry's first few sentences. That's wht will be
+  sent to the blog you're pinging, along with a link to your post. You can modify
+  the excerpt by editing this field.</dd>
+  
+  
+  <dt>Auto discover ping URLs</dt>
+  <dd>If your entries links specific posts and if the blog carrying those posts
+  is set to allow it, this tool will find the URLs to ping for you.</dd>
+</dl>
+
+</body>
+</html>
Index: locales/en/main.po
===================================================================
--- locales/en/main.po	(revision 1592)
+++ locales/en/main.po	(revision 1670)
@@ -211,5 +211,5 @@
 msgstr ""
 
-msgid "That blog Id is already in use."
+msgid "This blog ID is already used."
 msgstr ""
 
@@ -453,5 +453,5 @@
 
 #, php-format
-msgid "You are currently using \"%s\""
+msgid "You are currently using <strong>%s</strong>"
 msgstr ""
 
@@ -547,5 +547,5 @@
 
 msgid "Entries (all types)"
-msgstr "Entries & pages"
+msgstr "Entries"
 
 msgid "Status"
@@ -581,5 +581,5 @@
 msgstr ""
 
-msgid "No category yet."
+msgid "No category so far."
 msgstr ""
 
@@ -753,5 +753,5 @@
 msgstr ""
 
-msgid "You have one spam comments."
+msgid "You have one spam comment."
 msgstr ""
 
@@ -1712,8 +1712,8 @@
 msgstr ""
 
-msgid "Change category for entries"
-msgstr ""
-
-msgid "Change author for entries"
+msgid "Change category for this selection"
+msgstr ""
+
+msgid "Change author for this selection"
 msgstr ""
 
@@ -2074,4 +2074,7 @@
 msgstr ""
 
+msgid "Select:"
+msgstr ""
+
 msgid "no selection"
 msgstr ""
@@ -2080,5 +2083,5 @@
 msgstr ""
 
-msgid "invert selection"
+msgid "Invert selection"
 msgstr ""
 
@@ -2159,7 +2162,4 @@
 
 msgid "You have unsaved changes. Switch post format will loose these changes. Proceed anyway?"
-msgstr ""
-
-msgid "Warning: post format change will not convert existing content. You will need to apply new format by yourself. Proceed anyway?"
 msgstr ""
 
Index: locales/en/plugins.po
===================================================================
--- locales/en/plugins.po	(revision 1126)
+++ locales/en/plugins.po	(revision 1668)
@@ -280,4 +280,7 @@
 msgstr ""
 
+msgid "Attachments (%d)"
+msgstr ""
+
 msgid "remove"
 msgstr ""
@@ -852,5 +855,5 @@
 
 #, php-format
-msgid "This will import a single blog backup as new content in the current blog: %s."
+msgid "This will import a single blog backup as new content in the current blog: <strong>%s</strong>."
 msgstr ""
 
@@ -1073,14 +1076,14 @@
 msgstr ""
 
-msgid "Page status:"
-msgstr ""
-
-msgid "Page position:"
-msgstr ""
-
-msgid "Page lang:"
-msgstr ""
-
-msgid "Page password:"
+msgid "Page status"
+msgstr ""
+
+msgid "Page position"
+msgstr ""
+
+msgid "Page lang"
+msgstr ""
+
+msgid "Page password"
 msgstr ""
 
@@ -1247,5 +1250,5 @@
 msgstr ""
 
-msgid "Currently no menu items"
+msgid "No menu items so far."
 msgstr ""
 
@@ -1546,5 +1549,5 @@
 msgstr ""
 
-msgid "Once included in a sidebar, widgets have configuration options that you can reach by clicking on the + sign next to their name."
+msgid "Once included in a sidebar, widgets have configuration options that you can reach by clicking on the arrow next to their name."
 msgstr ""
 
Index: locales/en/resources.php
===================================================================
--- locales/en/resources.php	(revision 1179)
+++ locales/en/resources.php	(revision 1459)
@@ -15,9 +15,9 @@
 
 $__resources['doc'] = array(
-	"Dotclear 2 documentation" => 'http://dotclear.org/documentation/2.0',
-	'Dotclear 2 presentation' => 'http://dotclear.org/documentation/2.0/overview/tour',
+	"Dotclear documentation" => 'http://dotclear.org/documentation/2.0',
+	'Dotclear presentation' => 'http://dotclear.org/documentation/2.0/overview/tour',
 	"User manual" => 'http://dotclear.org/documentation/2.0/usage',
 	"Installation and administration guides" => 'http://dotclear.org/documentation/2.0/admin',
-	"Dotclear 2 support forum" => 'http://forum.dotclear.net/'
+	"Dotclear support forum" => 'http://forum.dotclear.net/'
 );
 
@@ -29,4 +29,5 @@
 	'core_post' => dirname(__FILE__).'/help/post.html',
 	'core_posts' => dirname(__FILE__).'/help/posts.html',
+	'core_trackbacks' => dirname(__FILE__).'/help/trackbacks.html',
 	'core_user_pref' => dirname(__FILE__).'/help/user_pref.html',
 	'core_user' => dirname(__FILE__).'/help/user.html',
Index: locales/eo/help/blowupConfig.html
===================================================================
--- locales/eo/help/blowupConfig.html	(revision 1264)
+++ locales/eo/help/blowupConfig.html	(revision 1280)
@@ -35,5 +35,5 @@
 <p>You can choose a header image among the list to use in place of the default one.</p>
 
-<p>When you choose "Custom..." in the image list, you will be able to upload your own image. <strong>The image file must be in JPG or PNG format and must be precisely 800px wide.</strong></p>
+<p>When you choose "Custom..." in the image list, you will be able to upload your own image. <strong>The image file must be in JPG or PNG format and must be precisely 800px wide.</strong>
 
 <p>If you upload a JPG image, a border will be added to the image, which is not the case with PNG images (the transparency of which will also be kept).</p>
Index: locales/eo/main.po
===================================================================
--- locales/eo/main.po	(revision 1592)
+++ locales/eo/main.po	(revision 1637)
@@ -211,5 +211,5 @@
 msgstr ""
 
-msgid "That blog Id is already in use."
+msgid "This blog ID is already used."
 msgstr ""
 
@@ -453,5 +453,5 @@
 
 #, php-format
-msgid "You are currently using \"%s\""
+msgid "You are currently using <strong>%s</strong>"
 msgstr ""
 
@@ -578,5 +578,5 @@
 msgstr ""
 
-msgid "No category yet."
+msgid "No category so far."
 msgstr ""
 
@@ -750,5 +750,5 @@
 msgstr ""
 
-msgid "You have one spam comments."
+msgid "You have one spam comment."
 msgstr ""
 
@@ -1708,8 +1708,8 @@
 msgstr ""
 
-msgid "Change category for entries"
-msgstr ""
-
-msgid "Change author for entries"
+msgid "Change category for this selection"
+msgstr ""
+
+msgid "Change author for this selection"
 msgstr ""
 
@@ -2073,5 +2073,5 @@
 msgstr ""
 
-msgid "invert selection"
+msgid "Invert selection"
 msgstr ""
 
Index: locales/eo/plugins.po
===================================================================
--- locales/eo/plugins.po	(revision 1126)
+++ locales/eo/plugins.po	(revision 1668)
@@ -835,5 +835,5 @@
 
 #, php-format
-msgid "This will import a single blog backup as new content in the current blog: %s."
+msgid "This will import a single blog backup as new content in the current blog: <strong>%s</strong>."
 msgstr ""
 
@@ -1056,14 +1056,14 @@
 msgstr ""
 
-msgid "Page status:"
-msgstr ""
-
-msgid "Page position:"
-msgstr ""
-
-msgid "Page lang:"
-msgstr ""
-
-msgid "Page password:"
+msgid "Page status"
+msgstr ""
+
+msgid "Page position"
+msgstr ""
+
+msgid "Page lang"
+msgstr ""
+
+msgid "Page password"
 msgstr ""
 
@@ -1230,5 +1230,5 @@
 msgstr ""
 
-msgid "Currently no menu items"
+msgid "No menu items so far."
 msgstr ""
 
@@ -1529,5 +1529,5 @@
 msgstr ""
 
-msgid "Once included in a sidebar, widgets have configuration options that you can reach by clicking on the + sign next to their name."
+msgid "Once included in a sidebar, widgets have configuration options that you can reach by clicking on the arrow next to their name."
 msgstr ""
 
Index: locales/es-ar/help/blowupConfig.html
===================================================================
--- locales/es-ar/help/blowupConfig.html	(revision 1264)
+++ locales/es-ar/help/blowupConfig.html	(revision 1280)
@@ -35,5 +35,5 @@
 <p>You can choose a header image among the list to use in place of the default one.</p>
 
-<p>When you choose "Custom..." in the image list, you will be able to upload your own image. <strong>The image file must be in JPG or PNG format and must be precisely 800px wide.</strong></p>
+<p>When you choose "Custom..." in the image list, you will be able to upload your own image. <strong>The image file must be in JPG or PNG format and must be precisely 800px wide.</strong>
 
 <p>If you upload a JPG image, a border will be added to the image, which is not the case with PNG images (the transparency of which will also be kept).</p>
Index: locales/es-ar/main.po
===================================================================
--- locales/es-ar/main.po	(revision 1592)
+++ locales/es-ar/main.po	(revision 1637)
@@ -217,5 +217,5 @@
 
 #, fuzzy
-msgid "That blog Id is already in use."
+msgid "This blog ID is already used."
 msgstr "Dotclear ya está instalado."
 
@@ -460,5 +460,5 @@
 
 #, php-format
-msgid "You are currently using \"%s\""
+msgid "You are currently using <strong>%s</strong>"
 msgstr "Actualmente usas \"%s\""
 
@@ -588,5 +588,5 @@
 msgstr "La categoría se ha movido con éxito."
 
-msgid "No category yet."
+msgid "No category so far."
 msgstr "No hay categorías aún."
 
@@ -767,5 +767,5 @@
 msgstr "Autor del comentario:"
 
-msgid "You have one spam comments."
+msgid "You have one spam comment."
 msgstr "Tiene un comentario no deseado."
 
@@ -1756,8 +1756,8 @@
 msgstr "Este usuario no existe"
 
-msgid "Change category for entries"
+msgid "Change category for this selection"
 msgstr "Cambiar la categoría para las entradas"
 
-msgid "Change author for entries"
+msgid "Change author for this selection"
 msgstr "Cambiar el autor de las entradas"
 
@@ -2141,5 +2141,5 @@
 msgstr "seleccionar todo"
 
-msgid "invert selection"
+msgid "Invert selection"
 msgstr "invertir la selección"
 
Index: locales/es-ar/plugins.po
===================================================================
--- locales/es-ar/plugins.po	(revision 1126)
+++ locales/es-ar/plugins.po	(revision 1668)
@@ -844,5 +844,5 @@
 
 #, php-format
-msgid "This will import a single blog backup as new content in the current blog: %s."
+msgid "This will import a single blog backup as new content in the current blog: <strong>%s</strong>."
 msgstr "Esto importará un archivo de resguardo de un blog individual como contenido nuevo del actual blog: %s."
 
@@ -1068,14 +1068,14 @@
 msgstr ""
 
-msgid "Page status:"
+msgid "Page status"
 msgstr "Estado de la pagina:"
 
-msgid "Page position:"
+msgid "Page position"
 msgstr "Posición de la pagina:"
 
-msgid "Page lang:"
+msgid "Page lang"
 msgstr "Idioma de la pagina:"
 
-msgid "Page password:"
+msgid "Page password"
 msgstr "Contraseña de la pagina:"
 
@@ -1259,5 +1259,5 @@
 msgstr "¿Esta seguro que desea eliminar los enlaces seleccionados?"
 
-msgid "Currently no menu items"
+msgid "No menu items so far."
 msgstr ""
 
@@ -1572,5 +1572,5 @@
 msgstr ""
 
-msgid "Once included in a sidebar, widgets have configuration options that you can reach by clicking on the + sign next to their name."
+msgid "Once included in a sidebar, widgets have configuration options that you can reach by clicking on the arrow next to their name."
 msgstr ""
 
Index: locales/es/help/blowupConfig.html
===================================================================
--- locales/es/help/blowupConfig.html	(revision 1264)
+++ locales/es/help/blowupConfig.html	(revision 1280)
@@ -35,5 +35,5 @@
 <p>You can choose a header image among the list to use in place of the default one.</p>
 
-<p>When you choose "Custom..." in the image list, you will be able to upload your own image. <strong>The image file must be in JPG or PNG format and must be precisely 800px wide.</strong></p>
+<p>When you choose "Custom..." in the image list, you will be able to upload your own image. <strong>The image file must be in JPG or PNG format and must be precisely 800px wide.</strong>
 
 <p>If you upload a JPG image, a border will be added to the image, which is not the case with PNG images (the transparency of which will also be kept).</p>
Index: locales/es/main.po
===================================================================
--- locales/es/main.po	(revision 1592)
+++ locales/es/main.po	(revision 1637)
@@ -218,5 +218,5 @@
 
 #, fuzzy
-msgid "That blog Id is already in use."
+msgid "This blog ID is already used."
 msgstr "Dotclear ya está instalado."
 
@@ -462,5 +462,5 @@
 
 #, php-format
-msgid "You are currently using \"%s\""
+msgid "You are currently using <strong>%s</strong>"
 msgstr "Actualmente está usando «%s»"
 
@@ -590,5 +590,5 @@
 msgstr "La categoría se ha movido con éxito."
 
-msgid "No category yet."
+msgid "No category so far."
 msgstr "Ninguna categoría todavía."
 
@@ -769,5 +769,5 @@
 msgstr "Autor del comentario:"
 
-msgid "You have one spam comments."
+msgid "You have one spam comment."
 msgstr "Tiene un comentario no deseado."
 
@@ -1750,8 +1750,8 @@
 msgstr "Este usuario no existe"
 
-msgid "Change category for entries"
+msgid "Change category for this selection"
 msgstr "Cambiar la categoría de las entradas"
 
-msgid "Change author for entries"
+msgid "Change author for this selection"
 msgstr "Cambiar el autor de las entradas"
 
@@ -2139,5 +2139,5 @@
 msgstr "Seleccionar todo"
 
-msgid "invert selection"
+msgid "Invert selection"
 msgstr "Invertir la selección"
 
Index: locales/es/plugins.po
===================================================================
--- locales/es/plugins.po	(revision 1126)
+++ locales/es/plugins.po	(revision 1668)
@@ -849,5 +849,5 @@
 
 #, php-format
-msgid "This will import a single blog backup as new content in the current blog: %s."
+msgid "This will import a single blog backup as new content in the current blog: <strong>%s</strong>."
 msgstr "Esto importará una copia de respaldo de un único blog como nuevo contenido del blog en uso: %s."
 
@@ -1074,14 +1074,14 @@
 msgstr ""
 
-msgid "Page status:"
+msgid "Page status"
 msgstr "Estado de la página:"
 
-msgid "Page position:"
+msgid "Page position"
 msgstr "Posición de la página:"
 
-msgid "Page lang:"
+msgid "Page lang"
 msgstr "Idioma de la página:"
 
-msgid "Page password:"
+msgid "Page password"
 msgstr "Contraseña de la página:"
 
@@ -1265,5 +1265,5 @@
 msgstr "¿Seguro que desea borrar los enlaces seleccionados?"
 
-msgid "Currently no menu items"
+msgid "No menu items so far."
 msgstr ""
 
@@ -1576,5 +1576,5 @@
 msgstr ""
 
-msgid "Once included in a sidebar, widgets have configuration options that you can reach by clicking on the + sign next to their name."
+msgid "Once included in a sidebar, widgets have configuration options that you can reach by clicking on the arrow next to their name."
 msgstr ""
 
Index: locales/eu/help/blowupConfig.html
===================================================================
--- locales/eu/help/blowupConfig.html	(revision 1264)
+++ locales/eu/help/blowupConfig.html	(revision 1280)
@@ -35,5 +35,5 @@
 <p>You can choose a header image among the list to use in place of the default one.</p>
 
-<p>When you choose "Custom..." in the image list, you will be able to upload your own image. <strong>The image file must be in JPG or PNG format and must be precisely 800px wide.</strong></p>
+<p>When you choose "Custom..." in the image list, you will be able to upload your own image. <strong>The image file must be in JPG or PNG format and must be precisely 800px wide.</strong>
 
 <p>If you upload a JPG image, a border will be added to the image, which is not the case with PNG images (the transparency of which will also be kept).</p>
Index: locales/eu/main.po
===================================================================
--- locales/eu/main.po	(revision 1592)
+++ locales/eu/main.po	(revision 1637)
@@ -211,5 +211,5 @@
 msgstr ""
 
-msgid "That blog Id is already in use."
+msgid "This blog ID is already used."
 msgstr ""
 
@@ -453,5 +453,5 @@
 
 #, php-format
-msgid "You are currently using \"%s\""
+msgid "You are currently using <strong>%s</strong>"
 msgstr ""
 
@@ -578,5 +578,5 @@
 msgstr ""
 
-msgid "No category yet."
+msgid "No category so far."
 msgstr ""
 
@@ -750,5 +750,5 @@
 msgstr ""
 
-msgid "You have one spam comments."
+msgid "You have one spam comment."
 msgstr ""
 
@@ -1708,8 +1708,8 @@
 msgstr ""
 
-msgid "Change category for entries"
-msgstr ""
-
-msgid "Change author for entries"
+msgid "Change category for this selection"
+msgstr ""
+
+msgid "Change author for this selection"
 msgstr ""
 
@@ -2073,5 +2073,5 @@
 msgstr ""
 
-msgid "invert selection"
+msgid "Invert selection"
 msgstr ""
 
Index: locales/eu/plugins.po
===================================================================
--- locales/eu/plugins.po	(revision 1126)
+++ locales/eu/plugins.po	(revision 1668)
@@ -835,5 +835,5 @@
 
 #, php-format
-msgid "This will import a single blog backup as new content in the current blog: %s."
+msgid "This will import a single blog backup as new content in the current blog: <strong>%s</strong>."
 msgstr ""
 
@@ -1056,14 +1056,14 @@
 msgstr ""
 
-msgid "Page status:"
-msgstr ""
-
-msgid "Page position:"
-msgstr ""
-
-msgid "Page lang:"
-msgstr ""
-
-msgid "Page password:"
+msgid "Page status"
+msgstr ""
+
+msgid "Page position"
+msgstr ""
+
+msgid "Page lang"
+msgstr ""
+
+msgid "Page password"
 msgstr ""
 
@@ -1230,5 +1230,5 @@
 msgstr ""
 
-msgid "Currently no menu items"
+msgid "No menu items so far."
 msgstr ""
 
@@ -1529,5 +1529,5 @@
 msgstr ""
 
-msgid "Once included in a sidebar, widgets have configuration options that you can reach by clicking on the + sign next to their name."
+msgid "Once included in a sidebar, widgets have configuration options that you can reach by clicking on the arrow next to their name."
 msgstr ""
 
Index: locales/fr/help/blowupConfig.html
===================================================================
--- locales/fr/help/blowupConfig.html	(revision 1264)
+++ locales/fr/help/blowupConfig.html	(revision 1588)
@@ -10,9 +10,9 @@
 ou choisissez un style prédéfini.</p>
 
-<h3>Couleurs</h3>
+<h4>Couleurs</h4>
 
 <p>Quand vous devez indiquer une valeur de couleur, celle-ci doit être au format
 hexadécimal. Par exemple&nbsp;: "#FF0000" donnera du rouge. Vous pouvez vous aider
-de la pipette à côté de chaque champs de couleur.</p>
+de la pipette à côté de chaque champ de couleur.</p>
 <p>Si vous manquez d'inspiration vous pouvez consulter&nbsp;:</p>
 <ul>
@@ -23,5 +23,5 @@
 </ul>
 
-<h3>Unités de mesure</h3>
+<h4>Unités de mesure</h4>
 
 <p>Quand vous devez indiquer une taille, celle-ci doit être suivie d'une unité
@@ -37,5 +37,5 @@
 </ul>
 
-<h3>Images d'en-tête</h3>
+<h4>Images d'en-tête</h4>
 
 <p>Vous pouvez choisir une image d'en-tête parmi une liste de nombreuses images
@@ -50,5 +50,5 @@
 transparence sera également préservée).</p>
 
-<h3>Styles prédéfinis</h3>
+<h4>Styles prédéfinis</h4>
 
 <p>Vous pouvez choisir un style prédéfini dans la liste d'option "Styles prédéfinis".
@@ -58,5 +58,5 @@
 <p>Vous pouvez ensuite modifier le style prédéfini comme bon vous semble.</p>
 
-<h3>Import / export de configuration</h3>
+<h4>Import / export de configuration</h4>
 
 <p>À la fin des options de Blowup, vous pouvez afficher une zone appelée "Import
Index: locales/fr/help/core_blog_pref.html
===================================================================
--- locales/fr/help/core_blog_pref.html	(revision 990)
+++ locales/fr/help/core_blog_pref.html	(revision 1573)
@@ -6,5 +6,5 @@
 <body>
 
-<h3>Informations du blog</h3>
+<h4>Informations du blog</h4>
 <dl>
   <dt>Identifiant du blog</dt>
@@ -13,5 +13,6 @@
   
   <dt>Nom du blog</dt>
-  <dd>Nom du blog, obligatoire.</dd>
+  <dd>Nom du blog, obligatoire. Il peut être modifié à tout moment sans incidence sur
+  le fonctionnement du blog.</dd>
   
   <dt>URL du blog</dt>
@@ -40,9 +41,9 @@
 </dl>
 
-<h3>Configuration du blog</h3>
+<h4>Configuration du blog</h4>
 <dl>
   <dt>Nom de l'éditeur du blog</dt>
   <dd>Nom de la personne responsable du contenu du blog. Peut être le propriétaire
-  ou le directeur de publication s'il existe. Information affichée dans les
+  ou le directeur de publication s'il existe. Cette information sera affichée dans les
   informations du flux de syndication.</dd>
   
@@ -53,5 +54,5 @@
   <dd>Langue de l'interface du blog. Si cette langue existe parmi les
   traductions, l'interface sera traduite dans celle-ci, sinon elle apparaîtra
-  en Anglais.</dd>
+  en anglais.</dd>
   
   <dt>Fuseau horaire du blog</dt>
@@ -126,5 +127,5 @@
 </dl>
 
-<h3>Formatage des dates</h3>
+<h4>Formatage des dates</h4>
 <p>Certains champs permettent de formater les dates avec des caractères
 particuliers dont voici la définition&nbsp;:</p>
Index: locales/fr/help/core_categories.html
===================================================================
--- locales/fr/help/core_categories.html	(revision 175)
+++ locales/fr/help/core_categories.html	(revision 1573)
@@ -5,5 +5,5 @@
 
 <body>
-<h3>Liste des categories</h3>
+<h4>Liste des categories</h4>
 <dl>
   <dt>Créer une nouvelle catégorie</dt>
@@ -23,5 +23,5 @@
 </dl>
 
-<h3>Modifier une catégorie</h3>
+<h4>Modifier une catégorie</h4>
 <dl>
   <dt>Titre</dt>
Index: locales/fr/help/core_comments.html
===================================================================
--- locales/fr/help/core_comments.html	(revision 0)
+++ locales/fr/help/core_comments.html	(revision 1573)
@@ -5,5 +5,5 @@
 
 <body>
-<h3>Filtres de la liste des commentaires</h3>
+<h4>Filtres de la liste des commentaires</h4>
 <dl>
   <dt>Type :</dt>
@@ -34,5 +34,5 @@
 </dl>
 
-<h3>Modifier ou ajouter un commentaire</h3>
+<h4>Modifier ou ajouter un commentaire</h4>
 <dl>
   <dt>Auteur :</dt>
Index: locales/fr/help/core_media.html
===================================================================
--- locales/fr/help/core_media.html	(revision 1194)
+++ locales/fr/help/core_media.html	(revision 1580)
@@ -1,11 +1,11 @@
 <html>
 <head>
-  <title>Gestionnaire de media</title>
+  <title>Médiathèque</title>
 </head>
 
 <body>
 
-<h3>Liste des médias</h3>
-<p>La page principale du gestionnaire de médias présente la liste des fichiers
+<h4>Liste des médias</h4>
+<p>La page principale de la médiathèque présente la liste des fichiers
 (médias) disponibles pour le blog en cours d'utilisation.</p>
 
@@ -19,5 +19,5 @@
 <p>Les images sont affichées avec une miniature quand cela est possible.</p>
 
-<h3>Ajouter des fichiers</h3>
+<h4>Ajouter des fichiers</h4>
 <dl>
   <dt>Choisissez un fichier</dt>
@@ -39,10 +39,10 @@
 </dl>
 
-<h3>Nouveau répertoire</h3>
+<h4>Nouveau répertoire</h4>
 <p>Ce formulaire permet de créer un nouveau répertoire dans le répertoire en
 cours d'utilisation. Indiquez simplement un nom comme vous le feriez sur votre
 ordinateur.</p>
 
-<h3>Détails du média</h3>
+<h4>Détails du média</h4>
 <p>La page individuelle d'un média présente un ensemble d'informations sur
 celui-ci et permet d'effectuer quelques opérations.</p>
@@ -70,5 +70,5 @@
 </dl>
 
-<h3>Cas particulier des images</h3>
+<h4>Cas particulier des images</h4>
 <p>Lors de l'ajout d'une image, jusqu'à quatre versions de celle-ci peuvent
 être disponibles (selon la taille de l'image d'origine)&nbsp;:</p>
@@ -82,8 +82,8 @@
 <p>Les tailles par défaut des versions miniature, petite et moyenne, peuvent être modifiées dans les paramètres du blog</p>
 
-<h3>Attacher un fichier à un billet</h3>
+<h4>Attacher un fichier à un billet</h4>
 <p>Vous pouvez attacher un fichier à un billet très facilement. Commencez par
 créer un nouveau billet et enregistrez-le. Cliquez alors sur "ajouter un fichier
-au billet" pour ouvrir le gestionnaire de médias.</p>
+au billet" pour ouvrir la médiathèque.</p>
 
 <p>En cliquant sur l'icône [+] (Attacher un fichier au billet) vous pourrez
@@ -95,5 +95,5 @@
 lecture directe du fichier.</p>
 
-<h3>Podcast et diffusion de fichiers musicaux</h3>
+<h4>Podcast et diffusion de fichiers musicaux</h4>
 <p>Tous les fichiers attachés à un billet seront présents dans les fils RSS de
 vos billets, vous permettant ainsi de réaliser des podcast de n'importe quel
Index: locales/fr/help/core_post.html
===================================================================
--- locales/fr/help/core_post.html	(revision 175)
+++ locales/fr/help/core_post.html	(revision 1580)
@@ -6,5 +6,5 @@
 <body>
 
-<h3>Rédaction du billet</h3>
+<h4>Rédaction du billet</h4>
 
 <dl>
@@ -91,33 +91,8 @@
   d'ajout d'une pièce jointe permet de choisir un fichier à ajouter au billet.
   Pensez à sauvegarder votre billet avant de choisir une pièce jointe. Consultez
-  l'aide du gestionnaire de médias pour plus de détails.</dd>
+  l'aide de la médiathèque pour plus de détails.</dd>
 </dl>
 
-<h3>Rétroliens</h3>
-<p>Pour faire un rétrolien cliquez sur le lien <em>Faire des rétroliens</em>.
-Si vous ne voyez pas ce lien, vérifiez que votre billet est bien dans l'état
-<em>publié</em>.</p>
-
-<dl>
-  <dt>URLs à rétrolier</dt>
-  <dd>Indiquez ici la ou les URL que vous aurez relevé dans le billet vers lequel
-  vous souhaitez envoyer un rétrolien.</dd>
-  
-  
-  <dt>Envoyer l'extrait</dt>
-  <dd>Par défaut, ce champ comporte le début de votre billet. C'est ce qui sera
-  envoyé vers le blog que vous rétroliez avec un lien vers votre billet complet.
-  Vous pouvez modifier le contenu de cette "accroche" en saisissant directement le
-  texte de votre choix dans ce champ.</dd>
-  
-  
-  <dt>Découverte automatique des URLs à rétrolier</dt>
-  <dd>Si votre billet comporte des liens vers des billets précis et si la
-  plate-forme du blog destinataire est configurée pour le permettre, cette
-  fonction découvrira automatiquement les URLs spécifiques d'envoi de
-  rétrolien.</dd>
-</dl>
-
-<h3>Commentaires</h3>
+<h4>Commentaires</h4>
 <dl>
   <dt>Liste les commentaires</dt>
Index: locales/fr/help/core_posts.html
===================================================================
--- locales/fr/help/core_posts.html	(revision 0)
+++ locales/fr/help/core_posts.html	(revision 1573)
@@ -6,5 +6,5 @@
 <body>
 
-<h3>Filtres de la liste des billets</h3>
+<h4>Filtres de la liste des billets</h4>
 
 <dl>
@@ -45,5 +45,5 @@
 </dl>
 
-<h3>Actions par lot sur les billets</h3>
+<h4>Actions par lot sur les billets</h4>
 <p>Il est possible d'effectuer un ensemble d'actions sur plusieurs billets, d'un
 seul coup. Les actions possibles dépendent des permissions de l'utilisateur.</p>
Index: locales/fr/help/core_trackbacks.html
===================================================================
--- locales/fr/help/core_trackbacks.html	(revision 1614)
+++ locales/fr/help/core_trackbacks.html	(revision 1614)
@@ -0,0 +1,34 @@
+<html>
+<head>
+  <title>Rédaction d'un billet</title>
+</head>
+
+<body>
+
+<h4>Rétroliens</h4>
+<p>Pour envoyer un rétrolien cliquez sur le lien <em>Faire des rétroliens</em>.
+Si vous ne voyez pas ce lien, vérifiez que votre billet est bien dans l'état
+<em>publié</em>.</p>
+
+<dl>
+  <dt>URLs à rétrolier</dt>
+  <dd>Indiquez ici la ou les URL que vous aurez relevé dans le billet vers lequel
+  vous souhaitez envoyer un rétrolien.</dd>
+  
+  
+  <dt>Envoyer l'extrait</dt>
+  <dd>Par défaut, ce champ comporte le début de votre billet. C'est ce qui sera
+  envoyé vers le blog que vous rétroliez avec un lien vers votre billet complet.
+  Vous pouvez modifier le contenu de cette "accroche" en saisissant directement le
+  texte de votre choix dans ce champ.</dd>
+  
+  
+  <dt>Découverte automatique des URLs à rétrolier</dt>
+  <dd>Si votre billet comporte des liens vers des billets précis et si la
+  plate-forme du blog destinataire est configurée pour le permettre, cette
+  fonction découvrira automatiquement les URLs spécifiques d'envoi de
+  rétrolien.</dd>
+</dl>
+
+</body>
+</html>
Index: locales/fr/help/core_user.html
===================================================================
--- locales/fr/help/core_user.html	(revision 175)
+++ locales/fr/help/core_user.html	(revision 1609)
@@ -6,7 +6,7 @@
 <body>
 
-<h3>Informations utilisateur</h3>
+<h4>Informations utilisateur</h4>
 <dl>
-  <dt>Nom d'utilisateur</dt>
+  <dt>Identifiant (login)</dt>
   <dd>Il doit être composé d'au moins 2 caractères (lettres non accentuées, chiffres ou symboles, pas d'espace). Ce champ est obligatoire.</dd>
 
@@ -18,8 +18,8 @@
   <dt>Nom, Prénom</dt>
   <dd>Si le pseudonyme n'est pas renseigné, le nom de l'auteur qui sera affiché
-  sera composé des noms et prénoms renseignés dans ces champs.</dd>
+  sera composé des nom et prénom renseignés dans ces champs.</dd>
 
   <dt>Pseudonyme</dt>
-  <dd>Vous pouvez choisir ici le nom sous lequel vos billets seront signés. S'il est renseigné, le pseudonyme se substitue au nom et au prénom.</dd>
+  <dd>Vous pouvez choisir ici le pseudonyme sous lequel vos billets seront signés. S'il est renseigné, le pseudonyme se substitue au nom et au prénom.</dd>
 
   <dt>Email</dt>
@@ -58,6 +58,6 @@
   <dd>Ce choix déterminera l'affichage de l'heure de publication des billets.</dd>
 
-  <dt>Changement de mot de passe requis pour la connexion</dt>
-  <dd>Cocher cette case permettra au nouvel utilisateur de choisir par lui-même son mot de passe de connexion.</dd>
+  <dt>Changement de mot de passe requis à la prochaine connexion</dt>
+  <dd>Cocher cette case permettra au nouvel utilisateur de choisir par lui-même son mot de passe à sa première connexion.</dd>
 
   <dt>Super administrateur</dt>
@@ -65,8 +65,8 @@
 </dl>
 
-<h3>Tags</h3>
+<h4>Mots-clés</h4>
 <dl>
-  <dt>Format de la liste des tags</dt>
-  <dd>Ce choix permet, dans la page d'édition d'un billet, d'afficher tous les tags
+  <dt>Format de la liste des mots-clés</dt>
+  <dd>Ce choix permet, dans la page d'édition d'un billet, d'afficher tous les mots-clés
   disponibles ou seulement les plus utilisés.</dd>
 </dl>
Index: locales/fr/help/core_user_pref.html
===================================================================
--- locales/fr/help/core_user_pref.html	(revision 243)
+++ locales/fr/help/core_user_pref.html	(revision 1580)
@@ -6,5 +6,5 @@
 <body>
 
-<h3>Mon profil</h3>
+<h4>Mon profil</h4>
 <dl>
   <dt>Nom, Prénom</dt>
@@ -37,5 +37,5 @@
 </dl>
   
-<h3>Mes options</h3>
+<h4>Mes options</h4>
 <dl> 
   <dt>Format d'édition préféré</dt>
@@ -63,5 +63,5 @@
   <dd>Permet d'activer ou non l'éditeur visuel des billets et des catégories.</dd>
   
-  <dt>Activer l'interface avancée du gestionnaire de médias</dt>
+  <dt>Activer l'interface avancée de la médiathèque</dt>
   <dd>Cette option permet d'envoyer plusieurs fichiers à la fois sur le serveur.
   Nécessite la présence du plugin Flash dans votre navigateur.</dd>
@@ -75,5 +75,5 @@
   disponibles ou seulement les plus utilisés.</dd>
 </dl>
-<h3>Mes favoris</h3>
+<h4>Mes favoris</h4>
 <dl>
   <dt>Mes favoris</dt>
Index: locales/fr/help/core_wiki.html
===================================================================
--- locales/fr/help/core_wiki.html	(revision 0)
+++ locales/fr/help/core_wiki.html	(revision 1573)
@@ -6,5 +6,5 @@
 <body>
 
-<h3>Référence de la syntaxe Wiki</h3>
+<h4>Référence de la syntaxe Wiki</h4>
 
 <p>La syntaxe Wiki est une manière d'écrire du texte avec un jeu de balises
Index: locales/fr/main.po
===================================================================
--- locales/fr/main.po	(revision 1592)
+++ locales/fr/main.po	(revision 1678)
@@ -82,9 +82,12 @@
 msgstr "Changer votre mot de passe"
 
+msgid "Change my password"
+msgstr "Changer mon mot de passe"
+
 msgid "New password:"
 msgstr "Nouveau mot de passe :"
 
 msgid "Confirm password:"
-msgstr "Confirmez le mot de passe :"
+msgstr "Confirmer le mot de passe :"
 
 msgid "change"
@@ -95,5 +98,5 @@
 
 msgid "This mode allows you to login without activating any of your plugins. This may be useful to solve compatibility problems"
-msgstr "\"Ce mode vous permet de vous connecter sans activer de plugins. Il peut être utile pour résoudre un problème de compatibilité"
+msgstr "Ce mode vous permet de vous connecter sans activer de plugins. Il peut être utile pour résoudre un problème de compatibilité"
 
 msgid "Disable or delete any plugin suspected to cause trouble, then log out and log back in normally."
@@ -168,5 +171,5 @@
 #, php-format
 msgid "You are about to delete the blog %s. Every entry, comment and category will be deleted."
-msgstr "Vous êtes sur le point de supprimer le blog %s. Tous ses billets, commentaires et catégories seront supprimés."
+msgstr "Vous êtes sur le point de supprimer le blog %s. Tous ses billets, pages, commentaires et catégories seront supprimés."
 
 msgid "Please give your password to confirm the blog deletion."
@@ -227,5 +230,5 @@
 msgstr "Je souhaite que mon blog ne soit ni indexé ni archivé par les moteurs de recherche et archiveurs."
 
-msgid "That blog Id is already in use."
+msgid "This blog ID is already used."
 msgstr "Cet identifiant est déjà utilisé."
 
@@ -335,5 +338,5 @@
 
 msgid "Display smilies on entries and comments"
-msgstr "Afficher des émoticônes dans les billets et commentaires"
+msgstr "Afficher des émoticônes dans les billets, pages et commentaires"
 
 #, php-format
@@ -371,5 +374,5 @@
 
 msgid "This defines image tag title when you insert it in a post from the media manager. It is retrieved from the picture's metadata."
-msgstr "Ceci définit le titre de la balise d'une image insérée depuis le gestionnaire de media. Les informations sont obtenues depuis les métadonnées de l'image."
+msgstr "Ceci définit le titre de la balise d'une image insérée depuis la médiathèque. Les informations sont obtenues depuis les métadonnées de l'image."
 
 msgid "Use original media date if possible"
@@ -481,6 +484,6 @@
 
 #, php-format
-msgid "You are currently using \"%s\""
-msgstr "Vous utilisez actuellement \"%s\""
+msgid "You are currently using <strong>%s</strong>"
+msgstr "Vous utilisez actuellement <strong>%s</strong>"
 
 msgid "Use selected theme"
@@ -575,5 +578,5 @@
 
 msgid "Entries (all types)"
-msgstr "Billets & pages"
+msgstr "Entrées"
 
 msgid "Status"
@@ -601,5 +604,7 @@
 
 msgid "The category has been successfully removed."
-msgstr "Catégorie supprimée avec succès."
+msgid_plural "The categories have been successfully removed."
+msgstr[0] "Catégorie supprimée avec succès."
+msgstr[1] "Catégories supprimées avec succès."
 
 msgid "Categories have been successfully reordered."
@@ -609,9 +614,9 @@
 msgstr "Catégorie déplacée avec succès."
 
-msgid "No category yet."
-msgstr "Pas encore de catégorie."
-
-msgid "Categories list"
-msgstr "Liste des catégories"
+msgid "No category so far."
+msgstr "Pas de catégorie pour le moment."
+
+msgid "List of blog\'s categories"
+msgstr "Liste des catégories du blog"
 
 #, php-format
@@ -647,6 +652,12 @@
 msgstr "Choisissez une catégorie à supprimer :"
 
-msgid "And choose the category which will receive its entries:"
-msgstr "Et sélectionnez la catégorie qui recevra ses (éventuels) billets :"
+msgid "Categories order"
+msgstr "Ordonnancement des catégories"
+
+msgid "Save categories order"
+msgstr "Enregistrer l'ordre des catégories"
+
+msgid "Choose the category which will receive its entries:"
+msgstr "Sélectionnez la catégorie qui recevra ses éventuels billets :"
 
 msgid "The entries cannot be moved to the category you choose to delete."
@@ -656,9 +667,12 @@
 msgstr "Supprimer"
 
-msgid "Reorder categories"
-msgstr "Réordonner les catégories"
+msgid "Reorder all categories on the top level"
+msgstr "Replacer toutes les catégories au premier niveau"
 
 msgid "This will relocate all categories on the top level"
 msgstr "Ceci va déplacer toutes les catégories au premier niveau"
+
+msgid "To rearrange categories order, move items by drag and drop, then click on “Save categories order” button."
+msgstr "Pour modifier l\'ordre des catégories, déplacez les items par glisser-déposer puis cliquez sur le bouton \"Enregistrer l\'ordre des catégories\"."
 
 msgid "Reorder"
@@ -767,5 +781,5 @@
 
 msgid "Entry title"
-msgstr "Titre du billet"
+msgstr "Titre de l'entrée"
 
 msgid "Author"
@@ -793,9 +807,9 @@
 msgstr "Auteur du commentaire :"
 
-msgid "You have one spam comments."
+msgid "You have one spam comment."
 msgstr "Vous avez un commentaire indésirable."
 
 msgid "Show it."
-msgstr "L'afficher"
+msgstr "L'afficher."
 
 #, php-format
@@ -860,8 +874,8 @@
 
 msgid "Following plugins have been installed:"
-msgstr "Les extensions suivantes ont été installées :"
+msgstr "Les plugins suivants ont été installés :"
 
 msgid "Following plugins have not been installed:"
-msgstr "Les extensions suivantes n'ont pas été installées :"
+msgstr "Les plugins suivants n'ont pas été installés :"
 
 #, php-format
@@ -880,5 +894,5 @@
 
 msgid "Some plugins are installed twice:"
-msgstr "Ces extensions sont installées en double :"
+msgstr "Ces plugins sont installés en double :"
 
 msgid "Quick entry"
@@ -1039,5 +1053,5 @@
 #, fuzzy, php-format
 msgid "Path <strong>%s</strong> is not writable."
-msgstr "Le répertoire <strong>%s</strong> n'est pas accessible en écriture."
+msgstr "Le répertoire de cache <strong>%s</strong> n'est pas accessible en écriture."
 
 #, fuzzy
@@ -1124,5 +1138,5 @@
 #, php-format
 msgid "You can change your user language in your <a href=\"%1$s\">preferences</a> or change your blog's main language in your <a href=\"%2$s\">blog settings</a>."
-msgstr "Vous pouvez changer votre langue d'utilisateur dans vos <a href=\"%1$s\">préférences</a> ou changer la langue principale de votre blog dans vos <a href=\"%2$s\">paramètres du blog</a>."
+msgstr "Vous pouvez changer votre langue d'utilisateur dans vos <a href=\"%1$s\">préférences</a> ou changer la langue principale de votre blog dans vos <a href=\"%2$s\">Paramètres du blog</a>."
 
 msgid "Installed languages"
@@ -1192,5 +1206,5 @@
 
 msgid "Media manager"
-msgstr "Gestionnaire de médias"
+msgstr "Médiathèque"
 
 msgid "Go to %s folder"
@@ -1264,4 +1278,7 @@
 msgstr "Taille maximale %s"
 
+msgid "maximum size %s"
+msgstr "taille maximale %s"
+
 msgid "Private"
 msgstr "Privé"
@@ -1379,11 +1396,11 @@
 
 msgid "Show entries containing this media"
-msgstr "Afficher les billets contenant ce média"
+msgstr "Afficher les entrées contenant ce média"
 
 msgid "Entries containing this media"
-msgstr "Billets contenant ce média"
+msgstr "Entrées contenant ce média"
 
 msgid "No entry seems contain this media."
-msgstr "Aucun billet ne semble contenir ce média."
+msgstr "Aucune entrée ne semble contenir ce média."
 
 msgid "Image details"
@@ -1445,57 +1462,57 @@
 
 msgid "No content found on this plugin."
-msgstr "Aucun contenu pour cette extension."
+msgstr "Aucun contenu pour ce plugin."
 
 msgid "Plugin not found"
-msgstr "Extension introuvable"
+msgstr "Plugin introuvable"
 
 msgid "The plugin you reached does not exist or does not have an admin page."
-msgstr "L'extension que vous essayez d'atteindre n'existe pas ou n'a pas de page d'administration."
+msgstr "Le plugin que vous essayez d'atteindre n'existe pas ou n'a pas de page d'administration."
 
 msgid "No such plugin."
-msgstr "Extension inexistante."
+msgstr "Plugin inexistant."
 
 msgid "You don't have permissions to delete this plugin."
-msgstr "Vous n'avez pas les permissions pour effacer cette extension."
+msgstr "Vous n'avez pas les permissions pour supprimer ce plugin."
 
 msgid "You don't have permissions to deactivate this plugin."
-msgstr "Vous n'avez pas les permissions pour désactiver cette extension."
+msgstr "Vous n'avez pas les permissions pour désactiver ce plugin."
 
 msgid "Plugins management"
-msgstr "Gestion des extensions"
+msgstr "Gestion des plugins"
 
 msgid "Plugin has been successfully deleted."
-msgstr "Extension supprimée avec succès."
+msgstr "Plugin supprimé avec succès."
 
 msgid "Plugin has been successfully installed."
-msgstr "Extension installée avec succès."
+msgstr "Plugin installé avec succès."
 
 msgid "Plugin has been successfully upgraded"
-msgstr "Extension mise à jour avec succès."
+msgstr "Plugin mis à jour avec succès."
 
 msgid "Plugins add new functionalities to Dotclear. Here you can activate or deactivate installed plugins."
-msgstr "Les extensions ajoutent de nouvelles fonctionnalités à Dotclear. Ici, vous pouvez activer ou désactiver les extensions installées."
+msgstr "Les plugins ajoutent de nouvelles fonctionnalités à Dotclear. Ici, vous pouvez activer ou désactiver les plugins installés."
 
 #, php-format
 msgid "You can find additional plugins for your blog on %s."
-msgstr "Vous pouvez trouver de nouvelles extensions pour votre blog sur %s."
+msgstr "Vous pouvez trouver d'autres plugins pour votre blog sur %s."
 
 msgid "You can find additional plugins for your blog on %s or using the %s."
-msgstr "Vous pouvez trouver de nouvelles extensions pour votre blog sur %s ou en utilisant l'%s."
+msgstr "Vous pouvez trouver d'autres plugins pour votre blog sur %s ou en utilisant l'%s."
 
 msgid "To install or upgrade a plugin you generally just need to upload it in \"Install or upgrade a plugin\" section."
-msgstr "Tout ce que vous avez à faire pour installer ou mettre à jour une extension est généralement de la déposer dans la section \"Installer ou mettre à jour une extension\"."
+msgstr "Pour installer ou mettre à jour un plugin il suffit de le déposer grâce au formulaire de la section \"Installer ou mettre à jour un plugin\"."
 
 msgid "To install or upgrade a plugin you just need to extract it in your plugins directory."
-msgstr "Tout ce que vous avez à faire pour installer une extension est de l'extraire dans votre répertoire d'extensions."
+msgstr "Pour installer un plugin il suffit de l'extraire dans votre répertoire de plugins."
 
 msgid "Plugins"
-msgstr "Extensions"
+msgstr "Plugins"
 
 msgid "Activated plugins"
-msgstr "Extensions activées"
+msgstr "Plugins activés"
 
 msgid "Plugin"
-msgstr "Extension"
+msgstr "Plugin"
 
 msgid "Version"
@@ -1509,5 +1526,5 @@
 
 msgid "Deactivated plugins"
-msgstr "Extensions désactivées"
+msgstr "Plugins désactivés"
 
 msgid "Activate"
@@ -1515,26 +1532,26 @@
 
 msgid "Install or upgrade a plugin"
-msgstr "Installer ou mettre à jour une extension"
+msgstr "Installer ou mettre à jour un plugin"
 
 msgid "You can install plugins by uploading or downloading zip files."
-msgstr "Vous pouvez installer des extensions en déposant ou téléchargeant des fichiers zip."
+msgstr "Vous pouvez installer des plugins en déposant ou téléchargeant des fichiers zip."
 
 msgid "Plugin zip file:"
-msgstr "Fichier zip de l'extension :"
+msgstr "Fichier zip de du plugin :"
 
 msgid "Upload plugin"
-msgstr "Déposer l'extension"
+msgstr "Déposer le plugin"
 
 msgid "Plugin zip file URL:"
-msgstr "URL du fichier zip de l'extension :"
+msgstr "URL du fichier zip du plugin :"
 
 msgid "Download plugin"
-msgstr "Télécharger l'extension"
+msgstr "Télécharger le plugin"
 
 msgid "To enable this function, please give write access to your plugins directory."
-msgstr "Pour activer cette fonction, donnez un accès en écriture à votre répertoire d'extensions."
+msgstr "Pour activer cette fonction, donnez un accès en écriture à votre répertoire de plugins."
 
 msgid "Plugin from official distribution"
-msgstr "Extension de la distribution officielle"
+msgstr "Plugin de la distribution officielle"
 
 msgid "Add a link"
@@ -1569,5 +1586,5 @@
 
 msgid "Search"
-msgstr "Recherche"
+msgstr "Rechercher"
 
 msgid "cancel"
@@ -1629,5 +1646,5 @@
 
 msgid "Text formating:"
-msgstr "Format du texte :"
+msgstr "Syntaxe de saisie :"
 
 msgid "Convert to XHTML"
@@ -1638,11 +1655,11 @@
 
 msgid "Warning: Comments are not accepted on this blog."
-msgstr "Attention : les commentaires ne sont pas acceptés sur ce blog."
+msgstr "Les commentaires sont fermés sur ce blog pour le moment."
 
 msgid "Warning: Trackbacks are not more accepted for this entry."
 msgstr "Attention : les rétroliens ne sont plus acceptés pour ce billet."
 
-msgid "Warning: Trackbacks are not accepted on this blog."
-msgstr "Attention : les rétroliens ne sont pas acceptés sur ce blog."
+msgid "Trackbacks are not accepted on this blog so far."
+msgstr "Les rétroliens sont fermés sur ce blog pour le moment."
 
 msgid "Selected entry"
@@ -1662,5 +1679,5 @@
 
 msgid "Ping blogs"
-msgstr "Faire des rétroliens"
+msgstr "Envoyer des rétroliens"
 
 msgid "Trackbacks"
@@ -1775,12 +1792,12 @@
 msgstr "Cet utilisateur n'existe pas"
 
-msgid "Change category for entries"
-msgstr "Changer la catégorie des billets"
-
-msgid "Change language for entries"
-msgstr "Changer la langue des billets"
-
-msgid "Change author for entries"
-msgstr "Changer l'auteur des billets"
+msgid "Change category for this selection"
+msgstr "Changer la catégorie de cette sélection"
+
+msgid "Change language for this selection"
+msgstr "Changer la langue de cette sélection"
+
+msgid "Change author for this selection"
+msgstr "Changer l'auteur de cette sélection"
 
 msgid "Author ID:"
@@ -1790,6 +1807,6 @@
 msgstr "Défaut"
 
-msgid "If you want to change your email or password you must provide your current password."
-msgstr "Si vous voulez changer votre adresse email ou votre mot de passe, vous devez indiquer votre mot de passe."
+msgid "If you have changed your email or password you must provide your current password to save these modifications."
+msgstr "Si vous avez modifié votre adresse email ou votre mot de passe, vous devez indiquer votre mot de passe actuel pour enregistrer ces modifications."
 
 msgid "No favorite selected"
@@ -1823,9 +1840,15 @@
 msgstr "Langue de l'utilisateur :"
 
+msgid "Language for my interface:"
+msgstr "Langue de mon interface :"
+
 msgid "User timezone:"
 msgstr "Fuseau horaire de l'utilisateur :"
 
+msgid "My timezone:"
+msgstr "Mon fuseau horaire :"
+
 msgid "If you have changed this user email or password you must provide your current password to save these modifications."
-msgstr "Si vous voulez changer votre adresse email ou votre mot de passe, vous devez indiquer votre mot de passe."
+msgstr "Si vous voulez changer votre adresse email ou votre mot de passe, vous devez indiquer votre mot de passe actuel pour enregistrer ces modifications."
 
 msgid "My options"
@@ -1845,5 +1868,5 @@
 
 msgid "Activate enhanced uploader in media manager"
-msgstr "Activer l'interface avancée du gestionnaire de médias"
+msgstr "Activer l'interface avancée de la médiathèque"
 
 #, fuzzy
@@ -1855,8 +1878,8 @@
 
 msgid "Do not use standard favicon"
-msgstr "Ne pas utiliser le favicon standard"
+msgstr "Ne pas utiliser le favicon standard de Dotclear"
 
 msgid "This will be applied for all users"
-msgstr "Ce choix sera actif pour tous les utilisateurs"
+msgstr "Ce choix sera appliqué pour tous les utilisateurs"
 
 msgid "Accessibility options"
@@ -1864,5 +1887,5 @@
 
 msgid "Disable javascript powered drag and drop for ordering items"
-msgstr "Désactiver le drag and drop javascript pour ordonnancer les éléments"
+msgstr "Désactiver le glisser-déposer pour ordonnancer les éléments"
 
 msgid "Numeric fields will allow to type the elements' ordering number."
@@ -1894,4 +1917,10 @@
 msgstr "Retirer les favoris sélectionnés"
 
+msgid "Your current password:"
+msgstr "Votre mot de passe actuel :"
+
+msgid "Update my profile"
+msgstr "Mettre à jour mon profil"
+
 msgid "Are you sure you want to remove selected favorites?"
 msgstr "Êtes-vous sûr de vouloir retirer les favoris sélectionnés ?"
@@ -1924,9 +1953,9 @@
 msgstr "Requête :"
 
-msgid "Search entries"
-msgstr "Rechercher des billets"
-
-msgid "Search comments"
-msgstr "Rechercher des commentaires"
+msgid "Search in entries"
+msgstr "Rechercher dans les billets"
+
+msgid "Search in comments"
+msgstr "Rechercher dans les commentaires"
 
 msgid "schedule"
@@ -2068,8 +2097,8 @@
 
 msgid "Mandatory for password recovering procedure."
-msgstr "Obligatoire pour la procédure de récupération de mot de passe."
+msgstr "Indispensable pour la procédure de récupération de mot de passe."
 
 msgid "Password change required to connect"
-msgstr "Changement de mot de passe requis pour la connexion"
+msgstr "Changement de mot de passe requis à la prochaine connexion"
 
 msgid "Save and create another"
@@ -2098,5 +2127,5 @@
 
 msgid "Number of entries"
-msgstr "Nombre de billets"
+msgstr "Nombre d'entrées"
 
 msgid "Set permissions"
@@ -2155,4 +2184,7 @@
 msgstr "Aller au menu"
 
+msgid "Go to search"
+msgstr "Aller à la recherche"
+
 msgid "Go to site"
 msgstr "Aller sur le site"
@@ -2178,4 +2210,7 @@
 msgstr "Aide"
 
+msgid "Help about this page"
+msgstr "Aide pour cette page"
+
 msgid "uncover"
 msgstr "dévoiler"
@@ -2187,12 +2222,15 @@
 msgstr "aide"
 
+msgid "Select:"
+msgstr "Sélectionner :"
+
 msgid "no selection"
-msgstr "aucune sélection"
+msgstr "aucun"
 
 msgid "select all"
-msgstr "tout sélectionner"
-
-msgid "invert selection"
-msgstr "inverser la sélection"
+msgstr "tous"
+
+msgid "Invert selection"
+msgstr "Inverser la sélection"
 
 msgid "view entry"
@@ -2214,5 +2252,5 @@
 
 msgid "Users with posts cannot be deleted."
-msgstr "Les utilisateurs ayant écrit des billets ne peuvent être supprimés."
+msgstr "Les utilisateurs ayant écrit des entrées ne peuvent être supprimés."
 
 #, php-format
@@ -2224,4 +2262,8 @@
 msgstr "Êtes-vous certain de vouloir supprimer la catégorie \"%s\" ?"
 
+#, php-format
+msgid "Are you sure you want to delete selected categories (%s)?"
+msgstr "Êtes-vous certain de vouloir supprimer les categories sélectionnées (%s) ?"
+
 msgid "Are you sure you want to reorder all categories?"
 msgstr "Êtes-vous certain de vouloir réinitialiser l'ordre des catégories ?"
@@ -2244,5 +2286,5 @@
 #, php-format
 msgid "Are you sure you want to delete \"%s\" plugin?"
-msgstr "Êtes-vous certain de vouloir supprimer l'extension \"%s\" ?"
+msgstr "Êtes-vous certain de vouloir supprimer le plugin \"%s\" ?"
 
 msgid "Use this theme"
@@ -2263,5 +2305,5 @@
 
 msgid "XHTML markup validator"
-msgstr "Validation XHTML"
+msgstr "Vérifier la validité XHTML"
 
 msgid "XHTML content is valid."
@@ -2428,9 +2470,9 @@
 msgstr "Erreur de file d'attente :"
 
-msgid "&#171;prev."
-msgstr "&#171;préc."
-
-msgid "next&#187;"
-msgstr "suiv.&#187;"
+msgid "&#171; prev."
+msgstr "&#171; préc."
+
+msgid "next &#187;"
+msgstr "suiv. &#187;"
 
 msgid "No entry"
@@ -2691,8 +2733,8 @@
 
 msgid "Cannot deactivate plugin."
-msgstr "L'extension ne peut pas être désactivée."
+msgstr "Le plugin ne peut pas être désactivé."
 
 msgid "Cannot activate plugin."
-msgstr "L'extension ne peut pas être activée."
+msgstr "Le plugin ne peut pas être activé."
 
 #, php-format
@@ -2948,4 +2990,139 @@
 msgstr "Date de publication invalide"
 
+msgid "System settings"
+msgstr "Réglages système"
+
+msgid "Additional plugins"
+msgstr "Modules complémentaires"
+
+msgid "Personal notes:"
+msgstr "Notes personnelles :"
+
+msgid "New user"
+msgstr "Nouvel utilisateur"
+
+msgid "Published"
+msgstr "Publié"
+
+msgid "Unpublished"
+msgstr "Non publié"
+
+msgid "Pending"
+msgstr "En attente"
+
+msgid "Junk"
+msgstr "Indésirable"
+
+msgid "Scheduled"
+msgstr "Programmé"
+
+msgid "Protected"
+msgstr "Protégé"
+
+msgid "Publish"
+msgstr "Publier"
+
+msgid "Unpublish"
+msgstr "Mettre hors ligne"
+
+msgid "Mark as pending"
+msgstr "Mettre en attente"
+
+msgid "Mark as junk"
+msgstr "Mettre en indésirable"
+
+msgid "Next entry"
+msgstr "Billet suivant"
+
+msgid "Previous entry"
+msgstr "Billet précédent"
+
+msgid "Add an introduction to the post."
+msgstr "Ajoute une introduction au billet."
+
+msgid "Add unpublished notes."
+msgstr "Ajoute des notes non publiées."
+
+msgid "Edit basename:"
+msgstr "Modifier l'URL spécifique :"
+
+msgid "Protect with password"
+msgstr "Protéger par un mot de passe"
+
+msgid "Information collected"
+msgstr "Informations recueillies"
+
+msgid "Comment submitted"
+msgstr "Commentaire déposé"
+
+msgid "Entry status"
+msgstr "État du billet"
+
+msgid "Publication date and hour"
+msgstr "Date et heure de publication"
+
+msgid "Text formating"
+msgstr "Syntaxe de saisie"
+
+msgid "Entry lang"
+msgstr "Langue du billet"
+
+msgid "Password"
+msgstr "Mot de passe"
+
+msgid "Edit basename"
+msgstr "URL spécifique"
+
+msgid "Ordering"
+msgstr "Classement"
+
+msgid "Filter posts list"
+msgstr "Filtrer la liste des billets"
+
+msgid "entries per page"
+msgstr "billets par page"
+
+msgid "Show"
+msgstr "Afficher"
+
+msgid "Filter blogs list"
+msgstr "Filtrer la liste des blogs"
+
+msgid "blogs per page"
+msgstr "blogs par page"
+
+msgid "Filter comments and trackbacks list"
+msgstr "Filtrer la liste des commentaires et rétroliens"
+
+msgid "comments per page"
+msgstr "commentaires par page"
+
+msgid "Filter users list"
+msgstr "Filtrer la liste des utilisateurs"
+
+msgid "users per page"
+msgstr "utilisateurs par page"
+
+msgid "Available themes in your installation"
+msgstr "Thèmes disponibles sur votre installation"
+
+msgid "You can also install themes by uploading or downloading zip files."
+msgstr "Vous pouvez aussi installer des thèmes en déposant ou en téléchargeant des fichiers zip."
+
+msgid "Add themes to your installation"
+msgstr "Ajouter des thèmes sur votre installation"
+
+msgid "Select this comment"
+msgstr "Sélectionner ce commentaire"
+
+msgid "Next page"
+msgstr "Page suivante"
+
+msgid "Previous page"
+msgstr "Page précédente"
+
+msgid "Add an introduction to the page."
+msgstr "Ajoute une introduction à la page."
+
 msgid "(No cat)"
 msgstr "(aucune)"
@@ -2969,4 +3146,144 @@
 msgstr "très fort"
 
+msgid "Confirm new password:"
+msgstr "Confirmer le nouveau mot de passe :"
+
+msgid "Not selected"
+msgstr "Non sélectionné"
+
+msgid "Back to comments list"
+msgstr "Retour à la liste des commentaires"
+
+msgid "The current blog cannot be deleted."
+msgstr "Le blog courant ne peut être détruit."
+
+msgid "Only superadmin can delete a blog."
+msgstr "Seul un superadministrateur peut supprimer un blog."
+
+msgid "Invalid publication date"
+msgstr "Date de publication invalide."
+
+msgid "Image alignment:"
+msgstr "Alignement de l'image :"
+
+msgid "Finish the update"
+msgstr "Finir la mise à jour"
+
+msgid "Information about this version"
+msgstr "Informations sur cette version"
+
+msgid "Updates and modifications"
+msgstr "Mises à jour et modifications"
+
+msgid "Back to user profile"
+msgstr "Retour au profil utilisateur"
+
+msgid "Back to Blog appearance"
+msgstr "Retour à Apparence du blog"
+
+msgid "Edit"
+msgstr "Modifier"
+
+msgid "Display options"
+msgstr "Options d\'affichage"
+
+msgid "Apply filters and display options"
+msgstr "Appliquer les filtres et options d\'affichage"
+
+msgid "Back to entries list"
+msgstr "Retour à la liste des billets"
+
+msgid "New author (author ID):"
+msgstr "Nouvel auteur (identifiant utilisateur) :"
+
+msgid "Hidden"
+msgstr "Masqué"
+
+msgid "Create a new category for the post(s)"
+msgstr "Créer une nouvelle catégorie pour ce(s) billet(s)"
+
 msgid "This category will be created when you will save your post."
 msgstr "Cette catégorie sera créée lorsque vous enregistrerez votre billet."
+
+msgid "Category which will receive entries of deleted categories:"
+msgstr "Catégorie d'accueil pour les billets des catégories supprimées :"
+
+msgid "Delete selected categories"
+msgstr "Supprimer les catégories sélectionnées"
+
+msgid "To rearrange categories order, change position number and click on “Save categories order”."
+msgstr "Pour changer l'ordre des catégories, modifier leur numéro de position et cliquez sur “Enregistrer l'ordre des catégories”."
+
+msgid "Reorder all categories on the top level and delete selected categories"
+msgstr "Replacer toutes les catégories au premier niveau et supprimer les catégories sélectionnées"
+
+#test tableau commentaires
+
+msgid "trackback from"
+msgstr "rétrolien de"
+
+msgid "comment from"
+msgstr "commentaire de"
+
+msgid "Type and author"
+msgstr "Type et auteur"
+
+msgid "Edit"
+msgstr "Modifier"
+
+msgid "Select"
+msgstr "Sélectionner"
+
+msgid "Click here to unlock the field"
+msgstr "Cliquez ici pour déverrouiller ce champ"
+
+msgid "User profile"
+msgstr "Profil utilisateur"
+
+msgid "User ID:"
+msgstr "Identifiant (login) :"
+
+msgid "%s is super admin (all rights on all blogs)."
+msgstr "%s est super administrateur (tous les droits sur tous les blogs)."
+
+msgid "Interface"
+msgstr "Interface"
+
+msgid "Edition"
+msgstr "Édition"
+
+msgid "Other options"
+msgstr "Autres options"
+
+msgid "No permissions so far."
+msgstr "Aucune permission pour le moment."
+
+msgid "Accessibility"
+msgstr "Accessibilité"
+
+msgid "Dashboard and menu"
+msgstr "Tableau de bord et menu"
+
+msgid "Dashboard modules"
+msgstr "Modules du tableau de bord"
+
+msgid "If checked, numeric fields will allow to type the elements' ordering number."
+msgstr "Si cette option est cochée, des champs numérique permettront l'ordonnancement des éléments."
+
+msgid "Save my options"
+msgstr "Enregistrer mes options"
+
+msgid "Blog id"
+msgstr "Identifiant"
+
+msgid "Edit blog settings for %s"
+msgstr "Modifier les paramètres de %s"
+
+msgid "Edit blog settings"
+msgstr "Modifier les paramètres du blog"
+
+msgid "Edit the %1$s from %2$s"
+msgstr "Modifier le %1$s de %2$s"
+
+msgid "Backup"
+msgstr "Sauvegarde"
Index: locales/fr/plugins.po
===================================================================
--- locales/fr/plugins.po	(revision 1445)
+++ locales/fr/plugins.po	(revision 1669)
@@ -42,5 +42,5 @@
 
 msgid "blog settings"
-msgstr "Réglages du blog"
+msgstr "paramètres du blog"
 
 msgid "Value"
@@ -56,6 +56,9 @@
 msgstr "Ok"
 
+msgid "Global settings"
+msgstr "Réglages généraux"
+
 msgid "global settings"
-msgstr "Réglages généraux"
+msgstr "réglages généraux"
 
 msgid "Akismet"
@@ -238,6 +241,6 @@
 
 #, php-format
-msgid "%s configuration"
-msgstr "configuration %s"
+msgid "%s filter configuration"
+msgstr "Configuration du filtre %s"
 
 msgid "Information"
@@ -266,5 +269,5 @@
 
 msgid "Filters configuration has been successfully saved."
-msgstr "La configurations des filtres a été enregistrée avec succès."
+msgstr "La configuration des filtres a été enregistrée avec succès."
 
 msgid "Available spam filters"
@@ -301,9 +304,12 @@
 msgstr "Annexes"
 
+msgid "Attachments (%d)"
+msgstr "Annexes (%s)"
+
 msgid "remove"
 msgstr "supprimer"
 
 msgid "No attachment."
-msgstr "Pas de fichier attaché"
+msgstr "Pas de fichier attaché."
 
 msgid "Add files to this entry"
@@ -500,5 +506,5 @@
 
 msgid "Import"
-msgstr "Importation"
+msgstr "Importer"
 
 msgid "Blowup Config"
@@ -803,5 +809,5 @@
 
 msgid "Compress file"
-msgstr "Compresse le fichier"
+msgstr "Compresser le fichier"
 
 msgid "You may also want to download your media directory as a zip file"
@@ -853,5 +859,5 @@
 msgstr ""
 "Notez que cela supprimera les catégories, liste de liens, billets et "
-"commentaires actuels de votre blog courant. "
+"commentaires actuels du blog courant. "
 
 msgid "Depending on the size of your blog, it could take a few minutes."
@@ -910,5 +916,5 @@
 msgstr ""
 "Notez que Dotclear a un nouveau schéma d'URL. Vous pouvez éviter les liens "
-"brisés en installant l'extension <a href=\"%s\">DC1 redirect</a> et en "
+"brisés en installant le plugin <a href=\"%s\">DC1 redirect</a> et en "
 "l'activant dans la configuration de votre blog."
 
@@ -961,8 +967,8 @@
 #, php-format
 msgid ""
-"This will import a single blog backup as new content in the current blog: %s."
+"This will import a single blog backup as new content in the current blog: <strong>%s</strong>."
 msgstr ""
 "Cela importera une sauvegarde d'un blog comme nouveau contenu du blog "
-"courant : %s."
+"courant : <strong>%s</strong>."
 
 msgid "Upload a backup file"
@@ -971,5 +977,5 @@
 msgid "or pick up a local file in your public directory"
 msgstr ""
-"ou sélectionnez un fichier local présent dans votre répertoire de média"
+"ou sélectionnez un fichier local présent dans votre répertoire de médias"
 
 msgid "This will reset all the content of your database, except users."
@@ -1015,5 +1021,5 @@
 msgstr ""
 "La gestion des catégories chez WordPress et Dotclear est tout à fait "
-"différente. Vous pouvez assigner plusieurs catégories à un seul poste dans "
+"différente. Vous pouvez assigner plusieurs catégories à un seul billet dans "
 "WordPress. Dans le monde Dotclear, nous le voyons davantage comme « une "
 "catégorie, plusieurs mots-clés ». Par conséquent Dotclear peut seulement "
@@ -1024,6 +1030,6 @@
 msgid ""
 "On the other hand, in WordPress, a post can not be uncategorized, and a "
-"default installation has a first category labelised <i>\"Uncategorized\"</"
-"i>. If you did not change that category, you can just ignore it while "
+"default installation has a first category labelised <i>\"Uncategorized\"</i>."
+"If you did not change that category, you can just ignore it while "
 "importing your blog, as Dotclear allows you to actually keep your posts "
 "uncategorized."
@@ -1131,5 +1137,5 @@
 
 msgid "Vacuum tables"
-msgstr "Optimiser les tables"
+msgstr "Vidage des tables"
 
 msgid "Counters"
@@ -1137,5 +1143,5 @@
 
 msgid "Reset comments and ping counters"
-msgstr "Recalculer les compteurs de commentaires et de signalements"
+msgstr "Remet à zéro les compteurs de commentaires et de signalements"
 
 msgid "Search engine index"
@@ -1146,8 +1152,8 @@
 
 msgid "Index all posts"
-msgstr "Indexer tous les billets"
+msgstr "Indexation de tous les billets"
 
 msgid "Index all comments"
-msgstr "Indexer tous les commentaires"
+msgstr "Indexation de tous les commentaires"
 
 msgid "Vacuum logs"
@@ -1155,5 +1161,5 @@
 
 msgid "Delete all logs"
-msgstr "Supprimer tous les journaux"
+msgstr "Suppression de tous les journaux"
 
 msgid "Empty templates cache directory"
@@ -1161,5 +1167,5 @@
 
 msgid "Empty directory"
-msgstr "Vider le répertoire"
+msgstr "Vidage du répertoire"
 
 msgid "Pages"
@@ -1247,17 +1253,17 @@
 
 msgid "Go to this page on the site"
-msgstr "Aller sur cette page"
-
-msgid "Page status:"
-msgstr "État de la page :"
-
-msgid "Page position:"
-msgstr "Position de la page :"
-
-msgid "Page lang:"
-msgstr "Langue de la page :"
-
-msgid "Page password:"
-msgstr "Mot de passe de la page :"
+msgstr "Voir cette page sur le site"
+
+msgid "Page status"
+msgstr "État de la page"
+
+msgid "Page position"
+msgstr "Position de la page"
+
+msgid "Page lang"
+msgstr "Langue de la page"
+
+msgid "Page password"
+msgstr "Mot de passe de la page"
 
 msgid ""
@@ -1283,5 +1289,5 @@
 
 msgid "Pings"
-msgstr "Signalements"
+msgstr "Signalements (pings)"
 
 msgid "Ping services"
@@ -1295,5 +1301,5 @@
 
 msgid "Activate pings extension"
-msgstr "Activer l'extension de signalement"
+msgstr "Activer le plugin de signalement"
 
 msgid "Service name:"
@@ -1447,6 +1453,6 @@
 msgstr "Êtes-vous sûr de vouloir supprimer les items de menu sélectionnés ?"
 
-msgid "Currently no menu items"
-msgstr "Aucun item de menu pour l'instant"
+msgid "No menu items so far."
+msgstr "Aucun item de menu pour l'instant."
 
 msgid "Tags:"
@@ -1455,5 +1461,5 @@
 #, php-format
 msgid "Are you sure you want to remove this %s?"
-msgstr "Êtes-vous sûr de vouloir retirer ce %s ?"
+msgstr "Êtes-vous sûr de vouloir supprimer ce %s ?"
 
 #, php-format
@@ -1543,5 +1549,5 @@
 
 msgid "Actions for this tag"
-msgstr "Actions pour ce mot-clé"
+msgstr "Actions sur ce mot-clé"
 
 msgid "Edit tag name:"
@@ -1669,4 +1675,7 @@
 msgstr "Avec le nombre de billets"
 
+msgid "Include empty categories"
+msgstr "Inclure les catégories vides"
+
 msgid "Subscribe links"
 msgstr "Liens de souscription"
@@ -1738,5 +1747,5 @@
 
 msgid "Are you sure you want to reset sidebars?"
-msgstr "Êtes-vous sûr de vouloir remettre à zéro les volets ?"
+msgstr "Êtes-vous sûr de vouloir réinitialiser les volets ?"
 
 msgid "Available widgets"
@@ -1756,11 +1765,11 @@
 
 msgid "Custom sidebar"
-msgstr "Bandeau supplémentaire"
+msgstr "Volet supplémentaire"
 
 msgid "Update sidebars"
-msgstr "Mettre à jour les bandeaux"
+msgstr "Mettre à jour les volets"
 
 msgid "Reset sidebars"
-msgstr "Réinitialiser les bandeaux"
+msgstr "Réinitialiser les volets"
 
 msgid "Use of widgets"
@@ -1783,8 +1792,8 @@
 msgid ""
 "Once included in a sidebar, widgets have configuration options that you can "
-"reach by clicking on the + sign next to their name."
+"reach by clicking on the arrow next to their name."
 msgstr ""
 "Une fois inclus dans un bandeau, les widgets ont généralement des options "
-"que vous pouvez configurer. Cliquez sur le signe + à côté de leur nom pour y "
+"que vous pouvez configurer. Cliquez sur la flèche à côté de leur nom pour y "
 "accéder."
 
@@ -1919,2 +1928,61 @@
 #~ msgid "The backup file does not appear to be well formed."
 #~ msgstr "Le fichier de sauvegarde semble mal formaté."
+
+msgid "Settings for %s"
+msgstr "Réglages pour %s"
+
+msgid "Settings for %s"
+msgstr "Réglages pour %s"
+
+msgid "User preferences"
+msgstr "Préférences utilisateur"
+
+msgid "Global preferences"
+msgstr "Préférences globales"
+
+msgid "Edit theme files"
+msgstr "Modifier les fichiers du thème"
+
+msgid "Blog settings"
+msgstr "Paramètres du blog"
+
+msgid "Move widgets from this list to one of the sidebars."
+msgstr "Déplacez des widgets de cette liste vers l'un des volets."
+
+msgid "Short"
+msgstr "Court"
+
+msgid "Extended"
+msgstr "Étendu"
+
+msgid "List of entries with the tag “%s”"
+msgstr "Liste des billets avec le mot-clé “%s”"
+
+msgid "RSS or Atom feed import"
+msgstr "Importation d'un flux RSS ou Atom"
+
+msgid "Add a feed content to the current blog: <strong>%s</strong>."
+msgstr "Ajouter les contenus d'un flux au blog courant : <strong>%s</strong>."
+
+msgid "Add a feed content to the blog."
+msgstr "Ajouter les contenus d'un flux au blog."
+
+#, php-format
+msgid ""
+"Import the content of a Dotclear 1.2\'s blog in the current "
+"blog: %s."
+msgstr ""
+"Importer le contenu d'un blog Dotclear 1.2 comme nouveau contenu dans le blog "
+"courant : %s."
+
+msgid "Are you sure you want to remove tag: “%s”?"
+msgstr "Êtes-vous sûr de vouloir supprimer le mot-clé “%s” ?"
+
+msgid "Syntax color for theme editor"
+msgstr "Coloration syntaxique de l'éditeur de thème"
+
+msgid "Hide in widget Pages"
+msgstr "Ne pas lister dans le widget Pages"
+
+msgid "Drag widgets here to remove them from this sidebar."
+msgstr "Glisser les widgets ici pour les retirer du volet."
Index: locales/fr/resources.php
===================================================================
--- locales/fr/resources.php	(revision 1179)
+++ locales/fr/resources.php	(revision 1343)
@@ -15,9 +15,9 @@
 
 $__resources['doc'] = array(
-	"Accueil de l'aide Dotclear 2" => 'http://doc.dotclear.net/2.0',
-	'Présentation de Dotclear 2' => 'http://doc.dotclear.net/2.0/overview/tour',
+	"Accueil de l'aide Dotclear" => 'http://fr.dotclear.org/documentation/2.0',
+	'Présentation de Dotclear' => 'http://doc.dotclear.net/2.0/overview/tour',
 	"Manuel de l'utilisateur" => 'http://doc.dotclear.net/2.0/usage',
 	"Guide d'installation et d'administration" => 'http://doc.dotclear.net/2.0/admin',
-	"Forum de support de Dotclear 2" => 'http://forum.dotclear.net/'
+	"Forum de support de Dotclear" => 'http://forum.dotclear.net/'
 );
 ?>
Index: locales/hu/help/blowupConfig.html
===================================================================
--- locales/hu/help/blowupConfig.html	(revision 1264)
+++ locales/hu/help/blowupConfig.html	(revision 1280)
@@ -35,5 +35,5 @@
 <p>You can choose a header image among the list to use in place of the default one.</p>
 
-<p>When you choose "Custom..." in the image list, you will be able to upload your own image. <strong>The image file must be in JPG or PNG format and must be precisely 800px wide.</strong></p>
+<p>When you choose "Custom..." in the image list, you will be able to upload your own image. <strong>The image file must be in JPG or PNG format and must be precisely 800px wide.</strong>
 
 <p>If you upload a JPG image, a border will be added to the image, which is not the case with PNG images (the transparency of which will also be kept).</p>
Index: locales/hu/main.po
===================================================================
--- locales/hu/main.po	(revision 1592)
+++ locales/hu/main.po	(revision 1637)
@@ -219,5 +219,5 @@
 
 #, fuzzy
-msgid "That blog Id is already in use."
+msgid "This blog ID is already used."
 msgstr "A DotClear már telepítve van."
 
@@ -465,5 +465,5 @@
 
 #, php-format
-msgid "You are currently using \"%s\""
+msgid "You are currently using <strong>%s</strong>"
 msgstr "A \"%s\"-t használod"
 
@@ -598,5 +598,5 @@
 
 #, fuzzy
-msgid "No category yet."
+msgid "No category so far."
 msgstr "Kategória létrehozása"
 
@@ -787,5 +787,5 @@
 msgstr "Megjegyzés szerzője:"
 
-msgid "You have one spam comments."
+msgid "You have one spam comment."
 msgstr "Van egy spam megjegyzésed."
 
@@ -1790,8 +1790,8 @@
 msgstr ""
 
-msgid "Change category for entries"
+msgid "Change category for this selection"
 msgstr "A bejegyzések kategóriája nem létezik"
 
-msgid "Change author for entries"
+msgid "Change author for this selection"
 msgstr "A szerző megváltoztatása"
 
@@ -2181,5 +2181,5 @@
 msgstr "mindet"
 
-msgid "invert selection"
+msgid "Invert selection"
 msgstr "ellenkezőket"
 
Index: locales/hu/plugins.po
===================================================================
--- locales/hu/plugins.po	(revision 1126)
+++ locales/hu/plugins.po	(revision 1668)
@@ -845,5 +845,5 @@
 
 #, php-format
-msgid "This will import a single blog backup as new content in the current blog: %s."
+msgid "This will import a single blog backup as new content in the current blog: <strong>%s</strong>."
 msgstr "Ezzel egy egyedüli blogot fogok importálni új tartalomként ide: %s"
 
@@ -1077,14 +1077,14 @@
 msgstr ""
 
-msgid "Page status:"
+msgid "Page status"
 msgstr "Oldal állapota:"
 
-msgid "Page position:"
+msgid "Page position"
 msgstr "Oldal pozíciója:"
 
-msgid "Page lang:"
+msgid "Page lang"
 msgstr "Oldal nyelve:"
 
-msgid "Page password:"
+msgid "Page password"
 msgstr "Oldal jelszava:"
 
@@ -1268,5 +1268,5 @@
 msgstr "Biztosan törölni szerenéd a kiválasztott hivatkozásokat?"
 
-msgid "Currently no menu items"
+msgid "No menu items so far."
 msgstr ""
 
@@ -1582,5 +1582,5 @@
 msgstr ""
 
-msgid "Once included in a sidebar, widgets have configuration options that you can reach by clicking on the + sign next to their name."
+msgid "Once included in a sidebar, widgets have configuration options that you can reach by clicking on the arrow next to their name."
 msgstr ""
 
Index: locales/it/help/blowupConfig.html
===================================================================
--- locales/it/help/blowupConfig.html	(revision 1264)
+++ locales/it/help/blowupConfig.html	(revision 1280)
@@ -35,5 +35,5 @@
 <p>You can choose a header image among the list to use in place of the default one.</p>
 
-<p>When you choose "Custom..." in the image list, you will be able to upload your own image. <strong>The image file must be in JPG or PNG format and must be precisely 800px wide.</strong></p>
+<p>When you choose "Custom..." in the image list, you will be able to upload your own image. <strong>The image file must be in JPG or PNG format and must be precisely 800px wide.</strong>
 
 <p>If you upload a JPG image, a border will be added to the image, which is not the case with PNG images (the transparency of which will also be kept).</p>
Index: locales/it/main.po
===================================================================
--- locales/it/main.po	(revision 1592)
+++ locales/it/main.po	(revision 1637)
@@ -212,5 +212,5 @@
 msgstr "Impedisci ai motori di ricerca e ai sistemi di archiviazione di indicizzare o salvare il contenuto del blog."
 
-msgid "That blog Id is already in use."
+msgid "This blog ID is already used."
 msgstr "L'ID del blog è già in uso."
 
@@ -456,5 +456,5 @@
 
 #, php-format
-msgid "You are currently using \"%s\""
+msgid "You are currently using <strong>%s</strong>"
 msgstr "Attualmente è in uso \"%s\""
 
@@ -584,5 +584,5 @@
 msgstr "La categoria è stata spostata correttamente."
 
-msgid "No category yet."
+msgid "No category so far."
 msgstr "Nessuna categoria."
 
@@ -763,5 +763,5 @@
 msgstr "Autore del commento:"
 
-msgid "You have one spam comments."
+msgid "You have one spam comment."
 msgstr "È presente un commento di spam."
 
@@ -1740,8 +1740,8 @@
 msgstr "Questo utente non esiste."
 
-msgid "Change category for entries"
+msgid "Change category for this selection"
 msgstr "Cambia categoria degli articoli"
 
-msgid "Change author for entries"
+msgid "Change author for this selection"
 msgstr "Cambia autore degli articoli"
 
@@ -2125,5 +2125,5 @@
 msgstr "seleziona tutto"
 
-msgid "invert selection"
+msgid "Invert selection"
 msgstr "inverti selezione"
 
Index: locales/it/plugins.po
===================================================================
--- locales/it/plugins.po	(revision 1126)
+++ locales/it/plugins.po	(revision 1668)
@@ -835,5 +835,5 @@
 
 #, php-format
-msgid "This will import a single blog backup as new content in the current blog: %s."
+msgid "This will import a single blog backup as new content in the current blog: <strong>%s</strong>."
 msgstr ""
 
@@ -1056,14 +1056,14 @@
 msgstr ""
 
-msgid "Page status:"
-msgstr ""
-
-msgid "Page position:"
-msgstr ""
-
-msgid "Page lang:"
-msgstr ""
-
-msgid "Page password:"
+msgid "Page status"
+msgstr ""
+
+msgid "Page position"
+msgstr ""
+
+msgid "Page lang"
+msgstr ""
+
+msgid "Page password"
 msgstr ""
 
@@ -1230,5 +1230,5 @@
 msgstr ""
 
-msgid "Currently no menu items"
+msgid "No menu items so far."
 msgstr ""
 
@@ -1529,5 +1529,5 @@
 msgstr ""
 
-msgid "Once included in a sidebar, widgets have configuration options that you can reach by clicking on the + sign next to their name."
+msgid "Once included in a sidebar, widgets have configuration options that you can reach by clicking on the arrow next to their name."
 msgstr ""
 
Index: locales/ja/help/blowupConfig.html
===================================================================
--- locales/ja/help/blowupConfig.html	(revision 1264)
+++ locales/ja/help/blowupConfig.html	(revision 1280)
@@ -35,5 +35,5 @@
 <p>デフォルトで指定されているものの代わりに、リストからヘッダ画像を選ぶことができます。</p>
 
-<p>画像リストで「カスタム...」を選んだ場合、独自の画像をアップロードすることができます。 <strong>画像ファイルは JPG または PNG フォーマットで、横幅が正確に800ピクセルである必要があります。</strong></p>
+<p>画像リストで「カスタム...」を選んだ場合、独自の画像をアップロードすることができます。 <strong>画像ファイルは JPG または PNG フォーマットで、横幅が正確に800ピクセルである必要があります。</strong>
 
 <p>JPG画像がアップロードされた場合、画像に境界線が付加されます。 PNG画像の場合には付加されず、透過性も維持されます。</p>
Index: locales/ja/main.po
===================================================================
--- locales/ja/main.po	(revision 1592)
+++ locales/ja/main.po	(revision 1637)
@@ -222,5 +222,5 @@
 
 #, fuzzy
-msgid "That blog Id is already in use."
+msgid "This blog ID is already used."
 msgstr "Dotclear はすでにインストールされています。"
 
@@ -465,5 +465,5 @@
 
 #, php-format
-msgid "You are currently using \"%s\""
+msgid "You are currently using <strong>%s</strong>"
 msgstr "現在使用中のテーマ： %s"
 
@@ -593,5 +593,5 @@
 msgstr "カテゴリは正常に移動されました。"
 
-msgid "No category yet."
+msgid "No category so far."
 msgstr "カテゴリはまだありません。"
 
@@ -772,5 +772,5 @@
 msgstr "コメントの投稿者："
 
-msgid "You have one spam comments."
+msgid "You have one spam comment."
 msgstr "1 のスパムコメントがあります。"
 
@@ -1765,8 +1765,8 @@
 msgstr "このユーザは存在しません"
 
-msgid "Change category for entries"
+msgid "Change category for this selection"
 msgstr "エントリのカテゴリを変更"
 
-msgid "Change author for entries"
+msgid "Change author for this selection"
 msgstr "エントリの投稿者を変更"
 
@@ -2154,5 +2154,5 @@
 msgstr "すべてを選択"
 
-msgid "invert selection"
+msgid "Invert selection"
 msgstr "選択を反転"
 
Index: locales/ja/plugins.po
===================================================================
--- locales/ja/plugins.po	(revision 1126)
+++ locales/ja/plugins.po	(revision 1668)
@@ -846,5 +846,5 @@
 
 #, php-format
-msgid "This will import a single blog backup as new content in the current blog: %s."
+msgid "This will import a single blog backup as new content in the current blog: <strong>%s</strong>."
 msgstr "これは単独ブログのバックアップを、現在のブログ「%s」の新しいコンテンツとしてインポートします。"
 
@@ -1072,14 +1072,14 @@
 msgstr ""
 
-msgid "Page status:"
+msgid "Page status"
 msgstr "ページの状態："
 
-msgid "Page position:"
+msgid "Page position"
 msgstr "ページの位置："
 
-msgid "Page lang:"
+msgid "Page lang"
 msgstr "ページの言語："
 
-msgid "Page password:"
+msgid "Page password"
 msgstr "ページのパスワード："
 
@@ -1263,5 +1263,5 @@
 msgstr "本当に、選択されたリンクを削除してもよろしいですか？"
 
-msgid "Currently no menu items"
+msgid "No menu items so far."
 msgstr ""
 
@@ -1576,5 +1576,5 @@
 msgstr ""
 
-msgid "Once included in a sidebar, widgets have configuration options that you can reach by clicking on the + sign next to their name."
+msgid "Once included in a sidebar, widgets have configuration options that you can reach by clicking on the arrow next to their name."
 msgstr ""
 
Index: locales/ko/help/blowupConfig.html
===================================================================
--- locales/ko/help/blowupConfig.html	(revision 1264)
+++ locales/ko/help/blowupConfig.html	(revision 1280)
@@ -34,5 +34,5 @@
 <p>기본이미지 대신, 목록에 있는 머리글 이미지를 쓰실 수 있습니다.</p>
 
-<p>이미지 목록에서 "개성에 맞게..."를 선택하시면, 당신 자신이 보유한 이미지를 올릴 수 있습니다. <strong>이미지 파일은 JPG나 PNG 포맷이어야하고 폭은 정확히 800px 이어야 합니다.</strong></p>
+<p>이미지 목록에서 "개성에 맞게..."를 선택하시면, 당신 자신이 보유한 이미지를 올릴 수 있습니다. <strong>이미지 파일은 JPG나 PNG 포맷이어야하고 폭은 정확히 800px 이어야 합니다.</strong>
 
 <p>JPG 이미지를 올리실 때는, 윤곽선이 추가됩니다. PNG 이미지의 경우는 해당되지 않습니다. (PNG 이미지의 투명도도 또한 유지됩니다.)</p>
Index: locales/ko/main.po
===================================================================
--- locales/ko/main.po	(revision 1592)
+++ locales/ko/main.po	(revision 1637)
@@ -220,5 +220,5 @@
 
 #, fuzzy
-msgid "That blog Id is already in use."
+msgid "This blog ID is already used."
 msgstr "Dotclear가 이미 설치되어 있습니다."
 
@@ -464,5 +464,5 @@
 
 #, php-format
-msgid "You are currently using \"%s\""
+msgid "You are currently using <strong>%s</strong>"
 msgstr "현재 사용 중인 테마 : \"%s\""
 
@@ -592,5 +592,5 @@
 msgstr "분류 이동 완료."
 
-msgid "No category yet."
+msgid "No category so far."
 msgstr "분류가 아직 없습니다."
 
@@ -771,5 +771,5 @@
 msgstr "댓글 글쓴이 :"
 
-msgid "You have one spam comments."
+msgid "You have one spam comment."
 msgstr "스팸댓글이 하나 있습니다."
 
@@ -1765,8 +1765,8 @@
 msgstr "이 사용자는 존재하지 않습니다."
 
-msgid "Change category for entries"
+msgid "Change category for this selection"
 msgstr "글꼭지들의 분류 변경"
 
-msgid "Change author for entries"
+msgid "Change author for this selection"
 msgstr "글꼭지들의 글쓴이 변경"
 
@@ -2154,5 +2154,5 @@
 msgstr "모두 선택하기"
 
-msgid "invert selection"
+msgid "Invert selection"
 msgstr "선택사항 뒤집기"
 
Index: locales/ko/plugins.po
===================================================================
--- locales/ko/plugins.po	(revision 1126)
+++ locales/ko/plugins.po	(revision 1668)
@@ -846,5 +846,5 @@
 
 #, php-format
-msgid "This will import a single blog backup as new content in the current blog: %s."
+msgid "This will import a single blog backup as new content in the current blog: <strong>%s</strong>."
 msgstr "이 과정은, 백업된 단일 블로그 내용을 현재 블로그 (%s) 의 새 내용으로 가져옵니다."
 
@@ -1079,14 +1079,14 @@
 msgstr ""
 
-msgid "Page status:"
+msgid "Page status"
 msgstr "페이지 공개상태 :"
 
-msgid "Page position:"
+msgid "Page position"
 msgstr "페이지 위치 :"
 
-msgid "Page lang:"
+msgid "Page lang"
 msgstr "페이지 언어 :"
 
-msgid "Page password:"
+msgid "Page password"
 msgstr "페이지 비밀번호 :"
 
@@ -1270,5 +1270,5 @@
 msgstr "선택된 링크들을 삭제하시려는 게 확실합니까 ?"
 
-msgid "Currently no menu items"
+msgid "No menu items so far."
 msgstr ""
 
@@ -1583,5 +1583,5 @@
 msgstr ""
 
-msgid "Once included in a sidebar, widgets have configuration options that you can reach by clicking on the + sign next to their name."
+msgid "Once included in a sidebar, widgets have configuration options that you can reach by clicking on the arrow next to their name."
 msgstr ""
 
Index: locales/lt/help/blowupConfig.html
===================================================================
--- locales/lt/help/blowupConfig.html	(revision 1264)
+++ locales/lt/help/blowupConfig.html	(revision 1280)
@@ -35,5 +35,5 @@
 <p>Du kannst ein Bild Deiner Wahl statt des Standardbildes einsetzen.</p>
 
-<p>Wenn Du  "Benutzerdefiniert..." in der Bilderliste ausw&auml;hlst, dann hast Du die M&ouml;glichkeit, Dein eigenes Bild upzuloaden. <strong>Das Dateiformat muss entweder JPG der PNG sein und es muss 800px breit sein.</strong></p>
+<p>Wenn Du  "Benutzerdefiniert..." in der Bilderliste ausw&auml;hlst, dann hast Du die M&ouml;glichkeit, Dein eigenes Bild upzuloaden. <strong>Das Dateiformat muss entweder JPG der PNG sein und es muss 800px breit sein.</strong>
 
 <p>Wenn Du ein JPG-Bild uploadest, dann wird automatisch ein Rahmen um das Bild gesetzt. Dies geschieht nicht bei der Verwendung eines PNG-Bildes und die Transparenz wird ebenfalls beibehalten.</p>
Index: locales/lt/main.po
===================================================================
--- locales/lt/main.po	(revision 1592)
+++ locales/lt/main.po	(revision 1637)
@@ -193,5 +193,5 @@
 msgstr "Nenoriu, kad paieškos sistemos ir archyvatoriai indeksuotų ir archyvuotų mano blogo turinio."
 
-msgid "That blog Id is already in use."
+msgid "This blog ID is already used."
 msgstr "Šito blogo ID jau yra naudojamas."
 
@@ -432,5 +432,5 @@
 
 #, php-format
-msgid "You are currently using \"%s\""
+msgid "You are currently using <strong>%s</strong>"
 msgstr "Šiuo metu jūs naudojate \"%s\""
 
@@ -554,5 +554,5 @@
 msgstr "Kategorija sėkmingai perkelta."
 
-msgid "No category yet."
+msgid "No category so far."
 msgstr "Kategorijos kolkas nėra."
 
@@ -742,5 +742,5 @@
 msgstr "Komentaro autorius:"
 
-msgid "You have one spam comments."
+msgid "You have one spam comment."
 msgstr "Turite vieną spamo komentarą."
 
@@ -1681,8 +1681,8 @@
 msgstr "Šis dalyvis neegzistuoja"
 
-msgid "Change category for entries"
+msgid "Change category for this selection"
 msgstr "Keisti įrašų kategoriją"
 
-msgid "Change author for entries"
+msgid "Change author for this selection"
 msgstr "Keisti įrašų autorių"
 
@@ -1935,5 +1935,5 @@
 msgstr "pasirinkti viską"
 
-msgid "invert selection"
+msgid "Invert selection"
 msgstr "atvirkščias pasirinkimas"
 
Index: locales/lt/plugins.po
===================================================================
--- locales/lt/plugins.po	(revision 1126)
+++ locales/lt/plugins.po	(revision 1668)
@@ -808,5 +808,5 @@
 
 #, php-format
-msgid "This will import a single blog backup as new content in the current blog: %s."
+msgid "This will import a single blog backup as new content in the current blog: <strong>%s</strong>."
 msgstr "Importuojama viena blogo atsarginė kopija kaip naujas turinys jūsų bloge: %s."
 
@@ -1024,14 +1024,14 @@
 msgstr "Peržiūrėti puslapį"
 
-msgid "Page status:"
+msgid "Page status"
 msgstr "Puslapio statusas:"
 
-msgid "Page position:"
+msgid "Page position"
 msgstr "Puslapio pozicija:"
 
-msgid "Page lang:"
+msgid "Page lang"
 msgstr "Puslapio kalba:"
 
-msgid "Page password:"
+msgid "Page password"
 msgstr "Puslapio slaptažodis:"
 
Index: locales/nl/help/blowupConfig.html
===================================================================
--- locales/nl/help/blowupConfig.html	(revision 1264)
+++ locales/nl/help/blowupConfig.html	(revision 1280)
@@ -35,5 +35,5 @@
 <p>You can choose a header image among the list to use in place of the default one.</p>
 
-<p>When you choose "Custom..." in the image list, you will be able to upload your own image. <strong>The image file must be in JPG or PNG format and must be precisely 800px wide.</strong></p>
+<p>When you choose "Custom..." in the image list, you will be able to upload your own image. <strong>The image file must be in JPG or PNG format and must be precisely 800px wide.</strong>
 
 <p>If you upload a JPG image, a border will be added to the image, which is not the case with PNG images (the transparency of which will also be kept).</p>
Index: locales/nl/main.po
===================================================================
--- locales/nl/main.po	(revision 1592)
+++ locales/nl/main.po	(revision 1637)
@@ -211,5 +211,5 @@
 msgstr "Zoekmachines mogen mijn blog niet indexeren en archiveren."
 
-msgid "That blog Id is already in use."
+msgid "This blog ID is already used."
 msgstr ""
 
@@ -454,5 +454,5 @@
 
 #, php-format
-msgid "You are currently using \"%s\""
+msgid "You are currently using <strong>%s</strong>"
 msgstr "Je gebruikt nu \"%s\""
 
@@ -581,5 +581,5 @@
 msgstr ""
 
-msgid "No category yet."
+msgid "No category so far."
 msgstr ""
 
@@ -753,5 +753,5 @@
 msgstr ""
 
-msgid "You have one spam comments."
+msgid "You have one spam comment."
 msgstr ""
 
@@ -1715,8 +1715,8 @@
 msgstr ""
 
-msgid "Change category for entries"
-msgstr ""
-
-msgid "Change author for entries"
+msgid "Change category for this selection"
+msgstr ""
+
+msgid "Change author for this selection"
 msgstr ""
 
@@ -2087,5 +2087,5 @@
 msgstr ""
 
-msgid "invert selection"
+msgid "Invert selection"
 msgstr ""
 
Index: locales/nl/plugins.po
===================================================================
--- locales/nl/plugins.po	(revision 1126)
+++ locales/nl/plugins.po	(revision 1668)
@@ -836,5 +836,5 @@
 
 #, php-format
-msgid "This will import a single blog backup as new content in the current blog: %s."
+msgid "This will import a single blog backup as new content in the current blog: <strong>%s</strong>."
 msgstr ""
 
@@ -1057,14 +1057,14 @@
 msgstr ""
 
-msgid "Page status:"
-msgstr ""
-
-msgid "Page position:"
-msgstr ""
-
-msgid "Page lang:"
-msgstr ""
-
-msgid "Page password:"
+msgid "Page status"
+msgstr ""
+
+msgid "Page position"
+msgstr ""
+
+msgid "Page lang"
+msgstr ""
+
+msgid "Page password"
 msgstr ""
 
@@ -1234,5 +1234,5 @@
 msgstr ""
 
-msgid "Currently no menu items"
+msgid "No menu items so far."
 msgstr ""
 
@@ -1536,5 +1536,5 @@
 msgstr ""
 
-msgid "Once included in a sidebar, widgets have configuration options that you can reach by clicking on the + sign next to their name."
+msgid "Once included in a sidebar, widgets have configuration options that you can reach by clicking on the arrow next to their name."
 msgstr ""
 
Index: locales/oc/help/blowupConfig.html
===================================================================
--- locales/oc/help/blowupConfig.html	(revision 1264)
+++ locales/oc/help/blowupConfig.html	(revision 1280)
@@ -35,5 +35,5 @@
 <p>You can choose a header image among the list to use in place of the default one.</p>
 
-<p>When you choose "Custom..." in the image list, you will be able to upload your own image. <strong>The image file must be in JPG or PNG format and must be precisely 800px wide.</strong></p>
+<p>When you choose "Custom..." in the image list, you will be able to upload your own image. <strong>The image file must be in JPG or PNG format and must be precisely 800px wide.</strong>
 
 <p>If you upload a JPG image, a border will be added to the image, which is not the case with PNG images (the transparency of which will also be kept).</p>
Index: locales/oc/main.po
===================================================================
--- locales/oc/main.po	(revision 1592)
+++ locales/oc/main.po	(revision 1637)
@@ -212,5 +212,5 @@
 msgstr ""
 
-msgid "That blog Id is already in use."
+msgid "This blog ID is already used."
 msgstr ""
 
@@ -455,5 +455,5 @@
 
 #, php-format
-msgid "You are currently using \"%s\""
+msgid "You are currently using <strong>%s</strong>"
 msgstr ""
 
@@ -580,5 +580,5 @@
 msgstr ""
 
-msgid "No category yet."
+msgid "No category so far."
 msgstr ""
 
@@ -757,5 +757,5 @@
 msgstr ""
 
-msgid "You have one spam comments."
+msgid "You have one spam comment."
 msgstr ""
 
@@ -1735,8 +1735,8 @@
 msgstr ""
 
-msgid "Change category for entries"
-msgstr ""
-
-msgid "Change author for entries"
+msgid "Change category for this selection"
+msgstr ""
+
+msgid "Change author for this selection"
 msgstr ""
 
@@ -2106,5 +2106,5 @@
 msgstr ""
 
-msgid "invert selection"
+msgid "Invert selection"
 msgstr ""
 
Index: locales/oc/plugins.po
===================================================================
--- locales/oc/plugins.po	(revision 1126)
+++ locales/oc/plugins.po	(revision 1668)
@@ -835,5 +835,5 @@
 
 #, php-format
-msgid "This will import a single blog backup as new content in the current blog: %s."
+msgid "This will import a single blog backup as new content in the current blog: <strong>%s</strong>."
 msgstr ""
 
@@ -1056,14 +1056,14 @@
 msgstr ""
 
-msgid "Page status:"
-msgstr ""
-
-msgid "Page position:"
-msgstr ""
-
-msgid "Page lang:"
-msgstr ""
-
-msgid "Page password:"
+msgid "Page status"
+msgstr ""
+
+msgid "Page position"
+msgstr ""
+
+msgid "Page lang"
+msgstr ""
+
+msgid "Page password"
 msgstr ""
 
@@ -1230,5 +1230,5 @@
 msgstr ""
 
-msgid "Currently no menu items"
+msgid "No menu items so far."
 msgstr ""
 
@@ -1529,5 +1529,5 @@
 msgstr ""
 
-msgid "Once included in a sidebar, widgets have configuration options that you can reach by clicking on the + sign next to their name."
+msgid "Once included in a sidebar, widgets have configuration options that you can reach by clicking on the arrow next to their name."
 msgstr ""
 
Index: locales/pl/help/blowupConfig.html
===================================================================
--- locales/pl/help/blowupConfig.html	(revision 1264)
+++ locales/pl/help/blowupConfig.html	(revision 1280)
@@ -35,5 +35,5 @@
 <p>You can choose a header image among the list to use in place of the default one.</p>
 
-<p>When you choose "Custom..." in the image list, you will be able to upload your own image. <strong>The image file must be in JPG or PNG format and must be precisely 800px wide.</strong></p>
+<p>When you choose "Custom..." in the image list, you will be able to upload your own image. <strong>The image file must be in JPG or PNG format and must be precisely 800px wide.</strong>
 
 <p>If you upload a JPG image, a border will be added to the image, which is not the case with PNG images (the transparency of which will also be kept).</p>
Index: locales/pl/main.po
===================================================================
--- locales/pl/main.po	(revision 1592)
+++ locales/pl/main.po	(revision 1637)
@@ -212,5 +212,5 @@
 msgstr "Chcę, aby wyszukiwarki i archiwizery nie indeksowały i nie archiwizowały zawartości mojego bloga."
 
-msgid "That blog Id is already in use."
+msgid "This blog ID is already used."
 msgstr "Ten identyfikator bloga jest już używany."
 
@@ -455,5 +455,5 @@
 
 #, php-format
-msgid "You are currently using \"%s\""
+msgid "You are currently using <strong>%s</strong>"
 msgstr "Aktualnie używasz \"%s\""
 
@@ -582,5 +582,5 @@
 msgstr "Kategoria została przeniesiona."
 
-msgid "No category yet."
+msgid "No category so far."
 msgstr "Brak kategorii."
 
@@ -760,5 +760,5 @@
 msgstr "Autor komentarza:"
 
-msgid "You have one spam comments."
+msgid "You have one spam comment."
 msgstr "Masz jeden komentarz oznaczony jako spam."
 
@@ -1729,8 +1729,8 @@
 msgstr "Ten użytkownik nie istnieje"
 
-msgid "Change category for entries"
+msgid "Change category for this selection"
 msgstr "Zmień kategorię dla wpisów"
 
-msgid "Change author for entries"
+msgid "Change author for this selection"
 msgstr "Zmień autora dla wpisów"
 
@@ -2099,5 +2099,5 @@
 msgstr "zaznacz wszystkie"
 
-msgid "invert selection"
+msgid "Invert selection"
 msgstr "odwróć zaznaczenie"
 
Index: locales/pl/plugins.po
===================================================================
--- locales/pl/plugins.po	(revision 1126)
+++ locales/pl/plugins.po	(revision 1668)
@@ -840,5 +840,5 @@
 
 #, php-format
-msgid "This will import a single blog backup as new content in the current blog: %s."
+msgid "This will import a single blog backup as new content in the current blog: <strong>%s</strong>."
 msgstr "Zaimportuje kopię zapasową pojedynczego bloga jako nową zawartość w aktualnym blogu: %s."
 
@@ -1061,14 +1061,14 @@
 msgstr ""
 
-msgid "Page status:"
+msgid "Page status"
 msgstr "Stan strony:"
 
-msgid "Page position:"
+msgid "Page position"
 msgstr "Pozycja strony:"
 
-msgid "Page lang:"
+msgid "Page lang"
 msgstr "Język strony:"
 
-msgid "Page password:"
+msgid "Page password"
 msgstr "Hasło strony"
 
@@ -1253,5 +1253,5 @@
 msgstr "Jesteś pewien, że chcesz usunąć wybrane odnośniki?"
 
-msgid "Currently no menu items"
+msgid "No menu items so far."
 msgstr ""
 
@@ -1559,5 +1559,5 @@
 msgstr ""
 
-msgid "Once included in a sidebar, widgets have configuration options that you can reach by clicking on the + sign next to their name."
+msgid "Once included in a sidebar, widgets have configuration options that you can reach by clicking on the arrow next to their name."
 msgstr ""
 
Index: locales/pt-br/help/blowupConfig.html
===================================================================
--- locales/pt-br/help/blowupConfig.html	(revision 1264)
+++ locales/pt-br/help/blowupConfig.html	(revision 1280)
@@ -35,5 +35,5 @@
 <p>You can choose a header image among the list to use in place of the default one.</p>
 
-<p>When you choose "Custom..." in the image list, you will be able to upload your own image. <strong>The image file must be in JPG or PNG format and must be precisely 800px wide.</strong></p>
+<p>When you choose "Custom..." in the image list, you will be able to upload your own image. <strong>The image file must be in JPG or PNG format and must be precisely 800px wide.</strong>
 
 <p>If you upload a JPG image, a border will be added to the image, which is not the case with PNG images (the transparency of which will also be kept).</p>
Index: locales/pt-br/main.po
===================================================================
--- locales/pt-br/main.po	(revision 1592)
+++ locales/pt-br/main.po	(revision 1637)
@@ -219,5 +219,5 @@
 
 #, fuzzy
-msgid "That blog Id is already in use."
+msgid "This blog ID is already used."
 msgstr "DotClear já está instalado."
 
@@ -470,5 +470,5 @@
 
 #, php-format
-msgid "You are currently using \"%s\""
+msgid "You are currently using <strong>%s</strong>"
 msgstr ""
 
@@ -603,5 +603,5 @@
 
 #, fuzzy
-msgid "No category yet."
+msgid "No category so far."
 msgstr "Nenhum categoria."
 
@@ -790,5 +790,5 @@
 msgstr "Autor do comentário:"
 
-msgid "You have one spam comments."
+msgid "You have one spam comment."
 msgstr "Você tem um comentário indesejável."
 
@@ -1824,8 +1824,8 @@
 msgstr "Este usuário não existe"
 
-msgid "Change category for entries"
+msgid "Change category for this selection"
 msgstr "Mudar a categoria para os posts"
 
-msgid "Change author for entries"
+msgid "Change author for this selection"
 msgstr "Mudar o autor para os posts"
 
@@ -2218,5 +2218,5 @@
 msgstr "selecionar tudo"
 
-msgid "invert selection"
+msgid "Invert selection"
 msgstr "inverter a seleção"
 
Index: locales/pt-br/plugins.po
===================================================================
--- locales/pt-br/plugins.po	(revision 1126)
+++ locales/pt-br/plugins.po	(revision 1668)
@@ -835,5 +835,5 @@
 
 #, php-format
-msgid "This will import a single blog backup as new content in the current blog: %s."
+msgid "This will import a single blog backup as new content in the current blog: <strong>%s</strong>."
 msgstr ""
 
@@ -1056,14 +1056,14 @@
 msgstr ""
 
-msgid "Page status:"
-msgstr ""
-
-msgid "Page position:"
-msgstr ""
-
-msgid "Page lang:"
-msgstr ""
-
-msgid "Page password:"
+msgid "Page status"
+msgstr ""
+
+msgid "Page position"
+msgstr ""
+
+msgid "Page lang"
+msgstr ""
+
+msgid "Page password"
 msgstr ""
 
@@ -1230,5 +1230,5 @@
 msgstr ""
 
-msgid "Currently no menu items"
+msgid "No menu items so far."
 msgstr ""
 
@@ -1529,5 +1529,5 @@
 msgstr ""
 
-msgid "Once included in a sidebar, widgets have configuration options that you can reach by clicking on the + sign next to their name."
+msgid "Once included in a sidebar, widgets have configuration options that you can reach by clicking on the arrow next to their name."
 msgstr ""
 
Index: locales/pt/help/blowupConfig.html
===================================================================
--- locales/pt/help/blowupConfig.html	(revision 1264)
+++ locales/pt/help/blowupConfig.html	(revision 1280)
@@ -51,5 +51,5 @@
 <br />
 
-<em>NOTA: Uma bordura aparecera a volta da imagem o formato JPG, isto não acontece com as imagem em PNG -é a transparência dos PNGs fica efectiva-</em></p>
+<em>NOTA: Uma bordura aparecera a volta da imagem o formato JPG, isto não acontece com as imagem em PNG -é a transparência dos PNGs fica efectiva-</em>
 
 <h4>Estilos pré-definidos</h4>
Index: locales/pt/main.po
===================================================================
--- locales/pt/main.po	(revision 1592)
+++ locales/pt/main.po	(revision 1637)
@@ -218,5 +218,5 @@
 
 #, fuzzy
-msgid "That blog Id is already in use."
+msgid "This blog ID is already used."
 msgstr "Dotclear já está instalado."
 
@@ -461,5 +461,5 @@
 
 #, php-format
-msgid "You are currently using \"%s\""
+msgid "You are currently using <strong>%s</strong>"
 msgstr "Você está a usar \"%s\""
 
@@ -589,5 +589,5 @@
 msgstr "A categoria foi movida com sucesso."
 
-msgid "No category yet."
+msgid "No category so far."
 msgstr "Nenhuma categoria ainda."
 
@@ -768,5 +768,5 @@
 msgstr "Autor do comentário:"
 
-msgid "You have one spam comments."
+msgid "You have one spam comment."
 msgstr "Tem um comentário de \"spam\""
 
@@ -1748,8 +1748,8 @@
 msgstr "Este utilizador não existe"
 
-msgid "Change category for entries"
+msgid "Change category for this selection"
 msgstr "Alterar a categoria das entradas"
 
-msgid "Change author for entries"
+msgid "Change author for this selection"
 msgstr "Alterar o autor das entradas"
 
@@ -2133,5 +2133,5 @@
 msgstr "seleccionar tudo"
 
-msgid "invert selection"
+msgid "Invert selection"
 msgstr "inverter selecção"
 
Index: locales/pt/plugins.po
===================================================================
--- locales/pt/plugins.po	(revision 1126)
+++ locales/pt/plugins.po	(revision 1668)
@@ -849,5 +849,5 @@
 
 #, php-format
-msgid "This will import a single blog backup as new content in the current blog: %s."
+msgid "This will import a single blog backup as new content in the current blog: <strong>%s</strong>."
 msgstr "Isto irá importar uma copia de simples blog como novo conteúdo no blog actual: %s."
 
@@ -1073,14 +1073,14 @@
 msgstr ""
 
-msgid "Page status:"
+msgid "Page status"
 msgstr "Estatutos da página:"
 
-msgid "Page position:"
+msgid "Page position"
 msgstr "Posição da página:"
 
-msgid "Page lang:"
+msgid "Page lang"
 msgstr "Língua da página:"
 
-msgid "Page password:"
+msgid "Page password"
 msgstr "Senha da página:"
 
@@ -1265,5 +1265,5 @@
 msgstr "Tem a certeza que pretende suprimir os links seleccionados?"
 
-msgid "Currently no menu items"
+msgid "No menu items so far."
 msgstr ""
 
@@ -1576,5 +1576,5 @@
 msgstr ""
 
-msgid "Once included in a sidebar, widgets have configuration options that you can reach by clicking on the + sign next to their name."
+msgid "Once included in a sidebar, widgets have configuration options that you can reach by clicking on the arrow next to their name."
 msgstr ""
 
Index: locales/ro/help/blowupConfig.html
===================================================================
--- locales/ro/help/blowupConfig.html	(revision 1264)
+++ locales/ro/help/blowupConfig.html	(revision 1280)
@@ -35,5 +35,5 @@
 <p>You can choose a header image among the list to use in place of the default one.</p>
 
-<p>When you choose "Custom..." in the image list, you will be able to upload your own image. <strong>The image file must be in JPG or PNG format and must be precisely 800px wide.</strong></p>
+<p>When you choose "Custom..." in the image list, you will be able to upload your own image. <strong>The image file must be in JPG or PNG format and must be precisely 800px wide.</strong>
 
 <p>If you upload a JPG image, a border will be added to the image, which is not the case with PNG images (the transparency of which will also be kept).</p>
Index: locales/ro/main.po
===================================================================
--- locales/ro/main.po	(revision 1592)
+++ locales/ro/main.po	(revision 1637)
@@ -213,5 +213,5 @@
 msgstr ""
 
-msgid "That blog Id is already in use."
+msgid "This blog ID is already used."
 msgstr ""
 
@@ -455,5 +455,5 @@
 
 #, php-format
-msgid "You are currently using \"%s\""
+msgid "You are currently using <strong>%s</strong>"
 msgstr ""
 
@@ -580,5 +580,5 @@
 msgstr ""
 
-msgid "No category yet."
+msgid "No category so far."
 msgstr ""
 
@@ -752,5 +752,5 @@
 msgstr ""
 
-msgid "You have one spam comments."
+msgid "You have one spam comment."
 msgstr ""
 
@@ -1710,8 +1710,8 @@
 msgstr ""
 
-msgid "Change category for entries"
-msgstr ""
-
-msgid "Change author for entries"
+msgid "Change category for this selection"
+msgstr ""
+
+msgid "Change author for this selection"
 msgstr ""
 
@@ -2084,5 +2084,5 @@
 msgstr ""
 
-msgid "invert selection"
+msgid "Invert selection"
 msgstr ""
 
Index: locales/ro/plugins.po
===================================================================
--- locales/ro/plugins.po	(revision 1126)
+++ locales/ro/plugins.po	(revision 1668)
@@ -845,5 +845,5 @@
 
 #, php-format
-msgid "This will import a single blog backup as new content in the current blog: %s."
+msgid "This will import a single blog backup as new content in the current blog: <strong>%s</strong>."
 msgstr ""
 
@@ -1068,14 +1068,14 @@
 msgstr ""
 
-msgid "Page status:"
-msgstr ""
-
-msgid "Page position:"
-msgstr ""
-
-msgid "Page lang:"
-msgstr ""
-
-msgid "Page password:"
+msgid "Page status"
+msgstr ""
+
+msgid "Page position"
+msgstr ""
+
+msgid "Page lang"
+msgstr ""
+
+msgid "Page password"
 msgstr ""
 
@@ -1251,5 +1251,5 @@
 msgstr "Sigur dorești a șterge legăturile selectate?"
 
-msgid "Currently no menu items"
+msgid "No menu items so far."
 msgstr ""
 
@@ -1554,5 +1554,5 @@
 msgstr ""
 
-msgid "Once included in a sidebar, widgets have configuration options that you can reach by clicking on the + sign next to their name."
+msgid "Once included in a sidebar, widgets have configuration options that you can reach by clicking on the arrow next to their name."
 msgstr ""
 
Index: locales/ru/main.po
===================================================================
--- locales/ru/main.po	(revision 1592)
+++ locales/ru/main.po	(revision 1637)
@@ -216,5 +216,5 @@
 msgstr "Я не хочу, чтобы мой блог индексировался и архивировался поисковыми машинами."
 
-msgid "That blog Id is already in use."
+msgid "This blog ID is already used."
 msgstr "Dotclear уже установлен."
 
@@ -460,5 +460,5 @@
 
 #, php-format
-msgid "You are currently using \"%s\""
+msgid "You are currently using <strong>%s</strong>"
 msgstr "В данный момент вы используете \"%s\""
 
@@ -588,5 +588,5 @@
 msgstr "Категория была успешно перенесена."
 
-msgid "No category yet."
+msgid "No category so far."
 msgstr "Нет категории."
 
@@ -767,5 +767,5 @@
 msgstr "Автор комментария:"
 
-msgid "You have one spam comments."
+msgid "You have one spam comment."
 msgstr "У вас один спам комментарий."
 
@@ -1742,8 +1742,8 @@
 msgstr "Этот пользователь не существует"
 
-msgid "Change category for entries"
+msgid "Change category for this selection"
 msgstr "Изменить категорию для записей"
 
-msgid "Change author for entries"
+msgid "Change author for this selection"
 msgstr "Изменить автора записей"
 
@@ -2126,5 +2126,5 @@
 msgstr "выбрать все"
 
-msgid "invert selection"
+msgid "Invert selection"
 msgstr "инвертировать выбор"
 
Index: locales/ru/plugins.po
===================================================================
--- locales/ru/plugins.po	(revision 1126)
+++ locales/ru/plugins.po	(revision 1668)
@@ -841,5 +841,5 @@
 
 #, php-format
-msgid "This will import a single blog backup as new content in the current blog: %s."
+msgid "This will import a single blog backup as new content in the current blog: <strong>%s</strong>."
 msgstr "Это импортирует резервный файл одного блога как новое содержимое в текущий блог: %s."
 
@@ -1064,14 +1064,14 @@
 msgstr ""
 
-msgid "Page status:"
+msgid "Page status"
 msgstr "Статус страницы:"
 
-msgid "Page position:"
+msgid "Page position"
 msgstr "Позиция страницы:"
 
-msgid "Page lang:"
+msgid "Page lang"
 msgstr "Язык страницы:"
 
-msgid "Page password:"
+msgid "Page password"
 msgstr "Пароль страницы:"
 
@@ -1256,5 +1256,5 @@
 msgstr "Вы уверены, что хотите удалить выбранные ссылки?"
 
-msgid "Currently no menu items"
+msgid "No menu items so far."
 msgstr ""
 
@@ -1565,5 +1565,5 @@
 msgstr ""
 
-msgid "Once included in a sidebar, widgets have configuration options that you can reach by clicking on the + sign next to their name."
+msgid "Once included in a sidebar, widgets have configuration options that you can reach by clicking on the arrow next to their name."
 msgstr ""
 
Index: locales/sr/help/blowupConfig.html
===================================================================
--- locales/sr/help/blowupConfig.html	(revision 1264)
+++ locales/sr/help/blowupConfig.html	(revision 1280)
@@ -35,5 +35,5 @@
 <p>You can choose a header image among the list to use in place of the default one.</p>
 
-<p>When you choose "Custom..." in the image list, you will be able to upload your own image. <strong>The image file must be in JPG or PNG format and must be precisely 800px wide.</strong></p>
+<p>When you choose "Custom..." in the image list, you will be able to upload your own image. <strong>The image file must be in JPG or PNG format and must be precisely 800px wide.</strong>
 
 <p>If you upload a JPG image, a border will be added to the image, which is not the case with PNG images (the transparency of which will also be kept).</p>
Index: locales/sr/main.po
===================================================================
--- locales/sr/main.po	(revision 1592)
+++ locales/sr/main.po	(revision 1637)
@@ -217,5 +217,5 @@
 
 #, fuzzy
-msgid "That blog Id is already in use."
+msgid "This blog ID is already used."
 msgstr "Dotclear est déjà installé."
 
@@ -460,5 +460,5 @@
 
 #, php-format
-msgid "You are currently using \"%s\""
+msgid "You are currently using <strong>%s</strong>"
 msgstr "Vous utilisez actuellement \"%s\""
 
@@ -592,5 +592,5 @@
 
 #, fuzzy
-msgid "No category yet."
+msgid "No category so far."
 msgstr "Pas de catégorie."
 
@@ -778,5 +778,5 @@
 msgstr "Auteur du commentaire :"
 
-msgid "You have one spam comments."
+msgid "You have one spam comment."
 msgstr "Vous avez un commentaire indésirable."
 
@@ -1172,5 +1172,5 @@
 
 msgid "Media manager"
-msgstr "Gestionnaire de médias"
+msgstr "Médiathèque"
 
 msgid "confirm removal"
@@ -1654,5 +1654,5 @@
 
 msgid "Ping blogs"
-msgstr "Faire des rétroliens"
+msgstr "Envoyer des rétroliens"
 
 msgid "Trackbacks"
@@ -1772,8 +1772,8 @@
 msgstr "Cet utilisateur n'existe pas"
 
-msgid "Change category for entries"
+msgid "Change category for this selection"
 msgstr "Changer de catégorie pour les billets"
 
-msgid "Change author for entries"
+msgid "Change author for this selection"
 msgstr "Changer l'auteur des billets"
 
@@ -2167,5 +2167,5 @@
 msgstr "tout sélectionner"
 
-msgid "invert selection"
+msgid "Invert selection"
 msgstr "inverser la sélection"
 
Index: locales/sr/plugins.po
===================================================================
--- locales/sr/plugins.po	(revision 1126)
+++ locales/sr/plugins.po	(revision 1668)
@@ -835,5 +835,5 @@
 
 #, php-format
-msgid "This will import a single blog backup as new content in the current blog: %s."
+msgid "This will import a single blog backup as new content in the current blog: <strong>%s</strong>."
 msgstr ""
 
@@ -1056,14 +1056,14 @@
 msgstr ""
 
-msgid "Page status:"
-msgstr ""
-
-msgid "Page position:"
-msgstr ""
-
-msgid "Page lang:"
-msgstr ""
-
-msgid "Page password:"
+msgid "Page status"
+msgstr ""
+
+msgid "Page position"
+msgstr ""
+
+msgid "Page lang"
+msgstr ""
+
+msgid "Page password"
 msgstr ""
 
@@ -1230,5 +1230,5 @@
 msgstr ""
 
-msgid "Currently no menu items"
+msgid "No menu items so far."
 msgstr ""
 
@@ -1529,5 +1529,5 @@
 msgstr ""
 
-msgid "Once included in a sidebar, widgets have configuration options that you can reach by clicking on the + sign next to their name."
+msgid "Once included in a sidebar, widgets have configuration options that you can reach by clicking on the arrow next to their name."
 msgstr ""
 
Index: locales/sv/help/blowupConfig.html
===================================================================
--- locales/sv/help/blowupConfig.html	(revision 1264)
+++ locales/sv/help/blowupConfig.html	(revision 1280)
@@ -35,5 +35,5 @@
 <p>You can choose a header image among the list to use in place of the default one.</p>
 
-<p>When you choose "Custom..." in the image list, you will be able to upload your own image. <strong>The image file must be in JPG or PNG format and must be precisely 800px wide.</strong></p>
+<p>When you choose "Custom..." in the image list, you will be able to upload your own image. <strong>The image file must be in JPG or PNG format and must be precisely 800px wide.</strong>
 
 <p>If you upload a JPG image, a border will be added to the image, which is not the case with PNG images (the transparency of which will also be kept).</p>
Index: locales/sv/main.po
===================================================================
--- locales/sv/main.po	(revision 1592)
+++ locales/sv/main.po	(revision 1637)
@@ -211,5 +211,5 @@
 msgstr ""
 
-msgid "That blog Id is already in use."
+msgid "This blog ID is already used."
 msgstr ""
 
@@ -453,5 +453,5 @@
 
 #, php-format
-msgid "You are currently using \"%s\""
+msgid "You are currently using <strong>%s</strong>"
 msgstr ""
 
@@ -578,5 +578,5 @@
 msgstr ""
 
-msgid "No category yet."
+msgid "No category so far."
 msgstr ""
 
@@ -750,5 +750,5 @@
 msgstr ""
 
-msgid "You have one spam comments."
+msgid "You have one spam comment."
 msgstr ""
 
@@ -1708,8 +1708,8 @@
 msgstr ""
 
-msgid "Change category for entries"
-msgstr ""
-
-msgid "Change author for entries"
+msgid "Change category for this selection"
+msgstr ""
+
+msgid "Change author for this selection"
 msgstr ""
 
@@ -2073,5 +2073,5 @@
 msgstr ""
 
-msgid "invert selection"
+msgid "Invert selection"
 msgstr ""
 
Index: locales/sv/plugins.po
===================================================================
--- locales/sv/plugins.po	(revision 1126)
+++ locales/sv/plugins.po	(revision 1668)
@@ -835,5 +835,5 @@
 
 #, php-format
-msgid "This will import a single blog backup as new content in the current blog: %s."
+msgid "This will import a single blog backup as new content in the current blog: <strong>%s</strong>."
 msgstr ""
 
@@ -1056,14 +1056,14 @@
 msgstr ""
 
-msgid "Page status:"
-msgstr ""
-
-msgid "Page position:"
-msgstr ""
-
-msgid "Page lang:"
-msgstr ""
-
-msgid "Page password:"
+msgid "Page status"
+msgstr ""
+
+msgid "Page position"
+msgstr ""
+
+msgid "Page lang"
+msgstr ""
+
+msgid "Page password"
 msgstr ""
 
@@ -1230,5 +1230,5 @@
 msgstr ""
 
-msgid "Currently no menu items"
+msgid "No menu items so far."
 msgstr ""
 
@@ -1529,5 +1529,5 @@
 msgstr ""
 
-msgid "Once included in a sidebar, widgets have configuration options that you can reach by clicking on the + sign next to their name."
+msgid "Once included in a sidebar, widgets have configuration options that you can reach by clicking on the arrow next to their name."
 msgstr ""
 
Index: locales/te/help/blowupConfig.html
===================================================================
--- locales/te/help/blowupConfig.html	(revision 1264)
+++ locales/te/help/blowupConfig.html	(revision 1280)
@@ -35,5 +35,5 @@
 <p>You can choose a header image among the list to use in place of the default one.</p>
 
-<p>When you choose "Custom..." in the image list, you will be able to upload your own image. <strong>The image file must be in JPG or PNG format and must be precisely 800px wide.</strong></p>
+<p>When you choose "Custom..." in the image list, you will be able to upload your own image. <strong>The image file must be in JPG or PNG format and must be precisely 800px wide.</strong>
 
 <p>If you upload a JPG image, a border will be added to the image, which is not the case with PNG images (the transparency of which will also be kept).</p>
Index: locales/te/main.po
===================================================================
--- locales/te/main.po	(revision 1592)
+++ locales/te/main.po	(revision 1637)
@@ -215,5 +215,5 @@
 
 #, fuzzy
-msgid "That blog Id is already in use."
+msgid "This blog ID is already used."
 msgstr "డాట్‌క్లియర్ ఇప్పటికే స్థాపితమైవుంది."
 
@@ -458,5 +458,5 @@
 
 #, php-format
-msgid "You are currently using \"%s\""
+msgid "You are currently using <strong>%s</strong>"
 msgstr "మీరు ప్రస్తుతం \"%s\" ని వాడుతున్నారు"
 
@@ -591,5 +591,5 @@
 
 #, fuzzy
-msgid "No category yet."
+msgid "No category so far."
 msgstr "వర్గాలు లేవు."
 
@@ -775,5 +775,5 @@
 msgstr "వ్యాఖ్యాత:"
 
-msgid "You have one spam comments."
+msgid "You have one spam comment."
 msgstr "ఒక చెత్త వ్యాఖ్య ఉంది."
 
@@ -1763,8 +1763,8 @@
 msgstr "ఈ వాడుకరి లేనే లేరు"
 
-msgid "Change category for entries"
-msgstr ""
-
-msgid "Change author for entries"
+msgid "Change category for this selection"
+msgstr ""
+
+msgid "Change author for this selection"
 msgstr "టపాలకి రచయితని మార్చండి"
 
@@ -2151,5 +2151,5 @@
 msgstr "అన్నీ ఎంచుకోండి"
 
-msgid "invert selection"
+msgid "Invert selection"
 msgstr ""
 
Index: locales/te/plugins.po
===================================================================
--- locales/te/plugins.po	(revision 1126)
+++ locales/te/plugins.po	(revision 1668)
@@ -838,5 +838,5 @@
 
 #, php-format
-msgid "This will import a single blog backup as new content in the current blog: %s."
+msgid "This will import a single blog backup as new content in the current blog: <strong>%s</strong>."
 msgstr ""
 
@@ -1061,14 +1061,14 @@
 msgstr ""
 
-msgid "Page status:"
+msgid "Page status"
 msgstr "పేజీ స్థితి:"
 
-msgid "Page position:"
+msgid "Page position"
 msgstr "పేజీ స్థానం:"
 
-msgid "Page lang:"
+msgid "Page lang"
 msgstr "పేజీ భాష:"
 
-msgid "Page password:"
+msgid "Page password"
 msgstr "పేజీ సంకేతపదం:"
 
@@ -1248,5 +1248,5 @@
 msgstr "ఈ పేజీని మీరు నిజంగానే తొలగించాలనుకుంటున్నారా?"
 
-msgid "Currently no menu items"
+msgid "No menu items so far."
 msgstr ""
 
@@ -1558,5 +1558,5 @@
 msgstr ""
 
-msgid "Once included in a sidebar, widgets have configuration options that you can reach by clicking on the + sign next to their name."
+msgid "Once included in a sidebar, widgets have configuration options that you can reach by clicking on the arrow next to their name."
 msgstr ""
 
Index: locales/tr/help/blowupConfig.html
===================================================================
--- locales/tr/help/blowupConfig.html	(revision 1264)
+++ locales/tr/help/blowupConfig.html	(revision 1280)
@@ -35,5 +35,5 @@
 <p>You can choose a header image among the list to use in place of the default one.</p>
 
-<p>When you choose "Custom..." in the image list, you will be able to upload your own image. <strong>The image file must be in JPG or PNG format and must be precisely 800px wide.</strong></p>
+<p>When you choose "Custom..." in the image list, you will be able to upload your own image. <strong>The image file must be in JPG or PNG format and must be precisely 800px wide.</strong>
 
 <p>If you upload a JPG image, a border will be added to the image, which is not the case with PNG images (the transparency of which will also be kept).</p>
Index: locales/tr/main.po
===================================================================
--- locales/tr/main.po	(revision 1592)
+++ locales/tr/main.po	(revision 1637)
@@ -217,5 +217,5 @@
 
 #, fuzzy
-msgid "That blog Id is already in use."
+msgid "This blog ID is already used."
 msgstr "Dotclear evvelce kurulmuş."
 
@@ -460,5 +460,5 @@
 
 #, php-format
-msgid "You are currently using \"%s\""
+msgid "You are currently using <strong>%s</strong>"
 msgstr "Şimdi \"%s\" kullanıyorsunuz."
 
@@ -588,5 +588,5 @@
 msgstr "Kategori silinimi başarılı."
 
-msgid "No category yet."
+msgid "No category so far."
 msgstr "Henüz kategori yok"
 
@@ -761,5 +761,5 @@
 msgstr "Ahkamı yazan:"
 
-msgid "You have one spam comments."
+msgid "You have one spam comment."
 msgstr ""
 
@@ -1746,8 +1746,8 @@
 msgstr "Bu kullanıcı mevcut değil"
 
-msgid "Change category for entries"
+msgid "Change category for this selection"
 msgstr "Yazıların kategorisini değiştir"
 
-msgid "Change author for entries"
+msgid "Change author for this selection"
 msgstr "Yazıların yazarını değiştir"
 
@@ -2129,5 +2129,5 @@
 msgstr "hepsini seç"
 
-msgid "invert selection"
+msgid "Invert selection"
 msgstr "seçimi evir"
 
Index: locales/tr/plugins.po
===================================================================
--- locales/tr/plugins.po	(revision 1126)
+++ locales/tr/plugins.po	(revision 1668)
@@ -839,5 +839,5 @@
 
 #, php-format
-msgid "This will import a single blog backup as new content in the current blog: %s."
+msgid "This will import a single blog backup as new content in the current blog: <strong>%s</strong>."
 msgstr ""
 
@@ -1061,14 +1061,14 @@
 msgstr ""
 
-msgid "Page status:"
-msgstr ""
-
-msgid "Page position:"
-msgstr ""
-
-msgid "Page lang:"
-msgstr ""
-
-msgid "Page password:"
+msgid "Page status"
+msgstr ""
+
+msgid "Page position"
+msgstr ""
+
+msgid "Page lang"
+msgstr ""
+
+msgid "Page password"
 msgstr ""
 
@@ -1242,5 +1242,5 @@
 msgstr ""
 
-msgid "Currently no menu items"
+msgid "No menu items so far."
 msgstr ""
 
@@ -1546,5 +1546,5 @@
 msgstr ""
 
-msgid "Once included in a sidebar, widgets have configuration options that you can reach by clicking on the + sign next to their name."
+msgid "Once included in a sidebar, widgets have configuration options that you can reach by clicking on the arrow next to their name."
 msgstr ""
 
Index: locales/zh-cn/help/blowupConfig.html
===================================================================
--- locales/zh-cn/help/blowupConfig.html	(revision 1264)
+++ locales/zh-cn/help/blowupConfig.html	(revision 1280)
@@ -35,5 +35,5 @@
 <p>您可以从列表中选择一个头部图片来取代默认的。</p>
 
-<p>当您在图片列表中选择“定制...”，您将可以上传自己的图片。<strong>图片必须是 JPG 或者 PNG 格式并且必须精确等于 800 像素宽。</strong></p>
+<p>当您在图片列表中选择“定制...”，您将可以上传自己的图片。<strong>图片必须是 JPG 或者 PNG 格式并且必须精确等于 800 像素宽。</strong>
 
 <p>如果您上传一个 JPG 图片，一个边框将会被添加。而 PNG 图片不会如此(透明特性也会被保留)。</p>
Index: locales/zh-cn/main.po
===================================================================
--- locales/zh-cn/main.po	(revision 1592)
+++ locales/zh-cn/main.po	(revision 1637)
@@ -215,5 +215,5 @@
 
 #, fuzzy
-msgid "That blog Id is already in use."
+msgid "This blog ID is already used."
 msgstr "Dotclear 已被安装。"
 
@@ -458,5 +458,5 @@
 
 #, php-format
-msgid "You are currently using \"%s\""
+msgid "You are currently using <strong>%s</strong>"
 msgstr "您正在使用“%s”"
 
@@ -586,5 +586,5 @@
 msgstr "成功移动分类目录。"
 
-msgid "No category yet."
+msgid "No category so far."
 msgstr "还没有分类目录。"
 
@@ -765,5 +765,5 @@
 msgstr "评论作者："
 
-msgid "You have one spam comments."
+msgid "You have one spam comment."
 msgstr "您有一个垃圾评论。"
 
@@ -1745,8 +1745,8 @@
 msgstr "用户不存在"
 
-msgid "Change category for entries"
+msgid "Change category for this selection"
 msgstr "改变文章的分类目录"
 
-msgid "Change author for entries"
+msgid "Change author for this selection"
 msgstr "改变文章的作者"
 
@@ -2131,5 +2131,5 @@
 msgstr "选择全部"
 
-msgid "invert selection"
+msgid "Invert selection"
 msgstr "反选"
 
Index: locales/zh-cn/plugins.po
===================================================================
--- locales/zh-cn/plugins.po	(revision 1126)
+++ locales/zh-cn/plugins.po	(revision 1668)
@@ -847,5 +847,5 @@
 
 #, php-format
-msgid "This will import a single blog backup as new content in the current blog: %s."
+msgid "This will import a single blog backup as new content in the current blog: <strong>%s</strong>."
 msgstr "这将会把一个单一博客的备份作为新内容导入到当前博客：%s。"
 
@@ -1071,14 +1071,14 @@
 msgstr ""
 
-msgid "Page status:"
+msgid "Page status"
 msgstr "页面状态："
 
-msgid "Page position:"
+msgid "Page position"
 msgstr "页面位置："
 
-msgid "Page lang:"
+msgid "Page lang"
 msgstr "页面语言："
 
-msgid "Page password:"
+msgid "Page password"
 msgstr "页面密码："
 
@@ -1262,5 +1262,5 @@
 msgstr "您确定您要删除选定的链接吗？"
 
-msgid "Currently no menu items"
+msgid "No menu items so far."
 msgstr ""
 
@@ -1573,5 +1573,5 @@
 msgstr ""
 
-msgid "Once included in a sidebar, widgets have configuration options that you can reach by clicking on the + sign next to their name."
+msgid "Once included in a sidebar, widgets have configuration options that you can reach by clicking on the arrow next to their name."
 msgstr ""
 
Index: plugins/aboutConfig/_admin.php
===================================================================
--- plugins/aboutConfig/_admin.php	(revision 1179)
+++ plugins/aboutConfig/_admin.php	(revision 1294)
@@ -12,5 +12,5 @@
 if (!defined('DC_CONTEXT_ADMIN')) { return; }
 
-$_menu['Plugins']->addItem('about:config','plugin.php?p=aboutConfig','index.php?pf=aboutConfig/icon.png',
+$_menu['System']->addItem('about:config','plugin.php?p=aboutConfig','index.php?pf=aboutConfig/icon.png',
 		preg_match('/plugin.php\?p=aboutConfig(&.*)?$/',$_SERVER['REQUEST_URI']),
 		$core->auth->isSuperAdmin());
Index: plugins/aboutConfig/index.php
===================================================================
--- plugins/aboutConfig/index.php	(revision 1274)
+++ plugins/aboutConfig/index.php	(revision 1553)
@@ -85,5 +85,5 @@
 	
 	return
-	'<tr>'.
+	'<tr class="line">'.
 	'<td scope="row"><label for="s_'.$id.'">'.sprintf($slabel,html::escapeHTML($id)).'</label></td>'.
 	'<td>'.$field.'</td>'.
@@ -97,10 +97,5 @@
   <title>about:config</title>
   <?php echo dcPage::jsPageTabs($part); ?>
-  <style type="text/css">
-  table.settings { border: 1px solid #999; margin-bottom: 2em; }
-  table.settings th { background: #f5f5f5; color: #444; padding-top: 0.3em; padding-bottom: 0.3em; }
-  p.anchor-nav {float: right; }
-  </style>
-	<script type="text/javascript">
+  <script type="text/javascript">
 	//<![CDATA[
 	$(function() {
@@ -120,18 +115,24 @@
 <body>
 <?php
+echo dcPage::breadcrumb(
+	array(
+		__('System') => '',
+		html::escapeHTML($core->blog->name) => '',
+		'<span class="page-title">'.__('about:config').'</span>' => ''
+	));
 if (!empty($_GET['upd'])) {
-	dcPage::message(__('Configuration successfully updated'));
+	dcPage::success(__('Configuration successfully updated'));
 }
 
 if (!empty($_GET['upda'])) {
-	dcPage::message(__('Settings definition successfully updated'));
-}
-?>
-<h2><?php echo html::escapeHTML($core->blog->name); ?> &rsaquo; <span class="page-title">about:config</span></h2>
-
-<div id="local" class="multi-part" title="<?php echo __('blog settings'); ?>">
-
-<?php 
-$table_header = '<table class="settings" id="%s"><caption>%s</caption>'.
+	dcPage::success(__('Settings definition successfully updated'));
+}
+?>
+
+<div id="local" class="multi-part" title="<?php echo sprintf(__('Settings for %s'),html::escapeHTML($core->blog->name)); ?>">
+
+
+<?php
+$table_header = '<table class="settings" id="%s"><caption class="as_h3">%s</caption>'.
 '<thead>'.
 '<tr>'."\n".
@@ -188,5 +189,5 @@
 </div>
 
-<div id="global" class="multi-part" title="<?php echo __('global settings'); ?>">
+<div id="global" class="multi-part" title="<?php echo __('Global settings'); ?>">
 
 <?php
@@ -209,6 +210,6 @@
 		'<form action="plugin.php" method="post">'.
 		'<p class="anchor-nav">'.
-		'<label for="gs_nav" class="classic">'.__('Goto:').'</label> '.form::combo('gs_nav',$ns_combo).
-		' <input type="submit" value="'.__('Ok').'" id="gs_submit" />'.
+		'<label for="gs_nav" class="classic">'.__('Goto:').'</label> '.form::combo('gs_nav',$ns_combo).' '.
+		'<input type="submit" value="'.__('Ok').'" id="gs_submit" />'.
 		'<input type="hidden" name="p" value="aboutConfig" />'.
 		$core->formNonce().'</p></form>';
Index: plugins/akismet/class.dc.filter.akismet.php
===================================================================
--- plugins/akismet/class.dc.filter.akismet.php	(revision 1179)
+++ plugins/akismet/class.dc.filter.akismet.php	(revision 1454)
@@ -137,6 +137,6 @@
 		$res =
 		'<form action="'.html::escapeURL($url).'" method="post" class="fieldset">'.
-		'<p><label for="ak_key" class="classic">'.__('Akismet API key:').' '.
-		form::field('ak_key',12,128,$ak_key).'</label>';
+		'<p><label for="ak_key" class="classic">'.__('Akismet API key:').'</label> '.
+		form::field('ak_key',12,128,$ak_key);
 		
 		if ($ak_verified !== null) {
Index: plugins/antispam/_admin.php
===================================================================
--- plugins/antispam/_admin.php	(revision 1207)
+++ plugins/antispam/_admin.php	(revision 1519)
@@ -59,6 +59,6 @@
 		if ($ttl != null && $ttl >=0) {
 			echo '<p>'.sprintf(__('All spam comments older than %s day(s) will be automatically deleted.'), $ttl).' '.
-			sprintf(__('You can modify this duration in the %s'),'<a href="blog_pref.php#antispam_moderation_ttl"> '.__('Blog preferences').'</a>').
-			'</p>';
+			sprintf(__('You can modify this duration in the %s'),'<a href="blog_pref.php#antispam_moderation_ttl"> '.__('Blog settings').'</a>').
+			'.</p>';
 		}
 	}
@@ -68,10 +68,10 @@
 		$ttl = $settings->antispam->antispam_moderation_ttl;
 		echo
-		'<fieldset><legend>Antispam</legend>'.
+		'<div class="fieldset"><h4>Antispam</h4>'.
 		'<p><label for="antispam_moderation_ttl" class="classic">'.__('Delete junk comments older than').' '.
 		form::field('antispam_moderation_ttl', 3, 3, $ttl).
 		' '.__('days').
 		'</label></p>'.
-		'</fieldset>';
+		'</div>';
 	}
 	
Index: plugins/antispam/antispam.js
===================================================================
--- plugins/antispam/antispam.js	(revision 1130)
+++ plugins/antispam/antispam.js	(revision 1423)
@@ -6,5 +6,5 @@
 		$(this).css({'cursor':'auto'});
 	});
-	$('#filters-form').submit(function() {
+	$('#filters-list-form').submit(function() {
 		var order=[];
 		$("#filters-list tr td input.position").each(function() {
Index: plugins/antispam/filters/class.dc.filter.ip.php
===================================================================
--- plugins/antispam/filters/class.dc.filter.ip.php	(revision 1179)
+++ plugins/antispam/filters/class.dc.filter.ip.php	(revision 1553)
@@ -17,8 +17,4 @@
 	public $has_gui = true;
 
-	private $style_list = 'height: 200px; overflow: auto; margin-bottom: 1em; ';
-	private $style_p = 'margin: 1px 0 0 0; padding: 0.2em 0.5em; ';
-	private $style_global = 'background: #ccff99; ';
-
 	private $con;
 	private $table;
@@ -103,8 +99,8 @@
 
 		if (!empty($_GET['added'])) {
-			$res .= dcPage::message(__('IP address has been successfully added.'),true,false,false);
+			$res .= dcPage::success(__('IP address has been successfully added.'),true,false,false);
 		}
 		if (!empty($_GET['removed'])) {
-			$res .= dcPage::message(__('IP addresses have been successfully removed.'),true,false,false);
+			$res .= dcPage::success(__('IP addresses have been successfully removed.'),true,false,false);
 		}
 
@@ -124,12 +120,13 @@
 
 		'<form action="'.html::escapeURL($url).'" method="post" class="fieldset">'.
+
+		'<p>'.
 		form::hidden(array('ip_type'),$type).
-		'<label class="classic" for="addip_'.$type.'">'.__('Add an IP address: ').' '.
-		form::field(array('addip', 'addip_'.$type),18,255).
-		'</label>';
-		if ($core->auth->isSuperAdmin()) {
-			$res .= '<label class="classic" for="globalip_'.$type.'">'.form::checkbox(array('globalip', 'globalip_'.$type),1).' '.
-			__('Global IP (used for all blogs)').'</label> ';
-		}
+		'<label class="classic" for="addip_'.$type.'">'.__('Add an IP address: ').'</label> '.
+		form::field(array('addip', 'addip_'.$type),18,255);
+			if ($core->auth->isSuperAdmin()) {
+				$res .= '<label class="classic" for="globalip_'.$type.'">'.form::checkbox(array('globalip', 'globalip_'.$type),1).' '.
+				__('Global IP (used for all blogs)').'</label> ';
+			}
 
 		$res .=
@@ -150,5 +147,5 @@
 			'<form action="'.html::escapeURL($url).'" method="post">'.
 			'<h3>' . __('IP list') . '</h3>'.
-			'<div style="'.$this->style_list.'">';
+			'<div class="antispam">';
 
 			$res_global = '';
@@ -162,12 +159,12 @@
 
 				$disabled_ip = false;
-				$p_style = $this->style_p;
+				$p_style = '';
 				if (!$rs->blog_id) {
 					$disabled_ip = !$core->auth->isSuperAdmin();
-					$p_style .= $this->style_global;
+					$p_style .= ' global';
 				}
 
 				$item =
-				'<p style="'.$p_style.'"><label class="classic" for="'.$type.'-ip-'.$rs->rule_id.'">'.
+				'<p class="'.$p_style.'"><label class="classic" for="'.$type.'-ip-'.$rs->rule_id.'">'.
 				form::checkbox(array('delip[]',$type.'-ip-'.$rs->rule_id),$rs->rule_id,false,'','',$disabled_ip).' '.
 				html::escapeHTML($pattern).
Index: plugins/antispam/filters/class.dc.filter.iplookup.php
===================================================================
--- plugins/antispam/filters/class.dc.filter.iplookup.php	(revision 1361)
+++ plugins/antispam/filters/class.dc.filter.iplookup.php	(revision 1622)
@@ -76,12 +76,11 @@
 
 		$res .=
-		'<form action="'.html::escapeURL($url).'" method="post">'.
-		'<fieldset><legend>' . __('IP Lookup servers') . '</legend>'.
-		'<p><label for="bls">'.__('Add here a coma separated list of servers.').
+		'<form action="'.html::escapeURL($url).'" method="post" class="fieldset">'.
+		'<h3>' . __('IP Lookup servers') . '</h3>'.
+		'<p><label for="bls">'.__('Add here a coma separated list of servers.').'</label>'.
 		form::textarea('bls',40,3,html::escapeHTML($bls),'maximal').
 		'</p>'.
-		'<p><input type="submit" value="'.__('Save').'" /></label></p>'.
+		'<p><input type="submit" value="'.__('Save').'" />'.
 		$this->core->formNonce().'</p>'.
-		'</fieldset>'.
 		'</form>';
 
Index: plugins/antispam/filters/class.dc.filter.words.php
===================================================================
--- plugins/antispam/filters/class.dc.filter.words.php	(revision 1179)
+++ plugins/antispam/filters/class.dc.filter.words.php	(revision 1512)
@@ -17,8 +17,4 @@
 	public $name = 'Bad Words';
 
-	private $style_list = 'height: 200px; overflow: auto; margin-bottom: 1em; ';
-	private $style_p = 'margin: 1px 0 0 0; padding: 0.2em 0.5em; ';
-	private $style_global = 'background: #ccff99; ';
-
 	private $con;
 	private $table;
@@ -120,9 +116,9 @@
 		$res .=
 		'<form action="'.html::escapeURL($url).'" method="post" class="fieldset">'.
-		'<p><label class="classic" for="swa">'.__('Add a word ').' '.form::field('swa',20,128).'</label>';
+		'<p><label class="classic" for="swa">'.__('Add a word ').'</label> '.form::field('swa',20,128);
 
 		if ($core->auth->isSuperAdmin()) {
-			$res .= '<label class="classic" for="globalsw">'.form::checkbox('globalsw',1).' '.
-			__('Global word (used for all blogs)').'</label> ';
+			$res .= '<label class="classic" for="globalsw">'.form::checkbox('globalsw',1).'</label> '.
+			__('Global word (used for all blogs)');
 		}
 
@@ -143,5 +139,5 @@
 			'<form action="'.html::escapeURL($url).'" method="post" class="fieldset">'.
 			'<h3>' . __('List of bad words') . '</h3>'.
-			'<div style="'.$this->style_list.'">';
+			'<div class="antispam">';
 
 			$res_global = '';
@@ -150,11 +146,13 @@
 			{
 				$disabled_word = false;
-				$p_style = $this->style_p;
+
+				$p_style = '';
+
 				if (!$rs->blog_id) {
 					$disabled_word = !$core->auth->isSuperAdmin();
-					$p_style .= $this->style_global;
+					$p_style .= ' global';
 				}
 
-				$item = '<p style="'.$p_style.'"><label class="classic" for="word-'.$rs->rule_id.'">'.
+				$item = '<p class="'.$p_style.'"><label class="classic" for="word-'.$rs->rule_id.'">'.
 					form::checkbox(array('swd[]', 'word-'.$rs->rule_id),$rs->rule_id,false,'','',$disabled_word).' '.
 					html::escapeHTML($rs->rule_content).
Index: plugins/antispam/index.php
===================================================================
--- plugins/antispam/index.php	(revision 1274)
+++ plugins/antispam/index.php	(revision 1553)
@@ -123,6 +123,10 @@
 if ($filter_gui !== false)
 {
-	echo '<h2>'.html::escapeHTML($core->blog->name).' &rsaquo; <a href="'.$p_url.'">'.$page_name.'</a>'.
-		' &rsaquo; <span class="page-title">'.sprintf(__('%s configuration'),$filter->name).'</span></h2>';
+	echo dcPage::breadcrumb(
+		array(
+			__('Plugins') => '',
+			$page_name => $p_url,
+			'<span class="page-title">'.sprintf(__('%s filter configuration'),$filter->name).'</span>' => ''
+		));
 
 	echo $filter_gui;
@@ -130,5 +134,9 @@
 else
 {
-	echo '<h2>'.html::escapeHTML($core->blog->name).' &rsaquo; <span class="page-title">'.$page_name.'</span></h2>';
+	echo dcPage::breadcrumb(
+		array(
+			__('Plugins') => '',
+			'<span class="page-title">'.$page_name.'</span>' => ''
+		));
 
 	# Information
@@ -139,8 +147,8 @@
 	echo
 	'<form action="'.$p_url.'" method="post" class="fieldset">'.
-	'<h3>'.__('Information').'</h3>';
+	'<h3>'.__('Informations').'</h3>';
 
 	if (!empty($_GET['del'])) {
-		dcPage::message(__('Spam comments have been successfully deleted.'));
+		dcPage::success(__('Spam comments have been successfully deleted.'));
 	}
 
@@ -162,6 +170,6 @@
 	if ($moderationTTL != null && $moderationTTL >=0) {
 		echo '<p>'.sprintf(__('All spam comments older than %s day(s) will be automatically deleted.'), $moderationTTL).' '.
-		sprintf(__('You can modify this duration in the %s'),'<a href="blog_pref.php#antispam_moderation_ttl"> '.__('Blog preferences').'</a>').
-			'</p>';
+		sprintf(__('You can modify this duration in the %s'),'<a href="blog_pref.php#antispam_moderation_ttl"> '.__('Blog settings').'</a>').
+			'.</p>';
 	}
 	echo '</form>';
@@ -170,13 +178,13 @@
 	# Filters
 	echo
-	'<form action="'.$p_url.'" method="post" class="fieldset" id="filters-form">';
+	'<form action="'.$p_url.'" method="post" id="filters-list-form">';
 
 	if (!empty($_GET['upd'])) {
-		dcPage::message(__('Filters configuration has been successfully saved.'));
+		dcPage::success(__('Filters configuration has been successfully saved.'));
 	}
 
 	echo
 	'<table class="dragable">'.
-	'<caption>'.__('Available spam filters').'</caption>'.
+	'<caption class="as_h3">'.__('Available spam filters').'</caption>'.
 	'<thead><tr>'.
 	'<th>'.__('Order').'</th>'.
Index: plugins/antispam/style.css
===================================================================
--- plugins/antispam/style.css	(revision 0)
+++ plugins/antispam/style.css	(revision 1516)
@@ -8,5 +8,4 @@
 	margin: 0.5em 0;
 	padding-left: 16px;
-	/*background: url(index.php?pf=antispam/feed.png) no-repeat center left;*/
 	background-color: transparent;
 	background-position: center left;
@@ -22,2 +21,15 @@
 	background-image: url(index.php?pf=antispam/feed.png);
 }
+/* ---------------------------------------------------------- listing of IPs / bad words */
+.antispam {
+	height: 200px;
+	overflow: auto;
+	margin-bottom: 1em;
+}
+.antispam p {
+	margin: 1px 0 0 0;
+	padding: 0.2em 0.5em;
+}
+.antispam p.global {
+	background: #fec;
+}
Index: plugins/attachments/_admin.php
===================================================================
--- plugins/attachments/_admin.php	(revision 1537)
+++ plugins/attachments/_admin.php	(revision 1620)
@@ -12,51 +12,59 @@
 if (!defined('DC_CONTEXT_ADMIN')) { return; }
 
-$core->addBehavior ('adminPostFormSidebar',array('attachmentAdmin','adminPostFormSidebar'));
+$core->addBehavior ('adminPostFormItems',array('attachmentAdmin','adminPostFormItems'));
 $core->addBehavior ('adminPostAfterForm',array('attachmentAdmin','adminPostAfterForm'));
+$core->addBehavior('adminPostHeaders',array('attachmentAdmin','postHeaders'));
+$core->addBehavior ('adminPageFormItems',array('attachmentAdmin','adminPostFormItems'));
+$core->addBehavior ('adminPageAfterForm',array('attachmentAdmin','adminPostAfterForm'));
+$core->addBehavior('adminPageHeaders',array('attachmentAdmin','postHeaders'));
 
 class attachmentAdmin
 {
-	public static function adminPostFormSidebar($post) 
+	public static function postHeaders()
+	{
+		return 
+		'<script type="text/javascript" src="index.php?pf=attachments/js/post.js"></script>';
+	}
+	public static function adminPostFormItems($main,$sidebar,$post) 
 	{
 		if ($post !== null)
 		{
 			$core =& $GLOBALS['core'];
-			if ( isset($core->media) ) {
-				$post_media = $core->media->getPostMedia($post->post_id);
-				echo
-				'<h3 class="clear">'.__('Attachments').'</h3>';
-				foreach ($post_media as $f)
-				{
-					$ftitle = $f->media_title;
-					if (strlen($ftitle) > 18) {
-						$ftitle = substr($ftitle,0,16).'...';
-					}
-					echo
-					'<div class="media-item">'.
-					'<a class="media-icon" href="media_item.php?id='.$f->media_id.'">'.
-					'<img src="'.$f->media_icon.'" alt="" title="'.$f->basename.'" /></a>'.
-					'<ul>'.
-					'<li><a class="media-link" href="media_item.php?id='.$f->media_id.'" '.
-					'title="'.$f->basename.'">'.$ftitle.'</a></li>'.
-					'<li>'.$f->media_dtstr.'</li>'.
-					'<li>'.files::size($f->size).' - '.
-					'<a href="'.$f->file_url.'">'.__('open').'</a>'.'</li>'.
-					
-					'<li class="media-action"><a class="attachment-remove" id="attachment-'.$f->media_id.'" '.
-					'href="post_media.php?post_id='.$post->post_id.'&amp;media_id='.$f->media_id.'&amp;remove=1">'.
-					'<img src="images/check-off.png" alt="'.__('remove').'" /></a>'.
-					'</li>'.
-					
-					'</ul>'.
-					'</div>';
+			$post_media = $core->media->getPostMedia($post->post_id);
+			$nb_media = count($post_media);
+			$title = !$nb_media ? __('Attachments') : sprintf(__('Attachments (%d)'),$nb_media);
+			$item = '<h5 class="clear s-attachments">'.$title.'</h5>';
+			foreach ($post_media as $f)
+			{
+				$ftitle = $f->media_title;
+				if (strlen($ftitle) > 18) {
+					$ftitle = substr($ftitle,0,16).'...';
 				}
-				unset($f);
+				$item .=
+				'<div class="media-item s-attachments">'.
+				'<a class="media-icon" href="media_item.php?id='.$f->media_id.'">'.
+				'<img src="'.$f->media_icon.'" alt="" title="'.$f->basename.'" /></a>'.
+				'<ul>'.
+				'<li><a class="media-link" href="media_item.php?id='.$f->media_id.'" '.
+				'title="'.$f->basename.'">'.$ftitle.'</a></li>'.
+				'<li>'.$f->media_dtstr.'</li>'.
+				'<li>'.files::size($f->size).' - '.
+				'<a href="'.$f->file_url.'">'.__('open').'</a>'.'</li>'.
+				
+				'<li class="media-action"><a class="attachment-remove" id="attachment-'.$f->media_id.'" '.
+				'href="post_media.php?post_id='.$post->post_id.'&amp;media_id='.$f->media_id.'&amp;remove=1">'.
+				'<img src="images/check-off.png" alt="'.__('remove').'" /></a>'.
+				'</li>'.
+				
+				'</ul>'.
+				'</div>';
 			}
+			unset($f);
 			
 			if (empty($post_media)) {
-				echo '<p>'.__('No attachment.').'</p>';
-			} else {
-			}
-			echo '<p><a class="button" href="media.php?post_id='.$post->post_id.'">'.__('Add files to this entry').'</a></p>';
+				$item .= '<p class="form-note s-attachments">'.__('No attachment.').'</p>';
+			} 
+			$item .= '<p class="s-attachments"><a class="button" href="media.php?post_id='.$post->post_id.'">'.__('Add files to this entry').'</a></p>';
+			$sidebar['metas-box']['items']['attachments']= $item;
 		}
 	}
Index: plugins/attachments/_public.php
===================================================================
--- plugins/attachments/_public.php	(revision 1266)
+++ plugins/attachments/_public.php	(revision 1280)
@@ -40,16 +40,12 @@
 		"<?php\n".
 		'if ($_ctx->posts !== null && $core->media) {'."\n".
-		'$_ctx->attachments = $core->media->getPostMedia($_ctx->posts->post_id, null, true);'."\n".
+			'$_ctx->attachments = new ArrayObject($core->media->getPostMedia($_ctx->posts->post_id));'."\n".
 		"?>\n".
 		
-		'<?php $attach_i = 0; ?>'. // LEGACY
-		'<?php while ($_ctx->attachments->fetch()) : ?>'.
-		
-		'<?php $GLOBALS[\'attach_i\'] = $attach_i; $attach_f = $_ctx->attachments; $GLOBALS[\'attach_f\'] = $attach_f;'. // LEGACY
-		'$_ctx->file_url = $attach_f->file_url; ?>'. // LEGACY
+		'<?php foreach ($_ctx->attachments as $attach_i => $attach_f) : '.
+		'$GLOBALS[\'attach_i\'] = $attach_i; $GLOBALS[\'attach_f\'] = $attach_f;'.
+		'$_ctx->file_url = $attach_f->file_url; ?>'.
 		$content.
-		'<?php $attach_i++; ?>'. // LEGACY
-		'<?php endwhile; '.
-		'$_ctx->attachments = null; ?>'.
+		'<?php endforeach; $_ctx->attachments = null; unset($attach_i,$attach_f,$_ctx->file_url); ?>'.
 		
 		"<?php } ?>\n";
@@ -64,5 +60,5 @@
 	{
 		return
-		"<?php if (\$_ctx->attachments->isStart()) : ?>".
+		"<?php if (\$attach_i == 0) : ?>".
 		$content.
 		"<?php endif; ?>";
@@ -75,5 +71,5 @@
 	{
 		return
-		"<?php if (\$_ctx->attachments->isEnd()) : ?>".
+		"<?php if (\$attach_i+1 == count(\$_ctx->attachments)) : ?>".
 		$content.
 		"<?php endif; ?>";
@@ -97,15 +93,15 @@
 		if (isset($attr['is_image'])) {
 			$sign = (boolean) $attr['is_image'] ? '' : '!';
-			$if[] = $sign.'$_ctx->attachments->media_image';
+			$if[] = $sign.'$attach_f->media_image';
 		}
 		
 		if (isset($attr['has_thumb'])) {
 			$sign = (boolean) $attr['has_thumb'] ? '' : '!';
-			$if[] = $sign.'isset($_ctx->attachments->media_thumb[\'sq\'])';
+			$if[] = $sign.'isset($attach_f->media_thumb[\'sq\'])';
 		}
 		
 		if (isset($attr['is_mp3'])) {
 			$sign = (boolean) $attr['is_mp3'] ? '==' : '!=';
-			$if[] = '$_ctx->attachments->type '.$sign.' "audio/mpeg3"';
+			$if[] = '$attach_f->type '.$sign.' "audio/mpeg3"';
 		}
 		
@@ -113,7 +109,7 @@
 			$sign = (boolean) $attr['is_flv'] ? '' : '!';
 			$if[] = $sign.
-				'($_ctx->attachments->type == "video/x-flv" || '.
-				'$_ctx->attachments->type == "video/mp4" || '.
-				'$_ctx->attachments->type == "video/x-m4v")';
+				'($attach_f->type == "video/x-flv" || '.
+				'$attach_f->type == "video/mp4" || '.
+				'$attach_f->type == "video/x-m4v")';
 		}
 		
@@ -131,5 +127,5 @@
 	{
 		$f = $GLOBALS['core']->tpl->getFilters($attr);
-		return '<?php echo '.sprintf($f,'$_ctx->attachments->type').'; ?>';
+		return '<?php echo '.sprintf($f,'$attach_f->type').'; ?>';
 	}
 	
@@ -140,5 +136,5 @@
 	{
 		$f = $GLOBALS['core']->tpl->getFilters($attr);
-		return '<?php echo '.sprintf($f,'$_ctx->attachments->media_type').'; ?>';
+		return '<?php echo '.sprintf($f,'$attach_f->media_type').'; ?>';
 	}
 	
@@ -149,5 +145,5 @@
 	{
 		$f = $GLOBALS['core']->tpl->getFilters($attr);
-		return '<?php echo '.sprintf($f,'$_ctx->attachments->basename').'; ?>';
+		return '<?php echo '.sprintf($f,'$attach_f->basename').'; ?>';
 	}
 	
@@ -162,7 +158,7 @@
 		$f = $GLOBALS['core']->tpl->getFilters($attr);
 		if (!empty($attr['full'])) {
-			return '<?php echo '.sprintf($f,'$_ctx->attachments->size').'; ?>';
-		}
-		return '<?php echo '.sprintf($f,'files::size($_ctx->attachments->size)').'; ?>';
+			return '<?php echo '.sprintf($f,'$attach_f->size').'; ?>';
+		}
+		return '<?php echo '.sprintf($f,'files::size($attach_f->size)').'; ?>';
 	}
 	
@@ -173,5 +169,5 @@
 	{
 		$f = $GLOBALS['core']->tpl->getFilters($attr);
-		return '<?php echo '.sprintf($f,'$_ctx->attachments->media_title').'; ?>';
+		return '<?php echo '.sprintf($f,'$attach_f->media_title').'; ?>';
 	}
 	
@@ -184,6 +180,6 @@
 		return
 		'<?php '.
-		'if (isset($_ctx->attachments->media_thumb[\'sq\'])) {'.
-			'echo '.sprintf($f,'$_ctx->attachments->media_thumb[\'sq\']').';'.
+		'if (isset($attach_f->media_thumb[\'sq\'])) {'.
+			'echo '.sprintf($f,'$attach_f->media_thumb[\'sq\']').';'.
 		'}'.
 		'?>';
@@ -196,5 +192,5 @@
 	{
 		$f = $GLOBALS['core']->tpl->getFilters($attr);
-		return '<?php echo '.sprintf($f,'$_ctx->attachments->file_url').'; ?>';
+		return '<?php echo '.sprintf($f,'$attach_f->file_url').'; ?>';
 	}
 	
Index: plugins/attachments/js/post.js
===================================================================
--- plugins/attachments/js/post.js	(revision 1606)
+++ plugins/attachments/js/post.js	(revision 1606)
@@ -0,0 +1,6 @@
+$(function() {
+	$('h5.s-attachments').toggleWithLegend($('.s-attachments').not('h5'),{
+		cookie: 'dcx_attachments',
+		legend_click: true
+	});
+});
Index: plugins/blogroll/_admin.php
===================================================================
--- plugins/blogroll/_admin.php	(revision 1179)
+++ plugins/blogroll/_admin.php	(revision 1502)
@@ -14,4 +14,6 @@
 $core->addBehavior('adminDashboardIcons','blogroll_dashboard');
 $core->addBehavior('adminDashboardFavs','blogroll_dashboard_favs');
+$core->addBehavior('adminUsersActionsHeaders','blogroll_users_actions_headers');
+
 function blogroll_dashboard($core,$icons)
 {
@@ -24,6 +26,10 @@
 		'usage,contentadmin',null,null));
 }
+function blogroll_users_actions_headers()
+{
+	return dcPage::jsLoad('index.php?pf=blogroll/_users_actions.js');
+}
 
-$_menu['Plugins']->addItem(__('Blogroll'),'plugin.php?p=blogroll','index.php?pf=blogroll/icon-small.png',
+$_menu['Blog']->addItem(__('Blogroll'),'plugin.php?p=blogroll','index.php?pf=blogroll/icon-small.png',
                 preg_match('/plugin.php\?p=blogroll(&.*)?$/',$_SERVER['REQUEST_URI']),
                 $core->auth->check('usage,contentadmin',$core->blog->id));
Index: plugins/blogroll/_users_actions.js
===================================================================
--- plugins/blogroll/_users_actions.js	(revision 1502)
+++ plugins/blogroll/_users_actions.js	(revision 1502)
@@ -0,0 +1,47 @@
+jQuery.fn.updateBlogrollPermissionsForm = function() {
+	return this.each(function() {
+		
+		var perms = {};
+		var re = /^perm\[(.+?)\]\[(.+?)\]$/;
+		var e,prop;
+		
+		// Building a nice object of form elements
+		for (var i=0; i<this.elements.length; i++) {
+			e = this.elements[i];
+			
+			if (e.name == undefined) {
+				continue;
+			}
+			var prop;
+			prop = e.name.match(re);
+			if (!prop) {
+				continue;
+			}
+			if (perms[prop[1]] == undefined) {
+				perms[prop[1]] = {};
+			}
+			perms[prop[1]][prop[2]] = e;
+			
+			// select related permissions for admin
+			if (prop[2] == 'admin') {
+				if (e.checked) {
+					admin(e,perms,re);
+				}
+				$(e).click(function(){
+					admin(this,perms,re);
+				});
+			}
+		}
+		
+		function admin(E,perms,re) {
+					P = E.name.match(re);
+					
+					perms[P[1]]['blogroll'].checked = E.checked;
+					perms[P[1]]['blogroll'].disabled = E.checked;
+		}
+	});
+};
+
+$(function() {
+	$('#permissions-form').updateBlogrollPermissionsForm();
+});
Index: plugins/blogroll/edit.php
===================================================================
--- plugins/blogroll/edit.php	(revision 1179)
+++ plugins/blogroll/edit.php	(revision 1553)
@@ -95,5 +95,13 @@
 
 <body>
-<?php echo '<p><a href="'.$p_url.'">'.__('Return to blogroll').'</a></p>'; ?>
+<?php
+	echo dcPage::breadcrumb(
+		array(
+			html::escapeHTML($core->blog->name) => '',
+			'<span class="page-title">'.__('Blogroll').'</span>' => $p_url
+		));
+?>
+
+<?php echo '<p><a class="back" href="'.$p_url.'">'.__('Return to blogroll').'</a></p>'; ?>
 
 <?php
@@ -101,13 +109,13 @@
 {
 	if (!empty($_GET['upd'])) {
-		dcPage::message(__('Category has been successfully updated'));
+		dcPage::success(__('Category has been successfully updated'));
 	}
 	
 	echo
 	'<form action="'.$p_url.'" method="post">'.
-	'<fieldset><legend>'.__('Edit category').'</legend>'.
-	
-	'<p><label for="link_desc" class="required classic"><abbr title="'.__('Required field').'">*</abbr> '.__('Title:').' '.
-	form::field('link_desc',30,255,html::escapeHTML($link_desc)).'</label> '.
+	'<h3>'.__('Edit category').'</h3>'.
+	
+	'<p><label for="link_desc" class="required classic"><abbr title="'.__('Required field').'">*</abbr> '.__('Title:').'</label> '.
+	form::field('link_desc',30,255,html::escapeHTML($link_desc)).
 	
 	form::hidden('edit',1).
@@ -115,5 +123,4 @@
 	$core->formNonce().
 	'<input type="submit" name="edit_cat" value="'.__('Save').'"/></p>'.
-	'</fieldset>'.
 	'</form>';
 }
@@ -121,36 +128,33 @@
 {
 	if (!empty($_GET['upd'])) {
-		dcPage::message(__('Link has been successfully updated'));
+		dcPage::success(__('Link has been successfully updated'));
 	}
 	
 	echo
-	'<form action="plugin.php" method="post">'.
-	'<fieldset class="two-cols"><legend>'.__('Edit link').'</legend>'.
-	
-	'<p class="col"><label for="link_title" class="required"><abbr title="'.__('Required field').'">*</abbr> '.__('Title:').' '.
-	form::field('link_title',30,255,html::escapeHTML($link_title)).'</label></p>'.
-	
-	'<p class="col"><label for="link_href" class="required"><abbr title="'.__('Required field').'">*</abbr> '.__('URL:').' '.
-	form::field('link_href',30,255,html::escapeHTML($link_href)).'</label></p>'.
-	
-	'<p class="col"><label for="link_desc">'.__('Description:').' '.
-	form::field('link_desc',30,255,html::escapeHTML($link_desc)).'</label></p>'.
-	
-	'<p class="col"><label for="link_lang">'.__('Language:').' '.
-	form::field('link_lang',5,5,html::escapeHTML($link_lang)).'</label></p>'.
-	
-	'<p>'.form::hidden('p','blogroll').
-	form::hidden('edit',1).
-	form::hidden('id',$id).
-	$core->formNonce().
-	'<input type="submit" name="edit_link" value="'.__('Save').'"/></p>'.
-	'</fieldset>'.
+	'<form action="plugin.php" method="post" class="two-cols fieldset">'.
+
+	'<div class="col30 first-col">'.
+	'<h3>'.__('Edit link').'</h3>'.
+	
+	'<p><label for="link_title" class="required"><abbr title="'.__('Required field').'">*</abbr> '.__('Title:').'</label> '.
+	form::field('link_title',30,255,html::escapeHTML($link_title)).'</p>'.
+	
+	'<p><label for="link_href" class="required"><abbr title="'.__('Required field').'">*</abbr> '.__('URL:').'</label> '.
+	form::field('link_href',30,255,html::escapeHTML($link_href)).'</p>'.
+	
+	'<p><label for="link_desc">'.__('Description:').'</label> '.
+	form::field('link_desc',30,255,html::escapeHTML($link_desc)).'</p>'.
+	
+	'<p><label for="link_lang">'.__('Language:').'</label> '.
+	form::field('link_lang',5,5,html::escapeHTML($link_lang)).'</p>'.
+	'</div>'.
 	
 	
 	# XFN nightmare
-	'<fieldset><legend>'.__('XFN').'</legend>'.
+	'<div class="col70 last-col">'.
+	'<h3>'.__('XFN informations').'</h3>'.
 	'<table class="noborder">'.
 	
-	'<tr>'.
+	'<tr class="line">'.
 	'<th>'.__('_xfn_Me').'</th>'.
 	'<td><p>'.'<label class="classic">'.
@@ -159,5 +163,5 @@
 	'</tr>'.
 	
-	'<tr>'.
+	'<tr class="line">'.
 	'<th>'.__('_xfn_Friendship').'</th>'.
 	'<td><p>'.
@@ -172,5 +176,5 @@
 	'</tr>'.
 	
-	'<tr>'.
+	'<tr class="line">'.
 	'<th>'.__('_xfn_Physical').'</th>'.
 	'<td><p>'.
@@ -180,5 +184,5 @@
 	'</tr>'.
 	
-	'<tr>'.
+	'<tr class="line">'.
 	'<th>'.__('_xfn_Professional').'</th>'.
 	'<td><p>'.
@@ -190,5 +194,5 @@
 	'</tr>'.
 	
-	'<tr>'.
+	'<tr class="line">'.
 	'<th>'.__('_xfn_Geographical').'</th>'.
 	'<td><p>'.
@@ -201,5 +205,5 @@
 	'</tr>'.
 	
-	'<tr>'.
+	'<tr class="line">'.
 	'<th>'.__('_xfn_Family').'</th>'.
 	'<td><p>'.
@@ -218,5 +222,5 @@
 	'</tr>'.
 	
-	'<tr>'.
+	'<tr class="line">'.
 	'<th>'.__('_xfn_Romantic').'</th>'.
 	'<td><p>'.
@@ -233,5 +237,10 @@
 	'</table>'.
 	
-	'</fieldset>'.
+	'</div>'.
+	'<p class="clear">'.form::hidden('p','blogroll').
+	form::hidden('edit',1).
+	form::hidden('id',$id).
+	$core->formNonce().
+	'<input type="submit" name="edit_link" value="'.__('Save').'"/></p>'.
 	
 	'</form>';
Index: plugins/blogroll/index.php
===================================================================
--- plugins/blogroll/index.php	(revision 1504)
+++ plugins/blogroll/index.php	(revision 1553)
@@ -177,25 +177,31 @@
 
 <body>
-<h2><?php echo html::escapeHTML($core->blog->name); ?> &rsaquo; <span class="page-title"><?php echo __('Blogroll'); ?></span></h2>
+<?php
+	echo dcPage::breadcrumb(
+		array(
+			html::escapeHTML($core->blog->name) => '',
+			'<span class="page-title">'.__('Blogroll').'</span>' => ''
+		));
+?>
 
 <?php
 if (!empty($_GET['neworder'])) {
-	dcPage::message(__('Items order has been successfully updated'));
+	dcPage::success(__('Items order has been successfully updated'));
 }
 
 if (!empty($_GET['removed'])) {
-	dcPage::message(__('Items have been successfully removed.'));
+	dcPage::success(__('Items have been successfully removed.'));
 }
 
 if (!empty($_GET['addlink'])) {
-	dcPage::message(__('Link has been successfully created.'));
+	dcPage::success(__('Link has been successfully created.'));
 }
 
 if (!empty($_GET['addcat'])) {
-	dcPage::message(__('category has been successfully created.'));
+	dcPage::success(__('category has been successfully created.'));
 }
 
 if (!empty($_GET['importlinks'])) {
-	dcPage::message(__('links have been successfully imported.'));
+	dcPage::success(__('links have been successfully imported.'));
 }
 ?>
@@ -277,24 +283,23 @@
 '<div class="multi-part clear" id="add-link" title="'.__('Add a link').'">'.
 '<form action="plugin.php" method="post" id="add-link-form">'.
-'<fieldset><legend>'.__('Add a new link').'</legend>'.
-'<p class="col"><label for="link_title" class="required"><abbr title="'.__('Required field').'">*</abbr> '.__('Title:').' '.
+'<h3>'.__('Add a new link').'</h3>'.
+'<p class="col"><label for="link_title" class="required"><abbr title="'.__('Required field').'">*</abbr> '.__('Title:').'</label> '.
 form::field('link_title',30,255,$link_title).
-'</label></p>'.
-
-'<p class="col"><label for="link_href" class="required"><abbr title="'.__('Required field').'">*</abbr> '.__('URL:').' '.
+'</p>'.
+
+'<p class="col"><label for="link_href" class="required"><abbr title="'.__('Required field').'">*</abbr> '.__('URL:').'</label> '.
 form::field('link_href',30,255,$link_href).
-'</label></p>'.
-
-'<p class="col"><label for="link_desc">'.__('Description:').' '.
+'</p>'.
+
+'<p class="col"><label for="link_desc">'.__('Description:').'</label> '.
 form::field('link_desc',30,255,$link_desc).
-'</label></p>'.
-
-'<p class="col"><label for="link_lang">'.__('Language:').' '.
+'</p>'.
+
+'<p class="col"><label for="link_lang">'.__('Language:').'</label> '.
 form::field('link_lang',5,5,$link_lang).
-'</label></p>'.
+'</p>'.
 '<p>'.form::hidden(array('p'),'blogroll').
 $core->formNonce().
 '<input type="submit" name="add_link" value="'.__('Save').'" /></p>'.
-'</fieldset>'.
 '</form>'.
 '</div>';
@@ -303,11 +308,10 @@
 '<div class="multi-part" id="add-cat" title="'.__('Add a category').'">'.
 '<form action="plugin.php" method="post" id="add-category-form">'.
-'<fieldset><legend>'.__('Add a new category').'</legend>'.
-'<p><label for="cat_title" class=" classic required"><abbr title="'.__('Required field').'">*</abbr> '.__('Title:').' '.
-form::field('cat_title',30,255,$cat_title).'</label> '.
+'<h3>'.__('Add a new category').'</h3>'.
+'<p><label for="cat_title" class=" classic required"><abbr title="'.__('Required field').'">*</abbr> '.__('Title:').'</label> '.
+form::field('cat_title',30,255,$cat_title).' '.
 form::hidden(array('p'),'blogroll').
 $core->formNonce().
 '<input type="submit" name="add_cat" value="'.__('Save').'" /></p>'.
-'</fieldset>'.
 '</form>'.
 '</div>';
@@ -318,11 +322,10 @@
 	echo
 	'<form action="plugin.php" method="post" id="import-links-form" enctype="multipart/form-data">'.
-	'<fieldset><legend>'.__('Import links').'</legend>'.
-	'<p><label for="links_file" class=" classic required"><abbr title="'.__('Required field').'">*</abbr> '.__('OPML or XBEL File:').' '.
-	'<input type="file" id="links_file" name="links_file" /></label></p>'.
+	'<h3>'.__('Import links').'</h3>'.
+	'<p><label for="links_file" class=" classic required"><abbr title="'.__('Required field').'">*</abbr> '.__('OPML or XBEL File:').'</label> '.
+	'<input type="file" id="links_file" name="links_file" /></p>'.
 	'<p>'.form::hidden(array('p'),'blogroll').
 	$core->formNonce().
 	'<input type="submit" name="import_links" value="'.__('Import').'" /></p>'.
-	'</fieldset>'.
 	'</form>';
 }
@@ -330,5 +333,5 @@
 	echo
 	'<form action="plugin.php" method="post" id="import-links-form">'.
-	'<fieldset><legend>'.__('Import links').'</legend>';
+	'<h3>'.__('Import links').'</h3>';
 	if (empty($imported)) {
 		echo '<p>'.__('Nothing to import').'</p>';
@@ -371,5 +374,4 @@
 	}
 	echo
-	'</fieldset>'.
 	'</form>';
 }
Index: plugins/blogroll/locales/en/help/blogroll.html
===================================================================
--- plugins/blogroll/locales/en/help/blogroll.html	(revision 215)
+++ plugins/blogroll/locales/en/help/blogroll.html	(revision 1573)
@@ -6,5 +6,4 @@
 <body>
 
-<h3>Blogroll</h3>
 <p>Blogroll allows you to display on your blog a list of links to other blogs or websites that 
 you wish to suggest to your visitors. </p>
Index: plugins/blogroll/locales/fr/help/blogroll.html
===================================================================
--- plugins/blogroll/locales/fr/help/blogroll.html	(revision 215)
+++ plugins/blogroll/locales/fr/help/blogroll.html	(revision 1573)
@@ -6,5 +6,4 @@
 <body>
 
-<h3>Liens</h3>
 <p>La gestion des liens vous permet d'afficher sur votre blog un "blogroll" ou liste de liens vers d'autres blogs ou sites que vous souhaitez porter à l'attention de vos visiteurs.</p>
 <dl>
Index: plugins/blowupConfig/_public.php
===================================================================
--- plugins/blowupConfig/_public.php	(revision 1179)
+++ plugins/blowupConfig/_public.php	(revision 1436)
@@ -23,172 +23,7 @@
 	public static function publicHeadContent($core)
 	{
-		echo '<style type="text/css">'."\n".self::blowUpStyleHelper()."\n</style>\n";
-	}
-
-	public static function blowUpStyleHelper()
-	{
-		$s = $GLOBALS['core']->blog->settings->themes->blowup_style;
-
-		if ($s === null) {
-			return;
-		}
-
-		$s = @unserialize($s);
-		if (!is_array($s)) {
-			return;
-		}
-
-		$css = array();
-
-		/* Sidebar position
-		---------------------------------------------- */
-		if ($s['sidebar_position'] == 'left') {
-			$css['#wrapper']['background-position'] = '-300px 0';
-			$css['#main']['float'] = 'right';
-			$css['#sidebar']['float'] = 'left';
-		}
-
-		/* Properties
-		---------------------------------------------- */
-		self::prop($css,'body','background-color',$s['body_bg_c']);
-
-		self::prop($css,'body','color',$s['body_txt_c']);
-		self::prop($css,'.post-tags li a:link, .post-tags li a:visited, .post-info-co a:link, .post-info-co a:visited','color',$s['body_txt_c']);
-		self::prop($css,'#page','font-size',$s['body_txt_s']);
-		self::prop($css,'body','font-family',blowupConfig::fontDef($s['body_txt_f']));
-
-		self::prop($css,'.post-content, .post-excerpt, #comments dd, #pings dd, dd.comment-preview','line-height',$s['body_line_height']);
-
-		if (!$s['blog_title_hide'])
-		{
-			self::prop($css,'#top h1 a','color',$s['blog_title_c']);
-			self::prop($css,'#top h1','font-size',$s['blog_title_s']);
-			self::prop($css,'#top h1','font-family',blowupConfig::fontDef($s['blog_title_f']));
-
-			if ($s['blog_title_a'] == 'right' || $s['blog_title_a'] == 'left') {
-				$css['#top h1'][$s['blog_title_a']] = '0px';
-				$css['#top h1']['width'] = 'auto';
-			}
-
-			if ($s['blog_title_p'])
-			{
-				$_p = explode(':',$s['blog_title_p']);
-				$css['#top h1']['top'] = $_p[1].'px';
-				if ($s['blog_title_a'] != 'center') {
-					$_a = $s['blog_title_a'] == 'right' ? 'right' : 'left';
-					$css['#top h1'][$_a] = $_p[0].'px';
-				}
-			}
-		}
-		else
-		{
-			self::prop($css,'#top h1 span','text-indent','-5000px');
-			self::prop($css,'#top h1','top','0px');
-			$css['#top h1 a'] = array(
-				'display' => 'block',
-				'height' => $s['top_height'] ? ($s['top_height']-10).'px' : '120px',
-				'width' => '800px'
-			);
-		}
-		self::prop($css,'#top','height',$s['top_height']);
-
-		self::prop($css,'.day-date','color',$s['date_title_c']);
-		self::prop($css,'.day-date','font-family',blowupConfig::fontDef($s['date_title_f']));
-		self::prop($css,'.day-date','font-size',$s['date_title_s']);
-
-		self::prop($css,'a','color',$s['body_link_c']);
-		self::prop($css,'a:visited','color',$s['body_link_v_c']);
-		self::prop($css,'a:hover, a:focus, a:active','color',$s['body_link_f_c']);
-
-		self::prop($css,'#comment-form input, #comment-form textarea','color',$s['body_link_c']);
-		self::prop($css,'#comment-form input.preview','color',$s['body_link_c']);
-		self::prop($css,'#comment-form input.preview:hover','background',$s['body_link_f_c']);
-		self::prop($css,'#comment-form input.preview:hover','border-color',$s['body_link_f_c']);
-		self::prop($css,'#comment-form input.submit','color',$s['body_link_c']);
-		self::prop($css,'#comment-form input.submit:hover','background',$s['body_link_f_c']);
-		self::prop($css,'#comment-form input.submit:hover','border-color',$s['body_link_f_c']);
-
-		self::prop($css,'#sidebar','font-family',blowupConfig::fontDef($s['sidebar_text_f']));
-		self::prop($css,'#sidebar','font-size',$s['sidebar_text_s']);
-		self::prop($css,'#sidebar','color',$s['sidebar_text_c']);
-
-		self::prop($css,'#sidebar h2','font-family',blowupConfig::fontDef($s['sidebar_title_f']));
-		self::prop($css,'#sidebar h2','font-size',$s['sidebar_title_s']);
-		self::prop($css,'#sidebar h2','color',$s['sidebar_title_c']);
-
-		self::prop($css,'#sidebar h3','font-family',blowupConfig::fontDef($s['sidebar_title2_f']));
-		self::prop($css,'#sidebar h3','font-size',$s['sidebar_title2_s']);
-		self::prop($css,'#sidebar h3','color',$s['sidebar_title2_c']);
-
-		self::prop($css,'#sidebar ul','border-top-color',$s['sidebar_line_c']);
-		self::prop($css,'#sidebar li','border-bottom-color',$s['sidebar_line_c']);
-		self::prop($css,'#topnav ul','border-bottom-color',$s['sidebar_line_c']);
-
-		self::prop($css,'#sidebar li a','color',$s['sidebar_link_c']);
-		self::prop($css,'#sidebar li a:visited','color',$s['sidebar_link_v_c']);
-		self::prop($css,'#sidebar li a:hover, #sidebar li a:focus, #sidebar li a:active','color',$s['sidebar_link_f_c']);
-		self::prop($css,'#search input','color',$s['sidebar_link_c']);
-		self::prop($css,'#search .submit','color',$s['sidebar_link_c']);
-		self::prop($css,'#search .submit:hover','background',$s['sidebar_link_f_c']);
-		self::prop($css,'#search .submit:hover','border-color',$s['sidebar_link_f_c']);
-
-		self::prop($css,'.post-title','color',$s['post_title_c']);
-		self::prop($css,'.post-title a, .post-title a:visited','color',$s['post_title_c']);
-		self::prop($css,'.post-title','font-family',blowupConfig::fontDef($s['post_title_f']));
-		self::prop($css,'.post-title','font-size',$s['post_title_s']);
-
-		self::prop($css,'#comments dd','background-color',$s['post_comment_bg_c']);
-		self::prop($css,'#comments dd','color',$s['post_comment_c']);
-		self::prop($css,'#comments dd.me','background-color',$s['post_commentmy_bg_c']);
-		self::prop($css,'#comments dd.me','color',$s['post_commentmy_c']);
-
-		self::prop($css,'#prelude, #prelude a','color',$s['prelude_c']);
-
-		self::prop($css,'#footer p','background-color',$s['footer_bg_c']);
-		self::prop($css,'#footer p','color',$s['footer_c']);
-		self::prop($css,'#footer p','font-size',$s['footer_s']);
-		self::prop($css,'#footer p','font-family',blowupConfig::fontDef($s['footer_f']));
-		self::prop($css,'#footer p a','color',$s['footer_l_c']);
-
-		/* Images
-		------------------------------------------------------ */
-		self::backgroundImg($css,'body',$s['body_bg_c'],'body-bg.png');
-		self::backgroundImg($css,'body',$s['body_bg_g'] != 'light','body-bg.png');
-		self::backgroundImg($css,'body',$s['prelude_c'],'body-bg.png');
-		self::backgroundImg($css,'#top',$s['body_bg_c'],'page-t.png');
-		self::backgroundImg($css,'#top',$s['body_bg_g'] != 'light','page-t.png');
-		self::backgroundImg($css,'#top',$s['uploaded'] || $s['top_image'],'page-t.png');
-		self::backgroundImg($css,'#footer',$s['body_bg_c'],'page-b.png');
-		self::backgroundImg($css,'#comments dt',$s['post_comment_bg_c'],'comment-t.png');
-		self::backgroundImg($css,'#comments dd',$s['post_comment_bg_c'],'comment-b.png');
-		self::backgroundImg($css,'#comments dt.me',$s['post_commentmy_bg_c'],'commentmy-t.png');
-		self::backgroundImg($css,'#comments dd.me',$s['post_commentmy_bg_c'],'commentmy-b.png');
-
-		$res = '';
-		foreach ($css as $selector => $values) {
-			$res .= $selector." {\n";
-			foreach ($values as $k => $v) {
-				$res .= $k.':'.$v.";\n";
-			}
-			$res .= "}\n";
-		}
-
-		$res .= $s['extra_css'];
-
-		return $res;
-	}
-
-	protected static function prop(&$css,$selector,$prop,$value)
-	{
-		if ($value) {
-			$css[$selector][$prop] = $value;
-		}
-	}
-
-	protected static function backgroundImg(&$css,$selector,$value,$image)
-	{
-		$file = blowupConfig::imagesPath().'/'.$image;
-		if ($value && file_exists($file)){
-			$css[$selector]['background-image'] = 'url('.blowupConfig::imagesURL().'/'.$image.')';
+		$url = blowupConfig::publicCssUrlHelper();
+		if ($url) {
+			echo '<link rel="stylesheet" href="'.$url.'" type="text/css" />';
 		}
 	}
Index: plugins/blowupConfig/config.js
===================================================================
--- plugins/blowupConfig/config.js	(revision 89)
+++ plugins/blowupConfig/config.js	(revision 1499)
@@ -49,5 +49,5 @@
 	
 	$('#theme_config').prepend(styles_combo);
-	$(styles_combo).wrap('<fieldset></fieldset>').before('<legend>' + dotclear.msg.predefined_styles + '</legend>').wrap('<p></p>');
+	$(styles_combo).wrap('<div class="fieldset"></div>').before('<h3>' + dotclear.msg.predefined_styles + '</h3>').wrap('<p></p>');
 	
 	$(styles_combo).change(function() {
@@ -62,5 +62,5 @@
 	
 	// Code import
-	var e = $('#bu_export ~ fieldset:first');
+	var e = $('#bu_export_content');
 	e.toggle();
 	
Index: plugins/blowupConfig/index.php
===================================================================
--- plugins/blowupConfig/index.php	(revision 1179)
+++ plugins/blowupConfig/index.php	(revision 1588)
@@ -15,4 +15,5 @@
 
 $can_write_images = blowupConfig::canWriteImages();
+$can_write_css = blowupConfig::canWriteCss();
 
 if ($core->error->flag()) {
@@ -188,4 +189,9 @@
 			$blowup_user['prelude_c'] = blowupConfig::adjustColor($_POST['prelude_c']);
 			blowupConfig::createImages($blowup_user,$uploaded);
+		}
+
+		if ($can_write_css)
+		{
+			blowupConfig::createCss($blowup_user);
 		}
 
@@ -221,8 +227,13 @@
 <body>
 <?php
-echo
-'<h2>'.html::escapeHTML($core->blog->name).
-' &rsaquo; <a href="blog_theme.php">'.__('Blog appearance').'</a> &rsaquo; <span class="page-title">'.__('Blowup configuration').'</span></h2>'.
-'<p><a class="back" href="blog_theme.php">'.__('back').'</a></p>';
+echo dcPage::breadcrumb(
+	array(
+		html::escapeHTML($core->blog->name) => '',
+		__('Blog appearance') => 'blog_theme.php',
+		'<span class="page-title">'.__('Blowup configuration').'</span>' => ''
+	));
+
+echo
+'<p><a class="back" href="blog_theme.php">'.__('Back to Blog appearance').'</a></p>';
 
 
@@ -233,51 +244,50 @@
 
 if (!empty($_GET['upd'])) {
-	dcPage::message(__('Theme configuration has been successfully updated.'));
+	dcPage::success(__('Theme configuration has been successfully updated.'));
 }
 
 echo '<form id="theme_config" action="'.$p_url.'" method="post" enctype="multipart/form-data">';
 
-echo '<fieldset><legend>'.__('General').'</legend>';
+echo '<div class="fieldset"><h3>'.__('Customization').'</h3>'.
+'<h4>'.__('General').'</h4>';
 
 if ($can_write_images) {
 	echo
-	'<p class="field"><label for="body_bg_c">'.__('Background color:').' '.
-	form::field('body_bg_c',7,7,$blowup_user['body_bg_c'],'colorpicker').'</label></p>'.
-
-	'<p class="field"><label for="body_bg_g">'.__('Background color fill:').' '.
-	form::combo('body_bg_g',$gradient_types,$blowup_user['body_bg_g']).'</label></p>';
-}
-
-echo
-'<p class="field"><label for="body_txt_f">'.__('Main text font:').' '.
-form::combo('body_txt_f',blowupConfig::fontsList(),$blowup_user['body_txt_f']).'</label></p>'.
-
-'<p class="field"><label for="body_txt_s">'.__('Main text font size:').' '.
-form::field('body_txt_s',7,7,$blowup_user['body_txt_s']).'</label></p>'.
-
-'<p class="field"><label for="body_txt_c">'.__('Main text color:').' '.
-form::field('body_txt_c',7,7,$blowup_user['body_txt_c'],'colorpicker').'</label></p>'.
-
-'<p class="field"><label for="body_line_height">'.__('Text line height:').' '.
-form::field('body_line_height',7,7,$blowup_user['body_line_height']).'</label></p>'.
-'</fieldset>'.
-
-'<fieldset><legend>'.__('Links').'</legend>'.
-'<p class="field"><label for="body_link_c">'.__('Links color:').' '.
-form::field('body_link_c',7,7,$blowup_user['body_link_c'],'colorpicker').'</label></p>'.
-
-'<p class="field"><label for="body_link_v_c">'.__('Visited links color:').' '.
-form::field('body_link_v_c',7,7,$blowup_user['body_link_v_c'],'colorpicker').'</label></p>'.
-
-'<p class="field"><label for="body_link_f_c">'.__('Focus links color:').' '.
-form::field('body_link_f_c',7,7,$blowup_user['body_link_f_c'],'colorpicker').'</label></p>'.
-'</fieldset>'.
-
-'<fieldset><legend>'.__('Page top').'</legend>';
+	'<p class="field"><label for="body_bg_c">'.__('Background color:').'</label> '.
+	form::field('body_bg_c',7,7,$blowup_user['body_bg_c'],'colorpicker').'</p>'.
+
+	'<p class="field"><label for="body_bg_g">'.__('Background color fill:').'</label> '.
+	form::combo('body_bg_g',$gradient_types,$blowup_user['body_bg_g']).'</p>';
+}
+
+echo
+'<p class="field"><label for="body_txt_f">'.__('Main text font:').'</label> '.
+form::combo('body_txt_f',blowupConfig::fontsList(),$blowup_user['body_txt_f']).'</p>'.
+
+'<p class="field"><label for="body_txt_s">'.__('Main text font size:').'</label> '.
+form::field('body_txt_s',7,7,$blowup_user['body_txt_s']).'</p>'.
+
+'<p class="field"><label for="body_txt_c">'.__('Main text color:').'</label> '.
+form::field('body_txt_c',7,7,$blowup_user['body_txt_c'],'colorpicker').'</p>'.
+
+'<p class="field"><label for="body_line_height">'.__('Text line height:').'</label> '.
+form::field('body_line_height',7,7,$blowup_user['body_line_height']).'</p>'.
+
+'<h4 class="border-top">'.__('Links').'</h4>'.
+'<p class="field"><label for="body_link_c">'.__('Links color:').'</label> '.
+form::field('body_link_c',7,7,$blowup_user['body_link_c'],'colorpicker').'</p>'.
+
+'<p class="field"><label for="body_link_v_c">'.__('Visited links color:').'</label> '.
+form::field('body_link_v_c',7,7,$blowup_user['body_link_v_c'],'colorpicker').'</p>'.
+
+'<p class="field"><label for="body_link_f_c">'.__('Focus links color:').'</label> '.
+form::field('body_link_f_c',7,7,$blowup_user['body_link_f_c'],'colorpicker').'</p>'.
+
+'<h4 class="border-top">'.__('Page top').'</h4>';
 
 if ($can_write_images) {
 	echo
-	'<p class="field"><label for="prelude_c">'.__('Prelude color:').' '.
-	form::field('prelude_c',7,7,$blowup_user['prelude_c'],'colorpicker').'</label></p>';
+	'<p class="field"><label for="prelude_c">'.__('Prelude color:').'</label> '.
+	form::field('prelude_c',7,7,$blowup_user['prelude_c'],'colorpicker').'</p>';
 }
 
@@ -286,19 +296,18 @@
 form::checkbox('blog_title_hide',1,$blowup_user['blog_title_hide']).'</label></p>'.
 
-'<p class="field"><label for="blog_title_f">'.__('Main title font:').' '.
-form::combo('blog_title_f',blowupConfig::fontsList(),$blowup_user['blog_title_f']).'</label></p>'.
-
-'<p class="field"><label for="blog_title_s">'.__('Main title font size:').' '.
-form::field('blog_title_s',7,7,$blowup_user['blog_title_s']).'</label></p>'.
-
-'<p class="field"><label for="blog_title_c">'.__('Main title color:').' '.
-form::field('blog_title_c',7,7,$blowup_user['blog_title_c'],'colorpicker').'</label></p>'.
-
-'<p class="field"><label for="blog_title_a">'.__('Main title alignment:').' '.
-form::combo('blog_title_a',array(__('center')=>'center',__('left')=>'left',__('right')=>'right'),$blowup_user['blog_title_a']).'</label></p>'.
-
-'<p class="field"><label for="blog_title_p">'.__('Main title position (x:y)').' '.
-form::field('blog_title_p',7,7,$blowup_user['blog_title_p']).'</label></p>'.
-'</fieldset>';
+'<p class="field"><label for="blog_title_f">'.__('Main title font:').'</label> '.
+form::combo('blog_title_f',blowupConfig::fontsList(),$blowup_user['blog_title_f']).'</p>'.
+
+'<p class="field"><label for="blog_title_s">'.__('Main title font size:').'</label> '.
+form::field('blog_title_s',7,7,$blowup_user['blog_title_s']).'</p>'.
+
+'<p class="field"><label for="blog_title_c">'.__('Main title color:').'</label> '.
+form::field('blog_title_c',7,7,$blowup_user['blog_title_c'],'colorpicker').'</p>'.
+
+'<p class="field"><label for="blog_title_a">'.__('Main title alignment:').'</label> '.
+form::combo('blog_title_a',array(__('center')=>'center',__('left')=>'left',__('right')=>'right'),$blowup_user['blog_title_a']).'</p>'.
+
+'<p class="field"><label for="blog_title_p">'.__('Main title position (x:y)').'</label> '.
+form::field('blog_title_p',7,7,$blowup_user['blog_title_p']).'</p>';
 
 if ($can_write_images) {
@@ -310,129 +319,125 @@
 
 	echo
-	'<fieldset><legend>'.__('Top image').'</legend>'.
-	'<p class="field"><label for="top_image">'.__('Top image').
-	form::combo('top_image',$top_images,($blowup_user['top_image'] ? $blowup_user['top_image'] : 'default')).'</label></p>'.
+	'<h4 class="border-top">'.__('Top image').'</h4>'.
+	'<p class="field"><label for="top_image">'.__('Top image').'</label> '.
+	form::combo('top_image',$top_images,($blowup_user['top_image'] ? $blowup_user['top_image'] : 'default')).'</p>'.
 	'<p>'.__('Choose "Custom..." to upload your own image.').'</p>'.
 
-	'<p id="uploader"><label for="upfile">'.__('Add your image:').
+	'<p id="uploader"><label for="upfile">'.__('Add your image:').'</label> '.
 	' ('.sprintf(__('JPEG or PNG file, 800 pixels wide, maximum size %s'),files::size(DC_MAX_UPLOAD_SIZE)).')'.
 	'<input type="file" name="upfile" id="upfile" size="35" />'.
-	'</label></p>'.
-
-	'<h3>'.__('Preview').'</h3>'.
+	'</p>'.
+
+	'<h5>'.__('Preview').'</h5>'.
 	'<div class="grid" style="width:800px;border:1px solid #ccc;">'.
 	'<img style="display:block;" src="'.$preview_image.'" alt="" id="image-preview" />'.
-	'</div>'.
-	'</fieldset>';
-}
-
-echo
-'<fieldset><legend>'.__('Sidebar').'</legend>'.
-'<p class="field"><label for="sidebar_position">'.__('Sidebar position:').' '.
-form::combo('sidebar_position',array(__('right')=>'right',__('left')=>'left'),$blowup_user['sidebar_position']).'</label></p>'.
-
-'<p class="field"><label for="sidebar_text_f">'.__('Sidebar text font:').' '.
-form::combo('sidebar_text_f',blowupConfig::fontsList(),$blowup_user['sidebar_text_f']).'</label></p>'.
-
-'<p class="field"><label for="sidebar_text_s">'.__('Sidebar text font size:').' '.
-form::field('sidebar_text_s',7,7,$blowup_user['sidebar_text_s']).'</label></p>'.
-
-'<p class="field"><label for="sidebar_text_c">'.__('Sidebar text color:').' '.
-form::field('sidebar_text_c',7,7,$blowup_user['sidebar_text_c'],'colorpicker').'</label></p>'.
-
-'<p class="field"><label for="sidebar_title_f">'.__('Sidebar titles font:').' '.
-form::combo('sidebar_title_f',blowupConfig::fontsList(),$blowup_user['sidebar_title_f']).'</label></p>'.
-
-'<p class="field"><label for="sidebar_title_s">'.__('Sidebar titles font size:').' '.
-form::field('sidebar_title_s',7,7,$blowup_user['sidebar_title_s']).'</label></p>'.
-
-'<p class="field"><label for="sidebar_title_c">'.__('Sidebar titles color:').' '.
-form::field('sidebar_title_c',7,7,$blowup_user['sidebar_title_c'],'colorpicker').'</label></p>'.
-
-'<p class="field"><label for="sidebar_title2_f">'.__('Sidebar 2nd level titles font:').' '.
-form::combo('sidebar_title2_f',blowupConfig::fontsList(),$blowup_user['sidebar_title2_f']).'</label></p>'.
-
-'<p class="field"><label for="sidebar_title2_s">'.__('Sidebar 2nd level titles font size:').' '.
-form::field('sidebar_title2_s',7,7,$blowup_user['sidebar_title2_s']).'</label></p>'.
-
-'<p class="field"><label for="sidebar_title2_c">'.__('Sidebar 2nd level titles color:').' '.
-form::field('sidebar_title2_c',7,7,$blowup_user['sidebar_title2_c'],'colorpicker').'</label></p>'.
-
-'<p class="field"><label for="sidebar_line_c">'.__('Sidebar lines color:').' '.
-form::field('sidebar_line_c',7,7,$blowup_user['sidebar_line_c'],'colorpicker').'</label></p>'.
-
-'<p class="field"><label for="sidebar_link_c">'.__('Sidebar links color:').' '.
-form::field('sidebar_link_c',7,7,$blowup_user['sidebar_link_c'],'colorpicker').'</label></p>'.
-
-'<p class="field"><label for="sidebar_link_v_c">'.__('Sidebar visited links color:').' '.
-form::field('sidebar_link_v_c',7,7,$blowup_user['sidebar_link_v_c'],'colorpicker').'</label></p>'.
-
-'<p class="field"><label for="sidebar_link_f_c">'.__('Sidebar focus links color:').' '.
-form::field('sidebar_link_f_c',7,7,$blowup_user['sidebar_link_f_c'],'colorpicker').'</label></p>'.
-'</fieldset>'.
-
-'<fieldset><legend>'.__('Entries').'</legend>'.
-'<p class="field"><label for="date_title_f">'.__('Date title font:').' '.
-form::combo('date_title_f',blowupConfig::fontsList(),$blowup_user['date_title_f']).'</label></p>'.
-
-'<p class="field"><label for="date_title_s">'.__('Date title font size:').' '.
-form::field('date_title_s',7,7,$blowup_user['date_title_s']).'</label></p>'.
-
-'<p class="field"><label for="date_title_c">'.__('Date title color:').' '.
-form::field('date_title_c',7,7,$blowup_user['date_title_c'],'colorpicker').'</label></p>'.
-
-'<p class="field"><label for="post_title_f">'.__('Entry title font:').' '.
-form::combo('post_title_f',blowupConfig::fontsList(),$blowup_user['post_title_f']).'</label></p>'.
-
-'<p class="field"><label for="post_title_s">'.__('Entry title font size:').' '.
-form::field('post_title_s',7,7,$blowup_user['post_title_s']).'</label></p>'.
-
-'<p class="field"><label for="post_title_c">'.__('Entry title color:').' '.
-form::field('post_title_c',7,7,$blowup_user['post_title_c'],'colorpicker').'</label></p>';
+	'</div>';
+}
+
+echo
+'<h4 class="border-top">'.__('Sidebar').'</h4>'.
+'<p class="field"><label for="sidebar_position">'.__('Sidebar position:').'</label> '.
+form::combo('sidebar_position',array(__('right')=>'right',__('left')=>'left'),$blowup_user['sidebar_position']).'</p>'.
+
+'<p class="field"><label for="sidebar_text_f">'.__('Sidebar text font:').'</label> '.
+form::combo('sidebar_text_f',blowupConfig::fontsList(),$blowup_user['sidebar_text_f']).'</p>'.
+
+'<p class="field"><label for="sidebar_text_s">'.__('Sidebar text font size:').'</label> '.
+form::field('sidebar_text_s',7,7,$blowup_user['sidebar_text_s']).'</p>'.
+
+'<p class="field"><label for="sidebar_text_c">'.__('Sidebar text color:').'</label> '.
+form::field('sidebar_text_c',7,7,$blowup_user['sidebar_text_c'],'colorpicker').'</p>'.
+
+'<p class="field"><label for="sidebar_title_f">'.__('Sidebar titles font:').'</label> '.
+form::combo('sidebar_title_f',blowupConfig::fontsList(),$blowup_user['sidebar_title_f']).'</p>'.
+
+'<p class="field"><label for="sidebar_title_s">'.__('Sidebar titles font size:').'</label> '.
+form::field('sidebar_title_s',7,7,$blowup_user['sidebar_title_s']).'</p>'.
+
+'<p class="field"><label for="sidebar_title_c">'.__('Sidebar titles color:').'</label> '.
+form::field('sidebar_title_c',7,7,$blowup_user['sidebar_title_c'],'colorpicker').'</p>'.
+
+'<p class="field"><label for="sidebar_title2_f">'.__('Sidebar 2nd level titles font:').'</label> '.
+form::combo('sidebar_title2_f',blowupConfig::fontsList(),$blowup_user['sidebar_title2_f']).'</p>'.
+
+'<p class="field"><label for="sidebar_title2_s">'.__('Sidebar 2nd level titles font size:').'</label> '.
+form::field('sidebar_title2_s',7,7,$blowup_user['sidebar_title2_s']).'</p>'.
+
+'<p class="field"><label for="sidebar_title2_c">'.__('Sidebar 2nd level titles color:').'</label> '.
+form::field('sidebar_title2_c',7,7,$blowup_user['sidebar_title2_c'],'colorpicker').'</p>'.
+
+'<p class="field"><label for="sidebar_line_c">'.__('Sidebar lines color:').'</label> '.
+form::field('sidebar_line_c',7,7,$blowup_user['sidebar_line_c'],'colorpicker').'</p>'.
+
+'<p class="field"><label for="sidebar_link_c">'.__('Sidebar links color:').'</label> '.
+form::field('sidebar_link_c',7,7,$blowup_user['sidebar_link_c'],'colorpicker').'</p>'.
+
+'<p class="field"><label for="sidebar_link_v_c">'.__('Sidebar visited links color:').'</label> '.
+form::field('sidebar_link_v_c',7,7,$blowup_user['sidebar_link_v_c'],'colorpicker').'</p>'.
+
+'<p class="field"><label for="sidebar_link_f_c">'.__('Sidebar focus links color:').'</label> '.
+form::field('sidebar_link_f_c',7,7,$blowup_user['sidebar_link_f_c'],'colorpicker').'</p>'.
+
+'<h4 class="border-top">'.__('Entries').'</h4>'.
+'<p class="field"><label for="date_title_f">'.__('Date title font:').'</label> '.
+form::combo('date_title_f',blowupConfig::fontsList(),$blowup_user['date_title_f']).'</p>'.
+
+'<p class="field"><label for="date_title_s">'.__('Date title font size:').'</label> '.
+form::field('date_title_s',7,7,$blowup_user['date_title_s']).'</p>'.
+
+'<p class="field"><label for="date_title_c">'.__('Date title color:').'</label> '.
+form::field('date_title_c',7,7,$blowup_user['date_title_c'],'colorpicker').'</p>'.
+
+'<p class="field"><label for="post_title_f">'.__('Entry title font:').'</label> '.
+form::combo('post_title_f',blowupConfig::fontsList(),$blowup_user['post_title_f']).'</p>'.
+
+'<p class="field"><label for="post_title_s">'.__('Entry title font size:').'</label> '.
+form::field('post_title_s',7,7,$blowup_user['post_title_s']).'</p>'.
+
+'<p class="field"><label for="post_title_c">'.__('Entry title color:').'</label> '.
+form::field('post_title_c',7,7,$blowup_user['post_title_c'],'colorpicker').'</p>';
 
 if ($can_write_images) {
 	echo
-	'<p class="field"><label for="post_comment_bg_c">'.__('Comment background color:').' '.
-	form::field('post_comment_bg_c',7,7,$blowup_user['post_comment_bg_c'],'colorpicker').'</label></p>';
-}
-
-echo
-'<p class="field"><label for="post_comment_c">'.__('Comment text color:').' '.
-form::field('post_comment_c',7,7,$blowup_user['post_comment_c'],'colorpicker').'</label></p>';
+	'<p class="field"><label for="post_comment_bg_c">'.__('Comment background color:').'</label> '.
+	form::field('post_comment_bg_c',7,7,$blowup_user['post_comment_bg_c'],'colorpicker').'</p>';
+}
+
+echo
+'<p class="field"><label for="post_comment_c">'.__('Comment text color:').'</label> '.
+form::field('post_comment_c',7,7,$blowup_user['post_comment_c'],'colorpicker').'</p>';
 
 if ($can_write_images) {
 	echo
-	'<p class="field"><label for="post_commentmy_bg_c">'.__('My comment background color:').' '.
-	form::field('post_commentmy_bg_c',7,7,$blowup_user['post_commentmy_bg_c'],'colorpicker').'</label></p>';
-}
-
-echo
-'<p class="field"><label for="post_commentmy_c">'.__('My comment text color:').' '.
-form::field('post_commentmy_c',7,7,$blowup_user['post_commentmy_c'],'colorpicker').'</label></p>'.
-'</fieldset>'.
-
-'<fieldset><legend>'.__('Footer').'</legend>'.
-'<p class="field"><label for="footer_f">'.__('Footer font:').' '.
-form::combo('footer_f',blowupConfig::fontsList(),$blowup_user['footer_f']).'</label></p>'.
-
-'<p class="field"><label for="footer_s">'.__('Footer font size:').' '.
-form::field('footer_s',7,7,$blowup_user['footer_s']).'</label></p>'.
-
-'<p class="field"><label for="footer_c">'.__('Footer color:').' '.
-form::field('footer_c',7,7,$blowup_user['footer_c'],'colorpicker').'</label></p>'.
-
-'<p class="field"><label for="footer_l_c">'.__('Footer links color:').' '.
-form::field('footer_l_c',7,7,$blowup_user['footer_l_c'],'colorpicker').'</label></p>'.
-
-'<p class="field"><label for="footer_bg_c">'.__('Footer background color:').' '.
-form::field('footer_bg_c',7,7,$blowup_user['footer_bg_c'],'colorpicker').'</label></p>'.
-'</fieldset>';
-
-echo
-'<fieldset><legend>'.__('Additional CSS').'</legend>'.
-'<p><label for="extra_css">'.__('Any additional CSS styles (must be written using the CSS syntax):').' '.
+	'<p class="field"><label for="post_commentmy_bg_c">'.__('My comment background color:').'</label> '.
+	form::field('post_commentmy_bg_c',7,7,$blowup_user['post_commentmy_bg_c'],'colorpicker').'</p>';
+}
+
+echo
+'<p class="field"><label for="post_commentmy_c">'.__('My comment text color:').'</label> '.
+form::field('post_commentmy_c',7,7,$blowup_user['post_commentmy_c'],'colorpicker').'</p>'.
+
+'<h4 class="border-top">'.__('Footer').'</h4>'.
+'<p class="field"><label for="footer_f">'.__('Footer font:').'</label> '.
+form::combo('footer_f',blowupConfig::fontsList(),$blowup_user['footer_f']).'</p>'.
+
+'<p class="field"><label for="footer_s">'.__('Footer font size:').'</label> '.
+form::field('footer_s',7,7,$blowup_user['footer_s']).'</p>'.
+
+'<p class="field"><label for="footer_c">'.__('Footer color:').'</label> '.
+form::field('footer_c',7,7,$blowup_user['footer_c'],'colorpicker').'</p>'.
+
+'<p class="field"><label for="footer_l_c">'.__('Footer links color:').'</label> '.
+form::field('footer_l_c',7,7,$blowup_user['footer_l_c'],'colorpicker').'</p>'.
+
+'<p class="field"><label for="footer_bg_c">'.__('Footer background color:').'</label> '.
+form::field('footer_bg_c',7,7,$blowup_user['footer_bg_c'],'colorpicker').'</p>';
+
+echo
+'<h4 class="border-top">'.__('Additional CSS').'</h4>'.
+'<p><label for="extra_css">'.__('Any additional CSS styles (must be written using the CSS syntax):').'</label> '.
 form::textarea('extra_css',72,5,html::escapeHTML($blowup_user['extra_css']),'maximal','',false,'title="'.__('Additional CSS').'"').
-'</label></p>'.
-'</fieldset>';
+'</p>'.
+'</div>';
 
 
@@ -450,8 +455,11 @@
 }
 echo
-'<h3 id="bu_export">'.__('Configuration import / export').'</h3><fieldset>'.
+'<div class="fieldset">'.
+'<h3 id="bu_export">'.__('Configuration import / export').'</h3>'.
+'<div id="bu_export_content">'.
 '<p>'.__('You can share your configuration using the following code. To apply a configuration, paste the code, click on "Apply code" and save.').'</p>'.
 '<p>'.form::textarea('export_code',72,5,implode('; ',$tmp_array),'maximal','',false,'title="'.__('Copy this code:').'"').'</p>'.
-'</fieldset>';
+'</div>'.
+'</div>';
 
 echo
Index: plugins/blowupConfig/lib/class.blowup.config.php
===================================================================
--- plugins/blowupConfig/lib/class.blowup.config.php	(revision 1179)
+++ plugins/blowupConfig/lib/class.blowup.config.php	(revision 1436)
@@ -141,4 +141,246 @@
 	}
 
+	public static function cssPath()
+	{
+		global $core;
+		return path::real($core->blog->public_path).'/blowup-css';
+	}
+
+	public static function cssURL()
+	{
+		global $core;
+		return $core->blog->settings->system->public_url.'/blowup-css';
+	}
+
+	public static function canWriteCss($create=false)
+	{
+		global $core;
+
+		$public = path::real($core->blog->public_path);
+		$css = self::cssPath();
+
+		if (!is_dir($public)) {
+			$core->error->add(__('The \'public\' directory does not exist.'));
+			return false;
+		}
+
+		if (!is_dir($css)) {
+			if (!is_writable($public)) {
+				$core->error->add(sprintf(__('The \'%s\' directory cannot be modified.'),'public'));
+				return false;
+			}
+			if ($create) {
+				files::makeDir($css);
+			}
+			return true;
+		}
+
+		if (!is_writable($css)) {
+			$core->error->add(sprintf(__('The \'%s\' directory cannot be modified.'),'public/blowup-css'));
+			return false;
+		}
+
+		return true;
+	}
+
+	public static function createCss($s)
+	{
+		global $core;
+		
+		if ($s === null) {
+			return;
+		}
+
+		$css = array();
+
+		/* Sidebar position
+		---------------------------------------------- */
+		if ($s['sidebar_position'] == 'left') {
+			$css['#wrapper']['background-position'] = '-300px 0';
+			$css['#main']['float'] = 'right';
+			$css['#sidebar']['float'] = 'left';
+		}
+
+		/* Properties
+		---------------------------------------------- */
+		self::prop($css,'body','background-color',$s['body_bg_c']);
+
+		self::prop($css,'body','color',$s['body_txt_c']);
+		self::prop($css,'.post-tags li a:link, .post-tags li a:visited, .post-info-co a:link, .post-info-co a:visited','color',$s['body_txt_c']);
+		self::prop($css,'#page','font-size',$s['body_txt_s']);
+		self::prop($css,'body','font-family',self::fontDef($s['body_txt_f']));
+
+		self::prop($css,'.post-content, .post-excerpt, #comments dd, #pings dd, dd.comment-preview','line-height',$s['body_line_height']);
+
+		if (!$s['blog_title_hide'])
+		{
+			self::prop($css,'#top h1 a','color',$s['blog_title_c']);
+			self::prop($css,'#top h1','font-size',$s['blog_title_s']);
+			self::prop($css,'#top h1','font-family',self::fontDef($s['blog_title_f']));
+
+			if ($s['blog_title_a'] == 'right' || $s['blog_title_a'] == 'left') {
+				$css['#top h1'][$s['blog_title_a']] = '0px';
+				$css['#top h1']['width'] = 'auto';
+			}
+
+			if ($s['blog_title_p'])
+			{
+				$_p = explode(':',$s['blog_title_p']);
+				$css['#top h1']['top'] = $_p[1].'px';
+				if ($s['blog_title_a'] != 'center') {
+					$_a = $s['blog_title_a'] == 'right' ? 'right' : 'left';
+					$css['#top h1'][$_a] = $_p[0].'px';
+				}
+			}
+		}
+		else
+		{
+			self::prop($css,'#top h1 span','text-indent','-5000px');
+			self::prop($css,'#top h1','top','0px');
+			$css['#top h1 a'] = array(
+				'display' => 'block',
+				'height' => $s['top_height'] ? ($s['top_height']-10).'px' : '120px',
+				'width' => '800px'
+			);
+		}
+		self::prop($css,'#top','height',$s['top_height']);
+
+		self::prop($css,'.day-date','color',$s['date_title_c']);
+		self::prop($css,'.day-date','font-family',self::fontDef($s['date_title_f']));
+		self::prop($css,'.day-date','font-size',$s['date_title_s']);
+
+		self::prop($css,'a','color',$s['body_link_c']);
+		self::prop($css,'a:visited','color',$s['body_link_v_c']);
+		self::prop($css,'a:hover, a:focus, a:active','color',$s['body_link_f_c']);
+
+		self::prop($css,'#comment-form input, #comment-form textarea','color',$s['body_link_c']);
+		self::prop($css,'#comment-form input.preview','color',$s['body_link_c']);
+		self::prop($css,'#comment-form input.preview:hover','background',$s['body_link_f_c']);
+		self::prop($css,'#comment-form input.preview:hover','border-color',$s['body_link_f_c']);
+		self::prop($css,'#comment-form input.submit','color',$s['body_link_c']);
+		self::prop($css,'#comment-form input.submit:hover','background',$s['body_link_f_c']);
+		self::prop($css,'#comment-form input.submit:hover','border-color',$s['body_link_f_c']);
+
+		self::prop($css,'#sidebar','font-family',self::fontDef($s['sidebar_text_f']));
+		self::prop($css,'#sidebar','font-size',$s['sidebar_text_s']);
+		self::prop($css,'#sidebar','color',$s['sidebar_text_c']);
+
+		self::prop($css,'#sidebar h2','font-family',self::fontDef($s['sidebar_title_f']));
+		self::prop($css,'#sidebar h2','font-size',$s['sidebar_title_s']);
+		self::prop($css,'#sidebar h2','color',$s['sidebar_title_c']);
+
+		self::prop($css,'#sidebar h3','font-family',self::fontDef($s['sidebar_title2_f']));
+		self::prop($css,'#sidebar h3','font-size',$s['sidebar_title2_s']);
+		self::prop($css,'#sidebar h3','color',$s['sidebar_title2_c']);
+
+		self::prop($css,'#sidebar ul','border-top-color',$s['sidebar_line_c']);
+		self::prop($css,'#sidebar li','border-bottom-color',$s['sidebar_line_c']);
+		self::prop($css,'#topnav ul','border-bottom-color',$s['sidebar_line_c']);
+
+		self::prop($css,'#sidebar li a','color',$s['sidebar_link_c']);
+		self::prop($css,'#sidebar li a:visited','color',$s['sidebar_link_v_c']);
+		self::prop($css,'#sidebar li a:hover, #sidebar li a:focus, #sidebar li a:active','color',$s['sidebar_link_f_c']);
+		self::prop($css,'#search input','color',$s['sidebar_link_c']);
+		self::prop($css,'#search .submit','color',$s['sidebar_link_c']);
+		self::prop($css,'#search .submit:hover','background',$s['sidebar_link_f_c']);
+		self::prop($css,'#search .submit:hover','border-color',$s['sidebar_link_f_c']);
+
+		self::prop($css,'.post-title','color',$s['post_title_c']);
+		self::prop($css,'.post-title a, .post-title a:visited','color',$s['post_title_c']);
+		self::prop($css,'.post-title','font-family',self::fontDef($s['post_title_f']));
+		self::prop($css,'.post-title','font-size',$s['post_title_s']);
+
+		self::prop($css,'#comments dd','background-color',$s['post_comment_bg_c']);
+		self::prop($css,'#comments dd','color',$s['post_comment_c']);
+		self::prop($css,'#comments dd.me','background-color',$s['post_commentmy_bg_c']);
+		self::prop($css,'#comments dd.me','color',$s['post_commentmy_c']);
+
+		self::prop($css,'#prelude, #prelude a','color',$s['prelude_c']);
+
+		self::prop($css,'#footer p','background-color',$s['footer_bg_c']);
+		self::prop($css,'#footer p','color',$s['footer_c']);
+		self::prop($css,'#footer p','font-size',$s['footer_s']);
+		self::prop($css,'#footer p','font-family',self::fontDef($s['footer_f']));
+		self::prop($css,'#footer p a','color',$s['footer_l_c']);
+
+		/* Images
+		------------------------------------------------------ */
+		self::backgroundImg($css,'body',$s['body_bg_c'],'body-bg.png');
+		self::backgroundImg($css,'body',$s['body_bg_g'] != 'light','body-bg.png');
+		self::backgroundImg($css,'body',$s['prelude_c'],'body-bg.png');
+		self::backgroundImg($css,'#top',$s['body_bg_c'],'page-t.png');
+		self::backgroundImg($css,'#top',$s['body_bg_g'] != 'light','page-t.png');
+		self::backgroundImg($css,'#top',$s['uploaded'] || $s['top_image'],'page-t.png');
+		self::backgroundImg($css,'#footer',$s['body_bg_c'],'page-b.png');
+		self::backgroundImg($css,'#comments dt',$s['post_comment_bg_c'],'comment-t.png');
+		self::backgroundImg($css,'#comments dd',$s['post_comment_bg_c'],'comment-b.png');
+		self::backgroundImg($css,'#comments dt.me',$s['post_commentmy_bg_c'],'commentmy-t.png');
+		self::backgroundImg($css,'#comments dd.me',$s['post_commentmy_bg_c'],'commentmy-b.png');
+
+		$res = '';
+		foreach ($css as $selector => $values) {
+			$res .= $selector." {\n";
+			foreach ($values as $k => $v) {
+				$res .= $k.':'.$v.";\n";
+			}
+			$res .= "}\n";
+		}
+
+		$res .= $s['extra_css'];
+
+		if (!self::canWriteCss(true)) {
+			throw new Exception(__('Unable to create css file.'));
+		}
+
+		# erase old css file
+		self::dropCss($core->blog->settings->system->theme);
+
+		# create new css file into public blowup-css subdirectory
+		self::writeCss($core->blog->settings->system->theme, $res);
+
+		return $res;
+	}
+
+	protected static function prop(&$css,$selector,$prop,$value)
+	{
+		if ($value) {
+			$css[$selector][$prop] = $value;
+		}
+	}
+
+	protected static function backgroundImg(&$css,$selector,$value,$image)
+	{
+		$file = self::imagesPath().'/'.$image;
+		if ($value && file_exists($file)){
+			$css[$selector]['background-image'] = 'url('.self::imagesURL().'/'.$image.')';
+		}
+	}
+
+	private static function writeCss($theme,$css)
+	{
+		file_put_contents(self::cssPath().'/'.$theme.'.css', $css);
+	}
+	
+	public static function dropCss($theme)
+	{
+		$file = path::real(self::cssPath().'/'.$theme.'.css');
+		if (is_writable(dirname($file))) {
+			@unlink($file);
+		}
+	}
+
+	public static function publicCssUrlHelper()
+	{
+		$theme = $GLOBALS['core']->blog->settings->system->theme;
+		$url = blowupConfig::cssURL();
+		$path = blowupConfig::cssPath();
+
+		if (file_exists($path.'/'.$theme.'.css')) {
+			return $url.'/'.$theme.'.css';
+		}
+
+		return null;
+	}
+
 	public static function imagesPath()
 	{
Index: plugins/daInstaller/_admin.php
===================================================================
--- plugins/daInstaller/_admin.php	(revision 1046)
+++ plugins/daInstaller/_admin.php	(revision 1505)
Index: plugins/daInstaller/_define.php
===================================================================
--- plugins/daInstaller/_define.php	(revision 1046)
+++ plugins/daInstaller/_define.php	(revision 1568)
@@ -10,5 +10,5 @@
 $this->registerModule(
 	'daInstaller',
-	'Install and update your extensions live from DotAddict.org',
+	'Install and update your plugins live from DotAddict.org',
 	'Tomtom / DotAddict.org',
 	'1.0.3',
Index: plugins/daInstaller/_install.php
===================================================================
--- plugins/daInstaller/_install.php	(revision 1046)
+++ plugins/daInstaller/_install.php	(revision 1505)
Index: plugins/daInstaller/inc/lib.da.installer.ui.php
===================================================================
--- plugins/daInstaller/inc/lib.da.installer.ui.php	(revision 1046)
+++ plugins/daInstaller/inc/lib.da.installer.ui.php	(revision 1568)
@@ -34,5 +34,5 @@
 		}
 		else {
-			$msg_no_entry = __('No extension');
+			$msg_no_entry = __('No plugins');
 			$msg_th_label = __('Plugins');
 			$lineMethod   = 'pluginLine';
@@ -64,5 +64,5 @@
 				'</table>';
 			
-			echo '<p>'.__('Page(s)').' : '.$pager->getLinks().'</p>';
+			echo '<p class="pagination">'.__('Page(s)').' : '.$pager->getLinks().'</p>';
 			$blocks = explode('%s',$html_block);
 			echo $blocks[0];
@@ -81,5 +81,5 @@
 			}
 			echo $blocks[1];
-			echo '<p>'.__('Page(s)').' : '.$pager->getLinks().'</p>';
+			echo '<p class="pagination">'.__('Page(s)').' : '.$pager->getLinks().'</p>';
 		}
 	}
Index: plugins/daInstaller/index.php
===================================================================
--- plugins/daInstaller/index.php	(revision 1237)
+++ plugins/daInstaller/index.php	(revision 1569)
@@ -135,5 +135,5 @@
 {
 	$res = '';
-	$p_msg = '<p class="message">%s</p>';
+	$p_msg = '<p class="success">%s</p>';
 	$p_err = '<p class="error">%s</p>';
 	
@@ -163,5 +163,5 @@
 		}
 		else {
-			$res .= '<div class="static-msg">'.__('Following plugins have been updated:').'<ul>'.$upd.'</ul></div>';
+			$res .= '<div class="success">'.__('Following plugins have been updated:').'<ul>'.$upd.'</ul></div>';
 		}
 	}
@@ -183,10 +183,10 @@
 		}
 		else {
-			$res .= '<div class="static-msg">'.__('Following themes have been updated:').'<ul>'.$upd.'</ul></div>';
+			$res .= '<div class="success">'.__('Following themes have been updated:').'<ul>'.$upd.'</ul></div>';
 		}
 	}
 	# Plugins install settings messages
 	if (!empty($plugins_install['success'])) {
-		$res .= '<div class="static-msg">'.__('Following plugins have been installed:').'<ul>';
+		$res .= '<div class="success">'.__('Following plugins have been installed:').'<ul>';
 		foreach ($plugins_install['success'] as $k => $v) {
 			$res .= '<li>'.$k.'</li>';
@@ -255,7 +255,15 @@
 '</head>'.
 '<body>'.
-infoMessages().
-'<h2 class="page-title">'.__('DotAddict.org Installer').'</h2>'.
-'<p>'.__('Install and update your extensions live from DotAddict.org').'</p>';
+
+dcPage::breadcrumb(
+	array(
+		__('System') => '',
+		'<span class="page-title">'.__('DotAddict.org Installer').'</span>' => ''
+	)).
+
+infoMessages();
+
+echo
+'<p>'.__('Install and update your plugins live from DotAddict.org').'</p>';
 
 echo
@@ -265,5 +273,5 @@
 	echo
 	'<p><strong>'.__('Detected updates for your system').'</strong></p>'.
-	'<p class="form-note warn">'.
+	'<p class="warning">'.
 		__('Changes can be required after installation of updates. Click on a support link before to be aware about').
 	'</p>';
@@ -290,20 +298,17 @@
 '<!-- Search -->'.
 '<div class="multi-part" id="search" title="'.__('Search').'">'.
-	'<fieldset><legend>'.__('Search options').
-	'</legend>'.
-	'<form method="get" action="'.$p_url.'">'.
+	'<form method="get" action="'.$p_url.'" class="fieldset">'.
+	'<h3>'.__('Search').'</h3>'.
 	'<p>'.form::hidden('p','daInstaller').
-	'<label for="q" class="classic">'.__('Query:').'&nbsp; '.
-	form::field('q',30,255,html::escapeHTML($q)).
-	'</label> '.
-	'<label for="mode" class="classic">'.
+	'<label for="q" class="classic">'.__('Query:').'&nbsp;</label> '.
+	form::field('q',30,255,html::escapeHTML($q)).'</p>'.
+	'<p><label for="mode" class="classic">'.
 	form::radio(array('mode','mode'),'plugins',$mode == 'plugins').
 	' '.__('Plugins').'&nbsp;</label> '.
 	'<label for="mode2" class="classic">'.
-	form::radio(array('mode','mode2'),'themes',$mode == 'themes')
-	.' '.__('Themes').'&nbsp;</label> '.
-	'<input type="submit" value="'.__('Search').'" /></p>'.
-	'</form>'.
-	'</fieldset>';
+	form::radio(array('mode','mode2'),'themes',$mode == 'themes').
+	' '.__('Themes').'&nbsp;</label></p>'.
+	'<p><input type="submit" value="'.__('Search').'" /></p>'.
+	'</form>';
 if (!empty($q)) {
 	echo '<p><strong>'.sprintf(__('%u %s found'),$s_m_nb,__($mode)).'</strong></p>';
Index: plugins/daInstaller/locales/en/help/da_installer.html
===================================================================
--- plugins/daInstaller/locales/en/help/da_installer.html	(revision 1046)
+++ plugins/daInstaller/locales/en/help/da_installer.html	(revision 1573)
@@ -1,20 +1,18 @@
 <html>
 <head>
-  <title>Extension update</title>
+  <title>Plugin update</title>
 </head>
 
 <body>
 
-<h3>Update of extensions</h3>
-
 <dl>
   <dd>It is possible, in Dotclear 2, to specify in the configuration <em>(PATH)</em>
-  many paths of folders containing plugins. But, the extension update are done only in
+  many paths of folders containing plugins. But, the plugin update are done only in
   the <strong>last folder specify</strong> in <em>PATH</em>.
-  You may have, for several reasons, in other folders, an older extension than currently 
+  You may have, for several reasons, in other folders, an older plugin than currently 
   available on DotAddict. <strong>In this case</strong>, you have two choices: <ul>
 
   <li><strong>Autorize</strong> multi-installation: the newer version of the
-  extension will be download and installed in the last folder of <em>PATH</em>
+  plugin will be downloaded and installed in the last folder of <em>PATH</em>
   and the older one will be disabled (a _disabled file will be created in his folder). This 
   old version <strong>will not be deleted</strong></li>
Index: plugins/daInstaller/locales/fr/help/da_installer.html
===================================================================
--- plugins/daInstaller/locales/fr/help/da_installer.html	(revision 1046)
+++ plugins/daInstaller/locales/fr/help/da_installer.html	(revision 1573)
@@ -1,21 +1,19 @@
 <html>
 <head>
-  <title>Mise à jour d'extension(s)</title>
+  <title>Mise à jour de plugins</title>
 </head>
 
 <body>
 
-<h3>Mise à jour d'extension(s)</h3>
-
 <dl>
   <dd>Il est possible dans Dotclear 2 de spécifier dans sa configuration <em>(PATH)</em>
-  plusieurs chemins de dossiers contenant des extensions. Or, les mises à jour des
-  extensions se font dans <strong>le dernier répertoire</strong> du <em>PATH</em>.
-  Il se peut, pour des raisons variées, que dans un des premiers, il existe une
-  extension avec une version inférieure à celle présente sur DotAddict. <strong>Dans
+  plusieurs chemins de dossiers contenant des plugins. Or, les mises à jour des
+  plugins se font dans <strong>le dernier répertoire</strong> du <em>PATH</em>.
+  Il se peut, pour des raisons variées, que dans un des premiers, il existe un
+  plugin avec une version inférieure à celle présente sur DotAddict. <strong>Dans
   ce cas préçis</strong>, vous avez deux choix possibles : <ul>
-  <li><strong>Autoriser</strong> la multi-installation : la nouvelle version de
-  l’extension sera téléchargée puis installée dans le dernier répertoire du <em>PATH</em>
-  et l’ancienne extension recevera un fichier _disabled afin de la désactiver. L’ancienne
+  <li><strong>Autoriser</strong> la multi-installation : la nouvelle version du
+  plugin sera téléchargé puis installée dans le dernier répertoire du <em>PATH</em>
+  et l’ancien plugin recevera un fichier _disabled afin de le désactiver. L’ancienne
   version <strong>ne sera pas supprimée</strong></li>
   <li><strong>Ne pas autoriser</strong> la multi-installation : la nouvelle version
Index: plugins/daInstaller/locales/fr/main.po
===================================================================
--- plugins/daInstaller/locales/fr/main.po	(revision 1046)
+++ plugins/daInstaller/locales/fr/main.po	(revision 1568)
@@ -41,6 +41,6 @@
 msgstr "Aucun thème disponible"
 
-msgid "No extension"
-msgstr "Aucune extension disponible"
+msgid "No plugin"
+msgstr "Aucun plugin disponible"
 
 msgid "Lastest Version"
@@ -69,17 +69,17 @@
 
 msgid "No support available"
-msgstr "Aucun support disponible"
+msgstr "Aucun support disponible."
 
 msgid "The plugin has been successfully installed."
-msgstr "Le plugin a été installé avec succès"
+msgstr "Le plugin a été installé avec succès."
 
 msgid "The theme has been successfully installed."
-msgstr "Le thème a été installé avec succès"
+msgstr "Le thème a été installé avec succès."
 
 msgid "Following plugins have not been updated:"
-msgstr "Les extensions suivantes n'ont pas été mises à jour :"
+msgstr "Les plugins suivants n'ont pas été mis à jour :"
 
 msgid "Following plugins have been updated:"
-msgstr "Les extensions suivantes ont été mises à jour :"
+msgstr "Les plugins suivants ont été mis à jour :"
 
 msgid "Following themes have not been updated:"
@@ -89,6 +89,6 @@
 msgstr "Les thèmes suivants ont été mis à jour :"
 
-msgid "Install and update your extensions live from DotAddict.org"
-msgstr "Installez et mettez à jour vos extensions en direct depuis DotAddict.org"
+msgid "Install and update your plugins live from DotAddict.org"
+msgstr "Installez et mettez à jour vos plugins en direct depuis DotAddict.org"
 
 msgid "Available updates"
@@ -96,14 +96,14 @@
 
 msgid "Detected updates for your system"
-msgstr "Mises à jour détectées pour votre système"
+msgstr "Mises à jour détectées pour votre système."
 
 msgid "Changes can be required after installation of updates. Click on a support link before to be aware about"
-msgstr "Des changements sont peut être nécessaires après la mise à jour. Pensez à vérifier en cliquant sur le lien de support"
+msgstr "Des changements sont peut-être nécessaires après la mise à jour. Pensez à vérifier en cliquant sur le lien de support."
 
 msgid "No update available"
-msgstr "Aucune mise à jour détectée pour votre système"
+msgstr "Aucune mise à jour détectée pour votre système."
 
 msgid "Get more plugins"
-msgstr "Obtenir plus d'extensions"
+msgstr "Obtenir plus de plugins"
 
 #, php-format
Index: plugins/importExport/inc/class.dc.export.flat.php
===================================================================
--- plugins/importExport/inc/class.dc.export.flat.php	(revision 840)
+++ plugins/importExport/inc/class.dc.export.flat.php	(revision 1559)
@@ -191,7 +191,7 @@
 	{
 		echo
-		'<form action="'.$this->getURL(true).'" method="post">'.
-		'<fieldset><legend>'.__('Single blog').'</legend>'.
-		'<p>'.sprintf(__('This will create an export of your current blog: %s'),html::escapeHTML($this->core->blog->name)).'</p>'.
+		'<form action="'.$this->getURL(true).'" method="post" class="fieldset">'.
+		'<h3>'.__('Single blog').'</h3>'.
+		'<p>'.sprintf(__('This will create an export of your current blog: %s'),'<strong>'.html::escapeHTML($this->core->blog->name)).'</strong>.</p>'.
 		
 		'<p><label for="file_name">'.__('File name:').'</label>'.
@@ -211,5 +211,4 @@
 		$this->core->formNonce().'</p>'.
 		
-		'</fieldset>'.
 		'</form>';
 		
@@ -217,6 +216,6 @@
 		{
 			echo
-			'<form action="'.$this->getURL(true).'" method="post">'.
-			'<fieldset><legend>'.__('Multiple blogs').'</legend>'.
+			'<form action="'.$this->getURL(true).'" method="post" class="fieldset">'.
+			'<h3>'.__('Multiple blogs').'</h3>'.
 			'<p>'.__('This will create an export of all the content of your database.').'</p>'.
 			
@@ -234,5 +233,4 @@
 			$this->core->formNonce().'</p>'.
 			
-			'</fieldset>'.
 			'</form>';
 		}
Index: plugins/importExport/inc/class.dc.ieModule.php
===================================================================
--- plugins/importExport/inc/class.dc.ieModule.php	(revision 840)
+++ plugins/importExport/inc/class.dc.ieModule.php	(revision 1553)
@@ -73,5 +73,5 @@
 		return
 		'<h3>'.__('Congratulation!').'</h3>'.
-		'<p>'.__('Your blog has been successfully imported. Welcome on Dotclear 2!').'</p>'.
+		'<p class="success">'.__('Your blog has been successfully imported. Welcome on Dotclear 2!').'</p>'.
 		'<ul><li><strong><a href="post.php">'.__('Why don\'t you blog this now?').'</a></strong></li>'.
 		'<li>'.__('or').' <a href="index.php">'.__('visit your dashboard').'</a></li></ul>';
Index: plugins/importExport/inc/class.dc.import.dc1.php
===================================================================
--- plugins/importExport/inc/class.dc.import.dc1.php	(revision 840)
+++ plugins/importExport/inc/class.dc.import.dc1.php	(revision 1622)
@@ -143,25 +143,24 @@
 			case 1:
 				echo
-				'<p>'.sprintf(__('This will import your Dotclear 1.2 content as new content in the current blog: %s.'),
+				'<p>'.sprintf(__('Import the content of a Dotclear 1.2\'s blog in the current blog: %s.'),
 				'<strong>'.html::escapeHTML($this->core->blog->name).'</strong>').'</p>'.
-				'<p class="static-msg">'.__('Please note that this process '.
-				'will empty your categories, blogroll, entries and comments on the current blog.').'</p>'.
-				'<p>'.__('Depending on the size of your blog, it could take a few minutes.').'</p>';
+				'<p class="warning">'.__('Please note that this process '.
+				'will empty your categories, blogroll, entries and comments on the current blog.').'</p>';
 				
 				printf($this->imForm(1,__('General information'),__('Import my blog now')),
-				'<h3>'.__('We first need some information about your old Dotclear 1.2 installation.').'</h3>'.
-				'<p><label for="db_host">'.__('Database Host Name:').' '.
-				form::field('db_host',30,255,html::escapeHTML($this->vars['db_host'])).'</label></p>'.
-				'<p><label for="db_name">'.__('Database Name:',html::escapeHTML($this->vars['db_name'])).' '.
-				form::field('db_name',30,255,html::escapeHTML($this->vars['db_name'])).'</label></p>'.
-				'<p><label for="db_user">'.__('Database User Name:').' '.
-				form::field('db_user',30,255,html::escapeHTML($this->vars['db_user'])).'</label></p>'.
-				'<p><label for="db_pwd">'.__('Database Password:').' '.
-				form::password('db_pwd',30,255).'</label></p>'.
-				'<p><label for="db_prefix">'.__('Database Tables Prefix:').' '.
-				form::field('db_prefix',30,255,html::escapeHTML($this->vars['db_prefix'])).'</label></p>'.
-				'<h3>'.__('Entries import options').'</h3>'.
-				'<p><label for="post_limit">'.__('Number of entries to import at once:').' '.
-				form::field('post_limit',3,3,html::escapeHTML($this->vars['post_limit'])).'</label></p>'
+				'<p>'.__('We first need some information about your old Dotclear 1.2 installation.').'</p>'.
+				'<p><label for="db_host">'.__('Database Host Name:').'</label> '.
+				form::field('db_host',30,255,html::escapeHTML($this->vars['db_host'])).'</p>'.
+				'<p><label for="db_name">'.__('Database Name:',html::escapeHTML($this->vars['db_name'])).'</label> '.
+				form::field('db_name',30,255,html::escapeHTML($this->vars['db_name'])).'</p>'.
+				'<p><label for="db_user">'.__('Database User Name:').'</label> '.
+				form::field('db_user',30,255,html::escapeHTML($this->vars['db_user'])).'</p>'.
+				'<p><label for="db_pwd">'.__('Database Password:').'</label> '.
+				form::password('db_pwd',30,255).'</p>'.
+				'<p><label for="db_prefix">'.__('Database Tables Prefix:').'</label> '.
+				form::field('db_prefix',30,255,html::escapeHTML($this->vars['db_prefix'])).'</p>'.
+				'<h3 class="vertical-separator">'.__('Entries import options').'</h3>'.
+				'<p><label for="post_limit">'.__('Number of entries to import at once:').'</label> '.
+				form::field('post_limit',3,3,html::escapeHTML($this->vars['post_limit'])).'</p>'
 				);
 				break;
@@ -191,5 +190,5 @@
 			case 6:
 				echo 
-				'<h3>'.__('Please read carefully').'</h3>'.
+				'<h3 class="vertical-separator">'.__('Please read carefully').'</h3>'.
 				'<ul>'.
 				'<li>'.__('Every newly imported user has received a random password '.
@@ -217,10 +216,10 @@
 		return
 		'<form action="'.$this->getURL(true).'" method="post">'.
-		'<fieldset><legend>'.$legend.'</legend>'.
-		$this->core->formNonce().
+		'<h3 class="vertical-separator">'.$legend.'</h3>'.
+		'<div>'.$this->core->formNonce().
 		form::hidden(array('do'),'step'.$step).
-		'%s'.
-		'<p><input type="submit" value="'.$submit_value.'" /></p>'.
-		'</fieldset>'.
+		'%s'.'</div>'.
+		'<p class="vertical-separator"><input type="submit" value="'.$submit_value.'" /></p>'.
+		'<p class="form-note info">'.__('Depending on the size of your blog, it could take a few minutes.').'</p>'.
 		'</form>';
 	}
Index: plugins/importExport/inc/class.dc.import.feed.php
===================================================================
--- plugins/importExport/inc/class.dc.import.feed.php	(revision 907)
+++ plugins/importExport/inc/class.dc.import.feed.php	(revision 1559)
@@ -20,6 +20,6 @@
 	{
 		$this->type = 'import';
-		$this->name = __('Feed import');
-		$this->description = __('Imports a feed as new entries.');
+		$this->name = __('RSS or Atom feed import');
+		$this->description = __('Add a feed content to the blog.');
 	}
 	
@@ -77,11 +77,10 @@
 	{
 		if ($this->status) {
-			dcPage::message(__('Content successfully imported.'));
+			dcPage::success(__('Content successfully imported.'));
 		}
 		
 		echo
 		'<form action="'.$this->getURL(true).'" method="post">'.
-		'<fieldset><legend>'.__('Single blog').'</legend>'.
-		'<p>'.sprintf(__('This will import a feed (RSS or Atom) a as new content in the current blog: %s.'),html::escapeHTML($this->core->blog->name)).'</p>'.
+		'<p>'.sprintf(__('Add a feed content to the current blog: <strong>%s</strong>.'),html::escapeHTML($this->core->blog->name)).'</p>'.
 		
 		'<p><label for="feed_url">'.__('Feed URL:').'</label>'.
@@ -93,5 +92,4 @@
 		'<input type="submit" value="'.__('Import').'" /></p>'.
 		
-		'</fieldset>'.
 		'</form>';
 	}
Index: plugins/importExport/inc/class.dc.import.flat.php
===================================================================
--- plugins/importExport/inc/class.dc.import.flat.php	(revision 939)
+++ plugins/importExport/inc/class.dc.import.flat.php	(revision 1559)
@@ -142,10 +142,10 @@
 		if ($this->status == 'single')
 		{
-			dcPage::message(__('Single blog successfully imported.'));
+			dcPage::success(__('Single blog successfully imported.'));
 			return;
 		}
 		if ($this->status == 'full')
 		{
-			dcPage::message(__('Content successfully imported.'));
+			dcPage::success(__('Content successfully imported.'));
 			return;
 		}
@@ -180,18 +180,18 @@
 		
 		echo
-		'<form action="'.$this->getURL(true).'" method="post" enctype="multipart/form-data">'.
-		'<fieldset><legend>'.__('Single blog').'</legend>'.
-		'<p>'.sprintf(__('This will import a single blog backup as new content in the current blog: %s.'),html::escapeHTML($this->core->blog->name)).'</p>'.
+		'<form action="'.$this->getURL(true).'" method="post" enctype="multipart/form-data" class="fieldset">'.
+		'<h3>'.__('Single blog').'</h3>'.
+		'<p>'.sprintf(__('This will import a single blog backup as new content in the current blog: <strong>%s</strong>.'),html::escapeHTML($this->core->blog->name)).'</p>'.
 		
 		'<p><label for="up_single_file">'.__('Upload a backup file').
-		' ('.sprintf(__('Maximum size %s'),files::size(DC_MAX_UPLOAD_SIZE)).')'.'</label>'.
-		'<input type="file" id="up_single_file" name="up_single_file" size="20" />'.
+		' ('.sprintf(__('maximum size %s'),files::size(DC_MAX_UPLOAD_SIZE)).')'.' </label>'.
+		' <input type="file" id="up_single_file" name="up_single_file" size="20" />'.
 		'</p>';
 		
 		if ($has_files) {
 			echo 
-			'<p><label for="public_single_file">'.__('or pick up a local file in your public directory').' '.
+			'<p><label for="public_single_file" class="">'.__('or pick up a local file in your public directory').' </label> '.
 			form::combo('public_single_file',$public_files).
-			'</label></p>';
+			'</p>';
 		}
 		
@@ -203,5 +203,4 @@
 		'<input type="submit" value="'.__('Import').'" /></p>'.
 		
-		'</fieldset>'.
 		'</form>';
 		
@@ -209,10 +208,10 @@
 		{
 			echo
-			'<form action="'.$this->getURL(true).'" method="post" enctype="multipart/form-data" id="formfull">'.
-			'<fieldset><legend>'.__('Multiple blogs').'</legend>'.
-			'<p>'.__('This will reset all the content of your database, except users.').'</p>'.
-			
-			'<p><label for="up_full_file">'.__('Upload a backup file').
-			' ('.sprintf(__('Maximum size %s'),files::size(DC_MAX_UPLOAD_SIZE)).')'.'</label>'.
+			'<form action="'.$this->getURL(true).'" method="post" enctype="multipart/form-data" id="formfull" class="fieldset">'.
+			'<h3>'.__('Multiple blogs').'</h3>'.
+			'<p class="warning">'.__('This will reset all the content of your database, except users.').'</p>'.
+			
+			'<p><label for="up_full_file">'.__('Upload a backup file').' '.
+			' ('.sprintf(__('maximum size %s'),files::size(DC_MAX_UPLOAD_SIZE)).')'.' </label>'.
 			'<input type="file" id="up_full_file" name="up_full_file" size="20" />'.
 			'</p>';
@@ -220,5 +219,5 @@
 			if ($has_files) {
 				echo 
-				'<p><label for="public_full_file">'.__('or pick up a local file in your public directory').'</label>'.
+				'<p><label for="public_full_file">'.__('or pick up a local file in your public directory').' </label>'.
 				form::combo('public_full_file',$public_files).
 				'</p>';
@@ -235,5 +234,4 @@
 			'<input type="submit" value="'.__('Import').'" /></p>'.
 			
-			'</fieldset>'.
 			'</form>';
 		}
Index: plugins/importExport/inc/class.dc.import.wp.php
===================================================================
--- plugins/importExport/inc/class.dc.import.wp.php	(revision 1185)
+++ plugins/importExport/inc/class.dc.import.wp.php	(revision 1622)
@@ -176,21 +176,24 @@
 				'<p>'.sprintf(__('This will import your WordPress content as new content in the current blog: %s.'),
 				'<strong>'.html::escapeHTML($this->core->blog->name).'</strong>').'</p>'.
-				'<p class="static-msg">'.__('Please note that this process '.
-				'will empty your categories, blogroll, entries and comments on the current blog.').'</p>'.
-				'<p>'.__('Depending on the size of your blog, it could take a few minutes.').'</p>';
+				'<p class="warning">'.__('Please note that this process '.
+				'will empty your categories, blogroll, entries and comments on the current blog.').'</p>';
 				
 				printf($this->imForm(1,__('General information'),__('Import my blog now')),
-				'<h3>'.__('We first need some information about your old WordPress installation.').'</h3>'.
-				'<p><label for="db_host">'.__('Database Host Name:').' '.
-				form::field('db_host',30,255,html::escapeHTML($this->vars['db_host'])).'</label></p>'.
-				'<p><label for="db_name">'.__('Database Name:',html::escapeHTML($this->vars['db_name'])).' '.
-				form::field('db_name',30,255,html::escapeHTML($this->vars['db_name'])).'</label></p>'.
-				'<p><label for="db_user">'.__('Database User Name:').' '.
-				form::field('db_user',30,255,html::escapeHTML($this->vars['db_user'])).'</label></p>'.
-				'<p><label for="db_pwd">'.__('Database Password:').' '.
-				form::password('db_pwd',30,255).'</label></p>'.
-				'<p><label for="db_prefix">'.__('Database Tables Prefix:').' '.
-				form::field('db_prefix',30,255,html::escapeHTML($this->vars['db_prefix'])).'</label></p>'.
-				'<h3>'.__('Entries import options').'</h3>'.
+				'<p>'.__('We first need some information about your old WordPress installation.').'</p>'.
+				'<p><label for="db_host">'.__('Database Host Name:').'</label> '.
+				form::field('db_host',30,255,html::escapeHTML($this->vars['db_host'])).'</p>'.
+				'<p><label for="db_name">'.__('Database Name:',html::escapeHTML($this->vars['db_name'])).'</label> '.
+				form::field('db_name',30,255,html::escapeHTML($this->vars['db_name'])).'</p>'.
+				'<p><label for="db_user">'.__('Database User Name:').'</label> '.
+				form::field('db_user',30,255,html::escapeHTML($this->vars['db_user'])).'</p>'.
+				'<p><label for="db_pwd">'.__('Database Password:').'</label> '.
+				form::password('db_pwd',30,255).'</p>'.
+				'<p><label for="db_prefix">'.__('Database Tables Prefix:').'</label> '.
+				form::field('db_prefix',30,255,html::escapeHTML($this->vars['db_prefix'])).'</p>'.
+
+				'<h3 class="vertical-separator">'.__('Entries import options').'</h3>'.
+				'<div class="two-cols">'.
+
+				'<div class="col">'.
 				'<p>'.__('WordPress and Dotclear\'s handling of categories are quite different. '.
 				'You can assign several categories to a single post in WordPress. In the Dotclear world, '.
@@ -198,8 +201,12 @@
 				'category per post and will chose the lowest numbered one. If you want to keep a trace of '.
 				'every category, you can import them as tags, with an optional prefix.').'</p>'.
-				'<p>'.__('On the other hand, in WordPress, a post can not be uncategorized, and a default '.
-				'installation has a first category labelised <i>"Uncategorized"</i>. If you did not change that '.
-				'category, you can just ignore it while importing your blog, as Dotclear allows you to '.
-				'actually keep your posts uncategorized.').'</p>'.
+				'<p>'.__('On the other hand, in WordPress, a post can not be uncategorized, and a '.
+				'default installation has a first category labelised <i>"Uncategorized"</i>.'.
+				'If you did not change that category, you can just ignore it while '.
+				'importing your blog, as Dotclear allows you to actually keep your posts '.
+				'uncategorized.').'</p>'.
+				'</div>'.
+
+				'<div class="col">'.
 				'<p><label for="ignore_first_cat" class="classic">'.form::checkbox('ignore_first_cat',1,$this->vars['ignore_first_cat']).' '.
 				__('Ignore the first category:').'</label></p>'.
@@ -208,13 +215,18 @@
 				'<p><label for="cat_as_tags" class="classic">'.form::checkbox('cat_as_tags',1,$this->vars['cat_as_tags']).' '.
 				__('Import all categories as tags:').'</label></p>'.
-				'<p><label for="cat_tags_prefix">'.__('Prefix such tags with:').' '.
-				form::field('cat_tags_prefix',10,20,html::escapeHTML($this->vars['cat_tags_prefix'])).'</label></p>'.
-				'<p><label for="post_limit">'.__('Number of entries to import at once:').' '.
-				form::field('post_limit',3,3,html::escapeHTML($this->vars['post_limit'])).'</label></p>'.
+				'<p><label for="cat_tags_prefix">'.__('Prefix such tags with:').'</label> '.
+				form::field('cat_tags_prefix',10,20,html::escapeHTML($this->vars['cat_tags_prefix'])).'</p>'.
+				'<p><label for="post_limit">'.__('Number of entries to import at once:').'</label> '.
+				form::field('post_limit',3,3,html::escapeHTML($this->vars['post_limit'])).'</p>'.
+				'</div>'.
 				
-				'<h3>'.__('Content filters').'</h3>'.
+				'</div>'.
+
+				'<h3 class="clear vertical-separator">'.__('Content filters').'</h3>'.
 				'<p>'.__('You may want to process your post and/or comment content with the following filters.').'</p>'.
-				'<p><label for="post_formater">'.__('Post content formatter:').' '.form::combo('post_formater',$this->formaters,$this->vars['post_formater']).'</label></p>'.
-				'<p><label for="comment_formater">'.__('Comment content formatter:').' '.form::combo('comment_formater',$this->formaters,$this->vars['comment_formater']).'</label></p>'
+				'<p><label for="post_formater">'.__('Post content formatter:').'</label> '.
+				form::combo('post_formater',$this->formaters,$this->vars['post_formater']).'</p>'.
+				'<p><label for="comment_formater">'.__('Comment content formatter:').'</label> '
+				.form::combo('comment_formater',$this->formaters,$this->vars['comment_formater']).'</p>'
 				);
 				break;
@@ -261,10 +273,10 @@
 		return
 		'<form action="'.$this->getURL(true).'" method="post">'.
-		'<fieldset><legend>'.$legend.'</legend>'.
-		$this->core->formNonce().
+		'<h3 class="vertical-separator">'.$legend.'</h3>'.
+		'<div>'.$this->core->formNonce().
 		form::hidden(array('do'),'step'.$step).
-		'%s'.
+		'%s'.'</div>'.
 		'<p><input type="submit" value="'.$submit_value.'" /></p>'.
-		'</fieldset>'.
+		'<p class="form-note info">'.__('Depending on the size of your blog, it could take a few minutes.').'</p>'.
 		'</form>';
 	}
Index: plugins/importExport/index.php
===================================================================
--- plugins/importExport/index.php	(revision 840)
+++ plugins/importExport/index.php	(revision 1358)
@@ -74,7 +74,12 @@
 
 if ($type && $module !== null) {
+	echo dcPage::breadcrumb(
+		array(
+			__('Plugins') => '',
+			$title => $p_url,
+			'<span class="page-title">'.html::escapeHTML($module->name).'</span>' => ''
+		));
+
 	echo
-	'<h2><a href="'.$p_url.'">'.$title.'</a>'.
-	' &rsaquo; <span class="page-title">'.html::escapeHTML($module->name).'</span></h2>'.
 	'<div id="ie-gui">';
 	
@@ -84,6 +89,11 @@
 }
 else {
+	echo dcPage::breadcrumb(
+		array(
+			__('Plugins') => '',
+			'<span class="page-title">'.$title.'</span>' => ''
+		));
+
 	echo
-	'<h2 class="page-title">'.$title.'</h2>'.
 	'<h3>'.__('Import').'</h3>'.listImportExportModules($core,$modules['import']).
 	'<h3>'.__('Export').'</h3>'.listImportExportModules($core,$modules['export']);
Index: plugins/importExport/locales/fr/main.po
===================================================================
--- plugins/importExport/locales/fr/main.po	(revision 841)
+++ plugins/importExport/locales/fr/main.po	(revision 1499)
@@ -223,5 +223,5 @@
 
 #: inc/class.dc.import.flat.php:184
-msgid "This will import a single blog backup as new content in the current blog: %s."
+msgid "This will import a single blog backup as new content in the current blog: <strong>%s</strong>."
 msgstr "Ceci va charger une sauvegarde de blog comme un nouveau contenu dans le blog en cours : %s."
 
Index: plugins/maintenance/index.php
===================================================================
--- plugins/maintenance/index.php	(revision 1179)
+++ plugins/maintenance/index.php	(revision 1553)
@@ -69,18 +69,24 @@
 
 <body>
-<h2 class="page-title"><?php echo __('Maintenance'); ?></h2>
+<?php
+	echo dcPage::breadcrumb(
+		array(
+			__('Plugins') => '',
+			'<span class="page-title">'.__('Maintenance').'</span>' => ''
+		));
+?>
 
 <?php
 if (!empty($_GET['vacuum'])) {
-	dcPage::message(__('Optimization successful.'));
+	dcPage::success(__('Optimization successful.'));
 }
 if (!empty($_GET['commentscount'])) {
-	dcPage::message(__('Comments and trackback counted.'));
+	dcPage::success(__('Comments and trackback counted.'));
 }
 if (!empty($_GET['empty_cache'])) {
-	dcPage::message(__('Templates cache directory emptied.'));
+	dcPage::success(__('Templates cache directory emptied.'));
 }
 if (!empty($_GET['delete_logs'])) {
-	dcPage::message(__('Logs deleted.'));
+	dcPage::success(__('Logs deleted.'));
 }
 
Index: plugins/maintenance/locales/en/help/maintenance.html
===================================================================
--- plugins/maintenance/locales/en/help/maintenance.html	(revision 207)
+++ plugins/maintenance/locales/en/help/maintenance.html	(revision 1573)
@@ -5,6 +5,4 @@
 
 <body>
-
-<h3>Maintenance</h3>
 
 <dl>
@@ -35,5 +33,5 @@
   <dd>It may be useful to empty this cache when modifying a theme's .html or .css files (or when updating 
   a theme or plugin).<br />
-  Notice : with some hosters, the templates cache cannot be emptied with this extension. 
+  Notice : with some hosters, the templates cache cannot be emptied with this plugin. 
   You may then have to delete the directory <strong>/cbtpl/</strong> directly on the server with your FTP software.</dd>
 </dl>
Index: plugins/maintenance/locales/fr/help/maintenance.html
===================================================================
--- plugins/maintenance/locales/fr/help/maintenance.html	(revision 1272)
+++ plugins/maintenance/locales/fr/help/maintenance.html	(revision 1605)
@@ -5,6 +5,4 @@
 
 <body>
-
-<h3>Maintenance</h3>
 
 <dl>
@@ -34,5 +32,5 @@
   <dt>Vider le répertoire du cache des templates</dt>
   <dd>La suppression du répertoire du cache des templates peut se révéler nécessaire lors de modifications dans les fichiers .html ou .css d'un thème (voire lors d'un changement de thème ou de mise à jour de plugin).<br />
-  Attention : chez certains hébergeurs (Free par exemple), le cache du répertoire des templates ne peut pas être vidé grâce à l'extension Maintenance, il faut supprimer le répertoire <strong>cbtpl</strong> situé dans le répertoire cache (dotclear/cache par défaut) avec un logiciel FTP.</dd>
+  Attention : chez certains hébergeurs (Free par exemple), le cache du répertoire des templates ne peut pas être vidé grâce au plugin Maintenance, il faut supprimer le répertoire <strong>cbtpl</strong> situé dans le répertoire cache (dotclear/cache par défaut) avec un logiciel FTP.</dd>
 </dl>
 </body>
Index: plugins/pages/_admin.php
===================================================================
--- plugins/pages/_admin.php	(revision 1179)
+++ plugins/pages/_admin.php	(revision 1503)
@@ -15,4 +15,6 @@
 $core->addBehavior('adminDashboardFavs','pages_dashboard_favs');
 $core->addBehavior('adminDashboardFavsIcon','pages_dashboard_favs_icon');
+$core->addBehavior('adminUsersActionsHeaders','pages_users_actions_headers');
+
 function pages_dashboard($core,$icons)
 {
@@ -41,4 +43,8 @@
 	}
 }
+function pages_users_actions_headers()
+{
+	return dcPage::jsLoad('index.php?pf=pages/_users_actions.js');
+}
 
 $_menu['Blog']->addItem(__('Pages'),'plugin.php?p=pages','index.php?pf=pages/icon.png',
Index: plugins/pages/_install.php
===================================================================
--- plugins/pages/_install.php	(revision 1494)
+++ plugins/pages/_install.php	(revision 1529)
Index: plugins/pages/_public.php
===================================================================
--- plugins/pages/_public.php	(revision 1179)
+++ plugins/pages/_public.php	(revision 1674)
@@ -181,4 +181,7 @@
 				
 				# The entry
+				if ($_ctx->posts->trackbacksActive()) {
+					header('X-Pingback: '.$core->blog->url.$core->url->getURLFor("xmlrpc",$core->blog->id));
+				}
 				$core->tpl->setPath($core->tpl->getPath(), dirname(__FILE__).'/default-templates');
 				self::serveDocument('page.html');
Index: plugins/pages/_users_actions.js
===================================================================
--- plugins/pages/_users_actions.js	(revision 1503)
+++ plugins/pages/_users_actions.js	(revision 1503)
@@ -0,0 +1,47 @@
+jQuery.fn.updatePagesPermissionsForm = function() {
+	return this.each(function() {
+		
+		var perms = {};
+		var re = /^perm\[(.+?)\]\[(.+?)\]$/;
+		var e,prop;
+		
+		// Building a nice object of form elements
+		for (var i=0; i<this.elements.length; i++) {
+			e = this.elements[i];
+			
+			if (e.name == undefined) {
+				continue;
+			}
+			var prop;
+			prop = e.name.match(re);
+			if (!prop) {
+				continue;
+			}
+			if (perms[prop[1]] == undefined) {
+				perms[prop[1]] = {};
+			}
+			perms[prop[1]][prop[2]] = e;
+			
+			// select related permissions for admin
+			if (prop[2] == 'admin') {
+				if (e.checked) {
+					admin(e,perms,re);
+				}
+				$(e).click(function(){
+					admin(this,perms,re);
+				});
+			}
+		}
+		
+		function admin(E,perms,re) {
+					P = E.name.match(re);
+					
+					perms[P[1]]['pages'].checked = E.checked;
+					perms[P[1]]['pages'].disabled = E.checked;
+		}
+	});
+};
+
+$(function() {
+	$('#permissions-form').updatePagesPermissionsForm();
+});
Index: plugins/pages/default-templates/page.html
===================================================================
--- plugins/pages/default-templates/page.html	(revision 725)
+++ plugins/pages/default-templates/page.html	(revision 1674)
@@ -25,4 +25,5 @@
   <link rel="top" href="{{tpl:BlogURL}}" title="{{tpl:lang Home}}" />
   <link rel="contents" href="{{tpl:BlogArchiveURL}}" title="{{tpl:lang Archives}}" />
+  <tpl:EntryIf pings_active="1"><link rel="pingback" href="{{tpl:BlogXMLRPCURL}}" /></tpl:EntryIf>
   
   <link rel="alternate" type="application/atom+xml" title="Atom 1.0" href="{{tpl:BlogFeedURL type="atom"}}" />
Index: plugins/pages/list.php
===================================================================
--- plugins/pages/list.php	(revision 1179)
+++ plugins/pages/list.php	(revision 1464)
@@ -44,5 +44,5 @@
 			}
 			
-			echo '<p>'.__('Page(s)').' : '.$pager->getLinks().'</p>';
+			echo '<p class="pagination">'.__('Page(s)').' : '.$pager->getLinks().'</p>';
 			
 			$blocks = explode('%s',$html_block);
@@ -57,5 +57,5 @@
 			echo $blocks[1];
 			
-			echo '<p>'.__('Page(s)').' : '.$pager->getLinks().'</p>';
+			echo '<p class="pagination">'.__('Page(s)').' : '.$pager->getLinks().'</p>';
 		}
 	}
@@ -66,14 +66,14 @@
 		switch ($this->rs->post_status) {
 			case 1:
-				$img_status = sprintf($img,__('published'),'check-on.png');
+				$img_status = sprintf($img,__('Published'),'check-on.png');
 				break;
 			case 0:
-				$img_status = sprintf($img,__('unpublished'),'check-off.png');
+				$img_status = sprintf($img,__('Unpublished'),'check-off.png');
 				break;
 			case -1:
-				$img_status = sprintf($img,__('scheduled'),'scheduled.png');
+				$img_status = sprintf($img,__('Scheduled'),'scheduled.png');
 				break;
 			case -2:
-				$img_status = sprintf($img,__('pending'),'check-wrn.png');
+				$img_status = sprintf($img,__('Pending'),'check-wrn.png');
 				break;
 		}
@@ -81,10 +81,10 @@
 		$protected = '';
 		if ($this->rs->post_password) {
-			$protected = sprintf($img,__('protected'),'locker.png');
+			$protected = sprintf($img,__('Protected'),'locker.png');
 		}
 		
 		$selected = '';
 		if ($this->rs->post_selected) {
-			$selected = sprintf($img,__('hidden'),'hidden.png');
+			$selected = sprintf($img,__('Hidden'),'hidden.png');
 		}
 		
@@ -101,5 +101,5 @@
 		$res .=
 		'<td class="nowrap">'.
-		form::checkbox(array('entries[]'),$this->rs->post_id,'','','',!$this->rs->isEditable(),'title="'.__('select this page').'"').'</td>'.
+		form::checkbox(array('entries[]'),$this->rs->post_id,'','','',!$this->rs->isEditable(),'title="'.__('Select this page').'"').'</td>'.
 		'<td class="maximal"><a href="'.$this->core->getPostAdminURL($this->rs->post_type,$this->rs->post_id).'">'.
 		html::escapeHTML($this->rs->post_title).'</a></td>'.
@@ -145,15 +145,15 @@
 if ($core->auth->check('publish,contentadmin',$core->blog->id))
 {
-	$combo_action[__('publish')] = 'publish';
-	$combo_action[__('unpublish')] = 'unpublish';
-	$combo_action[__('schedule')] = 'schedule';
-	$combo_action[__('mark as pending')] = 'pending';
+	$combo_action[__('Publish')] = 'publish';
+	$combo_action[__('Unpublish')] = 'unpublish';
+	$combo_action[__('Schedule')] = 'schedule';
+	$combo_action[__('Mark as pending')] = 'pending';
 }
 if ($core->auth->check('admin',$core->blog->id)) {
-	$combo_action[__('change author')] = 'author';
+	$combo_action[__('Change author')] = 'author';
 }
 if ($core->auth->check('delete,contentadmin',$core->blog->id))
 {
-	$combo_action[__('delete')] = 'delete';
+	$combo_action[__('Delete')] = 'delete';
 }
 
@@ -177,5 +177,11 @@
 <body>
 <?php
-echo '<h2>'.html::escapeHTML($core->blog->name).' &rsaquo; <span class="page-title">'.__('Pages').'</span></h2>'.
+echo dcPage::breadcrumb(
+	array(
+		html::escapeHTML($core->blog->name) => '',
+		'<span class="page-title">'.__('Pages').'</span>' => ''
+	));
+
+echo
 '<p class="top-add"><a class="button add" href="'.$p_url.'&amp;act=page">'.__('New page').'</a></p>';
 
Index: plugins/pages/locales/en/help/page.html
===================================================================
--- plugins/pages/locales/en/help/page.html	(revision 232)
+++ plugins/pages/locales/en/help/page.html	(revision 1573)
@@ -6,5 +6,5 @@
 <body>
 
-<h3>Editing a page</h3>
+<h4>Editing a page</h4>
 
 <dl>
@@ -73,5 +73,5 @@
 </dl>
 
-<h3>Comments</h3>
+<h4>Comments</h4>
 <dl>
   <dt>Comment list</dt>
@@ -87,5 +87,5 @@
 </dl>
 
-<h3>Wiki syntax reference</h3>
+<h4>Wiki syntax reference</h4>
 
 <p>The wiki syntax is a way to enhance your text with a minimal set
Index: plugins/pages/locales/fr/help/page.html
===================================================================
--- plugins/pages/locales/fr/help/page.html	(revision 232)
+++ plugins/pages/locales/fr/help/page.html	(revision 1573)
@@ -6,5 +6,5 @@
 <body>
 
-<h3>Rédaction de la page</h3>
+<h4>Rédaction de la page</h4>
 
 <dl>
@@ -79,5 +79,5 @@
 </dl>
 
-<h3>Commentaires</h3>
+<h4>Commentaires</h4>
 <dl>
   <dt>Liste les commentaires</dt>
@@ -94,5 +94,5 @@
 </dl>
 
-<h3>Référence de la syntaxe Wiki</h3>
+<h4>Référence de la syntaxe Wiki</h4>
 
 <p>La syntaxe Wiki est une manière d'écrire du texte avec un jeu de balises
Index: plugins/pages/page.php
===================================================================
--- plugins/pages/page.php	(revision 1537)
+++ plugins/pages/page.php	(revision 1668)
@@ -124,5 +124,5 @@
 		if ($next_rs !== null) {
 			$next_link = sprintf($post_link,$next_rs->post_id,
-				html::escapeHTML($next_rs->post_title),__('next page').'&nbsp;&#187;');
+				html::escapeHTML($next_rs->post_title),__('Next page').'&nbsp;&#187;');
 			$next_headlink = sprintf($post_headlink,'next',
 				html::escapeHTML($next_rs->post_title),$next_rs->post_id);
@@ -131,5 +131,5 @@
 		if ($prev_rs !== null) {
 			$prev_link = sprintf($post_link,$prev_rs->post_id,
-				html::escapeHTML($prev_rs->post_title),'&#171;&nbsp;'.__('previous page'));
+				html::escapeHTML($prev_rs->post_title),'&#171;&nbsp;'.__('Previous page'));
 			$prev_headlink = sprintf($post_headlink,'previous',
 				html::escapeHTML($prev_rs->post_title),$prev_rs->post_id);
@@ -304,5 +304,4 @@
   dcPage::jsToolBar().
   dcPage::jsModal().
-  dcPage::jsMetaEditor().
   dcPage::jsLoad('js/_post.js').
   dcPage::jsConfirmClose('entry-form','comment-form').
@@ -318,15 +317,43 @@
 <?php
 
+if ($post_id) {
+	switch ($post_status) {
+		case 1:
+			$img_status = sprintf($img_status_pattern,__('Published'),'check-on.png');
+			break;
+		case 0:
+			$img_status = sprintf($img_status_pattern,__('Unpublished'),'check-off.png');
+			break;
+		case -1:
+			$img_status = sprintf($img_status_pattern,__('Scheduled'),'scheduled.png');
+			break;
+		case -2:
+			$img_status = sprintf($img_status_pattern,__('Pending'),'check-wrn.png');
+			break;
+		default:
+			$img_status = '';
+	}
+	$edit_entry_title = '&ldquo;'.$post_title.'&rdquo;'.' '.$img_status;
+} else {
+	$edit_entry_title = $page_title;
+}
+echo dcPage::breadcrumb(
+	array(
+		html::escapeHTML($core->blog->name) => '',
+		__('Pages') => $p_url,
+		'<span class="page-title">'.$edit_entry_title.'</span>' => ''
+	));
+
 if (!empty($_GET['upd'])) {
-	dcPage::message(__('Page has been successfully updated.'));
+	dcPage::success(__('Page has been successfully updated.'));
 }
 elseif (!empty($_GET['crea'])) {
-	dcPage::message(__('Page has been successfully created.'));
+	dcPage::success(__('Page has been successfully created.'));
 }
 elseif (!empty($_GET['attached'])) {
-	dcPage::message(__('File has been successfully attached.'));
+	dcPage::success(__('File has been successfully attached.'));
 }
 elseif (!empty($_GET['rmattach'])) {
-	dcPage::message(__('Attachment has been successfully removed.'));
+	dcPage::success(__('Attachment has been successfully removed.'));
 }
 
@@ -341,29 +368,6 @@
 }
 
-echo '<h2>'.html::escapeHTML($core->blog->name).
-' &rsaquo; <a href="'.$p_url.'">'.__('Pages').'</a> &rsaquo; <span class="page-title">'.$page_title; 
-	if ($post_id) {
-		switch ($post_status) {
-			case 1:
-				$img_status = sprintf($img_status_pattern,__('published'),'check-on.png');
-				break;
-			case 0:
-				$img_status = sprintf($img_status_pattern,__('unpublished'),'check-off.png');
-				break;
-			case -1:
-				$img_status = sprintf($img_status_pattern,__('scheduled'),'scheduled.png');
-				break;
-			case -2:
-				$img_status = sprintf($img_status_pattern,__('pending'),'check-wrn.png');
-				break;
-			default:
-				$img_status = '';
-		}
-		echo ' &ldquo;'.$post_title.'&rdquo;'.' '.$img_status;
-	}
-echo	'</span></h2>';
-
 if ($post_id && $post->post_status == 1) {
-	echo '<p><a href="'.$post->getURL().'" onclick="window.open(this.href);return false;" title="'.$post_title.' ('.__('new window').')'.'">'.__('Go to this page on the site').' <img src="images/outgoing-blue.png" alt="" /></a></p>';
+	echo '<p><a class="onblog_link" href="'.$post->getURL().'" onclick="window.open(this.href);return false;" title="'.$post_title.' ('.__('new window').')'.'">'.__('Go to this page on the site').' <img src="images/outgoing-blue.png" alt="" /></a></p>';
 }
 
@@ -372,7 +376,7 @@
 if ($post_id)
 {
-	echo '<p>';
+	echo '<p class="nav_prevnext">';
 	if ($prev_link) { echo $prev_link; }
-	if ($next_link && $prev_link) { echo ' - '; }
+	if ($next_link && $prev_link) { echo ' | '; }
 	if ($next_link) { echo $next_link; }
 	
@@ -390,8 +394,110 @@
 
 
-/* Post form if we can edit post
+/* Post form if we can edit page
 -------------------------------------------------------- */
 if ($can_edit_page)
 {
+	$sidebar_items = new ArrayObject(array(
+		'status-box' => array(
+			'title' => __('Status'),
+			'items' => array(
+				'post_status' => 
+					'<p><label for="post_status" class="ib">'.__('Page status').'</label> '.
+					form::combo('post_status',$status_combo,$post_status,'','',!$can_publish).
+					'</p>',
+				'post_dt' => 
+					'<p><label for="post_dt" class="ib">'.__('Publication date and hour').'</label>'.
+					form::field('post_dt',16,16,$post_dt,($bad_dt ? 'invalid' : '')).
+					'</p>',
+				'post_lang' =>
+					'<p><label for="post_lang" class="ib">'.__('Page lang').'</label>'.
+					form::combo('post_lang',$lang_combo,$post_lang).
+					'</p>',
+				'post_format' =>
+					'<div>'.
+					'<h5 id="label_format"><label for="post_format" class="ib">'.__('Text formating').'</label></h5>'.
+					'<p>'.form::combo('post_format',$formaters_combo,$post_format,'maximal').
+					'</p>'.
+					'<p>'.($post_id && $post_format != 'xhtml' ? 
+					'<a id="convert-xhtml" class="button maximal" href="post.php?id='.$post_id.'&amp;xconv=1">'.
+					__('Convert to XHTML').'</a>' : '').'</p></div>')),
+		'metas-box' => array(
+			'title' => __('Ordering'),
+			'items' => array(
+				'post_position' => 
+					'<p><label for="post_position" class="classic">'.__('Page position').'</label> '.
+					form::field('post_position',3,3,(string) $post_position).
+					'</p>')),
+		'options-box' => array(
+			'title' => __('Options'),
+			'items' => array(
+				'post_open_comment' =>
+					'<p><label for="post_open_comment" class="classic">'.
+					form::checkbox('post_open_comment',1,$post_open_comment).' '.
+					__('Accept comments').'</label></p>'.
+					($core->blog->settings->system->allow_comments ? 
+						(isContributionAllowed($post_id,strtotime($post_dt),true) ? 
+							'' :
+							'<p class="form-note warn">'.
+							__('Warning: Comments are not more accepted for this entry.').'</p>') : 
+						'<p class="form-note warn">'.
+						__('Comments are not accepted on this blog so far.').'</p>'),
+				'post_open_tb' =>
+					'<p><label for="post_open_tb" class="classic">'.
+					form::checkbox('post_open_tb',1,$post_open_tb).' '.
+					__('Accept trackbacks').'</label></p>'.
+					($core->blog->settings->system->allow_trackbacks ? 
+						(isContributionAllowed($post_id,strtotime($post_dt),false) ? 
+							'' :
+							'<p class="form-note warn">'.
+							__('Warning: Trackbacks are not more accepted for this entry.').'</p>') : 
+						'<p class="form-note warn">'.__('Trackbacks are not accepted on this blog so far.').'</p>'),
+				'post_hide' =>	
+					'<p><label for="post_selected" class="classic">'.form::checkbox('post_selected',1,$post_selected).' '.
+					__('Hide in widget Pages').'</label>'.
+					'</p>',
+				'post_password' =>
+					'<p><label for="post_password" class="ib">'.__('Password').'</label>'.
+					form::field('post_password',10,32,html::escapeHTML($post_password),'maximal').
+					'</p>',
+				'post_url' =>
+					'<div class="lockable">'.
+					'<p><label for="post_url" class="ib">'.__('Edit basename').'</label>'.
+					form::field('post_url',10,255,html::escapeHTML($post_url),'maximal').
+					'</p>'.
+					'<p class="form-note warn">'.
+					__('Warning: If you set the URL manually, it may conflict with another entry.').
+					'</p></div>'
+	))));
+	$main_items = new ArrayObject(array(
+		"post_title" =>
+			'<p class="col">'.
+			'<label class="required no-margin"><abbr title="'.__('Required field').'">*</abbr> '.__('Title:').'</label>'.
+			form::field('post_title',20,255,html::escapeHTML($post_title),'maximal').
+			'</p>',
+		
+		"post_excerpt" =>
+			'<p class="area" id="excerpt-area"><label for="post_excerpt">'.__('Excerpt:').'<span class="form-note">'.
+			__('Add an introduction to the post.').'</span></label> '.
+			form::textarea('post_excerpt',50,5,html::escapeHTML($post_excerpt)).
+			'</p>',
+		
+		"post_content" =>
+			'<p class="area"><label class="required" '.
+			'for="post_content"><abbr title="'.__('Required field').'">*</abbr> '.__('Content:').'</label> '.
+			form::textarea('post_content',50,$core->auth->getOption('edit_size'),html::escapeHTML($post_content)).
+			'</p>',
+		
+		"post_notes" =>
+			'<p class="area" id="notes-area"><label for="post_notes">'.__('Personal notes:').'<span class="form-note">'.
+			__('Add unpublished notes.').'</span></label>'.
+			form::textarea('post_notes',50,5,html::escapeHTML($post_notes)).
+			'</p>'
+		)
+	);
+
+	# --BEHAVIOR-- adminPostFormItems
+	$core->callBehavior('adminPageFormItems',$main_items,$sidebar_items, isset($post) ? $post : null);
+
 	echo '<div class="multi-part" title="'.__('Edit page').'" id="edit-entry">';
 	echo '<form action="'.html::escapeURL($redir_url).'" method="post" id="entry-form">';
@@ -400,22 +506,8 @@
 	echo '<div id="entry-content"><div class="constrained">';
 	
-	echo
-	'<p class="col"><label for="post_title" class="required"><abbr title="'.__('Required field').'">*</abbr> '.__('Title:').
-	form::field('post_title',20,255,html::escapeHTML($post_title),'maximal').
-	'</label></p>'.
-	
-	'<p class="area" id="excerpt-area"><label for="post_excerpt">'.__('Excerpt:').'</label> '.
-	form::textarea('post_excerpt',50,5,html::escapeHTML($post_excerpt)).
-	'</p>'.
-	
-	'<p class="area"><label class="required" '.
-	'for="post_content"><abbr title="'.__('Required field').'">*</abbr> '.__('Content:').'</label> '.
-	form::textarea('post_content',50,$core->auth->getOption('edit_size'),html::escapeHTML($post_content)).
-	'</p>';
-	
-	echo
-	'<p class="area" id="notes-area"><label for="post_notes">'.__('Notes:').'</label>'.
-	form::textarea('post_notes',50,5,html::escapeHTML($post_notes)).
-	'</p>';
+	
+	foreach ($main_items as $id => $item) {
+		echo $item;
+	}
 
 	# --BEHAVIOR-- adminPageForm
@@ -423,5 +515,5 @@
 	
 	echo
-	'<p>'.
+	'<p class="border-top">'.
 	($post_id ? form::hidden('id',$post_id) : '').
 	'<input type="submit" value="'.__('Save').' (s)" '.
@@ -450,94 +542,11 @@
 	echo '<div id="entry-sidebar">';
 	
-	echo
-	'<p><label for="post_status">'.__('Page status:').
-	form::combo('post_status',$status_combo,$post_status,'','',!$can_publish).
-	'</label></p>'.
-	
-	'<p><label for="post_dt">'.__('Published on:').
-	form::field('post_dt',16,16,$post_dt,($bad_dt ? 'invalid' : '')).'</label></p>'.
-	
-	'<p><label for="post_format">'.__('Text formating:').
-	form::combo('post_format',$formaters_combo,$post_format).
-	($post_id && $post_format != 'xhtml' ? '<a href="'.html::escapeURL($redir_url).'&amp;id='.$post_id.'&amp;xconv=1">'.__('Convert to XHTML').'</a>' : '').
-	'</label></p>'.
-	
-	'<p><label for="post_open_comment" class="classic">'.form::checkbox('post_open_comment',1,$post_open_comment).' '.
-	__('Accept comments').'</label></p>'.
-	($core->blog->settings->system->allow_comments ? 
-		(isContributionAllowed($post_id,strtotime($post_dt),true) ? 
-			'' :
-			'<p class="form-note warn">'.__('Warning: Comments are not more accepted for this page.').'</p>') : 
-		'<p class="form-note warn">'.__('Warning: Comments are not accepted on this blog.').'</p>').
-
-	'<p><label for="post_open_tb" class="classic">'.form::checkbox('post_open_tb',1,$post_open_tb).' '.
-	__('Accept trackbacks').'</label></p>'.
-	($core->blog->settings->system->allow_trackbacks ? 
-		(isContributionAllowed($post_id,strtotime($post_dt),false) ? 
-			'' :
-			'<p class="form-note warn">'.__('Warning: Trackbacks are not more accepted for this page.').'</p>') : 
-		'<p class="form-note warn">'.__('Warning: Trackbacks are not accepted on this blog.').'</p>').
-	
-	'<p><label for="post_selected" class="classic">'.form::checkbox('post_selected',1,$post_selected).' '.
-	__('Hide').'</label></p>'.
-	'<p class="form-note">'.
-	__('If checked this page will be active but not listed in widget Pages.').
-	'</p>'.
-
-	'<p><label for="post_position" class="classic">'.__('Page position:').' '.
-	form::field('post_position',3,3,(string) $post_position).
-	'</label></p>'.
-	
-	'<p><label for="post_lang">'.__('Page lang:').
-	form::combo('post_lang',$lang_combo,$post_lang).'</label></p>'.
-	
-	'<p><label for="post_password">'.__('Page password:').
-	form::field('post_password',10,32,html::escapeHTML($post_password),'maximal').
-	'</label></p>'.
-	
-	'<div class="lockable">'.
-	'<p><label for="post_url">'.__('Basename:').
-	form::field('post_url',10,255,html::escapeHTML($post_url),'maximal').
-	'</label></p>'.
-	'<p class="form-note warn">'.
-	__('Warning: If you set the URL manually, it may conflict with another page.').
-	'</p>'.
-	'</div>';
-	
-	if ($post_id)
-	{
-		echo
-		'<h3 class="clear">'.__('Attachments').'</h3>';
-		foreach ($post_media as $f)
-		{
-			$ftitle = $f->media_title;
-			if (strlen($ftitle) > 18) {
-				$ftitle = substr($ftitle,0,16).'...';
-			}
-			echo
-			'<div class="media-item">'.
-			'<a class="media-icon" href="media_item.php?id='.$f->media_id.'">'.
-			'<img src="'.$f->media_icon.'" alt="" title="'.$f->basename.'" /></a>'.
-			'<ul>'.
-			'<li><a class="media-link" href="media_item.php?id='.$f->media_id.'"'.
-			'title="'.$f->basename.'">'.$ftitle.'</a></li>'.
-			'<li>'.$f->media_dtstr.'</li>'.
-			'<li>'.files::size($f->size).' - '.
-			'<a href="'.$f->file_url.'">'.__('open').'</a>'.'</li>'.
-			
-			'<li class="media-action"><a class="attachment-remove" id="attachment-'.$f->media_id.'" '.
-			'href="post_media.php?post_id='.$post_id.'&amp;media_id='.$f->media_id.'&amp;remove=1">'.
-			'<img src="images/check-off.png" alt="'.__('remove').'" /></a>'.
-			'</li>'.
-			
-			'</ul>'.
-			'</div>';
-		}
-		unset($f);
-		
-		if (empty($post_media)) {
-			echo '<p>'.__('No attachment.').'</p>';
-		}
-		echo '<p><a href="media.php?post_id='.$post_id.'">'.__('Add files to this page').'</a></p>';
+	foreach ($sidebar_items as $id => $c) {
+		echo '<div id="'.$id.'" class="box">'.
+			'<h4>'.$c['title'].'</h4>';
+		foreach ($c['items'] as $e_name=>$e_content) {
+			echo $e_content;
+		}
+		echo '</div>';
 	}
 	
@@ -548,5 +557,5 @@
 	
 	echo '</form>';
-	echo '</div>';
+	echo '</div>';		// End 
 	
 	if ($post_id && !empty($post_media))
@@ -575,13 +584,13 @@
 	if ($can_edit_page && $core->auth->check('publish,contentadmin',$core->blog->id))
 	{
-		$combo_action[__('publish')] = 'publish';
-		$combo_action[__('unpublish')] = 'unpublish';
-		$combo_action[__('mark as pending')] = 'pending';
-		$combo_action[__('mark as junk')] = 'junk';
+		$combo_action[__('Publish')] = 'publish';
+		$combo_action[__('Unpublish')] = 'unpublish';
+		$combo_action[__('Mark as pending')] = 'pending';
+		$combo_action[__('Mark as junk')] = 'junk';
 	}
 	
 	if ($can_edit_page && $core->auth->check('delete,contentadmin',$core->blog->id))
 	{
-		$combo_action[__('delete')] = 'delete';
+		$combo_action[__('Delete')] = 'delete';
 	}
 	
@@ -591,4 +600,7 @@
 	'<div id="comments" class="multi-part" title="'.__('Comments').'">';
 	
+	echo
+	'<p class="top-add"><a class="button add onblog_link" href="#comment-form">'.__('Add a comment').'</a></p>';
+
 	if ($has_action) {
 		echo '<form action="comments_actions.php" method="post">';
@@ -615,5 +627,5 @@
 		'<p class="col checkboxes-helpers"></p>'.
 		
-		'<p class="col right"><label for="action">'.__('Selected comments action:').'</label> '.
+		'<p class="col right"><label for="action" class="classic">'.__('Selected comments action:').'</label> '.
 		form::combo('action',$combo_action).
 		form::hidden('redir',html::escapeURL($redir_url).'&amp;id='.$post_id.'&amp;co=1').
@@ -623,31 +635,27 @@
 		'</form>';
 	}
-	
-	echo '</div>';
-}
-
-/* Add a comment
--------------------------------------------------------- */
-if ($post_id)
-{
+		/* Add a comment
+	-------------------------------------------------------- */
+
 	echo
-	'<div class="multi-part" id="add-comment" title="'.__('Add a comment').'">'.
+	'<div class="fieldset clear">'.
 	'<h3>'.__('Add a comment').'</h3>'.
 	
 	'<form action="comment.php" method="post" id="comment-form">'.
 	'<div class="constrained">'.
-	'<p><label for="comment_author" class="required"><abbr title="'.__('Required field').'">*</abbr> '.__('Name:').
+	'<p><label for="comment_author" class="required"><abbr title="'.__('Required field').'">*</abbr> '.__('Name:').'</label>'.
 	form::field('comment_author',30,255,html::escapeHTML($core->auth->getInfo('user_cn'))).
-	'</label></p>'.
-	
-	'<p><label for="comment_email">'.__('Email:').
+	'</p>'.
+	
+	'<p><label for="comment_email">'.__('Email:').'</label>'.
 	form::field('comment_email',30,255,html::escapeHTML($core->auth->getInfo('user_email'))).
-	'</label></p>'.
-	
-	'<p><label for="comment_site">'.__('Web site:').
+	'</p>'.
+	
+	'<p><label for="comment_site">'.__('Web site:').'</label>'.
 	form::field('comment_site',30,255,html::escapeHTML($core->auth->getInfo('user_url'))).
-	'</label></p>'.
-	
-	'<p class="area"><label for="comment_content" class="required"><abbr title="'.__('Required field').'">*</abbr> '.__('Comment:').'</label> '.
+	'</p>'.
+	
+	'<p class="area"><label for="comment_content" class="required"><abbr title="'.__('Required field').'">*</abbr> '.
+	__('Comment:').'</label> '.
 	form::textarea('comment_content',50,8,html::escapeHTML('')).
 	'</p>'.
@@ -656,7 +664,9 @@
 	$core->formNonce().
 	'<input type="submit" name="add" value="'.__('Save').'" /></p>'.
-	'</div>'.
+	'</div>'. #constrained
+
 	'</form>'.
-	'</div>';
+	'</div>'. #add comment
+	'</div>'; #comments
 }
 
@@ -688,9 +698,9 @@
 	echo
 	'<table class="comments-list"><tr>'.
-	'<th colspan="2">'.__('Author').'</th>'.
+	'<th colspan="2" class="nowrap first">'.__('Author').'</th>'.
 	'<th>'.__('Date').'</th>'.
 	'<th class="nowrap">'.__('IP address').'</th>'.
 	'<th>'.__('Status').'</th>'.
-	'<th>&nbsp;</th>'.
+	'<th>'.__('Edit').'</th>'.
 	'</tr>';
 	
@@ -702,14 +712,14 @@
 		switch ($rs->comment_status) {
 			case 1:
-				$img_status = sprintf($img,__('published'),'check-on.png');
+				$img_status = sprintf($img,__('Published'),'check-on.png');
 				break;
 			case 0:
-				$img_status = sprintf($img,__('unpublished'),'check-off.png');
+				$img_status = sprintf($img,__('Unpublished'),'check-off.png');
 				break;
 			case -1:
-				$img_status = sprintf($img,__('pending'),'check-wrn.png');
+				$img_status = sprintf($img,__('Pending'),'check-wrn.png');
 				break;
 			case -2:
-				$img_status = sprintf($img,__('junk'),'junk.png');
+				$img_status = sprintf($img,__('Junk'),'junk.png');
 				break;
 		}
@@ -720,5 +730,5 @@
 		
 		'<td class="nowrap">'.
-		($has_action ? form::checkbox(array('comments[]'),$rs->comment_id,'','','',0,'title="'.__('select this comment').'"') : '').'</td>'.
+		($has_action ? form::checkbox(array('comments[]'),$rs->comment_id,'','','',0,'title="'.__('Select this comment').'"') : '').'</td>'.
 		'<td class="maximal">'.$rs->comment_author.'</td>'.
 		'<td class="nowrap">'.dt::dt2str(__('%Y-%m-%d %H:%M'),$rs->comment_dt).'</td>'.
@@ -726,5 +736,5 @@
 		'<td class="nowrap status">'.$img_status.'</td>'.
 		'<td class="nowrap status"><a href="'.$comment_url.'">'.
-		'<img src="images/edit-mini.png" alt="" title="'.__('Edit this comment').'" /></a></td>'.
+		'<img src="images/edit-mini.png" alt="" title="'.__('Edit this comment').'" /> '.__('Edit').'</a></td>'.
 		
 		'</tr>';
Index: plugins/pings/_admin.php
===================================================================
--- plugins/pings/_admin.php	(revision 1179)
+++ plugins/pings/_admin.php	(revision 1398)
@@ -33,5 +33,5 @@
 
 $core->addBehavior('adminPostHeaders',array('pingsBehaviors','pingJS'));
-$core->addBehavior('adminPostFormSidebar',array('pingsBehaviors','pingsForm'));
+$core->addBehavior('adminPostFormItems',array('pingsBehaviors','pingsFormItems'));
 $core->addBehavior('adminAfterPostCreate',array('pingsBehaviors','doPings'));
 $core->addBehavior('adminAfterPostUpdate',array('pingsBehaviors','doPings'));
Index: plugins/pings/index.php
===================================================================
--- plugins/pings/index.php	(revision 1179)
+++ plugins/pings/index.php	(revision 1553)
@@ -51,14 +51,19 @@
 <body>
 <?php
-echo '<h2 class="page-title">'.__('Pings configuration').'</h2>';
+
+echo dcPage::breadcrumb(
+	array(
+		__('Plugins') => '',
+		'<span class="page-title">'.__('Pings configuration').'</span>' => ''
+	));
 
 if (!empty($_GET['up'])) {
-	dcPage::message(__('Settings have been successfully updated.'));
+	dcPage::success(__('Settings have been successfully updated.'));
 }
 
 echo
 '<form action="'.$p_url.'" method="post">'.
-'<p><label for="pings_active" class="classic">'.form::checkbox('pings_active',1,$core->blog->settings->pings->pings_active).' '.
-__('Activate pings extension').'</label></p>';
+'<p><label for="pings_active" class="classic">'.form::checkbox('pings_active',1,$core->blog->settings->pings->pings_active).'</label> '.
+__('Activate pings extension').'</p>';
 
 $i = 0;
@@ -66,8 +71,8 @@
 {
 	echo
-	'<p><label for="pings_srv_name-'.$i.'" class="classic">'.__('Service name:').' '.
-	form::field(array('pings_srv_name[]','pings_srv_name-'.$i),20,128,html::escapeHTML($n)).'</label> '.
-	'<label for="pings_srv_uri-'.$i.'" class="classic">'.__('Service URI:').' '.
-	form::field(array('pings_srv_uri[]','pings_srv_uri-'.$i),40,255,html::escapeHTML($u)).'</label>';
+	'<p><label for="pings_srv_name-'.$i.'" class="classic">'.__('Service name:').'</label> '.
+	form::field(array('pings_srv_name[]','pings_srv_name-'.$i),20,128,html::escapeHTML($n)).' '.
+	'<label for="pings_srv_uri-'.$i.'" class="classic">'.__('Service URI:').'</label> '.
+	form::field(array('pings_srv_uri[]','pings_srv_uri-'.$i),40,255,html::escapeHTML($u));
 	
 	if (!empty($_GET['test']))
@@ -75,7 +80,7 @@
 		try {
 			pingsAPI::doPings($u,'Example site','http://example.com');
-			echo ' <img src="images/check-on.png" alt="ok" />';
+			echo ' <img src="images/check-on.png" alt="OK" />';
 		} catch (Exception $e) {
-			echo ' <img src="images/check-off.png" alt="'.__('error').'" /> '.$e->getMessage();
+			echo ' <img src="images/check-off.png" alt="'.__('Error').'" /> '.$e->getMessage();
 		}
 	}
@@ -86,8 +91,8 @@
 
 echo
-'<p><label for="pings_srv_name2" class="classic">'.__('Service name:').' '.
-form::field(array('pings_srv_name[]','pings_srv_name2'),20,128).'</label> '.
-'<label for="pings_srv_uri2" class="classic">'.__('Service URI:').' '.
-form::field(array('pings_srv_uri[]','pings_srv_uri2'),40,255).'</label>'.
+'<p><label for="pings_srv_name2" class="classic">'.__('Service name:').'</label> '.
+form::field(array('pings_srv_name[]','pings_srv_name2'),20,128).' '.
+'<label for="pings_srv_uri2" class="classic">'.__('Service URI:').'</label> '.
+form::field(array('pings_srv_uri[]','pings_srv_uri2'),40,255).
 '</p>'.
 
@@ -96,5 +101,5 @@
 '</form>';
 
-echo '<p><a href="'.$p_url.'&amp;test=1">'.__('Test ping services').'</a></p>';
+echo '<p><a class="button" href="'.$p_url.'&amp;test=1">'.__('Test ping services').'</a></p>';
 ?>
 </body>
Index: plugins/pings/lib.pings.php
===================================================================
--- plugins/pings/lib.pings.php	(revision 1179)
+++ plugins/pings/lib.pings.php	(revision 1398)
@@ -41,5 +41,5 @@
 	}
 	
-	public static function pingsForm($post)
+	public static function pingsFormItems($main,$sidebar,$post)
 	{
 		$core =& $GLOBALS['core'];
@@ -59,9 +59,9 @@
 		}
 		
-		echo '<h3 class="ping-services">'.__('Pings:').'</h3>';
+		$item = '<h5 class="ping-services">'.__('Pings').'</h5>';
 		$i = 0;
 		foreach ($pings_uris as $k => $v)
 		{
-			echo
+			$item .=
 			'<p class="ping-services"><label for="pings_do-'.$i.'" class="classic">'.
 			form::checkbox(array('pings_do[]','pings_do-'.$i),html::escapeHTML($v),in_array($v,$pings_do)).' '.
@@ -69,4 +69,6 @@
 			$i++;
 		}
+		$sidebar['options-box']['items']['pings']=$item;
+		
 	}
 	
Index: plugins/pings/post.js
===================================================================
--- plugins/pings/post.js	(revision 0)
+++ plugins/pings/post.js	(revision 1606)
@@ -12,6 +12,7 @@
 			$('p.ping-services:last').after(p.append(a));
 		}
-		$('h3.ping-services').toggleWithLegend($('p.ping-services'),{
-			cookie: 'dcx_ping_services'
+		$('h5.ping-services').toggleWithLegend($('p.ping-services'),{
+			cookie: 'dcx_ping_services',
+			legend_click: true
 		});
 	});
Index: plugins/simpleMenu/_admin.php
===================================================================
--- plugins/simpleMenu/_admin.php	(revision 1179)
+++ plugins/simpleMenu/_admin.php	(revision 1292)
@@ -25,5 +25,5 @@
 }
 
-$_menu['Plugins']->addItem(__('Simple menu'),'plugin.php?p=simpleMenu','index.php?pf=simpleMenu/icon-small.png',
+$_menu['Blog']->addItem(__('Simple menu'),'plugin.php?p=simpleMenu','index.php?pf=simpleMenu/icon-small.png',
                 preg_match('/plugin.php\?p=simpleMenu(&.*)?$/',$_SERVER['REQUEST_URI']),
                 $core->auth->check('usage,contentadmin',$core->blog->id));
Index: plugins/simpleMenu/index.php
===================================================================
--- plugins/simpleMenu/index.php	(revision 1273)
+++ plugins/simpleMenu/index.php	(revision 1636)
@@ -233,5 +233,5 @@
 				
 					// All done successfully, return to menu items list
-					http::redirect($p_url.'&added=1');
+					http::redirect($p_url.'&amp;added=1');
 				} else {
 					throw new Exception(__('Label and URL of menu item are mandatory.'));
@@ -268,5 +268,5 @@
 				
 				// All done successfully, return to menu items list
-				http::redirect($p_url.'&removed=1');
+				http::redirect($p_url.'&amp;removed=1');
 			} else {
 				throw new Exception(__('No menu items selected.'));
@@ -302,5 +302,5 @@
 
 			// All done successfully, return to menu items list
-			http::redirect($p_url.'&updated=1');
+			http::redirect($p_url.'&amp;updated=1');
 		}
 		catch (Exception $e) {
@@ -339,5 +339,5 @@
 
 			// All done successfully, return to menu items list
-			http::redirect($p_url.'&neworder=1');
+			http::redirect($p_url.'&amp;neworder=1');
 		} 
 		catch (Exception $e) {
@@ -368,22 +368,35 @@
 <?php
 
+if ($step) {
+	echo dcPage::breadcrumb(
+		array(
+			html::escapeHTML($core->blog->name) => '',
+			$page_title => $p_url,
+			'<span class="page-title">'.__('Add item').'</span>' => ''
+		));
+} else {
+	echo dcPage::breadcrumb(
+		array(
+			html::escapeHTML($core->blog->name) => '',
+			'<span class="page-title">'.$page_title.'</span>' => ''
+		));
+}
+
 if (!empty($_GET['added'])) {
-	dcPage::message(__('Menu item has been successfully added.'));
+	dcPage::success(__('Menu item has been successfully added.'));
 }
 if (!empty($_GET['removed'])) {
-	dcPage::message(__('Menu items have been successfully removed.'));
+	dcPage::success(__('Menu items have been successfully removed.'));
 }
 if (!empty($_GET['neworder'])) {
-	dcPage::message(__('Menu items have been successfully updated.'));
+	dcPage::success(__('Menu items have been successfully updated.'));
 }
 if (!empty($_GET['updated'])) {
-	dcPage::message(__('Menu items have been successfully updated.'));
-}
-
-if ($step) 
+	dcPage::success(__('Menu items have been successfully updated.'));
+}
+
+if ($step)
 {
 	// Formulaire d'ajout d'un item
-	echo '<h2>'.html::escapeHTML($core->blog->name).' &rsaquo; <a href="'.$p_url.'">'.$page_title.'</a> &rsaquo; <span class="page-title">'.__('Add item').'</span></h2>';
-	
 	switch ($step) {
 		case 1:
@@ -454,10 +467,6 @@
 // Liste des items
 if (!$step) {
-	echo '<h2>'.html::escapeHTML($core->blog->name).' &rsaquo; <span class="page-title">'.$page_title.'</span></h2>';
-}
-
-if (!$step) {
 	echo '<form id="menuitemsappend" action="'.$p_url.'&amp;add=1" method="post">';
-	echo '<p>'.$core->formNonce().'<input class="add" type="submit" name="appendaction" value="'.__('Add an item').'" /></p>';
+	echo '<p class="top-add">'.$core->formNonce().'<input class="button add" type="submit" name="appendaction" value="'.__('Add an item').'" /></p>';
 	echo '</form>';
 }
@@ -517,5 +526,5 @@
 } else {
 	echo
-		'<p>'.__('Currently no menu items').'</p>';
+		'<p>'.__('No menu items so far.').'</p>';
 }
 
Index: plugins/simpleMenu/locales/en/help/help.html
===================================================================
--- plugins/simpleMenu/locales/en/help/help.html	(revision 553)
+++ plugins/simpleMenu/locales/en/help/help.html	(revision 1573)
@@ -6,5 +6,4 @@
 <body>
 
-<h3>Simple Menu</h3>
 <p>Simple Menu allows you to display on your blog a single level menu, if your theme supports it.</p>
 <dl>
Index: plugins/simpleMenu/locales/fr/help/help.html
===================================================================
--- plugins/simpleMenu/locales/fr/help/help.html	(revision 553)
+++ plugins/simpleMenu/locales/fr/help/help.html	(revision 1573)
@@ -6,5 +6,4 @@
 <body>
 
-<h3>Menu simple</h3>
 <p>Menu simple vous permet d’afficher un menu limité à un seul niveau sur votre blog, si votre thème le supporte.</p>
 <dl>
Index: plugins/tags/_admin.php
===================================================================
--- plugins/tags/_admin.php	(revision 1239)
+++ plugins/tags/_admin.php	(revision 1609)
@@ -18,10 +18,8 @@
 require dirname(__FILE__).'/_widgets.php';
 
-$core->addBehavior('adminPostFormSidebar',array('tagsBehaviors','tagsField'));
+$core->addBehavior('adminPostFormItems',array('tagsBehaviors','tagsField'));
 
 $core->addBehavior('adminAfterPostCreate',array('tagsBehaviors','setTags'));
 $core->addBehavior('adminAfterPostUpdate',array('tagsBehaviors','setTags'));
-
-$core->addBehavior('adminPageHeaders',array('tagsBehaviors','pageHeaders'));
 
 $core->addBehavior('adminPostHeaders',array('tagsBehaviors','postHeaders'));
@@ -73,5 +71,5 @@
 	}
 	
-	public static function tagsField($post)
+	public static function tagsField($main,$sidebar,$post)
 	{
 		$meta =& $GLOBALS['core']->meta;
@@ -82,8 +80,7 @@
 			$value = ($post) ? $meta->getMetaStr($post->post_meta,'tag') : '';
 		}
-		
-		echo
-		'<h3><label for="post_tags">'.__('Tags:').'</label></h3>'.
-		'<div class="p" id="tags-edit">'.form::textarea('post_tags',20,3,$value,'maximal').'</div>';
+		$sidebar['metas-box']['items']['post_tags']=
+		'<h5><label class="s-tags" for="post_tags">'.__('Tags').'</label></h5>'.
+		'<div class="p s-tags" id="tags-edit">'.form::textarea('post_tags',20,3,$value,'maximal').'</div>';
 	}
 	
@@ -101,33 +98,4 @@
 			}
 		}
-	}
-
-	public static function pageHeaders()
-	{
-		$tag_url = $GLOBALS['core']->blog->url.$GLOBALS['core']->url->getURLFor('tag');
-		
-		$opts = $GLOBALS['core']->auth->getOptions();
-		$type = isset($opts['tag_list_format']) ? $opts['tag_list_format'] : 'more';
-		
-		return 
-		'<script type="text/javascript" src="index.php?pf=tags/js/jquery.autocomplete.js"></script>'.
-		'<script type="text/javascript" src="index.php?pf=tags/js/page.js"></script>'.
-		'<script type="text/javascript">'."\n".
-		"//<![CDATA[\n".
-		"metaEditor.prototype.meta_url = 'plugin.php?p=tags&m=tag_posts&amp;tag=';\n".
-		"metaEditor.prototype.meta_type = '".html::escapeJS($type)."';\n".
-		"metaEditor.prototype.text_confirm_remove = '".html::escapeJS(__('Are you sure you want to remove this %s?'))."';\n".
-		"metaEditor.prototype.text_add_meta = '".html::escapeJS(__('Add a %s to this entry'))."';\n".
-		"metaEditor.prototype.text_choose = '".html::escapeJS(__('Choose from list'))."';\n".
-		"metaEditor.prototype.text_all = '".html::escapeJS(__('all'))."';\n".
-		"metaEditor.prototype.text_separation = '';\n".
-		"jsToolBar.prototype.elements.tag.title = '".html::escapeJS(__('Tag'))."';\n".
-		"jsToolBar.prototype.elements.tag.url = '".html::escapeJS($tag_url)."';\n".
-		"dotclear.msg.tags_autocomplete = '".html::escapeJS(__('used in %e - frequency %p%'))."';\n".
-		"dotclear.msg.entry = '".html::escapeJS(__('entry'))."';\n".
-		"dotclear.msg.entries = '".html::escapeJS(__('entries'))."';\n".
-		"\n//]]>\n".
-		"</script>\n".
-		'<link rel="stylesheet" type="text/css" href="index.php?pf=tags/style.css" />';
 	}
 	
@@ -261,11 +229,16 @@
 		if ($action == 'tags')
 		{
-			echo
-			'<h2 class="page-title">'.__('Add tags to entries').'</h2>'.
+			echo dcPage::breadcrumb(
+				array(
+					html::escapeHTML($core->blog->name) => '',
+					__('Entries') => 'posts.php',
+					'<span class="page-title">'.__('Add tags to entries').'</span>' => ''
+			)).
 			'<form action="'.$form_uri.'" method="post">'.
+			$hidden_fields->getEntries().
 			'<div><label for="new_tags" class="area">'.__('Tags to add:').'</label> '.
 			form::textarea('new_tags',60,3).
 			'</div>'.
-			$hidden_fields.
+			$hidden_fields->getHidden().
 			$core->formNonce().
 			form::hidden(array('action'),'tags').
@@ -291,6 +264,10 @@
 				}
 			}
-			
-			echo '<h2 class="page-title">'.__('Remove selected tags from entries').'</h2>';
+			echo dcPage::breadcrumb(
+				array(
+					html::escapeHTML($core->blog->name) => '',
+					__('Entries') => 'posts.php',
+					'<span class="page-title">'.__('Remove selected tags from entries').'</span>' => ''
+			));
 			
 			if (empty($tags)) {
@@ -338,14 +315,13 @@
 		
 		$combo = array();
-		$combo[__('short')] = 'more';
-		$combo[__('extended')] = 'all';
+		$combo[__('Short')] = 'more';
+		$combo[__('Extended')] = 'all';
 		
 		$value = array_key_exists('tag_list_format',$opts) ? $opts['tag_list_format'] : 'more';
 		
 		echo
-		'<fieldset><legend>'.__('Tags').'</legend>'.
-		'<p><label for="user_tag_list_format">'.__('Tags list format:').' '.
+		'<p><label for="user_tag_list_format">'.__('Tags list format:').'</label> '.
 		form::combo('user_tag_list_format',$combo,$value).
-		'</label></p></fieldset>';
+		'</p>';
 	}
 	
Index: plugins/tags/_define.php
===================================================================
--- plugins/tags/_define.php	(revision 1179)
+++ plugins/tags/_define.php	(revision 1392)
@@ -18,5 +18,6 @@
 	/* Version */			'1.2',
 	array(
-		'permissions' =>	'usage,contentadmin'
+		'permissions' =>	'usage,contentadmin',
+		'priority' =>		998
 	)
 );
Index: lugins/tags/js/page.js
===================================================================
--- plugins/tags/js/page.js	(revision 1240)
+++ 	(revision )
@@ -1,70 +1,0 @@
-$(function () {
-    $('#edit-entry').onetabload(function () {
-        var tags_edit = $('#tags-edit');
-        var post_id = $('#id');
-        var meta_field = null;
-        if (tags_edit.length > 0) {
-            post_id = (post_id.length > 0) ? post_id.get(0).value : false;
-            if (post_id == false) {
-                meta_field = $('<input type="hidden" name="post_tags" />');
-                meta_field.val($('#post_tags').val());
-            }
-            var mEdit = new metaEditor(tags_edit, meta_field, 'tag');
-            mEdit.meta_url = 'plugin.php?p=tags&m=tag_posts&amp;tag=';
-            mEdit.displayMeta('tag', post_id);
-            window.dc_tag_editor = mEdit;
-        }
-    });
-});
-jsToolBar.prototype.elements.tagSpace = {
-    type: 'space'
-};
-jsToolBar.prototype.elements.tag = {
-    type: 'button',
-    title: 'Keyword',
-    fn: {}
-};
-jsToolBar.prototype.elements.tag.context = 'post';
-jsToolBar.prototype.elements.tag.icon = 'index.php?pf=tags/img/tag-add.png';
-jsToolBar.prototype.elements.tag.fn.wiki = function () {
-    this.encloseSelection('', '', function (str) {
-        if (str == '') {
-            window.alert(dotclear.msg.no_selection);
-            return '';
-        }
-        if (str.indexOf(',') != -1) {
-            return str;
-        } else {
-            return '[' + str + '|tag:' + str + ']';
-        }
-    });
-};
-jsToolBar.prototype.elements.tag.fn.xhtml = function () {
-    var url = this.elements.tag.url;
-    this.encloseSelection('', '', function (str) {
-        if (str == '') {
-            window.alert(dotclear.msg.no_selection);
-            return '';
-        }
-        if (str.indexOf(',') != -1) {
-            return str;
-        } else {
-            return '<a href="' + this.stripBaseURL(url + '/' + str) + '">' + str + '</a>';
-        }
-    });
-};
-jsToolBar.prototype.elements.tag.fn.wysiwyg = function () {
-    var t = this.getSelectedText();
-    if (t == '') {
-        window.alert(dotclear.msg.no_selection);
-        return;
-    }
-    if (t.indexOf(',') != -1) {
-        return;
-    }
-    var n = this.getSelectedNode();
-    var a = document.createElement('a');
-    a.href = this.stripBaseURL(this.elements.tag.url + '/' + t);
-    a.appendChild(n);
-    this.insertNode(a);
-};
Index: plugins/tags/js/post.js
===================================================================
--- plugins/tags/js/post.js	(revision 1112)
+++ plugins/tags/js/post.js	(revision 1606)
@@ -53,9 +53,15 @@
 				')</em>';
 			},
-			formatResult: function(tag) { 
-				return tag.result; 
+			formatResult: function(tag) {
+				return tag.result;
 			}
 		});
 	});
+
+	$('h5 .s-tags').toggleWithLegend($('.s-tags').not('label'),{
+		cookie: 'post_tags',
+		legend_clik: true
+	});
+
 });
 
Index: plugins/tags/tag_posts.php
===================================================================
--- plugins/tags/tag_posts.php	(revision 1288)
+++ plugins/tags/tag_posts.php	(revision 1572)
@@ -98,5 +98,5 @@
   <script type="text/javascript">
   //<![CDATA[
-  dotclear.msg.confirm_tag_delete = '<?php echo html::escapeJS(sprintf(__('Are you sure you want to remove this %s?'),'tag')) ?>';
+  dotclear.msg.confirm_tag_delete = '<?php echo html::escapeJS(sprintf(__('Are you sure you want to remove tag: “%s”?'),html::escapeHTML($tag))) ?>';
   $(function() {
     $('#tag_delete').submit(function() {
@@ -109,13 +109,19 @@
 <body>
 
-<h2><?php echo html::escapeHTML($core->blog->name); ?> &rsaquo;
-<span class="page-title"><?php echo __('Edit tag').' &ldquo;'.html::escapeHTML($tag).'&rdquo;'; ?></span></h2>
+<?php
+echo dcPage::breadcrumb(
+	array(
+		html::escapeHTML($core->blog->name) => '',
+		__('Tags') => $p_url.'&amp;m=tags',
+		'<span class="page-title">'.__('Tag').' &ldquo;'.html::escapeHTML($tag).'&rdquo;'.'</span>' => ''
+	));
+?>
 
 <?php
 if (!empty($_GET['renamed'])) {
-	dcPage::message(__('Tag has been successfully renamed'));
+	dcPage::success(__('Tag has been successfully renamed'));
 }
 
-echo '<p><a href="'.$p_url.'&amp;m=tags">'.__('Back to tags list').'</a></p>';
+echo '<p><a class="back" href="'.$p_url.'&amp;m=tags">'.__('Back to tags list').'</a></p>';
 
 if (!$core->error->flag())
@@ -124,6 +130,7 @@
 	{
 		echo
+		'<div class="fieldset">'.
 		'<form action="'.$this_url.'" method="post">'.
-		'<div class="fieldset"><h3>'.__('Actions for this tag').'</h3>'.
+		'<h3>'.__('Actions').'</h3>'.
 		'<p><label for="new_tag_id">'.__('Edit tag name:').'</label>'.
 		form::field('new_tag_id',20,255,html::escapeHTML($tag)).
@@ -135,6 +142,6 @@
 			echo
 			'<form id="tag_delete" action="'.$this_url.'" method="post">'.
-			'<p class="no-margin">'.__('Delete this tag:').
-			'</p><p><input type="submit" class="delete" name="delete" value="'.__('Delete').'" />'.
+			'<p>'.__('Delete this tag:').' '.
+			'<input type="submit" class="delete" name="delete" value="'.__('Delete').'" />'.
 			$core->formNonce().
 			'</p></form>';
@@ -144,5 +151,5 @@
 	
 	# Show posts
-	echo '<h3>'.__('List of entries with this tag').'</h3>';
+	echo '<h3>'.sprintf(__('List of entries with the tag “%s”'),html::escapeHTML($tag)).'</h3>';
 	$post_list->display($page,$nb_per_page,
 	'<form action="posts_actions.php" method="post" id="form-entries">'.
@@ -155,5 +162,5 @@
 	'<p class="col right"><label for="action" class="classic">'.__('Selected entries action:').'</label> '.
 	form::combo('action',$combo_action).
-	'<input type="submit" value="'.__('ok').'" /></p>'.
+	'<input type="submit" value="'.__('OK').'" /></p>'.
 	form::hidden('post_type','').
 	form::hidden('redir',$p_url.'&amp;m=tag_posts&amp;tag='.
Index: plugins/tags/tags.php
===================================================================
--- plugins/tags/tags.php	(revision 1179)
+++ plugins/tags/tags.php	(revision 1358)
@@ -20,6 +20,11 @@
 
 <body>
-<h2><?php echo html::escapeHTML($core->blog->name); ?> &rsaquo;
-<span class="page-title"><?php echo __('Tags'); ?></span></h2>
+<?php
+echo dcPage::breadcrumb(
+	array(
+		html::escapeHTML($core->blog->name) => '',
+		'<span class="page-title">'.__('Tags').'</span>' => ''
+	));
+?>
 
 <?php
Index: plugins/themeEditor/_admin.php
===================================================================
--- plugins/themeEditor/_admin.php	(revision 1179)
+++ plugins/themeEditor/_admin.php	(revision 1609)
@@ -26,5 +26,5 @@
 	{
 		if ($id != 'default' && $core->auth->isSuperAdmin()) {
-			return '<p><a href="plugin.php?p=themeEditor" class="button">'.__('Theme Editor').'</a></p>';
+			return '<p><a href="plugin.php?p=themeEditor" class="button">'.__('Edit theme files').'</a></p>';
 		}
 	}
@@ -50,13 +50,9 @@
 		$core->auth->user_prefs->addWorkspace('interface');
 
-		echo
-		'<fieldset><legend>'.__('Theme Editor').'</legend>'.
-		
+		echo		
 		'<p><label for="colorsyntax" class="classic">'.
-		form::checkbox('colorsyntax',1,$core->auth->user_prefs->interface->colorsyntax).' '.
-		__('Syntax color').'</label></p>'.
-
-		'<br class="clear" />'. //Opera sucks
-		'</fieldset>';
+		form::checkbox('colorsyntax',1,$core->auth->user_prefs->interface->colorsyntax).'</label>'.
+		__('Syntax color for theme editor').
+		'</p>';
 	}
 }
Index: plugins/themeEditor/index.php
===================================================================
--- plugins/themeEditor/index.php	(revision 1179)
+++ plugins/themeEditor/index.php	(revision 1382)
@@ -61,5 +61,5 @@
 <html>
 <head>
-  <title><?php echo __('Theme Editor'); ?></title>
+  <title><?php echo __('Edit theme files'); ?></title>
   <link rel="stylesheet" type="text/css" href="index.php?pf=themeEditor/style.css" />
   <script type="text/javascript">
@@ -86,6 +86,12 @@
 
 <body>
-<?php echo '<h2>'.html::escapeHTML($core->blog->name).
-' &rsaquo; <a href="blog_theme.php">'.__('Blog appearance').'</a> &rsaquo; <span class="page-title">'.__('Theme Editor').'</span></h2>'; ?>
+<?php
+echo dcPage::breadcrumb(
+	array(
+		html::escapeHTML($core->blog->name) => '',
+		__('Blog appearance') => 'blog_theme.php',
+		'<span class="page-title">'.__('Edit theme files').'</span>' => ''
+	));
+?>
 
 <p><strong><?php echo sprintf(__('Your current theme on this blog is "%s".'),html::escapeHTML($T['name'])); ?></strong></p>
Index: plugins/userPref/_admin.php
===================================================================
--- plugins/userPref/_admin.php	(revision 1179)
+++ plugins/userPref/_admin.php	(revision 1293)
@@ -12,5 +12,5 @@
 if (!defined('DC_CONTEXT_ADMIN')) { return; }
 
-$_menu['Plugins']->addItem('user:preferences','plugin.php?p=userPref','index.php?pf=userPref/icon.png',
+$_menu['System']->addItem('user:preferences','plugin.php?p=userPref','index.php?pf=userPref/icon.png',
 		preg_match('/plugin.php\?p=userPref(&.*)?$/',$_SERVER['REQUEST_URI']),
 		$core->auth->isSuperAdmin());
Index: plugins/userPref/index.php
===================================================================
--- plugins/userPref/index.php	(revision 1274)
+++ plugins/userPref/index.php	(revision 1553)
@@ -81,5 +81,5 @@
 	
 	return
-	'<tr>'.
+	'<tr class="line">'.
 	'<td scope="row"><label for="s_'.$id.'">'.sprintf($slabel,html::escapeHTML($id)).'</label></td>'.
 	'<td>'.$field.'</td>'.
@@ -93,9 +93,4 @@
   <title>user:preferences</title>
   <?php echo dcPage::jsPageTabs($part); ?>
-  <style type="text/css">
-	table.prefs { border: 1px solid #999; margin-bottom: 2em; }
-	table.prefs th { background: #f5f5f5; color: #444; padding-top: 0.3em; padding-bottom: 0.3em; }
-	p.anchor-nav {float: right; }
-  </style>
 	<script type="text/javascript">
 	//<![CDATA[
@@ -116,18 +111,24 @@
 <body>
 <?php
+echo dcPage::breadcrumb(
+	array(
+		__('System') => '',
+		html::escapeHTML($core->auth->userID()) => '',
+		'<span class="page-title">'.__('user:preferences').'</span>' => ''
+	));
+
 if (!empty($_GET['upd'])) {
-	dcPage::message(__('Preferences successfully updated'));
+	dcPage::success(__('Preferences successfully updated'));
 }
 
 if (!empty($_GET['upda'])) {
-	dcPage::message(__('Preferences definition successfully updated'));
-}
-?>
-<h2><?php echo html::escapeHTML($core->auth->userID()); ?> &rsaquo; <span class="page-title">user:preferences</span></h2>
-
-<div id="local" class="multi-part" title="<?php echo __('user preferences'); ?>">
+	dcPage::success(__('Preferences definition successfully updated'));
+}
+?>
+
+<div id="local" class="multi-part" title="<?php echo __('User preferences'); ?>">
 
 <?php 
-$table_header = '<table class="prefs" id="%s"><caption>%s</caption>'.
+$table_header = '<table class="prefs" id="%s"><caption class="as_h3">%s</caption>'.
 '<thead>'.
 '<tr>'."\n".
@@ -184,5 +185,5 @@
 </div>
 
-<div id="global" class="multi-part" title="<?php echo __('global preferences'); ?>">
+<div id="global" class="multi-part" title="<?php echo __('Global preferences'); ?>">
 
 <?php
Index: plugins/widgets/_default_widgets.php
===================================================================
--- plugins/widgets/_default_widgets.php	(revision 1179)
+++ plugins/widgets/_default_widgets.php	(revision 1610)
@@ -47,7 +47,8 @@
 $__widgets->langs->setting('class',__('CSS class:'),'');
 
-$__widgets->create('categories',__('Categories list'),array('defaultWidgets','categories'),null,'List of categories');
+$__widgets->create('categories',__('Categories'),array('defaultWidgets','categories'),null,'List of categories');
 $__widgets->categories->setting('title',__('Title:'),__('Categories'));
 $__widgets->categories->setting('postcount',__('With entries counts'),0,'check');
+$__widgets->categories->setting('with_empty',__('Include empty categories'),0,'check');
 $__widgets->categories->setting('homeonly',__('Display on:'),0,'combo',
 	array(__('All pages') => 0, __('Home page only') => 1, __('Except on home page') => 2));
Index: plugins/widgets/_widgets_functions.php
===================================================================
--- plugins/widgets/_widgets_functions.php	(revision 1253)
+++ plugins/widgets/_widgets_functions.php	(revision 1610)
@@ -29,6 +29,8 @@
 		($w->title ? '<h2><label for="q">'.html::escapeHTML($w->title).'</label></h2>' : '').
 		'<form action="'.$core->blog->url.'" method="get">'.
+		'<fieldset>'.
 		'<p><input type="text" size="10" maxlength="255" id="q" name="q" value="'.$value.'" /> '.
 		'<input type="submit" class="submit" value="ok" /></p>'.
+		'</fieldset>'.
 		'</form>'.
 		($w->content_only ? '' : '</div>');
@@ -75,5 +77,5 @@
 		}
 
-		$rs = $core->blog->getCategories(array('post_type'=>'post'));
+		$rs = $core->blog->getCategories(array('post_type'=>'post','without_empty'=> !$w->with_empty));
 		if ($rs->isEmpty()) {
 			return;
Index: plugins/widgets/class.widgets.php
===================================================================
--- plugins/widgets/class.widgets.php	(revision 1179)
+++ plugins/widgets/class.widgets.php	(revision 1474)
@@ -238,13 +238,13 @@
 				case 'text':
 					$res .=
-					'<p><label for="'.$wfid.'">'.$s['title'].' '.
+					'<p><label for="'.$wfid.'">'.$s['title'].'</label> '.
 					form::field(array($iname,$wfid),20,255,html::escapeHTML($s['value']),'maximal').
-					'</label></p>';
+					'</p>';
 					break;
 				case 'textarea':
 					$res .=
-					'<p><label for="'.$wfid.'">'.$s['title'].' '.
+					'<p><label for="'.$wfid.'">'.$s['title'].'</label> '.
 					form::textarea(array($iname,$wfid),30,5,html::escapeHTML($s['value']),'maximal').
-					'</label></p>';
+					'</p>';
 					break;
 				case 'check':
@@ -257,7 +257,7 @@
 				case 'combo':
 					$res .=
-					'<p><label for="'.$wfid.'">'.$s['title'].' '.
+					'<p><label for="'.$wfid.'">'.$s['title'].'</label> '.
 					form::combo(array($iname,$wfid),$s['options'],$s['value']).
-					'</label></p>';
+					'</p>';
 					break;
 			}
Index: plugins/widgets/dragdrop.js
===================================================================
--- plugins/widgets/dragdrop.js	(revision 0)
+++ plugins/widgets/dragdrop.js	(revision 1659)
@@ -1,211 +1,98 @@
-ToolMan._coordinatesFactory.inside = function(item,container) {
-	var iTL = this.topLeftOffset(item);
-	var iBR = this.bottomRightOffset(item);
-	var cTL = this.topLeftOffset(container);
-	var cBR = this.bottomRightOffset(container);
+/*
+# -- BEGIN LICENSE BLOCK ---------------------------------------
+#
+# This file is part of Dotclear 2.
+#
+# Copyright (c) 2003-2013 Olivier Meunier & Association Dotclear
+# Licensed under the GPL version 2.0 license.
+# See LICENSE file or
+# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+#
+# -- END LICENSE BLOCK -----------------------------------------
+*/
+
+$(function() {
 	
-	return (iTL.x >= cTL.x && iTL.x <= cBR.x && iTL.y >= cTL.y && iTL.y <= cBR.y)
-	|| (iBR.x >= cTL.x && iBR.x <= cBR.x && iBR.y >= cTL.y && iBR.y <= cBR.y);
-}
-
-ToolMan._dragdropFactory = {
-	firstContainer: null,
-	lastContainer: null,
+	// clean
+	$('.remove-if-drag').remove();
+	$('.hidden-if-drag').hide();
+	$('.widgets, .sortable-delete').addClass('if-drag');
 	
-	makeDragable: function(item) {
-		var group = ToolMan.drag().createSimpleGroup(item);
-		group.register('dragstart',this._onDragStart);
-		group.register('dragmove', this._onDragMove);
-		group.register('dragend', this._onDragEnd);
-		
-		item.isOutside = false;
-		item.started = false;
-		
-		return group;
-	},
-	
-	makeListContainer: function(list,name) {
-		// each container becomes a linked list node
-		if (this.firstContainer == null) {
-			this.firstContainer = this.lastContainer = list;
-			list.previousContainer = null;
-			list.nextContainer = null;
-		} else {
-			list.previousContainer = this.lastContainer;
-			list.nextContainer = null;
-			this.lastContainer.nextContainer = list;
-			this.lastContainer = list;
-		}
-		
-		var helpers = ToolMan.helpers();
-		var coordinates = ToolMan.coordinates();
-		
-		//var children = list.childNodes;
-		var items = new Array();
-		for (var i=0; i<list.childNodes.length; i++) {
-			if (list.childNodes[i].nodeType == 1 &&
-			list.childNodes[i].nodeName.toLowerCase() == name.toLowerCase()) {
-				items.push(list.childNodes[i]);
-			}
-		}
-		
-		// these functions are called when an item is draged over
-		// a container or out of a container bounds.  onDragOut
-		// is also called when the drag ends with an item having
-		// been added to the container
-		list.onDragOver = new Function();
-		list.onDragOut = new Function();
-		list.onDragEnd = new Function();
-		
-		if (list.factory == undefined) {
-			list.factory = false;
-		}
-		
-		var This = this;
-		helpers.map(items, function(item) {
-			var dragGroup = This.makeDragable(item);
-			dragGroup.setThreshold(4);
-		});
-		for (var i = 2, n = arguments.length; i < n; i++) {
-			helpers.map(items, arguments[i]);
-		}
-	},
-	
-	_onDragStart: function(dragEvent) {
-		var container = ToolMan._dragdropFactory.firstContainer;
-		var item = dragEvent.group.element;
-		var coordinates = ToolMan.coordinates();
-		
-		// Factory is a sort of assembly pieces, we want to keep them
-		if (item.parentNode.factory) {
-			var origin = item.cloneNode(true);
-			item.parentNode.insertBefore(origin,item.nextSibling);
-			ToolMan._dragdropFactory.makeDragable(origin);
-		}
-		
-		while (container != null) {
-			container.topLeft = coordinates.topLeftOffset(container);
-			container.bottomRight = coordinates.bottomRightOffset(container);
-			container = container.nextContainer;
-		}
-		
-		// item starts out over current parent
-		item.started = true;
-		item.parentNode.onDragOver();
-	},
-	
-	_onDragMove: function(dragEvent) {
-		var helpers = ToolMan.helpers();
-		var coordinates = ToolMan.coordinates();
-		
-		var item = dragEvent.group.element;
-		var xmouse = dragEvent.transformedMouseOffset;
-		var moveTo = null;
-		
-		// Check if we are nowhere
-		if (item.isOutside) {
-			var container = ToolMan._dragdropFactory.firstContainer;
-			while (container != null) {
-				if (coordinates.inside(item,container) && !container.factory) {
-					container.onDragOver();
-					item.isOutside = false;
-					
-					// since isOutside was true, the current parent is a
-					// temporary clone of some previous container node and
-					// it needs to be removed from the document
-					var tempParent = item.parentNode;
-					tempParent.removeChild(item);
-					container.appendChild(item);
-					//tempParent.parentNode.removeChild(tempParent);
-					
-					break;
-				}
-				container = container.nextContainer;
+	// move
+	$( ".connected, .sortable-delete" ).sortable({
+		tolerance: "move",
+		cursor: "move",
+		axis: "y",
+		dropOnEmpty: true,
+		handle: ".widget-name",
+		placeholder: "ui-sortable-placeholder",
+		items: "li:not(.sortable-delete-placeholder)",
+		connectWith: ".connected, .sortable-delete",
+		start: function( event, ui ) {
+			// petit décalage éstétique
+			ui.item.css('left', ui.item.position().left + 20);
+		},
+		update: function(event, ui) {
+			
+			ul = $(this);
+			widget = ui.item;
+			field = ul.parents('.widgets');
+			
+			// met a zéro le décalage
+			ui.item.css('left', 'auto');
+			
+			// signale les zone vide
+			if( ul.find('li').length == 0 )
+				 field.find('.empty-widgets').show();
+			else field.find('.empty-widgets').hide();
+			
+			// remove
+			if( widget.parents('ul').is('.sortable-delete') ) {
+				widget.hide('slow', function() {
+					$(this).remove();
+				});
 			}
 			
-			if (this.isOutside) {
-				return;
+			// réordonne
+			if( ul.attr('id') ) {
+				ul.find('li').each(function(i) {
+					
+					// trouve la zone de récéption
+					var name = ul.attr('id').split('dnd').join('');
+					
+					// modifie le name en conséquence
+					$(this).find('*[name^=w]').each(function(){
+						tab = $(this).attr('name').split('][');
+						tab[0] = "w["+name;
+						tab[1] = i;
+						$(this).attr('name', tab.join(']['));
+					});
+					
+					// ainssi que le champ d'ordre sans js (au cas ou)
+					$(this).find('input[title=ordre]').val(i);
+					
+				});
 			}
+			
+			// expand
+			if(widget.find('img.expand').length == 0) {
+				dotclear.postExpander(widget);
+				dotclear.viewPostContent(widget, 'close');
+			}
+			
 		}
-		// Outside the parent node
-		else if (!coordinates.inside(item,item.parentNode)) {
-			item.parentNode.onDragOut();
-			item.isOutside = true;
-			var container = ToolMan._dragdropFactory.firstContainer;
-			while (container != null) {
-				if (coordinates.inside(item,container) && !container.factory) {
-					container.onDragOver();
-					item.isOutside = false;
-					container.appendChild(item);
-					break;
-				}
-				container = container.nextContainer;
-			}
-			// if we're not in any container now, make a temporary clone of
-			// the previous container node and add it to the document
-			if (this.isOutside) {
-				var tempParent = item.parentNode.cloneNode(false);
-				item.parentNode.removeChild(item);
-				tempParent.appendChild(item);
-				document.body.appendChild(tempParent);
-				return;
-			}
+	});
+	
+	// add
+	$( "#widgets-ref > li" ).draggable({
+		tolerance: "move",
+		cursor: "move",
+		connectToSortable: ".connected",
+		helper: "clone",
+		revert: "invalid",
+		start: function( event, ui ) {
+			ui.helper.css({'width': $('#widgets-ref > li').css('width')});
 		}
-		
-		// if we get here, we're inside some container bounds, so we do
-		// everything the original dragsort script did to swap us into the
-		// correct position
-		
-		if (item.parentNode.factory) {
-			return;
-		}
-		
-		var moveTo = null
-		
-		var previous = helpers.previousItem(item, item.nodeName)
-		while (previous != null) {
-			var bottomRight = coordinates.bottomRightOffset(previous)
-			if (xmouse.y <= bottomRight.y && xmouse.x <= bottomRight.x) {
-				moveTo = previous
-			}
-			previous = helpers.previousItem(previous, item.nodeName)
-		}
-		if (moveTo != null) {
-			helpers.moveBefore(item, moveTo)
-			return
-		}
-		
-		var next = helpers.nextItem(item, item.nodeName)
-		while (next != null) {
-			var topLeft = coordinates.topLeftOffset(next)
-			if (topLeft.y <= xmouse.y && topLeft.x <= xmouse.x) {
-				moveTo = next
-			}
-			next = helpers.nextItem(next, item.nodeName)
-		}
-		if (moveTo != null) {
-			helpers.moveBefore(item, helpers.nextItem(moveTo, item.nodeName))
-			return
-		}
-	},
+	});
 	
-	_onDragEnd: function(dragEvent) {
-		var item = dragEvent.group.element;
-		
-		if (!item.started) {
-			return;
-		}
-		
-		if (item.isOutside || item.parentNode.factory) {
-			item.parentNode.removeChild(item);
-			return;
-		}
-		
-		item.parentNode.onDragEnd.call(item);
-		ToolMan.coordinates().create(0, 0).reposition(dragEvent.group.element);
-	}
-};
-
-ToolMan.dragdrop = function() {
-	return ToolMan._dragdropFactory;
-};
+});
Index: plugins/widgets/index.php
===================================================================
--- plugins/widgets/index.php	(revision 1179)
+++ plugins/widgets/index.php	(revision 1669)
@@ -165,9 +165,9 @@
   <?php echo file_get_contents(dirname(__FILE__).'/style.css'); ?>
   </style>
-  <script type="text/javascript" src="js/tool-man/core.js"></script>
-  <script type="text/javascript" src="js/tool-man/events.js"></script>
-  <script type="text/javascript" src="js/tool-man/css.js"></script>
-  <script type="text/javascript" src="js/tool-man/coordinates.js"></script>
-  <script type="text/javascript" src="js/tool-man/drag.js"></script>
+  <?php
+		echo
+			dcPage::jsLoad('js/jquery/jquery-ui.custom.js').
+			dcPage::jsLoad('index.php?pf=widgets/widgets.js');
+  ?>
   <?php 
 	$core->auth->user_prefs->addWorkspace('accessibility'); 
@@ -177,5 +177,4 @@
   <script type="text/javascript" src="index.php?pf=widgets/dragdrop.js"></script>
   <?php endif; ?>
-  <script type="text/javascript" src="index.php?pf=widgets/widgets.js"></script>
   <script type="text/javascript">
   //<![CDATA[
@@ -188,30 +187,34 @@
 <body>
 <?php
-echo '<h2>'.html::escapeHTML($core->blog->name).' &rsaquo; <span class="page-title">'.__('Widgets').'</span></h2>';
+echo dcPage::breadcrumb(
+	array(
+		html::escapeHTML($core->blog->name) => '',
+		'<span class="page-title">'.__('Widgets').'</span>' => ''
+	));
 
 # All widgets
 echo
 '<form id="listWidgets" action="'.$p_url.'" method="post"  class="widgets">'.
-'<fieldset><legend>'.__('Available widgets').'</legend>'.
-'<div id="widgets">';
+'<h3>'.__('Available widgets').'</h3>'.
+'<p>'.__('Move widgets from this list to one of the sidebars.').'</p>'.
+'<ul id="widgets-ref">';
 
 $j = 0;
 foreach ($__widgets->elements(true) as $w) {
 	echo
-	'<div>'.form::hidden(array('w[void][0][id]'),html::escapeHTML($w->id())).
-	'<p class="widget-name">'.form::field(array('w[void][0][order]'),2,3,0,'hideControl').' '.
-	$w->name().($w->desc() != '' ? ' <span class="form-note">('.__($w->desc()).')</span>' : '').'</p>'.
-	'<p class="js-remove"><label class="classic">'.__('Append to:').' '.
-	form::combo(array('addw['.$w->id().']'),$append_combo).'</label></p>'.
-	'<div class="widgetSettings">'.$w->formSettings('w[void][0]',$j).'</div>'.
-	'</div>';
+	'<li>'.form::hidden(array('w[void][0][id]'),html::escapeHTML($w->id())).
+	'<p class="widget-name">'.form::field(array('w[void][0][order]'),2,3,0,'hide','',0,'title="'.__('order').'"').' '.$w->name().
+	($w->desc() != '' ? ' <span class="form-note">'.__($w->desc()).'</span>' : '').'</p>'.
+	'<p class="manual-move remove-if-drag"><label class="classic">'.__('Append to:').'</label> '.
+	form::combo(array('addw['.$w->id().']'),$append_combo).'</p>'.
+	'<div class="widgetSettings hidden-if-drag">'.$w->formSettings('w[void][0]',$j).'</div>'.
+	'</li>';
 	$j++;
 }
 
 echo
-'</div>'.
-'</fieldset>'.
-'<p><input type="submit" class="js-remove" name="append" value="'.__('Add widgets to sidebars').'" />'.
-$core->formNonce().'</p>'.
+'</ul>'.
+$core->formNonce().
+'<p class="remove-if-drag"><input type="submit" name="append" value="'.__('Add widgets to sidebars').'" /></p>'.
 '</form>';
 
@@ -219,19 +222,19 @@
 # Nav sidebar
 echo
-'<div id="sidebarNav" class="widgets">'.
-sidebarWidgets('dndnav',__('Navigation sidebar'),$widgets_nav,'nav',$__default_widgets['nav'],$j).
-'</div>';
+'<div id="sidebarNav" class="widgets fieldset">'.
+sidebarWidgets('dndnav',__('Navigation sidebar'),$widgets_nav,'nav',$__default_widgets['nav'],$j);
+echo '</div>';
 
 # Extra sidebar
 echo
-'<div id="sidebarExtra" class="widgets">'.
-sidebarWidgets('dndextra',__('Extra sidebar'),$widgets_extra,'extra',$__default_widgets['extra'],$j).
-'</div>';
+'<div id="sidebarExtra" class="widgets fieldset">'.
+sidebarWidgets('dndextra',__('Extra sidebar'),$widgets_extra,'extra',$__default_widgets['extra'],$j);
+echo '</div>';
 
 # Custom sidebar
 echo
-'<div id="sidebarCustom" class="widgets">'.
-sidebarWidgets('dndcustom',__('Custom sidebar'),$widgets_custom,'custom',$__default_widgets['custom'],$j).
-'</div>';
+'<div id="sidebarCustom" class="widgets fieldset">'.
+sidebarWidgets('dndcustom',__('Custom sidebar'),$widgets_custom,'custom',$__default_widgets['custom'],$j);
+echo '</div>';
 
 echo
@@ -248,5 +251,5 @@
 'drag it from the Available widgets list on the left to one of the sidebars on the right of this page. You can order '.
 'your widgets in a sidebar by dragging them up or down. You must update sidebars to apply your changes.').'</p>'.
-'<p>'.__('Once included in a sidebar, widgets have configuration options that you can reach by clicking on the + sign next '.
+'<p>'.__('Once included in a sidebar, widgets have configuration options that you can reach by clicking on the arrow next '.
 'to their name.').'</p>'.
 '<p>'.__('Reset sidebars to get back to default widgets installation.').'</p>'.
@@ -312,5 +315,5 @@
 function sidebarWidgets($id,$title,$widgets,$pr,$default_widgets,&$j)
 {
-	$res = '<fieldset><legend>'.$title.'</legend><div id="'.$id.'">';
+	$res = '<h3>'.$title.'</h3>';
 	
 	if (!($widgets instanceof dcWidgets))
@@ -319,7 +322,7 @@
 	}
 	
-	if ($widgets->isEmpty()) {
-		$res .= '<p class="empty-widgets">'.__('No widget.').'</p>';
-	}
+	$res .= '<p class="empty-widgets" '.(!$widgets->isEmpty() ? 'style="display: none;"' : '').'>'.__('No widget.').'</p>';
+	
+	$res .= '<ul id="'.$id.'" class="connected">';
 	
 	$i = 0;
@@ -329,12 +332,12 @@
 		
 		$res .=
-		'<div>'.form::hidden(array($iname.'[id]'),html::escapeHTML($w->id())).
-		'<p class="widget-name">'.form::field(array($iname.'[order]'),2,3,(string) $i,'js-hide','',0,'title="'.__('order').'"').' '.
-		$w->name().($w->desc() != '' ? ' <span class="form-note">('.__($w->desc()).')</span>' : '').'</p>'.
-		'<p class="removeWidget js-remove"><label class="classic">'.
+		'<li>'.form::hidden(array($iname.'[id]'),html::escapeHTML($w->id())).
+		'<p class="widget-name">'.form::field(array($iname.'[order]'),2,3,(string) $i,'hidden-if-drag','',0,'title="'.__('order').'"').' '.$w->name().
+		($w->desc() != '' ? ' <span class="form-note">'.__($w->desc()).'</span>' : '').'</p>'.
+		'<p class="removeWidget remove-if-drag"><label class="classic">'.
 		form::checkbox(array($iname.'[_rem]'),'1',0).' '.__('Remove widget').
 		'</label></p>'.
-		'<div class="widgetSettings">'.$w->formSettings($iname,$j).'</div>'.
-		'</div>';
+		'<div class="widgetSettings hidden-if-drag">'.$w->formSettings($iname,$j).'</div>'.
+		'</li>';
 		
 		$i++;
@@ -342,5 +345,10 @@
 	}
 	
-	$res .= '</div></fieldset>';
+	$res .= '</ul>';
+
+	if ($i > 0) {
+		$res .= '<ul class="sortable-delete"><li class="sortable-delete-placeholder">'.
+			__('Drag widgets here to remove them from this sidebar.').'</li></ul>';
+	}
 	
 	return $res;
Index: plugins/widgets/style.css
===================================================================
--- plugins/widgets/style.css	(revision 665)
+++ plugins/widgets/style.css	(revision 1669)
@@ -1,25 +1,108 @@
-#listWidgets {
-	float: left;
-	width: 33%;
-}
+/*
+# -- BEGIN LICENSE BLOCK ---------------------------------------
+#
+# This file is part of Dotclear 2.
+#
+# Copyright (c) 2003-2013 Olivier Meunier & Association Dotclear
+# Licensed under the GPL version 2.0 license.
+# See LICENSE file or
+# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+#
+# -- END LICENSE BLOCK -----------------------------------------
+*/
 
+
+/* ------------------------------------------------------------- side bars */
 #sidebarsWidgets {
 	float: left;
-	width: 65%;
-	margin-left: 1%;
+	width: 47%;
+	margin: 0 0 0 1%;
+	padding: 0 1%;
 }
-#sidebarNav {
-	float: left;
-	width: 50%;
-	margin-left: 0%;
+.widgets.fieldset {
+	margin-bottom: 2em;
 }
-#sidebarExtra {
-	float: left;
-	width: 49%;
-	margin-left: 1%;
+.widgets.fieldset.if-drag {
+	padding-bottom: 0;
+	border-radius: .5em;
 }
-#sidebarCustom {
-	float: left;
-	width: 100%;
+#dndnav, #dndextra, #dndcustom {
+	padding: 1em 0;
+	margin: 1em 0 0;
+}
+#dndnav > li,
+#dndextra > li,
+#dndcustom > li {
+	padding: 0;
+	border: 1px solid #999;
+	margin-bottom: 1em;
+	list-style: none;
+}
+#dndnav > li.ui-sortable-placeholder,
+#dndextra > li.ui-sortable-placeholder,
+#dndcustom > li.ui-sortable-placeholder,
+.sortable-delete > li.ui-sortable-placeholder {
+	border: 1px dashed #999;
+	height: 2em;
+	padding: .3em;
+}
+.sortable-delete > li.ui-sortable-placeholder {
+	border-width: 2px;
+	border-color: red;
+}
+.sortable-delete {
+	display: none;
+}
+.sortable-delete.if-drag {
+    border: 1px dotted #999;
+    color: #000;
+    font-weight: bold;
+    list-style-type: none;
+    margin: 0 0 1em;
+    padding: .5em 1em;
+    display: block;
+    background: #fafafa;
+}
+.sortable-delete > li {
+	margin-bottom: 3px;
+}
+.sortable-delete > li.sortable-delete-placeholder {
+    border: 0 none;
+    color: #aaa;
+    font-size: 1em;
+    font-weight: bold;
+    text-align: center;
+}
+.widget-name {
+	background: #eef;
+	color: #000;
+	padding: 4px 6px;
+	margin: 0;
+	font-weight: bold;
+}
+.widget-name img {
+	cursor: pointer;
+	margin-bottom: -1px;
+}
+.widget-name a.aexpand,
+.widget-name a.aexpand:link,
+.widget-name a.aexpand:visited {
+    border: 0 none;
+    color: #000;
+    text-decoration: none;
+}
+#dndnav .form-note,
+#dndextra .form-note,
+#dndcustom .form-note {
+	display: none;
+}
+.removeWidget {
+	padding: 8px 6px;
+	margin: 0;
+}
+.widgetSettings {
+	border-top: 1px solid #ddd;
+	padding: 8px 6px;
+	background: #f5f5f5;
 }
 
@@ -28,49 +111,47 @@
 }
 
-#widgets, #dndnav, #dndextra {
-	padding: 1em 0;
+/* ------------------------------------------------------------- list Widgets ref */
+#listWidgets {
+	float: left;
+	width: 46%;
+	background: #eee;
+	padding: 1.5em 1% 0; 
+	margin: 0 1% 0 0;
+}
+#listWidgets h3 {
+	color: #333;
 }
 
-.widgets fieldset {
-	border: 1px solid #999;
+#widgets-ref {
+	padding: 1em 0;
+	margin: 1em 0 0;
 }
-.widgets legend {
-	border: 1px solid #999;
+#widgets-ref > li {
+	border: 1px solid #ccc;
+	margin-bottom: .5em;
+	background: #fff;
+	min-height: 3em;
+	padding: 0 0 4px 0;
+	list-style: none;
 }
-
-.widgets p.widget-name {
-	background: #E5E3DA;
-	color: #000;
-	padding: 4px;
-	margin: 0.5em 0 0 0;
-	border-width: 1px 1px 1px 1px;
-	border-style: solid;
-	border-color: #666;
-	font-weight: bold;
+#widgets-ref .widget-name,
+#widgets-ref .manual-move {
+	background: #fff;
+	margin-bottom: 0;
+	padding: 4px 8px 0;
 }
-.widgets p.widget-name img {
-	cursor: pointer;
-	margin-bottom: -1px;
+#widgets-ref .widget-name {
+	min-height: 3em;
 }
-
-.widgetSettings {
-	border-width: 0 1px 1px 1px;
-	border-style: solid;
-	border-color: #666;
-	padding: 4px;
-	background: #E5E3DA;
+#widgets-ref .widget-name .form-note {
+	display: block;
+	font-style: normal;
+	font-size: 1.1rem;
 }
-
-#widgets .widgetSettings {
+#widgets-ref .widgetSettings {
 	display: none;
 }
 
-.hideControls .widgetSettings {
-	display: none;
-}
-.hideControl {
-	display: none;
-}
-
+/* ------------------------------------------------------------- help */
 #widgets-tpl dt {
 	margin: 1em 0 0 0;
Index: plugins/widgets/widgets.js
===================================================================
--- plugins/widgets/widgets.js	(revision 665)
+++ plugins/widgets/widgets.js	(revision 1661)
@@ -1,227 +1,71 @@
-var dragdrop = ToolMan.dragdrop();
-$(function() {
+/*
+# -- BEGIN LICENSE BLOCK ---------------------------------------
+#
+# This file is part of Dotclear 2.
+#
+# Copyright (c) 2003-2013 Olivier Meunier & Association Dotclear
+# Licensed under the GPL version 2.0 license.
+# See LICENSE file or
+# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+#
+# -- END LICENSE BLOCK -----------------------------------------
+*/
+
+dotclear.postExpander = function(line) {
+	var title = $(line).find('.widget-name');
+	title.find('.form-note').remove();
+	order = title.find('input[name*=order]');
+	link = $('<a href="#" alt="expand" class="aexpand"/>').append(title.text());
+	title.empty().append(order).append(link);
+	
+	var img = document.createElement('img');
+	img.src = dotclear.img_plus_src;
+	img.alt = dotclear.img_plus_alt;
+	img.className = 'expand';
+	$(img).css('cursor','pointer');
+	img.onclick = function() { dotclear.viewPostContent($(this).parents('li')); };
+	link.click(function(e) {
+		e.preventDefault();
+		dotclear.viewPostContent($(this).parents('li'));
+	});
+	
+	title.prepend(img);
+};
+
+dotclear.viewPostContent = function(line,action) {
+	var action = action || 'toogle';
+	var img = line.find('.expand');
+	var isopen = img.attr('alt') == dotclear.img_plus_alt;
+	
+	if( action == 'close' || ( action == 'toogle' && !isopen ) ) {
+		line.find('.widgetSettings').hide();
+		img.attr('src', dotclear.img_plus_src);
+		img.attr('alt', dotclear.img_plus_alt);
+	} else if ( action == 'open' || ( action == 'toogle' && isopen ) ) {
+		line.find('.widgetSettings').show();
+		img.attr('src', dotclear.img_minus_src);
+		img.attr('alt', dotclear.img_minus_alt);
+	}
+	
+};
+
+$(function() {	
+	// reset
 	$('input[name="wreset"]').click(function() {
 		return window.confirm(dotclear.msg.confirm_widgets_reset);
 	});
+	
+	// plier/déplier
+	$('#dndnav > li, #dndextra > li, #dndcustom > li').each(function() {
+		dotclear.postExpander(this);
+		dotclear.viewPostContent($(this), 'close');
+	});
+	
+	// remove
+	$('input[name*=rem]').change(function () {
+	    if ($(this).attr("checked")) {
+	        $(this).parents('li').remove();
+	    }
+	});
+	
 });
-
-$(function() {
-	var widgets = document.getElementById('widgets');
-	var w_nav = document.getElementById('dndnav');
-	var w_ext = document.getElementById('dndextra');
-	var w_custom = document.getElementById('dndcustom');
-	
-	w_nav.className = 'hideControls';
-	w_ext.className = 'hideControls';
-	w_custom.className = 'hideControls';
-	
-	removeElements(document.getElementById('listWidgets'),'input');
-	removeElements(widgets,'p');
-	removeElements(w_nav,'p');
-	removeElements(w_ext,'p');
-	removeElements(w_custom,'p');
-	hideElements(w_nav,'input');
-	hideElements(w_ext,'input');
-	hideElements(w_custom,'input');
-	
-	configControls(w_nav);
-	configControls(w_ext);
-	configControls(w_custom);
-	
-	dragdrop.makeListContainer(widgets,'div',setHandle);
-	if (!document.all) { widgets.factory = true; }
-	dragdrop.makeListContainer(w_nav,'div',setHandle);
-	w_nav.onDragEnd = navDragEnd;
-	dragdrop.makeListContainer(w_ext,'div',setHandle);
-	w_ext.onDragEnd = extraDragEnd;
-	dragdrop.makeListContainer(w_custom,'div',setHandle);
-	w_custom.onDragEnd = customDragEnd;
-	
-	// Helper to remove some elements
-	function removeElements(p,name) {
-		name = name || 'div';
-		$(p).find(name+'.js-remove').each(function() {
-			this.parentNode.removeChild(this);
-		});
-	}
-	
-	// Helper to hide elements (but keep them)
-	function hideElements(p,name) {
-		name = name || 'div';
-		$(p).find(name+'.js-hide').each(function() {
-			$(this).toggle();
-		});
-	}	
-	
-	function removeEmptyMsg(p) {
-		$(p).find('p.empty-widgets').each(function() {
-			this.parentNode.removeChild(this);
-		});
-	}
-	
-	// Events on dragEnd
-	function navDragEnd() {
-		formControls(this.parentNode,'nav');
-		configControls(this.parentNode);
-		removeEmptyMsg(this.parentNode);
-	}
-	function extraDragEnd() {
-		formControls(this.parentNode,'extra');
-		configControls(this.parentNode);
-		removeEmptyMsg(this.parentNode);
-	}
-	function customDragEnd() {
-		formControls(this.parentNode,'custom');
-		configControls(this.parentNode);
-		removeEmptyMsg(this.parentNode);
-	}
-	
-	// dragEnd helper
-	function formControls(e,pr) {
-		var items = new Array();
-		for (var i=0; i<e.childNodes.length; i++) {
-			if (e.childNodes[i].nodeType == 1 && e.childNodes[i].nodeName.toLowerCase() == 'div') {
-				items.push(e.childNodes[i]);
-			}
-		}
-		
-		var fields, itype;
-		var r = new RegExp('^w\[[a-z]+]\[[0-9]+][[](.+?)]$','');
-		for (i=0; i<items.length; i++) {
-			// Change field names
-			fields = getFormControls(items[i]);
-			var j;
-			var f;
-			for (j=0; j<fields.length; j++) {
-				if (r.test(fields[j].name)) {
-					itype = fields[j].name.replace(r,'$1');
-					
-					$(fields[j]).attr('name','w['+pr+']['+i+']['+itype+']');
-					
-					if (itype == 'order') {
-						fields[j].value = i;
-					}
-				}
-			}
-		}
-	}
-	
-	function getFormControls(e) {
-		var input = e.getElementsByTagName('input');
-		var textarea = e.getElementsByTagName('textarea');
-		var select = e.getElementsByTagName('select');
-		var items = new Array();
-		var i;
-		for (i=0; i<input.length; i++) { items.push(input[i]); }
-		for (i=0; i<select.length; i++) { items.push(select[i]); }
-		for (i=0; i<textarea.length; i++) { items.push(textarea[i]); }
-		
-		return items;
-	}
-	
-	function configControls(e) {
-		var items = new Array();
-		for (var i=0; i<e.childNodes.length; i++) {
-			if (e.childNodes[i].nodeType == 1 && e.childNodes[i].nodeName.toLowerCase() == 'div') {
-				items.push(e.childNodes[i]);
-			}
-		}
-		
-		var title, img_ctrl, img, space;
-		for (i in items) {
-			// Append config control
-			title = $('p.widget-name',items[i]).get(0);
-			img_ctrl = title.firstChild;
-			
-			// There already an image
-			if (img_ctrl.nodeName.toLowerCase() == 'img') {
-				continue;
-			}
-			
-			// Nothing to configure
-			if (title.nextSibling.childNodes.length == 0) {
-				continue;
-			}
-			
-			img = document.createElement('img');
-			img.src = dotclear.img_plus_src;
-			img.alt = dotclear.img_plus_alt;
-			img.control = title.nextSibling;
-			img.onclick = function() { widgetConfig.call(this); };
-			space = document.createTextNode(' ');
-			title.insertBefore(img,img_ctrl);
-			title.insertBefore(space,img_ctrl);
-		}
-	}
-	
-	function widgetConfig() {
-		if (this.control.style.display == 'block') {
-			this.control.style.display = 'none';
-			this.src = dotclear.img_plus_src;
-			this.alt = dotclear.img_plus_alt;
-		} else {
-			this.control.style.display = 'block';
-			this.src = dotclear.img_minus_src;
-			this.alt = dotclear.img_minus_alt;
-		}
-	}
-	
-	function setHandle(item) {
-		//var handle = item.getElementsByTagName('h4').item(0);
-		var handle = $('p.widget-name',item).get(0);
-		$(handle).addClass('handler');
-		item.toolManDragGroup.setHandle(handle);
-	}
-});
-
-//
-// For Safari, we need to make a hard copy of the form and submit copy.
-// Yeah, a simple clone of the form is not enough
-// I hate this browser!
-//
-if (document.childNodes && !document.all && !navigator.taintEnabled)
-{
-	$(function() {
-		$('#sidebarsWidgets').submit(function() {
-			// Create a new form and copy each element inside
-			var f = document.createElement('form');
-			f.action = this.action;
-			f.method = this.method;
-			$(f).hide();
-			var fset = document.createElement('fieldset');
-			f.appendChild(fset);
-			
-			document.body.appendChild(f);
-			
-			$(this).find('input').each(function() {
-				var i = document.createElement('input');
-				i.type = this.type;
-				i.name = this.name;
-				i.value = this.value;
-				if (this.type == 'checkbox') {
-					i.checked = this.checked;
-				}
-				fset.appendChild(i);
-			});
-			
-			$(this).find('textarea').each(function() {
-				var i = document.createElement('textarea');
-				i.name = this.name;
-				i.value = this.value;
-				fset.appendChild(i);
-			});
-			
-			$(this).find('select').each(function() {
-				var i = document.createElement('input');
-				i.name = this.name;
-				i.value = this.value;
-				fset.appendChild(i);
-			});
-			
-			$(fset).append('<input type="hidden" name="wup" value="1"/>');
-			f.submit();
-			
-			return false;
-		});
-	});
-}
Index: tests/functional/css/jasmine.css
===================================================================
--- tests/functional/css/jasmine.css	(revision 1602)
+++ tests/functional/css/jasmine.css	(revision 1602)
@@ -0,0 +1,82 @@
+body { background-color: #eeeeee; padding: 0; margin: 5px; overflow-y: scroll; }
+
+#HTMLReporter { font-size: 11px; font-family: Monaco, "Lucida Console", monospace; line-height: 14px; color: #333333; }
+#HTMLReporter a { text-decoration: none; }
+#HTMLReporter a:hover { text-decoration: underline; }
+#HTMLReporter p, #HTMLReporter h1, #HTMLReporter h2, #HTMLReporter h3, #HTMLReporter h4, #HTMLReporter h5, #HTMLReporter h6 { margin: 0; line-height: 14px; }
+#HTMLReporter .banner, #HTMLReporter .symbolSummary, #HTMLReporter .summary, #HTMLReporter .resultMessage, #HTMLReporter .specDetail .description, #HTMLReporter .alert .bar, #HTMLReporter .stackTrace { padding-left: 9px; padding-right: 9px; }
+#HTMLReporter #jasmine_content { position: fixed; right: 100%; }
+#HTMLReporter .version { color: #aaaaaa; }
+#HTMLReporter .banner { margin-top: 14px; }
+#HTMLReporter .duration { color: #aaaaaa; float: right; }
+#HTMLReporter .symbolSummary { overflow: hidden; *zoom: 1; margin: 14px 0; }
+#HTMLReporter .symbolSummary li { display: block; float: left; height: 7px; width: 14px; margin-bottom: 7px; font-size: 16px; }
+#HTMLReporter .symbolSummary li.passed { font-size: 14px; }
+#HTMLReporter .symbolSummary li.passed:before { color: #5e7d00; content: "\02022"; }
+#HTMLReporter .symbolSummary li.failed { line-height: 9px; }
+#HTMLReporter .symbolSummary li.failed:before { color: #b03911; content: "x"; font-weight: bold; margin-left: -1px; }
+#HTMLReporter .symbolSummary li.skipped { font-size: 14px; }
+#HTMLReporter .symbolSummary li.skipped:before { color: #bababa; content: "\02022"; }
+#HTMLReporter .symbolSummary li.pending { line-height: 11px; }
+#HTMLReporter .symbolSummary li.pending:before { color: #aaaaaa; content: "-"; }
+#HTMLReporter .exceptions { color: #fff; float: right; margin-top: 5px; margin-right: 5px; }
+#HTMLReporter .bar { line-height: 28px; font-size: 14px; display: block; color: #eee; }
+#HTMLReporter .runningAlert { background-color: #666666; }
+#HTMLReporter .skippedAlert { background-color: #aaaaaa; }
+#HTMLReporter .skippedAlert:first-child { background-color: #333333; }
+#HTMLReporter .skippedAlert:hover { text-decoration: none; color: white; text-decoration: underline; }
+#HTMLReporter .passingAlert { background-color: #a6b779; }
+#HTMLReporter .passingAlert:first-child { background-color: #5e7d00; }
+#HTMLReporter .failingAlert { background-color: #cf867e; }
+#HTMLReporter .failingAlert:first-child { background-color: #b03911; }
+#HTMLReporter .results { margin-top: 14px; }
+#HTMLReporter #details { display: none; }
+#HTMLReporter .resultsMenu, #HTMLReporter .resultsMenu a { background-color: #fff; color: #333333; }
+#HTMLReporter.showDetails .summaryMenuItem { font-weight: normal; text-decoration: inherit; }
+#HTMLReporter.showDetails .summaryMenuItem:hover { text-decoration: underline; }
+#HTMLReporter.showDetails .detailsMenuItem { font-weight: bold; text-decoration: underline; }
+#HTMLReporter.showDetails .summary { display: none; }
+#HTMLReporter.showDetails #details { display: block; }
+#HTMLReporter .summaryMenuItem { font-weight: bold; text-decoration: underline; }
+#HTMLReporter .summary { margin-top: 14px; }
+#HTMLReporter .summary .suite .suite, #HTMLReporter .summary .specSummary { margin-left: 14px; }
+#HTMLReporter .summary .specSummary.passed a { color: #5e7d00; }
+#HTMLReporter .summary .specSummary.failed a { color: #b03911; }
+#HTMLReporter .description + .suite { margin-top: 0; }
+#HTMLReporter .suite { margin-top: 14px; }
+#HTMLReporter .suite a { color: #333333; }
+#HTMLReporter #details .specDetail { margin-bottom: 28px; }
+#HTMLReporter #details .specDetail .description { display: block; color: white; background-color: #b03911; }
+#HTMLReporter .resultMessage { padding-top: 14px; color: #333333; }
+#HTMLReporter .resultMessage span.result { display: block; }
+#HTMLReporter .stackTrace { margin: 5px 0 0 0; max-height: 224px; overflow: auto; line-height: 18px; color: #666666; border: 1px solid #ddd; background: white; white-space: pre; }
+
+#TrivialReporter { padding: 8px 13px; position: absolute; top: 0; bottom: 0; left: 0; right: 0; overflow-y: scroll; background-color: white; font-family: "Helvetica Neue Light", "Lucida Grande", "Calibri", "Arial", sans-serif; /*.resultMessage {*/ /*white-space: pre;*/ /*}*/ }
+#TrivialReporter a:visited, #TrivialReporter a { color: #303; }
+#TrivialReporter a:hover, #TrivialReporter a:active { color: blue; }
+#TrivialReporter .run_spec { float: right; padding-right: 5px; font-size: .8em; text-decoration: none; }
+#TrivialReporter .banner { color: #303; background-color: #fef; padding: 5px; }
+#TrivialReporter .logo { float: left; font-size: 1.1em; padding-left: 5px; }
+#TrivialReporter .logo .version { font-size: .6em; padding-left: 1em; }
+#TrivialReporter .runner.running { background-color: yellow; }
+#TrivialReporter .options { text-align: right; font-size: .8em; }
+#TrivialReporter .suite { border: 1px outset gray; margin: 5px 0; padding-left: 1em; }
+#TrivialReporter .suite .suite { margin: 5px; }
+#TrivialReporter .suite.passed { background-color: #dfd; }
+#TrivialReporter .suite.failed { background-color: #fdd; }
+#TrivialReporter .spec { margin: 5px; padding-left: 1em; clear: both; }
+#TrivialReporter .spec.failed, #TrivialReporter .spec.passed, #TrivialReporter .spec.skipped { padding-bottom: 5px; border: 1px solid gray; }
+#TrivialReporter .spec.failed { background-color: #fbb; border-color: red; }
+#TrivialReporter .spec.passed { background-color: #bfb; border-color: green; }
+#TrivialReporter .spec.skipped { background-color: #bbb; }
+#TrivialReporter .messages { border-left: 1px dashed gray; padding-left: 1em; padding-right: 1em; }
+#TrivialReporter .passed { background-color: #cfc; display: none; }
+#TrivialReporter .failed { background-color: #fbb; }
+#TrivialReporter .skipped { color: #777; background-color: #eee; display: none; }
+#TrivialReporter .resultMessage span.result { display: block; line-height: 2em; color: black; }
+#TrivialReporter .resultMessage .mismatch { color: black; }
+#TrivialReporter .stackTrace { white-space: pre; font-size: .8em; margin-left: 10px; max-height: 5em; overflow: auto; border: 1px inset red; padding: 1em; background: #eef; }
+#TrivialReporter .finished-at { padding-left: 1em; font-size: .6em; }
+#TrivialReporter.show-passed .passed, #TrivialReporter.show-skipped .skipped { display: block; }
+#TrivialReporter #jasmine_content { position: fixed; right: 100%; }
+#TrivialReporter .runner { border: 1px solid gray; display: block; margin: 5px 0; padding: 2px 0 2px 10px; }
Index: tests/functional/fixtures/menu.html
===================================================================
--- tests/functional/fixtures/menu.html	(revision 1602)
+++ tests/functional/fixtures/menu.html	(revision 1602)
@@ -0,0 +1,36 @@
+<div id="menu">
+  <div id="status-box" class="box">
+    <h4>État</h4>
+    <p class="entry-status">
+      <label for="post_status" class="ib">État du billet <img class="img_select_option" alt="Publié" title="Publié" src="../../admin/images/check-on.png" /></label>
+      <select name="post_status" id="post_status" class="maximal" >
+	<option value="-2">En attente</option>
+	<option value="-1">Programmé</option>
+	<option value="0">Non publié</option>
+	<option value="1" selected="selected">Publié</option>
+      </select>
+    </p>
+    <p>
+      <label for="post_dt" class="ib">Date et heure de publication</label>
+      <input type="text" size="16" name="post_dt" id="post_dt" maxlength="16" value="2013-08-15 13:17"  /></p>
+    <p>
+      <label for="post_lang" class="ib">Langue du billet</label>
+      <select name="post_lang" id="post_lang" >
+	<option value=""></option>
+	<optgroup label="Plus utilisées">
+	  <option value="fr" selected="selected">fr - Français</option>
+	</optgroup>
+	<optgroup label="Disponible">
+	  <option value="aa">aa - Afaraf</option>
+	  <option value="zu">zu - isiZulu</option>
+	</optgroup>
+      </select>
+    </p>
+    <p>
+      <label for="post_format" class="ib">Syntaxe de saisie</label><select name="post_format" id="post_format" class="maximal" >
+	<option value="xhtml" selected="selected">xhtml</option>
+	<option value="wiki">wiki</option>
+      </select>
+    </p>
+  </div>
+</div>
Index: tests/functional/fixtures/normal.html
===================================================================
--- tests/functional/fixtures/normal.html	(revision 1602)
+++ tests/functional/fixtures/normal.html	(revision 1602)
@@ -0,0 +1,13 @@
+<form id="permissions-form" action="users_actions.php" method="post">
+  <input type="checkbox" name="perm[default][admin]" value="1" id="permdefaultadmin"  />
+  <input type="checkbox" name="perm[default][usage]" value="1" id="permdefaultusage"  />
+  <input type="checkbox" name="perm[default][publish]" value="1" id="permdefaultpublish"  />
+  <input type="checkbox" name="perm[default][delete]" value="1" id="permdefaultdelete"  />
+  <input type="checkbox" name="perm[default][contentadmin]" value="1" id="permdefaultcontentadmin"  />
+  <input type="checkbox" name="perm[default][categories]" value="1" id="permdefaultcategories"  />
+  <input type="checkbox" name="perm[default][media]" value="1" id="permdefaultmedia"  />
+  <input type="checkbox" name="perm[default][media_admin]" value="1" id="permdefaultmedia_admin"  />
+  <input type="checkbox" name="perm[default][pages]" value="1" id="permdefaultpages"  />
+  <input type="checkbox" name="perm[default][blogroll]" value="1" id="permdefaultblogroll"  />
+  <input type="submit" accesskey="s" value="Enregistrer" />
+</form>
Index: tests/functional/index.html
===================================================================
--- tests/functional/index.html	(revision 1602)
+++ tests/functional/index.html	(revision 1602)
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>Dotclear Spec Runner using jasmine</title>
+    <link rel="stylesheet" type="text/css" href="css/jasmine.css">
+
+    <script type="text/javascript" src="lib/jasmine.js"></script>
+    <script type="text/javascript" src="lib/jasmine-html.js"></script>
+    <script type="text/javascript" src="lib/jquery.js"></script>
+    <script type="text/javascript" src="lib/jasmine-jquery.js"></script>
+    <script type="text/javascript" src="lib/jasmine-jquery-bootstrap.js"></script>
+
+    <script type="text/javascript" src="../../admin/js/_users_actions.js"></script>
+    <script type="text/javascript" src="../../admin/js/common.js"></script>
+    <script type="text/javascript" src="js/fix_include.js"></script>
+
+    <script type="text/javascript" src="spec/users_actions.js"></script>
+    <script type="text/javascript" src="spec/toggle_with_legend.js"></script>
+  </head>
+  <body>
+  </body>
+</html>
Index: tests/functional/js/fix_include.js
===================================================================
--- tests/functional/js/fix_include.js	(revision 1602)
+++ tests/functional/js/fix_include.js	(revision 1602)
@@ -0,0 +1,9 @@
+var dotclear = dotclear || {};
+dotclear.img_plus_src = '../../admin/images/expand.png';
+dotclear.img_plus_alt = 'uncover';
+dotclear.img_minus_src = '../../admin/images/hide.png';
+dotclear.img_minus_alt = 'hide';
+
+jQuery.cookie = function() {};
+jQuery.fn.backgroundFade = function() {};
+
Index: tests/functional/js/plugins.js
===================================================================
--- tests/functional/js/plugins.js	(revision 1602)
+++ tests/functional/js/plugins.js	(revision 1602)
@@ -0,0 +1,83 @@
+var dotclear = {};
+dotclear.img_plus_src = '../../admin/images/expand.png';
+dotclear.img_plus_alt = 'uncover';
+dotclear.img_minus_src = '../../admin/images/hide.png';
+dotclear.img_minus_alt = 'hide';
+
+jQuery.fn.toggleWithLegend = function(target,s) {
+	var defaults = {
+		img_on_src: dotclear.img_plus_src,
+		img_on_alt: dotclear.img_plus_alt,
+		img_off_src: dotclear.img_minus_src,
+		img_off_alt: dotclear.img_minus_alt,
+		hide: true,
+		speed: 0,
+		legend_click: false,
+		fn: false, // A function called on first display,
+		cookie: false,
+		reverse_cookie: false // Reverse cookie behavior
+	};
+	var p = jQuery.extend(defaults,s);
+
+	if (!target) { return this; }
+
+	var set_cookie = p.hide ^ p.reverse_cookie;
+	if (p.cookie && jQuery.cookie(p.cookie)) {
+		p.hide = p.reverse_cookie;
+	}
+
+	var toggle = function(i,speed) {
+		speed = speed || 0;
+		if (p.hide) {
+			$(i).get(0).src = p.img_on_src;
+			$(i).get(0).alt = p.img_on_alt;
+			target.hide(speed);
+		} else {
+			$(i).get(0).src = p.img_off_src;
+			$(i).get(0).alt = p.img_off_alt;
+			target.show(speed);
+			if (p.fn) {
+				p.fn.apply(target);
+				p.fn = false;
+			}
+		}
+
+		if (p.cookie && set_cookie) {
+			if (p.hide ^ p.reverse_cookie) {
+				jQuery.cookie(p.cookie,'',{expires: -1});
+			} else {
+				jQuery.cookie(p.cookie,1,{expires: 30});
+			}
+		}
+
+		p.hide = !p.hide;
+	};
+
+	return this.each(function() {
+		var i = document.createElement('img');
+		i.src = p.img_off_src;
+		i.alt = p.img_off_alt;
+		var a = document.createElement('a');
+		a.href= '#';
+		$(a).append(i);
+		$(a).css({
+			border: 'none',
+			outline: 'none'
+		});
+
+		var ctarget = p.legend_click ? this : a;
+
+		$(ctarget).css('cursor','pointer');
+		if (p.legend_click) {
+			$(ctarget).find('label').css('cursor','pointer');
+		}
+		$(ctarget).click(function() {
+			toggle(i,p.speed);
+			return false;
+		});
+
+
+		toggle($(i).get(0));
+		$(this).prepend(' ').prepend(a);
+	});
+};
Index: tests/functional/lib/jasmine-html.js
===================================================================
--- tests/functional/lib/jasmine-html.js	(revision 1602)
+++ tests/functional/lib/jasmine-html.js	(revision 1602)
@@ -0,0 +1,681 @@
+jasmine.HtmlReporterHelpers = {};
+
+jasmine.HtmlReporterHelpers.createDom = function(type, attrs, childrenVarArgs) {
+  var el = document.createElement(type);
+
+  for (var i = 2; i < arguments.length; i++) {
+    var child = arguments[i];
+
+    if (typeof child === 'string') {
+      el.appendChild(document.createTextNode(child));
+    } else {
+      if (child) {
+        el.appendChild(child);
+      }
+    }
+  }
+
+  for (var attr in attrs) {
+    if (attr == "className") {
+      el[attr] = attrs[attr];
+    } else {
+      el.setAttribute(attr, attrs[attr]);
+    }
+  }
+
+  return el;
+};
+
+jasmine.HtmlReporterHelpers.getSpecStatus = function(child) {
+  var results = child.results();
+  var status = results.passed() ? 'passed' : 'failed';
+  if (results.skipped) {
+    status = 'skipped';
+  }
+
+  return status;
+};
+
+jasmine.HtmlReporterHelpers.appendToSummary = function(child, childElement) {
+  var parentDiv = this.dom.summary;
+  var parentSuite = (typeof child.parentSuite == 'undefined') ? 'suite' : 'parentSuite';
+  var parent = child[parentSuite];
+
+  if (parent) {
+    if (typeof this.views.suites[parent.id] == 'undefined') {
+      this.views.suites[parent.id] = new jasmine.HtmlReporter.SuiteView(parent, this.dom, this.views);
+    }
+    parentDiv = this.views.suites[parent.id].element;
+  }
+
+  parentDiv.appendChild(childElement);
+};
+
+
+jasmine.HtmlReporterHelpers.addHelpers = function(ctor) {
+  for(var fn in jasmine.HtmlReporterHelpers) {
+    ctor.prototype[fn] = jasmine.HtmlReporterHelpers[fn];
+  }
+};
+
+jasmine.HtmlReporter = function(_doc) {
+  var self = this;
+  var doc = _doc || window.document;
+
+  var reporterView;
+
+  var dom = {};
+
+  // Jasmine Reporter Public Interface
+  self.logRunningSpecs = false;
+
+  self.reportRunnerStarting = function(runner) {
+    var specs = runner.specs() || [];
+
+    if (specs.length == 0) {
+      return;
+    }
+
+    createReporterDom(runner.env.versionString());
+    doc.body.appendChild(dom.reporter);
+    setExceptionHandling();
+
+    reporterView = new jasmine.HtmlReporter.ReporterView(dom);
+    reporterView.addSpecs(specs, self.specFilter);
+  };
+
+  self.reportRunnerResults = function(runner) {
+    reporterView && reporterView.complete();
+  };
+
+  self.reportSuiteResults = function(suite) {
+    reporterView.suiteComplete(suite);
+  };
+
+  self.reportSpecStarting = function(spec) {
+    if (self.logRunningSpecs) {
+      self.log('>> Jasmine Running ' + spec.suite.description + ' ' + spec.description + '...');
+    }
+  };
+
+  self.reportSpecResults = function(spec) {
+    reporterView.specComplete(spec);
+  };
+
+  self.log = function() {
+    var console = jasmine.getGlobal().console;
+    if (console && console.log) {
+      if (console.log.apply) {
+        console.log.apply(console, arguments);
+      } else {
+        console.log(arguments); // ie fix: console.log.apply doesn't exist on ie
+      }
+    }
+  };
+
+  self.specFilter = function(spec) {
+    if (!focusedSpecName()) {
+      return true;
+    }
+
+    return spec.getFullName().indexOf(focusedSpecName()) === 0;
+  };
+
+  return self;
+
+  function focusedSpecName() {
+    var specName;
+
+    (function memoizeFocusedSpec() {
+      if (specName) {
+        return;
+      }
+
+      var paramMap = [];
+      var params = jasmine.HtmlReporter.parameters(doc);
+
+      for (var i = 0; i < params.length; i++) {
+        var p = params[i].split('=');
+        paramMap[decodeURIComponent(p[0])] = decodeURIComponent(p[1]);
+      }
+
+      specName = paramMap.spec;
+    })();
+
+    return specName;
+  }
+
+  function createReporterDom(version) {
+    dom.reporter = self.createDom('div', { id: 'HTMLReporter', className: 'jasmine_reporter' },
+      dom.banner = self.createDom('div', { className: 'banner' },
+        self.createDom('span', { className: 'title' }, "Jasmine "),
+        self.createDom('span', { className: 'version' }, version)),
+
+      dom.symbolSummary = self.createDom('ul', {className: 'symbolSummary'}),
+      dom.alert = self.createDom('div', {className: 'alert'},
+        self.createDom('span', { className: 'exceptions' },
+          self.createDom('label', { className: 'label', 'for': 'no_try_catch' }, 'No try/catch'),
+          self.createDom('input', { id: 'no_try_catch', type: 'checkbox' }))),
+      dom.results = self.createDom('div', {className: 'results'},
+        dom.summary = self.createDom('div', { className: 'summary' }),
+        dom.details = self.createDom('div', { id: 'details' }))
+    );
+  }
+
+  function noTryCatch() {
+    return window.location.search.match(/catch=false/);
+  }
+
+  function searchWithCatch() {
+    var params = jasmine.HtmlReporter.parameters(window.document);
+    var removed = false;
+    var i = 0;
+
+    while (!removed && i < params.length) {
+      if (params[i].match(/catch=/)) {
+        params.splice(i, 1);
+        removed = true;
+      }
+      i++;
+    }
+    if (jasmine.CATCH_EXCEPTIONS) {
+      params.push("catch=false");
+    }
+
+    return params.join("&");
+  }
+
+  function setExceptionHandling() {
+    var chxCatch = document.getElementById('no_try_catch');
+
+    if (noTryCatch()) {
+      chxCatch.setAttribute('checked', true);
+      jasmine.CATCH_EXCEPTIONS = false;
+    }
+    chxCatch.onclick = function() {
+      window.location.search = searchWithCatch();
+    };
+  }
+};
+jasmine.HtmlReporter.parameters = function(doc) {
+  var paramStr = doc.location.search.substring(1);
+  var params = [];
+
+  if (paramStr.length > 0) {
+    params = paramStr.split('&');
+  }
+  return params;
+}
+jasmine.HtmlReporter.sectionLink = function(sectionName) {
+  var link = '?';
+  var params = [];
+
+  if (sectionName) {
+    params.push('spec=' + encodeURIComponent(sectionName));
+  }
+  if (!jasmine.CATCH_EXCEPTIONS) {
+    params.push("catch=false");
+  }
+  if (params.length > 0) {
+    link += params.join("&");
+  }
+
+  return link;
+};
+jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter);
+jasmine.HtmlReporter.ReporterView = function(dom) {
+  this.startedAt = new Date();
+  this.runningSpecCount = 0;
+  this.completeSpecCount = 0;
+  this.passedCount = 0;
+  this.failedCount = 0;
+  this.skippedCount = 0;
+
+  this.createResultsMenu = function() {
+    this.resultsMenu = this.createDom('span', {className: 'resultsMenu bar'},
+      this.summaryMenuItem = this.createDom('a', {className: 'summaryMenuItem', href: "#"}, '0 specs'),
+      ' | ',
+      this.detailsMenuItem = this.createDom('a', {className: 'detailsMenuItem', href: "#"}, '0 failing'));
+
+    this.summaryMenuItem.onclick = function() {
+      dom.reporter.className = dom.reporter.className.replace(/ showDetails/g, '');
+    };
+
+    this.detailsMenuItem.onclick = function() {
+      showDetails();
+    };
+  };
+
+  this.addSpecs = function(specs, specFilter) {
+    this.totalSpecCount = specs.length;
+
+    this.views = {
+      specs: {},
+      suites: {}
+    };
+
+    for (var i = 0; i < specs.length; i++) {
+      var spec = specs[i];
+      this.views.specs[spec.id] = new jasmine.HtmlReporter.SpecView(spec, dom, this.views);
+      if (specFilter(spec)) {
+        this.runningSpecCount++;
+      }
+    }
+  };
+
+  this.specComplete = function(spec) {
+    this.completeSpecCount++;
+
+    if (isUndefined(this.views.specs[spec.id])) {
+      this.views.specs[spec.id] = new jasmine.HtmlReporter.SpecView(spec, dom);
+    }
+
+    var specView = this.views.specs[spec.id];
+
+    switch (specView.status()) {
+      case 'passed':
+        this.passedCount++;
+        break;
+
+      case 'failed':
+        this.failedCount++;
+        break;
+
+      case 'skipped':
+        this.skippedCount++;
+        break;
+    }
+
+    specView.refresh();
+    this.refresh();
+  };
+
+  this.suiteComplete = function(suite) {
+    var suiteView = this.views.suites[suite.id];
+    if (isUndefined(suiteView)) {
+      return;
+    }
+    suiteView.refresh();
+  };
+
+  this.refresh = function() {
+
+    if (isUndefined(this.resultsMenu)) {
+      this.createResultsMenu();
+    }
+
+    // currently running UI
+    if (isUndefined(this.runningAlert)) {
+      this.runningAlert = this.createDom('a', { href: jasmine.HtmlReporter.sectionLink(), className: "runningAlert bar" });
+      dom.alert.appendChild(this.runningAlert);
+    }
+    this.runningAlert.innerHTML = "Running " + this.completeSpecCount + " of " + specPluralizedFor(this.totalSpecCount);
+
+    // skipped specs UI
+    if (isUndefined(this.skippedAlert)) {
+      this.skippedAlert = this.createDom('a', { href: jasmine.HtmlReporter.sectionLink(), className: "skippedAlert bar" });
+    }
+
+    this.skippedAlert.innerHTML = "Skipping " + this.skippedCount + " of " + specPluralizedFor(this.totalSpecCount) + " - run all";
+
+    if (this.skippedCount === 1 && isDefined(dom.alert)) {
+      dom.alert.appendChild(this.skippedAlert);
+    }
+
+    // passing specs UI
+    if (isUndefined(this.passedAlert)) {
+      this.passedAlert = this.createDom('span', { href: jasmine.HtmlReporter.sectionLink(), className: "passingAlert bar" });
+    }
+    this.passedAlert.innerHTML = "Passing " + specPluralizedFor(this.passedCount);
+
+    // failing specs UI
+    if (isUndefined(this.failedAlert)) {
+      this.failedAlert = this.createDom('span', {href: "?", className: "failingAlert bar"});
+    }
+    this.failedAlert.innerHTML = "Failing " + specPluralizedFor(this.failedCount);
+
+    if (this.failedCount === 1 && isDefined(dom.alert)) {
+      dom.alert.appendChild(this.failedAlert);
+      dom.alert.appendChild(this.resultsMenu);
+    }
+
+    // summary info
+    this.summaryMenuItem.innerHTML = "" + specPluralizedFor(this.runningSpecCount);
+    this.detailsMenuItem.innerHTML = "" + this.failedCount + " failing";
+  };
+
+  this.complete = function() {
+    dom.alert.removeChild(this.runningAlert);
+
+    this.skippedAlert.innerHTML = "Ran " + this.runningSpecCount + " of " + specPluralizedFor(this.totalSpecCount) + " - run all";
+
+    if (this.failedCount === 0) {
+      dom.alert.appendChild(this.createDom('span', {className: 'passingAlert bar'}, "Passing " + specPluralizedFor(this.passedCount)));
+    } else {
+      showDetails();
+    }
+
+    dom.banner.appendChild(this.createDom('span', {className: 'duration'}, "finished in " + ((new Date().getTime() - this.startedAt.getTime()) / 1000) + "s"));
+  };
+
+  return this;
+
+  function showDetails() {
+    if (dom.reporter.className.search(/showDetails/) === -1) {
+      dom.reporter.className += " showDetails";
+    }
+  }
+
+  function isUndefined(obj) {
+    return typeof obj === 'undefined';
+  }
+
+  function isDefined(obj) {
+    return !isUndefined(obj);
+  }
+
+  function specPluralizedFor(count) {
+    var str = count + " spec";
+    if (count > 1) {
+      str += "s"
+    }
+    return str;
+  }
+
+};
+
+jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.ReporterView);
+
+
+jasmine.HtmlReporter.SpecView = function(spec, dom, views) {
+  this.spec = spec;
+  this.dom = dom;
+  this.views = views;
+
+  this.symbol = this.createDom('li', { className: 'pending' });
+  this.dom.symbolSummary.appendChild(this.symbol);
+
+  this.summary = this.createDom('div', { className: 'specSummary' },
+    this.createDom('a', {
+      className: 'description',
+      href: jasmine.HtmlReporter.sectionLink(this.spec.getFullName()),
+      title: this.spec.getFullName()
+    }, this.spec.description)
+  );
+
+  this.detail = this.createDom('div', { className: 'specDetail' },
+      this.createDom('a', {
+        className: 'description',
+        href: '?spec=' + encodeURIComponent(this.spec.getFullName()),
+        title: this.spec.getFullName()
+      }, this.spec.getFullName())
+  );
+};
+
+jasmine.HtmlReporter.SpecView.prototype.status = function() {
+  return this.getSpecStatus(this.spec);
+};
+
+jasmine.HtmlReporter.SpecView.prototype.refresh = function() {
+  this.symbol.className = this.status();
+
+  switch (this.status()) {
+    case 'skipped':
+      break;
+
+    case 'passed':
+      this.appendSummaryToSuiteDiv();
+      break;
+
+    case 'failed':
+      this.appendSummaryToSuiteDiv();
+      this.appendFailureDetail();
+      break;
+  }
+};
+
+jasmine.HtmlReporter.SpecView.prototype.appendSummaryToSuiteDiv = function() {
+  this.summary.className += ' ' + this.status();
+  this.appendToSummary(this.spec, this.summary);
+};
+
+jasmine.HtmlReporter.SpecView.prototype.appendFailureDetail = function() {
+  this.detail.className += ' ' + this.status();
+
+  var resultItems = this.spec.results().getItems();
+  var messagesDiv = this.createDom('div', { className: 'messages' });
+
+  for (var i = 0; i < resultItems.length; i++) {
+    var result = resultItems[i];
+
+    if (result.type == 'log') {
+      messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage log'}, result.toString()));
+    } else if (result.type == 'expect' && result.passed && !result.passed()) {
+      messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage fail'}, result.message));
+
+      if (result.trace.stack) {
+        messagesDiv.appendChild(this.createDom('div', {className: 'stackTrace'}, result.trace.stack));
+      }
+    }
+  }
+
+  if (messagesDiv.childNodes.length > 0) {
+    this.detail.appendChild(messagesDiv);
+    this.dom.details.appendChild(this.detail);
+  }
+};
+
+jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.SpecView);jasmine.HtmlReporter.SuiteView = function(suite, dom, views) {
+  this.suite = suite;
+  this.dom = dom;
+  this.views = views;
+
+  this.element = this.createDom('div', { className: 'suite' },
+    this.createDom('a', { className: 'description', href: jasmine.HtmlReporter.sectionLink(this.suite.getFullName()) }, this.suite.description)
+  );
+
+  this.appendToSummary(this.suite, this.element);
+};
+
+jasmine.HtmlReporter.SuiteView.prototype.status = function() {
+  return this.getSpecStatus(this.suite);
+};
+
+jasmine.HtmlReporter.SuiteView.prototype.refresh = function() {
+  this.element.className += " " + this.status();
+};
+
+jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.SuiteView);
+
+/* @deprecated Use jasmine.HtmlReporter instead
+ */
+jasmine.TrivialReporter = function(doc) {
+  this.document = doc || document;
+  this.suiteDivs = {};
+  this.logRunningSpecs = false;
+};
+
+jasmine.TrivialReporter.prototype.createDom = function(type, attrs, childrenVarArgs) {
+  var el = document.createElement(type);
+
+  for (var i = 2; i < arguments.length; i++) {
+    var child = arguments[i];
+
+    if (typeof child === 'string') {
+      el.appendChild(document.createTextNode(child));
+    } else {
+      if (child) { el.appendChild(child); }
+    }
+  }
+
+  for (var attr in attrs) {
+    if (attr == "className") {
+      el[attr] = attrs[attr];
+    } else {
+      el.setAttribute(attr, attrs[attr]);
+    }
+  }
+
+  return el;
+};
+
+jasmine.TrivialReporter.prototype.reportRunnerStarting = function(runner) {
+  var showPassed, showSkipped;
+
+  this.outerDiv = this.createDom('div', { id: 'TrivialReporter', className: 'jasmine_reporter' },
+      this.createDom('div', { className: 'banner' },
+        this.createDom('div', { className: 'logo' },
+            this.createDom('span', { className: 'title' }, "Jasmine"),
+            this.createDom('span', { className: 'version' }, runner.env.versionString())),
+        this.createDom('div', { className: 'options' },
+            "Show ",
+            showPassed = this.createDom('input', { id: "__jasmine_TrivialReporter_showPassed__", type: 'checkbox' }),
+            this.createDom('label', { "for": "__jasmine_TrivialReporter_showPassed__" }, " passed "),
+            showSkipped = this.createDom('input', { id: "__jasmine_TrivialReporter_showSkipped__", type: 'checkbox' }),
+            this.createDom('label', { "for": "__jasmine_TrivialReporter_showSkipped__" }, " skipped")
+            )
+          ),
+
+      this.runnerDiv = this.createDom('div', { className: 'runner running' },
+          this.createDom('a', { className: 'run_spec', href: '?' }, "run all"),
+          this.runnerMessageSpan = this.createDom('span', {}, "Running..."),
+          this.finishedAtSpan = this.createDom('span', { className: 'finished-at' }, ""))
+      );
+
+  this.document.body.appendChild(this.outerDiv);
+
+  var suites = runner.suites();
+  for (var i = 0; i < suites.length; i++) {
+    var suite = suites[i];
+    var suiteDiv = this.createDom('div', { className: 'suite' },
+        this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, "run"),
+        this.createDom('a', { className: 'description', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, suite.description));
+    this.suiteDivs[suite.id] = suiteDiv;
+    var parentDiv = this.outerDiv;
+    if (suite.parentSuite) {
+      parentDiv = this.suiteDivs[suite.parentSuite.id];
+    }
+    parentDiv.appendChild(suiteDiv);
+  }
+
+  this.startedAt = new Date();
+
+  var self = this;
+  showPassed.onclick = function(evt) {
+    if (showPassed.checked) {
+      self.outerDiv.className += ' show-passed';
+    } else {
+      self.outerDiv.className = self.outerDiv.className.replace(/ show-passed/, '');
+    }
+  };
+
+  showSkipped.onclick = function(evt) {
+    if (showSkipped.checked) {
+      self.outerDiv.className += ' show-skipped';
+    } else {
+      self.outerDiv.className = self.outerDiv.className.replace(/ show-skipped/, '');
+    }
+  };
+};
+
+jasmine.TrivialReporter.prototype.reportRunnerResults = function(runner) {
+  var results = runner.results();
+  var className = (results.failedCount > 0) ? "runner failed" : "runner passed";
+  this.runnerDiv.setAttribute("class", className);
+  //do it twice for IE
+  this.runnerDiv.setAttribute("className", className);
+  var specs = runner.specs();
+  var specCount = 0;
+  for (var i = 0; i < specs.length; i++) {
+    if (this.specFilter(specs[i])) {
+      specCount++;
+    }
+  }
+  var message = "" + specCount + " spec" + (specCount == 1 ? "" : "s" ) + ", " + results.failedCount + " failure" + ((results.failedCount == 1) ? "" : "s");
+  message += " in " + ((new Date().getTime() - this.startedAt.getTime()) / 1000) + "s";
+  this.runnerMessageSpan.replaceChild(this.createDom('a', { className: 'description', href: '?'}, message), this.runnerMessageSpan.firstChild);
+
+  this.finishedAtSpan.appendChild(document.createTextNode("Finished at " + new Date().toString()));
+};
+
+jasmine.TrivialReporter.prototype.reportSuiteResults = function(suite) {
+  var results = suite.results();
+  var status = results.passed() ? 'passed' : 'failed';
+  if (results.totalCount === 0) { // todo: change this to check results.skipped
+    status = 'skipped';
+  }
+  this.suiteDivs[suite.id].className += " " + status;
+};
+
+jasmine.TrivialReporter.prototype.reportSpecStarting = function(spec) {
+  if (this.logRunningSpecs) {
+    this.log('>> Jasmine Running ' + spec.suite.description + ' ' + spec.description + '...');
+  }
+};
+
+jasmine.TrivialReporter.prototype.reportSpecResults = function(spec) {
+  var results = spec.results();
+  var status = results.passed() ? 'passed' : 'failed';
+  if (results.skipped) {
+    status = 'skipped';
+  }
+  var specDiv = this.createDom('div', { className: 'spec '  + status },
+      this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(spec.getFullName()) }, "run"),
+      this.createDom('a', {
+        className: 'description',
+        href: '?spec=' + encodeURIComponent(spec.getFullName()),
+        title: spec.getFullName()
+      }, spec.description));
+
+
+  var resultItems = results.getItems();
+  var messagesDiv = this.createDom('div', { className: 'messages' });
+  for (var i = 0; i < resultItems.length; i++) {
+    var result = resultItems[i];
+
+    if (result.type == 'log') {
+      messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage log'}, result.toString()));
+    } else if (result.type == 'expect' && result.passed && !result.passed()) {
+      messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage fail'}, result.message));
+
+      if (result.trace.stack) {
+        messagesDiv.appendChild(this.createDom('div', {className: 'stackTrace'}, result.trace.stack));
+      }
+    }
+  }
+
+  if (messagesDiv.childNodes.length > 0) {
+    specDiv.appendChild(messagesDiv);
+  }
+
+  this.suiteDivs[spec.suite.id].appendChild(specDiv);
+};
+
+jasmine.TrivialReporter.prototype.log = function() {
+  var console = jasmine.getGlobal().console;
+  if (console && console.log) {
+    if (console.log.apply) {
+      console.log.apply(console, arguments);
+    } else {
+      console.log(arguments); // ie fix: console.log.apply doesn't exist on ie
+    }
+  }
+};
+
+jasmine.TrivialReporter.prototype.getLocation = function() {
+  return this.document.location;
+};
+
+jasmine.TrivialReporter.prototype.specFilter = function(spec) {
+  var paramMap = {};
+  var params = this.getLocation().search.substring(1).split('&');
+  for (var i = 0; i < params.length; i++) {
+    var p = params[i].split('=');
+    paramMap[decodeURIComponent(p[0])] = decodeURIComponent(p[1]);
+  }
+
+  if (!paramMap.spec) {
+    return true;
+  }
+  return spec.getFullName().indexOf(paramMap.spec) === 0;
+};
Index: tests/functional/lib/jasmine-jquery-bootstrap.js
===================================================================
--- tests/functional/lib/jasmine-jquery-bootstrap.js	(revision 1602)
+++ tests/functional/lib/jasmine-jquery-bootstrap.js	(revision 1602)
@@ -0,0 +1,28 @@
+(function() {
+    jasmine.getFixtures().fixturesPath = 'fixtures';
+
+    var jasmineEnv = jasmine.getEnv();
+    jasmineEnv.updateInterval = 1000;
+
+    var htmlReporter = new jasmine.HtmlReporter();
+
+    jasmineEnv.addReporter(htmlReporter);
+
+    jasmineEnv.specFilter = function(spec) {
+	return htmlReporter.specFilter(spec);
+    };
+
+    var currentWindowOnload = window.onload;
+
+    window.onload = function() {
+	if (currentWindowOnload) {
+	    currentWindowOnload();
+	}
+	execJasmine();
+    };
+
+    function execJasmine() {
+	jasmineEnv.execute();
+    }
+
+})();
Index: tests/functional/lib/jasmine-jquery.js
===================================================================
--- tests/functional/lib/jasmine-jquery.js	(revision 1602)
+++ tests/functional/lib/jasmine-jquery.js	(revision 1602)
@@ -0,0 +1,673 @@
+/*!
+ Jasmine-jQuery: a set of jQuery helpers for Jasmine tests.
+
+ Version 1.5.8
+
+ https://github.com/velesin/jasmine-jquery
+
+ Copyright (c) 2010-2013 Wojciech Zawistowski, Travis Jeffery
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+var readFixtures = function() {
+  return jasmine.getFixtures().proxyCallTo_('read', arguments)
+}
+
+var preloadFixtures = function() {
+  jasmine.getFixtures().proxyCallTo_('preload', arguments)
+}
+
+var loadFixtures = function() {
+  jasmine.getFixtures().proxyCallTo_('load', arguments)
+}
+
+var appendLoadFixtures = function() {
+  jasmine.getFixtures().proxyCallTo_('appendLoad', arguments)
+}
+
+var setFixtures = function(html) {
+  return jasmine.getFixtures().proxyCallTo_('set', arguments)
+}
+
+var appendSetFixtures = function() {
+  jasmine.getFixtures().proxyCallTo_('appendSet', arguments)
+}
+
+var sandbox = function(attributes) {
+  return jasmine.getFixtures().sandbox(attributes)
+}
+
+var spyOnEvent = function(selector, eventName) {
+  return jasmine.JQuery.events.spyOn(selector, eventName)
+}
+
+var preloadStyleFixtures = function() {
+  jasmine.getStyleFixtures().proxyCallTo_('preload', arguments)
+}
+
+var loadStyleFixtures = function() {
+  jasmine.getStyleFixtures().proxyCallTo_('load', arguments)
+}
+
+var appendLoadStyleFixtures = function() {
+  jasmine.getStyleFixtures().proxyCallTo_('appendLoad', arguments)
+}
+
+var setStyleFixtures = function(html) {
+  jasmine.getStyleFixtures().proxyCallTo_('set', arguments)
+}
+
+var appendSetStyleFixtures = function(html) {
+  jasmine.getStyleFixtures().proxyCallTo_('appendSet', arguments)
+}
+
+var loadJSONFixtures = function() {
+  return jasmine.getJSONFixtures().proxyCallTo_('load', arguments)
+}
+
+var getJSONFixture = function(url) {
+  return jasmine.getJSONFixtures().proxyCallTo_('read', arguments)[url]
+}
+
+jasmine.spiedEventsKey = function (selector, eventName) {
+  return [$(selector).selector, eventName].toString()
+}
+
+jasmine.getFixtures = function() {
+  return jasmine.currentFixtures_ = jasmine.currentFixtures_ || new jasmine.Fixtures()
+}
+
+jasmine.getStyleFixtures = function() {
+  return jasmine.currentStyleFixtures_ = jasmine.currentStyleFixtures_ || new jasmine.StyleFixtures()
+}
+
+jasmine.Fixtures = function() {
+  this.containerId = 'jasmine-fixtures'
+  this.fixturesCache_ = {}
+  this.fixturesPath = 'spec/javascripts/fixtures'
+}
+
+jasmine.Fixtures.prototype.set = function(html) {
+  this.cleanUp()
+  return this.createContainer_(html)
+}
+
+jasmine.Fixtures.prototype.appendSet= function(html) {
+  this.addToContainer_(html)
+}
+
+jasmine.Fixtures.prototype.preload = function() {
+  this.read.apply(this, arguments)
+}
+
+jasmine.Fixtures.prototype.load = function() {
+  this.cleanUp()
+  this.createContainer_(this.read.apply(this, arguments))
+}
+
+jasmine.Fixtures.prototype.appendLoad = function() {
+  this.addToContainer_(this.read.apply(this, arguments))
+}
+
+jasmine.Fixtures.prototype.read = function() {
+  var htmlChunks = []
+
+  var fixtureUrls = arguments
+  for(var urlCount = fixtureUrls.length, urlIndex = 0; urlIndex < urlCount; urlIndex++) {
+    htmlChunks.push(this.getFixtureHtml_(fixtureUrls[urlIndex]))
+  }
+
+  return htmlChunks.join('')
+}
+
+jasmine.Fixtures.prototype.clearCache = function() {
+  this.fixturesCache_ = {}
+}
+
+jasmine.Fixtures.prototype.cleanUp = function() {
+  $('#' + this.containerId).remove()
+}
+
+jasmine.Fixtures.prototype.sandbox = function(attributes) {
+  var attributesToSet = attributes || {}
+  return $('<div id="sandbox" />').attr(attributesToSet)
+}
+
+jasmine.Fixtures.prototype.createContainer_ = function(html) {
+  var container = $('<div>')
+    .attr('id', this.containerId)
+    .html(html);
+  $(document.body).append(container)
+  return container
+}
+
+jasmine.Fixtures.prototype.addToContainer_ = function(html){
+  var container = $(document.body).find('#'+this.containerId).append(html)
+  if(!container.length){
+    this.createContainer_(html)
+  }
+}
+
+jasmine.Fixtures.prototype.getFixtureHtml_ = function(url) {
+  if (typeof this.fixturesCache_[url] === 'undefined') {
+    this.loadFixtureIntoCache_(url)
+  }
+  return this.fixturesCache_[url]
+}
+
+jasmine.Fixtures.prototype.loadFixtureIntoCache_ = function(relativeUrl) {
+  var url = this.makeFixtureUrl_(relativeUrl)
+  var request = $.ajax({
+    type: "GET",
+    url: url + "?" + new Date().getTime(),
+    async: false
+  })
+  this.fixturesCache_[relativeUrl] = request.responseText
+}
+
+jasmine.Fixtures.prototype.makeFixtureUrl_ = function(relativeUrl){
+  return this.fixturesPath.match('/$') ? this.fixturesPath + relativeUrl : this.fixturesPath + '/' + relativeUrl
+}
+
+jasmine.Fixtures.prototype.proxyCallTo_ = function(methodName, passedArguments) {
+  return this[methodName].apply(this, passedArguments)
+}
+
+
+jasmine.StyleFixtures = function() {
+  this.fixturesCache_ = {}
+  this.fixturesNodes_ = []
+  this.fixturesPath = 'spec/javascripts/fixtures'
+}
+
+jasmine.StyleFixtures.prototype.set = function(css) {
+  this.cleanUp()
+  this.createStyle_(css)
+}
+
+jasmine.StyleFixtures.prototype.appendSet = function(css) {
+  this.createStyle_(css)
+}
+
+jasmine.StyleFixtures.prototype.preload = function() {
+  this.read_.apply(this, arguments)
+}
+
+jasmine.StyleFixtures.prototype.load = function() {
+  this.cleanUp()
+  this.createStyle_(this.read_.apply(this, arguments))
+}
+
+jasmine.StyleFixtures.prototype.appendLoad = function() {
+  this.createStyle_(this.read_.apply(this, arguments))
+}
+
+jasmine.StyleFixtures.prototype.cleanUp = function() {
+  while(this.fixturesNodes_.length) {
+    this.fixturesNodes_.pop().remove()
+  }
+}
+
+jasmine.StyleFixtures.prototype.createStyle_ = function(html) {
+  var styleText = $('<div></div>').html(html).text(),
+    style = $('<style>' + styleText + '</style>')
+
+  this.fixturesNodes_.push(style)
+
+  $('head').append(style)
+}
+
+jasmine.StyleFixtures.prototype.clearCache = jasmine.Fixtures.prototype.clearCache
+
+jasmine.StyleFixtures.prototype.read_ = jasmine.Fixtures.prototype.read
+
+jasmine.StyleFixtures.prototype.getFixtureHtml_ = jasmine.Fixtures.prototype.getFixtureHtml_
+
+jasmine.StyleFixtures.prototype.loadFixtureIntoCache_ = jasmine.Fixtures.prototype.loadFixtureIntoCache_
+
+jasmine.StyleFixtures.prototype.makeFixtureUrl_ = jasmine.Fixtures.prototype.makeFixtureUrl_
+
+jasmine.StyleFixtures.prototype.proxyCallTo_ = jasmine.Fixtures.prototype.proxyCallTo_
+
+jasmine.getJSONFixtures = function() {
+  return jasmine.currentJSONFixtures_ = jasmine.currentJSONFixtures_ || new jasmine.JSONFixtures()
+}
+
+jasmine.JSONFixtures = function() {
+  this.fixturesCache_ = {}
+  this.fixturesPath = 'spec/javascripts/fixtures/json'
+}
+
+jasmine.JSONFixtures.prototype.load = function() {
+  this.read.apply(this, arguments)
+  return this.fixturesCache_
+}
+
+jasmine.JSONFixtures.prototype.read = function() {
+  var fixtureUrls = arguments
+  for(var urlCount = fixtureUrls.length, urlIndex = 0; urlIndex < urlCount; urlIndex++) {
+    this.getFixtureData_(fixtureUrls[urlIndex])
+  }
+  return this.fixturesCache_
+}
+
+jasmine.JSONFixtures.prototype.clearCache = function() {
+  this.fixturesCache_ = {}
+}
+
+jasmine.JSONFixtures.prototype.getFixtureData_ = function(url) {
+  this.loadFixtureIntoCache_(url)
+  return this.fixturesCache_[url]
+}
+
+jasmine.JSONFixtures.prototype.loadFixtureIntoCache_ = function(relativeUrl) {
+  var self = this
+  var url = this.fixturesPath.match('/$') ? this.fixturesPath + relativeUrl : this.fixturesPath + '/' + relativeUrl
+  $.ajax({
+    async: false, // must be synchronous to guarantee that no tests are run before fixture is loaded
+    cache: false,
+    dataType: 'json',
+    url: url,
+    success: function(data) {
+      self.fixturesCache_[relativeUrl] = data
+    },
+    error: function(jqXHR, status, errorThrown) {
+        throw Error('JSONFixture could not be loaded: ' + url + ' (status: ' + status + ', message: ' + errorThrown.message + ')')
+    }
+  })
+}
+
+jasmine.JSONFixtures.prototype.proxyCallTo_ = function(methodName, passedArguments) {
+  return this[methodName].apply(this, passedArguments)
+}
+
+jasmine.JQuery = function() {}
+
+jasmine.JQuery.browserTagCaseIndependentHtml = function(html) {
+  return $('<div/>').append(html).html()
+}
+
+jasmine.JQuery.elementToString = function(element) {
+  var domEl = $(element).get(0)
+  if (domEl == undefined || domEl.cloneNode)
+    return $('<div />').append($(element).clone()).html()
+  else
+    return element.toString()
+}
+
+jasmine.JQuery.matchersClass = {}
+
+!function(namespace) {
+  var data = {
+    spiedEvents: {},
+    handlers:    []
+  }
+
+  namespace.events = {
+    spyOn: function(selector, eventName) {
+      var handler = function(e) {
+        data.spiedEvents[jasmine.spiedEventsKey(selector, eventName)] = jasmine.util.argsToArray(arguments)
+      }
+      $(selector).on(eventName, handler)
+      data.handlers.push(handler)
+      return {
+        selector: selector,
+        eventName: eventName,
+        handler: handler,
+        reset: function(){
+          delete data.spiedEvents[jasmine.spiedEventsKey(selector, eventName)]
+        }
+      }
+    },
+
+    args: function(selector, eventName) {
+      var actualArgs = data.spiedEvents[jasmine.spiedEventsKey(selector, eventName)];
+
+      if (!actualArgs) {
+        throw "There is no spy for " + eventName + " on " + selector.toString() + ". Make sure to create a spy using spyOnEvent.";
+      }
+
+      return actualArgs;
+    },
+
+    wasTriggered: function(selector, eventName) {
+      return !!(data.spiedEvents[jasmine.spiedEventsKey(selector, eventName)])
+    },
+
+    wasTriggeredWith: function(selector, eventName, expectedArgs, env) {
+      var actualArgs = jasmine.JQuery.events.args(selector, eventName).slice(1);
+      if (Object.prototype.toString.call(expectedArgs) !== '[object Array]') {
+        actualArgs = actualArgs[0];
+      }
+      return env.equals_(expectedArgs, actualArgs);
+    },
+
+    wasPrevented: function(selector, eventName) {
+      var args = data.spiedEvents[jasmine.spiedEventsKey(selector, eventName)],
+          e = args ? args[0] : undefined;
+      return e && e.isDefaultPrevented()
+    },
+
+    wasStopped: function(selector, eventName) {
+      var args = data.spiedEvents[jasmine.spiedEventsKey(selector, eventName)],
+          e = args ? args[0] : undefined;
+      return e && e.isPropagationStopped()
+    },
+
+    cleanUp: function() {
+      data.spiedEvents = {}
+      data.handlers    = []
+    }
+  }
+}(jasmine.JQuery)
+
+!function(){
+  var jQueryMatchers = {
+    toHaveClass: function(className) {
+      return this.actual.hasClass(className)
+    },
+
+    toHaveCss: function(css){
+      for (var prop in css){
+        if (this.actual.css(prop) !== css[prop]) return false
+      }
+      return true
+    },
+
+    toBeVisible: function() {
+      return this.actual.is(':visible')
+    },
+
+    toBeHidden: function() {
+      return this.actual.is(':hidden')
+    },
+
+    toBeSelected: function() {
+      return this.actual.is(':selected')
+    },
+
+    toBeChecked: function() {
+      return this.actual.is(':checked')
+    },
+
+    toBeEmpty: function() {
+      return this.actual.is(':empty')
+    },
+
+    toExist: function() {
+      return $(document).find(this.actual).length
+    },
+
+    toHaveLength: function(length) {
+      return this.actual.length === length
+    },
+
+    toHaveAttr: function(attributeName, expectedAttributeValue) {
+      return hasProperty(this.actual.attr(attributeName), expectedAttributeValue)
+    },
+
+    toHaveProp: function(propertyName, expectedPropertyValue) {
+      return hasProperty(this.actual.prop(propertyName), expectedPropertyValue)
+    },
+
+    toHaveId: function(id) {
+      return this.actual.attr('id') == id
+    },
+
+    toHaveHtml: function(html) {
+      return this.actual.html() == jasmine.JQuery.browserTagCaseIndependentHtml(html)
+    },
+
+    toContainHtml: function(html){
+      var actualHtml = this.actual.html()
+      var expectedHtml = jasmine.JQuery.browserTagCaseIndependentHtml(html)
+      return (actualHtml.indexOf(expectedHtml) >= 0)
+    },
+
+    toHaveText: function(text) {
+      var trimmedText = $.trim(this.actual.text())
+      if (text && $.isFunction(text.test)) {
+        return text.test(trimmedText)
+      } else {
+        return trimmedText == text
+      }
+    },
+
+    toContainText: function(text) {
+      var trimmedText = $.trim(this.actual.text())
+      if (text && $.isFunction(text.test)) {
+        return text.test(trimmedText)
+      } else {
+        return trimmedText.indexOf(text) != -1;
+      }
+    },
+
+    toHaveValue: function(value) {
+      return this.actual.val() === value
+    },
+
+    toHaveData: function(key, expectedValue) {
+      return hasProperty(this.actual.data(key), expectedValue)
+    },
+
+    toBe: function(selector) {
+      return this.actual.is(selector)
+    },
+
+    toContain: function(selector) {
+      return this.actual.find(selector).length
+    },
+    
+    toBeMatchedBy: function(selector) {
+      return this.actual.filter(selector).length
+    },
+
+    toBeDisabled: function(selector){
+      return this.actual.is(':disabled')
+    },
+
+    toBeFocused: function(selector) {
+      return this.actual[0] === this.actual[0].ownerDocument.activeElement
+    },
+
+    toHandle: function(event) {
+
+      var events = $._data(this.actual.get(0), "events")
+
+      if(!events || !event || typeof event !== "string") {
+        return false
+      }
+
+      var namespaces = event.split(".")
+      var eventType = namespaces.shift()
+      var sortedNamespaces = namespaces.slice(0).sort()
+      var namespaceRegExp = new RegExp("(^|\\.)" + sortedNamespaces.join("\\.(?:.*\\.)?") + "(\\.|$)")
+
+      if(events[eventType] && namespaces.length) {
+        for(var i = 0; i < events[eventType].length; i++) {
+          var namespace = events[eventType][i].namespace
+          if(namespaceRegExp.test(namespace)) {
+            return true
+          }
+        }
+      } else {
+        return events[eventType] && events[eventType].length > 0
+      }
+    },
+
+    // tests the existence of a specific event binding + handler
+    toHandleWith: function(eventName, eventHandler) {
+      var normalizedEventName = eventName.split('.')[0];
+      var stack = $._data(this.actual.get(0), "events")[normalizedEventName]
+      for (var i = 0; i < stack.length; i++) {
+        if (stack[i].handler == eventHandler) return true
+      }
+      return false
+    }
+  }
+
+  var hasProperty = function(actualValue, expectedValue) {
+    if (expectedValue === undefined) return actualValue !== undefined
+    return actualValue == expectedValue
+  }
+
+  var bindMatcher = function(methodName) {
+    var builtInMatcher = jasmine.Matchers.prototype[methodName]
+
+    jasmine.JQuery.matchersClass[methodName] = function() {
+      if (this.actual
+        && (this.actual instanceof $
+          || jasmine.isDomNode(this.actual))) {
+            this.actual = $(this.actual)
+            var result = jQueryMatchers[methodName].apply(this, arguments)
+            var element
+            if (this.actual.get && (element = this.actual.get()[0]) && !$.isWindow(element) && element.tagName !== "HTML")
+              this.actual = jasmine.JQuery.elementToString(this.actual)
+            return result
+          }
+
+          if (builtInMatcher) {
+            return builtInMatcher.apply(this, arguments)
+          }
+
+          return false
+    }
+  }
+
+  for(var methodName in jQueryMatchers) {
+    bindMatcher(methodName)
+  }
+}()
+
+beforeEach(function() {
+  this.addMatchers(jasmine.JQuery.matchersClass)
+  this.addMatchers({
+    toHaveBeenTriggeredOn: function(selector) {
+      this.message = function() {
+        return [
+          "Expected event " + this.actual + " to have been triggered on " + selector,
+          "Expected event " + this.actual + " not to have been triggered on " + selector
+        ]
+      }
+      return jasmine.JQuery.events.wasTriggered(selector, this.actual)
+    }
+  })
+  this.addMatchers({
+    toHaveBeenTriggered: function(){
+      var eventName = this.actual.eventName,
+          selector = this.actual.selector
+      this.message = function() {
+        return [
+          "Expected event " + eventName + " to have been triggered on " + selector,
+          "Expected event " + eventName + " not to have been triggered on " + selector
+        ]
+      }
+      return jasmine.JQuery.events.wasTriggered(selector, eventName)
+     }
+  })
+  this.addMatchers({
+    toHaveBeenTriggeredOnAndWith: function() {
+      var selector = arguments[0],
+          expectedArgs = arguments[1],
+          wasTriggered = jasmine.JQuery.events.wasTriggered(selector, this.actual);
+      this.message = function() {
+        if (wasTriggered) {
+          var actualArgs = jasmine.JQuery.events.args(selector, this.actual, expectedArgs)[1];
+          return [
+            "Expected event " + this.actual + " to have been triggered with " + jasmine.pp(expectedArgs) + "  but it was triggered with " + jasmine.pp(actualArgs),
+            "Expected event " + this.actual + " not to have been triggered with " + jasmine.pp(expectedArgs) + " but it was triggered with " + jasmine.pp(actualArgs)
+          ]
+        } else {
+          return [
+            "Expected event " + this.actual + " to have been triggered on " + selector,
+            "Expected event " + this.actual + " not to have been triggered on " + selector
+          ]
+        }
+      }
+      return wasTriggered && jasmine.JQuery.events.wasTriggeredWith(selector, this.actual, expectedArgs, this.env);
+    }
+  })
+  this.addMatchers({
+    toHaveBeenPreventedOn: function(selector) {
+      this.message = function() {
+        return [
+          "Expected event " + this.actual + " to have been prevented on " + selector,
+          "Expected event " + this.actual + " not to have been prevented on " + selector
+        ]
+      }
+      return jasmine.JQuery.events.wasPrevented(selector, this.actual)
+    }
+  })
+  this.addMatchers({
+    toHaveBeenPrevented: function() {
+      var eventName = this.actual.eventName,
+          selector = this.actual.selector
+      this.message = function() {
+        return [
+          "Expected event " + eventName + " to have been prevented on " + selector,
+          "Expected event " + eventName + " not to have been prevented on " + selector
+        ]
+      }
+      return jasmine.JQuery.events.wasPrevented(selector, eventName)
+    }
+  })
+  this.addMatchers({
+    toHaveBeenStoppedOn: function(selector) {
+      this.message = function() {
+        return [
+          "Expected event " + this.actual + " to have been stopped on " + selector,
+          "Expected event " + this.actual + " not to have been stopped on " + selector
+        ]
+      }
+      return jasmine.JQuery.events.wasStopped(selector, this.actual)
+    }
+  })
+  this.addMatchers({
+    toHaveBeenStopped: function() {
+      var eventName = this.actual.eventName,
+          selector = this.actual.selector
+      this.message = function() {
+        return [
+          "Expected event " + eventName + " to have been stopped on " + selector,
+          "Expected event " + eventName + " not to have been stopped on " + selector
+        ]
+      }
+      return jasmine.JQuery.events.wasStopped(selector, eventName)
+    }
+  })
+  jasmine.getEnv().addEqualityTester(function(a, b) {
+    if(a instanceof jQuery && b instanceof jQuery) {
+      if(a.size() != b.size()) {
+        return jasmine.undefined;
+      }
+      else if(a.is(b)) {
+        return true;
+      }
+    }
+    return jasmine.undefined;
+    
+  })
+})
+
+afterEach(function() {
+  jasmine.getFixtures().cleanUp()
+  jasmine.getStyleFixtures().cleanUp()
+  jasmine.JQuery.events.cleanUp()
+})
Index: tests/functional/lib/jasmine.js
===================================================================
--- tests/functional/lib/jasmine.js	(revision 1602)
+++ tests/functional/lib/jasmine.js	(revision 1602)
@@ -0,0 +1,2600 @@
+var isCommonJS = typeof window == "undefined" && typeof exports == "object";
+
+/**
+ * Top level namespace for Jasmine, a lightweight JavaScript BDD/spec/testing framework.
+ *
+ * @namespace
+ */
+var jasmine = {};
+if (isCommonJS) exports.jasmine = jasmine;
+/**
+ * @private
+ */
+jasmine.unimplementedMethod_ = function() {
+  throw new Error("unimplemented method");
+};
+
+/**
+ * Use <code>jasmine.undefined</code> instead of <code>undefined</code>, since <code>undefined</code> is just
+ * a plain old variable and may be redefined by somebody else.
+ *
+ * @private
+ */
+jasmine.undefined = jasmine.___undefined___;
+
+/**
+ * Show diagnostic messages in the console if set to true
+ *
+ */
+jasmine.VERBOSE = false;
+
+/**
+ * Default interval in milliseconds for event loop yields (e.g. to allow network activity or to refresh the screen with the HTML-based runner). Small values here may result in slow test running. Zero means no updates until all tests have completed.
+ *
+ */
+jasmine.DEFAULT_UPDATE_INTERVAL = 250;
+
+/**
+ * Maximum levels of nesting that will be included when an object is pretty-printed
+ */
+jasmine.MAX_PRETTY_PRINT_DEPTH = 40;
+
+/**
+ * Default timeout interval in milliseconds for waitsFor() blocks.
+ */
+jasmine.DEFAULT_TIMEOUT_INTERVAL = 5000;
+
+/**
+ * By default exceptions thrown in the context of a test are caught by jasmine so that it can run the remaining tests in the suite.
+ * Set to false to let the exception bubble up in the browser.
+ *
+ */
+jasmine.CATCH_EXCEPTIONS = true;
+
+jasmine.getGlobal = function() {
+  function getGlobal() {
+    return this;
+  }
+
+  return getGlobal();
+};
+
+/**
+ * Allows for bound functions to be compared.  Internal use only.
+ *
+ * @ignore
+ * @private
+ * @param base {Object} bound 'this' for the function
+ * @param name {Function} function to find
+ */
+jasmine.bindOriginal_ = function(base, name) {
+  var original = base[name];
+  if (original.apply) {
+    return function() {
+      return original.apply(base, arguments);
+    };
+  } else {
+    // IE support
+    return jasmine.getGlobal()[name];
+  }
+};
+
+jasmine.setTimeout = jasmine.bindOriginal_(jasmine.getGlobal(), 'setTimeout');
+jasmine.clearTimeout = jasmine.bindOriginal_(jasmine.getGlobal(), 'clearTimeout');
+jasmine.setInterval = jasmine.bindOriginal_(jasmine.getGlobal(), 'setInterval');
+jasmine.clearInterval = jasmine.bindOriginal_(jasmine.getGlobal(), 'clearInterval');
+
+jasmine.MessageResult = function(values) {
+  this.type = 'log';
+  this.values = values;
+  this.trace = new Error(); // todo: test better
+};
+
+jasmine.MessageResult.prototype.toString = function() {
+  var text = "";
+  for (var i = 0; i < this.values.length; i++) {
+    if (i > 0) text += " ";
+    if (jasmine.isString_(this.values[i])) {
+      text += this.values[i];
+    } else {
+      text += jasmine.pp(this.values[i]);
+    }
+  }
+  return text;
+};
+
+jasmine.ExpectationResult = function(params) {
+  this.type = 'expect';
+  this.matcherName = params.matcherName;
+  this.passed_ = params.passed;
+  this.expected = params.expected;
+  this.actual = params.actual;
+  this.message = this.passed_ ? 'Passed.' : params.message;
+
+  var trace = (params.trace || new Error(this.message));
+  this.trace = this.passed_ ? '' : trace;
+};
+
+jasmine.ExpectationResult.prototype.toString = function () {
+  return this.message;
+};
+
+jasmine.ExpectationResult.prototype.passed = function () {
+  return this.passed_;
+};
+
+/**
+ * Getter for the Jasmine environment. Ensures one gets created
+ */
+jasmine.getEnv = function() {
+  var env = jasmine.currentEnv_ = jasmine.currentEnv_ || new jasmine.Env();
+  return env;
+};
+
+/**
+ * @ignore
+ * @private
+ * @param value
+ * @returns {Boolean}
+ */
+jasmine.isArray_ = function(value) {
+  return jasmine.isA_("Array", value);
+};
+
+/**
+ * @ignore
+ * @private
+ * @param value
+ * @returns {Boolean}
+ */
+jasmine.isString_ = function(value) {
+  return jasmine.isA_("String", value);
+};
+
+/**
+ * @ignore
+ * @private
+ * @param value
+ * @returns {Boolean}
+ */
+jasmine.isNumber_ = function(value) {
+  return jasmine.isA_("Number", value);
+};
+
+/**
+ * @ignore
+ * @private
+ * @param {String} typeName
+ * @param value
+ * @returns {Boolean}
+ */
+jasmine.isA_ = function(typeName, value) {
+  return Object.prototype.toString.apply(value) === '[object ' + typeName + ']';
+};
+
+/**
+ * Pretty printer for expecations.  Takes any object and turns it into a human-readable string.
+ *
+ * @param value {Object} an object to be outputted
+ * @returns {String}
+ */
+jasmine.pp = function(value) {
+  var stringPrettyPrinter = new jasmine.StringPrettyPrinter();
+  stringPrettyPrinter.format(value);
+  return stringPrettyPrinter.string;
+};
+
+/**
+ * Returns true if the object is a DOM Node.
+ *
+ * @param {Object} obj object to check
+ * @returns {Boolean}
+ */
+jasmine.isDomNode = function(obj) {
+  return obj.nodeType > 0;
+};
+
+/**
+ * Returns a matchable 'generic' object of the class type.  For use in expecations of type when values don't matter.
+ *
+ * @example
+ * // don't care about which function is passed in, as long as it's a function
+ * expect(mySpy).toHaveBeenCalledWith(jasmine.any(Function));
+ *
+ * @param {Class} clazz
+ * @returns matchable object of the type clazz
+ */
+jasmine.any = function(clazz) {
+  return new jasmine.Matchers.Any(clazz);
+};
+
+/**
+ * Returns a matchable subset of a JSON object. For use in expectations when you don't care about all of the
+ * attributes on the object.
+ *
+ * @example
+ * // don't care about any other attributes than foo.
+ * expect(mySpy).toHaveBeenCalledWith(jasmine.objectContaining({foo: "bar"});
+ *
+ * @param sample {Object} sample
+ * @returns matchable object for the sample
+ */
+jasmine.objectContaining = function (sample) {
+    return new jasmine.Matchers.ObjectContaining(sample);
+};
+
+/**
+ * Jasmine Spies are test doubles that can act as stubs, spies, fakes or when used in an expecation, mocks.
+ *
+ * Spies should be created in test setup, before expectations.  They can then be checked, using the standard Jasmine
+ * expectation syntax. Spies can be checked if they were called or not and what the calling params were.
+ *
+ * A Spy has the following fields: wasCalled, callCount, mostRecentCall, and argsForCall (see docs).
+ *
+ * Spies are torn down at the end of every spec.
+ *
+ * Note: Do <b>not</b> call new jasmine.Spy() directly - a spy must be created using spyOn, jasmine.createSpy or jasmine.createSpyObj.
+ *
+ * @example
+ * // a stub
+ * var myStub = jasmine.createSpy('myStub');  // can be used anywhere
+ *
+ * // spy example
+ * var foo = {
+ *   not: function(bool) { return !bool; }
+ * }
+ *
+ * // actual foo.not will not be called, execution stops
+ * spyOn(foo, 'not');
+
+ // foo.not spied upon, execution will continue to implementation
+ * spyOn(foo, 'not').andCallThrough();
+ *
+ * // fake example
+ * var foo = {
+ *   not: function(bool) { return !bool; }
+ * }
+ *
+ * // foo.not(val) will return val
+ * spyOn(foo, 'not').andCallFake(function(value) {return value;});
+ *
+ * // mock example
+ * foo.not(7 == 7);
+ * expect(foo.not).toHaveBeenCalled();
+ * expect(foo.not).toHaveBeenCalledWith(true);
+ *
+ * @constructor
+ * @see spyOn, jasmine.createSpy, jasmine.createSpyObj
+ * @param {String} name
+ */
+jasmine.Spy = function(name) {
+  /**
+   * The name of the spy, if provided.
+   */
+  this.identity = name || 'unknown';
+  /**
+   *  Is this Object a spy?
+   */
+  this.isSpy = true;
+  /**
+   * The actual function this spy stubs.
+   */
+  this.plan = function() {
+  };
+  /**
+   * Tracking of the most recent call to the spy.
+   * @example
+   * var mySpy = jasmine.createSpy('foo');
+   * mySpy(1, 2);
+   * mySpy.mostRecentCall.args = [1, 2];
+   */
+  this.mostRecentCall = {};
+
+  /**
+   * Holds arguments for each call to the spy, indexed by call count
+   * @example
+   * var mySpy = jasmine.createSpy('foo');
+   * mySpy(1, 2);
+   * mySpy(7, 8);
+   * mySpy.mostRecentCall.args = [7, 8];
+   * mySpy.argsForCall[0] = [1, 2];
+   * mySpy.argsForCall[1] = [7, 8];
+   */
+  this.argsForCall = [];
+  this.calls = [];
+};
+
+/**
+ * Tells a spy to call through to the actual implemenatation.
+ *
+ * @example
+ * var foo = {
+ *   bar: function() { // do some stuff }
+ * }
+ *
+ * // defining a spy on an existing property: foo.bar
+ * spyOn(foo, 'bar').andCallThrough();
+ */
+jasmine.Spy.prototype.andCallThrough = function() {
+  this.plan = this.originalValue;
+  return this;
+};
+
+/**
+ * For setting the return value of a spy.
+ *
+ * @example
+ * // defining a spy from scratch: foo() returns 'baz'
+ * var foo = jasmine.createSpy('spy on foo').andReturn('baz');
+ *
+ * // defining a spy on an existing property: foo.bar() returns 'baz'
+ * spyOn(foo, 'bar').andReturn('baz');
+ *
+ * @param {Object} value
+ */
+jasmine.Spy.prototype.andReturn = function(value) {
+  this.plan = function() {
+    return value;
+  };
+  return this;
+};
+
+/**
+ * For throwing an exception when a spy is called.
+ *
+ * @example
+ * // defining a spy from scratch: foo() throws an exception w/ message 'ouch'
+ * var foo = jasmine.createSpy('spy on foo').andThrow('baz');
+ *
+ * // defining a spy on an existing property: foo.bar() throws an exception w/ message 'ouch'
+ * spyOn(foo, 'bar').andThrow('baz');
+ *
+ * @param {String} exceptionMsg
+ */
+jasmine.Spy.prototype.andThrow = function(exceptionMsg) {
+  this.plan = function() {
+    throw exceptionMsg;
+  };
+  return this;
+};
+
+/**
+ * Calls an alternate implementation when a spy is called.
+ *
+ * @example
+ * var baz = function() {
+ *   // do some stuff, return something
+ * }
+ * // defining a spy from scratch: foo() calls the function baz
+ * var foo = jasmine.createSpy('spy on foo').andCall(baz);
+ *
+ * // defining a spy on an existing property: foo.bar() calls an anonymnous function
+ * spyOn(foo, 'bar').andCall(function() { return 'baz';} );
+ *
+ * @param {Function} fakeFunc
+ */
+jasmine.Spy.prototype.andCallFake = function(fakeFunc) {
+  this.plan = fakeFunc;
+  return this;
+};
+
+/**
+ * Resets all of a spy's the tracking variables so that it can be used again.
+ *
+ * @example
+ * spyOn(foo, 'bar');
+ *
+ * foo.bar();
+ *
+ * expect(foo.bar.callCount).toEqual(1);
+ *
+ * foo.bar.reset();
+ *
+ * expect(foo.bar.callCount).toEqual(0);
+ */
+jasmine.Spy.prototype.reset = function() {
+  this.wasCalled = false;
+  this.callCount = 0;
+  this.argsForCall = [];
+  this.calls = [];
+  this.mostRecentCall = {};
+};
+
+jasmine.createSpy = function(name) {
+
+  var spyObj = function() {
+    spyObj.wasCalled = true;
+    spyObj.callCount++;
+    var args = jasmine.util.argsToArray(arguments);
+    spyObj.mostRecentCall.object = this;
+    spyObj.mostRecentCall.args = args;
+    spyObj.argsForCall.push(args);
+    spyObj.calls.push({object: this, args: args});
+    return spyObj.plan.apply(this, arguments);
+  };
+
+  var spy = new jasmine.Spy(name);
+
+  for (var prop in spy) {
+    spyObj[prop] = spy[prop];
+  }
+
+  spyObj.reset();
+
+  return spyObj;
+};
+
+/**
+ * Determines whether an object is a spy.
+ *
+ * @param {jasmine.Spy|Object} putativeSpy
+ * @returns {Boolean}
+ */
+jasmine.isSpy = function(putativeSpy) {
+  return putativeSpy && putativeSpy.isSpy;
+};
+
+/**
+ * Creates a more complicated spy: an Object that has every property a function that is a spy.  Used for stubbing something
+ * large in one call.
+ *
+ * @param {String} baseName name of spy class
+ * @param {Array} methodNames array of names of methods to make spies
+ */
+jasmine.createSpyObj = function(baseName, methodNames) {
+  if (!jasmine.isArray_(methodNames) || methodNames.length === 0) {
+    throw new Error('createSpyObj requires a non-empty array of method names to create spies for');
+  }
+  var obj = {};
+  for (var i = 0; i < methodNames.length; i++) {
+    obj[methodNames[i]] = jasmine.createSpy(baseName + '.' + methodNames[i]);
+  }
+  return obj;
+};
+
+/**
+ * All parameters are pretty-printed and concatenated together, then written to the current spec's output.
+ *
+ * Be careful not to leave calls to <code>jasmine.log</code> in production code.
+ */
+jasmine.log = function() {
+  var spec = jasmine.getEnv().currentSpec;
+  spec.log.apply(spec, arguments);
+};
+
+/**
+ * Function that installs a spy on an existing object's method name.  Used within a Spec to create a spy.
+ *
+ * @example
+ * // spy example
+ * var foo = {
+ *   not: function(bool) { return !bool; }
+ * }
+ * spyOn(foo, 'not'); // actual foo.not will not be called, execution stops
+ *
+ * @see jasmine.createSpy
+ * @param obj
+ * @param methodName
+ * @return {jasmine.Spy} a Jasmine spy that can be chained with all spy methods
+ */
+var spyOn = function(obj, methodName) {
+  return jasmine.getEnv().currentSpec.spyOn(obj, methodName);
+};
+if (isCommonJS) exports.spyOn = spyOn;
+
+/**
+ * Creates a Jasmine spec that will be added to the current suite.
+ *
+ * // TODO: pending tests
+ *
+ * @example
+ * it('should be true', function() {
+ *   expect(true).toEqual(true);
+ * });
+ *
+ * @param {String} desc description of this specification
+ * @param {Function} func defines the preconditions and expectations of the spec
+ */
+var it = function(desc, func) {
+  return jasmine.getEnv().it(desc, func);
+};
+if (isCommonJS) exports.it = it;
+
+/**
+ * Creates a <em>disabled</em> Jasmine spec.
+ *
+ * A convenience method that allows existing specs to be disabled temporarily during development.
+ *
+ * @param {String} desc description of this specification
+ * @param {Function} func defines the preconditions and expectations of the spec
+ */
+var xit = function(desc, func) {
+  return jasmine.getEnv().xit(desc, func);
+};
+if (isCommonJS) exports.xit = xit;
+
+/**
+ * Starts a chain for a Jasmine expectation.
+ *
+ * It is passed an Object that is the actual value and should chain to one of the many
+ * jasmine.Matchers functions.
+ *
+ * @param {Object} actual Actual value to test against and expected value
+ * @return {jasmine.Matchers}
+ */
+var expect = function(actual) {
+  return jasmine.getEnv().currentSpec.expect(actual);
+};
+if (isCommonJS) exports.expect = expect;
+
+/**
+ * Defines part of a jasmine spec.  Used in cominbination with waits or waitsFor in asynchrnous specs.
+ *
+ * @param {Function} func Function that defines part of a jasmine spec.
+ */
+var runs = function(func) {
+  jasmine.getEnv().currentSpec.runs(func);
+};
+if (isCommonJS) exports.runs = runs;
+
+/**
+ * Waits a fixed time period before moving to the next block.
+ *
+ * @deprecated Use waitsFor() instead
+ * @param {Number} timeout milliseconds to wait
+ */
+var waits = function(timeout) {
+  jasmine.getEnv().currentSpec.waits(timeout);
+};
+if (isCommonJS) exports.waits = waits;
+
+/**
+ * Waits for the latchFunction to return true before proceeding to the next block.
+ *
+ * @param {Function} latchFunction
+ * @param {String} optional_timeoutMessage
+ * @param {Number} optional_timeout
+ */
+var waitsFor = function(latchFunction, optional_timeoutMessage, optional_timeout) {
+  jasmine.getEnv().currentSpec.waitsFor.apply(jasmine.getEnv().currentSpec, arguments);
+};
+if (isCommonJS) exports.waitsFor = waitsFor;
+
+/**
+ * A function that is called before each spec in a suite.
+ *
+ * Used for spec setup, including validating assumptions.
+ *
+ * @param {Function} beforeEachFunction
+ */
+var beforeEach = function(beforeEachFunction) {
+  jasmine.getEnv().beforeEach(beforeEachFunction);
+};
+if (isCommonJS) exports.beforeEach = beforeEach;
+
+/**
+ * A function that is called after each spec in a suite.
+ *
+ * Used for restoring any state that is hijacked during spec execution.
+ *
+ * @param {Function} afterEachFunction
+ */
+var afterEach = function(afterEachFunction) {
+  jasmine.getEnv().afterEach(afterEachFunction);
+};
+if (isCommonJS) exports.afterEach = afterEach;
+
+/**
+ * Defines a suite of specifications.
+ *
+ * Stores the description and all defined specs in the Jasmine environment as one suite of specs. Variables declared
+ * are accessible by calls to beforeEach, it, and afterEach. Describe blocks can be nested, allowing for specialization
+ * of setup in some tests.
+ *
+ * @example
+ * // TODO: a simple suite
+ *
+ * // TODO: a simple suite with a nested describe block
+ *
+ * @param {String} description A string, usually the class under test.
+ * @param {Function} specDefinitions function that defines several specs.
+ */
+var describe = function(description, specDefinitions) {
+  return jasmine.getEnv().describe(description, specDefinitions);
+};
+if (isCommonJS) exports.describe = describe;
+
+/**
+ * Disables a suite of specifications.  Used to disable some suites in a file, or files, temporarily during development.
+ *
+ * @param {String} description A string, usually the class under test.
+ * @param {Function} specDefinitions function that defines several specs.
+ */
+var xdescribe = function(description, specDefinitions) {
+  return jasmine.getEnv().xdescribe(description, specDefinitions);
+};
+if (isCommonJS) exports.xdescribe = xdescribe;
+
+
+// Provide the XMLHttpRequest class for IE 5.x-6.x:
+jasmine.XmlHttpRequest = (typeof XMLHttpRequest == "undefined") ? function() {
+  function tryIt(f) {
+    try {
+      return f();
+    } catch(e) {
+    }
+    return null;
+  }
+
+  var xhr = tryIt(function() {
+    return new ActiveXObject("Msxml2.XMLHTTP.6.0");
+  }) ||
+    tryIt(function() {
+      return new ActiveXObject("Msxml2.XMLHTTP.3.0");
+    }) ||
+    tryIt(function() {
+      return new ActiveXObject("Msxml2.XMLHTTP");
+    }) ||
+    tryIt(function() {
+      return new ActiveXObject("Microsoft.XMLHTTP");
+    });
+
+  if (!xhr) throw new Error("This browser does not support XMLHttpRequest.");
+
+  return xhr;
+} : XMLHttpRequest;
+/**
+ * @namespace
+ */
+jasmine.util = {};
+
+/**
+ * Declare that a child class inherit it's prototype from the parent class.
+ *
+ * @private
+ * @param {Function} childClass
+ * @param {Function} parentClass
+ */
+jasmine.util.inherit = function(childClass, parentClass) {
+  /**
+   * @private
+   */
+  var subclass = function() {
+  };
+  subclass.prototype = parentClass.prototype;
+  childClass.prototype = new subclass();
+};
+
+jasmine.util.formatException = function(e) {
+  var lineNumber;
+  if (e.line) {
+    lineNumber = e.line;
+  }
+  else if (e.lineNumber) {
+    lineNumber = e.lineNumber;
+  }
+
+  var file;
+
+  if (e.sourceURL) {
+    file = e.sourceURL;
+  }
+  else if (e.fileName) {
+    file = e.fileName;
+  }
+
+  var message = (e.name && e.message) ? (e.name + ': ' + e.message) : e.toString();
+
+  if (file && lineNumber) {
+    message += ' in ' + file + ' (line ' + lineNumber + ')';
+  }
+
+  return message;
+};
+
+jasmine.util.htmlEscape = function(str) {
+  if (!str) return str;
+  return str.replace(/&/g, '&amp;')
+    .replace(/</g, '&lt;')
+    .replace(/>/g, '&gt;');
+};
+
+jasmine.util.argsToArray = function(args) {
+  var arrayOfArgs = [];
+  for (var i = 0; i < args.length; i++) arrayOfArgs.push(args[i]);
+  return arrayOfArgs;
+};
+
+jasmine.util.extend = function(destination, source) {
+  for (var property in source) destination[property] = source[property];
+  return destination;
+};
+
+/**
+ * Environment for Jasmine
+ *
+ * @constructor
+ */
+jasmine.Env = function() {
+  this.currentSpec = null;
+  this.currentSuite = null;
+  this.currentRunner_ = new jasmine.Runner(this);
+
+  this.reporter = new jasmine.MultiReporter();
+
+  this.updateInterval = jasmine.DEFAULT_UPDATE_INTERVAL;
+  this.defaultTimeoutInterval = jasmine.DEFAULT_TIMEOUT_INTERVAL;
+  this.lastUpdate = 0;
+  this.specFilter = function() {
+    return true;
+  };
+
+  this.nextSpecId_ = 0;
+  this.nextSuiteId_ = 0;
+  this.equalityTesters_ = [];
+
+  // wrap matchers
+  this.matchersClass = function() {
+    jasmine.Matchers.apply(this, arguments);
+  };
+  jasmine.util.inherit(this.matchersClass, jasmine.Matchers);
+
+  jasmine.Matchers.wrapInto_(jasmine.Matchers.prototype, this.matchersClass);
+};
+
+
+jasmine.Env.prototype.setTimeout = jasmine.setTimeout;
+jasmine.Env.prototype.clearTimeout = jasmine.clearTimeout;
+jasmine.Env.prototype.setInterval = jasmine.setInterval;
+jasmine.Env.prototype.clearInterval = jasmine.clearInterval;
+
+/**
+ * @returns an object containing jasmine version build info, if set.
+ */
+jasmine.Env.prototype.version = function () {
+  if (jasmine.version_) {
+    return jasmine.version_;
+  } else {
+    throw new Error('Version not set');
+  }
+};
+
+/**
+ * @returns string containing jasmine version build info, if set.
+ */
+jasmine.Env.prototype.versionString = function() {
+  if (!jasmine.version_) {
+    return "version unknown";
+  }
+
+  var version = this.version();
+  var versionString = version.major + "." + version.minor + "." + version.build;
+  if (version.release_candidate) {
+    versionString += ".rc" + version.release_candidate;
+  }
+  versionString += " revision " + version.revision;
+  return versionString;
+};
+
+/**
+ * @returns a sequential integer starting at 0
+ */
+jasmine.Env.prototype.nextSpecId = function () {
+  return this.nextSpecId_++;
+};
+
+/**
+ * @returns a sequential integer starting at 0
+ */
+jasmine.Env.prototype.nextSuiteId = function () {
+  return this.nextSuiteId_++;
+};
+
+/**
+ * Register a reporter to receive status updates from Jasmine.
+ * @param {jasmine.Reporter} reporter An object which will receive status updates.
+ */
+jasmine.Env.prototype.addReporter = function(reporter) {
+  this.reporter.addReporter(reporter);
+};
+
+jasmine.Env.prototype.execute = function() {
+  this.currentRunner_.execute();
+};
+
+jasmine.Env.prototype.describe = function(description, specDefinitions) {
+  var suite = new jasmine.Suite(this, description, specDefinitions, this.currentSuite);
+
+  var parentSuite = this.currentSuite;
+  if (parentSuite) {
+    parentSuite.add(suite);
+  } else {
+    this.currentRunner_.add(suite);
+  }
+
+  this.currentSuite = suite;
+
+  var declarationError = null;
+  try {
+    specDefinitions.call(suite);
+  } catch(e) {
+    declarationError = e;
+  }
+
+  if (declarationError) {
+    this.it("encountered a declaration exception", function() {
+      throw declarationError;
+    });
+  }
+
+  this.currentSuite = parentSuite;
+
+  return suite;
+};
+
+jasmine.Env.prototype.beforeEach = function(beforeEachFunction) {
+  if (this.currentSuite) {
+    this.currentSuite.beforeEach(beforeEachFunction);
+  } else {
+    this.currentRunner_.beforeEach(beforeEachFunction);
+  }
+};
+
+jasmine.Env.prototype.currentRunner = function () {
+  return this.currentRunner_;
+};
+
+jasmine.Env.prototype.afterEach = function(afterEachFunction) {
+  if (this.currentSuite) {
+    this.currentSuite.afterEach(afterEachFunction);
+  } else {
+    this.currentRunner_.afterEach(afterEachFunction);
+  }
+
+};
+
+jasmine.Env.prototype.xdescribe = function(desc, specDefinitions) {
+  return {
+    execute: function() {
+    }
+  };
+};
+
+jasmine.Env.prototype.it = function(description, func) {
+  var spec = new jasmine.Spec(this, this.currentSuite, description);
+  this.currentSuite.add(spec);
+  this.currentSpec = spec;
+
+  if (func) {
+    spec.runs(func);
+  }
+
+  return spec;
+};
+
+jasmine.Env.prototype.xit = function(desc, func) {
+  return {
+    id: this.nextSpecId(),
+    runs: function() {
+    }
+  };
+};
+
+jasmine.Env.prototype.compareRegExps_ = function(a, b, mismatchKeys, mismatchValues) {
+  if (a.source != b.source)
+    mismatchValues.push("expected pattern /" + b.source + "/ is not equal to the pattern /" + a.source + "/");
+
+  if (a.ignoreCase != b.ignoreCase)
+    mismatchValues.push("expected modifier i was" + (b.ignoreCase ? " " : " not ") + "set and does not equal the origin modifier");
+
+  if (a.global != b.global)
+    mismatchValues.push("expected modifier g was" + (b.global ? " " : " not ") + "set and does not equal the origin modifier");
+
+  if (a.multiline != b.multiline)
+    mismatchValues.push("expected modifier m was" + (b.multiline ? " " : " not ") + "set and does not equal the origin modifier");
+
+  if (a.sticky != b.sticky)
+    mismatchValues.push("expected modifier y was" + (b.sticky ? " " : " not ") + "set and does not equal the origin modifier");
+
+  return (mismatchValues.length === 0);
+};
+
+jasmine.Env.prototype.compareObjects_ = function(a, b, mismatchKeys, mismatchValues) {
+  if (a.__Jasmine_been_here_before__ === b && b.__Jasmine_been_here_before__ === a) {
+    return true;
+  }
+
+  a.__Jasmine_been_here_before__ = b;
+  b.__Jasmine_been_here_before__ = a;
+
+  var hasKey = function(obj, keyName) {
+    return obj !== null && obj[keyName] !== jasmine.undefined;
+  };
+
+  for (var property in b) {
+    if (!hasKey(a, property) && hasKey(b, property)) {
+      mismatchKeys.push("expected has key '" + property + "', but missing from actual.");
+    }
+  }
+  for (property in a) {
+    if (!hasKey(b, property) && hasKey(a, property)) {
+      mismatchKeys.push("expected missing key '" + property + "', but present in actual.");
+    }
+  }
+  for (property in b) {
+    if (property == '__Jasmine_been_here_before__') continue;
+    if (!this.equals_(a[property], b[property], mismatchKeys, mismatchValues)) {
+      mismatchValues.push("'" + property + "' was '" + (b[property] ? jasmine.util.htmlEscape(b[property].toString()) : b[property]) + "' in expected, but was '" + (a[property] ? jasmine.util.htmlEscape(a[property].toString()) : a[property]) + "' in actual.");
+    }
+  }
+
+  if (jasmine.isArray_(a) && jasmine.isArray_(b) && a.length != b.length) {
+    mismatchValues.push("arrays were not the same length");
+  }
+
+  delete a.__Jasmine_been_here_before__;
+  delete b.__Jasmine_been_here_before__;
+  return (mismatchKeys.length === 0 && mismatchValues.length === 0);
+};
+
+jasmine.Env.prototype.equals_ = function(a, b, mismatchKeys, mismatchValues) {
+  mismatchKeys = mismatchKeys || [];
+  mismatchValues = mismatchValues || [];
+
+  for (var i = 0; i < this.equalityTesters_.length; i++) {
+    var equalityTester = this.equalityTesters_[i];
+    var result = equalityTester(a, b, this, mismatchKeys, mismatchValues);
+    if (result !== jasmine.undefined) return result;
+  }
+
+  if (a === b) return true;
+
+  if (a === jasmine.undefined || a === null || b === jasmine.undefined || b === null) {
+    return (a == jasmine.undefined && b == jasmine.undefined);
+  }
+
+  if (jasmine.isDomNode(a) && jasmine.isDomNode(b)) {
+    return a === b;
+  }
+
+  if (a instanceof Date && b instanceof Date) {
+    return a.getTime() == b.getTime();
+  }
+
+  if (a.jasmineMatches) {
+    return a.jasmineMatches(b);
+  }
+
+  if (b.jasmineMatches) {
+    return b.jasmineMatches(a);
+  }
+
+  if (a instanceof jasmine.Matchers.ObjectContaining) {
+    return a.matches(b);
+  }
+
+  if (b instanceof jasmine.Matchers.ObjectContaining) {
+    return b.matches(a);
+  }
+
+  if (jasmine.isString_(a) && jasmine.isString_(b)) {
+    return (a == b);
+  }
+
+  if (jasmine.isNumber_(a) && jasmine.isNumber_(b)) {
+    return (a == b);
+  }
+
+  if (a instanceof RegExp && b instanceof RegExp) {
+    return this.compareRegExps_(a, b, mismatchKeys, mismatchValues);
+  }
+
+  if (typeof a === "object" && typeof b === "object") {
+    return this.compareObjects_(a, b, mismatchKeys, mismatchValues);
+  }
+
+  //Straight check
+  return (a === b);
+};
+
+jasmine.Env.prototype.contains_ = function(haystack, needle) {
+  if (jasmine.isArray_(haystack)) {
+    for (var i = 0; i < haystack.length; i++) {
+      if (this.equals_(haystack[i], needle)) return true;
+    }
+    return false;
+  }
+  return haystack.indexOf(needle) >= 0;
+};
+
+jasmine.Env.prototype.addEqualityTester = function(equalityTester) {
+  this.equalityTesters_.push(equalityTester);
+};
+/** No-op base class for Jasmine reporters.
+ *
+ * @constructor
+ */
+jasmine.Reporter = function() {
+};
+
+//noinspection JSUnusedLocalSymbols
+jasmine.Reporter.prototype.reportRunnerStarting = function(runner) {
+};
+
+//noinspection JSUnusedLocalSymbols
+jasmine.Reporter.prototype.reportRunnerResults = function(runner) {
+};
+
+//noinspection JSUnusedLocalSymbols
+jasmine.Reporter.prototype.reportSuiteResults = function(suite) {
+};
+
+//noinspection JSUnusedLocalSymbols
+jasmine.Reporter.prototype.reportSpecStarting = function(spec) {
+};
+
+//noinspection JSUnusedLocalSymbols
+jasmine.Reporter.prototype.reportSpecResults = function(spec) {
+};
+
+//noinspection JSUnusedLocalSymbols
+jasmine.Reporter.prototype.log = function(str) {
+};
+
+/**
+ * Blocks are functions with executable code that make up a spec.
+ *
+ * @constructor
+ * @param {jasmine.Env} env
+ * @param {Function} func
+ * @param {jasmine.Spec} spec
+ */
+jasmine.Block = function(env, func, spec) {
+  this.env = env;
+  this.func = func;
+  this.spec = spec;
+};
+
+jasmine.Block.prototype.execute = function(onComplete) {
+  if (!jasmine.CATCH_EXCEPTIONS) {
+    this.func.apply(this.spec);
+  }
+  else {
+    try {
+      this.func.apply(this.spec);
+    } catch (e) {
+      this.spec.fail(e);
+    }
+  }
+  onComplete();
+};
+/** JavaScript API reporter.
+ *
+ * @constructor
+ */
+jasmine.JsApiReporter = function() {
+  this.started = false;
+  this.finished = false;
+  this.suites_ = [];
+  this.results_ = {};
+};
+
+jasmine.JsApiReporter.prototype.reportRunnerStarting = function(runner) {
+  this.started = true;
+  var suites = runner.topLevelSuites();
+  for (var i = 0; i < suites.length; i++) {
+    var suite = suites[i];
+    this.suites_.push(this.summarize_(suite));
+  }
+};
+
+jasmine.JsApiReporter.prototype.suites = function() {
+  return this.suites_;
+};
+
+jasmine.JsApiReporter.prototype.summarize_ = function(suiteOrSpec) {
+  var isSuite = suiteOrSpec instanceof jasmine.Suite;
+  var summary = {
+    id: suiteOrSpec.id,
+    name: suiteOrSpec.description,
+    type: isSuite ? 'suite' : 'spec',
+    children: []
+  };
+  
+  if (isSuite) {
+    var children = suiteOrSpec.children();
+    for (var i = 0; i < children.length; i++) {
+      summary.children.push(this.summarize_(children[i]));
+    }
+  }
+  return summary;
+};
+
+jasmine.JsApiReporter.prototype.results = function() {
+  return this.results_;
+};
+
+jasmine.JsApiReporter.prototype.resultsForSpec = function(specId) {
+  return this.results_[specId];
+};
+
+//noinspection JSUnusedLocalSymbols
+jasmine.JsApiReporter.prototype.reportRunnerResults = function(runner) {
+  this.finished = true;
+};
+
+//noinspection JSUnusedLocalSymbols
+jasmine.JsApiReporter.prototype.reportSuiteResults = function(suite) {
+};
+
+//noinspection JSUnusedLocalSymbols
+jasmine.JsApiReporter.prototype.reportSpecResults = function(spec) {
+  this.results_[spec.id] = {
+    messages: spec.results().getItems(),
+    result: spec.results().failedCount > 0 ? "failed" : "passed"
+  };
+};
+
+//noinspection JSUnusedLocalSymbols
+jasmine.JsApiReporter.prototype.log = function(str) {
+};
+
+jasmine.JsApiReporter.prototype.resultsForSpecs = function(specIds){
+  var results = {};
+  for (var i = 0; i < specIds.length; i++) {
+    var specId = specIds[i];
+    results[specId] = this.summarizeResult_(this.results_[specId]);
+  }
+  return results;
+};
+
+jasmine.JsApiReporter.prototype.summarizeResult_ = function(result){
+  var summaryMessages = [];
+  var messagesLength = result.messages.length;
+  for (var messageIndex = 0; messageIndex < messagesLength; messageIndex++) {
+    var resultMessage = result.messages[messageIndex];
+    summaryMessages.push({
+      text: resultMessage.type == 'log' ? resultMessage.toString() : jasmine.undefined,
+      passed: resultMessage.passed ? resultMessage.passed() : true,
+      type: resultMessage.type,
+      message: resultMessage.message,
+      trace: {
+        stack: resultMessage.passed && !resultMessage.passed() ? resultMessage.trace.stack : jasmine.undefined
+      }
+    });
+  }
+
+  return {
+    result : result.result,
+    messages : summaryMessages
+  };
+};
+
+/**
+ * @constructor
+ * @param {jasmine.Env} env
+ * @param actual
+ * @param {jasmine.Spec} spec
+ */
+jasmine.Matchers = function(env, actual, spec, opt_isNot) {
+  this.env = env;
+  this.actual = actual;
+  this.spec = spec;
+  this.isNot = opt_isNot || false;
+  this.reportWasCalled_ = false;
+};
+
+// todo: @deprecated as of Jasmine 0.11, remove soon [xw]
+jasmine.Matchers.pp = function(str) {
+  throw new Error("jasmine.Matchers.pp() is no longer supported, please use jasmine.pp() instead!");
+};
+
+// todo: @deprecated Deprecated as of Jasmine 0.10. Rewrite your custom matchers to return true or false. [xw]
+jasmine.Matchers.prototype.report = function(result, failing_message, details) {
+  throw new Error("As of jasmine 0.11, custom matchers must be implemented differently -- please see jasmine docs");
+};
+
+jasmine.Matchers.wrapInto_ = function(prototype, matchersClass) {
+  for (var methodName in prototype) {
+    if (methodName == 'report') continue;
+    var orig = prototype[methodName];
+    matchersClass.prototype[methodName] = jasmine.Matchers.matcherFn_(methodName, orig);
+  }
+};
+
+jasmine.Matchers.matcherFn_ = function(matcherName, matcherFunction) {
+  return function() {
+    var matcherArgs = jasmine.util.argsToArray(arguments);
+    var result = matcherFunction.apply(this, arguments);
+
+    if (this.isNot) {
+      result = !result;
+    }
+
+    if (this.reportWasCalled_) return result;
+
+    var message;
+    if (!result) {
+      if (this.message) {
+        message = this.message.apply(this, arguments);
+        if (jasmine.isArray_(message)) {
+          message = message[this.isNot ? 1 : 0];
+        }
+      } else {
+        var englishyPredicate = matcherName.replace(/[A-Z]/g, function(s) { return ' ' + s.toLowerCase(); });
+        message = "Expected " + jasmine.pp(this.actual) + (this.isNot ? " not " : " ") + englishyPredicate;
+        if (matcherArgs.length > 0) {
+          for (var i = 0; i < matcherArgs.length; i++) {
+            if (i > 0) message += ",";
+            message += " " + jasmine.pp(matcherArgs[i]);
+          }
+        }
+        message += ".";
+      }
+    }
+    var expectationResult = new jasmine.ExpectationResult({
+      matcherName: matcherName,
+      passed: result,
+      expected: matcherArgs.length > 1 ? matcherArgs : matcherArgs[0],
+      actual: this.actual,
+      message: message
+    });
+    this.spec.addMatcherResult(expectationResult);
+    return jasmine.undefined;
+  };
+};
+
+
+
+
+/**
+ * toBe: compares the actual to the expected using ===
+ * @param expected
+ */
+jasmine.Matchers.prototype.toBe = function(expected) {
+  return this.actual === expected;
+};
+
+/**
+ * toNotBe: compares the actual to the expected using !==
+ * @param expected
+ * @deprecated as of 1.0. Use not.toBe() instead.
+ */
+jasmine.Matchers.prototype.toNotBe = function(expected) {
+  return this.actual !== expected;
+};
+
+/**
+ * toEqual: compares the actual to the expected using common sense equality. Handles Objects, Arrays, etc.
+ *
+ * @param expected
+ */
+jasmine.Matchers.prototype.toEqual = function(expected) {
+  return this.env.equals_(this.actual, expected);
+};
+
+/**
+ * toNotEqual: compares the actual to the expected using the ! of jasmine.Matchers.toEqual
+ * @param expected
+ * @deprecated as of 1.0. Use not.toEqual() instead.
+ */
+jasmine.Matchers.prototype.toNotEqual = function(expected) {
+  return !this.env.equals_(this.actual, expected);
+};
+
+/**
+ * Matcher that compares the actual to the expected using a regular expression.  Constructs a RegExp, so takes
+ * a pattern or a String.
+ *
+ * @param expected
+ */
+jasmine.Matchers.prototype.toMatch = function(expected) {
+  return new RegExp(expected).test(this.actual);
+};
+
+/**
+ * Matcher that compares the actual to the expected using the boolean inverse of jasmine.Matchers.toMatch
+ * @param expected
+ * @deprecated as of 1.0. Use not.toMatch() instead.
+ */
+jasmine.Matchers.prototype.toNotMatch = function(expected) {
+  return !(new RegExp(expected).test(this.actual));
+};
+
+/**
+ * Matcher that compares the actual to jasmine.undefined.
+ */
+jasmine.Matchers.prototype.toBeDefined = function() {
+  return (this.actual !== jasmine.undefined);
+};
+
+/**
+ * Matcher that compares the actual to jasmine.undefined.
+ */
+jasmine.Matchers.prototype.toBeUndefined = function() {
+  return (this.actual === jasmine.undefined);
+};
+
+/**
+ * Matcher that compares the actual to null.
+ */
+jasmine.Matchers.prototype.toBeNull = function() {
+  return (this.actual === null);
+};
+
+/**
+ * Matcher that compares the actual to NaN.
+ */
+jasmine.Matchers.prototype.toBeNaN = function() {
+	this.message = function() {
+		return [ "Expected " + jasmine.pp(this.actual) + " to be NaN." ];
+	};
+
+	return (this.actual !== this.actual);
+};
+
+/**
+ * Matcher that boolean not-nots the actual.
+ */
+jasmine.Matchers.prototype.toBeTruthy = function() {
+  return !!this.actual;
+};
+
+
+/**
+ * Matcher that boolean nots the actual.
+ */
+jasmine.Matchers.prototype.toBeFalsy = function() {
+  return !this.actual;
+};
+
+
+/**
+ * Matcher that checks to see if the actual, a Jasmine spy, was called.
+ */
+jasmine.Matchers.prototype.toHaveBeenCalled = function() {
+  if (arguments.length > 0) {
+    throw new Error('toHaveBeenCalled does not take arguments, use toHaveBeenCalledWith');
+  }
+
+  if (!jasmine.isSpy(this.actual)) {
+    throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');
+  }
+
+  this.message = function() {
+    return [
+      "Expected spy " + this.actual.identity + " to have been called.",
+      "Expected spy " + this.actual.identity + " not to have been called."
+    ];
+  };
+
+  return this.actual.wasCalled;
+};
+
+/** @deprecated Use expect(xxx).toHaveBeenCalled() instead */
+jasmine.Matchers.prototype.wasCalled = jasmine.Matchers.prototype.toHaveBeenCalled;
+
+/**
+ * Matcher that checks to see if the actual, a Jasmine spy, was not called.
+ *
+ * @deprecated Use expect(xxx).not.toHaveBeenCalled() instead
+ */
+jasmine.Matchers.prototype.wasNotCalled = function() {
+  if (arguments.length > 0) {
+    throw new Error('wasNotCalled does not take arguments');
+  }
+
+  if (!jasmine.isSpy(this.actual)) {
+    throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');
+  }
+
+  this.message = function() {
+    return [
+      "Expected spy " + this.actual.identity + " to not have been called.",
+      "Expected spy " + this.actual.identity + " to have been called."
+    ];
+  };
+
+  return !this.actual.wasCalled;
+};
+
+/**
+ * Matcher that checks to see if the actual, a Jasmine spy, was called with a set of parameters.
+ *
+ * @example
+ *
+ */
+jasmine.Matchers.prototype.toHaveBeenCalledWith = function() {
+  var expectedArgs = jasmine.util.argsToArray(arguments);
+  if (!jasmine.isSpy(this.actual)) {
+    throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');
+  }
+  this.message = function() {
+    var invertedMessage = "Expected spy " + this.actual.identity + " not to have been called with " + jasmine.pp(expectedArgs) + " but it was.";
+    var positiveMessage = "";
+    if (this.actual.callCount === 0) {
+      positiveMessage = "Expected spy " + this.actual.identity + " to have been called with " + jasmine.pp(expectedArgs) + " but it was never called.";
+    } else {
+      positiveMessage = "Expected spy " + this.actual.identity + " to have been called with " + jasmine.pp(expectedArgs) + " but actual calls were " + jasmine.pp(this.actual.argsForCall).replace(/^\[ | \]$/g, '')
+    }
+    return [positiveMessage, invertedMessage];
+  };
+
+  return this.env.contains_(this.actual.argsForCall, expectedArgs);
+};
+
+/** @deprecated Use expect(xxx).toHaveBeenCalledWith() instead */
+jasmine.Matchers.prototype.wasCalledWith = jasmine.Matchers.prototype.toHaveBeenCalledWith;
+
+/** @deprecated Use expect(xxx).not.toHaveBeenCalledWith() instead */
+jasmine.Matchers.prototype.wasNotCalledWith = function() {
+  var expectedArgs = jasmine.util.argsToArray(arguments);
+  if (!jasmine.isSpy(this.actual)) {
+    throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');
+  }
+
+  this.message = function() {
+    return [
+      "Expected spy not to have been called with " + jasmine.pp(expectedArgs) + " but it was",
+      "Expected spy to have been called with " + jasmine.pp(expectedArgs) + " but it was"
+    ];
+  };
+
+  return !this.env.contains_(this.actual.argsForCall, expectedArgs);
+};
+
+/**
+ * Matcher that checks that the expected item is an element in the actual Array.
+ *
+ * @param {Object} expected
+ */
+jasmine.Matchers.prototype.toContain = function(expected) {
+  return this.env.contains_(this.actual, expected);
+};
+
+/**
+ * Matcher that checks that the expected item is NOT an element in the actual Array.
+ *
+ * @param {Object} expected
+ * @deprecated as of 1.0. Use not.toContain() instead.
+ */
+jasmine.Matchers.prototype.toNotContain = function(expected) {
+  return !this.env.contains_(this.actual, expected);
+};
+
+jasmine.Matchers.prototype.toBeLessThan = function(expected) {
+  return this.actual < expected;
+};
+
+jasmine.Matchers.prototype.toBeGreaterThan = function(expected) {
+  return this.actual > expected;
+};
+
+/**
+ * Matcher that checks that the expected item is equal to the actual item
+ * up to a given level of decimal precision (default 2).
+ *
+ * @param {Number} expected
+ * @param {Number} precision, as number of decimal places
+ */
+jasmine.Matchers.prototype.toBeCloseTo = function(expected, precision) {
+  if (!(precision === 0)) {
+    precision = precision || 2;
+  }
+  return Math.abs(expected - this.actual) < (Math.pow(10, -precision) / 2);
+};
+
+/**
+ * Matcher that checks that the expected exception was thrown by the actual.
+ *
+ * @param {String} [expected]
+ */
+jasmine.Matchers.prototype.toThrow = function(expected) {
+  var result = false;
+  var exception;
+  if (typeof this.actual != 'function') {
+    throw new Error('Actual is not a function');
+  }
+  try {
+    this.actual();
+  } catch (e) {
+    exception = e;
+  }
+  if (exception) {
+    result = (expected === jasmine.undefined || this.env.equals_(exception.message || exception, expected.message || expected));
+  }
+
+  var not = this.isNot ? "not " : "";
+
+  this.message = function() {
+    if (exception && (expected === jasmine.undefined || !this.env.equals_(exception.message || exception, expected.message || expected))) {
+      return ["Expected function " + not + "to throw", expected ? expected.message || expected : "an exception", ", but it threw", exception.message || exception].join(' ');
+    } else {
+      return "Expected function to throw an exception.";
+    }
+  };
+
+  return result;
+};
+
+jasmine.Matchers.Any = function(expectedClass) {
+  this.expectedClass = expectedClass;
+};
+
+jasmine.Matchers.Any.prototype.jasmineMatches = function(other) {
+  if (this.expectedClass == String) {
+    return typeof other == 'string' || other instanceof String;
+  }
+
+  if (this.expectedClass == Number) {
+    return typeof other == 'number' || other instanceof Number;
+  }
+
+  if (this.expectedClass == Function) {
+    return typeof other == 'function' || other instanceof Function;
+  }
+
+  if (this.expectedClass == Object) {
+    return typeof other == 'object';
+  }
+
+  return other instanceof this.expectedClass;
+};
+
+jasmine.Matchers.Any.prototype.jasmineToString = function() {
+  return '<jasmine.any(' + this.expectedClass + ')>';
+};
+
+jasmine.Matchers.ObjectContaining = function (sample) {
+  this.sample = sample;
+};
+
+jasmine.Matchers.ObjectContaining.prototype.jasmineMatches = function(other, mismatchKeys, mismatchValues) {
+  mismatchKeys = mismatchKeys || [];
+  mismatchValues = mismatchValues || [];
+
+  var env = jasmine.getEnv();
+
+  var hasKey = function(obj, keyName) {
+    return obj != null && obj[keyName] !== jasmine.undefined;
+  };
+
+  for (var property in this.sample) {
+    if (!hasKey(other, property) && hasKey(this.sample, property)) {
+      mismatchKeys.push("expected has key '" + property + "', but missing from actual.");
+    }
+    else if (!env.equals_(this.sample[property], other[property], mismatchKeys, mismatchValues)) {
+      mismatchValues.push("'" + property + "' was '" + (other[property] ? jasmine.util.htmlEscape(other[property].toString()) : other[property]) + "' in expected, but was '" + (this.sample[property] ? jasmine.util.htmlEscape(this.sample[property].toString()) : this.sample[property]) + "' in actual.");
+    }
+  }
+
+  return (mismatchKeys.length === 0 && mismatchValues.length === 0);
+};
+
+jasmine.Matchers.ObjectContaining.prototype.jasmineToString = function () {
+  return "<jasmine.objectContaining(" + jasmine.pp(this.sample) + ")>";
+};
+// Mock setTimeout, clearTimeout
+// Contributed by Pivotal Computer Systems, www.pivotalsf.com
+
+jasmine.FakeTimer = function() {
+  this.reset();
+
+  var self = this;
+  self.setTimeout = function(funcToCall, millis) {
+    self.timeoutsMade++;
+    self.scheduleFunction(self.timeoutsMade, funcToCall, millis, false);
+    return self.timeoutsMade;
+  };
+
+  self.setInterval = function(funcToCall, millis) {
+    self.timeoutsMade++;
+    self.scheduleFunction(self.timeoutsMade, funcToCall, millis, true);
+    return self.timeoutsMade;
+  };
+
+  self.clearTimeout = function(timeoutKey) {
+    self.scheduledFunctions[timeoutKey] = jasmine.undefined;
+  };
+
+  self.clearInterval = function(timeoutKey) {
+    self.scheduledFunctions[timeoutKey] = jasmine.undefined;
+  };
+
+};
+
+jasmine.FakeTimer.prototype.reset = function() {
+  this.timeoutsMade = 0;
+  this.scheduledFunctions = {};
+  this.nowMillis = 0;
+};
+
+jasmine.FakeTimer.prototype.tick = function(millis) {
+  var oldMillis = this.nowMillis;
+  var newMillis = oldMillis + millis;
+  this.runFunctionsWithinRange(oldMillis, newMillis);
+  this.nowMillis = newMillis;
+};
+
+jasmine.FakeTimer.prototype.runFunctionsWithinRange = function(oldMillis, nowMillis) {
+  var scheduledFunc;
+  var funcsToRun = [];
+  for (var timeoutKey in this.scheduledFunctions) {
+    scheduledFunc = this.scheduledFunctions[timeoutKey];
+    if (scheduledFunc != jasmine.undefined &&
+        scheduledFunc.runAtMillis >= oldMillis &&
+        scheduledFunc.runAtMillis <= nowMillis) {
+      funcsToRun.push(scheduledFunc);
+      this.scheduledFunctions[timeoutKey] = jasmine.undefined;
+    }
+  }
+
+  if (funcsToRun.length > 0) {
+    funcsToRun.sort(function(a, b) {
+      return a.runAtMillis - b.runAtMillis;
+    });
+    for (var i = 0; i < funcsToRun.length; ++i) {
+      try {
+        var funcToRun = funcsToRun[i];
+        this.nowMillis = funcToRun.runAtMillis;
+        funcToRun.funcToCall();
+        if (funcToRun.recurring) {
+          this.scheduleFunction(funcToRun.timeoutKey,
+              funcToRun.funcToCall,
+              funcToRun.millis,
+              true);
+        }
+      } catch(e) {
+      }
+    }
+    this.runFunctionsWithinRange(oldMillis, nowMillis);
+  }
+};
+
+jasmine.FakeTimer.prototype.scheduleFunction = function(timeoutKey, funcToCall, millis, recurring) {
+  this.scheduledFunctions[timeoutKey] = {
+    runAtMillis: this.nowMillis + millis,
+    funcToCall: funcToCall,
+    recurring: recurring,
+    timeoutKey: timeoutKey,
+    millis: millis
+  };
+};
+
+/**
+ * @namespace
+ */
+jasmine.Clock = {
+  defaultFakeTimer: new jasmine.FakeTimer(),
+
+  reset: function() {
+    jasmine.Clock.assertInstalled();
+    jasmine.Clock.defaultFakeTimer.reset();
+  },
+
+  tick: function(millis) {
+    jasmine.Clock.assertInstalled();
+    jasmine.Clock.defaultFakeTimer.tick(millis);
+  },
+
+  runFunctionsWithinRange: function(oldMillis, nowMillis) {
+    jasmine.Clock.defaultFakeTimer.runFunctionsWithinRange(oldMillis, nowMillis);
+  },
+
+  scheduleFunction: function(timeoutKey, funcToCall, millis, recurring) {
+    jasmine.Clock.defaultFakeTimer.scheduleFunction(timeoutKey, funcToCall, millis, recurring);
+  },
+
+  useMock: function() {
+    if (!jasmine.Clock.isInstalled()) {
+      var spec = jasmine.getEnv().currentSpec;
+      spec.after(jasmine.Clock.uninstallMock);
+
+      jasmine.Clock.installMock();
+    }
+  },
+
+  installMock: function() {
+    jasmine.Clock.installed = jasmine.Clock.defaultFakeTimer;
+  },
+
+  uninstallMock: function() {
+    jasmine.Clock.assertInstalled();
+    jasmine.Clock.installed = jasmine.Clock.real;
+  },
+
+  real: {
+    setTimeout: jasmine.getGlobal().setTimeout,
+    clearTimeout: jasmine.getGlobal().clearTimeout,
+    setInterval: jasmine.getGlobal().setInterval,
+    clearInterval: jasmine.getGlobal().clearInterval
+  },
+
+  assertInstalled: function() {
+    if (!jasmine.Clock.isInstalled()) {
+      throw new Error("Mock clock is not installed, use jasmine.Clock.useMock()");
+    }
+  },
+
+  isInstalled: function() {
+    return jasmine.Clock.installed == jasmine.Clock.defaultFakeTimer;
+  },
+
+  installed: null
+};
+jasmine.Clock.installed = jasmine.Clock.real;
+
+//else for IE support
+jasmine.getGlobal().setTimeout = function(funcToCall, millis) {
+  if (jasmine.Clock.installed.setTimeout.apply) {
+    return jasmine.Clock.installed.setTimeout.apply(this, arguments);
+  } else {
+    return jasmine.Clock.installed.setTimeout(funcToCall, millis);
+  }
+};
+
+jasmine.getGlobal().setInterval = function(funcToCall, millis) {
+  if (jasmine.Clock.installed.setInterval.apply) {
+    return jasmine.Clock.installed.setInterval.apply(this, arguments);
+  } else {
+    return jasmine.Clock.installed.setInterval(funcToCall, millis);
+  }
+};
+
+jasmine.getGlobal().clearTimeout = function(timeoutKey) {
+  if (jasmine.Clock.installed.clearTimeout.apply) {
+    return jasmine.Clock.installed.clearTimeout.apply(this, arguments);
+  } else {
+    return jasmine.Clock.installed.clearTimeout(timeoutKey);
+  }
+};
+
+jasmine.getGlobal().clearInterval = function(timeoutKey) {
+  if (jasmine.Clock.installed.clearTimeout.apply) {
+    return jasmine.Clock.installed.clearInterval.apply(this, arguments);
+  } else {
+    return jasmine.Clock.installed.clearInterval(timeoutKey);
+  }
+};
+
+/**
+ * @constructor
+ */
+jasmine.MultiReporter = function() {
+  this.subReporters_ = [];
+};
+jasmine.util.inherit(jasmine.MultiReporter, jasmine.Reporter);
+
+jasmine.MultiReporter.prototype.addReporter = function(reporter) {
+  this.subReporters_.push(reporter);
+};
+
+(function() {
+  var functionNames = [
+    "reportRunnerStarting",
+    "reportRunnerResults",
+    "reportSuiteResults",
+    "reportSpecStarting",
+    "reportSpecResults",
+    "log"
+  ];
+  for (var i = 0; i < functionNames.length; i++) {
+    var functionName = functionNames[i];
+    jasmine.MultiReporter.prototype[functionName] = (function(functionName) {
+      return function() {
+        for (var j = 0; j < this.subReporters_.length; j++) {
+          var subReporter = this.subReporters_[j];
+          if (subReporter[functionName]) {
+            subReporter[functionName].apply(subReporter, arguments);
+          }
+        }
+      };
+    })(functionName);
+  }
+})();
+/**
+ * Holds results for a set of Jasmine spec. Allows for the results array to hold another jasmine.NestedResults
+ *
+ * @constructor
+ */
+jasmine.NestedResults = function() {
+  /**
+   * The total count of results
+   */
+  this.totalCount = 0;
+  /**
+   * Number of passed results
+   */
+  this.passedCount = 0;
+  /**
+   * Number of failed results
+   */
+  this.failedCount = 0;
+  /**
+   * Was this suite/spec skipped?
+   */
+  this.skipped = false;
+  /**
+   * @ignore
+   */
+  this.items_ = [];
+};
+
+/**
+ * Roll up the result counts.
+ *
+ * @param result
+ */
+jasmine.NestedResults.prototype.rollupCounts = function(result) {
+  this.totalCount += result.totalCount;
+  this.passedCount += result.passedCount;
+  this.failedCount += result.failedCount;
+};
+
+/**
+ * Adds a log message.
+ * @param values Array of message parts which will be concatenated later.
+ */
+jasmine.NestedResults.prototype.log = function(values) {
+  this.items_.push(new jasmine.MessageResult(values));
+};
+
+/**
+ * Getter for the results: message & results.
+ */
+jasmine.NestedResults.prototype.getItems = function() {
+  return this.items_;
+};
+
+/**
+ * Adds a result, tracking counts (total, passed, & failed)
+ * @param {jasmine.ExpectationResult|jasmine.NestedResults} result
+ */
+jasmine.NestedResults.prototype.addResult = function(result) {
+  if (result.type != 'log') {
+    if (result.items_) {
+      this.rollupCounts(result);
+    } else {
+      this.totalCount++;
+      if (result.passed()) {
+        this.passedCount++;
+      } else {
+        this.failedCount++;
+      }
+    }
+  }
+  this.items_.push(result);
+};
+
+/**
+ * @returns {Boolean} True if <b>everything</b> below passed
+ */
+jasmine.NestedResults.prototype.passed = function() {
+  return this.passedCount === this.totalCount;
+};
+/**
+ * Base class for pretty printing for expectation results.
+ */
+jasmine.PrettyPrinter = function() {
+  this.ppNestLevel_ = 0;
+};
+
+/**
+ * Formats a value in a nice, human-readable string.
+ *
+ * @param value
+ */
+jasmine.PrettyPrinter.prototype.format = function(value) {
+  this.ppNestLevel_++;
+  try {
+    if (value === jasmine.undefined) {
+      this.emitScalar('undefined');
+    } else if (value === null) {
+      this.emitScalar('null');
+    } else if (value === jasmine.getGlobal()) {
+      this.emitScalar('<global>');
+    } else if (value.jasmineToString) {
+      this.emitScalar(value.jasmineToString());
+    } else if (typeof value === 'string') {
+      this.emitString(value);
+    } else if (jasmine.isSpy(value)) {
+      this.emitScalar("spy on " + value.identity);
+    } else if (value instanceof RegExp) {
+      this.emitScalar(value.toString());
+    } else if (typeof value === 'function') {
+      this.emitScalar('Function');
+    } else if (typeof value.nodeType === 'number') {
+      this.emitScalar('HTMLNode');
+    } else if (value instanceof Date) {
+      this.emitScalar('Date(' + value + ')');
+    } else if (value.__Jasmine_been_here_before__) {
+      this.emitScalar('<circular reference: ' + (jasmine.isArray_(value) ? 'Array' : 'Object') + '>');
+    } else if (jasmine.isArray_(value) || typeof value == 'object') {
+      value.__Jasmine_been_here_before__ = true;
+      if (jasmine.isArray_(value)) {
+        this.emitArray(value);
+      } else {
+        this.emitObject(value);
+      }
+      delete value.__Jasmine_been_here_before__;
+    } else {
+      this.emitScalar(value.toString());
+    }
+  } finally {
+    this.ppNestLevel_--;
+  }
+};
+
+jasmine.PrettyPrinter.prototype.iterateObject = function(obj, fn) {
+  for (var property in obj) {
+    if (!obj.hasOwnProperty(property)) continue;
+    if (property == '__Jasmine_been_here_before__') continue;
+    fn(property, obj.__lookupGetter__ ? (obj.__lookupGetter__(property) !== jasmine.undefined && 
+                                         obj.__lookupGetter__(property) !== null) : false);
+  }
+};
+
+jasmine.PrettyPrinter.prototype.emitArray = jasmine.unimplementedMethod_;
+jasmine.PrettyPrinter.prototype.emitObject = jasmine.unimplementedMethod_;
+jasmine.PrettyPrinter.prototype.emitScalar = jasmine.unimplementedMethod_;
+jasmine.PrettyPrinter.prototype.emitString = jasmine.unimplementedMethod_;
+
+jasmine.StringPrettyPrinter = function() {
+  jasmine.PrettyPrinter.call(this);
+
+  this.string = '';
+};
+jasmine.util.inherit(jasmine.StringPrettyPrinter, jasmine.PrettyPrinter);
+
+jasmine.StringPrettyPrinter.prototype.emitScalar = function(value) {
+  this.append(value);
+};
+
+jasmine.StringPrettyPrinter.prototype.emitString = function(value) {
+  this.append("'" + value + "'");
+};
+
+jasmine.StringPrettyPrinter.prototype.emitArray = function(array) {
+  if (this.ppNestLevel_ > jasmine.MAX_PRETTY_PRINT_DEPTH) {
+    this.append("Array");
+    return;
+  }
+
+  this.append('[ ');
+  for (var i = 0; i < array.length; i++) {
+    if (i > 0) {
+      this.append(', ');
+    }
+    this.format(array[i]);
+  }
+  this.append(' ]');
+};
+
+jasmine.StringPrettyPrinter.prototype.emitObject = function(obj) {
+  if (this.ppNestLevel_ > jasmine.MAX_PRETTY_PRINT_DEPTH) {
+    this.append("Object");
+    return;
+  }
+
+  var self = this;
+  this.append('{ ');
+  var first = true;
+
+  this.iterateObject(obj, function(property, isGetter) {
+    if (first) {
+      first = false;
+    } else {
+      self.append(', ');
+    }
+
+    self.append(property);
+    self.append(' : ');
+    if (isGetter) {
+      self.append('<getter>');
+    } else {
+      self.format(obj[property]);
+    }
+  });
+
+  this.append(' }');
+};
+
+jasmine.StringPrettyPrinter.prototype.append = function(value) {
+  this.string += value;
+};
+jasmine.Queue = function(env) {
+  this.env = env;
+
+  // parallel to blocks. each true value in this array means the block will
+  // get executed even if we abort
+  this.ensured = [];
+  this.blocks = [];
+  this.running = false;
+  this.index = 0;
+  this.offset = 0;
+  this.abort = false;
+};
+
+jasmine.Queue.prototype.addBefore = function(block, ensure) {
+  if (ensure === jasmine.undefined) {
+    ensure = false;
+  }
+
+  this.blocks.unshift(block);
+  this.ensured.unshift(ensure);
+};
+
+jasmine.Queue.prototype.add = function(block, ensure) {
+  if (ensure === jasmine.undefined) {
+    ensure = false;
+  }
+
+  this.blocks.push(block);
+  this.ensured.push(ensure);
+};
+
+jasmine.Queue.prototype.insertNext = function(block, ensure) {
+  if (ensure === jasmine.undefined) {
+    ensure = false;
+  }
+
+  this.ensured.splice((this.index + this.offset + 1), 0, ensure);
+  this.blocks.splice((this.index + this.offset + 1), 0, block);
+  this.offset++;
+};
+
+jasmine.Queue.prototype.start = function(onComplete) {
+  this.running = true;
+  this.onComplete = onComplete;
+  this.next_();
+};
+
+jasmine.Queue.prototype.isRunning = function() {
+  return this.running;
+};
+
+jasmine.Queue.LOOP_DONT_RECURSE = true;
+
+jasmine.Queue.prototype.next_ = function() {
+  var self = this;
+  var goAgain = true;
+
+  while (goAgain) {
+    goAgain = false;
+    
+    if (self.index < self.blocks.length && !(this.abort && !this.ensured[self.index])) {
+      var calledSynchronously = true;
+      var completedSynchronously = false;
+
+      var onComplete = function () {
+        if (jasmine.Queue.LOOP_DONT_RECURSE && calledSynchronously) {
+          completedSynchronously = true;
+          return;
+        }
+
+        if (self.blocks[self.index].abort) {
+          self.abort = true;
+        }
+
+        self.offset = 0;
+        self.index++;
+
+        var now = new Date().getTime();
+        if (self.env.updateInterval && now - self.env.lastUpdate > self.env.updateInterval) {
+          self.env.lastUpdate = now;
+          self.env.setTimeout(function() {
+            self.next_();
+          }, 0);
+        } else {
+          if (jasmine.Queue.LOOP_DONT_RECURSE && completedSynchronously) {
+            goAgain = true;
+          } else {
+            self.next_();
+          }
+        }
+      };
+      self.blocks[self.index].execute(onComplete);
+
+      calledSynchronously = false;
+      if (completedSynchronously) {
+        onComplete();
+      }
+      
+    } else {
+      self.running = false;
+      if (self.onComplete) {
+        self.onComplete();
+      }
+    }
+  }
+};
+
+jasmine.Queue.prototype.results = function() {
+  var results = new jasmine.NestedResults();
+  for (var i = 0; i < this.blocks.length; i++) {
+    if (this.blocks[i].results) {
+      results.addResult(this.blocks[i].results());
+    }
+  }
+  return results;
+};
+
+
+/**
+ * Runner
+ *
+ * @constructor
+ * @param {jasmine.Env} env
+ */
+jasmine.Runner = function(env) {
+  var self = this;
+  self.env = env;
+  self.queue = new jasmine.Queue(env);
+  self.before_ = [];
+  self.after_ = [];
+  self.suites_ = [];
+};
+
+jasmine.Runner.prototype.execute = function() {
+  var self = this;
+  if (self.env.reporter.reportRunnerStarting) {
+    self.env.reporter.reportRunnerStarting(this);
+  }
+  self.queue.start(function () {
+    self.finishCallback();
+  });
+};
+
+jasmine.Runner.prototype.beforeEach = function(beforeEachFunction) {
+  beforeEachFunction.typeName = 'beforeEach';
+  this.before_.splice(0,0,beforeEachFunction);
+};
+
+jasmine.Runner.prototype.afterEach = function(afterEachFunction) {
+  afterEachFunction.typeName = 'afterEach';
+  this.after_.splice(0,0,afterEachFunction);
+};
+
+
+jasmine.Runner.prototype.finishCallback = function() {
+  this.env.reporter.reportRunnerResults(this);
+};
+
+jasmine.Runner.prototype.addSuite = function(suite) {
+  this.suites_.push(suite);
+};
+
+jasmine.Runner.prototype.add = function(block) {
+  if (block instanceof jasmine.Suite) {
+    this.addSuite(block);
+  }
+  this.queue.add(block);
+};
+
+jasmine.Runner.prototype.specs = function () {
+  var suites = this.suites();
+  var specs = [];
+  for (var i = 0; i < suites.length; i++) {
+    specs = specs.concat(suites[i].specs());
+  }
+  return specs;
+};
+
+jasmine.Runner.prototype.suites = function() {
+  return this.suites_;
+};
+
+jasmine.Runner.prototype.topLevelSuites = function() {
+  var topLevelSuites = [];
+  for (var i = 0; i < this.suites_.length; i++) {
+    if (!this.suites_[i].parentSuite) {
+      topLevelSuites.push(this.suites_[i]);
+    }
+  }
+  return topLevelSuites;
+};
+
+jasmine.Runner.prototype.results = function() {
+  return this.queue.results();
+};
+/**
+ * Internal representation of a Jasmine specification, or test.
+ *
+ * @constructor
+ * @param {jasmine.Env} env
+ * @param {jasmine.Suite} suite
+ * @param {String} description
+ */
+jasmine.Spec = function(env, suite, description) {
+  if (!env) {
+    throw new Error('jasmine.Env() required');
+  }
+  if (!suite) {
+    throw new Error('jasmine.Suite() required');
+  }
+  var spec = this;
+  spec.id = env.nextSpecId ? env.nextSpecId() : null;
+  spec.env = env;
+  spec.suite = suite;
+  spec.description = description;
+  spec.queue = new jasmine.Queue(env);
+
+  spec.afterCallbacks = [];
+  spec.spies_ = [];
+
+  spec.results_ = new jasmine.NestedResults();
+  spec.results_.description = description;
+  spec.matchersClass = null;
+};
+
+jasmine.Spec.prototype.getFullName = function() {
+  return this.suite.getFullName() + ' ' + this.description + '.';
+};
+
+
+jasmine.Spec.prototype.results = function() {
+  return this.results_;
+};
+
+/**
+ * All parameters are pretty-printed and concatenated together, then written to the spec's output.
+ *
+ * Be careful not to leave calls to <code>jasmine.log</code> in production code.
+ */
+jasmine.Spec.prototype.log = function() {
+  return this.results_.log(arguments);
+};
+
+jasmine.Spec.prototype.runs = function (func) {
+  var block = new jasmine.Block(this.env, func, this);
+  this.addToQueue(block);
+  return this;
+};
+
+jasmine.Spec.prototype.addToQueue = function (block) {
+  if (this.queue.isRunning()) {
+    this.queue.insertNext(block);
+  } else {
+    this.queue.add(block);
+  }
+};
+
+/**
+ * @param {jasmine.ExpectationResult} result
+ */
+jasmine.Spec.prototype.addMatcherResult = function(result) {
+  this.results_.addResult(result);
+};
+
+jasmine.Spec.prototype.expect = function(actual) {
+  var positive = new (this.getMatchersClass_())(this.env, actual, this);
+  positive.not = new (this.getMatchersClass_())(this.env, actual, this, true);
+  return positive;
+};
+
+/**
+ * Waits a fixed time period before moving to the next block.
+ *
+ * @deprecated Use waitsFor() instead
+ * @param {Number} timeout milliseconds to wait
+ */
+jasmine.Spec.prototype.waits = function(timeout) {
+  var waitsFunc = new jasmine.WaitsBlock(this.env, timeout, this);
+  this.addToQueue(waitsFunc);
+  return this;
+};
+
+/**
+ * Waits for the latchFunction to return true before proceeding to the next block.
+ *
+ * @param {Function} latchFunction
+ * @param {String} optional_timeoutMessage
+ * @param {Number} optional_timeout
+ */
+jasmine.Spec.prototype.waitsFor = function(latchFunction, optional_timeoutMessage, optional_timeout) {
+  var latchFunction_ = null;
+  var optional_timeoutMessage_ = null;
+  var optional_timeout_ = null;
+
+  for (var i = 0; i < arguments.length; i++) {
+    var arg = arguments[i];
+    switch (typeof arg) {
+      case 'function':
+        latchFunction_ = arg;
+        break;
+      case 'string':
+        optional_timeoutMessage_ = arg;
+        break;
+      case 'number':
+        optional_timeout_ = arg;
+        break;
+    }
+  }
+
+  var waitsForFunc = new jasmine.WaitsForBlock(this.env, optional_timeout_, latchFunction_, optional_timeoutMessage_, this);
+  this.addToQueue(waitsForFunc);
+  return this;
+};
+
+jasmine.Spec.prototype.fail = function (e) {
+  var expectationResult = new jasmine.ExpectationResult({
+    passed: false,
+    message: e ? jasmine.util.formatException(e) : 'Exception',
+    trace: { stack: e.stack }
+  });
+  this.results_.addResult(expectationResult);
+};
+
+jasmine.Spec.prototype.getMatchersClass_ = function() {
+  return this.matchersClass || this.env.matchersClass;
+};
+
+jasmine.Spec.prototype.addMatchers = function(matchersPrototype) {
+  var parent = this.getMatchersClass_();
+  var newMatchersClass = function() {
+    parent.apply(this, arguments);
+  };
+  jasmine.util.inherit(newMatchersClass, parent);
+  jasmine.Matchers.wrapInto_(matchersPrototype, newMatchersClass);
+  this.matchersClass = newMatchersClass;
+};
+
+jasmine.Spec.prototype.finishCallback = function() {
+  this.env.reporter.reportSpecResults(this);
+};
+
+jasmine.Spec.prototype.finish = function(onComplete) {
+  this.removeAllSpies();
+  this.finishCallback();
+  if (onComplete) {
+    onComplete();
+  }
+};
+
+jasmine.Spec.prototype.after = function(doAfter) {
+  if (this.queue.isRunning()) {
+    this.queue.add(new jasmine.Block(this.env, doAfter, this), true);
+  } else {
+    this.afterCallbacks.unshift(doAfter);
+  }
+};
+
+jasmine.Spec.prototype.execute = function(onComplete) {
+  var spec = this;
+  if (!spec.env.specFilter(spec)) {
+    spec.results_.skipped = true;
+    spec.finish(onComplete);
+    return;
+  }
+
+  this.env.reporter.reportSpecStarting(this);
+
+  spec.env.currentSpec = spec;
+
+  spec.addBeforesAndAftersToQueue();
+
+  spec.queue.start(function () {
+    spec.finish(onComplete);
+  });
+};
+
+jasmine.Spec.prototype.addBeforesAndAftersToQueue = function() {
+  var runner = this.env.currentRunner();
+  var i;
+
+  for (var suite = this.suite; suite; suite = suite.parentSuite) {
+    for (i = 0; i < suite.before_.length; i++) {
+      this.queue.addBefore(new jasmine.Block(this.env, suite.before_[i], this));
+    }
+  }
+  for (i = 0; i < runner.before_.length; i++) {
+    this.queue.addBefore(new jasmine.Block(this.env, runner.before_[i], this));
+  }
+  for (i = 0; i < this.afterCallbacks.length; i++) {
+    this.queue.add(new jasmine.Block(this.env, this.afterCallbacks[i], this), true);
+  }
+  for (suite = this.suite; suite; suite = suite.parentSuite) {
+    for (i = 0; i < suite.after_.length; i++) {
+      this.queue.add(new jasmine.Block(this.env, suite.after_[i], this), true);
+    }
+  }
+  for (i = 0; i < runner.after_.length; i++) {
+    this.queue.add(new jasmine.Block(this.env, runner.after_[i], this), true);
+  }
+};
+
+jasmine.Spec.prototype.explodes = function() {
+  throw 'explodes function should not have been called';
+};
+
+jasmine.Spec.prototype.spyOn = function(obj, methodName, ignoreMethodDoesntExist) {
+  if (obj == jasmine.undefined) {
+    throw "spyOn could not find an object to spy upon for " + methodName + "()";
+  }
+
+  if (!ignoreMethodDoesntExist && obj[methodName] === jasmine.undefined) {
+    throw methodName + '() method does not exist';
+  }
+
+  if (!ignoreMethodDoesntExist && obj[methodName] && obj[methodName].isSpy) {
+    throw new Error(methodName + ' has already been spied upon');
+  }
+
+  var spyObj = jasmine.createSpy(methodName);
+
+  this.spies_.push(spyObj);
+  spyObj.baseObj = obj;
+  spyObj.methodName = methodName;
+  spyObj.originalValue = obj[methodName];
+
+  obj[methodName] = spyObj;
+
+  return spyObj;
+};
+
+jasmine.Spec.prototype.removeAllSpies = function() {
+  for (var i = 0; i < this.spies_.length; i++) {
+    var spy = this.spies_[i];
+    spy.baseObj[spy.methodName] = spy.originalValue;
+  }
+  this.spies_ = [];
+};
+
+/**
+ * Internal representation of a Jasmine suite.
+ *
+ * @constructor
+ * @param {jasmine.Env} env
+ * @param {String} description
+ * @param {Function} specDefinitions
+ * @param {jasmine.Suite} parentSuite
+ */
+jasmine.Suite = function(env, description, specDefinitions, parentSuite) {
+  var self = this;
+  self.id = env.nextSuiteId ? env.nextSuiteId() : null;
+  self.description = description;
+  self.queue = new jasmine.Queue(env);
+  self.parentSuite = parentSuite;
+  self.env = env;
+  self.before_ = [];
+  self.after_ = [];
+  self.children_ = [];
+  self.suites_ = [];
+  self.specs_ = [];
+};
+
+jasmine.Suite.prototype.getFullName = function() {
+  var fullName = this.description;
+  for (var parentSuite = this.parentSuite; parentSuite; parentSuite = parentSuite.parentSuite) {
+    fullName = parentSuite.description + ' ' + fullName;
+  }
+  return fullName;
+};
+
+jasmine.Suite.prototype.finish = function(onComplete) {
+  this.env.reporter.reportSuiteResults(this);
+  this.finished = true;
+  if (typeof(onComplete) == 'function') {
+    onComplete();
+  }
+};
+
+jasmine.Suite.prototype.beforeEach = function(beforeEachFunction) {
+  beforeEachFunction.typeName = 'beforeEach';
+  this.before_.unshift(beforeEachFunction);
+};
+
+jasmine.Suite.prototype.afterEach = function(afterEachFunction) {
+  afterEachFunction.typeName = 'afterEach';
+  this.after_.unshift(afterEachFunction);
+};
+
+jasmine.Suite.prototype.results = function() {
+  return this.queue.results();
+};
+
+jasmine.Suite.prototype.add = function(suiteOrSpec) {
+  this.children_.push(suiteOrSpec);
+  if (suiteOrSpec instanceof jasmine.Suite) {
+    this.suites_.push(suiteOrSpec);
+    this.env.currentRunner().addSuite(suiteOrSpec);
+  } else {
+    this.specs_.push(suiteOrSpec);
+  }
+  this.queue.add(suiteOrSpec);
+};
+
+jasmine.Suite.prototype.specs = function() {
+  return this.specs_;
+};
+
+jasmine.Suite.prototype.suites = function() {
+  return this.suites_;
+};
+
+jasmine.Suite.prototype.children = function() {
+  return this.children_;
+};
+
+jasmine.Suite.prototype.execute = function(onComplete) {
+  var self = this;
+  this.queue.start(function () {
+    self.finish(onComplete);
+  });
+};
+jasmine.WaitsBlock = function(env, timeout, spec) {
+  this.timeout = timeout;
+  jasmine.Block.call(this, env, null, spec);
+};
+
+jasmine.util.inherit(jasmine.WaitsBlock, jasmine.Block);
+
+jasmine.WaitsBlock.prototype.execute = function (onComplete) {
+  if (jasmine.VERBOSE) {
+    this.env.reporter.log('>> Jasmine waiting for ' + this.timeout + ' ms...');
+  }
+  this.env.setTimeout(function () {
+    onComplete();
+  }, this.timeout);
+};
+/**
+ * A block which waits for some condition to become true, with timeout.
+ *
+ * @constructor
+ * @extends jasmine.Block
+ * @param {jasmine.Env} env The Jasmine environment.
+ * @param {Number} timeout The maximum time in milliseconds to wait for the condition to become true.
+ * @param {Function} latchFunction A function which returns true when the desired condition has been met.
+ * @param {String} message The message to display if the desired condition hasn't been met within the given time period.
+ * @param {jasmine.Spec} spec The Jasmine spec.
+ */
+jasmine.WaitsForBlock = function(env, timeout, latchFunction, message, spec) {
+  this.timeout = timeout || env.defaultTimeoutInterval;
+  this.latchFunction = latchFunction;
+  this.message = message;
+  this.totalTimeSpentWaitingForLatch = 0;
+  jasmine.Block.call(this, env, null, spec);
+};
+jasmine.util.inherit(jasmine.WaitsForBlock, jasmine.Block);
+
+jasmine.WaitsForBlock.TIMEOUT_INCREMENT = 10;
+
+jasmine.WaitsForBlock.prototype.execute = function(onComplete) {
+  if (jasmine.VERBOSE) {
+    this.env.reporter.log('>> Jasmine waiting for ' + (this.message || 'something to happen'));
+  }
+  var latchFunctionResult;
+  try {
+    latchFunctionResult = this.latchFunction.apply(this.spec);
+  } catch (e) {
+    this.spec.fail(e);
+    onComplete();
+    return;
+  }
+
+  if (latchFunctionResult) {
+    onComplete();
+  } else if (this.totalTimeSpentWaitingForLatch >= this.timeout) {
+    var message = 'timed out after ' + this.timeout + ' msec waiting for ' + (this.message || 'something to happen');
+    this.spec.fail({
+      name: 'timeout',
+      message: message
+    });
+
+    this.abort = true;
+    onComplete();
+  } else {
+    this.totalTimeSpentWaitingForLatch += jasmine.WaitsForBlock.TIMEOUT_INCREMENT;
+    var self = this;
+    this.env.setTimeout(function() {
+      self.execute(onComplete);
+    }, jasmine.WaitsForBlock.TIMEOUT_INCREMENT);
+  }
+};
+
+jasmine.version_= {
+  "major": 1,
+  "minor": 3,
+  "build": 1,
+  "revision": 1354556913
+};
Index: tests/functional/lib/jquery.js
===================================================================
--- tests/functional/lib/jquery.js	(revision 1602)
+++ tests/functional/lib/jquery.js	(revision 1602)
@@ -0,0 +1,9555 @@
+/*!
+ * jQuery JavaScript Library v1.9.0
+ * http://jquery.com/
+ *
+ * Includes Sizzle.js
+ * http://sizzlejs.com/
+ *
+ * Copyright 2005, 2012 jQuery Foundation, Inc. and other contributors
+ * Released under the MIT license
+ * http://jquery.org/license
+ *
+ * Date: 2013-1-14
+ */
+(function( window, undefined ) {
+"use strict";
+var
+	// A central reference to the root jQuery(document)
+	rootjQuery,
+
+	// The deferred used on DOM ready
+	readyList,
+
+	// Use the correct document accordingly with window argument (sandbox)
+	document = window.document,
+	location = window.location,
+
+	// Map over jQuery in case of overwrite
+	_jQuery = window.jQuery,
+
+	// Map over the $ in case of overwrite
+	_$ = window.$,
+
+	// [[Class]] -> type pairs
+	class2type = {},
+
+	// List of deleted data cache ids, so we can reuse them
+	core_deletedIds = [],
+
+	core_version = "1.9.0",
+
+	// Save a reference to some core methods
+	core_concat = core_deletedIds.concat,
+	core_push = core_deletedIds.push,
+	core_slice = core_deletedIds.slice,
+	core_indexOf = core_deletedIds.indexOf,
+	core_toString = class2type.toString,
+	core_hasOwn = class2type.hasOwnProperty,
+	core_trim = core_version.trim,
+
+	// Define a local copy of jQuery
+	jQuery = function( selector, context ) {
+		// The jQuery object is actually just the init constructor 'enhanced'
+		return new jQuery.fn.init( selector, context, rootjQuery );
+	},
+
+	// Used for matching numbers
+	core_pnum = /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,
+
+	// Used for splitting on whitespace
+	core_rnotwhite = /\S+/g,
+
+	// Make sure we trim BOM and NBSP (here's looking at you, Safari 5.0 and IE)
+	rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,
+
+	// A simple way to check for HTML strings
+	// Prioritize #id over <tag> to avoid XSS via location.hash (#9521)
+	// Strict HTML recognition (#11290: must start with <)
+	rquickExpr = /^(?:(<[\w\W]+>)[^>]*|#([\w-]*))$/,
+
+	// Match a standalone tag
+	rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>|)$/,
+
+	// JSON RegExp
+	rvalidchars = /^[\],:{}\s]*$/,
+	rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g,
+	rvalidescape = /\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,
+	rvalidtokens = /"[^"\\\r\n]*"|true|false|null|-?(?:\d+\.|)\d+(?:[eE][+-]?\d+|)/g,
+
+	// Matches dashed string for camelizing
+	rmsPrefix = /^-ms-/,
+	rdashAlpha = /-([\da-z])/gi,
+
+	// Used by jQuery.camelCase as callback to replace()
+	fcamelCase = function( all, letter ) {
+		return letter.toUpperCase();
+	},
+
+	// The ready event handler and self cleanup method
+	DOMContentLoaded = function() {
+		if ( document.addEventListener ) {
+			document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false );
+			jQuery.ready();
+		} else if ( document.readyState === "complete" ) {
+			// we're here because readyState === "complete" in oldIE
+			// which is good enough for us to call the dom ready!
+			document.detachEvent( "onreadystatechange", DOMContentLoaded );
+			jQuery.ready();
+		}
+	};
+
+jQuery.fn = jQuery.prototype = {
+	// The current version of jQuery being used
+	jquery: core_version,
+
+	constructor: jQuery,
+	init: function( selector, context, rootjQuery ) {
+		var match, elem;
+
+		// HANDLE: $(""), $(null), $(undefined), $(false)
+		if ( !selector ) {
+			return this;
+		}
+
+		// Handle HTML strings
+		if ( typeof selector === "string" ) {
+			if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) {
+				// Assume that strings that start and end with <> are HTML and skip the regex check
+				match = [ null, selector, null ];
+
+			} else {
+				match = rquickExpr.exec( selector );
+			}
+
+			// Match html or make sure no context is specified for #id
+			if ( match && (match[1] || !context) ) {
+
+				// HANDLE: $(html) -> $(array)
+				if ( match[1] ) {
+					context = context instanceof jQuery ? context[0] : context;
+
+					// scripts is true for back-compat
+					jQuery.merge( this, jQuery.parseHTML(
+						match[1],
+						context && context.nodeType ? context.ownerDocument || context : document,
+						true
+					) );
+
+					// HANDLE: $(html, props)
+					if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) {
+						for ( match in context ) {
+							// Properties of context are called as methods if possible
+							if ( jQuery.isFunction( this[ match ] ) ) {
+								this[ match ]( context[ match ] );
+
+							// ...and otherwise set as attributes
+							} else {
+								this.attr( match, context[ match ] );
+							}
+						}
+					}
+
+					return this;
+
+				// HANDLE: $(#id)
+				} else {
+					elem = document.getElementById( match[2] );
+
+					// Check parentNode to catch when Blackberry 4.6 returns
+					// nodes that are no longer in the document #6963
+					if ( elem && elem.parentNode ) {
+						// Handle the case where IE and Opera return items
+						// by name instead of ID
+						if ( elem.id !== match[2] ) {
+							return rootjQuery.find( selector );
+						}
+
+						// Otherwise, we inject the element directly into the jQuery object
+						this.length = 1;
+						this[0] = elem;
+					}
+
+					this.context = document;
+					this.selector = selector;
+					return this;
+				}
+
+			// HANDLE: $(expr, $(...))
+			} else if ( !context || context.jquery ) {
+				return ( context || rootjQuery ).find( selector );
+
+			// HANDLE: $(expr, context)
+			// (which is just equivalent to: $(context).find(expr)
+			} else {
+				return this.constructor( context ).find( selector );
+			}
+
+		// HANDLE: $(DOMElement)
+		} else if ( selector.nodeType ) {
+			this.context = this[0] = selector;
+			this.length = 1;
+			return this;
+
+		// HANDLE: $(function)
+		// Shortcut for document ready
+		} else if ( jQuery.isFunction( selector ) ) {
+			return rootjQuery.ready( selector );
+		}
+
+		if ( selector.selector !== undefined ) {
+			this.selector = selector.selector;
+			this.context = selector.context;
+		}
+
+		return jQuery.makeArray( selector, this );
+	},
+
+	// Start with an empty selector
+	selector: "",
+
+	// The default length of a jQuery object is 0
+	length: 0,
+
+	// The number of elements contained in the matched element set
+	size: function() {
+		return this.length;
+	},
+
+	toArray: function() {
+		return core_slice.call( this );
+	},
+
+	// Get the Nth element in the matched element set OR
+	// Get the whole matched element set as a clean array
+	get: function( num ) {
+		return num == null ?
+
+			// Return a 'clean' array
+			this.toArray() :
+
+			// Return just the object
+			( num < 0 ? this[ this.length + num ] : this[ num ] );
+	},
+
+	// Take an array of elements and push it onto the stack
+	// (returning the new matched element set)
+	pushStack: function( elems ) {
+
+		// Build a new jQuery matched element set
+		var ret = jQuery.merge( this.constructor(), elems );
+
+		// Add the old object onto the stack (as a reference)
+		ret.prevObject = this;
+		ret.context = this.context;
+
+		// Return the newly-formed element set
+		return ret;
+	},
+
+	// Execute a callback for every element in the matched set.
+	// (You can seed the arguments with an array of args, but this is
+	// only used internally.)
+	each: function( callback, args ) {
+		return jQuery.each( this, callback, args );
+	},
+
+	ready: function( fn ) {
+		// Add the callback
+		jQuery.ready.promise().done( fn );
+
+		return this;
+	},
+
+	slice: function() {
+		return this.pushStack( core_slice.apply( this, arguments ) );
+	},
+
+	first: function() {
+		return this.eq( 0 );
+	},
+
+	last: function() {
+		return this.eq( -1 );
+	},
+
+	eq: function( i ) {
+		var len = this.length,
+			j = +i + ( i < 0 ? len : 0 );
+		return this.pushStack( j >= 0 && j < len ? [ this[j] ] : [] );
+	},
+
+	map: function( callback ) {
+		return this.pushStack( jQuery.map(this, function( elem, i ) {
+			return callback.call( elem, i, elem );
+		}));
+	},
+
+	end: function() {
+		return this.prevObject || this.constructor(null);
+	},
+
+	// For internal use only.
+	// Behaves like an Array's method, not like a jQuery method.
+	push: core_push,
+	sort: [].sort,
+	splice: [].splice
+};
+
+// Give the init function the jQuery prototype for later instantiation
+jQuery.fn.init.prototype = jQuery.fn;
+
+jQuery.extend = jQuery.fn.extend = function() {
+	var options, name, src, copy, copyIsArray, clone,
+		target = arguments[0] || {},
+		i = 1,
+		length = arguments.length,
+		deep = false;
+
+	// Handle a deep copy situation
+	if ( typeof target === "boolean" ) {
+		deep = target;
+		target = arguments[1] || {};
+		// skip the boolean and the target
+		i = 2;
+	}
+
+	// Handle case when target is a string or something (possible in deep copy)
+	if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
+		target = {};
+	}
+
+	// extend jQuery itself if only one argument is passed
+	if ( length === i ) {
+		target = this;
+		--i;
+	}
+
+	for ( ; i < length; i++ ) {
+		// Only deal with non-null/undefined values
+		if ( (options = arguments[ i ]) != null ) {
+			// Extend the base object
+			for ( name in options ) {
+				src = target[ name ];
+				copy = options[ name ];
+
+				// Prevent never-ending loop
+				if ( target === copy ) {
+					continue;
+				}
+
+				// Recurse if we're merging plain objects or arrays
+				if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
+					if ( copyIsArray ) {
+						copyIsArray = false;
+						clone = src && jQuery.isArray(src) ? src : [];
+
+					} else {
+						clone = src && jQuery.isPlainObject(src) ? src : {};
+					}
+
+					// Never move original objects, clone them
+					target[ name ] = jQuery.extend( deep, clone, copy );
+
+				// Don't bring in undefined values
+				} else if ( copy !== undefined ) {
+					target[ name ] = copy;
+				}
+			}
+		}
+	}
+
+	// Return the modified object
+	return target;
+};
+
+jQuery.extend({
+	noConflict: function( deep ) {
+		if ( window.$ === jQuery ) {
+			window.$ = _$;
+		}
+
+		if ( deep && window.jQuery === jQuery ) {
+			window.jQuery = _jQuery;
+		}
+
+		return jQuery;
+	},
+
+	// Is the DOM ready to be used? Set to true once it occurs.
+	isReady: false,
+
+	// A counter to track how many items to wait for before
+	// the ready event fires. See #6781
+	readyWait: 1,
+
+	// Hold (or release) the ready event
+	holdReady: function( hold ) {
+		if ( hold ) {
+			jQuery.readyWait++;
+		} else {
+			jQuery.ready( true );
+		}
+	},
+
+	// Handle when the DOM is ready
+	ready: function( wait ) {
+
+		// Abort if there are pending holds or we're already ready
+		if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) {
+			return;
+		}
+
+		// Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
+		if ( !document.body ) {
+			return setTimeout( jQuery.ready );
+		}
+
+		// Remember that the DOM is ready
+		jQuery.isReady = true;
+
+		// If a normal DOM Ready event fired, decrement, and wait if need be
+		if ( wait !== true && --jQuery.readyWait > 0 ) {
+			return;
+		}
+
+		// If there are functions bound, to execute
+		readyList.resolveWith( document, [ jQuery ] );
+
+		// Trigger any bound ready events
+		if ( jQuery.fn.trigger ) {
+			jQuery( document ).trigger("ready").off("ready");
+		}
+	},
+
+	// See test/unit/core.js for details concerning isFunction.
+	// Since version 1.3, DOM methods and functions like alert
+	// aren't supported. They return false on IE (#2968).
+	isFunction: function( obj ) {
+		return jQuery.type(obj) === "function";
+	},
+
+	isArray: Array.isArray || function( obj ) {
+		return jQuery.type(obj) === "array";
+	},
+
+	isWindow: function( obj ) {
+		return obj != null && obj == obj.window;
+	},
+
+	isNumeric: function( obj ) {
+		return !isNaN( parseFloat(obj) ) && isFinite( obj );
+	},
+
+	type: function( obj ) {
+		if ( obj == null ) {
+			return String( obj );
+		}
+		return typeof obj === "object" || typeof obj === "function" ?
+			class2type[ core_toString.call(obj) ] || "object" :
+			typeof obj;
+	},
+
+	isPlainObject: function( obj ) {
+		// Must be an Object.
+		// Because of IE, we also have to check the presence of the constructor property.
+		// Make sure that DOM nodes and window objects don't pass through, as well
+		if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) {
+			return false;
+		}
+
+		try {
+			// Not own constructor property must be Object
+			if ( obj.constructor &&
+				!core_hasOwn.call(obj, "constructor") &&
+				!core_hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) {
+				return false;
+			}
+		} catch ( e ) {
+			// IE8,9 Will throw exceptions on certain host objects #9897
+			return false;
+		}
+
+		// Own properties are enumerated firstly, so to speed up,
+		// if last one is own, then all properties are own.
+
+		var key;
+		for ( key in obj ) {}
+
+		return key === undefined || core_hasOwn.call( obj, key );
+	},
+
+	isEmptyObject: function( obj ) {
+		var name;
+		for ( name in obj ) {
+			return false;
+		}
+		return true;
+	},
+
+	error: function( msg ) {
+		throw new Error( msg );
+	},
+
+	// data: string of html
+	// context (optional): If specified, the fragment will be created in this context, defaults to document
+	// keepScripts (optional): If true, will include scripts passed in the html string
+	parseHTML: function( data, context, keepScripts ) {
+		if ( !data || typeof data !== "string" ) {
+			return null;
+		}
+		if ( typeof context === "boolean" ) {
+			keepScripts = context;
+			context = false;
+		}
+		context = context || document;
+
+		var parsed = rsingleTag.exec( data ),
+			scripts = !keepScripts && [];
+
+		// Single tag
+		if ( parsed ) {
+			return [ context.createElement( parsed[1] ) ];
+		}
+
+		parsed = jQuery.buildFragment( [ data ], context, scripts );
+		if ( scripts ) {
+			jQuery( scripts ).remove();
+		}
+		return jQuery.merge( [], parsed.childNodes );
+	},
+
+	parseJSON: function( data ) {
+		// Attempt to parse using the native JSON parser first
+		if ( window.JSON && window.JSON.parse ) {
+			return window.JSON.parse( data );
+		}
+
+		if ( data === null ) {
+			return data;
+		}
+
+		if ( typeof data === "string" ) {
+
+			// Make sure leading/trailing whitespace is removed (IE can't handle it)
+			data = jQuery.trim( data );
+
+			if ( data ) {
+				// Make sure the incoming data is actual JSON
+				// Logic borrowed from http://json.org/json2.js
+				if ( rvalidchars.test( data.replace( rvalidescape, "@" )
+					.replace( rvalidtokens, "]" )
+					.replace( rvalidbraces, "")) ) {
+
+					return ( new Function( "return " + data ) )();
+				}
+			}
+		}
+
+		jQuery.error( "Invalid JSON: " + data );
+	},
+
+	// Cross-browser xml parsing
+	parseXML: function( data ) {
+		var xml, tmp;
+		if ( !data || typeof data !== "string" ) {
+			return null;
+		}
+		try {
+			if ( window.DOMParser ) { // Standard
+				tmp = new DOMParser();
+				xml = tmp.parseFromString( data , "text/xml" );
+			} else { // IE
+				xml = new ActiveXObject( "Microsoft.XMLDOM" );
+				xml.async = "false";
+				xml.loadXML( data );
+			}
+		} catch( e ) {
+			xml = undefined;
+		}
+		if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) {
+			jQuery.error( "Invalid XML: " + data );
+		}
+		return xml;
+	},
+
+	noop: function() {},
+
+	// Evaluates a script in a global context
+	// Workarounds based on findings by Jim Driscoll
+	// http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context
+	globalEval: function( data ) {
+		if ( data && jQuery.trim( data ) ) {
+			// We use execScript on Internet Explorer
+			// We use an anonymous function so that context is window
+			// rather than jQuery in Firefox
+			( window.execScript || function( data ) {
+				window[ "eval" ].call( window, data );
+			} )( data );
+		}
+	},
+
+	// Convert dashed to camelCase; used by the css and data modules
+	// Microsoft forgot to hump their vendor prefix (#9572)
+	camelCase: function( string ) {
+		return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase );
+	},
+
+	nodeName: function( elem, name ) {
+		return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();
+	},
+
+	// args is for internal usage only
+	each: function( obj, callback, args ) {
+		var value,
+			i = 0,
+			length = obj.length,
+			isArray = isArraylike( obj );
+
+		if ( args ) {
+			if ( isArray ) {
+				for ( ; i < length; i++ ) {
+					value = callback.apply( obj[ i ], args );
+
+					if ( value === false ) {
+						break;
+					}
+				}
+			} else {
+				for ( i in obj ) {
+					value = callback.apply( obj[ i ], args );
+
+					if ( value === false ) {
+						break;
+					}
+				}
+			}
+
+		// A special, fast, case for the most common use of each
+		} else {
+			if ( isArray ) {
+				for ( ; i < length; i++ ) {
+					value = callback.call( obj[ i ], i, obj[ i ] );
+
+					if ( value === false ) {
+						break;
+					}
+				}
+			} else {
+				for ( i in obj ) {
+					value = callback.call( obj[ i ], i, obj[ i ] );
+
+					if ( value === false ) {
+						break;
+					}
+				}
+			}
+		}
+
+		return obj;
+	},
+
+	// Use native String.trim function wherever possible
+	trim: core_trim && !core_trim.call("\uFEFF\xA0") ?
+		function( text ) {
+			return text == null ?
+				"" :
+				core_trim.call( text );
+		} :
+
+		// Otherwise use our own trimming functionality
+		function( text ) {
+			return text == null ?
+				"" :
+				( text + "" ).replace( rtrim, "" );
+		},
+
+	// results is for internal usage only
+	makeArray: function( arr, results ) {
+		var ret = results || [];
+
+		if ( arr != null ) {
+			if ( isArraylike( Object(arr) ) ) {
+				jQuery.merge( ret,
+					typeof arr === "string" ?
+					[ arr ] : arr
+				);
+			} else {
+				core_push.call( ret, arr );
+			}
+		}
+
+		return ret;
+	},
+
+	inArray: function( elem, arr, i ) {
+		var len;
+
+		if ( arr ) {
+			if ( core_indexOf ) {
+				return core_indexOf.call( arr, elem, i );
+			}
+
+			len = arr.length;
+			i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0;
+
+			for ( ; i < len; i++ ) {
+				// Skip accessing in sparse arrays
+				if ( i in arr && arr[ i ] === elem ) {
+					return i;
+				}
+			}
+		}
+
+		return -1;
+	},
+
+	merge: function( first, second ) {
+		var l = second.length,
+			i = first.length,
+			j = 0;
+
+		if ( typeof l === "number" ) {
+			for ( ; j < l; j++ ) {
+				first[ i++ ] = second[ j ];
+			}
+		} else {
+			while ( second[j] !== undefined ) {
+				first[ i++ ] = second[ j++ ];
+			}
+		}
+
+		first.length = i;
+
+		return first;
+	},
+
+	grep: function( elems, callback, inv ) {
+		var retVal,
+			ret = [],
+			i = 0,
+			length = elems.length;
+		inv = !!inv;
+
+		// Go through the array, only saving the items
+		// that pass the validator function
+		for ( ; i < length; i++ ) {
+			retVal = !!callback( elems[ i ], i );
+			if ( inv !== retVal ) {
+				ret.push( elems[ i ] );
+			}
+		}
+
+		return ret;
+	},
+
+	// arg is for internal usage only
+	map: function( elems, callback, arg ) {
+		var value,
+			i = 0,
+			length = elems.length,
+			isArray = isArraylike( elems ),
+			ret = [];
+
+		// Go through the array, translating each of the items to their
+		if ( isArray ) {
+			for ( ; i < length; i++ ) {
+				value = callback( elems[ i ], i, arg );
+
+				if ( value != null ) {
+					ret[ ret.length ] = value;
+				}
+			}
+
+		// Go through every key on the object,
+		} else {
+			for ( i in elems ) {
+				value = callback( elems[ i ], i, arg );
+
+				if ( value != null ) {
+					ret[ ret.length ] = value;
+				}
+			}
+		}
+
+		// Flatten any nested arrays
+		return core_concat.apply( [], ret );
+	},
+
+	// A global GUID counter for objects
+	guid: 1,
+
+	// Bind a function to a context, optionally partially applying any
+	// arguments.
+	proxy: function( fn, context ) {
+		var tmp, args, proxy;
+
+		if ( typeof context === "string" ) {
+			tmp = fn[ context ];
+			context = fn;
+			fn = tmp;
+		}
+
+		// Quick check to determine if target is callable, in the spec
+		// this throws a TypeError, but we will just return undefined.
+		if ( !jQuery.isFunction( fn ) ) {
+			return undefined;
+		}
+
+		// Simulated bind
+		args = core_slice.call( arguments, 2 );
+		proxy = function() {
+			return fn.apply( context || this, args.concat( core_slice.call( arguments ) ) );
+		};
+
+		// Set the guid of unique handler to the same of original handler, so it can be removed
+		proxy.guid = fn.guid = fn.guid || jQuery.guid++;
+
+		return proxy;
+	},
+
+	// Multifunctional method to get and set values of a collection
+	// The value/s can optionally be executed if it's a function
+	access: function( elems, fn, key, value, chainable, emptyGet, raw ) {
+		var i = 0,
+			length = elems.length,
+			bulk = key == null;
+
+		// Sets many values
+		if ( jQuery.type( key ) === "object" ) {
+			chainable = true;
+			for ( i in key ) {
+				jQuery.access( elems, fn, i, key[i], true, emptyGet, raw );
+			}
+
+		// Sets one value
+		} else if ( value !== undefined ) {
+			chainable = true;
+
+			if ( !jQuery.isFunction( value ) ) {
+				raw = true;
+			}
+
+			if ( bulk ) {
+				// Bulk operations run against the entire set
+				if ( raw ) {
+					fn.call( elems, value );
+					fn = null;
+
+				// ...except when executing function values
+				} else {
+					bulk = fn;
+					fn = function( elem, key, value ) {
+						return bulk.call( jQuery( elem ), value );
+					};
+				}
+			}
+
+			if ( fn ) {
+				for ( ; i < length; i++ ) {
+					fn( elems[i], key, raw ? value : value.call( elems[i], i, fn( elems[i], key ) ) );
+				}
+			}
+		}
+
+		return chainable ?
+			elems :
+
+			// Gets
+			bulk ?
+				fn.call( elems ) :
+				length ? fn( elems[0], key ) : emptyGet;
+	},
+
+	now: function() {
+		return ( new Date() ).getTime();
+	}
+});
+
+jQuery.ready.promise = function( obj ) {
+	if ( !readyList ) {
+
+		readyList = jQuery.Deferred();
+
+		// Catch cases where $(document).ready() is called after the browser event has already occurred.
+		// we once tried to use readyState "interactive" here, but it caused issues like the one
+		// discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15
+		if ( document.readyState === "complete" ) {
+			// Handle it asynchronously to allow scripts the opportunity to delay ready
+			setTimeout( jQuery.ready );
+
+		// Standards-based browsers support DOMContentLoaded
+		} else if ( document.addEventListener ) {
+			// Use the handy event callback
+			document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false );
+
+			// A fallback to window.onload, that will always work
+			window.addEventListener( "load", jQuery.ready, false );
+
+		// If IE event model is used
+		} else {
+			// Ensure firing before onload, maybe late but safe also for iframes
+			document.attachEvent( "onreadystatechange", DOMContentLoaded );
+
+			// A fallback to window.onload, that will always work
+			window.attachEvent( "onload", jQuery.ready );
+
+			// If IE and not a frame
+			// continually check to see if the document is ready
+			var top = false;
+
+			try {
+				top = window.frameElement == null && document.documentElement;
+			} catch(e) {}
+
+			if ( top && top.doScroll ) {
+				(function doScrollCheck() {
+					if ( !jQuery.isReady ) {
+
+						try {
+							// Use the trick by Diego Perini
+							// http://javascript.nwbox.com/IEContentLoaded/
+							top.doScroll("left");
+						} catch(e) {
+							return setTimeout( doScrollCheck, 50 );
+						}
+
+						// and execute any waiting functions
+						jQuery.ready();
+					}
+				})();
+			}
+		}
+	}
+	return readyList.promise( obj );
+};
+
+// Populate the class2type map
+jQuery.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(i, name) {
+	class2type[ "[object " + name + "]" ] = name.toLowerCase();
+});
+
+function isArraylike( obj ) {
+	var length = obj.length,
+		type = jQuery.type( obj );
+
+	if ( jQuery.isWindow( obj ) ) {
+		return false;
+	}
+
+	if ( obj.nodeType === 1 && length ) {
+		return true;
+	}
+
+	return type === "array" || type !== "function" &&
+		( length === 0 ||
+		typeof length === "number" && length > 0 && ( length - 1 ) in obj );
+}
+
+// All jQuery objects should point back to these
+rootjQuery = jQuery(document);
+// String to Object options format cache
+var optionsCache = {};
+
+// Convert String-formatted options into Object-formatted ones and store in cache
+function createOptions( options ) {
+	var object = optionsCache[ options ] = {};
+	jQuery.each( options.match( core_rnotwhite ) || [], function( _, flag ) {
+		object[ flag ] = true;
+	});
+	return object;
+}
+
+/*
+ * Create a callback list using the following parameters:
+ *
+ *	options: an optional list of space-separated options that will change how
+ *			the callback list behaves or a more traditional option object
+ *
+ * By default a callback list will act like an event callback list and can be
+ * "fired" multiple times.
+ *
+ * Possible options:
+ *
+ *	once:			will ensure the callback list can only be fired once (like a Deferred)
+ *
+ *	memory:			will keep track of previous values and will call any callback added
+ *					after the list has been fired right away with the latest "memorized"
+ *					values (like a Deferred)
+ *
+ *	unique:			will ensure a callback can only be added once (no duplicate in the list)
+ *
+ *	stopOnFalse:	interrupt callings when a callback returns false
+ *
+ */
+jQuery.Callbacks = function( options ) {
+
+	// Convert options from String-formatted to Object-formatted if needed
+	// (we check in cache first)
+	options = typeof options === "string" ?
+		( optionsCache[ options ] || createOptions( options ) ) :
+		jQuery.extend( {}, options );
+
+	var // Last fire value (for non-forgettable lists)
+		memory,
+		// Flag to know if list was already fired
+		fired,
+		// Flag to know if list is currently firing
+		firing,
+		// First callback to fire (used internally by add and fireWith)
+		firingStart,
+		// End of the loop when firing
+		firingLength,
+		// Index of currently firing callback (modified by remove if needed)
+		firingIndex,
+		// Actual callback list
+		list = [],
+		// Stack of fire calls for repeatable lists
+		stack = !options.once && [],
+		// Fire callbacks
+		fire = function( data ) {
+			memory = options.memory && data;
+			fired = true;
+			firingIndex = firingStart || 0;
+			firingStart = 0;
+			firingLength = list.length;
+			firing = true;
+			for ( ; list && firingIndex < firingLength; firingIndex++ ) {
+				if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) {
+					memory = false; // To prevent further calls using add
+					break;
+				}
+			}
+			firing = false;
+			if ( list ) {
+				if ( stack ) {
+					if ( stack.length ) {
+						fire( stack.shift() );
+					}
+				} else if ( memory ) {
+					list = [];
+				} else {
+					self.disable();
+				}
+			}
+		},
+		// Actual Callbacks object
+		self = {
+			// Add a callback or a collection of callbacks to the list
+			add: function() {
+				if ( list ) {
+					// First, we save the current length
+					var start = list.length;
+					(function add( args ) {
+						jQuery.each( args, function( _, arg ) {
+							var type = jQuery.type( arg );
+							if ( type === "function" ) {
+								if ( !options.unique || !self.has( arg ) ) {
+									list.push( arg );
+								}
+							} else if ( arg && arg.length && type !== "string" ) {
+								// Inspect recursively
+								add( arg );
+							}
+						});
+					})( arguments );
+					// Do we need to add the callbacks to the
+					// current firing batch?
+					if ( firing ) {
+						firingLength = list.length;
+					// With memory, if we're not firing then
+					// we should call right away
+					} else if ( memory ) {
+						firingStart = start;
+						fire( memory );
+					}
+				}
+				return this;
+			},
+			// Remove a callback from the list
+			remove: function() {
+				if ( list ) {
+					jQuery.each( arguments, function( _, arg ) {
+						var index;
+						while( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {
+							list.splice( index, 1 );
+							// Handle firing indexes
+							if ( firing ) {
+								if ( index <= firingLength ) {
+									firingLength--;
+								}
+								if ( index <= firingIndex ) {
+									firingIndex--;
+								}
+							}
+						}
+					});
+				}
+				return this;
+			},
+			// Control if a given callback is in the list
+			has: function( fn ) {
+				return jQuery.inArray( fn, list ) > -1;
+			},
+			// Remove all callbacks from the list
+			empty: function() {
+				list = [];
+				return this;
+			},
+			// Have the list do nothing anymore
+			disable: function() {
+				list = stack = memory = undefined;
+				return this;
+			},
+			// Is it disabled?
+			disabled: function() {
+				return !list;
+			},
+			// Lock the list in its current state
+			lock: function() {
+				stack = undefined;
+				if ( !memory ) {
+					self.disable();
+				}
+				return this;
+			},
+			// Is it locked?
+			locked: function() {
+				return !stack;
+			},
+			// Call all callbacks with the given context and arguments
+			fireWith: function( context, args ) {
+				args = args || [];
+				args = [ context, args.slice ? args.slice() : args ];
+				if ( list && ( !fired || stack ) ) {
+					if ( firing ) {
+						stack.push( args );
+					} else {
+						fire( args );
+					}
+				}
+				return this;
+			},
+			// Call all the callbacks with the given arguments
+			fire: function() {
+				self.fireWith( this, arguments );
+				return this;
+			},
+			// To know if the callbacks have already been called at least once
+			fired: function() {
+				return !!fired;
+			}
+		};
+
+	return self;
+};
+jQuery.extend({
+
+	Deferred: function( func ) {
+		var tuples = [
+				// action, add listener, listener list, final state
+				[ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ],
+				[ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ],
+				[ "notify", "progress", jQuery.Callbacks("memory") ]
+			],
+			state = "pending",
+			promise = {
+				state: function() {
+					return state;
+				},
+				always: function() {
+					deferred.done( arguments ).fail( arguments );
+					return this;
+				},
+				then: function( /* fnDone, fnFail, fnProgress */ ) {
+					var fns = arguments;
+					return jQuery.Deferred(function( newDefer ) {
+						jQuery.each( tuples, function( i, tuple ) {
+							var action = tuple[ 0 ],
+								fn = jQuery.isFunction( fns[ i ] ) && fns[ i ];
+							// deferred[ done | fail | progress ] for forwarding actions to newDefer
+							deferred[ tuple[1] ](function() {
+								var returned = fn && fn.apply( this, arguments );
+								if ( returned && jQuery.isFunction( returned.promise ) ) {
+									returned.promise()
+										.done( newDefer.resolve )
+										.fail( newDefer.reject )
+										.progress( newDefer.notify );
+								} else {
+									newDefer[ action + "With" ]( this === promise ? newDefer.promise() : this, fn ? [ returned ] : arguments );
+								}
+							});
+						});
+						fns = null;
+					}).promise();
+				},
+				// Get a promise for this deferred
+				// If obj is provided, the promise aspect is added to the object
+				promise: function( obj ) {
+					return obj != null ? jQuery.extend( obj, promise ) : promise;
+				}
+			},
+			deferred = {};
+
+		// Keep pipe for back-compat
+		promise.pipe = promise.then;
+
+		// Add list-specific methods
+		jQuery.each( tuples, function( i, tuple ) {
+			var list = tuple[ 2 ],
+				stateString = tuple[ 3 ];
+
+			// promise[ done | fail | progress ] = list.add
+			promise[ tuple[1] ] = list.add;
+
+			// Handle state
+			if ( stateString ) {
+				list.add(function() {
+					// state = [ resolved | rejected ]
+					state = stateString;
+
+				// [ reject_list | resolve_list ].disable; progress_list.lock
+				}, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock );
+			}
+
+			// deferred[ resolve | reject | notify ]
+			deferred[ tuple[0] ] = function() {
+				deferred[ tuple[0] + "With" ]( this === deferred ? promise : this, arguments );
+				return this;
+			};
+			deferred[ tuple[0] + "With" ] = list.fireWith;
+		});
+
+		// Make the deferred a promise
+		promise.promise( deferred );
+
+		// Call given func if any
+		if ( func ) {
+			func.call( deferred, deferred );
+		}
+
+		// All done!
+		return deferred;
+	},
+
+	// Deferred helper
+	when: function( subordinate /* , ..., subordinateN */ ) {
+		var i = 0,
+			resolveValues = core_slice.call( arguments ),
+			length = resolveValues.length,
+
+			// the count of uncompleted subordinates
+			remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0,
+
+			// the master Deferred. If resolveValues consist of only a single Deferred, just use that.
+			deferred = remaining === 1 ? subordinate : jQuery.Deferred(),
+
+			// Update function for both resolve and progress values
+			updateFunc = function( i, contexts, values ) {
+				return function( value ) {
+					contexts[ i ] = this;
+					values[ i ] = arguments.length > 1 ? core_slice.call( arguments ) : value;
+					if( values === progressValues ) {
+						deferred.notifyWith( contexts, values );
+					} else if ( !( --remaining ) ) {
+						deferred.resolveWith( contexts, values );
+					}
+				};
+			},
+
+			progressValues, progressContexts, resolveContexts;
+
+		// add listeners to Deferred subordinates; treat others as resolved
+		if ( length > 1 ) {
+			progressValues = new Array( length );
+			progressContexts = new Array( length );
+			resolveContexts = new Array( length );
+			for ( ; i < length; i++ ) {
+				if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) {
+					resolveValues[ i ].promise()
+						.done( updateFunc( i, resolveContexts, resolveValues ) )
+						.fail( deferred.reject )
+						.progress( updateFunc( i, progressContexts, progressValues ) );
+				} else {
+					--remaining;
+				}
+			}
+		}
+
+		// if we're not waiting on anything, resolve the master
+		if ( !remaining ) {
+			deferred.resolveWith( resolveContexts, resolveValues );
+		}
+
+		return deferred.promise();
+	}
+});
+jQuery.support = (function() {
+
+	var support, all, a, select, opt, input, fragment, eventName, isSupported, i,
+		div = document.createElement("div");
+
+	// Setup
+	div.setAttribute( "className", "t" );
+	div.innerHTML = "  <link/><table></table><a href='/a'>a</a><input type='checkbox'/>";
+
+	// Support tests won't run in some limited or non-browser environments
+	all = div.getElementsByTagName("*");
+	a = div.getElementsByTagName("a")[ 0 ];
+	if ( !all || !a || !all.length ) {
+		return {};
+	}
+
+	// First batch of tests
+	select = document.createElement("select");
+	opt = select.appendChild( document.createElement("option") );
+	input = div.getElementsByTagName("input")[ 0 ];
+
+	a.style.cssText = "top:1px;float:left;opacity:.5";
+	support = {
+		// Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7)
+		getSetAttribute: div.className !== "t",
+
+		// IE strips leading whitespace when .innerHTML is used
+		leadingWhitespace: div.firstChild.nodeType === 3,
+
+		// Make sure that tbody elements aren't automatically inserted
+		// IE will insert them into empty tables
+		tbody: !div.getElementsByTagName("tbody").length,
+
+		// Make sure that link elements get serialized correctly by innerHTML
+		// This requires a wrapper element in IE
+		htmlSerialize: !!div.getElementsByTagName("link").length,
+
+		// Get the style information from getAttribute
+		// (IE uses .cssText instead)
+		style: /top/.test( a.getAttribute("style") ),
+
+		// Make sure that URLs aren't manipulated
+		// (IE normalizes it by default)
+		hrefNormalized: a.getAttribute("href") === "/a",
+
+		// Make sure that element opacity exists
+		// (IE uses filter instead)
+		// Use a regex to work around a WebKit issue. See #5145
+		opacity: /^0.5/.test( a.style.opacity ),
+
+		// Verify style float existence
+		// (IE uses styleFloat instead of cssFloat)
+		cssFloat: !!a.style.cssFloat,
+
+		// Check the default checkbox/radio value ("" on WebKit; "on" elsewhere)
+		checkOn: !!input.value,
+
+		// Make sure that a selected-by-default option has a working selected property.
+		// (WebKit defaults to false instead of true, IE too, if it's in an optgroup)
+		optSelected: opt.selected,
+
+		// Tests for enctype support on a form (#6743)
+		enctype: !!document.createElement("form").enctype,
+
+		// Makes sure cloning an html5 element does not cause problems
+		// Where outerHTML is undefined, this still works
+		html5Clone: document.createElement("nav").cloneNode( true ).outerHTML !== "<:nav></:nav>",
+
+		// jQuery.support.boxModel DEPRECATED in 1.8 since we don't support Quirks Mode
+		boxModel: document.compatMode === "CSS1Compat",
+
+		// Will be defined later
+		deleteExpando: true,
+		noCloneEvent: true,
+		inlineBlockNeedsLayout: false,
+		shrinkWrapBlocks: false,
+		reliableMarginRight: true,
+		boxSizingReliable: true,
+		pixelPosition: false
+	};
+
+	// Make sure checked status is properly cloned
+	input.checked = true;
+	support.noCloneChecked = input.cloneNode( true ).checked;
+
+	// Make sure that the options inside disabled selects aren't marked as disabled
+	// (WebKit marks them as disabled)
+	select.disabled = true;
+	support.optDisabled = !opt.disabled;
+
+	// Support: IE<9
+	try {
+		delete div.test;
+	} catch( e ) {
+		support.deleteExpando = false;
+	}
+
+	// Check if we can trust getAttribute("value")
+	input = document.createElement("input");
+	input.setAttribute( "value", "" );
+	support.input = input.getAttribute( "value" ) === "";
+
+	// Check if an input maintains its value after becoming a radio
+	input.value = "t";
+	input.setAttribute( "type", "radio" );
+	support.radioValue = input.value === "t";
+
+	// #11217 - WebKit loses check when the name is after the checked attribute
+	input.setAttribute( "checked", "t" );
+	input.setAttribute( "name", "t" );
+
+	fragment = document.createDocumentFragment();
+	fragment.appendChild( input );
+
+	// Check if a disconnected checkbox will retain its checked
+	// value of true after appended to the DOM (IE6/7)
+	support.appendChecked = input.checked;
+
+	// WebKit doesn't clone checked state correctly in fragments
+	support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked;
+
+	// Support: IE<9
+	// Opera does not clone events (and typeof div.attachEvent === undefined).
+	// IE9-10 clones events bound via attachEvent, but they don't trigger with .click()
+	if ( div.attachEvent ) {
+		div.attachEvent( "onclick", function() {
+			support.noCloneEvent = false;
+		});
+
+		div.cloneNode( true ).click();
+	}
+
+	// Support: IE<9 (lack submit/change bubble), Firefox 17+ (lack focusin event)
+	// Beware of CSP restrictions (https://developer.mozilla.org/en/Security/CSP), test/csp.php
+	for ( i in { submit: true, change: true, focusin: true }) {
+		div.setAttribute( eventName = "on" + i, "t" );
+
+		support[ i + "Bubbles" ] = eventName in window || div.attributes[ eventName ].expando === false;
+	}
+
+	div.style.backgroundClip = "content-box";
+	div.cloneNode( true ).style.backgroundClip = "";
+	support.clearCloneStyle = div.style.backgroundClip === "content-box";
+
+	// Run tests that need a body at doc ready
+	jQuery(function() {
+		var container, marginDiv, tds,
+			divReset = "padding:0;margin:0;border:0;display:block;box-sizing:content-box;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;",
+			body = document.getElementsByTagName("body")[0];
+
+		if ( !body ) {
+			// Return for frameset docs that don't have a body
+			return;
+		}
+
+		container = document.createElement("div");
+		container.style.cssText = "border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px";
+
+		body.appendChild( container ).appendChild( div );
+
+		// Support: IE8
+		// Check if table cells still have offsetWidth/Height when they are set
+		// to display:none and there are still other visible table cells in a
+		// table row; if so, offsetWidth/Height are not reliable for use when
+		// determining if an element has been hidden directly using
+		// display:none (it is still safe to use offsets if a parent element is
+		// hidden; don safety goggles and see bug #4512 for more information).
+		div.innerHTML = "<table><tr><td></td><td>t</td></tr></table>";
+		tds = div.getElementsByTagName("td");
+		tds[ 0 ].style.cssText = "padding:0;margin:0;border:0;display:none";
+		isSupported = ( tds[ 0 ].offsetHeight === 0 );
+
+		tds[ 0 ].style.display = "";
+		tds[ 1 ].style.display = "none";
+
+		// Support: IE8
+		// Check if empty table cells still have offsetWidth/Height
+		support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 );
+
+		// Check box-sizing and margin behavior
+		div.innerHTML = "";
+		div.style.cssText = "box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;";
+		support.boxSizing = ( div.offsetWidth === 4 );
+		support.doesNotIncludeMarginInBodyOffset = ( body.offsetTop !== 1 );
+
+		// Use window.getComputedStyle because jsdom on node.js will break without it.
+		if ( window.getComputedStyle ) {
+			support.pixelPosition = ( window.getComputedStyle( div, null ) || {} ).top !== "1%";
+			support.boxSizingReliable = ( window.getComputedStyle( div, null ) || { width: "4px" } ).width === "4px";
+
+			// Check if div with explicit width and no margin-right incorrectly
+			// gets computed margin-right based on width of container. (#3333)
+			// Fails in WebKit before Feb 2011 nightlies
+			// WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
+			marginDiv = div.appendChild( document.createElement("div") );
+			marginDiv.style.cssText = div.style.cssText = divReset;
+			marginDiv.style.marginRight = marginDiv.style.width = "0";
+			div.style.width = "1px";
+
+			support.reliableMarginRight =
+				!parseFloat( ( window.getComputedStyle( marginDiv, null ) || {} ).marginRight );
+		}
+
+		if ( typeof div.style.zoom !== "undefined" ) {
+			// Support: IE<8
+			// Check if natively block-level elements act like inline-block
+			// elements when setting their display to 'inline' and giving
+			// them layout
+			div.innerHTML = "";
+			div.style.cssText = divReset + "width:1px;padding:1px;display:inline;zoom:1";
+			support.inlineBlockNeedsLayout = ( div.offsetWidth === 3 );
+
+			// Support: IE6
+			// Check if elements with layout shrink-wrap their children
+			div.style.display = "block";
+			div.innerHTML = "<div></div>";
+			div.firstChild.style.width = "5px";
+			support.shrinkWrapBlocks = ( div.offsetWidth !== 3 );
+
+			// Prevent IE 6 from affecting layout for positioned elements #11048
+			// Prevent IE from shrinking the body in IE 7 mode #12869
+			body.style.zoom = 1;
+		}
+
+		body.removeChild( container );
+
+		// Null elements to avoid leaks in IE
+		container = div = tds = marginDiv = null;
+	});
+
+	// Null elements to avoid leaks in IE
+	all = select = fragment = opt = a = input = null;
+
+	return support;
+})();
+
+var rbrace = /(?:\{[\s\S]*\}|\[[\s\S]*\])$/,
+	rmultiDash = /([A-Z])/g;
+
+function internalData( elem, name, data, pvt /* Internal Use Only */ ){
+	if ( !jQuery.acceptData( elem ) ) {
+		return;
+	}
+
+	var thisCache, ret,
+		internalKey = jQuery.expando,
+		getByName = typeof name === "string",
+
+		// We have to handle DOM nodes and JS objects differently because IE6-7
+		// can't GC object references properly across the DOM-JS boundary
+		isNode = elem.nodeType,
+
+		// Only DOM nodes need the global jQuery cache; JS object data is
+		// attached directly to the object so GC can occur automatically
+		cache = isNode ? jQuery.cache : elem,
+
+		// Only defining an ID for JS objects if its cache already exists allows
+		// the code to shortcut on the same path as a DOM node with no cache
+		id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey;
+
+	// Avoid doing any more work than we need to when trying to get data on an
+	// object that has no data at all
+	if ( (!id || !cache[id] || (!pvt && !cache[id].data)) && getByName && data === undefined ) {
+		return;
+	}
+
+	if ( !id ) {
+		// Only DOM nodes need a new unique ID for each element since their data
+		// ends up in the global cache
+		if ( isNode ) {
+			elem[ internalKey ] = id = core_deletedIds.pop() || jQuery.guid++;
+		} else {
+			id = internalKey;
+		}
+	}
+
+	if ( !cache[ id ] ) {
+		cache[ id ] = {};
+
+		// Avoids exposing jQuery metadata on plain JS objects when the object
+		// is serialized using JSON.stringify
+		if ( !isNode ) {
+			cache[ id ].toJSON = jQuery.noop;
+		}
+	}
+
+	// An object can be passed to jQuery.data instead of a key/value pair; this gets
+	// shallow copied over onto the existing cache
+	if ( typeof name === "object" || typeof name === "function" ) {
+		if ( pvt ) {
+			cache[ id ] = jQuery.extend( cache[ id ], name );
+		} else {
+			cache[ id ].data = jQuery.extend( cache[ id ].data, name );
+		}
+	}
+
+	thisCache = cache[ id ];
+
+	// jQuery data() is stored in a separate object inside the object's internal data
+	// cache in order to avoid key collisions between internal data and user-defined
+	// data.
+	if ( !pvt ) {
+		if ( !thisCache.data ) {
+			thisCache.data = {};
+		}
+
+		thisCache = thisCache.data;
+	}
+
+	if ( data !== undefined ) {
+		thisCache[ jQuery.camelCase( name ) ] = data;
+	}
+
+	// Check for both converted-to-camel and non-converted data property names
+	// If a data property was specified
+	if ( getByName ) {
+
+		// First Try to find as-is property data
+		ret = thisCache[ name ];
+
+		// Test for null|undefined property data
+		if ( ret == null ) {
+
+			// Try to find the camelCased property
+			ret = thisCache[ jQuery.camelCase( name ) ];
+		}
+	} else {
+		ret = thisCache;
+	}
+
+	return ret;
+}
+
+function internalRemoveData( elem, name, pvt /* For internal use only */ ){
+	if ( !jQuery.acceptData( elem ) ) {
+		return;
+	}
+
+	var thisCache, i, l,
+
+		isNode = elem.nodeType,
+
+		// See jQuery.data for more information
+		cache = isNode ? jQuery.cache : elem,
+		id = isNode ? elem[ jQuery.expando ] : jQuery.expando;
+
+	// If there is already no cache entry for this object, there is no
+	// purpose in continuing
+	if ( !cache[ id ] ) {
+		return;
+	}
+
+	if ( name ) {
+
+		thisCache = pvt ? cache[ id ] : cache[ id ].data;
+
+		if ( thisCache ) {
+
+			// Support array or space separated string names for data keys
+			if ( !jQuery.isArray( name ) ) {
+
+				// try the string as a key before any manipulation
+				if ( name in thisCache ) {
+					name = [ name ];
+				} else {
+
+					// split the camel cased version by spaces unless a key with the spaces exists
+					name = jQuery.camelCase( name );
+					if ( name in thisCache ) {
+						name = [ name ];
+					} else {
+						name = name.split(" ");
+					}
+				}
+			} else {
+				// If "name" is an array of keys...
+				// When data is initially created, via ("key", "val") signature,
+				// keys will be converted to camelCase.
+				// Since there is no way to tell _how_ a key was added, remove
+				// both plain key and camelCase key. #12786
+				// This will only penalize the array argument path.
+				name = name.concat( jQuery.map( name, jQuery.camelCase ) );
+			}
+
+			for ( i = 0, l = name.length; i < l; i++ ) {
+				delete thisCache[ name[i] ];
+			}
+
+			// If there is no data left in the cache, we want to continue
+			// and let the cache object itself get destroyed
+			if ( !( pvt ? isEmptyDataObject : jQuery.isEmptyObject )( thisCache ) ) {
+				return;
+			}
+		}
+	}
+
+	// See jQuery.data for more information
+	if ( !pvt ) {
+		delete cache[ id ].data;
+
+		// Don't destroy the parent cache unless the internal data object
+		// had been the only thing left in it
+		if ( !isEmptyDataObject( cache[ id ] ) ) {
+			return;
+		}
+	}
+
+	// Destroy the cache
+	if ( isNode ) {
+		jQuery.cleanData( [ elem ], true );
+
+	// Use delete when supported for expandos or `cache` is not a window per isWindow (#10080)
+	} else if ( jQuery.support.deleteExpando || cache != cache.window ) {
+		delete cache[ id ];
+
+	// When all else fails, null
+	} else {
+		cache[ id ] = null;
+	}
+}
+
+jQuery.extend({
+	cache: {},
+
+	// Unique for each copy of jQuery on the page
+	// Non-digits removed to match rinlinejQuery
+	expando: "jQuery" + ( core_version + Math.random() ).replace( /\D/g, "" ),
+
+	// The following elements throw uncatchable exceptions if you
+	// attempt to add expando properties to them.
+	noData: {
+		"embed": true,
+		// Ban all objects except for Flash (which handle expandos)
+		"object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",
+		"applet": true
+	},
+
+	hasData: function( elem ) {
+		elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ];
+		return !!elem && !isEmptyDataObject( elem );
+	},
+
+	data: function( elem, name, data ) {
+		return internalData( elem, name, data, false );
+	},
+
+	removeData: function( elem, name ) {
+		return internalRemoveData( elem, name, false );
+	},
+
+	// For internal use only.
+	_data: function( elem, name, data ) {
+		return internalData( elem, name, data, true );
+	},
+
+	_removeData: function( elem, name ) {
+		return internalRemoveData( elem, name, true );
+	},
+
+	// A method for determining if a DOM node can handle the data expando
+	acceptData: function( elem ) {
+		var noData = elem.nodeName && jQuery.noData[ elem.nodeName.toLowerCase() ];
+
+		// nodes accept data unless otherwise specified; rejection can be conditional
+		return !noData || noData !== true && elem.getAttribute("classid") === noData;
+	}
+});
+
+jQuery.fn.extend({
+	data: function( key, value ) {
+		var attrs, name,
+			elem = this[0],
+			i = 0,
+			data = null;
+
+		// Gets all values
+		if ( key === undefined ) {
+			if ( this.length ) {
+				data = jQuery.data( elem );
+
+				if ( elem.nodeType === 1 && !jQuery._data( elem, "parsedAttrs" ) ) {
+					attrs = elem.attributes;
+					for ( ; i < attrs.length; i++ ) {
+						name = attrs[i].name;
+
+						if ( !name.indexOf( "data-" ) ) {
+							name = jQuery.camelCase( name.substring(5) );
+
+							dataAttr( elem, name, data[ name ] );
+						}
+					}
+					jQuery._data( elem, "parsedAttrs", true );
+				}
+			}
+
+			return data;
+		}
+
+		// Sets multiple values
+		if ( typeof key === "object" ) {
+			return this.each(function() {
+				jQuery.data( this, key );
+			});
+		}
+
+		return jQuery.access( this, function( value ) {
+
+			if ( value === undefined ) {
+				// Try to fetch any internally stored data first
+				return elem ? dataAttr( elem, key, jQuery.data( elem, key ) ) : null;
+			}
+
+			this.each(function() {
+				jQuery.data( this, key, value );
+			});
+		}, null, value, arguments.length > 1, null, true );
+	},
+
+	removeData: function( key ) {
+		return this.each(function() {
+			jQuery.removeData( this, key );
+		});
+	}
+});
+
+function dataAttr( elem, key, data ) {
+	// If nothing was found internally, try to fetch any
+	// data from the HTML5 data-* attribute
+	if ( data === undefined && elem.nodeType === 1 ) {
+
+		var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase();
+
+		data = elem.getAttribute( name );
+
+		if ( typeof data === "string" ) {
+			try {
+				data = data === "true" ? true :
+				data === "false" ? false :
+				data === "null" ? null :
+				// Only convert to a number if it doesn't change the string
+				+data + "" === data ? +data :
+				rbrace.test( data ) ? jQuery.parseJSON( data ) :
+					data;
+			} catch( e ) {}
+
+			// Make sure we set the data so it isn't changed later
+			jQuery.data( elem, key, data );
+
+		} else {
+			data = undefined;
+		}
+	}
+
+	return data;
+}
+
+// checks a cache object for emptiness
+function isEmptyDataObject( obj ) {
+	var name;
+	for ( name in obj ) {
+
+		// if the public data object is empty, the private is still empty
+		if ( name === "data" && jQuery.isEmptyObject( obj[name] ) ) {
+			continue;
+		}
+		if ( name !== "toJSON" ) {
+			return false;
+		}
+	}
+
+	return true;
+}
+jQuery.extend({
+	queue: function( elem, type, data ) {
+		var queue;
+
+		if ( elem ) {
+			type = ( type || "fx" ) + "queue";
+			queue = jQuery._data( elem, type );
+
+			// Speed up dequeue by getting out quickly if this is just a lookup
+			if ( data ) {
+				if ( !queue || jQuery.isArray(data) ) {
+					queue = jQuery._data( elem, type, jQuery.makeArray(data) );
+				} else {
+					queue.push( data );
+				}
+			}
+			return queue || [];
+		}
+	},
+
+	dequeue: function( elem, type ) {
+		type = type || "fx";
+
+		var queue = jQuery.queue( elem, type ),
+			startLength = queue.length,
+			fn = queue.shift(),
+			hooks = jQuery._queueHooks( elem, type ),
+			next = function() {
+				jQuery.dequeue( elem, type );
+			};
+
+		// If the fx queue is dequeued, always remove the progress sentinel
+		if ( fn === "inprogress" ) {
+			fn = queue.shift();
+			startLength--;
+		}
+
+		hooks.cur = fn;
+		if ( fn ) {
+
+			// Add a progress sentinel to prevent the fx queue from being
+			// automatically dequeued
+			if ( type === "fx" ) {
+				queue.unshift( "inprogress" );
+			}
+
+			// clear up the last queue stop function
+			delete hooks.stop;
+			fn.call( elem, next, hooks );
+		}
+
+		if ( !startLength && hooks ) {
+			hooks.empty.fire();
+		}
+	},
+
+	// not intended for public consumption - generates a queueHooks object, or returns the current one
+	_queueHooks: function( elem, type ) {
+		var key = type + "queueHooks";
+		return jQuery._data( elem, key ) || jQuery._data( elem, key, {
+			empty: jQuery.Callbacks("once memory").add(function() {
+				jQuery._removeData( elem, type + "queue" );
+				jQuery._removeData( elem, key );
+			})
+		});
+	}
+});
+
+jQuery.fn.extend({
+	queue: function( type, data ) {
+		var setter = 2;
+
+		if ( typeof type !== "string" ) {
+			data = type;
+			type = "fx";
+			setter--;
+		}
+
+		if ( arguments.length < setter ) {
+			return jQuery.queue( this[0], type );
+		}
+
+		return data === undefined ?
+			this :
+			this.each(function() {
+				var queue = jQuery.queue( this, type, data );
+
+				// ensure a hooks for this queue
+				jQuery._queueHooks( this, type );
+
+				if ( type === "fx" && queue[0] !== "inprogress" ) {
+					jQuery.dequeue( this, type );
+				}
+			});
+	},
+	dequeue: function( type ) {
+		return this.each(function() {
+			jQuery.dequeue( this, type );
+		});
+	},
+	// Based off of the plugin by Clint Helfers, with permission.
+	// http://blindsignals.com/index.php/2009/07/jquery-delay/
+	delay: function( time, type ) {
+		time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;
+		type = type || "fx";
+
+		return this.queue( type, function( next, hooks ) {
+			var timeout = setTimeout( next, time );
+			hooks.stop = function() {
+				clearTimeout( timeout );
+			};
+		});
+	},
+	clearQueue: function( type ) {
+		return this.queue( type || "fx", [] );
+	},
+	// Get a promise resolved when queues of a certain type
+	// are emptied (fx is the type by default)
+	promise: function( type, obj ) {
+		var tmp,
+			count = 1,
+			defer = jQuery.Deferred(),
+			elements = this,
+			i = this.length,
+			resolve = function() {
+				if ( !( --count ) ) {
+					defer.resolveWith( elements, [ elements ] );
+				}
+			};
+
+		if ( typeof type !== "string" ) {
+			obj = type;
+			type = undefined;
+		}
+		type = type || "fx";
+
+		while( i-- ) {
+			tmp = jQuery._data( elements[ i ], type + "queueHooks" );
+			if ( tmp && tmp.empty ) {
+				count++;
+				tmp.empty.add( resolve );
+			}
+		}
+		resolve();
+		return defer.promise( obj );
+	}
+});
+var nodeHook, boolHook,
+	rclass = /[\t\r\n]/g,
+	rreturn = /\r/g,
+	rfocusable = /^(?:input|select|textarea|button|object)$/i,
+	rclickable = /^(?:a|area)$/i,
+	rboolean = /^(?:checked|selected|autofocus|autoplay|async|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped)$/i,
+	ruseDefault = /^(?:checked|selected)$/i,
+	getSetAttribute = jQuery.support.getSetAttribute,
+	getSetInput = jQuery.support.input;
+
+jQuery.fn.extend({
+	attr: function( name, value ) {
+		return jQuery.access( this, jQuery.attr, name, value, arguments.length > 1 );
+	},
+
+	removeAttr: function( name ) {
+		return this.each(function() {
+			jQuery.removeAttr( this, name );
+		});
+	},
+
+	prop: function( name, value ) {
+		return jQuery.access( this, jQuery.prop, name, value, arguments.length > 1 );
+	},
+
+	removeProp: function( name ) {
+		name = jQuery.propFix[ name ] || name;
+		return this.each(function() {
+			// try/catch handles cases where IE balks (such as removing a property on window)
+			try {
+				this[ name ] = undefined;
+				delete this[ name ];
+			} catch( e ) {}
+		});
+	},
+
+	addClass: function( value ) {
+		var classes, elem, cur, clazz, j,
+			i = 0,
+			len = this.length,
+			proceed = typeof value === "string" && value;
+
+		if ( jQuery.isFunction( value ) ) {
+			return this.each(function( j ) {
+				jQuery( this ).addClass( value.call( this, j, this.className ) );
+			});
+		}
+
+		if ( proceed ) {
+			// The disjunction here is for better compressibility (see removeClass)
+			classes = ( value || "" ).match( core_rnotwhite ) || [];
+
+			for ( ; i < len; i++ ) {
+				elem = this[ i ];
+				cur = elem.nodeType === 1 && ( elem.className ?
+					( " " + elem.className + " " ).replace( rclass, " " ) :
+					" "
+				);
+
+				if ( cur ) {
+					j = 0;
+					while ( (clazz = classes[j++]) ) {
+						if ( cur.indexOf( " " + clazz + " " ) < 0 ) {
+							cur += clazz + " ";
+						}
+					}
+					elem.className = jQuery.trim( cur );
+
+				}
+			}
+		}
+
+		return this;
+	},
+
+	removeClass: function( value ) {
+		var classes, elem, cur, clazz, j,
+			i = 0,
+			len = this.length,
+			proceed = arguments.length === 0 || typeof value === "string" && value;
+
+		if ( jQuery.isFunction( value ) ) {
+			return this.each(function( j ) {
+				jQuery( this ).removeClass( value.call( this, j, this.className ) );
+			});
+		}
+		if ( proceed ) {
+			classes = ( value || "" ).match( core_rnotwhite ) || [];
+
+			for ( ; i < len; i++ ) {
+				elem = this[ i ];
+				// This expression is here for better compressibility (see addClass)
+				cur = elem.nodeType === 1 && ( elem.className ?
+					( " " + elem.className + " " ).replace( rclass, " " ) :
+					""
+				);
+
+				if ( cur ) {
+					j = 0;
+					while ( (clazz = classes[j++]) ) {
+						// Remove *all* instances
+						while ( cur.indexOf( " " + clazz + " " ) >= 0 ) {
+							cur = cur.replace( " " + clazz + " ", " " );
+						}
+					}
+					elem.className = value ? jQuery.trim( cur ) : "";
+				}
+			}
+		}
+
+		return this;
+	},
+
+	toggleClass: function( value, stateVal ) {
+		var type = typeof value,
+			isBool = typeof stateVal === "boolean";
+
+		if ( jQuery.isFunction( value ) ) {
+			return this.each(function( i ) {
+				jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal );
+			});
+		}
+
+		return this.each(function() {
+			if ( type === "string" ) {
+				// toggle individual class names
+				var className,
+					i = 0,
+					self = jQuery( this ),
+					state = stateVal,
+					classNames = value.match( core_rnotwhite ) || [];
+
+				while ( (className = classNames[ i++ ]) ) {
+					// check each className given, space separated list
+					state = isBool ? state : !self.hasClass( className );
+					self[ state ? "addClass" : "removeClass" ]( className );
+				}
+
+			// Toggle whole class name
+			} else if ( type === "undefined" || type === "boolean" ) {
+				if ( this.className ) {
+					// store className if set
+					jQuery._data( this, "__className__", this.className );
+				}
+
+				// If the element has a class name or if we're passed "false",
+				// then remove the whole classname (if there was one, the above saved it).
+				// Otherwise bring back whatever was previously saved (if anything),
+				// falling back to the empty string if nothing was stored.
+				this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || "";
+			}
+		});
+	},
+
+	hasClass: function( selector ) {
+		var className = " " + selector + " ",
+			i = 0,
+			l = this.length;
+		for ( ; i < l; i++ ) {
+			if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) >= 0 ) {
+				return true;
+			}
+		}
+
+		return false;
+	},
+
+	val: function( value ) {
+		var hooks, ret, isFunction,
+			elem = this[0];
+
+		if ( !arguments.length ) {
+			if ( elem ) {
+				hooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ];
+
+				if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) {
+					return ret;
+				}
+
+				ret = elem.value;
+
+				return typeof ret === "string" ?
+					// handle most common string cases
+					ret.replace(rreturn, "") :
+					// handle cases where value is null/undef or number
+					ret == null ? "" : ret;
+			}
+
+			return;
+		}
+
+		isFunction = jQuery.isFunction( value );
+
+		return this.each(function( i ) {
+			var val,
+				self = jQuery(this);
+
+			if ( this.nodeType !== 1 ) {
+				return;
+			}
+
+			if ( isFunction ) {
+				val = value.call( this, i, self.val() );
+			} else {
+				val = value;
+			}
+
+			// Treat null/undefined as ""; convert numbers to string
+			if ( val == null ) {
+				val = "";
+			} else if ( typeof val === "number" ) {
+				val += "";
+			} else if ( jQuery.isArray( val ) ) {
+				val = jQuery.map(val, function ( value ) {
+					return value == null ? "" : value + "";
+				});
+			}
+
+			hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ];
+
+			// If set returns undefined, fall back to normal setting
+			if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) {
+				this.value = val;
+			}
+		});
+	}
+});
+
+jQuery.extend({
+	valHooks: {
+		option: {
+			get: function( elem ) {
+				// attributes.value is undefined in Blackberry 4.7 but
+				// uses .value. See #6932
+				var val = elem.attributes.value;
+				return !val || val.specified ? elem.value : elem.text;
+			}
+		},
+		select: {
+			get: function( elem ) {
+				var value, option,
+					options = elem.options,
+					index = elem.selectedIndex,
+					one = elem.type === "select-one" || index < 0,
+					values = one ? null : [],
+					max = one ? index + 1 : options.length,
+					i = index < 0 ?
+						max :
+						one ? index : 0;
+
+				// Loop through all the selected options
+				for ( ; i < max; i++ ) {
+					option = options[ i ];
+
+					// oldIE doesn't update selected after form reset (#2551)
+					if ( ( option.selected || i === index ) &&
+							// Don't return options that are disabled or in a disabled optgroup
+							( jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null ) &&
+							( !option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" ) ) ) {
+
+						// Get the specific value for the option
+						value = jQuery( option ).val();
+
+						// We don't need an array for one selects
+						if ( one ) {
+							return value;
+						}
+
+						// Multi-Selects return an array
+						values.push( value );
+					}
+				}
+
+				return values;
+			},
+
+			set: function( elem, value ) {
+				var values = jQuery.makeArray( value );
+
+				jQuery(elem).find("option").each(function() {
+					this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0;
+				});
+
+				if ( !values.length ) {
+					elem.selectedIndex = -1;
+				}
+				return values;
+			}
+		}
+	},
+
+	attr: function( elem, name, value ) {
+		var ret, hooks, notxml,
+			nType = elem.nodeType;
+
+		// don't get/set attributes on text, comment and attribute nodes
+		if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
+			return;
+		}
+
+		// Fallback to prop when attributes are not supported
+		if ( typeof elem.getAttribute === "undefined" ) {
+			return jQuery.prop( elem, name, value );
+		}
+
+		notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
+
+		// All attributes are lowercase
+		// Grab necessary hook if one is defined
+		if ( notxml ) {
+			name = name.toLowerCase();
+			hooks = jQuery.attrHooks[ name ] || ( rboolean.test( name ) ? boolHook : nodeHook );
+		}
+
+		if ( value !== undefined ) {
+
+			if ( value === null ) {
+				jQuery.removeAttr( elem, name );
+
+			} else if ( hooks && notxml && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) {
+				return ret;
+
+			} else {
+				elem.setAttribute( name, value + "" );
+				return value;
+			}
+
+		} else if ( hooks && notxml && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) {
+			return ret;
+
+		} else {
+
+			// In IE9+, Flash objects don't have .getAttribute (#12945)
+			// Support: IE9+
+			if ( typeof elem.getAttribute !== "undefined" ) {
+				ret =  elem.getAttribute( name );
+			}
+
+			// Non-existent attributes return null, we normalize to undefined
+			return ret == null ?
+				undefined :
+				ret;
+		}
+	},
+
+	removeAttr: function( elem, value ) {
+		var name, propName,
+			i = 0,
+			attrNames = value && value.match( core_rnotwhite );
+
+		if ( attrNames && elem.nodeType === 1 ) {
+			while ( (name = attrNames[i++]) ) {
+				propName = jQuery.propFix[ name ] || name;
+
+				// Boolean attributes get special treatment (#10870)
+				if ( rboolean.test( name ) ) {
+					// Set corresponding property to false for boolean attributes
+					// Also clear defaultChecked/defaultSelected (if appropriate) for IE<8
+					if ( !getSetAttribute && ruseDefault.test( name ) ) {
+						elem[ jQuery.camelCase( "default-" + name ) ] =
+							elem[ propName ] = false;
+					} else {
+						elem[ propName ] = false;
+					}
+
+				// See #9699 for explanation of this approach (setting first, then removal)
+				} else {
+					jQuery.attr( elem, name, "" );
+				}
+
+				elem.removeAttribute( getSetAttribute ? name : propName );
+			}
+		}
+	},
+
+	attrHooks: {
+		type: {
+			set: function( elem, value ) {
+				if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) {
+					// Setting the type on a radio button after the value resets the value in IE6-9
+					// Reset value to default in case type is set after value during creation
+					var val = elem.value;
+					elem.setAttribute( "type", value );
+					if ( val ) {
+						elem.value = val;
+					}
+					return value;
+				}
+			}
+		}
+	},
+
+	propFix: {
+		tabindex: "tabIndex",
+		readonly: "readOnly",
+		"for": "htmlFor",
+		"class": "className",
+		maxlength: "maxLength",
+		cellspacing: "cellSpacing",
+		cellpadding: "cellPadding",
+		rowspan: "rowSpan",
+		colspan: "colSpan",
+		usemap: "useMap",
+		frameborder: "frameBorder",
+		contenteditable: "contentEditable"
+	},
+
+	prop: function( elem, name, value ) {
+		var ret, hooks, notxml,
+			nType = elem.nodeType;
+
+		// don't get/set properties on text, comment and attribute nodes
+		if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
+			return;
+		}
+
+		notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
+
+		if ( notxml ) {
+			// Fix name and attach hooks
+			name = jQuery.propFix[ name ] || name;
+			hooks = jQuery.propHooks[ name ];
+		}
+
+		if ( value !== undefined ) {
+			if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) {
+				return ret;
+
+			} else {
+				return ( elem[ name ] = value );
+			}
+
+		} else {
+			if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) {
+				return ret;
+
+			} else {
+				return elem[ name ];
+			}
+		}
+	},
+
+	propHooks: {
+		tabIndex: {
+			get: function( elem ) {
+				// elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set
+				// http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/
+				var attributeNode = elem.getAttributeNode("tabindex");
+
+				return attributeNode && attributeNode.specified ?
+					parseInt( attributeNode.value, 10 ) :
+					rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ?
+						0 :
+						undefined;
+			}
+		}
+	}
+});
+
+// Hook for boolean attributes
+boolHook = {
+	get: function( elem, name ) {
+		var
+			// Use .prop to determine if this attribute is understood as boolean
+			prop = jQuery.prop( elem, name ),
+
+			// Fetch it accordingly
+			attr = typeof prop === "boolean" && elem.getAttribute( name ),
+			detail = typeof prop === "boolean" ?
+
+				getSetInput && getSetAttribute ?
+					attr != null :
+					// oldIE fabricates an empty string for missing boolean attributes
+					// and conflates checked/selected into attroperties
+					ruseDefault.test( name ) ?
+						elem[ jQuery.camelCase( "default-" + name ) ] :
+						!!attr :
+
+				// fetch an attribute node for properties not recognized as boolean
+				elem.getAttributeNode( name );
+
+		return detail && detail.value !== false ?
+			name.toLowerCase() :
+			undefined;
+	},
+	set: function( elem, value, name ) {
+		if ( value === false ) {
+			// Remove boolean attributes when set to false
+			jQuery.removeAttr( elem, name );
+		} else if ( getSetInput && getSetAttribute || !ruseDefault.test( name ) ) {
+			// IE<8 needs the *property* name
+			elem.setAttribute( !getSetAttribute && jQuery.propFix[ name ] || name, name );
+
+		// Use defaultChecked and defaultSelected for oldIE
+		} else {
+			elem[ jQuery.camelCase( "default-" + name ) ] = elem[ name ] = true;
+		}
+
+		return name;
+	}
+};
+
+// fix oldIE value attroperty
+if ( !getSetInput || !getSetAttribute ) {
+	jQuery.attrHooks.value = {
+		get: function( elem, name ) {
+			var ret = elem.getAttributeNode( name );
+			return jQuery.nodeName( elem, "input" ) ?
+
+				// Ignore the value *property* by using defaultValue
+				elem.defaultValue :
+
+				ret && ret.specified ? ret.value : undefined;
+		},
+		set: function( elem, value, name ) {
+			if ( jQuery.nodeName( elem, "input" ) ) {
+				// Does not return so that setAttribute is also used
+				elem.defaultValue = value;
+			} else {
+				// Use nodeHook if defined (#1954); otherwise setAttribute is fine
+				return nodeHook && nodeHook.set( elem, value, name );
+			}
+		}
+	};
+}
+
+// IE6/7 do not support getting/setting some attributes with get/setAttribute
+if ( !getSetAttribute ) {
+
+	// Use this for any attribute in IE6/7
+	// This fixes almost every IE6/7 issue
+	nodeHook = jQuery.valHooks.button = {
+		get: function( elem, name ) {
+			var ret = elem.getAttributeNode( name );
+			return ret && ( name === "id" || name === "name" || name === "coords" ? ret.value !== "" : ret.specified ) ?
+				ret.value :
+				undefined;
+		},
+		set: function( elem, value, name ) {
+			// Set the existing or create a new attribute node
+			var ret = elem.getAttributeNode( name );
+			if ( !ret ) {
+				elem.setAttributeNode(
+					(ret = elem.ownerDocument.createAttribute( name ))
+				);
+			}
+
+			ret.value = value += "";
+
+			// Break association with cloned elements by also using setAttribute (#9646)
+			return name === "value" || value === elem.getAttribute( name ) ?
+				value :
+				undefined;
+		}
+	};
+
+	// Set contenteditable to false on removals(#10429)
+	// Setting to empty string throws an error as an invalid value
+	jQuery.attrHooks.contenteditable = {
+		get: nodeHook.get,
+		set: function( elem, value, name ) {
+			nodeHook.set( elem, value === "" ? false : value, name );
+		}
+	};
+
+	// Set width and height to auto instead of 0 on empty string( Bug #8150 )
+	// This is for removals
+	jQuery.each([ "width", "height" ], function( i, name ) {
+		jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], {
+			set: function( elem, value ) {
+				if ( value === "" ) {
+					elem.setAttribute( name, "auto" );
+					return value;
+				}
+			}
+		});
+	});
+}
+
+
+// Some attributes require a special call on IE
+// http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx
+if ( !jQuery.support.hrefNormalized ) {
+	jQuery.each([ "href", "src", "width", "height" ], function( i, name ) {
+		jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], {
+			get: function( elem ) {
+				var ret = elem.getAttribute( name, 2 );
+				return ret == null ? undefined : ret;
+			}
+		});
+	});
+
+	// href/src property should get the full normalized URL (#10299/#12915)
+	jQuery.each([ "href", "src" ], function( i, name ) {
+		jQuery.propHooks[ name ] = {
+			get: function( elem ) {
+				return elem.getAttribute( name, 4 );
+			}
+		};
+	});
+}
+
+if ( !jQuery.support.style ) {
+	jQuery.attrHooks.style = {
+		get: function( elem ) {
+			// Return undefined in the case of empty string
+			// Note: IE uppercases css property names, but if we were to .toLowerCase()
+			// .cssText, that would destroy case senstitivity in URL's, like in "background"
+			return elem.style.cssText || undefined;
+		},
+		set: function( elem, value ) {
+			return ( elem.style.cssText = value + "" );
+		}
+	};
+}
+
+// Safari mis-reports the default selected property of an option
+// Accessing the parent's selectedIndex property fixes it
+if ( !jQuery.support.optSelected ) {
+	jQuery.propHooks.selected = jQuery.extend( jQuery.propHooks.selected, {
+		get: function( elem ) {
+			var parent = elem.parentNode;
+
+			if ( parent ) {
+				parent.selectedIndex;
+
+				// Make sure that it also works with optgroups, see #5701
+				if ( parent.parentNode ) {
+					parent.parentNode.selectedIndex;
+				}
+			}
+			return null;
+		}
+	});
+}
+
+// IE6/7 call enctype encoding
+if ( !jQuery.support.enctype ) {
+	jQuery.propFix.enctype = "encoding";
+}
+
+// Radios and checkboxes getter/setter
+if ( !jQuery.support.checkOn ) {
+	jQuery.each([ "radio", "checkbox" ], function() {
+		jQuery.valHooks[ this ] = {
+			get: function( elem ) {
+				// Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified
+				return elem.getAttribute("value") === null ? "on" : elem.value;
+			}
+		};
+	});
+}
+jQuery.each([ "radio", "checkbox" ], function() {
+	jQuery.valHooks[ this ] = jQuery.extend( jQuery.valHooks[ this ], {
+		set: function( elem, value ) {
+			if ( jQuery.isArray( value ) ) {
+				return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 );
+			}
+		}
+	});
+});
+var rformElems = /^(?:input|select|textarea)$/i,
+	rkeyEvent = /^key/,
+	rmouseEvent = /^(?:mouse|contextmenu)|click/,
+	rfocusMorph = /^(?:focusinfocus|focusoutblur)$/,
+	rtypenamespace = /^([^.]*)(?:\.(.+)|)$/;
+
+function returnTrue() {
+	return true;
+}
+
+function returnFalse() {
+	return false;
+}
+
+/*
+ * Helper functions for managing events -- not part of the public interface.
+ * Props to Dean Edwards' addEvent library for many of the ideas.
+ */
+jQuery.event = {
+
+	global: {},
+
+	add: function( elem, types, handler, data, selector ) {
+
+		var handleObjIn, eventHandle, tmp,
+			events, t, handleObj,
+			special, handlers, type, namespaces, origType,
+			// Don't attach events to noData or text/comment nodes (but allow plain objects)
+			elemData = elem.nodeType !== 3 && elem.nodeType !== 8 && jQuery._data( elem );
+
+		if ( !elemData ) {
+			return;
+		}
+
+		// Caller can pass in an object of custom data in lieu of the handler
+		if ( handler.handler ) {
+			handleObjIn = handler;
+			handler = handleObjIn.handler;
+			selector = handleObjIn.selector;
+		}
+
+		// Make sure that the handler has a unique ID, used to find/remove it later
+		if ( !handler.guid ) {
+			handler.guid = jQuery.guid++;
+		}
+
+		// Init the element's event structure and main handler, if this is the first
+		if ( !(events = elemData.events) ) {
+			events = elemData.events = {};
+		}
+		if ( !(eventHandle = elemData.handle) ) {
+			eventHandle = elemData.handle = function( e ) {
+				// Discard the second event of a jQuery.event.trigger() and
+				// when an event is called after a page has unloaded
+				return typeof jQuery !== "undefined" && (!e || jQuery.event.triggered !== e.type) ?
+					jQuery.event.dispatch.apply( eventHandle.elem, arguments ) :
+					undefined;
+			};
+			// Add elem as a property of the handle fn to prevent a memory leak with IE non-native events
+			eventHandle.elem = elem;
+		}
+
+		// Handle multiple events separated by a space
+		// jQuery(...).bind("mouseover mouseout", fn);
+		types = ( types || "" ).match( core_rnotwhite ) || [""];
+		t = types.length;
+		while ( t-- ) {
+			tmp = rtypenamespace.exec( types[t] ) || [];
+			type = origType = tmp[1];
+			namespaces = ( tmp[2] || "" ).split( "." ).sort();
+
+			// If event changes its type, use the special event handlers for the changed type
+			special = jQuery.event.special[ type ] || {};
+
+			// If selector defined, determine special event api type, otherwise given type
+			type = ( selector ? special.delegateType : special.bindType ) || type;
+
+			// Update special based on newly reset type
+			special = jQuery.event.special[ type ] || {};
+
+			// handleObj is passed to all event handlers
+			handleObj = jQuery.extend({
+				type: type,
+				origType: origType,
+				data: data,
+				handler: handler,
+				guid: handler.guid,
+				selector: selector,
+				needsContext: selector && jQuery.expr.match.needsContext.test( selector ),
+				namespace: namespaces.join(".")
+			}, handleObjIn );
+
+			// Init the event handler queue if we're the first
+			if ( !(handlers = events[ type ]) ) {
+				handlers = events[ type ] = [];
+				handlers.delegateCount = 0;
+
+				// Only use addEventListener/attachEvent if the special events handler returns false
+				if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
+					// Bind the global event handler to the element
+					if ( elem.addEventListener ) {
+						elem.addEventListener( type, eventHandle, false );
+
+					} else if ( elem.attachEvent ) {
+						elem.attachEvent( "on" + type, eventHandle );
+					}
+				}
+			}
+
+			if ( special.add ) {
+				special.add.call( elem, handleObj );
+
+				if ( !handleObj.handler.guid ) {
+					handleObj.handler.guid = handler.guid;
+				}
+			}
+
+			// Add to the element's handler list, delegates in front
+			if ( selector ) {
+				handlers.splice( handlers.delegateCount++, 0, handleObj );
+			} else {
+				handlers.push( handleObj );
+			}
+
+			// Keep track of which events have ever been used, for event optimization
+			jQuery.event.global[ type ] = true;
+		}
+
+		// Nullify elem to prevent memory leaks in IE
+		elem = null;
+	},
+
+	// Detach an event or set of events from an element
+	remove: function( elem, types, handler, selector, mappedTypes ) {
+
+		var j, origCount, tmp,
+			events, t, handleObj,
+			special, handlers, type, namespaces, origType,
+			elemData = jQuery.hasData( elem ) && jQuery._data( elem );
+
+		if ( !elemData || !(events = elemData.events) ) {
+			return;
+		}
+
+		// Once for each type.namespace in types; type may be omitted
+		types = ( types || "" ).match( core_rnotwhite ) || [""];
+		t = types.length;
+		while ( t-- ) {
+			tmp = rtypenamespace.exec( types[t] ) || [];
+			type = origType = tmp[1];
+			namespaces = ( tmp[2] || "" ).split( "." ).sort();
+
+			// Unbind all events (on this namespace, if provided) for the element
+			if ( !type ) {
+				for ( type in events ) {
+					jQuery.event.remove( elem, type + types[ t ], handler, selector, true );
+				}
+				continue;
+			}
+
+			special = jQuery.event.special[ type ] || {};
+			type = ( selector ? special.delegateType : special.bindType ) || type;
+			handlers = events[ type ] || [];
+			tmp = tmp[2] && new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" );
+
+			// Remove matching events
+			origCount = j = handlers.length;
+			while ( j-- ) {
+				handleObj = handlers[ j ];
+
+				if ( ( mappedTypes || origType === handleObj.origType ) &&
+					( !handler || handler.guid === handleObj.guid ) &&
+					( !tmp || tmp.test( handleObj.namespace ) ) &&
+					( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) {
+					handlers.splice( j, 1 );
+
+					if ( handleObj.selector ) {
+						handlers.delegateCount--;
+					}
+					if ( special.remove ) {
+						special.remove.call( elem, handleObj );
+					}
+				}
+			}
+
+			// Remove generic event handler if we removed something and no more handlers exist
+			// (avoids potential for endless recursion during removal of special event handlers)
+			if ( origCount && !handlers.length ) {
+				if ( !special.teardown || special.teardown.call( elem, namespaces, elemData.handle ) === false ) {
+					jQuery.removeEvent( elem, type, elemData.handle );
+				}
+
+				delete events[ type ];
+			}
+		}
+
+		// Remove the expando if it's no longer used
+		if ( jQuery.isEmptyObject( events ) ) {
+			delete elemData.handle;
+
+			// removeData also checks for emptiness and clears the expando if empty
+			// so use it instead of delete
+			jQuery._removeData( elem, "events" );
+		}
+	},
+
+	trigger: function( event, data, elem, onlyHandlers ) {
+
+		var i, cur, tmp, bubbleType, ontype, handle, special,
+			eventPath = [ elem || document ],
+			type = event.type || event,
+			namespaces = event.namespace ? event.namespace.split(".") : [];
+
+		cur = tmp = elem = elem || document;
+
+		// Don't do events on text and comment nodes
+		if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
+			return;
+		}
+
+		// focus/blur morphs to focusin/out; ensure we're not firing them right now
+		if ( rfocusMorph.test( type + jQuery.event.triggered ) ) {
+			return;
+		}
+
+		if ( type.indexOf(".") >= 0 ) {
+			// Namespaced trigger; create a regexp to match event type in handle()
+			namespaces = type.split(".");
+			type = namespaces.shift();
+			namespaces.sort();
+		}
+		ontype = type.indexOf(":") < 0 && "on" + type;
+
+		// Caller can pass in a jQuery.Event object, Object, or just an event type string
+		event = event[ jQuery.expando ] ?
+			event :
+			new jQuery.Event( type, typeof event === "object" && event );
+
+		event.isTrigger = true;
+		event.namespace = namespaces.join(".");
+		event.namespace_re = event.namespace ?
+			new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" ) :
+			null;
+
+		// Clean up the event in case it is being reused
+		event.result = undefined;
+		if ( !event.target ) {
+			event.target = elem;
+		}
+
+		// Clone any incoming data and prepend the event, creating the handler arg list
+		data = data == null ?
+			[ event ] :
+			jQuery.makeArray( data, [ event ] );
+
+		// Allow special events to draw outside the lines
+		special = jQuery.event.special[ type ] || {};
+		if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) {
+			return;
+		}
+
+		// Determine event propagation path in advance, per W3C events spec (#9951)
+		// Bubble up to document, then to window; watch for a global ownerDocument var (#9724)
+		if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) {
+
+			bubbleType = special.delegateType || type;
+			if ( !rfocusMorph.test( bubbleType + type ) ) {
+				cur = cur.parentNode;
+			}
+			for ( ; cur; cur = cur.parentNode ) {
+				eventPath.push( cur );
+				tmp = cur;
+			}
+
+			// Only add window if we got to document (e.g., not plain obj or detached DOM)
+			if ( tmp === (elem.ownerDocument || document) ) {
+				eventPath.push( tmp.defaultView || tmp.parentWindow || window );
+			}
+		}
+
+		// Fire handlers on the event path
+		i = 0;
+		while ( (cur = eventPath[i++]) && !event.isPropagationStopped() ) {
+
+			event.type = i > 1 ?
+				bubbleType :
+				special.bindType || type;
+
+			// jQuery handler
+			handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" );
+			if ( handle ) {
+				handle.apply( cur, data );
+			}
+
+			// Native handler
+			handle = ontype && cur[ ontype ];
+			if ( handle && jQuery.acceptData( cur ) && handle.apply && handle.apply( cur, data ) === false ) {
+				event.preventDefault();
+			}
+		}
+		event.type = type;
+
+		// If nobody prevented the default action, do it now
+		if ( !onlyHandlers && !event.isDefaultPrevented() ) {
+
+			if ( (!special._default || special._default.apply( elem.ownerDocument, data ) === false) &&
+				!(type === "click" && jQuery.nodeName( elem, "a" )) && jQuery.acceptData( elem ) ) {
+
+				// Call a native DOM method on the target with the same name name as the event.
+				// Can't use an .isFunction() check here because IE6/7 fails that test.
+				// Don't do default actions on window, that's where global variables be (#6170)
+				if ( ontype && elem[ type ] && !jQuery.isWindow( elem ) ) {
+
+					// Don't re-trigger an onFOO event when we call its FOO() method
+					tmp = elem[ ontype ];
+
+					if ( tmp ) {
+						elem[ ontype ] = null;
+					}
+
+					// Prevent re-triggering of the same event, since we already bubbled it above
+					jQuery.event.triggered = type;
+					try {
+						elem[ type ]();
+					} catch ( e ) {
+						// IE<9 dies on focus/blur to hidden element (#1486,#12518)
+						// only reproducible on winXP IE8 native, not IE9 in IE8 mode
+					}
+					jQuery.event.triggered = undefined;
+
+					if ( tmp ) {
+						elem[ ontype ] = tmp;
+					}
+				}
+			}
+		}
+
+		return event.result;
+	},
+
+	dispatch: function( event ) {
+
+		// Make a writable jQuery.Event from the native event object
+		event = jQuery.event.fix( event );
+
+		var i, j, ret, matched, handleObj,
+			handlerQueue = [],
+			args = core_slice.call( arguments ),
+			handlers = ( jQuery._data( this, "events" ) || {} )[ event.type ] || [],
+			special = jQuery.event.special[ event.type ] || {};
+
+		// Use the fix-ed jQuery.Event rather than the (read-only) native event
+		args[0] = event;
+		event.delegateTarget = this;
+
+		// Call the preDispatch hook for the mapped type, and let it bail if desired
+		if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) {
+			return;
+		}
+
+		// Determine handlers
+		handlerQueue = jQuery.event.handlers.call( this, event, handlers );
+
+		// Run delegates first; they may want to stop propagation beneath us
+		i = 0;
+		while ( (matched = handlerQueue[ i++ ]) && !event.isPropagationStopped() ) {
+			event.currentTarget = matched.elem;
+
+			j = 0;
+			while ( (handleObj = matched.handlers[ j++ ]) && !event.isImmediatePropagationStopped() ) {
+
+				// Triggered event must either 1) have no namespace, or
+				// 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace).
+				if ( !event.namespace_re || event.namespace_re.test( handleObj.namespace ) ) {
+
+					event.handleObj = handleObj;
+					event.data = handleObj.data;
+
+					ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler )
+							.apply( matched.elem, args );
+
+					if ( ret !== undefined ) {
+						if ( (event.result = ret) === false ) {
+							event.preventDefault();
+							event.stopPropagation();
+						}
+					}
+				}
+			}
+		}
+
+		// Call the postDispatch hook for the mapped type
+		if ( special.postDispatch ) {
+			special.postDispatch.call( this, event );
+		}
+
+		return event.result;
+	},
+
+	handlers: function( event, handlers ) {
+		var i, matches, sel, handleObj,
+			handlerQueue = [],
+			delegateCount = handlers.delegateCount,
+			cur = event.target;
+
+		// Find delegate handlers
+		// Black-hole SVG <use> instance trees (#13180)
+		// Avoid non-left-click bubbling in Firefox (#3861)
+		if ( delegateCount && cur.nodeType && (!event.button || event.type !== "click") ) {
+
+			for ( ; cur != this; cur = cur.parentNode || this ) {
+
+				// Don't process clicks on disabled elements (#6911, #8165, #11382, #11764)
+				if ( cur.disabled !== true || event.type !== "click" ) {
+					matches = [];
+					for ( i = 0; i < delegateCount; i++ ) {
+						handleObj = handlers[ i ];
+
+						// Don't conflict with Object.prototype properties (#13203)
+						sel = handleObj.selector + " ";
+
+						if ( matches[ sel ] === undefined ) {
+							matches[ sel ] = handleObj.needsContext ?
+								jQuery( sel, this ).index( cur ) >= 0 :
+								jQuery.find( sel, this, null, [ cur ] ).length;
+						}
+						if ( matches[ sel ] ) {
+							matches.push( handleObj );
+						}
+					}
+					if ( matches.length ) {
+						handlerQueue.push({ elem: cur, handlers: matches });
+					}
+				}
+			}
+		}
+
+		// Add the remaining (directly-bound) handlers
+		if ( delegateCount < handlers.length ) {
+			handlerQueue.push({ elem: this, handlers: handlers.slice( delegateCount ) });
+		}
+
+		return handlerQueue;
+	},
+
+	fix: function( event ) {
+		if ( event[ jQuery.expando ] ) {
+			return event;
+		}
+
+		// Create a writable copy of the event object and normalize some properties
+		var i, prop,
+			originalEvent = event,
+			fixHook = jQuery.event.fixHooks[ event.type ] || {},
+			copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props;
+
+		event = new jQuery.Event( originalEvent );
+
+		i = copy.length;
+		while ( i-- ) {
+			prop = copy[ i ];
+			event[ prop ] = originalEvent[ prop ];
+		}
+
+		// Support: IE<9
+		// Fix target property (#1925)
+		if ( !event.target ) {
+			event.target = originalEvent.srcElement || document;
+		}
+
+		// Support: Chrome 23+, Safari?
+		// Target should not be a text node (#504, #13143)
+		if ( event.target.nodeType === 3 ) {
+			event.target = event.target.parentNode;
+		}
+
+		// Support: IE<9
+		// For mouse/key events, metaKey==false if it's undefined (#3368, #11328)
+		event.metaKey = !!event.metaKey;
+
+		return fixHook.filter ? fixHook.filter( event, originalEvent ) : event;
+	},
+
+	// Includes some event props shared by KeyEvent and MouseEvent
+	props: "altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),
+
+	fixHooks: {},
+
+	keyHooks: {
+		props: "char charCode key keyCode".split(" "),
+		filter: function( event, original ) {
+
+			// Add which for key events
+			if ( event.which == null ) {
+				event.which = original.charCode != null ? original.charCode : original.keyCode;
+			}
+
+			return event;
+		}
+	},
+
+	mouseHooks: {
+		props: "button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),
+		filter: function( event, original ) {
+			var eventDoc, doc, body,
+				button = original.button,
+				fromElement = original.fromElement;
+
+			// Calculate pageX/Y if missing and clientX/Y available
+			if ( event.pageX == null && original.clientX != null ) {
+				eventDoc = event.target.ownerDocument || document;
+				doc = eventDoc.documentElement;
+				body = eventDoc.body;
+
+				event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 );
+				event.pageY = original.clientY + ( doc && doc.scrollTop  || body && body.scrollTop  || 0 ) - ( doc && doc.clientTop  || body && body.clientTop  || 0 );
+			}
+
+			// Add relatedTarget, if necessary
+			if ( !event.relatedTarget && fromElement ) {
+				event.relatedTarget = fromElement === event.target ? original.toElement : fromElement;
+			}
+
+			// Add which for click: 1 === left; 2 === middle; 3 === right
+			// Note: button is not normalized, so don't use it
+			if ( !event.which && button !== undefined ) {
+				event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) );
+			}
+
+			return event;
+		}
+	},
+
+	special: {
+		load: {
+			// Prevent triggered image.load events from bubbling to window.load
+			noBubble: true
+		},
+		click: {
+			// For checkbox, fire native event so checked state will be right
+			trigger: function() {
+				if ( jQuery.nodeName( this, "input" ) && this.type === "checkbox" && this.click ) {
+					this.click();
+					return false;
+				}
+			}
+		},
+		focus: {
+			// Fire native event if possible so blur/focus sequence is correct
+			trigger: function() {
+				if ( this !== document.activeElement && this.focus ) {
+					try {
+						this.focus();
+						return false;
+					} catch ( e ) {
+						// Support: IE<9
+						// If we error on focus to hidden element (#1486, #12518),
+						// let .trigger() run the handlers
+					}
+				}
+			},
+			delegateType: "focusin"
+		},
+		blur: {
+			trigger: function() {
+				if ( this === document.activeElement && this.blur ) {
+					this.blur();
+					return false;
+				}
+			},
+			delegateType: "focusout"
+		},
+
+		beforeunload: {
+			postDispatch: function( event ) {
+
+				// Even when returnValue equals to undefined Firefox will still show alert
+				if ( event.result !== undefined ) {
+					event.originalEvent.returnValue = event.result;
+				}
+			}
+		}
+	},
+
+	simulate: function( type, elem, event, bubble ) {
+		// Piggyback on a donor event to simulate a different one.
+		// Fake originalEvent to avoid donor's stopPropagation, but if the
+		// simulated event prevents default then we do the same on the donor.
+		var e = jQuery.extend(
+			new jQuery.Event(),
+			event,
+			{ type: type,
+				isSimulated: true,
+				originalEvent: {}
+			}
+		);
+		if ( bubble ) {
+			jQuery.event.trigger( e, null, elem );
+		} else {
+			jQuery.event.dispatch.call( elem, e );
+		}
+		if ( e.isDefaultPrevented() ) {
+			event.preventDefault();
+		}
+	}
+};
+
+jQuery.removeEvent = document.removeEventListener ?
+	function( elem, type, handle ) {
+		if ( elem.removeEventListener ) {
+			elem.removeEventListener( type, handle, false );
+		}
+	} :
+	function( elem, type, handle ) {
+		var name = "on" + type;
+
+		if ( elem.detachEvent ) {
+
+			// #8545, #7054, preventing memory leaks for custom events in IE6-8
+			// detachEvent needed property on element, by name of that event, to properly expose it to GC
+			if ( typeof elem[ name ] === "undefined" ) {
+				elem[ name ] = null;
+			}
+
+			elem.detachEvent( name, handle );
+		}
+	};
+
+jQuery.Event = function( src, props ) {
+	// Allow instantiation without the 'new' keyword
+	if ( !(this instanceof jQuery.Event) ) {
+		return new jQuery.Event( src, props );
+	}
+
+	// Event object
+	if ( src && src.type ) {
+		this.originalEvent = src;
+		this.type = src.type;
+
+		// Events bubbling up the document may have been marked as prevented
+		// by a handler lower down the tree; reflect the correct value.
+		this.isDefaultPrevented = ( src.defaultPrevented || src.returnValue === false ||
+			src.getPreventDefault && src.getPreventDefault() ) ? returnTrue : returnFalse;
+
+	// Event type
+	} else {
+		this.type = src;
+	}
+
+	// Put explicitly provided properties onto the event object
+	if ( props ) {
+		jQuery.extend( this, props );
+	}
+
+	// Create a timestamp if incoming event doesn't have one
+	this.timeStamp = src && src.timeStamp || jQuery.now();
+
+	// Mark it as fixed
+	this[ jQuery.expando ] = true;
+};
+
+// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
+// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
+jQuery.Event.prototype = {
+	isDefaultPrevented: returnFalse,
+	isPropagationStopped: returnFalse,
+	isImmediatePropagationStopped: returnFalse,
+
+	preventDefault: function() {
+		var e = this.originalEvent;
+
+		this.isDefaultPrevented = returnTrue;
+		if ( !e ) {
+			return;
+		}
+
+		// If preventDefault exists, run it on the original event
+		if ( e.preventDefault ) {
+			e.preventDefault();
+
+		// Support: IE
+		// Otherwise set the returnValue property of the original event to false
+		} else {
+			e.returnValue = false;
+		}
+	},
+	stopPropagation: function() {
+		var e = this.originalEvent;
+
+		this.isPropagationStopped = returnTrue;
+		if ( !e ) {
+			return;
+		}
+		// If stopPropagation exists, run it on the original event
+		if ( e.stopPropagation ) {
+			e.stopPropagation();
+		}
+
+		// Support: IE
+		// Set the cancelBubble property of the original event to true
+		e.cancelBubble = true;
+	},
+	stopImmediatePropagation: function() {
+		this.isImmediatePropagationStopped = returnTrue;
+		this.stopPropagation();
+	}
+};
+
+// Create mouseenter/leave events using mouseover/out and event-time checks
+jQuery.each({
+	mouseenter: "mouseover",
+	mouseleave: "mouseout"
+}, function( orig, fix ) {
+	jQuery.event.special[ orig ] = {
+		delegateType: fix,
+		bindType: fix,
+
+		handle: function( event ) {
+			var ret,
+				target = this,
+				related = event.relatedTarget,
+				handleObj = event.handleObj;
+
+			// For mousenter/leave call the handler if related is outside the target.
+			// NB: No relatedTarget if the mouse left/entered the browser window
+			if ( !related || (related !== target && !jQuery.contains( target, related )) ) {
+				event.type = handleObj.origType;
+				ret = handleObj.handler.apply( this, arguments );
+				event.type = fix;
+			}
+			return ret;
+		}
+	};
+});
+
+// IE submit delegation
+if ( !jQuery.support.submitBubbles ) {
+
+	jQuery.event.special.submit = {
+		setup: function() {
+			// Only need this for delegated form submit events
+			if ( jQuery.nodeName( this, "form" ) ) {
+				return false;
+			}
+
+			// Lazy-add a submit handler when a descendant form may potentially be submitted
+			jQuery.event.add( this, "click._submit keypress._submit", function( e ) {
+				// Node name check avoids a VML-related crash in IE (#9807)
+				var elem = e.target,
+					form = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.form : undefined;
+				if ( form && !jQuery._data( form, "submitBubbles" ) ) {
+					jQuery.event.add( form, "submit._submit", function( event ) {
+						event._submit_bubble = true;
+					});
+					jQuery._data( form, "submitBubbles", true );
+				}
+			});
+			// return undefined since we don't need an event listener
+		},
+
+		postDispatch: function( event ) {
+			// If form was submitted by the user, bubble the event up the tree
+			if ( event._submit_bubble ) {
+				delete event._submit_bubble;
+				if ( this.parentNode && !event.isTrigger ) {
+					jQuery.event.simulate( "submit", this.parentNode, event, true );
+				}
+			}
+		},
+
+		teardown: function() {
+			// Only need this for delegated form submit events
+			if ( jQuery.nodeName( this, "form" ) ) {
+				return false;
+			}
+
+			// Remove delegated handlers; cleanData eventually reaps submit handlers attached above
+			jQuery.event.remove( this, "._submit" );
+		}
+	};
+}
+
+// IE change delegation and checkbox/radio fix
+if ( !jQuery.support.changeBubbles ) {
+
+	jQuery.event.special.change = {
+
+		setup: function() {
+
+			if ( rformElems.test( this.nodeName ) ) {
+				// IE doesn't fire change on a check/radio until blur; trigger it on click
+				// after a propertychange. Eat the blur-change in special.change.handle.
+				// This still fires onchange a second time for check/radio after blur.
+				if ( this.type === "checkbox" || this.type === "radio" ) {
+					jQuery.event.add( this, "propertychange._change", function( event ) {
+						if ( event.originalEvent.propertyName === "checked" ) {
+							this._just_changed = true;
+						}
+					});
+					jQuery.event.add( this, "click._change", function( event ) {
+						if ( this._just_changed && !event.isTrigger ) {
+							this._just_changed = false;
+						}
+						// Allow triggered, simulated change events (#11500)
+						jQuery.event.simulate( "change", this, event, true );
+					});
+				}
+				return false;
+			}
+			// Delegated event; lazy-add a change handler on descendant inputs
+			jQuery.event.add( this, "beforeactivate._change", function( e ) {
+				var elem = e.target;
+
+				if ( rformElems.test( elem.nodeName ) && !jQuery._data( elem, "changeBubbles" ) ) {
+					jQuery.event.add( elem, "change._change", function( event ) {
+						if ( this.parentNode && !event.isSimulated && !event.isTrigger ) {
+							jQuery.event.simulate( "change", this.parentNode, event, true );
+						}
+					});
+					jQuery._data( elem, "changeBubbles", true );
+				}
+			});
+		},
+
+		handle: function( event ) {
+			var elem = event.target;
+
+			// Swallow native change events from checkbox/radio, we already triggered them above
+			if ( this !== elem || event.isSimulated || event.isTrigger || (elem.type !== "radio" && elem.type !== "checkbox") ) {
+				return event.handleObj.handler.apply( this, arguments );
+			}
+		},
+
+		teardown: function() {
+			jQuery.event.remove( this, "._change" );
+
+			return !rformElems.test( this.nodeName );
+		}
+	};
+}
+
+// Create "bubbling" focus and blur events
+if ( !jQuery.support.focusinBubbles ) {
+	jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
+
+		// Attach a single capturing handler while someone wants focusin/focusout
+		var attaches = 0,
+			handler = function( event ) {
+				jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true );
+			};
+
+		jQuery.event.special[ fix ] = {
+			setup: function() {
+				if ( attaches++ === 0 ) {
+					document.addEventListener( orig, handler, true );
+				}
+			},
+			teardown: function() {
+				if ( --attaches === 0 ) {
+					document.removeEventListener( orig, handler, true );
+				}
+			}
+		};
+	});
+}
+
+jQuery.fn.extend({
+
+	on: function( types, selector, data, fn, /*INTERNAL*/ one ) {
+		var origFn, type;
+
+		// Types can be a map of types/handlers
+		if ( typeof types === "object" ) {
+			// ( types-Object, selector, data )
+			if ( typeof selector !== "string" ) {
+				// ( types-Object, data )
+				data = data || selector;
+				selector = undefined;
+			}
+			for ( type in types ) {
+				this.on( type, selector, data, types[ type ], one );
+			}
+			return this;
+		}
+
+		if ( data == null && fn == null ) {
+			// ( types, fn )
+			fn = selector;
+			data = selector = undefined;
+		} else if ( fn == null ) {
+			if ( typeof selector === "string" ) {
+				// ( types, selector, fn )
+				fn = data;
+				data = undefined;
+			} else {
+				// ( types, data, fn )
+				fn = data;
+				data = selector;
+				selector = undefined;
+			}
+		}
+		if ( fn === false ) {
+			fn = returnFalse;
+		} else if ( !fn ) {
+			return this;
+		}
+
+		if ( one === 1 ) {
+			origFn = fn;
+			fn = function( event ) {
+				// Can use an empty set, since event contains the info
+				jQuery().off( event );
+				return origFn.apply( this, arguments );
+			};
+			// Use same guid so caller can remove using origFn
+			fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );
+		}
+		return this.each( function() {
+			jQuery.event.add( this, types, fn, data, selector );
+		});
+	},
+	one: function( types, selector, data, fn ) {
+		return this.on( types, selector, data, fn, 1 );
+	},
+	off: function( types, selector, fn ) {
+		var handleObj, type;
+		if ( types && types.preventDefault && types.handleObj ) {
+			// ( event )  dispatched jQuery.Event
+			handleObj = types.handleObj;
+			jQuery( types.delegateTarget ).off(
+				handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType,
+				handleObj.selector,
+				handleObj.handler
+			);
+			return this;
+		}
+		if ( typeof types === "object" ) {
+			// ( types-object [, selector] )
+			for ( type in types ) {
+				this.off( type, selector, types[ type ] );
+			}
+			return this;
+		}
+		if ( selector === false || typeof selector === "function" ) {
+			// ( types [, fn] )
+			fn = selector;
+			selector = undefined;
+		}
+		if ( fn === false ) {
+			fn = returnFalse;
+		}
+		return this.each(function() {
+			jQuery.event.remove( this, types, fn, selector );
+		});
+	},
+
+	bind: function( types, data, fn ) {
+		return this.on( types, null, data, fn );
+	},
+	unbind: function( types, fn ) {
+		return this.off( types, null, fn );
+	},
+
+	delegate: function( selector, types, data, fn ) {
+		return this.on( types, selector, data, fn );
+	},
+	undelegate: function( selector, types, fn ) {
+		// ( namespace ) or ( selector, types [, fn] )
+		return arguments.length === 1 ? this.off( selector, "**" ) : this.off( types, selector || "**", fn );
+	},
+
+	trigger: function( type, data ) {
+		return this.each(function() {
+			jQuery.event.trigger( type, data, this );
+		});
+	},
+	triggerHandler: function( type, data ) {
+		var elem = this[0];
+		if ( elem ) {
+			return jQuery.event.trigger( type, data, elem, true );
+		}
+	},
+
+	hover: function( fnOver, fnOut ) {
+		return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
+	}
+});
+
+jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +
+	"mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
+	"change select submit keydown keypress keyup error contextmenu").split(" "), function( i, name ) {
+
+	// Handle event binding
+	jQuery.fn[ name ] = function( data, fn ) {
+		return arguments.length > 0 ?
+			this.on( name, null, data, fn ) :
+			this.trigger( name );
+	};
+
+	if ( rkeyEvent.test( name ) ) {
+		jQuery.event.fixHooks[ name ] = jQuery.event.keyHooks;
+	}
+
+	if ( rmouseEvent.test( name ) ) {
+		jQuery.event.fixHooks[ name ] = jQuery.event.mouseHooks;
+	}
+});
+/*!
+ * Sizzle CSS Selector Engine
+ * Copyright 2012 jQuery Foundation and other contributors
+ * Released under the MIT license
+ * http://sizzlejs.com/
+ */
+(function( window, undefined ) {
+
+var i,
+	cachedruns,
+	Expr,
+	getText,
+	isXML,
+	compile,
+	hasDuplicate,
+	outermostContext,
+
+	// Local document vars
+	setDocument,
+	document,
+	docElem,
+	documentIsXML,
+	rbuggyQSA,
+	rbuggyMatches,
+	matches,
+	contains,
+	sortOrder,
+
+	// Instance-specific data
+	expando = "sizzle" + -(new Date()),
+	preferredDoc = window.document,
+	support = {},
+	dirruns = 0,
+	done = 0,
+	classCache = createCache(),
+	tokenCache = createCache(),
+	compilerCache = createCache(),
+
+	// General-purpose constants
+	strundefined = typeof undefined,
+	MAX_NEGATIVE = 1 << 31,
+
+	// Array methods
+	arr = [],
+	pop = arr.pop,
+	push = arr.push,
+	slice = arr.slice,
+	// Use a stripped-down indexOf if we can't use a native one
+	indexOf = arr.indexOf || function( elem ) {
+		var i = 0,
+			len = this.length;
+		for ( ; i < len; i++ ) {
+			if ( this[i] === elem ) {
+				return i;
+			}
+		}
+		return -1;
+	},
+
+
+	// Regular expressions
+
+	// Whitespace characters http://www.w3.org/TR/css3-selectors/#whitespace
+	whitespace = "[\\x20\\t\\r\\n\\f]",
+	// http://www.w3.org/TR/css3-syntax/#characters
+	characterEncoding = "(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",
+
+	// Loosely modeled on CSS identifier characters
+	// An unquoted value should be a CSS identifier http://www.w3.org/TR/css3-selectors/#attribute-selectors
+	// Proper syntax: http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier
+	identifier = characterEncoding.replace( "w", "w#" ),
+
+	// Acceptable operators http://www.w3.org/TR/selectors/#attribute-selectors
+	operators = "([*^$|!~]?=)",
+	attributes = "\\[" + whitespace + "*(" + characterEncoding + ")" + whitespace +
+		"*(?:" + operators + whitespace + "*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|(" + identifier + ")|)|)" + whitespace + "*\\]",
+
+	// Prefer arguments quoted,
+	//   then not containing pseudos/brackets,
+	//   then attribute selectors/non-parenthetical expressions,
+	//   then anything else
+	// These preferences are here to reduce the number of selectors
+	//   needing tokenize in the PSEUDO preFilter
+	pseudos = ":(" + characterEncoding + ")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|" + attributes.replace( 3, 8 ) + ")*)|.*)\\)|)",
+
+	// Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter
+	rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ),
+
+	rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ),
+	rcombinators = new RegExp( "^" + whitespace + "*([\\x20\\t\\r\\n\\f>+~])" + whitespace + "*" ),
+	rpseudo = new RegExp( pseudos ),
+	ridentifier = new RegExp( "^" + identifier + "$" ),
+
+	matchExpr = {
+		"ID": new RegExp( "^#(" + characterEncoding + ")" ),
+		"CLASS": new RegExp( "^\\.(" + characterEncoding + ")" ),
+		"NAME": new RegExp( "^\\[name=['\"]?(" + characterEncoding + ")['\"]?\\]" ),
+		"TAG": new RegExp( "^(" + characterEncoding.replace( "w", "w*" ) + ")" ),
+		"ATTR": new RegExp( "^" + attributes ),
+		"PSEUDO": new RegExp( "^" + pseudos ),
+		"CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace +
+			"*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace +
+			"*(\\d+)|))" + whitespace + "*\\)|)", "i" ),
+		// For use in libraries implementing .is()
+		// We use this for POS matching in `select`
+		"needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" +
+			whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" )
+	},
+
+	rsibling = /[\x20\t\r\n\f]*[+~]/,
+
+	rnative = /\{\s*\[native code\]\s*\}/,
+
+	// Easily-parseable/retrievable ID or TAG or CLASS selectors
+	rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,
+
+	rinputs = /^(?:input|select|textarea|button)$/i,
+	rheader = /^h\d$/i,
+
+	rescape = /'|\\/g,
+	rattributeQuotes = /\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g,
+
+	// CSS escapes http://www.w3.org/TR/CSS21/syndata.html#escaped-characters
+	runescape = /\\([\da-fA-F]{1,6}[\x20\t\r\n\f]?|.)/g,
+	funescape = function( _, escaped ) {
+		var high = "0x" + escaped - 0x10000;
+		// NaN means non-codepoint
+		return high !== high ?
+			escaped :
+			// BMP codepoint
+			high < 0 ?
+				String.fromCharCode( high + 0x10000 ) :
+				// Supplemental Plane codepoint (surrogate pair)
+				String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 );
+	};
+
+// Use a stripped-down slice if we can't use a native one
+try {
+	slice.call( docElem.childNodes, 0 )[0].nodeType;
+} catch ( e ) {
+	slice = function( i ) {
+		var elem,
+			results = [];
+		for ( ; (elem = this[i]); i++ ) {
+			results.push( elem );
+		}
+		return results;
+	};
+}
+
+/**
+ * For feature detection
+ * @param {Function} fn The function to test for native support
+ */
+function isNative( fn ) {
+	return rnative.test( fn + "" );
+}
+
+/**
+ * Create key-value caches of limited size
+ * @returns {Function(string, Object)} Returns the Object data after storing it on itself with
+ *	property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength)
+ *	deleting the oldest entry
+ */
+function createCache() {
+	var cache,
+		keys = [];
+
+	return (cache = function( key, value ) {
+		// Use (key + " ") to avoid collision with native prototype properties (see Issue #157)
+		if ( keys.push( key += " " ) > Expr.cacheLength ) {
+			// Only keep the most recent entries
+			delete cache[ keys.shift() ];
+		}
+		return (cache[ key ] = value);
+	});
+}
+
+/**
+ * Mark a function for special use by Sizzle
+ * @param {Function} fn The function to mark
+ */
+function markFunction( fn ) {
+	fn[ expando ] = true;
+	return fn;
+}
+
+/**
+ * Support testing using an element
+ * @param {Function} fn Passed the created div and expects a boolean result
+ */
+function assert( fn ) {
+	var div = document.createElement("div");
+
+	try {
+		return fn( div );
+	} catch (e) {
+		return false;
+	} finally {
+		// release memory in IE
+		div = null;
+	}
+}
+
+function Sizzle( selector, context, results, seed ) {
+	var match, elem, m, nodeType,
+		// QSA vars
+		i, groups, old, nid, newContext, newSelector;
+
+	if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) {
+		setDocument( context );
+	}
+
+	context = context || document;
+	results = results || [];
+
+	if ( !selector || typeof selector !== "string" ) {
+		return results;
+	}
+
+	if ( (nodeType = context.nodeType) !== 1 && nodeType !== 9 ) {
+		return [];
+	}
+
+	if ( !documentIsXML && !seed ) {
+
+		// Shortcuts
+		if ( (match = rquickExpr.exec( selector )) ) {
+			// Speed-up: Sizzle("#ID")
+			if ( (m = match[1]) ) {
+				if ( nodeType === 9 ) {
+					elem = context.getElementById( m );
+					// Check parentNode to catch when Blackberry 4.6 returns
+					// nodes that are no longer in the document #6963
+					if ( elem && elem.parentNode ) {
+						// Handle the case where IE, Opera, and Webkit return items
+						// by name instead of ID
+						if ( elem.id === m ) {
+							results.push( elem );
+							return results;
+						}
+					} else {
+						return results;
+					}
+				} else {
+					// Context is not a document
+					if ( context.ownerDocument && (elem = context.ownerDocument.getElementById( m )) &&
+						contains( context, elem ) && elem.id === m ) {
+						results.push( elem );
+						return results;
+					}
+				}
+
+			// Speed-up: Sizzle("TAG")
+			} else if ( match[2] ) {
+				push.apply( results, slice.call(context.getElementsByTagName( selector ), 0) );
+				return results;
+
+			// Speed-up: Sizzle(".CLASS")
+			} else if ( (m = match[3]) && support.getByClassName && context.getElementsByClassName ) {
+				push.apply( results, slice.call(context.getElementsByClassName( m ), 0) );
+				return results;
+			}
+		}
+
+		// QSA path
+		if ( support.qsa && !rbuggyQSA.test(selector) ) {
+			old = true;
+			nid = expando;
+			newContext = context;
+			newSelector = nodeType === 9 && selector;
+
+			// qSA works strangely on Element-rooted queries
+			// We can work around this by specifying an extra ID on the root
+			// and working up from there (Thanks to Andrew Dupont for the technique)
+			// IE 8 doesn't work on object elements
+			if ( nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) {
+				groups = tokenize( selector );
+
+				if ( (old = context.getAttribute("id")) ) {
+					nid = old.replace( rescape, "\\$&" );
+				} else {
+					context.setAttribute( "id", nid );
+				}
+				nid = "[id='" + nid + "'] ";
+
+				i = groups.length;
+				while ( i-- ) {
+					groups[i] = nid + toSelector( groups[i] );
+				}
+				newContext = rsibling.test( selector ) && context.parentNode || context;
+				newSelector = groups.join(",");
+			}
+
+			if ( newSelector ) {
+				try {
+					push.apply( results, slice.call( newContext.querySelectorAll(
+						newSelector
+					), 0 ) );
+					return results;
+				} catch(qsaError) {
+				} finally {
+					if ( !old ) {
+						context.removeAttribute("id");
+					}
+				}
+			}
+		}
+	}
+
+	// All others
+	return select( selector.replace( rtrim, "$1" ), context, results, seed );
+}
+
+/**
+ * Detect xml
+ * @param {Element|Object} elem An element or a document
+ */
+isXML = Sizzle.isXML = function( elem ) {
+	// documentElement is verified for cases where it doesn't yet exist
+	// (such as loading iframes in IE - #4833)
+	var documentElement = elem && (elem.ownerDocument || elem).documentElement;
+	return documentElement ? documentElement.nodeName !== "HTML" : false;
+};
+
+/**
+ * Sets document-related variables once based on the current document
+ * @param {Element|Object} [doc] An element or document object to use to set the document
+ * @returns {Object} Returns the current document
+ */
+setDocument = Sizzle.setDocument = function( node ) {
+	var doc = node ? node.ownerDocument || node : preferredDoc;
+
+	// If no document and documentElement is available, return
+	if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) {
+		return document;
+	}
+
+	// Set our document
+	document = doc;
+	docElem = doc.documentElement;
+
+	// Support tests
+	documentIsXML = isXML( doc );
+
+	// Check if getElementsByTagName("*") returns only elements
+	support.tagNameNoComments = assert(function( div ) {
+		div.appendChild( doc.createComment("") );
+		return !div.getElementsByTagName("*").length;
+	});
+
+	// Check if attributes should be retrieved by attribute nodes
+	support.attributes = assert(function( div ) {
+		div.innerHTML = "<select></select>";
+		var type = typeof div.lastChild.getAttribute("multiple");
+		// IE8 returns a string for some attributes even when not present
+		return type !== "boolean" && type !== "string";
+	});
+
+	// Check if getElementsByClassName can be trusted
+	support.getByClassName = assert(function( div ) {
+		// Opera can't find a second classname (in 9.6)
+		div.innerHTML = "<div class='hidden e'></div><div class='hidden'></div>";
+		if ( !div.getElementsByClassName || !div.getElementsByClassName("e").length ) {
+			return false;
+		}
+
+		// Safari 3.2 caches class attributes and doesn't catch changes
+		div.lastChild.className = "e";
+		return div.getElementsByClassName("e").length === 2;
+	});
+
+	// Check if getElementById returns elements by name
+	// Check if getElementsByName privileges form controls or returns elements by ID
+	support.getByName = assert(function( div ) {
+		// Inject content
+		div.id = expando + 0;
+		div.innerHTML = "<a name='" + expando + "'></a><div name='" + expando + "'></div>";
+		docElem.insertBefore( div, docElem.firstChild );
+
+		// Test
+		var pass = doc.getElementsByName &&
+			// buggy browsers will return fewer than the correct 2
+			doc.getElementsByName( expando ).length === 2 +
+			// buggy browsers will return more than the correct 0
+			doc.getElementsByName( expando + 0 ).length;
+		support.getIdNotName = !doc.getElementById( expando );
+
+		// Cleanup
+		docElem.removeChild( div );
+
+		return pass;
+	});
+
+	// IE6/7 return modified attributes
+	Expr.attrHandle = assert(function( div ) {
+		div.innerHTML = "<a href='#'></a>";
+		return div.firstChild && typeof div.firstChild.getAttribute !== strundefined &&
+			div.firstChild.getAttribute("href") === "#";
+	}) ?
+		{} :
+		{
+			"href": function( elem ) {
+				return elem.getAttribute( "href", 2 );
+			},
+			"type": function( elem ) {
+				return elem.getAttribute("type");
+			}
+		};
+
+	// ID find and filter
+	if ( support.getIdNotName ) {
+		Expr.find["ID"] = function( id, context ) {
+			if ( typeof context.getElementById !== strundefined && !documentIsXML ) {
+				var m = context.getElementById( id );
+				// Check parentNode to catch when Blackberry 4.6 returns
+				// nodes that are no longer in the document #6963
+				return m && m.parentNode ? [m] : [];
+			}
+		};
+		Expr.filter["ID"] = function( id ) {
+			var attrId = id.replace( runescape, funescape );
+			return function( elem ) {
+				return elem.getAttribute("id") === attrId;
+			};
+		};
+	} else {
+		Expr.find["ID"] = function( id, context ) {
+			if ( typeof context.getElementById !== strundefined && !documentIsXML ) {
+				var m = context.getElementById( id );
+
+				return m ?
+					m.id === id || typeof m.getAttributeNode !== strundefined && m.getAttributeNode("id").value === id ?
+						[m] :
+						undefined :
+					[];
+			}
+		};
+		Expr.filter["ID"] =  function( id ) {
+			var attrId = id.replace( runescape, funescape );
+			return function( elem ) {
+				var node = typeof elem.getAttributeNode !== strundefined && elem.getAttributeNode("id");
+				return node && node.value === attrId;
+			};
+		};
+	}
+
+	// Tag
+	Expr.find["TAG"] = support.tagNameNoComments ?
+		function( tag, context ) {
+			if ( typeof context.getElementsByTagName !== strundefined ) {
+				return context.getElementsByTagName( tag );
+			}
+		} :
+		function( tag, context ) {
+			var elem,
+				tmp = [],
+				i = 0,
+				results = context.getElementsByTagName( tag );
+
+			// Filter out possible comments
+			if ( tag === "*" ) {
+				for ( ; (elem = results[i]); i++ ) {
+					if ( elem.nodeType === 1 ) {
+						tmp.push( elem );
+					}
+				}
+
+				return tmp;
+			}
+			return results;
+		};
+
+	// Name
+	Expr.find["NAME"] = support.getByName && function( tag, context ) {
+		if ( typeof context.getElementsByName !== strundefined ) {
+			return context.getElementsByName( name );
+		}
+	};
+
+	// Class
+	Expr.find["CLASS"] = support.getByClassName && function( className, context ) {
+		if ( typeof context.getElementsByClassName !== strundefined && !documentIsXML ) {
+			return context.getElementsByClassName( className );
+		}
+	};
+
+	// QSA and matchesSelector support
+
+	// matchesSelector(:active) reports false when true (IE9/Opera 11.5)
+	rbuggyMatches = [];
+
+	// qSa(:focus) reports false when true (Chrome 21),
+	// no need to also add to buggyMatches since matches checks buggyQSA
+	// A support test would require too much code (would include document ready)
+	rbuggyQSA = [ ":focus" ];
+
+	if ( (support.qsa = isNative(doc.querySelectorAll)) ) {
+		// Build QSA regex
+		// Regex strategy adopted from Diego Perini
+		assert(function( div ) {
+			// Select is set to empty string on purpose
+			// This is to test IE's treatment of not explictly
+			// setting a boolean content attribute,
+			// since its presence should be enough
+			// http://bugs.jquery.com/ticket/12359
+			div.innerHTML = "<select><option selected=''></option></select>";
+
+			// IE8 - Some boolean attributes are not treated correctly
+			if ( !div.querySelectorAll("[selected]").length ) {
+				rbuggyQSA.push( "\\[" + whitespace + "*(?:checked|disabled|ismap|multiple|readonly|selected|value)" );
+			}
+
+			// Webkit/Opera - :checked should return selected option elements
+			// http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
+			// IE8 throws error here and will not see later tests
+			if ( !div.querySelectorAll(":checked").length ) {
+				rbuggyQSA.push(":checked");
+			}
+		});
+
+		assert(function( div ) {
+
+			// Opera 10-12/IE8 - ^= $= *= and empty values
+			// Should not select anything
+			div.innerHTML = "<input type='hidden' i=''/>";
+			if ( div.querySelectorAll("[i^='']").length ) {
+				rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:\"\"|'')" );
+			}
+
+			// FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled)
+			// IE8 throws error here and will not see later tests
+			if ( !div.querySelectorAll(":enabled").length ) {
+				rbuggyQSA.push( ":enabled", ":disabled" );
+			}
+
+			// Opera 10-11 does not throw on post-comma invalid pseudos
+			div.querySelectorAll("*,:x");
+			rbuggyQSA.push(",.*:");
+		});
+	}
+
+	if ( (support.matchesSelector = isNative( (matches = docElem.matchesSelector ||
+		docElem.mozMatchesSelector ||
+		docElem.webkitMatchesSelector ||
+		docElem.oMatchesSelector ||
+		docElem.msMatchesSelector) )) ) {
+
+		assert(function( div ) {
+			// Check to see if it's possible to do matchesSelector
+			// on a disconnected node (IE 9)
+			support.disconnectedMatch = matches.call( div, "div" );
+
+			// This should fail with an exception
+			// Gecko does not error, returns false instead
+			matches.call( div, "[s!='']:x" );
+			rbuggyMatches.push( "!=", pseudos );
+		});
+	}
+
+	rbuggyQSA = new RegExp( rbuggyQSA.join("|") );
+	rbuggyMatches = new RegExp( rbuggyMatches.join("|") );
+
+	// Element contains another
+	// Purposefully does not implement inclusive descendent
+	// As in, an element does not contain itself
+	contains = isNative(docElem.contains) || docElem.compareDocumentPosition ?
+		function( a, b ) {
+			var adown = a.nodeType === 9 ? a.documentElement : a,
+				bup = b && b.parentNode;
+			return a === bup || !!( bup && bup.nodeType === 1 && (
+				adown.contains ?
+					adown.contains( bup ) :
+					a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16
+			));
+		} :
+		function( a, b ) {
+			if ( b ) {
+				while ( (b = b.parentNode) ) {
+					if ( b === a ) {
+						return true;
+					}
+				}
+			}
+			return false;
+		};
+
+	// Document order sorting
+	sortOrder = docElem.compareDocumentPosition ?
+	function( a, b ) {
+		var compare;
+
+		if ( a === b ) {
+			hasDuplicate = true;
+			return 0;
+		}
+
+		if ( (compare = b.compareDocumentPosition && a.compareDocumentPosition && a.compareDocumentPosition( b )) ) {
+			if ( compare & 1 || a.parentNode && a.parentNode.nodeType === 11 ) {
+				if ( a === doc || contains( preferredDoc, a ) ) {
+					return -1;
+				}
+				if ( b === doc || contains( preferredDoc, b ) ) {
+					return 1;
+				}
+				return 0;
+			}
+			return compare & 4 ? -1 : 1;
+		}
+
+		return a.compareDocumentPosition ? -1 : 1;
+	} :
+	function( a, b ) {
+		var cur,
+			i = 0,
+			aup = a.parentNode,
+			bup = b.parentNode,
+			ap = [ a ],
+			bp = [ b ];
+
+		// The nodes are identical, we can exit early
+		if ( a === b ) {
+			hasDuplicate = true;
+			return 0;
+
+		// Fallback to using sourceIndex (in IE) if it's available on both nodes
+		} else if ( a.sourceIndex && b.sourceIndex ) {
+			return ( ~b.sourceIndex || MAX_NEGATIVE ) - ( contains( preferredDoc, a ) && ~a.sourceIndex || MAX_NEGATIVE );
+
+		// Parentless nodes are either documents or disconnected
+		} else if ( !aup || !bup ) {
+			return a === doc ? -1 :
+				b === doc ? 1 :
+				aup ? -1 :
+				bup ? 1 :
+				0;
+
+		// If the nodes are siblings, we can do a quick check
+		} else if ( aup === bup ) {
+			return siblingCheck( a, b );
+		}
+
+		// Otherwise we need full lists of their ancestors for comparison
+		cur = a;
+		while ( (cur = cur.parentNode) ) {
+			ap.unshift( cur );
+		}
+		cur = b;
+		while ( (cur = cur.parentNode) ) {
+			bp.unshift( cur );
+		}
+
+		// Walk down the tree looking for a discrepancy
+		while ( ap[i] === bp[i] ) {
+			i++;
+		}
+
+		return i ?
+			// Do a sibling check if the nodes have a common ancestor
+			siblingCheck( ap[i], bp[i] ) :
+
+			// Otherwise nodes in our document sort first
+			ap[i] === preferredDoc ? -1 :
+			bp[i] === preferredDoc ? 1 :
+			0;
+	};
+
+	// Always assume the presence of duplicates if sort doesn't
+	// pass them to our comparison function (as in Google Chrome).
+	hasDuplicate = false;
+	[0, 0].sort( sortOrder );
+	support.detectDuplicates = hasDuplicate;
+
+	return document;
+};
+
+Sizzle.matches = function( expr, elements ) {
+	return Sizzle( expr, null, null, elements );
+};
+
+Sizzle.matchesSelector = function( elem, expr ) {
+	// Set document vars if needed
+	if ( ( elem.ownerDocument || elem ) !== document ) {
+		setDocument( elem );
+	}
+
+	// Make sure that attribute selectors are quoted
+	expr = expr.replace( rattributeQuotes, "='$1']" );
+
+	// rbuggyQSA always contains :focus, so no need for an existence check
+	if ( support.matchesSelector && !documentIsXML && (!rbuggyMatches || !rbuggyMatches.test(expr)) && !rbuggyQSA.test(expr) ) {
+		try {
+			var ret = matches.call( elem, expr );
+
+			// IE 9's matchesSelector returns false on disconnected nodes
+			if ( ret || support.disconnectedMatch ||
+					// As well, disconnected nodes are said to be in a document
+					// fragment in IE 9
+					elem.document && elem.document.nodeType !== 11 ) {
+				return ret;
+			}
+		} catch(e) {}
+	}
+
+	return Sizzle( expr, document, null, [elem] ).length > 0;
+};
+
+Sizzle.contains = function( context, elem ) {
+	// Set document vars if needed
+	if ( ( context.ownerDocument || context ) !== document ) {
+		setDocument( context );
+	}
+	return contains( context, elem );
+};
+
+Sizzle.attr = function( elem, name ) {
+	var val;
+
+	// Set document vars if needed
+	if ( ( elem.ownerDocument || elem ) !== document ) {
+		setDocument( elem );
+	}
+
+	if ( !documentIsXML ) {
+		name = name.toLowerCase();
+	}
+	if ( (val = Expr.attrHandle[ name ]) ) {
+		return val( elem );
+	}
+	if ( documentIsXML || support.attributes ) {
+		return elem.getAttribute( name );
+	}
+	return ( (val = elem.getAttributeNode( name )) || elem.getAttribute( name ) ) && elem[ name ] === true ?
+		name :
+		val && val.specified ? val.value : null;
+};
+
+Sizzle.error = function( msg ) {
+	throw new Error( "Syntax error, unrecognized expression: " + msg );
+};
+
+// Document sorting and removing duplicates
+Sizzle.uniqueSort = function( results ) {
+	var elem,
+		duplicates = [],
+		i = 1,
+		j = 0;
+
+	// Unless we *know* we can detect duplicates, assume their presence
+	hasDuplicate = !support.detectDuplicates;
+	results.sort( sortOrder );
+
+	if ( hasDuplicate ) {
+		for ( ; (elem = results[i]); i++ ) {
+			if ( elem === results[ i - 1 ] ) {
+				j = duplicates.push( i );
+			}
+		}
+		while ( j-- ) {
+			results.splice( duplicates[ j ], 1 );
+		}
+	}
+
+	return results;
+};
+
+function siblingCheck( a, b ) {
+	var cur = a && b && a.nextSibling;
+
+	for ( ; cur; cur = cur.nextSibling ) {
+		if ( cur === b ) {
+			return -1;
+		}
+	}
+
+	return a ? 1 : -1;
+}
+
+// Returns a function to use in pseudos for input types
+function createInputPseudo( type ) {
+	return function( elem ) {
+		var name = elem.nodeName.toLowerCase();
+		return name === "input" && elem.type === type;
+	};
+}
+
+// Returns a function to use in pseudos for buttons
+function createButtonPseudo( type ) {
+	return function( elem ) {
+		var name = elem.nodeName.toLowerCase();
+		return (name === "input" || name === "button") && elem.type === type;
+	};
+}
+
+// Returns a function to use in pseudos for positionals
+function createPositionalPseudo( fn ) {
+	return markFunction(function( argument ) {
+		argument = +argument;
+		return markFunction(function( seed, matches ) {
+			var j,
+				matchIndexes = fn( [], seed.length, argument ),
+				i = matchIndexes.length;
+
+			// Match elements found at the specified indexes
+			while ( i-- ) {
+				if ( seed[ (j = matchIndexes[i]) ] ) {
+					seed[j] = !(matches[j] = seed[j]);
+				}
+			}
+		});
+	});
+}
+
+/**
+ * Utility function for retrieving the text value of an array of DOM nodes
+ * @param {Array|Element} elem
+ */
+getText = Sizzle.getText = function( elem ) {
+	var node,
+		ret = "",
+		i = 0,
+		nodeType = elem.nodeType;
+
+	if ( !nodeType ) {
+		// If no nodeType, this is expected to be an array
+		for ( ; (node = elem[i]); i++ ) {
+			// Do not traverse comment nodes
+			ret += getText( node );
+		}
+	} else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {
+		// Use textContent for elements
+		// innerText usage removed for consistency of new lines (see #11153)
+		if ( typeof elem.textContent === "string" ) {
+			return elem.textContent;
+		} else {
+			// Traverse its children
+			for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
+				ret += getText( elem );
+			}
+		}
+	} else if ( nodeType === 3 || nodeType === 4 ) {
+		return elem.nodeValue;
+	}
+	// Do not include comment or processing instruction nodes
+
+	return ret;
+};
+
+Expr = Sizzle.selectors = {
+
+	// Can be adjusted by the user
+	cacheLength: 50,
+
+	createPseudo: markFunction,
+
+	match: matchExpr,
+
+	find: {},
+
+	relative: {
+		">": { dir: "parentNode", first: true },
+		" ": { dir: "parentNode" },
+		"+": { dir: "previousSibling", first: true },
+		"~": { dir: "previousSibling" }
+	},
+
+	preFilter: {
+		"ATTR": function( match ) {
+			match[1] = match[1].replace( runescape, funescape );
+
+			// Move the given value to match[3] whether quoted or unquoted
+			match[3] = ( match[4] || match[5] || "" ).replace( runescape, funescape );
+
+			if ( match[2] === "~=" ) {
+				match[3] = " " + match[3] + " ";
+			}
+
+			return match.slice( 0, 4 );
+		},
+
+		"CHILD": function( match ) {
+			/* matches from matchExpr["CHILD"]
+				1 type (only|nth|...)
+				2 what (child|of-type)
+				3 argument (even|odd|\d*|\d*n([+-]\d+)?|...)
+				4 xn-component of xn+y argument ([+-]?\d*n|)
+				5 sign of xn-component
+				6 x of xn-component
+				7 sign of y-component
+				8 y of y-component
+			*/
+			match[1] = match[1].toLowerCase();
+
+			if ( match[1].slice( 0, 3 ) === "nth" ) {
+				// nth-* requires argument
+				if ( !match[3] ) {
+					Sizzle.error( match[0] );
+				}
+
+				// numeric x and y parameters for Expr.filter.CHILD
+				// remember that false/true cast respectively to 0/1
+				match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) );
+				match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" );
+
+			// other types prohibit arguments
+			} else if ( match[3] ) {
+				Sizzle.error( match[0] );
+			}
+
+			return match;
+		},
+
+		"PSEUDO": function( match ) {
+			var excess,
+				unquoted = !match[5] && match[2];
+
+			if ( matchExpr["CHILD"].test( match[0] ) ) {
+				return null;
+			}
+
+			// Accept quoted arguments as-is
+			if ( match[4] ) {
+				match[2] = match[4];
+
+			// Strip excess characters from unquoted arguments
+			} else if ( unquoted && rpseudo.test( unquoted ) &&
+				// Get excess from tokenize (recursively)
+				(excess = tokenize( unquoted, true )) &&
+				// advance to the next closing parenthesis
+				(excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) {
+
+				// excess is a negative index
+				match[0] = match[0].slice( 0, excess );
+				match[2] = unquoted.slice( 0, excess );
+			}
+
+			// Return only captures needed by the pseudo filter method (type and argument)
+			return match.slice( 0, 3 );
+		}
+	},
+
+	filter: {
+
+		"TAG": function( nodeName ) {
+			if ( nodeName === "*" ) {
+				return function() { return true; };
+			}
+
+			nodeName = nodeName.replace( runescape, funescape ).toLowerCase();
+			return function( elem ) {
+				return elem.nodeName && elem.nodeName.toLowerCase() === nodeName;
+			};
+		},
+
+		"CLASS": function( className ) {
+			var pattern = classCache[ className + " " ];
+
+			return pattern ||
+				(pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) &&
+				classCache( className, function( elem ) {
+					return pattern.test( elem.className || (typeof elem.getAttribute !== strundefined && elem.getAttribute("class")) || "" );
+				});
+		},
+
+		"ATTR": function( name, operator, check ) {
+			return function( elem ) {
+				var result = Sizzle.attr( elem, name );
+
+				if ( result == null ) {
+					return operator === "!=";
+				}
+				if ( !operator ) {
+					return true;
+				}
+
+				result += "";
+
+				return operator === "=" ? result === check :
+					operator === "!=" ? result !== check :
+					operator === "^=" ? check && result.indexOf( check ) === 0 :
+					operator === "*=" ? check && result.indexOf( check ) > -1 :
+					operator === "$=" ? check && result.substr( result.length - check.length ) === check :
+					operator === "~=" ? ( " " + result + " " ).indexOf( check ) > -1 :
+					operator === "|=" ? result === check || result.substr( 0, check.length + 1 ) === check + "-" :
+					false;
+			};
+		},
+
+		"CHILD": function( type, what, argument, first, last ) {
+			var simple = type.slice( 0, 3 ) !== "nth",
+				forward = type.slice( -4 ) !== "last",
+				ofType = what === "of-type";
+
+			return first === 1 && last === 0 ?
+
+				// Shortcut for :nth-*(n)
+				function( elem ) {
+					return !!elem.parentNode;
+				} :
+
+				function( elem, context, xml ) {
+					var cache, outerCache, node, diff, nodeIndex, start,
+						dir = simple !== forward ? "nextSibling" : "previousSibling",
+						parent = elem.parentNode,
+						name = ofType && elem.nodeName.toLowerCase(),
+						useCache = !xml && !ofType;
+
+					if ( parent ) {
+
+						// :(first|last|only)-(child|of-type)
+						if ( simple ) {
+							while ( dir ) {
+								node = elem;
+								while ( (node = node[ dir ]) ) {
+									if ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) {
+										return false;
+									}
+								}
+								// Reverse direction for :only-* (if we haven't yet done so)
+								start = dir = type === "only" && !start && "nextSibling";
+							}
+							return true;
+						}
+
+						start = [ forward ? parent.firstChild : parent.lastChild ];
+
+						// non-xml :nth-child(...) stores cache data on `parent`
+						if ( forward && useCache ) {
+							// Seek `elem` from a previously-cached index
+							outerCache = parent[ expando ] || (parent[ expando ] = {});
+							cache = outerCache[ type ] || [];
+							nodeIndex = cache[0] === dirruns && cache[1];
+							diff = cache[0] === dirruns && cache[2];
+							node = nodeIndex && parent.childNodes[ nodeIndex ];
+
+							while ( (node = ++nodeIndex && node && node[ dir ] ||
+
+								// Fallback to seeking `elem` from the start
+								(diff = nodeIndex = 0) || start.pop()) ) {
+
+								// When found, cache indexes on `parent` and break
+								if ( node.nodeType === 1 && ++diff && node === elem ) {
+									outerCache[ type ] = [ dirruns, nodeIndex, diff ];
+									break;
+								}
+							}
+
+						// Use previously-cached element index if available
+						} else if ( useCache && (cache = (elem[ expando ] || (elem[ expando ] = {}))[ type ]) && cache[0] === dirruns ) {
+							diff = cache[1];
+
+						// xml :nth-child(...) or :nth-last-child(...) or :nth(-last)?-of-type(...)
+						} else {
+							// Use the same loop as above to seek `elem` from the start
+							while ( (node = ++nodeIndex && node && node[ dir ] ||
+								(diff = nodeIndex = 0) || start.pop()) ) {
+
+								if ( ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) && ++diff ) {
+									// Cache the index of each encountered element
+									if ( useCache ) {
+										(node[ expando ] || (node[ expando ] = {}))[ type ] = [ dirruns, diff ];
+									}
+
+									if ( node === elem ) {
+										break;
+									}
+								}
+							}
+						}
+
+						// Incorporate the offset, then check against cycle size
+						diff -= last;
+						return diff === first || ( diff % first === 0 && diff / first >= 0 );
+					}
+				};
+		},
+
+		"PSEUDO": function( pseudo, argument ) {
+			// pseudo-class names are case-insensitive
+			// http://www.w3.org/TR/selectors/#pseudo-classes
+			// Prioritize by case sensitivity in case custom pseudos are added with uppercase letters
+			// Remember that setFilters inherits from pseudos
+			var args,
+				fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] ||
+					Sizzle.error( "unsupported pseudo: " + pseudo );
+
+			// The user may use createPseudo to indicate that
+			// arguments are needed to create the filter function
+			// just as Sizzle does
+			if ( fn[ expando ] ) {
+				return fn( argument );
+			}
+
+			// But maintain support for old signatures
+			if ( fn.length > 1 ) {
+				args = [ pseudo, pseudo, "", argument ];
+				return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ?
+					markFunction(function( seed, matches ) {
+						var idx,
+							matched = fn( seed, argument ),
+							i = matched.length;
+						while ( i-- ) {
+							idx = indexOf.call( seed, matched[i] );
+							seed[ idx ] = !( matches[ idx ] = matched[i] );
+						}
+					}) :
+					function( elem ) {
+						return fn( elem, 0, args );
+					};
+			}
+
+			return fn;
+		}
+	},
+
+	pseudos: {
+		// Potentially complex pseudos
+		"not": markFunction(function( selector ) {
+			// Trim the selector passed to compile
+			// to avoid treating leading and trailing
+			// spaces as combinators
+			var input = [],
+				results = [],
+				matcher = compile( selector.replace( rtrim, "$1" ) );
+
+			return matcher[ expando ] ?
+				markFunction(function( seed, matches, context, xml ) {
+					var elem,
+						unmatched = matcher( seed, null, xml, [] ),
+						i = seed.length;
+
+					// Match elements unmatched by `matcher`
+					while ( i-- ) {
+						if ( (elem = unmatched[i]) ) {
+							seed[i] = !(matches[i] = elem);
+						}
+					}
+				}) :
+				function( elem, context, xml ) {
+					input[0] = elem;
+					matcher( input, null, xml, results );
+					return !results.pop();
+				};
+		}),
+
+		"has": markFunction(function( selector ) {
+			return function( elem ) {
+				return Sizzle( selector, elem ).length > 0;
+			};
+		}),
+
+		"contains": markFunction(function( text ) {
+			return function( elem ) {
+				return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1;
+			};
+		}),
+
+		// "Whether an element is represented by a :lang() selector
+		// is based solely on the element's language value
+		// being equal to the identifier C,
+		// or beginning with the identifier C immediately followed by "-".
+		// The matching of C against the element's language value is performed case-insensitively.
+		// The identifier C does not have to be a valid language name."
+		// http://www.w3.org/TR/selectors/#lang-pseudo
+		"lang": markFunction( function( lang ) {
+			// lang value must be a valid identifider
+			if ( !ridentifier.test(lang || "") ) {
+				Sizzle.error( "unsupported lang: " + lang );
+			}
+			lang = lang.replace( runescape, funescape ).toLowerCase();
+			return function( elem ) {
+				var elemLang;
+				do {
+					if ( (elemLang = documentIsXML ?
+						elem.getAttribute("xml:lang") || elem.getAttribute("lang") :
+						elem.lang) ) {
+
+						elemLang = elemLang.toLowerCase();
+						return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0;
+					}
+				} while ( (elem = elem.parentNode) && elem.nodeType === 1 );
+				return false;
+			};
+		}),
+
+		// Miscellaneous
+		"target": function( elem ) {
+			var hash = window.location && window.location.hash;
+			return hash && hash.slice( 1 ) === elem.id;
+		},
+
+		"root": function( elem ) {
+			return elem === docElem;
+		},
+
+		"focus": function( elem ) {
+			return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex);
+		},
+
+		// Boolean properties
+		"enabled": function( elem ) {
+			return elem.disabled === false;
+		},
+
+		"disabled": function( elem ) {
+			return elem.disabled === true;
+		},
+
+		"checked": function( elem ) {
+			// In CSS3, :checked should return both checked and selected elements
+			// http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
+			var nodeName = elem.nodeName.toLowerCase();
+			return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected);
+		},
+
+		"selected": function( elem ) {
+			// Accessing this property makes selected-by-default
+			// options in Safari work properly
+			if ( elem.parentNode ) {
+				elem.parentNode.selectedIndex;
+			}
+
+			return elem.selected === true;
+		},
+
+		// Contents
+		"empty": function( elem ) {
+			// http://www.w3.org/TR/selectors/#empty-pseudo
+			// :empty is only affected by element nodes and content nodes(including text(3), cdata(4)),
+			//   not comment, processing instructions, or others
+			// Thanks to Diego Perini for the nodeName shortcut
+			//   Greater than "@" means alpha characters (specifically not starting with "#" or "?")
+			for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
+				if ( elem.nodeName > "@" || elem.nodeType === 3 || elem.nodeType === 4 ) {
+					return false;
+				}
+			}
+			return true;
+		},
+
+		"parent": function( elem ) {
+			return !Expr.pseudos["empty"]( elem );
+		},
+
+		// Element/input types
+		"header": function( elem ) {
+			return rheader.test( elem.nodeName );
+		},
+
+		"input": function( elem ) {
+			return rinputs.test( elem.nodeName );
+		},
+
+		"button": function( elem ) {
+			var name = elem.nodeName.toLowerCase();
+			return name === "input" && elem.type === "button" || name === "button";
+		},
+
+		"text": function( elem ) {
+			var attr;
+			// IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc)
+			// use getAttribute instead to test this case
+			return elem.nodeName.toLowerCase() === "input" &&
+				elem.type === "text" &&
+				( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === elem.type );
+		},
+
+		// Position-in-collection
+		"first": createPositionalPseudo(function() {
+			return [ 0 ];
+		}),
+
+		"last": createPositionalPseudo(function( matchIndexes, length ) {
+			return [ length - 1 ];
+		}),
+
+		"eq": createPositionalPseudo(function( matchIndexes, length, argument ) {
+			return [ argument < 0 ? argument + length : argument ];
+		}),
+
+		"even": createPositionalPseudo(function( matchIndexes, length ) {
+			var i = 0;
+			for ( ; i < length; i += 2 ) {
+				matchIndexes.push( i );
+			}
+			return matchIndexes;
+		}),
+
+		"odd": createPositionalPseudo(function( matchIndexes, length ) {
+			var i = 1;
+			for ( ; i < length; i += 2 ) {
+				matchIndexes.push( i );
+			}
+			return matchIndexes;
+		}),
+
+		"lt": createPositionalPseudo(function( matchIndexes, length, argument ) {
+			var i = argument < 0 ? argument + length : argument;
+			for ( ; --i >= 0; ) {
+				matchIndexes.push( i );
+			}
+			return matchIndexes;
+		}),
+
+		"gt": createPositionalPseudo(function( matchIndexes, length, argument ) {
+			var i = argument < 0 ? argument + length : argument;
+			for ( ; ++i < length; ) {
+				matchIndexes.push( i );
+			}
+			return matchIndexes;
+		})
+	}
+};
+
+// Add button/input type pseudos
+for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) {
+	Expr.pseudos[ i ] = createInputPseudo( i );
+}
+for ( i in { submit: true, reset: true } ) {
+	Expr.pseudos[ i ] = createButtonPseudo( i );
+}
+
+function tokenize( selector, parseOnly ) {
+	var matched, match, tokens, type,
+		soFar, groups, preFilters,
+		cached = tokenCache[ selector + " " ];
+
+	if ( cached ) {
+		return parseOnly ? 0 : cached.slice( 0 );
+	}
+
+	soFar = selector;
+	groups = [];
+	preFilters = Expr.preFilter;
+
+	while ( soFar ) {
+
+		// Comma and first run
+		if ( !matched || (match = rcomma.exec( soFar )) ) {
+			if ( match ) {
+				// Don't consume trailing commas as valid
+				soFar = soFar.slice( match[0].length ) || soFar;
+			}
+			groups.push( tokens = [] );
+		}
+
+		matched = false;
+
+		// Combinators
+		if ( (match = rcombinators.exec( soFar )) ) {
+			matched = match.shift();
+			tokens.push( {
+				value: matched,
+				// Cast descendant combinators to space
+				type: match[0].replace( rtrim, " " )
+			} );
+			soFar = soFar.slice( matched.length );
+		}
+
+		// Filters
+		for ( type in Expr.filter ) {
+			if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] ||
+				(match = preFilters[ type ]( match ))) ) {
+				matched = match.shift();
+				tokens.push( {
+					value: matched,
+					type: type,
+					matches: match
+				} );
+				soFar = soFar.slice( matched.length );
+			}
+		}
+
+		if ( !matched ) {
+			break;
+		}
+	}
+
+	// Return the length of the invalid excess
+	// if we're just parsing
+	// Otherwise, throw an error or return tokens
+	return parseOnly ?
+		soFar.length :
+		soFar ?
+			Sizzle.error( selector ) :
+			// Cache the tokens
+			tokenCache( selector, groups ).slice( 0 );
+}
+
+function toSelector( tokens ) {
+	var i = 0,
+		len = tokens.length,
+		selector = "";
+	for ( ; i < len; i++ ) {
+		selector += tokens[i].value;
+	}
+	return selector;
+}
+
+function addCombinator( matcher, combinator, base ) {
+	var dir = combinator.dir,
+		checkNonElements = base && combinator.dir === "parentNode",
+		doneName = done++;
+
+	return combinator.first ?
+		// Check against closest ancestor/preceding element
+		function( elem, context, xml ) {
+			while ( (elem = elem[ dir ]) ) {
+				if ( elem.nodeType === 1 || checkNonElements ) {
+					return matcher( elem, context, xml );
+				}
+			}
+		} :
+
+		// Check against all ancestor/preceding elements
+		function( elem, context, xml ) {
+			var data, cache, outerCache,
+				dirkey = dirruns + " " + doneName;
+
+			// We can't set arbitrary data on XML nodes, so they don't benefit from dir caching
+			if ( xml ) {
+				while ( (elem = elem[ dir ]) ) {
+					if ( elem.nodeType === 1 || checkNonElements ) {
+						if ( matcher( elem, context, xml ) ) {
+							return true;
+						}
+					}
+				}
+			} else {
+				while ( (elem = elem[ dir ]) ) {
+					if ( elem.nodeType === 1 || checkNonElements ) {
+						outerCache = elem[ expando ] || (elem[ expando ] = {});
+						if ( (cache = outerCache[ dir ]) && cache[0] === dirkey ) {
+							if ( (data = cache[1]) === true || data === cachedruns ) {
+								return data === true;
+							}
+						} else {
+							cache = outerCache[ dir ] = [ dirkey ];
+							cache[1] = matcher( elem, context, xml ) || cachedruns;
+							if ( cache[1] === true ) {
+								return true;
+							}
+						}
+					}
+				}
+			}
+		};
+}
+
+function elementMatcher( matchers ) {
+	return matchers.length > 1 ?
+		function( elem, context, xml ) {
+			var i = matchers.length;
+			while ( i-- ) {
+				if ( !matchers[i]( elem, context, xml ) ) {
+					return false;
+				}
+			}
+			return true;
+		} :
+		matchers[0];
+}
+
+function condense( unmatched, map, filter, context, xml ) {
+	var elem,
+		newUnmatched = [],
+		i = 0,
+		len = unmatched.length,
+		mapped = map != null;
+
+	for ( ; i < len; i++ ) {
+		if ( (elem = unmatched[i]) ) {
+			if ( !filter || filter( elem, context, xml ) ) {
+				newUnmatched.push( elem );
+				if ( mapped ) {
+					map.push( i );
+				}
+			}
+		}
+	}
+
+	return newUnmatched;
+}
+
+function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) {
+	if ( postFilter && !postFilter[ expando ] ) {
+		postFilter = setMatcher( postFilter );
+	}
+	if ( postFinder && !postFinder[ expando ] ) {
+		postFinder = setMatcher( postFinder, postSelector );
+	}
+	return markFunction(function( seed, results, context, xml ) {
+		var temp, i, elem,
+			preMap = [],
+			postMap = [],
+			preexisting = results.length,
+
+			// Get initial elements from seed or context
+			elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ),
+
+			// Prefilter to get matcher input, preserving a map for seed-results synchronization
+			matcherIn = preFilter && ( seed || !selector ) ?
+				condense( elems, preMap, preFilter, context, xml ) :
+				elems,
+
+			matcherOut = matcher ?
+				// If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results,
+				postFinder || ( seed ? preFilter : preexisting || postFilter ) ?
+
+					// ...intermediate processing is necessary
+					[] :
+
+					// ...otherwise use results directly
+					results :
+				matcherIn;
+
+		// Find primary matches
+		if ( matcher ) {
+			matcher( matcherIn, matcherOut, context, xml );
+		}
+
+		// Apply postFilter
+		if ( postFilter ) {
+			temp = condense( matcherOut, postMap );
+			postFilter( temp, [], context, xml );
+
+			// Un-match failing elements by moving them back to matcherIn
+			i = temp.length;
+			while ( i-- ) {
+				if ( (elem = temp[i]) ) {
+					matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem);
+				}
+			}
+		}
+
+		if ( seed ) {
+			if ( postFinder || preFilter ) {
+				if ( postFinder ) {
+					// Get the final matcherOut by condensing this intermediate into postFinder contexts
+					temp = [];
+					i = matcherOut.length;
+					while ( i-- ) {
+						if ( (elem = matcherOut[i]) ) {
+							// Restore matcherIn since elem is not yet a final match
+							temp.push( (matcherIn[i] = elem) );
+						}
+					}
+					postFinder( null, (matcherOut = []), temp, xml );
+				}
+
+				// Move matched elements from seed to results to keep them synchronized
+				i = matcherOut.length;
+				while ( i-- ) {
+					if ( (elem = matcherOut[i]) &&
+						(temp = postFinder ? indexOf.call( seed, elem ) : preMap[i]) > -1 ) {
+
+						seed[temp] = !(results[temp] = elem);
+					}
+				}
+			}
+
+		// Add elements to results, through postFinder if defined
+		} else {
+			matcherOut = condense(
+				matcherOut === results ?
+					matcherOut.splice( preexisting, matcherOut.length ) :
+					matcherOut
+			);
+			if ( postFinder ) {
+				postFinder( null, results, matcherOut, xml );
+			} else {
+				push.apply( results, matcherOut );
+			}
+		}
+	});
+}
+
+function matcherFromTokens( tokens ) {
+	var checkContext, matcher, j,
+		len = tokens.length,
+		leadingRelative = Expr.relative[ tokens[0].type ],
+		implicitRelative = leadingRelative || Expr.relative[" "],
+		i = leadingRelative ? 1 : 0,
+
+		// The foundational matcher ensures that elements are reachable from top-level context(s)
+		matchContext = addCombinator( function( elem ) {
+			return elem === checkContext;
+		}, implicitRelative, true ),
+		matchAnyContext = addCombinator( function( elem ) {
+			return indexOf.call( checkContext, elem ) > -1;
+		}, implicitRelative, true ),
+		matchers = [ function( elem, context, xml ) {
+			return ( !leadingRelative && ( xml || context !== outermostContext ) ) || (
+				(checkContext = context).nodeType ?
+					matchContext( elem, context, xml ) :
+					matchAnyContext( elem, context, xml ) );
+		} ];
+
+	for ( ; i < len; i++ ) {
+		if ( (matcher = Expr.relative[ tokens[i].type ]) ) {
+			matchers = [ addCombinator(elementMatcher( matchers ), matcher) ];
+		} else {
+			matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches );
+
+			// Return special upon seeing a positional matcher
+			if ( matcher[ expando ] ) {
+				// Find the next relative operator (if any) for proper handling
+				j = ++i;
+				for ( ; j < len; j++ ) {
+					if ( Expr.relative[ tokens[j].type ] ) {
+						break;
+					}
+				}
+				return setMatcher(
+					i > 1 && elementMatcher( matchers ),
+					i > 1 && toSelector( tokens.slice( 0, i - 1 ) ).replace( rtrim, "$1" ),
+					matcher,
+					i < j && matcherFromTokens( tokens.slice( i, j ) ),
+					j < len && matcherFromTokens( (tokens = tokens.slice( j )) ),
+					j < len && toSelector( tokens )
+				);
+			}
+			matchers.push( matcher );
+		}
+	}
+
+	return elementMatcher( matchers );
+}
+
+function matcherFromGroupMatchers( elementMatchers, setMatchers ) {
+	// A counter to specify which element is currently being matched
+	var matcherCachedRuns = 0,
+		bySet = setMatchers.length > 0,
+		byElement = elementMatchers.length > 0,
+		superMatcher = function( seed, context, xml, results, expandContext ) {
+			var elem, j, matcher,
+				setMatched = [],
+				matchedCount = 0,
+				i = "0",
+				unmatched = seed && [],
+				outermost = expandContext != null,
+				contextBackup = outermostContext,
+				// We must always have either seed elements or context
+				elems = seed || byElement && Expr.find["TAG"]( "*", expandContext && context.parentNode || context ),
+				// Nested matchers should use non-integer dirruns
+				dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.E);
+
+			if ( outermost ) {
+				outermostContext = context !== document && context;
+				cachedruns = matcherCachedRuns;
+			}
+
+			// Add elements passing elementMatchers directly to results
+			for ( ; (elem = elems[i]) != null; i++ ) {
+				if ( byElement && elem ) {
+					for ( j = 0; (matcher = elementMatchers[j]); j++ ) {
+						if ( matcher( elem, context, xml ) ) {
+							results.push( elem );
+							break;
+						}
+					}
+					if ( outermost ) {
+						dirruns = dirrunsUnique;
+						cachedruns = ++matcherCachedRuns;
+					}
+				}
+
+				// Track unmatched elements for set filters
+				if ( bySet ) {
+					// They will have gone through all possible matchers
+					if ( (elem = !matcher && elem) ) {
+						matchedCount--;
+					}
+
+					// Lengthen the array for every element, matched or not
+					if ( seed ) {
+						unmatched.push( elem );
+					}
+				}
+			}
+
+			// Apply set filters to unmatched elements
+			// `i` starts as a string, so matchedCount would equal "00" if there are no elements
+			matchedCount += i;
+			if ( bySet && i !== matchedCount ) {
+				for ( j = 0; (matcher = setMatchers[j]); j++ ) {
+					matcher( unmatched, setMatched, context, xml );
+				}
+
+				if ( seed ) {
+					// Reintegrate element matches to eliminate the need for sorting
+					if ( matchedCount > 0 ) {
+						while ( i-- ) {
+							if ( !(unmatched[i] || setMatched[i]) ) {
+								setMatched[i] = pop.call( results );
+							}
+						}
+					}
+
+					// Discard index placeholder values to get only actual matches
+					setMatched = condense( setMatched );
+				}
+
+				// Add matches to results
+				push.apply( results, setMatched );
+
+				// Seedless set matches succeeding multiple successful matchers stipulate sorting
+				if ( outermost && !seed && setMatched.length > 0 &&
+					( matchedCount + setMatchers.length ) > 1 ) {
+
+					Sizzle.uniqueSort( results );
+				}
+			}
+
+			// Override manipulation of globals by nested matchers
+			if ( outermost ) {
+				dirruns = dirrunsUnique;
+				outermostContext = contextBackup;
+			}
+
+			return unmatched;
+		};
+
+	return bySet ?
+		markFunction( superMatcher ) :
+		superMatcher;
+}
+
+compile = Sizzle.compile = function( selector, group /* Internal Use Only */ ) {
+	var i,
+		setMatchers = [],
+		elementMatchers = [],
+		cached = compilerCache[ selector + " " ];
+
+	if ( !cached ) {
+		// Generate a function of recursive functions that can be used to check each element
+		if ( !group ) {
+			group = tokenize( selector );
+		}
+		i = group.length;
+		while ( i-- ) {
+			cached = matcherFromTokens( group[i] );
+			if ( cached[ expando ] ) {
+				setMatchers.push( cached );
+			} else {
+				elementMatchers.push( cached );
+			}
+		}
+
+		// Cache the compiled function
+		cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) );
+	}
+	return cached;
+};
+
+function multipleContexts( selector, contexts, results ) {
+	var i = 0,
+		len = contexts.length;
+	for ( ; i < len; i++ ) {
+		Sizzle( selector, contexts[i], results );
+	}
+	return results;
+}
+
+function select( selector, context, results, seed ) {
+	var i, tokens, token, type, find,
+		match = tokenize( selector );
+
+	if ( !seed ) {
+		// Try to minimize operations if there is only one group
+		if ( match.length === 1 ) {
+
+			// Take a shortcut and set the context if the root selector is an ID
+			tokens = match[0] = match[0].slice( 0 );
+			if ( tokens.length > 2 && (token = tokens[0]).type === "ID" &&
+					context.nodeType === 9 && !documentIsXML &&
+					Expr.relative[ tokens[1].type ] ) {
+
+				context = Expr.find["ID"]( token.matches[0].replace( runescape, funescape ), context )[0];
+				if ( !context ) {
+					return results;
+				}
+
+				selector = selector.slice( tokens.shift().value.length );
+			}
+
+			// Fetch a seed set for right-to-left matching
+			for ( i = matchExpr["needsContext"].test( selector ) ? -1 : tokens.length - 1; i >= 0; i-- ) {
+				token = tokens[i];
+
+				// Abort if we hit a combinator
+				if ( Expr.relative[ (type = token.type) ] ) {
+					break;
+				}
+				if ( (find = Expr.find[ type ]) ) {
+					// Search, expanding context for leading sibling combinators
+					if ( (seed = find(
+						token.matches[0].replace( runescape, funescape ),
+						rsibling.test( tokens[0].type ) && context.parentNode || context
+					)) ) {
+
+						// If seed is empty or no tokens remain, we can return early
+						tokens.splice( i, 1 );
+						selector = seed.length && toSelector( tokens );
+						if ( !selector ) {
+							push.apply( results, slice.call( seed, 0 ) );
+							return results;
+						}
+
+						break;
+					}
+				}
+			}
+		}
+	}
+
+	// Compile and execute a filtering function
+	// Provide `match` to avoid retokenization if we modified the selector above
+	compile( selector, match )(
+		seed,
+		context,
+		documentIsXML,
+		results,
+		rsibling.test( selector )
+	);
+	return results;
+}
+
+// Deprecated
+Expr.pseudos["nth"] = Expr.pseudos["eq"];
+
+// Easy API for creating new setFilters
+function setFilters() {}
+Expr.filters = setFilters.prototype = Expr.pseudos;
+Expr.setFilters = new setFilters();
+
+// Initialize with the default document
+setDocument();
+
+// Override sizzle attribute retrieval
+Sizzle.attr = jQuery.attr;
+jQuery.find = Sizzle;
+jQuery.expr = Sizzle.selectors;
+jQuery.expr[":"] = jQuery.expr.pseudos;
+jQuery.unique = Sizzle.uniqueSort;
+jQuery.text = Sizzle.getText;
+jQuery.isXMLDoc = Sizzle.isXML;
+jQuery.contains = Sizzle.contains;
+
+
+})( window );
+var runtil = /Until$/,
+	rparentsprev = /^(?:parents|prev(?:Until|All))/,
+	isSimple = /^.[^:#\[\.,]*$/,
+	rneedsContext = jQuery.expr.match.needsContext,
+	// methods guaranteed to produce a unique set when starting from a unique set
+	guaranteedUnique = {
+		children: true,
+		contents: true,
+		next: true,
+		prev: true
+	};
+
+jQuery.fn.extend({
+	find: function( selector ) {
+		var i, ret, self;
+
+		if ( typeof selector !== "string" ) {
+			self = this;
+			return this.pushStack( jQuery( selector ).filter(function() {
+				for ( i = 0; i < self.length; i++ ) {
+					if ( jQuery.contains( self[ i ], this ) ) {
+						return true;
+					}
+				}
+			}) );
+		}
+
+		ret = [];
+		for ( i = 0; i < this.length; i++ ) {
+			jQuery.find( selector, this[ i ], ret );
+		}
+
+		// Needed because $( selector, context ) becomes $( context ).find( selector )
+		ret = this.pushStack( jQuery.unique( ret ) );
+		ret.selector = ( this.selector ? this.selector + " " : "" ) + selector;
+		return ret;
+	},
+
+	has: function( target ) {
+		var i,
+			targets = jQuery( target, this ),
+			len = targets.length;
+
+		return this.filter(function() {
+			for ( i = 0; i < len; i++ ) {
+				if ( jQuery.contains( this, targets[i] ) ) {
+					return true;
+				}
+			}
+		});
+	},
+
+	not: function( selector ) {
+		return this.pushStack( winnow(this, selector, false) );
+	},
+
+	filter: function( selector ) {
+		return this.pushStack( winnow(this, selector, true) );
+	},
+
+	is: function( selector ) {
+		return !!selector && (
+			typeof selector === "string" ?
+				// If this is a positional/relative selector, check membership in the returned set
+				// so $("p:first").is("p:last") won't return true for a doc with two "p".
+				rneedsContext.test( selector ) ?
+					jQuery( selector, this.context ).index( this[0] ) >= 0 :
+					jQuery.filter( selector, this ).length > 0 :
+				this.filter( selector ).length > 0 );
+	},
+
+	closest: function( selectors, context ) {
+		var cur,
+			i = 0,
+			l = this.length,
+			ret = [],
+			pos = rneedsContext.test( selectors ) || typeof selectors !== "string" ?
+				jQuery( selectors, context || this.context ) :
+				0;
+
+		for ( ; i < l; i++ ) {
+			cur = this[i];
+
+			while ( cur && cur.ownerDocument && cur !== context && cur.nodeType !== 11 ) {
+				if ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) {
+					ret.push( cur );
+					break;
+				}
+				cur = cur.parentNode;
+			}
+		}
+
+		return this.pushStack( ret.length > 1 ? jQuery.unique( ret ) : ret );
+	},
+
+	// Determine the position of an element within
+	// the matched set of elements
+	index: function( elem ) {
+
+		// No argument, return index in parent
+		if ( !elem ) {
+			return ( this[0] && this[0].parentNode ) ? this.first().prevAll().length : -1;
+		}
+
+		// index in selector
+		if ( typeof elem === "string" ) {
+			return jQuery.inArray( this[0], jQuery( elem ) );
+		}
+
+		// Locate the position of the desired element
+		return jQuery.inArray(
+			// If it receives a jQuery object, the first element is used
+			elem.jquery ? elem[0] : elem, this );
+	},
+
+	add: function( selector, context ) {
+		var set = typeof selector === "string" ?
+				jQuery( selector, context ) :
+				jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ),
+			all = jQuery.merge( this.get(), set );
+
+		return this.pushStack( jQuery.unique(all) );
+	},
+
+	addBack: function( selector ) {
+		return this.add( selector == null ?
+			this.prevObject : this.prevObject.filter(selector)
+		);
+	}
+});
+
+jQuery.fn.andSelf = jQuery.fn.addBack;
+
+function sibling( cur, dir ) {
+	do {
+		cur = cur[ dir ];
+	} while ( cur && cur.nodeType !== 1 );
+
+	return cur;
+}
+
+jQuery.each({
+	parent: function( elem ) {
+		var parent = elem.parentNode;
+		return parent && parent.nodeType !== 11 ? parent : null;
+	},
+	parents: function( elem ) {
+		return jQuery.dir( elem, "parentNode" );
+	},
+	parentsUntil: function( elem, i, until ) {
+		return jQuery.dir( elem, "parentNode", until );
+	},
+	next: function( elem ) {
+		return sibling( elem, "nextSibling" );
+	},
+	prev: function( elem ) {
+		return sibling( elem, "previousSibling" );
+	},
+	nextAll: function( elem ) {
+		return jQuery.dir( elem, "nextSibling" );
+	},
+	prevAll: function( elem ) {
+		return jQuery.dir( elem, "previousSibling" );
+	},
+	nextUntil: function( elem, i, until ) {
+		return jQuery.dir( elem, "nextSibling", until );
+	},
+	prevUntil: function( elem, i, until ) {
+		return jQuery.dir( elem, "previousSibling", until );
+	},
+	siblings: function( elem ) {
+		return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem );
+	},
+	children: function( elem ) {
+		return jQuery.sibling( elem.firstChild );
+	},
+	contents: function( elem ) {
+		return jQuery.nodeName( elem, "iframe" ) ?
+			elem.contentDocument || elem.contentWindow.document :
+			jQuery.merge( [], elem.childNodes );
+	}
+}, function( name, fn ) {
+	jQuery.fn[ name ] = function( until, selector ) {
+		var ret = jQuery.map( this, fn, until );
+
+		if ( !runtil.test( name ) ) {
+			selector = until;
+		}
+
+		if ( selector && typeof selector === "string" ) {
+			ret = jQuery.filter( selector, ret );
+		}
+
+		ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret;
+
+		if ( this.length > 1 && rparentsprev.test( name ) ) {
+			ret = ret.reverse();
+		}
+
+		return this.pushStack( ret );
+	};
+});
+
+jQuery.extend({
+	filter: function( expr, elems, not ) {
+		if ( not ) {
+			expr = ":not(" + expr + ")";
+		}
+
+		return elems.length === 1 ?
+			jQuery.find.matchesSelector(elems[0], expr) ? [ elems[0] ] : [] :
+			jQuery.find.matches(expr, elems);
+	},
+
+	dir: function( elem, dir, until ) {
+		var matched = [],
+			cur = elem[ dir ];
+
+		while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) {
+			if ( cur.nodeType === 1 ) {
+				matched.push( cur );
+			}
+			cur = cur[dir];
+		}
+		return matched;
+	},
+
+	sibling: function( n, elem ) {
+		var r = [];
+
+		for ( ; n; n = n.nextSibling ) {
+			if ( n.nodeType === 1 && n !== elem ) {
+				r.push( n );
+			}
+		}
+
+		return r;
+	}
+});
+
+// Implement the identical functionality for filter and not
+function winnow( elements, qualifier, keep ) {
+
+	// Can't pass null or undefined to indexOf in Firefox 4
+	// Set to 0 to skip string check
+	qualifier = qualifier || 0;
+
+	if ( jQuery.isFunction( qualifier ) ) {
+		return jQuery.grep(elements, function( elem, i ) {
+			var retVal = !!qualifier.call( elem, i, elem );
+			return retVal === keep;
+		});
+
+	} else if ( qualifier.nodeType ) {
+		return jQuery.grep(elements, function( elem ) {
+			return ( elem === qualifier ) === keep;
+		});
+
+	} else if ( typeof qualifier === "string" ) {
+		var filtered = jQuery.grep(elements, function( elem ) {
+			return elem.nodeType === 1;
+		});
+
+		if ( isSimple.test( qualifier ) ) {
+			return jQuery.filter(qualifier, filtered, !keep);
+		} else {
+			qualifier = jQuery.filter( qualifier, filtered );
+		}
+	}
+
+	return jQuery.grep(elements, function( elem ) {
+		return ( jQuery.inArray( elem, qualifier ) >= 0 ) === keep;
+	});
+}
+function createSafeFragment( document ) {
+	var list = nodeNames.split( "|" ),
+		safeFrag = document.createDocumentFragment();
+
+	if ( safeFrag.createElement ) {
+		while ( list.length ) {
+			safeFrag.createElement(
+				list.pop()
+			);
+		}
+	}
+	return safeFrag;
+}
+
+var nodeNames = "abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|" +
+		"header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",
+	rinlinejQuery = / jQuery\d+="(?:null|\d+)"/g,
+	rnoshimcache = new RegExp("<(?:" + nodeNames + ")[\\s/>]", "i"),
+	rleadingWhitespace = /^\s+/,
+	rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,
+	rtagName = /<([\w:]+)/,
+	rtbody = /<tbody/i,
+	rhtml = /<|&#?\w+;/,
+	rnoInnerhtml = /<(?:script|style|link)/i,
+	manipulation_rcheckableType = /^(?:checkbox|radio)$/i,
+	// checked="checked" or checked
+	rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i,
+	rscriptType = /^$|\/(?:java|ecma)script/i,
+	rscriptTypeMasked = /^true\/(.*)/,
+	rcleanScript = /^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,
+
+	// We have to close these tags to support XHTML (#13200)
+	wrapMap = {
+		option: [ 1, "<select multiple='multiple'>", "</select>" ],
+		legend: [ 1, "<fieldset>", "</fieldset>" ],
+		area: [ 1, "<map>", "</map>" ],
+		param: [ 1, "<object>", "</object>" ],
+		thead: [ 1, "<table>", "</table>" ],
+		tr: [ 2, "<table><tbody>", "</tbody></table>" ],
+		col: [ 2, "<table><tbody></tbody><colgroup>", "</colgroup></table>" ],
+		td: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ],
+
+		// IE6-8 can't serialize link, script, style, or any html5 (NoScope) tags,
+		// unless wrapped in a div with non-breaking characters in front of it.
+		_default: jQuery.support.htmlSerialize ? [ 0, "", "" ] : [ 1, "X<div>", "</div>"  ]
+	},
+	safeFragment = createSafeFragment( document ),
+	fragmentDiv = safeFragment.appendChild( document.createElement("div") );
+
+wrapMap.optgroup = wrapMap.option;
+wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
+wrapMap.th = wrapMap.td;
+
+jQuery.fn.extend({
+	text: function( value ) {
+		return jQuery.access( this, function( value ) {
+			return value === undefined ?
+				jQuery.text( this ) :
+				this.empty().append( ( this[0] && this[0].ownerDocument || document ).createTextNode( value ) );
+		}, null, value, arguments.length );
+	},
+
+	wrapAll: function( html ) {
+		if ( jQuery.isFunction( html ) ) {
+			return this.each(function(i) {
+				jQuery(this).wrapAll( html.call(this, i) );
+			});
+		}
+
+		if ( this[0] ) {
+			// The elements to wrap the target around
+			var wrap = jQuery( html, this[0].ownerDocument ).eq(0).clone(true);
+
+			if ( this[0].parentNode ) {
+				wrap.insertBefore( this[0] );
+			}
+
+			wrap.map(function() {
+				var elem = this;
+
+				while ( elem.firstChild && elem.firstChild.nodeType === 1 ) {
+					elem = elem.firstChild;
+				}
+
+				return elem;
+			}).append( this );
+		}
+
+		return this;
+	},
+
+	wrapInner: function( html ) {
+		if ( jQuery.isFunction( html ) ) {
+			return this.each(function(i) {
+				jQuery(this).wrapInner( html.call(this, i) );
+			});
+		}
+
+		return this.each(function() {
+			var self = jQuery( this ),
+				contents = self.contents();
+
+			if ( contents.length ) {
+				contents.wrapAll( html );
+
+			} else {
+				self.append( html );
+			}
+		});
+	},
+
+	wrap: function( html ) {
+		var isFunction = jQuery.isFunction( html );
+
+		return this.each(function(i) {
+			jQuery( this ).wrapAll( isFunction ? html.call(this, i) : html );
+		});
+	},
+
+	unwrap: function() {
+		return this.parent().each(function() {
+			if ( !jQuery.nodeName( this, "body" ) ) {
+				jQuery( this ).replaceWith( this.childNodes );
+			}
+		}).end();
+	},
+
+	append: function() {
+		return this.domManip(arguments, true, function( elem ) {
+			if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
+				this.appendChild( elem );
+			}
+		});
+	},
+
+	prepend: function() {
+		return this.domManip(arguments, true, function( elem ) {
+			if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
+				this.insertBefore( elem, this.firstChild );
+			}
+		});
+	},
+
+	before: function() {
+		return this.domManip( arguments, false, function( elem ) {
+			if ( this.parentNode ) {
+				this.parentNode.insertBefore( elem, this );
+			}
+		});
+	},
+
+	after: function() {
+		return this.domManip( arguments, false, function( elem ) {
+			if ( this.parentNode ) {
+				this.parentNode.insertBefore( elem, this.nextSibling );
+			}
+		});
+	},
+
+	// keepData is for internal use only--do not document
+	remove: function( selector, keepData ) {
+		var elem,
+			i = 0;
+
+		for ( ; (elem = this[i]) != null; i++ ) {
+			if ( !selector || jQuery.filter( selector, [ elem ] ).length > 0 ) {
+				if ( !keepData && elem.nodeType === 1 ) {
+					jQuery.cleanData( getAll( elem ) );
+				}
+
+				if ( elem.parentNode ) {
+					if ( keepData && jQuery.contains( elem.ownerDocument, elem ) ) {
+						setGlobalEval( getAll( elem, "script" ) );
+					}
+					elem.parentNode.removeChild( elem );
+				}
+			}
+		}
+
+		return this;
+	},
+
+	empty: function() {
+		var elem,
+			i = 0;
+
+		for ( ; (elem = this[i]) != null; i++ ) {
+			// Remove element nodes and prevent memory leaks
+			if ( elem.nodeType === 1 ) {
+				jQuery.cleanData( getAll( elem, false ) );
+			}
+
+			// Remove any remaining nodes
+			while ( elem.firstChild ) {
+				elem.removeChild( elem.firstChild );
+			}
+
+			// If this is a select, ensure that it displays empty (#12336)
+			// Support: IE<9
+			if ( elem.options && jQuery.nodeName( elem, "select" ) ) {
+				elem.options.length = 0;
+			}
+		}
+
+		return this;
+	},
+
+	clone: function( dataAndEvents, deepDataAndEvents ) {
+		dataAndEvents = dataAndEvents == null ? false : dataAndEvents;
+		deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;
+
+		return this.map( function () {
+			return jQuery.clone( this, dataAndEvents, deepDataAndEvents );
+		});
+	},
+
+	html: function( value ) {
+		return jQuery.access( this, function( value ) {
+			var elem = this[0] || {},
+				i = 0,
+				l = this.length;
+
+			if ( value === undefined ) {
+				return elem.nodeType === 1 ?
+					elem.innerHTML.replace( rinlinejQuery, "" ) :
+					undefined;
+			}
+
+			// See if we can take a shortcut and just use innerHTML
+			if ( typeof value === "string" && !rnoInnerhtml.test( value ) &&
+				( jQuery.support.htmlSerialize || !rnoshimcache.test( value )  ) &&
+				( jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value ) ) &&
+				!wrapMap[ ( rtagName.exec( value ) || ["", ""] )[1].toLowerCase() ] ) {
+
+				value = value.replace( rxhtmlTag, "<$1></$2>" );
+
+				try {
+					for (; i < l; i++ ) {
+						// Remove element nodes and prevent memory leaks
+						elem = this[i] || {};
+						if ( elem.nodeType === 1 ) {
+							jQuery.cleanData( getAll( elem, false ) );
+							elem.innerHTML = value;
+						}
+					}
+
+					elem = 0;
+
+				// If using innerHTML throws an exception, use the fallback method
+				} catch(e) {}
+			}
+
+			if ( elem ) {
+				this.empty().append( value );
+			}
+		}, null, value, arguments.length );
+	},
+
+	replaceWith: function( value ) {
+		var isFunc = jQuery.isFunction( value );
+
+		// Make sure that the elements are removed from the DOM before they are inserted
+		// this can help fix replacing a parent with child elements
+		if ( !isFunc && typeof value !== "string" ) {
+			value = jQuery( value ).not( this ).detach();
+		}
+
+		return this.domManip( [ value ], true, function( elem ) {
+			var next = this.nextSibling,
+				parent = this.parentNode;
+
+			if ( parent && this.nodeType === 1 || this.nodeType === 11 ) {
+
+				jQuery( this ).remove();
+
+				if ( next ) {
+					next.parentNode.insertBefore( elem, next );
+				} else {
+					parent.appendChild( elem );
+				}
+			}
+		});
+	},
+
+	detach: function( selector ) {
+		return this.remove( selector, true );
+	},
+
+	domManip: function( args, table, callback ) {
+
+		// Flatten any nested arrays
+		args = core_concat.apply( [], args );
+
+		var fragment, first, scripts, hasScripts, node, doc,
+			i = 0,
+			l = this.length,
+			set = this,
+			iNoClone = l - 1,
+			value = args[0],
+			isFunction = jQuery.isFunction( value );
+
+		// We can't cloneNode fragments that contain checked, in WebKit
+		if ( isFunction || !( l <= 1 || typeof value !== "string" || jQuery.support.checkClone || !rchecked.test( value ) ) ) {
+			return this.each(function( index ) {
+				var self = set.eq( index );
+				if ( isFunction ) {
+					args[0] = value.call( this, index, table ? self.html() : undefined );
+				}
+				self.domManip( args, table, callback );
+			});
+		}
+
+		if ( l ) {
+			fragment = jQuery.buildFragment( args, this[ 0 ].ownerDocument, false, this );
+			first = fragment.firstChild;
+
+			if ( fragment.childNodes.length === 1 ) {
+				fragment = first;
+			}
+
+			if ( first ) {
+				table = table && jQuery.nodeName( first, "tr" );
+				scripts = jQuery.map( getAll( fragment, "script" ), disableScript );
+				hasScripts = scripts.length;
+
+				// Use the original fragment for the last item instead of the first because it can end up
+				// being emptied incorrectly in certain situations (#8070).
+				for ( ; i < l; i++ ) {
+					node = fragment;
+
+					if ( i !== iNoClone ) {
+						node = jQuery.clone( node, true, true );
+
+						// Keep references to cloned scripts for later restoration
+						if ( hasScripts ) {
+							jQuery.merge( scripts, getAll( node, "script" ) );
+						}
+					}
+
+					callback.call(
+						table && jQuery.nodeName( this[i], "table" ) ?
+							findOrAppend( this[i], "tbody" ) :
+							this[i],
+						node,
+						i
+					);
+				}
+
+				if ( hasScripts ) {
+					doc = scripts[ scripts.length - 1 ].ownerDocument;
+
+					// Reenable scripts
+					jQuery.map( scripts, restoreScript );
+
+					// Evaluate executable scripts on first document insertion
+					for ( i = 0; i < hasScripts; i++ ) {
+						node = scripts[ i ];
+						if ( rscriptType.test( node.type || "" ) &&
+							!jQuery._data( node, "globalEval" ) && jQuery.contains( doc, node ) ) {
+
+							if ( node.src ) {
+								// Hope ajax is available...
+								jQuery.ajax({
+									url: node.src,
+									type: "GET",
+									dataType: "script",
+									async: false,
+									global: false,
+									"throws": true
+								});
+							} else {
+								jQuery.globalEval( ( node.text || node.textContent || node.innerHTML || "" ).replace( rcleanScript, "" ) );
+							}
+						}
+					}
+				}
+
+				// Fix #11809: Avoid leaking memory
+				fragment = first = null;
+			}
+		}
+
+		return this;
+	}
+});
+
+function findOrAppend( elem, tag ) {
+	return elem.getElementsByTagName( tag )[0] || elem.appendChild( elem.ownerDocument.createElement( tag ) );
+}
+
+// Replace/restore the type attribute of script elements for safe DOM manipulation
+function disableScript( elem ) {
+	var attr = elem.getAttributeNode("type");
+	elem.type = ( attr && attr.specified ) + "/" + elem.type;
+	return elem;
+}
+function restoreScript( elem ) {
+	var match = rscriptTypeMasked.exec( elem.type );
+	if ( match ) {
+		elem.type = match[1];
+	} else {
+		elem.removeAttribute("type");
+	}
+	return elem;
+}
+
+// Mark scripts as having already been evaluated
+function setGlobalEval( elems, refElements ) {
+	var elem,
+		i = 0;
+	for ( ; (elem = elems[i]) != null; i++ ) {
+		jQuery._data( elem, "globalEval", !refElements || jQuery._data( refElements[i], "globalEval" ) );
+	}
+}
+
+function cloneCopyEvent( src, dest ) {
+
+	if ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) {
+		return;
+	}
+
+	var type, i, l,
+		oldData = jQuery._data( src ),
+		curData = jQuery._data( dest, oldData ),
+		events = oldData.events;
+
+	if ( events ) {
+		delete curData.handle;
+		curData.events = {};
+
+		for ( type in events ) {
+			for ( i = 0, l = events[ type ].length; i < l; i++ ) {
+				jQuery.event.add( dest, type, events[ type ][ i ] );
+			}
+		}
+	}
+
+	// make the cloned public data object a copy from the original
+	if ( curData.data ) {
+		curData.data = jQuery.extend( {}, curData.data );
+	}
+}
+
+function fixCloneNodeIssues( src, dest ) {
+	var nodeName, data, e;
+
+	// We do not need to do anything for non-Elements
+	if ( dest.nodeType !== 1 ) {
+		return;
+	}
+
+	nodeName = dest.nodeName.toLowerCase();
+
+	// IE6-8 copies events bound via attachEvent when using cloneNode.
+	if ( !jQuery.support.noCloneEvent && dest[ jQuery.expando ] ) {
+		data = jQuery._data( dest );
+
+		for ( e in data.events ) {
+			jQuery.removeEvent( dest, e, data.handle );
+		}
+
+		// Event data gets referenced instead of copied if the expando gets copied too
+		dest.removeAttribute( jQuery.expando );
+	}
+
+	// IE blanks contents when cloning scripts, and tries to evaluate newly-set text
+	if ( nodeName === "script" && dest.text !== src.text ) {
+		disableScript( dest ).text = src.text;
+		restoreScript( dest );
+
+	// IE6-10 improperly clones children of object elements using classid.
+	// IE10 throws NoModificationAllowedError if parent is null, #12132.
+	} else if ( nodeName === "object" ) {
+		if ( dest.parentNode ) {
+			dest.outerHTML = src.outerHTML;
+		}
+
+		// This path appears unavoidable for IE9. When cloning an object
+		// element in IE9, the outerHTML strategy above is not sufficient.
+		// If the src has innerHTML and the destination does not,
+		// copy the src.innerHTML into the dest.innerHTML. #10324
+		if ( jQuery.support.html5Clone && ( src.innerHTML && !jQuery.trim(dest.innerHTML) ) ) {
+			dest.innerHTML = src.innerHTML;
+		}
+
+	} else if ( nodeName === "input" && manipulation_rcheckableType.test( src.type ) ) {
+		// IE6-8 fails to persist the checked state of a cloned checkbox
+		// or radio button. Worse, IE6-7 fail to give the cloned element
+		// a checked appearance if the defaultChecked value isn't also set
+
+		dest.defaultChecked = dest.checked = src.checked;
+
+		// IE6-7 get confused and end up setting the value of a cloned
+		// checkbox/radio button to an empty string instead of "on"
+		if ( dest.value !== src.value ) {
+			dest.value = src.value;
+		}
+
+	// IE6-8 fails to return the selected option to the default selected
+	// state when cloning options
+	} else if ( nodeName === "option" ) {
+		dest.defaultSelected = dest.selected = src.defaultSelected;
+
+	// IE6-8 fails to set the defaultValue to the correct value when
+	// cloning other types of input fields
+	} else if ( nodeName === "input" || nodeName === "textarea" ) {
+		dest.defaultValue = src.defaultValue;
+	}
+}
+
+jQuery.each({
+	appendTo: "append",
+	prependTo: "prepend",
+	insertBefore: "before",
+	insertAfter: "after",
+	replaceAll: "replaceWith"
+}, function( name, original ) {
+	jQuery.fn[ name ] = function( selector ) {
+		var elems,
+			i = 0,
+			ret = [],
+			insert = jQuery( selector ),
+			last = insert.length - 1;
+
+		for ( ; i <= last; i++ ) {
+			elems = i === last ? this : this.clone(true);
+			jQuery( insert[i] )[ original ]( elems );
+
+			// Modern browsers can apply jQuery collections as arrays, but oldIE needs a .get()
+			core_push.apply( ret, elems.get() );
+		}
+
+		return this.pushStack( ret );
+	};
+});
+
+function getAll( context, tag ) {
+	var elems, elem,
+		i = 0,
+		found = typeof context.getElementsByTagName !== "undefined" ? context.getElementsByTagName( tag || "*" ) :
+			typeof context.querySelectorAll !== "undefined" ? context.querySelectorAll( tag || "*" ) :
+			undefined;
+
+	if ( !found ) {
+		for ( found = [], elems = context.childNodes || context; (elem = elems[i]) != null; i++ ) {
+			if ( !tag || jQuery.nodeName( elem, tag ) ) {
+				found.push( elem );
+			} else {
+				jQuery.merge( found, getAll( elem, tag ) );
+			}
+		}
+	}
+
+	return tag === undefined || tag && jQuery.nodeName( context, tag ) ?
+		jQuery.merge( [ context ], found ) :
+		found;
+}
+
+// Used in buildFragment, fixes the defaultChecked property
+function fixDefaultChecked( elem ) {
+	if ( manipulation_rcheckableType.test( elem.type ) ) {
+		elem.defaultChecked = elem.checked;
+	}
+}
+
+jQuery.extend({
+	clone: function( elem, dataAndEvents, deepDataAndEvents ) {
+		var destElements, srcElements, node, i, clone,
+			inPage = jQuery.contains( elem.ownerDocument, elem );
+
+		if ( jQuery.support.html5Clone || jQuery.isXMLDoc(elem) || !rnoshimcache.test( "<" + elem.nodeName + ">" ) ) {
+			clone = elem.cloneNode( true );
+
+		// IE<=8 does not properly clone detached, unknown element nodes
+		} else {
+			fragmentDiv.innerHTML = elem.outerHTML;
+			fragmentDiv.removeChild( clone = fragmentDiv.firstChild );
+		}
+
+		if ( (!jQuery.support.noCloneEvent || !jQuery.support.noCloneChecked) &&
+				(elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem) ) {
+
+			// We eschew Sizzle here for performance reasons: http://jsperf.com/getall-vs-sizzle/2
+			destElements = getAll( clone );
+			srcElements = getAll( elem );
+
+			// Fix all IE cloning issues
+			for ( i = 0; (node = srcElements[i]) != null; ++i ) {
+				// Ensure that the destination node is not null; Fixes #9587
+				if ( destElements[i] ) {
+					fixCloneNodeIssues( node, destElements[i] );
+				}
+			}
+		}
+
+		// Copy the events from the original to the clone
+		if ( dataAndEvents ) {
+			if ( deepDataAndEvents ) {
+				srcElements = srcElements || getAll( elem );
+				destElements = destElements || getAll( clone );
+
+				for ( i = 0; (node = srcElements[i]) != null; i++ ) {
+					cloneCopyEvent( node, destElements[i] );
+				}
+			} else {
+				cloneCopyEvent( elem, clone );
+			}
+		}
+
+		// Preserve script evaluation history
+		destElements = getAll( clone, "script" );
+		if ( destElements.length > 0 ) {
+			setGlobalEval( destElements, !inPage && getAll( elem, "script" ) );
+		}
+
+		destElements = srcElements = node = null;
+
+		// Return the cloned set
+		return clone;
+	},
+
+	buildFragment: function( elems, context, scripts, selection ) {
+		var contains, elem, tag, tmp, wrap, tbody, j,
+			l = elems.length,
+
+			// Ensure a safe fragment
+			safe = createSafeFragment( context ),
+
+			nodes = [],
+			i = 0;
+
+		for ( ; i < l; i++ ) {
+			elem = elems[ i ];
+
+			if ( elem || elem === 0 ) {
+
+				// Add nodes directly
+				if ( jQuery.type( elem ) === "object" ) {
+					jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem );
+
+				// Convert non-html into a text node
+				} else if ( !rhtml.test( elem ) ) {
+					nodes.push( context.createTextNode( elem ) );
+
+				// Convert html into DOM nodes
+				} else {
+					tmp = tmp || safe.appendChild( context.createElement("div") );
+
+					// Deserialize a standard representation
+					tag = ( rtagName.exec( elem ) || ["", ""] )[1].toLowerCase();
+					wrap = wrapMap[ tag ] || wrapMap._default;
+
+					tmp.innerHTML = wrap[1] + elem.replace( rxhtmlTag, "<$1></$2>" ) + wrap[2];
+
+					// Descend through wrappers to the right content
+					j = wrap[0];
+					while ( j-- ) {
+						tmp = tmp.lastChild;
+					}
+
+					// Manually add leading whitespace removed by IE
+					if ( !jQuery.support.leadingWhitespace && rleadingWhitespace.test( elem ) ) {
+						nodes.push( context.createTextNode( rleadingWhitespace.exec( elem )[0] ) );
+					}
+
+					// Remove IE's autoinserted <tbody> from table fragments
+					if ( !jQuery.support.tbody ) {
+
+						// String was a <table>, *may* have spurious <tbody>
+						elem = tag === "table" && !rtbody.test( elem ) ?
+							tmp.firstChild :
+
+							// String was a bare <thead> or <tfoot>
+							wrap[1] === "<table>" && !rtbody.test( elem ) ?
+								tmp :
+								0;
+
+						j = elem && elem.childNodes.length;
+						while ( j-- ) {
+							if ( jQuery.nodeName( (tbody = elem.childNodes[j]), "tbody" ) && !tbody.childNodes.length ) {
+								elem.removeChild( tbody );
+							}
+						}
+					}
+
+					jQuery.merge( nodes, tmp.childNodes );
+
+					// Fix #12392 for WebKit and IE > 9
+					tmp.textContent = "";
+
+					// Fix #12392 for oldIE
+					while ( tmp.firstChild ) {
+						tmp.removeChild( tmp.firstChild );
+					}
+
+					// Remember the top-level container for proper cleanup
+					tmp = safe.lastChild;
+				}
+			}
+		}
+
+		// Fix #11356: Clear elements from fragment
+		if ( tmp ) {
+			safe.removeChild( tmp );
+		}
+
+		// Reset defaultChecked for any radios and checkboxes
+		// about to be appended to the DOM in IE 6/7 (#8060)
+		if ( !jQuery.support.appendChecked ) {
+			jQuery.grep( getAll( nodes, "input" ), fixDefaultChecked );
+		}
+
+		i = 0;
+		while ( (elem = nodes[ i++ ]) ) {
+
+			// #4087 - If origin and destination elements are the same, and this is
+			// that element, do not do anything
+			if ( selection && jQuery.inArray( elem, selection ) !== -1 ) {
+				continue;
+			}
+
+			contains = jQuery.contains( elem.ownerDocument, elem );
+
+			// Append to fragment
+			tmp = getAll( safe.appendChild( elem ), "script" );
+
+			// Preserve script evaluation history
+			if ( contains ) {
+				setGlobalEval( tmp );
+			}
+
+			// Capture executables
+			if ( scripts ) {
+				j = 0;
+				while ( (elem = tmp[ j++ ]) ) {
+					if ( rscriptType.test( elem.type || "" ) ) {
+						scripts.push( elem );
+					}
+				}
+			}
+		}
+
+		tmp = null;
+
+		return safe;
+	},
+
+	cleanData: function( elems, /* internal */ acceptData ) {
+		var data, id, elem, type,
+			i = 0,
+			internalKey = jQuery.expando,
+			cache = jQuery.cache,
+			deleteExpando = jQuery.support.deleteExpando,
+			special = jQuery.event.special;
+
+		for ( ; (elem = elems[i]) != null; i++ ) {
+
+			if ( acceptData || jQuery.acceptData( elem ) ) {
+
+				id = elem[ internalKey ];
+				data = id && cache[ id ];
+
+				if ( data ) {
+					if ( data.events ) {
+						for ( type in data.events ) {
+							if ( special[ type ] ) {
+								jQuery.event.remove( elem, type );
+
+							// This is a shortcut to avoid jQuery.event.remove's overhead
+							} else {
+								jQuery.removeEvent( elem, type, data.handle );
+							}
+						}
+					}
+
+					// Remove cache only if it was not already removed by jQuery.event.remove
+					if ( cache[ id ] ) {
+
+						delete cache[ id ];
+
+						// IE does not allow us to delete expando properties from nodes,
+						// nor does it have a removeAttribute function on Document nodes;
+						// we must handle all of these cases
+						if ( deleteExpando ) {
+							delete elem[ internalKey ];
+
+						} else if ( typeof elem.removeAttribute !== "undefined" ) {
+							elem.removeAttribute( internalKey );
+
+						} else {
+							elem[ internalKey ] = null;
+						}
+
+						core_deletedIds.push( id );
+					}
+				}
+			}
+		}
+	}
+});
+var curCSS, getStyles, iframe,
+	ralpha = /alpha\([^)]*\)/i,
+	ropacity = /opacity\s*=\s*([^)]*)/,
+	rposition = /^(top|right|bottom|left)$/,
+	// swappable if display is none or starts with table except "table", "table-cell", or "table-caption"
+	// see here for display values: https://developer.mozilla.org/en-US/docs/CSS/display
+	rdisplayswap = /^(none|table(?!-c[ea]).+)/,
+	rmargin = /^margin/,
+	rnumsplit = new RegExp( "^(" + core_pnum + ")(.*)$", "i" ),
+	rnumnonpx = new RegExp( "^(" + core_pnum + ")(?!px)[a-z%]+$", "i" ),
+	rrelNum = new RegExp( "^([+-])=(" + core_pnum + ")", "i" ),
+	elemdisplay = { BODY: "block" },
+
+	cssShow = { position: "absolute", visibility: "hidden", display: "block" },
+	cssNormalTransform = {
+		letterSpacing: 0,
+		fontWeight: 400
+	},
+
+	cssExpand = [ "Top", "Right", "Bottom", "Left" ],
+	cssPrefixes = [ "Webkit", "O", "Moz", "ms" ];
+
+// return a css property mapped to a potentially vendor prefixed property
+function vendorPropName( style, name ) {
+
+	// shortcut for names that are not vendor prefixed
+	if ( name in style ) {
+		return name;
+	}
+
+	// check for vendor prefixed names
+	var capName = name.charAt(0).toUpperCase() + name.slice(1),
+		origName = name,
+		i = cssPrefixes.length;
+
+	while ( i-- ) {
+		name = cssPrefixes[ i ] + capName;
+		if ( name in style ) {
+			return name;
+		}
+	}
+
+	return origName;
+}
+
+function isHidden( elem, el ) {
+	// isHidden might be called from jQuery#filter function;
+	// in that case, element will be second argument
+	elem = el || elem;
+	return jQuery.css( elem, "display" ) === "none" || !jQuery.contains( elem.ownerDocument, elem );
+}
+
+function showHide( elements, show ) {
+	var elem,
+		values = [],
+		index = 0,
+		length = elements.length;
+
+	for ( ; index < length; index++ ) {
+		elem = elements[ index ];
+		if ( !elem.style ) {
+			continue;
+		}
+		values[ index ] = jQuery._data( elem, "olddisplay" );
+		if ( show ) {
+			// Reset the inline display of this element to learn if it is
+			// being hidden by cascaded rules or not
+			if ( !values[ index ] && elem.style.display === "none" ) {
+				elem.style.display = "";
+			}
+
+			// Set elements which have been overridden with display: none
+			// in a stylesheet to whatever the default browser style is
+			// for such an element
+			if ( elem.style.display === "" && isHidden( elem ) ) {
+				values[ index ] = jQuery._data( elem, "olddisplay", css_defaultDisplay(elem.nodeName) );
+			}
+		} else if ( !values[ index ] && !isHidden( elem ) ) {
+			jQuery._data( elem, "olddisplay", jQuery.css( elem, "display" ) );
+		}
+	}
+
+	// Set the display of most of the elements in a second loop
+	// to avoid the constant reflow
+	for ( index = 0; index < length; index++ ) {
+		elem = elements[ index ];
+		if ( !elem.style ) {
+			continue;
+		}
+		if ( !show || elem.style.display === "none" || elem.style.display === "" ) {
+			elem.style.display = show ? values[ index ] || "" : "none";
+		}
+	}
+
+	return elements;
+}
+
+jQuery.fn.extend({
+	css: function( name, value ) {
+		return jQuery.access( this, function( elem, name, value ) {
+			var styles, len,
+				map = {},
+				i = 0;
+
+			if ( jQuery.isArray( name ) ) {
+				styles = getStyles( elem );
+				len = name.length;
+
+				for ( ; i < len; i++ ) {
+					map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles );
+				}
+
+				return map;
+			}
+
+			return value !== undefined ?
+				jQuery.style( elem, name, value ) :
+				jQuery.css( elem, name );
+		}, name, value, arguments.length > 1 );
+	},
+	show: function() {
+		return showHide( this, true );
+	},
+	hide: function() {
+		return showHide( this );
+	},
+	toggle: function( state ) {
+		var bool = typeof state === "boolean";
+
+		return this.each(function() {
+			if ( bool ? state : isHidden( this ) ) {
+				jQuery( this ).show();
+			} else {
+				jQuery( this ).hide();
+			}
+		});
+	}
+});
+
+jQuery.extend({
+	// Add in style property hooks for overriding the default
+	// behavior of getting and setting a style property
+	cssHooks: {
+		opacity: {
+			get: function( elem, computed ) {
+				if ( computed ) {
+					// We should always get a number back from opacity
+					var ret = curCSS( elem, "opacity" );
+					return ret === "" ? "1" : ret;
+				}
+			}
+		}
+	},
+
+	// Exclude the following css properties to add px
+	cssNumber: {
+		"columnCount": true,
+		"fillOpacity": true,
+		"fontWeight": true,
+		"lineHeight": true,
+		"opacity": true,
+		"orphans": true,
+		"widows": true,
+		"zIndex": true,
+		"zoom": true
+	},
+
+	// Add in properties whose names you wish to fix before
+	// setting or getting the value
+	cssProps: {
+		// normalize float css property
+		"float": jQuery.support.cssFloat ? "cssFloat" : "styleFloat"
+	},
+
+	// Get and set the style property on a DOM Node
+	style: function( elem, name, value, extra ) {
+		// Don't set styles on text and comment nodes
+		if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {
+			return;
+		}
+
+		// Make sure that we're working with the right name
+		var ret, type, hooks,
+			origName = jQuery.camelCase( name ),
+			style = elem.style;
+
+		name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( style, origName ) );
+
+		// gets hook for the prefixed version
+		// followed by the unprefixed version
+		hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
+
+		// Check if we're setting a value
+		if ( value !== undefined ) {
+			type = typeof value;
+
+			// convert relative number strings (+= or -=) to relative numbers. #7345
+			if ( type === "string" && (ret = rrelNum.exec( value )) ) {
+				value = ( ret[1] + 1 ) * ret[2] + parseFloat( jQuery.css( elem, name ) );
+				// Fixes bug #9237
+				type = "number";
+			}
+
+			// Make sure that NaN and null values aren't set. See: #7116
+			if ( value == null || type === "number" && isNaN( value ) ) {
+				return;
+			}
+
+			// If a number was passed in, add 'px' to the (except for certain CSS properties)
+			if ( type === "number" && !jQuery.cssNumber[ origName ] ) {
+				value += "px";
+			}
+
+			// Fixes #8908, it can be done more correctly by specifing setters in cssHooks,
+			// but it would mean to define eight (for every problematic property) identical functions
+			if ( !jQuery.support.clearCloneStyle && value === "" && name.indexOf("background") === 0 ) {
+				style[ name ] = "inherit";
+			}
+
+			// If a hook was provided, use that value, otherwise just set the specified value
+			if ( !hooks || !("set" in hooks) || (value = hooks.set( elem, value, extra )) !== undefined ) {
+
+				// Wrapped to prevent IE from throwing errors when 'invalid' values are provided
+				// Fixes bug #5509
+				try {
+					style[ name ] = value;
+				} catch(e) {}
+			}
+
+		} else {
+			// If a hook was provided get the non-computed value from there
+			if ( hooks && "get" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) {
+				return ret;
+			}
+
+			// Otherwise just get the value from the style object
+			return style[ name ];
+		}
+	},
+
+	css: function( elem, name, extra, styles ) {
+		var val, num, hooks,
+			origName = jQuery.camelCase( name );
+
+		// Make sure that we're working with the right name
+		name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( elem.style, origName ) );
+
+		// gets hook for the prefixed version
+		// followed by the unprefixed version
+		hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
+
+		// If a hook was provided get the computed value from there
+		if ( hooks && "get" in hooks ) {
+			val = hooks.get( elem, true, extra );
+		}
+
+		// Otherwise, if a way to get the computed value exists, use that
+		if ( val === undefined ) {
+			val = curCSS( elem, name, styles );
+		}
+
+		//convert "normal" to computed value
+		if ( val === "normal" && name in cssNormalTransform ) {
+			val = cssNormalTransform[ name ];
+		}
+
+		// Return, converting to number if forced or a qualifier was provided and val looks numeric
+		if ( extra ) {
+			num = parseFloat( val );
+			return extra === true || jQuery.isNumeric( num ) ? num || 0 : val;
+		}
+		return val;
+	},
+
+	// A method for quickly swapping in/out CSS properties to get correct calculations
+	swap: function( elem, options, callback, args ) {
+		var ret, name,
+			old = {};
+
+		// Remember the old values, and insert the new ones
+		for ( name in options ) {
+			old[ name ] = elem.style[ name ];
+			elem.style[ name ] = options[ name ];
+		}
+
+		ret = callback.apply( elem, args || [] );
+
+		// Revert the old values
+		for ( name in options ) {
+			elem.style[ name ] = old[ name ];
+		}
+
+		return ret;
+	}
+});
+
+// NOTE: we've included the "window" in window.getComputedStyle
+// because jsdom on node.js will break without it.
+if ( window.getComputedStyle ) {
+	getStyles = function( elem ) {
+		return window.getComputedStyle( elem, null );
+	};
+
+	curCSS = function( elem, name, _computed ) {
+		var width, minWidth, maxWidth,
+			computed = _computed || getStyles( elem ),
+
+			// getPropertyValue is only needed for .css('filter') in IE9, see #12537
+			ret = computed ? computed.getPropertyValue( name ) || computed[ name ] : undefined,
+			style = elem.style;
+
+		if ( computed ) {
+
+			if ( ret === "" && !jQuery.contains( elem.ownerDocument, elem ) ) {
+				ret = jQuery.style( elem, name );
+			}
+
+			// A tribute to the "awesome hack by Dean Edwards"
+			// Chrome < 17 and Safari 5.0 uses "computed value" instead of "used value" for margin-right
+			// Safari 5.1.7 (at least) returns percentage for a larger set of values, but width seems to be reliably pixels
+			// this is against the CSSOM draft spec: http://dev.w3.org/csswg/cssom/#resolved-values
+			if ( rnumnonpx.test( ret ) && rmargin.test( name ) ) {
+
+				// Remember the original values
+				width = style.width;
+				minWidth = style.minWidth;
+				maxWidth = style.maxWidth;
+
+				// Put in the new values to get a computed value out
+				style.minWidth = style.maxWidth = style.width = ret;
+				ret = computed.width;
+
+				// Revert the changed values
+				style.width = width;
+				style.minWidth = minWidth;
+				style.maxWidth = maxWidth;
+			}
+		}
+
+		return ret;
+	};
+} else if ( document.documentElement.currentStyle ) {
+	getStyles = function( elem ) {
+		return elem.currentStyle;
+	};
+
+	curCSS = function( elem, name, _computed ) {
+		var left, rs, rsLeft,
+			computed = _computed || getStyles( elem ),
+			ret = computed ? computed[ name ] : undefined,
+			style = elem.style;
+
+		// Avoid setting ret to empty string here
+		// so we don't default to auto
+		if ( ret == null && style && style[ name ] ) {
+			ret = style[ name ];
+		}
+
+		// From the awesome hack by Dean Edwards
+		// http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291
+
+		// If we're not dealing with a regular pixel number
+		// but a number that has a weird ending, we need to convert it to pixels
+		// but not position css attributes, as those are proportional to the parent element instead
+		// and we can't measure the parent instead because it might trigger a "stacking dolls" problem
+		if ( rnumnonpx.test( ret ) && !rposition.test( name ) ) {
+
+			// Remember the original values
+			left = style.left;
+			rs = elem.runtimeStyle;
+			rsLeft = rs && rs.left;
+
+			// Put in the new values to get a computed value out
+			if ( rsLeft ) {
+				rs.left = elem.currentStyle.left;
+			}
+			style.left = name === "fontSize" ? "1em" : ret;
+			ret = style.pixelLeft + "px";
+
+			// Revert the changed values
+			style.left = left;
+			if ( rsLeft ) {
+				rs.left = rsLeft;
+			}
+		}
+
+		return ret === "" ? "auto" : ret;
+	};
+}
+
+function setPositiveNumber( elem, value, subtract ) {
+	var matches = rnumsplit.exec( value );
+	return matches ?
+		// Guard against undefined "subtract", e.g., when used as in cssHooks
+		Math.max( 0, matches[ 1 ] - ( subtract || 0 ) ) + ( matches[ 2 ] || "px" ) :
+		value;
+}
+
+function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) {
+	var i = extra === ( isBorderBox ? "border" : "content" ) ?
+		// If we already have the right measurement, avoid augmentation
+		4 :
+		// Otherwise initialize for horizontal or vertical properties
+		name === "width" ? 1 : 0,
+
+		val = 0;
+
+	for ( ; i < 4; i += 2 ) {
+		// both box models exclude margin, so add it if we want it
+		if ( extra === "margin" ) {
+			val += jQuery.css( elem, extra + cssExpand[ i ], true, styles );
+		}
+
+		if ( isBorderBox ) {
+			// border-box includes padding, so remove it if we want content
+			if ( extra === "content" ) {
+				val -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
+			}
+
+			// at this point, extra isn't border nor margin, so remove border
+			if ( extra !== "margin" ) {
+				val -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
+			}
+		} else {
+			// at this point, extra isn't content, so add padding
+			val += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
+
+			// at this point, extra isn't content nor padding, so add border
+			if ( extra !== "padding" ) {
+				val += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
+			}
+		}
+	}
+
+	return val;
+}
+
+function getWidthOrHeight( elem, name, extra ) {
+
+	// Start with offset property, which is equivalent to the border-box value
+	var valueIsBorderBox = true,
+		val = name === "width" ? elem.offsetWidth : elem.offsetHeight,
+		styles = getStyles( elem ),
+		isBorderBox = jQuery.support.boxSizing && jQuery.css( elem, "boxSizing", false, styles ) === "border-box";
+
+	// some non-html elements return undefined for offsetWidth, so check for null/undefined
+	// svg - https://bugzilla.mozilla.org/show_bug.cgi?id=649285
+	// MathML - https://bugzilla.mozilla.org/show_bug.cgi?id=491668
+	if ( val <= 0 || val == null ) {
+		// Fall back to computed then uncomputed css if necessary
+		val = curCSS( elem, name, styles );
+		if ( val < 0 || val == null ) {
+			val = elem.style[ name ];
+		}
+
+		// Computed unit is not pixels. Stop here and return.
+		if ( rnumnonpx.test(val) ) {
+			return val;
+		}
+
+		// we need the check for style in case a browser which returns unreliable values
+		// for getComputedStyle silently falls back to the reliable elem.style
+		valueIsBorderBox = isBorderBox && ( jQuery.support.boxSizingReliable || val === elem.style[ name ] );
+
+		// Normalize "", auto, and prepare for extra
+		val = parseFloat( val ) || 0;
+	}
+
+	// use the active box-sizing model to add/subtract irrelevant styles
+	return ( val +
+		augmentWidthOrHeight(
+			elem,
+			name,
+			extra || ( isBorderBox ? "border" : "content" ),
+			valueIsBorderBox,
+			styles
+		)
+	) + "px";
+}
+
+// Try to determine the default display value of an element
+function css_defaultDisplay( nodeName ) {
+	var doc = document,
+		display = elemdisplay[ nodeName ];
+
+	if ( !display ) {
+		display = actualDisplay( nodeName, doc );
+
+		// If the simple way fails, read from inside an iframe
+		if ( display === "none" || !display ) {
+			// Use the already-created iframe if possible
+			iframe = ( iframe ||
+				jQuery("<iframe frameborder='0' width='0' height='0'/>")
+				.css( "cssText", "display:block !important" )
+			).appendTo( doc.documentElement );
+
+			// Always write a new HTML skeleton so Webkit and Firefox don't choke on reuse
+			doc = ( iframe[0].contentWindow || iframe[0].contentDocument ).document;
+			doc.write("<!doctype html><html><body>");
+			doc.close();
+
+			display = actualDisplay( nodeName, doc );
+			iframe.detach();
+		}
+
+		// Store the correct default display
+		elemdisplay[ nodeName ] = display;
+	}
+
+	return display;
+}
+
+// Called ONLY from within css_defaultDisplay
+function actualDisplay( name, doc ) {
+	var elem = jQuery( doc.createElement( name ) ).appendTo( doc.body ),
+		display = jQuery.css( elem[0], "display" );
+	elem.remove();
+	return display;
+}
+
+jQuery.each([ "height", "width" ], function( i, name ) {
+	jQuery.cssHooks[ name ] = {
+		get: function( elem, computed, extra ) {
+			if ( computed ) {
+				// certain elements can have dimension info if we invisibly show them
+				// however, it must have a current display style that would benefit from this
+				return elem.offsetWidth === 0 && rdisplayswap.test( jQuery.css( elem, "display" ) ) ?
+					jQuery.swap( elem, cssShow, function() {
+						return getWidthOrHeight( elem, name, extra );
+					}) :
+					getWidthOrHeight( elem, name, extra );
+			}
+		},
+
+		set: function( elem, value, extra ) {
+			var styles = extra && getStyles( elem );
+			return setPositiveNumber( elem, value, extra ?
+				augmentWidthOrHeight(
+					elem,
+					name,
+					extra,
+					jQuery.support.boxSizing && jQuery.css( elem, "boxSizing", false, styles ) === "border-box",
+					styles
+				) : 0
+			);
+		}
+	};
+});
+
+if ( !jQuery.support.opacity ) {
+	jQuery.cssHooks.opacity = {
+		get: function( elem, computed ) {
+			// IE uses filters for opacity
+			return ropacity.test( (computed && elem.currentStyle ? elem.currentStyle.filter : elem.style.filter) || "" ) ?
+				( 0.01 * parseFloat( RegExp.$1 ) ) + "" :
+				computed ? "1" : "";
+		},
+
+		set: function( elem, value ) {
+			var style = elem.style,
+				currentStyle = elem.currentStyle,
+				opacity = jQuery.isNumeric( value ) ? "alpha(opacity=" + value * 100 + ")" : "",
+				filter = currentStyle && currentStyle.filter || style.filter || "";
+
+			// IE has trouble with opacity if it does not have layout
+			// Force it by setting the zoom level
+			style.zoom = 1;
+
+			// if setting opacity to 1, and no other filters exist - attempt to remove filter attribute #6652
+			// if value === "", then remove inline opacity #12685
+			if ( ( value >= 1 || value === "" ) &&
+					jQuery.trim( filter.replace( ralpha, "" ) ) === "" &&
+					style.removeAttribute ) {
+
+				// Setting style.filter to null, "" & " " still leave "filter:" in the cssText
+				// if "filter:" is present at all, clearType is disabled, we want to avoid this
+				// style.removeAttribute is IE Only, but so apparently is this code path...
+				style.removeAttribute( "filter" );
+
+				// if there is no filter style applied in a css rule or unset inline opacity, we are done
+				if ( value === "" || currentStyle && !currentStyle.filter ) {
+					return;
+				}
+			}
+
+			// otherwise, set new filter values
+			style.filter = ralpha.test( filter ) ?
+				filter.replace( ralpha, opacity ) :
+				filter + " " + opacity;
+		}
+	};
+}
+
+// These hooks cannot be added until DOM ready because the support test
+// for it is not run until after DOM ready
+jQuery(function() {
+	if ( !jQuery.support.reliableMarginRight ) {
+		jQuery.cssHooks.marginRight = {
+			get: function( elem, computed ) {
+				if ( computed ) {
+					// WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
+					// Work around by temporarily setting element display to inline-block
+					return jQuery.swap( elem, { "display": "inline-block" },
+						curCSS, [ elem, "marginRight" ] );
+				}
+			}
+		};
+	}
+
+	// Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084
+	// getComputedStyle returns percent when specified for top/left/bottom/right
+	// rather than make the css module depend on the offset module, we just check for it here
+	if ( !jQuery.support.pixelPosition && jQuery.fn.position ) {
+		jQuery.each( [ "top", "left" ], function( i, prop ) {
+			jQuery.cssHooks[ prop ] = {
+				get: function( elem, computed ) {
+					if ( computed ) {
+						computed = curCSS( elem, prop );
+						// if curCSS returns percentage, fallback to offset
+						return rnumnonpx.test( computed ) ?
+							jQuery( elem ).position()[ prop ] + "px" :
+							computed;
+					}
+				}
+			};
+		});
+	}
+
+});
+
+if ( jQuery.expr && jQuery.expr.filters ) {
+	jQuery.expr.filters.hidden = function( elem ) {
+		return ( elem.offsetWidth === 0 && elem.offsetHeight === 0 ) || (!jQuery.support.reliableHiddenOffsets && ((elem.style && elem.style.display) || jQuery.css( elem, "display" )) === "none");
+	};
+
+	jQuery.expr.filters.visible = function( elem ) {
+		return !jQuery.expr.filters.hidden( elem );
+	};
+}
+
+// These hooks are used by animate to expand properties
+jQuery.each({
+	margin: "",
+	padding: "",
+	border: "Width"
+}, function( prefix, suffix ) {
+	jQuery.cssHooks[ prefix + suffix ] = {
+		expand: function( value ) {
+			var i = 0,
+				expanded = {},
+
+				// assumes a single number if not a string
+				parts = typeof value === "string" ? value.split(" ") : [ value ];
+
+			for ( ; i < 4; i++ ) {
+				expanded[ prefix + cssExpand[ i ] + suffix ] =
+					parts[ i ] || parts[ i - 2 ] || parts[ 0 ];
+			}
+
+			return expanded;
+		}
+	};
+
+	if ( !rmargin.test( prefix ) ) {
+		jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber;
+	}
+});
+var r20 = /%20/g,
+	rbracket = /\[\]$/,
+	rCRLF = /\r?\n/g,
+	rsubmitterTypes = /^(?:submit|button|image|reset)$/i,
+	rsubmittable = /^(?:input|select|textarea|keygen)/i;
+
+jQuery.fn.extend({
+	serialize: function() {
+		return jQuery.param( this.serializeArray() );
+	},
+	serializeArray: function() {
+		return this.map(function(){
+			// Can add propHook for "elements" to filter or add form elements
+			var elements = jQuery.prop( this, "elements" );
+			return elements ? jQuery.makeArray( elements ) : this;
+		})
+		.filter(function(){
+			var type = this.type;
+			// Use .is(":disabled") so that fieldset[disabled] works
+			return this.name && !jQuery( this ).is( ":disabled" ) &&
+				rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) &&
+				( this.checked || !manipulation_rcheckableType.test( type ) );
+		})
+		.map(function( i, elem ){
+			var val = jQuery( this ).val();
+
+			return val == null ?
+				null :
+				jQuery.isArray( val ) ?
+					jQuery.map( val, function( val ){
+						return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
+					}) :
+					{ name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
+		}).get();
+	}
+});
+
+//Serialize an array of form elements or a set of
+//key/values into a query string
+jQuery.param = function( a, traditional ) {
+	var prefix,
+		s = [],
+		add = function( key, value ) {
+			// If value is a function, invoke it and return its value
+			value = jQuery.isFunction( value ) ? value() : ( value == null ? "" : value );
+			s[ s.length ] = encodeURIComponent( key ) + "=" + encodeURIComponent( value );
+		};
+
+	// Set traditional to true for jQuery <= 1.3.2 behavior.
+	if ( traditional === undefined ) {
+		traditional = jQuery.ajaxSettings && jQuery.ajaxSettings.traditional;
+	}
+
+	// If an array was passed in, assume that it is an array of form elements.
+	if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {
+		// Serialize the form elements
+		jQuery.each( a, function() {
+			add( this.name, this.value );
+		});
+
+	} else {
+		// If traditional, encode the "old" way (the way 1.3.2 or older
+		// did it), otherwise encode params recursively.
+		for ( prefix in a ) {
+			buildParams( prefix, a[ prefix ], traditional, add );
+		}
+	}
+
+	// Return the resulting serialization
+	return s.join( "&" ).replace( r20, "+" );
+};
+
+function buildParams( prefix, obj, traditional, add ) {
+	var name;
+
+	if ( jQuery.isArray( obj ) ) {
+		// Serialize array item.
+		jQuery.each( obj, function( i, v ) {
+			if ( traditional || rbracket.test( prefix ) ) {
+				// Treat each array item as a scalar.
+				add( prefix, v );
+
+			} else {
+				// Item is non-scalar (array or object), encode its numeric index.
+				buildParams( prefix + "[" + ( typeof v === "object" ? i : "" ) + "]", v, traditional, add );
+			}
+		});
+
+	} else if ( !traditional && jQuery.type( obj ) === "object" ) {
+		// Serialize object item.
+		for ( name in obj ) {
+			buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add );
+		}
+
+	} else {
+		// Serialize scalar item.
+		add( prefix, obj );
+	}
+}
+var
+	// Document location
+	ajaxLocParts,
+	ajaxLocation,
+
+	ajax_nonce = jQuery.now(),
+
+	ajax_rquery = /\?/,
+	rhash = /#.*$/,
+	rts = /([?&])_=[^&]*/,
+	rheaders = /^(.*?):[ \t]*([^\r\n]*)\r?$/mg, // IE leaves an \r character at EOL
+	// #7653, #8125, #8152: local protocol detection
+	rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/,
+	rnoContent = /^(?:GET|HEAD)$/,
+	rprotocol = /^\/\//,
+	rurl = /^([\w.+-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,
+
+	// Keep a copy of the old load method
+	_load = jQuery.fn.load,
+
+	/* Prefilters
+	 * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example)
+	 * 2) These are called:
+	 *    - BEFORE asking for a transport
+	 *    - AFTER param serialization (s.data is a string if s.processData is true)
+	 * 3) key is the dataType
+	 * 4) the catchall symbol "*" can be used
+	 * 5) execution will start with transport dataType and THEN continue down to "*" if needed
+	 */
+	prefilters = {},
+
+	/* Transports bindings
+	 * 1) key is the dataType
+	 * 2) the catchall symbol "*" can be used
+	 * 3) selection will start with transport dataType and THEN go to "*" if needed
+	 */
+	transports = {},
+
+	// Avoid comment-prolog char sequence (#10098); must appease lint and evade compression
+	allTypes = "*/".concat("*");
+
+// #8138, IE may throw an exception when accessing
+// a field from window.location if document.domain has been set
+try {
+	ajaxLocation = location.href;
+} catch( e ) {
+	// Use the href attribute of an A element
+	// since IE will modify it given document.location
+	ajaxLocation = document.createElement( "a" );
+	ajaxLocation.href = "";
+	ajaxLocation = ajaxLocation.href;
+}
+
+// Segment location into parts
+ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || [];
+
+// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport
+function addToPrefiltersOrTransports( structure ) {
+
+	// dataTypeExpression is optional and defaults to "*"
+	return function( dataTypeExpression, func ) {
+
+		if ( typeof dataTypeExpression !== "string" ) {
+			func = dataTypeExpression;
+			dataTypeExpression = "*";
+		}
+
+		var dataType,
+			i = 0,
+			dataTypes = dataTypeExpression.toLowerCase().match( core_rnotwhite ) || [];
+
+		if ( jQuery.isFunction( func ) ) {
+			// For each dataType in the dataTypeExpression
+			while ( (dataType = dataTypes[i++]) ) {
+				// Prepend if requested
+				if ( dataType[0] === "+" ) {
+					dataType = dataType.slice( 1 ) || "*";
+					(structure[ dataType ] = structure[ dataType ] || []).unshift( func );
+
+				// Otherwise append
+				} else {
+					(structure[ dataType ] = structure[ dataType ] || []).push( func );
+				}
+			}
+		}
+	};
+}
+
+// Base inspection function for prefilters and transports
+function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) {
+
+	var inspected = {},
+		seekingTransport = ( structure === transports );
+
+	function inspect( dataType ) {
+		var selected;
+		inspected[ dataType ] = true;
+		jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) {
+			var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR );
+			if( typeof dataTypeOrTransport === "string" && !seekingTransport && !inspected[ dataTypeOrTransport ] ) {
+				options.dataTypes.unshift( dataTypeOrTransport );
+				inspect( dataTypeOrTransport );
+				return false;
+			} else if ( seekingTransport ) {
+				return !( selected = dataTypeOrTransport );
+			}
+		});
+		return selected;
+	}
+
+	return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" );
+}
+
+// A special extend for ajax options
+// that takes "flat" options (not to be deep extended)
+// Fixes #9887
+function ajaxExtend( target, src ) {
+	var key, deep,
+		flatOptions = jQuery.ajaxSettings.flatOptions || {};
+
+	for ( key in src ) {
+		if ( src[ key ] !== undefined ) {
+			( flatOptions[ key ] ? target : ( deep || (deep = {}) ) )[ key ] = src[ key ];
+		}
+	}
+	if ( deep ) {
+		jQuery.extend( true, target, deep );
+	}
+
+	return target;
+}
+
+jQuery.fn.load = function( url, params, callback ) {
+	if ( typeof url !== "string" && _load ) {
+		return _load.apply( this, arguments );
+	}
+
+	var selector, type, response,
+		self = this,
+		off = url.indexOf(" ");
+
+	if ( off >= 0 ) {
+		selector = url.slice( off, url.length );
+		url = url.slice( 0, off );
+	}
+
+	// If it's a function
+	if ( jQuery.isFunction( params ) ) {
+
+		// We assume that it's the callback
+		callback = params;
+		params = undefined;
+
+	// Otherwise, build a param string
+	} else if ( params && typeof params === "object" ) {
+		type = "POST";
+	}
+
+	// If we have elements to modify, make the request
+	if ( self.length > 0 ) {
+		jQuery.ajax({
+			url: url,
+
+			// if "type" variable is undefined, then "GET" method will be used
+			type: type,
+			dataType: "html",
+			data: params
+		}).done(function( responseText ) {
+
+			// Save response for use in complete callback
+			response = arguments;
+
+			self.html( selector ?
+
+				// If a selector was specified, locate the right elements in a dummy div
+				// Exclude scripts to avoid IE 'Permission Denied' errors
+				jQuery("<div>").append( jQuery.parseHTML( responseText ) ).find( selector ) :
+
+				// Otherwise use the full result
+				responseText );
+
+		}).complete( callback && function( jqXHR, status ) {
+			self.each( callback, response || [ jqXHR.responseText, status, jqXHR ] );
+		});
+	}
+
+	return this;
+};
+
+// Attach a bunch of functions for handling common AJAX events
+jQuery.each( [ "ajaxStart", "ajaxStop", "ajaxComplete", "ajaxError", "ajaxSuccess", "ajaxSend" ], function( i, type ){
+	jQuery.fn[ type ] = function( fn ){
+		return this.on( type, fn );
+	};
+});
+
+jQuery.each( [ "get", "post" ], function( i, method ) {
+	jQuery[ method ] = function( url, data, callback, type ) {
+		// shift arguments if data argument was omitted
+		if ( jQuery.isFunction( data ) ) {
+			type = type || callback;
+			callback = data;
+			data = undefined;
+		}
+
+		return jQuery.ajax({
+			url: url,
+			type: method,
+			dataType: type,
+			data: data,
+			success: callback
+		});
+	};
+});
+
+jQuery.extend({
+
+	// Counter for holding the number of active queries
+	active: 0,
+
+	// Last-Modified header cache for next request
+	lastModified: {},
+	etag: {},
+
+	ajaxSettings: {
+		url: ajaxLocation,
+		type: "GET",
+		isLocal: rlocalProtocol.test( ajaxLocParts[ 1 ] ),
+		global: true,
+		processData: true,
+		async: true,
+		contentType: "application/x-www-form-urlencoded; charset=UTF-8",
+		/*
+		timeout: 0,
+		data: null,
+		dataType: null,
+		username: null,
+		password: null,
+		cache: null,
+		throws: false,
+		traditional: false,
+		headers: {},
+		*/
+
+		accepts: {
+			"*": allTypes,
+			text: "text/plain",
+			html: "text/html",
+			xml: "application/xml, text/xml",
+			json: "application/json, text/javascript"
+		},
+
+		contents: {
+			xml: /xml/,
+			html: /html/,
+			json: /json/
+		},
+
+		responseFields: {
+			xml: "responseXML",
+			text: "responseText"
+		},
+
+		// Data converters
+		// Keys separate source (or catchall "*") and destination types with a single space
+		converters: {
+
+			// Convert anything to text
+			"* text": window.String,
+
+			// Text to html (true = no transformation)
+			"text html": true,
+
+			// Evaluate text as a json expression
+			"text json": jQuery.parseJSON,
+
+			// Parse text as xml
+			"text xml": jQuery.parseXML
+		},
+
+		// For options that shouldn't be deep extended:
+		// you can add your own custom options here if
+		// and when you create one that shouldn't be
+		// deep extended (see ajaxExtend)
+		flatOptions: {
+			url: true,
+			context: true
+		}
+	},
+
+	// Creates a full fledged settings object into target
+	// with both ajaxSettings and settings fields.
+	// If target is omitted, writes into ajaxSettings.
+	ajaxSetup: function( target, settings ) {
+		return settings ?
+
+			// Building a settings object
+			ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) :
+
+			// Extending ajaxSettings
+			ajaxExtend( jQuery.ajaxSettings, target );
+	},
+
+	ajaxPrefilter: addToPrefiltersOrTransports( prefilters ),
+	ajaxTransport: addToPrefiltersOrTransports( transports ),
+
+	// Main method
+	ajax: function( url, options ) {
+
+		// If url is an object, simulate pre-1.5 signature
+		if ( typeof url === "object" ) {
+			options = url;
+			url = undefined;
+		}
+
+		// Force options to be an object
+		options = options || {};
+
+		var transport,
+			// URL without anti-cache param
+			cacheURL,
+			// Response headers
+			responseHeadersString,
+			responseHeaders,
+			// timeout handle
+			timeoutTimer,
+			// Cross-domain detection vars
+			parts,
+			// To know if global events are to be dispatched
+			fireGlobals,
+			// Loop variable
+			i,
+			// Create the final options object
+			s = jQuery.ajaxSetup( {}, options ),
+			// Callbacks context
+			callbackContext = s.context || s,
+			// Context for global events is callbackContext if it is a DOM node or jQuery collection
+			globalEventContext = s.context && ( callbackContext.nodeType || callbackContext.jquery ) ?
+				jQuery( callbackContext ) :
+				jQuery.event,
+			// Deferreds
+			deferred = jQuery.Deferred(),
+			completeDeferred = jQuery.Callbacks("once memory"),
+			// Status-dependent callbacks
+			statusCode = s.statusCode || {},
+			// Headers (they are sent all at once)
+			requestHeaders = {},
+			requestHeadersNames = {},
+			// The jqXHR state
+			state = 0,
+			// Default abort message
+			strAbort = "canceled",
+			// Fake xhr
+			jqXHR = {
+				readyState: 0,
+
+				// Builds headers hashtable if needed
+				getResponseHeader: function( key ) {
+					var match;
+					if ( state === 2 ) {
+						if ( !responseHeaders ) {
+							responseHeaders = {};
+							while ( (match = rheaders.exec( responseHeadersString )) ) {
+								responseHeaders[ match[1].toLowerCase() ] = match[ 2 ];
+							}
+						}
+						match = responseHeaders[ key.toLowerCase() ];
+					}
+					return match == null ? null : match;
+				},
+
+				// Raw string
+				getAllResponseHeaders: function() {
+					return state === 2 ? responseHeadersString : null;
+				},
+
+				// Caches the header
+				setRequestHeader: function( name, value ) {
+					var lname = name.toLowerCase();
+					if ( !state ) {
+						name = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name;
+						requestHeaders[ name ] = value;
+					}
+					return this;
+				},
+
+				// Overrides response content-type header
+				overrideMimeType: function( type ) {
+					if ( !state ) {
+						s.mimeType = type;
+					}
+					return this;
+				},
+
+				// Status-dependent callbacks
+				statusCode: function( map ) {
+					var code;
+					if ( map ) {
+						if ( state < 2 ) {
+							for ( code in map ) {
+								// Lazy-add the new callback in a way that preserves old ones
+								statusCode[ code ] = [ statusCode[ code ], map[ code ] ];
+							}
+						} else {
+							// Execute the appropriate callbacks
+							jqXHR.always( map[ jqXHR.status ] );
+						}
+					}
+					return this;
+				},
+
+				// Cancel the request
+				abort: function( statusText ) {
+					var finalText = statusText || strAbort;
+					if ( transport ) {
+						transport.abort( finalText );
+					}
+					done( 0, finalText );
+					return this;
+				}
+			};
+
+		// Attach deferreds
+		deferred.promise( jqXHR ).complete = completeDeferred.add;
+		jqXHR.success = jqXHR.done;
+		jqXHR.error = jqXHR.fail;
+
+		// Remove hash character (#7531: and string promotion)
+		// Add protocol if not provided (#5866: IE7 issue with protocol-less urls)
+		// Handle falsy url in the settings object (#10093: consistency with old signature)
+		// We also use the url parameter if available
+		s.url = ( ( url || s.url || ajaxLocation ) + "" ).replace( rhash, "" ).replace( rprotocol, ajaxLocParts[ 1 ] + "//" );
+
+		// Alias method option to type as per ticket #12004
+		s.type = options.method || options.type || s.method || s.type;
+
+		// Extract dataTypes list
+		s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().match( core_rnotwhite ) || [""];
+
+		// A cross-domain request is in order when we have a protocol:host:port mismatch
+		if ( s.crossDomain == null ) {
+			parts = rurl.exec( s.url.toLowerCase() );
+			s.crossDomain = !!( parts &&
+				( parts[ 1 ] !== ajaxLocParts[ 1 ] || parts[ 2 ] !== ajaxLocParts[ 2 ] ||
+					( parts[ 3 ] || ( parts[ 1 ] === "http:" ? 80 : 443 ) ) !=
+						( ajaxLocParts[ 3 ] || ( ajaxLocParts[ 1 ] === "http:" ? 80 : 443 ) ) )
+			);
+		}
+
+		// Convert data if not already a string
+		if ( s.data && s.processData && typeof s.data !== "string" ) {
+			s.data = jQuery.param( s.data, s.traditional );
+		}
+
+		// Apply prefilters
+		inspectPrefiltersOrTransports( prefilters, s, options, jqXHR );
+
+		// If request was aborted inside a prefilter, stop there
+		if ( state === 2 ) {
+			return jqXHR;
+		}
+
+		// We can fire global events as of now if asked to
+		fireGlobals = s.global;
+
+		// Watch for a new set of requests
+		if ( fireGlobals && jQuery.active++ === 0 ) {
+			jQuery.event.trigger("ajaxStart");
+		}
+
+		// Uppercase the type
+		s.type = s.type.toUpperCase();
+
+		// Determine if request has content
+		s.hasContent = !rnoContent.test( s.type );
+
+		// Save the URL in case we're toying with the If-Modified-Since
+		// and/or If-None-Match header later on
+		cacheURL = s.url;
+
+		// More options handling for requests with no content
+		if ( !s.hasContent ) {
+
+			// If data is available, append data to url
+			if ( s.data ) {
+				cacheURL = ( s.url += ( ajax_rquery.test( cacheURL ) ? "&" : "?" ) + s.data );
+				// #9682: remove data so that it's not used in an eventual retry
+				delete s.data;
+			}
+
+			// Add anti-cache in url if needed
+			if ( s.cache === false ) {
+				s.url = rts.test( cacheURL ) ?
+
+					// If there is already a '_' parameter, set its value
+					cacheURL.replace( rts, "$1_=" + ajax_nonce++ ) :
+
+					// Otherwise add one to the end
+					cacheURL + ( ajax_rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ajax_nonce++;
+			}
+		}
+
+		// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
+		if ( s.ifModified ) {
+			if ( jQuery.lastModified[ cacheURL ] ) {
+				jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] );
+			}
+			if ( jQuery.etag[ cacheURL ] ) {
+				jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] );
+			}
+		}
+
+		// Set the correct header, if data is being sent
+		if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {
+			jqXHR.setRequestHeader( "Content-Type", s.contentType );
+		}
+
+		// Set the Accepts header for the server, depending on the dataType
+		jqXHR.setRequestHeader(
+			"Accept",
+			s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ?
+				s.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) :
+				s.accepts[ "*" ]
+		);
+
+		// Check for headers option
+		for ( i in s.headers ) {
+			jqXHR.setRequestHeader( i, s.headers[ i ] );
+		}
+
+		// Allow custom headers/mimetypes and early abort
+		if ( s.beforeSend && ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) {
+			// Abort if not done already and return
+			return jqXHR.abort();
+		}
+
+		// aborting is no longer a cancellation
+		strAbort = "abort";
+
+		// Install callbacks on deferreds
+		for ( i in { success: 1, error: 1, complete: 1 } ) {
+			jqXHR[ i ]( s[ i ] );
+		}
+
+		// Get transport
+		transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );
+
+		// If no transport, we auto-abort
+		if ( !transport ) {
+			done( -1, "No Transport" );
+		} else {
+			jqXHR.readyState = 1;
+
+			// Send global event
+			if ( fireGlobals ) {
+				globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] );
+			}
+			// Timeout
+			if ( s.async && s.timeout > 0 ) {
+				timeoutTimer = setTimeout(function() {
+					jqXHR.abort("timeout");
+				}, s.timeout );
+			}
+
+			try {
+				state = 1;
+				transport.send( requestHeaders, done );
+			} catch ( e ) {
+				// Propagate exception as error if not done
+				if ( state < 2 ) {
+					done( -1, e );
+				// Simply rethrow otherwise
+				} else {
+					throw e;
+				}
+			}
+		}
+
+		// Callback for when everything is done
+		function done( status, nativeStatusText, responses, headers ) {
+			var isSuccess, success, error, response, modified,
+				statusText = nativeStatusText;
+
+			// Called once
+			if ( state === 2 ) {
+				return;
+			}
+
+			// State is "done" now
+			state = 2;
+
+			// Clear timeout if it exists
+			if ( timeoutTimer ) {
+				clearTimeout( timeoutTimer );
+			}
+
+			// Dereference transport for early garbage collection
+			// (no matter how long the jqXHR object will be used)
+			transport = undefined;
+
+			// Cache response headers
+			responseHeadersString = headers || "";
+
+			// Set readyState
+			jqXHR.readyState = status > 0 ? 4 : 0;
+
+			// Get response data
+			if ( responses ) {
+				response = ajaxHandleResponses( s, jqXHR, responses );
+			}
+
+			// If successful, handle type chaining
+			if ( status >= 200 && status < 300 || status === 304 ) {
+
+				// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
+				if ( s.ifModified ) {
+					modified = jqXHR.getResponseHeader("Last-Modified");
+					if ( modified ) {
+						jQuery.lastModified[ cacheURL ] = modified;
+					}
+					modified = jqXHR.getResponseHeader("etag");
+					if ( modified ) {
+						jQuery.etag[ cacheURL ] = modified;
+					}
+				}
+
+				// If not modified
+				if ( status === 304 ) {
+					isSuccess = true;
+					statusText = "notmodified";
+
+				// If we have data
+				} else {
+					isSuccess = ajaxConvert( s, response );
+					statusText = isSuccess.state;
+					success = isSuccess.data;
+					error = isSuccess.error;
+					isSuccess = !error;
+				}
+			} else {
+				// We extract error from statusText
+				// then normalize statusText and status for non-aborts
+				error = statusText;
+				if ( status || !statusText ) {
+					statusText = "error";
+					if ( status < 0 ) {
+						status = 0;
+					}
+				}
+			}
+
+			// Set data for the fake xhr object
+			jqXHR.status = status;
+			jqXHR.statusText = ( nativeStatusText || statusText ) + "";
+
+			// Success/Error
+			if ( isSuccess ) {
+				deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] );
+			} else {
+				deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] );
+			}
+
+			// Status-dependent callbacks
+			jqXHR.statusCode( statusCode );
+			statusCode = undefined;
+
+			if ( fireGlobals ) {
+				globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError",
+					[ jqXHR, s, isSuccess ? success : error ] );
+			}
+
+			// Complete
+			completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] );
+
+			if ( fireGlobals ) {
+				globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] );
+				// Handle the global AJAX counter
+				if ( !( --jQuery.active ) ) {
+					jQuery.event.trigger("ajaxStop");
+				}
+			}
+		}
+
+		return jqXHR;
+	},
+
+	getScript: function( url, callback ) {
+		return jQuery.get( url, undefined, callback, "script" );
+	},
+
+	getJSON: function( url, data, callback ) {
+		return jQuery.get( url, data, callback, "json" );
+	}
+});
+
+/* Handles responses to an ajax request:
+ * - sets all responseXXX fields accordingly
+ * - finds the right dataType (mediates between content-type and expected dataType)
+ * - returns the corresponding response
+ */
+function ajaxHandleResponses( s, jqXHR, responses ) {
+
+	var ct, type, finalDataType, firstDataType,
+		contents = s.contents,
+		dataTypes = s.dataTypes,
+		responseFields = s.responseFields;
+
+	// Fill responseXXX fields
+	for ( type in responseFields ) {
+		if ( type in responses ) {
+			jqXHR[ responseFields[type] ] = responses[ type ];
+		}
+	}
+
+	// Remove auto dataType and get content-type in the process
+	while( dataTypes[ 0 ] === "*" ) {
+		dataTypes.shift();
+		if ( ct === undefined ) {
+			ct = s.mimeType || jqXHR.getResponseHeader("Content-Type");
+		}
+	}
+
+	// Check if we're dealing with a known content-type
+	if ( ct ) {
+		for ( type in contents ) {
+			if ( contents[ type ] && contents[ type ].test( ct ) ) {
+				dataTypes.unshift( type );
+				break;
+			}
+		}
+	}
+
+	// Check to see if we have a response for the expected dataType
+	if ( dataTypes[ 0 ] in responses ) {
+		finalDataType = dataTypes[ 0 ];
+	} else {
+		// Try convertible dataTypes
+		for ( type in responses ) {
+			if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[0] ] ) {
+				finalDataType = type;
+				break;
+			}
+			if ( !firstDataType ) {
+				firstDataType = type;
+			}
+		}
+		// Or just use first one
+		finalDataType = finalDataType || firstDataType;
+	}
+
+	// If we found a dataType
+	// We add the dataType to the list if needed
+	// and return the corresponding response
+	if ( finalDataType ) {
+		if ( finalDataType !== dataTypes[ 0 ] ) {
+			dataTypes.unshift( finalDataType );
+		}
+		return responses[ finalDataType ];
+	}
+}
+
+// Chain conversions given the request and the original response
+function ajaxConvert( s, response ) {
+
+	var conv, conv2, current, tmp,
+		converters = {},
+		i = 0,
+		// Work with a copy of dataTypes in case we need to modify it for conversion
+		dataTypes = s.dataTypes.slice(),
+		prev = dataTypes[ 0 ];
+
+	// Apply the dataFilter if provided
+	if ( s.dataFilter ) {
+		response = s.dataFilter( response, s.dataType );
+	}
+
+	// Create converters map with lowercased keys
+	if ( dataTypes[ 1 ] ) {
+		for ( conv in s.converters ) {
+			converters[ conv.toLowerCase() ] = s.converters[ conv ];
+		}
+	}
+
+	// Convert to each sequential dataType, tolerating list modification
+	for ( ; (current = dataTypes[++i]); ) {
+
+		// There's only work to do if current dataType is non-auto
+		if ( current !== "*" ) {
+
+			// Convert response if prev dataType is non-auto and differs from current
+			if ( prev !== "*" && prev !== current ) {
+
+				// Seek a direct converter
+				conv = converters[ prev + " " + current ] || converters[ "* " + current ];
+
+				// If none found, seek a pair
+				if ( !conv ) {
+					for ( conv2 in converters ) {
+
+						// If conv2 outputs current
+						tmp = conv2.split(" ");
+						if ( tmp[ 1 ] === current ) {
+
+							// If prev can be converted to accepted input
+							conv = converters[ prev + " " + tmp[ 0 ] ] ||
+								converters[ "* " + tmp[ 0 ] ];
+							if ( conv ) {
+								// Condense equivalence converters
+								if ( conv === true ) {
+									conv = converters[ conv2 ];
+
+								// Otherwise, insert the intermediate dataType
+								} else if ( converters[ conv2 ] !== true ) {
+									current = tmp[ 0 ];
+									dataTypes.splice( i--, 0, current );
+								}
+
+								break;
+							}
+						}
+					}
+				}
+
+				// Apply converter (if not an equivalence)
+				if ( conv !== true ) {
+
+					// Unless errors are allowed to bubble, catch and return them
+					if ( conv && s["throws"] ) {
+						response = conv( response );
+					} else {
+						try {
+							response = conv( response );
+						} catch ( e ) {
+							return { state: "parsererror", error: conv ? e : "No conversion from " + prev + " to " + current };
+						}
+					}
+				}
+			}
+
+			// Update prev for next iteration
+			prev = current;
+		}
+	}
+
+	return { state: "success", data: response };
+}
+// Install script dataType
+jQuery.ajaxSetup({
+	accepts: {
+		script: "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"
+	},
+	contents: {
+		script: /(?:java|ecma)script/
+	},
+	converters: {
+		"text script": function( text ) {
+			jQuery.globalEval( text );
+			return text;
+		}
+	}
+});
+
+// Handle cache's special case and global
+jQuery.ajaxPrefilter( "script", function( s ) {
+	if ( s.cache === undefined ) {
+		s.cache = false;
+	}
+	if ( s.crossDomain ) {
+		s.type = "GET";
+		s.global = false;
+	}
+});
+
+// Bind script tag hack transport
+jQuery.ajaxTransport( "script", function(s) {
+
+	// This transport only deals with cross domain requests
+	if ( s.crossDomain ) {
+
+		var script,
+			head = document.head || jQuery("head")[0] || document.documentElement;
+
+		return {
+
+			send: function( _, callback ) {
+
+				script = document.createElement("script");
+
+				script.async = true;
+
+				if ( s.scriptCharset ) {
+					script.charset = s.scriptCharset;
+				}
+
+				script.src = s.url;
+
+				// Attach handlers for all browsers
+				script.onload = script.onreadystatechange = function( _, isAbort ) {
+
+					if ( isAbort || !script.readyState || /loaded|complete/.test( script.readyState ) ) {
+
+						// Handle memory leak in IE
+						script.onload = script.onreadystatechange = null;
+
+						// Remove the script
+						if ( script.parentNode ) {
+							script.parentNode.removeChild( script );
+						}
+
+						// Dereference the script
+						script = null;
+
+						// Callback if not abort
+						if ( !isAbort ) {
+							callback( 200, "success" );
+						}
+					}
+				};
+
+				// Circumvent IE6 bugs with base elements (#2709 and #4378) by prepending
+				// Use native DOM manipulation to avoid our domManip AJAX trickery
+				head.insertBefore( script, head.firstChild );
+			},
+
+			abort: function() {
+				if ( script ) {
+					script.onload( undefined, true );
+				}
+			}
+		};
+	}
+});
+var oldCallbacks = [],
+	rjsonp = /(=)\?(?=&|$)|\?\?/;
+
+// Default jsonp settings
+jQuery.ajaxSetup({
+	jsonp: "callback",
+	jsonpCallback: function() {
+		var callback = oldCallbacks.pop() || ( jQuery.expando + "_" + ( ajax_nonce++ ) );
+		this[ callback ] = true;
+		return callback;
+	}
+});
+
+// Detect, normalize options and install callbacks for jsonp requests
+jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) {
+
+	var callbackName, overwritten, responseContainer,
+		jsonProp = s.jsonp !== false && ( rjsonp.test( s.url ) ?
+			"url" :
+			typeof s.data === "string" && !( s.contentType || "" ).indexOf("application/x-www-form-urlencoded") && rjsonp.test( s.data ) && "data"
+		);
+
+	// Handle iff the expected data type is "jsonp" or we have a parameter to set
+	if ( jsonProp || s.dataTypes[ 0 ] === "jsonp" ) {
+
+		// Get callback name, remembering preexisting value associated with it
+		callbackName = s.jsonpCallback = jQuery.isFunction( s.jsonpCallback ) ?
+			s.jsonpCallback() :
+			s.jsonpCallback;
+
+		// Insert callback into url or form data
+		if ( jsonProp ) {
+			s[ jsonProp ] = s[ jsonProp ].replace( rjsonp, "$1" + callbackName );
+		} else if ( s.jsonp !== false ) {
+			s.url += ( ajax_rquery.test( s.url ) ? "&" : "?" ) + s.jsonp + "=" + callbackName;
+		}
+
+		// Use data converter to retrieve json after script execution
+		s.converters["script json"] = function() {
+			if ( !responseContainer ) {
+				jQuery.error( callbackName + " was not called" );
+			}
+			return responseContainer[ 0 ];
+		};
+
+		// force json dataType
+		s.dataTypes[ 0 ] = "json";
+
+		// Install callback
+		overwritten = window[ callbackName ];
+		window[ callbackName ] = function() {
+			responseContainer = arguments;
+		};
+
+		// Clean-up function (fires after converters)
+		jqXHR.always(function() {
+			// Restore preexisting value
+			window[ callbackName ] = overwritten;
+
+			// Save back as free
+			if ( s[ callbackName ] ) {
+				// make sure that re-using the options doesn't screw things around
+				s.jsonpCallback = originalSettings.jsonpCallback;
+
+				// save the callback name for future use
+				oldCallbacks.push( callbackName );
+			}
+
+			// Call if it was a function and we have a response
+			if ( responseContainer && jQuery.isFunction( overwritten ) ) {
+				overwritten( responseContainer[ 0 ] );
+			}
+
+			responseContainer = overwritten = undefined;
+		});
+
+		// Delegate to script
+		return "script";
+	}
+});
+var xhrCallbacks, xhrSupported,
+	xhrId = 0,
+	// #5280: Internet Explorer will keep connections alive if we don't abort on unload
+	xhrOnUnloadAbort = window.ActiveXObject && function() {
+		// Abort all pending requests
+		var key;
+		for ( key in xhrCallbacks ) {
+			xhrCallbacks[ key ]( undefined, true );
+		}
+	};
+
+// Functions to create xhrs
+function createStandardXHR() {
+	try {
+		return new window.XMLHttpRequest();
+	} catch( e ) {}
+}
+
+function createActiveXHR() {
+	try {
+		return new window.ActiveXObject("Microsoft.XMLHTTP");
+	} catch( e ) {}
+}
+
+// Create the request object
+// (This is still attached to ajaxSettings for backward compatibility)
+jQuery.ajaxSettings.xhr = window.ActiveXObject ?
+	/* Microsoft failed to properly
+	 * implement the XMLHttpRequest in IE7 (can't request local files),
+	 * so we use the ActiveXObject when it is available
+	 * Additionally XMLHttpRequest can be disabled in IE7/IE8 so
+	 * we need a fallback.
+	 */
+	function() {
+		return !this.isLocal && createStandardXHR() || createActiveXHR();
+	} :
+	// For all other browsers, use the standard XMLHttpRequest object
+	createStandardXHR;
+
+// Determine support properties
+xhrSupported = jQuery.ajaxSettings.xhr();
+jQuery.support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported );
+xhrSupported = jQuery.support.ajax = !!xhrSupported;
+
+// Create transport if the browser can provide an xhr
+if ( xhrSupported ) {
+
+	jQuery.ajaxTransport(function( s ) {
+		// Cross domain only allowed if supported through XMLHttpRequest
+		if ( !s.crossDomain || jQuery.support.cors ) {
+
+			var callback;
+
+			return {
+				send: function( headers, complete ) {
+
+					// Get a new xhr
+					var handle, i,
+						xhr = s.xhr();
+
+					// Open the socket
+					// Passing null username, generates a login popup on Opera (#2865)
+					if ( s.username ) {
+						xhr.open( s.type, s.url, s.async, s.username, s.password );
+					} else {
+						xhr.open( s.type, s.url, s.async );
+					}
+
+					// Apply custom fields if provided
+					if ( s.xhrFields ) {
+						for ( i in s.xhrFields ) {
+							xhr[ i ] = s.xhrFields[ i ];
+						}
+					}
+
+					// Override mime type if needed
+					if ( s.mimeType && xhr.overrideMimeType ) {
+						xhr.overrideMimeType( s.mimeType );
+					}
+
+					// X-Requested-With header
+					// For cross-domain requests, seeing as conditions for a preflight are
+					// akin to a jigsaw puzzle, we simply never set it to be sure.
+					// (it can always be set on a per-request basis or even using ajaxSetup)
+					// For same-domain requests, won't change header if already provided.
+					if ( !s.crossDomain && !headers["X-Requested-With"] ) {
+						headers["X-Requested-With"] = "XMLHttpRequest";
+					}
+
+					// Need an extra try/catch for cross domain requests in Firefox 3
+					try {
+						for ( i in headers ) {
+							xhr.setRequestHeader( i, headers[ i ] );
+						}
+					} catch( err ) {}
+
+					// Do send the request
+					// This may raise an exception which is actually
+					// handled in jQuery.ajax (so no try/catch here)
+					xhr.send( ( s.hasContent && s.data ) || null );
+
+					// Listener
+					callback = function( _, isAbort ) {
+
+						var status,
+							statusText,
+							responseHeaders,
+							responses,
+							xml;
+
+						// Firefox throws exceptions when accessing properties
+						// of an xhr when a network error occurred
+						// http://helpful.knobs-dials.com/index.php/Component_returned_failure_code:_0x80040111_(NS_ERROR_NOT_AVAILABLE)
+						try {
+
+							// Was never called and is aborted or complete
+							if ( callback && ( isAbort || xhr.readyState === 4 ) ) {
+
+								// Only called once
+								callback = undefined;
+
+								// Do not keep as active anymore
+								if ( handle ) {
+									xhr.onreadystatechange = jQuery.noop;
+									if ( xhrOnUnloadAbort ) {
+										delete xhrCallbacks[ handle ];
+									}
+								}
+
+								// If it's an abort
+								if ( isAbort ) {
+									// Abort it manually if needed
+									if ( xhr.readyState !== 4 ) {
+										xhr.abort();
+									}
+								} else {
+									responses = {};
+									status = xhr.status;
+									xml = xhr.responseXML;
+									responseHeaders = xhr.getAllResponseHeaders();
+
+									// Construct response list
+									if ( xml && xml.documentElement /* #4958 */ ) {
+										responses.xml = xml;
+									}
+
+									// When requesting binary data, IE6-9 will throw an exception
+									// on any attempt to access responseText (#11426)
+									if ( typeof xhr.responseText === "string" ) {
+										responses.text = xhr.responseText;
+									}
+
+									// Firefox throws an exception when accessing
+									// statusText for faulty cross-domain requests
+									try {
+										statusText = xhr.statusText;
+									} catch( e ) {
+										// We normalize with Webkit giving an empty statusText
+										statusText = "";
+									}
+
+									// Filter status for non standard behaviors
+
+									// If the request is local and we have data: assume a success
+									// (success with no data won't get notified, that's the best we
+									// can do given current implementations)
+									if ( !status && s.isLocal && !s.crossDomain ) {
+										status = responses.text ? 200 : 404;
+									// IE - #1450: sometimes returns 1223 when it should be 204
+									} else if ( status === 1223 ) {
+										status = 204;
+									}
+								}
+							}
+						} catch( firefoxAccessException ) {
+							if ( !isAbort ) {
+								complete( -1, firefoxAccessException );
+							}
+						}
+
+						// Call complete if needed
+						if ( responses ) {
+							complete( status, statusText, responses, responseHeaders );
+						}
+					};
+
+					if ( !s.async ) {
+						// if we're in sync mode we fire the callback
+						callback();
+					} else if ( xhr.readyState === 4 ) {
+						// (IE6 & IE7) if it's in cache and has been
+						// retrieved directly we need to fire the callback
+						setTimeout( callback );
+					} else {
+						handle = ++xhrId;
+						if ( xhrOnUnloadAbort ) {
+							// Create the active xhrs callbacks list if needed
+							// and attach the unload handler
+							if ( !xhrCallbacks ) {
+								xhrCallbacks = {};
+								jQuery( window ).unload( xhrOnUnloadAbort );
+							}
+							// Add to list of active xhrs callbacks
+							xhrCallbacks[ handle ] = callback;
+						}
+						xhr.onreadystatechange = callback;
+					}
+				},
+
+				abort: function() {
+					if ( callback ) {
+						callback( undefined, true );
+					}
+				}
+			};
+		}
+	});
+}
+var fxNow, timerId,
+	rfxtypes = /^(?:toggle|show|hide)$/,
+	rfxnum = new RegExp( "^(?:([+-])=|)(" + core_pnum + ")([a-z%]*)$", "i" ),
+	rrun = /queueHooks$/,
+	animationPrefilters = [ defaultPrefilter ],
+	tweeners = {
+		"*": [function( prop, value ) {
+			var end, unit,
+				tween = this.createTween( prop, value ),
+				parts = rfxnum.exec( value ),
+				target = tween.cur(),
+				start = +target || 0,
+				scale = 1,
+				maxIterations = 20;
+
+			if ( parts ) {
+				end = +parts[2];
+				unit = parts[3] || ( jQuery.cssNumber[ prop ] ? "" : "px" );
+
+				// We need to compute starting value
+				if ( unit !== "px" && start ) {
+					// Iteratively approximate from a nonzero starting point
+					// Prefer the current property, because this process will be trivial if it uses the same units
+					// Fallback to end or a simple constant
+					start = jQuery.css( tween.elem, prop, true ) || end || 1;
+
+					do {
+						// If previous iteration zeroed out, double until we get *something*
+						// Use a string for doubling factor so we don't accidentally see scale as unchanged below
+						scale = scale || ".5";
+
+						// Adjust and apply
+						start = start / scale;
+						jQuery.style( tween.elem, prop, start + unit );
+
+					// Update scale, tolerating zero or NaN from tween.cur()
+					// And breaking the loop if scale is unchanged or perfect, or if we've just had enough
+					} while ( scale !== (scale = tween.cur() / target) && scale !== 1 && --maxIterations );
+				}
+
+				tween.unit = unit;
+				tween.start = start;
+				// If a +=/-= token was provided, we're doing a relative animation
+				tween.end = parts[1] ? start + ( parts[1] + 1 ) * end : end;
+			}
+			return tween;
+		}]
+	};
+
+// Animations created synchronously will run synchronously
+function createFxNow() {
+	setTimeout(function() {
+		fxNow = undefined;
+	});
+	return ( fxNow = jQuery.now() );
+}
+
+function createTweens( animation, props ) {
+	jQuery.each( props, function( prop, value ) {
+		var collection = ( tweeners[ prop ] || [] ).concat( tweeners[ "*" ] ),
+			index = 0,
+			length = collection.length;
+		for ( ; index < length; index++ ) {
+			if ( collection[ index ].call( animation, prop, value ) ) {
+
+				// we're done with this property
+				return;
+			}
+		}
+	});
+}
+
+function Animation( elem, properties, options ) {
+	var result,
+		stopped,
+		index = 0,
+		length = animationPrefilters.length,
+		deferred = jQuery.Deferred().always( function() {
+			// don't match elem in the :animated selector
+			delete tick.elem;
+		}),
+		tick = function() {
+			if ( stopped ) {
+				return false;
+			}
+			var currentTime = fxNow || createFxNow(),
+				remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ),
+				// archaic crash bug won't allow us to use 1 - ( 0.5 || 0 ) (#12497)
+				temp = remaining / animation.duration || 0,
+				percent = 1 - temp,
+				index = 0,
+				length = animation.tweens.length;
+
+			for ( ; index < length ; index++ ) {
+				animation.tweens[ index ].run( percent );
+			}
+
+			deferred.notifyWith( elem, [ animation, percent, remaining ]);
+
+			if ( percent < 1 && length ) {
+				return remaining;
+			} else {
+				deferred.resolveWith( elem, [ animation ] );
+				return false;
+			}
+		},
+		animation = deferred.promise({
+			elem: elem,
+			props: jQuery.extend( {}, properties ),
+			opts: jQuery.extend( true, { specialEasing: {} }, options ),
+			originalProperties: properties,
+			originalOptions: options,
+			startTime: fxNow || createFxNow(),
+			duration: options.duration,
+			tweens: [],
+			createTween: function( prop, end ) {
+				var tween = jQuery.Tween( elem, animation.opts, prop, end,
+						animation.opts.specialEasing[ prop ] || animation.opts.easing );
+				animation.tweens.push( tween );
+				return tween;
+			},
+			stop: function( gotoEnd ) {
+				var index = 0,
+					// if we are going to the end, we want to run all the tweens
+					// otherwise we skip this part
+					length = gotoEnd ? animation.tweens.length : 0;
+				if ( stopped ) {
+					return this;
+				}
+				stopped = true;
+				for ( ; index < length ; index++ ) {
+					animation.tweens[ index ].run( 1 );
+				}
+
+				// resolve when we played the last frame
+				// otherwise, reject
+				if ( gotoEnd ) {
+					deferred.resolveWith( elem, [ animation, gotoEnd ] );
+				} else {
+					deferred.rejectWith( elem, [ animation, gotoEnd ] );
+				}
+				return this;
+			}
+		}),
+		props = animation.props;
+
+	propFilter( props, animation.opts.specialEasing );
+
+	for ( ; index < length ; index++ ) {
+		result = animationPrefilters[ index ].call( animation, elem, props, animation.opts );
+		if ( result ) {
+			return result;
+		}
+	}
+
+	createTweens( animation, props );
+
+	if ( jQuery.isFunction( animation.opts.start ) ) {
+		animation.opts.start.call( elem, animation );
+	}
+
+	jQuery.fx.timer(
+		jQuery.extend( tick, {
+			elem: elem,
+			anim: animation,
+			queue: animation.opts.queue
+		})
+	);
+
+	// attach callbacks from options
+	return animation.progress( animation.opts.progress )
+		.done( animation.opts.done, animation.opts.complete )
+		.fail( animation.opts.fail )
+		.always( animation.opts.always );
+}
+
+function propFilter( props, specialEasing ) {
+	var index, name, easing, value, hooks;
+
+	// camelCase, specialEasing and expand cssHook pass
+	for ( index in props ) {
+		name = jQuery.camelCase( index );
+		easing = specialEasing[ name ];
+		value = props[ index ];
+		if ( jQuery.isArray( value ) ) {
+			easing = value[ 1 ];
+			value = props[ index ] = value[ 0 ];
+		}
+
+		if ( index !== name ) {
+			props[ name ] = value;
+			delete props[ index ];
+		}
+
+		hooks = jQuery.cssHooks[ name ];
+		if ( hooks && "expand" in hooks ) {
+			value = hooks.expand( value );
+			delete props[ name ];
+
+			// not quite $.extend, this wont overwrite keys already present.
+			// also - reusing 'index' from above because we have the correct "name"
+			for ( index in value ) {
+				if ( !( index in props ) ) {
+					props[ index ] = value[ index ];
+					specialEasing[ index ] = easing;
+				}
+			}
+		} else {
+			specialEasing[ name ] = easing;
+		}
+	}
+}
+
+jQuery.Animation = jQuery.extend( Animation, {
+
+	tweener: function( props, callback ) {
+		if ( jQuery.isFunction( props ) ) {
+			callback = props;
+			props = [ "*" ];
+		} else {
+			props = props.split(" ");
+		}
+
+		var prop,
+			index = 0,
+			length = props.length;
+
+		for ( ; index < length ; index++ ) {
+			prop = props[ index ];
+			tweeners[ prop ] = tweeners[ prop ] || [];
+			tweeners[ prop ].unshift( callback );
+		}
+	},
+
+	prefilter: function( callback, prepend ) {
+		if ( prepend ) {
+			animationPrefilters.unshift( callback );
+		} else {
+			animationPrefilters.push( callback );
+		}
+	}
+});
+
+function defaultPrefilter( elem, props, opts ) {
+	/*jshint validthis:true */
+	var index, prop, value, length, dataShow, toggle, tween, hooks, oldfire,
+		anim = this,
+		style = elem.style,
+		orig = {},
+		handled = [],
+		hidden = elem.nodeType && isHidden( elem );
+
+	// handle queue: false promises
+	if ( !opts.queue ) {
+		hooks = jQuery._queueHooks( elem, "fx" );
+		if ( hooks.unqueued == null ) {
+			hooks.unqueued = 0;
+			oldfire = hooks.empty.fire;
+			hooks.empty.fire = function() {
+				if ( !hooks.unqueued ) {
+					oldfire();
+				}
+			};
+		}
+		hooks.unqueued++;
+
+		anim.always(function() {
+			// doing this makes sure that the complete handler will be called
+			// before this completes
+			anim.always(function() {
+				hooks.unqueued--;
+				if ( !jQuery.queue( elem, "fx" ).length ) {
+					hooks.empty.fire();
+				}
+			});
+		});
+	}
+
+	// height/width overflow pass
+	if ( elem.nodeType === 1 && ( "height" in props || "width" in props ) ) {
+		// Make sure that nothing sneaks out
+		// Record all 3 overflow attributes because IE does not
+		// change the overflow attribute when overflowX and
+		// overflowY are set to the same value
+		opts.overflow = [ style.overflow, style.overflowX, style.overflowY ];
+
+		// Set display property to inline-block for height/width
+		// animations on inline elements that are having width/height animated
+		if ( jQuery.css( elem, "display" ) === "inline" &&
+				jQuery.css( elem, "float" ) === "none" ) {
+
+			// inline-level elements accept inline-block;
+			// block-level elements need to be inline with layout
+			if ( !jQuery.support.inlineBlockNeedsLayout || css_defaultDisplay( elem.nodeName ) === "inline" ) {
+				style.display = "inline-block";
+
+			} else {
+				style.zoom = 1;
+			}
+		}
+	}
+
+	if ( opts.overflow ) {
+		style.overflow = "hidden";
+		if ( !jQuery.support.shrinkWrapBlocks ) {
+			anim.done(function() {
+				style.overflow = opts.overflow[ 0 ];
+				style.overflowX = opts.overflow[ 1 ];
+				style.overflowY = opts.overflow[ 2 ];
+			});
+		}
+	}
+
+
+	// show/hide pass
+	for ( index in props ) {
+		value = props[ index ];
+		if ( rfxtypes.exec( value ) ) {
+			delete props[ index ];
+			toggle = toggle || value === "toggle";
+			if ( value === ( hidden ? "hide" : "show" ) ) {
+				continue;
+			}
+			handled.push( index );
+		}
+	}
+
+	length = handled.length;
+	if ( length ) {
+		dataShow = jQuery._data( elem, "fxshow" ) || jQuery._data( elem, "fxshow", {} );
+		if ( "hidden" in dataShow ) {
+			hidden = dataShow.hidden;
+		}
+
+		// store state if its toggle - enables .stop().toggle() to "reverse"
+		if ( toggle ) {
+			dataShow.hidden = !hidden;
+		}
+		if ( hidden ) {
+			jQuery( elem ).show();
+		} else {
+			anim.done(function() {
+				jQuery( elem ).hide();
+			});
+		}
+		anim.done(function() {
+			var prop;
+			jQuery._removeData( elem, "fxshow" );
+			for ( prop in orig ) {
+				jQuery.style( elem, prop, orig[ prop ] );
+			}
+		});
+		for ( index = 0 ; index < length ; index++ ) {
+			prop = handled[ index ];
+			tween = anim.createTween( prop, hidden ? dataShow[ prop ] : 0 );
+			orig[ prop ] = dataShow[ prop ] || jQuery.style( elem, prop );
+
+			if ( !( prop in dataShow ) ) {
+				dataShow[ prop ] = tween.start;
+				if ( hidden ) {
+					tween.end = tween.start;
+					tween.start = prop === "width" || prop === "height" ? 1 : 0;
+				}
+			}
+		}
+	}
+}
+
+function Tween( elem, options, prop, end, easing ) {
+	return new Tween.prototype.init( elem, options, prop, end, easing );
+}
+jQuery.Tween = Tween;
+
+Tween.prototype = {
+	constructor: Tween,
+	init: function( elem, options, prop, end, easing, unit ) {
+		this.elem = elem;
+		this.prop = prop;
+		this.easing = easing || "swing";
+		this.options = options;
+		this.start = this.now = this.cur();
+		this.end = end;
+		this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" );
+	},
+	cur: function() {
+		var hooks = Tween.propHooks[ this.prop ];
+
+		return hooks && hooks.get ?
+			hooks.get( this ) :
+			Tween.propHooks._default.get( this );
+	},
+	run: function( percent ) {
+		var eased,
+			hooks = Tween.propHooks[ this.prop ];
+
+		if ( this.options.duration ) {
+			this.pos = eased = jQuery.easing[ this.easing ](
+				percent, this.options.duration * percent, 0, 1, this.options.duration
+			);
+		} else {
+			this.pos = eased = percent;
+		}
+		this.now = ( this.end - this.start ) * eased + this.start;
+
+		if ( this.options.step ) {
+			this.options.step.call( this.elem, this.now, this );
+		}
+
+		if ( hooks && hooks.set ) {
+			hooks.set( this );
+		} else {
+			Tween.propHooks._default.set( this );
+		}
+		return this;
+	}
+};
+
+Tween.prototype.init.prototype = Tween.prototype;
+
+Tween.propHooks = {
+	_default: {
+		get: function( tween ) {
+			var result;
+
+			if ( tween.elem[ tween.prop ] != null &&
+				(!tween.elem.style || tween.elem.style[ tween.prop ] == null) ) {
+				return tween.elem[ tween.prop ];
+			}
+
+			// passing a non empty string as a 3rd parameter to .css will automatically
+			// attempt a parseFloat and fallback to a string if the parse fails
+			// so, simple values such as "10px" are parsed to Float.
+			// complex values such as "rotate(1rad)" are returned as is.
+			result = jQuery.css( tween.elem, tween.prop, "auto" );
+			// Empty strings, null, undefined and "auto" are converted to 0.
+			return !result || result === "auto" ? 0 : result;
+		},
+		set: function( tween ) {
+			// use step hook for back compat - use cssHook if its there - use .style if its
+			// available and use plain properties where available
+			if ( jQuery.fx.step[ tween.prop ] ) {
+				jQuery.fx.step[ tween.prop ]( tween );
+			} else if ( tween.elem.style && ( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null || jQuery.cssHooks[ tween.prop ] ) ) {
+				jQuery.style( tween.elem, tween.prop, tween.now + tween.unit );
+			} else {
+				tween.elem[ tween.prop ] = tween.now;
+			}
+		}
+	}
+};
+
+// Remove in 2.0 - this supports IE8's panic based approach
+// to setting things on disconnected nodes
+
+Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = {
+	set: function( tween ) {
+		if ( tween.elem.nodeType && tween.elem.parentNode ) {
+			tween.elem[ tween.prop ] = tween.now;
+		}
+	}
+};
+
+jQuery.each([ "toggle", "show", "hide" ], function( i, name ) {
+	var cssFn = jQuery.fn[ name ];
+	jQuery.fn[ name ] = function( speed, easing, callback ) {
+		return speed == null || typeof speed === "boolean" ?
+			cssFn.apply( this, arguments ) :
+			this.animate( genFx( name, true ), speed, easing, callback );
+	};
+});
+
+jQuery.fn.extend({
+	fadeTo: function( speed, to, easing, callback ) {
+
+		// show any hidden elements after setting opacity to 0
+		return this.filter( isHidden ).css( "opacity", 0 ).show()
+
+			// animate to the value specified
+			.end().animate({ opacity: to }, speed, easing, callback );
+	},
+	animate: function( prop, speed, easing, callback ) {
+		var empty = jQuery.isEmptyObject( prop ),
+			optall = jQuery.speed( speed, easing, callback ),
+			doAnimation = function() {
+				// Operate on a copy of prop so per-property easing won't be lost
+				var anim = Animation( this, jQuery.extend( {}, prop ), optall );
+				doAnimation.finish = function() {
+					anim.stop( true );
+				};
+				// Empty animations, or finishing resolves immediately
+				if ( empty || jQuery._data( this, "finish" ) ) {
+					anim.stop( true );
+				}
+			};
+			doAnimation.finish = doAnimation;
+
+		return empty || optall.queue === false ?
+			this.each( doAnimation ) :
+			this.queue( optall.queue, doAnimation );
+	},
+	stop: function( type, clearQueue, gotoEnd ) {
+		var stopQueue = function( hooks ) {
+			var stop = hooks.stop;
+			delete hooks.stop;
+			stop( gotoEnd );
+		};
+
+		if ( typeof type !== "string" ) {
+			gotoEnd = clearQueue;
+			clearQueue = type;
+			type = undefined;
+		}
+		if ( clearQueue && type !== false ) {
+			this.queue( type || "fx", [] );
+		}
+
+		return this.each(function() {
+			var dequeue = true,
+				index = type != null && type + "queueHooks",
+				timers = jQuery.timers,
+				data = jQuery._data( this );
+
+			if ( index ) {
+				if ( data[ index ] && data[ index ].stop ) {
+					stopQueue( data[ index ] );
+				}
+			} else {
+				for ( index in data ) {
+					if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) {
+						stopQueue( data[ index ] );
+					}
+				}
+			}
+
+			for ( index = timers.length; index--; ) {
+				if ( timers[ index ].elem === this && (type == null || timers[ index ].queue === type) ) {
+					timers[ index ].anim.stop( gotoEnd );
+					dequeue = false;
+					timers.splice( index, 1 );
+				}
+			}
+
+			// start the next in the queue if the last step wasn't forced
+			// timers currently will call their complete callbacks, which will dequeue
+			// but only if they were gotoEnd
+			if ( dequeue || !gotoEnd ) {
+				jQuery.dequeue( this, type );
+			}
+		});
+	},
+	finish: function( type ) {
+		if ( type !== false ) {
+			type = type || "fx";
+		}
+		return this.each(function() {
+			var index,
+				data = jQuery._data( this ),
+				queue = data[ type + "queue" ],
+				hooks = data[ type + "queueHooks" ],
+				timers = jQuery.timers,
+				length = queue ? queue.length : 0;
+
+			// enable finishing flag on private data
+			data.finish = true;
+
+			// empty the queue first
+			jQuery.queue( this, type, [] );
+
+			if ( hooks && hooks.cur && hooks.cur.finish ) {
+				hooks.cur.finish.call( this );
+			}
+
+			// look for any active animations, and finish them
+			for ( index = timers.length; index--; ) {
+				if ( timers[ index ].elem === this && timers[ index ].queue === type ) {
+					timers[ index ].anim.stop( true );
+					timers.splice( index, 1 );
+				}
+			}
+
+			// look for any animations in the old queue and finish them
+			for ( index = 0; index < length; index++ ) {
+				if ( queue[ index ] && queue[ index ].finish ) {
+					queue[ index ].finish.call( this );
+				}
+			}
+
+			// turn off finishing flag
+			delete data.finish;
+		});
+	}
+});
+
+// Generate parameters to create a standard animation
+function genFx( type, includeWidth ) {
+	var which,
+		attrs = { height: type },
+		i = 0;
+
+	// if we include width, step value is 1 to do all cssExpand values,
+	// if we don't include width, step value is 2 to skip over Left and Right
+	includeWidth = includeWidth? 1 : 0;
+	for( ; i < 4 ; i += 2 - includeWidth ) {
+		which = cssExpand[ i ];
+		attrs[ "margin" + which ] = attrs[ "padding" + which ] = type;
+	}
+
+	if ( includeWidth ) {
+		attrs.opacity = attrs.width = type;
+	}
+
+	return attrs;
+}
+
+// Generate shortcuts for custom animations
+jQuery.each({
+	slideDown: genFx("show"),
+	slideUp: genFx("hide"),
+	slideToggle: genFx("toggle"),
+	fadeIn: { opacity: "show" },
+	fadeOut: { opacity: "hide" },
+	fadeToggle: { opacity: "toggle" }
+}, function( name, props ) {
+	jQuery.fn[ name ] = function( speed, easing, callback ) {
+		return this.animate( props, speed, easing, callback );
+	};
+});
+
+jQuery.speed = function( speed, easing, fn ) {
+	var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : {
+		complete: fn || !fn && easing ||
+			jQuery.isFunction( speed ) && speed,
+		duration: speed,
+		easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing
+	};
+
+	opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration :
+		opt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[ opt.duration ] : jQuery.fx.speeds._default;
+
+	// normalize opt.queue - true/undefined/null -> "fx"
+	if ( opt.queue == null || opt.queue === true ) {
+		opt.queue = "fx";
+	}
+
+	// Queueing
+	opt.old = opt.complete;
+
+	opt.complete = function() {
+		if ( jQuery.isFunction( opt.old ) ) {
+			opt.old.call( this );
+		}
+
+		if ( opt.queue ) {
+			jQuery.dequeue( this, opt.queue );
+		}
+	};
+
+	return opt;
+};
+
+jQuery.easing = {
+	linear: function( p ) {
+		return p;
+	},
+	swing: function( p ) {
+		return 0.5 - Math.cos( p*Math.PI ) / 2;
+	}
+};
+
+jQuery.timers = [];
+jQuery.fx = Tween.prototype.init;
+jQuery.fx.tick = function() {
+	var timer,
+		timers = jQuery.timers,
+		i = 0;
+
+	fxNow = jQuery.now();
+
+	for ( ; i < timers.length; i++ ) {
+		timer = timers[ i ];
+		// Checks the timer has not already been removed
+		if ( !timer() && timers[ i ] === timer ) {
+			timers.splice( i--, 1 );
+		}
+	}
+
+	if ( !timers.length ) {
+		jQuery.fx.stop();
+	}
+	fxNow = undefined;
+};
+
+jQuery.fx.timer = function( timer ) {
+	if ( timer() && jQuery.timers.push( timer ) ) {
+		jQuery.fx.start();
+	}
+};
+
+jQuery.fx.interval = 13;
+
+jQuery.fx.start = function() {
+	if ( !timerId ) {
+		timerId = setInterval( jQuery.fx.tick, jQuery.fx.interval );
+	}
+};
+
+jQuery.fx.stop = function() {
+	clearInterval( timerId );
+	timerId = null;
+};
+
+jQuery.fx.speeds = {
+	slow: 600,
+	fast: 200,
+	// Default speed
+	_default: 400
+};
+
+// Back Compat <1.8 extension point
+jQuery.fx.step = {};
+
+if ( jQuery.expr && jQuery.expr.filters ) {
+	jQuery.expr.filters.animated = function( elem ) {
+		return jQuery.grep(jQuery.timers, function( fn ) {
+			return elem === fn.elem;
+		}).length;
+	};
+}
+jQuery.fn.offset = function( options ) {
+	if ( arguments.length ) {
+		return options === undefined ?
+			this :
+			this.each(function( i ) {
+				jQuery.offset.setOffset( this, options, i );
+			});
+	}
+
+	var docElem, win,
+		box = { top: 0, left: 0 },
+		elem = this[ 0 ],
+		doc = elem && elem.ownerDocument;
+
+	if ( !doc ) {
+		return;
+	}
+
+	docElem = doc.documentElement;
+
+	// Make sure it's not a disconnected DOM node
+	if ( !jQuery.contains( docElem, elem ) ) {
+		return box;
+	}
+
+	// If we don't have gBCR, just use 0,0 rather than error
+	// BlackBerry 5, iOS 3 (original iPhone)
+	if ( typeof elem.getBoundingClientRect !== "undefined" ) {
+		box = elem.getBoundingClientRect();
+	}
+	win = getWindow( doc );
+	return {
+		top: box.top  + ( win.pageYOffset || docElem.scrollTop )  - ( docElem.clientTop  || 0 ),
+		left: box.left + ( win.pageXOffset || docElem.scrollLeft ) - ( docElem.clientLeft || 0 )
+	};
+};
+
+jQuery.offset = {
+
+	setOffset: function( elem, options, i ) {
+		var position = jQuery.css( elem, "position" );
+
+		// set position first, in-case top/left are set even on static elem
+		if ( position === "static" ) {
+			elem.style.position = "relative";
+		}
+
+		var curElem = jQuery( elem ),
+			curOffset = curElem.offset(),
+			curCSSTop = jQuery.css( elem, "top" ),
+			curCSSLeft = jQuery.css( elem, "left" ),
+			calculatePosition = ( position === "absolute" || position === "fixed" ) && jQuery.inArray("auto", [curCSSTop, curCSSLeft]) > -1,
+			props = {}, curPosition = {}, curTop, curLeft;
+
+		// need to be able to calculate position if either top or left is auto and position is either absolute or fixed
+		if ( calculatePosition ) {
+			curPosition = curElem.position();
+			curTop = curPosition.top;
+			curLeft = curPosition.left;
+		} else {
+			curTop = parseFloat( curCSSTop ) || 0;
+			curLeft = parseFloat( curCSSLeft ) || 0;
+		}
+
+		if ( jQuery.isFunction( options ) ) {
+			options = options.call( elem, i, curOffset );
+		}
+
+		if ( options.top != null ) {
+			props.top = ( options.top - curOffset.top ) + curTop;
+		}
+		if ( options.left != null ) {
+			props.left = ( options.left - curOffset.left ) + curLeft;
+		}
+
+		if ( "using" in options ) {
+			options.using.call( elem, props );
+		} else {
+			curElem.css( props );
+		}
+	}
+};
+
+
+jQuery.fn.extend({
+
+	position: function() {
+		if ( !this[ 0 ] ) {
+			return;
+		}
+
+		var offsetParent, offset,
+			parentOffset = { top: 0, left: 0 },
+			elem = this[ 0 ];
+
+		// fixed elements are offset from window (parentOffset = {top:0, left: 0}, because it is it's only offset parent
+		if ( jQuery.css( elem, "position" ) === "fixed" ) {
+			// we assume that getBoundingClientRect is available when computed position is fixed
+			offset = elem.getBoundingClientRect();
+		} else {
+			// Get *real* offsetParent
+			offsetParent = this.offsetParent();
+
+			// Get correct offsets
+			offset = this.offset();
+			if ( !jQuery.nodeName( offsetParent[ 0 ], "html" ) ) {
+				parentOffset = offsetParent.offset();
+			}
+
+			// Add offsetParent borders
+			parentOffset.top  += jQuery.css( offsetParent[ 0 ], "borderTopWidth", true );
+			parentOffset.left += jQuery.css( offsetParent[ 0 ], "borderLeftWidth", true );
+		}
+
+		// Subtract parent offsets and element margins
+		// note: when an element has margin: auto the offsetLeft and marginLeft
+		// are the same in Safari causing offset.left to incorrectly be 0
+		return {
+			top:  offset.top  - parentOffset.top - jQuery.css( elem, "marginTop", true ),
+			left: offset.left - parentOffset.left - jQuery.css( elem, "marginLeft", true)
+		};
+	},
+
+	offsetParent: function() {
+		return this.map(function() {
+			var offsetParent = this.offsetParent || document.documentElement;
+			while ( offsetParent && ( !jQuery.nodeName( offsetParent, "html" ) && jQuery.css( offsetParent, "position") === "static" ) ) {
+				offsetParent = offsetParent.offsetParent;
+			}
+			return offsetParent || document.documentElement;
+		});
+	}
+});
+
+
+// Create scrollLeft and scrollTop methods
+jQuery.each( {scrollLeft: "pageXOffset", scrollTop: "pageYOffset"}, function( method, prop ) {
+	var top = /Y/.test( prop );
+
+	jQuery.fn[ method ] = function( val ) {
+		return jQuery.access( this, function( elem, method, val ) {
+			var win = getWindow( elem );
+
+			if ( val === undefined ) {
+				return win ? (prop in win) ? win[ prop ] :
+					win.document.documentElement[ method ] :
+					elem[ method ];
+			}
+
+			if ( win ) {
+				win.scrollTo(
+					!top ? val : jQuery( win ).scrollLeft(),
+					top ? val : jQuery( win ).scrollTop()
+				);
+
+			} else {
+				elem[ method ] = val;
+			}
+		}, method, val, arguments.length, null );
+	};
+});
+
+function getWindow( elem ) {
+	return jQuery.isWindow( elem ) ?
+		elem :
+		elem.nodeType === 9 ?
+			elem.defaultView || elem.parentWindow :
+			false;
+}
+// Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods
+jQuery.each( { Height: "height", Width: "width" }, function( name, type ) {
+	jQuery.each( { padding: "inner" + name, content: type, "": "outer" + name }, function( defaultExtra, funcName ) {
+		// margin is only for outerHeight, outerWidth
+		jQuery.fn[ funcName ] = function( margin, value ) {
+			var chainable = arguments.length && ( defaultExtra || typeof margin !== "boolean" ),
+				extra = defaultExtra || ( margin === true || value === true ? "margin" : "border" );
+
+			return jQuery.access( this, function( elem, type, value ) {
+				var doc;
+
+				if ( jQuery.isWindow( elem ) ) {
+					// As of 5/8/2012 this will yield incorrect results for Mobile Safari, but there
+					// isn't a whole lot we can do. See pull request at this URL for discussion:
+					// https://github.com/jquery/jquery/pull/764
+					return elem.document.documentElement[ "client" + name ];
+				}
+
+				// Get document width or height
+				if ( elem.nodeType === 9 ) {
+					doc = elem.documentElement;
+
+					// Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height], whichever is greatest
+					// unfortunately, this causes bug #3838 in IE6/8 only, but there is currently no good, small way to fix it.
+					return Math.max(
+						elem.body[ "scroll" + name ], doc[ "scroll" + name ],
+						elem.body[ "offset" + name ], doc[ "offset" + name ],
+						doc[ "client" + name ]
+					);
+				}
+
+				return value === undefined ?
+					// Get width or height on the element, requesting but not forcing parseFloat
+					jQuery.css( elem, type, extra ) :
+
+					// Set width or height on the element
+					jQuery.style( elem, type, value, extra );
+			}, type, chainable ? margin : undefined, chainable, null );
+		};
+	});
+});
+// Limit scope pollution from any deprecated API
+// (function() {
+
+// })();
+// Expose jQuery to the global object
+window.jQuery = window.$ = jQuery;
+
+// Expose jQuery as an AMD module, but only for AMD loaders that
+// understand the issues with loading multiple versions of jQuery
+// in a page that all might call define(). The loader will indicate
+// they have special allowances for multiple jQuery versions by
+// specifying define.amd.jQuery = true. Register as a named module,
+// since jQuery can be concatenated with other files that may use define,
+// but not use a proper concatenation script that understands anonymous
+// AMD modules. A named AMD is safest and most robust way to register.
+// Lowercase jquery is used because AMD module names are derived from
+// file names, and jQuery is normally delivered in a lowercase file name.
+// Do this after creating the global so that if an AMD module wants to call
+// noConflict to hide this version of jQuery, it will work.
+if ( typeof define === "function" && define.amd && define.amd.jQuery ) {
+	define( "jquery", [], function () { return jQuery; } );
+}
+
+})( window );
Index: tests/functional/spec/toggle_with_legend.js
===================================================================
--- tests/functional/spec/toggle_with_legend.js	(revision 1606)
+++ tests/functional/spec/toggle_with_legend.js	(revision 1606)
@@ -0,0 +1,47 @@
+describe("Label clickable", function() {
+    it("Click arrow must make target visible", function() {
+	loadFixtures('menu.html');
+	$('#post_status').parent().toggleWithLegend($('#post_status'),{	});
+
+	var $arrow = $('#post_status').parent().find('img');
+	$arrow.click();
+	expect($('#post_status')).toBeVisible();
+    });
+    it("Click arrow twice,must make target visible and after second click hidden", function() {
+	loadFixtures('menu.html');
+	$('#post_status').parent().toggleWithLegend($('#post_status'),{	});
+
+	var $arrow = $('#post_status').parent().find('img');
+	$arrow.click();
+	expect($('#post_status')).toBeVisible();
+
+	$arrow.click();
+	expect($('#post_status')).toBeHidden();
+    });
+    it("Chick target must not hide target", function() {
+	loadFixtures('menu.html');
+	$('#post_status').parent().toggleWithLegend($('#post_status'),{	});
+
+	var $arrow = $('#post_status').parent().find('img');
+	$arrow.click();
+	expect($('#post_status')).toBeVisible();
+
+	$('#post_status option[value="-2"]').attr('selected', 'selected');
+	expect($('#post_status')).toBeVisible();
+    });
+    it("Chick target must not hide target, when legend_click is true", function() {
+	loadFixtures('menu.html');
+	var $label = $('#post_status').parent().children('label');
+	$label.toggleWithLegend($('#post_status'),{'legend_click':true, a_container:false});
+
+	$label.click();
+	expect($('#post_status')).toBeVisible();
+
+	var $arrow = $('#post_status').parent().find('img');
+	$arrow.click();
+	expect($('#post_status')).toBeVisible();
+
+	$('#post_status').val(-2).trigger('change');
+	expect($('#post_status')).toBeVisible();
+    });
+});
Index: tests/functional/spec/users_actions.js
===================================================================
--- tests/functional/spec/users_actions.js	(revision 1602)
+++ tests/functional/spec/users_actions.js	(revision 1602)
@@ -0,0 +1,25 @@
+describe("Permissions feature", function() {
+    it("Click admin persmission must checked all associated permissions", function() {
+	loadFixtures('normal.html');
+	$('#permissions-form').updatePermissionsForm();
+	var permissions = ['usage','publish','delete','contentadmin','categories'];
+
+	$('input[name="perm[default][admin]"]').click();
+	for (var _i=0,_len=permissions.length;_i<_len;_i++) {
+	    expect($('input[name="perm[default]['+permissions[_i]+']"]')).toBeChecked();
+	    expect($('input[name="perm[default]['+permissions[_i]+']"]')).toBeDisabled();
+	}
+    });
+
+    it("Click contentadmin persmission must checked all associated permissions", function() {
+	loadFixtures('normal.html');
+	$('#permissions-form').updatePermissionsForm();
+	var permissions = ['usage','publish','delete'];
+
+	$('input[name="perm[default][contentadmin]"]').click();
+	for (var _i=0,_len=permissions.length;_i<_len;_i++) {
+	    expect($('input[name="perm[default]['+permissions[_i]+']"]')).toBeChecked();
+	    expect($('input[name="perm[default]['+permissions[_i]+']"]')).toBeDisabled();
+	}
+    });
+});
Index: themes/customCSS/_config.php
===================================================================
--- themes/customCSS/_config.php	(revision 1179)
+++ themes/customCSS/_config.php	(revision 1454)
@@ -34,5 +34,5 @@
 
 echo
-'<p class="area"><label>'.__('Style sheet:').' '.
-form::textarea('css',60,20,html::escapeHTML($css_content)).'</label></p>';
+'<p class="area"><label>'.__('Style sheet:').'</label> '.
+form::textarea('css',60,20,html::escapeHTML($css_content)).'</p>';
 ?>
Index: themes/ductile/_config.php
===================================================================
--- themes/ductile/_config.php	(revision 1096)
+++ themes/ductile/_config.php	(revision 1622)
@@ -54,5 +54,5 @@
 
 $fonts = array(
-	__('default') => '',
+	__('Default') => '',
 	__('Ductile primary') => 'Ductile body',
 	__('Ductile secondary') => 'Ductile alternate',
@@ -471,6 +471,6 @@
 	'<td class="handle minimal">'.form::field(array('order['.$i.']'),2,3,$count,'position','',false).
 		form::hidden(array('dynorder[]','dynorder-'.$i),$i).'</td>'.
-	'<td>'.form::hidden(array('sticker_image[]'),$v['image']).'<img src="'.$img_url.$v['image'].'" /> '.'</td>'.
-	'<td scope="raw">'.form::field(array('sticker_label[]','dsl-'.$i),20,255,$v['label']).'</td>'.
+	'<td>'.form::hidden(array('sticker_image[]'),$v['image']).'<img src="'.$img_url.$v['image'].'" alt="'.$v['image'].'" /> '.'</td>'.
+	'<td scope="row">'.form::field(array('sticker_label[]','dsl-'.$i),20,255,$v['label']).'</td>'.
 	'<td>'.form::field(array('sticker_url[]','dsu-'.$i),40,255,$v['url']).'</td>'.
 	'</tr>';
@@ -496,5 +496,5 @@
 	echo 
 		'<tr>'.
-		'<td scope="raw">'.$contexts[$k].'</td>'.
+		'<td scope="row">'.$contexts[$k].'</td>'.
 		'<td>'.form::hidden(array('list_ctx[]'),$k).form::combo(array('list_type[]'),$list_types,$v).'</td>';
 	if (array_key_exists($k,$ductile_counts)) {
@@ -517,5 +517,5 @@
 echo '</fieldset>';
 
-echo '<input type="hidden" name="conf_tab" value="html">';
+echo '<p><input type="hidden" name="conf_tab" value="html" /></p>';
 echo '<p class="clear">'.form::hidden('ds_order','').'<input type="submit" value="'.__('Save').'" />'.$core->formNonce().'</p>';
 echo '</form>';
@@ -540,5 +540,5 @@
 (!empty($ductile_user['body_font']) ? ' '.fontDef($ductile_user['body_font']) : '').
 '</p>'.
-'<p class="form-note">'.__('Set main font to default to use webfont below.').'</p> '.
+'<p class="form-note">'.__('Set main font to Default to use webfont below.').'</p> '.
 '<p class="field"><label for="body_webfont_family">'.__('Webfont family:').'</label> '.
 form::field('body_webfont_family',25,255,$ductile_user['body_webfont_family']).'</p>'.
@@ -554,5 +554,5 @@
 (!empty($ductile_user['alternate_font']) ? ' '.fontDef($ductile_user['alternate_font']) : '').
 '</p>'.
-'<p class="form-note">'.__('Set secondary font to default to use webfont below.').'</p> '.
+'<p class="form-note">'.__('Set secondary font to Default to use webfont below.').'</p> '.
 '<p class="field"><label for="alternate_webfont_family">'.__('Webfont family:').'</label> '.
 form::field('alternate_webfont_family',25,255,$ductile_user['alternate_webfont_family']).'</p>'.
@@ -674,5 +674,5 @@
 echo '</div>';
 
-echo '<input type="hidden" name="conf_tab" value="css">';
+echo '<p><input type="hidden" name="conf_tab" value="css" /></p>';
 echo '<p class="clear"><input type="submit" value="'.__('Save').'" />'.$core->formNonce().'</p>';
 echo '</form>';
Index: themes/ductile/locales/fr/admin.po
===================================================================
--- themes/ductile/locales/fr/admin.po	(revision 1096)
+++ themes/ductile/locales/fr/admin.po	(revision 1568)
@@ -1,4 +1,4 @@
 msgid "Theme configuration upgraded."
-msgstr "Configuration du thème mise à jour."
+msgstr "La configuration du thème a été mise à jour."
 
 msgid "Content"
@@ -15,5 +15,5 @@
 
 msgid "To configure the top menu go to the <a href=\"%s\">Simple Menu administration page</a>."
-msgstr "Pour configurer le menu allez à la <a href=\"%s\">page d'administration de l'extension Menu Simple</a>."
+msgstr "Pour configurer le menu allez à la <a href=\"%s\">page d'administration de Menu Simple</a>."
 
 msgid "Stickers"
@@ -51,5 +51,5 @@
 
 msgid "Search result entries"
-msgstr "Billets résultants d'une recherche"
+msgstr "Billets résultant d'une recherche"
 
 msgid "Month archive entries"
@@ -69,5 +69,5 @@
 
 msgid "Comment preview is not mandatory:"
-msgstr "Prévisualisation du commentaire optionnelle :"
+msgstr "Prévisualisation du commentaire non obligatoire :"
 
 msgid "Presentation"
@@ -87,5 +87,5 @@
 
 msgid "Font size (in em by default):"
-msgstr "Taille de police (en em par défaut) :"
+msgstr "Taille du texte courant (en em par défaut) :"
 
 msgid "Color:"
@@ -125,8 +125,8 @@
 msgstr "feuille de style (Google)"
 
-msgid "Set main font to default to use webfont below."
+msgid "Set main font to Default to use webfont below."
 msgstr "Mettre la police de caractère principale à Défaut pour utiliser la fonte web ci-dessous."
 
-msgid "Set secondary font to default to use webfont below."
+msgid "Set secondary font to Default to use webfont below."
 msgstr "Mettre la police de caractère secondaire à Défaut pour utiliser la fonte web ci-dessous."
 
Index: themes/ductile/locales/fr/help/help.html
===================================================================
--- themes/ductile/locales/fr/help/help.html	(revision 810)
+++ themes/ductile/locales/fr/help/help.html	(revision 1568)
@@ -15,5 +15,5 @@
 
 <p>Cochez la case qui suit « Cacher la description du blog » pour ne pas afficher la description du blog habituellement affichée sous le titre.</p>
-<p>Vous pouvez, si l'extension « Menu Simple » est installée et active, cliquer sur le lien indiqué pour paramétrer le menu affiché en entête.</p>
+<p>Vous pouvez, si « Menu Simple » est installé et actif, cliquer sur le lien indiqué pour paramétrer le menu affiché en entête.</p>
 <p>Vous pouvez indiquer l'URL d'un logo à utiliser à la place du logo par défaut. Si l'URL ne débute pas par un <code>/</code> il s'agira d'une URL relative au dossier <code>img</code> du thème (mettre <code>logo.png</code> revient par exemple à utiliser le logo par défaut). Videz ce champ pour revenir à la configuration par défaut.</p>
 
