[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,"&").replace(/</g,"<").replace(/>/g,">")},unescapeHTML:function(){return this.replace(/&/g,"&").replace(/</g,"<").replace(/>/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,"&").replace(/</g,"<").replace(/>/g,">")},unescapeHTML:function(){return this.stripTags().replace(/&/g,"&").replace(/</g,"<").replace(/>/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,'&').replace(/</g,'<').replace(/>/g,'>');
},
unescapeHTML: function() {
- return this.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>');
+ return this.stripTags().replace(/&/g,'&').replace(/</g,'<').replace(/>/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(' ', $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 Tu^XNðÜÞ)"
+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 Ì^XN\"
+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 "^XN %s Ì®¹ªANZXÛ³êܵ½B"
+msgstr "%s töö lõpetamiseks õigus puudub."
#: task.php:24
#, php-format
msgid "Access denied deleting %s"
-msgstr "%s ÌíªANZXÛ³êܵ½"
+msgstr "%s kustutamiseks õigus puudub"
#: task.php:84 task.php:90
msgid "Access denied editing task."
-msgstr "^XN %s ÌÒWªANZXÛ³êܵ½B"
+msgstr "Töö muutmise õigus puudub."
#: task.php:82
#, php-format
msgid "Access denied editing task: %s"
-msgstr "^XNÌÒWªANZXÛ³êܵ½F%s"
+msgstr "%s töö muutmise õigus puudub"
#: task.php:163
#, php-format
msgid "Access denied moving the task to %s."
-msgstr "^XNÌ %s ÖÌÚ®ªANZXÛ³êܵ½B"
+msgstr "%s töö liigutamise õigus puudub."
#: task.php:166
#, php-format
msgid "Access denied removing task from %s."
-msgstr "^XNÌ %s ©çÌíªANZXÛ³êܵ½B"
+msgstr "%s töö kustutamise õigus puudub."
#: task.php:125
#, php-format
msgid "Access denied saving task to %s."
-msgstr "^XNÌ %s ÖÌÛ¶ªANZXÛ³êܵ½B"
+msgstr "%s töö salvestamise õigus puudub."
#: task.php:121
#, php-format
msgid "Access denied saving task: %s"
-msgstr "^XNÌÛ¶ªANZXÛ³êܵ½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^XN"
+msgstr "Kõik tööd"
#: lib/Block/summary.php:63
msgid "Always show completed tasks?"
-msgstr "®¹µ½^XNðíÉ\¦µÜ·©H"
+msgstr "Alati näita lõpetatud töid?"
#: lib/Block/summary.php:60
msgid "Always show overdue tasks?"
-msgstr "úÀÌ߬½^XNðíÉ\¦µÜ·©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 "ubN^Cg"
+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 "^XNÌÀÑÆ\¦IvVðÏ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 "^XNÌ}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 ""
-"^XNðÇÁAÏXAíµ½É[ÅÊ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 "^XNðÏXµ½ÉÊmµÄ~µ¢ÈçIðµÄº³¢B"
+msgstr "Vali kui soovid teavitust muudetud töödest."
#: config/prefs.php.dist:36
msgid "Choose your default task list."
-msgstr "ftHgÌ^XN\ð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 "®¹^XN"
+msgstr "Lõpeta töö"
#: config/prefs.php.dist:203
msgid "Complete tasks"
-msgstr "®¹^XN"
+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 "®¹^XN"
+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 "Ú±¸sF%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 "ftHgÌ^XN\"
+msgstr "Vaike tööde nimekiri"
#: config/prefs.php.dist:29
msgid "Defaults for new tasks"
-msgstr "Vçµ¢^XNÌftHg"
+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 "íÌmF"
+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 "±Ì^XNðí"
+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 "\¦IvV"
+msgstr "Kuvamise seaded"
#: config/prefs.php.dist:129
msgid "Do you want to confirm deleting entries?"
-msgstr "Gg[ðí·éÛÉmFµÜ·©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 "^XNÒ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 "ÒWF%s"
+msgstr "Muuda: %s"
#: task.php:19
#, php-format
msgid "Error deleting task: %s"
-msgstr "^XNÌíªANZXÛ³êܵ½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 "GNX|[g"
+msgstr "Eksport"
#: templates/data/export.inc:6
msgid "Export Tasks"
-msgstr "^XNÌGNX|[g"
+msgstr "Ekspordi tööd"
#: config/prefs.php.dist:57
msgid "External Data"
-msgstr "Of[^"
+msgstr "Välised andmed"
#: config/prefs.php.dist:13 config/prefs.php.dist:20 config/prefs.php.dist:27
msgid "General Options"
-msgstr "êÊIvV"
+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 "^XNÌC|[gAXebv %d"
+msgstr "Impordi Tööd, Samm %d"
#: data.php:205
msgid "Import/Export Tasks"
-msgstr "C|[g^GNX|[g ^XN"
+msgstr "Tööde import/eksport"
#: list.php:112
msgid "Incom_plete tasks"
-msgstr "_P¢®^XN"
+msgstr "Pooleli olevad tööd"
#: templates/search/search.inc:26
msgid "Incomplete Tasks"
-msgstr "¢®^XN"
+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 "¢®^XN"
+msgstr "Pooleli olevad tööd"
#: templates/view/task.inc:64
msgid "Last Modified"
-msgstr "ÅIXVú"
+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 "^XNÌÅå"
+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
[Xg"
+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 "»Ì¼ÌIvV"
+msgstr "Rohkem seadeid..."
#: lib/api.php:986
msgid "Multiple iCalendar components found; only one vTodo is supported."
-msgstr ""
-"¡Ì iCalendar R|[lgðoµÜµ½G êÂÌ vTodo ¾¯ðT|[gµ"
-"ĢܷB"
+msgstr "Mitu iCal osa leitud; ainult üks vTodo on toetatud."
#: templates/panel.inc:38
msgid "My Tasklists:"
-msgstr "Ì^XN\F"
+msgstr "Minu Tööd:"
#: list.php:34
msgid "My Tasks"
-msgstr "Ì^XN"
+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: ^XN %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 "¼OF"
+msgstr "Nimi:"
#: task.php:74 task.php:109 lib/Block/tree_menu.php:27
msgid "New Task"
-msgstr "V^XN"
+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^XNȵ"
+msgstr "Ülemtööd puudub"
#: lib/Nag.php:605
msgid "No task lists are available to guests."
-msgstr "QXgÉÍ^XN\Í èܹñB"
+msgstr "Mitte ühtegi tööde nimekirja ei ole külalistele."
#: templates/list/task_footers.inc:5
msgid "No tasks match"
-msgstr "êv·é^XNÍ èܹñ"
+msgstr "Töid ei leitud"
#: lib/Block/summary.php:222
msgid "No tasks to display"
-msgstr "\¦·é׫^XNÍ èܹñ"
+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 "ÂlpÅÈ¢"
+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ÄÌ^XN\"
+msgstr "Kõigil näidatavatel töödel"
#: config/prefs.php.dist:170
msgid "On all tasklists I have read access to"
-msgstr "ÇÝoµ Ì éSÄÌ^XN\"
+msgstr "Kõigil töödel millel on lugemis õigus"
#: config/prefs.php.dist:168
msgid "On my tasklists only"
-msgstr "Ì^XN\ÌÝ"
+msgstr "Minu töödel"
#: templates/list/task_headers.inc:39
msgid "P_ri"
-msgstr "_RDæx"
+msgstr "Pri"
#: lib/Forms/task.php:69
msgid "Parent task"
-msgstr "e^XN"
+msgstr "Ülemtöö"
#: templates/tasklists/tasklists.inc:71
msgid "Permission"
-msgstr "ANZX "
+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 "ANZXÛ³êܵ½"
+msgstr "Ligipääs keelatud"
#: lib/api.php:178
msgid "Permission denied"
-msgstr "ANZXÛ³êܵ½"
+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 "Âlp"
+msgstr "Privaatne"
#: lib/Driver.php:900
msgid "Private Task"
-msgstr "ÂlI^XN"
+msgstr "Privaatne töö"
#: templates/view/task.inc:12 lib/Forms/task.php:82
msgid "Private?"
-msgstr "ÂlpH"
+msgstr "Privaatne?"
#: view.php:106
msgid "Really delete this task?"
-msgstr "±Ì^XNð{ÉíµÄàǢŷ©H"
+msgstr "Kindel et tahad kustutada selle töö?"
#: templates/tasklists/tasklists.inc:81
msgid "Remote Subscription URL"
-msgstr "uwÇ 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 "^XN\ð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 "^XN\ðIÑAuwÇ 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 "^XN\ðIÑ URL ð\¦³¹Äº³¢"
+msgstr "Vali tööde nimekiri ülevalt et näha URLi"
#: templates/data/export.inc:11
msgid "Select the export format:"
-msgstr "GNX|[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^XN\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 "^XNêÅ^XN\̼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 "®¹µ½^XNA¢®Ì^XNÈÇSÄÌ^XNð\¦µÜ·©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 "¼ÌAvP[VÌf[^à^XN\É\¦µÜ·©H"
+msgstr "Näita andmeid järgmistest allikatest?"
#: config/prefs.php.dist:58
msgid "Show data from other applications or sources."
-msgstr "¼ÌAvP[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 "^XN\ÌIvVð\¦µÜ·©H"
+msgstr "Näita seadistamise paneeli?"
#: lib/Block/summary.php:51
msgid "Show tasklist name?"
-msgstr "^XN\̼Oð\¦µÜ·©H"
+msgstr "Näita tööde nimekirja nime?"
#: lib/Block/summary.php:70
msgid "Show tasks from these categories"
-msgstr "±êç̪ÞÌ^XNð\¦"
+msgstr "Näita töid nendest kategooriatest"
#: lib/Block/summary.php:66
msgid "Show tasks from these tasklists"
-msgstr "±êçÌ^XN\Ì^XNð\¦"
+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 "^XNÌÀÑF"
+msgstr "Sorteeri tööd:"
#: data.php:56
msgid "Start"
-msgstr "Jn"
+msgstr "Algus"
#: templates/view/task.inc:18
msgid "Start Date"
-msgstr "Jnú"
+msgstr "Algus aeg"
#: lib/UI/VarRenderer/nag.php:50
msgid "Start date specified."
-msgstr "Jnúªwè³êܵ½B"
+msgstr "Algus aeg määratud."
#: templates/list/task_summaries.inc:57
msgid "Task Alarm"
-msgstr "^XNA["
+msgstr "Töö teavitus"
#: templates/list/task_headers.inc:48
msgid "Task Alarm?"
-msgstr "^XNA[H"
+msgstr "Töö teavitus?"
#: config/prefs.php.dist:28
msgid "Task Defaults"
-msgstr "^XNftHg"
+msgstr "Töö vaike seaded"
#: lib/Forms/task.php:65
msgid "Task List"
-msgstr "^XN\"
+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 "^XN\ƤLÌIvV"
+msgstr "Tööde nimekiri ja jagamise seaded"
-#: tasklists.php:117
+#: tasklists.php:119
msgid "Task Lists"
-msgstr "^XN\"
+msgstr "Tööde nimekiri"
#: config/prefs.php.dist:89 config/prefs.php.dist:104
msgid "Task Name"
-msgstr "^XN¼"
+msgstr "Töö nimi"
#: templates/list/task_summaries.inc:55
msgid "Task Note"
-msgstr "^XNm[g"
+msgstr "Töö märkmed"
#: templates/list/task_headers.inc:47
msgid "Task Note?"
-msgstr "^XNm[gH"
+msgstr "Töö märge?"
#: templates/search/search.inc:6
msgid "Task Search"
-msgstr "^XNõ"
+msgstr "Töö otsing"
#: lib/Nag.php:630
msgid "Task added:"
-msgstr "ÇÁ³ê½^XNF"
+msgstr "Töö lisatud:"
#: lib/Nag.php:640
msgid "Task deleted:"
-msgstr "í³ê½^XNF"
+msgstr "Töö kustutatud:"
-#: tasklists.php:32
+#: tasklists.php:34
msgid "Task lists must have a name."
-msgstr "^XN\ɼOªKvÅ·B"
+msgstr "Töö nimekirjal peab olema nimi."
#: lib/Nag.php:635
msgid "Task modified:"
-msgstr "XVúF"
+msgstr "Töö muudetud:"
#: task.php:88 view.php:44
msgid "Task not found."
-msgstr "^XNª©t©èܹñB"
+msgstr "Tööd ei leitud."
#: config/prefs.php.dist:93 config/prefs.php.dist:108
msgid "Tasklist"
-msgstr "^XN\"
+msgstr "Tööde nimekiri"
#: templates/panel.inc:30 templates/panel.inc:31
#: templates/tasklists/tasklists.inc:58
msgid "Tasklists"
-msgstr "^XN\"
+msgstr "Tööde nimekirjad"
#: templates/tasklists/tasklists.inc:60
msgid "Tasklists:"
-msgstr "^XN\F"
+msgstr "Tööde nimekirjad:"
#: lib/api.php:1041
msgid "Tasks"
-msgstr "^XN"
+msgstr "Tööd"
#: lib/Block/summary.php:3
msgid "Tasks Summary"
-msgstr "^XNTv"
+msgstr "Tööde kokkuvõte"
#: data.php:193
#, php-format
msgid "The %s file didn't contain any tasks."
-msgstr "t@C %s ÉÍ^XNÍêÂàÜÜêĢܹñB"
+msgstr "Fail %s ei sisaldanud ühtki tööd."
#: lib/Driver.php:56
msgid "The Tasks backend is not currently available."
-msgstr "^XNÌobNGhÍ»ÝgpūܹñB"
+msgstr "Tööde alusrakendus ei ole saadaval."
#: lib/Driver.php:137
#, php-format
msgid "The Tasks backend is not currently available: %s"
-msgstr "^XNÌobNGhÍ»Ýgpūܹñ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 "^XN \"%s\" Í^XN\ \"%s\" ÉÇÁ³êܵ½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 "^XN \"%s\" Í^XN\ \"%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 "^XN \"%s\" Í^XN\ \"%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 "^XN\ \"%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 "^XN\ \"%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 "^XN\ \"%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 "^XN\ \"%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 "^XN\ \"%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·é^XNÍ èܹñ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 "^XNðÛ¶Éâèª èܵ½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 "GNX|[g·é^XNª èܹñ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 ""
-"^XNÌúúÉ¢ÄÈºÌæ¤Éã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 "ftHgÌúúÔð½ÉµÜ·©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^XNðìéAftHgÌúúð½úãɵܷ©i0Í¡újH"
+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^XNðìéAftHgÅúú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 "ÇÌ^XN\ÉÇÁµÜ·©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 ÈãÌ^XNðì¬Å«Ü¹ñB"
+msgstr "Pole lubatud luua rohkem kui %d tööd."
#: view.php:52
msgid "You do not have permission to view this tasklist."
-msgstr " ȽÉͱÌ^XN\ð\¦·é Àª èܹñ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 "í·é׫^XN\ð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 "í·é׫^XN\ð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 ""
-" È½Í È½Ì^XN\É^XNªÇÁ³ê½ÉÊ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 ""
-" È½Í È½Ì^XN\©ç^XNªí³ê½ÉÊ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 ""
-" È½Í È½Ì^XN\Ì^XNªÏX³ê½ÉÊm·é±ÆðvµÜµ½B"
+msgstr "Te soovisite teavitust kui tööde nimekirja muudetakse."
#: templates/prefs/tasklistselect.inc:10
msgid "Your default task list:"
-msgstr "ftHgÌ^XN\F"
+msgstr "Sinu vaike tööde nimekiri:"
#: templates/panel.inc:43
msgid "[Manage My Tasklists]"
-msgstr "[Ì^XN\ÌÇ]"
+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 "_AS^XN"
+msgstr "_Kõik tööd"
#: list.php:111
msgid "_All tasks"
-msgstr "_AS^XN"
+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®¹^XN"
+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¡ãÌ^XN"
+msgstr "Tu_leviku tööd"
#: lib/Nag.php:553
msgid "_Import/Export"
-msgstr "_IC/AEg"
+msgstr "_Import/Eksport"
#: lib/Nag.php:540
msgid "_List Tasks"
-msgstr "_L^XNê"
+msgstr "_Nimekiri"
#: lib/Nag.php:545
msgid "_New Task"
-msgstr "_NV^XN"
+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^XN\"
+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