[pkg-horde] [SCM] Debian Horde Packages repository: turba2 package branch, debian-sid, updated. cf7c7f7d40b5a0dfe7b9c7ae50cb1cf0484683e0
Gregory Colpart
reg at foulademer.gcolpart.com
Sun Apr 26 18:22:13 UTC 2009
The following commit has been merged in the debian-sid branch:
commit 07c353451974be25e9127d5e7211c2eef902db3f
Author: Gregory Colpart <reg at foulademer.gcolpart.com>
Date: Sun Apr 26 19:32:17 2009 +0200
Merge from upstream
diff --git a/bug5476.phpt b/bug5476.phpt
deleted file mode 100644
index 9a6177a..0000000
--- a/bug5476.phpt
+++ /dev/null
@@ -1,264 +0,0 @@
---TEST--
-[Bug #5476] Possibly invalid VBook search criteria
---FILE--
-<?php
-// Pretend that we are turba
-class Registry {
- function getApp()
- {
- return 'turba';
- }
- function get()
- {
- return 'turba';
- }
-}
-$registry = new Registry;
-
-// Set a dummy server name
-$_SERVER['SERVER_NAME'] = 'localhost';
-
-// Indicate that we want the dummy IMAP driver
-$GLOBALS['KOLAB_TESTING'] = array(
- "INBOX/Contacts" => array(
- "status" => array(
- "uidvalidity" => 1205144313,
- "uidnext" => 1
- ),
- "mails" => array(),
- "permissions" => array(
- "wrobel at dev.pardus.de" => "alriswcd"
- ),
- "annotations" => array(
- "/vendor/kolab/folder-type" => array(
- "value.shared" => "contact.default"
- ),
- ),
- ),
- "INBOX/test2" => array(
- "status" => array(
- "uidvalidity" => 1205144313,
- "uidnext" => 1
- ),
- "mails" => array(),
- "permissions" => array(
- "wrobel at dev.pardus.de" => "alriswcd"
- ),
- "annotations" => array(
- "/vendor/kolab/folder-type" => array(
- "value.shared" => "contact"
- ),
- "/vendor/horde/share-params" => array(
- "value.shared" => "YTozOntzOjQ6InR5cGUiO3M6NToidmJvb2siO3M6Njoic291cmNlIjtzOjIwOiJ3cm9iZWxAZGV2LnBhcmR1cy5kZSI7czo4OiJjcml0ZXJpYSI7YToxOntzOjk6ImZpcnN0bmFtZSI7czo1OiJ0ZXN0MiI7fX0="
- ),
- ),
- ),
-);
-
-// We need the basic PEAR library
-require_once 'PEAR.php';
-require_once 'Horde/Auth.php';
-require_once 'Horde/Perms.php';
-require_once 'Horde/Share.php';
-require_once 'Horde/Kolab.php';
-
-session_start();
-$_SESSION['__auth']['userId'] = 'wrobel at dev.pardus.de';
-$_SESSION['__auth']['authenticated'] = true;
-
-// Find the base file path of Turba.
-if (!defined('TURBA_BASE')) {
- define('TURBA_BASE', dirname(__FILE__) . '/../..');
-}
-
-// Turba base libraries.
-require_once TURBA_BASE . '/lib/Turba.php';
-require_once TURBA_BASE . '/lib/Driver.php';
-require_once TURBA_BASE . '/lib/Object.php';
-
-$cfgSources = array();
-
- $cfgSources['kolab'] = array(
- 'title' => _("Contacts"),
- 'type' => 'kolab',
- 'params' => array(
- 'charset' => 'utf-8',
- ),
- 'map' => array(
- '__key' => 'uid',
- '__uid' => 'uid',
- /* Personal */
- 'name' => array('fields' => array('firstname', 'middlenames', 'lastname'),
- 'format' => '%s %s %s',
- 'attribute' => 'full-name'),
- 'firstname' => 'given-name',
- 'lastname' => 'last-name',
- 'middlenames' => 'middle-names',
- 'namePrefix' => 'prefix',
- 'nameSuffix' => 'suffix',
- 'initials' => 'initials',
- 'nickname' => 'nick-name',
- 'gender' => 'gender',
- 'birthday' => 'birthday',
- 'spouse' => 'spouse-name',
- 'anniversary' => 'anniversary',
- 'children' => 'children',
- /* Location */
- 'workStreet' => 'addr-business-street',
- 'workCity' => 'addr-business-locality',
- 'workProvince' => 'addr-business-region',
- 'workPostalCode' => 'addr-business-postal-code',
- 'workCountry' => 'addr-business-country',
- 'homeStreet' => 'addr-home-street',
- 'homeCity' => 'addr-home-locality',
- 'homeProvince' => 'addr-home-region',
- 'homePostalCode' => 'addr-home-postal-code',
- 'homeCountry' => 'addr-home-country',
- /* Communications */
- 'emails' => 'emails',
- 'homePhone' => 'phone-home1',
- 'workPhone' => 'phone-business1',
- 'cellPhone' => 'phone-mobile',
- 'fax' => 'phone-businessfax',
- 'instantMessenger' => 'im-address',
- /* Organization */
- 'title' => 'job-title',
- 'role' => 'profession',
- 'company' => 'organization',
- 'department' => 'department',
- 'office' => 'office-location',
- 'manager' => 'manager-name',
- 'assistant' => 'assistant',
- /* Other */
- 'category' => 'categories',
- 'notes' => 'body',
- 'website' => 'web-page',
- 'freebusyUrl' => 'free-busy-url',
- 'language' => 'language',
- 'latitude' => 'latitude',
- 'longitude' => 'longitude',
- ),
- 'tabs' => array(
- _("Personal") => array('name', 'firstname', 'lastname', 'middlenames',
- 'namePrefix', 'nameSuffix', 'initials', 'nickname',
- 'gender', 'birthday', 'spouse', 'anniversary',
- 'children'),
- _("Location") => array('homeStreet', 'homeCity', 'homeProvince',
- 'homePostalCode', 'homeCountry', 'workStreet',
- 'workCity', 'workProvince', 'workPostalCode',
- 'workCountry'),
- _("Communications") => array('emails', 'homePhone', 'workPhone',
- 'cellPhone', 'fax', 'instantMessenger'),
- _("Organization") => array('title', 'role', 'company', 'department',
- 'office', 'manager', 'assistant'),
- _("Other") => array('category', 'notes', 'website', 'freebusyUrl',
- 'language', 'latitude', 'longitude'),
- ),
- 'search' => array(
- /* Personal */
- 'firstname',
- 'lastname',
- 'middlenames',
- 'namePrefix',
- 'nameSuffix',
- 'initials',
- 'nickname',
- 'gender',
- 'birthday',
- 'spouse',
- 'anniversary',
- 'children',
- /* Location */
- 'workStreet',
- 'workCity',
- 'workProvince',
- 'workPostalCode',
- 'workCountry',
- 'homeStreet',
- 'homeCity',
- 'homeProvince',
- 'homePostalCode',
- 'homeCountry',
- /* Communications */
- 'emails',
- 'homePhone',
- 'workPhone',
- 'cellPhone',
- 'fax',
- 'instantMessenger',
- /* Organization */
- 'title',
- 'role',
- 'company',
- 'department',
- 'office',
- 'manager',
- 'assistant',
- /* Other */
- 'category',
- 'notes',
- 'website',
- 'language',
- ),
- 'strict' => array(
- 'uid',
- ),
- 'export' => true,
- 'browse' => true,
- 'use_shares' => true,
- 'shares_only' => true,
- );
-
-
-/* Pretend that we are kronolith */
-$kolab = &new Kolab('turba');
-
-/* Open our calendar */
-$kolab->open('INBOX/Contacts', 1);
-
-$object = array(
- 'uid' => 1,
- 'given-name' => 'test',
- 'last-name' => 'test',
- 'full-name' => 'test test',
-);
-
-// Save the contact
-$kolab->_storage->save($object);
-
-$object = array(
- 'uid' => 2,
- 'given-name' => 'test2',
- 'last-name' => 'test2',
- 'full-name' => 'test2 test2',
-);
-
-// Save the contact
-$kolab->_storage->save($object);
-
-$GLOBALS['conf']['log']['enabled'] = false;
-$GLOBALS['conf']['prefs']['driver'] = 'session';
-$GLOBALS['conf']['share']['driver'] = 'kolab';
-$GLOBALS['conf']['kolab']['enabled'] = true;
-$GLOBALS['conf']['kolab']['imap']['server'] = 'localhost';
-$GLOBALS['conf']['kolab']['imap']['port'] = 0;
-$GLOBALS['perms'] = &Perms::singleton();
-$_SESSION['turba']['has_share'] = true;
-$GLOBALS['turba_shares'] = &Horde_Share::singleton($registry->getApp());
-
-$GLOBALS['cfgSources'] = Turba::getConfigFromShares($cfgSources);
-
-// Check that the driver can be created
-$turba = Turba_Driver::singleton('wrobel at dev.pardus.de');
-$result = $turba->search(array(), array('last-name'));
-
-var_dump($result->count());
-
-$turba = Turba_Driver::singleton('INBOX%2Ftest2');
-$result = $turba->search(array(), array('last-name'));
-
-var_dump($result->count());
-
---EXPECT--
-int(2)
-int(0)
diff --git a/config/attributes.php.dist b/config/attributes.php.dist
index 9532ed1..e2f58a8 100644
--- a/config/attributes.php.dist
+++ b/config/attributes.php.dist
@@ -39,7 +39,7 @@
* http://wiki.horde.org/Doc/Dev/FormTypes.
* </pre>
*
- * $Horde: turba/config/attributes.php.dist,v 1.36.6.10 2008/05/09 22:34:47 jan Exp $
+ * $Horde: turba/config/attributes.php.dist,v 1.36.6.18 2008/11/12 06:29:26 wrobel Exp $
*/
/* Personal stuff. */
@@ -95,13 +95,13 @@ $attributes['birthday'] = array(
'label' => _("Birthday"),
'type' => 'monthdayyear',
'required' => false,
- 'params' => array('start_year' => 1900, 'end_year' => null, 'picker' => true, 'format_in' => '%Y-%m-%d', 'format_out' => '%x'),
+ 'params' => array('start_year' => 1900, 'end_year' => null, 'picker' => true, 'format_in' => '%Y-%m-%d', 'format_out' => $GLOBALS['prefs']->getValue('date_format')),
'time_object_label' => _("Birthdays"),
);
$attributes['anniversary'] = array(
'label' => _("Anniversary"),
'type' => 'monthdayyear',
- 'params' => array('start_year' => 1900, 'end_year' => null, 'picker' => true, 'format_in' => '%Y-%m-%d', 'format_out' => '%x'),
+ 'params' => array('start_year' => 1900, 'end_year' => null, 'picker' => true, 'format_in' => '%Y-%m-%d', 'format_out' => $GLOBALS['prefs']->getValue('date_format')),
'required' => false,
'time_object_label' => _("Anniversaries"),
);
@@ -117,6 +117,18 @@ $attributes['children'] = array(
'required' => false,
'params' => array('regex' => '', 'size' => 40, 'maxlength' => 255)
);
+$attributes['photo'] = array(
+ 'label' => _("Photo"),
+ 'type' => 'image',
+ 'required' => false,
+ 'params' => array('show_upload' => true, 'show_keeporig' => true, 'max_filesize' => null),
+);
+$attributes['phototype'] = array(
+ 'label' => _("Photo MIME Type"),
+ 'type' => 'text',
+ 'required' => false,
+ 'params' => array('regex' => '', 'size' => 40, 'maxlength' => 255)
+);
/* Locations, addresses. */
$attributes['homeAddress'] = array(
@@ -308,6 +320,18 @@ $attributes['office'] = array(
'required' => false,
'params' => array('regex' => '', 'size' => 40, 'maxlength' => 255)
);
+$attributes['logo'] = array(
+ 'label' => _("Logo"),
+ 'type' => 'image',
+ 'required' => false,
+ 'params' => array('show_upload' => true, 'show_keeporig' => true, 'max_filesize' => null),
+);
+$attributes['logotype'] = array(
+ 'label' => _("Logo MIME Type"),
+ 'type' => 'text',
+ 'required' => false,
+ 'params' => array('regex' => '', 'size' => 40, 'maxlength' => 255)
+);
/* Other */
$attributes['notes'] = array(
@@ -340,6 +364,20 @@ $attributes['smimePublicKey'] = array(
'required' => false,
'params' => array('rows' => 3, 'cols' => 40)
);
+/* If using Horde 3.3 or later, you can enable the following attributes to
+ * enable pretty rendering of PGP and S/MIME keys. */
+// $attributes['pgpPublicKey'] = array(
+// 'label' => _("PGP Public Key"),
+// 'type' => 'pgp',
+// 'required' => false,
+// 'params' => array('gpg' => '/usr/bin/gpg', 'temp_dir' => Horde::getTempDir(), 'rows' => 3, 'cols' => 40)
+// );
+// $attributes['smimePublicKey'] = array(
+// 'label' => _("S/MIME Public Certificate"),
+// 'type' => 'smime',
+// 'required' => false,
+// 'params' => array('temp_dir' => Horde::getTempDir(), 'rows' => 3, 'cols' => 40)
+// );
/* This attribute uses Horde's categories and is an example how to use an enum
* field. Don't forget to add a 'map' entry to config/sources.php if you want
* to use this attribute. */
@@ -354,8 +392,22 @@ $attributes['category'] = array(
'prompt' => false),
'required' => false
);
+/* If using Horde 3.2 or later, you can use the following category attribute
+ * instead which shows category colors and allows to add new categories. */
+// $attributes['category'] = array(
+// 'label' => _("Category"),
+// 'type' => 'category',
+// 'params' => array(),
+// 'required' => false
+// );
/* Additional attributes supported by Kolab */
+$attributes['kolabHomeServer'] = array(
+ 'label' => _("Kolab Home Server"),
+ 'type' => 'text',
+ 'required' => false,
+ 'params' => array('regex' => '', 'size' => 40, 'maxlength' => 255)
+);
$attributes['initials'] = array(
'label' => _("Initials"),
'type' => 'text',
diff --git a/config/conf.xml b/config/conf.xml
index 8eaaf4a..b7a80b8 100644
--- a/config/conf.xml
+++ b/config/conf.xml
@@ -1,10 +1,12 @@
<?xml version="1.0"?>
-<!-- $Horde: turba/config/conf.xml,v 1.6.2.5 2008/05/06 21:26:59 bklang Exp $ -->
+<!-- $Horde: turba/config/conf.xml,v 1.6.2.6 2008/06/25 15:52:54 jan Exp $ -->
<configuration>
<configsection name="menu">
<configheader>Menu Settings</configheader>
- <configboolean name="import_export" desc="Should we display an Import/Export link in Turba's menu?">true</configboolean>
- <configmultienum name="apps" desc="Select any applications that should be linked in Turba's menu">
+ <configboolean name="import_export" desc="Should we display an Import/Export
+ link in Turba's menu?">true</configboolean>
+ <configmultienum name="apps" desc="Select any applications that should be
+ linked in Turba's menu">
<values>
<configspecial name="list-horde-apps"/>
</values>
@@ -13,20 +15,23 @@
<configsection name="client">
<configheader>Clients</configheader>
- <configstring name="addressbook" desc="Name of client addressbook. Must not be configured for shares.">localsql</configstring>
+ <configstring name="addressbook" desc="Name of client addressbook. If this
+ is a shared address book, use the share id, not the source
+ name.">localsql</configstring>
</configsection>
<configsection name="shares">
- <configheader>Shares</configheader>
- <configstring name="source" desc="Name of source for creating new shares.<br />
- Note that leaving this blank will prevent users from being able to create
- new address books."
- required="false">localsql</configstring>
+ <configheader>Shares</configheader>
+ <configstring name="source" desc="Name of source for creating new
+ shares.<br /> Note that leaving this blank will prevent users from
+ being able to create new address books."
+ required="false">localsql</configstring>
</configsection>
<configsection name="comments">
<configheader>Comments</configheader>
- <configboolean name="allow" desc="Can users comment on contacts?">true</configboolean>
+ <configboolean name="allow" desc="Can users comment on
+ contacts?">true</configboolean>
</configsection>
<configsection name="documents">
diff --git a/config/prefs.php.dist b/config/prefs.php.dist
index 282d4f1..2f7c7c3 100644
--- a/config/prefs.php.dist
+++ b/config/prefs.php.dist
@@ -1,6 +1,6 @@
<?php
/**
- * $Horde: turba/config/prefs.php.dist,v 1.28.10.9 2008/06/13 14:44:04 jan Exp $
+ * $Horde: turba/config/prefs.php.dist,v 1.28.10.10 2008/07/10 22:52:41 jan Exp $
*
* See horde/config/prefs.php for documentation on the structure of this file.
*/
@@ -153,3 +153,12 @@ $_prefs['turba_maintenance_tasks'] = array(
'shared' => false,
'type' => 'implicit'
);
+
+// Personal contact.
+$_prefs['own_contact'] = array(
+ // The format is 'source_name;contact_id'.
+ 'value' => '',
+ 'locked' => false,
+ 'shared' => false,
+ 'type' => 'implicit'
+);
diff --git a/config/sources.php.dist b/config/sources.php.dist
index 88ac1c5..bc0bf1d 100644
--- a/config/sources.php.dist
+++ b/config/sources.php.dist
@@ -1,6 +1,6 @@
<?php
/**
- * $Horde: turba/config/sources.php.dist,v 1.97.6.29 2008/04/24 12:14:29 wrobel Exp $
+ * $Horde: turba/config/sources.php.dist,v 1.97.6.38 2008/11/12 06:29:26 wrobel Exp $
*
* This file is where you specify the sources of contacts available to users
* at your installation. It contains a large number of EXAMPLES. Please
@@ -142,10 +142,15 @@
* will still be enforced. Also note that the backend driver
* must have support for using this. Currently SQL and IMSP.
*
- * list_name_field: If this is present and non-empty, it will be taken as the
- * name of the turba field to store contact list names in.
- * This is required when using a composite field as the 'name'
- * field.
+ * list_name_field: If this is present and non-empty, it will be taken as the
+ * field to store contact list names in.
+ * This is required when using a composite field as the 'name'
+ * field.
+ *
+ * alternative_name: If this is present and non-empty, it will be taken as the
+ * field to use an alternative in case that the name field is
+ * empty.
+ *
* Here are some example configurations:
*/
@@ -195,6 +200,10 @@ $cfgSources['localsql'] = array(
// 'format' => '%s %s'),
'alias' => 'object_alias',
'birthday' => 'object_bday',
+ // The photo field requires at least Horde 3.3 and a matching type
+ // field.
+ // 'photo' => 'object_photo',
+ // 'phototype' => 'object_phototype',
'homeStreet' => 'object_homestreet',
'homePOBox' => 'object_homepob',
'homeCity' => 'object_homecity',
@@ -204,10 +213,10 @@ $cfgSources['localsql'] = array(
// This is an example composite field for addresses, so you can display
// the various map links. If you use this, be sure to add 'homeAddress'
// to the 'tabs' parameter below.
- //'homeAddress' => array('fields' => array('homeStreet', 'homeCity',
- // 'homeProvince',
- // 'homePostalCode'),
- // 'format' => "%s \n %s, %s %s"),
+ // 'homeAddress' => array('fields' => array('homeStreet', 'homeCity',
+ // 'homeProvince',
+ // 'homePostalCode'),
+ // 'format' => "%s \n %s, %s %s"),
'workStreet' => 'object_workstreet',
'workPOBox' => 'object_workpob',
'workCity' => 'object_workcity',
@@ -224,6 +233,10 @@ $cfgSources['localsql'] = array(
'title' => 'object_title',
'role' => 'object_role',
'company' => 'object_company',
+ // The logo field requires at least Horde 3.3 and a matching type
+ // field.
+ // 'logo' => 'object_logo',
+ // 'logotype' => 'object_logotype',
'category' => 'object_category',
'notes' => 'object_notes',
'website' => 'object_url',
@@ -234,7 +247,7 @@ $cfgSources['localsql'] = array(
'tabs' => array(
_("Personal") => array('firstname', 'lastname', 'middlenames',
'namePrefix', 'nameSuffix', 'name', 'alias',
- 'birthday'),
+ 'birthday', 'photo'),
_("Location") => array('homeStreet', 'homePOBox', 'homeCity',
'homeProvince', 'homePostalCode', 'homeCountry',
'workStreet', 'workPOBox', 'workCity',
@@ -242,7 +255,7 @@ $cfgSources['localsql'] = array(
'timezone'),
_("Communications") => array('email', 'homePhone', 'workPhone',
'cellPhone', 'fax', 'pager'),
- _("Organization") => array('title', 'role', 'company'),
+ _("Organization") => array('title', 'role', 'company', 'logo'),
_("Other") => array('category', 'notes', 'website', 'freebusyUrl',
'pgpPublicKey', 'smimePublicKey'),
),
@@ -259,6 +272,7 @@ $cfgSources['localsql'] = array(
'browse' => true,
'use_shares' => true,
'list_name_field' => 'lastname',
+ 'alternative_name' => 'company',
);
/**
@@ -288,9 +302,10 @@ $cfgSources['localsql'] = array(
// 'organizationalPerson',
// 'inetOrgPerson'),
// // Add 'turbaContact' to this array if using
-// // 'turbaType' attribute below
+// // 'turbaType' attribute below, and 'calEntry'
+// // if using 'freebusyUrl'.
// 'scope' => 'one',
-// 'charset' => 'iso-8859-1',
+// 'charset' => 'utf-8',
// // Consult the LDAP schema to verify that all required attributes for
// // an entry are set and add them if needed.
// 'checkrequired' => false,
@@ -309,7 +324,7 @@ $cfgSources['localsql'] = array(
// // From horde.schema. Make sure you have 'turbaContact' objectClass
// // included above:
// // '__type' => 'turbaType',
-// // '__members' => 'turbaMembers'
+// // '__members' => 'turbaMembers',
//
// 'name' => 'cn',
// 'email' => 'mail',
@@ -364,7 +379,7 @@ $cfgSources['localsql'] = array(
// 'root' => 'ou=' . $_ldap_uid . ',ou=personal_addressbook,' . $_ldap_basedn,
// 'bind_dn' => 'uid=' . $_ldap_uid . ',ou=People,' . $_ldap_basedn,
// 'bind_password' => Auth::getCredential('password'),
-// 'dn' => array('cn', 'uid'),
+// 'dn' => array('uid'),
// 'objectclass' => array('top',
// 'person',
// // 'turbaContact',
@@ -381,7 +396,7 @@ $cfgSources['localsql'] = array(
//
// // From horde.schema:
// // '__type' => 'turbaType',
-// // '__members' => 'turbaMembers'
+// // '__members' => 'turbaMembers',
//
// 'name' => 'cn',
// 'email' => 'mail',
@@ -810,7 +825,9 @@ if (!empty($GLOBALS['conf']['kolab']['enabled'])) {
'cellPhone' => 'mobile',
'fax' => 'fax',
'notes' => 'description',
- 'freebusyUrl' => 'kolabHomeServer',
+ 'kolabHomeServer' => 'kolabHomeServer',
+ 'freebusyUrl' => array('fields' => array('kolabHomeServer', 'email'),
+ 'format' => 'https://%s/freebusy/%s.ifb'),
),
'search' => array(
'name',
@@ -862,7 +879,15 @@ if (!empty($GLOBALS['conf']['kolab']['enabled'])) {
/* Personal */
'name' => array('fields' => array('firstname', 'middlenames', 'lastname'),
'format' => '%s %s %s',
- 'attribute' => 'full-name'),
+ 'parse' => array(
+ array('fields' => array('firstname', 'middlenames',
+ 'lastname'),
+ 'format' => '%s %s %s'),
+ array('fields' => array( 'lastname', 'firstname'),
+ 'format' => '%s, %s'),
+ array('fields' => array('firstname', 'lastname'),
+ 'format' => '%s %s'),
+ )),
'firstname' => 'given-name',
'lastname' => 'last-name',
'middlenames' => 'middle-names',
@@ -870,6 +895,8 @@ if (!empty($GLOBALS['conf']['kolab']['enabled'])) {
'nameSuffix' => 'suffix',
'initials' => 'initials',
'nickname' => 'nick-name',
+ 'photo' => 'photo',
+ 'phototype' => 'phototype',
'gender' => 'gender',
'birthday' => 'birthday',
'spouse' => 'spouse-name',
@@ -909,11 +936,14 @@ if (!empty($GLOBALS['conf']['kolab']['enabled'])) {
'language' => 'language',
'latitude' => 'latitude',
'longitude' => 'longitude',
+ /* Invisible */
+ 'email' => 'email',
+ 'pgpPublicKey' => 'pgp-publickey',
),
'tabs' => array(
_("Personal") => array('name', 'firstname', 'lastname', 'middlenames',
'namePrefix', 'nameSuffix', 'initials', 'nickname',
- 'gender', 'birthday', 'spouse', 'anniversary',
+ 'photo', 'gender', 'birthday', 'spouse', 'anniversary',
'children'),
_("Location") => array('homeStreet', 'homeCity', 'homeProvince',
'homePostalCode', 'homeCountry', 'workStreet',
@@ -928,6 +958,7 @@ if (!empty($GLOBALS['conf']['kolab']['enabled'])) {
),
'search' => array(
/* Personal */
+ 'name',
'firstname',
'lastname',
'middlenames',
diff --git a/contact.php b/contact.php
index 7f6738c..1b43fd7 100644
--- a/contact.php
+++ b/contact.php
@@ -1,6 +1,6 @@
<?php
/**
- * $Horde: turba/contact.php,v 1.8.2.5 2008/06/13 21:48:56 chuck Exp $
+ * $Horde: turba/contact.php,v 1.8.2.6 2008/07/10 22:52:41 jan Exp $
*
* Copyright 2000-2008 The Horde Project (http://www.horde.org/)
*
@@ -51,6 +51,12 @@ if (!$contact || is_a($contact, 'PEAR_Error')) {
}
}
+// Mark this contact as the user's own?
+if ($vars->get('action') == 'mark_own') {
+ $prefs->setValue('own_contact', $source . ';' . $contact->getValue('__key'));
+ $notification->push(_("This contact has been marked as your own."), 'horde.success');
+}
+
// Are we printing?
$print_view = (bool)Util::getFormData('print');
@@ -90,6 +96,19 @@ if ($contact->hasPermission(PERMS_DELETE)) {
array('tabname' => 'DeleteContact', 'id' => 'tabDeleteContact', 'onclick' => 'return ShowTab(\'DeleteContact\');'));
}
+ at list($own_source, $own_id) = explode(';', $prefs->getValue('own_contact'));
+if ($own_source == $source && $own_id == $contact->getValue('__key')) {
+ $own_icon = ' ' . Horde::img('user.png', _("Your own contact"),
+ array('title' => _("Your own contact")),
+ $registry->getImageDir('horde'));
+ $own_link = '';
+} else {
+ $own_icon = '';
+ $own_link = '<span class="smallheader rightFloat">'
+ . Horde::link(Util::addParameter($url, array('action' => 'mark_own')))
+ . _("Mark this as your own contact") . '</a></span>';
+}
+
$title = $view->getTitle();
Horde::addScriptFile('prototype.js', 'turba', true);
Horde::addScriptFile('contact_tabs.js', 'turba', true);
@@ -103,7 +122,11 @@ echo '<div id="page">';
if (!$print_view) {
echo $tabs->render($viewName);
}
-echo '<h1 class="header">' . ($contact->getValue('name') ? htmlspecialchars($contact->getValue('name')) : '<em>' . _("Blank name") . '</em>') . '</h1>';
+echo '<h1 class="header">' . $own_link
+ . ($contact->getValue('name')
+ ? htmlspecialchars($contact->getValue('name'))
+ : '<em>' . _("Blank name") . '</em>')
+ . $own_icon . '</h1>';
$view->html();
echo '</div>';
require $registry->get('templates', 'horde') . '/common-footer.inc';
diff --git a/data.php b/data.php
index 0e62e97..d6c867d 100644
--- a/data.php
+++ b/data.php
@@ -1,6 +1,6 @@
<?php
/**
- * $Horde: turba/data.php,v 1.70.4.17 2008/06/13 08:40:03 jan Exp $
+ * $Horde: turba/data.php,v 1.70.4.20 2008/08/11 12:50:18 jan Exp $
*
* Copyright 2001-2008 The Horde Project (http://www.horde.org/)
*
@@ -42,10 +42,11 @@ function _emptyAttributeFilter($var)
* Static function to make a given email address rfc822 compliant.
*
* @param string $address An email address.
+ * @param boolean $allow_multi Allow multiple email addresses.
*
* @return string The RFC822-formatted email address.
*/
-function _getBareEmail($address)
+function _getBareEmail($address, $allow_multi = false)
{
// Empty values are still empty.
if (!$address) {
@@ -60,12 +61,26 @@ function _getBareEmail($address)
$rfc822 = new Mail_RFC822();
}
- $rfc822->validateMailbox($address);
- return MIME::rfc822WriteAddress($address->mailbox, $address->host);
+ // Split multiple email addresses
+ if ($allow_multi) {
+ $addrs = MIME::rfc822Explode($address);
+ } else {
+ $addrs = array($address);
+ }
+
+ $result = array();
+ foreach ($addrs as $addr) {
+ $addr = trim($addr);
+
+ if ($rfc822->validateMailbox($addr)) {
+ $result[] = MIME::rfc822WriteAddress($addr->mailbox, $addr->host);
+ }
+ }
+
+ return implode(', ', $result);
}
- at define('TURBA_BASE', dirname(__FILE__));
-require_once TURBA_BASE . '/lib/base.php';
+require_once dirname(__FILE__) . '/lib/base.php';
require_once 'Horde/Data.php';
if (!$conf['menu']['import_export']) {
@@ -107,6 +122,48 @@ $app_fields = array();
$time_fields = array();
$error = false;
$outlook_mapping = array(
+ 'Title' => 'namePrefix',
+ 'First Name' => 'firstname',
+ 'Middle Name' => 'middlenames',
+ 'Last Name' => 'lastname',
+ 'Nickname' => 'nickname',
+ 'Suffix' => 'nameSuffix',
+ 'Company' => 'company',
+ 'Department' => 'department',
+ 'Job Title' => 'title',
+ 'Business Street' => 'workStreet',
+ 'Business City' => 'workCity',
+ 'Business State' => 'workProvince',
+ 'Business Postal Code' => 'workPostalCode',
+ 'Business Country' => 'workCountry',
+ 'Home Street' => 'homeStreet',
+ 'Home City' => 'homeCity',
+ 'Home State' => 'homeProvince',
+ 'Home Postal Code' => 'homePostalCode',
+ 'Home Country' => 'homeCountry',
+ 'Business Fax' => 'workFax',
+ 'Business Phone' => 'workPhone',
+ 'Home Phone' => 'homePhone',
+ 'Mobile Phone' => 'cellPhone',
+ 'Pager' => 'pager',
+ 'Anniversary' => 'anniversary',
+ 'Assistant\'s Name' => 'assistant',
+ 'Birthday' => 'birthday',
+ 'Business Address PO Box' => 'workPOBox',
+ 'Categories' => 'category',
+ 'Children' => 'children',
+ 'E-mail Address' => 'email',
+ 'Home Address PO Box' => 'homePOBox',
+ 'Initials' => 'initials',
+ 'Internet Free Busy' => 'freebusyUrl',
+ 'Language' => 'language',
+ 'Notes' => 'notes',
+ 'Profession' => 'role',
+ 'Office Location' => 'office',
+ 'Spouse' => 'spouse',
+ 'Web Page' => 'website',
+);
+$import_mapping = array(
'e-mail' => 'email',
'homeaddress' => 'homeAddress',
'businessaddress' => 'workAddress',
@@ -116,10 +173,41 @@ $outlook_mapping = array(
'businessfax' => 'fax',
'jobtitle' => 'title',
'internetfreebusy' => 'freebusyUrl',
- );
+
+ // Entourage on MacOS
+ 'Dept' => 'department',
+ 'Work Street Address' => 'workStreet',
+ 'Work City' => 'workCity',
+ 'Work State' => 'workProvince',
+ 'Work Zip' => 'workPostalCode',
+ 'Work Country/Region' => 'workCountry',
+ 'Home Street Address' => 'homeStreet',
+ 'Home City' => 'homeCity',
+ 'Home State' => 'homeProvince',
+ 'Home Zip' => 'homePostalCode',
+ 'Home Country/Region' => 'homeCountry',
+ 'Work Fax' => 'workFax',
+ 'Work Phone 1' => 'workPhone',
+ 'Home Phone 1' => 'homePhone',
+ 'Instant Messaging 1' => 'instantMessenger',
+
+ // Thunderbird
+ 'Primary Email' => 'email',
+ 'Fax Number' => 'fax',
+ 'Pager Number' => 'pager',
+ 'Mobile Number' => 'Mobile Phone',
+ 'Home Address' => 'homeStreet',
+ 'Home ZipCode' => 'homePostalCode',
+ 'Work Address' => 'workStreet',
+ 'Work ZipCode' => 'workPostalCode',
+ 'Work Country' => 'workCountry',
+ 'Work Phone' => 'workPhone',
+ 'Organization' => 'company',
+ 'Web Page 1' => 'website',
+);
$param = array('time_fields' => $time_fields,
'file_types' => $file_types,
- 'import_mapping' => $outlook_mapping);
+ 'import_mapping' => array_merge($outlook_mapping, $import_mapping));
$import_format = Util::getFormData('import_format', '');
if ($import_format == 'mulberry' || $import_format == 'pine') {
$import_format = 'tsv';
@@ -364,12 +452,15 @@ if (is_array($next_step)) {
} elseif ($result->count()) {
$result->reset();
$object = $result->next();
- $notification->push(sprintf(_("\"%s\" already exists and was not imported."), $object->getValue('name')), 'horde.message');
+ $notification->push(sprintf(_("\"%s\" already exists and was not imported."),
+ $object->getValue('name')), 'horde.message');
} else {
/* Check for, and validate, any email fields */
foreach (array_keys($row) as $field) {
if ($attributes[$field]['type'] == 'email') {
- $row[$field] = _getBareEmail($row[$field]);
+ $allow_multi = is_array($attributes[$field]['params']) &&
+ !empty($attributes[$field]['params']['allow_multi']);
+ $row[$field] = _getBareEmail($row[$field], $allow_multi);
}
}
$row['__owner'] = $driver->getContactOwner();
diff --git a/docs/CHANGES b/docs/CHANGES
index 8cf6776..a8a3a27 100644
--- a/docs/CHANGES
+++ b/docs/CHANGES
@@ -1,4 +1,76 @@
------
+v2.3.1
+------
+
+[jan] SECURITY: Escape output in test.php.
+[jan] Add script to import contacts from SquirrelMail database.
+[gwr] Correct support for the freebusy URL in Kolab.
+[gwr] Add photo support for the Kolab driver.
+[jan] Import broken vCards from Synthesis clients (Bug #7407).
+[cjh] Add two retries to find a contact after adding it (Bug #7478).
+[cjh] Add a PostgreSQL-specific upgrade script for 2.2.1 to 2.3
+ (michael.menge at zdv.uni-tuebingen.de, Bug #7462).
+[jan] Don't overwrite empty address books preference when creating new shares
+ (Bug #7399).
+[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] Fix exporting address books with country fields as vCards (Bug #7372).
+[mjr] Make sure we use all address books when searching via the api and the
+ user's addressbooks pref is empty (Bug #7357).
+[mjr] Correctly calculate the age of time objects (Bug #7330).
+
+
+--------
+v2.3-RC1
+--------
+
+[jan] Improve vCard EMAIL field parsing (Bug #7281).
+[jan] Correctly import and export address extensions (Bug #7279).
+[jan] Export full country names to vCard addresses.
+[jan] Respect precedence of multiple vCard properties (Request #7122).
+[jan] Remove deleted address books from address book preference (Request #6938).
+[jan] Export LABEL properties to vCard if address fields are available.
+[gwr] Add support for storing public PGP keys when using Kolab.
+[gwr] Add support for adding addresses from IMP when using Kolab.
+[jan] Add configuration option for an alternative name field.
+[jan] Add support for image fields to SQL driver (requires Horde 3.3).
+[jan] Add more default field mappings for CSV import (Request #6901).
+[jan] Update field names for Outlook 2003 export (Request #6901).
+[jan] Improve logic which entries to show in the sidebar menu.
+[jan] Add support for the category form field (Request #6884).
+[jan] Fix sorting so that sort order is always reflected correctly,
+ independent of name format.
+[jan] Add Basque translation (Euskal Herriko Unibertsitatea EHU/UPV
+ <xabier.arrieta at ehu.es>).
+[jan] Add ability to mark a contact as your own and API method to export it.
+[jan] Fix importing phone numbers from Synthesis clients (Bug #7011).
+[mjr] Fix issue with searching composite fields when the number of search terms
+ is less than the number of composed fields (Bug #6796)
+[cjh] Allow importing multiple address into an email field if allow_multi
+ is set to true on the field in attributes.php (Bug #6897).
+[mjr] Remove user permissions on all shares when deleting a user.
+[jan] Fix searching of client address books that have been disabled in the
+ preferences (Bug #6961).
+[mjr] Fix issue with removeUserData api that caused the deleted user's
+ address books to not be deleted as well as remove an erroneous error
+ notification (Bug #6969).
+[cjh] Fix the column selector/sorter in IE (Bug #6912).
+
+
+------
+v2.2.2
+------
+
+[jan] SECURITY: Escape output in test.php.
+
+
+------
v2.2.1
------
diff --git a/docs/CREDITS b/docs/CREDITS
index d8ef2d1..c56d36b 100644
--- a/docs/CREDITS
+++ b/docs/CREDITS
@@ -8,6 +8,7 @@ Core Developers
- Chuck Hagenbuch <chuck at horde.org>
- Jan Schneider <jan at horde.org>
+- Michael J. Rubinsky <mrubinsk at horde.org>
Localization
@@ -15,8 +16,11 @@ Localization
===================== ======================================================
Arabic (Syria) Platinum Development Team <devteam at platinum-sy.net>
+Basque Euskal Herriko Unibertsitatea <xabier.arrieta at ehu.es>
Brazilian Portuguese Carlos Daniel Kibrit <kibrit at terra.com.br>
Fabio Gomes <flgoms at uol.com.br>
+ Luis Felipe Marzagao <duli at fedoraproject.org>
+ Eduardo de Carli <carliedu at ig.com.br>
Bulgarian Miroslav Pendev <pendev at hotmail.com>
Catalan Angels Guimerà <angels.Guimera at uab.es>
Jordi Giralt <projecte.k2 at upcnet.es>
@@ -30,6 +34,7 @@ Danish Martin List-Petersen <martin at list-petersen.dk>
Dutch Jan Kuipers <jrkuipers at lauwerscollege.nl>
Han Spruyt <han.spruyt at ijsselgroep.nl>
Estonian Toomas Aas <toomas.aas at raad.tartu.ee>
+ Alar Sing <alar.sing at err.ee>
Finnish Leena Heino <liinu at uta.fi>
French Sam Przyswa <samp at arial-concept.com>
Ronnie Garcia <ronnie at mk2.net>
diff --git a/docs/INSTALL b/docs/INSTALL
index e9596f7..7c9bd35 100644
--- a/docs/INSTALL
+++ b/docs/INSTALL
@@ -1,9 +1,9 @@
======================
- Installing Turba 2.2
+ Installing Turba 2.3
======================
-:Last update: $Date: 2007/12/20 14:34:25 $
-:Revision: $Revision: 1.10.10.6 $
+:Last update: $Date: 2008/09/05 14:09:08 $
+:Revision: $Revision: 1.10.10.7 $
:Contact: turba at lists.horde.org
.. contents:: Contents
diff --git a/docs/RELEASE_NOTES b/docs/RELEASE_NOTES
index a0fe244..6c08eb8 100644
--- a/docs/RELEASE_NOTES
+++ b/docs/RELEASE_NOTES
@@ -17,27 +17,32 @@ $this->notes['fm']['focus'] = 8;
/* Mailing list release notes. */
$this->notes['ml']['changes'] = <<<ML
The Horde Team is pleased to announce the final release of the Turba Contact
-Manager version H3 (2.2.1).
+Manager version H3 (2.3.1). The original release was packaged with the wrong
+name; this second release of 2.3.1 has no changes to the package or the code,
+only to the version name.
-This is a bugfix release that also fixes an XSS (cross site scripting)
-vulnerability in the contact view.
+This is a minor security release that fixes unescaped output in the test
+script. All users are encouraged to upgrade to this release. In addition all
+users are encouraged to disable test.php in production, per the install
+documentation.
Turba is the Horde contact management application. It is a production level
address book, and makes heavy use of the Horde framework to provide
integration with IMP and other Horde applications. It supports SQL, LDAP,
Kolab, and IMSP address books.
-Major new changes in this release:
- * Fixed unescaped output in the contact view.
- * Improved importing of phone numbers.
- * Fixed upgrade script.
+The major changes compared to the Turba version H3 (2.3) are:
+ * SECURITY: Escape output in test.php
+ * A SquirrelMail contact import script.
+ * Kolab fixes for free/busy URLs and photos.
+ * prototype.js has been upgraded to 1.6.0.3.
ML;
/* Freshmeat release notes, not more than 600 characters. */
$this->notes['fm']['changes'] = <<<FM
-Unescaped output in the contact view has been fixed.
-Importing of phone numbers has been improved.
-The upgrade script has been fixed.
+This release fixes unescaped output in a utility test script. In addition, an
+import script for SquirrelMail contacts has been added, several Kolab issues
+have been fixed, and prototype.js has been upgraded to 1.6.0.3.
FM;
$this->notes['name'] = 'Turba';
diff --git a/docs/UPGRADING b/docs/UPGRADING
index bdcbeaf..24f5648 100644
--- a/docs/UPGRADING
+++ b/docs/UPGRADING
@@ -2,11 +2,41 @@
Upgrading Turba
=================
-:Last update: $Date: 2008/04/30 03:37:39 $
-:Revision: $Revision: 1.3.6.15 $
+:Last update: $Date: 2008/11/14 17:27:39 $
+:Revision: $Revision: 1.3.6.27 $
:Contact: turba at lists.horde.org
+These are instructions to upgrade from earlier Turba versions. Please backup
+your existing data before running any of the steps described below. You can't
+use the updated data with your old Turba version anymore.
+
+
+Upgrading Turba from 2.2.1 to 2.3
+=================================
+
+
+Share Table Updates
+-------------------
+
+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/upgrade/2.2.1_to_2.3.sql
+
+
+New fields
+----------
+
+Examples for a few new fields have been added to
+``config/attributes.php.dist`` and ``config/sources.php.dist``. These field
+require Horde 3.3 or later though, so they are disabled by default. If you
+update your ``attributes.php`` and ``sources.php`` files and are using a
+sufficiently recent Horde version, you may want to uncomment those
+examples. These are the ``photo``, ``phototype``, ``logo``, ``logotype``,
+``pgpPublicKey`` and ``smimePublicKey`` fields.
+
Upgrading to Turba 2.2
======================
@@ -18,6 +48,7 @@ These are notes on upgrading from Turba 2.1.x to Turba 2.2.x.
follow the upgrade steps described in `Upgrading to Turba 2.1`_
first.
+
New Default Schema
------------------
@@ -27,7 +58,7 @@ other address book applications and to ease synchronization with those.
You can still use your old address book schema without any restrictions, but
if you want to migrate existing address books to the new default scheme, you
can use the provided upgrade script. This script assumes that you use the old
-default schema from Turba 2.1 and doesn't permanentely change any data unless
+default schema from Turba 2.1 and doesn't permanently change any data unless
you edit it.
To run the script you have to open it in any text editor and change the three
@@ -66,15 +97,15 @@ or "text".
New Beta SQL Share Driver Support
---------------------------------
-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 running Horde 3.2-RC3 or
-later. To add the new SQL tables for this driver, execute the sql script
-``2.1_to_2.2_add_sql_share_tables`` that is appropriate for your RDBMS. You then
-must execute the ``2.1_to_2.2_datatree_to_sql_share_migration.php`` upgrade
-script to migrate your existing share data. Both of these scripts can be found
-in the ``scripts/upgrades`` folder.
+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 running Horde
+3.2-RC3 or later. To add the new SQL tables for this driver, execute the sql
+script ``2.1_to_2.2_add_sql_share_tables`` that is appropriate for your
+RDBMS. You then must execute the ``convert_datatree_shares_to_sql.php``
+upgrade script to migrate your existing share data. Both of these scripts can
+be found in the ``scripts/upgrades`` folder.
Flattened Horde Shares
@@ -94,7 +125,9 @@ Turba transparently during each user's first login after the update.
Additionally, if you are currently using the configuration setting,
``Name of Client Address Book`` and have it set to a share enabled source, you
will most likely have to change the entry. The correct share key to enter here
-can be found by browsing the datatree via the administration UI.
+is the share name and can be found by browsing the datatree via the
+administration UI if using datatree shares, or by looking in the turba_shares
+table if using SQL based shares.
IMSP Driver and Share Support
@@ -133,6 +166,7 @@ All hooks that are specific to Turba have been moved from the
Upgrading to Turba 2.1
======================
+
These are notes on upgrading from Turba 2.0.x to Turba 2.1.
.. Important:: These upgrade instructions assume that you are upgrading from
@@ -140,6 +174,7 @@ These are notes on upgrading from Turba 2.0.x to Turba 2.1.
follow the upgrade steps described in `Upgrading to Turba 2.0`_
first.
+
Synchronization Support
-----------------------
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/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/lib/Block/tree_menu.php b/lib/Block/tree_menu.php
index c82eaeb..10c52dc 100644
--- a/lib/Block/tree_menu.php
+++ b/lib/Block/tree_menu.php
@@ -4,7 +4,7 @@ $block_name = _("Menu List");
$block_type = 'tree';
/**
- * $Horde: turba/lib/Block/tree_menu.php,v 1.5.2.4 2008/06/11 17:45:54 mrubinsk Exp $
+ * $Horde: turba/lib/Block/tree_menu.php,v 1.5.2.5 2008/08/11 08:29:21 jan Exp $
*
* @package Horde_Block
*/
@@ -22,25 +22,29 @@ class Horde_Block_turba_tree_menu extends Horde_Block {
$add = Horde::applicationUrl('add.php');
$icondir = $registry->getImageDir() . '/menu';
- $tree->addNode($parent . '__new',
- $parent,
- _("New Contact"),
- $indent + 1,
- false,
- array('icon' => 'new.png',
- 'icondir' => $icondir,
- 'url' => $add));
-
- foreach (Turba::getAddressBooks(PERMS_EDIT) as $addressbook => $config) {
- $tree->addNode($parent . $addressbook . '__new',
- $parent . '__new',
- sprintf(_("in %s"), $config['title']),
- $indent + 2,
+ if ($addSources) {
+ $tree->addNode($parent . '__new',
+ $parent,
+ _("New Contact"),
+ $indent + 1,
false,
array('icon' => 'new.png',
'icondir' => $icondir,
- 'url' => Util::addParameter($add, array('source' => $addressbook))));
+ 'url' => $add));
+
+ foreach ($addSources as $addressbook => $config) {
+ $tree->addNode($parent . $addressbook . '__new',
+ $parent . '__new',
+ sprintf(_("in %s"), $config['title']),
+ $indent + 2,
+ false,
+ array('icon' => 'new.png',
+ 'icondir' => $icondir,
+ 'url' => Util::addParameter($add, array('source' => $addressbook))));
+ }
+ }
+ foreach (Turba::getAddressBooks() as $addressbook => $config) {
if (!empty($config['browse'])) {
$tree->addNode($parent . $addressbook,
$parent,
diff --git a/lib/Driver.php b/lib/Driver.php
index 226a199..a138d71 100644
--- a/lib/Driver.php
+++ b/lib/Driver.php
@@ -4,7 +4,7 @@
* various directory search drivers. It includes functions for searching,
* adding, removing, and modifying directory entries.
*
- * $Horde: turba/lib/Driver.php,v 1.57.2.60 2008/06/12 22:16:44 jan Exp $
+ * $Horde: turba/lib/Driver.php,v 1.57.2.83 2008/10/28 23:40:38 jan Exp $
*
* @author Chuck Hagenbuch <chuck at horde.org>
* @author Jon Parise <jon at csh.rit.edu>
@@ -65,12 +65,19 @@ class Turba_Driver {
var $approximate = array();
/**
- * Whether this source stores one address book, or multiple private address
- * books.
+ * The name of a field to store contact list names in if not the default.
*
- * @var boolean
+ * @var string
+ */
+ var $listNameField = null;
+
+ /**
+ * The name of a field to use as an alternative to the name field if that
+ * one is empty.
+ *
+ * @var string
*/
- var $public = false;
+ var $alternativeName = null;
/**
* Hash holding the driver's additional parameters.
@@ -94,14 +101,6 @@ class Turba_Driver {
var $_count = null;
/**
- * Hold name of field to store contact list names in if not
- * the default.
- *
- * @var string
- */
- var $_listNameField = null;
-
- /**
* Hold the value for the owner of this address book.
*
* @var string
@@ -142,6 +141,26 @@ class Turba_Driver {
}
/**
+ * Returns the attributes that are blob types.
+ *
+ * @return array List of blob attributes in the array keys.
+ */
+ function getBlobs()
+ {
+ global $attributes;
+
+ $blobs = array();
+ foreach (array_keys($this->fields) as $attribute) {
+ if (isset($attributes[$attribute]) &&
+ $attributes[$attribute]['type'] == 'image') {
+ $blobs[$attribute] = true;
+ }
+ }
+
+ return $blobs;
+ }
+
+ /**
* Translates the keys of the first hash from the generalized Turba
* attributes to the driver-specific fields. The translation is based on
* the contents of $this->map.
@@ -152,6 +171,17 @@ class Turba_Driver {
*/
function toDriverKeys($hash)
{
+ /* Handle category. */
+ if (!empty($hash['category']) &&
+ $GLOBALS['attributes']['category']['type'] == 'category') {
+ if (!empty($hash['category']['new'])) {
+ require_once 'Horde/Prefs/CategoryManager.php';
+ $cManager = new Prefs_CategoryManager();
+ $cManager->add($hash['category']['value']);
+ }
+ $hash['category'] = $hash['category']['value'];
+ }
+
// Add composite fields to $hash if at least one field part exists
// and the composite field will be saved to storage.
// Otherwise composite fields won't be computed during an import.
@@ -170,10 +200,10 @@ class Turba_Driver {
}
}
- if (!empty($hash['name']) && !empty($this->_listNameField) &&
+ if (!empty($hash['name']) && !empty($this->listNameField) &&
!empty($hash['__type']) && is_array($this->map['name']) &&
$hash['__type'] == 'Group') {
- $hash[$this->_listNameField] = $hash['name'];
+ $hash[$this->listNameField] = $hash['name'];
unset($hash['name']);
}
@@ -436,8 +466,8 @@ class Turba_Driver {
$search_type = 'AND', $return_fields = array(),
$custom_strict = array(), $match_begin = false)
{
- /* If we are not using Horde_Share, enfore the requirement that the
- current user must be the owner of the addressbook. */
+ /* If we are not using Horde_Share, enforce the requirement that the
+ * current user must be the owner of the addressbook. */
$search_criteria['__owner'] = $this->getContactOwner();
$strict_fields = array($this->toDriver('__owner') => true);
@@ -575,9 +605,24 @@ class Turba_Driver {
++$t_object_end->mday;
$t_object_end->correct();
$key = $ob->getValue('__key');
- $title = sprintf(_("%s of %s"), $GLOBALS['attributes'][$category]['label'],
+
+ // Calculate the age of the time object
+ if ($start->year == $end->year) {
+ $age = $start->year - $t_object->year;
+ } elseif ($t_object->month <= $end->month) {
+ // t_object must be in later year
+ $age = $end->year - $t_object->year;
+ } else {
+ // t_object must be in earlier year
+ $age = $start->year - $t_object->year;
+ }
+
+ $title = sprintf(_("%d. %s of %s"),
+ $age,
+ $GLOBALS['attributes'][$category]['label'],
$ob->getValue('name'));
+
$t_objects[] = array(
'id' => $key,
'title' => $title,
@@ -645,7 +690,8 @@ class Turba_Driver {
{
$objects = $this->_read($this->map['__key'], $objectIds,
$this->getContactOwner(),
- array_values($this->fields));
+ array_values($this->fields),
+ $this->toDriverKeys($this->getBlobs()));
if (is_a($objects, 'PEAR_Error')) {
return $objects;
}
@@ -730,7 +776,7 @@ class Turba_Driver {
$uid = $attributes['__uid'];
$attributes = $this->toDriverKeys($attributes);
- $result = $this->_add($attributes);
+ $result = $this->_add($attributes, $this->toDriverKeys($this->getBlobs()));
if (is_a($result, 'PEAR_Error')) {
return $result;
}
@@ -802,11 +848,11 @@ class Turba_Driver {
*/
function save($object)
{
- $attributes = $this->toDriverKeys($object->getAttributes());
- $key = $this->toDriverKeys(array('__key' => $object->getValue('__key')));
- list($object_key, $object_id) = each($key);
+ list($object_key, $object_id) = each($this->toDriverKeys(array('__key' => $object->getValue('__key'))));
- $object_id = $this->_save($object_key, $object_id, $attributes);
+ $object_id = $this->_save($object_key, $object_id,
+ $this->toDriverKeys($object->getAttributes()),
+ $this->toDriverKeys($this->getBlobs()));
if (is_a($object_id, 'PEAR_Error')) {
return $object_id;
}
@@ -897,6 +943,9 @@ class Turba_Driver {
$geo = null;
foreach ($hash as $key => $val) {
+ if (!strlen($val)) {
+ continue;
+ }
if ($version != '2.1') {
$val = String::convertCharset($val, NLS::getCharset(), 'utf-8');
}
@@ -912,6 +961,28 @@ class Turba_Driver {
MIME::is8bit($val) ? $charset : array());
break;
+ case 'homeAddress':
+ if ($version == '2.1') {
+ $vcard->setAttribute('LABEL', $val, array('HOME' => null));
+ } else {
+ $vcard->setAttribute('LABEL', $val, array('TYPE' => 'HOME'));
+ }
+ break;
+ case 'workAddress':
+ if ($version == '2.1') {
+ $vcard->setAttribute('LABEL', $val, array('HOME' => null));
+ } else {
+ $vcard->setAttribute('LABEL', $val, array('TYPE' => 'WORK'));
+ }
+ break;
+ case 'otherAddress':
+ if ($version == '2.1') {
+ $vcard->setAttribute('LABEL', $val);
+ } else {
+ $vcard->setAttribute('LABEL', $val);
+ }
+ break;
+
case 'phone':
if ($version == '2.1') {
$vcard->setAttribute('TEL', $val);
@@ -933,7 +1004,6 @@ class Turba_Driver {
$vcard->setAttribute('TEL', $val, array('TYPE' => 'WORK'));
}
break;
-
case 'cellPhone':
if ($version == '2.1') {
$vcard->setAttribute('TEL', $val, array('CELL' => null));
@@ -1063,7 +1133,6 @@ class Turba_Driver {
array('TYPE' => 'WORK'));
}
break;
-
case 'emails':
$emails = explode(',', $val);
foreach ($emails as $email) {
@@ -1076,7 +1145,6 @@ class Turba_Driver {
$vcard->setAttribute('TITLE', $val,
MIME::is8bit($val) ? $charset : array());
break;
-
case 'role':
$vcard->setAttribute('ROLE', $val,
MIME::is8bit($val) ? $charset : array());
@@ -1169,11 +1237,22 @@ class Turba_Driver {
}
}
break;
+
+ case 'photo':
+ case 'logo':
+ $params = array('ENCODING' => 'b');
+ if (isset($hash[$key . 'type'])) {
+ $params['TYPE'] = $hash[$key . 'type'];
+ }
+ $vcard->setAttribute(String::upper($key),
+ base64_encode($val),
+ $params);
+ break;
}
}
// No explicit firstname/lastname in data source: we have to guess.
- if (!isset($hash['lastname'])) {
+ if (!isset($hash['lastname']) && isset($hash['name'])) {
$i = strpos($hash['name'], ',');
if (is_int($i)) {
// Assume Last, First
@@ -1216,15 +1295,17 @@ class Turba_Driver {
if (isset($hash['department'])) {
$org[] = $hash['department'];
}
- $val = implode(';', $org);
- if ($version != '2.1') {
- $val = String::convertCharset($val, NLS::getCharset(), 'utf-8');
- $org = String::convertCharset($org, NLS::getCharset(), 'utf-8');
+ if (count($org)) {
+ $val = implode(';', $org);
+ if ($version != '2.1') {
+ $val = String::convertCharset($val, NLS::getCharset(), 'utf-8');
+ $org = String::convertCharset($org, NLS::getCharset(), 'utf-8');
+ }
+ $vcard->setAttribute('ORG', $val, MIME::is8bit($val) ? $charset : array(), false, $org);
}
- $vcard->setAttribute('ORG', $val, MIME::is8bit($val) ? $charset : array(), false, $org);
if (isset($hash['commonAddress']) || isset($hash['commonStreet']) ||
- isset($hash['commonPOBox']) || isset($hash['commonExtend']) ||
+ isset($hash['commonPOBox']) || isset($hash['commonExtended']) ||
isset($hash['commonStreet']) || isset($hash['commonCity']) ||
isset($hash['commonProvince']) ||
isset($hash['commonPostalCode']) || isset($hash['commonCountry'])) {
@@ -1239,8 +1320,8 @@ class Turba_Driver {
$a = array(
VCARD_ADR_POB => isset($hash['commonPOBox'])
? $hash['commonPOBox'] : '',
- VCARD_ADR_EXTEND => isset($hash['commonExtend'])
- ? $hash['commonExtend'] : '',
+ VCARD_ADR_EXTEND => isset($hash['commonExtended'])
+ ? $hash['commonExtended'] : '',
VCARD_ADR_STREET => isset($hash['commonStreet'])
? $hash['commonStreet'] : '',
VCARD_ADR_LOCALITY => isset($hash['commonCity'])
@@ -1250,7 +1331,7 @@ class Turba_Driver {
VCARD_ADR_POSTCODE => isset($hash['commonPostalCode'])
? $hash['commonPostalCode'] : '',
VCARD_ADR_COUNTRY => isset($hash['commonCountry'])
- ? $hash['commonCountry'] : '',
+ ? Turba_Driver::getCountry($hash['commonCountry']) : '',
);
$val = implode(';', $a);
@@ -1268,7 +1349,7 @@ class Turba_Driver {
}
if (isset($hash['homeAddress']) || isset($hash['homeStreet']) ||
- isset($hash['homePOBox']) || isset($hash['homeExtend']) ||
+ isset($hash['homePOBox']) || isset($hash['homeExtended']) ||
isset($hash['homeStreet']) || isset($hash['homeCity']) ||
isset($hash['homeProvince']) || isset($hash['homePostalCode']) ||
isset($hash['homeCountry'])) {
@@ -1278,8 +1359,8 @@ class Turba_Driver {
$a = array(
VCARD_ADR_POB => isset($hash['homePOBox'])
? $hash['homePOBox'] : '',
- VCARD_ADR_EXTEND => isset($hash['homeExtend'])
- ? $hash['homeExtend'] : '',
+ VCARD_ADR_EXTEND => isset($hash['homeExtended'])
+ ? $hash['homeExtended'] : '',
VCARD_ADR_STREET => isset($hash['homeStreet'])
? $hash['homeStreet'] : '',
VCARD_ADR_LOCALITY => isset($hash['homeCity'])
@@ -1289,7 +1370,7 @@ class Turba_Driver {
VCARD_ADR_POSTCODE => isset($hash['homePostalCode'])
? $hash['homePostalCode'] : '',
VCARD_ADR_COUNTRY => isset($hash['homeCountry'])
- ? $hash['homeCountry'] : '',
+ ? Turba_Driver::getCountry($hash['homeCountry']) : '',
);
$val = implode(';', $a);
@@ -1307,7 +1388,7 @@ class Turba_Driver {
}
if (isset($hash['workAddress']) || isset($hash['workStreet']) ||
- isset($hash['workPOBox']) || isset($hash['workExtend']) ||
+ isset($hash['workPOBox']) || isset($hash['workExtended']) ||
isset($hash['workStreet']) || isset($hash['workCity']) ||
isset($hash['workProvince']) || isset($hash['workPostalCode']) ||
isset($hash['workCountry'])) {
@@ -1317,8 +1398,8 @@ class Turba_Driver {
$a = array(
VCARD_ADR_POB => isset($hash['workPOBox'])
? $hash['workPOBox'] : '',
- VCARD_ADR_EXTEND => isset($hash['workExtend'])
- ? $hash['workExtend'] : '',
+ VCARD_ADR_EXTEND => isset($hash['workExtended'])
+ ? $hash['workExtended'] : '',
VCARD_ADR_STREET => isset($hash['workStreet'])
? $hash['workStreet'] : '',
VCARD_ADR_LOCALITY => isset($hash['workCity'])
@@ -1328,7 +1409,7 @@ class Turba_Driver {
VCARD_ADR_POSTCODE => isset($hash['workPostalCode'])
? $hash['workPostalCode'] : '',
VCARD_ADR_COUNTRY => isset($hash['workCountry'])
- ? $hash['workCountry'] : '',
+ ? Turba_Driver::getCountry($hash['workCountry']) : '',
);
$val = implode(';', $a);
@@ -1349,6 +1430,24 @@ class Turba_Driver {
}
/**
+ * Returns the (localized) country name.
+ *
+ * @param string $country The two-letter country code.
+ *
+ * @return string The country name or the country code if a name cannot be
+ * found.
+ */
+ function getCountry($country)
+ {
+ static $countries;
+ if (!isset($countries)) {
+ include 'Horde/NLS/countries.php';
+ }
+
+ return isset($countries[$country]) ? $countries[$country] : $country;
+ }
+
+ /**
* Function to convert a Horde_iCalendar_vcard object into a Turba
* Object Hash with Turba attributes suitable as a parameter for add().
*
@@ -1403,16 +1502,15 @@ class Turba_Driver {
// We use LABEL but also support ADR.
case 'LABEL':
- if (isset($item['params']['HOME'])) {
+ if (isset($item['params']['HOME']) && !isset($hash['homeAddress'])) {
$hash['homeAddress'] = $item['value'];
- } elseif (isset($item['params']['WORK'])) {
+ } elseif (isset($item['params']['WORK']) && !isset($hash['workAddress'])) {
$hash['workAddress'] = $item['value'];
- } else {
+ } elseif (!isset($hash['commonAddress'])) {
$hash['commonAddress'] = $item['value'];
}
break;
- // For vCard 3.0.
case 'ADR':
if (isset($item['params']['TYPE'])) {
if (!is_array($item['params']['TYPE'])) {
@@ -1446,46 +1544,47 @@ class Turba_Driver {
$prefix = 'common';
}
- if ($prefix) {
- $hash[$prefix . 'Address'] = '';
+ if (isset($hash[$prefix . 'Address'])) {
+ continue;
+ }
- if (!empty($address[VCARD_ADR_STREET])) {
- $hash[$prefix . 'Street'] = $address[VCARD_ADR_STREET];
- $hash[$prefix . 'Address'] .= $hash[$prefix . 'Street'] . "\n";
- }
- if (!empty($address[VCARD_ADR_EXTEND])) {
- $hash[$prefix . 'Extend'] = $address[VCARD_ADR_EXTEND];
- $hash[$prefix . 'Address'] .= $hash[$prefix . 'Extend'] . "\n";
- }
- if (!empty($address[VCARD_ADR_POB])) {
- $hash[$prefix . 'POBox'] = $address[VCARD_ADR_POB];
- $hash[$prefix . 'Address'] .= $hash[$prefix . 'POBox'] . "\n";
- }
- if (!empty($address[VCARD_ADR_LOCALITY])) {
- $hash[$prefix . 'City'] = $address[VCARD_ADR_LOCALITY];
- $hash[$prefix . 'Address'] .= $hash[$prefix . 'City'];
- }
- if (!empty($address[VCARD_ADR_REGION])) {
- $hash[$prefix . 'Province'] = $address[VCARD_ADR_REGION];
- $hash[$prefix . 'Address'] .= ', ' . $hash[$prefix . 'Province'];
- }
- if (!empty($address[VCARD_ADR_POSTCODE])) {
- $hash[$prefix . 'PostalCode'] = $address[VCARD_ADR_POSTCODE];
- $hash[$prefix . 'Address'] .= ' ' . $hash[$prefix . 'PostalCode'];
- }
- if (!empty($address[VCARD_ADR_COUNTRY])) {
- $hash[$prefix . 'Address'] .= "\n" . $address[VCARD_ADR_COUNTRY];
- include 'Horde/NLS/countries.php';
- $country = array_search($address[VCARD_ADR_COUNTRY], $countries);
- if ($country !== false) {
- $hash[$prefix . 'Country'] = $country;
- } else {
- $hash[$prefix . 'Country'] = $address[VCARD_ADR_COUNTRY];
- }
- }
+ $hash[$prefix . 'Address'] = '';
- $hash[$prefix . 'Address'] = trim($hash[$prefix . 'Address']);
+ if (!empty($address[VCARD_ADR_STREET])) {
+ $hash[$prefix . 'Street'] = $address[VCARD_ADR_STREET];
+ $hash[$prefix . 'Address'] .= $hash[$prefix . 'Street'] . "\n";
+ }
+ if (!empty($address[VCARD_ADR_EXTEND])) {
+ $hash[$prefix . 'Extended'] = $address[VCARD_ADR_EXTEND];
+ $hash[$prefix . 'Address'] .= $hash[$prefix . 'Extended'] . "\n";
+ }
+ if (!empty($address[VCARD_ADR_POB])) {
+ $hash[$prefix . 'POBox'] = $address[VCARD_ADR_POB];
+ $hash[$prefix . 'Address'] .= $hash[$prefix . 'POBox'] . "\n";
}
+ if (!empty($address[VCARD_ADR_LOCALITY])) {
+ $hash[$prefix . 'City'] = $address[VCARD_ADR_LOCALITY];
+ $hash[$prefix . 'Address'] .= $hash[$prefix . 'City'];
+ }
+ if (!empty($address[VCARD_ADR_REGION])) {
+ $hash[$prefix . 'Province'] = $address[VCARD_ADR_REGION];
+ $hash[$prefix . 'Address'] .= ', ' . $hash[$prefix . 'Province'];
+ }
+ if (!empty($address[VCARD_ADR_POSTCODE])) {
+ $hash[$prefix . 'PostalCode'] = $address[VCARD_ADR_POSTCODE];
+ $hash[$prefix . 'Address'] .= ' ' . $hash[$prefix . 'PostalCode'];
+ }
+ if (!empty($address[VCARD_ADR_COUNTRY])) {
+ include 'Horde/NLS/countries.php';
+ $country = array_search($address[VCARD_ADR_COUNTRY], $countries);
+ if ($country === false) {
+ $country = $address[VCARD_ADR_COUNTRY];
+ }
+ $hash[$prefix . 'Country'] = $country;
+ $hash[$prefix . 'Address'] .= "\n" . $address[VCARD_ADR_COUNTRY];
+ }
+
+ $hash[$prefix . 'Address'] = trim($hash[$prefix . 'Address']);
}
break;
@@ -1520,14 +1619,17 @@ class Turba_Driver {
case 'TEL':
if (isset($item['params']['FAX'])) {
- if (isset($item['params']['WORK'])) {
+ if (isset($item['params']['WORK']) &&
+ !isset($hash['workFax'])) {
$hash['workFax'] = $item['value'];
- } elseif (isset($item['params']['HOME'])) {
+ } elseif (isset($item['params']['HOME']) &&
+ !isset($hash['homeFax'])) {
$hash['homeFax'] = $item['value'];
- } else {
+ } elseif (!isset($hash['fax'])) {
$hash['fax'] = $item['value'];
}
- } elseif (isset($item['params']['PAGER'])) {
+ } elseif (isset($item['params']['PAGER']) &&
+ !isset($hash['pager'])) {
$hash['pager'] = $item['value'];
} elseif (isset($item['params']['TYPE'])) {
if (!is_array($item['params']['TYPE'])) {
@@ -1535,88 +1637,115 @@ class Turba_Driver {
}
// For vCard 3.0.
if (in_array('CELL', $item['params']['TYPE'])) {
- if (in_array('HOME', $item['params']['TYPE'])) {
+ if (in_array('HOME', $item['params']['TYPE']) &&
+ !isset($hash['homeCellPhone'])) {
$hash['homeCellPhone'] = $item['value'];
- } elseif (in_array('WORK', $item['params']['TYPE'])) {
+ } elseif (in_array('WORK', $item['params']['TYPE']) &&
+ !isset($hash['workCellPhone'])) {
$hash['workCellPhone'] = $item['value'];
- } else {
+ } elseif (!isset($hash['cellPhone'])) {
$hash['cellPhone'] = $item['value'];
}
} elseif (in_array('FAX', $item['params']['TYPE'])) {
- if (in_array('HOME', $item['params']['TYPE'])) {
+ if (in_array('HOME', $item['params']['TYPE']) &&
+ !isset($hash['homeFax'])) {
$hash['homeFax'] = $item['value'];
- } elseif (in_array('WORK', $item['params']['TYPE'])) {
+ } elseif (in_array('WORK', $item['params']['TYPE']) &&
+ !isset($hash['workFax'])) {
$hash['workFax'] = $item['value'];
- } else {
+ } elseif (!isset($hash['fax'])) {
$hash['fax'] = $item['value'];
}
} elseif (in_array('VIDEO', $item['params']['TYPE'])) {
- if (in_array('HOME', $item['params']['TYPE'])) {
+ if (in_array('HOME', $item['params']['TYPE']) &&
+ !isset($hash['homeVideoCall'])) {
$hash['homeVideoCall'] = $item['value'];
- } elseif (in_array('WORK', $item['params']['TYPE'])) {
+ } elseif (in_array('WORK', $item['params']['TYPE']) &&
+ !isset($hash['workVideoCall'])) {
$hash['workVideoCall'] = $item['value'];
- } else {
+ } elseif (!isset($hash['videoCall'])) {
$hash['videoCall'] = $item['value'];
}
- } elseif (in_array('PAGER', $item['params']['TYPE'])) {
+ } elseif (in_array('PAGER', $item['params']['TYPE']) &&
+ !isset($hash['pager'])) {
$hash['pager'] = $item['value'];
- } elseif (in_array('WORK', $item['params']['TYPE'])) {
+ } elseif (in_array('WORK', $item['params']['TYPE']) &&
+ !isset($hash['workPhone'])) {
$hash['workPhone'] = $item['value'];
- } elseif (in_array('HOME', $item['params']['TYPE'])) {
+ } elseif (in_array('HOME', $item['params']['TYPE']) &&
+ !isset($hash['homePhone'])) {
$hash['homePhone'] = $item['value'];
}
} elseif (isset($item['params']['CELL'])) {
- if (isset($item['params']['WORK'])) {
+ if (isset($item['params']['WORK']) &&
+ !isset($hash['workCellPhone'])) {
$hash['workCellPhone'] = $item['value'];
- } elseif (isset($item['params']['HOME'])) {
+ } elseif (isset($item['params']['HOME']) &&
+ !isset($hash['homeCellPhone'])) {
$hash['homeCellPhone'] = $item['value'];
- } else {
+ } elseif (!isset($hash['cellPhone'])) {
$hash['cellPhone'] = $item['value'];
}
} elseif (isset($item['params']['VIDEO'])) {
- if (isset($item['params']['WORK'])) {
+ if (isset($item['params']['WORK']) &&
+ !isset($hash['workVideoCall'])) {
$hash['workVideoCall'] = $item['value'];
- } elseif (isset($item['params']['HOME'])) {
+ } elseif (isset($item['params']['HOME']) &&
+ !isset($hash['homeVideoCall'])) {
$hash['homeVideoCall'] = $item['value'];
- } else {
+ } elseif (!isset($hash['homeVideoCall'])) {
$hash['videoCall'] = $item['value'];
}
} elseif (count($item['params']) <= 1 ||
- (count($item['params']) <= 2 &&
- isset($item['params']['VOICE']))) {
+ isset($item['params']['VOICE'])) {
// There might be e.g. SAT;WORK which must not overwrite
// WORK.
- if (isset($item['params']['WORK'])) {
+ if (isset($item['params']['WORK']) &&
+ !isset($hash['workPhone'])) {
$hash['workPhone'] = $item['value'];
- } elseif (isset($item['params']['HOME'])) {
+ } elseif (isset($item['params']['HOME']) &&
+ !isset($hash['homePhone'])) {
$hash['homePhone'] = $item['value'];
- } elseif (count($item['params']) == 0 ||
- (count($item['params']) == 1 &&
- isset($item['params']['VOICE']))) {
+ } elseif ((count($item['params']) == 0 ||
+ (count($item['params']) == 1 &&
+ isset($item['params']['VOICE']))) &&
+ !isset($hash['phone'])) {
$hash['phone'] = $item['value'];
}
}
break;
case 'EMAIL':
- if (isset($item['params']['PREF']) || !isset($hash['email'])) {
- $hash['email'] = Horde_iCalendar_vcard::getBareEmail($item['value']);
- } elseif (isset($item['params']['HOME'])) {
+ $email_set = false;
+ if (isset($item['params']['HOME']) &&
+ (!isset($hash['homeEmail']) ||
+ isset($item['params']['PREF']))) {
$hash['homeEmail'] = Horde_iCalendar_vcard::getBareEmail($item['value']);
- } elseif (isset($item['params']['WORK'])) {
+ $email_set = true;
+ } elseif (isset($item['params']['WORK']) &&
+ (!isset($hash['workEmail']) ||
+ isset($item['params']['PREF']))) {
$hash['workEmail'] = Horde_iCalendar_vcard::getBareEmail($item['value']);
+ $email_set = true;
} elseif (isset($item['params']['TYPE'])) {
if (!is_array($item['params']['TYPE'])) {
$item['params']['TYPE'] = array($item['params']['TYPE']);
}
- if (in_array('HOME', $item['params']['TYPE'])) {
+ if (in_array('HOME', $item['params']['TYPE']) &&
+ (!isset($hash['homeEmail']) ||
+ in_array('PREF', $item['params']['TYPE']))) {
$hash['homeEmail'] = Horde_iCalendar_vcard::getBareEmail($item['value']);
- } elseif (in_array('WORK', $item['params']['TYPE'])) {
+ $email_set = true;
+ } elseif (in_array('WORK', $item['params']['TYPE']) &&
+ (!isset($hash['workEmail']) ||
+ in_array('PREF', $item['params']['TYPE']))) {
$hash['workEmail'] = Horde_iCalendar_vcard::getBareEmail($item['value']);
- } else {
- $hash['email'] = Horde_iCalendar_vcard::getBareEmail($item['value']);
+ $email_set = true;
}
- } else {
+ }
+ if (!$email_set &&
+ (!isset($hash['email']) ||
+ isset($item['params']['PREF']))) {
$hash['email'] = Horde_iCalendar_vcard::getBareEmail($item['value']);
}
@@ -1652,11 +1781,13 @@ class Turba_Driver {
break;
case 'URL':
- if (isset($item['params']['HOME'])) {
+ if (isset($item['params']['HOME']) &&
+ !isset($hash['homeWebsite'])) {
$hash['homeWebsite'] = $item['value'];
- } elseif (isset($item['params']['WORK'])) {
+ } elseif (isset($item['params']['WORK']) &&
+ !isset($hash['workWebsite'])) {
$hash['workWebsite'] = $item['value'];
- } else {
+ } elseif (!isset($hash['website'])) {
$hash['website'] = $item['value'];
}
break;
@@ -1665,14 +1796,37 @@ class Turba_Driver {
$hash['birthday'] = $item['value']['year'] . '-' . $item['value']['month'] . '-' . $item['value']['mday'];
break;
+ case 'PHOTO':
+ case 'LOGO':
+ if (isset($item['params']['VALUE']) &&
+ String::lower($item['params']['VALUE']) == 'uri') {
+ // No support for URIs yet.
+ break;
+ }
+ if (!isset($item['params']['ENCODING']) ||
+ (String::lower($item['params']['ENCODING']) != 'b' &&
+ String::upper($item['params']['ENCODING']) != 'BASE64')) {
+ // Invalid property.
+ break;
+ }
+ $type = String::lower($item['name']);
+ $hash[$type] = base64_decode($item['value']);
+ if (isset($item['params']['TYPE'])) {
+ $hash[$type . 'type'] = $item['params']['TYPE'];
+ }
+ break;
+
case 'X-SIP':
- if (isset($item['params']['POC'])) {
+ if (isset($item['params']['POC']) &&
+ !isset($hash['ptt'])) {
$hash['ptt'] = $item['value'];
- } elseif (isset($item['params']['VOIP'])) {
+ } elseif (isset($item['params']['VOIP']) &&
+ !isset($hash['voip'])) {
$hash['voip'] = $item['value'];
- } elseif (isset($item['params']['SWIS'])) {
+ } elseif (isset($item['params']['SWIS']) &&
+ !isset($hash['shareView'])) {
$hash['shareView'] = $item['value'];
- } else {
+ } elseif (!isset($hash['sip'])) {
$hash['sip'] = $item['value'];
}
break;
@@ -1854,16 +2008,18 @@ class Turba_Driver {
$driver->tabs = $config['tabs'];
}
- /* Store strict and approximate fields. */
+ /* Store remaining fields. */
if (isset($config['strict'])) {
$driver->strict = $config['strict'];
}
if (isset($config['approximate'])) {
$driver->approximate = $config['approximate'];
}
-
- if (!empty($config['list_name_field'])) {
- $driver->_listNameField = $config['list_name_field'];
+ if (isset($config['list_name_field'])) {
+ $driver->listNameField = $config['list_name_field'];
+ }
+ if (isset($config['alternative_name'])) {
+ $driver->alternativeName = $config['alternative_name'];
}
return $driver;
diff --git a/lib/Driver/favourites.php b/lib/Driver/favourites.php
index c54581d..ad17bc9 100644
--- a/lib/Driver/favourites.php
+++ b/lib/Driver/favourites.php
@@ -3,7 +3,7 @@
* Read-only Turba directory driver implementation for favourite
* recipients. Relies on the contacts/favouriteRecipients API method.
*
- * $Horde: turba/lib/Driver/favourites.php,v 1.5.2.2 2008/04/25 04:58:31 chuck Exp $
+ * $Horde: turba/lib/Driver/favourites.php,v 1.5.2.3 2008/08/03 16:50:06 jan Exp $
*
* @author Jan Schneider <jan at horde.org>
* @since Turba 2.1
@@ -124,7 +124,7 @@ class Turba_Driver_favourites extends Turba_Driver {
return PEAR::raiseError(_("No source for favourite recipients exists."));
}
- $addresses = $registry->call('contacts/favouriteRecipients', $this->_params['limit']);
+ $addresses = $registry->call('contacts/favouriteRecipients', array($this->_params['limit']));
if (is_a($addresses, 'PEAR_Error')) {
return $addresses;
}
diff --git a/lib/Driver/kolab.php b/lib/Driver/kolab.php
index 56a3c86..166c0a6 100644
--- a/lib/Driver/kolab.php
+++ b/lib/Driver/kolab.php
@@ -2,7 +2,7 @@
/**
* @package Turba
*
- * $Horde: turba/lib/Driver/kolab.php,v 1.5.10.21 2008/06/12 22:12:51 jan Exp $
+ * $Horde: turba/lib/Driver/kolab.php,v 1.5.10.23 2008/11/07 13:15:23 wrobel Exp $
*/
/** Kolab support class. */
@@ -184,7 +184,7 @@ class Turba_Driver_kolab extends Turba_Driver {
/**
* Horde Turba wrapper to distinguish between both Kolab driver implementations.
*
- * $Horde: turba/lib/Driver/kolab.php,v 1.5.10.21 2008/06/12 22:12:51 jan Exp $
+ * $Horde: turba/lib/Driver/kolab.php,v 1.5.10.23 2008/11/07 13:15:23 wrobel Exp $
*
* Copyright 2004-2008 The Horde Project (http://www.horde.org/)
*
@@ -742,11 +742,26 @@ class Turba_Driver_kolab_wrapper_new extends Turba_Driver_kolab_wrapper {
$this->_store = &$this->_kolab->_storage;
/* Fetch the contacts first */
- $contacts = $this->_store->getObjectArray();
- if (!$contacts) {
- $contacts = array();
+ $raw_contacts = $this->_store->getObjectArray();
+ if (!$raw_contacts) {
+ $raw_contacts = array();
+ }
+ $contacts = array();
+ foreach ($raw_contacts as $id => $contact) {
+ if (isset($contact['email'])) {
+ unset($contact['email']);
+ }
+ if (isset($contact['picture'])) {
+ $name = $contact['picture'];
+ if (isset($contact['_attachments'][$name])) {
+ $contact['photo'] = $this->_store->_data->getAttachment($contact['_attachments'][$name]['key']);
+ $contact['phototype'] = $contact['_attachments'][$name]['type'];
+ }
+ }
+
+ $contacts[$id] = $contact;
}
-
+
/* Now we retrieve distribution-lists */
$result = $this->_store->setObjectType('distribution-list');
if (is_a($result, 'PEAR_Error')) {
@@ -1073,29 +1088,19 @@ class Turba_Driver_kolab_wrapper_new extends Turba_Driver_kolab_wrapper {
return $result;
}
- $group = false;
- if (isset($attributes['__type']) && $attributes['__type'] == 'Group') {
- $group = true;
- $result = $this->_store->setObjectType('distribution-list');
- if (is_a($result, 'PEAR_Error')) {
- return $result;
- }
- $this->_convertMembers($attributes);
+ $attributes['full-name'] = $attributes['last-name'];
+ if (isset($attributes['middle-names'])) {
+ $attributes['full-name'] = $attributes['middle-names'] . ' ' . $attributes['full-name'];
}
-
- $object_id = $this->_store->save($attributes, null);
- if (is_a($object_id, 'PEAR_Error')) {
- return $object_id;
+ if (isset($attributes['given-name'])) {
+ $attributes['full-name'] = $attributes['given-name'] . ' ' . $attributes['full-name'];
}
- if ($group) {
- $result = $this->_store->setObjectType('contact');
- if (is_a($result, 'PEAR_Error')) {
- return $result;
- }
+ $result = $this->_store($attributes);
+ if (is_a($result, 'PEAR_Error')) {
+ return $result;
}
-
- return $object_id;
+ return true;
}
/**
@@ -1111,9 +1116,19 @@ class Turba_Driver_kolab_wrapper_new extends Turba_Driver_kolab_wrapper {
}
if ($object_key != 'uid') {
- return PEAR::raiseError(sprintf(_("Key for saving must be a UID not %s!"), $object_key));
+ return PEAR::raiseError(sprintf(_("Key for saving must be \'uid\' not %s!"), $object_key));
}
+ return $this->_store($attributes, $object_id);
+ }
+
+ /**
+ * Stores an object in the Kolab message store.
+ *
+ * @return string The object id, possibly updated.
+ */
+ function _store($attributes, $object_id = null)
+ {
$group = false;
if (isset($attributes['__type']) && $attributes['__type'] == 'Group') {
$group = true;
@@ -1124,6 +1139,14 @@ class Turba_Driver_kolab_wrapper_new extends Turba_Driver_kolab_wrapper {
$this->_convertMembers($attributes);
}
+ if (isset($attributes['photo']) && isset($attributes['phototype'])) {
+ $attributes['_attachments']['photo.attachment'] = array('type' => $attributes['phototype'],
+ 'content' => $attributes['photo']);
+ $attributes['picture'] = 'photo.attachment';
+ unset($attributes['photo']);
+ unset($attributes['phototype']);
+ }
+
$result = $this->_store->save($attributes, $object_id);
if (is_a($result, 'PEAR_Error')) {
return $result;
diff --git a/lib/Driver/share.php b/lib/Driver/share.php
index aa6528d..57222a4 100644
--- a/lib/Driver/share.php
+++ b/lib/Driver/share.php
@@ -4,7 +4,7 @@
* various directory search drivers. It includes functions for searching,
* adding, removing, and modifying directory entries.
*
- * $Horde: turba/lib/Driver/share.php,v 1.11.2.4 2008/02/15 16:44:06 chuck Exp $
+ * $Horde: turba/lib/Driver/share.php,v 1.11.2.6 2008/08/11 16:34:17 jan Exp $
*
* @author Chuck Hagenbuch <chuck at horde.org>
* @author Jon Parise <jon at csh.rit.edu>
@@ -116,17 +116,17 @@ class Turba_Driver_share extends Turba_Driver {
*
* @return array Hash containing the search results.
*/
- function _read($key, $ids, $owner, $fields)
+ function _read($key, $ids, $owner, $fields, $blob_fields = array())
{
- return $this->_driver->_read($key, $ids, $owner, $fields);
+ return $this->_driver->_read($key, $ids, $owner, $fields, $blob_fields);
}
/**
* Adds the specified object to the SQL database.
*/
- function _add($attributes)
+ function _add($attributes, $blob_fields = array())
{
- return $this->_driver->_add($attributes);
+ return $this->_driver->_add($attributes, $blob_fields);
}
/**
@@ -155,17 +155,14 @@ class Turba_Driver_share extends Turba_Driver {
*
* @return string The object id, possibly updated.
*/
- function _save($object_key, $object_id, $attributes)
+ function _save($object_key, $object_id, $attributes, $blob_fields = array())
{
- return $this->_driver->_save($object_key, $object_id, $attributes);
+ return $this->_driver->_save($object_key, $object_id, $attributes, $blob_fields);
}
/**
* Stub for removing all data for a specific user - to be overridden
* by child class.
- *
- * @TODO This should actually call _deleteAll for the underlying
- * driver and remove the share.
*/
function removeUserData($user)
{
diff --git a/lib/Driver/sql.php b/lib/Driver/sql.php
index e50baaa..5bb64b3 100644
--- a/lib/Driver/sql.php
+++ b/lib/Driver/sql.php
@@ -3,7 +3,7 @@
* Turba directory driver implementation for PHP's PEAR database abstraction
* layer.
*
- * $Horde: turba/lib/Driver/sql.php,v 1.59.10.23 2008/06/09 03:28:07 chuck Exp $
+ * $Horde: turba/lib/Driver/sql.php,v 1.59.10.29 2008/08/12 09:24:50 jan Exp $
*
* @author Jon Parise <jon at csh.rit.edu>
* @package Turba
@@ -204,7 +204,7 @@ class Turba_Driver_sql extends Turba_Driver {
*
* @return array Hash containing the search results.
*/
- function _read($key, $ids, $owner, $fields)
+ function _read($key, $ids, $owner, $fields, $blob_fields = array())
{
$values = array();
@@ -231,8 +231,8 @@ class Turba_Driver_sql extends Turba_Driver {
$where .= ' AND ' . $this->_params['filter'];
}
- $query = 'SELECT ' . implode(', ', $fields) . ' ';
- $query .= 'FROM ' . $this->_params['table'] . ' WHERE ' . $where;
+ $query = 'SELECT ' . implode(', ', $fields) . ' FROM '
+ . $this->_params['table'] . ' WHERE ' . $where;
/* Log the query at a DEBUG log level. */
Horde::logMessage('SQL query by Turba_Driver_sql::_read(): ' . $query,
@@ -246,15 +246,25 @@ class Turba_Driver_sql extends Turba_Driver {
$results = array();
$iMax = count($fields);
- if (!is_a($result, 'PEAR_Error')) {
- foreach ($result as $row) {
- $entry = array();
- for ($i=0; $i < $iMax; $i++) {
- $field = $fields[$i];
+ foreach ($result as $row) {
+ $entry = array();
+ for ($i = 0; $i < $iMax; $i++) {
+ $field = $fields[$i];
+ if (isset($blob_fields[$field])) {
+ switch ($this->_db->dbsyntax) {
+ case 'pgsql':
+ case 'mssql':
+ $entry[$field] = pack('H' . strlen($row[$i]), $row[$i]);
+ break;
+ default:
+ $entry[$field] = $row[$i];
+ break;
+ }
+ } else {
$entry[$field] = $this->_convertFromDriver($row[$i]);
}
- $results[] = $entry;
}
+ $results[] = $entry;
}
return $results;
@@ -263,15 +273,24 @@ class Turba_Driver_sql extends Turba_Driver {
/**
* Adds the specified object to the SQL database.
*/
- function _add($attributes)
+ function _add($attributes, $blob_fields = array())
{
- $fields = array();
- $values = array();
+ $fields = $values = array();
foreach ($attributes as $field => $value) {
$fields[] = $field;
- $values[] = $this->_convertToDriver($value);
+ if (!empty($value) && isset($blob_fields[$field])) {
+ switch ($this->_write_db->dbsyntax) {
+ case 'mssql':
+ case 'pgsql':
+ $values[] = bin2hex($value);
+ break;
+ default:
+ $values[] = $value;
+ }
+ } else {
+ $values[] = $this->_convertToDriver($value);
+ }
}
-
$query = 'INSERT INTO ' . $this->_params['table']
. ' (' . implode(', ', $fields) . ')'
. ' VALUES (' . str_repeat('?, ', count($values) - 1) . '?)';
@@ -338,16 +357,26 @@ class Turba_Driver_sql extends Turba_Driver {
*
* @return string The object id, possibly updated.
*/
- function _save($object_key, $object_id, $attributes)
+ function _save($object_key, $object_id, $attributes, $blob_fields = array())
{
$where = $object_key . ' = ?';
unset($attributes[$object_key]);
- $fields = array();
- $values = array();
+ $fields = $values = array();
foreach ($attributes as $field => $value) {
$fields[] = $field . ' = ?';
- $values[] = $this->_convertToDriver($value);
+ if (!empty($value) && isset($blob_fields[$field])) {
+ switch ($this->_write_db->dbsyntax) {
+ case 'mssql':
+ case 'pgsql':
+ $values[] = bin2hex($value);
+ break;
+ default:
+ $values[] = $value;
+ }
+ } else {
+ $values[] = $this->_convertToDriver($value);
+ }
}
$values[] = $object_id;
diff --git a/lib/Forms/AddContact.php b/lib/Forms/AddContact.php
index bd8e5f6..babc7da 100644
--- a/lib/Forms/AddContact.php
+++ b/lib/Forms/AddContact.php
@@ -2,7 +2,7 @@
/**
* @package Turba
*
- * $Horde: turba/lib/Forms/AddContact.php,v 1.9.2.1 2007/12/20 14:34:30 jan Exp $
+ * $Horde: turba/lib/Forms/AddContact.php,v 1.9.2.3 2008/10/25 01:36:42 chuck Exp $
*/
/** Turba_ContactForm */
@@ -68,7 +68,12 @@ class Turba_AddContactForm extends Turba_ContactForm {
$this->getInfo($this->_vars, $info);
$source = $info['source'];
foreach ($info['object'] as $info_key => $info_val) {
- $this->_contact->setValue($info_key, $info_val);
+ if ($GLOBALS['attributes'][$info_key]['type'] == 'image' && !empty($info_val['file'])) {
+ $this->_contact->setValue($info_key, file_get_contents($info_val['file']));
+ $this->_contact->setValue($info_key . 'type', $info_val['type']);
+ } else {
+ $this->_contact->setValue($info_key, $info_val);
+ }
}
$contact = $this->_contact->attributes;
unset($contact['__owner']);
@@ -78,11 +83,16 @@ class Turba_AddContactForm extends Turba_ContactForm {
if (is_a($key, 'PEAR_Error')) {
Horde::logMessage($key, __FILE__, __LINE__, PEAR_LOG_ERR);
} else {
- $ob = $driver->getObject($key);
- if (!is_a($ob, 'PEAR_Error')) {
- $notification->push(sprintf(_("%s added."), $ob->getValue('name')), 'horde.success');
- header('Location: ' . (!empty($info['url']) ? $info['url'] : $ob->url('Contact', true)));
- exit;
+ // Try 3 times to get the new entry. We retry to allow setups like
+ // LDAP replication to work.
+ for ($i = 0; $i < 3; $i++) {
+ $ob = $driver->getObject($key);
+ if (!is_a($ob, 'PEAR_Error')) {
+ $notification->push(sprintf(_("%s added."), $ob->getValue('name')), 'horde.success');
+ header('Location: ' . (!empty($info['url']) ? $info['url'] : $ob->url('Contact', true)));
+ exit;
+ }
+ sleep(1);
}
Horde::logMessage($ob, __FILE__, __LINE__, PEAR_LOG_ERR);
}
diff --git a/lib/Forms/DeleteAddressBook.php b/lib/Forms/DeleteAddressBook.php
index 4641184..fae2552 100644
--- a/lib/Forms/DeleteAddressBook.php
+++ b/lib/Forms/DeleteAddressBook.php
@@ -2,7 +2,7 @@
/**
* Horde_Form for deleting address books.
*
- * $Horde: turba/lib/Forms/DeleteAddressBook.php,v 1.1.2.1 2007/12/24 05:18:00 chuck Exp $
+ * $Horde: turba/lib/Forms/DeleteAddressBook.php,v 1.1.2.2 2008/08/25 17:10:16 jan Exp $
*
* See the enclosed file LICENSE for license information (ASL). If you
* did not receive this file, see http://www.horde.org/licenses/asl.php.
@@ -81,6 +81,12 @@ class Turba_DeleteAddressBookForm extends Horde_Form {
unset($_SESSION['turba']['source']);
}
+ $abooks = explode("\n", $GLOBALS['prefs']->getValue('addressbooks'));
+ if (($pos = array_search($this->_addressbook->getName(), $abooks)) !== false) {
+ unset($abooks[$pos]);
+ $GLOBALS['prefs']->setValue('addressbooks', implode("\n", $abooks));
+ }
+
return true;
}
diff --git a/lib/Forms/EditContact.php b/lib/Forms/EditContact.php
index 34d6346..b3499c6 100644
--- a/lib/Forms/EditContact.php
+++ b/lib/Forms/EditContact.php
@@ -2,7 +2,7 @@
/**
* @package Turba
*
- * $Horde: turba/lib/Forms/EditContact.php,v 1.6.2.2 2008/04/17 15:53:54 chuck Exp $
+ * $Horde: turba/lib/Forms/EditContact.php,v 1.6.2.5 2008/08/12 22:05:57 jan Exp $
*/
/** Turba_ContactForm */
@@ -64,7 +64,14 @@ class Turba_EditContactForm extends Turba_ContactForm {
/* Update the contact. */
foreach ($info['object'] as $info_key => $info_val) {
if ($info_key != '__key') {
- $this->_contact->setValue($info_key, $info_val);
+ if ($GLOBALS['attributes'][$info_key]['type'] == 'image' && !empty($info_val['file'])) {
+ $this->_contact->setValue($info_key, file_get_contents($info_val['file']));
+ if (isset($info_val['type'])) {
+ $this->_contact->setValue($info_key . 'type', $info_val['type']);
+ }
+ } else {
+ $this->_contact->setValue($info_key, $info_val);
+ }
}
}
diff --git a/lib/List.php b/lib/List.php
index 1997a44..dac18f0 100644
--- a/lib/List.php
+++ b/lib/List.php
@@ -3,7 +3,7 @@
* The Turba_List:: class provides an interface for dealing with a
* list of Turba_Objects.
*
- * $Horde: turba/lib/List.php,v 1.41.10.5 2007/12/20 14:34:28 jan Exp $
+ * $Horde: turba/lib/List.php,v 1.41.10.8 2008/08/28 21:24:04 chuck Exp $
*
* @author Chuck Hagenbuch <chuck at horde.org>
* @author Jon Parise <jon at csh.rit.edu>
@@ -106,8 +106,13 @@ class Turba_List {
}
$need_lastname = false;
- foreach ($order as $sort_order) {
- if ($sort_order['field'] == 'lastname') {
+ $last_first = $GLOBALS['prefs']->getValue('name_format') == 'last_first';
+ foreach (array_keys($order) as $key) {
+ if ($last_first && $order[$key]['field'] == 'name') {
+ $order[$key]['field'] = 'lastname';
+ }
+ if ($order[$key]['field'] == 'lastname') {
+ $order[$key]['field'] = '__lastname';
$need_lastname = true;
break;
}
@@ -118,11 +123,11 @@ class Turba_List {
} else {
$sorted_objects = array();
foreach ($this->objects as $key => $object) {
- if (!$object->getValue('lastname')) {
- $object->setValue(
- 'lastname',
- Turba::guessLastname($object->getValue('name')));
+ $lastname = $object->getValue('lastname');
+ if (!$lastname) {
+ $lastname = Turba::guessLastname($object->getValue('name'));
}
+ $object->setValue('__lastname', $lastname);
$sorted_objects[$key] = $object;
}
}
diff --git a/lib/ListView.php b/lib/ListView.php
index 1f59365..38c62d4 100644
--- a/lib/ListView.php
+++ b/lib/ListView.php
@@ -3,7 +3,7 @@
* The Turba_ListView:: class provides an interface for objects that
* visualize Turba_lists.
*
- * $Horde: turba/lib/ListView.php,v 1.17.10.19 2008/04/24 03:42:56 mrubinsk Exp $
+ * $Horde: turba/lib/ListView.php,v 1.17.10.21 2008/07/20 08:01:45 jan Exp $
*
* @author Chuck Hagenbuch <chuck at horde.org>
* @author Jon Parise <jon at csh.rit.edu>
@@ -305,7 +305,7 @@ class Turba_ListView {
*/
function getSortInfoForColumn($i)
{
- $sortorder = Turba::getPreferredSortOrder($this->columns);
+ $sortorder = Turba::getPreferredSortOrder();
$column_name = $this->getColumnName($i);
$i = 0;
foreach ($sortorder as $sortfield) {
@@ -337,7 +337,7 @@ class Turba_ListView {
function getSortOrderDescription()
{
$description = array();
- $sortorder = Turba::getPreferredSortOrder($this->columns);
+ $sortorder = Turba::getPreferredSortOrder();
foreach ($sortorder as $elt) {
$field = $elt['field'];
if ($field == 'lastname') {
@@ -389,6 +389,7 @@ class Turba_ListView {
{
ob_start();
$width = floor(90 / (count($this->columns) + 1));
+ @list($own_source, $own_id) = explode(';', $GLOBALS['prefs']->getValue('own_contact'));
include TURBA_TEMPLATES . '/browse/column_headers.inc';
diff --git a/lib/Object.php b/lib/Object.php
index bc49f29..57f21f3 100644
--- a/lib/Object.php
+++ b/lib/Object.php
@@ -3,7 +3,7 @@
* The Turba_Object:: class provides a base implementation for Turba
* objects - people, groups, restaurants, etc.
*
- * $Horde: turba/lib/Object.php,v 1.17.10.8 2008/03/10 09:17:35 jan Exp $
+ * $Horde: turba/lib/Object.php,v 1.17.10.10 2008/11/07 13:20:23 wrobel Exp $
*
* @author Chuck Hagenbuch <chuck at horde.org>
* @author Jon Parise <jon at csh.rit.edu>
@@ -118,8 +118,14 @@ class Turba_Object {
$args[] = $this->getValue($field);
}
return trim(vsprintf($this->driver->map[$attribute]['format'], $args), " \t\n\r\0\x0B,");
+ } elseif (!isset($this->attributes[$attribute])) {
+ return null;
+ } elseif (isset($GLOBALS['attributes'][$attribute]) &&
+ $GLOBALS['attributes'][$attribute]['type'] == 'image') {
+ return array('load' => array('file' => basename(tempnam(Horde::getTempDir(), 'horde_form_')),
+ 'data' => $this->attributes[$attribute]));
} else {
- return isset($this->attributes[$attribute]) ? $this->attributes[$attribute] : null;
+ return $this->attributes[$attribute];
}
}
@@ -243,7 +249,10 @@ class Turba_Object {
*/
function addFile($info)
{
- $this->_vfsInit();
+ $result = $this->_vfsInit();
+ if (is_a($result, 'PEAR_Error')) {
+ return $result;
+ }
$dir = TURBA_VFS_PATH . '/' . $this->getValue('__uid');
$file = $info['name'];
diff --git a/lib/Turba.php b/lib/Turba.php
index da2437f..e785172 100644
--- a/lib/Turba.php
+++ b/lib/Turba.php
@@ -1,6 +1,6 @@
<?php
/**
- * $Horde: turba/lib/Turba.php,v 1.59.4.39 2008/06/13 09:59:43 jan Exp $
+ * $Horde: turba/lib/Turba.php,v 1.59.4.43 2008/10/07 12:56:17 jan Exp $
*
* @package Turba
*/
@@ -153,20 +153,9 @@ class Turba {
/**
* Returns the sort order selected by the user
*/
- function getPreferredSortOrder($columns)
+ function getPreferredSortOrder()
{
- global $prefs;
-
- $order = @unserialize($prefs->getValue('sortorder'));
- if ($prefs->getValue('name_format') == 'last_first') {
- for ($i = 0, $i_max = count($order); $i < $i_max; ++$i) {
- if ($order[$i]['field'] == 'name') {
- $order[$i]['field'] = 'lastname';
- }
- }
- }
-
- return $order;
+ return @unserialize($GLOBALS['prefs']->getValue('sortorder'));
}
/**
@@ -174,15 +163,7 @@ class Turba {
*/
function getColumnName($i, $columns)
{
- if ($i == 0) {
- if ($GLOBALS['prefs']->getValue('name_format') == 'first_last') {
- return 'name';
- } else {
- return 'lastname';
- }
- } else {
- return $columns[$i - 1];
- }
+ return $i == 0 ? 'name' : $columns[$i - 1];
}
/**
@@ -234,7 +215,7 @@ class Turba {
$name = $namelist[$nameindex];
}
}
- return $name;
+ return strlen($name) ? $name : null;
}
/**
@@ -592,14 +573,19 @@ class Turba {
/* Update share_id as backends like Kolab change it to the IMAP folder
* name. */
- $share_id = $share->getId();
-
- /* Add the new addressbook to the user's list of visible
- * address books. */
- $prefs = explode("\n", $GLOBALS['prefs']->getValue('addressbooks'));
- if (array_search($share_id, $prefs) === false) {
- $GLOBALS['prefs']->setValue('addressbooks', $GLOBALS['prefs']->getValue('addressbooks') . "\n" . $share_id);
+ $share_id = $share->getName();
+
+ /* Add the new addressbook to the user's list of visible address
+ * books. */
+ $prefs = $GLOBALS['prefs']->getValue('addressbooks');
+ if ($prefs) {
+ $prefs = explode("\n", $prefs);
+ if (array_search($share_id, $prefs) === false) {
+ $prefs[] = $share_id;
+ $GLOBALS['prefs']->setValue('addressbooks', implode("\n", $prefs));
+ }
}
+
return $share;
}
diff --git a/lib/Views/Browse.php b/lib/Views/Browse.php
index 2068e60..c1433cf 100644
--- a/lib/Views/Browse.php
+++ b/lib/Views/Browse.php
@@ -1,6 +1,6 @@
<?php
/**
- * $Horde: turba/lib/Views/Browse.php,v 1.12.2.6 2008/04/04 20:13:34 jan Exp $
+ * $Horde: turba/lib/Views/Browse.php,v 1.12.2.8 2008/09/11 08:46:20 jan Exp $
*
* Copyright 2000-2008 The Horde Project (http://www.horde.org/)
*
@@ -43,7 +43,7 @@ class Turba_View_Browse {
{
extract($this->_params, EXTR_REFS);
- if (($sortby = $vars->get('sortby')) !== null && $sortby != '') {
+ if (strlen($sortby = $vars->get('sortby'))) {
$sources = Turba::getColumns();
$columns = isset($sources[$source]) ? $sources[$source] : array();
$column_name = Turba::getColumnName($sortby, $columns);
@@ -51,7 +51,7 @@ class Turba_View_Browse {
$append = true;
$ascending = ($vars->get('sortdir') == 0);
if ($vars->get('sortadd')) {
- $sortorder = Turba::getPreferredSortOrder($columns);
+ $sortorder = Turba::getPreferredSortOrder();
foreach ($sortorder as $i => $elt) {
if ($elt['field'] == $column_name) {
$sortorder[$i]['ascending'] = $ascending;
@@ -220,6 +220,13 @@ class Turba_View_Browse {
if (is_a($sourceDriver->delete($objectKey), 'PEAR_Error')) {
$notification->push(sprintf(_("There was an error deleting \"%s\" from the source address book."), $object->getValue('name')), 'horde.error');
}
+
+ /* Log the adding of this item in the history again,
+ * because otherwise the delete log would be after the
+ * add log. */
+ $history = &Horde_History::singleton();
+ $history->log('turba:' . $targetDriver->getName() . ':' . $objAttributes['__uid'],
+ array('action' => 'add'), true);
}
}
break;
@@ -329,7 +336,7 @@ class Turba_View_Browse {
// Read the columns to display from the preferences.
$sources = Turba::getColumns();
$columns = isset($sources[$source]) ? $sources[$source] : array();
- $sortorder = Turba::getPreferredSortOrder($columns);
+ $sortorder = Turba::getPreferredSortOrder();
if ($vars->get('key')) {
// We are displaying a list.
diff --git a/lib/api.php b/lib/api.php
index 9c327f6..b4d18d1 100644
--- a/lib/api.php
+++ b/lib/api.php
@@ -2,7 +2,7 @@
/**
* Turba external API interface.
*
- * $Horde: turba/lib/api.php,v 1.120.2.49 2008/05/31 20:20:51 mrubinsk Exp $
+ * $Horde: turba/lib/api.php,v 1.120.2.61 2008/09/18 17:25:41 mrubinsk Exp $
*
* This file defines Turba's external API interface. Other applications can
* interact with Turba through this API.
@@ -69,6 +69,11 @@ $_services['export'] = array(
'type' => 'string',
);
+$_services['ownVCard'] = array(
+ 'args' => array(),
+ 'type' => 'string',
+);
+
$_services['delete'] = array(
'args' => array('uid' => 'string'),
'type' => 'boolean',
@@ -83,7 +88,8 @@ $_services['search'] = array(
'args' => array('names' => '{urn:horde}stringArray',
'sources' => '{urn:horde}stringArray',
'fields' => '{urn:horde}stringArray',
- 'matchBegin' => 'boolean'),
+ 'matchBegin' => 'boolean',
+ 'forceSource' => 'boolean'),
'type' => '{urn:horde}stringArray',
);
@@ -201,33 +207,50 @@ function _turba_removeUserData($user)
/* We need a clean copy of the $cfgSources array here.*/
require TURBA_BASE . '/config/sources.php';
$hasError = false;
- $shares = null;
foreach ($cfgSources as $source) {
if (empty($source['use_shares'])) {
// Shares not enabled for this source
$driver = &Turba_Driver::singleton($source);
if (is_a($driver, 'PEAR_Error')) {
+ Horde::logMessage($driver, __FILE__, __LINE__, PEAR_LOG_ERR);
$hasError = true;
} else {
$result = $driver->removeUserData($user);
if (is_a($result, 'PEAR_Error')) {
- $hasError = true;
+ Horde::logMessage($result, __FILE__, __LINE__, PEAR_LOG_ERR);
}
}
}
}
- $shares = &$GLOBALS['turba_shares']->listShares($user,
- PERMS_EDIT,
- $user);
- foreach ($shares as $share) {
- $params = @unserialize($share->get('params'));
- $config = Turba::getSourceFromShare($share);
- $driver = &Turba_Driver::singleton($config);
- $result = $driver->removeUserData($user);
- if (is_a($result, 'PEAR_Error')) {
- $hasError = true;
+ /* Only attempt share removal if we have shares configured */
+ if ($_SESSION['turba']['has_share']) {
+ $shares = &$GLOBALS['turba_shares']->listShares(
+ $user, PERMS_EDIT, $user);
+
+ /* Look for the deleted user's default share and remove it */
+ foreach ($shares as $share) {
+ $params = @unserialize($share->get('params'));
+ /* Only attempt to delete the user's default share */
+ if (!empty($params['default'])) {
+ $config = Turba::getSourceFromShare($share);
+ $driver = &Turba_Driver::singleton($config);
+ $result = $driver->removeUserData($user);
+ if (is_a($result, 'PEAR_Error')) {
+ Horde::logMessage($result, __FILE__, __LINE__, PEAR_LOG_ERR);
+ $hasError = true;
+ }
+ }
+ }
+
+ /* Get a list of all shares this user has perms to and remove the perms */
+ $shares = $GLOBALS['turba_shares']->listShares($user);
+ if (is_a($shares, 'PEAR_Error')) {
+ Horde::logMessage($shares, __FILE__, __LINE__, PEAR_LOG_ERR);
+ }
+ foreach ($shares as $share) {
+ $share->removeUser($user);
}
}
@@ -809,7 +832,8 @@ function _turba_getActionTimestamp($uid, $action, $sources = null)
*
* @param string $content The content of the contact.
* @param string $contentType What format is the data in? Currently supports
- * array and text/(x-)vcard.
+ * array, text/directory, text/vcard and
+ * text/x-vcard.
* @param string $source The source into which the contact will be
* imported.
*
@@ -858,6 +882,7 @@ function _turba_import($content, $contentType = 'array', $import_source = null)
case 'text/x-vcard':
case 'text/vcard':
+ case 'text/directory':
require_once 'Horde/iCalendar.php';
$iCal = new Horde_iCalendar();
if (!$iCal->parsevCalendar($content)) {
@@ -936,9 +961,10 @@ function _turba_import($content, $contentType = 'array', $import_source = null)
* @param string $uid Identify the contact to export.
* @param mixed $contentType What format should the data be in?
* Either a string with one of:
+ * - text/directory
* - text/vcard
* - text/x-vcard
- * The first produces a vcard3.0 (rfc2426),
+ * The first two produce a vcard3.0 (rfc2426),
* the second produces a vcard in old 2.1 format
* defined by imc.org
* @param string|array $sources The source(s) from which the contact will be
@@ -992,16 +1018,16 @@ function _turba_export($uid, $contentType, $sources = null)
}
$version = '3.0';
+ list($contentType,) = explode(';', $contentType);
switch ($contentType) {
- case 'text/x-vcard;version=2.1':
case 'text/x-vcard':
$version = '2.1';
case 'text/vcard':
+ case 'text/directory':
require_once 'Horde/iCalendar.php';
$export = '';
foreach ($result->objects as $obj) {
$vcard = $driver->tovCard($obj, $version);
- $vcard->setAttribute('VERSION', $version);
/* vCards are not enclosed in BEGIN:VCALENDAR..END:VCALENDAR.
* Export the individual cards instead. */
$export .= $vcard->exportvCalendar();
@@ -1016,6 +1042,47 @@ function _turba_export($uid, $contentType, $sources = null)
}
/**
+ * Exports the user's own contact as a vCard string.
+ *
+ * @return string The requested vCard data or PEAR_Error.
+ */
+function _turba_ownVCard()
+{
+ require_once dirname(__FILE__) . '/base.php';
+ global $cfgSources;
+
+ $own_contact = $GLOBALS['prefs']->getValue('own_contact');
+ if (empty($own_contact)) {
+ return PEAR::raiseError(_("You didn't mark a contact as your own yet."));
+ }
+ @list($source, $id) = explode(';', $own_contact);
+
+ if (!isset($cfgSources[$source])) {
+ return PEAR::raiseError(_("The address book with your own contact doesn't exist anymore."));
+ }
+
+ $driver = &Turba_Driver::singleton($source);
+ if (is_a($driver, 'PEAR_Error')) {
+ return PEAR::raiseError(sprintf(_("Connection failed: %s"), $driver->getMessage()));
+ }
+
+ if (!$driver->hasPermission(PERMS_READ)) {
+ return PEAR::raiseError(_("You don't have sufficient permissions to read the address book that contains your own contact."));
+ }
+
+ $contact = $driver->getObject($id);
+ if (is_a($contact, 'PEAR_Error')) {
+ return PEAR::raiseError(_("Your own contact cannot be found in the address book."));
+ }
+
+ require_once 'Horde/iCalendar.php';
+ $vcard = $driver->tovCard($contact, '3.0');
+ $vcard->setAttribute('VERSION', '3.0');
+
+ return $vcard->exportvCalendar();
+}
+
+/**
* Deletes a contact identified by UID.
*
* @param string|array $uid Identify the contact to delete, either a
@@ -1097,7 +1164,8 @@ function _turba_delete($uid, $sources = null)
* @param string $uid Idenfity the contact to replace.
* @param string $content The content of the contact.
* @param string $contentType What format is the data in? Currently supports
- * array and text/(x-)vcard.
+ * array, text/directory, text/vcard and
+ * text/x-vcard.
* @param string|array $sources The source(s) where the contact will be
* replaced.
*
@@ -1155,6 +1223,7 @@ function _turba_replace($uid, $content, $contentType, $sources = null)
case 'text/x-vcard':
case 'text/vcard':
+ case 'text/directory':
require_once 'Horde/iCalendar.php';
$iCal = new Horde_iCalendar();
if (!$iCal->parsevCalendar($content)) {
@@ -1198,11 +1267,13 @@ function _turba_replace($uid, $content, $contentType, $sources = null)
* @param array $sources The sources to serach in
* @param array $fields The fields to serach on
* @param boolean $matchBegin Match word boundaries only
+ * @param boolean $forceSource Whether to use the specified sources, even if
+ * they have been disabled in the preferences.
*
* @return array Hash containing the search results.
*/
function _turba_search($names = array(), $sources = array(), $fields = array(),
- $matchBegin = false)
+ $matchBegin = false, $forceSource = false)
{
require_once dirname(__FILE__) . '/base.php';
require_once 'Horde/MIME.php';
@@ -1216,11 +1287,13 @@ function _turba_search($names = array(), $sources = array(), $fields = array(),
$names = is_null($names) ? array() : array($names);
}
- // Make sure the selected source is activated in Turba.
- $addressbooks = array_keys(Turba::getAddressBookOrder());
- foreach (array_keys($sources) as $id) {
- if (!in_array($sources[$id], $addressbooks)) {
- unset($sources[$id]);
+ if (!$forceSource) {
+ // Make sure the selected source is activated in Turba.
+ $addressbooks = array_keys(Turba::getAddressBooks());
+ foreach (array_keys($sources) as $id) {
+ if (!in_array($sources[$id], $addressbooks)) {
+ unset($sources[$id]);
+ }
}
}
@@ -1266,7 +1339,7 @@ function _turba_search($names = array(), $sources = array(), $fields = array(),
$criteria['name'] = trim($name);
}
- $search = $driver->search($criteria, Turba::getPreferredSortOrder($columns), 'OR', array(), array(), $matchBegin);
+ $search = $driver->search($criteria, Turba::getPreferredSortOrder(), 'OR', array(), array(), $matchBegin);
if (!is_a($search, 'Turba_List')) {
continue;
}
@@ -1301,9 +1374,15 @@ function _turba_search($names = array(), $sources = array(), $fields = array(),
}
}
+ if ($ob->hasValue('name') ||
+ !isset($ob->driver->alternativeName)) {
+ $display_name = Turba::formatName($ob);
+ } else {
+ $display_name = $ob->getValue($ob->driver->alternativeName);
+ }
if (count($email)) {
for ($i = 0; $i < count($email); $i++) {
- $seen_key = trim(String::lower($ob->getValue('name'))) . '/' . trim(String::lower($email[$i]));
+ $seen_key = trim(String::lower($display_name)) . '/' . trim(String::lower($email[$i]));
if (!empty($seen[$seen_key])) {
continue;
}
@@ -1313,7 +1392,7 @@ function _turba_search($names = array(), $sources = array(), $fields = array(),
}
$results[$name][] = array_merge($att,
array('id' => $att['__key'],
- 'name' => Turba::formatName($ob),
+ 'name' => $display_name,
'email' => $email[$i],
'__type' => 'Object',
'source' => $source));
@@ -1324,7 +1403,7 @@ function _turba_search($names = array(), $sources = array(), $fields = array(),
}
$results[$name][] = array_merge($att,
array('id' => $att['__key'],
- 'name' => Turba::formatName($ob),
+ 'name' => $display_name,
'email' => null,
'__type' => 'Object',
'source' => $source));
@@ -1666,14 +1745,16 @@ function _turba_deleteClient($objectId = '')
*/
function _turba_searchClients($names = array(), $fields = array(), $matchBegin = false)
{
- return _turba_search($names,
- array($GLOBALS['conf']['client']['addressbook']),
- array($GLOBALS['conf']['client']['addressbook'] => $fields),
- $matchBegin);
+ return _turba_search(
+ $names,
+ array($GLOBALS['conf']['client']['addressbook']),
+ array($GLOBALS['conf']['client']['addressbook'] => $fields),
+ $matchBegin,
+ true);
}
/**
- * Sets the value of the specified attribute of an contact
+ * Sets the value of the specified attribute of a contact
*
* @param string $address Contact email address
* @param string $name Contact name
diff --git a/lib/prefs.php b/lib/prefs.php
index 741d7b1..b8416df 100644
--- a/lib/prefs.php
+++ b/lib/prefs.php
@@ -1,6 +1,6 @@
<?php
/**
- * $Horde: turba/lib/prefs.php,v 1.2.10.9 2008/04/10 13:37:07 jan Exp $
+ * $Horde: turba/lib/prefs.php,v 1.2.10.10 2008/08/25 17:10:33 jan Exp $
*
* Copyright 2001-2008 The Horde Project (http://www.horde.org/)
*
@@ -22,7 +22,7 @@ function handle_columnselect($updated)
function handle_addressbookselect($updated)
{
$addressbooks = Util::getFormData('addressbooks');
- $GLOBALS['prefs']->setValue('addressbooks', $addressbooks);
+ $GLOBALS['prefs']->setValue('addressbooks', str_replace("\r", '', $addressbooks));
return true;
}
diff --git a/lib/tests/KolabTest.php b/lib/tests/KolabTest.php
new file mode 100644
index 0000000..5c697f1
--- /dev/null
+++ b/lib/tests/KolabTest.php
@@ -0,0 +1,203 @@
+<?php
+
+require_once dirname(__FILE__) . '/KolabTestBase.php';
+
+/**
+ * $Horde: turba/lib/tests/KolabTest.php,v 1.1.2.2 2008/11/07 15:03:33 selsky Exp $
+ *
+ * @author Jason M. Felice <jason.m.felice at gmail.com>
+ * @package Turba
+ * @subpackage UnitTests
+ */
+class Turba_KolabTest extends Turba_KolabTestBase {
+
+ /**
+ * Test setup.
+ *
+ * @return NULL
+ */
+ public function setUp()
+ {
+ $this->prepareTurba();
+
+ $this->_kolab = &new Kolab();
+ }
+
+ function testBug5476()
+ {
+ /* Open our addressbook */
+ $this->_kolab->open('INBOX/Contacts', 1);
+
+ $object = array(
+ 'uid' => 1,
+ 'given-name' => 'test',
+ 'last-name' => 'test',
+ 'full-name' => 'test test',
+ );
+
+ // Save the contact
+ $this->_kolab->_storage->save($object);
+
+ $object = array(
+ 'uid' => 2,
+ 'given-name' => 'test2',
+ 'last-name' => 'test2',
+ 'full-name' => 'test2 test2',
+ );
+
+ // Save the contact
+ $this->_kolab->_storage->save($object);
+
+ // Check that the driver can be created
+ $turba = Turba_Driver::singleton('wrobel at example.org');
+ $this->assertNoError($turba);
+
+ $result = $turba->search(array(), array('last-name'));
+ $this->assertNoError($result);
+ $this->assertEquals(2, $result->count());
+
+ $turba = Turba_Driver::singleton('INBOX%2Ftest2');
+ $result = $turba->search(array(), array('last-name'));
+
+ $this->assertEquals(0, $result->count());
+ }
+
+ function testPhoto()
+ {
+ /* Open our addressbook */
+ $this->_kolab->open('INBOX/Contacts', 1);
+
+ $object = array(
+ 'uid' => 1,
+ 'given-name' => 'photo',
+ 'last-name' => 'photo',
+ 'full-name' => 'photo photo',
+ 'photo' => 'abcd',
+ 'phototype' => 'image/jpeg',
+ );
+
+ // Save the contact
+ $turba = Turba_Driver::singleton('wrobel at example.org');
+ $this->assertNoError($turba);
+
+ $this->assertNoError($turba->_add($object));
+
+ $list = Kolab_List::singleton();
+ $share = &$list->getByShare('INBOX/Contacts', 'contact');
+ $data = &$share->getData();
+ $object = $data->getObject('1');
+ $this->assertTrue(isset($object['_attachments'][$object['picture']]));
+ $attachment = $data->getAttachment($object['_attachments'][$object['picture']]['key']);
+ $this->assertEquals("abcd\n", $attachment);
+ }
+
+ function testAttachments()
+ {
+ /* Open our addressbook */
+ $this->_kolab->open('INBOX/Contacts', 1);
+
+ $object = array(
+ 'uid' => 'a',
+ 'given-name' => 'atc',
+ 'last-name' => 'atc',
+ 'full-name' => 'atc atc',
+ );
+
+ // Save the contact
+ $turba = Turba_Driver::singleton('wrobel at example.org');
+ $this->assertNoError($turba);
+
+ $this->assertNoError($turba->_add($object));
+
+ $contact = $turba->getObject('a');
+ $this->assertNoError($contact);
+
+ $list = Kolab_List::singleton();
+ $share = &$list->getByShare('INBOX/Contacts', 'contact');
+ $data = &$share->getData();
+
+ $atc1 = Util::getTempFile();
+ $fh = fopen($atc1, 'w');
+ fwrite($fh, 'test');
+ fclose($fh);
+
+ $info = array('tmp_name' => $atc1,
+ 'name' => 'test.txt');
+ $this->assertNoError($contact->addFile($info));
+
+ $objects = $data->getObjects();
+ $this->assertEquals(1, count($objects));
+ $object = $data->getObject('a');
+ $this->assertTrue(isset($object['_attachments']));
+ $this->assertEquals(1, count($object['_attachments']));
+ $this->assertEquals(1, count($object['link-attachment']));
+ $this->assertContains('test.txt', $object['link-attachment']);
+ $attachment = $data->getAttachment($object['_attachments']['test.txt']['key']);
+ $this->assertEquals("test\n", $attachment);
+
+ $atc1 = Util::getTempFile();
+ $fh = fopen($atc1, 'w');
+ fwrite($fh, 'hhhh');
+ fclose($fh);
+
+ $info = array('tmp_name' => $atc1,
+ 'name' => 'test.txt');
+ $this->assertNoError($contact->addFile($info));
+
+ $objects = $data->getObjects();
+ $this->assertEquals(1, count($objects));
+ $object = $data->getObject('a');
+ $this->assertTrue(isset($object['_attachments']));
+ $this->assertEquals(2, count($object['_attachments']));
+ $this->assertEquals(2, count($object['link-attachment']));
+ $this->assertContains('test[1].txt', $object['link-attachment']);
+ $attachment = $data->getAttachment($object['_attachments']['test[1].txt']['key']);
+ $this->assertEquals("hhhh\n", $attachment);
+
+ $atc1 = Util::getTempFile();
+ $fh = fopen($atc1, 'w');
+ fwrite($fh, 'dummy');
+ fclose($fh);
+
+ $info = array('tmp_name' => $atc1,
+ 'name' => 'dummy.txt');
+ $this->assertNoError($contact->addFile($info));
+
+ $objects = $data->getObjects();
+ $this->assertEquals(1, count($objects));
+ $object = $data->getObject('a');
+ $this->assertTrue(isset($object['_attachments']));
+ $this->assertEquals(3, count($object['_attachments']));
+ $this->assertEquals(3, count($object['link-attachment']));
+ $this->assertContains('dummy.txt', $object['link-attachment']);
+ $attachment = $data->getAttachment($object['_attachments']['dummy.txt']['key']);
+ $this->assertEquals("dummy\n", $attachment);
+
+ $this->assertError($contact->deleteFile('doesnotexist.txt'), "Unable to delete VFS file.");
+
+ $this->assertNoError($contact->deleteFile('test[1].txt'));
+
+ $objects = $data->getObjects();
+ $this->assertEquals(1, count($objects));
+ $object = $data->getObject('a');
+ $this->assertTrue(!isset($object['_attachments']['test[1].txt']));
+ $this->assertEquals(2, count($object['_attachments']));
+ $this->assertEquals(2, count($object['link-attachment']));
+ $this->assertNotContains('test[1].txt', $object['link-attachment']);
+
+ $files = $contact->listFiles();
+ $this->assertNoError($files);
+
+ $this->assertContains('test.txt', array_keys($files));
+ $this->assertContains('dummy.txt', array_keys($files));
+
+ $this->assertNoError($contact->deleteFiles());
+
+ $objects = $data->getObjects();
+ $this->assertEquals(1, count($objects));
+ $object = $data->getObject('a');
+ $this->assertTrue(!isset($object['_attachments']['test.txt']));
+ $this->assertTrue(!isset($object['_attachments']));
+ $this->assertTrue(!isset($object['link-attachment']));
+ }
+}
diff --git a/lib/tests/KolabTestBase.php b/lib/tests/KolabTestBase.php
new file mode 100644
index 0000000..ab1048e
--- /dev/null
+++ b/lib/tests/KolabTestBase.php
@@ -0,0 +1,185 @@
+<?php
+/**
+ * Base for PHPUnit scenarios.
+ *
+ * $Horde: turba/lib/tests/KolabTestBase.php,v 1.1.2.1 2008/11/07 13:20:23 wrobel Exp $
+ *
+ * PHP version 5
+ *
+ * @category Kolab
+ * @package Kolab_Test
+ * @author Gunnar Wrobel <wrobel at pardus.de>
+ * @license http://www.fsf.org/copyleft/lgpl.html LGPL
+ * @link http://pear.horde.org/index.php?package=Kolab_Storage
+ */
+
+/**
+ * We need the unit test framework
+ */
+require_once 'Horde/Kolab/Test/Storage.php';
+
+/**
+ * We need some additional tools for Turba
+ */
+require_once 'Horde/Share.php';
+require_once 'Horde/Kolab.php';
+
+/**
+ * Base for PHPUnit scenarios.
+ *
+ * $Horde: turba/lib/tests/KolabTestBase.php,v 1.1.2.1 2008/11/07 13:20:23 wrobel Exp $
+ *
+ * Copyright 2008 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.
+ *
+ * @category Kolab
+ * @package Kolab_Test
+ * @author Gunnar Wrobel <wrobel at pardus.de>
+ * @license http://www.fsf.org/copyleft/lgpl.html LGPL
+ * @link http://pear.horde.org/index.php?package=Kolab_Storage
+ */
+class Turba_KolabTestBase extends Horde_Kolab_Test_Storage
+{
+ /**
+ * Handle a "given" step.
+ *
+ * @param array &$world Joined "world" of variables.
+ * @param string $action The description of the step.
+ * @param array $arguments Additional arguments to the step.
+ *
+ * @return mixed The outcome of the step.
+ */
+ public function runGiven(&$world, $action, $arguments)
+ {
+ switch($action) {
+ default:
+ return parent::runGiven($world, $action, $arguments);
+ }
+ }
+
+ /**
+ * Handle a "when" step.
+ *
+ * @param array &$world Joined "world" of variables.
+ * @param string $action The description of the step.
+ * @param array $arguments Additional arguments to the step.
+ *
+ * @return mixed The outcome of the step.
+ */
+ public function runWhen(&$world, $action, $arguments)
+ {
+ switch($action) {
+ default:
+ return parent::runWhen($world, $action, $arguments);
+ }
+ }
+
+ /**
+ * Handle a "then" step.
+ *
+ * @param array &$world Joined "world" of variables.
+ * @param string $action The description of the step.
+ * @param array $arguments Additional arguments to the step.
+ *
+ * @return mixed The outcome of the step.
+ */
+ public function runThen(&$world, $action, $arguments)
+ {
+ switch($action) {
+ default:
+ return parent::runThen($world, $action, $arguments);
+ }
+ }
+
+ /**
+ * Prepare the configuration.
+ *
+ * @return NULL
+ */
+ public function prepareConfiguration()
+ {
+ }
+
+ /**
+ * Prepare the registry.
+ *
+ * @return NULL
+ */
+ public function prepareRegistry()
+ {
+ }
+
+ /**
+ * Prepare the notification setup.
+ *
+ * @return NULL
+ */
+ public function prepareNotification()
+ {
+ }
+
+ /**
+ * Fix the read configuration.
+ *
+ * @return NULL
+ */
+ public function prepareFixedConfiguration()
+ {
+ $GLOBALS['conf'] = &$GLOBALS['registry']->_confCache['horde'];
+ $GLOBALS['conf']['kolab']['server']['driver'] = 'test';
+ $GLOBALS['conf']['documents']['type'] = 'horde';
+ }
+
+ /**
+ * Prepare the Turba setup.
+ *
+ * @return NULL
+ */
+ public function prepareTurba()
+ {
+ $world = &$this->prepareBasicSetup();
+
+ $this->assertTrue($world['auth']->authenticate('wrobel at example.org',
+ array('password' => 'none')));
+
+ $GLOBALS['registry']->pushApp('turba');
+
+ // Find the base file path of Turba.
+ if (!defined('TURBA_BASE')) {
+ define('TURBA_BASE', dirname(__FILE__) . '/../..');
+ }
+
+ // Turba base libraries.
+ require_once TURBA_BASE . '/lib/Turba.php';
+ require_once TURBA_BASE . '/lib/Driver.php';
+ require_once TURBA_BASE . '/lib/Object.php';
+
+ // Turba source and attribute configuration.
+ include TURBA_BASE . '/config/attributes.php';
+ include TURBA_BASE . '/config/sources.php';
+ unset($cfgSources['kolab_global']);
+
+ $this->prepareNewFolder($world['storage'], 'Contacts', 'contact', true);
+ $this->prepareNewFolder($world['storage'], 'test2', 'contact');
+
+ $_SESSION['turba']['has_share'] = true;
+ $GLOBALS['turba_shares'] = &Horde_Share::singleton('turba');
+
+ $GLOBALS['cfgSources'] = Turba::getConfigFromShares($cfgSources);
+
+ // Disable maintenance
+ $GLOBALS['prefs']->setValue('turba_maintenance_tasks',
+ serialize(array('upgradeprefs', 'upgradelists')));
+ }
+
+
+ function provideServerName() {
+ return 'localhost.localdomain';
+ }
+
+ function provideHordeBase() {
+ return dirname(__FILE__) . '/../../../';
+ }
+}
diff --git a/themes/graphics/az.png b/lib/tests/az.png
similarity index 100%
copy from themes/graphics/az.png
copy to lib/tests/az.png
diff --git a/lib/tests/tohash.phpt b/lib/tests/tohash.phpt
index 2e401bb..50c9652 100644
--- a/lib/tests/tohash.phpt
+++ b/lib/tests/tohash.phpt
@@ -22,6 +22,7 @@ EMAIL:jan at horde.org
NICKNAME:yunosh
TEL;HOME:+49 521 555123
TEL;WORK:+49 521 555456
+TEL;WORK:+49 521 999999
TEL;CELL:+49 177 555123
TEL;FAX:+49 521 555789
TEL;PAGER:+49 123 555789
@@ -42,7 +43,7 @@ ADR;HOME;CHARSET=ISO-8859-1;ENCODING=QUOTED-PRINTABLE:=
ADR;WORK;CHARSET=ISO-8859-1;ENCODING=QUOTED-PRINTABLE:=
;;H=FCbschestr. 19;K=F6ln;Allg=E4u;;D=E4nemark
TZ;VALUE=text:+02:00; Europe/Berlin
-GEO:52.516276;13.377778
+GEO:13.377778,52.516276
BODY:
END:VCARD
';
@@ -103,6 +104,95 @@ TEL;VOICE;WORK:6
END:VCARD
';
+$vcard6 = '
+BEGIN:VCARD
+VERSION:2.1
+N:Lastname;Firstname;;;
+FN:Lastname, Firstname
+TITLE:
+ORG:Company Name;
+BDAY:
+TEL;HOME;VOICE;X-Synthesis-Ref1:(xxx) xxx-xxxx
+TEL;WORK;VOICE;X-Synthesis-Ref1:(xxx) xxx-xxxx
+TEL;CELL;VOICE;X-Synthesis-Ref1:(xxx) xxx-xxxx
+EMAIL:email at domain.com
+URL:
+CATEGORIES:Friends
+NOTE;ENCODING=QUOTED-PRINTABLE:
+EIN: xx-xxxxxxx
+ADR;HOME:;;Street address;City;St;12345;USA
+ADR;WORK:;;Street address;City;St;12345;USA
+PHOTO:
+END:VCARD
+';
+
+$vcard7 = '
+BEGIN:VCARD
+FN:Jan Schneider
+N:Schneider;Jan;;;
+PHOTO;ENCODING=b;TYPE=image/png:iVBORw0KGgoAAAANSUhEUgAAAAkAAAAJAgMAAACd/+6D
+ AAAACVBMVEW6ABZmZmYAAACMtcxCAAAAAXRSTlMAQObYZgAAABpJREFUCFtjYACBBgYmRgEIZm
+ GBYAFGMAYBABVmAOEH9qP8AAAAAElFTkSuQmCC
+UID:nhCnPyv0u7
+VERSION:2.1
+END:VCARD
+';
+
+$vcard8 = '
+BEGIN:VCARD
+FN:Jan Schneider
+N:Schneider;Jan;;;
+EMAIL;WORK:work at example.com
+EMAIL;HOME:home at example.com
+EMAIL:mail at example.com
+EMAIL;PREF:pref at example.com
+UID:nhCnPyv0u7
+VERSION:2.1
+END:VCARD
+';
+
+$vcard9 = '
+BEGIN:VCARD
+VERSION:2.1
+N:Blow;Joe;;;
+FN:Blow, Joe
+TITLE:
+ORG:;
+BDAY:19700327
+TEL;HOME;VOICE;X-Synthesis-Ref1:302 834 9999
+TEL;CELL;VOICE;X-Synthesis-Ref1:302 521 9999
+EMAIL:Blow at somwhere.net
+URL:
+CATEGORIES:Personal
+NOTE:
+ADR;HOME:;;;;;;
+PHOTO:
+END:VCARD
+';
+
+// Invalid ENCODING value.
+$vcard10 = '
+BEGIN:VCARD
+VERSION:3.0
+PRODID:-//Synthesis AG//NONSGML SyncML Engine V3.1.6.10//EN
+REV:20081004T151032
+N:McTester;Testie;;;
+FN:Testie McTester
+ORG:Testers Inc;
+TEL;TYPE=VOICE,CELL,X-Synthesis-Ref0:+44 775550555
+TEL;TYPE=HOME,VOICE,X-Synthesis-Ref1:+44 205550555
+TEL;TYPE=WORK,VOICE,X-Synthesis-Ref2:+44 205550556
+EMAIL;TYPE=HOME,INTERNET,X-Synthesis-Ref0:test at example.org
+EMAIL;TYPE=WORK,INTERNET,X-Synthesis-Ref1:test at example.com
+ADR;TYPE=HOME,X-Synthesis-Ref0:;;111 One Street;London;;W1 1AA;
+BDAY:20081008
+PHOTO;TYPE=JPEG;ENCODING=BASE64:wolQTkcNChoKAAAADUlIRFIAAAAJAAAACQIDAAAAwp3
+ Dv8OuwoMAAAAJUExURcK6ABZmZmYAAADCjMK1w4xCAAAAAXRSTlMAQMOmw5hmAAAAGklEQVQIW2
+ NgAMKBBgYmRgEIZmHCgWABRjAGAQAVZgDDoQfDtsKjw7wAAAAASUVORMKuQmDCgg==
+
+END:VCARD
+';
+
$driver = new Turba_Driver(array());
$iCal = new Horde_iCalendar();
@@ -135,6 +225,30 @@ $iCal->parsevCalendar($vcard5);
var_export($driver->toHash($iCal->getComponent(0)));
echo "\n";
+$iCal->parsevCalendar($vcard6);
+var_export($driver->toHash($iCal->getComponent(0)));
+echo "\n";
+
+$iCal->parsevCalendar($vcard7);
+$hash = $driver->toHash($iCal->getComponent(0));
+var_export($hash['photo'] == file_get_contents(dirname(__FILE__) . '/az.png'));
+echo "\n";
+
+$iCal->parsevCalendar($vcard8);
+var_export($driver->toHash($iCal->getComponent(0)));
+echo "\n";
+
+$iCal->parsevCalendar($vcard9);
+var_export($driver->toHash($iCal->getComponent(0)));
+echo "\n";
+
+$iCal->parsevCalendar($vcard10);
+$hash = $driver->toHash($iCal->getComponent(0));
+var_export(strlen($hash['photo']));
+echo "\n";
+unset($hash['photo']);
+var_export($hash);
+
?>
--EXPECT--
array (
@@ -245,3 +359,84 @@ array (
'workPhone' => '6',
'name' => 'A B',
)
+array (
+ 'lastname' => 'Lastname',
+ 'firstname' => 'Firstname',
+ 'name' => 'Lastname, Firstname',
+ 'company' => 'Company Name',
+ 'department' => '',
+ 'homePhone' => '(xxx) xxx-xxxx',
+ 'workPhone' => '(xxx) xxx-xxxx',
+ 'cellPhone' => '(xxx) xxx-xxxx',
+ 'email' => 'email at domain.com',
+ 'emails' => 'email at domain.com',
+ 'category' => 'Friends',
+ 'businessCategory' => 'Friends',
+ 'homeAddress' => 'Street address
+City, St 12345
+USA',
+ 'homeStreet' => 'Street address',
+ 'homeCity' => 'City',
+ 'homeProvince' => 'St',
+ 'homePostalCode' => '12345',
+ 'homeCountry' => 'USA',
+ 'workAddress' => 'Street address
+City, St 12345
+USA',
+ 'workStreet' => 'Street address',
+ 'workCity' => 'City',
+ 'workProvince' => 'St',
+ 'workPostalCode' => '12345',
+ 'workCountry' => 'USA',
+)
+true
+array (
+ 'name' => 'Jan Schneider',
+ 'lastname' => 'Schneider',
+ 'firstname' => 'Jan',
+ 'workEmail' => 'work at example.com',
+ 'emails' => 'work at example.com, home at example.com, mail at example.com, pref at example.com',
+ 'homeEmail' => 'home at example.com',
+ 'email' => 'pref at example.com',
+)
+array (
+ 'lastname' => 'Blow',
+ 'firstname' => 'Joe',
+ 'name' => 'Blow, Joe',
+ 'company' => '',
+ 'department' => '',
+ 'birthday' => '1970-03-27',
+ 'homePhone' => '302 834 9999',
+ 'cellPhone' => '302 521 9999',
+ 'email' => 'Blow at somwhere.net',
+ 'emails' => 'Blow at somwhere.net',
+ 'category' => 'Personal',
+ 'businessCategory' => 'Personal',
+ 'homeAddress' => '',
+)
+136
+array (
+ 'lastname' => 'McTester',
+ 'firstname' => 'Testie',
+ 'name' => 'Testie McTester',
+ 'company' => 'Testers Inc',
+ 'department' => '',
+ 'cellPhone' => '+44 775550555',
+ 'homePhone' => '+44 205550555',
+ 'workPhone' => '+44 205550556',
+ 'homeEmail' => 'test at example.org',
+ 'emails' => 'test at example.org, test at example.com',
+ 'workEmail' => 'test at example.com',
+ 'homeAddress' => '111 One Street
+London W1 1AA',
+ 'homeStreet' => '111 One Street',
+ 'homeCity' => 'London',
+ 'homePostalCode' => 'W1 1AA',
+ 'commonAddress' => '111 One Street
+London W1 1AA',
+ 'commonStreet' => '111 One Street',
+ 'commonCity' => 'London',
+ 'commonPostalCode' => 'W1 1AA',
+ 'birthday' => '2008-10-08',
+ 'phototype' => 'JPEG',
+)
diff --git a/lib/tests/tovcard.phpt b/lib/tests/tovcard.phpt
index de171e3..0eb9c2a 100644
--- a/lib/tests/tovcard.phpt
+++ b/lib/tests/tovcard.phpt
@@ -36,6 +36,8 @@ $attributes = array(
'timezone' => 'Europe/Berlin',
'latitude' => '52.516276',
'longitude' => '13.377778',
+ 'photo' => file_get_contents(dirname(__FILE__) . '/az.png'),
+ 'phototype' => 'image/png',
);
$driver = new Turba_Driver(array());
@@ -52,6 +54,8 @@ VERSION:2.1
FN;CHARSET=ISO-8859-1;ENCODING=QUOTED-PRINTABLE:Jan Schneider=F6
EMAIL:jan at horde.org
NICKNAME:yunosh
+LABEL;HOME;ENCODING=QUOTED-PRINTABLE;CHARSET=ISO-8859-1:Sch=F6nestr. 15=0D=0A=
+33604 Bielefeld
TEL;HOME:+49 521 555123
TEL;WORK:+49 521 555456
TEL;CELL:+49 177 555123
@@ -63,13 +67,13 @@ ROLE;CHARSET=ISO-8859-1;ENCODING=QUOTED-PRINTABLE:Developer (=E4=F6=FC)
NOTE;CHARSET=ISO-8859-1;ENCODING=QUOTED-PRINTABLE:A German guy (=E4=F6=FC)
URL:http://janschneider.de
TZ;VALUE=text:Europe/Berlin
-GEO:52.516276;13.377778
+GEO:13.377778,52.516276
+PHOTO;ENCODING=b;TYPE=image/png:iVBORw0KGgoAAAANSUhEUgAAAAkAAAAJAgMAAACd/+6DAAAACVBMVEW6ABZmZmYAAACMtcxCAAAAAXRSTlMAQObYZgAAABpJREFUCFtjYACBBgYmRgEIZmGBYAFGMAYBABVmAOEH9qP8AAAAAElFTkSuQmCC
N;CHARSET=ISO-8859-1;ENCODING=QUOTED-PRINTABLE:Schneider=F6;Jan;K.;Mr.;
ORG;CHARSET=ISO-8859-1;ENCODING=QUOTED-PRINTABLE:Horde Project;=E4=F6=FC
ADR;HOME;CHARSET=ISO-8859-1;ENCODING=QUOTED-PRINTABLE:;;Sch=F6nestr. 15=0D=0A=
33604 Bielefeld;;;;
ADR;WORK;CHARSET=ISO-8859-1;ENCODING=QUOTED-PRINTABLE:;;H=FCbschestr. 19;K=F6ln;Allg=E4u;;D=E4nemark
-BODY:
END:VCARD
BEGIN:VCARD
@@ -77,6 +81,7 @@ VERSION:3.0
FN:Jan Schneiderö
EMAIL:jan at horde.org
NICKNAME:yunosh
+LABEL;TYPE=HOME:Schönestr. 15\n33604 Bielefeld
TEL;TYPE=HOME:+49 521 555123
TEL;TYPE=WORK:+49 521 555456
TEL;TYPE=CELL:+49 177 555123
@@ -89,9 +94,11 @@ NOTE:A German guy (äöü)
URL:http://janschneider.de
TZ;VALUE=text:Europe/Berlin
GEO:52.516276;13.377778
+PHOTO;ENCODING=b;TYPE=image/png:wolQTkcNChoKAAAADUlIRFIAAAAJAAAACQIDAAAAwp3
+ Dv8OuwoMAAAAJUExURcK6ABZmZmYAAADCjMK1w4xCAAAAAXRSTlMAQMOmw5hmAAAAGklEQVQIW2
+ NgAMKBBgYmRgEIZmHCgWABRjAGAQAVZgDDoQfDtsKjw7wAAAAASUVORMKuQmDCgg==
N:Schneiderö;Jan;K.;Mr.;
ORG:Horde Project;äöü
ADR;TYPE=HOME:;;Schönestr. 15\n33604 Bielefeld;;;;
ADR;TYPE=WORK:;;Hübschestr. 19;Köln;Allgäu;;Dänemark
-BODY:
END:VCARD
diff --git a/lib/version.php b/lib/version.php
index 0d6f882..d7dfb6c 100644
--- a/lib/version.php
+++ b/lib/version.php
@@ -1 +1 @@
-<?php define('TURBA_VERSION', 'H3 (2.2.1)') ?>
+<?php define('TURBA_VERSION', 'H3 (2.3.1)') ?>
diff --git a/locale/de_DE/LC_MESSAGES/turba.mo b/locale/de_DE/LC_MESSAGES/turba.mo
index 2de8f6a..1884a7a 100644
Binary files a/locale/de_DE/LC_MESSAGES/turba.mo and b/locale/de_DE/LC_MESSAGES/turba.mo differ
diff --git a/locale/et_EE/LC_MESSAGES/turba.mo b/locale/et_EE/LC_MESSAGES/turba.mo
index 2f189e1..47f8d66 100644
Binary files a/locale/et_EE/LC_MESSAGES/turba.mo and b/locale/et_EE/LC_MESSAGES/turba.mo differ
diff --git a/locale/eu_ES/LC_MESSAGES/turba.mo b/locale/eu_ES/LC_MESSAGES/turba.mo
new file mode 100644
index 0000000..d1cc726
Binary files /dev/null and b/locale/eu_ES/LC_MESSAGES/turba.mo differ
diff --git a/locale/eu_ES/help.xml b/locale/eu_ES/help.xml
new file mode 100644
index 0000000..d7a47a8
--- /dev/null
+++ b/locale/eu_ES/help.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0"?>
+<!-- $Horde: turba/locale/eu_ES/help.xml,v 1.1.2.1 2008/07/17 21:09:27 jan Exp $ -->
+<help>
+
+<entry id="Overview" md5="290506ade4e6f749246f77bbe5d48835" state="uptodate">
+ <title>Informazio orokorra</title>
+ <heading>Sarrera</heading> <para>Helbide-liburuak kontaktuen informazioa gordetzeko metodo eta leku egokia eskaintzen ditu, informazio hori erraz eskuratzeko eta erabiltzeko. Administratzaileak sistema konfiguratzeko erabilitako moduaren arabera, helbide-liburu pribatu bat nahiz sareko direktorio-zerbitzu publikoetarako sarbidea izan dezakezu. Banaketa-zerrendak ere onartzen dituenez, zure "posta-zerrendak" sor ditzakezu.</para></entry>
+
+<entry id="menu-add" md5="3c1f92eb1a82839404d11d9b0a20b3ce" state="uptodate">
+ <title>Menua: Kontaktu berria</title>
+ <heading>Kontaktu berria</heading> <para>Helbide-liburuan beste erabiltzaile bat sartzea da. Helbide-liburuan, idazteko baimena eman dizuten erabiltzaileak sar ditzakezu soilik. Partekatutako helbide-liburuak edo helbide-liburu publikoak gaitu badira, askotan irakurtzeko soilik izaten dira; kasu horretan, ezingo duzu kontakturik sartu.</para></entry>
+
+<entry id="menu-search" md5="8daf81ab28602d772358a174571f9ad2" state="uptodate">
+ <title>Menua: Bilatu</title>
+ <heading>Bilatu</heading> <para>Helbide-liburu batean bilaketak egin ditzakezu informazioa eskuratzeko. Hori bilaketa erraza da, eta oinarrizko eremu batzuetan informazioa bilatzeko balio du. Askotan izena eta helbide elektronikoa eremuak erabili ohi dira, baina alda daitezke administratzaileak helbide-liburua konfiguratzeko erabilitako moduaren arabera.</para> <para>Bilaketa konplexuagoa egiteko "<ref module="turba" entry="menu-advanced-search">Bilaketa aurreratua</ref>" erabil dezakezu, eta horrela beste eremu batzuetan ere bilaketak egin ahal izango dituzu.</para></entry>
+
+<entry id="menu-advanced-search" md5="6be703ffeba614f6ada151749fa44ab5" state="uptodate">
+ <title>Menua: Bilaketa aurreratua</title>
+ <heading>Bilaketa aurreratua</heading> <para>Helbide-liburu batean bilaketak egin ditzakezu informazioa eskuratzeko. Bilaketa aurreratuaren bidez, hainbat eremutan egin ditzakezu bilaketak. Bilaketak egiteko zein eremu egongo diren erabilgarri, bilaketak egingo diren helbide-liburuaren arabera dago.</para></entry>
+
+<entry id="menu-import" md5="3c6c40f2a6213e9fc1f9a77827bfb5d4" state="uptodate">
+ <title>Menua: Inportatu/Esportatu</title>
+ <heading>Inportatu/Esportatu</heading>
+
+ <para>Menu honen bidez, helbide-liburura inportatu eta helbide-liburutik esporta dezakezu. Formatu hauek onartzen ditu: CSV (komaz bereizitako balioak), Outlook eta vCard formatuak, baita beste formatu ezagun batzuk ere.</para>
+
+ <heading>Inportatu helbide-liburua</heading> <para>Helbide-liburu bat inportatzeko, helbide-liburuko datuak makina lokalean eduki behar dituzu (web-arakatzailea bertan exekutatzen baita). Hori egiteko, aurrena helbide-liburuko informazioa esportatu behar duzu uneko posta elektronikotik.</para>
+
+ <para>Outlook Express erabiltzen baduzu:</para> <para>1) Hautatu Fitxategia > Esportatu > Helbide-liburua</para> <para>2) Hautatu "Helbide-liburua esportatzeko tresnak" aukerako "Testu-fitxategia" (Komaz bereizitako balioak). Egin klik "Esportatu" aukeran.</para> <para>3) "Gorde honela esportatutako fitxategia" eremuan, idatzi zure helbide-liburuaren izena. Egin klik "Hurrengoa" aukeran.</para> <para>4) Jarri hautamarka bat esportatu nahi duzun eremu bakoitzaren ezkerrean dagoen koadroan. Egin klik "Amaitu" aukeran.</para> <para>5) 'Helbide-liburuaren esportazio-prozesua amaitu da' adierazten duen mezu bat jasoko duzu. Sakatu 'Ados'.</para> <para>6) Sakatu ''Helbide-liburua esportatzeko tresnak" aukerako "Itxi" botoia eta itxi Outlook Express.</para>
+
+ <tip>Esportatutako helbide-liburuko fitxategia ez badago zure mahaigainean eta Windows sistema eragilea erabiltzen ari bazara, sakatu Hasi > Bilatu> Karpetak eta bilatu 3. urratsean idatzi duzun fitxategi-izena disko gogorrean. Idatzi ohar batean fitxategiaren kokapena.</tip>
+
+ <para>Helbide-liburu bat inportatzeko, ireki inportatu nahi duzun helbide-liburua, informazioa bertan jartzeko. Egin klik "Inportatu/Esportatu" ikonoan. Hautatu hautapen-zerrendatik inportatu nahi duzun datu-fitxategiko helbidearen informazioa. Egin klik "arakatzailea" botoian, helbidearen datu-fitxategia bilatzeko zure ordenagailuan. Hautatu fitxategia eta egin klik "Inportatu" botoian. Fitxategiko informazioa helbide-liburura inportatuko da.</para> <tip>Sarrera konplexu batzuk edo zure helbide-liburuko eremuekin bat ez datozen eremuak dauzkaten sarrera batzuk, agian, ez dira behar bezala inportatuko. Inportazio bat egin ondoren, inportatutako datuak egiaztatu beharko zenituzke.</tip></entry>
+
+<entry id="searching-search_results" md5="ffed8d72fa3b710df8e902c2493b254f" state="uptodate">
+ <title>Bilaketa: Bilaketaren emaitzak</title>
+ <heading>Bilaketaren emaitzak</heading> <para>Bilaketak emaitzaren bat ematen badu, "Bilaketaren emaitzak" arean azalduko dira.</para> <para>"Posta elektronikoa" sarreraren eremuan klik eginez, mezu berria idazteko leiho bat irekiko da, helbide horretara mezu bat bidaltzeko. "Izena" sarreraren eremuan klik eginez, izen horren helbide-liburua bistaratuko da. Horrela, sarrera hori editatu edo ezabatu ahal izango duzu.</para> <para>Zure administratzailearen sistema ezartzeko moduaren arabera, emaitzak metagarriak izan daitezke. Bilaketa bakoitzak ematen duen edozein emaitza lehendik dauden emaitzekin batera agertuko da. Hori lagungarria da zerrendak eraikitzean. Metatutako bilaketen emaitzak kentzeko eta beste bilaketa bat egiteko, egin klik "Garbitu bilaketa" estekan.</para>
+
+ <tip>Sarreren zerrenda bat ikustean, sarrerak ordena ditzakezu dauden eremuen arabera, zutabearen goiburu egokian klik eginez. Goranzko edo beheranzko ordenara aldatzeko, egin klik zutabearen izenburuko geziaren ikonoan.</tip></entry>
+
+</help>
diff --git a/locale/fi_FI/LC_MESSAGES/turba.mo b/locale/fi_FI/LC_MESSAGES/turba.mo
index 1ae252c..caca5ac 100644
Binary files a/locale/fi_FI/LC_MESSAGES/turba.mo and b/locale/fi_FI/LC_MESSAGES/turba.mo differ
diff --git a/locale/fr_FR/LC_MESSAGES/turba.mo b/locale/fr_FR/LC_MESSAGES/turba.mo
index e9598d1..5f48e18 100644
Binary files a/locale/fr_FR/LC_MESSAGES/turba.mo and b/locale/fr_FR/LC_MESSAGES/turba.mo differ
diff --git a/locale/ja_JP/LC_MESSAGES/turba.mo b/locale/ja_JP/LC_MESSAGES/turba.mo
index b3b2f0a..660c9d8 100644
Binary files a/locale/ja_JP/LC_MESSAGES/turba.mo and b/locale/ja_JP/LC_MESSAGES/turba.mo differ
diff --git a/locale/nl_NL/LC_MESSAGES/turba.mo b/locale/nl_NL/LC_MESSAGES/turba.mo
index 85c9269..6f94eb6 100644
Binary files a/locale/nl_NL/LC_MESSAGES/turba.mo and b/locale/nl_NL/LC_MESSAGES/turba.mo differ
diff --git a/locale/pt_BR/LC_MESSAGES/turba.mo b/locale/pt_BR/LC_MESSAGES/turba.mo
index c0b0fbd..47fcf24 100644
Binary files a/locale/pt_BR/LC_MESSAGES/turba.mo and b/locale/pt_BR/LC_MESSAGES/turba.mo differ
diff --git a/locale/sk_SK/LC_MESSAGES/turba.mo b/locale/sk_SK/LC_MESSAGES/turba.mo
index 805e9e8..847400a 100644
Binary files a/locale/sk_SK/LC_MESSAGES/turba.mo and b/locale/sk_SK/LC_MESSAGES/turba.mo differ
diff --git a/locale/tr_TR/LC_MESSAGES/turba.mo b/locale/tr_TR/LC_MESSAGES/turba.mo
index 0165106..d6264b2 100644
Binary files a/locale/tr_TR/LC_MESSAGES/turba.mo and b/locale/tr_TR/LC_MESSAGES/turba.mo differ
diff --git a/locale/uk_UA/LC_MESSAGES/turba.mo b/locale/uk_UA/LC_MESSAGES/turba.mo
index 843f0d5..967cb72 100644
Binary files a/locale/uk_UA/LC_MESSAGES/turba.mo and b/locale/uk_UA/LC_MESSAGES/turba.mo differ
diff --git a/po/de_DE.po b/po/de_DE.po
index 5a90f22..126ac3f 100644
--- a/po/de_DE.po
+++ b/po/de_DE.po
@@ -7,13 +7,14 @@ msgid ""
msgstr ""
"Project-Id-Version: Turba 2.2-cvs\n"
"Report-Msgid-Bugs-To: dev at lists.horde.org\n"
-"POT-Creation-Date: 2008-06-13 23:43+0200\n"
-"PO-Revision-Date: 2008-06-13 23:45+0200\n"
+"POT-Creation-Date: 2008-09-25 12:32+0200\n"
+"PO-Revision-Date: 2008-09-06 12:20+0200\n"
"Last-Translator: Jan Schneider <jan at horde.org>\n"
"Language-Team: German <i18n 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"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: templates/prefs/imsp_opt.inc:40
msgid " Add an IMSP Address Book"
@@ -23,19 +24,19 @@ msgstr "IMSP-Adressbuch hinzuf
msgid " Delete IMSP Address Book"
msgstr "IMSP-Adressbuch löschen"
-#: data.php:367
+#: data.php:455
#, php-format
msgid "\"%s\" already exists and was not imported."
msgstr "\"%s\" existiert bereits und wurde nicht importiert."
-#: lib/Forms/EditContact.php:76
+#: lib/Forms/EditContact.php:83
#, php-format
msgid "\"%s\" updated, but saving the uploaded file failed: %s"
msgstr ""
"\"%s\" wurde aktualisiert, aber die hochgeladene Datei konnte nicht "
"gespeichert werden: %s"
-#: lib/Forms/EditContact.php:78 lib/Forms/EditContact.php:81
+#: lib/Forms/EditContact.php:85 lib/Forms/EditContact.php:88
#, php-format
msgid "\"%s\" updated."
msgstr "\"%s\" aktualisiert."
@@ -58,30 +59,30 @@ msgstr "\"Vorname Nachname\" (z.B. Max Mustermann)"
msgid "\"Lastname, Firstname\" (ie. Doe, John)"
msgstr "\"Nachname, Vorname\" (z.B. Mustermann, Max)"
-#: lib/Forms/AddContact.php:83
+#: lib/Driver.php:619
+#, php-format
+msgid "%d. %s of %s"
+msgstr "%d. %s von %s"
+
+#: lib/Forms/AddContact.php:88
#, php-format
msgid "%s added."
msgstr "%s hinzugefügt."
-#: data.php:392
+#: data.php:483
#, php-format
msgid "%s file successfully imported."
msgstr "Die %s-Datei wurde erfolgreich importiert."
-#: lib/Driver.php:578
-#, php-format
-msgid "%s of %s"
-msgstr "%s von %s"
-
#: templates/list/numPager.inc:6
#, php-format
msgid "%s to %s of %s"
msgstr "%s bis %s von %s"
-#: lib/Turba.php:560
+#: lib/Turba.php:541
#, php-format
msgid "%s's Address Book"
-msgstr "%ss Adressbuch"
+msgstr "Adressbuch von %s"
#: lib/Block/minisearch.php:44
msgid "A browser that supports iframes is required"
@@ -112,7 +113,7 @@ msgstr "Datei hinzuf
msgid "Add to"
msgstr "Hinzufügen zu"
-#: lib/Driver.php:1959 lib/Driver/null.php:57
+#: lib/Driver.php:2113 lib/Driver/null.php:57
msgid "Adding contacts is not available."
msgstr "Hinzufügen von Kontakten nicht unterstützt."
@@ -132,7 +133,7 @@ msgstr "Adressbuchliste"
msgid "Address Books"
msgstr "Adressbücher"
-#: data.php:347
+#: data.php:435
msgid "Address book successfully purged."
msgstr "Adressbuch wurde erfolgreich geleert."
@@ -141,7 +142,7 @@ msgstr "Adressbuch wurde erfolgreich geleert."
msgid "Address books that will not be displayed:"
msgstr "Adressbücher, die nicht angezeigt werden:"
-#: search.php:199 templates/browse/search.inc:47
+#: search.php:184 templates/browse/search.inc:47
msgid "Advanced Search"
msgstr "Erweiterte Suche"
@@ -153,7 +154,7 @@ msgstr "Spitzname"
msgid "All"
msgstr "Alle"
-#: lib/api.php:916
+#: lib/api.php:941
msgid "Already Exists"
msgstr "Existiert bereits"
@@ -174,11 +175,11 @@ msgstr "Sind Sie sicher, dass Sie %s l
msgid "Are you sure that you want to delete the selected contacts?"
msgstr "Sind Sie sicher, dass Sie die ausgewählten Kontakte löschen möchten?"
-#: config/attributes.php.dist:378
+#: config/attributes.php.dist:424
msgid "Assistant"
msgstr "Assistent"
-#: search.php:196 templates/browse/search.inc:46
+#: search.php:181 templates/browse/search.inc:46
msgid "Basic Search"
msgstr "Einfache Suche"
@@ -195,7 +196,7 @@ msgstr "Geburtstag"
msgid "Birthdays"
msgstr "Geburtstage"
-#: contact.php:106 templates/browse/row.inc:6
+#: contact.php:128 templates/browse/row.inc:10
msgid "Blank name"
msgstr "Leerer Name"
@@ -208,11 +209,11 @@ msgstr "Beides"
msgid "Browse"
msgstr "Liste"
-#: config/attributes.php.dist:288
+#: config/attributes.php.dist:300
msgid "Business Category"
msgstr "Geschäftskategorie"
-#: data.php:86
+#: data.php:101
msgid "CSV"
msgstr "CSV"
@@ -229,7 +230,7 @@ msgstr "Abbrechen"
msgid "Cannot delete all address book entries for %s"
msgstr "Es konnten nicht alle Adressbucheinträge für %s gelöscht werden"
-#: config/attributes.php.dist:350
+#: config/attributes.php.dist:388
msgid "Category"
msgstr "Kategorie"
@@ -297,58 +298,59 @@ msgstr "Kommagetrennte Werte"
msgid "Comma separated values (Microsoft Outlook)"
msgstr "Kommagetrennte Werte (Microsoft Outlook)"
-#: config/attributes.php.dist:476
+#: config/attributes.php.dist:522
msgid "Common Address Extended"
msgstr "Erweiterte Adresse allgemein"
-#: config/attributes.php.dist:494
+#: config/attributes.php.dist:540
msgid "Common City"
msgstr "Stadt allgemein"
-#: config/attributes.php.dist:512
+#: config/attributes.php.dist:558
msgid "Common Country"
msgstr "Land allgemein"
-#: config/attributes.php.dist:420
+#: config/attributes.php.dist:466
msgid "Common Phone"
msgstr "Telefon allgemein"
-#: config/attributes.php.dist:488
+#: config/attributes.php.dist:534
msgid "Common Post Office Box"
msgstr "Postfach allgemein"
-#: config/attributes.php.dist:506
+#: config/attributes.php.dist:552
msgid "Common Postal Code"
msgstr "Postleitzahl allgemein"
-#: config/attributes.php.dist:500
+#: config/attributes.php.dist:546
msgid "Common State/Province"
msgstr "Bundesstaat oder Provinz allgemein"
-#: config/attributes.php.dist:482
+#: config/attributes.php.dist:528
msgid "Common Street"
msgstr "Straße allgemein"
-#: config/attributes.php.dist:445
+#: config/attributes.php.dist:491
msgid "Common Video Call"
msgstr "Bildtelefon allgemein"
-#: config/sources.php.dist:243 config/sources.php.dist:922
+#: config/sources.php.dist:256 config/sources.php.dist:948
msgid "Communications"
msgstr "Kommunikation"
-#: config/attributes.php.dist:294
+#: config/attributes.php.dist:306
msgid "Company"
msgstr "Firma"
-#: config/attributes.php.dist:223
+#: config/attributes.php.dist:235
msgid "Company Address"
msgstr "Firmenadresse"
-#: scripts/import_squirrelmail_abook.php:112 lib/api.php:523 lib/api.php:577
-#: lib/api.php:630 lib/api.php:678 lib/api.php:733 lib/api.php:792
-#: lib/api.php:842 lib/api.php:978 lib/api.php:1070 lib/api.php:1136
-#: lib/api.php:1251 lib/api.php:1484 lib/api.php:1561 lib/api.php:1710
+#: scripts/import_squirrelmail_abook.php:112 lib/api.php:546 lib/api.php:600
+#: lib/api.php:653 lib/api.php:701 lib/api.php:756 lib/api.php:815
+#: lib/api.php:866 lib/api.php:1004 lib/api.php:1066 lib/api.php:1137
+#: lib/api.php:1204 lib/api.php:1324 lib/api.php:1563 lib/api.php:1640
+#: lib/api.php:1791
#, php-format
msgid "Connection failed: %s"
msgstr "Verbindung fehlgeschlagen: %s"
@@ -361,7 +363,7 @@ msgstr "Verbindung fehlgeschlagen"
msgid "Contact Search"
msgstr "Kontaktsuche"
-#: config/sources.php.dist:851
+#: config/sources.php.dist:866
msgid "Contacts"
msgstr "Kontakte"
@@ -369,7 +371,7 @@ msgstr "Kontakte"
msgid "Contacts displayed:"
msgstr "Angezeigte Kontakte:"
-#: lib/Views/Browse.php:339
+#: lib/Views/Browse.php:346
#, php-format
msgid "Contacts in list: %s"
msgstr "Kontakte in Liste: %s"
@@ -390,7 +392,7 @@ msgstr "Adressbuch Erstellen"
msgid "Create a new Address Book"
msgstr "Neues Adressbuch erstellen"
-#: lib/ListView.php:447
+#: lib/ListView.php:448
msgid "Create a new Contact List in:"
msgstr "Neue Kontaktliste anlegen in:"
@@ -398,7 +400,7 @@ msgstr "Neue Kontaktliste anlegen in:"
msgid "Created"
msgstr "Erstellt"
-#: contact.php:89
+#: contact.php:95
msgid "De_lete"
msgstr "_Löschen"
@@ -413,7 +415,7 @@ msgstr "L
msgid "Delete %s"
msgstr "%s löschen"
-#: lib/api.php:621
+#: lib/api.php:644
msgid "Delete denied."
msgstr "Löschen nicht erlaubt."
@@ -422,7 +424,7 @@ msgstr "L
msgid "Delete failed: (%s) %s"
msgstr "Löschen fehlgeschlagen: (%s) %s"
-#: lib/Driver.php:1967 lib/Driver/null.php:62
+#: lib/Driver.php:2121 lib/Driver/null.php:62
msgid "Deleting contacts is not available."
msgstr "Löschen von Kontakten nicht unterstützt."
@@ -430,7 +432,7 @@ msgstr "L
msgid "Deletion failed"
msgstr "Löschen ist fehlgeschlagen"
-#: config/attributes.php.dist:300
+#: config/attributes.php.dist:312
msgid "Department"
msgstr "Abteilung"
@@ -451,17 +453,17 @@ msgstr "Anzeige"
msgid "Display Options"
msgstr "Anzeige-Einstellungen"
-#: lib/Object.php:348
+#: lib/Object.php:354
msgid "Download"
msgstr "Herunterladen"
-#: templates/browse/row.inc:15 templates/browse/row.inc:16
+#: templates/browse/row.inc:27 templates/browse/row.inc:28
#: templates/browse/contactrow.inc:25
msgid "Download vCard"
msgstr "vCard herunterladen"
-#: templates/addressbook_list.php:31 templates/browse/row.inc:28
-#: templates/browse/row.inc:29 templates/browse/column_headers.inc:11
+#: templates/addressbook_list.php:31 templates/browse/row.inc:40
+#: templates/browse/row.inc:41 templates/browse/column_headers.inc:11
#: templates/browse/actions.inc:6 templates/browse/contactrow.inc:33
#: addressbooks/index.php:40
msgid "Edit"
@@ -477,20 +479,20 @@ msgstr "\"%s\" bearbeiten"
msgid "Edit %s"
msgstr "%s Bearbeiten"
-#: config/attributes.php.dist:237
+#: config/attributes.php.dist:249
msgid "Email"
msgstr "E-Mail-Adresse"
-#: config/attributes.php.dist:243
+#: config/attributes.php.dist:255
msgid "Emails"
msgstr "E-Mail-Adressen"
-#: lib/Views/Browse.php:263 lib/Views/Browse.php:303
+#: lib/Views/Browse.php:270 lib/Views/Browse.php:310
#, php-format
msgid "Error adding %d contact(s) to list."
msgstr "Fehler beim Hinzufügen von %d Kontakten zur Liste."
-#: lib/Views/Browse.php:265 lib/Views/Browse.php:305
+#: lib/Views/Browse.php:272 lib/Views/Browse.php:312
#, php-format
msgid "Error adding %d of %d requested contact(s) to list."
msgstr "Fehler beim Hinzufügen von %d von %d Kontakten zur Liste."
@@ -515,7 +517,7 @@ msgstr "Fehler beim Entfernen von %d Kontakten aus der Liste."
msgid "Error removing %d of %d requested contact(s) from list."
msgstr "Fehler beim Entfernen von %d von %d Kontakten aus der Liste."
-#: lib/api.php:684
+#: lib/api.php:707
#, php-format
msgid "Error searching the address book: %s"
msgstr "Das Adressbuch konnte nicht durchsucht werden: %s"
@@ -536,7 +538,7 @@ msgstr "Nur die ausgew
msgid "Export the following address book completely."
msgstr "Das folgende Adressbuch komplett exportieren."
-#: data.php:159 data.php:258 data.php:336 add.php:42 search.php:121
+#: data.php:247 data.php:346 data.php:424 add.php:42 search.php:106
#: lib/Views/Browse.php:84 lib/Views/Browse.php:152 lib/Views/Browse.php:180
#, php-format
msgid "Failed to access the address book: %s"
@@ -547,11 +549,11 @@ msgstr "Das Adressbuch konnte nicht ge
msgid "Failed to add %s to %s: %s"
msgstr "%s konnte nicht zu %s hinzugefügt werden: %s"
-#: lib/Views/Browse.php:345
+#: lib/Views/Browse.php:352
msgid "Failed to browse list"
msgstr "Die Liste konnte nicht angezeigt werden"
-#: lib/Views/Browse.php:376
+#: lib/Views/Browse.php:383
msgid "Failed to browse the directory"
msgstr "Das Verzeichnis konnte nicht angezeigt werden"
@@ -568,20 +570,20 @@ msgid "Failed to find object to be added: %s"
msgstr ""
"Das Objekt, das hinzugefügt werden sollte, konnte nicht gefunden werden: %s"
-#: search.php:190
+#: search.php:175
msgid "Failed to search the address book"
msgstr "Das Adressbuch konnte nicht durchsucht werden"
-#: data.php:174
+#: data.php:262
#, php-format
msgid "Failed to search the directory: %s"
msgstr "Das Verzeichnis %s konnte nicht durchsucht werden."
-#: config/sources.php.dist:550
+#: config/sources.php.dist:565
msgid "Favourite Recipients"
msgstr "Häufigste Empfänger"
-#: config/attributes.php.dist:264
+#: config/attributes.php.dist:276
msgid "Fax"
msgstr "Fax"
@@ -593,7 +595,7 @@ msgstr "Dateien"
msgid "Find"
msgstr "Durchsuchen von "
-#: lib/Forms/EditContact.php:121 lib/Forms/EditContact.php:160
+#: lib/Forms/EditContact.php:128 lib/Forms/EditContact.php:167
msgid "Finish"
msgstr "Beenden"
@@ -601,7 +603,7 @@ msgstr "Beenden"
msgid "First Name"
msgstr "Vorname"
-#: config/attributes.php.dist:326
+#: config/attributes.php.dist:350
msgid "Freebusy URL"
msgstr "Frei-/Gebucht-URL"
@@ -609,83 +611,83 @@ msgstr "Frei-/Gebucht-URL"
msgid "From"
msgstr "Von"
-#: config/attributes.php.dist:384
+#: config/attributes.php.dist:430
msgid "Gender"
msgstr "Geschlecht"
-#: config/sources.php.dist:776
+#: config/sources.php.dist:791
msgid "Global Address Book"
msgstr "Allgemeines Adressbuch"
-#: templates/browse/row.inc:49 templates/browse/contactrow.inc:44
+#: templates/browse/row.inc:61 templates/browse/contactrow.inc:44
msgid "Group"
msgstr "Gruppe"
-#: config/attributes.php.dist:123
+#: config/attributes.php.dist:135
msgid "Home Address"
msgstr "Adresse privat"
-#: config/attributes.php.dist:546
+#: config/attributes.php.dist:592
msgid "Home Address Extended"
msgstr "Erweiterte Adresse privat"
-#: config/attributes.php.dist:141
+#: config/attributes.php.dist:153
msgid "Home City"
msgstr "Stadt privat"
-#: config/attributes.php.dist:159
+#: config/attributes.php.dist:171
msgid "Home Country"
msgstr "Land privat"
-#: config/attributes.php.dist:414
+#: config/attributes.php.dist:460
msgid "Home Email"
msgstr "E-Mail-Adresse privat"
-#: config/attributes.php.dist:430
+#: config/attributes.php.dist:476
msgid "Home Fax"
msgstr "Fax privat"
-#: config/attributes.php.dist:552
+#: config/attributes.php.dist:598
msgid "Home Latitude"
msgstr "Breitengrad privat"
-#: config/attributes.php.dist:557
+#: config/attributes.php.dist:603
msgid "Home Longitude"
msgstr "Längengrad privat"
-#: config/attributes.php.dist:440
+#: config/attributes.php.dist:486
msgid "Home Mobile Phone"
msgstr "Telefon mobil privat"
-#: config/attributes.php.dist:249
+#: config/attributes.php.dist:261
msgid "Home Phone"
msgstr "Telefon privat"
-#: config/attributes.php.dist:135
+#: config/attributes.php.dist:147
msgid "Home Post Office Box"
msgstr "Postfach privat"
-#: config/attributes.php.dist:153
+#: config/attributes.php.dist:165
msgid "Home Postal Code"
msgstr "Postleitzahl privat"
-#: config/attributes.php.dist:147
+#: config/attributes.php.dist:159
msgid "Home State/Province"
msgstr "Bundesstaat oder Provinz privat"
-#: config/attributes.php.dist:129
+#: config/attributes.php.dist:141
msgid "Home Street Address"
msgstr "Straße privat"
-#: config/attributes.php.dist:455
+#: config/attributes.php.dist:501
msgid "Home Video Call"
msgstr "Bildtelefon privat"
-#: config/attributes.php.dist:540
+#: config/attributes.php.dist:586
msgid "Home Website URL"
msgstr "Website-URL privat"
-#: config/sources.php.dist:667
+#: config/sources.php.dist:682
msgid "IMSP"
msgstr "IMSP"
@@ -694,38 +696,38 @@ msgstr "IMSP"
msgid "Import Address Book, Step %d"
msgstr "Adressbuch importieren, Schritt %d"
-#: data.php:410
+#: data.php:501
msgid "Import/Export Address Books"
msgstr "Adressbücher Import/Export"
-#: config/attributes.php.dist:360
+#: config/attributes.php.dist:406
msgid "Initials"
msgstr "Initialien"
-#: config/attributes.php.dist:366
+#: config/attributes.php.dist:412
msgid "Instant Messenger"
msgstr "Instant Messenger"
-#: lib/api.php:973 lib/api.php:1065
+#: lib/api.php:999 lib/api.php:1132
msgid "Invalid ID"
msgstr "Ungültige ID"
-#: scripts/import_squirrelmail_abook.php:105 lib/api.php:345 lib/api.php:673
-#: lib/api.php:728 lib/api.php:787 lib/api.php:835 lib/api.php:969
-#: lib/api.php:1061 lib/api.php:1126 lib/api.php:1693
+#: scripts/import_squirrelmail_abook.php:105 lib/api.php:368 lib/api.php:696
+#: lib/api.php:751 lib/api.php:810 lib/api.php:859 lib/api.php:995
+#: lib/api.php:1128 lib/api.php:1194 lib/api.php:1774
#, php-format
msgid "Invalid address book: %s"
msgstr "Ungültiges Adressbuch: %s"
-#: lib/api.php:1130
+#: lib/api.php:1198
msgid "Invalid contact unique ID"
msgstr "Ungültige eindeutige Kontakt-ID"
-#: lib/api.php:1697 lib/api.php:1783 lib/api.php:1844
+#: lib/api.php:1778 lib/api.php:1864 lib/api.php:1925
msgid "Invalid email"
msgstr "Ungültige E-Mail-Adresse"
-#: lib/api.php:1705
+#: lib/api.php:1786
msgid "Invalid entry"
msgstr "Ungültiger Eintrag"
@@ -733,15 +735,15 @@ msgstr "Ung
msgid "Invalid key specified."
msgstr "Ungültiger Schlüssel angegeben."
-#: lib/api.php:1701
+#: lib/api.php:1782
msgid "Invalid name"
msgstr "Ungültiger Name"
-#: config/attributes.php.dist:276
+#: config/attributes.php.dist:288
msgid "Job Title"
msgstr "Position"
-#: lib/Driver/kolab.php:1114 lib/Driver/kolab.php:1180
+#: lib/Driver/kolab.php:1129 lib/Driver/kolab.php:1195
#, php-format
msgid "Key for saving must be a UID not %s!"
msgstr "Der Schlüssel fürs Speichern muss eine UID sein, kein(e) %s!"
@@ -753,11 +755,11 @@ msgstr ""
"LDAP-Unterstützung wird benötigt, aber das LDAP-Modul ist nicht verfügbar "
"oder wurde nicht geladen."
-#: data.php:91 templates/data/import.inc:18 templates/data/export.inc:16
+#: data.php:106 templates/data/import.inc:18 templates/data/export.inc:16
msgid "LDIF Address Book"
msgstr "LDIF-Adressbuch"
-#: config/attributes.php.dist:390
+#: config/attributes.php.dist:436
msgid "Language"
msgstr "Sprache"
@@ -769,7 +771,7 @@ msgstr "Letzte
msgid "Last Name"
msgstr "Nachname"
-#: config/attributes.php.dist:396
+#: config/attributes.php.dist:442
msgid "Latitude"
msgstr "Breitengrad"
@@ -777,15 +779,23 @@ msgstr "Breitengrad"
msgid "List"
msgstr "Liste"
-#: config/sources.php.dist:238 config/sources.php.dist:918
+#: config/sources.php.dist:251 config/sources.php.dist:944
msgid "Location"
msgstr "Ort"
-#: config/attributes.php.dist:401
+#: config/attributes.php.dist:324
+msgid "Logo"
+msgstr "Logo"
+
+#: config/attributes.php.dist:330
+msgid "Logo MIME Type"
+msgstr "Logo-Dateityp"
+
+#: config/attributes.php.dist:447
msgid "Longitude"
msgstr "Längengrad"
-#: lib/api.php:593
+#: lib/api.php:616
msgid "Malformed request."
msgstr "Ungültige Anfrage."
@@ -793,15 +803,19 @@ msgstr "Ung
msgid "Manage Address Books"
msgstr "Adressbücher-Verwaltung"
-#: config/attributes.php.dist:372
+#: config/attributes.php.dist:418
msgid "Manager"
msgstr "Vorgesetzter"
+#: contact.php:109
+msgid "Mark this as your own contact"
+msgstr "Diesen Kontakt als Ihre Visitenkarte markieren"
+
#: templates/browse/search.inc:109
msgid "Matching"
msgstr "nach"
-#: lib/api.php:306
+#: lib/api.php:329
msgid "Maximum Number of Contacts"
msgstr "Maximale Anzahl an Kontakten"
@@ -821,7 +835,7 @@ msgstr "Weitere Namen"
msgid "Missing DN in LDAP source configuration."
msgstr "DN fehlt in der LDAP-Konfiguration."
-#: config/attributes.php.dist:259
+#: config/attributes.php.dist:271
msgid "Mobile Phone"
msgstr "Telefon mobil"
@@ -834,7 +848,7 @@ msgstr "
msgid "More Options..."
msgstr "Weitere Optionen..."
-#: lib/api.php:1821
+#: lib/api.php:1902
msgid "More than 1 entry found"
msgstr "Mehr als 1 Eintrag zurückgeliefert"
@@ -850,11 +864,11 @@ msgstr "Nach links"
msgid "Move right"
msgstr "Nach rechts"
-#: data.php:89 templates/data/import.inc:16
+#: data.php:104 templates/data/import.inc:16
msgid "Mulberry Address Book"
msgstr "Mulberry-Adressbuch"
-#: lib/api.php:1729
+#: lib/api.php:1810
#, php-format
msgid ""
"Multiple persons with address [%s], but none with name [%s] already exist"
@@ -862,7 +876,7 @@ msgstr ""
"Mehrere Personen mit der Adresse [%s], aber keine mit dem Namen [%s] im "
"Adressbuch"
-#: config/sources.php.dist:162
+#: config/sources.php.dist:167
msgid "My Address Book"
msgstr "Mein Adressbuch"
@@ -887,12 +901,12 @@ msgstr "Titel nach dem Namen"
msgid "Name:"
msgstr "Name:"
-#: add.php:70 lib/Block/tree_menu.php:27
+#: add.php:70 lib/Block/tree_menu.php:28
msgid "New Contact"
msgstr "Neuer Kontakt"
-#: templates/data/import.inc:46 lib/Forms/EditContact.php:112
-#: lib/Forms/EditContact.php:119 lib/Forms/EditContact.php:174
+#: templates/data/import.inc:46 lib/Forms/EditContact.php:119
+#: lib/Forms/EditContact.php:126 lib/Forms/EditContact.php:181
msgid "Next"
msgstr "Weiter"
@@ -900,26 +914,26 @@ msgstr "Weiter"
msgid "Nickname"
msgstr "Spitzname"
-#: lib/api.php:1824 lib/api.php:1884
+#: lib/api.php:1905 lib/api.php:1965
#, php-format
msgid "No %s entry found for %s"
msgstr "Es wurde kein %s Eintrag für %s gefunden"
-#: data.php:78
+#: data.php:93
msgid ""
"No Address Books are currently available. Import and Export is disabled."
msgstr ""
"Zur Zeit sind keine Adressbücher verfügbar. Import und Export stehen nicht "
"zur Verfügung."
-#: search.php:107
+#: search.php:92
msgid "No Address Books are currently available. Searching is disabled."
msgstr ""
"Zur Zeit sind keine Adressbücher verfügbar. Die Suche steht nicht zur "
"Verfügung."
-#: lib/api.php:667 lib/api.php:722 lib/api.php:782 lib/api.php:964
-#: lib/api.php:1056 lib/api.php:1121
+#: lib/api.php:690 lib/api.php:745 lib/api.php:805 lib/api.php:990
+#: lib/api.php:1123 lib/api.php:1189
msgid "No address book specified"
msgstr "Kein Adressbuch angegeben"
@@ -939,7 +953,7 @@ msgstr "Keine passende Kontakte"
msgid "No source for favourite recipients exists."
msgstr "Es existiert keine Quelle für häufigste Empfänger."
-#: lib/api.php:868 lib/api.php:1166
+#: lib/api.php:893 lib/api.php:1235
msgid "No vCard data was found."
msgstr "Es wurden keine vCard-Daten gefunden."
@@ -956,7 +970,7 @@ msgstr "Nicht gefunden"
msgid "Not found"
msgstr "Nicht gefunden"
-#: config/attributes.php.dist:314
+#: config/attributes.php.dist:338
msgid "Notes"
msgstr "Bemerkungen"
@@ -964,20 +978,20 @@ msgstr "Bemerkungen"
msgid "Number of items per page"
msgstr "Anzahl der Einträge pro Seite"
-#: lib/api.php:1015 lib/api.php:1191
+#: lib/api.php:1041 lib/api.php:1260
msgid "Object not found"
msgstr "Objekt nicht gefunden"
-#: lib/Driver/kolab.php:1184
+#: lib/Driver/kolab.php:1199
#, php-format
msgid "Object with UID %s does not exist!"
msgstr "Objekt mit der UID %s existiert nicht!"
-#: config/attributes.php.dist:282
+#: config/attributes.php.dist:294
msgid "Occupation"
msgstr "Beruf"
-#: config/attributes.php.dist:306
+#: config/attributes.php.dist:318
msgid "Office"
msgstr "Büro"
@@ -991,27 +1005,27 @@ msgstr ""
"endgültig gelöscht. Wenn Sie das nicht möchten, ändern Sie Ihre Auswahl auf "
"\"kein\"."
-#: lib/api.php:1174
+#: lib/api.php:1243
msgid "Only one vcard supported."
msgstr "Nur einzelne vCards werden unterstützt."
-#: config/sources.php.dist:245 config/sources.php.dist:924
+#: config/sources.php.dist:258 config/sources.php.dist:950
msgid "Organization"
msgstr "Firma"
-#: config/sources.php.dist:246 config/sources.php.dist:926
+#: config/sources.php.dist:259 config/sources.php.dist:952
msgid "Other"
msgstr "Sonstige"
-#: config/attributes.php.dist:332
+#: config/attributes.php.dist:356
msgid "PGP Public Key"
msgstr "Öffentlicher PGP-Schlüssel"
-#: config/attributes.php.dist:471
+#: config/attributes.php.dist:517
msgid "PTT"
msgstr "PTT"
-#: config/attributes.php.dist:269
+#: config/attributes.php.dist:281
msgid "Pager"
msgstr "Pager"
@@ -1019,16 +1033,24 @@ msgstr "Pager"
msgid "Permanently delete this contact?"
msgstr "Diesen Kontakt unwiederbringlich löschen?"
-#: deletefile.php:36 lib/Driver.php:759 lib/api.php:846 lib/api.php:1714
-#: lib/Driver/sql.php:486
+#: deletefile.php:36 lib/Driver.php:804 lib/api.php:870 lib/api.php:1795
+#: lib/Driver/sql.php:515
msgid "Permission denied"
msgstr "Zugriff verweigert"
-#: config/sources.php.dist:235 config/sources.php.dist:914
+#: config/sources.php.dist:248 config/sources.php.dist:940
msgid "Personal"
msgstr "Persönlich"
-#: data.php:90 templates/data/import.inc:17
+#: config/attributes.php.dist:121
+msgid "Photo"
+msgstr "Foto"
+
+#: config/attributes.php.dist:127
+msgid "Photo MIME Type"
+msgstr "Foto-Dateityp"
+
+#: data.php:105 templates/data/import.inc:17
msgid "Pine Address Book"
msgstr "Pine-Adressbuch"
@@ -1036,8 +1058,8 @@ msgstr "Pine-Adressbuch"
msgid "Please name the new contact list:"
msgstr "Bitte einen Namen für die neue Kontakliste angeben:"
-#: lib/Forms/EditContact.php:115 lib/Forms/EditContact.php:118
-#: lib/Forms/EditContact.php:167
+#: lib/Forms/EditContact.php:122 lib/Forms/EditContact.php:125
+#: lib/Forms/EditContact.php:174
msgid "Previous"
msgstr "Zurück"
@@ -1051,7 +1073,7 @@ msgstr "Abfrage fehlgeschlagen: (%s) %s"
msgid "Read failed: (%s) %s"
msgstr "Lesen fehlgeschlagen: (%s) %s"
-#: lib/Driver.php:1951 lib/Driver/null.php:52
+#: lib/Driver.php:2105 lib/Driver/null.php:52
msgid "Reading contacts is not available."
msgstr "Anzeigen von Kontakten nicht unterstützt."
@@ -1073,7 +1095,7 @@ msgstr "Adressbuch entfernen"
msgid "Remove from this list"
msgstr "Aus dieser Liste entfernen"
-#: lib/Driver.php:1989
+#: lib/Driver.php:2143
msgid ""
"Removing user data is not supported in the current address book storage "
"driver."
@@ -1089,7 +1111,7 @@ msgstr ""
"Existierendes Adressbuch mit dem importierten ersetzen? <strong>Warnung: "
"Damit werden alle aktuellen Einträge in dem Adressbuch gelöscht.</strong>"
-#: lib/Driver.php:653
+#: lib/Driver.php:698
msgid "Requested object not found."
msgstr "Gewünschtes Objekt nicht gefunden."
@@ -1097,11 +1119,11 @@ msgstr "Gew
msgid "Reset to Defaults"
msgstr "Zurücksetzen"
-#: config/attributes.php.dist:338
+#: config/attributes.php.dist:362
msgid "S/MIME Public Certificate"
msgstr "Öffentliches S/MIME-Zertifikat"
-#: config/attributes.php.dist:465
+#: config/attributes.php.dist:511
msgid "SIP"
msgstr "SIP"
@@ -1118,21 +1140,21 @@ msgstr "Speichern"
msgid "Save search as a virtual address book?"
msgstr "Suche als Virtuelles Adressbuch speichern?"
-#: lib/Driver.php:1977 lib/Driver/null.php:67
+#: lib/Driver.php:2131 lib/Driver/null.php:67
msgid "Saving contacts is not available."
msgstr "Speichern von Kontakten nicht unterstützt."
#: templates/browse/search.inc:111 templates/browse/search.inc:119
#: templates/browse/header.inc:3 templates/block/minisearch.inc:25
-#: lib/Block/tree_menu.php:58 config/prefs.php.dist:116
+#: lib/Block/tree_menu.php:62 config/prefs.php.dist:116
msgid "Search"
msgstr "Suche"
-#: lib/api.php:1489
+#: lib/api.php:1568
msgid "Search failed"
msgstr "Suche fehlgeschlagen"
-#: lib/api.php:1719 lib/api.php:1725 lib/api.php:1734 lib/api.php:1747
+#: lib/api.php:1800 lib/api.php:1806 lib/api.php:1815 lib/api.php:1828
#, php-format
msgid "Search failed: %s"
msgstr "Suche fehlgeschlagen: %s"
@@ -1141,11 +1163,11 @@ msgstr "Suche fehlgeschlagen: %s"
msgid "Search for: "
msgstr "Suchen nach: "
-#: lib/Driver.php:1936 lib/Driver/null.php:47
+#: lib/Driver.php:2090 lib/Driver/null.php:47
msgid "Searching is not available."
msgstr "Suchen von Kontakten nicht unterstützt."
-#: templates/browse/row.inc:40
+#: templates/browse/row.inc:52
msgid "Select contact"
msgstr "Kontakt auswählen"
@@ -1243,7 +1265,7 @@ msgstr "Sortieren nach %s, dann nach %s"
msgid "Source:"
msgstr "Quelle:"
-#: lib/api.php:299
+#: lib/api.php:322
msgid "Sources"
msgstr "Quellen"
@@ -1251,7 +1273,7 @@ msgstr "Quellen"
msgid "Spouse"
msgstr "Partner"
-#: lib/Views/Browse.php:261 lib/Views/Browse.php:301
+#: lib/Views/Browse.php:268 lib/Views/Browse.php:308
#, php-format
msgid "Successfully added %d contact(s) to list."
msgstr "%d Kontakte erfolgreich zur Liste hinzugefügt."
@@ -1261,12 +1283,12 @@ msgstr "%d Kontakte erfolgreich zur Liste hinzugef
msgid "Successfully added %s to %s"
msgstr "%s wurde erfolgreich zu %s hinzugefügt"
-#: lib/Views/Browse.php:291
+#: lib/Views/Browse.php:298
#, php-format
msgid "Successfully created the contact list \"%s\"."
msgstr "Die Kontaktliste \"%s\" wurde erfolgreich erstellt."
-#: search.php:165
+#: search.php:150
#, php-format
msgid "Successfully created virtual address book \"%s\""
msgstr "Virtuelles Adressbuch \"%s\" erfolgreich erstellt."
@@ -1281,7 +1303,7 @@ msgstr "%d Kontakte erfolgreich gel
msgid "Successfully removed %d contact(s) from list."
msgstr "%d Kontakte erfolgreich aus der Liste entfernt."
-#: data.php:87
+#: data.php:102
msgid "TSV"
msgstr "TSV"
@@ -1297,7 +1319,7 @@ msgstr "Zieladressbuch"
msgid "Target Contact List"
msgstr "Zielkontaktliste"
-#: data.php:338
+#: data.php:426
#, php-format
msgid "The %s file didn't contain any contacts."
msgstr "Die %s-Datei enthielt keine Kontakte."
@@ -1308,7 +1330,7 @@ msgstr ""
"Das VFS-Backend muss konfiguriert sein, um das Hochladen von Dateien zu "
"erlauben."
-#: lib/Driver.php:1907
+#: lib/Driver.php:2061
#, php-format
msgid "The address book \"%s\" does not exist."
msgstr "Das Adressbuch \"%s\" existiert nicht."
@@ -1318,11 +1340,15 @@ msgstr "Das Adressbuch \"%s\" existiert nicht."
msgid "The address book \"%s\" has been created."
msgstr "Das Adressbuch \"%s\" wurde erzeugt."
-#: data.php:345
+#: data.php:433
#, php-format
msgid "The address book could not be purged: %s"
msgstr "Das Adressbuch konnte nicht geleert werden: %s"
+#: lib/api.php:1061
+msgid "The address book with your own contact doesn't exist anymore."
+msgstr "Das Adressbuch mit Ihrer Visitenkarte existiert nicht mehr."
+
#: addressbooks/delete.php:50
#, php-format
msgid "The addressbook \"%s\" has been deleted."
@@ -1347,7 +1373,7 @@ msgstr "Der ausgew
msgid "The file \"%s\" has been deleted."
msgstr "Die Datei \"%s\" wurde gelöscht."
-#: data.php:318
+#: data.php:406
msgid "The import can be finished despite the warnings."
msgstr "Der Import kann trotz der Warnungen abgeschlossen werden."
@@ -1371,20 +1397,22 @@ msgstr ""
"dass es sich dabei um einen Fehler handelt, wenden Sie sich bitte an Ihren "
"System-Administrator."
-#: lib/Views/Browse.php:349
+#: lib/Views/Browse.php:356
#, php-format
msgid "There is %d contact in this list that is not viewable to you"
msgid_plural "There are %d contacts in this list that are not viewable to you"
msgstr[0] ""
+"In dieser Liste befindet sich %d Kontakt, den Sie nicht einsehen dürfen"
msgstr[1] ""
+"In dieser Liste befinden sich %d Kontakte, die Sie nicht einsehen dürfen"
-#: search.php:161
+#: search.php:146
#, php-format
msgid "There was a problem creating the virtual address book: %s"
msgstr ""
"Beim Erstellen des Virtuellen Adressbuchs ist ein Fehler aufgetreten: %s"
-#: lib/Forms/AddContact.php:90
+#: lib/Forms/AddContact.php:95
msgid ""
"There was an error adding the new contact. Contact your system administrator "
"for further help."
@@ -1392,7 +1420,7 @@ msgstr ""
"Beim Hinzufügen dieses Kontakts ist ein Fehler aufgetreten. Bitte wenden Sie "
"sich an Ihren Systemadministrator für weitere Hilfe."
-#: lib/Views/Browse.php:311
+#: lib/Views/Browse.php:318
msgid "There was an error creating a new list."
msgstr "Beim Erstellen einer neuen Liste ist ein Fehler aufgetreten."
@@ -1406,25 +1434,25 @@ msgstr "Beim L
msgid "There was an error deleting this contact: %s"
msgstr "Beim Löschen des Kontakts ist ein Fehler aufgetreten: %s"
-#: lib/Views/Browse.php:355
+#: lib/Views/Browse.php:362
msgid "There was an error displaying the list"
msgstr "Beim Anzeigen der Liste ist ein Fehler aufgetreten"
-#: data.php:378
+#: data.php:469
#, php-format
msgid "There was an error importing the data: %s"
msgstr "Beim Importieren der Daten ist ein Fehler aufgetreten: %s"
-#: lib/api.php:864 lib/api.php:1161
+#: lib/api.php:889 lib/api.php:1230
msgid "There was an error importing the iCalendar data."
msgstr "Beim Importieren der iCalendar Daten ist ein Fehler aufgetreten."
-#: lib/api.php:235
+#: lib/api.php:258
#, php-format
msgid "There was an error removing an address book for %s"
msgstr "Beim Löschen eines Adressbuchs von %s ist ein Fehler aufgetreten"
-#: lib/Forms/EditContact.php:86
+#: lib/Forms/EditContact.php:93
msgid ""
"There was an error saving the contact. Contact your system administrator for "
"further help."
@@ -1432,7 +1460,7 @@ msgstr ""
"Beim Speichern des Kontaktes ist ein Fehler aufgetreten. Bitte wenden Sie "
"sich an Ihren Systemadministrator für weitere Hilfe."
-#: data.php:204
+#: data.php:292
msgid "There were no addresses to export."
msgstr "Es konnten keine Adressen zum Exportieren gefunden werden."
@@ -1445,11 +1473,15 @@ msgstr "Diese Adressb
msgid "This addressbook cannot be deleted"
msgstr "Dieses Adressbuch kann nicht gelöscht werden"
-#: data.php:303
+#: contact.php:57
+msgid "This contact has been marked as your own."
+msgstr "Der Kontakt wurde als Ihre Visitenkarte markiert."
+
+#: data.php:391
msgid "This file format is not supported."
msgstr "Dieses Dateiformat wird nicht unterstützt."
-#: lib/api.php:1738 lib/api.php:1751
+#: lib/api.php:1819 lib/api.php:1832
#, php-format
msgid "This person already has a %s entry in the address book"
msgstr "Diese Person hat bereits einen %s-Eintrag in Ihrem Adressbuch"
@@ -1461,7 +1493,7 @@ msgstr ""
"Dies wird als Standardadressbuch für das Hinzufügen oder Importieren von "
"Kontakten benutzt."
-#: config/attributes.php.dist:229
+#: config/attributes.php.dist:241
msgid "Time Zone"
msgstr "Zeitzone"
@@ -1469,7 +1501,7 @@ msgstr "Zeitzone"
msgid "Unable to find contact owner."
msgstr "Kontaktbesitzer konnte nicht gefunden werden."
-#: lib/Driver.php:1829 lib/Turba.php:676
+#: lib/Driver.php:1981 lib/Turba.php:659
#, php-format
msgid "Unable to load the definition of %s."
msgstr "Der %s-Treiber konnte nicht geladen werden."
@@ -1483,11 +1515,11 @@ msgstr "Das Adressbuch \"%s\" kann nicht gespeichert werden: %s"
msgid "Unable to search."
msgstr "Suche nicht möglich."
-#: config/attributes.php.dist:353
+#: config/attributes.php.dist:391
msgid "Unfiled"
msgstr "Nicht zugeordnet"
-#: lib/api.php:902 lib/api.php:1012 lib/api.php:1179
+#: lib/api.php:927 lib/api.php:1038 lib/api.php:1248
#, php-format
msgid "Unsupported Content-Type: %s"
msgstr "Nicht unterstützter Inhaltstyp: %s"
@@ -1505,75 +1537,75 @@ msgstr "Kontakt anzeigen"
msgid "View to display by default:"
msgstr "Standardansicht:"
-#: config/attributes.php.dist:460
+#: config/attributes.php.dist:506
msgid "VoIP"
msgstr "VoIP"
-#: config/attributes.php.dist:320
+#: config/attributes.php.dist:344
msgid "Website URL"
msgstr "Website-URL"
-#: config/attributes.php.dist:173
+#: config/attributes.php.dist:185
msgid "Work Address"
msgstr "Adresse geschäftlich"
-#: config/attributes.php.dist:524
+#: config/attributes.php.dist:570
msgid "Work Address Extended"
msgstr "Erweiterte Adresse geschäftlich"
-#: config/attributes.php.dist:191
+#: config/attributes.php.dist:203
msgid "Work City"
msgstr "Stadt geschäftlich"
-#: config/attributes.php.dist:209
+#: config/attributes.php.dist:221
msgid "Work Country"
msgstr "Land geschäftlich"
-#: config/attributes.php.dist:408
+#: config/attributes.php.dist:454
msgid "Work Email"
msgstr "E-Mail-Adresse geschäftlich"
-#: config/attributes.php.dist:425
+#: config/attributes.php.dist:471
msgid "Work Fax"
msgstr "Fax geschäftlich"
-#: config/attributes.php.dist:530
+#: config/attributes.php.dist:576
msgid "Work Latitude"
msgstr "Breitengrad geschäftlich"
-#: config/attributes.php.dist:535
+#: config/attributes.php.dist:581
msgid "Work Longitude"
msgstr "Längengrad geschäftlich"
-#: config/attributes.php.dist:435
+#: config/attributes.php.dist:481
msgid "Work Mobile Phone"
msgstr "Telefon mobil geschäftlich"
-#: config/attributes.php.dist:254
+#: config/attributes.php.dist:266
msgid "Work Phone"
msgstr "Telefon geschäftlich"
-#: config/attributes.php.dist:185
+#: config/attributes.php.dist:197
msgid "Work Post Office Box"
msgstr "Postfach geschäftlich"
-#: config/attributes.php.dist:203
+#: config/attributes.php.dist:215
msgid "Work Postal Code"
msgstr "Postleitzahl geschäftlich"
-#: config/attributes.php.dist:197
+#: config/attributes.php.dist:209
msgid "Work State/Province"
msgstr "Bundesstaat oder Provinz geschäftlich"
-#: config/attributes.php.dist:179
+#: config/attributes.php.dist:191
msgid "Work Street Address"
msgstr "Straße geschäftlich"
-#: config/attributes.php.dist:450
+#: config/attributes.php.dist:496
msgid "Work Video Call"
msgstr "Bildtelefon geschäftlich"
-#: config/attributes.php.dist:518
+#: config/attributes.php.dist:564
msgid "Work Website URL"
msgstr "Website-URL geschäftlich"
@@ -1581,7 +1613,7 @@ msgstr "Website-URL gesch
msgid "You are not allowed to change this addressbook."
msgstr "Sie dürfen dieses Adressbuch nicht ändern."
-#: data.php:267 add.php:48 lib/Views/Browse.php:159 lib/Views/Browse.php:274
+#: data.php:355 add.php:48 lib/Views/Browse.php:159 lib/Views/Browse.php:281
#, php-format
msgid "You are not allowed to create more than %d contacts in \"%s\"."
msgstr "Sie dürfen nicht mehr als %d Kontakte in \"%s\" erstellen."
@@ -1590,7 +1622,7 @@ msgstr "Sie d
msgid "You are not allowed to delete this addressbook."
msgstr "Sie dürfen dieses Adressbuch nicht löschen."
-#: lib/api.php:198
+#: lib/api.php:204
msgid "You are not allowed to remove user data."
msgstr "Sie dürfen keine Benutzerdaten löschen."
@@ -1606,6 +1638,10 @@ msgstr "Sie k
msgid "You cannot delete contacts from a virtual address book"
msgstr "Sie können keine Kontakte aus Virtuellen Adressbüchern löschen"
+#: lib/api.php:1056
+msgid "You didn't mark a contact as your own yet."
+msgstr "Sie haben noch keinen Kontakt als Ihre Visitenkarte markiert."
+
#: edit.php:66 view.php:38 lib/Views/EditContact.php:49
#: lib/Views/DeleteContact.php:42
msgid "You do not have permission to view this contact."
@@ -1619,6 +1655,14 @@ msgstr "Sie haben nicht gen
msgid "You do not have permissions to delete this address book."
msgstr "Sie haben nicht genügend Rechte, um dieses Adressbuch zu löschen."
+#: lib/api.php:1070
+msgid ""
+"You don't have sufficient permissions to read the address book that contains "
+"your own contact."
+msgstr ""
+"Sie haben nicht genügend Rechte, um das Adressbuch zu lesen, das Ihre "
+"Visitenkarte enthält."
+
#: lib/Driver/ldap.php:741
msgid ""
"You must have the Net_LDAP PEAR library installed to use the schema check "
@@ -1627,7 +1671,7 @@ msgstr ""
"Sie müssen die Net_LDAP PEAR-Bibliothek installieren, um die "
"Schemaüberprüfung verwenden zu können."
-#: search.php:148
+#: search.php:133
msgid "You must provide a name for virtual address books."
msgstr "Sie müssen einen Namen für das Virtuelle Adressbuch angeben."
@@ -1648,15 +1692,24 @@ msgstr "Sie m
msgid "You only have permission to view this contact."
msgstr "Sie haben nur das Recht, diesen Kontakt anzusehen."
-#: lib/Views/Browse.php:362
+#: lib/Views/Browse.php:369
msgid "Your default address book is not browseable."
msgstr "Ihr Standard-Adressbuch kann nicht angezeigt werden."
+#: contact.php:101 contact.php:102 templates/browse/row.inc:14
+#: templates/browse/row.inc:15
+msgid "Your own contact"
+msgstr "Ihre Visitenkarte"
+
+#: lib/api.php:1075
+msgid "Your own contact cannot be found in the address book."
+msgstr "Ihre Visitenkarte konnte in dem Adressbuch nicht gefunden werden."
+
#: templates/browse/contactrow.inc:12
msgid "[no value]"
msgstr "[kein Wert]"
-#: lib/Turba.php:618
+#: lib/Turba.php:601
msgid "_Browse"
msgstr "_Liste"
@@ -1668,11 +1721,11 @@ msgstr "_Kontakte"
msgid "_Delete"
msgstr "Lös_chen"
-#: contact.php:85
+#: contact.php:91
msgid "_Edit"
msgstr "_Bearbeiten"
-#: lib/Turba.php:627
+#: lib/Turba.php:610
msgid "_Import/Export"
msgstr "_Import/Export"
@@ -1680,15 +1733,15 @@ msgstr "_Import/Export"
msgid "_Lists"
msgstr "_Listen"
-#: lib/Turba.php:615
+#: lib/Turba.php:598
msgid "_My Address Books"
msgstr "_Meine Adressbücher"
-#: lib/Turba.php:621
+#: lib/Turba.php:604
msgid "_New Contact"
msgstr "_Neuer Kontakt"
-#: lib/Turba.php:632
+#: lib/Turba.php:615
msgid "_Print"
msgstr "_Drucken"
@@ -1696,11 +1749,11 @@ msgstr "_Drucken"
msgid "_Remove from this list"
msgstr "_Aus dieser Liste entfernen"
-#: lib/Turba.php:623
+#: lib/Turba.php:606
msgid "_Search"
msgstr "_Suche"
-#: contact.php:82
+#: contact.php:88
msgid "_View"
msgstr "_Anzeigen"
@@ -1721,19 +1774,19 @@ msgstr "durch mich"
msgid "contact"
msgstr "Kontakt"
-#: data.php:224 data.php:229 templates/data/export.inc:1
+#: data.php:312 data.php:317 templates/data/export.inc:1
msgid "contacts.csv"
msgstr "adressen.csv"
-#: data.php:249
+#: data.php:337
msgid "contacts.ldif"
msgstr "adressen.ldif"
-#: data.php:234
+#: data.php:322
msgid "contacts.tsv"
msgstr "adressen.tsv"
-#: data.php:244
+#: data.php:332
msgid "contacts.vcf"
msgstr "adressen.vcf"
@@ -1741,16 +1794,16 @@ msgstr "adressen.vcf"
msgid "descending"
msgstr "absteigend"
-#: config/attributes.php.dist:387
+#: config/attributes.php.dist:433
msgid "female"
msgstr "weiblich"
-#: lib/Block/tree_menu.php:37
+#: lib/Block/tree_menu.php:38
#, php-format
msgid "in %s"
msgstr "in %s"
-#: config/attributes.php.dist:387
+#: config/attributes.php.dist:433
msgid "male"
msgstr "männlich"
@@ -1770,7 +1823,7 @@ msgstr "zu einer Kontaktliste"
msgid "to a different Address Book"
msgstr "zu einem anderen Adressbuch"
-#: data.php:88 templates/browse/column_headers.inc:14
+#: data.php:103 templates/browse/column_headers.inc:14
#: templates/data/import.inc:15 templates/data/export.inc:15
msgid "vCard"
msgstr "vCard"
diff --git a/po/et_EE.po b/po/et_EE.po
index b8375ab..51c5da7 100644
--- a/po/et_EE.po
+++ b/po/et_EE.po
@@ -5,107 +5,118 @@ msgid ""
msgstr ""
"Project-Id-Version: Turba 2.1-cvs\n"
"Report-Msgid-Bugs-To: dev at lists.horde.org\n"
-"POT-Creation-Date: 2005-10-18 15:12+0200\n"
-"PO-Revision-Date: 2006-03-27 23:09+0300\n"
-"Last-Translator: Toomas Aas <toomas.aas at mail.ee>\n"
+"POT-Creation-Date: 2008-05-29 15:48+0300\n"
+"PO-Revision-Date: 2008-06-05 19:27+0200\n"
+"Last-Translator: Alar SIng <alar.sing at err.ee>\n"
"Language-Team: Estonian <dev at lists.horde.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=ISO-8859-13\n"
-"Content-Transfer-Encoding: 8-bit\n"
+"Content-Transfer-Encoding: 8bit\n"
-#: templates/prefs/imsp_opt.inc:42
+#: templates/prefs/imsp_opt.inc:40
msgid " Add an IMSP Address Book"
msgstr " Lisa IMSP aadressiraamat"
-#: templates/prefs/imsp_opt.inc:31
+#: templates/prefs/imsp_opt.inc:29
msgid " Delete IMSP Address Book"
msgstr " Kustuta IMSP aadressiraamat"
-#: data.php:325
+#: data.php:351
#, php-format
msgid "\"%s\" already exists and was not imported."
msgstr "\"%s\" ei imporditud, kuna see oli juba olemas."
-#: browse.php:126
+#: lib/Forms/EditContact.php:76
+#, php-format
+msgid "\"%s\" updated, but saving the uploaded file failed: %s"
+msgstr ""
+"\"%s\" kanne uuendati, kuid serverisse laetud faili salvestamine nurjus: %s"
+
+#: lib/Forms/EditContact.php:78 lib/Forms/EditContact.php:81
+#, php-format
+msgid "\"%s\" updated."
+msgstr "\"%s\" kanne muudetud."
+
+#: lib/Views/Browse.php:192
#, php-format
msgid "\"%s\" was not copied because it is a list."
msgstr "\"%s\" ei kopeeritud, kuna see on list."
-#: browse.php:124
+#: lib/Views/Browse.php:190
#, php-format
msgid "\"%s\" was not moved because it is a list."
msgstr "\"%s\" ei teisaldatud, kuna see on list."
-#: config/prefs.php.dist:137
+#: config/prefs.php.dist:118
msgid "\"Firstname Lastname\" (ie. John Doe)"
msgstr "\"Eesnimi Perekonnanimi\" (nt. Jaan Kask)"
-#: config/prefs.php.dist:136
+#: config/prefs.php.dist:117
msgid "\"Lastname, Firstname\" (ie. Doe, John)"
msgstr "\"Perekonnanimi, Eesnimi\" (nt. Kask, Jaan)"
-#: add.php:109
+#: lib/Forms/AddContact.php:83
#, php-format
msgid "%s added."
msgstr "%s lisatud."
-#: data.php:343
+#: data.php:370
#, php-format
-msgid "%s file successfully imported"
+msgid "%s file successfully imported."
msgstr "%s faili import õnnestus"
-#: templates/browse/footer.inc:5
+#: templates/list/numPager.inc:6
#, php-format
msgid "%s to %s of %s"
msgstr "%s kuni %s, kokku %s"
-#: lib/Turba.php:446
+#: lib/Turba.php:531
#, php-format
msgid "%s's Address Book"
msgstr "Kasutaja %s aadressiraamat"
-#: lib/Block/minisearch.php:45
+#: lib/Block/minisearch.php:42
msgid "A browser that supports iFrames is required"
msgstr "Vajalik on iFrame toetav veebilehitseja"
-#: config/prefs.php.dist:159
-msgid "Above search form"
-msgstr "Otsinguvormi kohal"
-
-#: view.php:52
+#: view.php:54
#, php-format
msgid "Access denied to %s"
msgstr "Puudub õigus failile %s"
-#: add.php:56 templates/browse/actions.inc:22
+#: templates/browse/actions.inc:30 lib/Forms/AddContact.php:25
msgid "Add"
msgstr "Lisa"
-#: templates/prefs/addressbookselect.inc:174
+#: lib/Forms/AddContact.php:22
+msgid "Add Contact"
+msgstr "Lisa kontakt"
+
+#: templates/prefs/addressbookselect.inc:173
msgid "Add address book"
msgstr "Lisa aadressiraamat"
-#: config/prefs.php.dist:48
-msgid "Add and Delete IMSP address books"
-msgstr "Lisa ja kustuta IMSP aadressiraamatuid"
-
#: templates/prefs/columnselect.inc:237
msgid "Add column"
msgstr "Lisa veerg"
-#: edit.php:128
+#: lib/Forms/EditContact.php:34
msgid "Add file"
msgstr "Lisa fail"
-#: templates/browse/actions.inc:22
+#: templates/browse/actions.inc:30
msgid "Add to"
msgstr "Lisa"
-#: templates/addressbooks.inc:86
+#: lib/Driver.php:1518
+msgid "Adding contacts is not available."
+msgstr "Kontaktide lisamine ei ole saadaval."
+
+#: templates/addressbooks.inc:105
msgid "Address Book"
msgstr "Aadressiraamat"
-#: browse.php:28 config/prefs.php.dist:125
+#: lib/Views/Browse.php:78 config/prefs.php.dist:106
msgid "Address Book Listing"
msgstr "Aadresside loend"
@@ -113,102 +124,141 @@ msgstr "Aadresside loend"
msgid "Address Books"
msgstr "Aadressiraamatud"
-#: add.php:108
-msgid "Address book entry"
-msgstr "Aadressiraamatu kanne"
-
-#: data.php:305
+#: data.php:331
msgid "Address book successfully purged."
msgstr "Aadressiraamat on tühjendatud."
-#: templates/addressbooks.inc:62
+#: templates/addressbooks.inc:80
msgid "Address book to delete "
msgstr "Kustutatav aadressiraamat "
-#: templates/prefs/addressbookselect.inc:170
+#: templates/prefs/addressbookselect.inc:167
+#: templates/prefs/addressbookselect.inc:169
msgid "Address books that will not be displayed:"
msgstr "Aadressiraamatud, mida ei näidata:"
-#: search.php:88 templates/browse/search.inc:37
+#: search.php:161 templates/browse/search.inc:47
msgid "Advanced Search"
msgstr "Põhjalik otsing"
-#: config/attributes.php.dist:64
+#: config/attributes.php.dist:77
msgid "Alias"
msgstr "Alias"
-#: templates/browse/footerAlpha.inc:7 templates/browse/footerAlpha.inc:10
-#: templates/browse/actions.inc:41
+#: templates/list/alphaPager.inc:7 templates/list/alphaPager.inc:10
msgid "All"
msgstr "Kõik"
-#: lib/api.php:552
+#: lib/api.php:725
msgid "Already Exists"
msgstr "On juba olemas"
-#: templates/browse/javascript.inc:93
+#: config/attributes.php.dist:95
+msgid "Anniversary"
+msgstr "Aastapäev"
+
+#: templates/browse/javascript.inc:85
#, php-format
msgid "Are you sure that you want to delete %s?"
msgstr "Kas oled kindel, et soovid %s kustutada?"
-#: templates/browse/javascript.inc:67
-msgid "Are you sure that you want to delete the selected entries?"
+#: templates/browse/javascript.inc:66
+msgid "Are you sure that you want to delete the selected contacts?"
msgstr "Kas oled kindel, et soovid märgitud kanded kustutada?"
-#: config/prefs.php.dist:96
-msgid "Ascending"
-msgstr "Kasvav"
+#: templates/addressbooks.inc:45
+msgid "Are you sure you want to delete the addressbook: "
+msgstr "Kas oled kindel, et soovid selle aadressi raamatu kustutada:"
-#: search.php:85 templates/browse/search.inc:36
+#: config/attributes.php.dist:368
+msgid "Assistant"
+msgstr "Assistent"
+
+#: search.php:158 templates/browse/search.inc:46
msgid "Basic Search"
msgstr "Lihtotsing"
-#: config/prefs.php.dist:158
-msgid "Below search form"
-msgstr "Otsinguvormi all"
-
-#: lib/Driver/ldap.php:77 lib/Driver/ldap.php:80
+#: lib/Driver/ldap.php:95 lib/Driver/ldap.php:98
#, php-format
msgid "Bind failed: (%s) %s"
msgstr "Bind nurjus: (%s) %s"
-#: config/attributes.php.dist:178
+#: config/attributes.php.dist:89
msgid "Birthday"
msgstr "Sünnipäev"
-#: templates/menu.inc:7
+#: lib/Driver.php:524
+#, php-format
+msgid "Birthday of %s"
+msgstr "Sünnipäev %s"
+
+#: lib/api.php:1255
+msgid "Birthdays"
+msgstr "Sünnipäevad"
+
+#: contact.php:103 templates/browse/row.inc:6
+msgid "Blank name"
+msgstr "Tühi nimi"
+
+#: templates/browse/actions.inc:51
+msgid "Both"
+msgstr "Mõlemad"
+
+#: templates/menu.inc:8
msgid "Browse"
msgstr "Sirvi"
-#: config/attributes.php.dist:173
+#: config/attributes.php.dist:280
msgid "Business Category"
msgstr "Tegevusala"
-#: data.php:49
+#: data.php:60
msgid "CSV"
msgstr "CSV"
-#: lib/Object/Group.php:57
+#: lib/Object/Group.php:68
msgid "Can't add a group to itself."
msgstr "Gruppi ei saa lisada iseenda liikmeks."
+#: lib/Driver/kolab.php:620
+#, fuzzy, php-format
+msgid "Cannot delete all address book entries for %s"
+msgstr "Ava \"%s\" kanne aadressiraamatus"
+
+#: config/attributes.php.dist:342
+msgid "Category"
+msgstr "Kategooria"
+
+#: templates/browse/column_headers.inc:24
+#, php-format
+msgid "Change %s sort to %s"
+msgstr "Vaheta sorteerimine %s - %s vastu"
+
+#: templates/browse/column_headers.inc:7
+msgid "Check All/None"
+msgstr "Märgi/tühjenda kõik"
+
#: templates/browse/column_headers.inc:7
msgid "Check _All/None"
msgstr "Märgi/tühjenda _kõik"
-#: templates/addressbooks.inc:44
+#: config/attributes.php.dist:107
+msgid "Children"
+msgstr "Lapsed"
+
+#: templates/addressbooks.inc:60
msgid "Choose a name"
msgstr "Vali nimi"
-#: add.php:48
+#: lib/Forms/AddContact.php:36
msgid "Choose an address book"
msgstr "Vali aadressiraamat"
-#: templates/prefs/columnselect.inc:221
+#: templates/prefs/columnselect.inc:218 templates/prefs/columnselect.inc:220
msgid "Choose an address book:"
msgstr "Vali aadressiraamat:"
-#: templates/prefs/addressbookselect.inc:165
+#: templates/prefs/addressbookselect.inc:163
msgid "Choose which address books to display, and in what order:"
msgstr "Vali, milliseid aadressiraamatuid näidata, ja millises järjestuses:"
@@ -216,15 +266,23 @@ msgstr "Vali, milliseid aadressiraamatuid n
msgid "Choose which address books to use."
msgstr "Vali, milliseid aadressiraamatuid kasutada."
-#: templates/prefs/columnselect.inc:228
+#: templates/prefs/columnselect.inc:227
msgid "Choose which columns to display and in what order:"
msgstr "Vali, milliseid veerge näidata, ja millises järjestuses."
+#: templates/block/minisearch.inc:27
+msgid "Close"
+msgstr "Sule"
+
+#: templates/browse/header.inc:7
+msgid "Close Search"
+msgstr "Sulge otsing"
+
#: config/prefs.php.dist:17
msgid "Column Options"
msgstr "Veeru seaded"
-#: templates/prefs/columnselect.inc:233
+#: templates/prefs/columnselect.inc:231 templates/prefs/columnselect.inc:233
msgid "Columns that will not be displayed:"
msgstr "Veerud, mida ei näidata:"
@@ -236,101 +294,111 @@ msgstr "Komaga eraldatud v
msgid "Comma separated values (Microsoft Outlook)"
msgstr "Komaga eraldatud väljad (Microsoft Outlook)"
-#: config/attributes.php.dist:76
+#: config/sources.php.dist:228 config/sources.php.dist:901
+#, fuzzy
+msgid "Communications"
+msgstr "Veeru seaded"
+
+#: config/attributes.php.dist:286
msgid "Company"
msgstr "Firma"
-#: config/attributes.php.dist:144
+#: config/attributes.php.dist:215
msgid "Company Address"
msgstr "Töökoha aadress"
-#: lib/api.php:318 lib/api.php:363 lib/api.php:407 lib/api.php:491
-#: lib/api.php:601 lib/api.php:688 lib/api.php:741 lib/api.php:819
-#: lib/api.php:1006 lib/api.php:1094
+#: scripts/import_squirrelmail_abook.php:112 lib/api.php:394 lib/api.php:439
+#: lib/api.php:490 lib/api.php:525 lib/api.php:574 lib/api.php:620
+#: lib/api.php:661 lib/api.php:778 lib/api.php:865 lib/api.php:923
+#: lib/api.php:1012 lib/api.php:1231 lib/api.php:1289 lib/api.php:1371
#, php-format
msgid "Connection failed: %s"
msgstr "Ühendus nurjus: %s"
-#: lib/Driver/ldap.php:58
+#: lib/Driver/ldap.php:71
msgid "Connection failure"
msgstr "Ühendus nurjus"
-#: browse.php:191 browse.php:232
-msgid "Contact added to list."
-msgstr "Aadress lisati listi."
+#: lib/Block/minisearch.php:3 lib/Block/minisearch.php:26
+#, fuzzy
+msgid "Contact Search"
+msgstr "Lihtotsing"
-#: browse.php:60
-msgid "Contact removed from list."
-msgstr "Aadress eemaldati listist."
+#: config/sources.php.dist:833
+msgid "Contacts"
+msgstr "Kontaktid"
-#: browse.php:266
+#: templates/list/numPager.inc:3
+#, fuzzy
+msgid "Contacts displayed:"
+msgstr "Näidatavad kanded:"
+
+#: lib/Views/Browse.php:336
#, php-format
msgid "Contacts in list: %s"
msgstr "Aadressid listis: %s"
-#: templates/browse/actions.inc:12
+#: templates/browse/actions.inc:18
msgid "Copy"
msgstr "Kopeeri"
-#: templates/addressbooks.inc:53
+#: templates/addressbooks.inc:69
msgid "Create"
msgstr "Loo"
-#: templates/addressbooks.inc:40
+#: templates/addressbooks.inc:56
msgid "Create Address Book"
msgstr "Loo aadressiraamat"
-#: lib/ListView.php:315
+#: lib/ListView.php:443
msgid "Create a new Contact List in:"
msgstr "Loo uus list siia:"
-#: lib/ObjectView.php:133
+#: lib/Views/Contact.php:74
msgid "Created"
msgstr "Loodud"
-#: config/prefs.php.dist:98
-msgid "Default sorting direction:"
-msgstr "Vaikimisi järjestuse suund:"
+#: contact.php:86
+msgid "De_lete"
+msgstr "Kustuta"
-#: templates/addressbooks.inc:76 templates/browse/actions.inc:2
-#: lib/Object.php:328 lib/Renderer.php:47 lib/Renderer.php:50
+#: templates/addressbooks.inc:94 templates/browse/actions.inc:3
+#: lib/Views/DeleteContact.php:58
msgid "Delete"
msgstr "Kustuta"
-#: templates/addressbooks.inc:58
+#: lib/Views/DeleteContact.php:28
+#, php-format
+msgid "Delete %s"
+msgstr "Kustuta %s"
+
+#: templates/addressbooks.inc:76
msgid "Delete Address Book"
msgstr "Kustuta aadressiraamat"
-#: config/prefs.php.dist:38
-msgid "Delete Confirmation"
-msgstr "Kustutamise kinnitus"
-
-#: config/prefs.php.dist:39
-msgid "Delete button behaviour"
-msgstr "Kustutusnupu käitumine"
-
-#: lib/Driver/ldap.php:270
+#: lib/Driver/ldap.php:288
#, php-format
msgid "Delete failed: (%s) %s"
msgstr "Kustutamine nurjus: (%s) %s"
-#: delete.php:38
+#: lib/Driver.php:1526
+#, fuzzy
+msgid "Deleting contacts is not available."
+msgstr "FTP laiendus ei ole saadaval."
+
+#: delete.php:40
msgid "Deletion failed"
msgstr "Kustutamine ebaõnnestus"
-#: config/attributes.php.dist:213
+#: config/attributes.php.dist:292
msgid "Department"
msgstr "Osakond"
-#: config/prefs.php.dist:97
-msgid "Descending"
-msgstr "Kahanev"
-
-#: templates/addressbooks.inc:115
+#: templates/addressbooks.inc:138
msgid "Description"
msgstr "Kirjeldus"
-#: templates/browse/search.inc:118
+#: templates/browse/search.inc:125
msgid "Directory"
msgstr "Kataloog"
@@ -343,63 +411,78 @@ msgstr "Esitus"
msgid "Display Options"
msgstr "Esituse seaded"
-#: config/prefs.php.dist:176
-msgid "Do you want to confirm deleting entries?"
-msgstr "Küsi kannete kustutamisel kinnitust"
-
-#: lib/Object.php:297
+#: lib/Object.php:348
msgid "Download"
msgstr "Salvesta"
-#: templates/browse/row.inc:17 templates/browse/contactrow.inc:25
+#: templates/browse/row.inc:13
msgid "Download vCard"
msgstr "Salvesta vCard"
-#: templates/addressbooks.inc:102 templates/browse/row.inc:25
-#: templates/browse/column_headers.inc:10 templates/browse/actions.inc:3
-#: templates/browse/contactrow.inc:33 lib/Renderer.php:42
+#: templates/addressbooks.inc:123 templates/browse/column_headers.inc:10
+#: templates/browse/row.inc:21 templates/browse/actions.inc:6
msgid "Edit"
msgstr "Muuda"
-#: templates/browse/row.inc:25 templates/browse/contactrow.inc:33
+#: edit.php:91
#, php-format
msgid "Edit \"%s\""
msgstr "Muuda \"%s\""
-#: templates/addressbooks.inc:81
+#: lib/Views/EditContact.php:35
+#, php-format
+msgid "Edit %s"
+msgstr "Muuda %s"
+
+#: templates/addressbooks.inc:100
msgid "Edit Address Books"
msgstr "Muuda aadressiraamatuid"
-#: edit.php:78 edit.php:154
-#, php-format
-msgid "Edit entry for %s"
-msgstr "Muuda %s andmeid"
-
-#: config/attributes.php.dist:58
+#: config/attributes.php.dist:229
msgid "Email"
msgstr "E-post"
-#: edit.php:147
-#, php-format
-msgid "Entry for %s updated, but saving the uploaded file failed: %s"
-msgstr ""
-"%s kanne uuendati, kuid serverisse laetud faili salvestamine nurjus: %s"
+#: config/attributes.php.dist:235
+#, fuzzy
+msgid "Emails"
+msgstr "E-post"
+
+#: lib/Views/Browse.php:260 lib/Views/Browse.php:300
+#, fuzzy, php-format
+msgid "Error adding %d contact(s) to list."
+msgstr "%d sissekannet lisati listi."
+
+#: lib/Views/Browse.php:262 lib/Views/Browse.php:302
+#, fuzzy, php-format
+msgid "Error adding %d of %d requested contact(s) to list."
+msgstr "%d sissekannet lisati listi."
+
+#: lib/Views/Browse.php:134
+#, fuzzy, php-format
+msgid "Error deleting %d contact(s)."
+msgstr "Viga sisu laadimisel: %s"
-#: edit.php:149 edit.php:152
+#: lib/Views/Browse.php:136
#, php-format
-msgid "Entry for %s updated."
-msgstr "%s kanne muudetud."
+msgid "Error deleting %d of %d requested contacts(s)."
+msgstr "Viga kustutamise %d'l kontakti %d'st. "
+
+#: lib/Views/Browse.php:117
+#, fuzzy, php-format
+msgid "Error removing %d contact(s) from list."
+msgstr "%d sissekanne(t) listist eemaldatud."
-#: browse.php:74
-msgid "Entry successfully deleted."
-msgstr "Kanne kustutatud."
+#: lib/Views/Browse.php:119
+#, fuzzy, php-format
+msgid "Error removing %d of %d requested contact(s) from list."
+msgstr "%d sissekanne(t) listist eemaldatud."
-#: lib/api.php:413
+#: lib/api.php:531
#, php-format
msgid "Error searching the address book: %s"
msgstr "Aadressiraamatu otsingu viga: %s"
-#: templates/browse/actions.inc:6 templates/data/export.inc:41
+#: templates/browse/actions.inc:10 templates/data/export.inc:42
msgid "Export"
msgstr "Eksport"
@@ -407,168 +490,204 @@ msgstr "Eksport"
msgid "Export Address Book"
msgstr "Aadressiraamatu eksport"
-#: templates/data/export.inc:21
+#: templates/data/export.inc:22
msgid "Export only the selected contacts."
msgstr "Ekspordi ainult märgitud kanded."
-#: templates/data/export.inc:27
+#: templates/data/export.inc:28
msgid "Export the following address book completely."
msgstr "Ekspordi see aadressiraamat täies ulatuses."
-#: data.php:134 data.php:228 data.php:297 browse.php:35 browse.php:90
-#: browse.php:112 add.php:67 search.php:37
+#: search.php:86 add.php:42 data.php:143 data.php:242 data.php:320
+#: lib/Views/Browse.php:84 lib/Views/Browse.php:152 lib/Views/Browse.php:180
#, php-format
msgid "Failed to access the address book: %s"
msgstr "Juurdepääs aadressiraamatule nurjus: %s"
-#: browse.php:139
+#: lib/Views/Browse.php:208
#, php-format
msgid "Failed to add %s to %s: %s"
msgstr "%s lisamine %s-le nurjus: %s"
-#: browse.php:272
+#: lib/Views/Browse.php:342
msgid "Failed to browse list"
msgstr "Listi sirvimine nurjus"
-#: browse.php:310
+#: lib/Views/Browse.php:369
msgid "Failed to browse the directory"
msgstr "Kataloogi sirvimine ebaõnnestus"
-#: lib/Driver/ldap.php:309
+#: lib/Driver/ldap.php:321
#, php-format
msgid "Failed to change name: (%s) %s; Old DN = %s, New DN = %s, Root = %s"
msgstr "Nime muutmine nurjus: (%s) %s; Vana DN = %s, uus DN = %s, Root = %s"
-#: browse.php:120
+#: lib/Views/Browse.php:186
#, php-format
msgid "Failed to find object to be added: %s"
msgstr "Ei leidnud objekti, mida lisada: %s"
-#: search.php:79
+#: search.php:152
msgid "Failed to search the address book"
msgstr "Aadressiraamatu otsing nurjus"
-#: data.php:149
+#: data.php:158
#, php-format
msgid "Failed to search the directory: %s"
msgstr "Otsing kataloogist ebaõnnestus: %s"
-#: config/attributes.php.dist:167
+#: config/sources.php.dist:532
+#, fuzzy
+msgid "Favourite Recipients"
+msgstr "Nähtamatud adressaadid"
+
+#: config/attributes.php.dist:256
msgid "Fax"
msgstr "Faks"
-#: edit.php:124 display.php:100
+#: lib/Forms/Contact.php:40
msgid "Files"
msgstr "Failid"
-#: templates/browse/search.inc:70
+#: templates/browse/search.inc:104
msgid "Find"
msgstr "Leia"
-#: edit.php:97 edit.php:187
+#: lib/Forms/EditContact.php:121 lib/Forms/EditContact.php:159
msgid "Finish"
msgstr "Lõpp"
-#: config/attributes.php.dist:48
+#: config/attributes.php.dist:47
msgid "First Name"
msgstr "Eesnimi"
-#: config/attributes.php.dist:202
+#: config/attributes.php.dist:318
msgid "Freebusy URL"
msgstr "Freebusy URL"
-#: templates/browse/search.inc:83
+#: templates/browse/search.inc:98
msgid "From"
msgstr "Kellelt"
-#: config/sources.php.dist:604
+#: config/attributes.php.dist:374
+msgid "Gender"
+msgstr "Sugu"
+
+#: config/sources.php.dist:758
msgid "Global Address Book"
msgstr "Globaalne aadressiraamat"
-#: templates/browse/row.inc:43 templates/browse/contactrow.inc:44
+#: templates/browse/row.inc:39
msgid "Group"
msgstr "Grupp"
-#: config/attributes.php.dist:82
+#: config/attributes.php.dist:115
msgid "Home Address"
msgstr "Kodune aadress"
-#: config/attributes.php.dist:93
+#: config/attributes.php.dist:133
msgid "Home City"
msgstr "Kodulinn"
-#: config/attributes.php.dist:108
+#: config/attributes.php.dist:151
msgid "Home Country"
msgstr "Kodumaa"
-#: config/attributes.php.dist:150
+#: config/attributes.php.dist:241
msgid "Home Phone"
msgstr "Kodune telefon"
-#: config/attributes.php.dist:103
+#: config/attributes.php.dist:127
+msgid "Home Post Office Box"
+msgstr "Kodune postiindeks"
+
+#: config/attributes.php.dist:145
msgid "Home Postal Code"
msgstr "Kodune postiindeks"
-#: config/attributes.php.dist:98
+#: config/attributes.php.dist:139
msgid "Home State/Province"
msgstr "Kodumaakond"
-#: config/attributes.php.dist:88
+#: config/attributes.php.dist:121
msgid "Home Street Address"
msgstr "Kodune tänav/maja"
-#: config/sources.php.dist:506
+#: config/sources.php.dist:649
msgid "IMSP"
msgstr "IMSP"
-#: config/prefs.php.dist:47
-msgid "IMSP Address Book Administration"
-msgstr "IMSP aadressiraamatu haldus"
-
#: templates/data/import.inc:7
#, php-format
msgid "Import Address Book, Step %d"
msgstr "Aadressiraamatu import, samm %d"
-#: data.php:361
+#: data.php:388
msgid "Import/Export Address Books"
msgstr "Aadressiraamatute import/eksport"
-#: lib/api.php:596 lib/api.php:683
+#: config/attributes.php.dist:350
+msgid "Initials"
+msgstr "Initsiaalid"
+
+#: config/attributes.php.dist:356
+msgid "Instant Messenger"
+msgstr "Otse suhtlus"
+
+#: lib/api.php:773 lib/api.php:860
msgid "Invalid ID"
msgstr "Vigane ID"
-#: lib/api.php:230 lib/api.php:402 lib/api.php:486 lib/api.php:592
-#: lib/api.php:679 lib/api.php:731 lib/api.php:1077
-msgid "Invalid address book"
-msgstr "Vigane aadressiraamat"
+#: scripts/import_squirrelmail_abook.php:105 lib/api.php:306 lib/api.php:520
+#: lib/api.php:569 lib/api.php:615 lib/api.php:656 lib/api.php:769
+#: lib/api.php:856 lib/api.php:913 lib/api.php:1354
+#, php-format
+msgid "Invalid address book: %s"
+msgstr "Vigane aadressiraamat: %s"
-#: lib/api.php:1081 lib/api.php:1154 lib/api.php:1207
+#: lib/api.php:1358 lib/api.php:1432 lib/api.php:1489
msgid "Invalid email"
msgstr "Vigane e-posti aadress"
-#: lib/api.php:1089
+#: lib/api.php:1366
msgid "Invalid entry"
msgstr "Vigane kanne"
-#: lib/Driver/ldap.php:266
+#: lib/Driver/ldap.php:284
msgid "Invalid key specified."
msgstr "Määrati vigane võti."
-#: lib/api.php:1085
+#: lib/api.php:1362
msgid "Invalid name"
msgstr "Vigane nimi"
-#: lib/api.php:735
+#: lib/api.php:917
msgid "Invalid objectId"
msgstr "Vigane objectId"
-#: lib/Driver/ldap.php:30
+#: config/attributes.php.dist:268
+msgid "Job Title"
+msgstr "Tiitel"
+
+#: lib/Driver/kolab.php:855 lib/Driver/kolab.php:877
+#, php-format
+msgid "Key for saving must be a UID not %s!"
+msgstr "Salvestamise võti peab olema UID mitte %s!"
+
+#: lib/Driver/ldap.php:67
msgid ""
"LDAP support is required but the LDAP module is not available or not loaded."
msgstr "Vajalik on LDAP toetus, ent LDAP moodul puudub või pole laetud."
-#: lib/ObjectView.php:138
+#: data.php:65 templates/data/import.inc:18 templates/data/export.inc:16
+msgid "LDIF Address Book"
+msgstr "LDIF Aadressiraamat"
+
+#: config/attributes.php.dist:380
+msgid "Language"
+msgstr "Keel"
+
+#: lib/Views/Contact.php:80
msgid "Last Modified"
msgstr "Viimati muudetud"
@@ -576,19 +695,35 @@ msgstr "Viimati muudetud"
msgid "Last Name"
msgstr "Perekonnanimi"
+#: config/attributes.php.dist:386
+msgid "Latitude"
+msgstr "laiuskraad"
+
#: templates/browse/column_headers.inc:16
msgid "List"
msgstr "Nimekiri"
-#: templates/browse/search.inc:77
+#: config/sources.php.dist:223 config/sources.php.dist:897
+msgid "Location"
+msgstr "Asukoht"
+
+#: config/attributes.php.dist:391
+msgid "Longitude"
+msgstr "Pikkuskraad"
+
+#: config/attributes.php.dist:362
+msgid "Manager"
+msgstr "Haldur"
+
+#: templates/browse/search.inc:109
msgid "Matching"
msgstr " mis sisaldab "
-#: lib/api.php:205
+#: lib/api.php:281
msgid "Maximum Number of Contacts"
msgstr "Kannete suurim arv"
-#: config/prefs.php.dist:107
+#: config/prefs.php.dist:88
msgid "Maximum number of pages"
msgstr "Lehekülgede suurim arv"
@@ -596,60 +731,65 @@ msgstr "Lehek
msgid "Menu List"
msgstr "Menüü nimekiri"
-#: lib/Block/minisearch.php:3
-msgid "Mini Search"
-msgstr "Miniotsing"
+#: config/attributes.php.dist:59
+msgid "Middle Names"
+msgstr "Kesknimi"
-#: lib/Driver/ldap.php:302
+#: lib/Driver/ldap.php:314
msgid "Missing DN in LDAP source configuration."
msgstr "LDAP allika seadistuses puudub DN."
-#: config/attributes.php.dist:162
+#: config/attributes.php.dist:251
msgid "Mobile Phone"
msgstr "Mobiiltelefon"
-#: lib/Driver/ldap.php:332 lib/Driver/ldap.php:348
+#: lib/Driver/ldap.php:343 lib/Driver/ldap.php:359
#, php-format
msgid "Modify failed: (%s) %s"
msgstr "Muutmine nurjus: (%s) %s"
-#: lib/api.php:1193
+#: templates/browse/header.inc:8
+#, fuzzy
+msgid "More Options..."
+msgstr "Kirja seaded"
+
+#: lib/api.php:1474
msgid "More than 1 entry found"
msgstr "Leiti rohkem kui 1 kanne"
-#: templates/browse/actions.inc:11
+#: templates/browse/actions.inc:16
msgid "Move"
msgstr "Nihuta"
-#: templates/prefs/columnselect.inc:247
#: templates/prefs/addressbookselect.inc:184
+#: templates/prefs/columnselect.inc:248
msgid "Move left"
msgstr "nihuta vasakule"
-#: templates/prefs/columnselect.inc:249
#: templates/prefs/addressbookselect.inc:186
+#: templates/prefs/columnselect.inc:250
msgid "Move right"
msgstr "nihuta paremale"
-#: data.php:52 templates/data/import.inc:16
+#: data.php:63 templates/data/import.inc:16
msgid "Mulberry Address Book"
msgstr "Mulberry aadressiraamat"
-#: lib/api.php:1113
+#: lib/api.php:1390
#, php-format
msgid ""
"Multiple persons with address [%s], but none with name [%s] already exist"
msgstr "Kirjas on juba mitu inimest aadressiga [%s], kuid ühegi nimi pole [%s]"
-#: config/sources.php.dist:107 config/sources.php.dist:243
+#: config/sources.php.dist:161
msgid "My Address Book"
msgstr "Minu aadressiraamat"
-#: addressbooks.php:120
+#: addressbooks.php:174
msgid "My Address Books"
msgstr "Minu aadressiraamatud"
-#: templates/addressbooks.inc:107 config/attributes.php.dist:42
+#: templates/addressbooks.inc:130 config/attributes.php.dist:41
msgid "Name"
msgstr "Nimi"
@@ -657,61 +797,103 @@ msgstr "Nimi"
msgid "Name Format"
msgstr "Nime esitus"
-#: config/sources.php.dist:315
-msgid "Netcenter Member Directory"
-msgstr "Netcenteri liikmete kataloog"
+#: config/attributes.php.dist:65
+msgid "Name Prefixes"
+msgstr "Nime liides"
+
+#: config/attributes.php.dist:71
+msgid "Name Suffixes"
+msgstr "Nime liited."
+
+#: templates/browse/search_vbook.inc:6
+msgid "Name:"
+msgstr "Nimi:"
-#: add.php:36 add.php:124 lib/Block/minisearch.php:27
-#: lib/Block/tree_menu.php:27
+#: add.php:70 lib/Block/tree_menu.php:28
msgid "New Contact"
msgstr "Lisa uus sissekanne"
-#: edit.php:88 edit.php:95 edit.php:202 templates/data/import.inc:45
+#: templates/data/import.inc:46 lib/Forms/EditContact.php:112
+#: lib/Forms/EditContact.php:119 lib/Forms/EditContact.php:174
msgid "Next"
msgstr "Edasi"
-#: config/attributes.php.dist:218
+#: config/attributes.php.dist:83
msgid "Nickname"
msgstr "Hüüdnimi"
-#: lib/api.php:1195 lib/api.php:1244
+#: lib/api.php:1477 lib/api.php:1526
#, php-format
msgid "No %s entry found for %s"
msgstr "%s kannet %s jaoks ei leitud"
-#: lib/api.php:1163
+#: data.php:52
+msgid ""
+"No Address Books are currently available. Import and Export is disabled."
+msgstr "Aadressi raamatuid ei ole saadaval. Import ja eksport on keelatud."
+
+#: search.php:72
+msgid "No Address Books are currently available. Searching is disabled."
+msgstr "Aadressi raamatuid ei ole saadaval. Otsimine on keelatud."
+
+#: lib/api.php:1441
msgid "No address books found."
msgstr "Ei leitud ühtki aadressiraamatut."
-#: minisearch.php:83
+#: minisearch.php:81
msgid "No contacts found"
msgstr "Kandeid ei leitud"
-#: lib/api.php:511 lib/api.php:766
+#: templates/browse/column_headers.inc:43
+msgid "No contacts match the current filter."
+msgstr "Ühtegi vastet ei leitud otsingule."
+
+#: lib/ListView.php:251
+msgid "No matching contacts"
+msgstr "Ühtegi vastet ei leitud."
+
+#: lib/Driver/favourites.php:120
+msgid "No source for favourite recipients exists."
+msgstr "Lemmik saajate allikat ei leidu."
+
+#: lib/api.php:682 lib/api.php:949
msgid "No vCard data was found."
msgstr "vCard andmeid ei leitud."
-#: templates/browse/footer.inc:7
+#: templates/list/numPager.inc:8
msgid "None"
msgstr "Puudub"
-#: config/attributes.php.dist:184
+#: lib/Views/EditContact.php:33 lib/Views/Contact.php:49
+#: lib/Views/DeleteContact.php:26
+msgid "Not Found"
+msgstr "Ei leitud"
+
+#: deletefile.php:22 edit.php:48
+msgid "Not found"
+msgstr "Ei leitud"
+
+#: config/attributes.php.dist:306
msgid "Notes"
msgstr "Märkmed"
-#: config/prefs.php.dist:115
+#: config/prefs.php.dist:96
msgid "Number of items per page"
msgstr "Kannete arv leheküljel"
-#: lib/api.php:614 lib/api.php:747
+#: lib/api.php:789 lib/api.php:929
msgid "Object not found"
msgstr "Objekti ei leitud"
-#: config/attributes.php.dist:223
+#: config/attributes.php.dist:274
+msgid "Occupation"
+msgstr "Amet"
+
+#: config/attributes.php.dist:298
msgid "Office"
msgstr "Töökoht"
-#: templates/prefs/imsp_opt.inc:23
+#: templates/prefs/imsp_opt.inc:22
msgid ""
"Once you save this option page, the address book will be permanently "
"deleted. If this is not what you want, then you must change your selection "
@@ -720,69 +902,71 @@ msgstr ""
"Selle seadistuse lehe salvestamisel kustutatakse aadressiraamat jäädavalt."
"Kui sa seda ei taha, pead valima \"Puudub\"."
-#: lib/api.php:774
+#: lib/api.php:957
msgid "Only one vcard supported."
msgstr "Lubatud on ainult üks vCard."
-#: config/prefs.php.dist:37 config/prefs.php.dist:46
-msgid "Other Options"
-msgstr "Muud seaded"
+#: config/sources.php.dist:230 config/sources.php.dist:903
+msgid "Organization"
+msgstr "Organisatsioon"
+
+#: config/sources.php.dist:231 config/sources.php.dist:905
+msgid "Other"
+msgstr "Muu"
-#: config/attributes.php.dist:190
+#: config/attributes.php.dist:324
msgid "PGP Public Key"
msgstr "PGP avalik võti"
-#: lib/api.php:495 lib/api.php:605 lib/api.php:692 lib/api.php:934
-#: lib/api.php:1098
-msgid "Permission Denied"
-msgstr "Juurdepääs puudub"
+#: config/attributes.php.dist:261
+msgid "Pager"
+msgstr "Piipar"
+
+#: lib/Views/DeleteContact.php:57
+msgid "Permanently delete this contact?"
+msgstr "Kustutada see kontakt igaveseks?"
-#: lib/Driver.php:543
+#: deletefile.php:36 lib/Driver.php:676 lib/api.php:665 lib/api.php:782
+#: lib/api.php:869 lib/api.php:1159 lib/api.php:1375 lib/Driver/sql.php:481
msgid "Permission denied"
msgstr "Juurdepääs puudub"
-#: templates/addressbooks.inc:99
+#: templates/addressbooks.inc:120
msgid "Permissions"
msgstr "Õigused"
-#: data.php:53 templates/data/import.inc:17
+#: config/sources.php.dist:221 config/sources.php.dist:893
+msgid "Personal"
+msgstr "Isiklik"
+
+#: data.php:64 templates/data/import.inc:17
msgid "Pine Address Book"
msgstr "Pine aadressiraamat"
-#: templates/browse/javascript.inc:28
+#: templates/browse/javascript.inc:27
msgid "Please name the new contact list:"
msgstr "Sisesta uue listi nimi:"
-#: edit.php:91 edit.php:94 edit.php:194
+#: lib/Forms/EditContact.php:115 lib/Forms/EditContact.php:118
+#: lib/Forms/EditContact.php:166
msgid "Previous"
msgstr "Tagasi"
-#: config/sources.php.dist:416
-msgid "Private Address Book"
-msgstr "Isiklik aadressiraamat"
-
-#: lib/Driver/ldap.php:147
+#: lib/Driver/ldap.php:165
+#, php-format
msgid "Query failed: (%s) %s"
msgstr "Päring nurjus: (%s) %s"
-#: templates/block/minisearch.inc:18
-msgid "Quick Search"
-msgstr "Kiirotsing"
-
-#: lib/Driver/ldap.php:191 lib/Driver/ldap.php:199 lib/Driver/ldap.php:429
+#: lib/Driver/ldap.php:209 lib/Driver/ldap.php:217 lib/Driver/ldap.php:453
#, php-format
msgid "Read failed: (%s) %s"
msgstr "Lugemine nurjus: (%s) %s"
-#: lib/Renderer.php:49
-msgid "Really delete this contact?"
-msgstr "Kas tõesti kustutada see kanne?"
-
-#: templates/browse/footer.inc:2
-msgid "Records displayed:"
-msgstr "Näidatavad kanded:"
+#: lib/Driver.php:1510
+msgid "Reading contacts is not available."
+msgstr "Kontaktide kuvamine ei ole võimalik."
-#: templates/prefs/addressbookselect.inc:176
+#: templates/prefs/addressbookselect.inc:175
msgid "Remove address book"
msgstr "Eemalda aadressiraamat"
@@ -790,11 +974,19 @@ msgstr "Eemalda aadressiraamat"
msgid "Remove column"
msgstr "eemalda veerg"
-#: templates/browse/actions.inc:2
+#: templates/browse/actions.inc:3
msgid "Remove from this list"
msgstr "Eemalda sellest listist"
-#: templates/data/import.inc:21
+#: lib/Driver.php:1548
+msgid ""
+"Removing user data is not supported in the current address book storage "
+"driver."
+msgstr ""
+"Kasutaja andmete kustutamine ei ole võimalik antud aadressi raamatu "
+"draiveriga."
+
+#: templates/data/import.inc:22
msgid ""
"Replace existing address book with the imported one? <strong>Warning: This "
"deletes all entries in your current address book.</strong>"
@@ -802,75 +994,87 @@ msgstr ""
"Kas asendame olemasoleva aadressiraamatu imporditavaga? <strong>Hoiatus: "
"sellega hävivad kõik olemasolevad sissekanded aadressiraamatus.</strong>"
-#: lib/Driver.php:438
+#: lib/Driver.php:573
msgid "Requested object not found."
msgstr "Soovitud objekti ei leitud."
-#: add.php:37 templates/browse/search.inc:113
+#: templates/browse/search.inc:120
msgid "Reset to Defaults"
msgstr "Taasta vaikeväärtused"
-#: config/attributes.php.dist:196
+#: config/attributes.php.dist:330
msgid "S/MIME Public Certificate"
msgstr "S/MIME avalik sertifikaat"
-#: lib/Driver/ldap.php:69
+#: lib/Driver/ldap.php:87
#, php-format
msgid "STARTTLS failed: (%s) %s"
msgstr "STARTTLS nurjus: (%s) %s"
-#: edit.php:99 add.php:37 templates/addressbooks.inc:124
+#: templates/addressbooks.inc:147 lib/Forms/EditContact.php:26
msgid "Save"
msgstr "Salvesta"
-#: templates/browse/search.inc:96 templates/browse/search.inc:112
-#: templates/block/minisearch.inc:21 lib/Block/tree_menu.php:49
-#: config/prefs.php.dist:126
+#: templates/browse/search_vbook.inc:4
+msgid "Save search as a virtual address book?"
+msgstr "Säilita otsingutulemus virtuaalkaustana?"
+
+#: lib/Driver.php:1536
+msgid "Saving contacts is not available."
+msgstr "Kontatkide salvestamine ei ole saadaval."
+
+#: templates/browse/header.inc:3 templates/browse/search.inc:111
+#: templates/browse/search.inc:119 templates/block/minisearch.inc:26
+#: lib/Block/tree_menu.php:59 config/prefs.php.dist:107
msgid "Search"
msgstr "Otsing"
-#: minisearch.php:63
-msgid "Search Results:"
-msgstr "Otsingu tulemus:"
-
-#: lib/api.php:1011
+#: lib/api.php:1236
msgid "Search failed"
msgstr "Otsing nurjus"
-#: lib/api.php:1103 lib/api.php:1109 lib/api.php:1118 lib/api.php:1131
+#: lib/api.php:1380 lib/api.php:1386 lib/api.php:1395 lib/api.php:1408
#, php-format
msgid "Search failed: %s"
msgstr "Otsing nurjus: %s"
-#: templates/block/minisearch.inc:22
-msgid "Searching..."
-msgstr "Otsing käib..."
+#: templates/block/minisearch.inc:24
+msgid "Search for: "
+msgstr "Otsing: %s"
-#: templates/addressbooks.inc:66
+#: lib/Driver.php:1495
+msgid "Searching is not available."
+msgstr "Otismine ei ole saadaval."
+
+#: templates/addressbooks.inc:84
msgid "Select an address book to delete"
msgstr "Vali kustutamisele kuuluv aadressiraamat."
-#: templates/addressbooks.inc:90
+#: templates/addressbooks.inc:109
msgid "Select an address book to edit"
msgstr "Vali aadressiraamat, mida soovid muuta."
-#: templates/data/export.inc:32
+#: templates/browse/row.inc:30
+msgid "Select contact"
+msgstr "Vali kontakt"
+
+#: templates/data/export.inc:33
msgid "Select the address book to export from:"
msgstr "Kust eksportida:"
-#: templates/data/import.inc:26
+#: templates/data/import.inc:27
msgid "Select the address book to import to:"
msgstr "Kuhu importida:"
-#: templates/data/import.inc:35
+#: templates/data/import.inc:36
msgid "Select the charset of the source file:"
msgstr "Vali lähtefaili märgistik:"
#: templates/data/export.inc:10
-msgid "Seect the export format:"
+msgid "Select the export format:"
msgstr "Ekspordi vorming:"
-#: templates/data/import.inc:43
+#: templates/data/import.inc:44
msgid "Select the file to import:"
msgstr "Vali imporditav fail:"
@@ -878,7 +1082,7 @@ msgstr "Vali imporditav fail:"
msgid "Select the format of the source file:"
msgstr "Vali lähtefaili vorming:"
-#: config/prefs.php.dist:135
+#: config/prefs.php.dist:116
msgid "Select the format used to display names:"
msgstr "Vali nimede esitusviis:"
@@ -894,71 +1098,90 @@ msgstr "Vali, milliseid v
msgid "Select which format to display names."
msgstr "Vali, millisel kujul näidata nimesid."
-#: add.php:54
+#: lib/Forms/AddContact.php:42
#, php-format
msgid "Selected address book \"%s\"."
msgstr "Valitud aadressiraamat \"%s\"."
-#: config/sources.php.dist:173
-msgid "Shared Directory"
-msgstr "Ühiskataloog"
-
-#: templates/browse/actions.inc:39
+#: templates/browse/actions.inc:49
#, php-format
msgid "Show %s"
msgstr "Näita %s"
-#: templates/browse/actions.inc:41
-msgid "Show All"
-msgstr "Näita kõiki"
+#: templates/browse/actions.inc:51
+msgid "Show Both"
+msgstr "Näita mõlemaid"
-#: templates/browse/actions.inc:40
+#: templates/browse/actions.inc:50
msgid "Show Contacts"
msgstr "Näita sissekandeid"
-#: templates/browse/actions.inc:39
+#: templates/browse/actions.inc:49
msgid "Show Lists"
msgstr "Näita liste"
-#: templates/browse/column_headers.inc:21
-#: templates/browse/column_headers.inc:34
+#: lib/ListView.php:319 lib/ListView.php:325
msgid "Sort Direction"
msgstr "Järjestuse suund"
-#: lib/api.php:198
+#: templates/browse/column_headers.inc:31
+#, php-format
+msgid "Sort by %s"
+msgstr "Järjesta %s järgi"
+
+#: templates/browse/column_headers.inc:26
+#, php-format
+msgid "Sort by %s only"
+msgstr "Järjesta ainult %s järgi"
+
+#: templates/browse/column_headers.inc:29
+#, php-format
+msgid "Sort by %s, then by %s"
+msgstr "Sorteeri %s ja siis %s"
+
+#: templates/menu.inc:6
+msgid "Source:"
+msgstr "Allikad:"
+
+#: lib/api.php:274
msgid "Sources"
msgstr "Allikad"
-#: config/prefs.php.dist:157
-msgid "Specify where you want advanced search results to appear."
-msgstr "Määra, kus peaksid ilmuma põhjaliku otsingu tulemused."
+#: config/attributes.php.dist:101
+msgid "Spouse"
+msgstr "Abikaasa"
-#: browse.php:214 browse.php:262
+#: lib/Views/Browse.php:258 lib/Views/Browse.php:298
#, php-format
msgid "Successfully added %d contact(s) to list."
msgstr "%d sissekannet lisati listi."
-#: browse.php:141
+#: lib/Views/Browse.php:212
#, php-format
msgid "Successfully added %s to %s"
msgstr "%s lisati %s-i"
-#: browse.php:222
+#: lib/Views/Browse.php:288
#, php-format
msgid "Successfully created the contact list \"%s\"."
msgstr "List \"%s\" loodud."
-#: browse.php:84
+#: search.php:127
+#, php-format
+msgid "Successfully created virtual address book \"%s\""
+msgstr "Virtuaal aadressiraamatu \"%s\" tegemine õnnestus"
+
+#: lib/Views/Browse.php:132
#, php-format
msgid "Successfully deleted %d contact(s)."
msgstr "%d sissekanne(t) kustutatud."
-#: browse.php:64
+#: lib/Views/Browse.php:115
#, php-format
msgid "Successfully removed %d contact(s) from list."
msgstr "%d sissekanne(t) listist eemaldatud."
-#: data.php:50
+#: data.php:61
msgid "TSV"
msgstr "TSV"
@@ -966,53 +1189,71 @@ msgstr "TSV"
msgid "Tab separated values"
msgstr "Tabulaatoriga eraldatud väljad"
-#: view.php:15
+#: templates/browse/actions.inc:20
+msgid "Target Address Book"
+msgstr "Siht aadressiraamat"
+
+#: templates/browse/actions.inc:31
+msgid "Target Contact List"
+msgstr "Siht kontaktide nimekiri"
+
+#: data.php:322
+#, php-format
+msgid "The %s file didn't contain any contacts."
+msgstr "Fail %s ei sisaldanud ühtegi kontakti."
+
+#: view.php:17
msgid "The VFS backend needs to be configured to enable attachment uploads."
msgstr "Lisandite üleslaadimiseks peab VFS olema seadistatud."
-#: lib/Driver.php:1054
+#: lib/Driver.php:1466
#, php-format
msgid "The address book \"%s\" does not exist."
msgstr "Aadressiraamatut \"%s\" pole olemas."
-#: addressbooks.php:45
+#: addressbooks.php:104
#, php-format
msgid "The address book \"%s\" was created successfully."
msgstr "Aadressiraamat \"%s\" loodud."
-#: addressbooks.php:70
+#: addressbooks.php:130
#, php-format
msgid "The address book \"%s\" was removed successfully."
msgstr "Aadressiraamat \"%s\" kustutatud."
-#: addressbooks.php:89
+#: addressbooks.php:151
#, php-format
msgid "The address book \"%s\" was successfully updated."
msgstr "Muudatused aadressiraamatus \"%s\" salvestatud."
-#: data.php:303
+#: data.php:329
#, php-format
msgid "The address book could not be purged: %s"
msgstr "Aadressiraamatut ei saanud tühjendada: %s"
-#: edit.php:47 vcard.php:22 display.php:23 view.php:26
+#: contact.php:23 view.php:28 vcard.php:19
msgid "The contact you requested does not exist."
msgstr "Soovitud sissekannet pole olemas."
-#: edit.php:116
+#: deletefile.php:46
#, php-format
-msgid "The file \"%s\" has successfully been deleted."
-msgstr "Faili \"%s\" kustutamine õnnestus."
+msgid "The file \"%s\" has been deleted."
+msgstr "Fail \"%s\" on kustutatud."
-#: data.php:284
+#: data.php:302
msgid "The import can be finished despite the warnings."
msgstr "Import on võimalik sooritada hoiatustele vaatamata."
-#: browse.php:31
+#: lib/Views/EditContact.php:43 lib/Views/Contact.php:59
+#: lib/Views/DeleteContact.php:36
+msgid "The requested contact was not found."
+msgstr "Otsitud kontakti ei leitud."
+
+#: lib/Views/Browse.php:80
msgid "There are no browseable address books."
msgstr "Ükski aadressiraamat ei luba sirvimist."
-#: add.php:29
+#: add.php:32
msgid ""
"There are no writeable address books. None of the available address books "
"are configured to allow you to add new entries to them. If you believe this "
@@ -1021,7 +1262,12 @@ msgstr ""
"Ükski kasutatav aadressiraamat ei võimalda sul aadresse lisada. Kui see on "
"sinu arvates viga, võta ühendust süsteemi halduriga."
-#: add.php:121
+#: search.php:123
+#, php-format
+msgid "There was a problem creating the virtual address book: %s"
+msgstr "Selle aadressiraamatu loomisel tekkis viga: %s"
+
+#: lib/Forms/AddContact.php:90
msgid ""
"There was an error adding the new contact. Contact your system administrator "
"for further help."
@@ -1029,275 +1275,334 @@ msgstr ""
"Uue sissekande lisamisel tekkis viga. Abi saamiseks võta ühendust süsteemi "
"halduriga."
-#: browse.php:189 browse.php:230
-msgid "There was an error adding this object."
-msgstr "Selle objekti lisamisel tekkis viga."
-
-#: browse.php:238
+#: lib/Views/Browse.php:308
msgid "There was an error creating a new list."
msgstr "Listi loomisel tekkis viga."
-#: addressbooks.php:35
+#: addressbooks.php:96 addressbooks.php:102
#, php-format
msgid "There was an error creating this address book: %s"
msgstr "Selle aadressiraamatu loomisel tekkis viga: %s"
-#: browse.php:147
+#: lib/Views/Browse.php:218
#, php-format
msgid "There was an error deleting \"%s\" from the source address book."
msgstr "\"%s\" kustutamisel lähteaadressiraamatust tekkis viga."
-#: delete.php:37
+#: delete.php:39
#, php-format
msgid "There was an error deleting this contact: %s"
msgstr "Selle sissekande kustutamisel tekkis viga: %s"
-#: browse.php:72
-msgid "There was an error deleting this object."
-msgstr "Selle objekti kustutamisel tekkis viga."
-
-#: browse.php:278
+#: lib/Views/Browse.php:348
msgid "There was an error displaying the list"
msgstr "Listi näitamisel tekkis viga"
-#: data.php:335
+#: data.php:356
#, php-format
msgid "There was an error importing the data: %s"
msgstr "Andmete impordil tekkis viga: %s"
-#: lib/api.php:507 lib/api.php:761
+#: lib/api.php:678 lib/api.php:944
msgid "There was an error importing the iCalendar data."
msgstr "iCalendar andmete impordil tekkis viga."
-#: browse.php:58
-msgid "There was an error removing a contact from the list."
-msgstr "Liikme eemaldamisel listist tekkis viga."
+#: lib/api.php:227
+#, php-format
+msgid "There was an error removing an address book for %s"
+msgstr "Selle aadressiraamatu eemaldamisel tekkis viga: %s"
-#: addressbooks.php:55 addressbooks.php:60 addressbooks.php:68
+#: addressbooks.php:113 addressbooks.php:120 addressbooks.php:128
#, php-format
msgid "There was an error removing this address book: %s"
msgstr "Selle aadressiraamatu eemaldamisel tekkis viga: %s"
-#: addressbooks.php:81 addressbooks.php:87
+#: lib/Forms/EditContact.php:86
+msgid ""
+"There was an error saving the contact. Contact your system administrator for "
+"further help."
+msgstr ""
+"Uue sissekande lisamisel tekkis viga. Abi saamiseks võta ühendust süsteemi "
+"halduriga."
+
+#: addressbooks.php:149
#, php-format
msgid "There was an error updating this address book: %s"
msgstr "Selle aadressiraamatu muutmisel tekkis viga: %s"
-#: edit.php:158
-#, php-format
-msgid "There was an error updating this entry: %s"
-msgstr "Andmete muutmisel tekkis viga: %s"
-
-#: data.php:179
+#: data.php:188
msgid "There were no addresses to export."
msgstr "Polnudki aadresse, mida eksportida."
+#: templates/prefs/addressbookselect.inc:178
#: templates/prefs/addressbookselect.inc:180
msgid "These address books will display in this order:"
msgstr "Aadressiraamatuid näidatakse selles järjestuses:"
-#: templates/prefs/columnselect.inc:243
+#: templates/prefs/columnselect.inc:242 templates/prefs/columnselect.inc:244
msgid "These columns will display in this order:"
msgstr "Veerge näidatakse selles järjekorras:"
-#: data.php:269
+#: data.php:287
msgid "This file format is not supported."
msgstr "Seda failivormingut ei toetata."
-#: lib/api.php:1122 lib/api.php:1135
+#: lib/api.php:1399 lib/api.php:1412
#, php-format
msgid "This person already has a %s entry in the address book"
msgstr "Sellel isikul on juba aadressiraamatus %s kanne"
-#: config/prefs.php.dist:147
+#: config/prefs.php.dist:129
msgid ""
"This will be the default address book when adding or importing contacts."
msgstr ""
"See on aadressiraamat, kuhu aadresse vaikimisi lisatakse ja imporditakse."
-#: config/attributes.php.dist:70
-msgid "Title"
-msgstr "Tiitel"
+#: config/attributes.php.dist:221
+msgid "Time Zone"
+msgstr "Ajatsoon"
-#: lib/Turba.php:435
-#, php-format
-msgid "Unable to create new share. Missing source type."
-msgstr "Uue jao loomine nurjus. Puudub allika tüüp."
+#: lib/Driver/share.php:77
+msgid "Unable to find contact owner."
+msgstr "Kontakti omaniku ei leitud."
-#: lib/Driver.php:979
+#: lib/Turba.php:643 lib/Driver.php:1388
#, php-format
msgid "Unable to load the definition of %s."
msgstr "Ei suuda laadida %s kirjeldust."
-#: edit.php:88 edit.php:91 edit.php:94 edit.php:99 edit.php:196
+#: lib/Driver/kolab.php:486
+msgid "Unable to search."
+msgstr "Otsing ei õnnestunud."
+
+#: lib/Forms/EditContact.php:26 lib/Forms/EditContact.php:112
+#: lib/Forms/EditContact.php:115 lib/Forms/EditContact.php:118
+#: lib/Forms/EditContact.php:168
msgid "Undo Changes"
msgstr "Võta tagasi"
-#: lib/api.php:540 lib/api.php:643 lib/api.php:779
+#: config/attributes.php.dist:340
+msgid "Unfiled"
+msgstr "Kategooriata"
+
+#: lib/api.php:711 lib/api.php:814 lib/api.php:962
#, php-format
msgid "Unsupported Content-Type: %s"
msgstr "Toetamata Content-Type: %s"
-#: config/sources.php.dist:376
-msgid "Verisign Directory"
-msgstr "Verisigni kataloog"
-
-#: templates/browse/row.inc:19 templates/browse/contactrow.inc:27
-#, php-format
-msgid "View \"%s\""
-msgstr "Vaata \"%s\""
-
-#: minisearch.php:78
+#: minisearch.php:76
msgid "View Contact"
msgstr "Vaata sissekannet"
-#: config/prefs.php.dist:124
+#: config/prefs.php.dist:105
msgid "View to display by default:"
msgstr "Vaikimisi näidatav vaade:"
-#: config/attributes.php.dist:208
+#: config/attributes.php.dist:312
msgid "Website URL"
msgstr "Veebilehe URL"
-#: config/attributes.php.dist:113
+#: config/attributes.php.dist:165
msgid "Work Address"
msgstr "Tööaadress"
-#: config/attributes.php.dist:124
+#: config/attributes.php.dist:183
msgid "Work City"
msgstr "Töökoha linn"
-#: config/attributes.php.dist:139
+#: config/attributes.php.dist:201
msgid "Work Country"
msgstr "Töökoha riik"
-#: config/attributes.php.dist:156
+#: config/attributes.php.dist:246
msgid "Work Phone"
msgstr "Töötelefon"
-#: config/attributes.php.dist:134
+#: config/attributes.php.dist:177
+msgid "Work Post Office Box"
+msgstr "Töökoha postiindeks"
+
+#: config/attributes.php.dist:195
msgid "Work Postal Code"
msgstr "Töökoha postiindeks"
-#: config/attributes.php.dist:129
+#: config/attributes.php.dist:189
msgid "Work State/Province"
msgstr "Töökoha maakond"
-#: config/attributes.php.dist:119
+#: config/attributes.php.dist:171
msgid "Work Street Address"
msgstr "Töökoha tänav/maja"
-#: data.php:237 browse.php:93 browse.php:201 add.php:73
+#: add.php:48 data.php:251 lib/Views/Browse.php:159 lib/Views/Browse.php:271
#, php-format
msgid "You are not allowed to create more than %d contacts in \"%s\"."
msgstr "Sa ei saa luua rohkem kui %d sissekannet \"%s\"-sse"
-#: edit.php:69 display.php:58 view.php:36
+#: lib/Driver/vbook.php:137
+msgid "You cannot add an entry to a virtual address book."
+msgstr "Virtuaal aadressiraamatusse ei saa lisada kirjeid."
+
+#: lib/Driver/vbook.php:121
+msgid "You cannot add new contacts to a virtual address book"
+msgstr "Virtuaal aadressiraamatusse ei saa lisada kirjeid."
+
+#: lib/Driver/vbook.php:129
+msgid "You cannot delete contacts from a virtual address book"
+msgstr "Virtuaal aadressiraamatust ei saa kustutada kirjeid."
+
+#: edit.php:66 view.php:38 lib/Views/EditContact.php:49
+#: lib/Views/DeleteContact.php:42
msgid "You do not have permission to view this contact."
msgstr "Sul puuduvad õigused selle sissekande vaatamiseks."
-#: vcard.php:40
+#: vcard.php:37
msgid "You do not have permission to view this object."
msgstr "Sul puuduvad õigused selle objekti vaatamiseks."
-#: templates/browse/javascript.inc:55
+#: addressbooks.php:59
+msgid "You do not have permissions to delete this source."
+msgstr "Sul puuduvad õigused selle objekti kustutamiseks."
+
+#: lib/Driver/ldap.php:708
+msgid ""
+"You must have the Net_LDAP PEAR library installed to use the schema check "
+"function."
+msgstr ""
+"Sul peab olema installeeritud PEAR pakket Net_LDAP kasutamaks raamistik "
+"kontroll funktsiooni."
+
+#: search.php:110
+msgid "You must provide a name for virtual address books."
+msgstr "Sa pead sisestama nime sellele virtuaal aadressiraamatule."
+
+#: templates/browse/javascript.inc:54
msgid "You must select a target address book."
msgstr "Sa pead valima sihtaadressiraamatu."
-#: templates/browse/javascript.inc:23
-msgid "You must select a target list."
+#: templates/browse/javascript.inc:22
+msgid "You must select a target contact list."
msgstr "Sa pead valima sihtlisti."
-#: edit.php:32
+#: edit.php:31 templates/browse/javascript.inc:16
+#: templates/browse/javascript.inc:48 templates/browse/javascript.inc:71
msgid "You must select at least one contact first."
msgstr "Kõigepealt pead valima vähemalt ühe sissekande."
-#: templates/browse/javascript.inc:17 templates/browse/javascript.inc:49
-#: templates/browse/javascript.inc:72
-msgid "You must select at least one entry first."
-msgstr "Kõigepealt pead valima vähemalt ühe sissekande."
-
-#: edit.php:73
+#: edit.php:70 lib/Views/EditContact.php:52 lib/Views/DeleteContact.php:45
msgid "You only have permission to view this contact."
msgstr "Sul on õigus seda sissekannet ainult vaadata."
-#: browse.php:285
+#: lib/Views/Browse.php:355
msgid "Your default address book is not browseable."
msgstr "Sinu vaikeaadressiraamat ei võimalda sirvimist."
-#: templates/browse/row.inc:6 templates/browse/contactrow.inc:12
-msgid "[no value]"
-msgstr "[väärtus puudub]"
-
-#: lib/Turba.php:484
+#: lib/Turba.php:585
msgid "_Browse"
msgstr "Sir_vi"
-#: templates/browse/actions.inc:40
+#: templates/browse/actions.inc:50
msgid "_Contacts"
msgstr "_Kanded"
-#: templates/browse/actions.inc:2
+#: templates/browse/actions.inc:3
msgid "_Delete"
msgstr "K_ustuta"
-#: lib/Turba.php:493
+#: contact.php:82
+msgid "_Edit"
+msgstr "Muuda"
+
+#: lib/Turba.php:594
msgid "_Import/Export"
msgstr "_Import/Eksport"
-#: templates/browse/actions.inc:39
+#: templates/browse/actions.inc:49
msgid "_Lists"
msgstr "_Listid"
-#: lib/Turba.php:481
+#: lib/Turba.php:582
msgid "_My Address Books"
msgstr "_Minu aadressiraamatud"
-#: lib/Turba.php:487
+#: lib/Turba.php:588
msgid "_New Contact"
msgstr "_Uus sissekanne"
-#: templates/browse/actions.inc:2
+#: lib/Turba.php:599
+msgid "_Print"
+msgstr "_Prindi"
+
+#: templates/browse/actions.inc:3
msgid "_Remove from this list"
msgstr "_Eemalda sellest listist"
-#: lib/Turba.php:489
+#: lib/Turba.php:590
msgid "_Search"
msgstr "_Otsing"
-#: vcard.php:46
-msgid "contact.vcf"
-msgstr "aadress.vcf"
+#: contact.php:79
+msgid "_View"
+msgstr "Vaata"
-#: data.php:199 data.php:204 templates/data/export.inc:1
+#: templates/browse/column_headers.inc:24
+msgid "ascending"
+msgstr "Kasvav"
+
+#: vcard.php:45
+msgid "contact"
+msgstr "kontakt"
+
+#: data.php:208 data.php:213 templates/data/export.inc:1
msgid "contacts.csv"
msgstr "aadressid.csv"
-#: data.php:209
+#: data.php:233
+msgid "contacts.ldif"
+msgstr "contacts.ldif"
+
+#: data.php:218
msgid "contacts.tsv"
msgstr "aadressid.tsv"
-#: data.php:219
+#: data.php:228
msgid "contacts.vcf"
msgstr "aadressid.vcf"
-#: config/prefs.php.dist:138
+#: templates/browse/column_headers.inc:24
+msgid "descending"
+msgstr "Kahanev"
+
+#: config/attributes.php.dist:377
+msgid "female"
+msgstr "naine"
+
+#: lib/Block/tree_menu.php:38
+#, php-format
+msgid "in %s"
+msgstr "%s sees"
+
+#: config/attributes.php.dist:377
+msgid "male"
+msgstr "mees"
+
+#: config/prefs.php.dist:119
msgid "no formatting"
msgstr "suvaline"
-#: templates/prefs/imsp_opt.inc:34
+#: templates/prefs/imsp_opt.inc:32
msgid "none"
msgstr "puudub"
-#: templates/browse/actions.inc:24
+#: templates/browse/actions.inc:33
msgid "to a Contact List"
msgstr "listi"
-#: templates/browse/actions.inc:14
+#: templates/browse/actions.inc:22
msgid "to a different Address Book"
msgstr "teise aadressiraamatusse"
-#: data.php:51 templates/browse/column_headers.inc:13
+#: data.php:62 templates/browse/column_headers.inc:13
#: templates/data/import.inc:15 templates/data/export.inc:15
msgid "vCard"
msgstr "vCard"
diff --git a/po/cs_CZ.po b/po/eu_ES.po
similarity index 57%
copy from po/cs_CZ.po
copy to po/eu_ES.po
index a8ed468..67a2ee3 100644
--- a/po/cs_CZ.po
+++ b/po/eu_ES.po
@@ -1,197 +1,188 @@
-# translation of turba.po to Cestina
-# Turba Czech Translation.
-# Copyright (C) 2004 Horde Project
-# This file is distributed under the same license as the Horde package.
-# Pavel Chytil <pavel at chytil.tk>, 2001-2004.
+# Basque translations for Turba.
+# Copyright (C) 2008 Horde Project
+# This file is distributed under the same license as the Turba package.
+# Euskal Herriko Unibertsitatea EHU/UPV <xabier.arrieta at ehu.es>, 2008.
#
msgid ""
msgstr ""
-"Project-Id-Version: turba\n"
+"Project-Id-Version: Turba H3 (2.1)\n"
"Report-Msgid-Bugs-To: dev at lists.horde.org\n"
-"POT-Creation-Date: 2007-03-30 18:15+0200\n"
-"PO-Revision-Date: 2007-04-05 11:35+0200\n"
-"Last-Translator: Jan Krivanek <honza at atack.cz>\n"
-"Language-Team: Cestina <cs at li.org>\n"
+"POT-Creation-Date: 2008-01-16 09:33+0100\n"
+"PO-Revision-Date: 2008-07-17 14:28+0200\n"
+"Last-Translator: Euskal Herriko Unibertsitatea EHU/UPV <xabier.arrieta at ehu."
+"es>\n"
+"Language-Team: Euskal Herriko Unibertsitatea EHU/UPV <xabier.arrieta at ehu."
+"es>\n"
"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=ISO-8859-2\n"
+"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n"
-"X-Generator: KBabel 1.11.4\n"
#: templates/prefs/imsp_opt.inc:40
msgid " Add an IMSP Address Book"
-msgstr "Pøidat IMSP Adresáø"
+msgstr " Gehitu IMSP helbide-liburu bat"
#: templates/prefs/imsp_opt.inc:29
msgid " Delete IMSP Address Book"
-msgstr "Smazat IMSP Adresáø"
+msgstr " Ezabatu IMSP helbide-liburua"
-#: data.php:333
+#: data.php:339
#, php-format
msgid "\"%s\" already exists and was not imported."
-msgstr "\"%s\" ji¾ existuje a nebyl naimportován."
+msgstr "\"%s\" badago lehendik eta ez da inportatu."
#: browse.php:140
#, php-format
msgid "\"%s\" was not copied because it is a list."
-msgstr "\"%s\" nebyl zkopírován, proto¾e je to seznam."
+msgstr "\"%s\" ez da kopiatu zerrenda bat delako."
#: browse.php:138
#, php-format
msgid "\"%s\" was not moved because it is a list."
-msgstr "\"%s\" nebyl pøesunut, proto¾e je to seznam."
+msgstr "\"%s\" ez da lekuz aldatu zerrenda bat delako."
-#: config/prefs.php.dist:137
+#: config/prefs.php.dist:130
msgid "\"Firstname Lastname\" (ie. John Doe)"
-msgstr "\"Jméno pøíjmení\" (napø. Josef Novák)"
+msgstr "\"Izena Abizena\" (adib. Maialen Ugarte)"
-#: config/prefs.php.dist:136
+#: config/prefs.php.dist:129
msgid "\"Lastname, Firstname\" (ie. Doe, John)"
-msgstr "\"Pøíjmení, jméno\" (napø. Novák, Josef) "
+msgstr "\"Abizena, Izena\" (adib. Ugarte, Maialen)"
#: add.php:112
#, php-format
msgid "%s added."
-msgstr "%s pøidán."
+msgstr "%s gehitu da."
-#: data.php:357
+#: data.php:363
#, php-format
-msgid "%s file successfully imported"
-msgstr "%s soubor byl úspì¹nì importován"
+msgid "%s file successfully imported."
+msgstr "%s fitxategia ondo inportatu da."
#: templates/browse/footer.inc:5
#, php-format
msgid "%s to %s of %s"
-msgstr "%s a¾ %s z %s"
+msgstr "%s - %s / %s"
-#: lib/Turba.php:458
+#: lib/Turba.php:460
#, php-format
msgid "%s's Address Book"
-msgstr "Adresáø %s"
+msgstr "%s(r)en helbide-liburua"
#: lib/Block/minisearch.php:42
msgid "A browser that supports iFrames is required"
-msgstr "Je nutné pou¾ít prohlí¾eè podporující iFrames."
-
-#: config/prefs.php.dist:160
-msgid "Above search form"
-msgstr "Vý¹e uvedený formuláø pro vyhledávání"
+msgstr "iFrames onartzen duen arakatzailea behar da."
#: view.php:52
#, php-format
msgid "Access denied to %s"
-msgstr "Do %s byl pøístup zamítnut"
+msgstr "%s(e)rako sarbidea ukatuta"
#: add.php:56 templates/browse/actions.inc:29
msgid "Add"
-msgstr "Pøidat"
+msgstr "Gehitu"
#: templates/prefs/addressbookselect.inc:174
msgid "Add address book"
-msgstr "Pøidat Adresáø"
+msgstr "Gehitu helbide-liburua"
-#: config/prefs.php.dist:48
+#: config/prefs.php.dist:41
msgid "Add and Delete IMSP address books"
-msgstr "Pøidat a smazat IMSP adresáøe"
+msgstr "Gehitu eta ezabatu IMPSP helbide-liburua"
#: templates/prefs/columnselect.inc:237
msgid "Add column"
-msgstr "Pøidat sloupec"
+msgstr "Gehitu zutabea"
#: edit.php:135
msgid "Add file"
-msgstr "Pøidat soubor"
+msgstr "Gehitu fitxategia"
#: templates/browse/actions.inc:29
msgid "Add to"
-msgstr "Pøidat do"
+msgstr "Gehitu hemen"
#: lib/Driver/null.php:57
msgid "Adding contacts is not available."
-msgstr "Pøidávání kontaktù není k dispozici."
+msgstr "Kontaktu-gehitzea ez dago erabilgarri."
#: templates/addressbooks.inc:93
msgid "Address Book"
-msgstr "Adresáø"
+msgstr "Helbide-liburua"
-#: browse.php:28 config/prefs.php.dist:125
+#: browse.php:28 config/prefs.php.dist:118
msgid "Address Book Listing"
-msgstr "Výpis adresáøe"
+msgstr "Helbide-liburuen zerrenda"
#: config/prefs.php.dist:10
msgid "Address Books"
-msgstr "Adresáøe"
+msgstr "Helbide-liburuak"
#: add.php:111
msgid "Address book entry"
-msgstr "Polo¾ka adresáøe"
+msgstr "Helbide-liburuko sarrera"
-#: data.php:313
+#: data.php:319
msgid "Address book successfully purged."
-msgstr "Adresáø byl úspì¹nì vyèistìný."
+msgstr "Helbide-liburua behar bezala purgatu da."
#: templates/addressbooks.inc:69
msgid "Address book to delete "
-msgstr "Adresáø ke smazání "
+msgstr "Ezabatzeko helbide-liburua "
#: templates/prefs/addressbookselect.inc:170
msgid "Address books that will not be displayed:"
-msgstr "Adresáøe, které nebudou zobrazeny:"
+msgstr "Bistaratuko ez diren helbide-liburuak:"
#: search.php:88 templates/browse/search.inc:38
msgid "Advanced Search"
-msgstr "Pokroèilé vyhledávání"
+msgstr "Bilaketa aurreratua"
#: config/attributes.php.dist:64
msgid "Alias"
-msgstr "Alias"
+msgstr "Aliasa"
#: templates/browse/footerAlpha.inc:7 templates/browse/footerAlpha.inc:10
-#: templates/browse/actions.inc:48
+#: templates/browse/actions.inc:49
msgid "All"
-msgstr "V¹e"
+msgstr "Denak"
#: lib/api.php:607
msgid "Already Exists"
-msgstr "Ji¾ existuje"
+msgstr "Badago lehendik"
#: templates/browse/javascript.inc:93
#, php-format
msgid "Are you sure that you want to delete %s?"
-msgstr "Jste si jistí, ¾e chcete smazat %s?"
+msgstr "Ziur zaude %s ezabatu nahi duzula?"
#: templates/browse/javascript.inc:67
msgid "Are you sure that you want to delete the selected entries?"
-msgstr "Jste si jistí, ¾e chcete smazat vybrané polo¾ky?"
+msgstr "Ziur zaude hautatutako sarrerak ezabatu nahi dituzula?"
-#: config/prefs.php.dist:96
+#: config/prefs.php.dist:89
msgid "Ascending"
-msgstr "Vzestupnì"
+msgstr "Gorantz"
#: search.php:85 templates/browse/search.inc:37
msgid "Basic Search"
-msgstr "Vyhledat"
-
-#: config/prefs.php.dist:159
-msgid "Below search form"
-msgstr "Pod formuláøem pro vyhledávání"
+msgstr "Oinarrizko bilaketa"
#: lib/Driver/ldap.php:77 lib/Driver/ldap.php:80
#, php-format
msgid "Bind failed: (%s) %s"
-msgstr "Spojení selhalo: (%s) %s"
+msgstr "Loturak huts egin du: (%s) %s"
#: config/attributes.php.dist:178
msgid "Birthday"
-msgstr "Narozeniny"
+msgstr "Urtebetetzea"
#: templates/menu.inc:7
msgid "Browse"
-msgstr "Prohlí¾et"
+msgstr "Arakatu"
#: config/attributes.php.dist:173
msgid "Business Category"
-msgstr "Obchodní kategorie"
+msgstr "Negozio kategoria"
#: data.php:49
msgid "CSV"
@@ -199,549 +190,541 @@ msgstr "CSV"
#: lib/Object/Group.php:57
msgid "Can't add a group to itself."
-msgstr "Nelze pøidat skupinu sama sobì."
+msgstr "Ezin zaio talde bat gehitu bere buruari."
#: templates/browse/column_headers.inc:7
msgid "Check _All/None"
-msgstr "Vybrat _v¹e/¾ádné"
+msgstr "Egiaztatu _guztiak/bat ere ez"
#: templates/addressbooks.inc:51
msgid "Choose a name"
-msgstr "Zvolte název"
+msgstr "Aukeratu izen bat"
#: add.php:48
msgid "Choose an address book"
-msgstr "Vyberte adresáø"
+msgstr "Aukeratu helbide-liburu bat"
#: templates/prefs/columnselect.inc:221
msgid "Choose an address book:"
-msgstr "Zvolte Adresáø:"
+msgstr "Aukeratu helbide-liburu bat:"
#: templates/prefs/addressbookselect.inc:165
msgid "Choose which address books to display, and in what order:"
-msgstr "Zvolte adresáøe k zobrazení a jejich poøadí:"
+msgstr "Aukeratu zein helbide-liburu bistaratuko diren eta zein ordenatan:"
#: config/prefs.php.dist:11
msgid "Choose which address books to use."
-msgstr "Vyberte adresáø, který chcete pou¾ívat."
+msgstr "Aukeratu zein helbide-liburu erabiliko diren."
#: templates/prefs/columnselect.inc:228
msgid "Choose which columns to display and in what order:"
-msgstr "Vyberte sloupce k zobrazení a jejich poøadí:"
+msgstr "Aukeratu zein zutabe bistaratuko diren eta zein ordenatan:"
#: config/prefs.php.dist:17
msgid "Column Options"
-msgstr "Mo¾nosti sloupce"
+msgstr "Zutabe-aukerak"
#: templates/prefs/columnselect.inc:233
msgid "Columns that will not be displayed:"
-msgstr "Sloupce, které nebudou zobrazeny:"
+msgstr "Bistaratuko ez diren zutabeak:"
-#: templates/data/import.inc:13 templates/data/export.inc:12
+#: templates/data/export.inc:12 templates/data/import.inc:13
msgid "Comma separated values"
-msgstr "Èárkou oddìlené hodnoty"
+msgstr "Komaz bereizitako balioak"
#: templates/data/export.inc:13
msgid "Comma separated values (Microsoft Outlook)"
-msgstr "Èárkou oddìlené hodnoty (Microsoft Outlook)"
+msgstr "Komaz bereizitako balioak (Microsoft Outlook)"
#: config/attributes.php.dist:76
msgid "Company"
-msgstr "Firma"
+msgstr "Enpresa"
#: config/attributes.php.dist:144
msgid "Company Address"
-msgstr "Adresa firmy"
+msgstr "Enpresaren helbidea"
#: lib/api.php:319 lib/api.php:364 lib/api.php:414 lib/api.php:546
#: lib/api.php:660 lib/api.php:747 lib/api.php:805 lib/api.php:886
-#: lib/api.php:1086 lib/api.php:1175
+#: lib/api.php:1087 lib/api.php:1176
#, php-format
msgid "Connection failed: %s"
-msgstr "Spojení selhalo: %s"
+msgstr "Konexioak huts egin du: %s"
#: lib/Driver/ldap.php:58
msgid "Connection failure"
-msgstr "Spojení selhalo"
+msgstr "Konexioak huts egin du"
#: lib/Block/minisearch.php:3 lib/Block/minisearch.php:26
msgid "Contact Search"
-msgstr "Vyhledat kontakt"
+msgstr "Kontaktu-bilaketa"
-#: browse.php:306
+#: browse.php:310
#, php-format
msgid "Contacts in list: %s"
-msgstr "Kontakty v seznamu: %s"
+msgstr "Zerrendako kontaktuak: %s"
#: templates/browse/actions.inc:18
msgid "Copy"
-msgstr "Kopírovat"
+msgstr "Kopiatu"
#: templates/addressbooks.inc:60
msgid "Create"
-msgstr "Vytvoøit"
+msgstr "Sortu"
#: templates/addressbooks.inc:47
msgid "Create Address Book"
-msgstr "Vytvoøit Adresáø"
+msgstr "Sortu helbide-liburua"
-#: lib/ListView.php:348
+#: lib/ListView.php:350
msgid "Create a new Contact List in:"
-msgstr "Vytvoøit nový seznam kontaktù v:"
+msgstr "Sortu kontaktu-zerrenda berria hemen:"
#: lib/ObjectView.php:133
msgid "Created"
-msgstr "Vytvoøeno"
+msgstr "Sortu da"
-#: config/prefs.php.dist:98
+#: config/prefs.php.dist:91
msgid "Default sorting direction:"
-msgstr "Implicitní smìr tøídìní:"
+msgstr "Ordenatze-noranzko lehenetsia:"
#: lib/Renderer.php:47 lib/Renderer.php:50 lib/Object.php:328
#: templates/addressbooks.inc:83 templates/browse/actions.inc:3
msgid "Delete"
-msgstr "Smazat"
+msgstr "Ezabatu"
#: templates/addressbooks.inc:65
msgid "Delete Address Book"
-msgstr "Smazat Adresáø"
-
-#: config/prefs.php.dist:38
-msgid "Delete Confirmation"
-msgstr "Potvrzení smazání"
-
-#: config/prefs.php.dist:39
-msgid "Delete button behaviour"
-msgstr "Vlastnosti tlaèítka pro smazání"
+msgstr "Ezabatu helbide-liburua"
#: lib/Driver/ldap.php:270
#, php-format
msgid "Delete failed: (%s) %s"
-msgstr "Smazaní selhalo: (%s) %s"
+msgstr "Huts egin du ezabatzean: (%s) %s"
#: lib/Driver/null.php:62
msgid "Deleting contacts is not available."
-msgstr "Mazání kontaktù není k dispozici."
+msgstr "Kontaktu-ezabatzea ez dago erabilgarri."
#: delete.php:38
msgid "Deletion failed"
-msgstr "Smazaní selhalo"
+msgstr "Huts egin du ezabatzean"
#: config/attributes.php.dist:213
msgid "Department"
-msgstr "Oddìlìní"
+msgstr "Saila"
-#: config/prefs.php.dist:97
+#: config/prefs.php.dist:90
msgid "Descending"
-msgstr "Sestupnì"
+msgstr "Beherantz"
#: templates/addressbooks.inc:122
msgid "Description"
-msgstr "Popis"
+msgstr "Azalpena"
-#: templates/browse/search.inc:119
+#: templates/browse/search.inc:106
msgid "Directory"
-msgstr "Adresáø"
+msgstr "Direktorioa"
#: config/prefs.php.dist:24
msgid "Display"
-msgstr "Zobrazit"
+msgstr "Bistaratu"
#: config/prefs.php.dist:9 config/prefs.php.dist:16 config/prefs.php.dist:23
#: config/prefs.php.dist:30
msgid "Display Options"
-msgstr "Zobrazit mo¾nosti"
-
-#: config/prefs.php.dist:177
-msgid "Do you want to confirm deleting entries?"
-msgstr "Chcete potvrdit smazání polo¾ek?"
+msgstr "Bistaratzeko aukerak"
#: lib/Object.php:297
msgid "Download"
-msgstr "Stáhnout"
+msgstr "Deskargatu"
#: templates/browse/row.inc:17 templates/browse/contactrow.inc:25
msgid "Download vCard"
-msgstr "Stahnout vCard"
+msgstr "Deskargatu vCard"
#: lib/Renderer.php:42 templates/addressbooks.inc:109
#: templates/browse/row.inc:25 templates/browse/column_headers.inc:10
#: templates/browse/contactrow.inc:33 templates/browse/actions.inc:6
msgid "Edit"
-msgstr "Upravit"
+msgstr "Editatu"
#: templates/browse/row.inc:25 templates/browse/contactrow.inc:33
#, php-format
msgid "Edit \"%s\""
-msgstr "Upravit \"%s\""
+msgstr "Editatu \"%s\""
#: templates/addressbooks.inc:88
msgid "Edit Address Books"
-msgstr "Upravit Adresáøe"
+msgstr "Editatu helbide-liburuak"
#: edit.php:85 edit.php:161
#, php-format
msgid "Edit entry for %s"
-msgstr "Upravit polo¾ku pro %s"
+msgstr "Editatu %s(r)en sarrera"
#: config/attributes.php.dist:58
msgid "Email"
-msgstr "Email"
+msgstr "Helb.el."
#: edit.php:154
#, php-format
msgid "Entry for %s updated, but saving the uploaded file failed: %s"
msgstr ""
-"Polo¾ka pro %s byla zaktualizována, ale selhalo ulo¾ení poslaného soubory: %"
-"s"
+"%s(r)en sarrera eguneratu da, baina huts egin du eguneratutako fitxategia "
+"gordetzean: %s"
#: edit.php:156 edit.php:159
#, php-format
msgid "Entry for %s updated."
-msgstr "Polo¾ky pro %s byly aktualizovány."
+msgstr "%s(r)en sarrera eguneratu da."
-#: browse.php:216 browse.php:264
+#: browse.php:220 browse.php:268
#, php-format
msgid "Error adding %d contact(s) to list."
-msgstr "Chyba pøi pøidávání %d kontaktu(ù) do seznamu."
+msgstr "Errorea %d kontaktu zerrendan gehitzean."
-#: browse.php:218 browse.php:266
+#: browse.php:222 browse.php:270
#, php-format
msgid "Error adding %d of %d requested contact(s) to list."
-msgstr "Chyba pøi pøidávání %d z %d po¾adovaných kontaktù do seznamu."
+msgstr "Errorea eskatutako %d / %d kontaktu zerrendan gehitzean."
#: browse.php:86
#, php-format
msgid "Error deleting %d contact(s)."
-msgstr "Chyba pøi mazání %d kontaktu(ù)."
+msgstr "Errorea %d kontaktu ezabatzean."
#: browse.php:88
#, php-format
msgid "Error deleting %d of %d requested contacts(s)."
-msgstr "Chyba pøi odstraòování %d z po¾adovaných %d kontaktù."
+msgstr "Errorea eskatutako %d / %d kontaktu ezabatzean."
#: browse.php:66
#, php-format
msgid "Error removing %d contact(s) from list."
-msgstr "Chyba pøi odstraòování %d kontakt(ù) ze seznamu."
+msgstr "Errorea %d kontaktu zerrendatik kentzean."
#: browse.php:68
#, php-format
msgid "Error removing %d of %d requested contact(s) from list."
-msgstr "Chyba pøi odstraòování %d z po¾adovaných %d kontaktù ze seznamu."
+msgstr "Errorea eskatutako %d / %d kontaktu zerrendatik kentzean."
#: lib/api.php:420
#, php-format
msgid "Error searching the address book: %s"
-msgstr "Chyba pøi hledání v Adresáøi: %s"
+msgstr "Errorea helbide liburuan bilatzean: %s"
#: templates/browse/actions.inc:10 templates/data/export.inc:41
msgid "Export"
-msgstr "Exportovat"
+msgstr "Esportatu"
#: templates/data/export.inc:6
msgid "Export Address Book"
-msgstr "Exportovat adresáø"
+msgstr "Esportatu helbide-liburua"
#: templates/data/export.inc:21
msgid "Export only the selected contacts."
-msgstr "Exportovat pouze vybrané kontakty."
+msgstr "Esportatu hautatako kontaktuak bakarrik."
#: templates/data/export.inc:27
msgid "Export the following address book completely."
-msgstr "Kompletnì exportovat následující adresáø."
+msgstr "Esportatu helbide-liburu hau osorik."
-#: data.php:134 data.php:228 data.php:302 browse.php:35 browse.php:103
-#: browse.php:130 search.php:37 add.php:67
+#: add.php:67 search.php:37 browse.php:35 browse.php:103 browse.php:130
+#: data.php:134 data.php:228 data.php:302
#, php-format
msgid "Failed to access the address book: %s"
-msgstr "Nelze pøistoupit k adresáøi: %s"
+msgstr "Huts egin du helbide-liburua atzitzean: %s"
#: browse.php:158
#, php-format
msgid "Failed to add %s to %s: %s"
-msgstr "Selhalo pøidání %s do %s: %s"
+msgstr "Huts egin du gehitzean %s --> %s: %s"
-#: browse.php:312
+#: browse.php:316
msgid "Failed to browse list"
-msgstr "Nelze prohlédnout seznam"
+msgstr "Huts egin du zerrenda arakatzean"
-#: browse.php:350
+#: browse.php:354
msgid "Failed to browse the directory"
-msgstr "Nelze prohlédnout adresáø"
+msgstr "Huts egin du direktorioa arakatzean"
#: lib/Driver/ldap.php:303
#, php-format
msgid "Failed to change name: (%s) %s; Old DN = %s, New DN = %s, Root = %s"
-msgstr "Selhala zmìna jména: (%s) %s; staré DN = %s, nové DN = %s, Root = %s"
+msgstr ""
+"Huts egin du izena aldatzean: (%s) %s; DN zaharra = %s, DN berria = %s, Root "
+"= %s"
#: browse.php:134
#, php-format
msgid "Failed to find object to be added: %s"
-msgstr "Nelze nalézt objekt k pøidání: %s"
+msgstr "Huts egin du gehitzeko objektua aurkitzean: %s"
#: search.php:79
msgid "Failed to search the address book"
-msgstr "Hledání v adresáøi je nedostupné"
+msgstr "Huts egin du helbide-liburuan bilatzean"
#: data.php:149
#, php-format
msgid "Failed to search the directory: %s"
-msgstr "Nelze prohledat kontakty: %s"
+msgstr "Huts egin du direktorioan bilatzean: %s"
#: config/attributes.php.dist:167
msgid "Fax"
-msgstr "Fax"
+msgstr "Faxa"
-#: edit.php:131 display.php:99
+#: display.php:99 edit.php:131
msgid "Files"
-msgstr "Soubory"
+msgstr "Fitxategiak"
-#: templates/browse/search.inc:71
+#: templates/browse/search.inc:77
msgid "Find"
-msgstr "Hledat"
+msgstr "bilatu"
#: edit.php:104 edit.php:195
msgid "Finish"
-msgstr "Konec"
+msgstr "Amaitu"
#: config/attributes.php.dist:48
msgid "First Name"
-msgstr "Jméno"
+msgstr "Izena"
#: config/attributes.php.dist:202
msgid "Freebusy URL"
-msgstr "Free/Busy URL"
+msgstr "Libre/lanpetutaren URLa"
-#: templates/browse/search.inc:84
+#: templates/browse/search.inc:69
msgid "From"
-msgstr "Od"
+msgstr "Hemen"
-#: config/sources.php.dist:589
+#: config/sources.php.dist:625
msgid "Global Address Book"
-msgstr "Globální adresáø"
+msgstr "Helbide-liburu orokorra"
#: templates/browse/row.inc:43 templates/browse/contactrow.inc:44
msgid "Group"
-msgstr "Skupina"
+msgstr "Taldea"
#: config/attributes.php.dist:82
msgid "Home Address"
-msgstr "Adresa domù"
+msgstr "Helbidea (etxea)"
#: config/attributes.php.dist:93
msgid "Home City"
-msgstr "Mìsto adresy domù"
+msgstr "Herria (etxea)"
#: config/attributes.php.dist:108
msgid "Home Country"
-msgstr "Zemì adresy domù"
+msgstr "Estatua (etxea)"
#: config/attributes.php.dist:150
msgid "Home Phone"
-msgstr "Telefon domù"
+msgstr "Telefonoa (etxekoa)"
#: config/attributes.php.dist:103
msgid "Home Postal Code"
-msgstr "PSÈ domù"
+msgstr "Posta-kodea (etxea)"
#: config/attributes.php.dist:98
msgid "Home State/Province"
-msgstr "Stát/provincie adresy domù"
+msgstr "Herrialdea/probintzia (etxea)"
#: config/attributes.php.dist:88
msgid "Home Street Address"
-msgstr "Ulice adresy domù"
+msgstr "Kale-helbidea (etxea)"
-#: config/sources.php.dist:491
+#: config/sources.php.dist:527
msgid "IMSP"
msgstr "IMSP"
-#: config/prefs.php.dist:47
+#: config/prefs.php.dist:40
msgid "IMSP Address Book Administration"
-msgstr "Správa IMSP Adresáøe"
+msgstr "IMSP helbide-liburuen administrazioa"
#: templates/data/import.inc:7
#, php-format
msgid "Import Address Book, Step %d"
-msgstr "Importovat adresáø, krok %d"
+msgstr "Inportatu helbide-liburua, %d. urratsa"
-#: data.php:375
+#: data.php:381
msgid "Import/Export Address Books"
-msgstr "Importovat/exportovat adresáøe"
+msgstr "Inportatu/esportatu helbide-liburuak"
#: lib/api.php:655 lib/api.php:742
msgid "Invalid ID"
-msgstr "Neplatné ID"
+msgstr "IDa ez da baliozkoa"
-#: lib/api.php:231 lib/api.php:1158
+#: lib/api.php:231 lib/api.php:1159
msgid "Invalid address book"
-msgstr "Neplatný adresáø"
+msgstr "Helbide-liburua ez da baliozkoa"
#: lib/api.php:409 lib/api.php:541 lib/api.php:651 lib/api.php:738
#: lib/api.php:795
#, php-format
msgid "Invalid address book: %s"
-msgstr "Neplatný Adresáø: %s"
+msgstr "Helbide-liburua ez da baliozkoa: %s"
-#: lib/api.php:1162 lib/api.php:1236 lib/api.php:1292
+#: lib/api.php:1163 lib/api.php:1237 lib/api.php:1293
msgid "Invalid email"
-msgstr "Neplatný email"
+msgstr "Helbide elektronikoa ez da baliozkoa"
-#: lib/api.php:1170
+#: lib/api.php:1171
msgid "Invalid entry"
-msgstr "Neplatná polo¾ka"
+msgstr "Sarrera ez da baliozkoa"
#: lib/Driver/ldap.php:266
msgid "Invalid key specified."
-msgstr "Byl poskytnut neplatný klíè."
+msgstr "Gako baliogabea zehaztu da."
-#: lib/api.php:1166
+#: lib/api.php:1167
msgid "Invalid name"
-msgstr "Neplatné jméno"
+msgstr "Izena ez da baliozkoa"
#: lib/api.php:799
msgid "Invalid objectId"
-msgstr "Neplatné ID objektu"
+msgstr "objectId ez da baliozkoa"
#: lib/Driver/ldap.php:30
msgid ""
"LDAP support is required but the LDAP module is not available or not loaded."
-msgstr "Je vy¾adován LDAP, ale tento modul není dostupný nebo instalovaný."
+msgstr ""
+"LDAP euskarria behar da, baina LDAP modulua ez dago erabilgarri edo ez da "
+"kargatu."
#: lib/ObjectView.php:138
msgid "Last Modified"
-msgstr "Naposledy zmìnìno"
+msgstr "Aldatze-data"
#: config/attributes.php.dist:53
msgid "Last Name"
-msgstr "Pøíjmení"
+msgstr "Abizena"
#: templates/browse/column_headers.inc:16
msgid "List"
-msgstr "Seznam"
+msgstr "Zerrenda"
-#: templates/browse/search.inc:78
+#: templates/browse/search.inc:82
msgid "Matching"
-msgstr "Shodující se s"
+msgstr "hau"
#: lib/api.php:206
msgid "Maximum Number of Contacts"
-msgstr "Maximální poèet kontaktù"
+msgstr "kontaktu gehienez"
-#: config/prefs.php.dist:107
+#: config/prefs.php.dist:100
msgid "Maximum number of pages"
-msgstr "Maximální poèet stránek"
+msgstr "orri gehienez"
#: lib/Block/tree_menu.php:3
msgid "Menu List"
-msgstr "Seznam nabídky"
+msgstr "Menu-zerrenda"
#: lib/Driver/ldap.php:296
msgid "Missing DN in LDAP source configuration."
-msgstr "Chybìjící DN u konfigurace zdroje LDAP."
+msgstr "DN falta da LDAP iturburuen konfigurazioan."
#: config/attributes.php.dist:162
msgid "Mobile Phone"
-msgstr "Mobilní telefon"
+msgstr "Telefono mugikorra"
#: lib/Driver/ldap.php:325 lib/Driver/ldap.php:341
#, php-format
msgid "Modify failed: (%s) %s"
-msgstr "Selhala úprava: (%s) %s"
+msgstr "Huts egin du aldaketak: (%s) %s"
-#: lib/api.php:1277
+#: lib/api.php:1278
msgid "More than 1 entry found"
-msgstr "Byla nalezena více ne¾ 1 polo¾ka"
+msgstr "Sarrera bat baino gehiago aurkitu da"
#: templates/browse/actions.inc:16
msgid "Move"
-msgstr "Pøesunout"
+msgstr "Lekuz aldatu"
#: templates/prefs/addressbookselect.inc:184
#: templates/prefs/columnselect.inc:247
msgid "Move left"
-msgstr "Pøesunout vlevo"
+msgstr "Eraman ezkerrera"
#: templates/prefs/addressbookselect.inc:186
#: templates/prefs/columnselect.inc:249
msgid "Move right"
-msgstr "Pøesunout vpravo"
+msgstr "Mugitu eskuinera"
#: data.php:52 templates/data/import.inc:16
msgid "Mulberry Address Book"
-msgstr "Mulberry adresáø"
+msgstr "Mulberry helbide-liburua"
-#: lib/api.php:1194
+#: lib/api.php:1195
#, php-format
msgid ""
"Multiple persons with address [%s], but none with name [%s] already exist"
-msgstr "Více osob s adresou [%s], ale se jménem [%s] neexistuje nikdo"
+msgstr "Hainbat pertsonak dute helbidea [%s], baina ez dago [%s] izena duenik"
-#: config/sources.php.dist:114
+#: config/sources.php.dist:132
msgid "My Address Book"
-msgstr "Mùj Adresáø"
+msgstr "Nire helbide-liburua"
#: addressbooks.php:119
msgid "My Address Books"
-msgstr "Mé Adresáøe"
+msgstr "Nire helbide-liburuak"
#: templates/addressbooks.inc:114 config/attributes.php.dist:42
msgid "Name"
-msgstr "Jméno"
+msgstr "Izena"
#: config/prefs.php.dist:31
msgid "Name Format"
-msgstr "Formát jména"
+msgstr "Izen-formatua"
#: add.php:36 add.php:127 lib/Block/tree_menu.php:27
msgid "New Contact"
-msgstr "Nový kontakt"
+msgstr "Kontaktu berria"
#: edit.php:95 edit.php:102 edit.php:210 templates/data/import.inc:45
msgid "Next"
-msgstr "Dal¹í"
+msgstr "Hurrengoa"
#: config/attributes.php.dist:218
msgid "Nickname"
-msgstr "Pøezdívka/alias"
+msgstr "Goitizena"
-#: lib/api.php:1280 lib/api.php:1329
+#: lib/api.php:1281 lib/api.php:1330
#, php-format
msgid "No %s entry found for %s"
-msgstr "®ádná polo¾ka %s nebyla nalezena pro %s"
+msgstr "Ez da aurkitu %s sarrerarik %s(r)entzat"
-#: lib/api.php:1245
+#: lib/api.php:1246
msgid "No address books found."
-msgstr "Nebyl nalezen ¾ádný adresáø."
+msgstr "Ez da aurkitu helbide-libururik."
-#: minisearch.php:81
+#: minisearch.php:83
msgid "No contacts found"
-msgstr "Nebyly nalezeny ¾ádné kontakty."
+msgstr "Ez da aurkitu kontakturik"
#: lib/api.php:566 lib/api.php:830
msgid "No vCard data was found."
-msgstr "Nebyly nalezeny ¾ádná vCard data."
+msgstr "Ez da aurkitu vCard daturik."
#: templates/browse/footer.inc:7
msgid "None"
-msgstr "®ádný"
+msgstr "Bat ere ez"
#: config/attributes.php.dist:184
msgid "Notes"
-msgstr "Poznámka"
+msgstr "Oharrak"
-#: config/prefs.php.dist:115
+#: config/prefs.php.dist:108
msgid "Number of items per page"
-msgstr "Poèet polo¾ek na stránku"
+msgstr "Elementu kopurua orriko"
#: lib/api.php:671 lib/api.php:811
msgid "Object not found"
-msgstr "Objekt nebyl nalezen"
+msgstr "Objektua ez da aurkitu"
#: config/attributes.php.dist:223
msgid "Office"
-msgstr "Kanceláø"
+msgstr "Bulegoa"
#: templates/prefs/imsp_opt.inc:22
msgid ""
@@ -749,306 +732,305 @@ msgid ""
"deleted. If this is not what you want, then you must change your selection "
"to \"None\"."
msgstr ""
-"Po ulo¾ení tohoto nastavení bude Adresáø nenávratnì odstranìn. Jestli¾e si "
-"to nepøejete, musíte zmìnit Va¹i volbu na \"®ádný\"."
+"Aukera-orri hau gordetzen duzunean, helbide-liburua betiko ezabatuko da. Ez "
+"baduzu hori nahi, hautatu \"Bat ere ez\"."
#: lib/api.php:838
msgid "Only one vcard supported."
-msgstr "Je podporávána jen jedna vCard."
+msgstr "vcard bat bakarrik onartzen da."
-#: config/prefs.php.dist:37 config/prefs.php.dist:46
+#: config/prefs.php.dist:39
msgid "Other Options"
-msgstr "Dal¹í mo¾nosti"
+msgstr "Beste aukera batzuk"
#: config/attributes.php.dist:190
msgid "PGP Public Key"
-msgstr "Veøejný PGP klíè"
+msgstr "PGP gako publikoa"
-#: lib/api.php:550 lib/api.php:664 lib/api.php:751 lib/api.php:1014
-#: lib/api.php:1179
+#: lib/api.php:550 lib/api.php:664 lib/api.php:751 lib/api.php:1015
+#: lib/api.php:1180
msgid "Permission Denied"
-msgstr "Nepovolený pøístup"
+msgstr "Baimena ukatu da"
#: lib/Driver.php:554
msgid "Permission denied"
-msgstr "Nepovolený pøístup"
+msgstr "Baimena ukatuta"
#: templates/addressbooks.inc:106
msgid "Permissions"
-msgstr "Oprávnìní"
+msgstr "Baimenak"
#: data.php:53 templates/data/import.inc:17
msgid "Pine Address Book"
-msgstr "Pine adresáø"
+msgstr "Pine helbide-liburua"
#: templates/browse/javascript.inc:28
msgid "Please name the new contact list:"
-msgstr "Zadejte jméno nového seznamu kontaktù:"
+msgstr "Idatzi kontaktu-zerrenda berriaren izena:"
#: edit.php:98 edit.php:101 edit.php:202
msgid "Previous"
-msgstr "Pøedchozí"
+msgstr "Aurrekoa"
#: lib/Driver/ldap.php:147
#, php-format
msgid "Query failed: (%s) %s"
-msgstr "Vyhledávání selhalo: (%s) %s"
+msgstr "Kontsulta honek huts egin du: (%s) %s"
#: templates/block/minisearch.inc:15
msgid "Quick Search"
-msgstr "Rychlé vyhledávání"
+msgstr "Bilaketa azkarra"
#: lib/Driver/ldap.php:191 lib/Driver/ldap.php:199 lib/Driver/ldap.php:435
#, php-format
msgid "Read failed: (%s) %s"
-msgstr "Ètení selhalo: (%s) %s"
+msgstr "Huts egin du irakurtzean: (%s) %s"
#: lib/Driver/null.php:52
msgid "Reading contacts is not available."
-msgstr "Ètení kontaktù není dostupné."
+msgstr "Kontaktu-irakurtzea ez dago erabilgarri."
#: lib/Renderer.php:49
msgid "Really delete this contact?"
-msgstr "Skuteènì odstranit tento kontakt?"
+msgstr