[pkg-horde] [SCM] Debian Horde Packages repository: nag2 package branch, debian-sid, updated. 1b9e234d7ea19c1f286d1ed96b65929b495081fe

Gregory Colpart reg at foulademer.gcolpart.com
Sun May 3 00:00:53 UTC 2009


The following commit has been merged in the debian-sid branch:
commit 68097946b814ffb86a83d7bf1e3ead4b8dc14b3a
Author: Gregory Colpart <reg at foulademer.gcolpart.com>
Date:   Sun May 3 00:59:28 2009 +0200

    merge from upstream

diff --git a/COPYING b/COPYING
index 5a965fb..a6b6756 100644
--- a/COPYING
+++ b/COPYING
@@ -1,7 +1,7 @@
 		    GNU GENERAL PUBLIC LICENSE
 		       Version 2, June 1991
 
- Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ Copyright 1989, 1991 Free Software Foundation, Inc.
      59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  Everyone is permitted to copy and distribute verbatim copies
  of this license document, but changing it is not allowed.
diff --git a/config/hooks.php.dist b/config/hooks.php.dist
new file mode 100644
index 0000000..1f59034
--- /dev/null
+++ b/config/hooks.php.dist
@@ -0,0 +1,26 @@
+<?php
+/**
+ * Example hooks for Nag
+ *
+ * $Horde: nag/config/hooks.php.dist,v 1.1.2.1 2008/11/26 21:25:25 chuck Exp $
+ */
+
+// if (!function_exists('_nag_hook_format_description')) {
+//     function _nag_hook_format_description($text)
+//     {
+//         $text = preg_replace('/#(\d+)/', '<a href="http://bugs.horde.org/ticket/\1">\0</a>', $text);
+//         $text = preg_replace('/(bug|ticket|request|enhancement|issue):\s*#?(\d+)/i', '<a href="http://bugs.horde.org/ticket/\1">\0</a>', $text);
+// 
+//         $text = preg_replace_callback('/\[\[note: ?(.*)\]\]/i', create_function('$m', 'return \'<a href="/horde/mnemo/notes/?q=\' . urlencode($m[1]) . \'">\' . htmlspecialchars($m[0]) . \'</a>\';'), $text);
+//         $text = preg_replace_callback('/\[\[task: ?(.*)\]\]/i', create_function('$m', 'return \'<a href="/horde/nag/tasks/?q=\' . urlencode($m[1]) . \'">\' . htmlspecialchars($m[0]) . \'</a>\';'), $text);
+// 
+//         return $text;
+//     }
+// }
+
+// if (!function_exists('_nag_hook_description_help')) {
+//     function _nag_hook_description_help()
+//     {
+//         return '<p>To create a link to a bug, use #123 where 123 is the bug number. To create a link to another task, use [[task: name]], where name is the beginning of the task name. To create a link to a note, use [[note: title]] where title is the beginning of the note title.</p>';
+//     }
+// }
diff --git a/config/prefs.php.dist b/config/prefs.php.dist
index 8676358..bb62035 100644
--- a/config/prefs.php.dist
+++ b/config/prefs.php.dist
@@ -1,6 +1,6 @@
 <?php
 /**
- * $Horde: nag/config/prefs.php.dist,v 1.42.2.8 2008/02/13 19:56:58 chuck Exp $
+ * $Horde: nag/config/prefs.php.dist,v 1.42.2.11 2008/11/25 20:56:00 chuck Exp $
  *
  * See horde/config/prefs.php for documentation on the structure of this file.
  */
@@ -12,7 +12,8 @@ $prefGroups['display'] = array(
     'column' => _("General Options"),
     'label' => _("Display Options"),
     'desc' => _("Change your task sorting and display options."),
-    'members' => array('show_tasklist', 'show_panel', 'sortby', 'altsortby', 'sortdir'),
+    'members' => array('tasklist_columns', 'show_panel', 'sortby', 'altsortby',
+                       'sortdir'),
 );
 
 $prefGroups['deletion'] = array(
@@ -59,13 +60,19 @@ if (count($_show_external)) {
     );
 }
 
-// show a task list column in the list view?
-$_prefs['show_tasklist'] = array(
-    'value' => 0,
+// columns in the list view
+$_prefs['tasklist_columns'] = array(
+    'value' => 'a:3:{i:0;s:8:"priority";i:1;s:3:"due";i:2;s:8:"category";}',
     'locked' => false,
     'shared' => false,
-    'type' => 'checkbox',
-    'desc' => _("Should the Task List be shown in its own column in the List view?")
+    'type' => 'multienum',
+    'enum' => array('tasklist' => _("Task List"),
+                    'priority' => _("Priority"),
+                    'assignee' => _("Assignee"),
+                    'due' => _("Due Date"),
+                    'estimate' => _("Estimated Time"),
+                    'category' => _("Category")),
+    'desc' => _("Select the columns that should be shown in the list view:")
 );
 
 // show the task list options panel?
@@ -89,6 +96,8 @@ $_prefs['sortby'] = array(
                     NAG_SORT_CATEGORY => _("Category"),
                     NAG_SORT_DUE => _("Due Date"),
                     NAG_SORT_COMPLETION => _("Completed?"),
+                    NAG_SORT_ESTIMATE => _("Estimated Time"),
+                    NAG_SORT_ASSIGNEE => _("Assignee"),
                     NAG_SORT_OWNER => _("Task List")),
     'desc' => _("Sort tasks by:"),
 );
@@ -104,6 +113,8 @@ $_prefs['altsortby'] = array(
                     NAG_SORT_CATEGORY => _("Category"),
                     NAG_SORT_DUE => _("Due Date"),
                     NAG_SORT_COMPLETION => _("Completed?"),
+                    NAG_SORT_ESTIMATE => _("Estimated Time"),
+                    NAG_SORT_ASSIGNEE => _("Assignee"),
                     NAG_SORT_OWNER => _("Task List")),
     'desc' => _("Then:"),
 );
@@ -219,7 +230,7 @@ $_prefs['tasklistselect'] = array('type' => 'special');
 $_prefs['default_tasklist'] = array(
     'value' => Auth::getAuth() ? Auth::getAuth() : 0,
     'locked' => false,
-    'shared' => true,
+    'shared' => false,
     'type' => 'implicit',
 );
 
diff --git a/data.php b/data.php
index 9763e9e..1d68c6c 100644
--- a/data.php
+++ b/data.php
@@ -1,8 +1,8 @@
 <?php
 /**
- * $Horde: nag/data.php,v 1.39.8.16 2008/05/25 13:59:37 jan Exp $
+ * $Horde: nag/data.php,v 1.39.8.19 2009/01/06 15:25:04 jan Exp $
  *
- * Copyright 2001-2008 The Horde Project (http://www.horde.org/)
+ * Copyright 2001-2009 The Horde Project (http://www.horde.org/)
  *
  * See the enclosed file COPYING for license information (GPL). If you
  * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
@@ -79,9 +79,14 @@ $error         = false;
 switch ($actionID) {
 case 'export':
     $exportID = Util::getFormData('exportID');
+    $tasklists = Util::getFormData('exportList', $display_tasklists);
+    if (!is_array($tasklists)) {
+        $tasklists = array($tasklists);
+    }
 
     /* Get the full, sorted task list. */
-    $tasks = Nag::listTasks($prefs->getValue('sortby'), $prefs->getValue('sortdir'), $prefs->getValue('altsortby'));
+    $tasks = Nag::listTasks(null, null, null, $tasklists,
+                            Util::getFormData('exportTasks'));
     if (is_a($tasks, 'PEAR_Error')) {
         $notification->push($tasks);
         $error = true;
@@ -187,7 +192,8 @@ if (is_array($next_step)) {
                                 $row['estimate'], $row['completed'],
                                 $row['category'], $row['alarm'], $row['uid'],
                                 isset($row['parent']) ? $row['parent'] : '',
-                                $row['private']);
+                                $row['private'], Auth::getAuth(),
+                                $row['assignee']);
         if (is_a($result, 'PEAR_Error')) {
             break;
         }
diff --git a/docs/CHANGES b/docs/CHANGES
index 48e11f3..c672bd6 100644
--- a/docs/CHANGES
+++ b/docs/CHANGES
@@ -1,3 +1,58 @@
+------
+v2.3.2
+------
+
+[jan] Don't allow to set alarms if no due date has been set.
+[cjh] Work around BC break with Horde versions before 3.2 (Bug #7820).
+[cjh] Add URL access to tasks by "starts-with" search on the task name.
+[cjh] Add hooks for altering the displayed task description and showing help
+      text next to the task description entry field.
+[cjh] Add estimated time to the fields available in the task list.
+[jan] Fix link escaping in notification messages (Alfonso Marín Marín
+      <almarin at um.es>, Bug #7509).
+
+
+------
+v2.3.1
+------
+
+[cjh] Add a PostgreSQL-specific upgrade script for 2.2 to 2.3.
+[cjh] Fix fatal error when completing tasks (Bug #7400).
+[mms] Upgrade prototype.js to v1.6.0.3.
+
+
+----
+v2.3
+----
+
+[jan] Change group field in shares table to work with LDAP groups (Bug #6883).
+[jan] Log completion date if adding a completed task (Bug #7275).
+[jan] Fix user name conversion with user hooks in the task list panel
+      (Bug #7366).
+[jan] Fix displayed WebDAV subscription URLs in the task list manager.
+
+
+--------
+v2.3-RC1
+--------
+
+[jan] Log moving of tasks in the history backend (Bug #3207).
+[jan] Fix deleting all tasks over WebDAV (Bug #7004).
+[jan] Add Estonian translation (Alar Sing <alar.sing at err.ee>).
+[jan] Send a more detailed notification message and use the recipient's
+      preferred language and date/time format after a task has changed.
+[jan] Add Basque translation (Euskal Herriko Unibertsitatea EHU/UPV
+      <xabier.arrieta at ehu.es>).
+[jan] Fix task relationship getting lost when importing tasks
+      (tkrah at fachschaft.imn.htwk-leipzig.de, bb.apc.ag, Bug #6770).
+[jan] Add preference to set columns for the list view.
+[jan] Allow to set task assignee.
+[jan] Add options to export screen for choosing task lists and task states.
+[mjr] Remove user permissions on all shares when deleting a user.
+[mjr] Fix issue with removeUserData api that caused the deleted user's task list
+      to not be deleted (Bug #6969).
+
+
 ----
 v2.2
 ----
@@ -237,7 +292,7 @@ v2.0-BETA
       (Andrew Coleman <mercury at appisolutions.net>).
 [cjh] Preserve searches while re-sorting (Francois Marier <francois at nit.ca>).
 [jan] Add access keys.
-[cjh] Add Kolab drivers (Stuart Bingë <s.binge at codefusion.co.za>).
+[cjh] Add Kolab drivers (Stuart Bingë <s.binge at codefusion.co.za>).
 
 
 ----------
@@ -357,7 +412,7 @@ v1.0
 [jon] Enable the "portability" option in the SQL driver.
 [jan] Remove the standard value for the language preference. The language to
       fall back to should be set Horde wide in lang.php instead.
-[jan] Add Swedish translation (Andreas Dahlén <andreas at dahlen.ws>).
+[jan] Add Swedish translation (Andreas Dahlén <andreas at dahlen.ws>).
 [jan] Add Traditional Chinese translation (David Chang <david at thbuo.gov.tw>).
 [bjn] Change 'en' and 'en_EN' locales to 'en_US' (default).
 [cjh] Change Nag_Storage:: to Nag_Driver::.
@@ -366,7 +421,7 @@ v1.0
 [jon] Apply a "strike-through" style to closed (completed) tasks.
 [jon] Remove task dependency code.
 [jon] Add completion status. (Paul Cooper <pgc at ucecom.com>)
-[jan] Add French translation (Mikhaël Janson <mik at galaxie.net>).
+[jan] Add French translation (Mikhaël Janson <mik at galaxie.net>).
 [cjh] Let the Registry handle retrieving preferences.
 [jan] Due tasks can now be shown in Kronolith.
 [jan] Add Italian translation (Giovanni Meneghetti <gmeneghetti at infvic.it>).
diff --git a/docs/CREDITS b/docs/CREDITS
index 40c49e8..bb0452c 100644
--- a/docs/CREDITS
+++ b/docs/CREDITS
@@ -15,8 +15,11 @@ Localization
 
 =====================   ======================================================
 Arabic (Syria)          Platinum Development Team <devteam at platinum-sy.net>
+Basque                  Euskal Herriko Unibertsitatea <xabier.arrieta at ehu.es>
 Brazilian Portuguese    Antonio Dias <accdias at sst.com.br>
                         Fabio Gomes <flgomes at fazenda.sp.gov.br>
+                        Luis Felipe Marzagao <duli at fedoraproject.org>
+                        Eduardo de Carli <carliedu at ig.com.br>
 Bulgarian               Miroslav Pendev <miro at cybershade.us>
 Catalan                 Jordi Giralt <projecte.k2 at upcnet.es>
 Chinese (Simplified)    Peter Wang <whw at oulink.net>
@@ -26,6 +29,7 @@ Danish                  Martin List-Petersen <martin at list-petersen.dk>
                         Brian Truelsen <horde+i18n at briantruelsen.dk>
 Dutch                   Jan Kuipers <jrkuipers at lauwerscollege.nl>
                         Ariën Huisken <arien at huisken-systems.nl>
+Estonian                Alar Sing <alar.sing at err.ee>
 Finnish                 Tero Matinlassi <terom at iki.fi>
                         Leena Heino <leena.heino at uta.fi>
 French                  Mikhaël Janson <mik at galaxie.net>
diff --git a/docs/INSTALL b/docs/INSTALL
index ecdac48..f17f6b7 100644
--- a/docs/INSTALL
+++ b/docs/INSTALL
@@ -1,9 +1,9 @@
 ====================
- Installing Nag 2.2
+ Installing Nag 2.3
 ====================
 
-:Last update:   $Date: 2007/12/20 14:23:06 $
-:Revision:      $Revision: 1.19.10.8 $
+:Last update:   $Date: 2008/09/05 14:09:07 $
+:Revision:      $Revision: 1.19.10.9 $
 :Contact:       nag at lists.horde.org
 
 .. contents:: Contents
diff --git a/docs/RELEASE_NOTES b/docs/RELEASE_NOTES
index f9ede31..7be6593 100644
--- a/docs/RELEASE_NOTES
+++ b/docs/RELEASE_NOTES
@@ -12,44 +12,27 @@
  * 8 - Minor security fixes
  * 9 - Major security fixes
  */
-$this->notes['fm']['focus'] = 5;
+$this->notes['fm']['focus'] = 4;
 
 /* Mailing list release notes. */
 $this->notes['ml']['changes'] = <<<ML
 The Horde Team is pleased to announce the final release of the Nag Task List
-Manager version H3 (2.2).
+Manager version H3 (2.3.2).
 
 Nag is a web-based application built upon the Horde Application Framework which
-provides a simple, clean interface for managing online task lists (i.e., TODO
+provides a simple, clean interface for managing online task lists (i.e., todo
 lists).  It also includes strong integration with the other Horde applications
 and offers shared task lists.
 
-Nag version H3 (2.2) is a major upgrade in the 2.x release series, including
-these enhancements:
-    * Support for the Horde_Alarm system (requires Horde 3.2) for email or
-      inline alarms on any event.
-    * Support for sub-tasks and tasks with delayed start dates.
-    * WCAG 1.0 Priority 2/Section 508 accessibility guidelines compliance.
-    * WebDAV support.
-    * Improved vCalendar and iCalendar support.
-    * Support for private tasks.
-    * Dynamic inline searching of the task list, with the option for an
-      advanced search that includes additional options.
-    * All tasklists are now shown in a collapsible panel with easy access to
-      managing your tasklists and choosing which tasks to view.
-    * Completion of tasks is now tracked in a completion date field and in
-      the Horde_History system.
-    * Full Kolab webclient support
-    * Database access can be split between read and write databases.
-    * More graceful operation if the calendar backend is not available.
-    * Improved API support.
-    * Improved tasklist management interface.
-    * and much, much more.
+The major changes compared to the Nag version H3 (2.3.1) are:
+    * Added estimated time to the fields available in the task list.
+    * Added hook for altering the displayed task description.
 ML;
 
 /* Freshmeat release notes, not more than 600 characters. */
 $this->notes['fm']['changes'] = <<<FM
-New in this release: Support for the Horde_Alarm system (requires Horde 3.2); support for sub-tasks and tasks with delayed start dates; WCAG 1.0 Priority 2/Section 508 accessibility guidelines compliance; WebDAV support; improved vCalendar and iCalendar support; support for private tasks; inline task list search; a dynamic tasklist panel; history tracking of task completion; full Kolab webclient support; support for separate read and write databases; smoother operation when the database is down; and many, many bug fixes and small enhancements.
+The estimated time has been added to the fields available in the task list.
+A hook for altering the displayed task description has been added.
 FM;
 
 $this->notes['name'] = 'Nag';
diff --git a/docs/UPGRADING b/docs/UPGRADING
index 7420640..d595074 100644
--- a/docs/UPGRADING
+++ b/docs/UPGRADING
@@ -2,8 +2,8 @@
  Upgrading Nag
 ===============
 
-:Last update:   $Date: 2008/04/30 03:37:38 $
-:Revision:      $Revision: 1.1.8.4 $
+:Last update:   $Date: 2008/09/23 15:18:23 $
+:Revision:      $Revision: 1.1.8.13 $
 :Contact:       nag at lists.horde.org
 
 
@@ -12,6 +12,16 @@ your existing data before running any of the steps described below. You can't
 use the updated data with your old Nag version anymore.
 
 
+Upgrading Nag from 2.2.x to 2.3.x
+=================================
+
+Some fields in the SQL share driver tables have been changed. Execute the
+provided SQL script to update your database if you are using the native SQL
+share driver.
+
+   mysql --user=root --password=<MySQL-root-password>  <db name> < scripts/upgrades/2.2_to_2.3.sql
+
+
 Upgrading Nag from 2.1.x to 2.2.x
 =================================
 
@@ -38,9 +48,13 @@ A new beta-level SQL Horde_Share driver has been added in Horde 3.2. This driver
 offers significant performance improvements over the existing Datatree driver,
 but it has not received the same level of testing, thus the beta designation.
 In order to make use of this driver, you must be using Horde 3.2-RC3 or
-later. To migrate your existing share data, run
-``scripts/upgrades/2.1_to_2.2.php``.  Be sure to read the entry above and create
-the new SQL tables before running the migration script.
+later. The new tables needed for this driver already should have been created
+by the step above.
+
+If you want to use the new SQL Share driver, you must also execute the
+provided PHP script to migrate your existing share data to the new format::
+
+   php scripts/upgrades/convert_datatree_shares_to_sql.php
 
 
 Upgrading Nag from 1.1.x to 2.0.x
diff --git a/ics.php b/ics.php
index e2f8379..8d0a693 100644
--- a/ics.php
+++ b/ics.php
@@ -1,8 +1,8 @@
 <?php
 /**
- * $Horde: nag/ics.php,v 1.4.2.6 2008/01/02 11:32:29 jan Exp $
+ * $Horde: nag/ics.php,v 1.4.2.7 2009/01/06 15:25:04 jan Exp $
  *
- * Copyright 1999-2008 The Horde Project (http://www.horde.org/)
+ * Copyright 1999-2009 The Horde Project (http://www.horde.org/)
  *
  * See the enclosed file COPYING for license information (GPL). If you
  * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
diff --git a/index.php b/index.php
index e6e1372..6c587d9 100644
--- a/index.php
+++ b/index.php
@@ -1,8 +1,8 @@
 <?php
 /**
- * $Horde: nag/index.php,v 1.16.10.6 2008/01/02 11:32:29 jan Exp $
+ * $Horde: nag/index.php,v 1.16.10.7 2009/01/06 15:25:04 jan Exp $
  *
- * Copyright 2001-2008 The Horde Project (http://www.horde.org/)
+ * Copyright 2001-2009 The Horde Project (http://www.horde.org/)
  *
  * See the enclosed file COPYING for license information (GPL). If you
  * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
diff --git a/js/prototype.js b/js/prototype.js
index ab8726c..3c2493f 100644
--- a/js/prototype.js
+++ b/js/prototype.js
@@ -1 +1 @@
-var Prototype={Version:"1.6.0.2",Browser:{IE:!!(window.attachEvent&&!window.opera),Opera:!!window.opera,WebKit:navigator.userAgent.indexOf("AppleWebKit/")>-1,Gecko:navigator.userAgent.indexOf("Gecko")>-1&&navigator.userAgent.indexOf("KHTML")==-1,MobileSafari:!!navigator.userAgent.match(/Apple.*Mobile.*Safari/)},BrowserFeatures:{XPath:!!document.evaluate,ElementExtensions:!!window.HTMLElement,SpecificElementExtensions:document.createElement("div").__proto__&&document.createElement("div").__proto__!==document.createElement("form").__proto__},ScriptFragment:"<script[^>]*>([\\S\\s]*?)<\/script>",JSONFilter:/^\/\*-secure-([\s\S]*)\*\/\s*$/,emptyFunction:function(){},K:function(A){return A}};if(Prototype.Browser.MobileSafari){Prototype.BrowserFeatures.SpecificElementExtensions=false}var Class={create:function(){var E=null,D=$A(arguments);if(Object.isFunction(D[0])){E=D.shift()}function A(){this.initialize.apply(this,arguments)}Object.extend(A,Class.Methods);A.superclass=E;A.subclasses=[];if(E){var B=function(){};B.prototype=E.prototype;A.prototype=new B;E.subclasses.push(A)}for(var C=0;C<D.length;C++){A.addMethods(D[C])}if(!A.prototype.initialize){A.prototype.initialize=Prototype.emptyFunction}A.prototype.constructor=A;return A}};Class.Methods={addMethods:function(G){var C=this.superclass&&this.superclass.prototype;var B=Object.keys(G);if(!Object.keys({toString:true}).length){B.push("toString","valueOf")}for(var A=0,D=B.length;A<D;A++){var F=B[A],E=G[F];if(C&&Object.isFunction(E)&&E.argumentNames().first()=="$super"){var H=E,E=Object.extend((function(I){return function(){return C[I].apply(this,arguments)}})(F).wrap(H),{valueOf:function(){return H},toString:function(){return H.toString()}})}this.prototype[F]=E}return this}};var Abstract={};Object.extend=function(A,C){for(var B in C){A[B]=C[B]}return A};Object.extend(Object,{inspect:function(A){try{if(Object.isUndefined(A)){return"undefined"}if(A===null){return"null"}return A.inspect?A.inspect():String(A)}catch(B){if(B instanceof RangeError){return"..."}throw B}},toJSON:function(A){var C=typeof A;switch(C){case"undefined":case"function":case"unknown":return ;case"boolean":return A.toString()}if(A===null){return"null"}if(A.toJSON){return A.toJSON()}if(Object.isElement(A)){return }var B=[];for(var E in A){var D=Object.toJSON(A[E]);if(!Object.isUndefined(D)){B.push(E.toJSON()+": "+D)}}return"{"+B.join(", ")+"}"},toQueryString:function(A){return $H(A).toQueryString()},toHTML:function(A){return A&&A.toHTML?A.toHTML():String.interpret(A)},keys:function(A){var B=[];for(var C in A){B.push(C)}return B},values:function(B){var A=[];for(var C in B){A.push(B[C])}return A},clone:function(A){return Object.extend({},A)},isElement:function(A){return A&&A.nodeType==1},isArray:function(A){return A!=null&&typeof A=="object"&&"splice" in A&&"join" in A},isHash:function(A){return A instanceof Hash},isFunction:function(A){return typeof A=="function"},isString:function(A){return typeof A=="string"},isNumber:function(A){return typeof A=="number"},isUndefined:function(A){return typeof A=="undefined"}});Object.extend(Function.prototype,{argumentNames:function(){var A=this.toString().match(/^[\s\(]*function[^(]*\((.*?)\)/)[1].split(",").invoke("strip");return A.length==1&&!A[0]?[]:A},bind:function(){if(arguments.length<2&&Object.isUndefined(arguments[0])){return this}var A=this,C=$A(arguments),B=C.shift();return function(){return A.apply(B,C.concat($A(arguments)))}},bindAsEventListener:function(){var A=this,C=$A(arguments),B=C.shift();return function(D){return A.apply(B,[D||window.event].concat(C))}},curry:function(){if(!arguments.length){return this}var A=this,B=$A(arguments);return function(){return A.apply(this,B.concat($A(arguments)))}},delay:function(){var A=this,B=$A(arguments),C=B.shift()*1000;return window.setTimeout(function(){return A.apply(A,B)},C)},wrap:function(B){var A=this;return function(){return B.apply(this,[A.bind(this)].concat($A(arguments)))}},methodize:function(){if(this._methodized){return this._methodized}var A=this;return this._methodized=function(){return A.apply(null,[this].concat($A(arguments)))}}});Function.prototype.defer=Function.prototype.delay.curry(0.01);Date.prototype.toJSON=function(){return'"'+this.getUTCFullYear()+"-"+(this.getUTCMonth()+1).toPaddedString(2)+"-"+this.getUTCDate().toPaddedString(2)+"T"+this.getUTCHours().toPaddedString(2)+":"+this.getUTCMinutes().toPaddedString(2)+":"+this.getUTCSeconds().toPaddedString(2)+'Z"'};var Try={these:function(){var C;for(var B=0,D=arguments.length;B<D;B++){var A=arguments[B];try{C=A();break}catch(E){}}return C}};RegExp.prototype.match=RegExp.prototype.test;RegExp.escape=function(A){return String(A).replace(/([.*+?^=!:${}()|[\]\/\\])/g,"\\$1")};var PeriodicalExecuter=Class.create({initialize:function(B,A){this.callback=B;this.frequency=A;this.currentlyExecuting=false;this.registerCallback()},registerCallback:function(){this.timer=setInterval(this.onTimerEvent.bind(this),this.frequency*1000)},execute:function(){this.callback(this)},stop:function(){if(!this.timer){return }clearInterval(this.timer);this.timer=null},onTimerEvent:function(){if(!this.currentlyExecuting){try{this.currentlyExecuting=true;this.execute()}finally{this.currentlyExecuting=false}}}});Object.extend(String,{interpret:function(A){return A==null?"":String(A)},specialChar:{"\b":"\\b","\t":"\\t","\n":"\\n","\f":"\\f","\r":"\\r","\\":"\\\\"}});Object.extend(String.prototype,{gsub:function(E,C){var A="",D=this,B;C=arguments.callee.prepareReplacement(C);while(D.length>0){if(B=D.match(E)){A+=D.slice(0,B.index);A+=String.interpret(C(B));D=D.slice(B.index+B[0].length)}else{A+=D,D=""}}return A},sub:function(C,A,B){A=this.gsub.prepareReplacement(A);B=Object.isUndefined(B)?1:B;return this.gsub(C,function(D){if(--B<0){return D[0]}return A(D)})},scan:function(B,A){this.gsub(B,A);return String(this)},truncate:function(B,A){B=B||30;A=Object.isUndefined(A)?"...":A;return this.length>B?this.slice(0,B-A.length)+A:String(this)},strip:function(){return this.replace(/^\s+/,"").replace(/\s+$/,"")},stripTags:function(){return this.replace(/<\/?[^>]+>/gi,"")},stripScripts:function(){return this.replace(new RegExp(Prototype.ScriptFragment,"img"),"")},extractScripts:function(){var B=new RegExp(Prototype.ScriptFragment,"img");var A=new RegExp(Prototype.ScriptFragment,"im");return(this.match(B)||[]).map(function(C){return(C.match(A)||["",""])[1]})},evalScripts:function(){return this.extractScripts().map(function(script){return eval(script)})},escapeHTML:function(){var A=arguments.callee;A.text.data=this;return A.div.innerHTML},unescapeHTML:function(){var A=new Element("div");A.innerHTML=this.stripTags();return A.childNodes[0]?(A.childNodes.length>1?$A(A.childNodes).inject("",function(B,C){return B+C.nodeValue}):A.childNodes[0].nodeValue):""},toQueryParams:function(B){var A=this.strip().match(/([^?#]*)(#.*)?$/);if(!A){return{}}return A[1].split(B||"&").inject({},function(E,F){if((F=F.split("="))[0]){var C=decodeURIComponent(F.shift());var D=F.length>1?F.join("="):F[0];if(D!=undefined){D=decodeURIComponent(D)}if(C in E){if(!Object.isArray(E[C])){E[C]=[E[C]]}E[C].push(D)}else{E[C]=D}}return E})},toArray:function(){return this.split("")},succ:function(){return this.slice(0,this.length-1)+String.fromCharCode(this.charCodeAt(this.length-1)+1)},times:function(A){return A<1?"":new Array(A+1).join(this)},camelize:function(){var D=this.split("-"),A=D.length;if(A==1){return D[0]}var C=this.charAt(0)=="-"?D[0].charAt(0).toUpperCase()+D[0].substring(1):D[0];for(var B=1;B<A;B++){C+=D[B].charAt(0).toUpperCase()+D[B].substring(1)}return C},capitalize:function(){return this.charAt(0).toUpperCase()+this.substring(1).toLowerCase()},underscore:function(){return this.gsub(/::/,"/").gsub(/([A-Z]+)([A-Z][a-z])/,"#{1}_#{2}").gsub(/([a-z\d])([A-Z])/,"#{1}_#{2}").gsub(/-/,"_").toLowerCase()},dasherize:function(){return this.gsub(/_/,"-")},inspect:function(B){var A=this.gsub(/[\x00-\x1f\\]/,function(C){var D=String.specialChar[C[0]];return D?D:"\\u00"+C[0].charCodeAt().toPaddedString(2,16)});if(B){return'"'+A.replace(/"/g,'\\"')+'"'}return"'"+A.replace(/'/g,"\\'")+"'"},toJSON:function(){return this.inspect(true)},unfilterJSON:function(A){return this.sub(A||Prototype.JSONFilter,"#{1}")},isJSON:function(){var A=this;if(A.blank()){return false}A=this.replace(/\\./g,"@").replace(/"[^"\\\n\r]*"/g,"");return(/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(A)},evalJSON:function(sanitize){var json=this.unfilterJSON();try{if(!sanitize||json.isJSON()){return eval("("+json+")")}}catch(e){}throw new SyntaxError("Badly formed JSON string: "+this.inspect())},include:function(A){return this.indexOf(A)>-1},startsWith:function(A){return this.indexOf(A)===0},endsWith:function(A){var B=this.length-A.length;return B>=0&&this.lastIndexOf(A)===B},empty:function(){return this==""},blank:function(){return/^\s*$/.test(this)},interpolate:function(A,B){return new Template(this,B).evaluate(A)}});if(Prototype.Browser.WebKit||Prototype.Browser.IE){Object.extend(String.prototype,{escapeHTML:function(){return this.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;")},unescapeHTML:function(){return this.replace(/&amp;/g,"&").replace(/&lt;/g,"<").replace(/&gt;/g,">")}})}String.prototype.gsub.prepareReplacement=function(B){if(Object.isFunction(B)){return B}var A=new Template(B);return function(C){return A.evaluate(C)}};String.prototype.parseQuery=String.prototype.toQueryParams;Object.extend(String.prototype.escapeHTML,{div:document.createElement("div"),text:document.createTextNode("")});with(String.prototype.escapeHTML){div.appendChild(text)}var Template=Class.create({initialize:function(A,B){this.template=A.toString();this.pattern=B||Template.Pattern},evaluate:function(A){if(Object.isFunction(A.toTemplateReplacements)){A=A.toTemplateReplacements()}return this.template.gsub(this.pattern,function(D){if(A==null){return""}var F=D[1]||"";if(F=="\\"){return D[2]}var B=A,G=D[3];var E=/^([^.[]+|\[((?:.*?[^\\])?)\])(\.|\[|$)/;D=E.exec(G);if(D==null){return F}while(D!=null){var C=D[1].startsWith("[")?D[2].gsub("\\\\]","]"):D[1];B=B[C];if(null==B||""==D[3]){break}G=G.substring("["==D[3]?D[1].length:D[0].length);D=E.exec(G)}return F+String.interpret(B)})}});Template.Pattern=/(^|.|\r|\n)(#\{(.*?)\})/;var $break={};var Enumerable={each:function(C,B){var A=0;C=C.bind(B);try{this._each(function(E){C(E,A++)})}catch(D){if(D!=$break){throw D}}return this},eachSlice:function(D,C,B){C=C?C.bind(B):Prototype.K;var A=-D,E=[],F=this.toArray();while((A+=D)<F.length){E.push(F.slice(A,A+D))}return E.collect(C,B)},all:function(C,B){C=C?C.bind(B):Prototype.K;var A=true;this.each(function(E,D){A=A&&!!C(E,D);if(!A){throw $break}});return A},any:function(C,B){C=C?C.bind(B):Prototype.K;var A=false;this.each(function(E,D){if(A=!!C(E,D)){throw $break}});return A},collect:function(C,B){C=C?C.bind(B):Prototype.K;var A=[];this.each(function(E,D){A.push(C(E,D))});return A},detect:function(C,B){C=C.bind(B);var A;this.each(function(E,D){if(C(E,D)){A=E;throw $break}});return A},findAll:function(C,B){C=C.bind(B);var A=[];this.each(function(E,D){if(C(E,D)){A.push(E)}});return A},grep:function(D,C,B){C=C?C.bind(B):Prototype.K;var A=[];if(Object.isString(D)){D=new RegExp(D)}this.each(function(F,E){if(D.match(F)){A.push(C(F,E))}});return A},include:function(A){if(Object.isFunction(this.indexOf)){if(this.indexOf(A)!=-1){return true}}var B=false;this.each(function(C){if(C==A){B=true;throw $break}});return B},inGroupsOf:function(B,A){A=Object.isUndefined(A)?null:A;return this.eachSlice(B,function(C){while(C.length<B){C.push(A)}return C})},inject:function(A,C,B){C=C.bind(B);this.each(function(E,D){A=C(A,E,D)});return A},invoke:function(B){var A=$A(arguments).slice(1);return this.map(function(C){return C[B].apply(C,A)})},max:function(C,B){C=C?C.bind(B):Prototype.K;var A;this.each(function(E,D){E=C(E,D);if(A==null||E>=A){A=E}});return A},min:function(C,B){C=C?C.bind(B):Prototype.K;var A;this.each(function(E,D){E=C(E,D);if(A==null||E<A){A=E}});return A},partition:function(D,B){D=D?D.bind(B):Prototype.K;var C=[],A=[];this.each(function(F,E){(D(F,E)?C:A).push(F)});return[C,A]},pluck:function(B){var A=[];this.each(function(C){A.push(C[B])});return A},reject:function(C,B){C=C.bind(B);var A=[];this.each(function(E,D){if(!C(E,D)){A.push(E)}});return A},sortBy:function(B,A){B=B.bind(A);return this.map(function(D,C){return{value:D,criteria:B(D,C)}}).sort(function(F,E){var D=F.criteria,C=E.criteria;return D<C?-1:D>C?1:0}).pluck("value")},toArray:function(){return this.map()},zip:function(){var B=Prototype.K,A=$A(arguments);if(Object.isFunction(A.last())){B=A.pop()}var C=[this].concat(A).map($A);return this.map(function(E,D){return B(C.pluck(D))})},size:function(){return this.toArray().length},inspect:function(){return"#<Enumerable:"+this.toArray().inspect()+">"}};Object.extend(Enumerable,{map:Enumerable.collect,find:Enumerable.detect,select:Enumerable.findAll,filter:Enumerable.findAll,member:Enumerable.include,entries:Enumerable.toArray,every:Enumerable.all,some:Enumerable.any});function $A(C){if(!C){return[]}if(C.toArray){return C.toArray()}var B=C.length||0,A=new Array(B);while(B--){A[B]=C[B]}return A}if(Prototype.Browser.WebKit){$A=function(C){if(!C){return[]}if(!(Object.isFunction(C)&&C=="[object NodeList]")&&C.toArray){return C.toArray()}var B=C.length||0,A=new Array(B);while(B--){A[B]=C[B]}return A}}Array.from=$A;Object.extend(Array.prototype,Enumerable);if(!Array.prototype._reverse){Array.prototype._reverse=Array.prototype.reverse}Object.extend(Array.prototype,{_each:function(B){for(var A=0,C=this.length;A<C;A++){B(this[A])}},clear:function(){this.length=0;return this},first:function(){return this[0]},last:function(){return this[this.length-1]},compact:function(){return this.select(function(A){return A!=null})},flatten:function(){return this.inject([],function(B,A){return B.concat(Object.isArray(A)?A.flatten():[A])})},without:function(){var A=$A(arguments);return this.select(function(B){return !A.include(B)})},reverse:function(A){return(A!==false?this:this.toArray())._reverse()},reduce:function(){return this.length>1?this:this[0]},uniq:function(A){return this.inject([],function(D,C,B){if(0==B||(A?D.last()!=C:!D.include(C))){D.push(C)}return D})},intersect:function(A){return this.uniq().findAll(function(B){return A.detect(function(C){return B===C})})},clone:function(){return[].concat(this)},size:function(){return this.length},inspect:function(){return"["+this.map(Object.inspect).join(", ")+"]"},toJSON:function(){var A=[];this.each(function(B){var C=Object.toJSON(B);if(!Object.isUndefined(C)){A.push(C)}});return"["+A.join(", ")+"]"}});if(Object.isFunction(Array.prototype.forEach)){Array.prototype._each=Array.prototype.forEach}if(!Array.prototype.indexOf){Array.prototype.indexOf=function(C,A){A||(A=0);var B=this.length;if(A<0){A=B+A}for(;A<B;A++){if(this[A]===C){return A}}return -1}}if(!Array.prototype.lastIndexOf){Array.prototype.lastIndexOf=function(B,A){A=isNaN(A)?this.length:(A<0?this.length+A:A)+1;var C=this.slice(0,A).reverse().indexOf(B);return(C<0)?C:A-C-1}}Array.prototype.toArray=Array.prototype.clone;function $w(A){if(!Object.isString(A)){return[]}A=A.strip();return A?A.split(/\s+/):[]}if(Prototype.Browser.Opera){Array.prototype.concat=function(){var E=[];for(var B=0,C=this.length;B<C;B++){E.push(this[B])}for(var B=0,C=arguments.length;B<C;B++){if(Object.isArray(arguments[B])){for(var A=0,D=arguments[B].length;A<D;A++){E.push(arguments[B][A])}}else{E.push(arguments[B])}}return E}}Object.extend(Number.prototype,{toColorPart:function(){return this.toPaddedString(2,16)},succ:function(){return this+1},times:function(A){$R(0,this,true).each(A);return this},toPaddedString:function(C,B){var A=this.toString(B||10);return"0".times(C-A.length)+A},toJSON:function(){return isFinite(this)?this.toString():"null"}});$w("abs round ceil floor").each(function(A){Number.prototype[A]=Math[A].methodize()});function $H(A){return new Hash(A)}var Hash=Class.create(Enumerable,(function(){function A(B,C){if(Object.isUndefined(C)){return B}return B+"="+encodeURIComponent(String.interpret(C))}return{initialize:function(B){this._object=Object.isHash(B)?B.toObject():Object.clone(B)},_each:function(C){for(var B in this._object){var D=this._object[B],E=[B,D];E.key=B;E.value=D;C(E)}},set:function(B,C){return this._object[B]=C},get:function(B){return this._object[B]},unset:function(B){var C=this._object[B];delete this._object[B];return C},toObject:function(){return Object.clone(this._object)},keys:function(){return this.pluck("key")},values:function(){return this.pluck("value")},index:function(C){var B=this.detect(function(D){return D.value===C});return B&&B.key},merge:function(B){return this.clone().update(B)},update:function(B){return new Hash(B).inject(this,function(C,D){C.set(D.key,D.value);return C})},toQueryString:function(){return this.map(function(D){var C=encodeURIComponent(D.key),B=D.value;if(B&&typeof B=="object"){if(Object.isArray(B)){return B.map(A.curry(C)).join("&")}}return A(C,B)}).join("&")},inspect:function(){return"#<Hash:{"+this.map(function(B){return B.map(Object.inspect).join(": ")}).join(", ")+"}>"},toJSON:function(){return Object.toJSON(this.toObject())},clone:function(){return new Hash(this)}}})());Hash.prototype.toTemplateReplacements=Hash.prototype.toObject;Hash.from=$H;var ObjectRange=Class.create(Enumerable,{initialize:function(C,A,B){this.start=C;this.end=A;this.exclusive=B},_each:function(A){var B=this.start;while(this.include(B)){A(B);B=B.succ()}},include:function(A){if(A<this.start){return false}if(this.exclusive){return A<this.end}return A<=this.end}});var $R=function(C,A,B){return new ObjectRange(C,A,B)};var Ajax={getTransport:function(){return Try.these(function(){return new XMLHttpRequest()},function(){return new ActiveXObject("Msxml2.XMLHTTP")},function(){return new ActiveXObject("Microsoft.XMLHTTP")})||false},activeRequestCount:0};Ajax.Responders={responders:[],_each:function(A){this.responders._each(A)},register:function(A){if(!this.include(A)){this.responders.push(A)}},unregister:function(A){this.responders=this.responders.without(A)},dispatch:function(D,B,C,A){this.each(function(E){if(Object.isFunction(E[D])){try{E[D].apply(E,[B,C,A])}catch(F){}}})}};Object.extend(Ajax.Responders,Enumerable);Ajax.Responders.register({onCreate:function(){Ajax.activeRequestCount++},onComplete:function(){Ajax.activeRequestCount--}});Ajax.Base=Class.create({initialize:function(A){this.options={method:"post",asynchronous:true,contentType:"application/x-www-form-urlencoded",encoding:"UTF-8",parameters:"",evalJSON:true,evalJS:true};Object.extend(this.options,A||{});this.options.method=this.options.method.toLowerCase();if(Object.isString(this.options.parameters)){this.options.parameters=this.options.parameters.toQueryParams()}else{if(Object.isHash(this.options.parameters)){this.options.parameters=this.options.parameters.toObject()}}}});Ajax.Request=Class.create(Ajax.Base,{_complete:false,initialize:function($super,B,A){$super(A);this.transport=Ajax.getTransport();this.request(B)},request:function(B){this.url=B;this.method=this.options.method;var D=Object.clone(this.options.parameters);if(!["get","post"].include(this.method)){D._method=this.method;this.method="post"}this.parameters=D;if(D=Object.toQueryString(D)){if(this.method=="get"){this.url+=(this.url.include("?")?"&":"?")+D}else{if(/Konqueror|Safari|KHTML/.test(navigator.userAgent)){D+="&_="}}}try{var A=new Ajax.Response(this);if(this.options.onCreate){this.options.onCreate(A)}Ajax.Responders.dispatch("onCreate",this,A);this.transport.open(this.method.toUpperCase(),this.url,this.options.asynchronous);if(this.options.asynchronous){this.respondToReadyState.bind(this).defer(1)}this.transport.onreadystatechange=this.onStateChange.bind(this);this.setRequestHeaders();this.body=this.method=="post"?(this.options.postBody||D):null;this.transport.send(this.body);if(!this.options.asynchronous&&this.transport.overrideMimeType){this.onStateChange()}}catch(C){this.dispatchException(C)}},onStateChange:function(){var A=this.transport.readyState;if(A>1&&!((A==4)&&this._complete)){this.respondToReadyState(this.transport.readyState)}},setRequestHeaders:function(){var E={"X-Requested-With":"XMLHttpRequest","X-Prototype-Version":Prototype.Version,Accept:"text/javascript, text/html, application/xml, text/xml, */*"};if(this.method=="post"){E["Content-type"]=this.options.contentType+(this.options.encoding?"; charset="+this.options.encoding:"");if(this.transport.overrideMimeType&&(navigator.userAgent.match(/Gecko\/(\d{4})/)||[0,2005])[1]<2005){E.Connection="close"}}if(typeof this.options.requestHeaders=="object"){var C=this.options.requestHeaders;if(Object.isFunction(C.push)){for(var B=0,D=C.length;B<D;B+=2){E[C[B]]=C[B+1]}}else{$H(C).each(function(F){E[F.key]=F.value})}}for(var A in E){this.transport.setRequestHeader(A,E[A])}},success:function(){var A=this.getStatus();return !A||(A>=200&&A<300)},getStatus:function(){try{return this.transport.status||0}catch(A){return 0}},respondToReadyState:function(A){var C=Ajax.Request.Events[A],B=new Ajax.Response(this);if(C=="Complete"){try{this._complete=true;(this.options["on"+B.status]||this.options["on"+(this.success()?"Success":"Failure")]||Prototype.emptyFunction)(B,B.headerJSON)}catch(D){this.dispatchException(D)}var E=B.getHeader("Content-type");if(this.options.evalJS=="force"||(this.options.evalJS&&this.isSameOrigin()&&E&&E.match(/^\s*(text|application)\/(x-)?(java|ecma)script(;.*)?\s*$/i))){this.evalResponse()}}try{(this.options["on"+C]||Prototype.emptyFunction)(B,B.headerJSON);Ajax.Responders.dispatch("on"+C,this,B,B.headerJSON)}catch(D){this.dispatchException(D)}if(C=="Complete"){this.transport.onreadystatechange=Prototype.emptyFunction}},isSameOrigin:function(){var A=this.url.match(/^\s*https?:\/\/[^\/]*/);return !A||(A[0]=="#{protocol}//#{domain}#{port}".interpolate({protocol:location.protocol,domain:document.domain,port:location.port?":"+location.port:""}))},getHeader:function(A){try{return this.transport.getResponseHeader(A)||null}catch(B){return null}},evalResponse:function(){try{return eval((this.transport.responseText||"").unfilterJSON())}catch(e){this.dispatchException(e)}},dispatchException:function(A){(this.options.onException||Prototype.emptyFunction)(this,A);Ajax.Responders.dispatch("onException",this,A)}});Ajax.Request.Events=["Uninitialized","Loading","Loaded","Interactive","Complete"];Ajax.Response=Class.create({initialize:function(C){this.request=C;var D=this.transport=C.transport,A=this.readyState=D.readyState;if((A>2&&!Prototype.Browser.IE)||A==4){this.status=this.getStatus();this.statusText=this.getStatusText();this.responseText=String.interpret(D.responseText);this.headerJSON=this._getHeaderJSON()}if(A==4){var B=D.responseXML;this.responseXML=Object.isUndefined(B)?null:B;this.responseJSON=this._getResponseJSON()}},status:0,statusText:"",getStatus:Ajax.Request.prototype.getStatus,getStatusText:function(){try{return this.transport.statusText||""}catch(A){return""}},getHeader:Ajax.Request.prototype.getHeader,getAllHeaders:function(){try{return this.getAllResponseHeaders()}catch(A){return null}},getResponseHeader:function(A){return this.transport.getResponseHeader(A)},getAllResponseHeaders:function(){return this.transport.getAllResponseHeaders()},_getHeaderJSON:function(){var A=this.getHeader("X-JSON");if(!A){return null}A=decodeURIComponent(escape(A));try{return A.evalJSON(this.request.options.sanitizeJSON||!this.request.isSameOrigin())}catch(B){this.request.dispatchException(B)}},_getResponseJSON:function(){var A=this.request.options;if(!A.evalJSON||(A.evalJSON!="force"&&!(this.getHeader("Content-type")||"").include("application/json"))||this.responseText.blank()){return null}try{return this.responseText.evalJSON(A.sanitizeJSON||!this.request.isSameOrigin())}catch(B){this.request.dispatchException(B)}}});Ajax.Updater=Class.create(Ajax.Request,{initialize:function($super,A,C,B){this.container={success:(A.success||A),failure:(A.failure||(A.success?null:A))};B=Object.clone(B);var D=B.onComplete;B.onComplete=(function(E,F){this.updateContent(E.responseText);if(Object.isFunction(D)){D(E,F)}}).bind(this);$super(C,B)},updateContent:function(D){var C=this.container[this.success()?"success":"failure"],A=this.options;if(!A.evalScripts){D=D.stripScripts()}if(C=$(C)){if(A.insertion){if(Object.isString(A.insertion)){var B={};B[A.insertion]=D;C.insert(B)}else{A.insertion(C,D)}}else{C.update(D)}}}});Ajax.PeriodicalUpdater=Class.create(Ajax.Base,{initialize:function($super,A,C,B){$super(B);this.onComplete=this.options.onComplete;this.frequency=(this.options.frequency||2);this.decay=(this.options.decay||1);this.updater={};this.container=A;this.url=C;this.start()},start:function(){this.options.onComplete=this.updateComplete.bind(this);this.onTimerEvent()},stop:function(){this.updater.options.onComplete=undefined;clearTimeout(this.timer);(this.onComplete||Prototype.emptyFunction).apply(this,arguments)},updateComplete:function(A){if(this.options.decay){this.decay=(A.responseText==this.lastText?this.decay*this.options.decay:1);this.lastText=A.responseText}this.timer=this.onTimerEvent.bind(this).delay(this.decay*this.frequency)},onTimerEvent:function(){this.updater=new Ajax.Updater(this.container,this.url,this.options)}});function $(B){if(arguments.length>1){for(var A=0,D=[],C=arguments.length;A<C;A++){D.push($(arguments[A]))}return D}if(Object.isString(B)){B=document.getElementById(B)}return Element.extend(B)}if(Prototype.BrowserFeatures.XPath){document._getElementsByXPath=function(F,A){var C=[];var E=document.evaluate(F,$(A)||document,null,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,null);for(var B=0,D=E.snapshotLength;B<D;B++){C.push(Element.extend(E.snapshotItem(B)))}return C}}if(!window.Node){var Node={}}if(!Node.ELEMENT_NODE){Object.extend(Node,{ELEMENT_NODE:1,ATTRIBUTE_NODE:2,TEXT_NODE:3,CDATA_SECTION_NODE:4,ENTITY_REFERENCE_NODE:5,ENTITY_NODE:6,PROCESSING_INSTRUCTION_NODE:7,COMMENT_NODE:8,DOCUMENT_NODE:9,DOCUMENT_TYPE_NODE:10,DOCUMENT_FRAGMENT_NODE:11,NOTATION_NODE:12})}(function(){var A=this.Element;this.Element=function(D,C){C=C||{};D=D.toLowerCase();var B=Element.cache;if(Prototype.Browser.IE&&C.name){D="<"+D+' name="'+C.name+'">';delete C.name;return Element.writeAttribute(document.createElement(D),C)}if(!B[D]){B[D]=Element.extend(document.createElement(D))}return Element.writeAttribute(B[D].cloneNode(false),C)};Object.extend(this.Element,A||{})}).call(window);Element.cache={};Element.Methods={visible:function(A){return $(A).style.display!="none"},toggle:function(A){A=$(A);Element[Element.visible(A)?"hide":"show"](A);return A},hide:function(A){$(A).style.display="none";return A},show:function(A){$(A).style.display="";return A},remove:function(A){A=$(A);A.parentNode.removeChild(A);return A},update:function(A,B){A=$(A);if(B&&B.toElement){B=B.toElement()}if(Object.isElement(B)){return A.update().insert(B)}B=Object.toHTML(B);A.innerHTML=B.stripScripts();B.evalScripts.bind(B).defer();return A},replace:function(B,C){B=$(B);if(C&&C.toElement){C=C.toElement()}else{if(!Object.isElement(C)){C=Object.toHTML(C);var A=B.ownerDocument.createRange();A.selectNode(B);C.evalScripts.bind(C).defer();C=A.createContextualFragment(C.stripScripts())}}B.parentNode.replaceChild(C,B);return B},insert:function(C,E){C=$(C);if(Object.isString(E)||Object.isNumber(E)||Object.isElement(E)||(E&&(E.toElement||E.toHTML))){E={bottom:E}}var D,F,B,G;for(var A in E){D=E[A];A=A.toLowerCase();F=Element._insertionTranslations[A];if(D&&D.toElement){D=D.toElement()}if(Object.isElement(D)){F(C,D);continue}D=Object.toHTML(D);B=((A=="before"||A=="after")?C.parentNode:C).tagName.toUpperCase();G=Element._getContentFromAnonymousElement(B,D.stripScripts());if(A=="top"||A=="after"){G.reverse()}G.each(F.curry(C));D.evalScripts.bind(D).defer()}return C},wrap:function(B,C,A){B=$(B);if(Object.isElement(C)){$(C).writeAttribute(A||{})}else{if(Object.isString(C)){C=new Element(C,A)}else{C=new Element("div",C)}}if(B.parentNode){B.parentNode.replaceChild(C,B)}C.appendChild(B);return C},inspect:function(B){B=$(B);var A="<"+B.tagName.toLowerCase();$H({id:"id",className:"class"}).each(function(F){var E=F.first(),C=F.last();var D=(B[E]||"").toString();if(D){A+=" "+C+"="+D.inspect(true)}});return A+">"},recursivelyCollect:function(A,C){A=$(A);var B=[];while(A=A[C]){if(A.nodeType==1){B.push(Element.extend(A))}}return B},ancestors:function(A){return $(A).recursivelyCollect("parentNode")},descendants:function(A){return $(A).select("*")},firstDescendant:function(A){A=$(A).firstChild;while(A&&A.nodeType!=1){A=A.nextSibling}return $(A)},immediateDescendants:function(A){if(!(A=$(A).firstChild)){return[]}while(A&&A.nodeType!=1){A=A.nextSibling}if(A){return[A].concat($(A).nextSiblings())}return[]},previousSiblings:function(A){return $(A).recursivelyCollect("previousSibling")},nextSiblings:function(A){return $(A).recursivelyCollect("nextSibling")},siblings:function(A){A=$(A);return A.previousSiblings().reverse().concat(A.nextSiblings())},match:function(B,A){if(Object.isString(A)){A=new Selector(A)}return A.match($(B))},up:function(B,D,A){B=$(B);if(arguments.length==1){return $(B.parentNode)}var C=B.ancestors();return Object.isNumber(D)?C[D]:Selector.findElement(C,D,A)},down:function(B,C,A){B=$(B);if(arguments.length==1){return B.firstDescendant()}return Object.isNumber(C)?B.descendants()[C]:B.select(C)[A||0]},previous:function(B,D,A){B=$(B);if(arguments.length==1){return $(Selector.handlers.previousElementSibling(B))}var C=B.previousSiblings();return Object.isNumber(D)?C[D]:Selector.findElement(C,D,A)},next:function(C,D,B){C=$(C);if(arguments.length==1){return $(Selector.handlers.nextElementSibling(C))}var A=C.nextSiblings();return Object.isNumber(D)?A[D]:Selector.findElement(A,D,B)},select:function(){var A=$A(arguments),B=$(A.shift());return Selector.findChildElements(B,A)},adjacent:function(){var A=$A(arguments),B=$(A.shift());return Selector.findChildElements(B.parentNode,A).without(B)},identify:function(B){B=$(B);var C=B.readAttribute("id"),A=arguments.callee;if(C){return C}do{C="anonymous_element_"+A.counter++}while($(C));B.writeAttribute("id",C);return C},readAttribute:function(C,A){C=$(C);if(Prototype.Browser.IE){var B=Element._attributeTranslations.read;if(B.values[A]){return B.values[A](C,A)}if(B.names[A]){A=B.names[A]}if(A.include(":")){return(!C.attributes||!C.attributes[A])?null:C.attributes[A].value}}return C.getAttribute(A)},writeAttribute:function(E,C,F){E=$(E);var B={},D=Element._attributeTranslations.write;if(typeof C=="object"){B=C}else{B[C]=Object.isUndefined(F)?true:F}for(var A in B){C=D.names[A]||A;F=B[A];if(D.values[A]){C=D.values[A](E,F)}if(F===false||F===null){E.removeAttribute(C)}else{if(F===true){E.setAttribute(C,C)}else{E.setAttribute(C,F)}}}return E},getHeight:function(A){return $(A).getDimensions().height},getWidth:function(A){return $(A).getDimensions().width},classNames:function(A){return new Element.ClassNames(A)},hasClassName:function(A,B){if(!(A=$(A))){return }var C=A.className;return(C.length>0&&(C==B||new RegExp("(^|\\s)"+B+"(\\s|$)").test(C)))},addClassName:function(A,B){if(!(A=$(A))){return }if(!A.hasClassName(B)){A.className+=(A.className?" ":"")+B}return A},removeClassName:function(A,B){if(!(A=$(A))){return }A.className=A.className.replace(new RegExp("(^|\\s+)"+B+"(\\s+|$)")," ").strip();return A},toggleClassName:function(A,B){if(!(A=$(A))){return }return A[A.hasClassName(B)?"removeClassName":"addClassName"](B)},cleanWhitespace:function(B){B=$(B);var C=B.firstChild;while(C){var A=C.nextSibling;if(C.nodeType==3&&!/\S/.test(C.nodeValue)){B.removeChild(C)}C=A}return B},empty:function(A){return $(A).innerHTML.blank()},descendantOf:function(D,C){D=$(D),C=$(C);var F=C;if(D.compareDocumentPosition){return(D.compareDocumentPosition(C)&8)===8}if(D.sourceIndex&&!Prototype.Browser.Opera){var E=D.sourceIndex,B=C.sourceIndex,A=C.nextSibling;if(!A){do{C=C.parentNode}while(!(A=C.nextSibling)&&C.parentNode)}if(A&&A.sourceIndex){return(E>B&&E<A.sourceIndex)}}while(D=D.parentNode){if(D==F){return true}}return false},scrollTo:function(A){A=$(A);var B=A.cumulativeOffset();window.scrollTo(B[0],B[1]);return A},getStyle:function(B,C){B=$(B);C=C=="float"?"cssFloat":C.camelize();var D=B.style[C];if(!D){var A=document.defaultView.getComputedStyle(B,null);D=A?A[C]:null}if(C=="opacity"){return D?parseFloat(D):1}return D=="auto"?null:D},getOpacity:function(A){return $(A).getStyle("opacity")},setStyle:function(B,C){B=$(B);var E=B.style,A;if(Object.isString(C)){B.style.cssText+=";"+C;return C.include("opacity")?B.setOpacity(C.match(/opacity:\s*(\d?\.?\d*)/)[1]):B}for(var D in C){if(D=="opacity"){B.setOpacity(C[D])}else{E[(D=="float"||D=="cssFloat")?(Object.isUndefined(E.styleFloat)?"cssFloat":"styleFloat"):D]=C[D]}}return B},setOpacity:function(A,B){A=$(A);A.style.opacity=(B==1||B==="")?"":(B<0.00001)?0:B;return A},getDimensions:function(C){C=$(C);var G=$(C).getStyle("display");if(G!="none"&&G!=null){return{width:C.offsetWidth,height:C.offsetHeight}}var B=C.style;var F=B.visibility;var D=B.position;var A=B.display;B.visibility="hidden";B.position="absolute";B.display="block";var H=C.clientWidth;var E=C.clientHeight;B.display=A;B.position=D;B.visibility=F;return{width:H,height:E}},makePositioned:function(A){A=$(A);var B=Element.getStyle(A,"position");if(B=="static"||!B){A._madePositioned=true;A.style.position="relative";if(window.opera){A.style.top=0;A.style.left=0}}return A},undoPositioned:function(A){A=$(A);if(A._madePositioned){A._madePositioned=undefined;A.style.position=A.style.top=A.style.left=A.style.bottom=A.style.right=""}return A},makeClipping:function(A){A=$(A);if(A._overflow){return A}A._overflow=Element.getStyle(A,"overflow")||"auto";if(A._overflow!=="hidden"){A.style.overflow="hidden"}return A},undoClipping:function(A){A=$(A);if(!A._overflow){return A}A.style.overflow=A._overflow=="auto"?"":A._overflow;A._overflow=null;return A},cumulativeOffset:function(B){var A=0,C=0;do{A+=B.offsetTop||0;C+=B.offsetLeft||0;B=B.offsetParent}while(B);return Element._returnOffset(C,A)},positionedOffset:function(B){var A=0,D=0;do{A+=B.offsetTop||0;D+=B.offsetLeft||0;B=B.offsetParent;if(B){if(B.tagName=="BODY"){break}var C=Element.getStyle(B,"position");if(C!=="static"){break}}}while(B);return Element._returnOffset(D,A)},absolutize:function(B){B=$(B);if(B.getStyle("position")=="absolute"){return }var D=B.positionedOffset();var F=D[1];var E=D[0];var C=B.clientWidth;var A=B.clientHeight;B._originalLeft=E-parseFloat(B.style.left||0);B._originalTop=F-parseFloat(B.style.top||0);B._originalWidth=B.style.width;B._originalHeight=B.style.height;B.style.position="absolute";B.style.top=F+"px";B.style.left=E+"px";B.style.width=C+"px";B.style.height=A+"px";return B},relativize:function(A){A=$(A);if(A.getStyle("position")=="relative"){return }A.style.position="relative";var C=parseFloat(A.style.top||0)-(A._originalTop||0);var B=parseFloat(A.style.left||0)-(A._originalLeft||0);A.style.top=C+"px";A.style.left=B+"px";A.style.height=A._originalHeight;A.style.width=A._originalWidth;return A},cumulativeScrollOffset:function(B){var A=0,C=0;do{A+=B.scrollTop||0;C+=B.scrollLeft||0;B=B.parentNode}while(B);return Element._returnOffset(C,A)},getOffsetParent:function(B){B=$(B);var D=B.offsetParent,A=document.body,C=document.documentElement;if(D&&D!==C){return $(D)}if(D===C||B===C||B===A){return $(A)}while((B=B.parentNode)&&B!==A){if(Element.getStyle(B,"position")!="static"){return $(B)}}return $(A)},viewportOffset:function(D){D=$(D);var B=D,A=0,C=0;do{A+=B.offsetTop||0;C+=B.offsetLeft||0}while((B=B.getOffsetParent())!=document.body);B=D;do{if(!Prototype.Browser.Opera||B.tagName=="BODY"){A-=B.scrollTop||0;C-=B.scrollLeft||0}}while(B=B.parentNode);return Element._returnOffset(C,A)},clonePosition:function(B,D){var A=Object.extend({setLeft:true,setTop:true,setWidth:true,setHeight:true,offsetTop:0,offsetLeft:0},arguments[2]||{});D=$(D);var E=D.viewportOffset();B=$(B);var F=[0,0];var C=null;if(Element.getStyle(B,"position")=="absolute"){C=B.getOffsetParent();F=C.viewportOffset()}if(C==document.body){F[0]-=document.body.offsetLeft;F[1]-=document.body.offsetTop}if(A.setLeft){B.style.left=(E[0]-F[0]+A.offsetLeft)+"px"}if(A.setTop){B.style.top=(E[1]-F[1]+A.offsetTop)+"px"}if(A.setWidth){B.style.width=D.offsetWidth+"px"}if(A.setHeight){B.style.height=D.offsetHeight+"px"}return B}};Element.Methods.identify.counter=1;Object.extend(Element.Methods,{getElementsBySelector:Element.Methods.select,childElements:Element.Methods.immediateDescendants});Element._attributeTranslations={write:{names:{className:"class",htmlFor:"for"},values:{}}};if(Prototype.Browser.Opera){Element.Methods.getStyle=Element.Methods.getStyle.wrap(function(D,B,C){switch(C){case"left":case"top":case"right":case"bottom":if(D(B,"position")==="static"){return null}case"height":case"width":if(!Element.visible(B)){return null}var E=parseInt(D(B,C),10);if(E!==B["offset"+C.capitalize()]){return E+"px"}var A;if(C==="height"){A=["border-top-width","padding-top","padding-bottom","border-bottom-width"]}else{A=["border-left-width","padding-left","padding-right","border-right-width"]}return A.inject(E,function(F,G){var H=D(B,G);return H===null?F:F-parseInt(H,10)})+"px";default:return D(B,C)}});Element.Methods.readAttribute=Element.Methods.readAttribute.wrap(function(C,A,B){if(B==="title"){return A.title}return C(A,B)})}else{if(Prototype.Browser.IE){Element.Methods.getOffsetParent=Element.Methods.getOffsetParent.wrap(function(C,B){B=$(B);var A=B.getStyle("position");if(A!=="static"){return C(B)}B.setStyle({position:"relative"});var D=C(B);B.setStyle({position:A});return D});$w("positionedOffset viewportOffset").each(function(A){Element.Methods[A]=Element.Methods[A].wrap(function(E,C){C=$(C);var B=C.getStyle("position");if(B!=="static"){return E(C)}var D=C.getOffsetParent();if(D&&D.getStyle("position")==="fixed"){D.setStyle({zoom:1})}C.setStyle({position:"relative"});var F=E(C);C.setStyle({position:B});return F})});Element.Methods.getStyle=function(A,B){A=$(A);B=(B=="float"||B=="cssFloat")?"styleFloat":B.camelize();var C=A.style[B];if(!C&&A.currentStyle){C=A.currentStyle[B]}if(B=="opacity"){if(C=(A.getStyle("filter")||"").match(/alpha\(opacity=(.*)\)/)){if(C[1]){return parseFloat(C[1])/100}}return 1}if(C=="auto"){if((B=="width"||B=="height")&&(A.getStyle("display")!="none")){return A["offset"+B.capitalize()]+"px"}return null}return C};Element.Methods.setOpacity=function(B,E){function F(G){return G.replace(/alpha\([^\)]*\)/gi,"")}B=$(B);var A=B.currentStyle;if((A&&!A.hasLayout)||(!A&&B.style.zoom=="normal")){B.style.zoom=1}var D=B.getStyle("filter"),C=B.style;if(E==1||E===""){(D=F(D))?C.filter=D:C.removeAttribute("filter");return B}else{if(E<0.00001){E=0}}C.filter=F(D)+"alpha(opacity="+(E*100)+")";return B};Element._attributeTranslations={read:{names:{"class":"className","for":"htmlFor"},values:{_getAttr:function(A,B){return A.getAttribute(B,2)},_getAttrNode:function(A,C){var B=A.getAttributeNode(C);return B?B.value:""},_getEv:function(A,B){B=A.getAttribute(B);return B?B.toString().slice(23,-2):null},_flag:function(A,B){return $(A).hasAttribute(B)?B:null},style:function(A){return A.style.cssText.toLowerCase()},title:function(A){return A.title}}}};Element._attributeTranslations.write={names:Object.extend({cellpadding:"cellPadding",cellspacing:"cellSpacing"},Element._attributeTranslations.read.names),values:{checked:function(A,B){A.checked=!!B},style:function(A,B){A.style.cssText=B?B:""}}};Element._attributeTranslations.has={};$w("colSpan rowSpan vAlign dateTime accessKey tabIndex encType maxLength readOnly longDesc").each(function(A){Element._attributeTranslations.write.names[A.toLowerCase()]=A;Element._attributeTranslations.has[A.toLowerCase()]=A});(function(A){Object.extend(A,{href:A._getAttr,src:A._getAttr,type:A._getAttr,action:A._getAttrNode,disabled:A._flag,checked:A._flag,readonly:A._flag,multiple:A._flag,onload:A._getEv,onunload:A._getEv,onclick:A._getEv,ondblclick:A._getEv,onmousedown:A._getEv,onmouseup:A._getEv,onmouseover:A._getEv,onmousemove:A._getEv,onmouseout:A._getEv,onfocus:A._getEv,onblur:A._getEv,onkeypress:A._getEv,onkeydown:A._getEv,onkeyup:A._getEv,onsubmit:A._getEv,onreset:A._getEv,onselect:A._getEv,onchange:A._getEv})})(Element._attributeTranslations.read.values)}else{if(Prototype.Browser.Gecko&&/rv:1\.8\.0/.test(navigator.userAgent)){Element.Methods.setOpacity=function(A,B){A=$(A);A.style.opacity=(B==1)?0.999999:(B==="")?"":(B<0.00001)?0:B;return A}}else{if(Prototype.Browser.WebKit){Element.Methods.setOpacity=function(A,B){A=$(A);A.style.opacity=(B==1||B==="")?"":(B<0.00001)?0:B;if(B==1){if(A.tagName=="IMG"&&A.width){A.width++;A.width--}else{try{var D=document.createTextNode(" ");A.appendChild(D);A.removeChild(D)}catch(C){}}}return A};Element.Methods.cumulativeOffset=function(B){var A=0,C=0;do{A+=B.offsetTop||0;C+=B.offsetLeft||0;if(B.offsetParent==document.body){if(Element.getStyle(B,"position")=="absolute"){break}}B=B.offsetParent}while(B);return Element._returnOffset(C,A)}}}}}if(Prototype.Browser.IE||Prototype.Browser.Opera){Element.Methods.update=function(B,C){B=$(B);if(C&&C.toElement){C=C.toElement()}if(Object.isElement(C)){return B.update().insert(C)}C=Object.toHTML(C);var A=B.tagName.toUpperCase();if(A in Element._insertionTranslations.tags){$A(B.childNodes).each(function(D){B.removeChild(D)});Element._getContentFromAnonymousElement(A,C.stripScripts()).each(function(D){B.appendChild(D)})}else{B.innerHTML=C.stripScripts()}C.evalScripts.bind(C).defer();return B}}if("outerHTML" in document.createElement("div")){Element.Methods.replace=function(C,E){C=$(C);if(E&&E.toElement){E=E.toElement()}if(Object.isElement(E)){C.parentNode.replaceChild(E,C);return C}E=Object.toHTML(E);var D=C.parentNode,B=D.tagName.toUpperCase();if(Element._insertionTranslations.tags[B]){var F=C.next();var A=Element._getContentFromAnonymousElement(B,E.stripScripts());D.removeChild(C);if(F){A.each(function(G){D.insertBefore(G,F)})}else{A.each(function(G){D.appendChild(G)})}}else{C.outerHTML=E.stripScripts()}E.evalScripts.bind(E).defer();return C}}Element._returnOffset=function(B,C){var A=[B,C];A.left=B;A.top=C;return A};Element._getContentFromAnonymousElement=function(C,B){var D=new Element("div"),A=Element._insertionTranslations.tags[C];if(A){D.innerHTML=A[0]+B+A[1];A[2].times(function(){D=D.firstChild})}else{D.innerHTML=B}return $A(D.childNodes)};Element._insertionTranslations={before:function(A,B){A.parentNode.insertBefore(B,A)},top:function(A,B){A.insertBefore(B,A.firstChild)},bottom:function(A,B){A.appendChild(B)},after:function(A,B){A.parentNode.insertBefore(B,A.nextSibling)},tags:{TABLE:["<table>","</table>",1],TBODY:["<table><tbody>","</tbody></table>",2],TR:["<table><tbody><tr>","</tr></tbody></table>",3],TD:["<table><tbody><tr><td>","</td></tr></tbody></table>",4],SELECT:["<select>","</select>",1]}};(function(){Object.extend(this.tags,{THEAD:this.tags.TBODY,TFOOT:this.tags.TBODY,TH:this.tags.TD})}).call(Element._insertionTranslations);Element.Methods.Simulated={hasAttribute:function(A,C){C=Element._attributeTranslations.has[C]||C;var B=$(A).getAttributeNode(C);return B&&B.specified}};Element.Methods.ByTag={};Object.extend(Element,Element.Methods);if(!Prototype.BrowserFeatures.ElementExtensions&&document.createElement("div").__proto__){window.HTMLElement={};window.HTMLElement.prototype=document.createElement("div").__proto__;Prototype.BrowserFeatures.ElementExtensions=true}Element.extend=(function(){if(Prototype.BrowserFeatures.SpecificElementExtensions){return Prototype.K}var A={},B=Element.Methods.ByTag;var C=Object.extend(function(F){if(!F||F._extendedByPrototype||F.nodeType!=1||F==window){return F}var D=Object.clone(A),E=F.tagName,H,G;if(B[E]){Object.extend(D,B[E])}for(H in D){G=D[H];if(Object.isFunction(G)&&!(H in F)){F[H]=G.methodize()}}F._extendedByPrototype=Prototype.emptyFunction;return F},{refresh:function(){if(!Prototype.BrowserFeatures.ElementExtensions){Object.extend(A,Element.Methods);Object.extend(A,Element.Methods.Simulated)}}});C.refresh();return C})();Element.hasAttribute=function(A,B){if(A.hasAttribute){return A.hasAttribute(B)}return Element.Methods.Simulated.hasAttribute(A,B)};Element.addMethods=function(C){var I=Prototype.BrowserFeatures,D=Element.Methods.ByTag;if(!C){Object.extend(Form,Form.Methods);Object.extend(Form.Element,Form.Element.Methods);Object.extend(Element.Methods.ByTag,{FORM:Object.clone(Form.Methods),INPUT:Object.clone(Form.Element.Methods),SELECT:Object.clone(Form.Element.Methods),TEXTAREA:Object.clone(Form.Element.Methods)})}if(arguments.length==2){var B=C;C=arguments[1]}if(!B){Object.extend(Element.Methods,C||{})}else{if(Object.isArray(B)){B.each(H)}else{H(B)}}function H(F){F=F.toUpperCase();if(!Element.Methods.ByTag[F]){Element.Methods.ByTag[F]={}}Object.extend(Element.Methods.ByTag[F],C)}function A(L,K,F){F=F||false;for(var N in L){var M=L[N];if(!Object.isFunction(M)){continue}if(!F||!(N in K)){K[N]=M.methodize()}}}function E(L){var F;var K={OPTGROUP:"OptGroup",TEXTAREA:"TextArea",P:"Paragraph",FIELDSET:"FieldSet",UL:"UList",OL:"OList",DL:"DList",DIR:"Directory",H1:"Heading",H2:"Heading",H3:"Heading",H4:"Heading",H5:"Heading",H6:"Heading",Q:"Quote",INS:"Mod",DEL:"Mod",A:"Anchor",IMG:"Image",CAPTION:"TableCaption",COL:"TableCol",COLGROUP:"TableCol",THEAD:"TableSection",TFOOT:"TableSection",TBODY:"TableSection",TR:"TableRow",TH:"TableCell",TD:"TableCell",FRAMESET:"FrameSet",IFRAME:"IFrame"};if(K[L]){F="HTML"+K[L]+"Element"}if(window[F]){return window[F]}F="HTML"+L+"Element";if(window[F]){return window[F]}F="HTML"+L.capitalize()+"Element";if(window[F]){return window[F]}window[F]={};window[F].prototype=document.createElement(L).__proto__;return window[F]}if(I.ElementExtensions){A(Element.Methods,HTMLElement.prototype);A(Element.Methods.Simulated,HTMLElement.prototype,true)}if(I.SpecificElementExtensions){for(var J in Element.Methods.ByTag){var G=E(J);if(Object.isUndefined(G)){continue}A(D[J],G.prototype)}}Object.extend(Element,Element.Methods);delete Element.ByTag;if(Element.extend.refresh){Element.extend.refresh()}Element.cache={}};document.viewport={getDimensions:function(){var A={};var C=Prototype.Browser;$w("width height").each(function(E){var B=E.capitalize();A[E]=(C.WebKit&&!document.evaluate)?self["inner"+B]:(C.Opera)?document.body["client"+B]:document.documentElement["client"+B]});return A},getWidth:function(){return this.getDimensions().width},getHeight:function(){return this.getDimensions().height},getScrollOffsets:function(){return Element._returnOffset(window.pageXOffset||document.documentElement.scrollLeft||document.body.scrollLeft,window.pageYOffset||document.documentElement.scrollTop||document.body.scrollTop)}};var Selector=Class.create({initialize:function(A){this.expression=A.strip();this.compileMatcher()},shouldUseXPath:function(){if(!Prototype.BrowserFeatures.XPath){return false}var A=this.expression;if(Prototype.Browser.WebKit&&(A.include("-of-type")||A.include(":empty"))){return false}if((/(\[[\w-]*?:|:checked)/).test(this.expression)){return false}return true},compileMatcher:function(){if(this.shouldUseXPath()){return this.compileXPathMatcher()}var e=this.expression,ps=Selector.patterns,h=Selector.handlers,c=Selector.criteria,le,p,m;if(Selector._cache[e]){this.matcher=Selector._cache[e];return }this.matcher=["this.matcher = function(root) {","var r = root, h = Selector.handlers, c = false, n;"];while(e&&le!=e&&(/\S/).test(e)){le=e;for(var i in ps){p=ps[i];if(m=e.match(p)){this.matcher.push(Object.isFunction(c[i])?c[i](m):new Template(c[i]).evaluate(m));e=e.replace(m[0],"");break}}}this.matcher.push("return h.unique(n);\n}");eval(this.matcher.join("\n"));Selector._cache[this.expression]=this.matcher},compileXPathMatcher:function(){var E=this.expression,F=Selector.patterns,B=Selector.xpath,D,A;if(Selector._cache[E]){this.xpath=Selector._cache[E];return }this.matcher=[".//*"];while(E&&D!=E&&(/\S/).test(E)){D=E;for(var C in F){if(A=E.match(F[C])){this.matcher.push(Object.isFunction(B[C])?B[C](A):new Template(B[C]).evaluate(A));E=E.replace(A[0],"");break}}}this.xpath=this.matcher.join("");Selector._cache[this.expression]=this.xpath},findElements:function(A){A=A||document;if(this.xpath){return document._getElementsByXPath(this.xpath,A)}return this.matcher(A)},match:function(H){this.tokens=[];var L=this.expression,A=Selector.patterns,E=Selector.assertions;var B,D,F;while(L&&B!==L&&(/\S/).test(L)){B=L;for(var I in A){D=A[I];if(F=L.match(D)){if(E[I]){this.tokens.push([I,Object.clone(F)]);L=L.replace(F[0],"")}else{return this.findElements(document).include(H)}}}}var K=true,C,J;for(var I=0,G;G=this.tokens[I];I++){C=G[0],J=G[1];if(!Selector.assertions[C](H,J)){K=false;break}}return K},toString:function(){return this.expression},inspect:function(){return"#<Selector:"+this.expression.inspect()+">"}});Object.extend(Selector,{_cache:{},xpath:{descendant:"//*",child:"/*",adjacent:"/following-sibling::*[1]",laterSibling:"/following-sibling::*",tagName:function(A){if(A[1]=="*"){return""}return"[local-name()='"+A[1].toLowerCase()+"' or local-name()='"+A[1].toUpperCase()+"']"},className:"[contains(concat(' ', @class, ' '), ' #{1} ')]",id:"[@id='#{1}']",attrPresence:function(A){A[1]=A[1].toLowerCase();return new Template("[@#{1}]").evaluate(A)},attr:function(A){A[1]=A[1].toLowerCase();A[3]=A[5]||A[6];return new Template(Selector.xpath.operators[A[2]]).evaluate(A)},pseudo:function(A){var B=Selector.xpath.pseudos[A[1]];if(!B){return""}if(Object.isFunction(B)){return B(A)}return new Template(Selector.xpath.pseudos[A[1]]).evaluate(A)},operators:{"=":"[@#{1}='#{3}']","!=":"[@#{1}!='#{3}']","^=":"[starts-with(@#{1}, '#{3}')]","$=":"[substring(@#{1}, (string-length(@#{1}) - string-length('#{3}') + 1))='#{3}']","*=":"[contains(@#{1}, '#{3}')]","~=":"[contains(concat(' ', @#{1}, ' '), ' #{3} ')]","|=":"[contains(concat('-', @#{1}, '-'), '-#{3}-')]"},pseudos:{"first-child":"[not(preceding-sibling::*)]","last-child":"[not(following-sibling::*)]","only-child":"[not(preceding-sibling::* or following-sibling::*)]",empty:"[count(*) = 0 and (count(text()) = 0 or translate(text(), ' \t\r\n', '') = '')]",checked:"[@checked]",disabled:"[@disabled]",enabled:"[not(@disabled)]",not:function(B){var H=B[6],G=Selector.patterns,A=Selector.xpath,E,C;var F=[];while(H&&E!=H&&(/\S/).test(H)){E=H;for(var D in G){if(B=H.match(G[D])){C=Object.isFunction(A[D])?A[D](B):new Template(A[D]).evaluate(B);F.push("("+C.substring(1,C.length-1)+")");H=H.replace(B[0],"");break}}}return"[not("+F.join(" and ")+")]"},"nth-child":function(A){return Selector.xpath.pseudos.nth("(count(./preceding-sibling::*) + 1) ",A)},"nth-last-child":function(A){return Selector.xpath.pseudos.nth("(count(./following-sibling::*) + 1) ",A)},"nth-of-type":function(A){return Selector.xpath.pseudos.nth("position() ",A)},"nth-last-of-type":function(A){return Selector.xpath.pseudos.nth("(last() + 1 - position()) ",A)},"first-of-type":function(A){A[6]="1";return Selector.xpath.pseudos["nth-of-type"](A)},"last-of-type":function(A){A[6]="1";return Selector.xpath.pseudos["nth-last-of-type"](A)},"only-of-type":function(A){var B=Selector.xpath.pseudos;return B["first-of-type"](A)+B["last-of-type"](A)},nth:function(E,C){var F,G=C[6],B;if(G=="even"){G="2n+0"}if(G=="odd"){G="2n+1"}if(F=G.match(/^(\d+)$/)){return"["+E+"= "+F[1]+"]"}if(F=G.match(/^(-?\d*)?n(([+-])(\d+))?/)){if(F[1]=="-"){F[1]=-1}var D=F[1]?Number(F[1]):1;var A=F[2]?Number(F[2]):0;B="[((#{fragment} - #{b}) mod #{a} = 0) and ((#{fragment} - #{b}) div #{a} >= 0)]";return new Template(B).evaluate({fragment:E,a:D,b:A})}}}},criteria:{tagName:'n = h.tagName(n, r, "#{1}", c);      c = false;',className:'n = h.className(n, r, "#{1}", c);    c = false;',id:'n = h.id(n, r, "#{1}", c);           c = false;',attrPresence:'n = h.attrPresence(n, r, "#{1}", c); c = false;',attr:function(A){A[3]=(A[5]||A[6]);return new Template('n = h.attr(n, r, "#{1}", "#{3}", "#{2}", c); c = false;').evaluate(A)},pseudo:function(A){if(A[6]){A[6]=A[6].replace(/"/g,'\\"')}return new Template('n = h.pseudo(n, "#{1}", "#{6}", r, c); c = false;').evaluate(A)},descendant:'c = "descendant";',child:'c = "child";',adjacent:'c = "adjacent";',laterSibling:'c = "laterSibling";'},patterns:{laterSibling:/^\s*~\s*/,child:/^\s*>\s*/,adjacent:/^\s*\+\s*/,descendant:/^\s/,tagName:/^\s*(\*|[\w\-]+)(\b|$)?/,id:/^#([\w\-\*]+)(\b|$)/,className:/^\.([\w\-\*]+)(\b|$)/,pseudo:/^:((first|last|nth|nth-last|only)(-child|-of-type)|empty|checked|(en|dis)abled|not)(\((.*?)\))?(\b|$|(?=\s|[:+~>]))/,attrPresence:/^\[([\w]+)\]/,attr:/\[((?:[\w-]*:)?[\w-]+)\s*(?:([!^$*~|]?=)\s*((['"])([^\4]*?)\4|([^'"][^\]]*?)))?\]/},assertions:{tagName:function(A,B){return B[1].toUpperCase()==A.tagName.toUpperCase()},className:function(A,B){return Element.hasClassName(A,B[1])},id:function(A,B){return A.id===B[1]},attrPresence:function(A,B){return Element.hasAttribute(A,B[1])},attr:function(B,C){var A=Element.readAttribute(B,C[1]);return A&&Selector.operators[C[2]](A,C[5]||C[6])}},handlers:{concat:function(B,A){for(var C=0,D;D=A[C];C++){B.push(D)}return B},mark:function(A){var D=Prototype.emptyFunction;for(var B=0,C;C=A[B];B++){C._countedByPrototype=D}return A},unmark:function(A){for(var B=0,C;C=A[B];B++){C._countedByPrototype=undefined}return A},index:function(A,D,G){A._countedByPrototype=Prototype.emptyFunction;if(D){for(var B=A.childNodes,E=B.length-1,C=1;E>=0;E--){var F=B[E];if(F.nodeType==1&&(!G||F._countedByPrototype)){F.nodeIndex=C++}}}else{for(var E=0,C=1,B=A.childNodes;F=B[E];E++){if(F.nodeType==1&&(!G||F._countedByPrototype)){F.nodeIndex=C++}}}},unique:function(B){if(B.length==0){return B}var D=[],E;for(var C=0,A=B.length;C<A;C++){if(!(E=B[C])._countedByPrototype){E._countedByPrototype=Prototype.emptyFunction;D.push(Element.extend(E))}}return Selector.handlers.unmark(D)},descendant:function(A){var D=Selector.handlers;for(var C=0,B=[],E;E=A[C];C++){D.concat(B,E.getElementsByTagName("*"))}return B},child:function(A){var E=Selector.handlers;for(var D=0,C=[],F;F=A[D];D++){for(var B=0,G;G=F.childNodes[B];B++){if(G.nodeType==1&&G.tagName!="!"){C.push(G)}}}return C},adjacent:function(A){for(var C=0,B=[],E;E=A[C];C++){var D=this.nextElementSibling(E);if(D){B.push(D)}}return B},laterSibling:function(A){var D=Selector.handlers;for(var C=0,B=[],E;E=A[C];C++){D.concat(B,Element.nextSiblings(E))}return B},nextElementSibling:function(A){while(A=A.nextSibling){if(A.nodeType==1){return A}}return null},previousElementSibling:function(A){while(A=A.previousSibling){if(A.nodeType==1){return A}}return null},tagName:function(A,H,C,B){var I=C.toUpperCase();var E=[],G=Selector.handlers;if(A){if(B){if(B=="descendant"){for(var F=0,D;D=A[F];F++){G.concat(E,D.getElementsByTagName(C))}return E}else{A=this[B](A)}if(C=="*"){return A}}for(var F=0,D;D=A[F];F++){if(D.tagName.toUpperCase()===I){E.push(D)}}return E}else{return H.getElementsByTagName(C)}},id:function(B,A,H,F){var G=$(H),D=Selector.handlers;if(!G){return[]}if(!B&&A==document){return[G]}if(B){if(F){if(F=="child"){for(var C=0,E;E=B[C];C++){if(G.parentNode==E){return[G]}}}else{if(F=="descendant"){for(var C=0,E;E=B[C];C++){if(Element.descendantOf(G,E)){return[G]}}}else{if(F=="adjacent"){for(var C=0,E;E=B[C];C++){if(Selector.handlers.previousElementSibling(G)==E){return[G]}}}else{B=D[F](B)}}}}for(var C=0,E;E=B[C];C++){if(E==G){return[G]}}return[]}return(G&&Element.descendantOf(G,A))?[G]:[]},className:function(B,A,C,D){if(B&&D){B=this[D](B)}return Selector.handlers.byClassName(B,A,C)},byClassName:function(C,B,F){if(!C){C=Selector.handlers.descendant([B])}var H=" "+F+" ";for(var E=0,D=[],G,A;G=C[E];E++){A=G.className;if(A.length==0){continue}if(A==F||(" "+A+" ").include(H)){D.push(G)}}return D},attrPresence:function(C,B,A,G){if(!C){C=B.getElementsByTagName("*")}if(C&&G){C=this[G](C)}var E=[];for(var D=0,F;F=C[D];D++){if(Element.hasAttribute(F,A)){E.push(F)}}return E},attr:function(A,I,H,J,C,B){if(!A){A=I.getElementsByTagName("*")}if(A&&B){A=this[B](A)}var K=Selector.operators[C],F=[];for(var E=0,D;D=A[E];E++){var G=Element.readAttribute(D,H);if(G===null){continue}if(K(G,J)){F.push(D)}}return F},pseudo:function(B,C,E,A,D){if(B&&D){B=this[D](B)}if(!B){B=A.getElementsByTagName("*")}return Selector.pseudos[C](B,E,A)}},pseudos:{"first-child":function(B,F,A){for(var D=0,C=[],E;E=B[D];D++){if(Selector.handlers.previousElementSibling(E)){continue}C.push(E)}return C},"last-child":function(B,F,A){for(var D=0,C=[],E;E=B[D];D++){if(Selector.handlers.nextElementSibling(E)){continue}C.push(E)}return C},"only-child":function(B,G,A){var E=Selector.handlers;for(var D=0,C=[],F;F=B[D];D++){if(!E.previousElementSibling(F)&&!E.nextElementSibling(F)){C.push(F)}}return C},"nth-child":function(B,C,A){return Selector.pseudos.nth(B,C,A)},"nth-last-child":function(B,C,A){return Selector.pseudos.nth(B,C,A,true)},"nth-of-type":function(B,C,A){return Selector.pseudos.nth(B,C,A,false,true)},"nth-last-of-type":function(B,C,A){return Selector.pseudos.nth(B,C,A,true,true)},"first-of-type":function(B,C,A){return Selector.pseudos.nth(B,"1",A,false,true)},"last-of-type":function(B,C,A){return Selector.pseudos.nth(B,"1",A,true,true)},"only-of-type":function(B,D,A){var C=Selector.pseudos;return C["last-of-type"](C["first-of-type"](B,D,A),D,A)},getIndices:function(B,A,C){if(B==0){return A>0?[A]:[]}return $R(1,C).inject([],function(D,E){if(0==(E-A)%B&&(E-A)/B>=0){D.push(E)}return D})},nth:function(A,L,N,K,C){if(A.length==0){return[]}if(L=="even"){L="2n+0"}if(L=="odd"){L="2n+1"}var J=Selector.handlers,I=[],B=[],E;J.mark(A);for(var H=0,D;D=A[H];H++){if(!D.parentNode._countedByPrototype){J.index(D.parentNode,K,C);B.push(D.parentNode)}}if(L.match(/^\d+$/)){L=Number(L);for(var H=0,D;D=A[H];H++){if(D.nodeIndex==L){I.push(D)}}}else{if(E=L.match(/^(-?\d*)?n(([+-])(\d+))?/)){if(E[1]=="-"){E[1]=-1}var O=E[1]?Number(E[1]):1;var M=E[2]?Number(E[2]):0;var P=Selector.pseudos.getIndices(O,M,A.length);for(var H=0,D,F=P.length;D=A[H];H++){for(var G=0;G<F;G++){if(D.nodeIndex==P[G]){I.push(D)}}}}}J.unmark(A);J.unmark(B);return I},empty:function(B,F,A){for(var D=0,C=[],E;E=B[D];D++){if(E.tagName=="!"||(E.firstChild&&!E.innerHTML.match(/^\s*$/))){continue}C.push(E)}return C},not:function(A,D,I){var G=Selector.handlers,J,C;var H=new Selector(D).findElements(I);G.mark(H);for(var F=0,E=[],B;B=A[F];F++){if(!B._countedByPrototype){E.push(B)}}G.unmark(H);return E},enabled:function(B,F,A){for(var D=0,C=[],E;E=B[D];D++){if(!E.disabled){C.push(E)}}return C},disabled:function(B,F,A){for(var D=0,C=[],E;E=B[D];D++){if(E.disabled){C.push(E)}}return C},checked:function(B,F,A){for(var D=0,C=[],E;E=B[D];D++){if(E.checked){C.push(E)}}return C}},operators:{"=":function(B,A){return B==A},"!=":function(B,A){return B!=A},"^=":function(B,A){return B.startsWith(A)},"$=":function(B,A){return B.endsWith(A)},"*=":function(B,A){return B.include(A)},"~=":function(B,A){return(" "+B+" ").include(" "+A+" ")},"|=":function(B,A){return("-"+B.toUpperCase()+"-").include("-"+A.toUpperCase()+"-")}},split:function(B){var A=[];B.scan(/(([\w#:.~>+()\s-]+|\*|\[.*?\])+)\s*(,|$)/,function(C){A.push(C[1].strip())});return A},matchElements:function(F,G){var E=$$(G),D=Selector.handlers;D.mark(E);for(var C=0,B=[],A;A=F[C];C++){if(A._countedByPrototype){B.push(A)}}D.unmark(E);return B},findElement:function(B,C,A){if(Object.isNumber(C)){A=C;C=false}return Selector.matchElements(B,C||"*")[A||0]},findChildElements:function(E,G){G=Selector.split(G.join(","));var D=[],F=Selector.handlers;for(var C=0,B=G.length,A;C<B;C++){A=new Selector(G[C].strip());F.concat(D,A.findElements(E))}return(B>1)?F.unique(D):D}});if(Prototype.Browser.IE){Object.extend(Selector.handlers,{concat:function(B,A){for(var C=0,D;D=A[C];C++){if(D.tagName!=="!"){B.push(D)}}return B},unmark:function(A){for(var B=0,C;C=A[B];B++){C.removeAttribute("_countedByPrototype")}return A}})}function $$(){return Selector.findChildElements(document,$A(arguments))}var Form={reset:function(A){$(A).reset();return A},serializeElements:function(G,B){if(typeof B!="object"){B={hash:!!B}}else{if(Object.isUndefined(B.hash)){B.hash=true}}var C,F,A=false,E=B.submit;var D=G.inject({},function(H,I){if(!I.disabled&&I.name){C=I.name;F=$(I).getValue();if(F!=null&&(I.type!="submit"||(!A&&E!==false&&(!E||C==E)&&(A=true)))){if(C in H){if(!Object.isArray(H[C])){H[C]=[H[C]]}H[C].push(F)}else{H[C]=F}}}return H});return B.hash?D:Object.toQueryString(D)}};Form.Methods={serialize:function(B,A){return Form.serializeElements(Form.getElements(B),A)},getElements:function(A){return $A($(A).getElementsByTagName("*")).inject([],function(B,C){if(Form.Element.Serializers[C.tagName.toLowerCase()]){B.push(Element.extend(C))}return B})},getInputs:function(G,C,D){G=$(G);var A=G.getElementsByTagName("input");if(!C&&!D){return $A(A).map(Element.extend)}for(var E=0,H=[],F=A.length;E<F;E++){var B=A[E];if((C&&B.type!=C)||(D&&B.name!=D)){continue}H.push(Element.extend(B))}return H},disable:function(A){A=$(A);Form.getElements(A).invoke("disable");return A},enable:function(A){A=$(A);Form.getElements(A).invoke("enable");return A},findFirstElement:function(B){var C=$(B).getElements().findAll(function(D){return"hidden"!=D.type&&!D.disabled});var A=C.findAll(function(D){return D.hasAttribute("tabIndex")&&D.tabIndex>=0}).sortBy(function(D){return D.tabIndex}).first();return A?A:C.find(function(D){return["input","select","textarea"].include(D.tagName.toLowerCase())})},focusFirstElement:function(A){A=$(A);A.findFirstElement().activate();return A},request:function(B,A){B=$(B),A=Object.clone(A||{});var D=A.parameters,C=B.readAttribute("action")||"";if(C.blank()){C=window.location.href}A.parameters=B.serialize(true);if(D){if(Object.isString(D)){D=D.toQueryParams()}Object.extend(A.parameters,D)}if(B.hasAttribute("method")&&!A.method){A.method=B.method}return new Ajax.Request(C,A)}};Form.Element={focus:function(A){$(A).focus();return A},select:function(A){$(A).select();return A}};Form.Element.Methods={serialize:function(A){A=$(A);if(!A.disabled&&A.name){var B=A.getValue();if(B!=undefined){var C={};C[A.name]=B;return Object.toQueryString(C)}}return""},getValue:function(A){A=$(A);var B=A.tagName.toLowerCase();return Form.Element.Serializers[B](A)},setValue:function(A,B){A=$(A);var C=A.tagName.toLowerCase();Form.Element.Serializers[C](A,B);return A},clear:function(A){$(A).value="";return A},present:function(A){return $(A).value!=""},activate:function(A){A=$(A);try{A.focus();if(A.select&&(A.tagName.toLowerCase()!="input"||!["button","reset","submit"].include(A.type))){A.select()}}catch(B){}return A},disable:function(A){A=$(A);A.blur();A.disabled=true;return A},enable:function(A){A=$(A);A.disabled=false;return A}};var Field=Form.Element;var $F=Form.Element.Methods.getValue;Form.Element.Serializers={input:function(A,B){switch(A.type.toLowerCase()){case"checkbox":case"radio":return Form.Element.Serializers.inputSelector(A,B);default:return Form.Element.Serializers.textarea(A,B)}},inputSelector:function(A,B){if(Object.isUndefined(B)){return A.checked?A.value:null}else{A.checked=!!B}},textarea:function(A,B){if(Object.isUndefined(B)){return A.value}else{A.value=B}},select:function(D,A){if(Object.isUndefined(A)){return this[D.type=="select-one"?"selectOne":"selectMany"](D)}else{var C,F,G=!Object.isArray(A);for(var B=0,E=D.length;B<E;B++){C=D.options[B];F=this.optionValue(C);if(G){if(F==A){C.selected=true;return }}else{C.selected=A.include(F)}}}},selectOne:function(B){var A=B.selectedIndex;return A>=0?this.optionValue(B.options[A]):null},selectMany:function(D){var A,E=D.length;if(!E){return null}for(var C=0,A=[];C<E;C++){var B=D.options[C];if(B.selected){A.push(this.optionValue(B))}}return A},optionValue:function(A){return Element.extend(A).hasAttribute("value")?A.value:A.text}};Abstract.TimedObserver=Class.create(PeriodicalExecuter,{initialize:function($super,A,B,C){$super(C,B);this.element=$(A);this.lastValue=this.getValue()},execute:function(){var A=this.getValue();if(Object.isString(this.lastValue)&&Object.isString(A)?this.lastValue!=A:String(this.lastValue)!=String(A)){this.callback(this.element,A);this.lastValue=A}}});Form.Element.Observer=Class.create(Abstract.TimedObserver,{getValue:function(){return Form.Element.getValue(this.element)}});Form.Observer=Class.create(Abstract.TimedObserver,{getValue:function(){return Form.serialize(this.element)}});Abstract.EventObserver=Class.create({initialize:function(A,B){this.element=$(A);this.callback=B;this.lastValue=this.getValue();if(this.element.tagName.toLowerCase()=="form"){this.registerFormCallbacks()}else{this.registerCallback(this.element)}},onElementEvent:function(){var A=this.getValue();if(this.lastValue!=A){this.callback(this.element,A);this.lastValue=A}},registerFormCallbacks:function(){Form.getElements(this.element).each(this.registerCallback,this)},registerCallback:function(A){if(A.type){switch(A.type.toLowerCase()){case"checkbox":case"radio":Event.observe(A,"click",this.onElementEvent.bind(this));break;default:Event.observe(A,"change",this.onElementEvent.bind(this));break}}}});Form.Element.EventObserver=Class.create(Abstract.EventObserver,{getValue:function(){return Form.Element.getValue(this.element)}});Form.EventObserver=Class.create(Abstract.EventObserver,{getValue:function(){return Form.serialize(this.element)}});if(!window.Event){var Event={}}Object.extend(Event,{KEY_BACKSPACE:8,KEY_TAB:9,KEY_RETURN:13,KEY_ESC:27,KEY_LEFT:37,KEY_UP:38,KEY_RIGHT:39,KEY_DOWN:40,KEY_DELETE:46,KEY_HOME:36,KEY_END:35,KEY_PAGEUP:33,KEY_PAGEDOWN:34,KEY_INSERT:45,cache:{},relatedTarget:function(B){var A;switch(B.type){case"mouseover":A=B.fromElement;break;case"mouseout":A=B.toElement;break;default:return null}return Element.extend(A)}});Event.Methods=(function(){var A;if(Prototype.Browser.IE){var B={0:1,1:4,2:2};A=function(D,C){return D.button==B[C]}}else{if(Prototype.Browser.WebKit){A=function(D,C){switch(C){case 0:return D.which==1&&!D.metaKey;case 1:return D.which==1&&D.metaKey;default:return false}}}else{A=function(D,C){return D.which?(D.which===C+1):(D.button===C)}}}return{isLeftClick:function(C){return A(C,0)},isMiddleClick:function(C){return A(C,1)},isRightClick:function(C){return A(C,2)},element:function(D){var C=Event.extend(D).target;return Element.extend(C.nodeType==Node.TEXT_NODE?C.parentNode:C)},findElement:function(D,F){var C=Event.element(D);if(!F){return C}var E=[C].concat(C.ancestors());return Selector.findElement(E,F,0)},pointer:function(C){return{x:C.pageX||(C.clientX+(document.documentElement.scrollLeft||document.body.scrollLeft)),y:C.pageY||(C.clientY+(document.documentElement.scrollTop||document.body.scrollTop))}},pointerX:function(C){return Event.pointer(C).x},pointerY:function(C){return Event.pointer(C).y},stop:function(C){Event.extend(C);C.preventDefault();C.stopPropagation();C.stopped=true}}})();Event.extend=(function(){var A=Object.keys(Event.Methods).inject({},function(B,C){B[C]=Event.Methods[C].methodize();return B});if(Prototype.Browser.IE){Object.extend(A,{stopPropagation:function(){this.cancelBubble=true},preventDefault:function(){this.returnValue=false},inspect:function(){return"[object Event]"}});return function(B){if(!B){return false}if(B._extendedByPrototype){return B}B._extendedByPrototype=Prototype.emptyFunction;var C=Event.pointer(B);Object.extend(B,{target:B.srcElement,relatedTarget:Event.relatedTarget(B),pageX:C.x,pageY:C.y});return Object.extend(B,A)}}else{Event.prototype=Event.prototype||document.createEvent("HTMLEvents").__proto__;Object.extend(Event.prototype,A);return Prototype.K}})();Object.extend(Event,(function(){var B=Event.cache;function C(J){if(J._prototypeEventID){return J._prototypeEventID[0]}arguments.callee.id=arguments.callee.id||1;return J._prototypeEventID=[++arguments.callee.id]}function G(J){if(J&&J.include(":")){return"dataavailable"}return J}function A(J){return B[J]=B[J]||{}}function F(L,J){var K=A(L);return K[J]=K[J]||[]}function H(K,J,L){var O=C(K);var N=F(O,J);if(N.pluck("handler").include(L)){return false}var M=function(P){if(!Event||!Event.extend||(P.eventName&&P.eventName!=J)){return false}Event.extend(P);L.call(K,P)};M.handler=L;N.push(M);return M}function I(M,J,K){var L=F(M,J);return L.find(function(N){return N.handler==K})}function D(M,J,K){var L=A(M);if(!L[J]){return false}L[J]=L[J].without(I(M,J,K))}function E(){for(var K in B){for(var J in B[K]){B[K][J]=null}}}if(window.attachEvent){window.attachEvent("onunload",E)}return{observe:function(L,J,M){L=$(L);var K=G(J);var N=H(L,J,M);if(!N){return L}if(L.addEventListener){L.addEventListener(K,N,false)}else{L.attachEvent("on"+K,N)}return L},stopObserving:function(L,J,M){L=$(L);var O=C(L),K=G(J);if(!M&&J){F(O,J).each(function(P){L.stopObserving(J,P.handler)});return L}else{if(!J){Object.keys(A(O)).each(function(P){L.stopObserving(P)});return L}}var N=I(O,J,M);if(!N){return L}if(L.removeEventListener){L.removeEventListener(K,N,false)}else{L.detachEvent("on"+K,N)}D(O,J,M);return L},fire:function(L,K,J){L=$(L);if(L==document&&document.createEvent&&!L.dispatchEvent){L=document.documentElement}var M;if(document.createEvent){M=document.createEvent("HTMLEvents");M.initEvent("dataavailable",true,true)}else{M=document.createEventObject();M.eventType="ondataavailable"}M.eventName=K;M.memo=J||{};if(document.createEvent){L.dispatchEvent(M)}else{L.fireEvent(M.eventType,M)}return Event.extend(M)}}})());Object.extend(Event,Event.Methods);Element.addMethods({fire:Event.fire,observe:Event.observe,stopObserving:Event.stopObserving});Object.extend(document,{fire:Element.Methods.fire.methodize(),observe:Element.Methods.observe.methodize(),stopObserving:Element.Methods.stopObserving.methodize(),loaded:false});(function(){var B;function A(){if(document.loaded){return }if(B){window.clearInterval(B)}document.fire("dom:loaded");document.loaded=true}if(document.addEventListener){if(Prototype.Browser.WebKit){B=window.setInterval(function(){if(/loaded|complete/.test(document.readyState)){A()}},0);Event.observe(window,"load",A)}else{document.addEventListener("DOMContentLoaded",A,false)}}else{document.write("<script id=__onDOMContentLoaded defer src=//:><\/script>");$("__onDOMContentLoaded").onreadystatechange=function(){if(this.readyState=="complete"){this.onreadystatechange=null;A()}}}})();Hash.toQueryString=Object.toQueryString;var Toggle={display:Element.toggle};Element.Methods.childOf=Element.Methods.descendantOf;var Insertion={Before:function(A,B){return Element.insert(A,{before:B})},Top:function(A,B){return Element.insert(A,{top:B})},Bottom:function(A,B){return Element.insert(A,{bottom:B})},After:function(A,B){return Element.insert(A,{after:B})}};var $continue=new Error('"throw $continue" is deprecated, use "return" instead');var Position={includeScrollOffsets:false,prepare:function(){this.deltaX=window.pageXOffset||document.documentElement.scrollLeft||document.body.scrollLeft||0;this.deltaY=window.pageYOffset||document.documentElement.scrollTop||document.body.scrollTop||0},within:function(B,A,C){if(this.includeScrollOffsets){return this.withinIncludingScrolloffsets(B,A,C)}this.xcomp=A;this.ycomp=C;this.offset=Element.cumulativeOffset(B);return(C>=this.offset[1]&&C<this.offset[1]+B.offsetHeight&&A>=this.offset[0]&&A<this.offset[0]+B.offsetWidth)},withinIncludingScrolloffsets:function(B,A,D){var C=Element.cumulativeScrollOffset(B);this.xcomp=A+C[0]-this.deltaX;this.ycomp=D+C[1]-this.deltaY;this.offset=Element.cumulativeOffset(B);return(this.ycomp>=this.offset[1]&&this.ycomp<this.offset[1]+B.offsetHeight&&this.xcomp>=this.offset[0]&&this.xcomp<this.offset[0]+B.offsetWidth)},overlap:function(B,A){if(!B){return 0}if(B=="vertical"){return((this.offset[1]+A.offsetHeight)-this.ycomp)/A.offsetHeight}if(B=="horizontal"){return((this.offset[0]+A.offsetWidth)-this.xcomp)/A.offsetWidth}},cumulativeOffset:Element.Methods.cumulativeOffset,positionedOffset:Element.Methods.positionedOffset,absolutize:function(A){Position.prepare();return Element.absolutize(A)},relativize:function(A){Position.prepare();return Element.relativize(A)},realOffset:Element.Methods.cumulativeScrollOffset,offsetParent:Element.Methods.getOffsetParent,page:Element.Methods.viewportOffset,clone:function(B,C,A){A=A||{};return Element.clonePosition(C,B,A)}};if(!document.getElementsByClassName){document.getElementsByClassName=function(B){function A(C){return C.blank()?null:"[contains(concat(' ', @class, ' '), ' "+C+" ')]"}B.getElementsByClassName=Prototype.BrowserFeatures.XPath?function(C,E){E=E.toString().strip();var D=/\s/.test(E)?$w(E).map(A).join(""):A(E);return D?document._getElementsByXPath(".//*"+D,C):[]}:function(E,F){F=F.toString().strip();var G=[],H=(/\s/.test(F)?$w(F):null);if(!H&&!F){return G}var C=$(E).getElementsByTagName("*");F=" "+F+" ";for(var D=0,J,I;J=C[D];D++){if(J.className&&(I=" "+J.className+" ")&&(I.include(F)||(H&&H.all(function(K){return !K.toString().blank()&&I.include(" "+K+" ")})))){G.push(Element.extend(J))}}return G};return function(D,C){return $(C||document.body).getElementsByClassName(D)}}(Element.Methods)}Element.ClassNames=Class.create();Element.ClassNames.prototype={initialize:function(A){this.element=$(A)},_each:function(A){this.element.className.split(/\s+/).select(function(B){return B.length>0})._each(A)},set:function(A){this.element.className=A},add:function(A){if(this.include(A)){return }this.set($A(this).concat(A).join(" "))},remove:function(A){if(!this.include(A)){return }this.set($A(this).without(A).join(" "))},toString:function(){return $A(this).join(" ")}};Object.extend(Element.ClassNames.prototype,Enumerable);Element.addMethods();
\ No newline at end of file
+var Prototype={Version:"1.6.0.3",Browser:{IE:!!(window.attachEvent&&navigator.userAgent.indexOf("Opera")===-1),Opera:navigator.userAgent.indexOf("Opera")>-1,WebKit:navigator.userAgent.indexOf("AppleWebKit/")>-1,Gecko:navigator.userAgent.indexOf("Gecko")>-1&&navigator.userAgent.indexOf("KHTML")===-1,MobileSafari:!!navigator.userAgent.match(/Apple.*Mobile.*Safari/)},BrowserFeatures:{XPath:!!document.evaluate,SelectorsAPI:!!document.querySelector,ElementExtensions:!!window.HTMLElement,SpecificElementExtensions:document.createElement("div")["__proto__"]&&document.createElement("div")["__proto__"]!==document.createElement("form")["__proto__"]},ScriptFragment:"<script[^>]*>([\\S\\s]*?)<\/script>",JSONFilter:/^\/\*-secure-([\s\S]*)\*\/\s*$/,emptyFunction:function(){},K:function(a){return a}};if(Prototype.Browser.MobileSafari){Prototype.BrowserFeatures.SpecificElementExtensions=false}var Class={create:function(){var e=null,d=$A(arguments);if(Object.isFunction(d[0])){e=d.shift()}function a(){this.initialize.apply(this,arguments)}Object.extend(a,Class.Methods);a.superclass=e;a.subclasses=[];if(e){var b=function(){};b.prototype=e.prototype;a.prototype=new b;e.subclasses.push(a)}for(var c=0;c<d.length;c++){a.addMethods(d[c])}if(!a.prototype.initialize){a.prototype.initialize=Prototype.emptyFunction}a.prototype.constructor=a;return a}};Class.Methods={addMethods:function(g){var c=this.superclass&&this.superclass.prototype;var b=Object.keys(g);if(!Object.keys({toString:true}).length){b.push("toString","valueOf")}for(var a=0,d=b.length;a<d;a++){var f=b[a],e=g[f];if(c&&Object.isFunction(e)&&e.argumentNames().first()=="$super"){var h=e;e=(function(i){return function(){return c[i].apply(this,arguments)}})(f).wrap(h);e.valueOf=h.valueOf.bind(h);e.toString=h.toString.bind(h)}this.prototype[f]=e}return this}};var Abstract={};Object.extend=function(a,c){for(var b in c){a[b]=c[b]}return a};Object.extend(Object,{inspect:function(a){try{if(Object.isUndefined(a)){return"undefined"}if(a===null){return"null"}return a.inspect?a.inspect():String(a)}catch(b){if(b instanceof RangeError){return"..."}throw b}},toJSON:function(a){var c=typeof a;switch(c){case"undefined":case"function":case"unknown":return;case"boolean":return a.toString()}if(a===null){return"null"}if(a.toJSON){return a.toJSON()}if(Object.isElement(a)){return}var b=[];for(var e in a){var d=Object.toJSON(a[e]);if(!Object.isUndefined(d)){b.push(e.toJSON()+": "+d)}}return"{"+b.join(", ")+"}"},toQueryString:function(a){return $H(a).toQueryString()},toHTML:function(a){return a&&a.toHTML?a.toHTML():String.interpret(a)},keys:function(a){var b=[];for(var c in a){b.push(c)}return b},values:function(b){var a=[];for(var c in b){a.push(b[c])}return a},clone:function(a){return Object.extend({},a)},isElement:function(a){return!!(a&&a.nodeType==1)},isArray:function(a){return a!=null&&typeof a=="object"&&"splice"in a&&"join"in a},isHash:function(a){return a instanceof Hash},isFunction:function(a){return typeof a=="function"},isString:function(a){return typeof a=="string"},isNumber:function(a){return typeof a=="number"},isUndefined:function(a){return typeof a=="undefined"}});Object.extend(Function.prototype,{argumentNames:function(){var a=this.toString().match(/^[\s\(]*function[^(]*\(([^\)]*)\)/)[1].replace(/\s+/g,"").split(",");return a.length==1&&!a[0]?[]:a},bind:function(){if(arguments.length<2&&Object.isUndefined(arguments[0])){return this}var a=this,c=$A(arguments),b=c.shift();return function(){return a.apply(b,c.concat($A(arguments)))}},bindAsEventListener:function(){var a=this,c=$A(arguments),b=c.shift();return function(d){return a.apply(b,[d||window.event].concat(c))}},curry:function(){if(!arguments.length){return this}var a=this,b=$A(arguments);return function(){return a.apply(this,b.concat($A(arguments)))}},delay:function(){var a=this,b=$A(arguments),c=b.shift()*1000;return window.setTimeout(function(){return a.apply(a,b)},c)},defer:function(){var a=[0.01].concat($A(arguments));return this.delay.apply(this,a)},wrap:function(b){var a=this;return function(){return b.apply(this,[a.bind(this)].concat($A(arguments)))}},methodize:function(){if(this._methodized){return this._methodized}var a=this;return this._methodized=function(){return a.apply(null,[this].concat($A(arguments)))}}});Date.prototype.toJSON=function(){return'"'+this.getUTCFullYear()+"-"+(this.getUTCMonth()+1).toPaddedString(2)+"-"+this.getUTCDate().toPaddedString(2)+"T"+this.getUTCHours().toPaddedString(2)+":"+this.getUTCMinutes().toPaddedString(2)+":"+this.getUTCSeconds().toPaddedString(2)+'Z"'};var Try={these:function(){var c;for(var b=0,d=arguments.length;b<d;b++){var a=arguments[b];try{c=a();break}catch(f){}}return c}};RegExp.prototype.match=RegExp.prototype.test;RegExp.escape=function(a){return String(a).replace(/([.*+?^=!:${}()|[\]\/\\])/g,"\\$1")};var PeriodicalExecuter=Class.create({initialize:function(b,a){this.callback=b;this.frequency=a;this.currentlyExecuting=false;this.registerCallback()},registerCallback:function(){this.timer=setInterval(this.onTimerEvent.bind(this),this.frequency*1000)},execute:function(){this.callback(this)},stop:function(){if(!this.timer){return}clearInterval(this.timer);this.timer=null},onTimerEvent:function(){if(!this.currentlyExecuting){try{this.currentlyExecuting=true;this.execute()}finally{this.currentlyExecuting=false}}}});Object.extend(String,{interpret:function(a){return a==null?"":String(a)},specialChar:{"\b":"\\b","\t":"\\t","\n":"\\n","\f":"\\f","\r":"\\r","\\":"\\\\"}});Object.extend(String.prototype,{gsub:function(e,c){var a="",d=this,b;c=arguments.callee.prepareReplacement(c);while(d.length>0){if(b=d.match(e)){a+=d.slice(0,b.index);a+=String.interpret(c(b));d=d.slice(b.index+b[0].length)}else{a+=d,d=""}}return a},sub:function(c,a,b){a=this.gsub.prepareReplacement(a);b=Object.isUndefined(b)?1:b;return this.gsub(c,function(d){if(--b<0){return d[0]}return a(d)})},scan:function(b,a){this.gsub(b,a);return String(this)},truncate:function(b,a){b=b||30;a=Object.isUndefined(a)?"...":a;return this.length>b?this.slice(0,b-a.length)+a:String(this)},strip:function(){return this.replace(/^\s+/,"").replace(/\s+$/,"")},stripTags:function(){return this.replace(/<\/?[^>]+>/gi,"")},stripScripts:function(){return this.replace(new RegExp(Prototype.ScriptFragment,"img"),"")},extractScripts:function(){var b=new RegExp(Prototype.ScriptFragment,"img");var a=new RegExp(Prototype.ScriptFragment,"im");return(this.match(b)||[]).map(function(c){return(c.match(a)||["",""])[1]})},evalScripts:function(){return this.extractScripts().map(function(script){return eval(script)})},escapeHTML:function(){var a=arguments.callee;a.text.data=this;return a.div.innerHTML},unescapeHTML:function(){var a=new Element("div");a.innerHTML=this.stripTags();return a.childNodes[0]?(a.childNodes.length>1?$A(a.childNodes).inject("",function(b,c){return b+c.nodeValue}):a.childNodes[0].nodeValue):""},toQueryParams:function(b){var a=this.strip().match(/([^?#]*)(#.*)?$/);if(!a){return{}}return a[1].split(b||"&").inject({},function(e,f){if((f=f.split("="))[0]){var c=decodeURIComponent(f.shift());var d=f.length>1?f.join("="):f[0];if(d!=undefined){d=decodeURIComponent(d)}if(c in e){if(!Object.isArray(e[c])){e[c]=[e[c]]}e[c].push(d)}else{e[c]=d}}return e})},toArray:function(){return this.split("")},succ:function(){return this.slice(0,this.length-1)+String.fromCharCode(this.charCodeAt(this.length-1)+1)},times:function(a){return a<1?"":new Array(a+1).join(this)},camelize:function(){var d=this.split("-"),a=d.length;if(a==1){return d[0]}var c=this.charAt(0)=="-"?d[0].charAt(0).toUpperCase()+d[0].substring(1):d[0];for(var b=1;b<a;b++){c+=d[b].charAt(0).toUpperCase()+d[b].substring(1)}return c},capitalize:function(){return this.charAt(0).toUpperCase()+this.substring(1).toLowerCase()},underscore:function(){return this.gsub(/::/,"/").gsub(/([A-Z]+)([A-Z][a-z])/,"#{1}_#{2}").gsub(/([a-z\d])([A-Z])/,"#{1}_#{2}").gsub(/-/,"_").toLowerCase()},dasherize:function(){return this.gsub(/_/,"-")},inspect:function(b){var a=this.gsub(/[\x00-\x1f\\]/,function(c){var d=String.specialChar[c[0]];return d?d:"\\u00"+c[0].charCodeAt().toPaddedString(2,16)});if(b){return'"'+a.replace(/"/g,'\\"')+'"'}return"'"+a.replace(/'/g,"\\'")+"'"},toJSON:function(){return this.inspect(true)},unfilterJSON:function(a){return this.sub(a||Prototype.JSONFilter,"#{1}")},isJSON:function(){var a=this;if(a.blank()){return false}a=this.replace(/\\./g,"@").replace(/"[^"\\\n\r]*"/g,"");return(/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(a)},evalJSON:function(sanitize){var json=this.unfilterJSON();try{if(!sanitize||json.isJSON()){return eval("("+json+")")}}catch(e){}throw new SyntaxError("Badly formed JSON string: "+this.inspect())},include:function(a){return this.indexOf(a)>-1},startsWith:function(a){return this.indexOf(a)===0},endsWith:function(a){var b=this.length-a.length;return b>=0&&this.lastIndexOf(a)===b},empty:function(){return this==""},blank:function(){return/^\s*$/.test(this)},interpolate:function(a,b){return new Template(this,b).evaluate(a)}});if(Prototype.Browser.WebKit||Prototype.Browser.IE){Object.extend(String.prototype,{escapeHTML:function(){return this.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;")},unescapeHTML:function(){return this.stripTags().replace(/&amp;/g,"&").replace(/&lt;/g,"<").replace(/&gt;/g,">")}})}String.prototype.gsub.prepareReplacement=function(b){if(Object.isFunction(b)){return b}var a=new Template(b);return function(c){return a.evaluate(c)}};String.prototype.parseQuery=String.prototype.toQueryParams;Object.extend(String.prototype.escapeHTML,{div:document.createElement("div"),text:document.createTextNode("")});String.prototype.escapeHTML.div.appendChild(String.prototype.escapeHTML.text);var Template=Class.create({initialize:function(a,b){this.template=a.toString();this.pattern=b||Template.Pattern},evaluate:function(a){if(Object.isFunction(a.toTemplateReplacements)){a=a.toTemplateReplacements()}return this.template.gsub(this.pattern,function(d){if(a==null){return""}var f=d[1]||"";if(f=="\\"){return d[2]}var b=a,g=d[3];var e=/^([^.[]+|\[((?:.*?[^\\])?)\])(\.|\[|$)/;d=e.exec(g);if(d==null){return f}while(d!=null){var c=d[1].startsWith("[")?d[2].gsub("\\\\]","]"):d[1];b=b[c];if(null==b||""==d[3]){break}g=g.substring("["==d[3]?d[1].length:d[0].length);d=e.exec(g)}return f+String.interpret(b)})}});Template.Pattern=/(^|.|\r|\n)(#\{(.*?)\})/;var $break={};var Enumerable={each:function(c,b){var a=0;try{this._each(function(e){c.call(b,e,a++)})}catch(d){if(d!=$break){throw d}}return this},eachSlice:function(d,c,b){var a=-d,e=[],f=this.toArray();if(d<1){return f}while((a+=d)<f.length){e.push(f.slice(a,a+d))}return e.collect(c,b)},all:function(c,b){c=c||Prototype.K;var a=true;this.each(function(e,d){a=a&&!!c.call(b,e,d);if(!a){throw $break}});return a},any:function(c,b){c=c||Prototype.K;var a=false;this.each(function(e,d){if(a=!!c.call(b,e,d)){throw $break}});return a},collect:function(c,b){c=c||Prototype.K;var a=[];this.each(function(e,d){a.push(c.call(b,e,d))});return a},detect:function(c,b){var a;this.each(function(e,d){if(c.call(b,e,d)){a=e;throw $break}});return a},findAll:function(c,b){var a=[];this.each(function(e,d){if(c.call(b,e,d)){a.push(e)}});return a},grep:function(d,c,b){c=c||Prototype.K;var a=[];if(Object.isString(d)){d=new RegExp(d)}this.each(function(f,e){if(d.match(f)){a.push(c.call(b,f,e))}});return a},include:function(a){if(Object.isFunction(this.indexOf)){if(this.indexOf(a)!=-1){return true}}var b=false;this.each(function(c){if(c==a){b=true;throw $break}});return b},inGroupsOf:function(b,a){a=Object.isUndefined(a)?null:a;return this.eachSlice(b,function(c){while(c.length<b){c.push(a)}return c})},inject:function(a,c,b){this.each(function(e,d){a=c.call(b,a,e,d)});return a},invoke:function(b){var a=$A(arguments).slice(1);return this.map(function(c){return c[b].apply(c,a)})},max:function(c,b){c=c||Prototype.K;var a;this.each(function(e,d){e=c.call(b,e,d);if(a==null||e>=a){a=e}});return a},min:function(c,b){c=c||Prototype.K;var a;this.each(function(e,d){e=c.call(b,e,d);if(a==null||e<a){a=e}});return a},partition:function(d,b){d=d||Prototype.K;var c=[],a=[];this.each(function(f,e){(d.call(b,f,e)?c:a).push(f)});return[c,a]},pluck:function(b){var a=[];this.each(function(c){a.push(c[b])});return a},reject:function(c,b){var a=[];this.each(function(e,d){if(!c.call(b,e,d)){a.push(e)}});return a},sortBy:function(b,a){return this.map(function(d,c){return{value:d,criteria:b.call(a,d,c)}}).sort(function(f,e){var d=f.criteria,c=e.criteria;return d<c?-1:d>c?1:0}).pluck("value")},toArray:function(){return this.map()},zip:function(){var b=Prototype.K,a=$A(arguments);if(Object.isFunction(a.last())){b=a.pop()}var c=[this].concat(a).map($A);return this.map(function(e,d){return b(c.pluck(d))})},size:function(){return this.toArray().length},inspect:function(){return"#<Enumerable:"+this.toArray().inspect()+">"}};Object.extend(Enumerable,{map:Enumerable.collect,find:Enumerable.detect,select:Enumerable.findAll,filter:Enumerable.findAll,member:Enumerable.include,entries:Enumerable.toArray,every:Enumerable.all,some:Enumerable.any});function $A(c){if(!c){return[]}if(c.toArray){return c.toArray()}var b=c.length||0,a=new Array(b);while(b--){a[b]=c[b]}return a}if(Prototype.Browser.WebKit){$A=function(c){if(!c){return[]}if(!(typeof c==="function"&&typeof c.length==="number"&&typeof c.item==="function")&&c.toArray){return c.toArray()}var b=c.length||0,a=new Array(b);while(b--){a[b]=c[b]}return a}}Array.from=$A;Object.extend(Array.prototype,Enumerable);if(!Array.prototype._reverse){Array.prototype._reverse=Array.prototype.reverse}Object.extend(Array.prototype,{_each:function(b){for(var a=0,c=this.length;a<c;a++){b(this[a])}},clear:function(){this.length=0;return this},first:function(){return this[0]},last:function(){return this[this.length-1]},compact:function(){return this.select(function(a){return a!=null})},flatten:function(){return this.inject([],function(b,a){return b.concat(Object.isArray(a)?a.flatten():[a])})},without:function(){var a=$A(arguments);return this.select(function(b){return!a.include(b)})},reverse:function(a){return(a!==false?this:this.toArray())._reverse()},reduce:function(){return this.length>1?this:this[0]},uniq:function(a){return this.inject([],function(d,c,b){if(0==b||(a?d.last()!=c:!d.include(c))){d.push(c)}return d})},intersect:function(a){return this.uniq().findAll(function(b){return a.detect(function(c){return b===c})})},clone:function(){return[].concat(this)},size:function(){return this.length},inspect:function(){return"["+this.map(Object.inspect).join(", ")+"]"},toJSON:function(){var a=[];this.each(function(b){var c=Object.toJSON(b);if(!Object.isUndefined(c)){a.push(c)}});return"["+a.join(", ")+"]"}});if(Object.isFunction(Array.prototype.forEach)){Array.prototype._each=Array.prototype.forEach}if(!Array.prototype.indexOf){Array.prototype.indexOf=function(c,a){a||(a=0);var b=this.length;if(a<0){a=b+a}for(;a<b;a++){if(this[a]===c){return a}}return-1}}if(!Array.prototype.lastIndexOf){Array.prototype.lastIndexOf=function(b,a){a=isNaN(a)?this.length:(a<0?this.length+a:a)+1;var c=this.slice(0,a).reverse().indexOf(b);return(c<0)?c:a-c-1}}Array.prototype.toArray=Array.prototype.clone;function $w(a){if(!Object.isString(a)){return[]}a=a.strip();return a?a.split(/\s+/):[]}if(Prototype.Browser.Opera){Array.prototype.concat=function(){var e=[];for(var b=0,c=this.length;b<c;b++){e.push(this[b])}for(var b=0,c=arguments.length;b<c;b++){if(Object.isArray(arguments[b])){for(var a=0,d=arguments[b].length;a<d;a++){e.push(arguments[b][a])}}else{e.push(arguments[b])}}return e}}Object.extend(Number.prototype,{toColorPart:function(){return this.toPaddedString(2,16)},succ:function(){return this+1},times:function(b,a){$R(0,this,true).each(b,a);return this},toPaddedString:function(c,b){var a=this.toString(b||10);return"0".times(c-a.length)+a},toJSON:function(){return isFinite(this)?this.toString():"null"}});$w("abs round ceil floor").each(function(a){Number.prototype[a]=Math[a].methodize()});function $H(a){return new Hash(a)}var Hash=Class.create(Enumerable,(function(){function a(b,c){if(Object.isUndefined(c)){return b}return b+"="+encodeURIComponent(String.interpret(c))}return{initialize:function(b){this._object=Object.isHash(b)?b.toObject():Object.clone(b)},_each:function(c){for(var b in this._object){var d=this._object[b],e=[b,d];e.key=b;e.value=d;c(e)}},set:function(b,c){return this._object[b]=c},get:function(b){if(this._object[b]!==Object.prototype[b]){return this._object[b]}},unset:function(b){var c=this._object[b];delete this._object[b];return c},toObject:function(){return Object.clone(this._object)},keys:function(){return this.pluck("key")},values:function(){return this.pluck("value")},index:function(c){var b=this.detect(function(d){return d.value===c});return b&&b.key},merge:function(b){return this.clone().update(b)},update:function(b){return new Hash(b).inject(this,function(c,d){c.set(d.key,d.value);return c})},toQueryString:function(){return this.inject([],function(d,e){var c=encodeURIComponent(e.key),b=e.value;if(b&&typeof b=="object"){if(Object.isArray(b)){return d.concat(b.map(a.curry(c)))}}else{d.push(a(c,b))}return d}).join("&")},inspect:function(){return"#<Hash:{"+this.map(function(b){return b.map(Object.inspect).join(": ")}).join(", ")+"}>"},toJSON:function(){return Object.toJSON(this.toObject())},clone:function(){return new Hash(this)}}})());Hash.prototype.toTemplateReplacements=Hash.prototype.toObject;Hash.from=$H;var ObjectRange=Class.create(Enumerable,{initialize:function(c,a,b){this.start=c;this.end=a;this.exclusive=b},_each:function(a){var b=this.start;while(this.include(b)){a(b);b=b.succ()}},include:function(a){if(a<this.start){return false}if(this.exclusive){return a<this.end}return a<=this.end}});var $R=function(c,a,b){return new ObjectRange(c,a,b)};var Ajax={getTransport:function(){return Try.these(function(){return new XMLHttpRequest()},function(){return new ActiveXObject("Msxml2.XMLHTTP")},function(){return new ActiveXObject("Microsoft.XMLHTTP")})||false},activeRequestCount:0};Ajax.Responders={responders:[],_each:function(a){this.responders._each(a)},register:function(a){if(!this.include(a)){this.responders.push(a)}},unregister:function(a){this.responders=this.responders.without(a)},dispatch:function(d,b,c,a){this.each(function(f){if(Object.isFunction(f[d])){try{f[d].apply(f,[b,c,a])}catch(g){}}})}};Object.extend(Ajax.Responders,Enumerable);Ajax.Responders.register({onCreate:function(){Ajax.activeRequestCount++},onComplete:function(){Ajax.activeRequestCount--}});Ajax.Base=Class.create({initialize:function(a){this.options={method:"post",asynchronous:true,contentType:"application/x-www-form-urlencoded",encoding:"UTF-8",parameters:"",evalJSON:true,evalJS:true};Object.extend(this.options,a||{});this.options.method=this.options.method.toLowerCase();if(Object.isString(this.options.parameters)){this.options.parameters=this.options.parameters.toQueryParams()}else{if(Object.isHash(this.options.parameters)){this.options.parameters=this.options.parameters.toObject()}}}});Ajax.Request=Class.create(Ajax.Base,{_complete:false,initialize:function($super,b,a){$super(a);this.transport=Ajax.getTransport();this.request(b)},request:function(b){this.url=b;this.method=this.options.method;var d=Object.clone(this.options.parameters);if(!["get","post"].include(this.method)){d._method=this.method;this.method="post"}this.parameters=d;if(d=Object.toQueryString(d)){if(this.method=="get"){this.url+=(this.url.include("?")?"&":"?")+d}else{if(/Konqueror|Safari|KHTML/.test(navigator.userAgent)){d+="&_="}}}try{var a=new Ajax.Response(this);if(this.options.onCreate){this.options.onCreate(a)}Ajax.Responders.dispatch("onCreate",this,a);this.transport.open(this.method.toUpperCase(),this.url,this.options.asynchronous);if(this.options.asynchronous){this.respondToReadyState.bind(this).defer(1)}this.transport.onreadystatechange=this.onStateChange.bind(this);this.setRequestHeaders();this.body=this.method=="post"?(this.options.postBody||d):null;this.transport.send(this.body);if(!this.options.asynchronous&&this.transport.overrideMimeType){this.onStateChange()}}catch(c){this.dispatchException(c)}},onStateChange:function(){var a=this.transport.readyState;if(a>1&&!((a==4)&&this._complete)){this.respondToReadyState(this.transport.readyState)}},setRequestHeaders:function(){var e={"X-Requested-With":"XMLHttpRequest","X-Prototype-Version":Prototype.Version,Accept:"text/javascript, text/html, application/xml, text/xml, */*"};if(this.method=="post"){e["Content-type"]=this.options.contentType+(this.options.encoding?"; charset="+this.options.encoding:"");if(this.transport.overrideMimeType&&(navigator.userAgent.match(/Gecko\/(\d{4})/)||[0,2005])[1]<2005){e.Connection="close"}}if(typeof this.options.requestHeaders=="object"){var c=this.options.requestHeaders;if(Object.isFunction(c.push)){for(var b=0,d=c.length;b<d;b+=2){e[c[b]]=c[b+1]}}else{$H(c).each(function(f){e[f.key]=f.value})}}for(var a in e){this.transport.setRequestHeader(a,e[a])}},success:function(){var a=this.getStatus();return!a||(a>=200&&a<300)},getStatus:function(){try{return this.transport.status||0}catch(a){return 0}},respondToReadyState:function(a){var c=Ajax.Request.Events[a],b=new Ajax.Response(this);if(c=="Complete"){try{this._complete=true;(this.options["on"+b.status]||this.options["on"+(this.success()?"Success":"Failure")]||Prototype.emptyFunction)(b,b.headerJSON)}catch(d){this.dispatchException(d)}var f=b.getHeader("Content-type");if(this.options.evalJS=="force"||(this.options.evalJS&&this.isSameOrigin()&&f&&f.match(/^\s*(text|application)\/(x-)?(java|ecma)script(;.*)?\s*$/i))){this.evalResponse()}}try{(this.options["on"+c]||Prototype.emptyFunction)(b,b.headerJSON);Ajax.Responders.dispatch("on"+c,this,b,b.headerJSON)}catch(d){this.dispatchException(d)}if(c=="Complete"){this.transport.onreadystatechange=Prototype.emptyFunction}},isSameOrigin:function(){var a=this.url.match(/^\s*https?:\/\/[^\/]*/);return!a||(a[0]=="#{protocol}//#{domain}#{port}".interpolate({protocol:location.protocol,domain:document.domain,port:location.port?":"+location.port:""}))},getHeader:function(a){try{return this.transport.getResponseHeader(a)||null}catch(b){return null}},evalResponse:function(){try{return eval((this.transport.responseText||"").unfilterJSON())}catch(e){this.dispatchException(e)}},dispatchException:function(a){(this.options.onException||Prototype.emptyFunction)(this,a);Ajax.Responders.dispatch("onException",this,a)}});Ajax.Request.Events=["Uninitialized","Loading","Loaded","Interactive","Complete"];Ajax.Response=Class.create({initialize:function(c){this.request=c;var d=this.transport=c.transport,a=this.readyState=d.readyState;if((a>2&&!Prototype.Browser.IE)||a==4){this.status=this.getStatus();this.statusText=this.getStatusText();this.responseText=String.interpret(d.responseText);this.headerJSON=this._getHeaderJSON()}if(a==4){var b=d.responseXML;this.responseXML=Object.isUndefined(b)?null:b;this.responseJSON=this._getResponseJSON()}},status:0,statusText:"",getStatus:Ajax.Request.prototype.getStatus,getStatusText:function(){try{return this.transport.statusText||""}catch(a){return""}},getHeader:Ajax.Request.prototype.getHeader,getAllHeaders:function(){try{return this.getAllResponseHeaders()}catch(a){return null}},getResponseHeader:function(a){return this.transport.getResponseHeader(a)},getAllResponseHeaders:function(){return this.transport.getAllResponseHeaders()},_getHeaderJSON:function(){var a=this.getHeader("X-JSON");if(!a){return null}a=decodeURIComponent(escape(a));try{return a.evalJSON(this.request.options.sanitizeJSON||!this.request.isSameOrigin())}catch(b){this.request.dispatchException(b)}},_getResponseJSON:function(){var a=this.request.options;if(!a.evalJSON||(a.evalJSON!="force"&&!(this.getHeader("Content-type")||"").include("application/json"))||this.responseText.blank()){return null}try{return this.responseText.evalJSON(a.sanitizeJSON||!this.request.isSameOrigin())}catch(b){this.request.dispatchException(b)}}});Ajax.Updater=Class.create(Ajax.Request,{initialize:function($super,a,c,b){this.container={success:(a.success||a),failure:(a.failure||(a.success?null:a))};b=Object.clone(b);var d=b.onComplete;b.onComplete=(function(e,f){this.updateContent(e.responseText);if(Object.isFunction(d)){d(e,f)}}).bind(this);$super(c,b)},updateContent:function(d){var c=this.container[this.success()?"success":"failure"],a=this.options;if(!a.evalScripts){d=d.stripScripts()}if(c=$(c)){if(a.insertion){if(Object.isString(a.insertion)){var b={};b[a.insertion]=d;c.insert(b)}else{a.insertion(c,d)}}else{c.update(d)}}}});Ajax.PeriodicalUpdater=Class.create(Ajax.Base,{initialize:function($super,a,c,b){$super(b);this.onComplete=this.options.onComplete;this.frequency=(this.options.frequency||2);this.decay=(this.options.decay||1);this.updater={};this.container=a;this.url=c;this.start()},start:function(){this.options.onComplete=this.updateComplete.bind(this);this.onTimerEvent()},stop:function(){this.updater.options.onComplete=undefined;clearTimeout(this.timer);(this.onComplete||Prototype.emptyFunction).apply(this,arguments)},updateComplete:function(a){if(this.options.decay){this.decay=(a.responseText==this.lastText?this.decay*this.options.decay:1);this.lastText=a.responseText}this.timer=this.onTimerEvent.bind(this).delay(this.decay*this.frequency)},onTimerEvent:function(){this.updater=new Ajax.Updater(this.container,this.url,this.options)}});function $(b){if(arguments.length>1){for(var a=0,d=[],c=arguments.length;a<c;a++){d.push($(arguments[a]))}return d}if(Object.isString(b)){b=document.getElementById(b)}return Element.extend(b)}if(Prototype.BrowserFeatures.XPath){document._getElementsByXPath=function(f,a){var c=[];var e=document.evaluate(f,$(a)||document,null,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,null);for(var b=0,d=e.snapshotLength;b<d;b++){c.push(Element.extend(e.snapshotItem(b)))}return c}}if(!window.Node){var Node={}}if(!Node.ELEMENT_NODE){Object.extend(Node,{ELEMENT_NODE:1,ATTRIBUTE_NODE:2,TEXT_NODE:3,CDATA_SECTION_NODE:4,ENTITY_REFERENCE_NODE:5,ENTITY_NODE:6,PROCESSING_INSTRUCTION_NODE:7,COMMENT_NODE:8,DOCUMENT_NODE:9,DOCUMENT_TYPE_NODE:10,DOCUMENT_FRAGMENT_NODE:11,NOTATION_NODE:12})}(function(){var a=this.Element;this.Element=function(d,c){c=c||{};d=d.toLowerCase();var b=Element.cache;if(Prototype.Browser.IE&&c.name){d="<"+d+' name="'+c.name+'">';delete c.name;return Element.writeAttribute(document.createElement(d),c)}if(!b[d]){b[d]=Element.extend(document.createElement(d))}return Element.writeAttribute(b[d].cloneNode(false),c)};Object.extend(this.Element,a||{});if(a){this.Element.prototype=a.prototype}}).call(window);Element.cache={};Element.Methods={visible:function(a){return $(a).style.display!="none"},toggle:function(a){a=$(a);Element[Element.visible(a)?"hide":"show"](a);return a},hide:function(a){a=$(a);a.style.display="none";return a},show:function(a){a=$(a);a.style.display="";return a},remove:function(a){a=$(a);a.parentNode.removeChild(a);return a},update:function(a,b){a=$(a);if(b&&b.toElement){b=b.toElement()}if(Object.isElement(b)){return a.update().insert(b)}b=Object.toHTML(b);a.innerHTML=b.stripScripts();b.evalScripts.bind(b).defer();return a},replace:function(b,c){b=$(b);if(c&&c.toElement){c=c.toElement()}else{if(!Object.isElement(c)){c=Object.toHTML(c);var a=b.ownerDocument.createRange();a.selectNode(b);c.evalScripts.bind(c).defer();c=a.createContextualFragment(c.stripScripts())}}b.parentNode.replaceChild(c,b);return b},insert:function(c,e){c=$(c);if(Object.isString(e)||Object.isNumber(e)||Object.isElement(e)||(e&&(e.toElement||e.toHTML))){e={bottom:e}}var d,f,b,g;for(var a in e){d=e[a];a=a.toLowerCase();f=Element._insertionTranslations[a];if(d&&d.toElement){d=d.toElement()}if(Object.isElement(d)){f(c,d);continue}d=Object.toHTML(d);b=((a=="before"||a=="after")?c.parentNode:c).tagName.toUpperCase();g=Element._getContentFromAnonymousElement(b,d.stripScripts());if(a=="top"||a=="after"){g.reverse()}g.each(f.curry(c));d.evalScripts.bind(d).defer()}return c},wrap:function(b,c,a){b=$(b);if(Object.isElement(c)){$(c).writeAttribute(a||{})}else{if(Object.isString(c)){c=new Element(c,a)}else{c=new Element("div",c)}}if(b.parentNode){b.parentNode.replaceChild(c,b)}c.appendChild(b);return c},inspect:function(b){b=$(b);var a="<"+b.tagName.toLowerCase();$H({id:"id",className:"class"}).each(function(f){var e=f.first(),c=f.last();var d=(b[e]||"").toString();if(d){a+=" "+c+"="+d.inspect(true)}});return a+">"},recursivelyCollect:function(a,c){a=$(a);var b=[];while(a=a[c]){if(a.nodeType==1){b.push(Element.extend(a))}}return b},ancestors:function(a){return $(a).recursivelyCollect("parentNode")},descendants:function(a){return $(a).select("*")},firstDescendant:function(a){a=$(a).firstChild;while(a&&a.nodeType!=1){a=a.nextSibling}return $(a)},immediateDescendants:function(a){if(!(a=$(a).firstChild)){return[]}while(a&&a.nodeType!=1){a=a.nextSibling}if(a){return[a].concat($(a).nextSiblings())}return[]},previousSiblings:function(a){return $(a).recursivelyCollect("previousSibling")},nextSiblings:function(a){return $(a).recursivelyCollect("nextSibling")},siblings:function(a){a=$(a);return a.previousSiblings().reverse().concat(a.nextSiblings())},match:function(b,a){if(Object.isString(a)){a=new Selector(a)}return a.match($(b))},up:function(b,d,a){b=$(b);if(arguments.length==1){return $(b.parentNode)}var c=b.ancestors();return Object.isNumber(d)?c[d]:Selector.findElement(c,d,a)},down:function(b,c,a){b=$(b);if(arguments.length==1){return b.firstDescendant()}return Object.isNumber(c)?b.descendants()[c]:Element.select(b,c)[a||0]},previous:function(b,d,a){b=$(b);if(arguments.length==1){return $(Selector.handlers.previousElementSibling(b))}var c=b.previousSiblings();return Object.isNumber(d)?c[d]:Selector.findElement(c,d,a)},next:function(c,d,b){c=$(c);if(arguments.length==1){return $(Selector.handlers.nextElementSibling(c))}var a=c.nextSiblings();return Object.isNumber(d)?a[d]:Selector.findElement(a,d,b)},select:function(){var a=$A(arguments),b=$(a.shift());return Selector.findChildElements(b,a)},adjacent:function(){var a=$A(arguments),b=$(a.shift());return Selector.findChildElements(b.parentNode,a).without(b)},identify:function(b){b=$(b);var c=b.readAttribute("id"),a=arguments.callee;if(c){return c}do{c="anonymous_element_"+a.counter++}while($(c));b.writeAttribute("id",c);return c},readAttribute:function(c,a){c=$(c);if(Prototype.Browser.IE){var b=Element._attributeTranslations.read;if(b.values[a]){return b.values[a](c,a)}if(b.names[a]){a=b.names[a]}if(a.include(":")){return(!c.attributes||!c.attributes[a])?null:c.attributes[a].value}}return c.getAttribute(a)},writeAttribute:function(e,c,f){e=$(e);var b={},d=Element._attributeTranslations.write;if(typeof c=="object"){b=c}else{b[c]=Object.isUndefined(f)?true:f}for(var a in b){c=d.names[a]||a;f=b[a];if(d.values[a]){c=d.values[a](e,f)}if(f===false||f===null){e.removeAttribute(c)}else{if(f===true){e.setAttribute(c,c)}else{e.setAttribute(c,f)}}}return e},getHeight:function(a){return $(a).getDimensions().height},getWidth:function(a){return $(a).getDimensions().width},classNames:function(a){return new Element.ClassNames(a)},hasClassName:function(a,b){if(!(a=$(a))){return}var c=a.className;return(c.length>0&&(c==b||new RegExp("(^|\\s)"+b+"(\\s|$)").test(c)))},addClassName:function(a,b){if(!(a=$(a))){return}if(!a.hasClassName(b)){a.className+=(a.className?" ":"")+b}return a},removeClassName:function(a,b){if(!(a=$(a))){return}a.className=a.className.replace(new RegExp("(^|\\s+)"+b+"(\\s+|$)")," ").strip();return a},toggleClassName:function(a,b){if(!(a=$(a))){return}return a[a.hasClassName(b)?"removeClassName":"addClassName"](b)},cleanWhitespace:function(b){b=$(b);var c=b.firstChild;while(c){var a=c.nextSibling;if(c.nodeType==3&&!/\S/.test(c.nodeValue)){b.removeChild(c)}c=a}return b},empty:function(a){return $(a).innerHTML.blank()},descendantOf:function(b,a){b=$(b),a=$(a);if(b.compareDocumentPosition){return(b.compareDocumentPosition(a)&8)===8}if(a.contains){return a.contains(b)&&a!==b}while(b=b.parentNode){if(b==a){return true}}return false},scrollTo:function(a){a=$(a);var b=a.cumulativeOffset();window.scrollTo(b[0],b[1]);return a},getStyle:function(b,c){b=$(b);c=c=="float"?"cssFloat":c.camelize();var d=b.style[c];if(!d||d=="auto"){var a=document.defaultView.getComputedStyle(b,null);d=a?a[c]:null}if(c=="opacity"){return d?parseFloat(d):1}return d=="auto"?null:d},getOpacity:function(a){return $(a).getStyle("opacity")},setStyle:function(b,c){b=$(b);var e=b.style,a;if(Object.isString(c)){b.style.cssText+=";"+c;return c.include("opacity")?b.setOpacity(c.match(/opacity:\s*(\d?\.?\d*)/)[1]):b}for(var d in c){if(d=="opacity"){b.setOpacity(c[d])}else{e[(d=="float"||d=="cssFloat")?(Object.isUndefined(e.styleFloat)?"cssFloat":"styleFloat"):d]=c[d]}}return b},setOpacity:function(a,b){a=$(a);a.style.opacity=(b==1||b==="")?"":(b<0.00001)?0:b;return a},getDimensions:function(c){c=$(c);var g=c.getStyle("display");if(g!="none"&&g!=null){return{width:c.offsetWidth,height:c.offsetHeight}}var b=c.style;var f=b.visibility;var d=b.position;var a=b.display;b.visibility="hidden";b.position="absolute";b.display="block";var h=c.clientWidth;var e=c.clientHeight;b.display=a;b.position=d;b.visibility=f;return{width:h,height:e}},makePositioned:function(a){a=$(a);var b=Element.getStyle(a,"position");if(b=="static"||!b){a._madePositioned=true;a.style.position="relative";if(Prototype.Browser.Opera){a.style.top=0;a.style.left=0}}return a},undoPositioned:function(a){a=$(a);if(a._madePositioned){a._madePositioned=undefined;a.style.position=a.style.top=a.style.left=a.style.bottom=a.style.right=""}return a},makeClipping:function(a){a=$(a);if(a._overflow){return a}a._overflow=Element.getStyle(a,"overflow")||"auto";if(a._overflow!=="hidden"){a.style.overflow="hidden"}return a},undoClipping:function(a){a=$(a);if(!a._overflow){return a}a.style.overflow=a._overflow=="auto"?"":a._overflow;a._overflow=null;return a},cumulativeOffset:function(b){var a=0,c=0;do{a+=b.offsetTop||0;c+=b.offsetLeft||0;b=b.offsetParent}while(b);return Element._returnOffset(c,a)},positionedOffset:function(b){var a=0,d=0;do{a+=b.offsetTop||0;d+=b.offsetLeft||0;b=b.offsetParent;if(b){if(b.tagName.toUpperCase()=="BODY"){break}var c=Element.getStyle(b,"position");if(c!=="static"){break}}}while(b);return Element._returnOffset(d,a)},absolutize:function(b){b=$(b);if(b.getStyle("position")=="absolute"){return b}var d=b.positionedOffset();var f=d[1];var e=d[0];var c=b.clientWidth;var a=b.clientHeight;b._originalLeft=e-parseFloat(b.style.left||0);b._originalTop=f-parseFloat(b.style.top||0);b._originalWidth=b.style.width;b._originalHeight=b.style.height;b.style.position="absolute";b.style.top=f+"px";b.style.left=e+"px";b.style.width=c+"px";b.style.height=a+"px";return b},relativize:function(a){a=$(a);if(a.getStyle("position")=="relative"){return a}a.style.position="relative";var c=parseFloat(a.style.top||0)-(a._originalTop||0);var b=parseFloat(a.style.left||0)-(a._originalLeft||0);a.style.top=c+"px";a.style.left=b+"px";a.style.height=a._originalHeight;a.style.width=a._originalWidth;return a},cumulativeScrollOffset:function(b){var a=0,c=0;do{a+=b.scrollTop||0;c+=b.scrollLeft||0;b=b.parentNode}while(b);return Element._returnOffset(c,a)},getOffsetParent:function(b){b=$(b);var d=b.offsetParent,a=document.body,c=document.documentElement;if(d&&d!==c){return $(d)}if(d===c||b===c||b===a){return $(a)}while((b=b.parentNode)&&b!==a){if(Element.getStyle(b,"position")!="static"){return $(b)}}return $(a)},viewportOffset:function(d){d=$(d);var b=d,a=0,c=0;do{a+=b.offsetTop||0;c+=b.offsetLeft||0}while((b=b.getOffsetParent())!=document.body);b=d;do{if(!Prototype.Browser.Opera||(b.tagName&&(b.tagName.toUpperCase()=="BODY"))){a-=b.scrollTop||0;c-=b.scrollLeft||0}}while(b=b.parentNode);return Element._returnOffset(c,a)},clonePosition:function(b,d){var a=Object.extend({setLeft:true,setTop:true,setWidth:true,setHeight:true,offsetTop:0,offsetLeft:0},arguments[2]||{});d=$(d);var e=d.viewportOffset();b=$(b);var f=[0,0];var c=null;if(Element.getStyle(b,"position")=="absolute"){c=b.getOffsetParent();f=c.viewportOffset()}if(c==document.body){f[0]-=document.body.offsetLeft;f[1]-=document.body.offsetTop}if(a.setLeft){b.style.left=(e[0]-f[0]+a.offsetLeft)+"px"}if(a.setTop){b.style.top=(e[1]-f[1]+a.offsetTop)+"px"}if(a.setWidth){b.style.width=d.offsetWidth+"px"}if(a.setHeight){b.style.height=d.offsetHeight+"px"}return b}};Element.Methods.identify.counter=1;Object.extend(Element.Methods,{getElementsBySelector:Element.Methods.select,childElements:Element.Methods.immediateDescendants});Element._attributeTranslations={write:{names:{className:"class",htmlFor:"for"},values:{}}};if(Prototype.Browser.Opera){Element.Methods.getStyle=Element.Methods.getStyle.wrap(function(d,b,c){switch(c){case"left":case"top":case"right":case"bottom":if(d(b,"position")==="static"){return null}case"height":case"width":if(!Element.visible(b)){return null}var e=parseInt(d(b,c),10);if(e!==b["offset"+c.capitalize()]){return e+"px"}var a;if(c==="height"){a=["border-top-width","padding-top","padding-bottom","border-bottom-width"]}else{a=["border-left-width","padding-left","padding-right","border-right-width"]}return a.inject(e,function(f,g){var h=d(b,g);return h===null?f:f-parseInt(h,10)})+"px";default:return d(b,c)}});Element.Methods.readAttribute=Element.Methods.readAttribute.wrap(function(c,a,b){if(b==="title"){return a.title}return c(a,b)})}else{if(Prototype.Browser.IE){Element.Methods.getOffsetParent=Element.Methods.getOffsetParent.wrap(function(c,b){b=$(b);try{b.offsetParent}catch(f){return $(document.body)}var a=b.getStyle("position");if(a!=="static"){return c(b)}b.setStyle({position:"relative"});var d=c(b);b.setStyle({position:a});return d});$w("positionedOffset viewportOffset").each(function(a){Element.Methods[a]=Element.Methods[a].wrap(function(f,c){c=$(c);try{c.offsetParent}catch(h){return Element._returnOffset(0,0)}var b=c.getStyle("position");if(b!=="static"){return f(c)}var d=c.getOffsetParent();if(d&&d.getStyle("position")==="fixed"){d.setStyle({zoom:1})}c.setStyle({position:"relative"});var g=f(c);c.setStyle({position:b});return g})});Element.Methods.cumulativeOffset=Element.Methods.cumulativeOffset.wrap(function(b,a){try{a.offsetParent}catch(c){return Element._returnOffset(0,0)}return b(a)});Element.Methods.getStyle=function(a,b){a=$(a);b=(b=="float"||b=="cssFloat")?"styleFloat":b.camelize();var c=a.style[b];if(!c&&a.currentStyle){c=a.currentStyle[b]}if(b=="opacity"){if(c=(a.getStyle("filter")||"").match(/alpha\(opacity=(.*)\)/)){if(c[1]){return parseFloat(c[1])/100}}return 1}if(c=="auto"){if((b=="width"||b=="height")&&(a.getStyle("display")!="none")){return a["offset"+b.capitalize()]+"px"}return null}return c};Element.Methods.setOpacity=function(b,e){function f(g){return g.replace(/alpha\([^\)]*\)/gi,"")}b=$(b);var a=b.currentStyle;if((a&&!a.hasLayout)||(!a&&b.style.zoom=="normal")){b.style.zoom=1}var d=b.getStyle("filter"),c=b.style;if(e==1||e===""){(d=f(d))?c.filter=d:c.removeAttribute("filter");return b}else{if(e<0.00001){e=0}}c.filter=f(d)+"alpha(opacity="+(e*100)+")";return b};Element._attributeTranslations={read:{names:{"class":"className","for":"htmlFor"},values:{_getAttr:function(a,b){return a.getAttribute(b,2)},_getAttrNode:function(a,c){var b=a.getAttributeNode(c);return b?b.value:""},_getEv:function(a,b){b=a.getAttribute(b);return b?b.toString().slice(23,-2):null},_flag:function(a,b){return $(a).hasAttribute(b)?b:null},style:function(a){return a.style.cssText.toLowerCase()},title:function(a){return a.title}}}};Element._attributeTranslations.write={names:Object.extend({cellpadding:"cellPadding",cellspacing:"cellSpacing"},Element._attributeTranslations.read.names),values:{checked:function(a,b){a.checked=!!b},style:function(a,b){a.style.cssText=b?b:""}}};Element._attributeTranslations.has={};$w("colSpan rowSpan vAlign dateTime accessKey tabIndex encType maxLength readOnly longDesc frameBorder").each(function(a){Element._attributeTranslations.write.names[a.toLowerCase()]=a;Element._attributeTranslations.has[a.toLowerCase()]=a});(function(a){Object.extend(a,{href:a._getAttr,src:a._getAttr,type:a._getAttr,action:a._getAttrNode,disabled:a._flag,checked:a._flag,readonly:a._flag,multiple:a._flag,onload:a._getEv,onunload:a._getEv,onclick:a._getEv,ondblclick:a._getEv,onmousedown:a._getEv,onmouseup:a._getEv,onmouseover:a._getEv,onmousemove:a._getEv,onmouseout:a._getEv,onfocus:a._getEv,onblur:a._getEv,onkeypress:a._getEv,onkeydown:a._getEv,onkeyup:a._getEv,onsubmit:a._getEv,onreset:a._getEv,onselect:a._getEv,onchange:a._getEv})})(Element._attributeTranslations.read.values)}else{if(Prototype.Browser.Gecko&&/rv:1\.8\.0/.test(navigator.userAgent)){Element.Methods.setOpacity=function(a,b){a=$(a);a.style.opacity=(b==1)?0.999999:(b==="")?"":(b<0.00001)?0:b;return a}}else{if(Prototype.Browser.WebKit){Element.Methods.setOpacity=function(a,b){a=$(a);a.style.opacity=(b==1||b==="")?"":(b<0.00001)?0:b;if(b==1){if(a.tagName.toUpperCase()=="IMG"&&a.width){a.width++;a.width--}else{try{var d=document.createTextNode(" ");a.appendChild(d);a.removeChild(d)}catch(c){}}}return a};Element.Methods.cumulativeOffset=function(b){var a=0,c=0;do{a+=b.offsetTop||0;c+=b.offsetLeft||0;if(b.offsetParent==document.body){if(Element.getStyle(b,"position")=="absolute"){break}}b=b.offsetParent}while(b);return Element._returnOffset(c,a)}}}}}if(Prototype.Browser.IE||Prototype.Browser.Opera){Element.Methods.update=function(b,c){b=$(b);if(c&&c.toElement){c=c.toElement()}if(Object.isElement(c)){return b.update().insert(c)}c=Object.toHTML(c);var a=b.tagName.toUpperCase();if(a in Element._insertionTranslations.tags){$A(b.childNodes).each(function(d){b.removeChild(d)});Element._getContentFromAnonymousElement(a,c.stripScripts()).each(function(d){b.appendChild(d)})}else{b.innerHTML=c.stripScripts()}c.evalScripts.bind(c).defer();return b}}if("outerHTML"in document.createElement("div")){Element.Methods.replace=function(c,e){c=$(c);if(e&&e.toElement){e=e.toElement()}if(Object.isElement(e)){c.parentNode.replaceChild(e,c);return c}e=Object.toHTML(e);var d=c.parentNode,b=d.tagName.toUpperCase();if(Element._insertionTranslations.tags[b]){var f=c.next();var a=Element._getContentFromAnonymousElement(b,e.stripScripts());d.removeChild(c);if(f){a.each(function(g){d.insertBefore(g,f)})}else{a.each(function(g){d.appendChild(g)})}}else{c.outerHTML=e.stripScripts()}e.evalScripts.bind(e).defer();return c}}Element._returnOffset=function(b,c){var a=[b,c];a.left=b;a.top=c;return a};Element._getContentFromAnonymousElement=function(c,b){var d=new Element("div"),a=Element._insertionTranslations.tags[c];if(a){d.innerHTML=a[0]+b+a[1];a[2].times(function(){d=d.firstChild})}else{d.innerHTML=b}return $A(d.childNodes)};Element._insertionTranslations={before:function(a,b){a.parentNode.insertBefore(b,a)},top:function(a,b){a.insertBefore(b,a.firstChild)},bottom:function(a,b){a.appendChild(b)},after:function(a,b){a.parentNode.insertBefore(b,a.nextSibling)},tags:{TABLE:["<table>","</table>",1],TBODY:["<table><tbody>","</tbody></table>",2],TR:["<table><tbody><tr>","</tr></tbody></table>",3],TD:["<table><tbody><tr><td>","</td></tr></tbody></table>",4],SELECT:["<select>","</select>",1]}};(function(){Object.extend(this.tags,{THEAD:this.tags.TBODY,TFOOT:this.tags.TBODY,TH:this.tags.TD})}).call(Element._insertionTranslations);Element.Methods.Simulated={hasAttribute:function(a,c){c=Element._attributeTranslations.has[c]||c;var b=$(a).getAttributeNode(c);return!!(b&&b.specified)}};Element.Methods.ByTag={};Object.extend(Element,Element.Methods);if(!Prototype.BrowserFeatures.ElementExtensions&&document.createElement("div")["__proto__"]){window.HTMLElement={};window.HTMLElement.prototype=document.createElement("div")["__proto__"];Prototype.BrowserFeatures.ElementExtensions=true}Element.extend=(function(){if(Prototype.BrowserFeatures.SpecificElementExtensions){return Prototype.K}var a={},b=Element.Methods.ByTag;var c=Object.extend(function(f){if(!f||f._extendedByPrototype||f.nodeType!=1||f==window){return f}var d=Object.clone(a),e=f.tagName.toUpperCase(),h,g;if(b[e]){Object.extend(d,b[e])}for(h in d){g=d[h];if(Object.isFunction(g)&&!(h in f)){f[h]=g.methodize()}}f._extendedByPrototype=Prototype.emptyFunction;return f},{refresh:function(){if(!Prototype.BrowserFeatures.ElementExtensions){Object.extend(a,Element.Methods);Object.extend(a,Element.Methods.Simulated)}}});c.refresh();return c})();Element.hasAttribute=function(a,b){if(a.hasAttribute){return a.hasAttribute(b)}return Element.Methods.Simulated.hasAttribute(a,b)};Element.addMethods=function(c){var h=Prototype.BrowserFeatures,d=Element.Methods.ByTag;if(!c){Object.extend(Form,Form.Methods);Object.extend(Form.Element,Form.Element.Methods);Object.extend(Element.Methods.ByTag,{FORM:Object.clone(Form.Methods),INPUT:Object.clone(Form.Element.Methods),SELECT:Object.clone(Form.Element.Methods),TEXTAREA:Object.clone(Form.Element.Methods)})}if(arguments.length==2){var b=c;c=arguments[1]}if(!b){Object.extend(Element.Methods,c||{})}else{if(Object.isArray(b)){b.each(g)}else{g(b)}}function g(j){j=j.toUpperCase();if(!Element.Methods.ByTag[j]){Element.Methods.ByTag[j]={}}Object.extend(Element.Methods.ByTag[j],c)}function a(l,k,j){j=j||false;for(var n in l){var m=l[n];if(!Object.isFunction(m)){continue}if(!j||!(n in k)){k[n]=m.methodize()}}}function e(l){var j;var k={OPTGROUP:"OptGroup",TEXTAREA:"TextArea",P:"Paragraph",FIELDSET:"FieldSet",UL:"UList",OL:"OList",DL:"DList",DIR:"Directory",H1:"Heading",H2:"Heading",H3:"Heading",H4:"Heading",H5:"Heading",H6:"Heading",Q:"Quote",INS:"Mod",DEL:"Mod",A:"Anchor",IMG:"Image",CAPTION:"TableCaption",COL:"TableCol",COLGROUP:"TableCol",THEAD:"TableSection",TFOOT:"TableSection",TBODY:"TableSection",TR:"TableRow",TH:"TableCell",TD:"TableCell",FRAMESET:"FrameSet",IFRAME:"IFrame"};if(k[l]){j="HTML"+k[l]+"Element"}if(window[j]){return window[j]}j="HTML"+l+"Element";if(window[j]){return window[j]}j="HTML"+l.capitalize()+"Element";if(window[j]){return window[j]}window[j]={};window[j].prototype=document.createElement(l)["__proto__"];return window[j]}if(h.ElementExtensions){a(Element.Methods,HTMLElement.prototype);a(Element.Methods.Simulated,HTMLElement.prototype,true)}if(h.SpecificElementExtensions){for(var i in Element.Methods.ByTag){var f=e(i);if(Object.isUndefined(f)){continue}a(d[i],f.prototype)}}Object.extend(Element,Element.Methods);delete Element.ByTag;if(Element.extend.refresh){Element.extend.refresh()}Element.cache={}};document.viewport={getDimensions:function(){var a={},b=Prototype.Browser;$w("width height").each(function(e){var c=e.capitalize();if(b.WebKit&&!document.evaluate){a[e]=self["inner"+c]}else{if(b.Opera&&parseFloat(window.opera.version())<9.5){a[e]=document.body["client"+c]}else{a[e]=document.documentElement["client"+c]}}});return a},getWidth:function(){return this.getDimensions().width},getHeight:function(){return this.getDimensions().height},getScrollOffsets:function(){return Element._returnOffset(window.pageXOffset||document.documentElement.scrollLeft||document.body.scrollLeft,window.pageYOffset||document.documentElement.scrollTop||document.body.scrollTop)}};var Selector=Class.create({initialize:function(a){this.expression=a.strip();if(this.shouldUseSelectorsAPI()){this.mode="selectorsAPI"}else{if(this.shouldUseXPath()){this.mode="xpath";this.compileXPathMatcher()}else{this.mode="normal";this.compileMatcher()}}},shouldUseXPath:function(){if(!Prototype.BrowserFeatures.XPath){return false}var a=this.expression;if(Prototype.Browser.WebKit&&(a.include("-of-type")||a.include(":empty"))){return false}if((/(\[[\w-]*?:|:checked)/).test(a)){return false}return true},shouldUseSelectorsAPI:function(){if(!Prototype.BrowserFeatures.SelectorsAPI){return false}if(!Selector._div){Selector._div=new Element("div")}try{Selector._div.querySelector(this.expression)}catch(a){return false}return true},compileMatcher:function(){var e=this.expression,ps=Selector.patterns,h=Selector.handlers,c=Selector.criteria,le,p,m;if(Selector._cache[e]){this.matcher=Selector._cache[e];return}this.matcher=["this.matcher = function(root) {","var r = root, h = Selector.handlers, c = false, n;"];while(e&&le!=e&&(/\S/).test(e)){le=e;for(var i in ps){p=ps[i];if(m=e.match(p)){this.matcher.push(Object.isFunction(c[i])?c[i](m):new Template(c[i]).evaluate(m));e=e.replace(m[0],"");break}}}this.matcher.push("return h.unique(n);\n}");eval(this.matcher.join("\n"));Selector._cache[this.expression]=this.matcher},compileXPathMatcher:function(){var f=this.expression,g=Selector.patterns,b=Selector.xpath,d,a;if(Selector._cache[f]){this.xpath=Selector._cache[f];return}this.matcher=[".//*"];while(f&&d!=f&&(/\S/).test(f)){d=f;for(var c in g){if(a=f.match(g[c])){this.matcher.push(Object.isFunction(b[c])?b[c](a):new Template(b[c]).evaluate(a));f=f.replace(a[0],"");break}}}this.xpath=this.matcher.join("");Selector._cache[this.expression]=this.xpath},findElements:function(a){a=a||document;var c=this.expression,b;switch(this.mode){case"selectorsAPI":if(a!==document){var d=a.id,f=$(a).identify();c="#"+f+" "+c}b=$A(a.querySelectorAll(c)).map(Element.extend);a.id=d;return b;case"xpath":return document._getElementsByXPath(this.xpath,a);default:return this.matcher(a)}},match:function(j){this.tokens=[];var o=this.expression,a=Selector.patterns,f=Selector.assertions;var b,d,g;while(o&&b!==o&&(/\S/).test(o)){b=o;for(var k in a){d=a[k];if(g=o.match(d)){if(f[k]){this.tokens.push([k,Object.clone(g)]);o=o.replace(g[0],"")}else{return this.findElements(document).include(j)}}}}var n=true,c,l;for(var k=0,h;h=this.tokens[k];k++){c=h[0],l=h[1];if(!Selector.assertions[c](j,l)){n=false;break}}return n},toString:function(){return this.expression},inspect:function(){return"#<Selector:"+this.expression.inspect()+">"}});Object.extend(Selector,{_cache:{},xpath:{descendant:"//*",child:"/*",adjacent:"/following-sibling::*[1]",laterSibling:"/following-sibling::*",tagName:function(a){if(a[1]=="*"){return""}return"[local-name()='"+a[1].toLowerCase()+"' or local-name()='"+a[1].toUpperCase()+"']"},className:"[contains(concat(' ', @class, ' '), ' #{1} ')]",id:"[@id='#{1}']",attrPresence:function(a){a[1]=a[1].toLowerCase();return new Template("[@#{1}]").evaluate(a)},attr:function(a){a[1]=a[1].toLowerCase();a[3]=a[5]||a[6];return new Template(Selector.xpath.operators[a[2]]).evaluate(a)},pseudo:function(a){var b=Selector.xpath.pseudos[a[1]];if(!b){return""}if(Object.isFunction(b)){return b(a)}return new Template(Selector.xpath.pseudos[a[1]]).evaluate(a)},operators:{"=":"[@#{1}='#{3}']","!=":"[@#{1}!='#{3}']","^=":"[starts-with(@#{1}, '#{3}')]","$=":"[substring(@#{1}, (string-length(@#{1}) - string-length('#{3}') + 1))='#{3}']","*=":"[contains(@#{1}, '#{3}')]","~=":"[contains(concat(' ', @#{1}, ' '), ' #{3} ')]","|=":"[contains(concat('-', @#{1}, '-'), '-#{3}-')]"},pseudos:{"first-child":"[not(preceding-sibling::*)]","last-child":"[not(following-sibling::*)]","only-child":"[not(preceding-sibling::* or following-sibling::*)]",empty:"[count(*) = 0 and (count(text()) = 0)]",checked:"[@checked]",disabled:"[(@disabled) and (@type!='hidden')]",enabled:"[not(@disabled) and (@type!='hidden')]",not:function(b){var j=b[6],h=Selector.patterns,a=Selector.xpath,f,c;var g=[];while(j&&f!=j&&(/\S/).test(j)){f=j;for(var d in h){if(b=j.match(h[d])){c=Object.isFunction(a[d])?a[d](b):new Template(a[d]).evaluate(b);g.push("("+c.substring(1,c.length-1)+")");j=j.replace(b[0],"");break}}}return"[not("+g.join(" and ")+")]"},"nth-child":function(a){return Selector.xpath.pseudos.nth("(count(./preceding-sibling::*) + 1) ",a)},"nth-last-child":function(a){return Selector.xpath.pseudos.nth("(count(./following-sibling::*) + 1) ",a)},"nth-of-type":function(a){return Selector.xpath.pseudos.nth("position() ",a)},"nth-last-of-type":function(a){return Selector.xpath.pseudos.nth("(last() + 1 - position()) ",a)},"first-of-type":function(a){a[6]="1";return Selector.xpath.pseudos["nth-of-type"](a)},"last-of-type":function(a){a[6]="1";return Selector.xpath.pseudos["nth-last-of-type"](a)},"only-of-type":function(a){var b=Selector.xpath.pseudos;return b["first-of-type"](a)+b["last-of-type"](a)},nth:function(g,e){var h,i=e[6],d;if(i=="even"){i="2n+0"}if(i=="odd"){i="2n+1"}if(h=i.match(/^(\d+)$/)){return"["+g+"= "+h[1]+"]"}if(h=i.match(/^(-?\d*)?n(([+-])(\d+))?/)){if(h[1]=="-"){h[1]=-1}var f=h[1]?Number(h[1]):1;var c=h[2]?Number(h[2]):0;d="[((#{fragment} - #{b}) mod #{a} = 0) and ((#{fragment} - #{b}) div #{a} >= 0)]";return new Template(d).evaluate({fragment:g,a:f,b:c})}}}},criteria:{tagName:'n = h.tagName(n, r, "#{1}", c);      c = false;',className:'n = h.className(n, r, "#{1}", c);    c = false;',id:'n = h.id(n, r, "#{1}", c);           c = false;',attrPresence:'n = h.attrPresence(n, r, "#{1}", c); c = false;',attr:function(a){a[3]=(a[5]||a[6]);return new Template('n = h.attr(n, r, "#{1}", "#{3}", "#{2}", c); c = false;').evaluate(a)},pseudo:function(a){if(a[6]){a[6]=a[6].replace(/"/g,'\\"')}return new Template('n = h.pseudo(n, "#{1}", "#{6}", r, c); c = false;').evaluate(a)},descendant:'c = "descendant";',child:'c = "child";',adjacent:'c = "adjacent";',laterSibling:'c = "laterSibling";'},patterns:{laterSibling:/^\s*~\s*/,child:/^\s*>\s*/,adjacent:/^\s*\+\s*/,descendant:/^\s/,tagName:/^\s*(\*|[\w\-]+)(\b|$)?/,id:/^#([\w\-\*]+)(\b|$)/,className:/^\.([\w\-\*]+)(\b|$)/,pseudo:/^:((first|last|nth|nth-last|only)(-child|-of-type)|empty|checked|(en|dis)abled|not)(\((.*?)\))?(\b|$|(?=\s|[:+~>]))/,attrPresence:/^\[((?:[\w]+:)?[\w]+)\]/,attr:/\[((?:[\w-]*:)?[\w-]+)\s*(?:([!^$*~|]?=)\s*((['"])([^\4]*?)\4|([^'"][^\]]*?)))?\]/},assertions:{tagName:function(a,b){return b[1].toUpperCase()==a.tagName.toUpperCase()},className:function(a,b){return Element.hasClassName(a,b[1])},id:function(a,b){return a.id===b[1]},attrPresence:function(a,b){return Element.hasAttribute(a,b[1])},attr:function(b,c){var a=Element.readAttribute(b,c[1]);return a&&Selector.operators[c[2]](a,c[5]||c[6])}},handlers:{concat:function(d,c){for(var e=0,f;f=c[e];e++){d.push(f)}return d},mark:function(a){var d=Prototype.emptyFunction;for(var b=0,c;c=a[b];b++){c._countedByPrototype=d}return a},unmark:function(a){for(var b=0,c;c=a[b];b++){c._countedByPrototype=undefined}return a},index:function(a,d,g){a._countedByPrototype=Prototype.emptyFunction;if(d){for(var b=a.childNodes,e=b.length-1,c=1;e>=0;e--){var f=b[e];if(f.nodeType==1&&(!g||f._countedByPrototype)){f.nodeIndex=c++}}}else{for(var e=0,c=1,b=a.childNodes;f=b[e];e++){if(f.nodeType==1&&(!g||f._countedByPrototype)){f.nodeIndex=c++}}}},unique:function(b){if(b.length==0){return b}var d=[],e;for(var c=0,a=b.length;c<a;c++){if(!(e=b[c])._countedByPrototype){e._countedByPrototype=Prototype.emptyFunction;d.push(Element.extend(e))}}return Selector.handlers.unmark(d)},descendant:function(a){var d=Selector.handlers;for(var c=0,b=[],e;e=a[c];c++){d.concat(b,e.getElementsByTagName("*"))}return b},child:function(a){var e=Selector.handlers;for(var d=0,c=[],f;f=a[d];d++){for(var b=0,g;g=f.childNodes[b];b++){if(g.nodeType==1&&g.tagName!="!"){c.push(g)}}}return c},adjacent:function(a){for(var c=0,b=[],e;e=a[c];c++){var d=this.nextElementSibling(e);if(d){b.push(d)}}return b},laterSibling:function(a){var d=Selector.handlers;for(var c=0,b=[],e;e=a[c];c++){d.concat(b,Element.nextSiblings(e))}return b},nextElementSibling:function(a){while(a=a.nextSibling){if(a.nodeType==1){return a}}return null},previousElementSibling:function(a){while(a=a.previousSibling){if(a.nodeType==1){return a}}return null},tagName:function(a,j,c,b){var k=c.toUpperCase();var e=[],g=Selector.handlers;if(a){if(b){if(b=="descendant"){for(var f=0,d;d=a[f];f++){g.concat(e,d.getElementsByTagName(c))}return e}else{a=this[b](a)}if(c=="*"){return a}}for(var f=0,d;d=a[f];f++){if(d.tagName.toUpperCase()===k){e.push(d)}}return e}else{return j.getElementsByTagName(c)}},id:function(b,a,j,f){var g=$(j),d=Selector.handlers;if(!g){return[]}if(!b&&a==document){return[g]}if(b){if(f){if(f=="child"){for(var c=0,e;e=b[c];c++){if(g.parentNode==e){return[g]}}}else{if(f=="descendant"){for(var c=0,e;e=b[c];c++){if(Element.descendantOf(g,e)){return[g]}}}else{if(f=="adjacent"){for(var c=0,e;e=b[c];c++){if(Selector.handlers.previousElementSibling(g)==e){return[g]}}}else{b=d[f](b)}}}}for(var c=0,e;e=b[c];c++){if(e==g){return[g]}}return[]}return(g&&Element.descendantOf(g,a))?[g]:[]},className:function(b,a,c,d){if(b&&d){b=this[d](b)}return Selector.handlers.byClassName(b,a,c)},byClassName:function(c,b,f){if(!c){c=Selector.handlers.descendant([b])}var h=" "+f+" ";for(var e=0,d=[],g,a;g=c[e];e++){a=g.className;if(a.length==0){continue}if(a==f||(" "+a+" ").include(h)){d.push(g)}}return d},attrPresence:function(c,b,a,g){if(!c){c=b.getElementsByTagName("*")}if(c&&g){c=this[g](c)}var e=[];for(var d=0,f;f=c[d];d++){if(Element.hasAttribute(f,a)){e.push(f)}}return e},attr:function(a,j,h,k,c,b){if(!a){a=j.getElementsByTagName("*")}if(a&&b){a=this[b](a)}var l=Selector.operators[c],f=[];for(var e=0,d;d=a[e];e++){var g=Element.readAttribute(d,h);if(g===null){continue}if(l(g,k)){f.push(d)}}return f},pseudo:function(b,c,e,a,d){if(b&&d){b=this[d](b)}if(!b){b=a.getElementsByTagName("*")}return Selector.pseudos[c](b,e,a)}},pseudos:{"first-child":function(b,f,a){for(var d=0,c=[],e;e=b[d];d++){if(Selector.handlers.previousElementSibling(e)){continue}c.push(e)}return c},"last-child":function(b,f,a){for(var d=0,c=[],e;e=b[d];d++){if(Selector.handlers.nextElementSibling(e)){continue}c.push(e)}return c},"only-child":function(b,g,a){var e=Selector.handlers;for(var d=0,c=[],f;f=b[d];d++){if(!e.previousElementSibling(f)&&!e.nextElementSibling(f)){c.push(f)}}return c},"nth-child":function(b,c,a){return Selector.pseudos.nth(b,c,a)},"nth-last-child":function(b,c,a){return Selector.pseudos.nth(b,c,a,true)},"nth-of-type":function(b,c,a){return Selector.pseudos.nth(b,c,a,false,true)},"nth-last-of-type":function(b,c,a){return Selector.pseudos.nth(b,c,a,true,true)},"first-of-type":function(b,c,a){return Selector.pseudos.nth(b,"1",a,false,true)},"last-of-type":function(b,c,a){return Selector.pseudos.nth(b,"1",a,true,true)},"only-of-type":function(b,d,a){var c=Selector.pseudos;return c["last-of-type"](c["first-of-type"](b,d,a),d,a)},getIndices:function(d,c,e){if(d==0){return c>0?[c]:[]}return $R(1,e).inject([],function(a,b){if(0==(b-c)%d&&(b-c)/d>=0){a.push(b)}return a})},nth:function(c,s,u,r,e){if(c.length==0){return[]}if(s=="even"){s="2n+0"}if(s=="odd"){s="2n+1"}var q=Selector.handlers,p=[],d=[],g;q.mark(c);for(var o=0,f;f=c[o];o++){if(!f.parentNode._countedByPrototype){q.index(f.parentNode,r,e);d.push(f.parentNode)}}if(s.match(/^\d+$/)){s=Number(s);for(var o=0,f;f=c[o];o++){if(f.nodeIndex==s){p.push(f)}}}else{if(g=s.match(/^(-?\d*)?n(([+-])(\d+))?/)){if(g[1]=="-"){g[1]=-1}var v=g[1]?Number(g[1]):1;var t=g[2]?Number(g[2]):0;var w=Selector.pseudos.getIndices(v,t,c.length);for(var o=0,f,k=w.length;f=c[o];o++){for(var n=0;n<k;n++){if(f.nodeIndex==w[n]){p.push(f)}}}}}q.unmark(c);q.unmark(d);return p},empty:function(b,f,a){for(var d=0,c=[],e;e=b[d];d++){if(e.tagName=="!"||e.firstChild){continue}c.push(e)}return c},not:function(a,d,k){var g=Selector.handlers,l,c;var j=new Selector(d).findElements(k);g.mark(j);for(var f=0,e=[],b;b=a[f];f++){if(!b._countedByPrototype){e.push(b)}}g.unmark(j);return e},enabled:function(b,f,a){for(var d=0,c=[],e;e=b[d];d++){if(!e.disabled&&(!e.type||e.type!=="hidden")){c.push(e)}}return c},disabled:function(b,f,a){for(var d=0,c=[],e;e=b[d];d++){if(e.disabled){c.push(e)}}return c},checked:function(b,f,a){for(var d=0,c=[],e;e=b[d];d++){if(e.checked){c.push(e)}}return c}},operators:{"=":function(b,a){return b==a},"!=":function(b,a){return b!=a},"^=":function(b,a){return b==a||b&&b.startsWith(a)},"$=":function(b,a){return b==a||b&&b.endsWith(a)},"*=":function(b,a){return b==a||b&&b.include(a)},"$=":function(b,a){return b.endsWith(a)},"*=":function(b,a){return b.include(a)},"~=":function(b,a){return(" "+b+" ").include(" "+a+" ")},"|=":function(b,a){return("-"+(b||"").toUpperCase()+"-").include("-"+(a||"").toUpperCase()+"-")}},split:function(b){var a=[];b.scan(/(([\w#:.~>+()\s-]+|\*|\[.*?\])+)\s*(,|$)/,function(c){a.push(c[1].strip())});return a},matchElements:function(f,g){var e=$$(g),d=Selector.handlers;d.mark(e);for(var c=0,b=[],a;a=f[c];c++){if(a._countedByPrototype){b.push(a)}}d.unmark(e);return b},findElement:function(b,c,a){if(Object.isNumber(c)){a=c;c=false}return Selector.matchElements(b,c||"*")[a||0]},findChildElements:function(e,g){g=Selector.split(g.join(","));var d=[],f=Selector.handlers;for(var c=0,b=g.length,a;c<b;c++){a=new Selector(g[c].strip());f.concat(d,a.findElements(e))}return(b>1)?f.unique(d):d}});if(Prototype.Browser.IE){Object.extend(Selector.handlers,{concat:function(d,c){for(var e=0,f;f=c[e];e++){if(f.tagName!=="!"){d.push(f)}}return d},unmark:function(a){for(var b=0,c;c=a[b];b++){c.removeAttribute("_countedByPrototype")}return a}})}function $$(){return Selector.findChildElements(document,$A(arguments))}var Form={reset:function(a){$(a).reset();return a},serializeElements:function(g,b){if(typeof b!="object"){b={hash:!!b}}else{if(Object.isUndefined(b.hash)){b.hash=true}}var c,f,a=false,e=b.submit;var d=g.inject({},function(h,i){if(!i.disabled&&i.name){c=i.name;f=$(i).getValue();if(f!=null&&i.type!="file"&&(i.type!="submit"||(!a&&e!==false&&(!e||c==e)&&(a=true)))){if(c in h){if(!Object.isArray(h[c])){h[c]=[h[c]]}h[c].push(f)}else{h[c]=f}}}return h});return b.hash?d:Object.toQueryString(d)}};Form.Methods={serialize:function(b,a){return Form.serializeElements(Form.getElements(b),a)},getElements:function(a){return $A($(a).getElementsByTagName("*")).inject([],function(b,c){if(Form.Element.Serializers[c.tagName.toLowerCase()]){b.push(Element.extend(c))}return b})},getInputs:function(g,c,d){g=$(g);var a=g.getElementsByTagName("input");if(!c&&!d){return $A(a).map(Element.extend)}for(var e=0,h=[],f=a.length;e<f;e++){var b=a[e];if((c&&b.type!=c)||(d&&b.name!=d)){continue}h.push(Element.extend(b))}return h},disable:function(a){a=$(a);Form.getElements(a).invoke("disable");return a},enable:function(a){a=$(a);Form.getElements(a).invoke("enable");return a},findFirstElement:function(b){var c=$(b).getElements().findAll(function(d){return"hidden"!=d.type&&!d.disabled});var a=c.findAll(function(d){return d.hasAttribute("tabIndex")&&d.tabIndex>=0}).sortBy(function(d){return d.tabIndex}).first();return a?a:c.find(function(d){return["input","select","textarea"].include(d.tagName.toLowerCase())})},focusFirstElement:function(a){a=$(a);a.findFirstElement().activate();return a},request:function(b,a){b=$(b),a=Object.clone(a||{});var d=a.parameters,c=b.readAttribute("action")||"";if(c.blank()){c=window.location.href}a.parameters=b.serialize(true);if(d){if(Object.isString(d)){d=d.toQueryParams()}Object.extend(a.parameters,d)}if(b.hasAttribute("method")&&!a.method){a.method=b.method}return new Ajax.Request(c,a)}};Form.Element={focus:function(a){$(a).focus();return a},select:function(a){$(a).select();return a}};Form.Element.Methods={serialize:function(a){a=$(a);if(!a.disabled&&a.name){var b=a.getValue();if(b!=undefined){var c={};c[a.name]=b;return Object.toQueryString(c)}}return""},getValue:function(a){a=$(a);var b=a.tagName.toLowerCase();return Form.Element.Serializers[b](a)},setValue:function(a,b){a=$(a);var c=a.tagName.toLowerCase();Form.Element.Serializers[c](a,b);return a},clear:function(a){$(a).value="";return a},present:function(a){return $(a).value!=""},activate:function(a){a=$(a);try{a.focus();if(a.select&&(a.tagName.toLowerCase()!="input"||!["button","reset","submit"].include(a.type))){a.select()}}catch(b){}return a},disable:function(a){a=$(a);a.disabled=true;return a},enable:function(a){a=$(a);a.disabled=false;return a}};var Field=Form.Element;var $F=Form.Element.Methods.getValue;Form.Element.Serializers={input:function(a,b){switch(a.type.toLowerCase()){case"checkbox":case"radio":return Form.Element.Serializers.inputSelector(a,b);default:return Form.Element.Serializers.textarea(a,b)}},inputSelector:function(a,b){if(Object.isUndefined(b)){return a.checked?a.value:null}else{a.checked=!!b}},textarea:function(a,b){if(Object.isUndefined(b)){return a.value}else{a.value=b}},select:function(c,f){if(Object.isUndefined(f)){return this[c.type=="select-one"?"selectOne":"selectMany"](c)}else{var b,d,g=!Object.isArray(f);for(var a=0,e=c.length;a<e;a++){b=c.options[a];d=this.optionValue(b);if(g){if(d==f){b.selected=true;return}}else{b.selected=f.include(d)}}}},selectOne:function(b){var a=b.selectedIndex;return a>=0?this.optionValue(b.options[a]):null},selectMany:function(d){var a,e=d.length;if(!e){return null}for(var c=0,a=[];c<e;c++){var b=d.options[c];if(b.selected){a.push(this.optionValue(b))}}return a},optionValue:function(a){return Element.extend(a).hasAttribute("value")?a.value:a.text}};Abstract.TimedObserver=Class.create(PeriodicalExecuter,{initialize:function($super,a,b,c){$super(c,b);this.element=$(a);this.lastValue=this.getValue()},execute:function(){var a=this.getValue();if(Object.isString(this.lastValue)&&Object.isString(a)?this.lastValue!=a:String(this.lastValue)!=String(a)){this.callback(this.element,a);this.lastValue=a}}});Form.Element.Observer=Class.create(Abstract.TimedObserver,{getValue:function(){return Form.Element.getValue(this.element)}});Form.Observer=Class.create(Abstract.TimedObserver,{getValue:function(){return Form.serialize(this.element)}});Abstract.EventObserver=Class.create({initialize:function(a,b){this.element=$(a);this.callback=b;this.lastValue=this.getValue();if(this.element.tagName.toLowerCase()=="form"){this.registerFormCallbacks()}else{this.registerCallback(this.element)}},onElementEvent:function(){var a=this.getValue();if(this.lastValue!=a){this.callback(this.element,a);this.lastValue=a}},registerFormCallbacks:function(){Form.getElements(this.element).each(this.registerCallback,this)},registerCallback:function(a){if(a.type){switch(a.type.toLowerCase()){case"checkbox":case"radio":Event.observe(a,"click",this.onElementEvent.bind(this));break;default:Event.observe(a,"change",this.onElementEvent.bind(this));break}}}});Form.Element.EventObserver=Class.create(Abstract.EventObserver,{getValue:function(){return Form.Element.getValue(this.element)}});Form.EventObserver=Class.create(Abstract.EventObserver,{getValue:function(){return Form.serialize(this.element)}});if(!window.Event){var Event={}}Object.extend(Event,{KEY_BACKSPACE:8,KEY_TAB:9,KEY_RETURN:13,KEY_ESC:27,KEY_LEFT:37,KEY_UP:38,KEY_RIGHT:39,KEY_DOWN:40,KEY_DELETE:46,KEY_HOME:36,KEY_END:35,KEY_PAGEUP:33,KEY_PAGEDOWN:34,KEY_INSERT:45,cache:{},relatedTarget:function(b){var a;switch(b.type){case"mouseover":a=b.fromElement;break;case"mouseout":a=b.toElement;break;default:return null}return Element.extend(a)}});Event.Methods=(function(){var a;if(Prototype.Browser.IE){var b={0:1,1:4,2:2};a=function(d,c){return d.button==b[c]}}else{if(Prototype.Browser.WebKit){a=function(d,c){switch(c){case 0:return d.which==1&&!d.metaKey;case 1:return d.which==1&&d.metaKey;default:return false}}}else{a=function(d,c){return d.which?(d.which===c+1):(d.button===c)}}}return{isLeftClick:function(c){return a(c,0)},isMiddleClick:function(c){return a(c,1)},isRightClick:function(c){return a(c,2)},element:function(e){e=Event.extend(e);var d=e.target,c=e.type,f=e.currentTarget;if(f&&f.tagName){if(c==="load"||c==="error"||(c==="click"&&f.tagName.toLowerCase()==="input"&&f.type==="radio")){d=f}}if(d.nodeType==Node.TEXT_NODE){d=d.parentNode}return Element.extend(d)},findElement:function(d,f){var c=Event.element(d);if(!f){return c}var e=[c].concat(c.ancestors());return Selector.findElement(e,f,0)},pointer:function(e){var d=document.documentElement,c=document.body||{scrollLeft:0,scrollTop:0};return{x:e.pageX||(e.clientX+(d.scrollLeft||c.scrollLeft)-(d.clientLeft||0)),y:e.pageY||(e.clientY+(d.scrollTop||c.scrollTop)-(d.clientTop||0))}},pointerX:function(c){return Event.pointer(c).x},pointerY:function(c){return Event.pointer(c).y},stop:function(c){Event.extend(c);c.preventDefault();c.stopPropagation();c.stopped=true}}})();Event.extend=(function(){var a=Object.keys(Event.Methods).inject({},function(b,c){b[c]=Event.Methods[c].methodize();return b});if(Prototype.Browser.IE){Object.extend(a,{stopPropagation:function(){this.cancelBubble=true},preventDefault:function(){this.returnValue=false},inspect:function(){return"[object Event]"}});return function(b){if(!b){return false}if(b._extendedByPrototype){return b}b._extendedByPrototype=Prototype.emptyFunction;var c=Event.pointer(b);Object.extend(b,{target:b.srcElement,relatedTarget:Event.relatedTarget(b),pageX:c.x,pageY:c.y});return Object.extend(b,a)}}else{Event.prototype=Event.prototype||document.createEvent("HTMLEvents")["__proto__"];Object.extend(Event.prototype,a);return Prototype.K}})();Object.extend(Event,(function(){var b=Event.cache;function c(j){if(j._prototypeEventID){return j._prototypeEventID[0]}arguments.callee.id=arguments.callee.id||1;return j._prototypeEventID=[++arguments.callee.id]}function g(j){if(j&&j.include(":")){return"dataavailable"}return j}function a(j){return b[j]=b[j]||{}}function f(l,j){var k=a(l);return k[j]=k[j]||[]}function h(k,j,l){var o=c(k);var n=f(o,j);if(n.pluck("handler").include(l)){return false}var m=function(p){if(!Event||!Event.extend||(p.eventName&&p.eventName!=j)){return false}Event.extend(p);l.call(k,p)};m.handler=l;n.push(m);return m}function i(m,j,k){var l=f(m,j);return l.find(function(n){return n.handler==k})}function d(m,j,k){var l=a(m);if(!l[j]){return false}l[j]=l[j].without(i(m,j,k))}function e(){for(var k in b){for(var j in b[k]){b[k][j]=null}}}if(window.attachEvent){window.attachEvent("onunload",e)}if(Prototype.Browser.WebKit){window.addEventListener("unload",Prototype.emptyFunction,false)}return{observe:function(l,j,m){l=$(l);var k=g(j);var n=h(l,j,m);if(!n){return l}if(l.addEventListener){l.addEventListener(k,n,false)}else{l.attachEvent("on"+k,n)}return l},stopObserving:function(l,j,m){l=$(l);var o=c(l),k=g(j);if(!m&&j){f(o,j).each(function(p){l.stopObserving(j,p.handler)});return l}else{if(!j){Object.keys(a(o)).each(function(p){l.stopObserving(p)});return l}}var n=i(o,j,m);if(!n){return l}if(l.removeEventListener){l.removeEventListener(k,n,false)}else{l.detachEvent("on"+k,n)}d(o,j,m);return l},fire:function(l,k,j){l=$(l);if(l==document&&document.createEvent&&!l.dispatchEvent){l=document.documentElement}var m;if(document.createEvent){m=document.createEvent("HTMLEvents");m.initEvent("dataavailable",true,true)}else{m=document.createEventObject();m.eventType="ondataavailable"}m.eventName=k;m.memo=j||{};if(document.createEvent){l.dispatchEvent(m)}else{l.fireEvent(m.eventType,m)}return Event.extend(m)}}})());Object.extend(Event,Event.Methods);Element.addMethods({fire:Event.fire,observe:Event.observe,stopObserving:Event.stopObserving});Object.extend(document,{fire:Element.Methods.fire.methodize(),observe:Element.Methods.observe.methodize(),stopObserving:Element.Methods.stopObserving.methodize(),loaded:false});(function(){var b;function a(){if(document.loaded){return}if(b){window.clearInterval(b)}document.fire("dom:loaded");document.loaded=true}if(document.addEventListener){if(Prototype.Browser.WebKit){b=window.setInterval(function(){if(/loaded|complete/.test(document.readyState)){a()}},0);Event.observe(window,"load",a)}else{document.addEventListener("DOMContentLoaded",a,false)}}else{document.write("<script id=__onDOMContentLoaded defer src=//:><\/script>");$("__onDOMContentLoaded").onreadystatechange=function(){if(this.readyState=="complete"){this.onreadystatechange=null;a()}}}})();Hash.toQueryString=Object.toQueryString;var Toggle={display:Element.toggle};Element.Methods.childOf=Element.Methods.descendantOf;var Insertion={Before:function(a,b){return Element.insert(a,{before:b})},Top:function(a,b){return Element.insert(a,{top:b})},Bottom:function(a,b){return Element.insert(a,{bottom:b})},After:function(a,b){return Element.insert(a,{after:b})}};var $continue=new Error('"throw $continue" is deprecated, use "return" instead');var Position={includeScrollOffsets:false,prepare:function(){this.deltaX=window.pageXOffset||document.documentElement.scrollLeft||document.body.scrollLeft||0;this.deltaY=window.pageYOffset||document.documentElement.scrollTop||document.body.scrollTop||0},within:function(b,a,c){if(this.includeScrollOffsets){return this.withinIncludingScrolloffsets(b,a,c)}this.xcomp=a;this.ycomp=c;this.offset=Element.cumulativeOffset(b);return(c>=this.offset[1]&&c<this.offset[1]+b.offsetHeight&&a>=this.offset[0]&&a<this.offset[0]+b.offsetWidth)},withinIncludingScrolloffsets:function(b,a,d){var c=Element.cumulativeScrollOffset(b);this.xcomp=a+c[0]-this.deltaX;this.ycomp=d+c[1]-this.deltaY;this.offset=Element.cumulativeOffset(b);return(this.ycomp>=this.offset[1]&&this.ycomp<this.offset[1]+b.offsetHeight&&this.xcomp>=this.offset[0]&&this.xcomp<this.offset[0]+b.offsetWidth)},overlap:function(b,a){if(!b){return 0}if(b=="vertical"){return((this.offset[1]+a.offsetHeight)-this.ycomp)/a.offsetHeight}if(b=="horizontal"){return((this.offset[0]+a.offsetWidth)-this.xcomp)/a.offsetWidth}},cumulativeOffset:Element.Methods.cumulativeOffset,positionedOffset:Element.Methods.positionedOffset,absolutize:function(a){Position.prepare();return Element.absolutize(a)},relativize:function(a){Position.prepare();return Element.relativize(a)},realOffset:Element.Methods.cumulativeScrollOffset,offsetParent:Element.Methods.getOffsetParent,page:Element.Methods.viewportOffset,clone:function(b,c,a){a=a||{};return Element.clonePosition(c,b,a)}};if(!document.getElementsByClassName){document.getElementsByClassName=function(b){function a(c){return c.blank()?null:"[contains(concat(' ', @class, ' '), ' "+c+" ')]"}b.getElementsByClassName=Prototype.BrowserFeatures.XPath?function(c,e){e=e.toString().strip();var d=/\s/.test(e)?$w(e).map(a).join(""):a(e);return d?document._getElementsByXPath(".//*"+d,c):[]}:function(e,f){f=f.toString().strip();var g=[],h=(/\s/.test(f)?$w(f):null);if(!h&&!f){return g}var c=$(e).getElementsByTagName("*");f=" "+f+" ";for(var d=0,k,j;k=c[d];d++){if(k.className&&(j=" "+k.className+" ")&&(j.include(f)||(h&&h.all(function(i){return!i.toString().blank()&&j.include(" "+i+" ")})))){g.push(Element.extend(k))}}return g};return function(d,c){return $(c||document.body).getElementsByClassName(d)}}(Element.Methods)}Element.ClassNames=Class.create();Element.ClassNames.prototype={initialize:function(a){this.element=$(a)},_each:function(a){this.element.className.split(/\s+/).select(function(b){return b.length>0})._each(a)},set:function(a){this.element.className=a},add:function(a){if(this.include(a)){return}this.set($A(this).concat(a).join(" "))},remove:function(a){if(!this.include(a)){return}this.set($A(this).without(a).join(" "))},toString:function(){return $A(this).join(" ")}};Object.extend(Element.ClassNames.prototype,Enumerable);Element.addMethods();
\ No newline at end of file
diff --git a/js/src/effects.js b/js/src/effects.js
index 27c2901..5097fa0 100644
--- a/js/src/effects.js
+++ b/js/src/effects.js
@@ -1,6 +1,6 @@
 // script.aculo.us effects.js v1.8.0, Tue Nov 06 15:01:40 +0300 2007
 
-// Copyright (c) 2005-2007 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
+// Copyright 2005-2007 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
 // Contributors:
 //  Justin Palmer (http://encytemedia.com/)
 //  Mark Pilgrim (http://diveintomark.org/)
diff --git a/js/src/prototype.js b/js/src/prototype.js
index 0bb8807..a7fd383 100644
--- a/js/src/prototype.js
+++ b/js/src/prototype.js
@@ -1,4 +1,4 @@
-/*  Prototype JavaScript framework, version 1.6.0.2
+/*  Prototype JavaScript framework, version 1.6.0.3
  *  (c) 2005-2008 Sam Stephenson
  *
  *  Prototype is freely distributable under the terms of an MIT-style license.
@@ -7,23 +7,26 @@
  *--------------------------------------------------------------------------*/
 
 var Prototype = {
-  Version: '1.6.0.2',
+  Version: '1.6.0.3',
 
   Browser: {
-    IE:     !!(window.attachEvent && !window.opera),
-    Opera:  !!window.opera,
+    IE:     !!(window.attachEvent &&
+      navigator.userAgent.indexOf('Opera') === -1),
+    Opera:  navigator.userAgent.indexOf('Opera') > -1,
     WebKit: navigator.userAgent.indexOf('AppleWebKit/') > -1,
-    Gecko:  navigator.userAgent.indexOf('Gecko') > -1 && navigator.userAgent.indexOf('KHTML') == -1,
+    Gecko:  navigator.userAgent.indexOf('Gecko') > -1 &&
+      navigator.userAgent.indexOf('KHTML') === -1,
     MobileSafari: !!navigator.userAgent.match(/Apple.*Mobile.*Safari/)
   },
 
   BrowserFeatures: {
     XPath: !!document.evaluate,
+    SelectorsAPI: !!document.querySelector,
     ElementExtensions: !!window.HTMLElement,
     SpecificElementExtensions:
-      document.createElement('div').__proto__ &&
-      document.createElement('div').__proto__ !==
-        document.createElement('form').__proto__
+      document.createElement('div')['__proto__'] &&
+      document.createElement('div')['__proto__'] !==
+        document.createElement('form')['__proto__']
   },
 
   ScriptFragment: '<script[^>]*>([\\S\\s]*?)<\/script>',
@@ -83,12 +86,13 @@ Class.Methods = {
       var property = properties[i], value = source[property];
       if (ancestor && Object.isFunction(value) &&
           value.argumentNames().first() == "$super") {
-        var method = value, value = Object.extend((function(m) {
+        var method = value;
+        value = (function(m) {
           return function() { return ancestor[m].apply(this, arguments) };
-        })(property).wrap(method), {
-          valueOf:  function() { return method },
-          toString: function() { return method.toString() }
-        });
+        })(property).wrap(method);
+
+        value.valueOf = method.valueOf.bind(method);
+        value.toString = method.toString.bind(method);
       }
       this.prototype[property] = value;
     }
@@ -167,7 +171,7 @@ Object.extend(Object, {
   },
 
   isElement: function(object) {
-    return object && object.nodeType == 1;
+    return !!(object && object.nodeType == 1);
   },
 
   isArray: function(object) {
@@ -198,7 +202,8 @@ Object.extend(Object, {
 
 Object.extend(Function.prototype, {
   argumentNames: function() {
-    var names = this.toString().match(/^[\s\(]*function[^(]*\((.*?)\)/)[1].split(",").invoke("strip");
+    var names = this.toString().match(/^[\s\(]*function[^(]*\(([^\)]*)\)/)[1]
+      .replace(/\s+/g, '').split(',');
     return names.length == 1 && !names[0] ? [] : names;
   },
 
@@ -232,6 +237,11 @@ Object.extend(Function.prototype, {
     }, timeout);
   },
 
+  defer: function() {
+    var args = [0.01].concat($A(arguments));
+    return this.delay.apply(this, args);
+  },
+
   wrap: function(wrapper) {
     var __method = this;
     return function() {
@@ -248,8 +258,6 @@ Object.extend(Function.prototype, {
   }
 });
 
-Function.prototype.defer = Function.prototype.delay.curry(0.01);
-
 Date.prototype.toJSON = function() {
   return '"' + this.getUTCFullYear() + '-' +
     (this.getUTCMonth() + 1).toPaddedString(2) + '-' +
@@ -530,7 +538,7 @@ if (Prototype.Browser.WebKit || Prototype.Browser.IE) Object.extend(String.proto
     return this.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
   },
   unescapeHTML: function() {
-    return this.replace(/&amp;/g,'&').replace(/&lt;/g,'<').replace(/&gt;/g,'>');
+    return this.stripTags().replace(/&amp;/g,'&').replace(/&lt;/g,'<').replace(/&gt;/g,'>');
   }
 });
 
@@ -547,7 +555,7 @@ Object.extend(String.prototype.escapeHTML, {
   text: document.createTextNode('')
 });
 
-with (String.prototype.escapeHTML) div.appendChild(text);
+String.prototype.escapeHTML.div.appendChild(String.prototype.escapeHTML.text);
 
 var Template = Class.create({
   initialize: function(template, pattern) {
@@ -589,10 +597,9 @@ var $break = { };
 var Enumerable = {
   each: function(iterator, context) {
     var index = 0;
-    iterator = iterator.bind(context);
     try {
       this._each(function(value) {
-        iterator(value, index++);
+        iterator.call(context, value, index++);
       });
     } catch (e) {
       if (e != $break) throw e;
@@ -601,47 +608,46 @@ var Enumerable = {
   },
 
   eachSlice: function(number, iterator, context) {
-    iterator = iterator ? iterator.bind(context) : Prototype.K;
     var index = -number, slices = [], array = this.toArray();
+    if (number < 1) return array;
     while ((index += number) < array.length)
       slices.push(array.slice(index, index+number));
     return slices.collect(iterator, context);
   },
 
   all: function(iterator, context) {
-    iterator = iterator ? iterator.bind(context) : Prototype.K;
+    iterator = iterator || Prototype.K;
     var result = true;
     this.each(function(value, index) {
-      result = result && !!iterator(value, index);
+      result = result && !!iterator.call(context, value, index);
       if (!result) throw $break;
     });
     return result;
   },
 
   any: function(iterator, context) {
-    iterator = iterator ? iterator.bind(context) : Prototype.K;
+    iterator = iterator || Prototype.K;
     var result = false;
     this.each(function(value, index) {
-      if (result = !!iterator(value, index))
+      if (result = !!iterator.call(context, value, index))
         throw $break;
     });
     return result;
   },
 
   collect: function(iterator, context) {
-    iterator = iterator ? iterator.bind(context) : Prototype.K;
+    iterator = iterator || Prototype.K;
     var results = [];
     this.each(function(value, index) {
-      results.push(iterator(value, index));
+      results.push(iterator.call(context, value, index));
     });
     return results;
   },
 
   detect: function(iterator, context) {
-    iterator = iterator.bind(context);
     var result;
     this.each(function(value, index) {
-      if (iterator(value, index)) {
+      if (iterator.call(context, value, index)) {
         result = value;
         throw $break;
       }
@@ -650,17 +656,16 @@ var Enumerable = {
   },
 
   findAll: function(iterator, context) {
-    iterator = iterator.bind(context);
     var results = [];
     this.each(function(value, index) {
-      if (iterator(value, index))
+      if (iterator.call(context, value, index))
         results.push(value);
     });
     return results;
   },
 
   grep: function(filter, iterator, context) {
-    iterator = iterator ? iterator.bind(context) : Prototype.K;
+    iterator = iterator || Prototype.K;
     var results = [];
 
     if (Object.isString(filter))
@@ -668,7 +673,7 @@ var Enumerable = {
 
     this.each(function(value, index) {
       if (filter.match(value))
-        results.push(iterator(value, index));
+        results.push(iterator.call(context, value, index));
     });
     return results;
   },
@@ -696,9 +701,8 @@ var Enumerable = {
   },
 
   inject: function(memo, iterator, context) {
-    iterator = iterator.bind(context);
     this.each(function(value, index) {
-      memo = iterator(memo, value, index);
+      memo = iterator.call(context, memo, value, index);
     });
     return memo;
   },
@@ -711,10 +715,10 @@ var Enumerable = {
   },
 
   max: function(iterator, context) {
-    iterator = iterator ? iterator.bind(context) : Prototype.K;
+    iterator = iterator || Prototype.K;
     var result;
     this.each(function(value, index) {
-      value = iterator(value, index);
+      value = iterator.call(context, value, index);
       if (result == null || value >= result)
         result = value;
     });
@@ -722,10 +726,10 @@ var Enumerable = {
   },
 
   min: function(iterator, context) {
-    iterator = iterator ? iterator.bind(context) : Prototype.K;
+    iterator = iterator || Prototype.K;
     var result;
     this.each(function(value, index) {
-      value = iterator(value, index);
+      value = iterator.call(context, value, index);
       if (result == null || value < result)
         result = value;
     });
@@ -733,10 +737,10 @@ var Enumerable = {
   },
 
   partition: function(iterator, context) {
-    iterator = iterator ? iterator.bind(context) : Prototype.K;
+    iterator = iterator || Prototype.K;
     var trues = [], falses = [];
     this.each(function(value, index) {
-      (iterator(value, index) ?
+      (iterator.call(context, value, index) ?
         trues : falses).push(value);
     });
     return [trues, falses];
@@ -751,19 +755,20 @@ var Enumerable = {
   },
 
   reject: function(iterator, context) {
-    iterator = iterator.bind(context);
     var results = [];
     this.each(function(value, index) {
-      if (!iterator(value, index))
+      if (!iterator.call(context, value, index))
         results.push(value);
     });
     return results;
   },
 
   sortBy: function(iterator, context) {
-    iterator = iterator.bind(context);
     return this.map(function(value, index) {
-      return {value: value, criteria: iterator(value, index)};
+      return {
+        value: value,
+        criteria: iterator.call(context, value, index)
+      };
     }).sort(function(left, right) {
       var a = left.criteria, b = right.criteria;
       return a < b ? -1 : a > b ? 1 : 0;
@@ -815,8 +820,12 @@ function $A(iterable) {
 if (Prototype.Browser.WebKit) {
   $A = function(iterable) {
     if (!iterable) return [];
-    if (!(Object.isFunction(iterable) && iterable == '[object NodeList]') &&
-        iterable.toArray) return iterable.toArray();
+    // In Safari, only use the `toArray` method if it's not a NodeList.
+    // A NodeList is a function, has an function `item` property, and a numeric
+    // `length` property. Adapted from Google Doctype.
+    if (!(typeof iterable === 'function' && typeof iterable.length ===
+        'number' && typeof iterable.item === 'function') && iterable.toArray)
+      return iterable.toArray();
     var length = iterable.length || 0, results = new Array(length);
     while (length--) results[length] = iterable[length];
     return results;
@@ -963,8 +972,8 @@ Object.extend(Number.prototype, {
     return this + 1;
   },
 
-  times: function(iterator) {
-    $R(0, this, true).each(iterator);
+  times: function(iterator, context) {
+    $R(0, this, true).each(iterator, context);
     return this;
   },
 
@@ -1011,7 +1020,9 @@ var Hash = Class.create(Enumerable, (function() {
     },
 
     get: function(key) {
-      return this._object[key];
+      // simulating poorly supported hasOwnProperty
+      if (this._object[key] !== Object.prototype[key])
+        return this._object[key];
     },
 
     unset: function(key) {
@@ -1051,14 +1062,14 @@ var Hash = Class.create(Enumerable, (function() {
     },
 
     toQueryString: function() {
-      return this.map(function(pair) {
+      return this.inject([], function(results, pair) {
         var key = encodeURIComponent(pair.key), values = pair.value;
 
         if (values && typeof values == 'object') {
           if (Object.isArray(values))
-            return values.map(toQueryPair.curry(key)).join('&');
-        }
-        return toQueryPair(key, values);
+            return results.concat(values.map(toQueryPair.curry(key)));
+        } else results.push(toQueryPair(key, values));
+        return results;
       }).join('&');
     },
 
@@ -1558,6 +1569,7 @@ if (!Node.ELEMENT_NODE) {
     return Element.writeAttribute(cache[tagName].cloneNode(false), attributes);
   };
   Object.extend(this.Element, element || { });
+  if (element) this.Element.prototype = element.prototype;
 }).call(window);
 
 Element.cache = { };
@@ -1574,12 +1586,14 @@ Element.Methods = {
   },
 
   hide: function(element) {
-    $(element).style.display = 'none';
+    element = $(element);
+    element.style.display = 'none';
     return element;
   },
 
   show: function(element) {
-    $(element).style.display = '';
+    element = $(element);
+    element.style.display = '';
     return element;
   },
 
@@ -1733,7 +1747,7 @@ Element.Methods = {
     element = $(element);
     if (arguments.length == 1) return element.firstDescendant();
     return Object.isNumber(expression) ? element.descendants()[expression] :
-      element.select(expression)[index || 0];
+      Element.select(element, expression)[index || 0];
   },
 
   previous: function(element, expression, index) {
@@ -1863,24 +1877,16 @@ Element.Methods = {
 
   descendantOf: function(element, ancestor) {
     element = $(element), ancestor = $(ancestor);
-    var originalAncestor = ancestor;
 
     if (element.compareDocumentPosition)
       return (element.compareDocumentPosition(ancestor) & 8) === 8;
 
-    if (element.sourceIndex && !Prototype.Browser.Opera) {
-      var e = element.sourceIndex, a = ancestor.sourceIndex,
-       nextAncestor = ancestor.nextSibling;
-      if (!nextAncestor) {
-        do { ancestor = ancestor.parentNode; }
-        while (!(nextAncestor = ancestor.nextSibling) && ancestor.parentNode);
-      }
-      if (nextAncestor && nextAncestor.sourceIndex)
-       return (e > a && e < nextAncestor.sourceIndex);
-    }
+    if (ancestor.contains)
+      return ancestor.contains(element) && ancestor !== element;
 
     while (element = element.parentNode)
-      if (element == originalAncestor) return true;
+      if (element == ancestor) return true;
+
     return false;
   },
 
@@ -1895,7 +1901,7 @@ Element.Methods = {
     element = $(element);
     style = style == 'float' ? 'cssFloat' : style.camelize();
     var value = element.style[style];
-    if (!value) {
+    if (!value || value == 'auto') {
       var css = document.defaultView.getComputedStyle(element, null);
       value = css ? css[style] : null;
     }
@@ -1934,7 +1940,7 @@ Element.Methods = {
 
   getDimensions: function(element) {
     element = $(element);
-    var display = $(element).getStyle('display');
+    var display = element.getStyle('display');
     if (display != 'none' && display != null) // Safari bug
       return {width: element.offsetWidth, height: element.offsetHeight};
 
@@ -1963,7 +1969,7 @@ Element.Methods = {
       element.style.position = 'relative';
       // Opera returns the offset relative to the positioning context, when an
       // element is position relative but top and left have not been defined
-      if (window.opera) {
+      if (Prototype.Browser.Opera) {
         element.style.top = 0;
         element.style.left = 0;
       }
@@ -2018,7 +2024,7 @@ Element.Methods = {
       valueL += element.offsetLeft || 0;
       element = element.offsetParent;
       if (element) {
-        if (element.tagName == 'BODY') break;
+        if (element.tagName.toUpperCase() == 'BODY') break;
         var p = Element.getStyle(element, 'position');
         if (p !== 'static') break;
       }
@@ -2028,7 +2034,7 @@ Element.Methods = {
 
   absolutize: function(element) {
     element = $(element);
-    if (element.getStyle('position') == 'absolute') return;
+    if (element.getStyle('position') == 'absolute') return element;
     // Position.prepare(); // To be done manually by Scripty when it needs it.
 
     var offsets = element.positionedOffset();
@@ -2052,7 +2058,7 @@ Element.Methods = {
 
   relativize: function(element) {
     element = $(element);
-    if (element.getStyle('position') == 'relative') return;
+    if (element.getStyle('position') == 'relative') return element;
     // Position.prepare(); // To be done manually by Scripty when it needs it.
 
     element.style.position = 'relative';
@@ -2077,15 +2083,15 @@ Element.Methods = {
   },
 
   getOffsetParent: function(element) {
-    element = $(element);  
-    var op = element.offsetParent, body = document.body, docEl = document.documentElement;  
-
-    /* IE with strict doctype may try to return documentElement as offsetParent  
-       on relatively positioned elements, we will return body instead */  
-    if (op && op !== docEl) return $(op);  
-    if (op === docEl || element === docEl || element === body) return $(body);  
-         
-    while ((element = element.parentNode) && element !== body)  
+    element = $(element);
+    var op = element.offsetParent, body = document.body, docEl = document.documentElement;
+
+    /* IE with strict doctype may try to return documentElement as offsetParent
+       on relatively positioned elements, we will return body instead */
+    if (op && op !== docEl) return $(op);
+    if (op === docEl || element === docEl || element === body) return $(body);
+
+    while ((element = element.parentNode) && element !== body)
       if (Element.getStyle(element, 'position') != 'static')
         return $(element);
 
@@ -2103,7 +2109,7 @@ Element.Methods = {
 
     element = forElement;
     do {
-      if (!Prototype.Browser.Opera || element.tagName == 'BODY') {
+      if (!Prototype.Browser.Opera || (element.tagName && (element.tagName.toUpperCase() == 'BODY'))) {
         valueT -= element.scrollTop  || 0;
         valueL -= element.scrollLeft || 0;
       }
@@ -2218,6 +2224,9 @@ else if (Prototype.Browser.IE) {
   Element.Methods.getOffsetParent = Element.Methods.getOffsetParent.wrap(
     function(proceed, element) {
       element = $(element);
+      // IE throws an error if element is not in document
+      try { element.offsetParent }
+      catch(e) { return $(document.body) }
       var position = element.getStyle('position');
       if (position !== 'static') return proceed(element);
       element.setStyle({ position: 'relative' });
@@ -2231,6 +2240,8 @@ else if (Prototype.Browser.IE) {
     Element.Methods[method] = Element.Methods[method].wrap(
       function(proceed, element) {
         element = $(element);
+        try { element.offsetParent }
+        catch(e) { return Element._returnOffset(0,0) }
         var position = element.getStyle('position');
         if (position !== 'static') return proceed(element);
         // Trigger hasLayout on the offset parent so that IE6 reports
@@ -2246,6 +2257,14 @@ else if (Prototype.Browser.IE) {
     );
   });
 
+  Element.Methods.cumulativeOffset = Element.Methods.cumulativeOffset.wrap(
+    function(proceed, element) {
+      try { element.offsetParent }
+      catch(e) { return Element._returnOffset(0,0) }
+      return proceed(element);
+    }
+  );
+
   Element.Methods.getStyle = function(element, style) {
     element = $(element);
     style = (style == 'float' || style == 'cssFloat') ? 'styleFloat' : style.camelize();
@@ -2337,7 +2356,7 @@ else if (Prototype.Browser.IE) {
   Element._attributeTranslations.has = {};
 
   $w('colSpan rowSpan vAlign dateTime accessKey tabIndex ' +
-      'encType maxLength readOnly longDesc').each(function(attr) {
+      'encType maxLength readOnly longDesc frameBorder').each(function(attr) {
     Element._attributeTranslations.write.names[attr.toLowerCase()] = attr;
     Element._attributeTranslations.has[attr.toLowerCase()] = attr;
   });
@@ -2390,7 +2409,7 @@ else if (Prototype.Browser.WebKit) {
       (value < 0.00001) ? 0 : value;
 
     if (value == 1)
-      if(element.tagName == 'IMG' && element.width) {
+      if(element.tagName.toUpperCase() == 'IMG' && element.width) {
         element.width++; element.width--;
       } else try {
         var n = document.createTextNode(' ');
@@ -2521,7 +2540,7 @@ Element.Methods.Simulated = {
   hasAttribute: function(element, attribute) {
     attribute = Element._attributeTranslations.has[attribute] || attribute;
     var node = $(element).getAttributeNode(attribute);
-    return node && node.specified;
+    return !!(node && node.specified);
   }
 };
 
@@ -2530,9 +2549,9 @@ Element.Methods.ByTag = { };
 Object.extend(Element, Element.Methods);
 
 if (!Prototype.BrowserFeatures.ElementExtensions &&
-    document.createElement('div').__proto__) {
+    document.createElement('div')['__proto__']) {
   window.HTMLElement = { };
-  window.HTMLElement.prototype = document.createElement('div').__proto__;
+  window.HTMLElement.prototype = document.createElement('div')['__proto__'];
   Prototype.BrowserFeatures.ElementExtensions = true;
 }
 
@@ -2547,7 +2566,7 @@ Element.extend = (function() {
         element.nodeType != 1 || element == window) return element;
 
     var methods = Object.clone(Methods),
-      tagName = element.tagName, property, value;
+      tagName = element.tagName.toUpperCase(), property, value;
 
     // extend methods for specific tags
     if (ByTag[tagName]) Object.extend(methods, ByTag[tagName]);
@@ -2643,7 +2662,7 @@ Element.addMethods = function(methods) {
     if (window[klass]) return window[klass];
 
     window[klass] = { };
-    window[klass].prototype = document.createElement(tagName).__proto__;
+    window[klass].prototype = document.createElement(tagName)['__proto__'];
     return window[klass];
   }
 
@@ -2669,12 +2688,18 @@ Element.addMethods = function(methods) {
 
 document.viewport = {
   getDimensions: function() {
-    var dimensions = { };
-    var B = Prototype.Browser;
+    var dimensions = { }, B = Prototype.Browser;
     $w('width height').each(function(d) {
       var D = d.capitalize();
-      dimensions[d] = (B.WebKit && !document.evaluate) ? self['inner' + D] :
-        (B.Opera) ? document.body['client' + D] : document.documentElement['client' + D];
+      if (B.WebKit && !document.evaluate) {
+        // Safari <3.0 needs self.innerWidth/Height
+        dimensions[d] = self['inner' + D];
+      } else if (B.Opera && parseFloat(window.opera.version()) < 9.5) {
+        // Opera <9.5 needs document.body.clientWidth/Height
+        dimensions[d] = document.body['client' + D]
+      } else {
+        dimensions[d] = document.documentElement['client' + D];
+      }
     });
     return dimensions;
   },
@@ -2693,14 +2718,24 @@ document.viewport = {
       window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop);
   }
 };
-/* Portions of the Selector class are derived from Jack Slocum’s DomQuery,
+/* Portions of the Selector class are derived from Jack Slocum's DomQuery,
  * part of YUI-Ext version 0.40, distributed under the terms of an MIT-style
  * license.  Please see http://www.yui-ext.com/ for more information. */
 
 var Selector = Class.create({
   initialize: function(expression) {
     this.expression = expression.strip();
-    this.compileMatcher();
+
+    if (this.shouldUseSelectorsAPI()) {
+      this.mode = 'selectorsAPI';
+    } else if (this.shouldUseXPath()) {
+      this.mode = 'xpath';
+      this.compileXPathMatcher();
+    } else {
+      this.mode = "normal";
+      this.compileMatcher();
+    }
+
   },
 
   shouldUseXPath: function() {
@@ -2715,16 +2750,29 @@ var Selector = Class.create({
 
     // XPath can't do namespaced attributes, nor can it read
     // the "checked" property from DOM nodes
-    if ((/(\[[\w-]*?:|:checked)/).test(this.expression))
+    if ((/(\[[\w-]*?:|:checked)/).test(e))
       return false;
 
     return true;
   },
 
-  compileMatcher: function() {
-    if (this.shouldUseXPath())
-      return this.compileXPathMatcher();
+  shouldUseSelectorsAPI: function() {
+    if (!Prototype.BrowserFeatures.SelectorsAPI) return false;
+
+    if (!Selector._div) Selector._div = new Element('div');
+
+    // Make sure the browser treats the selector as valid. Test on an
+    // isolated element to minimize cost of this check.
+    try {
+      Selector._div.querySelector(this.expression);
+    } catch(e) {
+      return false;
+    }
+
+    return true;
+  },
 
+  compileMatcher: function() {
     var e = this.expression, ps = Selector.patterns, h = Selector.handlers,
         c = Selector.criteria, le, p, m;
 
@@ -2742,7 +2790,7 @@ var Selector = Class.create({
         p = ps[i];
         if (m = e.match(p)) {
           this.matcher.push(Object.isFunction(c[i]) ? c[i](m) :
-    	      new Template(c[i]).evaluate(m));
+            new Template(c[i]).evaluate(m));
           e = e.replace(m[0], '');
           break;
         }
@@ -2781,8 +2829,27 @@ var Selector = Class.create({
 
   findElements: function(root) {
     root = root || document;
-    if (this.xpath) return document._getElementsByXPath(this.xpath, root);
-    return this.matcher(root);
+    var e = this.expression, results;
+
+    switch (this.mode) {
+      case 'selectorsAPI':
+        // querySelectorAll queries document-wide, then filters to descendants
+        // of the context element. That's not what we want.
+        // Add an explicit context to the selector if necessary.
+        if (root !== document) {
+          var oldId = root.id, id = $(root).identify();
+          e = "#" + id + " " + e;
+        }
+
+        results = $A(root.querySelectorAll(e)).map(Element.extend);
+        root.id = oldId;
+
+        return results;
+      case 'xpath':
+        return document._getElementsByXPath(this.xpath, root);
+      default:
+       return this.matcher(root);
+    }
   },
 
   match: function(element) {
@@ -2873,10 +2940,10 @@ Object.extend(Selector, {
       'first-child': '[not(preceding-sibling::*)]',
       'last-child':  '[not(following-sibling::*)]',
       'only-child':  '[not(preceding-sibling::* or following-sibling::*)]',
-      'empty':       "[count(*) = 0 and (count(text()) = 0 or translate(text(), ' \t\r\n', '') = '')]",
+      'empty':       "[count(*) = 0 and (count(text()) = 0)]",
       'checked':     "[@checked]",
-      'disabled':    "[@disabled]",
-      'enabled':     "[not(@disabled)]",
+      'disabled':    "[(@disabled) and (@type!='hidden')]",
+      'enabled':     "[not(@disabled) and (@type!='hidden')]",
       'not': function(m) {
         var e = m[6], p = Selector.patterns,
             x = Selector.xpath, le, v;
@@ -2968,7 +3035,7 @@ Object.extend(Selector, {
     className:    /^\.([\w\-\*]+)(\b|$)/,
     pseudo:
 /^:((first|last|nth|nth-last|only)(-child|-of-type)|empty|checked|(en|dis)abled|not)(\((.*?)\))?(\b|$|(?=\s|[:+~>]))/,
-    attrPresence: /^\[([\w]+)\]/,
+    attrPresence: /^\[((?:[\w]+:)?[\w]+)\]/,
     attr:         /\[((?:[\w-]*:)?[\w-]+)\s*(?:([!^$*~|]?=)\s*((['"])([^\4]*?)\4|([^'"][^\]]*?)))?\]/
   },
 
@@ -3081,7 +3148,7 @@ Object.extend(Selector, {
 
     nextElementSibling: function(node) {
       while (node = node.nextSibling)
-	      if (node.nodeType == 1) return node;
+        if (node.nodeType == 1) return node;
       return null;
     },
 
@@ -3270,7 +3337,7 @@ Object.extend(Selector, {
     'empty': function(nodes, value, root) {
       for (var i = 0, results = [], node; node = nodes[i]; i++) {
         // IE treats comments as element nodes
-        if (node.tagName == '!' || (node.firstChild && !node.innerHTML.match(/^\s*$/))) continue;
+        if (node.tagName == '!' || node.firstChild) continue;
         results.push(node);
       }
       return results;
@@ -3288,7 +3355,8 @@ Object.extend(Selector, {
 
     'enabled': function(nodes, value, root) {
       for (var i = 0, results = [], node; node = nodes[i]; i++)
-        if (!node.disabled) results.push(node);
+        if (!node.disabled && (!node.type || node.type !== 'hidden'))
+          results.push(node);
       return results;
     },
 
@@ -3308,11 +3376,14 @@ Object.extend(Selector, {
   operators: {
     '=':  function(nv, v) { return nv == v; },
     '!=': function(nv, v) { return nv != v; },
-    '^=': function(nv, v) { return nv.startsWith(v); },
+    '^=': function(nv, v) { return nv == v || nv && nv.startsWith(v); },
+    '$=': function(nv, v) { return nv == v || nv && nv.endsWith(v); },
+    '*=': function(nv, v) { return nv == v || nv && nv.include(v); },
     '$=': function(nv, v) { return nv.endsWith(v); },
     '*=': function(nv, v) { return nv.include(v); },
     '~=': function(nv, v) { return (' ' + nv + ' ').include(' ' + v + ' '); },
-    '|=': function(nv, v) { return ('-' + nv.toUpperCase() + '-').include('-' + v.toUpperCase() + '-'); }
+    '|=': function(nv, v) { return ('-' + (nv || "").toUpperCase() +
+     '-').include('-' + (v || "").toUpperCase() + '-'); }
   },
 
   split: function(expression) {
@@ -3386,7 +3457,7 @@ var Form = {
     var data = elements.inject({ }, function(result, element) {
       if (!element.disabled && element.name) {
         key = element.name; value = $(element).getValue();
-        if (value != null && (element.type != 'submit' || (!submitted &&
+        if (value != null && element.type != 'file' && (element.type != 'submit' || (!submitted &&
             submit !== false && (!submit || key == submit) && (submitted = true)))) {
           if (key in result) {
             // a key is already present; construct an array of values
@@ -3547,7 +3618,6 @@ Form.Element.Methods = {
 
   disable: function(element) {
     element = $(element);
-    element.blur();
     element.disabled = true;
     return element;
   },
@@ -3587,22 +3657,22 @@ Form.Element.Serializers = {
     else element.value = value;
   },
 
-  select: function(element, index) {
-    if (Object.isUndefined(index))
+  select: function(element, value) {
+    if (Object.isUndefined(value))
       return this[element.type == 'select-one' ?
         'selectOne' : 'selectMany'](element);
     else {
-      var opt, value, single = !Object.isArray(index);
+      var opt, currentValue, single = !Object.isArray(value);
       for (var i = 0, length = element.length; i < length; i++) {
         opt = element.options[i];
-        value = this.optionValue(opt);
+        currentValue = this.optionValue(opt);
         if (single) {
-          if (value == index) {
+          if (currentValue == value) {
             opt.selected = true;
             return;
           }
         }
-        else opt.selected = index.include(value);
+        else opt.selected = value.include(currentValue);
       }
     }
   },
@@ -3773,8 +3843,23 @@ Event.Methods = (function() {
     isRightClick:  function(event) { return isButton(event, 2) },
 
     element: function(event) {
-      var node = Event.extend(event).target;
-      return Element.extend(node.nodeType == Node.TEXT_NODE ? node.parentNode : node);
+      event = Event.extend(event);
+
+      var node          = event.target,
+          type          = event.type,
+          currentTarget = event.currentTarget;
+
+      if (currentTarget && currentTarget.tagName) {
+        // Firefox screws up the "click" event when moving between radio buttons
+        // via arrow keys. It also screws up the "load" and "error" events on images,
+        // reporting the document as the target instead of the original image.
+        if (type === 'load' || type === 'error' ||
+          (type === 'click' && currentTarget.tagName.toLowerCase() === 'input'
+            && currentTarget.type === 'radio'))
+              node = currentTarget;
+      }
+      if (node.nodeType == Node.TEXT_NODE) node = node.parentNode;
+      return Element.extend(node);
     },
 
     findElement: function(event, expression) {
@@ -3785,11 +3870,15 @@ Event.Methods = (function() {
     },
 
     pointer: function(event) {
+      var docElement = document.documentElement,
+      body = document.body || { scrollLeft: 0, scrollTop: 0 };
       return {
         x: event.pageX || (event.clientX +
-          (document.documentElement.scrollLeft || document.body.scrollLeft)),
+          (docElement.scrollLeft || body.scrollLeft) -
+          (docElement.clientLeft || 0)),
         y: event.pageY || (event.clientY +
-          (document.documentElement.scrollTop || document.body.scrollTop))
+          (docElement.scrollTop || body.scrollTop) -
+          (docElement.clientTop || 0))
       };
     },
 
@@ -3834,7 +3923,7 @@ Event.extend = (function() {
     };
 
   } else {
-    Event.prototype = Event.prototype || document.createEvent("HTMLEvents").__proto__;
+    Event.prototype = Event.prototype || document.createEvent("HTMLEvents")['__proto__'];
     Object.extend(Event.prototype, methods);
     return Prototype.K;
   }
@@ -3899,10 +3988,20 @@ Object.extend(Event, (function() {
         cache[id][eventName] = null;
   }
 
+
+  // Internet Explorer needs to remove event handlers on page unload
+  // in order to avoid memory leaks.
   if (window.attachEvent) {
     window.attachEvent("onunload", destroyCache);
   }
 
+  // Safari has a dummy event handler on page unload so that it won't
+  // use its bfcache. Safari <= 3.1 has an issue with restoring the "document"
+  // object when page is returned to via the back button using its bfcache.
+  if (Prototype.Browser.WebKit) {
+    window.addEventListener('unload', Prototype.emptyFunction, false);
+  }
+
   return {
     observe: function(element, eventName, handler) {
       element = $(element);
diff --git a/js/src/scriptaculous.js b/js/src/scriptaculous.js
index c976e6b..de4289e 100644
--- a/js/src/scriptaculous.js
+++ b/js/src/scriptaculous.js
@@ -1,6 +1,6 @@
 // script.aculo.us scriptaculous.js v1.8.0, Tue Nov 06 15:01:40 +0300 2007
 
-// Copyright (c) 2005-2007 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
+// Copyright 2005-2007 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
 // 
 // Permission is hereby granted, free of charge, to any person obtaining
 // a copy of this software and associated documentation files (the
diff --git a/lib/Block/summary.php b/lib/Block/summary.php
index ec3dd42..ae5513e 100644
--- a/lib/Block/summary.php
+++ b/lib/Block/summary.php
@@ -3,7 +3,7 @@
 $block_name = _("Tasks Summary");
 
 /**
- * $Horde: nag/lib/Block/summary.php,v 1.51.8.17 2008/05/20 22:02:10 jan Exp $
+ * $Horde: nag/lib/Block/summary.php,v 1.51.8.18 2008/06/15 11:52:20 jan Exp $
  *
  * @package Horde_Block
  */
@@ -18,7 +18,8 @@ class Horde_Block_nag_summary extends Horde_Block {
         $label = !empty($this->_params['block_title'])
             ? $this->_params['block_title']
             : $registry->get('name');
-        return Horde::link(Horde::applicationUrl($registry->getInitialPage(), true))
+        return Horde::link(Horde::applicationUrl($registry->getInitialPage(),
+                                                 true))
             . htmlspecialchars($label) . '</a>';
     }
 
@@ -72,7 +73,7 @@ class Horde_Block_nag_summary extends Horde_Block {
                          'default' => 1),
                      'show_completed' => array(
                          'type' => 'checkbox',
-                         'name' => _("Always show completed tasks?"),
+                         'name' => _("Always show completed and future tasks?"),
                          'default' => 1),
                      'show_tasklists' => array(
                          'type' => 'multienum',
@@ -111,8 +112,10 @@ class Horde_Block_nag_summary extends Horde_Block {
                     'view.php',
                     array('task' => $task->id,
                           'tasklist' => $task->tasklist));
-                $link = Horde::link(htmlspecialchars(Horde::applicationUrl($viewurl, true)))
-                    . (!empty($task->name) ? htmlspecialchars($task->name) : _("[none]"))
+                $link = Horde::link(
+                    htmlspecialchars(Horde::applicationUrl($viewurl, true)))
+                    . (!empty($task->name)
+                       ? htmlspecialchars($task->name) : _("[none]"))
                     . '</a>';
                 if ($differential >= -60 && $differential < 60) {
                     $messages[$key] = sprintf(_("%s is due now."), $link);
@@ -138,7 +141,10 @@ class Horde_Block_nag_summary extends Horde_Block {
         $i = 0;
         $tasks = Nag::listTasks(
             null, null, null,
-            isset($this->_params['show_tasklists']) ? $this->_params['show_tasklists'] : null);
+            isset($this->_params['show_tasklists'])
+                ? $this->_params['show_tasklists']
+            : array_keys(Nag::listTasklists(false, PERMS_READ)),
+            empty($this->_params['show_completed']) ? 0 : 1);
         if (is_a($tasks, 'PEAR_Error')) {
             return '<em>' . htmlspecialchars($tasks->getMessage()) . '</em>';
         }
@@ -157,12 +163,6 @@ class Horde_Block_nag_summary extends Horde_Block {
                 continue;
             }
 
-            // Only display completed tasks if the show_completed parameter is
-            // on.
-            if ($task->completed && empty($this->_params['show_completed'])) {
-                continue;
-            }
-
             if ($task->completed) {
                 $style = 'closed';
             } elseif (!empty($task->due) && $task->due < $now) {
@@ -182,7 +182,8 @@ class Horde_Block_nag_summary extends Horde_Block {
                 $label = sprintf(_("Edit \"%s\""), $task->name);
                 $html .= '<td width="1%">'
                     . Horde::link(htmlspecialchars(Horde::applicationUrl(Util::addParameter($taskurl, 'actionID', 'modify_task'), true)), $label)
-                    . Horde::img('edit.png', $label, null, $registry->getImageDir('horde'))
+                    . Horde::img('edit.png', $label, null,
+                                 $registry->getImageDir('horde'))
                     . '</a></td>';
                 if ($task->completed) {
                     $html .= '<td width="1%">'
@@ -218,8 +219,11 @@ class Horde_Block_nag_summary extends Horde_Block {
                 array('task' => $task->id,
                       'tasklist' => $task->tasklist));
             $html .= $task->treeIcons()
-                . Horde::link(htmlspecialchars(Horde::applicationUrl($viewurl, true)), $task->desc)
-                . (!empty($task->name) ? htmlspecialchars($task->name) : _("[none]"))
+                . Horde::link(
+                    htmlspecialchars(Horde::applicationUrl($viewurl, true)),
+                    $task->desc)
+                . (!empty($task->name)
+                   ? htmlspecialchars($task->name) : _("[none]"))
                 . '</a>';
 
             if ($task->due > 0 &&
@@ -235,7 +239,8 @@ class Horde_Block_nag_summary extends Horde_Block {
             if (!empty($this->_params['show_category'])) {
                 $html .= '<td width="1%" class="category'
                     . md5($task->category) . '">'
-                    . htmlspecialchars($task->category ? $task->category : _("Unfiled"))
+                    . htmlspecialchars($task->category
+                                       ? $task->category : _("Unfiled"))
                     . '</td>';
             }
             $html .= "</tr>\n";
diff --git a/lib/Driver.php b/lib/Driver.php
index 1850bbf..7cb350b 100644
--- a/lib/Driver.php
+++ b/lib/Driver.php
@@ -2,7 +2,7 @@
 /**
  * Nag_Driver:: defines an API for implementing storage backends for Nag.
  *
- * $Horde: nag/lib/Driver.php,v 1.57.2.18 2008/05/25 13:59:18 jan Exp $
+ * $Horde: nag/lib/Driver.php,v 1.57.2.28 2008/11/26 21:25:25 chuck Exp $
  *
  * See the enclosed file COPYING for license information (GPL). If you
  * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
@@ -169,7 +169,7 @@ class Nag_Driver {
      */
     function &singleton($tasklist = '', $driver = null, $params = null)
     {
-        static $instances;
+        static $instances = array();
 
         if (is_null($driver)) {
             $driver = $GLOBALS['conf']['storage']['driver'];
@@ -179,10 +179,6 @@ class Nag_Driver {
             $params = Horde::getDriverConfig('storage', $driver);
         }
 
-        if (!isset($instances)) {
-            $instances = array();
-        }
-
         $signature = serialize(array($tasklist, $driver, $params));
         if (!isset($instances[$signature])) {
             $instances[$signature] =& Nag_Driver::factory($tasklist, $driver, $params);
@@ -229,20 +225,25 @@ class Nag_Driver {
         if (is_a($taskId, 'PEAR_Error')) {
             return $taskId;
         }
+        $task = $this->get($taskId);
 
         /* Log the creation of this item in the history log. */
         $history = &Horde_History::singleton();
         $history->log('nag:' . $this->_tasklist . ':' . $uid, array('action' => 'add'), true);
 
+        /* Log completion status changes. */
+        if ($completed) {
+            $history->log('nag:' . $this->_tasklist . ':' . $uid, array('action' => 'complete'), true);
+        }
+
         /* Notify users about the new event. */
-        $result = Nag::sendNotification('add', $this->_tasklist, $name, $desc, $due, $priority);
+        $result = Nag::sendNotification('add', $task);
         if (is_a($result, 'PEAR_Error')) {
             Horde::logMessage($result, __FILE__, __LINE__, PEAR_LOG_ERR);
         }
 
         /* Add an alarm if necessary. */
         if (!empty($GLOBALS['conf']['alarms']['driver']) && !empty($alarm)) {
-            $task = $this->get($taskId);
             $alarm = $task->toAlarm();
             if ($alarm) {
                 $alarm['start'] = new Horde_Date($alarm['start']);
@@ -273,11 +274,13 @@ class Nag_Driver {
      * @param string $owner            The owner of the event.
      * @param string $assignee         The assignee of the event.
      * @param integer $completed_date  The task's completion date.
+     * @param string $tasklist         The new tasklist.
      */
     function modify($taskId, $name, $desc, $start = 0, $due = 0, $priority = 0,
                     $estimate = 0.0, $completed = 0, $category = '',
                     $alarm = 0, $parent = '', $private = false,
-                    $owner = null, $assignee = null, $completed_date = null)
+                    $owner = null, $assignee = null, $completed_date = null,
+                    $tasklist = null)
     {
         /* Retrieve unmodified task. */
         $task = $this->get($taskId);
@@ -298,10 +301,65 @@ class Nag_Driver {
             return $modify;
         }
 
+        /* Update alarm if necessary. */
+        if (!empty($GLOBALS['conf']['alarms']['driver'])) {
+            require_once 'Horde/Alarm.php';
+            $horde_alarm = Horde_Alarm::factory();
+            if (empty($alarm) || $completed) {
+                $horde_alarm->delete($task->uid);
+            } else {
+                $task = $this->get($taskId);
+                $alarm = $task->toAlarm();
+                if ($alarm) {
+                    $alarm['start'] = new Horde_Date($alarm['start']);
+                    $horde_alarm->set($alarm);
+                }
+            }
+        }
+
+        $new_task = $this->get($task->id);
+        $log_tasklist = $this->_tasklist;
+        if (!is_null($tasklist) && $task->tasklist != $tasklist) {
+            /* Moving the task to another tasklist. */
+            $share = $GLOBALS['nag_shares']->getShare($task->tasklist);
+            if (is_a($share, 'PEAR_Error')) {
+                return $share;
+            }
+
+            if (!$share->hasPermission(Auth::getAuth(), PERMS_DELETE)) {
+                $GLOBALS['notification']->push(sprintf(_("Access denied removing task from %s."), $share->get('name')), 'horde.error');
+                return false;
+            }
+
+            $share = $GLOBALS['nag_shares']->getShare($tasklist);
+            if (is_a($share, 'PEAR_Error')) {
+                return $share;
+            }
+
+            if (!$share->hasPermission(Auth::getAuth(), PERMS_EDIT)) {
+                $GLOBALS['notification']->push(sprintf(_("Access denied moving the task to %s."), $share->get('name')), 'horde.error');
+            }
+
+            $moved = $this->_move($task->id, $tasklist);
+            if (is_a($moved, 'PEAR_Error')) {
+                return $moved;
+            }
+            $new_storage = &Nag_Driver::singleton($tasklist);
+            $new_task = $new_storage->get($task->id);
+
+            /* Log the moving of this item in the history log. */
+            if (!empty($task->uid)) {
+                $history = &Horde_History::singleton();
+                $history->log('nag:' . $task->tasklist . ':' . $task->uid, array('action' => 'delete'), true);
+                $history->log('nag:' . $tasklist . ':' . $task->uid, array('action' => 'add'), true);
+                $log_tasklist = $tasklist;
+            }
+        }
+
         /* Log the modification of this item in the history log. */
         if (!empty($task->uid)) {
             $history = &Horde_History::singleton();
-            $history->log('nag:' . $this->_tasklist . ':' . $task->uid, array('action' => 'modify'), true);
+            $history->log('nag:' . $log_tasklist . ':' . $task->uid, array('action' => 'modify'), true);
         }
 
         /* Log completion status changes. */
@@ -311,34 +369,18 @@ class Nag_Driver {
             if (!$completed) {
                 $attributes['ts'] = 0;
             }
-            $history->log('nag:' . $this->_tasklist . ':' . $task->uid, $attributes, true);
+            $history->log('nag:' . $log_tasklist . ':' . $task->uid, $attributes, true);
         }
 
         /* Notify users about the changed event. */
-        $result = Nag::sendNotification('edit', $this->_tasklist, $name, $desc, $due, $priority);
+        $result = Nag::sendNotification('edit', $new_task, $task);
         if (is_a($result, 'PEAR_Error')) {
             Horde::logMessage($result, __FILE__, __LINE__, PEAR_LOG_ERR);
         }
 
-        /* Update alarm if necessary. */
-        if (!empty($GLOBALS['conf']['alarms']['driver'])) {
-            require_once 'Horde/Alarm.php';
-            $horde_alarm = Horde_Alarm::factory();
-            if (empty($alarm) || $completed) {
-                $horde_alarm->delete($task->uid);
-            } else {
-                $task = $this->get($taskId);
-                $alarm = $task->toAlarm();
-                if ($alarm) {
-                    $alarm['start'] = new Horde_Date($alarm['start']);
-                    $horde_alarm->set($alarm);
-                }
-            }
-        }
-
         return true;
     }
-
+    
     /**
      * Deletes a task and handles notification.
      *
@@ -361,7 +403,7 @@ class Nag_Driver {
         }
 
         /* Notify users about the deleted event. */
-        $result = Nag::sendNotification('delete', $this->_tasklist, $task->name, $task->desc, $task->due, $task->priority);
+        $result = Nag::sendNotification('delete', $task);
         if (is_a($result, 'PEAR_Error')) {
             Horde::logMessage($result, __FILE__, __LINE__, PEAR_LOG_ERR);
         }
@@ -688,6 +730,20 @@ class Nag_Task {
     }
 
     /**
+     * Returns the parent task of this task, if one exists.
+     *
+     * @return Nag_Task  The parent task, null if none exists, PEAR_Error on
+     *                   failure.
+     */
+    function getParent()
+    {
+        if (!$this->parent_id) {
+            return null;
+        }
+        return Nag::getTask($this->tasklist, $this->parent_id);
+    }
+
+    /**
      * Adds a sub task to this task.
      *
      * @param Nag_Task $task  A sub task.
@@ -817,6 +873,19 @@ class Nag_Task {
     }
 
     /**
+     * Format the description - link URLs, etc.
+     *
+     * @return string
+     */
+    function getFormattedDescription()
+    {
+        require_once 'Horde/Text/Filter.php';
+        $desc = Text_Filter::filter($this->desc, 'text2html', array('parselevel' => TEXT_HTML_MICRO));
+        $desc = Horde::callHook('_nag_hook_format_description', array($desc), 'nag', $desc);
+        return $desc;
+    }
+
+    /**
      * Resets the tasks iterator.
      *
      * Call this each time before looping through the tasks.
@@ -966,6 +1035,8 @@ class Nag_Task {
             NAG_SORT_CATEGORY => 'ByCategory',
             NAG_SORT_DUE => 'ByDue',
             NAG_SORT_COMPLETION => 'ByCompletion',
+            NAG_SORT_ASSIGNEE => 'ByAssignee',
+            NAG_SORT_ESTIMATE => 'ByEstimate',
             NAG_SORT_OWNER => 'ByOwner'
         );
 
@@ -1114,8 +1185,6 @@ class Nag_Task {
 
         if (!empty($this->assignee)) {
             $vTodo->setAttribute('ORGANIZER', $this->assignee);
-        } elseif (!empty($this->owner)) {
-            $vTodo->setAttribute('ORGANIZER', $this->owner);
         }
 
         if (!empty($this->name)) {
diff --git a/lib/Driver/kolab.php b/lib/Driver/kolab.php
index 4f2d808..1c3c961 100644
--- a/lib/Driver/kolab.php
+++ b/lib/Driver/kolab.php
@@ -2,9 +2,9 @@
 /**
  * Nag driver classes for the Kolab IMAP server.
  *
- * $Horde: nag/lib/Driver/kolab.php,v 1.6.10.13 2008/01/02 11:32:30 jan Exp $
+ * $Horde: nag/lib/Driver/kolab.php,v 1.6.10.16 2009/01/06 15:25:06 jan Exp $
  *
- * Copyright 2004-2008 The Horde Project (http://www.horde.org/)
+ * Copyright 2004-2009 The Horde Project (http://www.horde.org/)
  *
  * See the enclosed file COPYING for license information (GPL). If you
  * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
@@ -165,7 +165,7 @@ class Nag_Driver_kolab extends Nag_Driver {
      * @param string $taskId       The task to move.
      * @param string $newTasklist  The new tasklist.
      */
-    function move($taskId, $newTasklist)
+    function _move($taskId, $newTasklist)
     {
         return $this->_wrapper->move($taskId, $newTasklist);
     }
@@ -820,7 +820,7 @@ class Nag_Driver_kolab_wrapper_new extends Nag_Driver_kolab_wrapper {
                                           'alarm' => $alarm,
                                           'parent' => $parent,
                                           'sensitivity' => $sensitivity,
-                                          'estimate' => (int) $estimate,
+                                          'estimate' => $estimate,
                                           'completed_date' => $completed_date,
                                           'creator' => array(
                                               'smpt-address' => $owner,
diff --git a/lib/Driver/sql.php b/lib/Driver/sql.php
index 80045fc..beafb1f 100644
--- a/lib/Driver/sql.php
+++ b/lib/Driver/sql.php
@@ -29,7 +29,7 @@
  *
  * The table structure can be created by the scripts/sql/nag.sql script.
  *
- * $Horde: nag/lib/Driver/sql.php,v 1.60.2.21 2008/05/25 17:02:09 jan Exp $
+ * $Horde: nag/lib/Driver/sql.php,v 1.60.2.23 2009/02/17 18:43:18 chuck Exp $
  *
  * See the enclosed file COPYING for license information (GPL). If you
  * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
@@ -290,7 +290,7 @@ class Nag_Driver_sql extends Nag_Driver {
      * @param string $taskId       The task to move.
      * @param string $newTasklist  The new tasklist.
      */
-    function move($taskId, $newTasklist)
+    function _move($taskId, $newTasklist)
     {
         $query = sprintf('UPDATE %s SET task_owner = ? WHERE task_owner = ? AND task_id = ?',
                          $this->_params['table']);
@@ -591,7 +591,8 @@ class Nag_Driver_sql extends Nag_Driver {
         /* Connect to the SQL server using the supplied parameters. */
         require_once 'DB.php';
         $this->_write_db = &DB::connect($this->_params,
-                                        array('persistent' => !empty($this->_params['persistent'])));
+                                        array('persistent' => !empty($this->_params['persistent']),
+                                              'ssl' => !empty($this->_params['ssl'])));
         if (is_a($this->_write_db, 'PEAR_Error')) {
             return $this->_write_db;
         }
@@ -610,7 +611,8 @@ class Nag_Driver_sql extends Nag_Driver {
         if (!empty($this->_params['splitread'])) {
             $params = array_merge($this->_params, $this->_params['read']);
             $this->_db = &DB::connect($params,
-                                      array('persistent' => !empty($params['persistent'])));
+                                      array('persistent' => !empty($params['persistent']),
+                                            'ssl' => !empty($params['ssl'])));
             if (is_a($this->_db, 'PEAR_Error')) {
                 return $this->_db;
             }
diff --git a/lib/Forms/CreateTaskList.php b/lib/Forms/CreateTaskList.php
index 1d04f19..f9e9dcf 100644
--- a/lib/Forms/CreateTaskList.php
+++ b/lib/Forms/CreateTaskList.php
@@ -2,7 +2,7 @@
 /**
  * Horde_Form for creating task lists.
  *
- * $Horde: nag/lib/Forms/CreateTaskList.php,v 1.1.2.1 2007/12/20 14:23:08 jan Exp $
+ * $Horde: nag/lib/Forms/CreateTaskList.php,v 1.1.2.2 2008/07/31 10:10:03 jan Exp $
  *
  * See the enclosed file COPYING for license information (GPL). If you
  * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
@@ -33,8 +33,8 @@ class Nag_CreateTaskListForm extends Horde_Form {
     {
         parent::Horde_Form($vars, _("Create Task List"));
 
-        $this->addVariable(_("Name"), 'name', 'text', true);
-        $this->addVariable(_("Description"), 'description', 'longtext', false, false, null, array(4, 60));
+        $this->addVariable(_("Task List Name"), 'name', 'text', true);
+        $this->addVariable(_("Task List Description"), 'description', 'longtext', false, false, null, array(4, 60));
 
         $this->setButtons(array(_("Create")));
     }
diff --git a/lib/Forms/EditTaskList.php b/lib/Forms/EditTaskList.php
index 8114e22..9ff9cda 100644
--- a/lib/Forms/EditTaskList.php
+++ b/lib/Forms/EditTaskList.php
@@ -2,7 +2,7 @@
 /**
  * Horde_Form for editing task lists.
  *
- * $Horde: nag/lib/Forms/EditTaskList.php,v 1.1.2.1 2007/12/20 14:23:08 jan Exp $
+ * $Horde: nag/lib/Forms/EditTaskList.php,v 1.1.2.2 2008/07/31 10:10:03 jan Exp $
  *
  * See the enclosed file COPYING for license information (GPL). If you
  * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
@@ -40,8 +40,8 @@ class Nag_EditTaskListForm extends Horde_Form {
         parent::Horde_Form($vars, sprintf(_("Edit %s"), $tasklist->get('name')));
 
         $this->addHidden('', 't', 'text', true);
-        $this->addVariable(_("Name"), 'name', 'text', true);
-        $this->addVariable(_("Description"), 'description', 'longtext', false, false, null, array(4, 60));
+        $this->addVariable(_("Task List Name"), 'name', 'text', true);
+        $this->addVariable(_("Task List Description"), 'description', 'longtext', false, false, null, array(4, 60));
 
         $this->setButtons(array(_("Save")));
     }
diff --git a/lib/Forms/task.php b/lib/Forms/task.php
index 9b2cf0b..6c7ad37 100644
--- a/lib/Forms/task.php
+++ b/lib/Forms/task.php
@@ -2,7 +2,7 @@
 /**
  * This file contains all Horde_Form extensions required for editing tasks.
  *
- * $Horde: nag/lib/Forms/task.php,v 1.11.2.4 2008/04/19 05:58:50 chuck Exp $
+ * $Horde: nag/lib/Forms/task.php,v 1.11.2.10 2009/03/31 14:51:04 chuck Exp $
  *
  * See the enclosed file COPYING for license information (GPL). If you
  * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
@@ -58,6 +58,29 @@ class Nag_TaskForm extends Horde_Form {
             }
             $task_enums[htmlspecialchars($task->id)] = str_repeat('&nbsp;', $task->indent * 4) . htmlentities($task->name, ENT_COMPAT, NLS::getCharset());
         }
+        $users = array();
+        $share = &$GLOBALS['nag_shares']->getShare($tasklist);
+        if (!is_a($share, 'PEAR_Error')) {
+            $users = $share->listUsers(PERMS_READ);
+            $groups = $share->listGroups(PERMS_READ);
+            if (count($groups)) {
+                require_once 'Horde/Group.php';
+                $horde_group = &Group::singleton();
+                foreach ($groups as $group) {
+                    $users = array_merge($users,
+                                         $horde_group->listAllUsers($group));
+                }
+            }
+            $users = array_flip($users);
+        }
+        if (count($users)) {
+            require_once 'Horde/Identity.php';
+            foreach (array_keys($users) as $user) {
+                $identity = &Identity::singleton('none', $user);
+                $fullname = $identity->getValue('fullname');
+                $users[$user] = strlen($fullname) ? $fullname : $user;
+            }
+        }
         $priorities = array(1 => '1 ' . _("(highest)"), 2 => 2, 3 => 3,
                             4 => 4, 5 => '5 ' . _("(lowest)"));
 
@@ -81,10 +104,11 @@ class Nag_TaskForm extends Horde_Form {
             require_once 'Horde/Prefs/CategoryManager.php';
             require_once 'Horde/Array.php';
             $values = Horde_Array::valuesToKeys(Prefs_CategoryManager::get());
-            $values = array_merge(array('' => _("Unfiled")), $values);
-            $this->addVariable(_("Category"), 'category', 'enum', false, false, false, array($values));
+            $this->addVariable(_("Category"), 'category', 'enum', false, false, false, array($values, _("Unfiled")));
         }
 
+        $this->addVariable(_("Assignee"), 'assignee', 'enum', false, false,
+                           null, array($users, _("None")));
         $this->addVariable(_("Private?"), 'private', 'boolean', false);
         $this->addVariable(_("Due By"), 'due', 'nag_due', false);
         $this->addVariable(_("Delay Start Until"), 'start', 'nag_start', false);
@@ -95,7 +119,8 @@ class Nag_TaskForm extends Horde_Form {
 
         $this->addVariable(_("Estimated Time"), 'estimate', 'number', false);
         $this->addVariable(_("Completed?"), 'completed', 'boolean', false);
-        $this->addVariable(_("Description"), 'desc', 'longtext', false);
+        $this->addVariable(_("Description"), 'desc', 'longtext', false, false,
+                           Horde::callHook('_nag_hook_description_help', array(), 'nag', ''));
 
         $buttons = array(_("Save"));
         if ($delete) {
@@ -128,7 +153,7 @@ class Nag_TaskForm_Renderer extends Horde_Form_Renderer {
 <?php if ($this->delete): ?>
     <input class="button rightFloat" name="submitbutton" type="submit" value="<?php echo _("Delete this task") ?>" />
 <?php endif; ?>
-    <br class="clear" />
+    <div class="clear"></div>
 </div>
 <?php
     }
@@ -156,9 +181,15 @@ class Horde_Form_Type_nag_alarm extends Horde_Form_Type {
 
     function isValid(&$var, &$vars, $value, &$message)
     {
-        if ($value['on'] && empty($value['value'])) {
-            $message = _("The alarm value must not be empty.");
-            return false;
+        if ($value['on']) {
+            if ($vars->get('due_type') == 'none') {
+                $message = _("A due date must be set to enable alarms.");
+                return false;
+            }
+            if (empty($value['value'])) {
+                $message = _("The alarm value must not be empty.");
+                return false;
+            }
         }
 
         return true;
diff --git a/lib/Nag.php b/lib/Nag.php
index 412be77..869f969 100644
--- a/lib/Nag.php
+++ b/lib/Nag.php
@@ -31,6 +31,16 @@ define('NAG_SORT_CATEGORY', 'category');
 define('NAG_SORT_OWNER', 'tasklist');
 
 /**
+ * Sort by estimate.
+ */
+define('NAG_SORT_ESTIMATE', 'estimate');
+
+/**
+ * Sort by assignee.
+ */
+define('NAG_SORT_ASSIGNEE', 'assignee');
+
+/**
  * Sort in ascending order.
  */
 define('NAG_SORT_ASCEND', 0);
@@ -43,7 +53,7 @@ define('NAG_SORT_DESCEND', 1);
 /**
  * Nag Base Class.
  *
- * $Horde: nag/lib/Nag.php,v 1.124.2.24 2008/05/25 17:03:12 jan Exp $
+ * $Horde: nag/lib/Nag.php,v 1.124.2.33 2009/01/13 15:46:34 chuck Exp $
  *
  * See the enclosed file COPYING for license information (GPL). If you
  * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
@@ -90,9 +100,7 @@ class Nag {
      *
      * This function will also sort the resulting list, if requested.
      *
-     * @param string $sortby      The field by which to sort
-     *                            (NAG_SORT_PRIORITY, NAG_SORT_NAME
-     *                            NAG_SORT_DUE, NAG_SORT_COMPLETION).
+     * @param string $sortby      The field by which to sort (NAG_SORT_*).
      * @param integer $sortdir    The direction by which to sort
      *                            (NAG_SORT_ASCEND, NAG_SORT_DESCEND).
      * @param string $altsortby   The secondary sort field.
@@ -157,6 +165,9 @@ class Nag {
                 if ($app != 'nag' &&
                     $registry->hasMethod('getListTypes', $app)) {
                     $types = $registry->callByPackage($app, 'getListTypes');
+                    if (is_a($types, 'PEAR_Error')) {
+                        continue;
+                    }
                     if (!empty($types['taskHash'])) {
                         $newtasks = $registry->callByPackage($app, 'listAs', array('taskHash'));
                         if (is_a($newtasks, 'PEAR_Error')) {
@@ -271,7 +282,13 @@ class Nag {
      */
     function listTasklists($owneronly = false, $permission = PERMS_SHOW)
     {
-        $tasklists = $GLOBALS['nag_shares']->listShares(Auth::getAuth(), $permission, $owneronly ? Auth::getAuth() : null, 0, 0, 'name');
+        // Work around BC break in listShares() parameters (http://bugs.horde.org/ticket/7820)
+        include_once $GLOBALS['registry']->get('fileroot', 'horde') . '/lib/version.php';
+        if (version_compare(HORDE_VERSION, '3.2', '<')) {
+            $tasklists = $GLOBALS['nag_shares']->listShares(Auth::getAuth(), $permission, $owneronly ? Auth::getAuth() : null, DATATREE_ROOT, true, 0, 0, 'name');
+        } else {
+            $tasklists = $GLOBALS['nag_shares']->listShares(Auth::getAuth(), $permission, $owneronly ? Auth::getAuth() : null, 0, 0, 'name');
+        }
         if (is_a($tasklists, 'PEAR_Error')) {
             Horde::logMessage($tasklists, __FILE__, __LINE__, PEAR_LOG_ERR);
             return array();
@@ -453,6 +470,40 @@ class Nag {
     }
 
     /**
+     * Returns the full name and a compose to message an assignee.
+     *
+     * @param string $assignee  The assignee's user name.
+     * @param boolean $link     Whether to link to an email compose screen.
+     *
+     * @return string  The formatted assignee name.
+     */
+    function formatAssignee($assignee, $link = false)
+    {
+        if (!strlen($assignee)) {
+            return '';
+        }
+
+        require_once 'Horde/Identity.php';
+        $identity = &Identity::singleton('none', $assignee);
+        $fullname = $identity->getValue('fullname');
+        if (!strlen($fullname)) {
+            $fullname = $assignee;
+        }
+        $email = $identity->getValue('from_addr');
+        if ($link && !empty($email) &&
+            $GLOBALS['registry']->hasMethod('mail/compose')) {
+            return Horde::link($GLOBALS['registry']->call(
+                                   'mail/compose',
+                                   array(array('to' => $email))))
+                . @htmlspecialchars($fullname . ' <' . $email . '>',
+                                    ENT_COMPAT, NLS::getCharset())
+                . '</a>';
+        } else {
+            return @htmlspecialchars($fullname, ENT_COMPAT, NLS::getCharset());
+        }
+    }
+
+    /**
      * Returns the specified permission for the current user.
      *
      * @since Nag 2.1
@@ -642,62 +693,39 @@ class Nag {
      * Sends email notifications that a task has been added, edited, or
      * deleted to users that want such notifications.
      *
-     * @param string $action     The event action. One of "add", "edit", or
-     *                           "delete".
-     * @param string $tasklist   The tasklist of the task we are dealing with.
-     * @param string $name       The name (short) of the task.
-     * @param string $desc       The description (long) of the task.
-     * @param integer $due       The due date of the task.
-     * @param integer $priority  The priority of the task.
+     * @param string $action      The event action. One of "add", "edit", or
+     *                            "delete".
+     * @param Nag_Task $task      The changed task.
+     * @param Nag_Task $old_task  The original task if $action is "edit".
      */
-    function sendNotification($action, $tasklist, $name, $desc, $due, $priority)
+    function sendNotification($action, $task, $old_task = null)
     {
-        global $conf;
-
-        switch ($action) {
-        case 'add':
-            $subject = _("Task added:");
-            $notification_message = _("You requested to be notified when tasks are added to your tasklists.") . "\n\n" . _("The task \"%s\" has been added to \"%s\" tasklist, with a due date of: %s.");
-            break;
-
-        case 'edit':
-            $subject = _("Task modified:");
-            $notification_message = _("You requested to be notified when tasks are edited on your tasklists.") . "\n\n" . _("The task \"%s\" has been edited on \"%s\" tasklist, with a due date of: %s.");
-            break;
-
-        case 'delete':
-            $subject = _("Task deleted:");
-            $notification_message = _("You requested to be notified when tasks are deleted from your tasklists.") . "\n\n" . _("The task \"%s\" has been deleted from \"%s\" tasklist, with a due date of: %s.");
-            break;
-
-        default:
+        if (!in_array($action, array('add', 'edit', 'delete'))) {
             return PEAR::raiseError('Unknown event action: ' . $action);
         }
 
+        $share = &$GLOBALS['nag_shares']->getShare($task->tasklist);
+        if (is_a($share, 'PEAR_Error')) {
+            return $share;
+        }
+
         require_once 'Horde/Group.php';
         require_once 'Horde/Identity.php';
         require_once 'Horde/MIME.php';
         require_once 'Horde/MIME/Headers.php';
         require_once 'Horde/MIME/Message.php';
 
-        $share = &$GLOBALS['nag_shares']->getShare($tasklist);
-        if (is_a($share, 'PEAR_Error')) {
-            return $share;
-        }
-
         $groups = &Group::singleton();
         $recipients = array();
         $identity = &Identity::singleton();
         $from = $identity->getDefaultFromAddress(true);
 
         $owner = $share->get('owner');
-        if (Nag::_notificationPref($owner, 'owner')) {
-            $recipients[$owner] = true;
-        }
+        $recipients[$owner] = Nag::_notificationPref($owner, 'owner');
 
         foreach ($share->listUsers(PERMS_READ) as $user) {
-            if (!isset($recipients[$user])) {
-                $recipients[$user] = Nag::_notificationPref($user, 'read', $tasklist);
+            if (empty($recipients[$user])) {
+                $recipients[$user] = Nag::_notificationPref($user, 'read', $task->tasklist);
             }
         }
         foreach ($share->listGroups(PERMS_READ) as $group) {
@@ -711,53 +739,199 @@ class Nag {
                 continue;
             }
             foreach ($group_users as $user) {
-                if (!isset($recipients[$user])) {
-                    $recipients[$user] = Nag::_notificationPref($user, 'read', $tasklist);
+                if (empty($recipients[$user])) {
+                    $recipients[$user] = Nag::_notificationPref($user, 'read', $task->tasklist);
                 }
             }
         }
 
         $addresses = array();
-        foreach ($recipients as $user => $send) {
-            if ($send) {
-                $identity = &Identity::singleton('none', $user);
-                $email = $identity->getValue('from_addr');
-                if (strstr($email, '@')) {
-                    list($mailbox, $host) = explode('@', $email);
-                    $addresses[] = MIME::rfc822WriteAddress($mailbox, $host, $identity->getValue('fullname'));
-                }
+        foreach ($recipients as $user => $vals) {
+            if (!$vals) {
+                continue;
             }
+            $identity = &Identity::singleton('none', $user);
+            $email = $identity->getValue('from_addr');
+            if (strpos($email, '@') === false) {
+                continue;
+            }
+            list($mailbox, $host) = explode('@', $email);
+            if (!isset($addresses[$vals['lang']][$vals['tf']][$vals['df']])) {
+                $addresses[$vals['lang']][$vals['tf']][$vals['df']] = array();
+            }
+            $addresses[$vals['lang']][$vals['tf']][$vals['df']][] = MIME::rfc822WriteAddress($mailbox, $host, $identity->getValue('fullname'));
         }
 
-        if (!count($addresses)) {
+        if (!$addresses) {
             return;
         }
 
+        $mail_driver = $GLOBALS['conf']['mailer']['type'];
+        $mail_params = $GLOBALS['conf']['mailer']['params'];
+        if ($mail_driver == 'smtp' && $mail_params['auth'] &&
+            empty($mail_params['username'])) {
+            $mail_params['username'] = Auth::getAuth();
+            $mail_params['password'] = Auth::getCredential('password');
+        }
+
         $msg_headers = new MIME_Headers();
         $msg_headers->addMessageIdHeader();
         $msg_headers->addAgentHeader();
         $msg_headers->addHeader('Date', date('r'));
         $msg_headers->addHeader('From', $from);
-        $msg_headers->addHeader('Subject', $subject . ' ' . $name);
 
-        $message = "\n" . sprintf($notification_message, $name, $share->get('name'), $due ? strftime('%x %X', $due) : 'no due date' . "\n\n" . $desc);
+        foreach ($addresses as $lang => $twentyFour) {
+            NLS::setLang($lang);
+
+            $view_link = Util::addParameter(Horde::applicationUrl('view.php', true),
+                                            array('tasklist' => $task->tasklist,
+                                                  'task' => $task->id),
+                                            null, false);
+
+            switch ($action) {
+            case 'add':
+                $subject = _("Task added:");
+                $notification_message = _("You requested to be notified when tasks are added to your task lists.")
+                    . "\n\n"
+                    . _("The task \"%s\" has been added to task list \"%s\", with a due date of: %s.")
+                    . "\n"
+                    . str_replace("%","%%",$view_link);
+                break;
+
+            case 'edit':
+                $subject = _("Task modified:");
+                $notification_message = _("You requested to be notified when tasks are edited on your task lists.")
+                    . "\n\n"
+                    . _("The task \"%s\" has been edited on task list \"%s\".")
+                    . "\n"
+                    . str_replace("%","%%",$view_link)
+                    . "\n\n"
+                    . _("Changes made for this task:");
+                if ($old_task->name != $task->name) {
+                    $notification_message .= "\n - "
+                        . sprintf(_("Changed name from \"%s\" to \"%s\""),
+                                  $old_task->name, $task->name);
+                }
+                if ($old_task->tasklist != $task->tasklist) {
+                    $old_share = &$GLOBALS['nag_shares']->getShare($old_task->tasklist);
+                    $notification_message .= "\n - "
+                        . sprintf(_("Changed task list from \"%s\" to \"%s\""),
+                                  $old_share->get('name'), $share->get('name'));
+                }
+                if ($old_task->parent_id != $task->parent_id) {
+                    $old_parent = $old_task->getParent();
+                    if (!is_a($old_parent, 'PEAR_Error')) {
+                        $parent = $task->getParent();
+                        if (!is_a($parent, 'PEAR_Error')) {
+                            $notification_message .= "\n - "
+                                . sprintf(_("Changed parent task from \"%s\" to \"%s\""),
+                                          $old_parent ? $old_parent->name : _("no parent"),
+                                          $parent ? $parent->name : _("no parent"));
+                        }
+                    }
+                }
+                if ($old_task->category != $task->category) {
+                    $notification_message .= "\n - "
+                        . sprintf(_("Changed category from \"%s\" to \"%s\""),
+                                  $old_task->category, $task->category);
+                }
+                if ($old_task->assignee != $task->assignee) {
+                    require_once 'Horde/Identity.php';
+                    $identity = &Identity::singleton('none', $old_task->assignee);
+                    $old_name = $identity->getValue('fullname');
+                    if (!strlen($old_name)) {
+                        $old_name = $old_task->assignee;
+                    }
+                    $identity = &Identity::singleton('none', $task->assignee);
+                    $new_name = $identity->getValue('fullname');
+                    if (!strlen($new_name)) {
+                        $new_name = $new_task->assignee;
+                    }
+                    $notification_message .= "\n - "
+                        . sprintf(_("Changed assignee from \"%s\" to \"%s\""),
+                                  $old_name, $new_name);
+                }
+                if ($old_task->private != $task->private) {
+                    $notification_message .= "\n - "
+                        . ($task->private ? _("Turned privacy on") : _("Turned privacy off"));
+                }
+                if ($old_task->due != $task->due) {
+                    $notification_message .= "\n - "
+                        . sprintf(_("Changed due date from %s to %s"),
+                                  $old_task->due ? Nag::formatDate($old_task->due) : _("no due date"),
+                                  $task->due ? Nag::formatDate($task->due) : _("no due date"));
+                }
+                if ($old_task->start != $task->start) {
+                    $notification_message .= "\n - "
+                        . sprintf(_("Changed start date from %s to %s"),
+                                  $old_task->start ? Nag::formatDate($old_task->start) : _("no start date"),
+                                  $task->start ? Nag::formatDate($task->start) : _("no start date"));
+                }
+                if ($old_task->alarm != $task->alarm) {
+                    $notification_message .= "\n - "
+                        . sprintf(_("Changed alarm from %s to %s"),
+                                  Nag::formatAlarm($old_task->alarm), Nag::formatAlarm($task->alarm));
+                }
+                if ($old_task->priority != $task->priority) {
+                    $notification_message .= "\n - "
+                        . sprintf(_("Changed priority from %s to %s"),
+                                  $old_task->priority, $task->priority);
+                }
+                if ($old_task->estimate != $task->estimate) {
+                    $notification_message .= "\n - "
+                        . sprintf(_("Changed estimate from %s to %s"),
+                                  $old_task->estimate, $task->estimate);
+                }
+                if ($old_task->completed != $task->completed) {
+                    $notification_message .= "\n - "
+                        . sprintf(_("Changed completion from %s to %s"),
+                                  $old_task->completed ? _("completed") : _("not completed"),
+                                  $task->completed ? _("completed") : _("not completed"));
+                }
+                if ($old_task->desc != $task->desc) {
+                    $notification_message .= "\n - " . _("Changed description");
+                }
+                break;
+
+            case 'delete':
+                $subject = _("Task deleted:");
+                $notification_message =
+                    _("You requested to be notified when tasks are deleted from your task lists.")
+                    . "\n\n"
+                    . _("The task \"%s\" has been deleted from task list \"%s\".");
+                break;
+            }
 
-        $mime = new MIME_Message();
-        $body = new MIME_Part('text/plain', String::wrap($message, 76, "\n"), NLS::getCharset());
+            $msg_headers->removeHeader('Subject');
+            $msg_headers->addHeader('Subject', $subject . ' ' . $task->name);
+
+            foreach ($twentyFour as $tf => $dateFormat) {
+                foreach ($dateFormat as $df => $df_recipients) {
+                    $message = sprintf($notification_message,
+                                       $task->name,
+                                       $share->get('name'),
+                                       $task->due ? strftime($df, $task->due) . ' ' . date($tf ? 'H:i' : 'h:ia', $task->due) : _("no due date"));
+                    if (strlen(trim($task->desc))) {
+                        $message .= "\n\n" . _("Task description:") . "\n\n" . $task->desc;
+                    }
 
-        $mime->addPart($body);
-        $msg_headers->addMIMEHeaders($mime);
+                    $mime = new MIME_Message();
+                    $body = new MIME_Part('text/plain', String::wrap($message, 76, "\n"), NLS::getCharset());
 
-        $mail_driver = $conf['mailer']['type'];
-        $mail_params = $conf['mailer']['params'];
-        if ($mail_driver == 'smtp' && $mail_params['auth'] &&
-            empty($mail_params['username'])) {
-            $mail_params['username'] = Auth::getAuth();
-            $mail_params['password'] = Auth::getCredential('password');
-        }
+                    $mime->addPart($body);
+                    $msg_headers->addMIMEHeaders($mime);
 
-        Horde::logMessage(sprintf('Sending event notifications for %s to %s', $name, implode(', ', $addresses)), __FILE__, __LINE__, PEAR_LOG_DEBUG);
-        return $mime->send(implode(', ', $addresses), $msg_headers, $mail_driver, $mail_params);
+                    Horde::logMessage(sprintf('Sending event notifications for %s to %s',
+                                              $task->name, implode(', ', $df_recipients)),
+                                      __FILE__, __LINE__, PEAR_LOG_INFO);
+                    $sent = $mime->send(implode(', ', $df_recipients), $msg_headers,
+                                        $mail_driver, $mail_params);
+                    if (is_a($sent, 'PEAR_Error')) {
+                        return $sent;
+                    }
+                }
+            }
+        }
     }
 
     /**
@@ -808,17 +982,25 @@ class Nag {
                                    'nag', $user, '', null,
                                    false);
         $prefs->retrieve();
+        $vals = array('lang' => $prefs->getValue('language'),
+                      'tf' => $prefs->getValue('twentyFour'),
+                      'df' => $prefs->getValue('date_format'));
+
+        if ($prefs->getValue('task_notification_exclude_self') &&
+            $user == Auth::getAuth()) {
+            return false;
+        }
 
         $notification = $prefs->getValue('task_notification');
         switch ($notification) {
         case 'owner':
-            return $mode == 'owner';
+            return $mode == 'owner' ? $vals : false;
         case 'read':
-            return $mode == 'read';
+            return $mode == 'read' ? $vals : false;
         case 'show':
             if ($mode == 'read') {
                 $display_tasklists = unserialize($prefs->getValue('display_tasklists'));
-                return in_array($tasklist, $display_tasklists);
+                return in_array($tasklist, $display_tasklists) ? $vals : false;;
             }
         }
 
@@ -888,6 +1070,72 @@ class Nag {
     }
 
     /**
+     * Comparison function for sorting tasks by assignee.
+     *
+     * @param array $a  Task one.
+     * @param array $b  Task two.
+     *
+     * @return integer  1 if task one is greater, -1 if task two is greater;
+     *                  0 if they are equal.
+     */
+    function _sortByAssignee($a, $b)
+    {
+        return strcasecmp($a->assignee, $b->assignee);
+    }
+
+    /**
+     * Comparison function for reverse sorting tasks by assignee.
+     *
+     * @param array $a  Task one.
+     * @param array $b  Task two.
+     *
+     * @return integer  -1 if task one is greater, 1 if task two is greater;
+     *                  0 if they are equal.
+     */
+    function _rsortByAssignee($a, $b)
+    {
+        return strcasecmp($b->assignee, $a->assignee);
+    }
+
+    /**
+     * Comparison function for sorting tasks by assignee.
+     *
+     * @param array $a  Task one.
+     * @param array $b  Task two.
+     *
+     * @return integer  1 if task one is greater, -1 if task two is greater;
+     *                  0 if they are equal.
+     */
+    function _sortByEstimate($a, $b)
+    {
+        $a_est = $a->estimation();
+        $b_est = $b->estimation();
+        if ($a_est == $b_est) {
+            return 0;
+        }
+        return ($a_est > $b_est) ? 1 : -1;
+    }
+
+    /**
+     * Comparison function for reverse sorting tasks by name.
+     *
+     * @param array $a  Task one.
+     * @param array $b  Task two.
+     *
+     * @return integer  -1 if task one is greater, 1 if task two is greater;
+     *                  0 if they are equal.
+     */
+    function _rsortByEstimate($a, $b)
+    {
+        $a_est = $a->estimation();
+        $b_est = $b->estimation();
+        if ($a_est == $b_est) {
+            return 0;
+        }
+        return ($a_est > $b_est) ? -1 : 1;
+    }
+
+    /**
      * Comparison function for sorting tasks by category.
      *
      * @param array $a  Task one.
diff --git a/lib/Recurrence.php b/lib/Recurrence.php
new file mode 100644
index 0000000..ecc1306
--- /dev/null
+++ b/lib/Recurrence.php
@@ -0,0 +1,1467 @@
+<?php
+/**
+ * This file contains the Nag_Recurrence class and according constants.
+ *
+ * $Horde: nag/lib/Recurrence.php,v 1.1.2.3 2009/01/06 15:25:05 jan Exp $
+ *
+ * Copyright 2007-2009 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file COPYING for license information (LGPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
+ *
+ * @since   Horde 3.2
+ * @package Horde_Date
+ */
+
+/** Horde_Date */
+require_once 'Horde/Date.php';
+
+/** Date_Calc */
+require_once 'Date/Calc.php';
+
+/** No recurrence. */
+define('NAG_RECUR_NONE', 0);
+/** Recurs daily. */
+define('NAG_RECUR_DAILY', 1);
+/** Recurs weekly. */
+define('NAG_RECUR_WEEKLY', 2);
+/** Recurs monthly on the same date. */
+define('NAG_RECUR_MONTHLY_DATE', 3);
+/** Recurs monthly on the same week day. */
+define('NAG_RECUR_MONTHLY_WEEKDAY', 4);
+/** Recurs yearly on the same date. */
+define('NAG_RECUR_YEARLY_DATE', 5);
+/** Recurs yearly on the same day of the year. */
+define('NAG_RECUR_YEARLY_DAY', 6);
+/** Recurs yearly on the same week day. */
+define('NAG_RECUR_YEARLY_WEEKDAY', 7);
+
+/**
+ * The Nag_Recurrence class implements algorithms for calculating
+ * recurrences of events, including several recurrence types, intervals,
+ * exceptions, and conversion from and to vCalendar and iCalendar recurrence
+ * rules.
+ *
+ * All methods expecting dates as parameters accept all values that the
+ * Horde_Date constructor accepts, i.e. a timestamp, another Horde_Date
+ * object, an ISO time string or a hash.
+ *
+ * @author  Jan Schneider <jan at horde.org>
+ * @since   Horde 3.2
+ * @package Horde_Date
+ */
+class Nag_Recurrence {
+
+    /**
+     * The start time of the event.
+     *
+     * @var Horde_Date
+     */
+    var $start;
+
+    /**
+     * The end date of the recurrence interval.
+     *
+     * @var Horde_Date
+     */
+    var $recurEnd = null;
+
+    /**
+     * The number of recurrences.
+     *
+     * @var integer
+     */
+    var $recurCount = null;
+
+    /**
+     * The type of recurrence this event follows. NAG_RECUR_* constant.
+     *
+     * @var integer
+     */
+    var $recurType = NAG_RECUR_NONE;
+
+    /**
+     * The length of time between recurrences. The time unit depends on the
+     * recurrence type.
+     *
+     * @var integer
+     */
+    var $recurInterval = 1;
+
+    /**
+     * Any additional recurrence data.
+     *
+     * @var integer
+     */
+    var $recurData = null;
+
+    /**
+     * All the exceptions from recurrence for this event.
+     *
+     * @var array
+     */
+    var $exceptions = array();
+
+    /**
+     * All the dates this recurrence has been marked as completed.
+     *
+     * @var array
+     */
+    var $completions = array();
+
+    /**
+     * Constructor.
+     *
+     * @param Horde_Date $start  Start of the recurring event.
+     */
+    function Nag_Recurrence($start)
+    {
+        $this->start = new Horde_Date($start);
+    }
+
+    /**
+     * Checks if this event recurs on a given day of the week.
+     *
+     * @param integer $dayMask  A mask consisting of HORDE_DATE_MASK_*
+     *                          constants specifying the day(s) to check.
+     *
+     * @return boolean  True if this event recurs on the given day(s).
+     */
+    function recurOnDay($dayMask)
+    {
+        return ($this->recurData & $dayMask);
+    }
+
+    /**
+     * Specifies the days this event recurs on.
+     *
+     * @param integer $dayMask  A mask consisting of HORDE_DATE_MASK_*
+     *                          constants specifying the day(s) to recur on.
+     */
+    function setRecurOnDay($dayMask)
+    {
+        $this->recurData = $dayMask;
+    }
+
+    /**
+     * Returns the days this event recurs on.
+     *
+     * @return integer  A mask consisting of HORDE_DATE_MASK_* constants
+     *                  specifying the day(s) this event recurs on.
+     */
+    function getRecurOnDays()
+    {
+        return $this->recurData;
+    }
+
+    /**
+     * Returns whether this event has a specific recurrence type.
+     *
+     * @param integer $recurrence  NAG_RECUR_* constant of the
+     *                             recurrence type to check for.
+     *
+     * @return boolean  True if the event has the specified recurrence type.
+     */
+    function hasRecurType($recurrence)
+    {
+        return ($recurrence == $this->recurType);
+    }
+
+    /**
+     * Sets a recurrence type for this event.
+     *
+     * @param integer $recurrence  A NAG_RECUR_* constant.
+     */
+    function setRecurType($recurrence)
+    {
+        $this->recurType = $recurrence;
+    }
+
+    /**
+     * Returns recurrence type of this event.
+     *
+     * @return integer  A NAG_RECUR_* constant.
+     */
+    function getRecurType()
+    {
+        return $this->recurType;
+    }
+
+    /**
+     * Returns a description of this event's recurring type.
+     *
+     * @return string  Human readable recurring type.
+     */
+    function getRecurName()
+    {
+        switch ($this->getRecurType()) {
+            case NAG_RECUR_NONE: return _("No recurrence");
+            case NAG_RECUR_DAILY: return _("Daily");
+            case NAG_RECUR_WEEKLY: return _("Weekly");
+            case NAG_RECUR_MONTHLY_DATE:
+            case NAG_RECUR_MONTHLY_WEEKDAY: return _("Monthly");
+            case NAG_RECUR_YEARLY_DATE:
+            case NAG_RECUR_YEARLY_DAY:
+            case NAG_RECUR_YEARLY_WEEKDAY: return _("Yearly");
+        }
+    }
+
+    /**
+     * Sets the length of time between recurrences of this event.
+     *
+     * @param integer $interval  The time between recurrences.
+     */
+    function setRecurInterval($interval)
+    {
+        if ($interval > 0) {
+            $this->recurInterval = $interval;
+        }
+    }
+
+    /**
+     * Retrieves the length of time between recurrences of this event.
+     *
+     * @return integer  The number of seconds between recurrences.
+     */
+    function getRecurInterval()
+    {
+        return $this->recurInterval;
+    }
+
+    /**
+     * Sets the number of recurrences of this event.
+     *
+     * @param integer $count  The number of recurrences.
+     */
+    function setRecurCount($count)
+    {
+        if ($count > 0) {
+            $this->recurCount = (int)$count;
+            // Recurrence counts and end dates are mutually exclusive.
+            $this->recurEnd = null;
+        } else {
+            $this->recurCount = null;
+        }
+    }
+
+    /**
+     * Retrieves the number of recurrences of this event.
+     *
+     * @return integer  The number recurrences.
+     */
+    function getRecurCount()
+    {
+        return $this->recurCount;
+    }
+
+    /**
+     * Returns whether this event has a recurrence with a fixed count.
+     *
+     * @return boolean  True if this recurrence has a fixed count.
+     */
+    function hasRecurCount()
+    {
+        return isset($this->recurCount);
+    }
+
+    /**
+     * Sets the start date of the recurrence interval.
+     *
+     * @param Horde_Date $start  The recurrence start.
+     */
+    function setRecurStart($start)
+    {
+        $this->start = new Horde_Date($start);
+    }
+
+    /**
+     * Retrieves the start date of the recurrence interval.
+     *
+     * @return Horde_Date  The recurrence start.
+     */
+    function getRecurStart()
+    {
+        return $this->start;
+    }
+
+    /**
+     * Sets the end date of the recurrence interval.
+     *
+     * @param Horde_Date $end  The recurrence end.
+     */
+    function setRecurEnd($end)
+    {
+        if (!empty($end)) {
+            // Recurrence counts and end dates are mutually exclusive.
+            $this->recurCount = null;
+        }
+        $this->recurEnd = new Horde_Date($end);
+    }
+
+    /**
+     * Retrieves the end date of the recurrence interval.
+     *
+     * @return Horde_Date  The recurrence end.
+     */
+    function getRecurEnd()
+    {
+        return $this->recurEnd;
+    }
+
+    /**
+     * Returns whether this event has a recurrence end.
+     *
+     * @return boolean  True if this recurrence ends.
+     */
+    function hasRecurEnd()
+    {
+        return isset($this->recurEnd) && isset($this->recurEnd->year) &&
+            $this->recurEnd->year != 9999;
+    }
+
+    /**
+     * Finds the next recurrence of this event that's after $afterDate.
+     *
+     * @param Horde_Date $afterDate  Return events after this date.
+     *
+     * @return Horde_Date|boolean  The date of the next recurrence or false
+     *                             if the event does not recur after
+     *                             $afterDate.
+     */
+    function nextRecurrence($afterDate)
+    {
+        $after = new Horde_Date($afterDate);
+        $after->correct();
+
+        if ($this->start->compareDateTime($after) >= 0) {
+            return new Horde_Date($this->start);
+        }
+
+        if ($this->recurInterval == 0) {
+            return false;
+        }
+
+        switch ($this->getRecurType()) {
+        case NAG_RECUR_DAILY:
+            $diff = Date_Calc::dateDiff($this->start->mday, $this->start->month, $this->start->year, $after->mday, $after->month, $after->year);
+            $recur = ceil($diff / $this->recurInterval);
+            if ($this->recurCount && $recur >= $this->recurCount) {
+                return false;
+            }
+            $recur *= $this->recurInterval;
+            $next = new Horde_Date($this->start);
+            list($next->mday, $next->month, $next->year) = explode('/', Date_Calc::daysToDate(Date_Calc::dateToDays($next->mday, $next->month, $next->year) + $recur, '%e/%m/%Y'));
+            if ((!$this->hasRecurEnd() ||
+                 $next->compareDateTime($this->recurEnd) <= 0) &&
+                $next->compareDateTime($after) >= 0) {
+                return new Horde_Date($next);
+            }
+            break;
+
+        case NAG_RECUR_WEEKLY:
+            if (empty($this->recurData)) {
+                return false;
+            }
+
+            list($start_week->mday, $start_week->month, $start_week->year) = explode('/', Date_Calc::beginOfWeek($this->start->mday, $this->start->month, $this->start->year, '%e/%m/%Y'));
+            $start_week->hour = $this->start->hour;
+            $start_week->min = $this->start->min;
+            $start_week->sec = $this->start->sec;
+            list($after_week->mday, $after_week->month, $after_week->year) = explode('/', Date_Calc::beginOfWeek($after->mday, $after->month, $after->year, '%e/%m/%Y'));
+            $after_week_end = new Horde_Date($after_week);
+            $after_week_end->mday += 7;
+            $after_week_end->correct();
+
+            $diff = Date_Calc::dateDiff($start_week->mday, $start_week->month, $start_week->year,
+                                        $after_week->mday, $after_week->month, $after_week->year);
+            $recur = $diff + ($diff % ($this->recurInterval * 7));
+            if ($this->recurCount &&
+                ceil($recur / 7) / $this->recurInterval >= $this->recurCount) {
+                return false;
+            }
+            $next = $start_week;
+            list($next->mday, $next->month, $next->year) = explode('/', Date_Calc::daysToDate(Date_Calc::dateToDays($next->mday, $next->month, $next->year) + $recur, '%e/%m/%Y'));
+            $next = new Horde_Date($next);
+            while ($next->compareDateTime($after) < 0 &&
+                   $next->compareDateTime($after_week_end) < 0) {
+                ++$next->mday;
+                $next->correct();
+            }
+            if (!$this->hasRecurEnd() ||
+                $next->compareDateTime($this->recurEnd) <= 0) {
+                if ($next->compareDateTime($after_week_end) >= 0) {
+                    return $this->nextRecurrence($after_week_end);
+                }
+                while (!$this->recurOnDay((int)pow(2, $next->dayOfWeek())) &&
+                       $next->compareDateTime($after_week_end) < 0) {
+                    ++$next->mday;
+                    $next->correct();
+                }
+                if (!$this->hasRecurEnd() ||
+                    $next->compareDateTime($this->recurEnd) <= 0) {
+                    if ($next->compareDateTime($after_week_end) >= 0) {
+                        return $this->nextRecurrence($after_week_end);
+                    } else {
+                        return $next;
+                    }
+                }
+            }
+            break;
+
+        case NAG_RECUR_MONTHLY_DATE:
+            $start = new Horde_Date($this->start);
+            if ($after->compareDateTime($start) < 0) {
+                $after = $start;
+            }
+
+            // If we're starting past this month's recurrence of the event,
+            // look in the next month on the day the event recurs.
+            if ($after->mday > $start->mday) {
+                ++$after->month;
+                $after->mday = $start->mday;
+                $after->correct();
+            }
+
+            // Adjust $start to be the first match.
+            $offset = ($after->month - $start->month) + ($after->year - $start->year) * 12;
+            $offset = floor(($offset + $this->recurInterval - 1) / $this->recurInterval) * $this->recurInterval;
+
+            if ($this->recurCount &&
+                ($offset / $this->recurInterval) >= $this->recurCount) {
+                return false;
+            }
+            $start->month += $offset;
+            $count = $offset / $this->recurInterval;
+
+            do {
+                if ($this->recurCount &&
+                    $count++ >= $this->recurCount) {
+                    return false;
+                }
+
+                // Don't correct for day overflow; we just skip February 30th,
+                // for example.
+                $start->correct(HORDE_DATE_MASK_MONTH);
+
+                // Bail if we've gone past the end of recurrence.
+                if ($this->hasRecurEnd() &&
+                    $this->recurEnd->compareDateTime($start) < 0) {
+                    return false;
+                }
+                if ($start->isValid()) {
+                    return $start;
+                }
+
+                // If the interval is 12, and the date isn't valid, then we
+                // need to see if February 29th is an option. If not, then the
+                // event will _never_ recur, and we need to stop checking to
+                // avoid an infinite loop.
+                if ($this->recurInterval == 12 && ($start->month != 2 || $start->mday > 29)) {
+                    return false;
+                }
+
+                // Add the recurrence interval.
+                $start->month += $this->recurInterval;
+            } while (true);
+
+            break;
+
+        case NAG_RECUR_MONTHLY_WEEKDAY:
+            // Start with the start date of the event.
+            $estart = new Horde_Date($this->start);
+
+            // What day of the week, and week of the month, do we recur on?
+            $nth = ceil($this->start->mday / 7);
+            $weekday = $estart->dayOfWeek();
+
+            // Adjust $estart to be the first candidate.
+            $offset = ($after->month - $estart->month) + ($after->year - $estart->year) * 12;
+            $offset = floor(($offset + $this->recurInterval - 1) / $this->recurInterval) * $this->recurInterval;
+
+            // Adjust our working date until it's after $after.
+            $estart->month += $offset - $this->recurInterval;
+
+            $count = $offset / $this->recurInterval;
+            do {
+                if ($this->recurCount &&
+                    $count++ >= $this->recurCount) {
+                    return false;
+                }
+
+                $estart->month += $this->recurInterval;
+                $estart->correct();
+
+                $next = new Horde_Date($estart);
+                $next->setNthWeekday($weekday, $nth);
+
+                if ($next->compareDateTime($after) < 0) {
+                    // We haven't made it past $after yet, try again.
+                    continue;
+                }
+                if ($this->hasRecurEnd() &&
+                    $next->compareDateTime($this->recurEnd) > 0) {
+                    // We've gone past the end of recurrence; we can give up
+                    // now.
+                    return false;
+                }
+
+                // We have a candidate to return.
+                break;
+            } while (true);
+
+            return $next;
+
+        case NAG_RECUR_YEARLY_DATE:
+            // Start with the start date of the event.
+            $estart = new Horde_Date($this->start);
+
+            if ($after->month > $estart->month ||
+                ($after->month == $estart->month && $after->mday > $estart->mday)) {
+                ++$after->year;
+                $after->month = $estart->month;
+                $after->mday = $estart->mday;
+            }
+
+            // Seperate case here for February 29th
+            if ($estart->month == 2 && $estart->mday == 29) {
+                while (!Horde_Date::isLeapYear($after->year)) {
+                    ++$after->year;
+                }
+            }
+
+            // Adjust $estart to be the first candidate.
+            $offset = $after->year - $estart->year;
+            if ($offset > 0) {
+                $offset = floor(($offset + $this->recurInterval - 1) / $this->recurInterval) * $this->recurInterval;
+                $estart->year += $offset;
+            }
+
+            // We've gone past the end of recurrence; give up.
+            if ($this->recurCount &&
+                $offset >= $this->recurCount) {
+                return false;
+            }
+            if ($this->hasRecurEnd() &&
+                $this->recurEnd->compareDateTime($estart) < 0) {
+                return false;
+            }
+
+            return $estart;
+
+        case NAG_RECUR_YEARLY_DAY:
+            // Check count first.
+            $dayofyear = $this->start->dayOfYear();
+            $count = ($after->year - $this->start->year) / $this->recurInterval + 1;
+            if ($this->recurCount &&
+                ($count > $this->recurCount ||
+                 ($count == $this->recurCount &&
+                  $after->dayOfYear() > $dayofyear))) {
+                return false;
+            }
+
+            // Start with a rough interval.
+            $estart = new Horde_Date($this->start);
+            $estart->year += floor($count - 1) * $this->recurInterval;
+
+            // Now add the difference to the required day of year.
+            $estart->mday += $dayofyear - $estart->dayOfYear();
+            $estart->correct();
+
+            // Add an interval if the estimation was wrong.
+            if ($estart->compareDate($after) < 0) {
+                $estart->year += $this->recurInterval;
+                $estart->mday += $dayofyear - $estart->dayOfYear();
+                $estart->correct();
+            }
+
+            // We've gone past the end of recurrence; give up.
+            if ($this->hasRecurEnd() &&
+                $this->recurEnd->compareDateTime($estart) < 0) {
+                return false;
+            }
+
+            return $estart;
+
+        case NAG_RECUR_YEARLY_WEEKDAY:
+            // Start with the start date of the event.
+            $estart = new Horde_Date($this->start);
+
+            // What day of the week, and week of the month, do we recur on?
+            $nth = ceil($this->start->mday / 7);
+            $weekday = $estart->dayOfWeek();
+
+            // Adjust $estart to be the first candidate.
+            $offset = floor(($after->year - $estart->year + $this->recurInterval - 1) / $this->recurInterval) * $this->recurInterval;
+
+            // Adjust our working date until it's after $after.
+            $estart->year += $offset - $this->recurInterval;
+
+            $count = $offset / $this->recurInterval;
+            do {
+                if ($this->recurCount &&
+                    $count++ >= $this->recurCount) {
+                    return false;
+                }
+
+                $estart->year += $this->recurInterval;
+                $estart->correct();
+
+                $next = new Horde_Date($estart);
+                $next->setNthWeekday($weekday, $nth);
+
+                if ($next->compareDateTime($after) < 0) {
+                    // We haven't made it past $after yet, try again.
+                    continue;
+                }
+                if ($this->hasRecurEnd() &&
+                    $next->compareDateTime($this->recurEnd) > 0) {
+                    // We've gone past the end of recurrence; we can give up
+                    // now.
+                    return false;
+                }
+
+                // We have a candidate to return.
+                break;
+            } while (true);
+
+            return $next;
+        }
+
+        // We didn't find anything, the recurType was bad, or something else
+        // went wrong - return false.
+        return false;
+    }
+
+    /**
+     * Returns whether this event has any date that matches the recurrence
+     * rules and is not an exception.
+     *
+     * @return boolean  True if an active recurrence exists.
+     */
+    function hasActiveRecurrence()
+    {
+        if (!$this->hasRecurEnd()) {
+            return true;
+        }
+
+        $next = $this->nextRecurrence(new Horde_Date($this->start));
+        while (is_object($next)) {
+            if (!$this->hasException($next->year, $next->month, $next->mday) &&
+                !$this->hasCompletion($next->year, $next->month, $next->mday)) {
+                return true;
+            }
+
+            $next = $this->nextRecurrence(array('year' => $next->year,
+                                                'month' => $next->month,
+                                                'mday' => $next->mday + 1,
+                                                'hour' => $next->hour,
+                                                'min' => $next->min,
+                                                'sec' => $next->sec));
+        }
+
+        return false;
+    }
+
+    /**
+     * Returns the next active recurrence.
+     *
+     * @param Horde_Date $afterDate  Return events after this date.
+     *
+     * @return Horde_Date|boolean The date of the next active
+     *                             recurrence or false if the event
+     *                             has no active recurrence after
+     *                             $afterDate.
+     */
+    function nextActiveRecurrence($afterDate)
+    {
+        $next = $this->nextRecurrence($afterDate);
+        while (is_object($next)) {
+            if (!$this->hasException($next->year, $next->month, $next->mday) &&
+                !$this->hasCompletion($next->year, $next->month, $next->mday)) {
+                return $next;
+            }
+            $next->mday++;
+            $next = $this->nextRecurrence($next);
+        }
+
+        return false;
+    }
+
+    /**
+     * Adds an exception to a recurring event.
+     *
+     * @param integer $year   The year of the execption.
+     * @param integer $month  The month of the execption.
+     * @param integer $mday   The day of the month of the exception.
+     */
+    function addException($year, $month, $mday)
+    {
+        $this->exceptions[] = sprintf('%04d%02d%02d', $year, $month, $mday);
+    }
+
+    /**
+     * Deletes an exception from a recurring event.
+     *
+     * @param integer $year   The year of the execption.
+     * @param integer $month  The month of the execption.
+     * @param integer $mday   The day of the month of the exception.
+     */
+    function deleteException($year, $month, $mday)
+    {
+        $key = array_search(sprintf('%04d%02d%02d', $year, $month, $mday), $this->exceptions);
+        if ($key !== false) {
+            unset($this->exceptions[$key]);
+        }
+    }
+
+    /**
+     * Checks if an exception exists for a given reccurence of an event.
+     *
+     * @param integer $year   The year of the reucrance.
+     * @param integer $month  The month of the reucrance.
+     * @param integer $mday   The day of the month of the reucrance.
+     *
+     * @return boolean  True if an exception exists for the given date.
+     */
+    function hasException($year, $month, $mday)
+    {
+        return in_array(sprintf('%04d%02d%02d', $year, $month, $mday),
+                        $this->getExceptions());
+    }
+
+    /**
+     * Retrieves all the exceptions for this event.
+     *
+     * @return array  Array containing the dates of all the exceptions in
+     *                YYYYMMDD form.
+     */
+    function getExceptions()
+    {
+        return $this->exceptions;
+    }
+
+    /**
+     * Adds a completion to a recurring event.
+     *
+     * @param integer $year   The year of the execption.
+     * @param integer $month  The month of the execption.
+     * @param integer $mday   The day of the month of the completion.
+     */
+    function addCompletion($year, $month, $mday)
+    {
+        $this->completions[] = sprintf('%04d%02d%02d', $year, $month, $mday);
+    }
+
+    /**
+     * Deletes a completion from a recurring event.
+     *
+     * @param integer $year   The year of the execption.
+     * @param integer $month  The month of the execption.
+     * @param integer $mday   The day of the month of the completion.
+     */
+    function deleteCompletion($year, $month, $mday)
+    {
+        $key = array_search(sprintf('%04d%02d%02d', $year, $month, $mday), $this->completions);
+        if ($key !== false) {
+            unset($this->completions[$key]);
+        }
+    }
+
+    /**
+     * Checks if a completion exists for a given reccurence of an event.
+     *
+     * @param integer $year   The year of the reucrance.
+     * @param integer $month  The month of the recurrance.
+     * @param integer $mday   The day of the month of the recurrance.
+     *
+     * @return boolean  True if a completion exists for the given date.
+     */
+    function hasCompletion($year, $month, $mday)
+    {
+        return in_array(sprintf('%04d%02d%02d', $year, $month, $mday),
+                        $this->getCompletions());
+    }
+
+    /**
+     * Retrieves all the completions for this event.
+     *
+     * @return array  Array containing the dates of all the completions in
+     *                YYYYMMDD form.
+     */
+    function getCompletions()
+    {
+        return $this->completions;
+    }
+
+    /**
+     * Parses a vCalendar 1.0 recurrence rule.
+     *
+     * @link http://www.imc.org/pdi/vcal-10.txt
+     * @link http://www.shuchow.com/vCalAddendum.html
+     *
+     * @param string $rrule  A vCalendar 1.0 conform RRULE value.
+     */
+    function fromRRule10($rrule)
+    {
+        if (!$rrule) {
+            return;
+        }
+
+        if (!preg_match('/([A-Z]+)(\d+)?(.*)/', $rrule, $matches)) {
+            // No recurrence data - event does not recur.
+            $this->setRecurType(NAG_RECUR_NONE);
+        }
+
+        // Always default the recurInterval to 1.
+        $this->setRecurInterval(!empty($matches[2]) ? $matches[2] : 1);
+
+        $remainder = trim($matches[3]);
+
+        switch ($matches[1]) {
+        case 'D':
+            $this->setRecurType(NAG_RECUR_DAILY);
+            break;
+
+        case 'W':
+            $this->setRecurType(NAG_RECUR_WEEKLY);
+            if (!empty($remainder)) {
+                $maskdays = array('SU' => HORDE_DATE_MASK_SUNDAY,
+                                  'MO' => HORDE_DATE_MASK_MONDAY,
+                                  'TU' => HORDE_DATE_MASK_TUESDAY,
+                                  'WE' => HORDE_DATE_MASK_WEDNESDAY,
+                                  'TH' => HORDE_DATE_MASK_THURSDAY,
+                                  'FR' => HORDE_DATE_MASK_FRIDAY,
+                                  'SA' => HORDE_DATE_MASK_SATURDAY);
+                $mask = 0;
+                while (preg_match('/^ ?[A-Z]{2} ?/', $remainder, $matches)) {
+                    $day = trim($matches[0]);
+                    $remainder = substr($remainder, strlen($matches[0]));
+                    $mask |= $maskdays[$day];
+                }
+                $this->setRecurOnDay($mask);
+            } else {
+                // Recur on the day of the week of the original recurrence.
+                $maskdays = array(HORDE_DATE_SUNDAY => HORDE_DATE_MASK_SUNDAY,
+                                  HORDE_DATE_MONDAY => HORDE_DATE_MASK_MONDAY,
+                                  HORDE_DATE_TUESDAY => HORDE_DATE_MASK_TUESDAY,
+                                  HORDE_DATE_WEDNESDAY => HORDE_DATE_MASK_WEDNESDAY,
+                                  HORDE_DATE_THURSDAY => HORDE_DATE_MASK_THURSDAY,
+                                  HORDE_DATE_FRIDAY => HORDE_DATE_MASK_FRIDAY,
+                                  HORDE_DATE_SATURDAY => HORDE_DATE_MASK_SATURDAY);
+                $this->setRecurOnDay($maskdays[$this->start->dayOfWeek()]);
+            }
+            break;
+
+        case 'MP':
+            $this->setRecurType(NAG_RECUR_MONTHLY_WEEKDAY);
+            break;
+
+        case 'MD':
+            $this->setRecurType(NAG_RECUR_MONTHLY_DATE);
+            break;
+
+        case 'YM':
+            $this->setRecurType(NAG_RECUR_YEARLY_DATE);
+            break;
+
+        case 'YD':
+            $this->setRecurType(NAG_RECUR_YEARLY_DAY);
+            break;
+        }
+
+        // We don't support modifiers at the moment, strip them.
+        while ($remainder && !preg_match('/^(#\d+|\d{8})($| |T\d{6})/', $remainder)) {
+               $remainder = substr($remainder, 1);
+        }
+        if (!empty($remainder)) {
+            if (strpos($remainder, '#') !== false) {
+                $this->setRecurCount(substr($remainder, 1));
+            } else {
+                list($year, $month, $mday) = sscanf($remainder, '%04d%02d%02d');
+                $this->setRecurEnd(new Horde_Date(array('year' => $year,
+                                                        'month' => $month,
+                                                        'mday' => $mday)));
+            }
+        }
+    }
+
+    /**
+     * Creates a vCalendar 1.0 recurrence rule.
+     *
+     * @link http://www.imc.org/pdi/vcal-10.txt
+     * @link http://www.shuchow.com/vCalAddendum.html
+     *
+     * @param Horde_iCalendar $calendar  A Horde_iCalendar object instance.
+     *
+     * @return string  A vCalendar 1.0 conform RRULE value.
+     */
+    function toRRule10($calendar)
+    {
+        switch ($this->recurType) {
+        case NAG_RECUR_NONE:
+            return '';
+
+        case NAG_RECUR_DAILY:
+            $rrule = 'D' . $this->recurInterval;
+            break;
+
+        case NAG_RECUR_WEEKLY:
+            $rrule = 'W' . $this->recurInterval;
+            $vcaldays = array('SU', 'MO', 'TU', 'WE', 'TH', 'FR', 'SA');
+
+            for ($i = 0; $i <= 7 ; ++$i) {
+                if ($this->recurOnDay(pow(2, $i))) {
+                    $rrule .= ' ' . $vcaldays[$i];
+                }
+            }
+            break;
+
+        case NAG_RECUR_MONTHLY_DATE:
+            $rrule = 'MD' . $this->recurInterval . ' ' . trim($this->start->mday);
+            break;
+
+        case NAG_RECUR_MONTHLY_WEEKDAY:
+            $next_week = new Horde_Date($this->start);
+            $next_week->mday += 7;
+            $next_week->correct();
+
+            if ($this->start->month != $next_week->month) {
+                $p = 5;
+            } else {
+                $p = (int)($this->start->mday / 7);
+                if (($this->start->mday % 7) > 0) {
+                    $p++;
+                }
+            }
+
+            $vcaldays = array('SU', 'MO', 'TU', 'WE', 'TH', 'FR', 'SA');
+            $rrule = 'MP' . $this->recurInterval . ' ' . $p . '+ ' . $vcaldays[$this->start->dayOfWeek()];
+            break;
+
+        case NAG_RECUR_YEARLY_DATE:
+            $rrule = 'YM' . $this->recurInterval . ' ' . trim($this->start->month);
+            break;
+
+        case NAG_RECUR_YEARLY_DAY:
+            $rrule = 'YD' . $this->recurInterval . ' ' . $this->start->dayOfYear();
+            break;
+
+        default:
+            return '';
+        }
+
+        return $this->hasRecurEnd() ?
+            $rrule . ' ' . $calendar->_exportDate($this->recurEnd) :
+            $rrule . ' #' . (int)$this->getRecurCount();
+    }
+
+    /**
+     * Parses an iCalendar 2.0 recurrence rule.
+     *
+     * @link http://rfc.net/rfc2445.html#s4.8.5
+     * @link http://www.shuchow.com/vCalAddendum.html
+     *
+     * @param string $rrule  An iCalendar 2.0 conform RRULE value.
+     */
+    function fromRRule20($rrule)
+    {
+        // Parse the recurrence rule into keys and values.
+        $rdata = array();
+        $parts = explode(';', $rrule);
+        foreach ($parts as $part) {
+            list($key, $value) = explode('=', $part, 2);
+            $rdata[String::upper($key)] = $value;
+        }
+
+        if (isset($rdata['FREQ'])) {
+            // Always default the recurInterval to 1.
+            $this->setRecurInterval(isset($rdata['INTERVAL']) ? $rdata['INTERVAL'] : 1);
+
+            switch (String::upper($rdata['FREQ'])) {
+            case 'DAILY':
+                $this->setRecurType(NAG_RECUR_DAILY);
+                break;
+
+            case 'WEEKLY':
+                $this->setRecurType(NAG_RECUR_WEEKLY);
+                if (isset($rdata['BYDAY'])) {
+                    $maskdays = array('SU' => HORDE_DATE_MASK_SUNDAY,
+                                      'MO' => HORDE_DATE_MASK_MONDAY,
+                                      'TU' => HORDE_DATE_MASK_TUESDAY,
+                                      'WE' => HORDE_DATE_MASK_WEDNESDAY,
+                                      'TH' => HORDE_DATE_MASK_THURSDAY,
+                                      'FR' => HORDE_DATE_MASK_FRIDAY,
+                                      'SA' => HORDE_DATE_MASK_SATURDAY);
+                    $days = explode(',', $rdata['BYDAY']);
+                    $mask = 0;
+                    foreach ($days as $day) {
+                        $mask |= $maskdays[$day];
+                    }
+                    $this->setRecurOnDay($mask);
+                } else {
+                    // Recur on the day of the week of the original
+                    // recurrence.
+                    $maskdays = array(
+                        HORDE_DATE_SUNDAY => HORDE_DATE_MASK_SUNDAY,
+                        HORDE_DATE_MONDAY => HORDE_DATE_MASK_MONDAY,
+                        HORDE_DATE_TUESDAY => HORDE_DATE_MASK_TUESDAY,
+                        HORDE_DATE_WEDNESDAY => HORDE_DATE_MASK_WEDNESDAY,
+                        HORDE_DATE_THURSDAY => HORDE_DATE_MASK_THURSDAY,
+                        HORDE_DATE_FRIDAY => HORDE_DATE_MASK_FRIDAY,
+                        HORDE_DATE_SATURDAY => HORDE_DATE_MASK_SATURDAY);
+                    $this->setRecurOnDay($maskdays[$this->start->dayOfWeek()]);
+                }
+                break;
+
+            case 'MONTHLY':
+                if (isset($rdata['BYDAY'])) {
+                    $this->setRecurType(NAG_RECUR_MONTHLY_WEEKDAY);
+                } else {
+                    $this->setRecurType(NAG_RECUR_MONTHLY_DATE);
+                }
+                break;
+
+            case 'YEARLY':
+                if (isset($rdata['BYYEARDAY'])) {
+                    $this->setRecurType(NAG_RECUR_YEARLY_DAY);
+                } elseif (isset($rdata['BYDAY'])) {
+                    $this->setRecurType(NAG_RECUR_YEARLY_WEEKDAY);
+                } else {
+                    $this->setRecurType(NAG_RECUR_YEARLY_DATE);
+                }
+                break;
+            }
+
+            if (isset($rdata['UNTIL'])) {
+                list($year, $month, $mday) = sscanf($rdata['UNTIL'],
+                                                    '%04d%02d%02d');
+                $this->setRecurEnd(new Horde_Date(array('year' => $year,
+                                                        'month' => $month,
+                                                        'mday' => $mday)));
+            }
+            if (isset($rdata['COUNT'])) {
+                $this->setRecurCount($rdata['COUNT']);
+            }
+        } else {
+            // No recurrence data - event does not recur.
+            $this->setRecurType(NAG_RECUR_NONE);
+        }
+    }
+
+    /**
+     * Creates an iCalendar 2.0 recurrence rule.
+     *
+     * @link http://rfc.net/rfc2445.html#s4.8.5
+     * @link http://www.shuchow.com/vCalAddendum.html
+     *
+     * @param Horde_iCalendar $calendar  A Horde_iCalendar object instance.
+     *
+     * @return string  An iCalendar 2.0 conform RRULE value.
+     */
+    function toRRule20($calendar)
+    {
+        switch ($this->recurType) {
+        case NAG_RECUR_NONE:
+            return '';
+
+        case NAG_RECUR_DAILY:
+            $rrule = 'FREQ=DAILY;INTERVAL='  . $this->recurInterval;
+            break;
+
+        case NAG_RECUR_WEEKLY:
+            $rrule = 'FREQ=WEEKLY;INTERVAL=' . $this->recurInterval . ';BYDAY=';
+            $vcaldays = array('SU', 'MO', 'TU', 'WE', 'TH', 'FR', 'SA');
+
+            for ($i = $flag = 0; $i <= 7 ; ++$i) {
+                if ($this->recurOnDay(pow(2, $i))) {
+                    if ($flag) {
+                        $rrule .= ',';
+                    }
+                    $rrule .= $vcaldays[$i];
+                    $flag = true;
+                }
+            }
+            break;
+
+        case NAG_RECUR_MONTHLY_DATE:
+            $rrule = 'FREQ=MONTHLY;INTERVAL=' . $this->recurInterval;
+            break;
+
+        case NAG_RECUR_MONTHLY_WEEKDAY:
+            $next_week = new Horde_Date($this->start);
+            $next_week->mday += 7;
+            $next_week->correct();
+            if ($this->start->month != $next_week->month) {
+                $p = 5;
+            } else {
+                $p = (int)($this->start->mday / 7);
+                if (($this->start->mday % 7) > 0) {
+                    $p++;
+                }
+            }
+            $vcaldays = array('SU', 'MO', 'TU', 'WE', 'TH', 'FR', 'SA');
+            $rrule = 'FREQ=MONTHLY;INTERVAL=' . $this->recurInterval
+                . ';BYDAY=' . $p . $vcaldays[$this->start->dayOfWeek()];
+            break;
+
+        case NAG_RECUR_YEARLY_DATE:
+            $rrule = 'FREQ=YEARLY;INTERVAL=' . $this->recurInterval;
+            break;
+
+        case NAG_RECUR_YEARLY_DAY:
+            $rrule = 'FREQ=YEARLY;INTERVAL=' . $this->recurInterval
+                . ';BYYEARDAY=' . $this->start->dayOfYear();
+            break;
+
+        case NAG_RECUR_YEARLY_WEEKDAY:
+            $vcaldays = array('SU', 'MO', 'TU', 'WE', 'TH', 'FR', 'SA');
+            $weekday = new Horde_Date(array('month' => $this->start->month,
+                                            'mday' => 1,
+                                            'year' => $this->start->year));
+            $rrule = 'FREQ=YEARLY;INTERVAL=' . $this->recurInterval
+                . ';BYDAY='
+                . ($this->start->weekOfYear() - $weekday->weekOfYear() + 1)
+                . $vcaldays[$this->start->dayOfWeek()]
+                . ';BYMONTH=' . $this->start->month;
+            break;
+        }
+
+        if ($this->hasRecurEnd()) {
+            $rrule .= ';UNTIL=' . $calendar->_exportDate($this->recurEnd);
+        }
+        if ($count = $this->getRecurCount()) {
+            $rrule .= ';COUNT=' . $count;
+        }
+        return $rrule;
+    }
+
+    /**
+     * Parses the recurrence data from a hash.
+     *
+     * @param array $hash  The hash to convert.
+     *
+     * @return boolean  True if the hash seemed valid, false otherwise.
+     */
+    function fromHash($hash)
+    {
+        if (!isset($hash['interval']) || !isset($hash['interval']) ||
+            !isset($hash['range-type'])) {
+            $this->setRecurType(NAG_RECUR_NONE);
+            return false;
+        }
+
+        $this->setRecurInterval((int) $hash['interval']);
+
+        $parse_day = false;
+        $set_daymask = false;
+        $update_month = false;
+        $update_daynumber = false;
+        $update_weekday = false;
+        $nth_weekday = -1;
+
+        switch ($hash['cycle']) {
+        case 'daily':
+            $this->setRecurType(NAG_RECUR_DAILY);
+            break;
+
+        case 'weekly':
+            $this->setRecurType(NAG_RECUR_WEEKLY);
+            $parse_day = true;
+            $set_daymask = true;
+            break;
+
+        case 'monthly':
+            if (!isset($hash['daynumber'])) {
+                $this->setRecurType(NAG_RECUR_NONE);
+                return false;
+            }
+
+            switch ($hash['type']) {
+            case 'daynumber':
+                $this->setRecurType(NAG_RECUR_MONTHLY_DATE);
+                $update_daynumber = true;
+                break;
+
+            case 'weekday':
+                $this->setRecurType(NAG_RECUR_MONTHLY_WEEKDAY);
+                $nth_weekday = (int) $hash['daynumber'];
+                $hash['daynumber'] = 1;
+                $parse_day = true;
+                $update_daynumber = true;
+                $update_weekday = true;
+                break;
+            }
+            break;
+
+        case 'yearly':
+            if (!isset($hash['type'])) {
+                $this->setRecurType(NAG_RECUR_NONE);
+                return false;
+            }
+
+            switch ($hash['type']) {
+            case 'monthday':
+                $this->setRecurType(NAG_RECUR_YEARLY_DATE);
+                $update_month = true;
+                $update_daynumber = true;
+                break;
+
+            case 'yearday':
+                if (!isset($hash['month'])) {
+                    $this->setRecurType(NAG_RECUR_NONE);
+                    return false;
+                }
+
+                $this->setRecurType(NAG_RECUR_YEARLY_DAY);
+                // Start counting days in January.
+                $hash['month'] = 'january';
+                $update_month = true;
+                $update_daynumber = true;
+                break;
+
+            case 'weekday':
+                if (!isset($hash['daynumber'])) {
+                    $this->setRecurType(NAG_RECUR_NONE);
+                    return false;
+                }
+
+                $this->setRecurType(NAG_RECUR_YEARLY_WEEKDAY);
+                $nth_weekday = (int) $hash['daynumber'];
+                $hash['daynumber'] = 1;
+                $parse_day = true;
+                $update_month = true;
+                $update_daynumber = true;
+                $update_weekday = true;
+                break;
+            }
+        }
+
+        switch ($hash['range-type']) {
+        case 'number':
+            if (!isset($hash['range'])) {
+                $this->setRecurType(NAG_RECUR_NONE);
+                return false;
+            }
+
+            $this->setRecurCount((int) $hash['range']);
+            break;
+
+        case 'date':
+            $recur_end = new Horde_Date($hash['range']);
+            $recur_end->hour = 23;
+            $recur_end->min = 59;
+            $recur_end->sec = 59;
+            $this->setRecurEnd($recur_end);
+            break;
+        }
+
+        // Need to parse <day>?
+        $last_found_day = -1;
+        if ($parse_day) {
+            if (!isset($hash['day'])) {
+                $this->setRecurType(NAG_RECUR_NONE);
+                return false;
+            }
+
+            $mask = 0;
+            $bits = array(
+                'monday' => HORDE_DATE_MASK_MONDAY,
+                'tuesday' => HORDE_DATE_MASK_TUESDAY,
+                'wednesday' => HORDE_DATE_MASK_WEDNESDAY,
+                'thursday' => HORDE_DATE_MASK_THURSDAY,
+                'friday' => HORDE_DATE_MASK_FRIDAY,
+                'saturday' => HORDE_DATE_MASK_SATURDAY,
+                'sunday' => HORDE_DATE_MASK_SUNDAY,
+            );
+            $days = array(
+                'monday' => HORDE_DATE_MONDAY,
+                'tuesday' => HORDE_DATE_TUESDAY,
+                'wednesday' => HORDE_DATE_WEDNESDAY,
+                'thursday' => HORDE_DATE_THURSDAY,
+                'friday' => HORDE_DATE_FRIDAY,
+                'saturday' => HORDE_DATE_SATURDAY,
+                'sunday' => HORDE_DATE_SUNDAY,
+            );
+
+            foreach ($hash['day'] as $day) {
+                // Validity check.
+                if (empty($day) || !isset($bits[$day])) {
+                    continue;
+                }
+
+                $mask |= $bits[$day];
+                $last_found_day = $days[$day];
+            }
+
+            if ($set_daymask) {
+                $this->setRecurOnDay($mask);
+            }
+        }
+
+        if ($update_month || $update_daynumber || $update_weekday) {
+            if ($update_month) {
+                $month2number = array(
+                    'january'   => 1,
+                    'february'  => 2,
+                    'march'     => 3,
+                    'april'     => 4,
+                    'may'       => 5,
+                    'june'      => 6,
+                    'july'      => 7,
+                    'august'    => 8,
+                    'september' => 9,
+                    'october'   => 10,
+                    'november'  => 11,
+                    'december'  => 12,
+                );
+
+                if (isset($month2number[$hash['month']])) {
+                    $this->start->month = $month2number[$hash['month']];
+                }
+            }
+
+            if ($update_daynumber) {
+                if (!isset($hash['daynumber'])) {
+                    $this->setRecurType(NAG_RECUR_NONE);
+                    return false;
+                }
+
+                $this->start->mday = $hash['daynumber'];
+            }
+
+            if ($update_weekday) {
+                $this->start->setNthWeekday($last_found_day, $nth_weekday);
+            }
+
+            $this->start->correct();
+        }
+
+        // Exceptions.
+        if (isset($hash['exceptions'])) {
+            $this->exceptions = $hash['exceptions'];
+        }
+
+        if (isset($hash['completions'])) {
+            $this->completions = $hash['completions'];
+        }
+
+        return true;
+    }
+
+    /**
+     * Export this object into a hash.
+     *
+     * @return array  The recurrence hash.
+     */
+    function toHash()
+    {
+        if ($this->getRecurType() == NAG_RECUR_NONE) {
+            return array();
+        }
+
+        $day2number = array(
+            0 => 'sunday',
+            1 => 'monday',
+            2 => 'tuesday',
+            3 => 'wednesday',
+            4 => 'thursday',
+            5 => 'friday',
+            6 => 'saturday'
+        );
+        $month2number = array(
+            1 => 'january',
+            2 => 'february',
+            3 => 'march',
+            4 => 'april',
+            5 => 'may',
+            6 => 'june',
+            7 => 'july',
+            8 => 'august',
+            9 => 'september',
+            10 => 'october',
+            11 => 'november',
+            12 => 'december'
+        );
+
+        $hash = array('interval' => $this->getRecurInterval());
+        $start = $this->getRecurStart();
+
+        switch ($this->getRecurType()) {
+        case NAG_RECUR_DAILY:
+            $hash['cycle'] = 'daily';
+            break;
+
+        case NAG_RECUR_WEEKLY:
+            $hash['cycle'] = 'weekly';
+            $bits = array(
+                'monday' => HORDE_DATE_MASK_MONDAY,
+                'tuesday' => HORDE_DATE_MASK_TUESDAY,
+                'wednesday' => HORDE_DATE_MASK_WEDNESDAY,
+                'thursday' => HORDE_DATE_MASK_THURSDAY,
+                'friday' => HORDE_DATE_MASK_FRIDAY,
+                'saturday' => HORDE_DATE_MASK_SATURDAY,
+                'sunday' => HORDE_DATE_MASK_SUNDAY,
+            );
+            $days = array();
+            foreach($bits as $name => $bit) {
+                if ($this->recurOnDay($bit)) {
+                    $days[] = $name;
+                }
+            }
+            $hash['day'] = $days;
+            break;
+
+        case NAG_RECUR_MONTHLY_DATE:
+            $hash['cycle'] = 'monthly';
+            $hash['type'] = 'daynumber';
+            $hash['daynumber'] = $start->mday;
+            break;
+
+        case NAG_RECUR_MONTHLY_WEEKDAY:
+            $hash['cycle'] = 'monthly';
+            $hash['type'] = 'weekday';
+            $hash['daynumber'] = $start->weekOfMonth();
+            $hash['day'] = array ($day2number[$start->dayOfWeek()]);
+            break;
+
+        case NAG_RECUR_YEARLY_DATE:
+            $hash['cycle'] = 'yearly';
+            $hash['type'] = 'monthday';
+            $hash['daynumber'] = $start->mday;
+            $hash['month'] = $month2number[$start->month];
+            break;
+
+        case NAG_RECUR_YEARLY_DAY:
+            $hash['cycle'] = 'yearly';
+            $hash['type'] = 'yearday';
+            $hash['daynumber'] = $start->dayOfYear();
+            break;
+
+        case NAG_RECUR_YEARLY_WEEKDAY:
+            $hash['cycle'] = 'yearly';
+            $hash['type'] = 'weekday';
+            $hash['daynumber'] = $start->weekOfMonth();
+            $hash['day'] = array ($day2number[$start->dayOfWeek()]);
+            $hash['month'] = $month2number[$start->month];
+        }
+
+        if ($this->hasRecurCount()) {
+            $hash['range-type'] = 'number';
+            $hash['range'] = $this->getRecurCount();
+        } elseif ($this->hasRecurEnd()) {
+            $date = $this->getRecurEnd();
+            $hash['range-type'] = 'date';
+            $hash['range'] = $date->datestamp();
+        } else {
+            $hash['range-type'] = 'none';
+            $hash['range'] = '';
+        }
+
+        // Recurrence exceptions
+        $hash['exceptions'] = $this->exceptions;
+        $hash['completions'] = $this->completions;
+
+        return $hash;
+    }
+
+}
diff --git a/lib/api.php b/lib/api.php
index bac181d..db77df3 100644
--- a/lib/api.php
+++ b/lib/api.php
@@ -2,7 +2,7 @@
 /**
  * Nag external API interface.
  *
- * $Horde: nag/lib/api.php,v 1.100.10.31 2008/05/10 17:07:08 bklang Exp $
+ * $Horde: nag/lib/api.php,v 1.100.10.42 2008/08/18 22:38:51 jan Exp $
  *
  * This file defines Nag's external API interface. Other applications can
  * interact with Nag through this API.
@@ -137,30 +137,81 @@ function _nag_perms()
  */
 function _nag_removeUserData($user)
 {
-    /* Retrieve all entries for user datasource ... */
-    $uids = _nag_list($user);
-    if (is_a($uids, 'PEAR_Error')) {
-        return $uids;
+    require_once dirname(__FILE__) . '/base.php';
+
+    if (!Auth::isAdmin() && $user != Auth::getAuth()) {
+        return PEAR::raiseError(_("You are not allowed to remove user data."));
     }
 
-    /* ... and delete them. */
-    foreach ($uids as $uid) {
-        _nag_delete($uid);
+    /* Error flag */
+    $hasError = false;
+
+    /* Get the share for later deletion */
+    $share = $GLOBALS['nag_shares']->getShare($user);
+    if(is_a($share, 'PEAR_Error')) {
+        Horde::logMessage($share->getMessage(), __FILE__, __LINE__, PEAR_LOG_ERR);
+        unset($share);
+    } else {
+        /* Get the list of all tasks */
+        $tasks = Nag::listTasks(null, null, null, $user, 1);
+        if (is_a($tasks, 'PEAR_Error')) {
+            $hasError = true;
+            Horde::logMessage($share->getMessage(), __FILE__, __LINE__, PEAR_LOG_ERR);
+        } else {
+            $uids = array();
+            $tasks->reset();
+            while ($task = $tasks->each()) {
+                $uids[] = $task->uid;
+            }
+
+            /* ... and delete them. */
+            foreach ($uids as $uid) {
+                _nag_delete($uid);
+            }
+        }
     }
 
     /* Now delete history as well. */
     $history = &Horde_History::singleton();
     if (method_exists($history, 'removeByParent')) {
         $histories = $history->removeByParent('nag:' . $user);
-   } else {
+    } else {
         /* Remove entries 100 at a time. */
-        $all = array_keys($history->getByTimestamp('>', 0, array(), 'nag:' . $user));
-        while (count($d = array_splice($all, 0, 100)) > 0) {
-            $history->removebyNames($d);
+        $all = $history->getByTimestamp('>', 0, array(), 'nag:' . $user);
+        if (is_a($all, 'PEAR_Error')) {
+            Horde::logMessage($all, __FILE__, __LINE__, PEAR_LOG_ERR);
+        } else {
+            $all = array_keys($all);
+            while (count($d = array_splice($all, 0, 100)) > 0) {
+                $history->removebyNames($d);
+            }
         }
     }
 
-    return true;
+    /* ...and finally, delete the actual share */
+    if (!empty($share)) {
+        $result = $GLOBALS['nag_shares']->removeShare($share);
+        if (is_a($result, 'PEAR_Error')) {
+            $hasError = true;
+            Horde::logMessage($result->getMessage(), __FILE__, __LINE__, PEAR_LOG_ERR);
+        }
+    }
+
+    /* Now remove perms for this user from all other shares */
+    $shares = $GLOBALS['nag_shares']->listShares($user);
+    if (is_a($shares, 'PEAR_Error')) {
+        $hasError = true;
+        Horde::logMessage($shares, __FILE__, __LINE__, PEAR_LOG_ERR);
+    }
+    foreach ($shares as $share) {
+        $share->removeUser($user);
+    }
+
+    if ($hasError) {
+        return PEAR::raiseError(sprintf(_("There was an error removing tasks for %s. Details have been logged."), $user));
+    } else {
+        return true;
+    }
 }
 
 /**
@@ -291,7 +342,7 @@ function _nag_browse($path = '', $properties = array())
         //
         // This request is for a list of all users who have tasklists visible
         // to the requesting user.
-        // 
+        //
         $tasklists = Nag::listTasklists(false, PERMS_READ);
         $owners = array();
         foreach ($tasklists as $tasklist) {
@@ -377,6 +428,22 @@ function _nag_browse($path = '', $properties = array())
         }
         return $results;
 
+    } elseif (count($parts) == 2 && substr($parts[1], -4) == '.ics') {
+        //
+        // This is a request for the entire tasklist in iCalendar format.
+        //
+        $tasklist = substr($parts[1], 0, -4);
+        if (!array_key_exists($tasklist, Nag::listTasklists(false, PERMS_READ))) {
+            return PEAR::raiseError(_("Invalid tasklist file requested."), 404);
+        }
+        $ical_data = _nag_exportTasklist($tasklist, 'text/calendar');
+        $result = array('data'          => $ical_data,
+                        'mimetype'      => 'text/calendar',
+                        'contentlength' => strlen($ical_data),
+                        'mtime'         => $_SERVER['REQUEST_TIME']);
+
+        return $result;
+
     } elseif (count($parts) == 2) {
         //
         // This request is browsing into a specific tasklist.  Generate the list
@@ -396,7 +463,7 @@ function _nag_browse($path = '', $properties = array())
         $results = array();
         $storage->tasks->reset();
         while ($task = $storage->tasks->each()) {
-            $key = 'nag/' . $parts[1] . '/' . $parts[2] . '/' . $task->id;
+            $key = 'nag/' . $parts[0] . '/' . $parts[1] . '/' . $task->id;
             if (in_array('name', $properties)) {
                 $results[$key]['name'] = $task->name;
             }
@@ -407,7 +474,7 @@ function _nag_browse($path = '', $properties = array())
                 $results[$key]['browseable'] = false;
             }
             if (in_array('contenttype', $properties)) {
-                $results[$key]['contenttype'] = 'text/x-vtodo';
+                $results[$key]['contenttype'] = 'text/calendar';
             }
             if (in_array('contentlength', $properties)) {
                 // FIXME:  This is a hack.  If the content length is longer
@@ -428,8 +495,7 @@ function _nag_browse($path = '', $properties = array())
         return $results;
     } else {
         //
-        // The only valid request left is for either a specific task item
-        // or for the entire tasklist.
+        // The only valid request left is for either a specific task item.
         //
         if (count($parts) == 3 &&
             array_key_exists($parts[1], Nag::listTasklists(false,
@@ -450,8 +516,8 @@ function _nag_browse($path = '', $properties = array())
                 return $task;
             }
 
-            $result = array('data' => _nag_export($task->uid, 'text/x-vtodo'),
-                            'mimetype' => 'text/x-vtodo');
+            $result = array('data' => _nag_export($task->uid, 'text/calendar'),
+                            'mimetype' => 'text/calendar');
             $modified = __nag_modified($task->uid, $parts[1]);
             if (!empty($modified)) {
                 $result['mtime'] = $modified;
@@ -460,16 +526,6 @@ function _nag_browse($path = '', $properties = array())
         } elseif (count($parts) == 2 &&
                   substr($parts[1], -4) == '.ics' &&
                   array_key_exists(substr($parts[1], 0, -4), Nag::listTasklists(false, PERMS_READ))) {
-            //
-            // This request is for an entire tasklist (tasklist.ics).
-            //
-            $ical_data = _nag_exportTasklist(substr($parts[1], 0, -4), 'text/calendar');
-            $result = array('data'          => $ical_data,
-                            'mimetype'      => 'text/calendar',
-                            'contentlength' => strlen($ical_data),
-                            'mtime'         => $_SERVER['REQUEST_TIME']);
-
-            return $result;
         } else {
             //
             // All other requests are a 404: Not Found
@@ -512,9 +568,9 @@ function _nag_put($path, $content, $content_type)
 
         // Workaround for WebDAV clients that are not smart enough to send
         // the right content type.  Assume the same format we send individual
-        // tasklist items: text/x-vtodo
+        // tasklist items: text/calendar
         if ($content_type == 'application/octet-stream') {
-            $content_type = 'text/x-vtodo';
+            $content_type = 'text/calendar';
         }
     } else {
         return PEAR::raiseError(_("Invalid tasklist name supplied."), 403);
@@ -535,9 +591,7 @@ function _nag_put($path, $content, $content_type)
 
     switch ($content_type) {
     case 'text/calendar':
-    case 'text/x-icalendar':
     case 'text/x-vcalendar':
-    case 'text/x-vevent':
         require_once 'Horde/iCalendar.php';
         $iCal = new Horde_iCalendar();
         if (!is_a($content, 'Horde_iCalendar_vtodo')) {
@@ -548,12 +602,7 @@ function _nag_put($path, $content, $content_type)
             $iCal->addComponent($content);
         }
 
-        $components = $iCal->getComponents();
-        if (count($components) == 0) {
-            return PEAR::raiseError(_("No iCalendar data was found."), 400);
-        }
-
-        foreach ($components as $content) {
+        foreach ($iCal->getComponents() as $content) {
             if (is_a($content, 'Horde_iCalendar_vtodo')) {
                 $task = new Nag_Task();
                 $task->fromiCalendar($content);
@@ -611,7 +660,7 @@ function _nag_put($path, $content, $content_type)
                         isset($task->completed) ? (int)$task->completed : $existing->completed,
                         isset($task->category) ? $task->category : $existing->category,
                         isset($task->alarm) ? $task->alarm : $existing->alarm,
-                        isset($task->parent) ? $task->parent : $existing->parent,
+                        isset($task->parent_id) ? $task->parent_id : $existing->parent_id,
                         isset($task->private) ? $task->private : $existing->private,
                         $owner,
                         isset($task->assignee) ? $task->assignee : $existing->assignee);
@@ -633,7 +682,7 @@ function _nag_put($path, $content, $content_type)
                         isset($task->category) ? $task->category : '',
                         isset($task->alarm) ? $task->alarm : 0,
                         isset($task->uid) ? $task->uid : null,
-                        isset($task->parent) ? $task->parent : '',
+                        isset($task->parent_id) ? $task->parent_id : '',
                         !empty($task->private),
                         Auth::getAuth(),
                         isset($task->assignee) ? $task->assignee : null);
@@ -852,9 +901,8 @@ function _nag_getActionTimestamp($uid, $action, $tasklist = null)
  *
  * @param string $content      The content of the task.
  * @param string $contentType  What format is the data in? Currently supports:
- *                             text/x-icalendar
+ *                             text/calendar
  *                             text/x-vcalendar
- *                             text/x-vtodo
  * @param string $tasklist     The tasklist into which the task will be
  *                             imported.  If 'null', the user's default
  *                             tasklist will be used.
@@ -884,10 +932,9 @@ function _nag_import($content, $contentType, $tasklist = null)
     $storage = &Nag_Driver::singleton($tasklist);
 
     switch ($contentType) {
-    case 'text/x-icalendar':
     case 'text/x-vcalendar':
-    case 'text/x-vtodo':
     case 'text/calendar':
+    case 'text/x-vtodo':
         $iCal = new Horde_iCalendar();
         if (!is_a($content, 'Horde_iCalendar_vtodo')) {
             if (!$iCal->parsevCalendar($content)) {
@@ -921,7 +968,7 @@ function _nag_import($content, $contentType, $tasklist = null)
                         isset($task->completed) ? (int)$task->completed : $existing->completed,
                         isset($task->category) ? $task->category : $existing->category,
                         isset($task->alarm) ? $task->alarm : $existing->alarm,
-                        isset($task->parent) ? $task->parent : $existing->parent,
+                        isset($task->parent_id) ? $task->parent_id : $existing->parent_id,
                         isset($task->private) ? $task->private : $existing->private,
                         isset($task->owner) ? $task->owner : $existing->owner,
                         isset($task->assignee) ? $task->assignee : $existing->assignee);
@@ -942,7 +989,7 @@ function _nag_import($content, $contentType, $tasklist = null)
                         isset($task->category) ? $task->category : '',
                         isset($task->alarm) ? $task->alarm : 0,
                         isset($task->uid) ? $task->uid : null,
-                        isset($task->parent) ? $task->parent : '',
+                        isset($task->parent_id) ? $task->parent_id : '',
                         !empty($task->private),
                         Auth::getAuth(),
                         isset($task->assignee) ? $task->assignee : null);
@@ -977,9 +1024,7 @@ function _nag_import($content, $contentType, $tasklist = null)
  * <pre>
  * text/calendar    - (VCALENDAR 2.0. Recommended as this is specified in
  *                    rfc2445)
- * text/x-vtodo     - (seems to be used by horde only. Do we need this?)
  * text/x-vcalendar - (old VCALENDAR 1.0 format. Still in wide use)
- * text/x-icalendar
  * </pre>
  *
  * @return string  The requested data.
@@ -1003,8 +1048,6 @@ function _nag_export($uid, $contentType)
     case 'text/x-vcalendar':
         $version = '1.0';
     case 'text/calendar':
-    case 'text/x-icalendar':
-    case 'text/x-vtodo':
         require_once dirname(__FILE__) . '/version.php';
         require_once 'Horde/iCalendar.php';
 
@@ -1035,11 +1078,8 @@ function _nag_export($uid, $contentType)
  *                             <pre>
  *                             text/calendar (VCALENDAR 2.0. Recommended as
  *                                            this is specified in rfc2445)
- *                             text/x-vtodo    Seems to be used by horde only.
- *                                             Do we need this?
  *                             text/x-vcalendar (old VCALENDAR 1.0 format.
  *                                              Still in wide use)
- *                             text/x-icalendar
  *                             </pre>
  *
  * @return string  The iCalendar representation of the tasklist.
@@ -1060,8 +1100,6 @@ function _nag_exportTasklist($tasklist, $contentType)
     case 'text/x-vcalendar':
         $version = '1.0';
     case 'text/calendar':
-    case 'text/x-icalendar':
-    case 'text/x-vtodo':
         $share = &$GLOBALS['nag_shares']->getShare($tasklist);
 
         require_once 'Horde/iCalendar.php';
@@ -1132,9 +1170,7 @@ function _nag_delete($uid)
  * @param string $uid          Identify the task to replace.
  * @param string $content      The content of the task.
  * @param string $contentType  What format is the data in? Currently supports:
- *                             - text/x-icalendar
  *                             - text/x-vcalendar
- *                             - text/x-vtodo
  *                             - text/calendar
  *
  * @return boolean  Success or failure.
@@ -1156,9 +1192,7 @@ function _nag_replace($uid, $content, $contentType)
 
     switch ($contentType) {
     case 'text/calendar':
-    case 'text/x-icalendar':
     case 'text/x-vcalendar':
-    case 'text/x-vtodo':
         if (!is_a($content, 'Horde_iCalendar_vtodo')) {
             require_once 'Horde/iCalendar.php';
             $iCal = new Horde_iCalendar();
@@ -1193,7 +1227,7 @@ function _nag_replace($uid, $content, $contentType)
             isset($task->completed) ? (int)$task->completed : $existing->completed,
             isset($task->category) ? $task->category : $existing->category,
             isset($task->alarm) ? $task->alarm : $existing->alarm,
-            isset($task->parent) ? $task->parent : $existing->parent,
+            isset($task->parent_id) ? $task->parent_id : $existing->parent_id,
             isset($task->private) ? $task->private : $existing->private,
             isset($task->owner) ? $task->owner : $existing->owner,
             isset($task->assignee) ? $task->assignee : $existing->assignee);
diff --git a/lib/prefs.php b/lib/prefs.php
index b75f7b0..82c2961 100644
--- a/lib/prefs.php
+++ b/lib/prefs.php
@@ -1,8 +1,8 @@
 <?php
 /**
- * $Horde: nag/lib/prefs.php,v 1.3.10.6 2008/01/02 11:32:29 jan Exp $
+ * $Horde: nag/lib/prefs.php,v 1.3.10.7 2009/01/06 15:25:05 jan Exp $
  *
- * Copyright 2001-2008 The Horde Project (http://www.horde.org/)
+ * Copyright 2001-2009 The Horde Project (http://www.horde.org/)
  *
  * See the enclosed file COPYING for license information (GPL). If you
  * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
diff --git a/lib/version.php b/lib/version.php
index a194aba..08be9d0 100644
--- a/lib/version.php
+++ b/lib/version.php
@@ -1 +1 @@
-<?php define('NAG_VERSION', 'H3 (2.2)') ?>
+<?php define('NAG_VERSION', 'H3 (2.3.2)') ?>
diff --git a/list.php b/list.php
index 1b0712c..920b758 100644
--- a/list.php
+++ b/list.php
@@ -1,8 +1,8 @@
 <?php
 /**
- * $Horde: nag/list.php,v 1.93.8.8 2008/01/02 11:32:29 jan Exp $
+ * $Horde: nag/list.php,v 1.93.8.11 2009/01/06 15:25:04 jan Exp $
  *
- * Copyright 2001-2008 The Horde Project (http://www.horde.org/)
+ * Copyright 2001-2009 The Horde Project (http://www.horde.org/)
  *
  * See the enclosed file COPYING for license information (GPL). If you
  * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
@@ -116,64 +116,7 @@ if ($print_view) {
     }
 }
 
-require NAG_TEMPLATES . '/list/header.inc';
-
-if ($tasks->hasTasks()) {
-    $sortby = $prefs->getValue('sortby');
-    $sortdir = $prefs->getValue('sortdir');
-    $dateFormat = $prefs->getValue('date_format');
-    $showTasklist = $prefs->getValue('show_tasklist');
-    $dynamic_sort = true;
-
-    $baseurl = 'list.php';
-    if ($actionID == 'search_tasks') {
-        $baseurl = Util::addParameter(
-            $baseurl,
-            array('actionID' => 'search_tasks',
-                  'search_pattern' => $search_pattern,
-                  'search_name' => $search_name ? 'on' : 'off',
-                  'search_desc' => $search_desc ? 'on' : 'off',
-                  'search_category' => $search_category ? 'on' : 'off'));
-    }
-
-    require NAG_TEMPLATES . '/list/task_headers.inc';
-
-    $tasks->reset();
-    while ($task = $tasks->each()) {
-        $dynamic_sort &= !$task->hasSubTasks();
-
-        if (!empty($task->completed)) {
-            $style = 'linedRow closed';
-        } elseif (!empty($task->due) && $task->due < time()) {
-            $style = 'linedRow overdue';
-        } else {
-            $style = 'linedRow';
-        }
-
-        if ($task->tasklist == '**EXTERNAL**') {
-            // Just use a new share that this user owns for tasks from
-            // external calls - if the API gives them back, we'll trust it.
-            $share = $GLOBALS['nag_shares']->newShare('**EXTERNAL**');
-        } else {
-            $share = $GLOBALS['nag_shares']->getShare($task->tasklist);
-        }
-
-        $owner = $task->tasklist;
-        if (!is_a($share, 'PEAR_Error')) {
-            $owner = $share->get('name');
-        }
-
-        require NAG_TEMPLATES . '/list/task_summaries.inc';
-    }
-
-    require NAG_TEMPLATES . '/list/task_footers.inc';
-
-    if (!$print_view && $dynamic_sort) {
-        Horde::addScriptFile('tables.js', 'nag', true);
-    }
-} else {
-    require NAG_TEMPLATES . '/list/empty.inc';
-}
+require NAG_TEMPLATES . '/list.html.php';
 
 if (!$print_view) {
     require NAG_TEMPLATES . '/panel.inc';
diff --git a/locale/de_DE/LC_MESSAGES/nag.mo b/locale/de_DE/LC_MESSAGES/nag.mo
index 7f36da0..46a1b09 100644
Binary files a/locale/de_DE/LC_MESSAGES/nag.mo and b/locale/de_DE/LC_MESSAGES/nag.mo differ
diff --git a/locale/es_ES/LC_MESSAGES/nag.mo b/locale/es_ES/LC_MESSAGES/nag.mo
index 3782f65..2be358c 100644
Binary files a/locale/es_ES/LC_MESSAGES/nag.mo and b/locale/es_ES/LC_MESSAGES/nag.mo differ
diff --git a/locale/et_EE/LC_MESSAGES/nag.mo b/locale/et_EE/LC_MESSAGES/nag.mo
new file mode 100644
index 0000000..f98d611
Binary files /dev/null and b/locale/et_EE/LC_MESSAGES/nag.mo differ
diff --git a/locale/eu_ES/LC_MESSAGES/nag.mo b/locale/eu_ES/LC_MESSAGES/nag.mo
new file mode 100644
index 0000000..4e3ce0f
Binary files /dev/null and b/locale/eu_ES/LC_MESSAGES/nag.mo differ
diff --git a/locale/eu_ES/help.xml b/locale/eu_ES/help.xml
new file mode 100644
index 0000000..2c73056
--- /dev/null
+++ b/locale/eu_ES/help.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0"?>
+<!-- $Horde: nag/locale/eu_ES/help.xml,v 1.1.2.1 2008/07/17 21:09:25 jan Exp $ -->
+<help><entry id="Overview" md5="67c67240d4ec4a037b8ae76f371c5ad3" state="uptodate">
+    <title>Informazio orokorra</title>
+    <heading>Sarrera</heading> <para>Eginbide askoko "egitekoen" fitxategi-kudeatzailea da, eta zeregin-zerrenda pribatuak eta partekatuak, Egutegi-funtzioa integratzea, kategoriak, lehentasunak, epemugak, bilaketak, inprimatzea eta inportatze-/esportatze-funtzioak onartzen du.</para></entry>
+
+  <entry id="sorting" md5="275a51456e8b440a5bf7afe2af24c777" state="uptodate">
+    <title>Ordenatu sarrerak</title>
+    <heading>Ordenatu sarrerak</heading> <para>Sarreren zerrenda ikustean, sarrerak edozein zutaberen arabera ordena ditzakezu zutabe egokian klik eginez gero.  Goranzko edo beheranzko ordenera aldatzeko, klik egin zutabearen izenburuko geziaren ikonoan.</para></entry></help>
diff --git a/locale/fi_FI/LC_MESSAGES/nag.mo b/locale/fi_FI/LC_MESSAGES/nag.mo
index d8b6b48..4292966 100644
Binary files a/locale/fi_FI/LC_MESSAGES/nag.mo and b/locale/fi_FI/LC_MESSAGES/nag.mo differ
diff --git a/locale/fr_FR/LC_MESSAGES/nag.mo b/locale/fr_FR/LC_MESSAGES/nag.mo
index c897990..27d72c4 100644
Binary files a/locale/fr_FR/LC_MESSAGES/nag.mo and b/locale/fr_FR/LC_MESSAGES/nag.mo differ
diff --git a/locale/it_IT/LC_MESSAGES/nag.mo b/locale/it_IT/LC_MESSAGES/nag.mo
index c8fa7f0..1c7a0a8 100644
Binary files a/locale/it_IT/LC_MESSAGES/nag.mo and b/locale/it_IT/LC_MESSAGES/nag.mo differ
diff --git a/locale/ja_JP/LC_MESSAGES/nag.mo b/locale/ja_JP/LC_MESSAGES/nag.mo
index eb62ae4..f5769bc 100644
Binary files a/locale/ja_JP/LC_MESSAGES/nag.mo and b/locale/ja_JP/LC_MESSAGES/nag.mo differ
diff --git a/locale/nl_NL/LC_MESSAGES/nag.mo b/locale/nl_NL/LC_MESSAGES/nag.mo
index 3dd9623..7835206 100644
Binary files a/locale/nl_NL/LC_MESSAGES/nag.mo and b/locale/nl_NL/LC_MESSAGES/nag.mo differ
diff --git a/locale/pt_BR/LC_MESSAGES/nag.mo b/locale/pt_BR/LC_MESSAGES/nag.mo
index cb84142..7e05edc 100644
Binary files a/locale/pt_BR/LC_MESSAGES/nag.mo and b/locale/pt_BR/LC_MESSAGES/nag.mo differ
diff --git a/locale/sk_SK/LC_MESSAGES/nag.mo b/locale/sk_SK/LC_MESSAGES/nag.mo
index eb867d1..d69c9f9 100644
Binary files a/locale/sk_SK/LC_MESSAGES/nag.mo and b/locale/sk_SK/LC_MESSAGES/nag.mo differ
diff --git a/locale/zh_TW/LC_MESSAGES/nag.mo b/locale/zh_TW/LC_MESSAGES/nag.mo
index 0aa67e2..769db58 100644
Binary files a/locale/zh_TW/LC_MESSAGES/nag.mo and b/locale/zh_TW/LC_MESSAGES/nag.mo differ
diff --git a/po/ar_SY.po b/po/ar_SY.po
index 9c6919c..deb47f9 100644
--- a/po/ar_SY.po
+++ b/po/ar_SY.po
@@ -1,6 +1,6 @@
 # Nag 1.0 Arabic translation.
 # This file is distributed under the same license as the Nag package.
-# Copyright (C) 2003 Platinum Inc. <pl at tinum.info>
+# Copyright 2003 Platinum Inc. <pl at tinum.info>
 # Custom Web Applications <http://platinum-sy.com>
 # Platinum Development Team <devteam at platinum-sy.net>
 #
diff --git a/po/bg_BG.po b/po/bg_BG.po
index f90eb4d..69e92b9 100644
--- a/po/bg_BG.po
+++ b/po/bg_BG.po
@@ -1,5 +1,5 @@
 # Bulgarian translations for Nag package.
-# Copyright (C) 2002 Horde Project
+# Copyright 2002-2009 The Horde Project
 # This file is distributed under the same license as the Whups package.
 # Miroslav Pendev <miro at cybershade.us>, 2002.
 #
diff --git a/po/ca_ES.po b/po/ca_ES.po
index ad50f13..6550020 100644
--- a/po/ca_ES.po
+++ b/po/ca_ES.po
@@ -1,6 +1,6 @@
 # Spanish translations for horde package
 # Traducciones al español para el paquete horde.
-# Copyright (C) 2004 Horde Project
+# Copyright 2004-2009 The Horde Project
 # This file is distributed under the same license as the horde package.
 # Automatically generated, 2004.
 #
diff --git a/po/cs_CZ.po b/po/cs_CZ.po
index bfe2782..68a1179 100644
--- a/po/cs_CZ.po
+++ b/po/cs_CZ.po
@@ -1,5 +1,5 @@
 # Nag Czech Translation.
-# Copyright (C) 2004 Horde Project
+# Copyright 2004-2009 The Horde Project
 # This file is distributed under the same license as the Horde package.
 # Pavel Chytil <pavel at chytil.tk>, 2001-2004.
 #
diff --git a/po/da_DK.po b/po/da_DK.po
index 024e31f..e67e697 100644
--- a/po/da_DK.po
+++ b/po/da_DK.po
@@ -1,6 +1,6 @@
 # Danish translations for Nag package
 # Danske oversættelser for pakke Nag
-# Copyright (C) 2006 Horde Project
+# Copyright 2006-2009 The Horde Project
 # This file is distributed under the same license as the Nag package.
 # Brian Truelsen <horde+i18n at briantruelsen.dk>, 2006.
 #
diff --git a/po/de_DE.po b/po/de_DE.po
index a4f3d81..999abb0 100644
--- a/po/de_DE.po
+++ b/po/de_DE.po
@@ -1,5 +1,5 @@
 # German translations for Nag.
-# Copyright (C) 2001-2008 Horde Project.
+# Copyright 2001-2009 The Horde Project.
 # This file is distributed under the same license as the Nag package.
 # Jan Schneider <jan at horde.org>, 2001-2008.
 #
@@ -7,98 +7,102 @@ msgid ""
 msgstr ""
 "Project-Id-Version: Nag 2.2-cvs\n"
 "Report-Msgid-Bugs-To: dev at lists.horde.org\n"
-"POT-Creation-Date: 2008-05-25 16:58+0200\n"
-"PO-Revision-Date: 2008-05-21 00:35+0200\n"
+"POT-Creation-Date: 2009-03-19 10:37+0100\n"
+"PO-Revision-Date: 2009-03-19 11:59+0100\n"
 "Last-Translator: Jan Schneider <jan at horde.org>\n"
 "Language-Team: German <dev at lists.horde.org>\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=iso-8859-1\n"
 "Content-Transfer-Encoding: 8-bit\n"
 
-#: templates/view/task.inc:35
+#: templates/view/task.inc:39
 #, php-format
 msgid " (%s including sub-tasks)"
 msgstr " (%s inklusive Unteraufgaben)"
 
-#: lib/Nag.php:71
+#: lib/Nag.php:81
 #, php-format
 msgid "%d hour"
 msgstr "%d Stunde"
 
-#: lib/Nag.php:73
+#: lib/Nag.php:83
 #, php-format
 msgid "%d hour, %d minute"
 msgstr "%d Stunde, %d Minute"
 
-#: lib/Nag.php:75
+#: lib/Nag.php:85
 #, php-format
 msgid "%d hour, %d minutes"
 msgstr "%d Stunde, %d Minuten"
 
-#: lib/Nag.php:63
+#: lib/Nag.php:73
 #, php-format
 msgid "%d hours"
 msgstr "%d Stunden"
 
-#: lib/Nag.php:65
+#: lib/Nag.php:75
 #, php-format
 msgid "%d hours, %d minute"
 msgstr "%d Stunden, %d Minute"
 
-#: lib/Nag.php:67
+#: lib/Nag.php:77
 #, php-format
 msgid "%d hours, %d minutes"
 msgstr "%d Stunden, %d Minuten"
 
-#: lib/Nag.php:81
+#: lib/Nag.php:91
 #, php-format
 msgid "%d minute"
 msgstr "%d Minute"
 
-#: lib/Nag.php:83
+#: lib/Nag.php:93
 #, php-format
 msgid "%d minutes"
 msgstr "%d Minuten"
 
-#: lib/Nag.php:392
+#: lib/Nag.php:410
 #, php-format
 msgid "%s at %s"
 msgstr "%s um %s"
 
-#: lib/Nag.php:618 lib/Block/tree_alarms.php:41 lib/Block/summary.php:121
+#: lib/Nag.php:670 lib/Block/tree_alarms.php:41 lib/Block/summary.php:124
 #, php-format
 msgid "%s is due in %s"
 msgstr "%s ist in %s fällig"
 
-#: lib/Nag.php:616 lib/Block/tree_alarms.php:43 lib/Block/summary.php:118
+#: lib/Nag.php:668 lib/Block/tree_alarms.php:43 lib/Block/summary.php:121
 #, php-format
 msgid "%s is due now."
 msgstr "%s ist fällig."
 
-#: task.php:238
+#: task.php:222
 #, php-format
 msgid "%s is now incomplete."
 msgstr "%s ist jetzt unerledigt."
 
-#: data.php:212
+#: data.php:218
 #, php-format
 msgid "%s successfully imported"
 msgstr "Die %s-Datei wurde erfolgreich importiert"
 
-#: lib/Nag.php:544 lib/Forms/DeleteTaskList.php:86
+#: lib/Nag.php:596 lib/Forms/DeleteTaskList.php:86
 #, php-format
 msgid "%s's Task List"
-msgstr "%ss Aufgabenliste"
+msgstr "Aufgabenliste von %s"
 
-#: lib/Nag.php:343 lib/Forms/task.php:61
+#: lib/Nag.php:361 lib/Forms/task.php:84
 msgid "(highest)"
 msgstr "(Höchste)"
 
-#: lib/Nag.php:343 lib/Forms/task.php:62
+#: lib/Nag.php:361 lib/Forms/task.php:85
 msgid "(lowest)"
 msgstr "(Niedrigste)"
 
-#: task.php:222
+#: lib/Forms/task.php:186
+msgid "A due date must be set to enable alarms."
+msgstr "Ein Fälligkeitsdatum muss angegeben sein, um den Alarm zu aktivieren."
+
+#: task.php:206
 #, php-format
 msgid "Access denied completing task %s."
 msgstr "Zugriff verweigert beim Erledigen von Aufgabe %s."
@@ -116,12 +120,12 @@ msgstr "Zugriff verweigert beim Bearbeiten der Aufgabe."
 msgid "Access denied editing task: %s"
 msgstr "Zugriff verweigert beim Bearbeiten der Aufgabe: %s"
 
-#: task.php:170
+#: lib/Driver.php:340
 #, php-format
 msgid "Access denied moving the task to %s."
 msgstr "Zugriff verweigert beim Verschieben von Aufgabe %s."
 
-#: task.php:173
+#: lib/Driver.php:330
 #, php-format
 msgid "Access denied removing task from %s."
 msgstr "Zugriff verweigert beim Entfernen der Aufgabe von %s."
@@ -136,31 +140,33 @@ msgstr "Zugriff verweigert beim L
 msgid "Access denied saving task: %s"
 msgstr "Zugriff verweigert beim Speichern der Aufgabe: %s"
 
-#: data.php:57 templates/view/task.inc:26 lib/Forms/task.php:91
+#: data.php:57 templates/view/task.inc:30 lib/Forms/task.php:115
 msgid "Alarm"
 msgstr "Alarm"
 
-#: config/prefs.php.dist:200
+#: templates/data/export.inc:34 config/prefs.php.dist:211
 msgid "All tasks"
 msgstr "Alle Aufgaben"
 
-#: lib/Block/summary.php:75
-msgid "Always show completed tasks?"
-msgstr "Erledigte Aufgaben immer anzeigen?"
+#: lib/Block/summary.php:76
+msgid "Always show completed and future tasks?"
+msgstr "Erledigte und zukünftige Aufgaben immer anzeigen?"
 
-#: lib/Block/summary.php:71
+#: lib/Block/summary.php:72
 msgid "Always show overdue tasks?"
 msgstr "Überfällige Aufgaben immer anzeigen?"
 
-#: config/prefs.php.dist:117
+#: config/prefs.php.dist:128
 msgid "Ascending"
 msgstr "Aufsteigend"
 
-#: data.php:55
+#: data.php:55 templates/view/task.inc:12 templates/list/task_headers.inc:60
+#: lib/Forms/task.php:110 config/prefs.php.dist:71 config/prefs.php.dist:100
+#: config/prefs.php.dist:117
 msgid "Assignee"
 msgstr "Zuständiger"
 
-#: lib/Block/summary.php:43
+#: lib/Block/summary.php:44
 msgid "Block title"
 msgstr "Blocktitel"
 
@@ -176,16 +182,17 @@ msgstr "Kalender"
 msgid "Cancel"
 msgstr "Abbrechen"
 
-#: templates/list/task_headers.inc:53
+#: templates/list/task_headers.inc:64
 msgid "Cat_egory"
 msgstr "_Kategorie"
 
-#: data.php:54 templates/view/task.inc:8 lib/Forms/task.php:79
-#: lib/Forms/task.php:85 config/prefs.php.dist:89 config/prefs.php.dist:104
+#: data.php:54 templates/view/task.inc:8 lib/Forms/task.php:102
+#: lib/Forms/task.php:107 config/prefs.php.dist:74 config/prefs.php.dist:96
+#: config/prefs.php.dist:113
 msgid "Category"
 msgstr "Kategorie"
 
-#: templates/tasklist_list.php:35 tasklists/index.php:56
+#: templates/tasklist_list.php:33 tasklists/index.php:56
 msgid "Change Permissions"
 msgstr "Rechte Ändern"
 
@@ -193,30 +200,93 @@ msgstr "Rechte 
 msgid "Change your task sorting and display options."
 msgstr "Ändern Sie die Sortierreihenfolge und andere Anzeigeeinstellungen."
 
-#: config/prefs.php.dist:179
+#: lib/Nag.php:872
+#, php-format
+msgid "Changed alarm from %s to %s"
+msgstr "Alarm von %s zu %s geändert"
+
+#: lib/Nag.php:851
+#, php-format
+msgid "Changed assignee from \"%s\" to \"%s\""
+msgstr "Zuständigkeit von \"%s\" zu \"%s\" geändert"
+
+#: lib/Nag.php:835
+#, php-format
+msgid "Changed category from \"%s\" to \"%s\""
+msgstr "Kategorie von \"%s\" zu \"%s\" geändert"
+
+#: lib/Nag.php:887
+#, php-format
+msgid "Changed completion from %s to %s"
+msgstr "Status von %s zu %s geändert"
+
+#: lib/Nag.php:892
+msgid "Changed description"
+msgstr "Beschreibung geändert"
+
+#: lib/Nag.php:860
+#, php-format
+msgid "Changed due date from %s to %s"
+msgstr "Fälligkeitsdatum von %s zu %s geändert"
+
+#: lib/Nag.php:882
+#, php-format
+msgid "Changed estimate from %s to %s"
+msgstr "Geschätzte Zeit von %s zu %s geändert"
+
+#: lib/Nag.php:812
+#, php-format
+msgid "Changed name from \"%s\" to \"%s\""
+msgstr "Betreff von \"%s\" zu \"%s\" geändert"
+
+#: lib/Nag.php:827
+#, php-format
+msgid "Changed parent task from \"%s\" to \"%s\""
+msgstr "Überaufgabe von \"%s\" zu \"%s\" geändert"
+
+#: lib/Nag.php:877
+#, php-format
+msgid "Changed priority from %s to %s"
+msgstr "Priorität von %s zu %s geändert"
+
+#: lib/Nag.php:866
+#, php-format
+msgid "Changed start date from %s to %s"
+msgstr "Startdatum von %s zu %s geändert"
+
+#: lib/Nag.php:818
+#, php-format
+msgid "Changed task list from \"%s\" to \"%s\""
+msgstr "Aufgabenliste von \"%s\" zu \"%s\" geändert"
+
+#: lib/Nag.php:809
+msgid "Changes made for this task:"
+msgstr "Vorgenommene Änderungen:"
+
+#: config/prefs.php.dist:190
 msgid "Choose how you want to receive reminders for tasks with alarms:"
 msgstr ""
 "Legen Sie fest, wie Sie über Aufgaben mit Alarmen benachrichtigt werden "
 "möchten:"
 
-#: config/prefs.php.dist:170
+#: config/prefs.php.dist:181
 msgid ""
 "Choose if you want to be notified of new, edited, and deleted tasks by email:"
 msgstr ""
 "Legen Sie fest, ob Sie per Email über neue, geänderte oder gelöschte "
 "Aufgaben benachrichtigt werden möchten:"
 
-#: config/prefs.php.dist:42
+#: config/prefs.php.dist:43
 msgid "Choose if you want to be notified of task changes and task alarms."
 msgstr ""
 "Legen Sie fest, ob Sie über Aufgabenänderungen und Aufgabenalarme "
 "benachrichtigt werden möchten."
 
-#: config/prefs.php.dist:35
+#: config/prefs.php.dist:36
 msgid "Choose your default task list."
 msgstr "Wählen Sie Ihre Standard-Aufgabenliste aus."
 
-#: templates/tasklist_list.php:31 templates/tasklist_list.php:32
+#: templates/tasklist_list.php:29 templates/tasklist_list.php:30
 msgid "Click or copy this URL to display this task list"
 msgstr ""
 "Kopieren Sie diese Adresse in Ihren Browser oder klicken Sie darauf, um "
@@ -230,28 +300,28 @@ msgstr "Schlie
 msgid "Close Search"
 msgstr "Suche schließen"
 
-#: view.php:112
+#: view.php:113
 msgid "Complete"
 msgstr "Erledigen"
 
-#: templates/list/task_summaries.inc:11 lib/Block/summary.php:191
+#: templates/list/task_summaries.inc:11 lib/Block/summary.php:192
 #, php-format
 msgid "Complete \"%s\""
 msgstr "\"%s\" erledigen"
 
-#: templates/view/task.inc:42
+#: templates/view/task.inc:46
 msgid "Complete Task"
 msgstr "Aufgabe erledigen"
 
-#: config/prefs.php.dist:202
+#: config/prefs.php.dist:213
 msgid "Complete tasks"
 msgstr "Erledigte Aufgaben"
 
-#: lib/Nag.php:407 lib/Block/summary.php:189
+#: lib/Nag.php:425 lib/Block/summary.php:190
 msgid "Completed"
 msgstr "Erledigt"
 
-#: task.php:236
+#: task.php:220
 #, php-format
 msgid "Completed %s."
 msgstr "%s erledigt."
@@ -265,8 +335,12 @@ msgid "Completed parent task, mark it as incomplete first"
 msgstr ""
 "Überaufgabe ist bereits erledigt, markieren Sie diese erst als unerledigt"
 
-#: templates/view/task.inc:38 templates/list/task_headers.inc:31
-#: lib/Forms/task.php:97 config/prefs.php.dist:91 config/prefs.php.dist:106
+#: templates/data/export.inc:37
+msgid "Completed tasks"
+msgstr "Erledigte Aufgaben"
+
+#: templates/view/task.inc:42 templates/list/task_headers.inc:31
+#: lib/Forms/task.php:121 config/prefs.php.dist:98 config/prefs.php.dist:115
 msgid "Completed?"
 msgstr "Erledigt?"
 
@@ -278,7 +352,7 @@ msgstr "Erledigungsdatum"
 msgid "Completion Status"
 msgstr "Fortschritt"
 
-#: lib/api.php:443 lib/api.php:704
+#: lib/api.php:509 lib/api.php:753
 #, php-format
 msgid "Connection failed: %s"
 msgstr "Verbindung fehlgeschlagen: %s"
@@ -291,35 +365,39 @@ msgstr "Erstellen"
 msgid "Create Task List"
 msgstr "Aufgabenliste erstellen"
 
-#: templates/tasklist_list.php:8
+#: templates/tasklist_list.php:9
 msgid "Create a new Task List"
 msgstr "Neue Aufgabenliste erstellen"
 
-#: templates/view/task.inc:57
+#: templates/view/task.inc:61
 msgid "Created"
 msgstr "Erstellt"
 
+#: lib/Recurrence.php:199
+msgid "Daily"
+msgstr "Täglich"
+
 #: lib/UI/VarRenderer/nag.php:51 lib/UI/VarRenderer/nag.php:100
 msgid "Day"
 msgstr "Tag"
 
-#: lib/Nag.php:439 lib/UI/VarRenderer/nag.php:136
+#: lib/Nag.php:457 lib/UI/VarRenderer/nag.php:136
 msgid "Day(s)"
 msgstr "Tag(e)"
 
-#: config/prefs.php.dist:34
+#: config/prefs.php.dist:35
 msgid "Default Task List"
 msgstr "Standard-Aufgabenliste"
 
-#: config/prefs.php.dist:28
+#: config/prefs.php.dist:29
 msgid "Defaults for new tasks"
 msgstr "Standardeinstellungen für neue Aufgaben"
 
-#: lib/Forms/task.php:90
+#: lib/Forms/task.php:114
 msgid "Delay Start Until"
 msgstr "Start verzögern bis"
 
-#: view.php:119 templates/tasklist_list.php:37 tasklists/index.php:57
+#: view.php:120 templates/tasklist_list.php:35 tasklists/index.php:57
 #: lib/Forms/DeleteTaskList.php:45
 msgid "Delete"
 msgstr "Löschen"
@@ -329,15 +407,15 @@ msgstr "L
 msgid "Delete %s"
 msgstr "%s löschen"
 
-#: config/prefs.php.dist:20
+#: config/prefs.php.dist:21
 msgid "Delete Confirmation"
 msgstr "Löschbestätigung"
 
-#: config/prefs.php.dist:21
+#: config/prefs.php.dist:22
 msgid "Delete button behaviour"
 msgstr "Verhalten beim Löschen."
 
-#: task.php:112 lib/Forms/task.php:102 lib/Forms/task.php:129
+#: task.php:112 lib/Forms/task.php:127 lib/Forms/task.php:154
 msgid "Delete this task"
 msgstr "Diese Aufgabe löschen"
 
@@ -346,16 +424,15 @@ msgstr "Diese Aufgabe l
 msgid "Deleted %s."
 msgstr "%s gelöscht."
 
-#: lib/api.php:686
+#: lib/api.php:735
 msgid "Deleting entire tasklists is not supported."
 msgstr "Das Löschen ganzer Aufgabenlisten wird nicht unterstützt."
 
-#: config/prefs.php.dist:118
+#: config/prefs.php.dist:129
 msgid "Descending"
 msgstr "Absteigend"
 
-#: data.php:53 lib/Forms/EditTaskList.php:44 lib/Forms/CreateTaskList.php:37
-#: lib/Forms/task.php:98
+#: data.php:53 lib/Forms/task.php:122
 msgid "Description"
 msgstr "Beschreibung"
 
@@ -363,19 +440,19 @@ msgstr "Beschreibung"
 msgid "Display Options"
 msgstr "Anzeige-Einstellungen"
 
-#: templates/tasklist_list.php:16
+#: templates/tasklist_list.php:18
 msgid "Display URL"
 msgstr "Anzeige-Adresse"
 
-#: config/prefs.php.dist:128
+#: config/prefs.php.dist:139
 msgid "Do you want to confirm deleting entries?"
 msgstr "Möchten Sie das Löschen von Einträgen bestätigen?"
 
-#: data.php:56 templates/view/task.inc:22 lib/Forms/task.php:89
+#: data.php:56 templates/view/task.inc:26 lib/Forms/task.php:113
 msgid "Due By"
 msgstr "Fällig am"
 
-#: config/prefs.php.dist:90 config/prefs.php.dist:105
+#: config/prefs.php.dist:72 config/prefs.php.dist:97 config/prefs.php.dist:114
 msgid "Due Date"
 msgstr "Fälligkeitsdatum"
 
@@ -383,11 +460,11 @@ msgstr "F
 msgid "Due date specified."
 msgstr "Fälligkeitsdatum angegeben."
 
-#: view.php:115 templates/tasklist_list.php:33 tasklists/index.php:55
+#: view.php:116 templates/tasklist_list.php:31 tasklists/index.php:55
 msgid "Edit"
 msgstr "Bearbeiten"
 
-#: templates/list/task_summaries.inc:38 lib/Block/summary.php:182
+#: templates/list/task_summaries.inc:39 lib/Block/summary.php:182
 #, php-format
 msgid "Edit \"%s\""
 msgstr "\"%s\" bearbeiten"
@@ -397,11 +474,11 @@ msgstr "\"%s\" bearbeiten"
 msgid "Edit %s"
 msgstr "%s bearbeiten"
 
-#: templates/list/task_headers.inc:42
+#: templates/list/task_headers.inc:43
 msgid "Edit Task"
 msgstr "Aufgabe bearbeiten"
 
-#: templates/list/task_headers.inc:58
+#: templates/list/task_headers.inc:69
 msgid "Edit categories and colors"
 msgstr "Kategorien und Farben bearbeiten"
 
@@ -415,11 +492,13 @@ msgstr "Bearbeiten: %s"
 msgid "Error deleting task: %s"
 msgstr "Fehler beim Löschen der Aufgabe: %s"
 
-#: data.php:61 templates/view/task.inc:34 lib/Forms/task.php:96
+#: data.php:61 templates/view/task.inc:38 templates/list/task_headers.inc:56
+#: lib/Forms/task.php:120 config/prefs.php.dist:73 config/prefs.php.dist:99
+#: config/prefs.php.dist:116
 msgid "Estimated Time"
 msgstr "Geschätzte Zeit"
 
-#: templates/data/export.inc:17
+#: templates/data/export.inc:41
 msgid "Export"
 msgstr "Exportieren"
 
@@ -427,11 +506,15 @@ msgstr "Exportieren"
 msgid "Export Tasks"
 msgstr "Aufgaben exportieren"
 
-#: config/prefs.php.dist:56
+#: config/prefs.php.dist:57
 msgid "External Data"
 msgstr "Externe Daten"
 
-#: config/prefs.php.dist:12 config/prefs.php.dist:19 config/prefs.php.dist:26
+#: templates/data/export.inc:36
+msgid "Future tasks"
+msgstr "Zukünftige Aufgaben"
+
+#: config/prefs.php.dist:12 config/prefs.php.dist:20 config/prefs.php.dist:27
 msgid "General Options"
 msgstr "Allgemeine Einstellungen"
 
@@ -439,7 +522,7 @@ msgstr "Allgemeine Einstellungen"
 msgid "Hour"
 msgstr "Stunde"
 
-#: lib/Nag.php:442 lib/UI/VarRenderer/nag.php:135
+#: lib/Nag.php:460 lib/UI/VarRenderer/nag.php:135
 msgid "Hour(s)"
 msgstr "Stunde(n)"
 
@@ -448,7 +531,7 @@ msgstr "Stunde(n)"
 msgid "Import Tasks, Step %d"
 msgstr "Aufgaben importieren, Schritt %d"
 
-#: data.php:218
+#: data.php:224
 msgid "Import/Export Tasks"
 msgstr "Aufgaben Import/Export"
 
@@ -464,19 +547,23 @@ msgstr "Unerledigte Aufgaben"
 msgid "Incomplete sub tasks, complete them first"
 msgstr "Unerledigte Unteraufgaben, erledigen Sie diese erst"
 
-#: config/prefs.php.dist:201
+#: templates/data/export.inc:35 config/prefs.php.dist:212
 msgid "Incomplete tasks"
 msgstr "Unerledigte Aufgaben"
 
-#: lib/api.php:520
+#: lib/api.php:437
+msgid "Invalid tasklist file requested."
+msgstr "Ungültige Aufgabenliste angegeben."
+
+#: lib/api.php:576
 msgid "Invalid tasklist name supplied."
 msgstr "Ungültige Aufgabenliste angegeben."
 
-#: lib/api.php:386
+#: lib/api.php:453
 msgid "Invalid tasklist requested."
 msgstr "Ungültige Aufgabenliste angegeben."
 
-#: templates/view/task.inc:64
+#: templates/view/task.inc:68
 msgid "Last Modified"
 msgstr "Letzte Änderung"
 
@@ -489,7 +576,7 @@ msgstr "Aufgabenlisten-Verwaltung"
 msgid "Mark \"%s\" as incomplete"
 msgstr "\"%s\" als unerledigt markieren"
 
-#: templates/view/task.inc:44
+#: templates/view/task.inc:48
 msgid "Mark as incomplete"
 msgstr "Als unerledigt markieren"
 
@@ -509,7 +596,7 @@ msgstr "Men
 msgid "Minute"
 msgstr "Minute"
 
-#: lib/Nag.php:445 lib/UI/VarRenderer/nag.php:135
+#: lib/Nag.php:463 lib/UI/VarRenderer/nag.php:135
 msgid "Minute(s)"
 msgstr "Minute(n)"
 
@@ -517,11 +604,15 @@ msgstr "Minute(n)"
 msgid "Month"
 msgstr "Monat"
 
+#: lib/Recurrence.php:202
+msgid "Monthly"
+msgstr "Monatlich"
+
 #: templates/list/header.inc:9
 msgid "More Options..."
 msgstr "Weitere Optionen..."
 
-#: lib/api.php:1179
+#: lib/api.php:1213
 msgid "Multiple iCalendar components found; only one vTodo is supported."
 msgstr ""
 "Mehrere iCalendar-Komponenten gefunden; nur ein vTodo wird unterstützt."
@@ -538,7 +629,7 @@ msgstr "Meine Aufgaben"
 msgid "N_ame"
 msgstr "Na_me"
 
-#: templates/list/task_headers.inc:45
+#: templates/list/task_headers.inc:46
 msgid "Na_me"
 msgstr "Na_me"
 
@@ -547,10 +638,9 @@ msgstr "Na_me"
 msgid "Nag/kolab: Did not find task %s"
 msgstr "Nag/kolab: Aufgabe %s nicht gefunden"
 
-#: data.php:52 lib/Forms/EditTaskList.php:43 lib/Forms/CreateTaskList.php:36
-#: lib/Forms/task.php:68
+#: data.php:52 lib/Forms/task.php:91
 msgid "Name"
-msgstr "Name"
+msgstr "Betreff"
 
 #: task.php:81 task.php:116 lib/Block/tree_menu.php:26
 msgid "New Task"
@@ -560,7 +650,7 @@ msgstr "Neue Aufgabe"
 msgid "Next"
 msgstr "Weiter"
 
-#: config/prefs.php.dist:166
+#: config/prefs.php.dist:177
 msgid "No"
 msgstr "Nein"
 
@@ -572,7 +662,7 @@ msgstr "Keine Verz
 msgid "No due date."
 msgstr "Kein Fälligkeitsdatum"
 
-#: lib/api.php:553 lib/api.php:902 lib/api.php:960 lib/api.php:1172
+#: lib/api.php:949 lib/api.php:1007 lib/api.php:1206
 msgid "No iCalendar data was found."
 msgstr "Es wurden keine iCalendar-Daten gefunden."
 
@@ -580,7 +670,11 @@ msgstr "Es wurden keine iCalendar-Daten gefunden."
 msgid "No parent task"
 msgstr "Keine Überaufgabe"
 
-#: lib/Nag.php:633
+#: lib/Recurrence.php:198
+msgid "No recurrence"
+msgstr "Keine Wiederholung"
+
+#: lib/Nag.php:685
 msgid "No task lists are available to guests."
 msgstr "Es sind keine Aufgabenlisten für Gäste verfügbar."
 
@@ -588,43 +682,39 @@ msgstr "Es sind keine Aufgabenlisten f
 msgid "No tasks match"
 msgstr "Keine Treffer"
 
-#: lib/Block/summary.php:245
+#: lib/Block/summary.php:250
 msgid "No tasks to display"
 msgstr "Keine Aufgaben"
 
-#: lib/Nag.php:449 lib/UI/VarRenderer/nag.php:151
+#: lib/Nag.php:467 lib/Forms/task.php:111 lib/UI/VarRenderer/nag.php:151
 msgid "None"
 msgstr "Keiner"
 
-#: lib/Nag.php:408
+#: lib/Nag.php:426
 msgid "Not Completed"
 msgstr "Nicht Erledigt"
 
-#: templates/view/task.inc:14
+#: templates/view/task.inc:18
 msgid "Not Private"
 msgstr "Nicht Privat"
 
-#: lib/api.php:760
+#: lib/api.php:809
 msgid "Not configured"
 msgstr "Nicht konfiguriert"
 
-#: lib/Driver/sql.php:100 lib/Driver/sql.php:136
-msgid "Not found"
-msgstr "Nicht gefunden"
-
-#: config/prefs.php.dist:41
+#: config/prefs.php.dist:42
 msgid "Notifications"
 msgstr "Benachrichtigungen"
 
-#: config/prefs.php.dist:168
+#: config/prefs.php.dist:179
 msgid "On all shown task lists"
 msgstr "Bei allen angezeigten Aufgabenlisten"
 
-#: config/prefs.php.dist:169
+#: config/prefs.php.dist:180
 msgid "On all task lists I have read access to"
 msgstr "Bei allen Aufgabenlisten, für die ich Leserechte habe"
 
-#: config/prefs.php.dist:167
+#: config/prefs.php.dist:178
 msgid "On my task lists only"
 msgstr "Nur bei meinen Aufgabenlisten"
 
@@ -632,34 +722,34 @@ msgstr "Nur bei meinen Aufgabenlisten"
 msgid "P_ri"
 msgstr "_Pri"
 
-#: lib/Forms/task.php:75
+#: lib/Forms/task.php:98
 msgid "Parent task"
 msgstr "Überaufgabe"
 
-#: lib/api.php:769 lib/api.php:807 lib/api.php:840 lib/api.php:876
-#: lib/api.php:998 lib/api.php:1053 lib/api.php:1117 lib/api.php:1154
-#: lib/api.php:1267 lib/api.php:1314
+#: lib/api.php:818 lib/api.php:856 lib/api.php:889 lib/api.php:924
+#: lib/api.php:1043 lib/api.php:1093 lib/api.php:1155 lib/api.php:1190
+#: lib/api.php:1301 lib/api.php:1348
 msgid "Permission Denied"
 msgstr "Zugriff verweigert"
 
-#: lib/api.php:210 lib/Forms/DeleteTaskList.php:56
+#: lib/api.php:261 lib/Forms/DeleteTaskList.php:56
 msgid "Permission denied"
 msgstr "Zugriff verweigert"
 
-#: data.php:59 templates/view/task.inc:30 lib/Forms/task.php:93
-#: config/prefs.php.dist:87 config/prefs.php.dist:102
+#: data.php:59 templates/view/task.inc:34 lib/Forms/task.php:117
+#: config/prefs.php.dist:70 config/prefs.php.dist:94 config/prefs.php.dist:111
 msgid "Priority"
 msgstr "Priorität"
 
-#: templates/view/task.inc:14 lib/Driver.php:907
+#: templates/view/task.inc:18 lib/Driver.php:976
 msgid "Private"
 msgstr "Privat"
 
-#: data.php:60 lib/Driver.php:905
+#: data.php:60 lib/Driver.php:974
 msgid "Private Task"
 msgstr "Private Aufgabe"
 
-#: templates/view/task.inc:12 lib/Forms/task.php:88
+#: templates/view/task.inc:16 lib/Forms/task.php:112
 msgid "Private?"
 msgstr "Privat?"
 
@@ -673,16 +763,16 @@ msgstr ""
 "rückgängig gemacht werden, und alle Daten in dieser Aufgabenliste werden "
 "endgültig gelöscht."
 
-#: view.php:119
+#: view.php:120
 msgid "Really delete this task?"
 msgstr "Diese Aufgabe wirklich löschen?"
 
-#: templates/panel.inc:90 lib/Forms/EditTaskList.php:46 lib/Forms/task.php:100
-#: lib/Forms/task.php:127
+#: templates/panel.inc:90 lib/Forms/EditTaskList.php:46 lib/Forms/task.php:125
+#: lib/Forms/task.php:152
 msgid "Save"
 msgstr "Speichern"
 
-#: task.php:201
+#: task.php:185
 #, php-format
 msgid "Saved %s."
 msgstr "%s gespeichert."
@@ -708,7 +798,7 @@ msgstr "Nach Aufgabenlisten suchen:"
 msgid "Search:"
 msgstr "Suche:"
 
-#: list.php:73
+#: list.php:73 tasks/index.php:46
 #, php-format
 msgid "Search: Results for \"%s\""
 msgstr "Suche: Ergebnisse für \"%s\""
@@ -717,6 +807,11 @@ msgstr "Suche: Ergebnisse f
 msgid "Select a date"
 msgstr "Datum auswählen"
 
+#: config/prefs.php.dist:75
+msgid "Select the columns that should be shown in the list view:"
+msgstr ""
+"Wählen Sie die Spalten, die in der Listenansicht angezeigt werden sollen:"
+
 #: templates/data/export.inc:11
 msgid "Select the export format:"
 msgstr "Wählen Sie das Exportformat:"
@@ -729,66 +824,72 @@ msgstr "W
 msgid "Select the format of the source file:"
 msgstr "Wählen Sie das Format der importierten Datei:"
 
+#: templates/data/export.inc:20
+msgid "Select the task list(s) to export from:"
+msgstr "Wählen Sie die Aufgabenliste(n), die exportiert werden soll(en):"
+
+#: templates/data/export.inc:32
+msgid "Select the task states to export:"
+msgstr "Wählen Sie den Status der Aufgaben, die exportiert werden sollen:"
+
 #: templates/panel.inc:81
 msgid "Shared Task Lists:"
 msgstr "Gemeinsame Aufgabenlisten:"
 
-#: config/prefs.php.dist:68
-msgid "Should the Task List be shown in its own column in the List view?"
-msgstr ""
-"Soll die Aufgabenliste in einer eigenen Spalte in der Listenansicht "
-"angezeigt werden?"
-
-#: lib/Block/summary.php:51
+#: lib/Block/summary.php:52
 msgid "Show action buttons?"
 msgstr "Aktionsknöpfe anzeigen?"
 
-#: config/prefs.php.dist:203
+#: config/prefs.php.dist:214
 msgid "Show complete, incomplete, or all tasks in the task list?"
 msgstr ""
 "Erledigte, unerledigte oder alle Aufgaben in der Aufgabenliste anzeigen?"
 
-#: config/prefs.php.dist:190
+#: config/prefs.php.dist:201
 msgid "Show data from any of these other applications in your task list?"
 msgstr "Daten von einer dieser Anwendungen in Ihren Aufgabenlisten anzeigen?"
 
-#: config/prefs.php.dist:57
+#: config/prefs.php.dist:58
 msgid "Show data from other applications or sources."
 msgstr "Daten von anderen Anwendungen oder Quellen anzeigen."
 
-#: lib/Block/summary.php:55
+#: lib/Block/summary.php:56
 msgid "Show due dates?"
 msgstr "Fälligkeitsdaten anzeigen?"
 
-#: lib/Block/summary.php:47
+#: lib/Block/summary.php:48
 msgid "Show priorities?"
 msgstr "Prioritäten anzeigen?"
 
-#: lib/Block/summary.php:63
+#: lib/Block/summary.php:64
 msgid "Show task alarms?"
 msgstr "Aufgabenalarme anzeigen?"
 
-#: lib/Block/summary.php:67
+#: lib/Block/summary.php:68
 msgid "Show task category?"
 msgstr "Aufgabenkategorie anzeigen?"
 
-#: config/prefs.php.dist:78
+#: config/prefs.php.dist:85
 msgid "Show task list options panel?"
 msgstr "Kasten mit Aufgabenlisteninstellungen anzeigen?"
 
-#: lib/Block/summary.php:59
+#: lib/Block/summary.php:60
 msgid "Show tasklist name?"
 msgstr "Aufgabenlistennamen anzeigen?"
 
-#: lib/Block/summary.php:84
+#: lib/Block/summary.php:85
 msgid "Show tasks from these categories"
 msgstr "Aufgaben dieser Kategorien anzeigen"
 
-#: lib/Block/summary.php:79
+#: lib/Block/summary.php:80
 msgid "Show tasks from these tasklists"
 msgstr "Aufgaben dieser Listen anzeigen"
 
-#: templates/list/task_headers.inc:53
+#: templates/list/task_headers.inc:60
+msgid "Sort by Assignee"
+msgstr "Sortieren nach Zuständigem"
+
+#: templates/list/task_headers.inc:64
 msgid "Sort by Category"
 msgstr "Sortieren nach Kategorie"
 
@@ -796,11 +897,11 @@ msgstr "Sortieren nach Kategorie"
 msgid "Sort by Completion Status"
 msgstr "Sortieren nach Fortschritt"
 
-#: templates/list/task_headers.inc:50
+#: templates/list/task_headers.inc:52
 msgid "Sort by Due Date"
 msgstr "Sortieren nach Fälligkeitsdatum"
 
-#: templates/list/task_headers.inc:45
+#: templates/list/task_headers.inc:46
 msgid "Sort by Name"
 msgstr "Sortieren nach Betreff"
 
@@ -812,11 +913,15 @@ msgstr "Sortieren nach Priorit
 msgid "Sort by User Name"
 msgstr "Sortieren nach Benutzername"
 
-#: config/prefs.php.dist:119
+#: templates/list/task_headers.inc:56
+msgid "Sort by estimated time"
+msgstr "Sortieren nach geschätzter Zeit"
+
+#: config/prefs.php.dist:130
 msgid "Sort direction:"
 msgstr "Sortierrichtung:"
 
-#: config/prefs.php.dist:93
+#: config/prefs.php.dist:102
 msgid "Sort tasks by:"
 msgstr "Aufgaben sortieren nach:"
 
@@ -824,7 +929,7 @@ msgstr "Aufgaben sortieren nach:"
 msgid "Start"
 msgstr "Beginn"
 
-#: templates/view/task.inc:18
+#: templates/view/task.inc:22
 msgid "Start Date"
 msgstr "Startdatum"
 
@@ -832,36 +937,49 @@ msgstr "Startdatum"
 msgid "Start date specified."
 msgstr "Startdatum angegeben."
 
-#: templates/tasklist_list.php:17
+#: templates/tasklist_list.php:19
 msgid "Subscription URL"
 msgstr "Abonnement-Adresse"
 
-#: templates/list/task_summaries.inc:60
+#: templates/list/task_summaries.inc:61
 msgid "Task Alarm"
 msgstr "Aufgabenalarm"
 
-#: templates/list/task_headers.inc:48
+#: templates/list/task_headers.inc:49
 msgid "Task Alarm?"
 msgstr "Aufgabenalarm?"
 
-#: config/prefs.php.dist:27
+#: config/prefs.php.dist:28
 msgid "Task Defaults"
 msgstr "Standardvorgaben"
 
-#: templates/tasklist_list.php:15 lib/Forms/task.php:71
-#: config/prefs.php.dist:92 config/prefs.php.dist:107
+#: lib/Driver/sql.php:100
+msgid "Task ID not found"
+msgstr "Aufgaben-ID nicht gefunden"
+
+#: templates/tasklist_list.php:17 lib/Forms/task.php:94
+#: config/prefs.php.dist:69 config/prefs.php.dist:101
+#: config/prefs.php.dist:118
 msgid "Task List"
 msgstr "Aufgabenliste"
 
+#: lib/Forms/EditTaskList.php:44 lib/Forms/CreateTaskList.php:37
+msgid "Task List Description"
+msgstr "Aufgabenlistenbeschreibung"
+
 #: templates/panel.inc:5
 msgid "Task List Information"
 msgstr "Informationen über Aufgabenliste"
 
-#: templates/tasklist_list.php:12
+#: templates/tasklist_list.php:14
 msgid "Task List List"
 msgstr "Aufgabenlistenübersicht"
 
-#: config/prefs.php.dist:33 config/prefs.php.dist:40 config/prefs.php.dist:55
+#: lib/Forms/EditTaskList.php:43 lib/Forms/CreateTaskList.php:36
+msgid "Task List Name"
+msgstr "Aufgabenlistenname"
+
+#: config/prefs.php.dist:34 config/prefs.php.dist:41 config/prefs.php.dist:56
 msgid "Task List and Share Options"
 msgstr "Aufgabenliste- und Rechte-Einstellungen"
 
@@ -874,15 +992,15 @@ msgstr "Diese Aufgabenliste geh
 msgid "Task Lists"
 msgstr "Aufgabenlisten"
 
-#: config/prefs.php.dist:88 config/prefs.php.dist:103
+#: config/prefs.php.dist:95 config/prefs.php.dist:112
 msgid "Task Name"
 msgstr "Betreff"
 
-#: templates/list/task_summaries.inc:58
+#: templates/list/task_summaries.inc:59
 msgid "Task Note"
 msgstr "Bemerkung"
 
-#: templates/list/task_headers.inc:47
+#: templates/list/task_headers.inc:48
 msgid "Task Note?"
 msgstr "Bemerkung?"
 
@@ -890,31 +1008,39 @@ msgstr "Bemerkung?"
 msgid "Task Search"
 msgstr "Aufgabensuche"
 
-#: lib/Nag.php:658
+#: lib/Driver/sql.php:136
+msgid "Task UID not found"
+msgstr "Aufgaben-UID nicht gefunden."
+
+#: lib/Nag.php:793
 msgid "Task added:"
 msgstr "Neue Aufgabe:"
 
-#: lib/Nag.php:668
+#: lib/Nag.php:897
 msgid "Task deleted:"
 msgstr "Aufgabe gelöscht:"
 
-#: lib/Nag.php:663
+#: lib/Nag.php:915
+msgid "Task description:"
+msgstr "Aufgabenbeschreibung:"
+
+#: lib/Nag.php:802
 msgid "Task modified:"
 msgstr "Aufgabe geändert:"
 
-#: task.php:95 view.php:44
+#: task.php:95 view.php:42
 msgid "Task not found."
 msgstr "Aufgabe nicht gefunden."
 
-#: lib/api.php:698
+#: lib/api.php:747
 msgid "Tasklist does not exist or no permission to delete"
 msgstr "Die Aufgabenliste existiert nicht oder keine Berechtigung zu löschen."
 
-#: lib/api.php:526
+#: lib/api.php:582
 msgid "Tasklist does not exist or no permission to edit"
 msgstr "Die Aufgabenliste existiert nicht oder keine Berechtigung zum Ändern."
 
-#: lib/api.php:1236
+#: lib/api.php:1270
 msgid "Tasks"
 msgstr "Aufgaben"
 
@@ -922,12 +1048,12 @@ msgstr "Aufgaben"
 msgid "Tasks Summary"
 msgstr "Aufgabenübersicht"
 
-#: lib/api.php:348
+#: lib/api.php:399
 #, php-format
 msgid "Tasks from %s"
 msgstr "Aufgaben aus %s"
 
-#: data.php:206
+#: data.php:212
 #, php-format
 msgid "The %s file didn't contain any tasks."
 msgstr "Die %s-Datei enthielt keine Aufgaben."
@@ -941,7 +1067,7 @@ msgstr "Der Aufgabenserver ist zur Zeit nicht verf
 msgid "The Tasks backend is not currently available: %s"
 msgstr "Der Aufgabenserver ist zur Zeit nicht verfügbar: %s"
 
-#: lib/Forms/task.php:160
+#: lib/Forms/task.php:190
 msgid "The alarm value must not be empty."
 msgstr "Der Alarmwert darf nicht leer sein."
 
@@ -949,30 +1075,23 @@ msgstr "Der Alarmwert darf nicht leer sein."
 msgid "The current hour"
 msgstr "Die aktuelle Uhrzeit"
 
-#: lib/Nag.php:659
+#: lib/Nag.php:796
 #, php-format
 msgid ""
-"The task \"%s\" has been added to \"%s\" tasklist, with a due date of: %s."
+"The task \"%s\" has been added to task list \"%s\", with a due date of: %s."
 msgstr ""
 "Die Aufgabe \"%s\", die am %3$s fällig ist, wurde zur Aufgabenliste \"%2$s\" "
 "hinzugefügt."
 
-#: lib/Nag.php:669
+#: lib/Nag.php:901
 #, php-format
-msgid ""
-"The task \"%s\" has been deleted from \"%s\" tasklist, with a due date of: %"
-"s."
-msgstr ""
-"Die Aufgabe \"%s\", die am %3$s fällig ist, wurde aus der Aufgabenliste \"%2"
-"$s\" gelöscht."
+msgid "The task \"%s\" has been deleted from task list \"%s\"."
+msgstr "Die Aufgabe \"%s\" wurde aus der Aufgabenliste \"%s\" gelöscht."
 
-#: lib/Nag.php:664
+#: lib/Nag.php:805
 #, php-format
-msgid ""
-"The task \"%s\" has been edited on \"%s\" tasklist, with a due date of: %s."
-msgstr ""
-"Die Aufgabe \"%s\", die am %3$s fällig ist, wurde in der Aufgabenliste \"%2$s"
-"\" geändert."
+msgid "The task \"%s\" has been edited on task list \"%s\"."
+msgstr "Die Aufgabe \"%s\" wurde in der Aufgabenliste \"%s\" geändert."
 
 #: tasklists/create.php:31
 #, php-format
@@ -994,7 +1113,7 @@ msgstr "Die Aufgabenliste \"%s\" wurde nach \"%s\" umbenannt."
 msgid "The task list \"%s\" has been saved."
 msgstr "Die Aufgabenliste \"%s\" wurde gespeichert."
 
-#: config/prefs.php.dist:108
+#: config/prefs.php.dist:119
 msgid "Then:"
 msgstr "Dann:"
 
@@ -1002,7 +1121,7 @@ msgstr "Dann:"
 msgid "There are no tasks matching the current criteria."
 msgstr "Es gibt keine Aufgaben, die den Suchkriterien entsprechen."
 
-#: task.php:232
+#: task.php:216
 #, php-format
 msgid "There was a problem completing %s: %s"
 msgstr "Beim Erledigen von %s ist ein Problem aufgetreten: %s"
@@ -1012,25 +1131,32 @@ msgstr "Beim Erledigen von %s ist ein Problem aufgetreten: %s"
 msgid "There was a problem deleting %s: %s"
 msgstr "Beim Löschen von %s ist ein Problem aufgetreten: %s"
 
-#: task.php:199
+#: task.php:183
 #, php-format
 msgid "There was a problem saving the task: %s."
 msgstr "Beim Speichern der Aufgabe ist ein Fehler aufgetreten: %s."
 
-#: data.php:209
+#: data.php:215
 #, php-format
 msgid "There was an error importing the data: %s"
 msgstr "Beim Importieren der Daten ist ein Fehler aufgetreten: %s"
 
-#: lib/api.php:545 lib/api.php:894 lib/api.php:1166
+#: lib/api.php:599 lib/api.php:941 lib/api.php:1200
 msgid "There was an error importing the iCalendar data."
 msgstr "Beim Importieren der iCalendar Daten ist ein Fehler aufgetreten."
 
-#: data.php:89
+#: lib/api.php:211
+#, php-format
+msgid "There was an error removing tasks for %s. Details have been logged."
+msgstr ""
+"Beim Löschen der Aufgaben von %s ist ein Fehler aufgetreten. Details wurden "
+"protokolliert."
+
+#: data.php:94
 msgid "There were no tasks to export."
 msgstr "Es konnten keine Aufgaben zum Exportieren gefunden werden."
 
-#: data.php:138
+#: data.php:143
 msgid "This file format is not supported."
 msgstr "Dieses Dateiformat wird nicht unterstützt."
 
@@ -1044,12 +1170,20 @@ msgstr ""
 "Um diese Aufgabenliste mit einem anderen Programm zu abonnieren, verwenden "
 "Sie die folgende Adresse:"
 
+#: lib/Nag.php:856
+msgid "Turned privacy off"
+msgstr "Als privat markiert"
+
+#: lib/Nag.php:856
+msgid "Turned privacy on"
+msgstr "Nicht mehr als privat markiert"
+
 #: lib/Forms/DeleteTaskList.php:63
 #, php-format
 msgid "Unable to delete \"%s\": %s"
 msgstr "\"%s\" kann nicht gelöscht werden: %s"
 
-#: lib/api.php:719
+#: lib/api.php:768
 #, php-format
 msgid "Unable to delete tasklist \"%s\": %s"
 msgstr "Die Aufgabenliste \"%s\" kann nicht gelöscht werden: %s"
@@ -1064,9 +1198,9 @@ msgstr "Der %s-Treiber konnte nicht geladen werden."
 msgid "Unable to save task list \"%s\": %s"
 msgstr "Die Aufgabenliste \"%s\" kann nicht gespeichert werden: %s"
 
-#: templates/view/task.inc:9 templates/list/task_summaries.inc:65
-#: lib/Nag.php:900 lib/Nag.php:901 lib/Nag.php:915 lib/Nag.php:916
-#: lib/Forms/task.php:84 lib/Block/summary.php:34 lib/Block/summary.php:238
+#: templates/view/task.inc:9 templates/list/task_summaries.inc:76
+#: lib/Nag.php:1149 lib/Nag.php:1150 lib/Nag.php:1164 lib/Nag.php:1165
+#: lib/Forms/task.php:107 lib/Block/summary.php:35 lib/Block/summary.php:243
 msgid "Unfiled"
 msgstr "Nicht zugeordnet"
 
@@ -1074,13 +1208,13 @@ msgstr "Nicht zugeordnet"
 msgid "Unique ID"
 msgstr "Eindeutige ID"
 
-#: lib/api.php:652 lib/api.php:967 lib/api.php:1025 lib/api.php:1079
-#: lib/api.php:1204
+#: lib/api.php:701 lib/api.php:1014 lib/api.php:1068 lib/api.php:1117
+#: lib/api.php:1238
 #, php-format
 msgid "Unsupported Content-Type: %s"
 msgstr "Nicht unterstützer Inhaltstyp: %s"
 
-#: lib/Driver.php:1084
+#: lib/Driver.php:1155
 #, php-format
 msgid ""
 "We would like to remind you of this due task.\n"
@@ -1101,15 +1235,19 @@ msgstr ""
 "\n"
 "%s"
 
-#: lib/Nag.php:436 lib/UI/VarRenderer/nag.php:136
+#: lib/Nag.php:454 lib/UI/VarRenderer/nag.php:136
 msgid "Week(s)"
 msgstr "Woche(n)"
 
+#: lib/Recurrence.php:200
+msgid "Weekly"
+msgstr "Wöchentlich"
+
 #: templates/prefs/defaultduetimeselect.inc:6
 msgid "What do you want to be the default due time for tasks?"
 msgstr "Zur welcher Zeit sollen Aufgaben standardmäßig fällig sein?"
 
-#: config/prefs.php.dist:146
+#: config/prefs.php.dist:157
 msgid ""
 "When creating a new task, how many days in the future should the default due "
 "date be (0 means today)?"
@@ -1117,7 +1255,7 @@ msgstr ""
 "Wieviele Tage in der Zukunft soll das Fälligkeitsdatum von neuen Aufgaben "
 "standardmäßig liegen (0 bedeutet heute)?"
 
-#: config/prefs.php.dist:137
+#: config/prefs.php.dist:148
 msgid "When creating a new task, should it default to having a due date?"
 msgstr "Soll eine neue Aufgabe standardmäßig ein Fälligkeitsdatum haben?"
 
@@ -1129,11 +1267,15 @@ msgstr "Zu welcher Aufgabenliste sollen die Aufgaben hinzugef
 msgid "Year"
 msgstr "Jahr"
 
+#: lib/Recurrence.php:205
+msgid "Yearly"
+msgstr "Jährlich"
+
 #: tasklists/edit.php:28
 msgid "You are not allowed to change this task list."
 msgstr "Sie dürfen diese Aufgabenliste nicht ändern."
 
-#: data.php:41 data.php:163 task.php:68
+#: data.php:41 data.php:168 task.php:68
 #, php-format
 msgid "You are not allowed to create more than %d tasks."
 msgstr "Sie dürfen nicht an mehr als %d Aufgaben erstellen."
@@ -1142,25 +1284,29 @@ msgstr "Sie d
 msgid "You are not allowed to delete this task list."
 msgstr "Sie dürfen diese Aufgabenliste nicht löschen."
 
-#: view.php:52
+#: lib/api.php:143
+msgid "You are not allowed to remove user data."
+msgstr "Sie dürfen keine Benutzerdaten löschen."
+
+#: view.php:53
 msgid "You do not have permission to view this tasklist."
 msgstr "Sie haben nicht genügend Rechte, um diese Aufgabenliste anzuzeigen."
 
-#: lib/Nag.php:659
-msgid "You requested to be notified when tasks are added to your tasklists."
+#: lib/Nag.php:794
+msgid "You requested to be notified when tasks are added to your task lists."
 msgstr ""
 "Sie wollten benachrichtigt werden, wenn Aufgaben zu Ihren Aufgabenlisten "
 "hinzugefügt werden."
 
-#: lib/Nag.php:669
+#: lib/Nag.php:899
 msgid ""
-"You requested to be notified when tasks are deleted from your tasklists."
+"You requested to be notified when tasks are deleted from your task lists."
 msgstr ""
 "Sie wollten benachrichtigt werden, wenn Aufgaben aus Ihren Aufgabenlisten "
 "gelöscht werden."
 
-#: lib/Nag.php:664
-msgid "You requested to be notified when tasks are edited on your tasklists."
+#: lib/Nag.php:803
+msgid "You requested to be notified when tasks are edited on your task lists."
 msgstr ""
 "Sie wollten benachrichtigt werden, wenn Aufgaben in Ihren Aufgabenlisten "
 "geändert werden."
@@ -1173,8 +1319,8 @@ msgstr "Ihre Standard-Aufgabenliste:"
 msgid "[Manage Task Lists]"
 msgstr "[Aufgabenlisten verwalten]"
 
-#: templates/list/task_summaries.inc:48 lib/Block/summary.php:115
-#: lib/Block/summary.php:222
+#: templates/list/task_summaries.inc:49 lib/Block/summary.php:118
+#: lib/Block/summary.php:226
 msgid "[none]"
 msgstr "[keine]"
 
@@ -1190,7 +1336,7 @@ msgstr "_Alle Aufgaben"
 msgid "_Category"
 msgstr "_Kategorie"
 
-#: view.php:112
+#: view.php:113
 msgid "_Complete"
 msgstr "E_rledigen"
 
@@ -1198,7 +1344,7 @@ msgstr "E_rledigen"
 msgid "_Completed tasks"
 msgstr "E_rledigte Aufgaben"
 
-#: view.php:119
+#: view.php:120
 msgid "_Delete"
 msgstr "Lös_chen"
 
@@ -1206,11 +1352,11 @@ msgstr "L
 msgid "_Description"
 msgstr "Besch_reibung"
 
-#: templates/list/task_headers.inc:50
+#: templates/list/task_headers.inc:52
 msgid "_Due Date"
 msgstr "_Fälligkeitsdatum"
 
-#: view.php:115
+#: view.php:116
 msgid "_Edit"
 msgstr "_Bearbeiten"
 
@@ -1218,23 +1364,23 @@ msgstr "_Bearbeiten"
 msgid "_Future tasks"
 msgstr "_Zukünftige Aufgaben"
 
-#: lib/Nag.php:581
+#: lib/Nag.php:633
 msgid "_Import/Export"
 msgstr "_Import/Export"
 
-#: lib/Nag.php:568
+#: lib/Nag.php:620
 msgid "_List Tasks"
 msgstr "Aufgaben_liste"
 
-#: lib/Nag.php:573
+#: lib/Nag.php:625
 msgid "_New Task"
 msgstr "_Neue Aufgabe"
 
-#: lib/Nag.php:586
+#: lib/Nag.php:638
 msgid "_Print"
 msgstr "_Drucken"
 
-#: lib/Nag.php:577
+#: lib/Nag.php:629
 msgid "_Search"
 msgstr "_Suche"
 
@@ -1246,15 +1392,19 @@ msgstr "Aufga_benliste"
 msgid "am"
 msgstr "am"
 
-#: view.php:73 view.php:82
+#: view.php:74 view.php:83
 #, php-format
 msgid "by %s"
 msgstr "durch %s"
 
-#: view.php:75 view.php:84
+#: view.php:76 view.php:85
 msgid "by me"
 msgstr "durch mich"
 
+#: lib/Nag.php:888 lib/Nag.php:889
+msgid "completed"
+msgstr "erledigt"
+
 #: data.php:31
 msgid "iCalendar (vTodo)"
 msgstr "iCalendar (vTodo)"
@@ -1264,18 +1414,34 @@ msgstr "iCalendar (vTodo)"
 msgid "in %s"
 msgstr "in %s"
 
-#: lib/Nag.php:79
+#: lib/Nag.php:861 lib/Nag.php:862 lib/Nag.php:913
+msgid "no due date"
+msgstr "keins"
+
+#: lib/Nag.php:828 lib/Nag.php:829
+msgid "no parent"
+msgstr "keine"
+
+#: lib/Nag.php:867 lib/Nag.php:868
+msgid "no start date"
+msgstr "keins"
+
+#: lib/Nag.php:89
 msgid "no time"
 msgstr "keine Zeit"
 
+#: lib/Nag.php:888 lib/Nag.php:889
+msgid "not completed"
+msgstr "nicht erledigt"
+
 #: templates/prefs/defaultduetimeselect.inc:15
 msgid "pm"
 msgstr "pm"
 
-#: data.php:109 templates/data/export.inc:1
+#: data.php:114 templates/data/export.inc:1
 msgid "tasks.csv"
 msgstr "aufgaben.csv"
 
-#: data.php:123
+#: data.php:128
 msgid "tasks.ics"
 msgstr "aufgaben.ics"
diff --git a/po/el_GR.po b/po/el_GR.po
index eab62c0..63d5be8 100644
--- a/po/el_GR.po
+++ b/po/el_GR.po
@@ -1,5 +1,5 @@
 # Nag Greek translation
-# Copyright (C) 2002 Stefanos I. Dimitriou.
+# Copyright 2002 Stefanos I. Dimitriou.
 # Stefanos I. Dimitriou <support_webmail at teiath.gr>, 2002.
 # Silligardos Xristoforos, 2002.
 # Anagnostopoulos Apostolis, 2002.
diff --git a/po/es_ES.po b/po/es_ES.po
index 41ea873..c17e4d8 100644
--- a/po/es_ES.po
+++ b/po/es_ES.po
@@ -1,6 +1,6 @@
 # Spanish translations for nag package
 # Traducciones al español para el paquete nag.
-# Copyright (C) 2008 Horde Project
+# Copyright 2008-2009 The Horde Project
 # This file is distributed under the same license as the nag package.
 # Automatically generated, 2008.
 #
@@ -8,8 +8,8 @@ msgid ""
 msgstr ""
 "Project-Id-Version: Nag 2.2-rc3\n"
 "Report-Msgid-Bugs-To: dev at lists.horde.org\n"
-"POT-Creation-Date: 2008-05-24 09:44+0200\n"
-"PO-Revision-Date: 2008-05-24 09:44+0200\n"
+"POT-Creation-Date: 2009-02-20 15:36+0100\n"
+"PO-Revision-Date: 2009-02-20 15:36+0100\n"
 "Last-Translator: Manuel P. Ayala <mayala at unex.es>\n"
 "Language-Team: i18n at lists.horde.org\n"
 "MIME-Version: 1.0\n"
@@ -17,90 +17,94 @@ msgstr ""
 "Content-Transfer-Encoding: 8bit\n"
 "Plural-Forms: nplurals=2; plural=(n != 1);\n"
 
-#: templates/view/task.inc:35
+#: templates/view/task.inc:39
 #, php-format
 msgid " (%s including sub-tasks)"
 msgstr " (%s incluyendo subtareas)"
 
-#: lib/Nag.php:71
+#: lib/Nag.php:81
 #, php-format
 msgid "%d hour"
 msgstr "%d hora"
 
-#: lib/Nag.php:73
+#: lib/Nag.php:83
 #, php-format
 msgid "%d hour, %d minute"
 msgstr "%d hora, %d minuto"
 
-#: lib/Nag.php:75
+#: lib/Nag.php:85
 #, php-format
 msgid "%d hour, %d minutes"
 msgstr "%d hora, %d minutos"
 
-#: lib/Nag.php:63
+#: lib/Nag.php:73
 #, php-format
 msgid "%d hours"
 msgstr "%d horas"
 
-#: lib/Nag.php:65
+#: lib/Nag.php:75
 #, php-format
 msgid "%d hours, %d minute"
 msgstr "%d horas, %d minuto"
 
-#: lib/Nag.php:67
+#: lib/Nag.php:77
 #, php-format
 msgid "%d hours, %d minutes"
 msgstr "%d horas, %d minutos"
 
-#: lib/Nag.php:81
+#: lib/Nag.php:91
 #, php-format
 msgid "%d minute"
 msgstr "%d minuto"
 
-#: lib/Nag.php:83
+#: lib/Nag.php:93
 #, php-format
 msgid "%d minutes"
 msgstr "%d minutos"
 
-#: lib/Nag.php:392
+#: lib/Nag.php:410
 #, php-format
 msgid "%s at %s"
 msgstr "%s a las %s"
 
-#: lib/Nag.php:618 lib/Block/tree_alarms.php:41 lib/Block/summary.php:121
+#: lib/Nag.php:670 lib/Block/tree_alarms.php:41 lib/Block/summary.php:124
 #, php-format
 msgid "%s is due in %s"
 msgstr "%s vencerá el %s"
 
-#: lib/Nag.php:616 lib/Block/tree_alarms.php:43 lib/Block/summary.php:118
+#: lib/Nag.php:668 lib/Block/tree_alarms.php:43 lib/Block/summary.php:121
 #, php-format
 msgid "%s is due now."
 msgstr "%s acaba de vencer."
 
-#: task.php:238
+#: task.php:222
 #, php-format
 msgid "%s is now incomplete."
 msgstr "%s está incompleta por el momento."
 
-#: data.php:209
+#: data.php:218
 #, php-format
 msgid "%s successfully imported"
 msgstr "%s se ha importado correctamente"
 
-#: lib/Nag.php:544 lib/Forms/DeleteTaskList.php:86
+#: lib/Nag.php:596 lib/Forms/DeleteTaskList.php:86
 #, php-format
 msgid "%s's Task List"
 msgstr "Lista de tareas de %s"
 
-#: lib/Nag.php:343 lib/Forms/task.php:61
+#: lib/Nag.php:361 lib/Forms/task.php:84
 msgid "(highest)"
 msgstr "(elevada)"
 
-#: lib/Nag.php:343 lib/Forms/task.php:62
+#: lib/Nag.php:361 lib/Forms/task.php:85
 msgid "(lowest)"
 msgstr "(reducida)"
 
-#: task.php:222
+#: lib/Forms/task.php:186
+msgid "A due date must be set to enable alarms."
+msgstr "Para activar las alarmas hay que definir una fecha de vencimiento."
+
+#: task.php:206
 #, php-format
 msgid "Access denied completing task %s."
 msgstr "Se ha denegado el acceso para terminar la tarea %s."
@@ -118,12 +122,12 @@ msgstr "Se ha denegado el acceso para modificar la tarea."
 msgid "Access denied editing task: %s"
 msgstr "Se ha denegado el acceso para modificar la tarea: %s"
 
-#: task.php:170
+#: lib/Driver.php:340
 #, php-format
 msgid "Access denied moving the task to %s."
 msgstr "Se ha denegado el acceso para desplazar la tarea a %s."
 
-#: task.php:173
+#: lib/Driver.php:330
 #, php-format
 msgid "Access denied removing task from %s."
 msgstr "Se ha denegado el acceso para eliminar la tarea de %s."
@@ -138,31 +142,33 @@ msgstr "Se ha denegado el acceso para guardar la tarea en %s."
 msgid "Access denied saving task: %s"
 msgstr "Se ha denegado el acceso para guardar la tarea: %s."
 
-#: data.php:57 templates/view/task.inc:26 lib/Forms/task.php:91
+#: data.php:57 lib/Forms/task.php:115 templates/view/task.inc:30
 msgid "Alarm"
 msgstr "Alarma"
 
-#: config/.bak/prefs.php.dist:200
+#: templates/data/export.inc:34 config/.bak/prefs.php.dist:211
 msgid "All tasks"
 msgstr "Todas las tareas"
 
-#: lib/Block/summary.php:75
-msgid "Always show completed tasks?"
-msgstr "¿Mostrar siempre las tareas finalizadas?"
+#: lib/Block/summary.php:76
+msgid "Always show completed and future tasks?"
+msgstr "¿Mostrar siempre las tareas finalizadas y pendientes?"
 
-#: lib/Block/summary.php:71
+#: lib/Block/summary.php:72
 msgid "Always show overdue tasks?"
 msgstr "¿Mostrar siempre las tareas vencidas?"
 
-#: config/.bak/prefs.php.dist:117
+#: config/.bak/prefs.php.dist:128
 msgid "Ascending"
 msgstr "Ascendente"
 
-#: data.php:55
+#: data.php:55 lib/Forms/task.php:110 templates/list/task_headers.inc:60
+#: templates/view/task.inc:12 config/.bak/prefs.php.dist:71
+#: config/.bak/prefs.php.dist:100 config/.bak/prefs.php.dist:117
 msgid "Assignee"
 msgstr "Asignada"
 
-#: lib/Block/summary.php:43
+#: lib/Block/summary.php:44
 msgid "Block title"
 msgstr "Título del bloque"
 
@@ -178,17 +184,17 @@ msgstr "Agenda"
 msgid "Cancel"
 msgstr "Cancelar"
 
-#: templates/list/task_headers.inc:53
+#: templates/list/task_headers.inc:64
 msgid "Cat_egory"
 msgstr "_Categoría"
 
-#: data.php:54 templates/view/task.inc:8 lib/Forms/task.php:79
-#: lib/Forms/task.php:85 config/.bak/prefs.php.dist:89
-#: config/.bak/prefs.php.dist:104
+#: data.php:54 lib/Forms/task.php:102 lib/Forms/task.php:107
+#: templates/view/task.inc:8 config/.bak/prefs.php.dist:74
+#: config/.bak/prefs.php.dist:96 config/.bak/prefs.php.dist:113
 msgid "Category"
 msgstr "Categoría"
 
-#: tasklists/index.php:56 templates/tasklist_list.php:35
+#: tasklists/index.php:56 templates/tasklist_list.php:33
 msgid "Change Permissions"
 msgstr "Cambiar permisos"
 
@@ -196,28 +202,91 @@ msgstr "Cambiar permisos"
 msgid "Change your task sorting and display options."
 msgstr "Cambiar opciones de ordenación y visualización de tareas."
 
-#: config/.bak/prefs.php.dist:179
+#: lib/Nag.php:872
+#, php-format
+msgid "Changed alarm from %s to %s"
+msgstr "Se cambió la alarma de %s a %s"
+
+#: lib/Nag.php:851
+#, php-format
+msgid "Changed assignee from \"%s\" to \"%s\""
+msgstr "Se cambió la asignación de \"%s\" a \"%s\""
+
+#: lib/Nag.php:835
+#, php-format
+msgid "Changed category from \"%s\" to \"%s\""
+msgstr "Se cambió la categoría de \"%s\" a \"%s\""
+
+#: lib/Nag.php:887
+#, php-format
+msgid "Changed completion from %s to %s"
+msgstr "Se cambió la terminación de %s a %s"
+
+#: lib/Nag.php:892
+msgid "Changed description"
+msgstr "Se cambió la descripción"
+
+#: lib/Nag.php:860
+#, php-format
+msgid "Changed due date from %s to %s"
+msgstr "Se cambió la fecha de vencimiento de %s a %s"
+
+#: lib/Nag.php:882
+#, php-format
+msgid "Changed estimate from %s to %s"
+msgstr "Se cambió la estimación de %s a %s"
+
+#: lib/Nag.php:812
+#, php-format
+msgid "Changed name from \"%s\" to \"%s\""
+msgstr "Se cambió el nombre de \"%s\" a \"%s\""
+
+#: lib/Nag.php:827
+#, php-format
+msgid "Changed parent task from \"%s\" to \"%s\""
+msgstr "Se cambió la tarea padre de \"%s\" a \"%s\""
+
+#: lib/Nag.php:877
+#, php-format
+msgid "Changed priority from %s to %s"
+msgstr "Se cambió la prioridad de %s a %s"
+
+#: lib/Nag.php:866
+#, php-format
+msgid "Changed start date from %s to %s"
+msgstr "Se cambió la fecha de inicio de %s a %s"
+
+#: lib/Nag.php:818
+#, php-format
+msgid "Changed task list from \"%s\" to \"%s\""
+msgstr "Se ha cambiado la lista de tareas de \"%s\" a \"%s\"."
+
+#: lib/Nag.php:809
+msgid "Changes made for this task:"
+msgstr "Cambios realizados en la tarea:"
+
+#: config/.bak/prefs.php.dist:190
 msgid "Choose how you want to receive reminders for tasks with alarms:"
 msgstr "Elija cómo quiere recibir recordatorios de las tareas con alarmas:"
 
-#: config/.bak/prefs.php.dist:170
+#: config/.bak/prefs.php.dist:181
 msgid ""
 "Choose if you want to be notified of new, edited, and deleted tasks by email:"
 msgstr ""
 "Elija si desea que se le notifiquen por correo las tareas nuevas, "
 "modificadas o eliminadas:"
 
-#: config/.bak/prefs.php.dist:42
+#: config/.bak/prefs.php.dist:43
 msgid "Choose if you want to be notified of task changes and task alarms."
 msgstr ""
 "Elija si desea que se le notifiquen los cambios en las tareas y las alarmas "
 "de tareas."
 
-#: config/.bak/prefs.php.dist:35
+#: config/.bak/prefs.php.dist:36
 msgid "Choose your default task list."
 msgstr "Elija su lista de tareas por omisión."
 
-#: templates/tasklist_list.php:31 templates/tasklist_list.php:32
+#: templates/tasklist_list.php:29 templates/tasklist_list.php:30
 msgid "Click or copy this URL to display this task list"
 msgstr "Pulse esta URL o cópiela para mostrar este listado de tareas"
 
@@ -229,28 +298,28 @@ msgstr "Cerrar"
 msgid "Close Search"
 msgstr "Cerrar búsqueda"
 
-#: view.php:112
+#: view.php:113
 msgid "Complete"
 msgstr "Terminar"
 
-#: templates/list/task_summaries.inc:11 lib/Block/summary.php:191
+#: lib/Block/summary.php:192 templates/list/task_summaries.inc:11
 #, php-format
 msgid "Complete \"%s\""
 msgstr "Terminar \"%s\""
 
-#: templates/view/task.inc:42
+#: templates/view/task.inc:46
 msgid "Complete Task"
 msgstr "Terminar tarea"
 
-#: config/.bak/prefs.php.dist:202
+#: config/.bak/prefs.php.dist:213
 msgid "Complete tasks"
 msgstr "Terminar tareas"
 
-#: lib/Nag.php:407 lib/Block/summary.php:189
+#: lib/Nag.php:425 lib/Block/summary.php:190
 msgid "Completed"
 msgstr "Terminado"
 
-#: task.php:236
+#: task.php:220
 #, php-format
 msgid "Completed %s."
 msgstr "Se ha terminado %s."
@@ -263,9 +332,13 @@ msgstr "Tareas terminadas"
 msgid "Completed parent task, mark it as incomplete first"
 msgstr "La tarea padre está terminada, márquela como incompleta primero"
 
-#: templates/list/task_headers.inc:31 templates/view/task.inc:38
-#: lib/Forms/task.php:97 config/.bak/prefs.php.dist:91
-#: config/.bak/prefs.php.dist:106
+#: templates/data/export.inc:37
+msgid "Completed tasks"
+msgstr "Tareas terminadas"
+
+#: lib/Forms/task.php:121 templates/list/task_headers.inc:31
+#: templates/view/task.inc:42 config/.bak/prefs.php.dist:98
+#: config/.bak/prefs.php.dist:115
 msgid "Completed?"
 msgstr "¿Terminada?"
 
@@ -277,7 +350,7 @@ msgstr "Fecha de terminaci
 msgid "Completion Status"
 msgstr "Estado de terminación"
 
-#: lib/api.php:443 lib/api.php:704
+#: lib/api.php:509 lib/api.php:753
 #, php-format
 msgid "Connection failed: %s"
 msgstr "Ha fallado la conexión: %s"
@@ -290,36 +363,40 @@ msgstr "Crear"
 msgid "Create Task List"
 msgstr "Crear lista de tareas"
 
-#: templates/tasklist_list.php:8
+#: templates/tasklist_list.php:9
 msgid "Create a new Task List"
 msgstr "Crear una Lista de tareas"
 
-#: templates/view/task.inc:57
+#: templates/view/task.inc:61
 msgid "Created"
 msgstr "Creado"
 
+#: lib/Recurrence.php:199
+msgid "Daily"
+msgstr "Diaria"
+
 #: lib/UI/VarRenderer/nag.php:51 lib/UI/VarRenderer/nag.php:100
 msgid "Day"
 msgstr "Día"
 
-#: lib/Nag.php:439 lib/UI/VarRenderer/nag.php:136
+#: lib/Nag.php:457 lib/UI/VarRenderer/nag.php:136
 msgid "Day(s)"
 msgstr "Día(s)"
 
-#: config/.bak/prefs.php.dist:34
+#: config/.bak/prefs.php.dist:35
 msgid "Default Task List"
 msgstr "Lista de tareas por omisión"
 
-#: config/.bak/prefs.php.dist:28
+#: config/.bak/prefs.php.dist:29
 msgid "Defaults for new tasks"
 msgstr "Opciones por omisión para nuevas tareas"
 
-#: lib/Forms/task.php:90
+#: lib/Forms/task.php:114
 msgid "Delay Start Until"
 msgstr "Retrasar inicio hasta"
 
-#: view.php:119 tasklists/index.php:57 templates/tasklist_list.php:37
-#: lib/Forms/DeleteTaskList.php:45
+#: view.php:120 lib/Forms/DeleteTaskList.php:45 tasklists/index.php:57
+#: templates/tasklist_list.php:35
 msgid "Delete"
 msgstr "Eliminar"
 
@@ -328,15 +405,15 @@ msgstr "Eliminar"
 msgid "Delete %s"
 msgstr "Eliminar %s"
 
-#: config/.bak/prefs.php.dist:20
+#: config/.bak/prefs.php.dist:21
 msgid "Delete Confirmation"
 msgstr "Confirmación de eliminación"
 
-#: config/.bak/prefs.php.dist:21
+#: config/.bak/prefs.php.dist:22
 msgid "Delete button behaviour"
 msgstr "Comportamiento del botón eliminar"
 
-#: task.php:112 lib/Forms/task.php:102 lib/Forms/task.php:129
+#: task.php:112 lib/Forms/task.php:127 lib/Forms/task.php:154
 msgid "Delete this task"
 msgstr "Eliminar esta tarea"
 
@@ -345,16 +422,15 @@ msgstr "Eliminar esta tarea"
 msgid "Deleted %s."
 msgstr "Se ha eliminado %s."
 
-#: lib/api.php:686
+#: lib/api.php:735
 msgid "Deleting entire tasklists is not supported."
 msgstr "La eliminación de listas de tareas completas no está soportada."
 
-#: config/.bak/prefs.php.dist:118
+#: config/.bak/prefs.php.dist:129
 msgid "Descending"
 msgstr "Descendente"
 
-#: data.php:53 lib/Forms/CreateTaskList.php:37 lib/Forms/EditTaskList.php:44
-#: lib/Forms/task.php:98
+#: data.php:53 lib/Forms/task.php:122
 msgid "Description"
 msgstr "Descripción"
 
@@ -362,19 +438,20 @@ msgstr "Descripci
 msgid "Display Options"
 msgstr "Opciones de Visualización"
 
-#: templates/tasklist_list.php:16
+#: templates/tasklist_list.php:18
 msgid "Display URL"
 msgstr "URL de consulta"
 
-#: config/.bak/prefs.php.dist:128
+#: config/.bak/prefs.php.dist:139
 msgid "Do you want to confirm deleting entries?"
 msgstr "¿Quiere confirmar la eliminación de entradas?"
 
-#: data.php:56 templates/view/task.inc:22 lib/Forms/task.php:89
+#: data.php:56 lib/Forms/task.php:113 templates/view/task.inc:26
 msgid "Due By"
 msgstr "Vence el"
 
-#: config/.bak/prefs.php.dist:90 config/.bak/prefs.php.dist:105
+#: config/.bak/prefs.php.dist:72 config/.bak/prefs.php.dist:97
+#: config/.bak/prefs.php.dist:114
 msgid "Due Date"
 msgstr "Fecha de vencimiento"
 
@@ -382,11 +459,11 @@ msgstr "Fecha de vencimiento"
 msgid "Due date specified."
 msgstr "Se ha indicado una fecha de vencimiento."
 
-#: view.php:115 tasklists/index.php:55 templates/tasklist_list.php:33
+#: view.php:116 tasklists/index.php:55 templates/tasklist_list.php:31
 msgid "Edit"
 msgstr "Modificar"
 
-#: templates/list/task_summaries.inc:38 lib/Block/summary.php:182
+#: lib/Block/summary.php:182 templates/list/task_summaries.inc:39
 #, php-format
 msgid "Edit \"%s\""
 msgstr "Modificar \"%s\""
@@ -396,11 +473,11 @@ msgstr "Modificar \"%s\""
 msgid "Edit %s"
 msgstr "Modificar %s"
 
-#: templates/list/task_headers.inc:42
+#: templates/list/task_headers.inc:43
 msgid "Edit Task"
 msgstr "Modificar tarea"
 
-#: templates/list/task_headers.inc:58
+#: templates/list/task_headers.inc:69
 msgid "Edit categories and colors"
 msgstr "Modificar categorías y colores"
 
@@ -414,11 +491,13 @@ msgstr "Modificar: %s"
 msgid "Error deleting task: %s"
 msgstr "Error al eliminar la tarea: %s"
 
-#: data.php:61 templates/view/task.inc:34 lib/Forms/task.php:96
+#: data.php:61 lib/Forms/task.php:120 templates/list/task_headers.inc:56
+#: templates/view/task.inc:38 config/.bak/prefs.php.dist:73
+#: config/.bak/prefs.php.dist:99 config/.bak/prefs.php.dist:116
 msgid "Estimated Time"
 msgstr "Duración estimada"
 
-#: templates/data/export.inc:17
+#: templates/data/export.inc:41
 msgid "Export"
 msgstr "Exportar"
 
@@ -426,12 +505,16 @@ msgstr "Exportar"
 msgid "Export Tasks"
 msgstr "Exportar tareas"
 
-#: config/.bak/prefs.php.dist:56
+#: config/.bak/prefs.php.dist:57
 msgid "External Data"
 msgstr "Datos externos"
 
-#: config/.bak/prefs.php.dist:12 config/.bak/prefs.php.dist:19
-#: config/.bak/prefs.php.dist:26
+#: templates/data/export.inc:36
+msgid "Future tasks"
+msgstr "Tareas futuras"
+
+#: config/.bak/prefs.php.dist:12 config/.bak/prefs.php.dist:20
+#: config/.bak/prefs.php.dist:27
 msgid "General Options"
 msgstr "Opciones generales"
 
@@ -439,7 +522,7 @@ msgstr "Opciones generales"
 msgid "Hour"
 msgstr "Hora"
 
-#: lib/Nag.php:442 lib/UI/VarRenderer/nag.php:135
+#: lib/Nag.php:460 lib/UI/VarRenderer/nag.php:135
 msgid "Hour(s)"
 msgstr "Hora(s)"
 
@@ -448,7 +531,7 @@ msgstr "Hora(s)"
 msgid "Import Tasks, Step %d"
 msgstr "Importar tareas. Paso %d"
 
-#: data.php:215
+#: data.php:224
 msgid "Import/Export Tasks"
 msgstr "Importar/Exportar tareas"
 
@@ -464,19 +547,23 @@ msgstr "Tareas pendientes"
 msgid "Incomplete sub tasks, complete them first"
 msgstr "Subtareas pendientes, complételas primero"
 
-#: config/.bak/prefs.php.dist:201
+#: templates/data/export.inc:35 config/.bak/prefs.php.dist:212
 msgid "Incomplete tasks"
 msgstr "Tareas pendientes"
 
-#: lib/api.php:520
+#: lib/api.php:437
+msgid "Invalid tasklist file requested."
+msgstr "Se ha solicitado una lista de tareas inválida."
+
+#: lib/api.php:576
 msgid "Invalid tasklist name supplied."
 msgstr "Se ha indicado un nombre de lista de tareas inválido."
 
-#: lib/api.php:386
+#: lib/api.php:453
 msgid "Invalid tasklist requested."
 msgstr "Se ha solicitado una lista de tareas inválida."
 
-#: templates/view/task.inc:64
+#: templates/view/task.inc:68
 msgid "Last Modified"
 msgstr "Última modificación"
 
@@ -489,7 +576,7 @@ msgstr "Gestionar Listas de tareas"
 msgid "Mark \"%s\" as incomplete"
 msgstr "Marcar \"%s\" como pendiente"
 
-#: templates/view/task.inc:44
+#: templates/view/task.inc:48
 msgid "Mark as incomplete"
 msgstr "Marcar como pendiente"
 
@@ -509,7 +596,7 @@ msgstr "Listado del men
 msgid "Minute"
 msgstr "Minuto"
 
-#: lib/Nag.php:445 lib/UI/VarRenderer/nag.php:135
+#: lib/Nag.php:463 lib/UI/VarRenderer/nag.php:135
 msgid "Minute(s)"
 msgstr "Minuto(s)"
 
@@ -517,11 +604,15 @@ msgstr "Minuto(s)"
 msgid "Month"
 msgstr "Mes"
 
+#: lib/Recurrence.php:202
+msgid "Monthly"
+msgstr "Mensual"
+
 #: templates/list/header.inc:9
 msgid "More Options..."
 msgstr "Más opciones..."
 
-#: lib/api.php:1179
+#: lib/api.php:1213
 msgid "Multiple iCalendar components found; only one vTodo is supported."
 msgstr ""
 "Se han encontrado varios componentes iCalendar; sólo se soporta un vTodo "
@@ -539,7 +630,7 @@ msgstr "Mis tareas"
 msgid "N_ame"
 msgstr "_Nombre"
 
-#: templates/list/task_headers.inc:45
+#: templates/list/task_headers.inc:46
 msgid "Na_me"
 msgstr "_Nombre"
 
@@ -548,8 +639,7 @@ msgstr "_Nombre"
 msgid "Nag/kolab: Did not find task %s"
 msgstr "Nag/kolab: No se encontró la tarea %s"
 
-#: data.php:52 lib/Forms/CreateTaskList.php:36 lib/Forms/EditTaskList.php:43
-#: lib/Forms/task.php:68
+#: data.php:52 lib/Forms/task.php:91
 msgid "Name"
 msgstr "Nombre"
 
@@ -561,7 +651,7 @@ msgstr "A
 msgid "Next"
 msgstr "Siguiente"
 
-#: config/.bak/prefs.php.dist:166
+#: config/.bak/prefs.php.dist:177
 msgid "No"
 msgstr "No"
 
@@ -573,7 +663,7 @@ msgstr "Sin retraso"
 msgid "No due date."
 msgstr "Sin fecha de vencimiento."
 
-#: lib/api.php:553 lib/api.php:902 lib/api.php:960 lib/api.php:1172
+#: lib/api.php:949 lib/api.php:1007 lib/api.php:1206
 msgid "No iCalendar data was found."
 msgstr "No se encontraron datos iCalendar."
 
@@ -581,7 +671,11 @@ msgstr "No se encontraron datos iCalendar."
 msgid "No parent task"
 msgstr "Sin tarea padre"
 
-#: lib/Nag.php:633
+#: lib/Recurrence.php:198
+msgid "No recurrence"
+msgstr "Sin repetición"
+
+#: lib/Nag.php:685
 msgid "No task lists are available to guests."
 msgstr "No se dispone de listas de tareas para los invitados."
 
@@ -589,43 +683,39 @@ msgstr "No se dispone de listas de tareas para los invitados."
 msgid "No tasks match"
 msgstr "No hay tareas coincidentes"
 
-#: lib/Block/summary.php:245
+#: lib/Block/summary.php:250
 msgid "No tasks to display"
 msgstr "Sin tareas visibles"
 
-#: lib/Nag.php:449 lib/UI/VarRenderer/nag.php:151
+#: lib/Nag.php:467 lib/UI/VarRenderer/nag.php:151 lib/Forms/task.php:111
 msgid "None"
 msgstr "Ninguna"
 
-#: lib/Nag.php:408
+#: lib/Nag.php:426
 msgid "Not Completed"
 msgstr "No está terminado"
 
-#: templates/view/task.inc:14
+#: templates/view/task.inc:18
 msgid "Not Private"
 msgstr "Pública"
 
-#: lib/api.php:760
+#: lib/api.php:809
 msgid "Not configured"
 msgstr "Sin configurar"
 
-#: lib/Driver/sql.php:100 lib/Driver/sql.php:136
-msgid "Not found"
-msgstr "No encontrada"
-
-#: config/.bak/prefs.php.dist:41
+#: config/.bak/prefs.php.dist:42
 msgid "Notifications"
 msgstr "Notificaciones"
 
-#: config/.bak/prefs.php.dist:168
+#: config/.bak/prefs.php.dist:179
 msgid "On all shown task lists"
 msgstr "En todas las listas de tareas mostradas"
 
-#: config/.bak/prefs.php.dist:169
+#: config/.bak/prefs.php.dist:180
 msgid "On all task lists I have read access to"
 msgstr "En todas las listas de tareas a las que tengo acceso de lectura"
 
-#: config/.bak/prefs.php.dist:167
+#: config/.bak/prefs.php.dist:178
 msgid "On my task lists only"
 msgstr "Sólo en mis listas de tareas"
 
@@ -633,34 +723,35 @@ msgstr "S
 msgid "P_ri"
 msgstr "_Prioridad"
 
-#: lib/Forms/task.php:75
+#: lib/Forms/task.php:98
 msgid "Parent task"
 msgstr "Tarea padre"
 
-#: lib/api.php:769 lib/api.php:807 lib/api.php:840 lib/api.php:876
-#: lib/api.php:998 lib/api.php:1053 lib/api.php:1117 lib/api.php:1154
-#: lib/api.php:1267 lib/api.php:1314
+#: lib/api.php:818 lib/api.php:856 lib/api.php:889 lib/api.php:924
+#: lib/api.php:1043 lib/api.php:1093 lib/api.php:1155 lib/api.php:1190
+#: lib/api.php:1301 lib/api.php:1348
 msgid "Permission Denied"
 msgstr "Permiso denegado"
 
-#: lib/api.php:210 lib/Forms/DeleteTaskList.php:56
+#: lib/api.php:261 lib/Forms/DeleteTaskList.php:56
 msgid "Permission denied"
 msgstr "Permiso denegado"
 
-#: data.php:59 templates/view/task.inc:30 lib/Forms/task.php:93
-#: config/.bak/prefs.php.dist:87 config/.bak/prefs.php.dist:102
+#: data.php:59 lib/Forms/task.php:117 templates/view/task.inc:34
+#: config/.bak/prefs.php.dist:70 config/.bak/prefs.php.dist:94
+#: config/.bak/prefs.php.dist:111
 msgid "Priority"
 msgstr "Prioridad"
 
-#: templates/view/task.inc:14 lib/Driver.php:907
+#: lib/Driver.php:976 templates/view/task.inc:18
 msgid "Private"
 msgstr "Privada"
 
-#: data.php:60 lib/Driver.php:905
+#: data.php:60 lib/Driver.php:974
 msgid "Private Task"
 msgstr "Tarea privada"
 
-#: templates/view/task.inc:12 lib/Forms/task.php:88
+#: lib/Forms/task.php:112 templates/view/task.inc:16
 msgid "Private?"
 msgstr "¿Privada?"
 
@@ -673,22 +764,22 @@ msgstr ""
 "¿Eliminar realmente la lista de tareas \"%s\"? Ésto no se puede deshacer y "
 "todos los datos de esta lista de tareas se eliminarán definitivamente."
 
-#: view.php:119
+#: view.php:120
 msgid "Really delete this task?"
 msgstr "¿Eliminar realmente esta tarea?"
 
-#: templates/panel.inc:90 lib/Forms/EditTaskList.php:46 lib/Forms/task.php:100
-#: lib/Forms/task.php:127
+#: lib/Forms/EditTaskList.php:46 lib/Forms/task.php:125 lib/Forms/task.php:152
+#: templates/panel.inc:90
 msgid "Save"
 msgstr "Guardar"
 
-#: task.php:201
+#: task.php:185
 #, php-format
 msgid "Saved %s."
 msgstr "Se ha guardado %s."
 
-#: search.php:14 templates/search/search.inc:31 templates/list/header.inc:4
-#: lib/Block/tree_menu.php:46
+#: search.php:14 lib/Block/tree_menu.php:46 templates/search/search.inc:31
+#: templates/list/header.inc:4
 msgid "Search"
 msgstr "Buscar"
 
@@ -708,7 +799,7 @@ msgstr "Listas de tareas en las que buscar:"
 msgid "Search:"
 msgstr "Buscar:"
 
-#: list.php:73
+#: list.php:73 tasks/index.php:46
 #, php-format
 msgid "Search: Results for \"%s\""
 msgstr "Búsqueda: Resultados para \"%s\""
@@ -717,6 +808,10 @@ msgstr "B
 msgid "Select a date"
 msgstr "Seleccione una fecha"
 
+#: config/.bak/prefs.php.dist:75
+msgid "Select the columns that should be shown in the list view:"
+msgstr "Seleccione las columnas que deberían mostrarse en la vista de listado:"
+
 #: templates/data/export.inc:11
 msgid "Select the export format:"
 msgstr "Seleccione el formato de exportación:"
@@ -729,68 +824,74 @@ msgstr "Seleccione el archivo a importar:"
 msgid "Select the format of the source file:"
 msgstr "Seleccione el formato del archivo origen:"
 
+#: templates/data/export.inc:20
+msgid "Select the task list(s) to export from:"
+msgstr "Seleccione la(s) lista(s) de tareas desde la que exportar:"
+
+#: templates/data/export.inc:32
+msgid "Select the task states to export:"
+msgstr "Seleccione los estados de tareas a exportar:"
+
 #: templates/panel.inc:81
 msgid "Shared Task Lists:"
 msgstr "Listas de tareas compartidas:"
 
-#: config/.bak/prefs.php.dist:68
-msgid "Should the Task List be shown in its own column in the List view?"
-msgstr ""
-"¿Debería mostrarse la lista de tareas en su propia columna en la vista de "
-"listado?"
-
-#: lib/Block/summary.php:51
+#: lib/Block/summary.php:52
 msgid "Show action buttons?"
 msgstr "¿Mostrar botones de acción?"
 
-#: config/.bak/prefs.php.dist:203
+#: config/.bak/prefs.php.dist:214
 msgid "Show complete, incomplete, or all tasks in the task list?"
 msgstr ""
 "En la lista de tareas ¿mostrar las finalizadas, las pendientes o todas?"
 
-#: config/.bak/prefs.php.dist:190
+#: config/.bak/prefs.php.dist:201
 msgid "Show data from any of these other applications in your task list?"
 msgstr ""
 "¿Mostrar datos de cualquiera de estas otras aplicaciones en la lista de "
 "tareas?"
 
-#: config/.bak/prefs.php.dist:57
+#: config/.bak/prefs.php.dist:58
 msgid "Show data from other applications or sources."
 msgstr "Mostrar datos de otras aplicaciones u orígenes."
 
-#: lib/Block/summary.php:55
+#: lib/Block/summary.php:56
 msgid "Show due dates?"
 msgstr "¿Mostar fechas de vencimiento?"
 
-#: lib/Block/summary.php:47
+#: lib/Block/summary.php:48
 msgid "Show priorities?"
 msgstr "¿Mostrar prioridades"
 
-#: lib/Block/summary.php:63
+#: lib/Block/summary.php:64
 msgid "Show task alarms?"
 msgstr "¿Mostrar las alarmas de las tareas?"
 
-#: lib/Block/summary.php:67
+#: lib/Block/summary.php:68
 msgid "Show task category?"
 msgstr "¿Mostrar la categoría de las tareas?"
 
-#: config/.bak/prefs.php.dist:78
+#: config/.bak/prefs.php.dist:85
 msgid "Show task list options panel?"
 msgstr "¿Mostrar panel de opciones de lista de tareas?"
 
-#: lib/Block/summary.php:59
+#: lib/Block/summary.php:60
 msgid "Show tasklist name?"
 msgstr "¿Mostrar el nombre de la lista de tarea?"
 
-#: lib/Block/summary.php:84
+#: lib/Block/summary.php:85
 msgid "Show tasks from these categories"
 msgstr "¿Mostrar las tareas de estas categorías?"
 
-#: lib/Block/summary.php:79
+#: lib/Block/summary.php:80
 msgid "Show tasks from these tasklists"
 msgstr "Mostrar tareas de estas listas"
 
-#: templates/list/task_headers.inc:53
+#: templates/list/task_headers.inc:60
+msgid "Sort by Assignee"
+msgstr "Ordenar por asignación"
+
+#: templates/list/task_headers.inc:64
 msgid "Sort by Category"
 msgstr "Ordenar por categoría"
 
@@ -798,11 +899,11 @@ msgstr "Ordenar por categor
 msgid "Sort by Completion Status"
 msgstr "Ordenar por estado de terminación"
 
-#: templates/list/task_headers.inc:50
+#: templates/list/task_headers.inc:52
 msgid "Sort by Due Date"
 msgstr "Ordenar por fecha de vencimiento"
 
-#: templates/list/task_headers.inc:45
+#: templates/list/task_headers.inc:46
 msgid "Sort by Name"
 msgstr "Ordenar por nombre"
 
@@ -814,11 +915,15 @@ msgstr "Ordenar por prioridad"
 msgid "Sort by User Name"
 msgstr "Ordenar por nombre de usuario"
 
-#: config/.bak/prefs.php.dist:119
+#: templates/list/task_headers.inc:56
+msgid "Sort by estimated time"
+msgstr "Ordenar por duración estimada"
+
+#: config/.bak/prefs.php.dist:130
 msgid "Sort direction:"
 msgstr "Sentido de clasificación:"
 
-#: config/.bak/prefs.php.dist:93
+#: config/.bak/prefs.php.dist:102
 msgid "Sort tasks by:"
 msgstr "Ordenar tareas por:"
 
@@ -826,7 +931,7 @@ msgstr "Ordenar tareas por:"
 msgid "Start"
 msgstr "Inicio"
 
-#: templates/view/task.inc:18
+#: templates/view/task.inc:22
 msgid "Start Date"
 msgstr "Fecha de inicio"
 
@@ -834,37 +939,50 @@ msgstr "Fecha de inicio"
 msgid "Start date specified."
 msgstr "Se ha indicado una fecha de inicio"
 
-#: templates/tasklist_list.php:17
+#: templates/tasklist_list.php:19
 msgid "Subscription URL"
 msgstr "URL de suscripción"
 
-#: templates/list/task_summaries.inc:60
+#: templates/list/task_summaries.inc:61
 msgid "Task Alarm"
 msgstr "Alarma de tarea"
 
-#: templates/list/task_headers.inc:48
+#: templates/list/task_headers.inc:49
 msgid "Task Alarm?"
 msgstr "¿Alarma?"
 
-#: config/.bak/prefs.php.dist:27
+#: config/.bak/prefs.php.dist:28
 msgid "Task Defaults"
 msgstr "Opciones por omisión de la tarea"
 
-#: templates/tasklist_list.php:15 lib/Forms/task.php:71
-#: config/.bak/prefs.php.dist:92 config/.bak/prefs.php.dist:107
+#: lib/Driver/sql.php:100
+msgid "Task ID not found"
+msgstr "No se encontró el ID de tarea"
+
+#: lib/Forms/task.php:94 templates/tasklist_list.php:17
+#: config/.bak/prefs.php.dist:69 config/.bak/prefs.php.dist:101
+#: config/.bak/prefs.php.dist:118
 msgid "Task List"
 msgstr "Lista de tareas"
 
+#: lib/Forms/EditTaskList.php:44 lib/Forms/CreateTaskList.php:37
+msgid "Task List Description"
+msgstr "Descripción de la lista de tareas"
+
 #: templates/panel.inc:5
 msgid "Task List Information"
 msgstr "Información de la lista de tareas"
 
-#: templates/tasklist_list.php:12
+#: templates/tasklist_list.php:14
 msgid "Task List List"
 msgstr "Listado de listas de tareas"
 
-#: config/.bak/prefs.php.dist:33 config/.bak/prefs.php.dist:40
-#: config/.bak/prefs.php.dist:55
+#: lib/Forms/EditTaskList.php:43 lib/Forms/CreateTaskList.php:36
+msgid "Task List Name"
+msgstr "Nombre de la lista de tareas"
+
+#: config/.bak/prefs.php.dist:34 config/.bak/prefs.php.dist:41
+#: config/.bak/prefs.php.dist:56
 msgid "Task List and Share Options"
 msgstr "Opciones de listado y compartición de tareas"
 
@@ -877,15 +995,15 @@ msgstr "Lista de tareas de %s."
 msgid "Task Lists"
 msgstr "Listas de tareas"
 
-#: config/.bak/prefs.php.dist:88 config/.bak/prefs.php.dist:103
+#: config/.bak/prefs.php.dist:95 config/.bak/prefs.php.dist:112
 msgid "Task Name"
 msgstr "Nombre de tarea"
 
-#: templates/list/task_summaries.inc:58
+#: templates/list/task_summaries.inc:59
 msgid "Task Note"
 msgstr "Comentario de la tarea"
 
-#: templates/list/task_headers.inc:47
+#: templates/list/task_headers.inc:48
 msgid "Task Note?"
 msgstr "¿Comentario?"
 
@@ -893,31 +1011,39 @@ msgstr "
 msgid "Task Search"
 msgstr "Búsqueda de tareas"
 
-#: lib/Nag.php:658
+#: lib/Driver/sql.php:136
+msgid "Task UID not found"
+msgstr "No se encontró el UID de tarea"
+
+#: lib/Nag.php:793
 msgid "Task added:"
 msgstr "Tarea añadida:"
 
-#: lib/Nag.php:668
+#: lib/Nag.php:897
 msgid "Task deleted:"
 msgstr "Tarea eliminada:"
 
-#: lib/Nag.php:663
+#: lib/Nag.php:915
+msgid "Task description:"
+msgstr "Descripción de la tarea:"
+
+#: lib/Nag.php:802
 msgid "Task modified:"
 msgstr "Tarea modificada:"
 
-#: view.php:44 task.php:95
+#: task.php:95 view.php:42
 msgid "Task not found."
 msgstr "No se encontró la tarea."
 
-#: lib/api.php:698
+#: lib/api.php:747
 msgid "Tasklist does not exist or no permission to delete"
 msgstr "La lista de tareas no existe o carece de permisos para eliminar"
 
-#: lib/api.php:526
+#: lib/api.php:582
 msgid "Tasklist does not exist or no permission to edit"
 msgstr "La lista de tareas no existe o carece de permisos para modificar"
 
-#: lib/api.php:1236
+#: lib/api.php:1270
 msgid "Tasks"
 msgstr "Tareas"
 
@@ -925,12 +1051,12 @@ msgstr "Tareas"
 msgid "Tasks Summary"
 msgstr "Resumen de tareas"
 
-#: lib/api.php:348
+#: lib/api.php:399
 #, php-format
 msgid "Tasks from %s"
 msgstr "Tareas de %s"
 
-#: data.php:203
+#: data.php:212
 #, php-format
 msgid "The %s file didn't contain any tasks."
 msgstr "El archivo %s no contenía ninguna tarea."
@@ -944,7 +1070,7 @@ msgstr "El motor de tareas no est
 msgid "The Tasks backend is not currently available: %s"
 msgstr "El motor de tareas no está disponible en este momento: %s"
 
-#: lib/Forms/task.php:160
+#: lib/Forms/task.php:190
 msgid "The alarm value must not be empty."
 msgstr "El valor de la alarma no puede estar en blanco."
 
@@ -952,30 +1078,23 @@ msgstr "El valor de la alarma no puede estar en blanco."
 msgid "The current hour"
 msgstr "La hora actual"
 
-#: lib/Nag.php:659
+#: lib/Nag.php:796
 #, php-format
 msgid ""
-"The task \"%s\" has been added to \"%s\" tasklist, with a due date of: %s."
+"The task \"%s\" has been added to task list \"%s\", with a due date of: %s."
 msgstr ""
 "Se ha añadido la tarea \"%s\" a la lista de tareas \"%s\", con una fecha de "
 "vencimiento de: %s."
 
-#: lib/Nag.php:669
+#: lib/Nag.php:901
 #, php-format
-msgid ""
-"The task \"%s\" has been deleted from \"%s\" tasklist, with a due date of: %"
-"s."
-msgstr ""
-"Se ha eliminado la tarea \"%s\" de la lista de tareas \"%s\", con una fecha "
-"de vencimiento de: %s."
+msgid "The task \"%s\" has been deleted from task list \"%s\"."
+msgstr "Se ha eliminado la tarea \"%s\" de la lista de tareas \"%s\"."
 
-#: lib/Nag.php:664
+#: lib/Nag.php:805
 #, php-format
-msgid ""
-"The task \"%s\" has been edited on \"%s\" tasklist, with a due date of: %s."
-msgstr ""
-"Se ha modificado la tarea \"%s\" de la lista de tareas \"%s\", con una fecha "
-"de vencimiento de: %s."
+msgid "The task \"%s\" has been edited on task list \"%s\"."
+msgstr "Se ha modificado la tarea \"%s\" de la lista de tareas \"%s\"."
 
 #: tasklists/create.php:31
 #, php-format
@@ -997,7 +1116,7 @@ msgstr "La lista de tareas \"%s\" se ha renombrado como \"%s\"."
 msgid "The task list \"%s\" has been saved."
 msgstr "Se ha guardado la lista de tareas \"%s\"."
 
-#: config/.bak/prefs.php.dist:108
+#: config/.bak/prefs.php.dist:119
 msgid "Then:"
 msgstr "Además por:"
 
@@ -1005,7 +1124,7 @@ msgstr "Adem
 msgid "There are no tasks matching the current criteria."
 msgstr "No hay tareas coincidentes con los criterios actuales."
 
-#: task.php:232
+#: task.php:216
 #, php-format
 msgid "There was a problem completing %s: %s"
 msgstr "Se produjo un problema al completar %s: %s"
@@ -1015,25 +1134,32 @@ msgstr "Se produjo un problema al completar %s: %s"
 msgid "There was a problem deleting %s: %s"
 msgstr "Se produjo un problema al eliminar %s: %s"
 
-#: task.php:199
+#: task.php:183
 #, php-format
 msgid "There was a problem saving the task: %s."
 msgstr "Se produjo un problema al guardar la tarea: %s."
 
-#: data.php:206
+#: data.php:215
 #, php-format
 msgid "There was an error importing the data: %s"
 msgstr "Se produjo un error al importar los datos: %s"
 
-#: lib/api.php:545 lib/api.php:894 lib/api.php:1166
+#: lib/api.php:599 lib/api.php:941 lib/api.php:1200
 msgid "There was an error importing the iCalendar data."
 msgstr "Se produjo un error al importar los datos iCalendar."
 
-#: data.php:89
+#: lib/api.php:211
+#, php-format
+msgid "There was an error removing tasks for %s. Details have been logged."
+msgstr ""
+"Se produjo un error eliminando las tareas de %s. Se han registrado los "
+"detalles."
+
+#: data.php:94
 msgid "There were no tasks to export."
 msgstr "No hubo tareas a exportar."
 
-#: data.php:135
+#: data.php:143
 msgid "This file format is not supported."
 msgstr "Este formato de archivo no está soportado."
 
@@ -1047,12 +1173,20 @@ msgstr ""
 "Para suscribirse a esta lista de tareas desde otro programa, utilice esta "
 "URL: "
 
+#: lib/Nag.php:856
+msgid "Turned privacy off"
+msgstr "Se desactivó la privacidad"
+
+#: lib/Nag.php:856
+msgid "Turned privacy on"
+msgstr "Se activó la privacidad"
+
 #: lib/Forms/DeleteTaskList.php:63
 #, php-format
 msgid "Unable to delete \"%s\": %s"
 msgstr "Incapaz de eliminar \"%s\": %s"
 
-#: lib/api.php:719
+#: lib/api.php:768
 #, php-format
 msgid "Unable to delete tasklist \"%s\": %s"
 msgstr "Incapaz de eliminar la lista de tareas \"%s\": %s"
@@ -1067,9 +1201,9 @@ msgstr "Incapaz de cargar la definici
 msgid "Unable to save task list \"%s\": %s"
 msgstr "Incapaz de guardar la lista de tareas \"%s\": %s"
 
-#: templates/list/task_summaries.inc:65 templates/view/task.inc:9
-#: lib/Nag.php:900 lib/Nag.php:901 lib/Nag.php:915 lib/Nag.php:916
-#: lib/Forms/task.php:84 lib/Block/summary.php:34 lib/Block/summary.php:238
+#: lib/Nag.php:1149 lib/Nag.php:1150 lib/Nag.php:1164 lib/Nag.php:1165
+#: lib/Forms/task.php:107 lib/Block/summary.php:35 lib/Block/summary.php:243
+#: templates/list/task_summaries.inc:76 templates/view/task.inc:9
 msgid "Unfiled"
 msgstr "Sin categoría"
 
@@ -1077,13 +1211,13 @@ msgstr "Sin categor
 msgid "Unique ID"
 msgstr "ID único"
 
-#: lib/api.php:652 lib/api.php:967 lib/api.php:1025 lib/api.php:1079
-#: lib/api.php:1204
+#: lib/api.php:701 lib/api.php:1014 lib/api.php:1068 lib/api.php:1117
+#: lib/api.php:1238
 #, php-format
 msgid "Unsupported Content-Type: %s"
 msgstr "Tipo de contenido no soportado: %s"
 
-#: lib/Driver.php:1084
+#: lib/Driver.php:1155
 #, php-format
 msgid ""
 "We would like to remind you of this due task.\n"
@@ -1104,15 +1238,19 @@ msgstr ""
 "\n"
 "%s"
 
-#: lib/Nag.php:436 lib/UI/VarRenderer/nag.php:136
+#: lib/Nag.php:454 lib/UI/VarRenderer/nag.php:136
 msgid "Week(s)"
 msgstr "Semana(s)"
 
+#: lib/Recurrence.php:200
+msgid "Weekly"
+msgstr "Semanal"
+
 #: templates/prefs/defaultduetimeselect.inc:6
 msgid "What do you want to be the default due time for tasks?"
 msgstr "¿Cuál quiere que sea la hora de vencimiento por omisión de las tareas?"
 
-#: config/.bak/prefs.php.dist:146
+#: config/.bak/prefs.php.dist:157
 msgid ""
 "When creating a new task, how many days in the future should the default due "
 "date be (0 means today)?"
@@ -1120,7 +1258,7 @@ msgstr ""
 "Al crear una tarea, ¿a cuántos días en el futuro debería estar la fecha de "
 "vencimiento por omisión (0 significa hoy)?"
 
-#: config/.bak/prefs.php.dist:137
+#: config/.bak/prefs.php.dist:148
 msgid "When creating a new task, should it default to having a due date?"
 msgstr ""
 "Al crear una tarea, ¿Debería disponer por omisión de una fecha de "
@@ -1134,11 +1272,15 @@ msgstr "
 msgid "Year"
 msgstr "Año"
 
+#: lib/Recurrence.php:205
+msgid "Yearly"
+msgstr "Anual"
+
 #: tasklists/edit.php:28
 msgid "You are not allowed to change this task list."
 msgstr "Carece de permiso para cambiar esta lista de tareas."
 
-#: data.php:41 data.php:160 task.php:68
+#: task.php:68 data.php:41 data.php:168
 #, php-format
 msgid "You are not allowed to create more than %d tasks."
 msgstr "Carece de permiso para crear más de %d tareas."
@@ -1147,22 +1289,26 @@ msgstr "Carece de permiso para crear m
 msgid "You are not allowed to delete this task list."
 msgstr "Carece de permiso para ver eliminar esta lista de tareas."
 
-#: view.php:52
+#: lib/api.php:143
+msgid "You are not allowed to remove user data."
+msgstr "Carece de permiso para eliminar datos de usuario."
+
+#: view.php:53
 msgid "You do not have permission to view this tasklist."
 msgstr "No dispone de privilegios para ver esta lista de tareas."
 
-#: lib/Nag.php:659
-msgid "You requested to be notified when tasks are added to your tasklists."
+#: lib/Nag.php:794
+msgid "You requested to be notified when tasks are added to your task lists."
 msgstr "Solicitó la notificación de adición de tareas a sus listas de tareas."
 
-#: lib/Nag.php:669
+#: lib/Nag.php:899
 msgid ""
-"You requested to be notified when tasks are deleted from your tasklists."
+"You requested to be notified when tasks are deleted from your task lists."
 msgstr ""
 "Solicitó la notificación de eliminación de tareas de sus listas de tareas."
 
-#: lib/Nag.php:664
-msgid "You requested to be notified when tasks are edited on your tasklists."
+#: lib/Nag.php:803
+msgid "You requested to be notified when tasks are edited on your task lists."
 msgstr ""
 "Solicitó la notificación de modificación de tareas de sus listas de tareas."
 
@@ -1174,8 +1320,8 @@ msgstr "Su lista de tareas por omisi
 msgid "[Manage Task Lists]"
 msgstr "[Gestionar Listas de tareas]"
 
-#: templates/list/task_summaries.inc:48 lib/Block/summary.php:115
-#: lib/Block/summary.php:222
+#: lib/Block/summary.php:118 lib/Block/summary.php:226
+#: templates/list/task_summaries.inc:49
 msgid "[none]"
 msgstr "[ninguno]"
 
@@ -1191,7 +1337,7 @@ msgstr "_Todas"
 msgid "_Category"
 msgstr "_Categoría"
 
-#: view.php:112
+#: view.php:113
 msgid "_Complete"
 msgstr "_Terminada"
 
@@ -1199,7 +1345,7 @@ msgstr "_Terminada"
 msgid "_Completed tasks"
 msgstr "Tareas te_rminadas"
 
-#: view.php:119
+#: view.php:120
 msgid "_Delete"
 msgstr "_Eliminar"
 
@@ -1207,11 +1353,11 @@ msgstr "_Eliminar"
 msgid "_Description"
 msgstr "_Descripción"
 
-#: templates/list/task_headers.inc:50
+#: templates/list/task_headers.inc:52
 msgid "_Due Date"
 msgstr "Fecha de _vencimiento"
 
-#: view.php:115
+#: view.php:116
 msgid "_Edit"
 msgstr "Mo_dificar"
 
@@ -1219,23 +1365,23 @@ msgstr "Mo_dificar"
 msgid "_Future tasks"
 msgstr "Tareas _futuras"
 
-#: lib/Nag.php:581
+#: lib/Nag.php:633
 msgid "_Import/Export"
 msgstr "_Importar/Exportar"
 
-#: lib/Nag.php:568
+#: lib/Nag.php:620
 msgid "_List Tasks"
 msgstr "_Listar"
 
-#: lib/Nag.php:573
+#: lib/Nag.php:625
 msgid "_New Task"
 msgstr "_Añadir"
 
-#: lib/Nag.php:586
+#: lib/Nag.php:638
 msgid "_Print"
 msgstr "Im_primir"
 
-#: lib/Nag.php:577
+#: lib/Nag.php:629
 msgid "_Search"
 msgstr "_Buscar"
 
@@ -1247,15 +1393,19 @@ msgstr "Lista de tar_eas"
 msgid "am"
 msgstr "am"
 
-#: view.php:73 view.php:82
+#: view.php:74 view.php:83
 #, php-format
 msgid "by %s"
 msgstr "por %s"
 
-#: view.php:75 view.php:84
+#: view.php:76 view.php:85
 msgid "by me"
 msgstr "por mi"
 
+#: lib/Nag.php:888 lib/Nag.php:889
+msgid "completed"
+msgstr "terminada"
+
 #: data.php:31
 msgid "iCalendar (vTodo)"
 msgstr "iCalendario (vTodo)"
@@ -1265,18 +1415,34 @@ msgstr "iCalendario (vTodo)"
 msgid "in %s"
 msgstr "a %s"
 
-#: lib/Nag.php:79
+#: lib/Nag.php:861 lib/Nag.php:862 lib/Nag.php:913
+msgid "no due date"
+msgstr "sin fecha de vencimiento"
+
+#: lib/Nag.php:828 lib/Nag.php:829
+msgid "no parent"
+msgstr "sin padre"
+
+#: lib/Nag.php:867 lib/Nag.php:868
+msgid "no start date"
+msgstr "sin fecha de inicio"
+
+#: lib/Nag.php:89
 msgid "no time"
 msgstr "sin límite"
 
+#: lib/Nag.php:888 lib/Nag.php:889
+msgid "not completed"
+msgstr "sin terminar"
+
 #: templates/prefs/defaultduetimeselect.inc:15
 msgid "pm"
 msgstr "pm"
 
-#: data.php:109 templates/data/export.inc:1
+#: data.php:114 templates/data/export.inc:1
 msgid "tasks.csv"
 msgstr "tareas.csv"
 
-#: data.php:120
+#: data.php:128
 msgid "tasks.ics"
 msgstr "tareas.ics"
diff --git a/po/ja_JP.po b/po/et_EE.po
similarity index 66%
copy from po/ja_JP.po
copy to po/et_EE.po
index c574bd8..12e1e6f 100644
--- a/po/ja_JP.po
+++ b/po/et_EE.po
@@ -1,166 +1,161 @@
-# Japanese translation for Nag
-# Copyright (C) 2005 Horde Project
-# This file is distributed under the same license as the Nag package.
-# Hiromi Kimura <hiromi at tac.tsukuba.ac.jp>
-#
 msgid ""
 msgstr ""
-"Project-Id-Version: nag 2.2-RC1\n"
+"Project-Id-Version: Nag 2.2 RC1\n"
 "Report-Msgid-Bugs-To: dev at lists.horde.org\n"
-"POT-Creation-Date: 2007-08-03 12:47+0100\n"
-"PO-Revision-Date: 2007-11-30 20:38+0900\n"
-"Last-Translator: Hiromi Kimura <hiromi at tac.tsukuba.ac.jp>\n"
-"Language-Team: i18n at lists.horde.org\n"
+"POT-Creation-Date: 2008-05-29 15:49+0300\n"
+"PO-Revision-Date: \n"
+"Last-Translator: Alar SIng <alar.sing at err.ee>\n"
+"Language-Team: \n"
 "MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=SHIFT_JIS\n"
+"Content-Type: text/plain; charset=iso-8859-13\n"
 "Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=1; plural=0;\n"
+"X-Poedit-Language: Estonian\n"
 
 #: templates/view/task.inc:35
 #, php-format
 msgid " (%s including sub-tasks)"
-msgstr "(%s ƒTƒuƒ^ƒXƒN‚ðŠÜ‚Þ)"
+msgstr "(%s koos alamtöödega)"
 
 #: lib/Nag.php:71
 #, php-format
 msgid "%d hour"
-msgstr "%d ŽžŠÔ"
+msgstr "%d tund"
 
 #: lib/Nag.php:73
 #, php-format
 msgid "%d hour, %d minute"
-msgstr "%d ŽžŠÔ %d •ª"
+msgstr "%d tund, %d minuti"
 
 #: lib/Nag.php:75
 #, php-format
 msgid "%d hour, %d minutes"
-msgstr "%d ŽžŠÔ %d •ª"
+msgstr "%d tund, %d minutit"
 
 #: lib/Nag.php:63
 #, php-format
 msgid "%d hours"
-msgstr "%d ŽžŠÔ"
+msgstr "%d tundi"
 
 #: lib/Nag.php:65
 #, php-format
 msgid "%d hours, %d minute"
-msgstr "%d ŽžŠÔ %d •ª"
+msgstr "%d tundi, %d minut"
 
 #: lib/Nag.php:67
 #, php-format
 msgid "%d hours, %d minutes"
-msgstr "%d ŽžŠÔ %d •ª"
+msgstr "%d tundi, %d minutit"
 
 #: lib/Nag.php:81
 #, php-format
 msgid "%d minute"
-msgstr "%d •ª"
+msgstr "%d minut"
 
 #: lib/Nag.php:83
 #, php-format
 msgid "%d minutes"
-msgstr "%d •ª"
+msgstr "%d minutit"
 
 #: lib/Nag.php:364
 #, php-format
 msgid "%s at %s"
-msgstr ""
+msgstr "%s ajal %s"
 
 #: lib/Nag.php:590 lib/Block/tree_alarms.php:42 lib/Block/summary.php:106
 #, php-format
 msgid "%s is due in %s"
-msgstr "%s ‚ÌŠú“ú‚Í‚ ‚Æ %s ‚Å‚·"
+msgstr "%s tähtaeg on %s"
 
 #: lib/Nag.php:588 lib/Block/tree_alarms.php:44 lib/Block/summary.php:104
 #, php-format
 msgid "%s is due now."
-msgstr "%s ‚ÌŠú“ú‚Å‚·B"
+msgstr "%s tähtaeg on nüüd"
 
 #: task.php:231
 #, php-format
 msgid "%s is now incomplete."
-msgstr "%s ‚ÍŠ®—¹‚µ‚Ä‚¢‚Ü‚¹‚ñB"
+msgstr "%s on lõpetamata."
 
 #: data.php:199
 #, php-format
 msgid "%s successfully imported"
-msgstr "%s ‚͐³í‚ɃCƒ“ƒ|[ƒg‚³‚ê‚Ü‚µ‚½"
+msgstr "%s edukalt imporditud"
 
-#: tasklists.php:104 lib/Nag.php:516
+#: tasklists.php:106 lib/Nag.php:516
 #, php-format
 msgid "%s's Task List"
-msgstr "%s ‚̃^ƒXƒN•\"
+msgstr "%s Tööde nimekiri"
 
 #: lib/Nag.php:315 lib/Forms/task.php:55
 msgid "(highest)"
-msgstr "iÅ‚j"
+msgstr "(kõrgeim)"
 
 #: lib/Nag.php:315 lib/Forms/task.php:56
 msgid "(lowest)"
-msgstr "iÅ’áj"
+msgstr "(madalaim)"
 
 #: task.php:215
 #, php-format
 msgid "Access denied completing task %s."
-msgstr "ƒ^ƒXƒN %s ‚ÌŠ®—¹‚ªƒAƒNƒZƒX‹‘”Û‚³‚ê‚Ü‚µ‚½B"
+msgstr "%s töö lõpetamiseks õigus puudub."
 
 #: task.php:24
 #, php-format
 msgid "Access denied deleting %s"
-msgstr "%s ‚̍폜‚ªƒAƒNƒZƒX‹‘”Û‚³‚ê‚Ü‚µ‚½"
+msgstr "%s kustutamiseks õigus puudub"
 
 #: task.php:84 task.php:90
 msgid "Access denied editing task."
-msgstr "ƒ^ƒXƒN %s ‚̕ҏW‚ªƒAƒNƒZƒX‹‘”Û‚³‚ê‚Ü‚µ‚½B"
+msgstr "Töö muutmise õigus puudub."
 
 #: task.php:82
 #, php-format
 msgid "Access denied editing task: %s"
-msgstr "ƒ^ƒXƒN‚̕ҏW‚ªƒAƒNƒZƒX‹‘”Û‚³‚ê‚Ü‚µ‚½F%s"
+msgstr "%s töö muutmise õigus puudub"
 
 #: task.php:163
 #, php-format
 msgid "Access denied moving the task to %s."
-msgstr "ƒ^ƒXƒN‚Ì %s ‚ւ̈ړ®‚ªƒAƒNƒZƒX‹‘”Û‚³‚ê‚Ü‚µ‚½B"
+msgstr "%s töö liigutamise õigus puudub."
 
 #: task.php:166
 #, php-format
 msgid "Access denied removing task from %s."
-msgstr "ƒ^ƒXƒN‚Ì %s ‚©‚ç‚̍폜‚ªƒAƒNƒZƒX‹‘”Û‚³‚ê‚Ü‚µ‚½B"
+msgstr "%s töö kustutamise õigus puudub."
 
 #: task.php:125
 #, php-format
 msgid "Access denied saving task to %s."
-msgstr "ƒ^ƒXƒN‚Ì %s ‚ւ̕ۑ¶‚ªƒAƒNƒZƒX‹‘”Û‚³‚ê‚Ü‚µ‚½B"
+msgstr "%s töö salvestamise õigus puudub."
 
 #: task.php:121
 #, php-format
 msgid "Access denied saving task: %s"
-msgstr "ƒ^ƒXƒN‚̕ۑ¶‚ªƒAƒNƒZƒX‹‘”Û‚³‚ê‚Ü‚µ‚½F%s"
+msgstr "%s töö salvestamise õigus puudub"
 
 #: templates/view/task.inc:26 lib/Forms/task.php:85
 msgid "Alarm"
-msgstr "ƒAƒ‰[ƒ€"
+msgstr "Teavitus"
 
 #: config/prefs.php.dist:201
 msgid "All tasks"
-msgstr "‘Sƒ^ƒXƒN"
+msgstr "Kõik tööd"
 
 #: lib/Block/summary.php:63
 msgid "Always show completed tasks?"
-msgstr "Š®—¹‚µ‚½ƒ^ƒXƒN‚ðí‚É•\ަ‚µ‚Ü‚·‚©H"
+msgstr "Alati näita lõpetatud töid?"
 
 #: lib/Block/summary.php:60
 msgid "Always show overdue tasks?"
-msgstr "ŠúŒÀ‚̉߂¬‚½ƒ^ƒXƒN‚ðí‚É•\ަ‚µ‚Ü‚·‚©H"
+msgstr "Alati näita üle tähtaja töid?"
 
 #: config/prefs.php.dist:118
 msgid "Ascending"
-msgstr "¸‡"
+msgstr "Kasvav"
 
 #: lib/Block/summary.php:39
 msgid "Block title"
-msgstr "ƒuƒƒbƒNƒ^ƒCƒgƒ‹"
+msgstr "Ploki pealkiri"
 
 #: data.php:30
 msgid "CSV"
@@ -168,821 +163,819 @@ msgstr "CSV"
 
 #: lib/UI/VarRenderer/nag.php:58 lib/UI/VarRenderer/nag.php:106
 msgid "Calendar"
-msgstr "—\’è•\"
+msgstr "Kalender"
 
 #: templates/list/task_headers.inc:53
 msgid "Cat_egory"
-msgstr "_E•ª—Þ"
+msgstr "Kat_egooria"
 
 #: data.php:54 templates/view/task.inc:8 lib/Forms/task.php:73
 #: lib/Forms/task.php:79 config/prefs.php.dist:90 config/prefs.php.dist:105
 msgid "Category"
-msgstr "•ª—Þ"
+msgstr "Kategooria"
 
 #: templates/tasklists/tasklists.inc:26
 msgid "Change"
-msgstr "•ύX"
+msgstr "Muuda"
 
 #: config/prefs.php.dist:15
 msgid "Change your task sorting and display options."
-msgstr "ƒ^ƒXƒN‚Ì•À‚я‡‚Æ•\ަƒIƒvƒVƒ‡ƒ“‚ð•ύX‚µ‚Ü‚·B"
+msgstr "Muuda tööde sorteerimise ja vaate seadeid."
 
 #: config/prefs.php.dist:180
 msgid "Choose how you want to receive reminders for tasks with alarms:"
-msgstr "ƒ^ƒXƒN‚ÌƒŠƒ}ƒCƒ“ƒ_iÃ‘£j‚ð‚ǂ̂悤‚Ɏ󂯎æ‚é‚©‘I‘ð‚µ‚Ä‚­‚¾‚³‚¢F"
+msgstr "Vali kuidas sa tahad saada meeldetuletusi töödest:"
 
 #: config/prefs.php.dist:171
 msgid ""
 "Choose if you want to be notified of new, edited, and deleted tasks by email:"
 msgstr ""
-"ƒ^ƒXƒN‚ð’ljÁA•ύXAíœ‚µ‚½Žž‚Ƀ[ƒ‹‚Å’Ê’m‚µ‚Ä—~‚µ‚¢‚È‚ç‘I‘ð‚µ‚Ä‰º‚³‚¢F"
+"Vali kui soovid teavitusi mailiga uutest, muudetud ja kustutatud töödest:"
 
 #: config/prefs.php.dist:43
 msgid "Choose if you want to be notified of task changes and task alarms."
-msgstr "ƒ^ƒXƒN‚ð•ύX‚µ‚½Žž‚É’Ê’m‚µ‚Ä—~‚µ‚¢‚È‚ç‘I‘ð‚µ‚Ä‰º‚³‚¢B"
+msgstr "Vali kui soovid teavitust muudetud töödest."
 
 #: config/prefs.php.dist:36
 msgid "Choose your default task list."
-msgstr "ƒfƒtƒHƒ‹ƒg‚̃^ƒXƒN•\‚ð‘I‘ð‚µ‚Ü‚·B"
+msgstr "Vali oma vaikimisi tööde nimekiri."
 
 #: templates/list/header.inc:8
 msgid "Close Search"
-msgstr "ŒŸõ‚ð•‚¶‚é"
+msgstr "Sulge otsing"
 
 #: view.php:99
 msgid "Complete"
-msgstr "Š®—¹"
+msgstr "Lõpeta"
 
 #: templates/list/task_summaries.inc:11 lib/Block/summary.php:168
 #, php-format
 msgid "Complete \"%s\""
-msgstr "Š®—¹ \"%s\""
+msgstr "Lõpeta \"%s\""
 
 #: templates/view/task.inc:42
 msgid "Complete Task"
-msgstr "Š®—¹ƒ^ƒXƒN"
+msgstr "Lõpeta töö"
 
 #: config/prefs.php.dist:203
 msgid "Complete tasks"
-msgstr "Š®—¹ƒ^ƒXƒN"
+msgstr "Lõpeta tööd"
 
 #: lib/Nag.php:379 lib/Block/summary.php:166
 msgid "Completed"
-msgstr "Š®—¹"
+msgstr "Lõpetatud"
 
 #: task.php:229
 #, php-format
 msgid "Completed %s."
-msgstr "%s Š®—¹B"
+msgstr "Lõpetatud %s."
 
 #: templates/search/search.inc:27
 msgid "Completed Tasks"
-msgstr "Š®—¹ƒ^ƒXƒN"
+msgstr "Lõpetatud tööd"
 
 #: templates/list/task_summaries.inc:16
 msgid "Completed parent task, mark it as incomplete first"
-msgstr ""
+msgstr "Lõpetatud ülemtöö, märgi see ennem mittelõpetatuks"
 
-#: templates/view/task.inc:38 templates/list/task_headers.inc:31
+#: templates/list/task_headers.inc:31 templates/view/task.inc:38
 #: lib/Forms/task.php:91 config/prefs.php.dist:92 config/prefs.php.dist:107
 msgid "Completed?"
-msgstr "Š®—¹H"
+msgstr "Lõpetatud?"
 
 #: data.php:58
 msgid "Completion Status"
-msgstr "Š®—¹ó‹µ"
+msgstr "Progress"
 
 #: lib/api.php:317 lib/api.php:544
 #, php-format
 msgid "Connection failed: %s"
-msgstr "Ú‘±Ž¸”sF%s"
+msgstr "Ühendus ebaõnnestus: %s"
 
 #: templates/tasklists/tasklists.inc:17 templates/tasklists/tasklists.inc:86
 msgid "Create"
-msgstr "ì¬"
+msgstr "Loo"
 
 #: templates/view/task.inc:57
 msgid "Created"
-msgstr "ì¬“úŽž"
+msgstr "Loodud"
 
 #: lib/UI/VarRenderer/nag.php:51 lib/UI/VarRenderer/nag.php:100
 msgid "Day"
-msgstr "“ú"
+msgstr "Päev"
 
 #: lib/Nag.php:411 lib/UI/VarRenderer/nag.php:136
 msgid "Day(s)"
-msgstr "“ú"
+msgstr "Päev(ad)"
 
 #: config/prefs.php.dist:35
 msgid "Default Task List"
-msgstr "ƒfƒtƒHƒ‹ƒg‚̃^ƒXƒN•\"
+msgstr "Vaike tööde nimekiri"
 
 #: config/prefs.php.dist:29
 msgid "Defaults for new tasks"
-msgstr "V‚炵‚¢ƒ^ƒXƒN‚̃fƒtƒHƒ‹ƒg"
+msgstr "Vaike väärtused uuele tööle"
 
 #: lib/Forms/task.php:84
 msgid "Delay Start Until"
-msgstr "‰„Šú"
+msgstr "Viivita algusega kuni"
 
 #: view.php:106 templates/tasklists/tasklists.inc:87
 msgid "Delete"
-msgstr "íœ"
+msgstr "Kustuta"
 
 #: config/prefs.php.dist:21
 msgid "Delete Confirmation"
-msgstr "íœ‚ÌŠm”F"
+msgstr "Kustutamise kinnitus"
 
 #: config/prefs.php.dist:22
 msgid "Delete button behaviour"
-msgstr "íœƒ{ƒ^ƒ“‚̈µ‚¢"
+msgstr "Kustuta nupu käitumine"
 
 #: task.php:105 lib/Forms/task.php:96
 msgid "Delete this task"
-msgstr "‚±‚̃^ƒXƒN‚ðíœ"
+msgstr "Kustuta see töö"
 
 #: task.php:32
 #, php-format
 msgid "Deleted %s."
-msgstr "%s ‚ðíœ‚µ‚Ü‚µ‚½B"
+msgstr "%s kustutatud."
 
 #: config/prefs.php.dist:119
 msgid "Descending"
-msgstr "~‡"
+msgstr "Kahanev"
 
 #: data.php:53 lib/Forms/task.php:92
 msgid "Description"
-msgstr "à–¾"
+msgstr "Kirjeldus"
 
 #: templates/tasklists/tasklists.inc:75
 msgid "Description:"
-msgstr "à–¾F"
+msgstr "Kirjeldus:"
 
 #: config/prefs.php.dist:14
 msgid "Display Options"
-msgstr "•\ަƒIƒvƒVƒ‡ƒ“"
+msgstr "Kuvamise seaded"
 
 #: config/prefs.php.dist:129
 msgid "Do you want to confirm deleting entries?"
-msgstr "ƒGƒ“ƒgƒŠ[‚ðíœ‚·‚éÛ‚ÉŠm”F‚µ‚Ü‚·‚©H"
+msgstr "Kas sa tahad kinnitada kirjete kustutamist?"
 
 #: data.php:55 templates/view/task.inc:22 lib/Forms/task.php:83
 msgid "Due By"
-msgstr "Šú“ú"
+msgstr "Tähtaeg"
 
 #: config/prefs.php.dist:91 config/prefs.php.dist:106
 msgid "Due Date"
-msgstr "Šú“ú"
+msgstr "Tähtaja kuupäev"
 
 #: lib/UI/VarRenderer/nag.php:99
 msgid "Due date specified."
-msgstr ""
+msgstr "Tähtaeg määratud."
 
 #: view.php:102
 msgid "Edit"
-msgstr "•ҏW"
+msgstr "Muuda"
 
 #: templates/list/task_summaries.inc:38 lib/Block/summary.php:159
 #, php-format
 msgid "Edit \"%s\""
-msgstr "•ҏW \"%s\""
+msgstr "Muuda \"%s\""
 
 #: templates/list/task_headers.inc:42
 msgid "Edit Task"
-msgstr "ƒ^ƒXƒN•ҏW"
+msgstr "Muuda tööd"
 
 #: templates/list/task_headers.inc:58
 msgid "Edit categories and colors"
-msgstr "•ª—ނƐF‚̕ҏW"
+msgstr "Muuda kategooriaid ja värve"
 
 #: task.php:95 task.php:109
 #, php-format
 msgid "Edit: %s"
-msgstr "•ҏWF%s"
+msgstr "Muuda: %s"
 
 #: task.php:19
 #, php-format
 msgid "Error deleting task: %s"
-msgstr "ƒ^ƒXƒN‚̍폜‚ªƒAƒNƒZƒX‹‘”Û‚³‚ê‚Ü‚µ‚½F%s"
+msgstr "Viga töö: %s kustutamisel"
 
 #: templates/view/task.inc:34 lib/Forms/task.php:90
 msgid "Estimated Time"
-msgstr "Œ©Ï‚莞ŠÔ"
+msgstr "Eeldatav aeg"
 
 #: templates/data/export.inc:17
 msgid "Export"
-msgstr "ƒGƒNƒXƒ|[ƒg"
+msgstr "Eksport"
 
 #: templates/data/export.inc:6
 msgid "Export Tasks"
-msgstr "ƒ^ƒXƒN‚̃GƒNƒXƒ|[ƒg"
+msgstr "Ekspordi tööd"
 
 #: config/prefs.php.dist:57
 msgid "External Data"
-msgstr "ŠO•”ƒf[ƒ^"
+msgstr "Välised andmed"
 
 #: config/prefs.php.dist:13 config/prefs.php.dist:20 config/prefs.php.dist:27
 msgid "General Options"
-msgstr "ˆê”ʃIƒvƒVƒ‡ƒ“"
+msgstr "Üldised seaded"
 
 #: lib/UI/VarRenderer/nag.php:111
 msgid "Hour"
-msgstr "ŽžŠÔ"
+msgstr "Tund"
 
 #: lib/Nag.php:414 lib/UI/VarRenderer/nag.php:135
 msgid "Hour(s)"
-msgstr "ŽžŠÔ"
+msgstr "Tund(i)"
 
 #: templates/data/import.inc:7
 #, php-format
 msgid "Import Tasks, Step %d"
-msgstr "ƒ^ƒXƒN‚̃Cƒ“ƒ|[ƒgAƒXƒeƒbƒv %d"
+msgstr "Impordi Tööd, Samm %d"
 
 #: data.php:205
 msgid "Import/Export Tasks"
-msgstr "ƒCƒ“ƒ|[ƒg^ƒGƒNƒXƒ|[ƒg ƒ^ƒXƒN"
+msgstr "Tööde import/eksport"
 
 #: list.php:112
 msgid "Incom_plete tasks"
-msgstr "_P–¢Š®ƒ^ƒXƒN"
+msgstr "Pooleli olevad tööd"
 
 #: templates/search/search.inc:26
 msgid "Incomplete Tasks"
-msgstr "–¢Š®ƒ^ƒXƒN"
+msgstr "Pooleli olevad tööd"
 
 #: templates/list/task_summaries.inc:8
 msgid "Incomplete sub tasks, complete them first"
-msgstr ""
+msgstr "Pooleli olevad alamtööd, lõpeta need ennem"
 
 #: config/prefs.php.dist:202
 msgid "Incomplete tasks"
-msgstr "–¢Š®ƒ^ƒXƒN"
+msgstr "Pooleli olevad tööd"
 
 #: templates/view/task.inc:64
 msgid "Last Modified"
-msgstr "ÅIXV“úŽž"
+msgstr "Viimati muudetud"
 
 #: templates/list/task_summaries.inc:19
 #, php-format
 msgid "Mark \"%s\" as incomplete"
-msgstr ""
+msgstr "Märgi \"%s\" pooleli olevaks"
 
 #: templates/view/task.inc:44
 msgid "Mark as incomplete"
-msgstr ""
+msgstr "Märgi pooleli olevaks"
 
 #: lib/api.php:120
 msgid "Maximum Number of Tasks"
-msgstr "ƒ^ƒXƒN‚̍ő吔"
+msgstr "Suurim number töid"
 
 #: lib/Block/tree_alarms.php:3
 msgid "Menu Alarms"
-msgstr "ƒƒjƒ…[ƒAƒ‰[ƒ€"
+msgstr "Teavituste menüü"
 
 #: lib/Block/tree_menu.php:3
 msgid "Menu List"
-msgstr "ƒƒjƒ…[ƒŠƒXƒg"
+msgstr "Menüü"
 
 #: lib/UI/VarRenderer/nag.php:112
 msgid "Minute"
-msgstr "•ª"
+msgstr "Minut"
 
 #: lib/Nag.php:417 lib/UI/VarRenderer/nag.php:135
 msgid "Minute(s)"
-msgstr "•ª"
+msgstr "Minut(id)"
 
 #: lib/UI/VarRenderer/nag.php:52 lib/UI/VarRenderer/nag.php:101
 msgid "Month"
-msgstr "ŒŽ"
+msgstr "Kuu"
 
 #: templates/list/header.inc:9
 msgid "More Options..."
-msgstr "‚»‚Ì‘¼‚̃IƒvƒVƒ‡ƒ“"
+msgstr "Rohkem seadeid..."
 
 #: lib/api.php:986
 msgid "Multiple iCalendar components found; only one vTodo is supported."
-msgstr ""
-"•¡”‚Ì iCalendar ƒRƒ“ƒ|[ƒlƒ“ƒg‚ðŒŸo‚µ‚Ü‚µ‚½G ˆê‚Â‚Ì vTodo ‚¾‚¯‚ðƒTƒ|[ƒg‚µ"
-"‚Ä‚¢‚Ü‚·B"
+msgstr "Mitu iCal osa leitud; ainult üks vTodo on toetatud."
 
 #: templates/panel.inc:38
 msgid "My Tasklists:"
-msgstr "Ž„‚̃^ƒXƒN•\F"
+msgstr "Minu Tööd:"
 
 #: list.php:34
 msgid "My Tasks"
-msgstr "Ž„‚̃^ƒXƒN"
+msgstr "Minu tööd"
 
 #: templates/search/search.inc:18
 msgid "N_ame"
-msgstr "_A–¼‘O"
+msgstr "N_imi"
 
 #: templates/list/task_headers.inc:45
 msgid "Na_me"
-msgstr "_M–¼‘O"
+msgstr "Ni_mi"
 
 #: lib/Driver/kolab.php:741
 #, php-format
 msgid "Nag/kolab: Did not find task %s"
-msgstr "Nag/kolab: ƒ^ƒXƒN %s ‚ªŒ©‚‚©‚è‚Ü‚¹‚ñ"
+msgstr "Tööd/kolab: Ei leidnud tööd: %s"
 
 #: data.php:52 lib/Forms/task.php:62
 msgid "Name"
-msgstr "–¼‘O"
+msgstr "Nimi"
 
 #: templates/tasklists/tasklists.inc:68
 msgid "Name:"
-msgstr "–¼‘OF"
+msgstr "Nimi:"
 
 #: task.php:74 task.php:109 lib/Block/tree_menu.php:27
 msgid "New Task"
-msgstr "Vƒ^ƒXƒN"
+msgstr "Uus töö"
 
 #: templates/data/import.inc:39
 msgid "Next"
-msgstr "ŽŸ"
+msgstr "Järgmine"
 
 #: config/prefs.php.dist:167
 msgid "No"
-msgstr ""
+msgstr "Ei"
 
 #: lib/UI/VarRenderer/nag.php:46
 msgid "No delay"
-msgstr "‰„Šú‚µ‚È‚¢"
+msgstr "Ilma viivituseta"
 
 #: lib/UI/VarRenderer/nag.php:95
 msgid "No due date."
-msgstr "Šú“ú‚È‚µ"
+msgstr "Ilma lõpp kuupäevata"
 
 #: lib/api.php:405 lib/api.php:709 lib/api.php:767 lib/api.php:979
 msgid "No iCalendar data was found."
-msgstr "iCalendar ‚̃f[ƒ^‚ªŒ©•t‚©‚è‚Ü‚¹‚ñB"
+msgstr "iCal andmeid ei leitud."
 
 #: lib/Forms/task.php:50
 msgid "No parent task"
-msgstr "eƒ^ƒXƒN‚È‚µ"
+msgstr "Ülemtööd puudub"
 
 #: lib/Nag.php:605
 msgid "No task lists are available to guests."
-msgstr "ƒQƒXƒg‚ɂ̓^ƒXƒN•\‚Í‚ ‚è‚Ü‚¹‚ñB"
+msgstr "Mitte ühtegi tööde nimekirja ei ole külalistele."
 
 #: templates/list/task_footers.inc:5
 msgid "No tasks match"
-msgstr "ˆê’v‚·‚éƒ^ƒXƒN‚Í‚ ‚è‚Ü‚¹‚ñ"
+msgstr "Töid ei leitud"
 
 #: lib/Block/summary.php:222
 msgid "No tasks to display"
-msgstr "•\ަ‚·‚é‚ׂ«ƒ^ƒXƒN‚Í‚ ‚è‚Ü‚¹‚ñ"
+msgstr "Töid ei ole"
 
 #: lib/Nag.php:421 lib/UI/VarRenderer/nag.php:151
 msgid "None"
-msgstr "‚È‚µ"
+msgstr "Mitte midagi"
 
 #: lib/Nag.php:380
 msgid "Not Completed"
-msgstr "Š®—¹‚¹‚¸"
+msgstr "Pooleli"
 
 #: templates/view/task.inc:14
 msgid "Not Private"
-msgstr "ŒÂl—p‚łȂ¢"
+msgstr "Avalik"
 
 #: lib/Driver/sql.php:100 lib/Driver/sql.php:136
 msgid "Not found"
-msgstr "Œ©•t‚©‚è‚Ü‚¹‚ñB"
+msgstr "Ei leitud"
 
 #: config/prefs.php.dist:42
 msgid "Notifications"
-msgstr "’Ê’m"
+msgstr "Teavitused"
 
 #: config/prefs.php.dist:169
 msgid "On all shown tasklists"
-msgstr "•\ަ‚µ‚Ä‚¢‚é‘S‚Ẵ^ƒXƒN•\"
+msgstr "Kõigil näidatavatel töödel"
 
 #: config/prefs.php.dist:170
 msgid "On all tasklists I have read access to"
-msgstr "“ǂݏo‚µŒ ‚Ì‚ ‚é‘S‚Ẵ^ƒXƒN•\"
+msgstr "Kõigil töödel millel on lugemis õigus"
 
 #: config/prefs.php.dist:168
 msgid "On my tasklists only"
-msgstr "Ž„‚̃^ƒXƒN•\‚Ì‚Ý"
+msgstr "Minu töödel"
 
 #: templates/list/task_headers.inc:39
 msgid "P_ri"
-msgstr "_R—Dæ“x"
+msgstr "Pri"
 
 #: lib/Forms/task.php:69
 msgid "Parent task"
-msgstr "eƒ^ƒXƒN"
+msgstr "Ülemtöö"
 
 #: templates/tasklists/tasklists.inc:71
 msgid "Permission"
-msgstr "ƒAƒNƒZƒXŒ "
+msgstr "Õigused"
 
 #: lib/api.php:683 lib/api.php:805 lib/api.php:860 lib/api.php:924
 #: lib/api.php:961
 msgid "Permission Denied"
-msgstr "ƒAƒNƒZƒX‹‘”Û‚³‚ê‚Ü‚µ‚½"
+msgstr "Ligipääs keelatud"
 
 #: lib/api.php:178
 msgid "Permission denied"
-msgstr "ƒAƒNƒZƒX‹‘”Û‚³‚ê‚Ü‚µ‚½"
+msgstr "Ligipääs keelatud"
 
 #: data.php:57 templates/view/task.inc:30 lib/Forms/task.php:87
 #: config/prefs.php.dist:88 config/prefs.php.dist:103
 msgid "Priority"
-msgstr "—Dæ“x"
+msgstr "Prioriteet"
 
 #: templates/view/task.inc:14 lib/Driver.php:902
 msgid "Private"
-msgstr "ŒÂl—p"
+msgstr "Privaatne"
 
 #: lib/Driver.php:900
 msgid "Private Task"
-msgstr "ŒÂl“Iƒ^ƒXƒN"
+msgstr "Privaatne töö"
 
 #: templates/view/task.inc:12 lib/Forms/task.php:82
 msgid "Private?"
-msgstr "ŒÂl—pH"
+msgstr "Privaatne?"
 
 #: view.php:106
 msgid "Really delete this task?"
-msgstr "‚±‚̃^ƒXƒN‚ð–{“–‚ɍ폜‚µ‚Ä‚à—Ç‚¢‚Å‚·‚©H"
+msgstr "Kindel et tahad kustutada selle töö?"
 
 #: templates/tasklists/tasklists.inc:81
 msgid "Remote Subscription URL"
-msgstr "‰“Šuw“Ç URL"
+msgstr "Välise tellimuse URL"
 
 #: templates/panel.inc:57 lib/Forms/task.php:94
 msgid "Save"
-msgstr "•Û‘¶"
+msgstr "Salvesta"
 
 #: task.php:194
 #, php-format
 msgid "Saved %s."
-msgstr "%s ‚ð•Û‘¶‚µ‚Ü‚µ‚½B"
+msgstr "%s on salvestatud."
 
-#: search.php:14 templates/search/search.inc:31 templates/list/header.inc:4
+#: search.php:14 templates/list/header.inc:4 templates/search/search.inc:31
 #: lib/Block/tree_menu.php:47
 msgid "Search"
-msgstr "ŒŸõ"
+msgstr "Otsi"
 
 #: templates/search/search.inc:17
 msgid "Search In:"
-msgstr "ŒŸõF"
+msgstr "Otsi töös:"
 
 #: templates/search/search.inc:12
 msgid "Search _Text:"
-msgstr "ŒŸõ•¶Žš—ñF"
+msgstr "Otsi _teksti:"
 
 #: templates/search/search.inc:24
 msgid "Search:"
-msgstr "ŒŸõF"
+msgstr "Otsi:"
 
 #: list.php:73
 #, php-format
 msgid "Search: Results for \"%s\""
-msgstr "\"%s\" ‚ÌŒŸõŒ‹‰Ê"
+msgstr "Otsing: Tulemused \"%s\""
 
 #: lib/UI/VarRenderer/nag.php:58 lib/UI/VarRenderer/nag.php:106
 msgid "Select a date"
-msgstr "“ú‚ð‘I‘ð"
+msgstr "Vali kuupäev"
 
 #: templates/tasklists/tasklists.inc:62
 msgid "Select a tasklist"
-msgstr "ƒ^ƒXƒN•\‚ð‘I‘ð"
+msgstr "Vali töönimekiri"
 
 #: templates/tasklists/tasklists.inc:24 templates/tasklists/tasklists.inc:82
 msgid "Select a tasklist above to display the Remote Subscription URL"
-msgstr "ƒ^ƒXƒN•\‚ð‘I‚сA‰“Šuw“Ç URL ‚ð•\ަ‚³‚¹‚ĉº‚³‚¢"
+msgstr "Vali tööde nimekiri ülevalt et näha välise liitumise URLi"
 
 #: templates/tasklists/tasklists.inc:23 templates/tasklists/tasklists.inc:80
 msgid "Select a tasklist above to display the URL"
-msgstr "ƒ^ƒXƒN•\‚ð‘I‚Ñ URL ‚ð•\ަ‚³‚¹‚ĉº‚³‚¢"
+msgstr "Vali tööde nimekiri ülevalt et näha URLi"
 
 #: templates/data/export.inc:11
 msgid "Select the export format:"
-msgstr "ƒGƒNƒXƒ|[ƒgŒ`Ž®‚ð‘I‘ðF"
+msgstr "Vali eksportimise formaat:"
 
 #: templates/data/import.inc:36
 msgid "Select the file to import:"
-msgstr "ƒCƒ“ƒ|[ƒg‚·‚éƒtƒ@ƒCƒ‹‚ð‘I‘ðF"
+msgstr "Vali fail mida importida:"
 
 #: templates/data/import.inc:12
 msgid "Select the format of the source file:"
-msgstr "Œ³ƒtƒ@ƒCƒ‹‚ÌŒ`Ž®‚ð‘I‘ðF"
+msgstr "Vali faili tüüo:"
 
 #: templates/panel.inc:48
 msgid "Shared Tasklists:"
-msgstr "‹¤—Lƒ^ƒXƒN•\F"
+msgstr "Jagatud tööde nimekiri:"
 
 #: config/prefs.php.dist:69
 msgid "Should the Task List be shown in its own column in the List view?"
-msgstr "ƒ^ƒXƒNˆê——‚Ń^ƒXƒN•\‚Ì–¼‘O‚à•\ަ‚µ‚Ü‚·‚©H"
+msgstr "Kas tööde nimekiri peaks olema oma veerus nimekirja vaates?"
 
 #: lib/Block/summary.php:45
 msgid "Show action buttons?"
-msgstr "‘€ìƒ{ƒ^ƒ“‚ð•\ަ‚µ‚Ü‚·‚©H"
+msgstr "Näita tegevus nuppe?"
 
 #: config/prefs.php.dist:204
 msgid "Show complete, incomplete, or all tasks in the task list?"
-msgstr "Š®—¹‚µ‚½ƒ^ƒXƒNA–¢Š®‚̃^ƒXƒN‚ȂǑS‚Ẵ^ƒXƒN‚ð•\ަ‚µ‚Ü‚·‚©H"
+msgstr "Näita lõpetatud, poolikuid või kõiki töid tööde nimekirjas?"
 
 #: config/prefs.php.dist:191
 msgid "Show data from any of these other applications in your task list?"
-msgstr "‘¼‚̃AƒvƒŠƒP[ƒVƒ‡ƒ“‚̃f[ƒ^‚àƒ^ƒXƒN•\‚É•\ަ‚µ‚Ü‚·‚©H"
+msgstr "Näita andmeid järgmistest allikatest?"
 
 #: config/prefs.php.dist:58
 msgid "Show data from other applications or sources."
-msgstr "‘¼‚̃AƒvƒŠƒP[ƒVƒ‡ƒ“‚̃f[ƒ^‚à•\ަ‚·‚éB"
+msgstr "Näita andmeid teistest allikatest."
 
 #: lib/Block/summary.php:48
 msgid "Show due dates?"
-msgstr "Šú“ú‚ð•\ަ‚µ‚Ü‚·‚©H"
+msgstr "Näita tähtaegu?"
 
 #: lib/Block/summary.php:42
 msgid "Show priorities?"
-msgstr "—Dæ“x‚ð•\ަ‚µ‚Ü‚·‚©H"
+msgstr "Näita prioriteete?"
 
 #: lib/Block/summary.php:54
 msgid "Show task alarms?"
-msgstr "ƒAƒ‰[ƒ€‚ð•\ަ‚µ‚Ü‚·‚©H"
+msgstr "Näita tööde teavitusi?"
 
 #: lib/Block/summary.php:57
 msgid "Show task category?"
-msgstr "•ª—Þ‚ð•\ަ‚µ‚Ü‚·‚©H"
+msgstr "Näita töö kategooriat?"
 
 #: config/prefs.php.dist:79
 msgid "Show task list options panel?"
-msgstr "ƒ^ƒXƒN•\‚̃IƒvƒVƒ‡ƒ“‚ð•\ަ‚µ‚Ü‚·‚©H"
+msgstr "Näita seadistamise paneeli?"
 
 #: lib/Block/summary.php:51
 msgid "Show tasklist name?"
-msgstr "ƒ^ƒXƒN•\‚Ì–¼‘O‚ð•\ަ‚µ‚Ü‚·‚©H"
+msgstr "Näita tööde nimekirja nime?"
 
 #: lib/Block/summary.php:70
 msgid "Show tasks from these categories"
-msgstr "‚±‚ê‚ç‚Ì•ª—ނ̃^ƒXƒN‚ð•\ަ"
+msgstr "Näita töid nendest kategooriatest"
 
 #: lib/Block/summary.php:66
 msgid "Show tasks from these tasklists"
-msgstr "‚±‚ê‚ç‚̃^ƒXƒN•\‚̃^ƒXƒN‚ð•\ަ"
+msgstr "Näita töid nendest tööde nimekirjadest"
 
 #: templates/list/task_headers.inc:53
 msgid "Sort by Category"
-msgstr "•ª—ނ̏‡‚É•À‚ёւ¦‚é"
+msgstr "Sorteeri katekoorja järgi"
 
 #: templates/list/task_headers.inc:31
 msgid "Sort by Completion Status"
-msgstr "Š®—¹ó‹µ‚̏‡‚É•À‚ёւ¦‚é"
+msgstr "Sorteeri progressi järgi"
 
 #: templates/list/task_headers.inc:50
 msgid "Sort by Due Date"
-msgstr "Šú“ú‚̏‡‚É•À‚ёւ¦‚é"
+msgstr "Sorteeri tähtaja järgi"
 
 #: templates/list/task_headers.inc:45
 msgid "Sort by Name"
-msgstr "–¼‘O‚̏‡‚É•À‚ёւ¦‚é"
+msgstr "Sorteeri nime järgi"
 
 #: templates/list/task_headers.inc:39
 msgid "Sort by Priority"
-msgstr "—Dæ“x‚̏‡‚É•À‚ёւ¦‚é"
+msgstr "Sorteeri prioriteedi järgi"
 
 #: templates/list/task_headers.inc:35
 msgid "Sort by User Name"
-msgstr "–¼‘O‚̏‡‚É•À‚ёւ¦‚é"
+msgstr "Sorteeri kasutaja järgi"
 
 #: config/prefs.php.dist:120
 msgid "Sort direction:"
-msgstr "•À‚Ñ•ûŒüF"
+msgstr "Sorteerimise suund:"
 
 #: config/prefs.php.dist:94
 msgid "Sort tasks by:"
-msgstr "ƒ^ƒXƒN‚Ì•À‚я‡F"
+msgstr "Sorteeri tööd:"
 
 #: data.php:56
 msgid "Start"
-msgstr "ŠJŽn"
+msgstr "Algus"
 
 #: templates/view/task.inc:18
 msgid "Start Date"
-msgstr "ŠJŽn“úŽž"
+msgstr "Algus aeg"
 
 #: lib/UI/VarRenderer/nag.php:50
 msgid "Start date specified."
-msgstr "ŠJŽn“úŽž‚ªŽw’肳‚ê‚Ü‚µ‚½B"
+msgstr "Algus aeg määratud."
 
 #: templates/list/task_summaries.inc:57
 msgid "Task Alarm"
-msgstr "ƒ^ƒXƒNƒAƒ‰[ƒ€"
+msgstr "Töö teavitus"
 
 #: templates/list/task_headers.inc:48
 msgid "Task Alarm?"
-msgstr "ƒ^ƒXƒNƒAƒ‰[ƒ€H"
+msgstr "Töö teavitus?"
 
 #: config/prefs.php.dist:28
 msgid "Task Defaults"
-msgstr "ƒ^ƒXƒNƒfƒtƒHƒ‹ƒg"
+msgstr "Töö vaike seaded"
 
 #: lib/Forms/task.php:65
 msgid "Task List"
-msgstr "ƒ^ƒXƒN•\"
+msgstr "Tööde nimekiri"
 
 #: config/prefs.php.dist:34 config/prefs.php.dist:41 config/prefs.php.dist:56
 msgid "Task List and Share Options"
-msgstr "ƒ^ƒXƒN•\‚Æ‹¤—L‚̃IƒvƒVƒ‡ƒ“"
+msgstr "Tööde nimekiri ja jagamise seaded"
 
-#: tasklists.php:117
+#: tasklists.php:119
 msgid "Task Lists"
-msgstr "ƒ^ƒXƒN•\"
+msgstr "Tööde nimekiri"
 
 #: config/prefs.php.dist:89 config/prefs.php.dist:104
 msgid "Task Name"
-msgstr "ƒ^ƒXƒN–¼"
+msgstr "Töö nimi"
 
 #: templates/list/task_summaries.inc:55
 msgid "Task Note"
-msgstr "ƒ^ƒXƒNƒm[ƒg"
+msgstr "Töö märkmed"
 
 #: templates/list/task_headers.inc:47
 msgid "Task Note?"
-msgstr "ƒ^ƒXƒNƒm[ƒgH"
+msgstr "Töö märge?"
 
 #: templates/search/search.inc:6
 msgid "Task Search"
-msgstr "ƒ^ƒXƒNŒŸõ"
+msgstr "Töö otsing"
 
 #: lib/Nag.php:630
 msgid "Task added:"
-msgstr "’ljÁ‚³‚ꂽƒ^ƒXƒNF"
+msgstr "Töö lisatud:"
 
 #: lib/Nag.php:640
 msgid "Task deleted:"
-msgstr "íœ‚³‚ꂽƒ^ƒXƒNF"
+msgstr "Töö kustutatud:"
 
-#: tasklists.php:32
+#: tasklists.php:34
 msgid "Task lists must have a name."
-msgstr "ƒ^ƒXƒN•\‚É–¼‘O‚ª•K—v‚Å‚·B"
+msgstr "Töö nimekirjal peab olema nimi."
 
 #: lib/Nag.php:635
 msgid "Task modified:"
-msgstr "XV“úŽžF"
+msgstr "Töö muudetud:"
 
 #: task.php:88 view.php:44
 msgid "Task not found."
-msgstr "ƒ^ƒXƒN‚ªŒ©•t‚©‚è‚Ü‚¹‚ñB"
+msgstr "Tööd ei leitud."
 
 #: config/prefs.php.dist:93 config/prefs.php.dist:108
 msgid "Tasklist"
-msgstr "ƒ^ƒXƒN•\"
+msgstr "Tööde nimekiri"
 
 #: templates/panel.inc:30 templates/panel.inc:31
 #: templates/tasklists/tasklists.inc:58
 msgid "Tasklists"
-msgstr "ƒ^ƒXƒN•\"
+msgstr "Tööde nimekirjad"
 
 #: templates/tasklists/tasklists.inc:60
 msgid "Tasklists:"
-msgstr "ƒ^ƒXƒN•\F"
+msgstr "Tööde nimekirjad:"
 
 #: lib/api.php:1041
 msgid "Tasks"
-msgstr "ƒ^ƒXƒN"
+msgstr "Tööd"
 
 #: lib/Block/summary.php:3
 msgid "Tasks Summary"
-msgstr "ƒ^ƒXƒNŠT—v"
+msgstr "Tööde kokkuvõte"
 
 #: data.php:193
 #, php-format
 msgid "The %s file didn't contain any tasks."
-msgstr "ƒtƒ@ƒCƒ‹ %s ‚ɂ̓^ƒXƒN‚͈ê‚‚àŠÜ‚Ü‚ê‚Ä‚¢‚Ü‚¹‚ñB"
+msgstr "Fail %s ei sisaldanud ühtki tööd."
 
 #: lib/Driver.php:56
 msgid "The Tasks backend is not currently available."
-msgstr "ƒ^ƒXƒN‚̃oƒbƒNƒGƒ“ƒh‚ÍŒ»ÝŽg—p‚Å‚«‚Ü‚¹‚ñB"
+msgstr "Tööde alusrakendus ei ole saadaval."
 
 #: lib/Driver.php:137
 #, php-format
 msgid "The Tasks backend is not currently available: %s"
-msgstr "ƒ^ƒXƒN‚̃oƒbƒNƒGƒ“ƒh‚ÍŒ»ÝŽg—p‚Å‚«‚Ü‚¹‚ñF %s"
+msgstr "ööde alusrakendus ei ole saadaval: %s"
 
 #: lib/Forms/task.php:130
 msgid "The alarm value must not be empty."
-msgstr "ƒAƒ‰[ƒ€‚Ì’l‚Í‹ó‚ł͂¢‚¯‚Ü‚¹‚ñB"
+msgstr "Teavitus ei tohi olla tühi."
 
 #: templates/prefs/defaultduetimeselect.inc:8
 msgid "The current hour"
-msgstr "Œ»Ý‚ÌŽž"
+msgstr "Hetke tund"
 
 #: lib/Nag.php:631
 #, php-format
 msgid ""
 "The task \"%s\" has been added to \"%s\" tasklist, with a due date of: %s."
-msgstr "ƒ^ƒXƒN \"%s\" ‚̓^ƒXƒN•\ \"%s\" ‚ɒljÁ‚³‚ê‚Ü‚µ‚½BŠú“ú‚́F%s"
+msgstr "Töö \"%s\" on lisatud nimekirja \"%s\" tähtajaga: %s."
 
 #: lib/Nag.php:641
 #, php-format
 msgid ""
 "The task \"%s\" has been deleted from \"%s\" tasklist, with a due date of: %"
 "s."
-msgstr "ƒ^ƒXƒN \"%s\" ‚̓^ƒXƒN•\ \"%s\" ‚©‚çíœ‚³‚ê‚Ü‚µ‚½BŠú“ú‚́F%s"
+msgstr "Töö \"%s\" on kustutatud nimekirjast \"%s\" tähtajaga: %s."
 
 #: lib/Nag.php:636
 #, php-format
 msgid ""
 "The task \"%s\" has been edited on \"%s\" tasklist, with a due date of: %s."
-msgstr "ƒ^ƒXƒN \"%s\" ‚̓^ƒXƒN•\ \"%s\" ‚ŕύX‚³‚ê‚Ü‚µ‚½BŠú“ú‚́F%s"
+msgstr "Töö \"%s\" on muudetud nimekirjas \"%s\" tähtajaga: %s."
 
-#: tasklists.php:49
+#: tasklists.php:51
 #, php-format
 msgid "The task list \"%s\" couldn't be created: %s"
-msgstr "ƒ^ƒXƒN•\ \"%s\" ‚͍쐬‚Å‚«‚Ü‚¹‚ñ‚Å‚µ‚½F%s"
+msgstr "Tööde nimekirja \"%s\" ei saanud luua: %s"
 
-#: tasklists.php:60
+#: tasklists.php:62
 #, php-format
 msgid "The task list \"%s\" couldn't be saved: %s"
-msgstr "ƒ^ƒXƒN•\ \"%s\" ‚͕ۑ¶‚Å‚«‚Ü‚¹‚ñ‚Å‚µ‚½F%s"
+msgstr "Tööde nimekirja \"%s\" ei saanud salvestada: %s"
 
-#: tasklists.php:51
+#: tasklists.php:53
 #, php-format
 msgid "The task list \"%s\" has been created."
-msgstr "ƒ^ƒXƒN•\ \"%s\" ‚͍쐬‚³‚ê‚Ü‚µ‚½B"
+msgstr "Tööde nimekirja \"%s\" on loodud."
 
-#: tasklists.php:85
+#: tasklists.php:87
 #, php-format
 msgid "The task list \"%s\" has been deleted."
-msgstr "ƒ^ƒXƒN•\ \"%s\" ‚͍폜‚³‚ê‚Ü‚µ‚½B"
+msgstr "Tööde nimekirja \"%s\" on kustutatud."
 
-#: tasklists.php:62
+#: tasklists.php:64
 #, php-format
 msgid "The task list \"%s\" has been saved."
-msgstr "ƒ^ƒXƒN•\ \"%s\" ‚͕ۑ¶‚³‚ê‚Ü‚µ‚½B"
+msgstr "Tööde nimekirja \"%s\" on salvestatud."
 
 #: config/prefs.php.dist:109
 msgid "Then:"
-msgstr "‚³‚ç‚ɁF"
+msgstr "Siis:"
 
 #: templates/list/empty.inc:2
 msgid "There are no tasks matching the current criteria."
-msgstr "Œ»Ý‚̊‚Ɉê’v‚·‚éƒ^ƒXƒN‚Í‚ ‚è‚Ü‚¹‚ñB"
+msgstr "Hetke kriteeriumitele ei vasta ühtegi tööd."
 
 #: task.php:225
 #, php-format
 msgid "There was a problem completing %s: %s"
-msgstr "%s ‚ðŠ®—¹’†‚É–â‘肪‚ ‚è‚Ü‚µ‚½F%s"
+msgstr "Tekkis probleem töö %s lõpetamisel: %s"
 
 #: task.php:29
 #, php-format
 msgid "There was a problem deleting %s: %s"
-msgstr "%s ‚ðíœ’†‚É–â‘肪‚ ‚è‚Ü‚µ‚½F%s"
+msgstr "Tekkis probleem töö %s kustutamisel: %s"
 
 #: task.php:192
 #, php-format
 msgid "There was a problem saving the task: %s."
-msgstr "ƒ^ƒXƒN‚ð•Û‘¶’†‚É–â‘肪‚ ‚è‚Ü‚µ‚½F%s"
+msgstr "Tekkis probleem töö %s salvestamisel."
 
 #: data.php:196
 #, php-format
 msgid "There was an error importing the data: %s"
-msgstr "ƒf[ƒ^‚ðƒCƒ“ƒ|[ƒg’†‚ɃGƒ‰[‚ª‚ ‚è‚Ü‚µ‚½F%s"
+msgstr "Tekkis viga importimisel: %s"
 
 #: lib/api.php:397 lib/api.php:701 lib/api.php:973
 msgid "There was an error importing the iCalendar data."
-msgstr "iCalendar ƒf[ƒ^‚ðƒCƒ“ƒ|[ƒg’†‚ɃGƒ‰[‚ª‚ ‚è‚Ü‚µ‚½B"
+msgstr "Tekkis viga iCal andmete importimisel."
 
 #: data.php:80
 msgid "There were no tasks to export."
-msgstr "ƒGƒNƒXƒ|[ƒg‚·‚éƒ^ƒXƒN‚ª‚ ‚è‚Ü‚¹‚ñB"
+msgstr "Ühtegi tööd ei eksporditud."
 
 #: data.php:126
 msgid "This file format is not supported."
-msgstr "‚±‚̃tƒ@ƒCƒ‹Œ`Ž®‚̓Tƒ|[ƒg‚³‚ê‚Ä‚¢‚Ü‚¹‚ñB"
+msgstr "Faili formaat ei ole toetatud."
 
 #: templates/tasklists/tasklists.inc:79
 msgid "URL"
 msgstr "URL"
 
-#: tasklists.php:81
+#: tasklists.php:83
 #, php-format
 msgid "Unable to delete \"%s\": %s"
-msgstr "\"%s\" ‚ðíœ‚Å‚«‚Ü‚¹‚ñF%s"
+msgstr "Viga kustutamisel \"%s\": %s"
 
 #: lib/Driver.php:140
 #, php-format
 msgid "Unable to load the definition of %s."
-msgstr "%s ‚Ì’è‹`‚ªƒ[ƒh‚Å‚«‚Ü‚¹‚ñB"
+msgstr "Viga definitsioonide laadimisel: %s"
 
-#: templates/view/task.inc:9 templates/list/task_summaries.inc:62
+#: templates/list/task_summaries.inc:62 templates/view/task.inc:9
 #: lib/Nag.php:850 lib/Nag.php:851 lib/Nag.php:865 lib/Nag.php:866
-#: lib/Forms/task.php:78 lib/Block/summary.php:31 lib/Block/summary.php:215
+#: lib/Block/summary.php:31 lib/Block/summary.php:215 lib/Forms/task.php:78
 msgid "Unfiled"
-msgstr "–¢®—"
+msgstr "Täitmata"
 
 #: lib/api.php:502 lib/api.php:774 lib/api.php:832 lib/api.php:886
 #: lib/api.php:1011
 #, php-format
 msgid "Unsupported Content-Type: %s"
-msgstr "ƒTƒ|[ƒg‚³‚ê‚Ä‚¢‚È‚¢ Content-Type ‚Å‚·F%s"
+msgstr "Formaat ei ole toetatud: %s"
 
 #: lib/Driver.php:1079
 #, php-format
@@ -996,172 +989,169 @@ msgid ""
 "\n"
 "%s"
 msgstr ""
-"ƒ^ƒXƒN‚ÌŠú“ú‚ɂ‚¢‚Ĉȉº‚̂悤‚ɍÑ£’v‚µ‚Ü‚·B\n"
+"Me sooviksime meelde tuletada, et töö tähtaeg on.\n"
 "\n"
 "%s\n"
 "\n"
-"“úŽžF%s\n"
-"ŽžŠÔF%s\n"
+"Kuupäev: %s\n"
+"Kellaaeg: %s\n"
 "\n"
 "%s"
 
 #: lib/Nag.php:408 lib/UI/VarRenderer/nag.php:136
 msgid "Week(s)"
-msgstr "T"
+msgstr "Nädal(ad)"
 
 #: templates/prefs/defaultduetimeselect.inc:6
 msgid "What do you want to be the default due time for tasks?"
-msgstr "ƒfƒtƒHƒ‹ƒg‚ÌŠú“úŽžŠÔ‚ð‰½Žž‚É‚µ‚Ü‚·‚©H"
+msgstr "Vaike tähtaeg töödele oleks?"
 
 #: config/prefs.php.dist:147
 msgid ""
 "When creating a new task, how many days in the future should the default due "
 "date be (0 means today)?"
-msgstr "Vƒ^ƒXƒN‚ðì‚鎞AƒfƒtƒHƒ‹ƒg‚ÌŠú“ú‚ð‰½“úŒã‚É‚µ‚Ü‚·‚©i0‚͍¡“újH"
+msgstr ""
+"Töö loomisel mitu päeva tuleviku peaks olema vaike tähtaeg (0 tähendab täna)?"
 
 #: config/prefs.php.dist:138
 msgid "When creating a new task, should it default to having a due date?"
-msgstr "Vƒ^ƒXƒN‚ðì‚鎞AƒfƒtƒHƒ‹ƒg‚ÅŠú“ú•t‚É‚µ‚Ü‚·‚©H"
+msgstr "Kas töö loomisel peaks olema vaikimisi tähtaeg?"
 
 #: templates/data/import.inc:21
 msgid "Which tasklist should the tasks be added to?"
-msgstr "‚ǂ̃^ƒXƒN•\‚ɒljÁ‚µ‚Ü‚·‚©H"
+msgstr "Millisesse nimekirja peaks töö lisama?"
 
 #: lib/UI/VarRenderer/nag.php:53 lib/UI/VarRenderer/nag.php:102
 msgid "Year"
-msgstr "”N"
+msgstr "Aasta"
 
-#: data.php:41 data.php:151 task.php:61
+#: task.php:61 data.php:41 data.php:151
 #, php-format
 msgid "You are not allowed to create more than %d tasks."
-msgstr "‚ ‚È‚½‚Í %d ˆÈã‚̃^ƒXƒN‚ðì¬‚Å‚«‚Ü‚¹‚ñB"
+msgstr "Pole lubatud luua rohkem kui %d tööd."
 
 #: view.php:52
 msgid "You do not have permission to view this tasklist."
-msgstr "‚ ‚È‚½‚ɂ͂±‚̃^ƒXƒN•\‚ð•\ަ‚·‚錠ŒÀ‚ª‚ ‚è‚Ü‚¹‚ñB"
+msgstr "Sul puuduvad õigused selle tööde nimekirja vaatamiseks."
 
-#: tasklists.php:88
+#: tasklists.php:90
 msgid "You must select a task list to be deleted."
-msgstr "íœ‚·‚é‚ׂ«ƒ^ƒXƒN•\‚ð‘I‘ð‚µ‚Ä‰º‚³‚¢B"
+msgstr "Sa pead valima tööde nimekirja mida kustutada."
 
 #: templates/tasklists/tasklists.inc:47
 msgid "You must select a tasklist to be deleted."
-msgstr "íœ‚·‚é‚ׂ«ƒ^ƒXƒN•\‚ð‘I‘ð‚µ‚Ä‰º‚³‚¢B"
+msgstr "Sa pead valima tööde nimekirja mida kustutada."
 
 #: lib/Nag.php:631
 msgid "You requested to be notified when tasks are added to your tasklists."
-msgstr ""
-"‚ ‚È‚½‚Í‚ ‚È‚½‚̃^ƒXƒN•\‚Ƀ^ƒXƒN‚ª’ljÁ‚³‚ê‚½Žž‚É’Ê’m‚·‚邱‚Æ‚ð—v‹‚µ‚Ü‚µ‚½B"
+msgstr "Te soovisite teavitust kui tööde nimekirja lisatakse uus töö."
 
 #: lib/Nag.php:641
 msgid ""
 "You requested to be notified when tasks are deleted from your tasklists."
-msgstr ""
-"‚ ‚È‚½‚Í‚ ‚È‚½‚̃^ƒXƒN•\‚©‚çƒ^ƒXƒN‚ªíœ‚³‚ê‚½Žž‚É’Ê’m‚·‚邱‚Æ‚ð—v‹‚µ‚Ü‚µ"
-"‚½B"
+msgstr "Te soovisite teavitust kui tööde nimekirjast kustutatakse töö."
 
 #: lib/Nag.php:636
 msgid "You requested to be notified when tasks are edited on your tasklists."
-msgstr ""
-"‚ ‚È‚½‚Í‚ ‚È‚½‚̃^ƒXƒN•\‚̃^ƒXƒN‚ª•ύX‚³‚ê‚½Žž‚É’Ê’m‚·‚邱‚Æ‚ð—v‹‚µ‚Ü‚µ‚½B"
+msgstr "Te soovisite teavitust kui tööde nimekirja muudetakse."
 
 #: templates/prefs/tasklistselect.inc:10
 msgid "Your default task list:"
-msgstr "ƒfƒtƒHƒ‹ƒg‚̃^ƒXƒN•\F"
+msgstr "Sinu vaike tööde nimekiri:"
 
 #: templates/panel.inc:43
 msgid "[Manage My Tasklists]"
-msgstr "[Ž„‚̃^ƒXƒN•\‚ÌŠÇ—]"
+msgstr "[Halda Minu tööde nimekirja]"
 
 #: templates/list/task_summaries.inc:46 lib/Block/summary.php:101
 #: lib/Block/summary.php:199
 msgid "[none]"
-msgstr "[‚È‚µ]"
+msgstr "[midagi]"
 
 #: templates/search/search.inc:25
 msgid "_All Tasks"
-msgstr "_A‘Sƒ^ƒXƒN"
+msgstr "_Kõik tööd"
 
 #: list.php:111
 msgid "_All tasks"
-msgstr "_A‘Sƒ^ƒXƒN"
+msgstr "_Kõik tööd"
 
 #: templates/search/search.inc:20
 msgid "_Category"
-msgstr "_C•ª—Þ"
+msgstr "_Kategooria"
 
 #: view.php:99
 msgid "_Complete"
-msgstr "_CŠ®—¹"
+msgstr "_Lõpeta"
 
 #: list.php:114
 msgid "_Completed tasks"
-msgstr "_CŠ®—¹ƒ^ƒXƒN"
+msgstr "_Lõpetatud tööd"
 
 #: view.php:106
 msgid "_Delete"
-msgstr "_Díœ"
+msgstr "Ku_stuta"
 
 #: templates/search/search.inc:19
 msgid "_Description"
-msgstr "_Dà–¾"
+msgstr "_Kirjeldus"
 
 #: templates/list/task_headers.inc:50
 msgid "_Due Date"
-msgstr "_DŠú“ú"
+msgstr "Tä_htaeg"
 
 #: view.php:102
 msgid "_Edit"
-msgstr "_E•ҏW"
+msgstr "_Muuda"
 
 #: list.php:113
 msgid "_Future tasks"
-msgstr "_F¡Œã‚̃^ƒXƒN"
+msgstr "Tu_leviku tööd"
 
 #: lib/Nag.php:553
 msgid "_Import/Export"
-msgstr "_IƒCƒ“/ƒAƒEƒg"
+msgstr "_Import/Eksport"
 
 #: lib/Nag.php:540
 msgid "_List Tasks"
-msgstr "_Lƒ^ƒXƒNˆê——"
+msgstr "_Nimekiri"
 
 #: lib/Nag.php:545
 msgid "_New Task"
-msgstr "_NVƒ^ƒXƒN"
+msgstr "_Uus töö"
 
 #: lib/Nag.php:558
 msgid "_Print"
-msgstr "_Pˆóü"
+msgstr "_Prindi"
 
 #: lib/Nag.php:549
 msgid "_Search"
-msgstr "_SŒŸõ"
+msgstr "_Otsing"
 
 #: templates/list/task_headers.inc:35
 msgid "_Task List"
-msgstr "_Tƒ^ƒXƒN•\"
+msgstr "_Tööd"
 
 #: templates/prefs/defaultduetimeselect.inc:15
 msgid "am"
-msgstr "Œß‘O"
+msgstr "EL"
 
 #: data.php:31
 msgid "iCalendar (vTodo)"
-msgstr "iCalendar (vTodo)"
+msgstr "iCal (vTodo)"
 
 #: lib/Block/tree_menu.php:37
 #, php-format
 msgid "in %s"
-msgstr ""
+msgstr "%s ajal"
 
 #: lib/Nag.php:79
 msgid "no time"
-msgstr ""
+msgstr "Ilma ajata"
 
 #: templates/prefs/defaultduetimeselect.inc:15
 msgid "pm"
-msgstr "Χ΋"
+msgstr "PL"
 
 #: data.php:100 templates/data/export.inc:1
 msgid "tasks.csv"
diff --git a/po/pt_PT.po b/po/eu_ES.po
similarity index 57%
copy from po/pt_PT.po
copy to po/eu_ES.po
index bc728dd..7477d81 100644
--- a