Reorder the www structure in a way we might do it for Horde 4. I'm probably way off...
authorGunnar Wrobel <p@rdus.de>
Thu, 30 Apr 2009 09:56:59 +0000 (11:56 +0200)
committerGunnar Wrobel <p@rdus.de>
Thu, 30 Apr 2009 09:56:59 +0000 (11:56 +0200)
71 files changed:
koward/www/Koward/app/koward.php [deleted file]
koward/www/Koward/app/themes/graphics/favicon.ico [deleted file]
koward/www/Koward/app/themes/graphics/query.png [deleted file]
koward/www/Koward/app/themes/kolab/screen.css [deleted file]
koward/www/Koward/app/themes/screen.css [deleted file]
koward/www/Koward/config/.gitignore [deleted file]
koward/www/Koward/config/attributes.php.dist [deleted file]
koward/www/Koward/config/conf.php.dist [deleted file]
koward/www/Koward/config/hooks.php.dist [deleted file]
koward/www/Koward/config/koward.php.dist [deleted file]
koward/www/Koward/config/labels.php.dist [deleted file]
koward/www/Koward/config/nls.php.dist [deleted file]
koward/www/Koward/config/objects.php.dist [deleted file]
koward/www/Koward/config/order.php.dist [deleted file]
koward/www/Koward/config/registry.php.dist [deleted file]
koward/www/Koward/config/routes.php.dist [deleted file]
koward/www/Koward/config/search.php.dist [deleted file]
koward/www/Koward/config/visible.php.dist [deleted file]
koward/www/horde/config/conf.php.dist [new file with mode: 0644]
koward/www/horde/config/hooks.php.dist [new file with mode: 0644]
koward/www/horde/config/nls.php.dist [new file with mode: 0644]
koward/www/horde/config/prefs.php.dist [new file with mode: 0644]
koward/www/horde/config/registry.d/README [new file with mode: 0644]
koward/www/horde/config/registry.php.dist [new file with mode: 0644]
koward/www/htdocs/horde/js/accesskeys.js [new file with mode: 0644]
koward/www/htdocs/horde/js/effects.js [new file with mode: 0644]
koward/www/htdocs/horde/js/horde.js [new file with mode: 0644]
koward/www/htdocs/horde/js/prototype.js [new file with mode: 0644]
koward/www/htdocs/horde/js/redbox.js [new file with mode: 0644]
koward/www/htdocs/horde/themes/graphics/favicon.ico [new file with mode: 0644]
koward/www/htdocs/horde/themes/graphics/logout.png [new file with mode: 0644]
koward/www/htdocs/horde/themes/graphics/plus.png [new file with mode: 0644]
koward/www/htdocs/horde/themes/graphics/search.png [new file with mode: 0644]
koward/www/htdocs/horde/themes/graphics/tab_bottom.gif [new file with mode: 0644]
koward/www/htdocs/horde/themes/graphics/user.png [new file with mode: 0644]
koward/www/htdocs/horde/themes/ie5mac.css [new file with mode: 0644]
koward/www/htdocs/horde/themes/ie6_or_less.css [new file with mode: 0644]
koward/www/htdocs/horde/themes/moz14.css [new file with mode: 0644]
koward/www/htdocs/horde/themes/opera.css [new file with mode: 0644]
koward/www/htdocs/horde/themes/rtl.css [new file with mode: 0644]
koward/www/htdocs/horde/themes/screen.css [new file with mode: 0644]
koward/www/htdocs/horde/themes/silver/graphics/currentTab_left.png [new file with mode: 0644]
koward/www/htdocs/horde/themes/silver/graphics/currentTab_right.png [new file with mode: 0644]
koward/www/htdocs/horde/themes/silver/graphics/delete.png [new file with mode: 0644]
koward/www/htdocs/horde/themes/silver/graphics/edit.png [new file with mode: 0644]
koward/www/htdocs/horde/themes/silver/graphics/logout.png [new file with mode: 0644]
koward/www/htdocs/horde/themes/silver/graphics/plus.png [new file with mode: 0644]
koward/www/htdocs/horde/themes/silver/graphics/search.png [new file with mode: 0644]
koward/www/htdocs/horde/themes/silver/graphics/tab_left.png [new file with mode: 0644]
koward/www/htdocs/horde/themes/silver/graphics/tab_right.png [new file with mode: 0644]
koward/www/htdocs/horde/themes/silver/graphics/user.png [new file with mode: 0644]
koward/www/htdocs/horde/themes/silver/info.php [new file with mode: 0644]
koward/www/htdocs/horde/themes/silver/screen.css [new file with mode: 0644]
koward/www/htdocs/horde/themes/silver/themed_graphics [new file with mode: 0644]
koward/www/htdocs/horde/themes/webkit.css [new file with mode: 0644]
koward/www/htdocs/koward/koward.php [new file with mode: 0644]
koward/www/htdocs/koward/themes/graphics/favicon.ico [new file with mode: 0644]
koward/www/htdocs/koward/themes/graphics/query.png [new file with mode: 0644]
koward/www/htdocs/koward/themes/kolab/screen.css [new file with mode: 0644]
koward/www/htdocs/koward/themes/screen.css [new file with mode: 0644]
koward/www/koward/config/.gitignore [new file with mode: 0644]
koward/www/koward/config/attributes.php.dist [new file with mode: 0644]
koward/www/koward/config/base.php.dist [new file with mode: 0644]
koward/www/koward/config/conf.php.dist [new file with mode: 0644]
koward/www/koward/config/labels.php.dist [new file with mode: 0644]
koward/www/koward/config/objects.php.dist [new file with mode: 0644]
koward/www/koward/config/order.php.dist [new file with mode: 0644]
koward/www/koward/config/routes.php.dist [new file with mode: 0644]
koward/www/koward/config/search.php.dist [new file with mode: 0644]
koward/www/koward/config/visible.php.dist [new file with mode: 0644]
koward/www/koward/doc/INSTALL [new file with mode: 0644]

diff --git a/koward/www/Koward/app/koward.php b/koward/www/Koward/app/koward.php
deleted file mode 100644 (file)
index 3abd73d..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-<?php
-
-/** Tell the registry to take everything from this application directory. */
-if (!defined('HORDE_BASE')) {
-    define('HORDE_BASE', dirname(__FILE__) . '/..');
-}
-
-/**
- * The Autoloader allows us to omit "require/include" statements.
- */
-require_once 'Horde/Autoloader.php';
-
-/** Configure the Autoloader to handle the "Koward" pattern */
-Horde_Autoloader::addClassPattern('/^Koward_/', 'Koward/');
-
-/** Dispatch the request. */
-try {
-    Koward::dispatch(__FILE__);
-} catch (Exception $e) {
-    // @TODO Make nicer
-    echo '<h1>' . $e->getMessage() . '</h1>';
-    echo '<pre>'; var_dump($e); echo '</pre>';
-}
diff --git a/koward/www/Koward/app/themes/graphics/favicon.ico b/koward/www/Koward/app/themes/graphics/favicon.ico
deleted file mode 100644 (file)
index 0f8fa08..0000000
Binary files a/koward/www/Koward/app/themes/graphics/favicon.ico and /dev/null differ
diff --git a/koward/www/Koward/app/themes/graphics/query.png b/koward/www/Koward/app/themes/graphics/query.png
deleted file mode 100644 (file)
index ef46d4a..0000000
Binary files a/koward/www/Koward/app/themes/graphics/query.png and /dev/null differ
diff --git a/koward/www/Koward/app/themes/kolab/screen.css b/koward/www/Koward/app/themes/kolab/screen.css
deleted file mode 100644 (file)
index 017e2a7..0000000
+++ /dev/null
@@ -1,212 +0,0 @@
-/*
-  Local variables:
-  buffer-file-coding-system: utf-8
-  End:
-*/
-body {
-  color: black;
-  background-color: #F8FCF8;
-  font-family: verdana,arial,helvetica,sans-serif;
-  font-size: 95%;
-  border: 0;
-  margin: 0;
-}
-a, a:visited {
-  font-family: verdana,arial,helvetica,sans-serif;
-}
-
-a { color: #001155; }
-a:hover { color: #113399; }
-
-#page {
-  background-repeat: no-repeat;
-  background-position: top right;
-}
-
-#topbar {
-  display:block;
-  background-color: #B0BCD0;
-  height: 70px;
-  clear: both;
-}
-#toplogo {
-  display:block;
-  background-image: url(pics/kolab_logo.png);
-  background-color: #B0BCD0;
-  width: 245px;
-  height: 70px;
-  margin-left: 1em;
-  margin-top: 0.4em;
-  float: left;
-}
-#toptitle {
-  display:block;
-  text-align: right;
-  font-size: 200%;
-  padding-right: 1em;
-  padding-top: 0.5em;
-}
-#topuserinfo {
-  display:block;
-  background-color: #B0BCD0;
-  font-size: 80%;
-  padding: 0.1em;
-  border-bottom: solid 1px black;
-  text-align: right;
-}
-#topmenu {
-  background-color: #B0BCD0;
-  font-size: 90%;
-  border-bottom: solid 1px black;
-}
-#submenu {
-  background-color: #EEEEEE;
-  border-bottom: solid 1px black;
-  font-size: 90%;
-}
-
-.topmenuitem {
-  background-color: #B0BCD0;
-  border-right: solid 1px black;
-  padding-left: 0.5em;
-  padding-right: 0.5em;
-  margin: 0px;
-}
-.topmenuitemselected {
-  background-color: #EEEEEE;
-  border-right: solid 1px black;
-  padding-left: 0.5em;
-  padding-right: 0.5em;
-  margin: 0px;
-  border-bottom: solid 1px #EEEEEE;
-}
-.submenuitem {
-}
-.submenuitemselected {
-}
-.alphagroupitem {
-}
-.alphagroupitemselected {
-  font-weight:bold
-}
-#logout {
-  color: red;
-}
-#maintitle {
-  font-size: 200%;
-}
-#maincontent {
-  display:block;
-  padding: 1em;
-  margin: 1em;
-}
-#errorcontent {
-  display:block;
-  padding: 0.2em;
-  margin: 1em;
-  text-align: left;
-  color: red;
-  background-color: #EEEEEE;
-  border: solid 1px black;
-}
-#errorheader {
-  display:block;
-  text-align: left;
-  color: black;
-  background-color: #EEEEEE;
-  font-size: 150%;
-}
-#messagecontent {
-  display:block;
-  padding: 0.2em;
-  margin: 1em;
-  text-align: left;
-  color: green;
-  background-color: #EEEEEE;
-  border: solid 1px black;
-}
-#messageheader {
-  display:block;
-  text-align: left;
-  color: black;
-  background-color: #EEEEEE;
-  font-size: 150%;
-}
-.contenttext {
-  margin: 10px;
-}
-.contenttable {
-  width: 100%;
-  background-color: black;
-  border: 0px;
-}
-.contentroweven {
-  background-color: #C0CDE0;
-  margin: 0px;
-}
-.contentrowodd {
-  background-color: #D0DDF0;
-  margin: 0px;
-}
-.contentcell {
-  font-size: 90%;
-  padding: .1em .5em .1em .5em;
-  margin: 0px;
-/*  text-align: center; */
-}
-.actioncell {
-  font-size: 90%;
-  padding: .1em .5em .1em .5em;
-  width: 10%;
-  margin: 0px;
-  text-align: center;
-}
-.contentform {
-  /*float: left;*/
-  padding: .1em .5em .1em .5em;
-  background-color: #EEEEEE;
-  border: solid 1px black;
-}
-.contentformtable {
-  font-size: 90%;
-}
-.langcombo {
-  font-size: 80%;
-}
-
-#validators {
-  text-align: right;
-}
-
-th {
-  background-color: #EEEEEE;
-  border: 0px;
-}
-
-.ctrl {
-  background-color: #E0E3E0;
-  border: solid 1px black;
-  padding: .2em .5em .2em .5em;
-}
-
-.required_asterisk {
-  color: red;
-  font-size: 80%;
-  text-align: right;
-}
-
-label {
-  cursor: pointer;
-}
-
-.align_center {
-  text-align: center;
-}
-
-.align_right {
-  text-align: right;
-}
-
-.align_left {
-  text-align: left;
-}
diff --git a/koward/www/Koward/app/themes/screen.css b/koward/www/Koward/app/themes/screen.css
deleted file mode 100644 (file)
index 9075ea6..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-/**
- * Style for Koward.
- */
diff --git a/koward/www/Koward/config/.gitignore b/koward/www/Koward/config/.gitignore
deleted file mode 100644 (file)
index 8713fda..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-*.php
-*.local.php
diff --git a/koward/www/Koward/config/attributes.php.dist b/koward/www/Koward/config/attributes.php.dist
deleted file mode 100644 (file)
index 3a49086..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-<?php
-
-$attributes['givenName'] = array(
-    'label' => _("First Name"),
-    'type' => 'text',
-    'required' => true,
-    'params' => array('regex' => '', 'size' => 40, 'maxlength' => 255)
-);
-$attributes['sn'] = array(
-    'label' => _("Last Name"),
-    'type' => 'text',
-    'required' => true,
-    'params' => array('regex' => '', 'size' => 40, 'maxlength' => 255)
-);
-$attributes['mail'] = array(
-    'label' => _("Mail address"),
-    'type' => 'text',
-    'required' => true,
-    'params' => array('regex' => '', 'size' => 40, 'maxlength' => 255)
-);
-$attributes['uid'] = array(
-    'label' => _("User ID"),
-    'type' => 'text',
-    'required' => true,
-    'params' => array('regex' => '', 'size' => 40, 'maxlength' => 255)
-);
diff --git a/koward/www/Koward/config/conf.php.dist b/koward/www/Koward/config/conf.php.dist
deleted file mode 100644 (file)
index da94aad..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-<?php
-
-$conf['use_ssl'] = 2;
-$conf['server']['name'] = $_SERVER['SERVER_NAME'];
-$conf['server']['port'] = $_SERVER['SERVER_PORT'];
-$conf['cookie']['domain'] = $_SERVER['SERVER_NAME'];
-$conf['cookie']['path'] = '/';
-$conf['debug_level'] = E_ALL & ~E_NOTICE;
-$conf['umask'] = 077;
-$conf['compress_pages'] = true;
-$conf['session']['name'] = 'Horde';
-$conf['session']['cache_limiter'] = 'nocache';
-$conf['session']['timeout'] = 0;
-$conf['urls']['token_lifetime'] = 20;
-$conf['server']['token_lifetime'] = 20;
-$conf['auth']['admins'] = array('Administrator');
-$conf['auth']['driver'] = 'kolab';
-$conf['auth']['params'] = array();
-$conf['prefs']['driver'] = 'session';
-$conf['menu']['always'] = false;
-$conf['menu']['links']['logout'] = 'authenticated';
-$conf['portal']['fixed_blocks'] = array();
-$conf['imsp']['enabled'] = false;
-$conf['kolab']['enabled'] = true;
-$conf['kolab']['server']['driver'] = 'ldap';
-$conf['kolab']['imap']['allow_special_users'] = true;
-$conf['log']['priority'] = PEAR_LOG_DEBUG;
-$conf['log']['ident'] = 'HORDE';
-$conf['log']['params'] = array();
-$conf['log']['name'] = '/tmp/horde.log';
-$conf['log']['params']['append'] = true;
-$conf['log']['type'] = 'file';
-$conf['log']['enabled'] = true;
diff --git a/koward/www/Koward/config/hooks.php.dist b/koward/www/Koward/config/hooks.php.dist
deleted file mode 100644 (file)
index b3d9bbc..0000000
+++ /dev/null
@@ -1 +0,0 @@
-<?php
diff --git a/koward/www/Koward/config/koward.php.dist b/koward/www/Koward/config/koward.php.dist
deleted file mode 100644 (file)
index 656621c..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-<?php
-
-$conf['koward']['theme'] = 'silver';
diff --git a/koward/www/Koward/config/labels.php.dist b/koward/www/Koward/config/labels.php.dist
deleted file mode 100644 (file)
index a462447..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-<?php
-
-$labels['cn'] = _("Common Name");
-$labels['kolabSalutation'] = _("Salutation");
-$labels['givenName'] = _("First Name");
-$labels['middleNames'] = _("Additional Names");
-$labels['sn'] = _("Last Name");
-$labels['snsuffix'] = _("Name Suffix");
-$labels['personalTitle'] = _("Title");
-$labels['userPassword'] = _("Password");
-$labels['telephoneNumber'] = _("Phone");
-$labels['postOfficeBox'] = _("Post Office Box");
-$labels['street'] = _("Street");
-$labels['title'] = _("Job Title");
-$labels['postalCode'] = _("Postal Code");
-$labels['facsimileTelephoneNumber'] = _("Fax");
-$labels['l'] = _("City");
-$labels['jpegPhoto'] = _("Photo");
-$labels['mail'] = _("Mail Address");
-$labels['mobile'] = _("Mobile Phone");
-$labels['homePhone'] = _("Home Phone");
-$labels['homePostalAddress'] = _("Home Postal Address");
-$labels['labeledURI'] = _("Website");
-$labels['o'] = _("Company");
-$labels['birthName'] = _("Birth Name");
-$labels['kolabMaritalStatus'] = _("Marital Status");
-$labels['dateOfBirth'] = _("Date Of Birth");
-$labels['placeOfBirth'] = _("Place Of Birth");
-$labels['gender'] = _("Gender");
-
diff --git a/koward/www/Koward/config/nls.php.dist b/koward/www/Koward/config/nls.php.dist
deleted file mode 100644 (file)
index cf7cb14..0000000
+++ /dev/null
@@ -1,272 +0,0 @@
-<?php
-/**
- * NLS (National Language Support) configuration file.
- *
- * $Horde: horde/config/nls.php.dist,v 1.77 2008/10/14 21:11:47 jan Exp $
- */
-
-/**
- ** Defaults
- **/
-
-/* The language to fall back on if we cannot determine one any other
-   way (user choice or preferences). If empty, we will try to negotiate
-   with the browser using HTTP_ACCEPT_LANGUAGE. */
-$nls['defaults']['language'] = '';
-
-
-/**
- ** Language
- **/
-
-$nls['languages']['ar_OM'] = '&#x202d;Arabic (Oman) &#x202e;(&#x0627;&#x0644;&#x0639;&#x0631;&#x0628;&#x064a;&#x0629;)';
-$nls['languages']['ar_SY'] = '&#x202d;Arabic (Syria) &#x202e;(&#x0627;&#x0644;&#x0639;&#x0631;&#x0628;&#x064a;&#x0629;)';
-$nls['languages']['id_ID'] = 'Bahasa Indonesia';
-$nls['languages']['bs_BA'] = 'Bosanski';
-$nls['languages']['bg_BG'] = '&#x202d;Bulgarian (&#x0411;&#x044a;&#x043b;&#x0433;&#x0430;&#x0440;&#x0441;&#x043a;&#x0438;)';
-$nls['languages']['ca_ES'] = 'Catal&#xe0;';
-$nls['languages']['zh_CN'] = '&#x202d;Chinese (Simplified) (&#x7b80;&#x4f53;&#x4e2d;&#x6587;)';
-$nls['languages']['zh_TW'] = '&#x202d;Chinese (Traditional) (&#x6b63;&#x9ad4;&#x4e2d;&#x6587;)';
-$nls['languages']['cs_CZ'] = '&#x202d;Czech (&#x010c;esky)';
-$nls['languages']['da_DK'] = 'Dansk';
-$nls['languages']['de_DE'] = 'Deutsch';
-$nls['languages']['en_US'] = '&#x202d;English (American)';
-$nls['languages']['en_GB'] = '&#x202d;English (British)';
-$nls['languages']['en_CA'] = '&#x202d;English (Canadian)';
-$nls['languages']['es_ES'] = 'Espa&#xf1;ol';
-$nls['languages']['et_EE'] = 'Eesti';
-$nls['languages']['eu_ES'] = 'Euskara';
-$nls['languages']['fr_FR'] = 'Fran&#xe7;ais';
-$nls['languages']['gl_ES'] = 'Galego';
-$nls['languages']['el_GR'] = '&#x202d;Greek (&#x0395;&#x03bb;&#x03bb;&#x03b7;&#x03bd;&#x03b9;&#x03ba;&#x03ac;)';
-$nls['languages']['he_IL'] = '&#x202d;Hebrew &#x202e;(&#x05E2;&#x05D1;&#x05E8;&#x05D9;&#x05EA;)';
-$nls['languages']['is_IS'] = '&#xcd;slenska';
-$nls['languages']['it_IT'] = 'Italiano';
-$nls['languages']['ja_JP'] = '&#x202d;Japanese (&#x65e5;&#x672c;&#x8a9e;)';
-$nls['languages']['km_KH'] = '&#x202d;Khmer (&#x1781;&#x17d2;&#x1798;&#x17c2;&#x179a;)';
-$nls['languages']['ko_KR'] = '&#x202d;Korean (&#xd55c;&#xad6d;&#xc5b4;)';
-$nls['languages']['lv_LV'] = 'Latvie&#x0161;u';
-$nls['languages']['lt_LT'] = 'Lietuvi&#x0173;';
-$nls['languages']['mk_MK'] = '&#x202d;Macedonian (&#x041c;&#x0430;&#x043a;&#x0435;&#x0434;&#x043e;&#x043d;&#x0441;&#x043a;&#x0438;)';
-$nls['languages']['hu_HU'] = 'Magyar';
-$nls['languages']['nl_NL'] = 'Nederlands';
-$nls['languages']['nb_NO'] = 'Norsk bokm&#xe5;l';
-$nls['languages']['nn_NO'] = 'Norsk nynorsk';
-$nls['languages']['fa_IR'] = '&#x202d;Persian &#x202e;(&#x0641;&#x0627;&#x0631;&#x0633;&#x0649;)';
-$nls['languages']['pl_PL'] = 'Polski';
-$nls['languages']['pt_PT'] = 'Portugu&#xea;s';
-$nls['languages']['pt_BR'] = 'Portugu&#xea;s Brasileiro';
-$nls['languages']['ro_RO'] = 'Rom&#xe2;n&#xe4;';
-$nls['languages']['ru_RU'] = '&#x202d;Russian (&#x0420;&#x0443;&#x0441;&#x0441;&#x043a;&#x0438;&#x0439;)';
-$nls['languages']['sk_SK'] = '&#x202d;Slovak (Sloven&#x010d;ina)';
-$nls['languages']['sl_SI'] = '&#x202d;Slovenian (Sloven&#x0161;&#x010d;ina)';
-$nls['languages']['fi_FI'] = 'Suomi';
-$nls['languages']['sv_SE'] = 'Svenska';
-$nls['languages']['th_TH'] = '&#x202d;Thai (&#x0e44;&#x0e17;&#x0e22;)';
-if (version_compare(PHP_VERSION, '5', 'lt') || version_compare(PHP_VERSION, '6', 'ge')) {
-    $nls['languages']['tr_TR'] = 'T&#xfc;rk&#xe7;e';
-}
-$nls['languages']['uk_UA'] = '&#x202d;Ukrainian (&#x0423;&#x043a;&#x0440;&#x0430;&#x0457;&#x043d;&#x0441;&#x044c;&#x043a;&#x0430;)';
-
-
-/**
- ** Aliases for languages with different browser and gettext codes
- **/
-
-$nls['aliases']['ar'] = 'ar_SY';
-$nls['aliases']['bg'] = 'bg_BG';
-$nls['aliases']['bs'] = 'bs_BA';
-$nls['aliases']['ca'] = 'ca_ES';
-$nls['aliases']['cs'] = 'cs_CZ';
-$nls['aliases']['da'] = 'da_DK';
-$nls['aliases']['de'] = 'de_DE';
-$nls['aliases']['el'] = 'el_GR';
-$nls['aliases']['en'] = 'en_US';
-$nls['aliases']['es'] = 'es_ES';
-$nls['aliases']['et'] = 'et_EE';
-$nls['aliases']['fa'] = 'fa_IR';
-$nls['aliases']['fi'] = 'fi_FI';
-$nls['aliases']['fr'] = 'fr_FR';
-$nls['aliases']['gl'] = 'gl_ES';
-$nls['aliases']['he'] = 'he_IL';
-$nls['aliases']['hu'] = 'hu_HU';
-$nls['aliases']['id'] = 'id_ID';
-$nls['aliases']['is'] = 'is_IS';
-$nls['aliases']['it'] = 'it_IT';
-$nls['aliases']['ja'] = 'ja_JP';
-$nls['aliases']['km'] = 'km_KH';
-$nls['aliases']['ko'] = 'ko_KR';
-$nls['aliases']['lt'] = 'lt_LT';
-$nls['aliases']['lv'] = 'lv_LV';
-$nls['aliases']['mk'] = 'mk_MK';
-$nls['aliases']['nl'] = 'nl_NL';
-$nls['aliases']['nn'] = 'nn_NO';
-$nls['aliases']['no'] = 'nb_NO';
-$nls['aliases']['pl'] = 'pl_PL';
-$nls['aliases']['pt'] = 'pt_PT';
-$nls['aliases']['ro'] = 'ro_RO';
-$nls['aliases']['ru'] = 'ru_RU';
-$nls['aliases']['sk'] = 'sk_SK';
-$nls['aliases']['sl'] = 'sl_SI';
-$nls['aliases']['sv'] = 'sv_SE';
-$nls['aliases']['th'] = 'th_TH';
-if (version_compare(PHP_VERSION, '5', 'lt') || version_compare(PHP_VERSION, '6', 'ge')) {
-    $nls['aliases']['tr'] = 'tr_TR';
-}
-$nls['aliases']['uk'] = 'uk_UA';
-
-
-/**
- ** Charsets. These differ somewhat on different systems; see below
- ** for a set of BSD charset names.
- **/
-
-$nls['charsets']['ar_OM'] = 'windows-1256';
-$nls['charsets']['ar_SY'] = 'windows-1256';
-$nls['charsets']['bg_BG'] = 'windows-1251';
-$nls['charsets']['bs_BA'] = 'ISO-8859-2';
-$nls['charsets']['cs_CZ'] = 'ISO-8859-2';
-$nls['charsets']['el_GR'] = 'ISO-8859-7';
-$nls['charsets']['eu_ES'] = 'UTF-8';
-$nls['charsets']['fa_IR'] = 'UTF-8';
-$nls['charsets']['he_IL'] = 'UTF-8';
-$nls['charsets']['hu_HU'] = 'ISO-8859-2';
-$nls['charsets']['ja_JP'] = 'SHIFT_JIS';
-$nls['charsets']['km_KH'] = 'UTF-8';
-$nls['charsets']['ko_KR'] = 'EUC-KR';
-$nls['charsets']['lt_LT'] = 'ISO-8859-13';
-$nls['charsets']['lv_LV'] = 'windows-1257';
-$nls['charsets']['mk_MK'] = 'ISO-8859-5';
-$nls['charsets']['pl_PL'] = 'ISO-8859-2';
-$nls['charsets']['ru_RU'] = 'windows-1251';
-$nls['charsets']['ru_RU.KOI8-R'] = 'KOI8-R';
-$nls['charsets']['sk_SK'] = 'ISO-8859-2';
-$nls['charsets']['sl_SI'] = 'ISO-8859-2';
-$nls['charsets']['th_TH'] = 'TIS-620';
-if (version_compare(PHP_VERSION, '5', 'lt') || version_compare(PHP_VERSION, '6', 'ge')) {
-    $nls['charsets']['tr_TR'] = 'ISO-8859-9';
-}
-$nls['charsets']['uk_UA'] = 'windows-1251';
-$nls['charsets']['zh_CN'] = 'GB2312';
-$nls['charsets']['zh_TW'] = 'BIG5';
-
-/**
- * BSD charsets.
- */
-if (strpos(PHP_OS, 'BSD') !== false) {
-    $nls['charsets']['ar_OM'] = 'windows-1256';
-    $nls['charsets']['ar_SY'] = 'windows-1256';
-    $nls['charsets']['bg_BG'] = 'windows-1251';
-    $nls['charsets']['bs_BA'] = 'ISO8859-2';
-    $nls['charsets']['cs_CZ'] = 'ISO8859-2';
-    $nls['charsets']['el_GR'] = 'ISO8859-7';
-    $nls['charsets']['eu_ES'] = 'UTF-8';
-    $nls['charsets']['fa_IR'] = 'UTF-8';
-    $nls['charsets']['he_IL'] = 'UTF-8';
-    $nls['charsets']['hu_HU'] = 'ISO8859-2';
-    $nls['charsets']['ja_JP'] = 'SHIFT_JIS';
-    $nls['charsets']['km_KH'] = 'UTF-8';
-    $nls['charsets']['ko_KR'] = 'EUC-KR';
-    $nls['charsets']['lt_LT'] = 'ISO8859-13';
-    $nls['charsets']['lv_LV'] = 'windows-1257';
-    $nls['charsets']['mk_MK'] = 'ISO8859-5';
-    $nls['charsets']['pl_PL'] = 'ISO8859-2';
-    $nls['charsets']['ru_RU'] = 'windows-1251';
-    $nls['charsets']['ru_RU.KOI8-R'] = 'KOI8-R';
-    $nls['charsets']['sk_SK'] = 'ISO8859-2';
-    $nls['charsets']['sl_SI'] = 'ISO8859-2';
-    $nls['charsets']['th_TH'] = 'TIS-620';
-    if (version_compare(PHP_VERSION, '5', 'lt') ||
-        version_compare(PHP_VERSION, '6', 'ge')) {
-        $nls['charsets']['tr_TR'] = 'ISO-8859-9';
-    }
-    $nls['charsets']['uk_UA'] = 'windows-1251';
-    $nls['charsets']['zh_CN'] = 'GB2312';
-    $nls['charsets']['zh_TW'] = 'BIG5';
-}
-
-
-/**
- ** Multibyte charsets
- **/
-
-$nls['multibyte']['BIG5'] = true;
-$nls['multibyte']['EUC-KR'] = true;
-$nls['multibyte']['GB2312'] = true;
-$nls['multibyte']['SHIFT_JIS'] = true;
-$nls['multibyte']['UTF-8'] = true;
-
-
-/**
- ** Right-to-left languages
- **/
-
-$nls['rtl']['ar_OM'] = true;
-$nls['rtl']['ar_SY'] = true;
-$nls['rtl']['fa_IR'] = true;
-$nls['rtl']['he_IL'] = true;
-
-
-/**
- ** Preferred charsets for email traffic if not the languages' default
- ** charsets.
- **/
-
-$nls['emails']['ja_JP'] = 'ISO-2022-JP';
-
-
-/**
- ** Available charsets for outgoing email traffic.
- **/
-
-$nls['encodings']['windows-1256'] = _("Arabic (Windows-1256)");
-$nls['encodings']['ARMSCII-8'] = _("Armenian (ARMSCII-8)");
-$nls['encodings']['ISO-8859-13'] = _("Baltic (ISO-8859-13)");
-$nls['encodings']['ISO-8859-14'] = _("Celtic (ISO-8859-14)");
-$nls['encodings']['ISO-8859-2'] = _("Central European (ISO-8859-2)");
-$nls['encodings']['GB2312'] = _("Chinese Simplified (GB2312)");
-$nls['encodings']['BIG5'] = _("Chinese Traditional (Big5)");
-$nls['encodings']['KOI8-R'] = _("Cyrillic (KOI8-R)");
-$nls['encodings']['windows-1251'] = _("Cyrillic (Windows-1251)");
-$nls['encodings']['KOI8-U'] = _("Cyrillic/Ukrainian (KOI8-U)");
-$nls['encodings']['ISO-8859-7'] = _("Greek (ISO-8859-7)");
-$nls['encodings']['ISO-8859-8-I'] = _("Hebrew (ISO-8859-8-I)");
-$nls['encodings']['ISO-2022-JP'] = _("Japanese (ISO-2022-JP)");
-$nls['encodings']['EUC-KR'] = _("Korean (EUC-KR)");
-$nls['encodings']['ISO-8859-10'] = _("Nordic (ISO-8859-10)");
-$nls['encodings']['ISO-8859-3'] = _("South European (ISO-8859-3)");
-$nls['encodings']['TIS-620'] = _("Thai (TIS-620)");
-$nls['encodings']['ISO-8859-9'] = _("Turkish (ISO-8859-9)");
-$nls['encodings']['UTF-8'] = _("Unicode (UTF-8)");
-$nls['encodings']['VISCII'] = _("Vietnamese (VISCII)");
-$nls['encodings']['ISO-8859-1'] = _("Western (ISO-8859-1)");
-$nls['encodings']['ISO-8859-15'] = _("Western (ISO-8859-15)");
-asort($nls['encodings']);
-
-
-/**
- ** Multi-language spelling support
- **/
-
-$nls['spelling']['cs_CZ'] = '-T latin2 -d czech';
-$nls['spelling']['da_DK'] = '-d dansk';
-$nls['spelling']['de_DE'] = '-T latin1 -d deutsch';
-$nls['spelling']['el_GR'] = '-T latin1 -d ellinika';
-$nls['spelling']['en_CA'] = '-d canadian';
-$nls['spelling']['en_GB'] = '-d british';
-$nls['spelling']['en_US'] = '-d american';
-$nls['spelling']['es_ES'] = '-d espanol';
-$nls['spelling']['fr_FR'] = '-d francais';
-$nls['spelling']['it_IT'] = '-T latin1 -d italian';
-$nls['spelling']['nl_NL'] = '-d nederlands';
-$nls['spelling']['pl_PL'] = '-d polish';
-$nls['spelling']['pt_BR'] = '-d br';
-$nls['spelling']['pt_PT'] = '-T latin1 -d portuguese';
-$nls['spelling']['ru_RU'] = '-d russian';
-$nls['spelling']['sl_SI'] = '-d slovensko';
-$nls['spelling']['sv_SE'] = '-d svenska';
-if (isset($nls['charsets']['tr_TR'])) {
-    $nls['spelling']['tr_TR'] = '-d tr';
-}
-
-$GLOBALS['nls'] = &$nls;
diff --git a/koward/www/Koward/config/objects.php.dist b/koward/www/Koward/config/objects.php.dist
deleted file mode 100644 (file)
index 6c15803..0000000
+++ /dev/null
@@ -1,210 +0,0 @@
-<?php
-
-/* $objects['object'] = array( */
-/*     'class'       => 'Horde_Kolab_Server_Object', */
-/*     'label'       => _("Object"), */
-/*     'list_label'  => _("Objects"), */
-/*     'list_attributes'  => array( */
-/*         'id' => array( */
-/*             'title' => _("Object id"), */
-/*             'width' => 80, */
-/*             'link_view'=> true, */
-/*         ), */
-/*     ), */
-/*     'attributes'  => array( */
-/*         'override' => true, */
-/*         'fields' => array( */
-/*             'id' => array( */
-/*                 'label' => _("Object ID"), */
-/*                 'type' => 'text', */
-/*                 'params' => array('regex' => '', 'size' => 40, 'maxlength' => 255) */
-/*             ), */
-/*         ), */
-/*     ), */
-/* ); */
-
-/* $objects['person'] = array( */
-/*     'class'       => 'Horde_Kolab_Server_Object_Person', */
-/*     'label'       => _("Person"), */
-/*     'list_label'  => _("Persons"), */
-/*     'list_attributes'  => array( */
-/*         'cn' => array( */
-/*             'title' => _("Common name"), */
-/*             'width' => 40, */
-/*             'link_view'=> true, */
-/*         ), */
-/*         'sn' => array( */
-/*             'title' => _("Last name"), */
-/*             'width' => 40, */
-/*         ), */
-/*     ), */
-/*     'attributes'  => array( */
-/*         'fields' => array( */
-/*             'cn' => array( */
-/*                 'required' => false, */
-/*             ), */
-/*             'userPassword' => array( */
-/*                 'required' => true, */
-/*             ), */
-/*         ), */
-/*     ), */
-/* ); */
-
-/* $objects['organizationalperson'] = array( */
-/*     'class'       => 'Horde_Kolab_Server_Object_Organizationalperson', */
-/*     'label'       => _("Organizational person"), */
-/*     'list_label'  => _("Organizational persons"), */
-/*     'list_attributes'  => array( */
-/*         'cn' => array( */
-/*             'title' => _("Common name"), */
-/*             'width' => 40, */
-/*             'link_view'=> true, */
-/*         ), */
-/*         'sn' => array( */
-/*             'title' => _("Last name"), */
-/*             'width' => 40, */
-/*         ), */
-/*     ), */
-/*     'attributes'  => array( */
-/*         'fields' => array( */
-/*             'cn' => array( */
-/*                 'required' => false, */
-/*             ), */
-/*             'userPassword' => array( */
-/*                 'required' => true, */
-/*             ), */
-/*         ), */
-/*     ), */
-/* ); */
-
-/* $objects['inetperson'] = array( */
-/*     'class'       => 'Horde_Kolab_Server_Object_Inetorgperson', */
-/*     'label'       => _("Inet person"), */
-/*     'list_label'  => _("Inet persons"), */
-/*     'list_attributes'  => array( */
-/*         'cn' => array( */
-/*             'title' => _("Common name"), */
-/*             'width' => 40, */
-/*             'link_view'=> true, */
-/*         ), */
-/*         'sn' => array( */
-/*             'title' => _("Last name"), */
-/*             'width' => 40, */
-/*         ), */
-/*     ), */
-/*     'attributes'  => array( */
-/*         'fields' => array( */
-/*             'cn' => array( */
-/*                 'required' => false, */
-/*             ), */
-/*             'userPassword' => array( */
-/*                 'required' => true, */
-/*             ), */
-/*         ), */
-/*     ), */
-/* ); */
-
-/* $objects['user'] = array( */
-/*     'class'       => 'Horde_Kolab_Server_Object_Kolab_User', */
-/*     'label'       => _("User"), */
-/*     'list_label'  => _("Users"), */
-/*     'list_attributes'  => array( */
-/*         'sn' => array( */
-/*             'title' => _("Last name"), */
-/*             'width' => 20, */
-/*         ), */
-/*         'givenName' => array( */
-/*             'title' => _("First name"), */
-/*             'width' => 20, */
-/*         ), */
-/*         'mail' => array( */
-/*             'title' => _("E-mail"), */
-/*             'width' => 20, */
-/*             'link_view'=> true, */
-/*         ), */
-/*         'uid' => array( */
-/*             'title' => _("User ID"), */
-/*             'width' => 20, */
-/*         ), */
-/*     ), */
-/* ); */
-
-/* $objects['admin'] = array( */
-/*     'class'       => 'Horde_Kolab_Server_Object_Kolab_Administrator', */
-/*     'label'       => _("Administrator"), */
-/*     'list_label'  => _("Administrators"), */
-/*     'attributes'  => array( */
-/*     ), */
-/* ); */
-
-/* $objects['kolabuser'] = array( */
-/*     'class'       => 'Horde_Kolab_Server_Object_Kolab_User', */
-/*     'preferred'   => true, */
-/*     'label'       => _("Kolab user"), */
-/*     'list_label'  => _("Kolab users"), */
-/*     'list_attributes'  => array( */
-/*         'sn' => array( */
-/*             'title' => _("Last name"), */
-/*             'width' => 20, */
-/*         ), */
-/*         'givenName' => array( */
-/*             'title' => _("First name"), */
-/*             'width' => 20, */
-/*         ), */
-/*         'mail' => array( */
-/*             'title' => _("E-mail"), */
-/*             'width' => 20, */
-/*             'link_view'=> true, */
-/*         ), */
-/*         'uid' => array( */
-/*             'title' => _("User ID"), */
-/*             'width' => 20, */
-/*         ), */
-/*     ), */
-/*     'attributes'  => array( */
-/*         'hide' => array( */
-/*             'objectClass', */
-/*             'seeAlso', */
-/*             'x121Address', */
-/*             'registeredAddress', */
-/*             'destinationIndicator', */
-/*             'preferredDeliveryMethod', */
-/*             'telexNumber', */
-/*             'teletexTerminalIdentifier', */
-/*             'internationaliSDNNumber', */
-/*             'kolabEncryptedPassword', */
-/*             'kolabHomeMTA', */
-/*             'kolabDelegate', */
-/*         ), */
-/*         'labels' => array( */
-/*             'mail' => _("Account ID"), */
-/*         ), */
-/*         'fields' => array( */
-/*             'kolabSalutation' => array( */
-/*                 'type' => 'enum', */
-/*                 'params' => array('values' => array(_("Mr.") => _("Mr."), */
-/*                                                     _("Mrs.") => _("Mrs.")), */
-/*                                   'prompt' => true), */
-/*             ), */
-/*             'gender' => array( */
-/*                 'type' => 'enum', */
-/*                 'params' => array('values' => array(_("1") => _("male"), */
-/*                                                     _("2") => _("female")), */
-/*                                   'prompt' => true), */
-/*             ), */
-/*             'kolabMaritalStatus' => array( */
-/*                 'type' => 'enum', */
-/*                 'params' => array('values' => array(_("0") => _("single"), */
-/*                                                     _("1") => _("married")), */
-/*                                   'prompt' => true), */
-/*             ), */
-/*             'userPassword' => array( */
-/*                 'type' => 'passwordconfirm', */
-/*             ), */
-/*         ), */
-/*     ), */
-/* ); */
-
-if (file_exists(dirname(__FILE__) . '/objects.local.php')) {
-    require_once(dirname(__FILE__) . '/objects.local.php');
-}
diff --git a/koward/www/Koward/config/order.php.dist b/koward/www/Koward/config/order.php.dist
deleted file mode 100644 (file)
index 74e0a28..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-<?php
-$order['mail'] = 1;
-$order['kolabSalutation'] = 2;
-$order['givenName'] = 3;
-$order['middleNames'] = 4;
-$order['sn'] = 5;
-$order['snsuffix'] = 6;
-$order['gender'] = 7;
-$order['userPassword'] = 10;
-$order['dateOfBirth'] = 12;
-$order['placeOfBirth'] = 13;
-$order['kolabMaritalStatus'] = 14;
-$order['birthName'] = 15;
-$order['telephoneNumber'] = 30;
-$order['mobile'] = 31;
-$order['facsimileTelephoneNumber'] = 32;
-$order['homePhone'] = 33;
diff --git a/koward/www/Koward/config/registry.php.dist b/koward/www/Koward/config/registry.php.dist
deleted file mode 100644 (file)
index cfa8304..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-<?php
-/**
- * registry.php -- Horde application registry.
- *
- * $Horde: horde/config/registry.php.dist,v 1.306 2009/01/14 20:51:07 chuck Exp $
- *
- * This configuration file is used by Horde to determine which Horde
- * applications are installed and where, as well as how they interact.
- *
- * Application registry
- * --------------------
- * The following settings register installed Horde applications.
- * By default, Horde assumes that the application directories live
- * inside the horde directory.
- *
- * Attribute     Type     Description
- * ---------     ----     -----------
- * fileroot      string   The base filesystem path for the module's files.
- * webroot       string   The base URI for the module.
- * jsuri         string   The base URI for static javascript files.
- * jsfs          string   The base filesystem path for static javascript files.
- * themesuri     string   The base URI for the themes. This can be used to
- *                        serve all icons and style sheets from a separate
- *                        server.
- * themesfs      string   The base file system directory for the themes.
- * icon          string   The URI for an icon to show in menus for the module.
- *                        Setting this will override the default theme-based
- *                        logic in the code.
- * name          string   The name used in menus and descriptions for a module
- * status        string   'inactive', 'hidden', 'notoolbar', 'heading',
- *                        'block', 'admin', or 'active'.
- * provides      string   Service types the module provides.
- * initial_page  string   The initial (default) page (filename) for the module.
- * templates     string   The filesystem path to the templates directory.
- * menu_parent   string   The name of the 'heading' group that this app should
- *                        show up under.
- * target        string   The (optional) target frame for the link.
- * url           string   The (optional) URL of 'heading' entries.
- */
-
-// We try to automatically determine the proper webroot for Horde here. This
-// still assumes that applications live under horde/. If this results in
-// incorrect results for you, simply change the 'webroot' setting in the
-// 'horde' stanza below.
-
-$this->applications['horde'] = array(
-    'fileroot' => dirname(__FILE__) . '/..',
-    'webroot' => '/',
-    'initial_page' => 'login.php',
-    'name' => _("Horde"),
-    'status' => 'active',
-    'templates' => dirname(__FILE__) . '/../templates',
-    'provides' => 'horde',
-    'themesuri' => '/app/themes',
-    'themesfs' => dirname(__FILE__) . '/../app/themes',
-);
-
-$this->applications['koward'] = array(
-    'fileroot' => dirname(__FILE__) . '/..',
-    'webroot' => $this->applications['horde']['webroot'] . '/app',
-    'name' => _("Koward"),
-    'status' => 'active',
-    'initial_page' => 'index.php',
-    'themesuri' => '/app/themes',
-    'themesfs' => dirname(__FILE__) . '/../app/themes',
-);
diff --git a/koward/www/Koward/config/routes.php.dist b/koward/www/Koward/config/routes.php.dist
deleted file mode 100644 (file)
index 1043478..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-<?php
-
-$mapper->connect('index', array('controller' => 'index'));
-$mapper->connect('index.php', array('controller' => 'index'));
-
-$mapper->connect('check/:action/:id', array('controller' => 'check', 'action' => 'show'));
-$mapper->connect(':controller/:action/:id', array('controller' => 'object'));
-
-// Local route overrides
-if (file_exists(dirname(__FILE__) . '/routes.local.php')) {
-    include dirname(__FILE__) . '/routes.local.php';
-}
diff --git a/koward/www/Koward/config/search.php.dist b/koward/www/Koward/config/search.php.dist
deleted file mode 100644 (file)
index fb6264f..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-<?php
-
-$search = array(
-    'fields' => array(
-        'givenName' => array(
-            'label' => _("First Name"),
-            'type' => 'text',
-            'params' => array('regex' => '', 'size' => 40, 'maxlength' => 255)
-        ),
-    )
-);
-
-if (file_exists(dirname(__FILE__) . '/search.local.php')) {
-    require_once(dirname(__FILE__) . '/search.local.php');
-}
diff --git a/koward/www/Koward/config/visible.php.dist b/koward/www/Koward/config/visible.php.dist
deleted file mode 100644 (file)
index d869909..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-<?php
-$visible['hide'] = array(
-    'objectClass',
-    'id',
-    'lnfn',
-    'fnln',
-    'seeAlso',
-    'description',
-    'physicalDeliveryOfficeName',
-    'internationaliSDNNumber',
-    'x121Address',
-    'registeredAddress',
-    'destinationIndicator',
-    'preferredDeliveryMethod',
-    'telexNumber',
-    'teletexTerminalIdentifier',
-    'postalAddress',
-    'ou',
-    'st',
-    'manager',
-    'uid',
-    'employeeType',
-    'photo',
-    'x500uniqueIdentifier',
-    'secretary',
-    'userSMIMECertificate',
-    'employeeNumber',
-    'initials',
-    'audio',
-    'pager',
-    'businessCategory',
-    'roomNumber',
-    'carLicense',
-    'userCertificate',
-    'departmentNumber',
-    'preferredLanguage',
-    'displayName',
-    'userPKCS12',
-    'kolabVacationEndDateTime',
-    'kolabVacationReactDomain',
-    'kolabVacationAddress',
-    'kolabForwardKeepCopy',
-    'kolabDeleteflag',
-    'kolabVacationBeginDateTime',
-    'kolabVacationResendInterval',
-    'kolabVacationReplyToUCE',
-    'kolabForwardAddress',
-    'kolabForwardUCE',
-    'kolabAllowSMTPFrom',
-    'unrestrictedMailSize',
-    'kolabInvitationPolicy',
-    'kolabFreeBusyFuture',
-    'calFBURL',
-    'kolabComment',
-    'kolabImapServer',
-    'kolabFreeBusyServer',
-    'usertype',
-    'jpegPhoto',
-);
\ No newline at end of file
diff --git a/koward/www/horde/config/conf.php.dist b/koward/www/horde/config/conf.php.dist
new file mode 100644 (file)
index 0000000..da94aad
--- /dev/null
@@ -0,0 +1,33 @@
+<?php
+
+$conf['use_ssl'] = 2;
+$conf['server']['name'] = $_SERVER['SERVER_NAME'];
+$conf['server']['port'] = $_SERVER['SERVER_PORT'];
+$conf['cookie']['domain'] = $_SERVER['SERVER_NAME'];
+$conf['cookie']['path'] = '/';
+$conf['debug_level'] = E_ALL & ~E_NOTICE;
+$conf['umask'] = 077;
+$conf['compress_pages'] = true;
+$conf['session']['name'] = 'Horde';
+$conf['session']['cache_limiter'] = 'nocache';
+$conf['session']['timeout'] = 0;
+$conf['urls']['token_lifetime'] = 20;
+$conf['server']['token_lifetime'] = 20;
+$conf['auth']['admins'] = array('Administrator');
+$conf['auth']['driver'] = 'kolab';
+$conf['auth']['params'] = array();
+$conf['prefs']['driver'] = 'session';
+$conf['menu']['always'] = false;
+$conf['menu']['links']['logout'] = 'authenticated';
+$conf['portal']['fixed_blocks'] = array();
+$conf['imsp']['enabled'] = false;
+$conf['kolab']['enabled'] = true;
+$conf['kolab']['server']['driver'] = 'ldap';
+$conf['kolab']['imap']['allow_special_users'] = true;
+$conf['log']['priority'] = PEAR_LOG_DEBUG;
+$conf['log']['ident'] = 'HORDE';
+$conf['log']['params'] = array();
+$conf['log']['name'] = '/tmp/horde.log';
+$conf['log']['params']['append'] = true;
+$conf['log']['type'] = 'file';
+$conf['log']['enabled'] = true;
diff --git a/koward/www/horde/config/hooks.php.dist b/koward/www/horde/config/hooks.php.dist
new file mode 100644 (file)
index 0000000..b3d9bbc
--- /dev/null
@@ -0,0 +1 @@
+<?php
diff --git a/koward/www/horde/config/nls.php.dist b/koward/www/horde/config/nls.php.dist
new file mode 100644 (file)
index 0000000..cf7cb14
--- /dev/null
@@ -0,0 +1,272 @@
+<?php
+/**
+ * NLS (National Language Support) configuration file.
+ *
+ * $Horde: horde/config/nls.php.dist,v 1.77 2008/10/14 21:11:47 jan Exp $
+ */
+
+/**
+ ** Defaults
+ **/
+
+/* The language to fall back on if we cannot determine one any other
+   way (user choice or preferences). If empty, we will try to negotiate
+   with the browser using HTTP_ACCEPT_LANGUAGE. */
+$nls['defaults']['language'] = '';
+
+
+/**
+ ** Language
+ **/
+
+$nls['languages']['ar_OM'] = '&#x202d;Arabic (Oman) &#x202e;(&#x0627;&#x0644;&#x0639;&#x0631;&#x0628;&#x064a;&#x0629;)';
+$nls['languages']['ar_SY'] = '&#x202d;Arabic (Syria) &#x202e;(&#x0627;&#x0644;&#x0639;&#x0631;&#x0628;&#x064a;&#x0629;)';
+$nls['languages']['id_ID'] = 'Bahasa Indonesia';
+$nls['languages']['bs_BA'] = 'Bosanski';
+$nls['languages']['bg_BG'] = '&#x202d;Bulgarian (&#x0411;&#x044a;&#x043b;&#x0433;&#x0430;&#x0440;&#x0441;&#x043a;&#x0438;)';
+$nls['languages']['ca_ES'] = 'Catal&#xe0;';
+$nls['languages']['zh_CN'] = '&#x202d;Chinese (Simplified) (&#x7b80;&#x4f53;&#x4e2d;&#x6587;)';
+$nls['languages']['zh_TW'] = '&#x202d;Chinese (Traditional) (&#x6b63;&#x9ad4;&#x4e2d;&#x6587;)';
+$nls['languages']['cs_CZ'] = '&#x202d;Czech (&#x010c;esky)';
+$nls['languages']['da_DK'] = 'Dansk';
+$nls['languages']['de_DE'] = 'Deutsch';
+$nls['languages']['en_US'] = '&#x202d;English (American)';
+$nls['languages']['en_GB'] = '&#x202d;English (British)';
+$nls['languages']['en_CA'] = '&#x202d;English (Canadian)';
+$nls['languages']['es_ES'] = 'Espa&#xf1;ol';
+$nls['languages']['et_EE'] = 'Eesti';
+$nls['languages']['eu_ES'] = 'Euskara';
+$nls['languages']['fr_FR'] = 'Fran&#xe7;ais';
+$nls['languages']['gl_ES'] = 'Galego';
+$nls['languages']['el_GR'] = '&#x202d;Greek (&#x0395;&#x03bb;&#x03bb;&#x03b7;&#x03bd;&#x03b9;&#x03ba;&#x03ac;)';
+$nls['languages']['he_IL'] = '&#x202d;Hebrew &#x202e;(&#x05E2;&#x05D1;&#x05E8;&#x05D9;&#x05EA;)';
+$nls['languages']['is_IS'] = '&#xcd;slenska';
+$nls['languages']['it_IT'] = 'Italiano';
+$nls['languages']['ja_JP'] = '&#x202d;Japanese (&#x65e5;&#x672c;&#x8a9e;)';
+$nls['languages']['km_KH'] = '&#x202d;Khmer (&#x1781;&#x17d2;&#x1798;&#x17c2;&#x179a;)';
+$nls['languages']['ko_KR'] = '&#x202d;Korean (&#xd55c;&#xad6d;&#xc5b4;)';
+$nls['languages']['lv_LV'] = 'Latvie&#x0161;u';
+$nls['languages']['lt_LT'] = 'Lietuvi&#x0173;';
+$nls['languages']['mk_MK'] = '&#x202d;Macedonian (&#x041c;&#x0430;&#x043a;&#x0435;&#x0434;&#x043e;&#x043d;&#x0441;&#x043a;&#x0438;)';
+$nls['languages']['hu_HU'] = 'Magyar';
+$nls['languages']['nl_NL'] = 'Nederlands';
+$nls['languages']['nb_NO'] = 'Norsk bokm&#xe5;l';
+$nls['languages']['nn_NO'] = 'Norsk nynorsk';
+$nls['languages']['fa_IR'] = '&#x202d;Persian &#x202e;(&#x0641;&#x0627;&#x0631;&#x0633;&#x0649;)';
+$nls['languages']['pl_PL'] = 'Polski';
+$nls['languages']['pt_PT'] = 'Portugu&#xea;s';
+$nls['languages']['pt_BR'] = 'Portugu&#xea;s Brasileiro';
+$nls['languages']['ro_RO'] = 'Rom&#xe2;n&#xe4;';
+$nls['languages']['ru_RU'] = '&#x202d;Russian (&#x0420;&#x0443;&#x0441;&#x0441;&#x043a;&#x0438;&#x0439;)';
+$nls['languages']['sk_SK'] = '&#x202d;Slovak (Sloven&#x010d;ina)';
+$nls['languages']['sl_SI'] = '&#x202d;Slovenian (Sloven&#x0161;&#x010d;ina)';
+$nls['languages']['fi_FI'] = 'Suomi';
+$nls['languages']['sv_SE'] = 'Svenska';
+$nls['languages']['th_TH'] = '&#x202d;Thai (&#x0e44;&#x0e17;&#x0e22;)';
+if (version_compare(PHP_VERSION, '5', 'lt') || version_compare(PHP_VERSION, '6', 'ge')) {
+    $nls['languages']['tr_TR'] = 'T&#xfc;rk&#xe7;e';
+}
+$nls['languages']['uk_UA'] = '&#x202d;Ukrainian (&#x0423;&#x043a;&#x0440;&#x0430;&#x0457;&#x043d;&#x0441;&#x044c;&#x043a;&#x0430;)';
+
+
+/**
+ ** Aliases for languages with different browser and gettext codes
+ **/
+
+$nls['aliases']['ar'] = 'ar_SY';
+$nls['aliases']['bg'] = 'bg_BG';
+$nls['aliases']['bs'] = 'bs_BA';
+$nls['aliases']['ca'] = 'ca_ES';
+$nls['aliases']['cs'] = 'cs_CZ';
+$nls['aliases']['da'] = 'da_DK';
+$nls['aliases']['de'] = 'de_DE';
+$nls['aliases']['el'] = 'el_GR';
+$nls['aliases']['en'] = 'en_US';
+$nls['aliases']['es'] = 'es_ES';
+$nls['aliases']['et'] = 'et_EE';
+$nls['aliases']['fa'] = 'fa_IR';
+$nls['aliases']['fi'] = 'fi_FI';
+$nls['aliases']['fr'] = 'fr_FR';
+$nls['aliases']['gl'] = 'gl_ES';
+$nls['aliases']['he'] = 'he_IL';
+$nls['aliases']['hu'] = 'hu_HU';
+$nls['aliases']['id'] = 'id_ID';
+$nls['aliases']['is'] = 'is_IS';
+$nls['aliases']['it'] = 'it_IT';
+$nls['aliases']['ja'] = 'ja_JP';
+$nls['aliases']['km'] = 'km_KH';
+$nls['aliases']['ko'] = 'ko_KR';
+$nls['aliases']['lt'] = 'lt_LT';
+$nls['aliases']['lv'] = 'lv_LV';
+$nls['aliases']['mk'] = 'mk_MK';
+$nls['aliases']['nl'] = 'nl_NL';
+$nls['aliases']['nn'] = 'nn_NO';
+$nls['aliases']['no'] = 'nb_NO';
+$nls['aliases']['pl'] = 'pl_PL';
+$nls['aliases']['pt'] = 'pt_PT';
+$nls['aliases']['ro'] = 'ro_RO';
+$nls['aliases']['ru'] = 'ru_RU';
+$nls['aliases']['sk'] = 'sk_SK';
+$nls['aliases']['sl'] = 'sl_SI';
+$nls['aliases']['sv'] = 'sv_SE';
+$nls['aliases']['th'] = 'th_TH';
+if (version_compare(PHP_VERSION, '5', 'lt') || version_compare(PHP_VERSION, '6', 'ge')) {
+    $nls['aliases']['tr'] = 'tr_TR';
+}
+$nls['aliases']['uk'] = 'uk_UA';
+
+
+/**
+ ** Charsets. These differ somewhat on different systems; see below
+ ** for a set of BSD charset names.
+ **/
+
+$nls['charsets']['ar_OM'] = 'windows-1256';
+$nls['charsets']['ar_SY'] = 'windows-1256';
+$nls['charsets']['bg_BG'] = 'windows-1251';
+$nls['charsets']['bs_BA'] = 'ISO-8859-2';
+$nls['charsets']['cs_CZ'] = 'ISO-8859-2';
+$nls['charsets']['el_GR'] = 'ISO-8859-7';
+$nls['charsets']['eu_ES'] = 'UTF-8';
+$nls['charsets']['fa_IR'] = 'UTF-8';
+$nls['charsets']['he_IL'] = 'UTF-8';
+$nls['charsets']['hu_HU'] = 'ISO-8859-2';
+$nls['charsets']['ja_JP'] = 'SHIFT_JIS';
+$nls['charsets']['km_KH'] = 'UTF-8';
+$nls['charsets']['ko_KR'] = 'EUC-KR';
+$nls['charsets']['lt_LT'] = 'ISO-8859-13';
+$nls['charsets']['lv_LV'] = 'windows-1257';
+$nls['charsets']['mk_MK'] = 'ISO-8859-5';
+$nls['charsets']['pl_PL'] = 'ISO-8859-2';
+$nls['charsets']['ru_RU'] = 'windows-1251';
+$nls['charsets']['ru_RU.KOI8-R'] = 'KOI8-R';
+$nls['charsets']['sk_SK'] = 'ISO-8859-2';
+$nls['charsets']['sl_SI'] = 'ISO-8859-2';
+$nls['charsets']['th_TH'] = 'TIS-620';
+if (version_compare(PHP_VERSION, '5', 'lt') || version_compare(PHP_VERSION, '6', 'ge')) {
+    $nls['charsets']['tr_TR'] = 'ISO-8859-9';
+}
+$nls['charsets']['uk_UA'] = 'windows-1251';
+$nls['charsets']['zh_CN'] = 'GB2312';
+$nls['charsets']['zh_TW'] = 'BIG5';
+
+/**
+ * BSD charsets.
+ */
+if (strpos(PHP_OS, 'BSD') !== false) {
+    $nls['charsets']['ar_OM'] = 'windows-1256';
+    $nls['charsets']['ar_SY'] = 'windows-1256';
+    $nls['charsets']['bg_BG'] = 'windows-1251';
+    $nls['charsets']['bs_BA'] = 'ISO8859-2';
+    $nls['charsets']['cs_CZ'] = 'ISO8859-2';
+    $nls['charsets']['el_GR'] = 'ISO8859-7';
+    $nls['charsets']['eu_ES'] = 'UTF-8';
+    $nls['charsets']['fa_IR'] = 'UTF-8';
+    $nls['charsets']['he_IL'] = 'UTF-8';
+    $nls['charsets']['hu_HU'] = 'ISO8859-2';
+    $nls['charsets']['ja_JP'] = 'SHIFT_JIS';
+    $nls['charsets']['km_KH'] = 'UTF-8';
+    $nls['charsets']['ko_KR'] = 'EUC-KR';
+    $nls['charsets']['lt_LT'] = 'ISO8859-13';
+    $nls['charsets']['lv_LV'] = 'windows-1257';
+    $nls['charsets']['mk_MK'] = 'ISO8859-5';
+    $nls['charsets']['pl_PL'] = 'ISO8859-2';
+    $nls['charsets']['ru_RU'] = 'windows-1251';
+    $nls['charsets']['ru_RU.KOI8-R'] = 'KOI8-R';
+    $nls['charsets']['sk_SK'] = 'ISO8859-2';
+    $nls['charsets']['sl_SI'] = 'ISO8859-2';
+    $nls['charsets']['th_TH'] = 'TIS-620';
+    if (version_compare(PHP_VERSION, '5', 'lt') ||
+        version_compare(PHP_VERSION, '6', 'ge')) {
+        $nls['charsets']['tr_TR'] = 'ISO-8859-9';
+    }
+    $nls['charsets']['uk_UA'] = 'windows-1251';
+    $nls['charsets']['zh_CN'] = 'GB2312';
+    $nls['charsets']['zh_TW'] = 'BIG5';
+}
+
+
+/**
+ ** Multibyte charsets
+ **/
+
+$nls['multibyte']['BIG5'] = true;
+$nls['multibyte']['EUC-KR'] = true;
+$nls['multibyte']['GB2312'] = true;
+$nls['multibyte']['SHIFT_JIS'] = true;
+$nls['multibyte']['UTF-8'] = true;
+
+
+/**
+ ** Right-to-left languages
+ **/
+
+$nls['rtl']['ar_OM'] = true;
+$nls['rtl']['ar_SY'] = true;
+$nls['rtl']['fa_IR'] = true;
+$nls['rtl']['he_IL'] = true;
+
+
+/**
+ ** Preferred charsets for email traffic if not the languages' default
+ ** charsets.
+ **/
+
+$nls['emails']['ja_JP'] = 'ISO-2022-JP';
+
+
+/**
+ ** Available charsets for outgoing email traffic.
+ **/
+
+$nls['encodings']['windows-1256'] = _("Arabic (Windows-1256)");
+$nls['encodings']['ARMSCII-8'] = _("Armenian (ARMSCII-8)");
+$nls['encodings']['ISO-8859-13'] = _("Baltic (ISO-8859-13)");
+$nls['encodings']['ISO-8859-14'] = _("Celtic (ISO-8859-14)");
+$nls['encodings']['ISO-8859-2'] = _("Central European (ISO-8859-2)");
+$nls['encodings']['GB2312'] = _("Chinese Simplified (GB2312)");
+$nls['encodings']['BIG5'] = _("Chinese Traditional (Big5)");
+$nls['encodings']['KOI8-R'] = _("Cyrillic (KOI8-R)");
+$nls['encodings']['windows-1251'] = _("Cyrillic (Windows-1251)");
+$nls['encodings']['KOI8-U'] = _("Cyrillic/Ukrainian (KOI8-U)");
+$nls['encodings']['ISO-8859-7'] = _("Greek (ISO-8859-7)");
+$nls['encodings']['ISO-8859-8-I'] = _("Hebrew (ISO-8859-8-I)");
+$nls['encodings']['ISO-2022-JP'] = _("Japanese (ISO-2022-JP)");
+$nls['encodings']['EUC-KR'] = _("Korean (EUC-KR)");
+$nls['encodings']['ISO-8859-10'] = _("Nordic (ISO-8859-10)");
+$nls['encodings']['ISO-8859-3'] = _("South European (ISO-8859-3)");
+$nls['encodings']['TIS-620'] = _("Thai (TIS-620)");
+$nls['encodings']['ISO-8859-9'] = _("Turkish (ISO-8859-9)");
+$nls['encodings']['UTF-8'] = _("Unicode (UTF-8)");
+$nls['encodings']['VISCII'] = _("Vietnamese (VISCII)");
+$nls['encodings']['ISO-8859-1'] = _("Western (ISO-8859-1)");
+$nls['encodings']['ISO-8859-15'] = _("Western (ISO-8859-15)");
+asort($nls['encodings']);
+
+
+/**
+ ** Multi-language spelling support
+ **/
+
+$nls['spelling']['cs_CZ'] = '-T latin2 -d czech';
+$nls['spelling']['da_DK'] = '-d dansk';
+$nls['spelling']['de_DE'] = '-T latin1 -d deutsch';
+$nls['spelling']['el_GR'] = '-T latin1 -d ellinika';
+$nls['spelling']['en_CA'] = '-d canadian';
+$nls['spelling']['en_GB'] = '-d british';
+$nls['spelling']['en_US'] = '-d american';
+$nls['spelling']['es_ES'] = '-d espanol';
+$nls['spelling']['fr_FR'] = '-d francais';
+$nls['spelling']['it_IT'] = '-T latin1 -d italian';
+$nls['spelling']['nl_NL'] = '-d nederlands';
+$nls['spelling']['pl_PL'] = '-d polish';
+$nls['spelling']['pt_BR'] = '-d br';
+$nls['spelling']['pt_PT'] = '-T latin1 -d portuguese';
+$nls['spelling']['ru_RU'] = '-d russian';
+$nls['spelling']['sl_SI'] = '-d slovensko';
+$nls['spelling']['sv_SE'] = '-d svenska';
+if (isset($nls['charsets']['tr_TR'])) {
+    $nls['spelling']['tr_TR'] = '-d tr';
+}
+
+$GLOBALS['nls'] = &$nls;
diff --git a/koward/www/horde/config/prefs.php.dist b/koward/www/horde/config/prefs.php.dist
new file mode 100644 (file)
index 0000000..430237f
--- /dev/null
@@ -0,0 +1,589 @@
+<?php
+/**
+ * $Horde: horde/config/prefs.php.dist,v 1.108 2009/03/02 01:23:06 mrubinsk Exp $
+ *
+ * Preferences Information
+ * =======================
+ * Changes you make to the prefs.php file(s) will not be reflected until the
+ * user logs out and logs in again.
+ *
+ * If you change these preferences in a production system, you will
+ * need to delete any horde_prefs in your preferences database.
+ *
+ * prefGroups array
+ * ----------------
+ * $prefGroups are for display purposes when you press the options button.
+ * The options choice will appear when you set your preferences driver
+ * in the horde/config/conf.php file.
+ *
+ * $prefGroups array definition:
+ *    column:  What column head this group will go under
+ *     label:  Label for the group of settings
+ *      desc:  Description that will show under label
+ *   members:  List of preferences supported by this group
+ *
+ * _prefs array
+ * ------------
+ * The $_prefs array's are listed in the same order as listed in the
+ * members element of $prefGroups.
+ *
+ *   value: This entry will hold the default preference value depending on the
+ *          preference type:
+ *            checkbox:  0 or false for unchecked, 1 or true for checked
+ *                enum:  Preselected item from associated enumeration
+ *            implicit:  See Preference type
+ *                link:  Not used
+ *              number:  Number value
+ *            password:  Should be ''
+ *              select:  Preselected item from associated selection list
+ *             special:  Not used
+ *                text:  Text value
+ *            textarea:  Text value, lines separated with "\n"
+ *
+ *  locked: Allow preference to be changed from UI
+ *             true:  Do not show this preference in the UI.
+ *                    This has no effect on 'link' type preferences.
+ *            false:  Show this preference in the UI and allow changing.
+ *
+ *  shared: Share with other horde apps
+ *             true:  Share this pref with other Horde apps
+ *            false:  Keep this pref local to the current app
+ *
+ *    type: Preference type
+ *            checkbox:  Provides a checkbox.
+ *                enum:  Provides a selection list in the UI, list is
+ *                       specified in the associated 'enum' setting.
+ *            implicit:  Provides storage for 'special' types.
+ *                link:  Provides a link to another data entry form.
+ *              number:  Provides a 3-character textbox to enter a natural
+ *                       number; syntaxcheck is performed after data entry.
+ *            password:  Provides a textbox for password entry.
+ *              select:  Provides a selection list in the UI that is built in
+ *                       lib/prefs.php.
+ *             special:  Provides an UI widget.
+ *                text:  Provides a single-line textbox.
+ *            textarea:  Provides a multi-line textbox.
+ *
+ *    enum: Static list of elements for 'type' => 'enum'.
+ *
+ * escaped: For an enum or a select, are the keys and values already
+ *          html-escaped? Defaults to false if not present.
+ *
+ *    hook: Call a hook function for the value of this preference
+ *             true:  Will call the function _prefs_hook_<prefname>
+ *                    to fill in the value of this preference.
+ *                    See hooks.php for more details.
+ *            false:  Normal behaviour - no hook is called.
+ */
+
+$prefGroups['identities'] = array(
+    'column' => _("Your Information"),
+    'label' => _("Personal Information"),
+    'desc' => _("Change the name and address that people see when they read and reply to your emails."),
+    'members' => array('default_identity', 'identityselect', 'deleteidentity',
+                       'id', 'fullname', 'from_addr')
+);
+
+$prefGroups['authentication'] = array(
+    'column' => _("Your Information"),
+    'label' => _("Authentication Credentials"),
+    'desc' => _("Set authentication credentials like user names and passwords for external servers."),
+    'members' => array('credentialsui'),
+);
+
+$auth = &Auth::singleton($GLOBALS['conf']['auth']['driver']);
+if (is_a($auth, 'Auth') && $auth->hasCapability('update')) {
+    $prefGroups['forgotpass'] = array(
+        'column' => _("Your Information"),
+        'label' => _("Account Password"),
+        'desc' => _("Set options to allow you to reset your password if you ever forget it."),
+        'members' => array('security_question', 'security_answer', 'alternate_email')
+    );
+}
+
+$prefGroups['language'] = array(
+    'column' => _("Your Information"),
+    'label' => _("Locale and Time"),
+    'desc' => _("Set your preferred language, timezone and date options."),
+    'members' => array('language', 'timezone', 'twentyFour', 'date_format', 'first_week_day')
+);
+
+$prefGroups['categories'] = array(
+    'column' => _("Your Information"),
+    'label' => _("Categories and Labels"),
+    'desc' => _("Manage the list of categories you have to label items with, and colors associated with those categories."),
+    'members' => array('categorymanagement')
+);
+
+$prefGroups['display'] = array(
+    'column' => _("Other Information"),
+    'label' => _("Display Options"),
+    'desc' => _("Set your startup application, color scheme, page refreshing, and other display options."),
+    'members' => array('initial_application', 'show_last_login', 'theme',
+                       'summary_refresh_time', 'show_sidebar', 'sidebar_width',
+                       'moz_sidebar', 'menu_view', 'menu_refresh_time',
+                       'widget_accesskey')
+);
+
+$prefGroups['logintasks'] = array(
+    'column' => _("Other Information"),
+    'label' => _("Login Tasks"),
+    'desc' => sprintf(_("Customize tasks to run upon logon to %s."), $GLOBALS['registry']->get('name')),
+    'members' => array('do_maintenance', 'confirm_maintenance')
+);
+
+$prefGroups['remote'] = array(
+    'column' => _("Other Information"),
+    'label' => _("Remote Servers"),
+    'desc' => _("Set up remote servers that you want to access from your portal."),
+    'url' => 'services/portal/rpcsum.php'
+);
+
+if (!empty($GLOBALS['conf']['facebook']['key']) && !empty($GLOBAL['conf']['facebook']['secret'])) {
+    $prefGroups['facebook'] = array(
+        'column' => _("Other Information"),
+        'label' => _("Facebook Integration"),
+        'desc' => _("Set up integration with your Facebook account."),
+        'url' => 'services/facebook.php'
+    );
+}
+
+// For alternate IMSP authentication.
+if (!empty($GLOBALS['conf']['imsp']['enabled'])) {
+    $prefGroups['imspauth'] = array(
+        'column' => _("Other Information"),
+        'label' => _("Alternate IMSP Login"),
+        'desc' => _("Use if name/password is different for IMSP server."),
+        'members' => array('imsp_auth_user', 'imsp_auth_pass')
+    );
+}
+
+// Determine functionality of richtext editor
+$prefGroups['richtext'] = array(
+    'column' => _("Other Information"),
+    'label' => _("Rich Text Editor Options"),
+    'desc' => _("Which plugins to enable for the Rich Text editor."),
+    'members' => array('editor_plugins'),
+);
+
+$prefGroups['syncml'] = array(
+    'column' => _("Other Information"),
+    'label' => _("SyncML"),
+    'desc' => _("Configuration for syncing with PDAs, Smartphones and Outlook."),
+    'url' => 'services/portal/syncml.php',
+    'members' => array()
+);
+
+// Personal Information preferences
+
+// default identity
+// Set locked to true if you don't want the users to have multiple identities.
+$_prefs['default_identity'] = array(
+    'value' => 0,
+    'locked' => false,
+    'shared' => true,
+    'type' => 'enum',
+    'enum' => (isset($GLOBALS['identity']) && is_object($GLOBALS['identity'])) ? $GLOBALS['identity']->getAll('id') : array(),
+    'desc' => _("Your default identity:"),
+);
+
+// identities array
+// Don't change anything here.
+$_prefs['identities'] = array(
+    'value' => 'a:0:{}',
+    'locked' => false,
+    'shared' => true,
+    'type' => 'implicit',
+);
+
+// identify email confirmation
+$_prefs['confirm_email'] = array(
+    'value' => 'a:0:{}',
+    'locked' => false,
+    'shared' => true,
+    'type' => 'implicit',
+);
+
+// identity selection widget
+$_prefs['identityselect'] = array(
+    'shared' => true,
+    'type' => 'special',
+);
+
+// delete button
+$_prefs['deleteidentity'] = array(
+    'type' => 'special',
+    'shared' => true,
+);
+
+// identity name
+// If you lock this preference, you must specify a value or a hook for it in
+// horde/config/hooks.php.
+$_prefs['id'] = array(
+    'value' => '',
+    'locked' => false,
+    'shared' => true,
+    'type' => 'text',
+    'desc' => _("Identity's name:")
+);
+
+// user full name for From: line
+// If you lock this preference, you must specify a value or a hook for it in
+// horde/config/hooks.php.
+$_prefs['fullname'] = array(
+    'value' => '',
+    'locked' => false,
+    'shared' => true,
+    'type' => 'text',
+    'desc' => _("Your full name:")
+);
+
+// user preferred email address for From: line
+// If you lock this preference, you must specify a value or a hook for it in
+// horde/config/hooks.php.
+$_prefs['from_addr'] = array(
+    'value' => '',
+    'locked' => false,
+    'shared' => true,
+    'type' => 'text',
+    'desc' =>  _("Your From: address:")
+);
+
+// Authentication Options
+
+// credentials
+$_prefs['credentials'] = array(
+    'value' => 'a:0:{}',
+    'locked' => false,
+    'shared' => true,
+    'type' => 'implicit'
+);
+
+// credentials interface
+$_prefs['credentialsui'] = array(
+    'shared' => true,
+    'type' => 'special',
+);
+
+// user security question
+$_prefs['security_question'] = array(
+    'value' => '',
+    'locked' => false,
+    'shared' => true,
+    'type' => 'text',
+    'desc' => _("Enter a security question which you will be asked if you need to reset your password, e.g. 'what is the name of your pet?':")
+);
+
+// user security answer
+$_prefs['security_answer'] = array(
+    'value' => '',
+    'locked' => false,
+    'shared' => true,
+    'type' => 'text',
+    'desc' => _("Insert the required answer to the security question:")
+);
+
+// user alternate email
+$_prefs['alternate_email'] = array(
+    'value' => '',
+    'locked' => false,
+    'shared' => true,
+    'type' => 'text',
+    'desc' => _("Insert an email address to which you can receive the new password:")
+);
+
+// user language
+$_prefs['language'] = array(
+    'value' => '',
+    'locked' => false,
+    'shared' => true,
+    'type' => 'select',
+    'escaped' => true,
+    'desc' => _("Select your preferred language:")
+);
+
+// user time zone
+$_prefs['timezone'] = array(
+    'value' => '',
+    'locked' => false,
+    'shared' => true,
+    'type' => 'select',
+    'desc' => _("Your current time zone:")
+);
+
+// time format
+$_prefs['twentyFour'] = array(
+    'value' => false,
+    'locked' => false,
+    'shared' => true,
+    'type' => 'checkbox',
+    'desc' => _("Display 24-hour times?")
+);
+
+// date format
+$_prefs['date_format'] = array(
+    'value' => '%x',
+    'locked' => false,
+    'shared' => true,
+    'type' => 'enum',
+    'enum' => array(
+        '%x' => strftime('%x'),
+        '%Y-%m-%d' => strftime('%Y-%m-%d'),
+        '%d/%m/%Y' => strftime('%d/%m/%Y'),
+        '%A %B %d, %Y' => strftime('%A %B %d, %Y'),
+        '%A, %d. %B %Y' => strftime('%A, %d. %B %Y'),
+        '%A, %d %B %Y' => strftime('%A, %d %B %Y'),
+        '%a, %b %e, %Y' => strftime('%a, %b %e, %Y'),
+        '%a, %b %e, %y' => strftime('%a, %b %e, %y'),
+        '%a, %b %e' => strftime('%a, %b %e'),
+        '%a, %e %b %Y' => strftime('%a, %e %b %Y'),
+        '%a, %e %b %y' => strftime('%a, %e %b %y'),
+        '%a %d %b %Y' => strftime ('%a %d %b %Y'),
+        '%a %x' => strftime ('%a %x'),
+        '%a %Y-%m-%d' => strftime ('%a %Y-%m-%d'),
+        '%e %b %Y' => strftime('%e %b %Y'),
+        '%e. %b %Y' => strftime('%e. %b %Y'),
+        '%e. %m %Y' => strftime('%e %m %Y'),
+        '%e. %m.' => strftime('%e. %m.'),
+        '%e. %B' => strftime('%e. %B'),
+        '%e. %B %Y' => strftime('%e. %B %Y'),
+        '%e. %B %y' => strftime('%e. %B %y'),
+        '%B %e, %Y' => strftime('%B %e, %Y'),
+    ),
+    'desc' => _("Choose how to display dates:"),
+);
+
+// what day should be displayed as the first day of the week?
+$_prefs['first_week_day'] = array(
+    'value' => '0',
+    'locked' => false,
+    'shared' => true,
+    'type' => 'enum',
+    'desc' => _("Which day would you like to be displayed as the first day of the week?"),
+    'enum' => array('0' => _("Sunday"),
+                    '1' => _("Monday"))
+);
+
+// UI theme
+$_prefs['theme'] = array(
+    'value' => 'bluewhite',
+    'locked' => false,
+    'shared' => true,
+    'type' => 'select',
+    'desc' => _("Select your color scheme.")
+);
+
+// categories
+$_prefs['categories'] = array(
+    'value' => '',
+    'locked' => false,
+    'shared' => true,
+    'type' => 'implicit'
+);
+
+// category colors
+$_prefs['category_colors'] = array(
+    'value' => '',
+    'locked' => false,
+    'shared' => true,
+    'type' => 'implicit'
+);
+
+// UI for category management.
+$_prefs['categorymanagement'] = array(
+    'type' => 'special'
+);
+
+$_prefs['summary_refresh_time'] = array(
+    'value' => 300,
+    'locked' => false,
+    'shared' => false,
+    'type' => 'enum',
+    'enum' => array(0 => _("Never"),
+                    30 => _("Every 30 seconds"),
+                    60 => _("Every minute"),
+                    300 => _("Every 5 minutes"),
+                    900 => _("Every 15 minutes"),
+                    1800 => _("Every half hour")),
+    'desc' => _("Refresh Portal View:")
+);
+
+$_prefs['show_sidebar'] = array(
+    'value' => true,
+    'locked' => false,
+    'shared' => true,
+    'type' => 'checkbox',
+    'desc' => sprintf(_("Show the %s Menu on the left?"), $GLOBALS['registry']->get('name', 'horde'))
+);
+
+$_prefs['sidebar_width'] = array(
+    'value' => 150,
+    'locked' => false,
+    'shared' => false,
+    'type' => 'number',
+    'desc' => sprintf(_("Width of the %s menu on the left:"), $GLOBALS['registry']->get('name', 'horde'))
+);
+
+$_prefs['moz_sidebar'] = array(
+    'type' => 'link',
+    'xurl' => sprintf('javascript:if (window.sidebar && window.sidebar.addPanel) window.sidebar.addPanel(\'%s\', \'%s\', \'%s\'); else alert(\'%s\');',
+                      $GLOBALS['registry']->get('name', 'horde'),
+                      Util::addParameter(Horde::url($GLOBALS['registry']->get('webroot', 'horde') . '/services/portal/sidebar.php', true, -1), 'mozbar', '1'),
+                      Horde::url($GLOBALS['registry']->get('webroot', 'horde') . '/prefs.php', true, -1),
+                      addslashes(_("Couldn't find the Mozilla Sidebar. Make sure the sidebar is open."))),
+    'desc' => sprintf(_("Add the %s Menu as a Mozilla Sidebar"), $GLOBALS['registry']->get('name', 'horde'))
+);
+
+$_prefs['menu_view'] = array(
+    'value' => 'both',
+    'locked' => false,
+    'shared' => true,
+    'type' => 'enum',
+    'enum' => array('text' => _("Text Only"),
+                    'icon' => _("Icons Only"),
+                    'both' => _("Icons with text")),
+    'desc' => _("Menu mode:")
+);
+
+$_prefs['menu_refresh_time'] = array(
+    'value' => 300,
+    'locked' => false,
+    'shared' => true,
+    'type' => 'enum',
+    'enum' => array(0 => _("Never"),
+                    30 => _("Every 30 seconds"),
+                    60 => _("Every minute"),
+                    120 => _("Every 2 minutes"),
+                    300 => _("Every 5 minutes")),
+    'desc' => _("Refresh Dynamic Menu Elements:")
+);
+
+
+// Login/Maintenance Tasks preferences
+
+// To disable maintenance entirely, set 'value' = false and
+// 'locked' = true for all of these. To just turn it off by default,
+// set 'value' false for do_maintenance.
+// perform maintenance operations?
+$_prefs['do_maintenance'] = array(
+    'value' => true,
+    'locked' => false,
+    'shared' => true,
+    'type' => 'checkbox',
+    'desc' => _("Perform maintenance operations on login?"),
+    'help' => 'prefs-do_maintenance');
+
+// last time maintenance was run.
+// value is a UNIX timestamp of the last time maintenance ran for the user.
+$_prefs['last_maintenance'] = array(
+    'value' => 0,
+    'locked' => false,
+    'shared' => true,
+    'type' => 'implicit'
+);
+
+// confirm when doing maintenance operations? If false, they will
+// be performed with no input from/check with the user.
+$_prefs['confirm_maintenance'] = array(
+    'value' => true,
+    'locked' => false,
+    'shared' => true,
+    'type' => 'checkbox',
+    'desc' => _("Ask for confirmation before doing maintenance operations?"),
+    'help' => 'prefs-confirm_maintenance');
+
+// End Login/Maintenance preferences
+
+
+// what application should we go to after login?
+$_prefs['initial_application'] = array(
+    'value' => 'horde',
+    'locked' => false,
+    'shared' => true,
+    'type' => 'select',
+    'desc' => sprintf(_("What application should %s display after login?"), $GLOBALS['registry']->get('name'))
+);
+
+// should we create access keys?
+$_prefs['widget_accesskey'] = array(
+    'value' => true,
+    'locked' => false,
+    'shared' => true,
+    'type' => 'checkbox',
+    'desc' => _("Should access keys be defined for most links?")
+);
+
+// the layout of the portal page.
+$_prefs['portal_layout'] = array(
+    'value' => 'a:0:{}',
+    'locked' => false,
+    'shared' => false,
+    'type' => 'implicit'
+);
+
+// the remote servers.
+$_prefs['remote_summaries'] = array(
+    'value' => 'a:0:{}',
+    'locked' => false,
+    'shared' => false,
+    'type' => 'implicit'
+);
+
+$_prefs['facebook'] = array(
+    'value' => 'a:0:{}',
+    'locked' => false,
+    'shared' => true,
+    'type' => 'implicit');
+    
+// last login time of user
+// value is a serialized array of the UNIX timestamp of the last
+// login, and the host that the last login was from.
+$_prefs['last_login'] = array(
+    'value' => 'a:0:{}',
+    'locked' => false,
+    'shared' => true,
+    'type' => 'implicit'
+);
+
+// show the last login time of user
+$_prefs['show_last_login'] = array(
+    'value' => true,
+    'locked' => false,
+    'shared' => true,
+    'type' => 'checkbox',
+    'desc' => _("Show last login time when logging in?")
+);
+
+if (!empty($GLOBALS['conf']['imsp']['enabled'])) {
+    $_prefs['imsp_auth_user'] = array(
+        'value' => '',
+        'locked' => false,
+        'shared' => false,
+        'type' => 'text',
+        'desc' => _("Alternate IMSP Username")
+    );
+
+    $_prefs['imsp_auth_pass'] = array(
+        'value' => '',
+        'locked' => false,
+        'shared' => false,
+        'type' => 'password',
+        'desc' => _("Alternate IMSP Password")
+    );
+}
+
+// Rich Text Editor preferences.
+$_prefs['editor_plugins'] = array(
+    'value' => 'a:2:{i:0;s:8:"ListType";i:1;s:12:"CharacterMap";}',
+    'locked' => false,
+    'shared' => true,
+    'type' => 'multienum',
+    'enum' => array(
+        'ContextMenu' => _("Right click context menu"),
+        'TableOperations' => _("Table operations menu bar"),
+        'ListType' => _("Allow setting of ordered list type"),
+        'CharacterMap' => _("Special characters"),
+        'AnselImage' => _("Insertion of images from Photo Galleries in text")),
+    'desc' => _("Select editor plugins")
+);
+// End Rich Text Editor preferences.
diff --git a/koward/www/horde/config/registry.d/README b/koward/www/horde/config/registry.d/README
new file mode 100644 (file)
index 0000000..7a5c5cd
--- /dev/null
@@ -0,0 +1,9 @@
+This directory can hold registry configuration snippets. Any PHP file (*.php)
+is read; all other files are ignored and so are for information only. Snippets
+can contain anything that would go in registry.php - one or more applications,
+tree blocks, conditionals, etc.
+
+Scripts that install or update files in this directory should always touch()
+the registry.d directory after completion to ensure that its modification time
+has changed; that way Horde will know to drop any cached configuration
+information.
diff --git a/koward/www/horde/config/registry.php.dist b/koward/www/horde/config/registry.php.dist
new file mode 100644 (file)
index 0000000..a10117e
--- /dev/null
@@ -0,0 +1,66 @@
+<?php
+/**
+ * registry.php -- Horde application registry.
+ *
+ * $Horde: horde/config/registry.php.dist,v 1.306 2009/01/14 20:51:07 chuck Exp $
+ *
+ * This configuration file is used by Horde to determine which Horde
+ * applications are installed and where, as well as how they interact.
+ *
+ * Application registry
+ * --------------------
+ * The following settings register installed Horde applications.
+ * By default, Horde assumes that the application directories live
+ * inside the horde directory.
+ *
+ * Attribute     Type     Description
+ * ---------     ----     -----------
+ * fileroot      string   The base filesystem path for the module's files.
+ * webroot       string   The base URI for the module.
+ * jsuri         string   The base URI for static javascript files.
+ * jsfs          string   The base filesystem path for static javascript files.
+ * themesuri     string   The base URI for the themes. This can be used to
+ *                        serve all icons and style sheets from a separate
+ *                        server.
+ * themesfs      string   The base file system directory for the themes.
+ * icon          string   The URI for an icon to show in menus for the module.
+ *                        Setting this will override the default theme-based
+ *                        logic in the code.
+ * name          string   The name used in menus and descriptions for a module
+ * status        string   'inactive', 'hidden', 'notoolbar', 'heading',
+ *                        'block', 'admin', or 'active'.
+ * provides      string   Service types the module provides.
+ * initial_page  string   The initial (default) page (filename) for the module.
+ * templates     string   The filesystem path to the templates directory.
+ * menu_parent   string   The name of the 'heading' group that this app should
+ *                        show up under.
+ * target        string   The (optional) target frame for the link.
+ * url           string   The (optional) URL of 'heading' entries.
+ */
+
+// We try to automatically determine the proper webroot for Horde here. This
+// still assumes that applications live under horde/. If this results in
+// incorrect results for you, simply change the 'webroot' setting in the
+// 'horde' stanza below.
+
+$this->applications['horde'] = array(
+    'fileroot' => dirname(__FILE__) . '/..',
+    'webroot' => '/horde',
+    'initial_page' => 'login.php',
+    'name' => _("Horde"),
+    'status' => 'active',
+    'templates' => dirname(__FILE__) . '/../templates',
+    'provides' => 'horde',
+    'themesuri' => '/horde/themes',
+    'themesfs' => dirname(__FILE__) . '/../../htdocs/horde/themes',
+);
+
+$this->applications['koward'] = array(
+    'fileroot' => dirname(__FILE__) . '/../../koward',
+    'webroot' => '/koward',
+    'name' => _("Koward"),
+    'status' => 'active',
+    'initial_page' => 'index',
+    'themesuri' => '/koward/themes',
+    'themesfs' => dirname(__FILE__) . '/../../htdocs/koward/themes',
+);
diff --git a/koward/www/htdocs/horde/js/accesskeys.js b/koward/www/htdocs/horde/js/accesskeys.js
new file mode 100644 (file)
index 0000000..cf565f4
--- /dev/null
@@ -0,0 +1,46 @@
+/**
+ * Accesskeys javascript file.
+ *
+ * See the enclosed file COPYING for license information (LGPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
+ */
+var AccessKeys = {
+
+    macos: navigator.appVersion.indexOf("Mac") !=- 1,
+
+    keydownHandler: function(e)
+    {
+        var elt, elts, evt, key;
+
+        if ((this.macos && e.ctrlKey) ||
+            (!this.macos && e.altKey && !e.ctrlKey)) {
+            // Need to search for both upper and lowercase value
+            key = String.fromCharCode(e.keyCode || e.charCode);
+            elts = $$('[accesskey="' + key.toUpperCase() + '"]').concat($$('[accesskey="' + key.toLowerCase() + '"]'));
+
+            if (elt = elts.first()) {
+                // Remove duplicate accesskeys
+                if (elts.size() > 1) {
+                    elts.slice(1).invoke('writeAttribute', 'accesskey', null);
+                }
+
+                e.stop();
+
+                // Trigger a mouse event on the accesskey element.
+                if (elt.tagName == 'INPUT') {
+                    // NOOP
+                } else if (elt.match('A') && elt.onclick) {
+                    elt.onclick();
+                } else if (document.createEvent) {
+                    evt = document.createEvent('MouseEvents');
+                    evt.initMouseEvent('click', true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
+                    elt.dispatchEvent(evt);
+                } else {
+                    elt.fireEvent('onclick');
+                }
+            }
+        }
+    }
+};
+
+document.observe('keydown', AccessKeys.keydownHandler.bindAsEventListener(AccessKeys));
diff --git a/koward/www/htdocs/horde/js/effects.js b/koward/www/htdocs/horde/js/effects.js
new file mode 100644 (file)
index 0000000..5a639d2
--- /dev/null
@@ -0,0 +1,1128 @@
+// Copyright (c) 2005-2008 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
+// Contributors:
+//  Justin Palmer (http://encytemedia.com/)
+//  Mark Pilgrim (http://diveintomark.org/)
+//  Martin Bialasinki
+//
+// script.aculo.us is freely distributable under the terms of an MIT-style license.
+// For details, see the script.aculo.us web site: http://script.aculo.us/
+
+// converts rgb() and #xxx to #xxxxxx format,
+// returns self (or first argument) if not convertable
+String.prototype.parseColor = function() {
+  var color = '#';
+  if (this.slice(0,4) == 'rgb(') {
+    var cols = this.slice(4,this.length-1).split(',');
+    var i=0; do { color += parseInt(cols[i]).toColorPart() } while (++i<3);
+  } else {
+    if (this.slice(0,1) == '#') {
+      if (this.length==4) for(var i=1;i<4;i++) color += (this.charAt(i) + this.charAt(i)).toLowerCase();
+      if (this.length==7) color = this.toLowerCase();
+    }
+  }
+  return (color.length==7 ? color : (arguments[0] || this));
+};
+
+/*--------------------------------------------------------------------------*/
+
+Element.collectTextNodes = function(element) {
+  return $A($(element).childNodes).collect( function(node) {
+    return (node.nodeType==3 ? node.nodeValue :
+      (node.hasChildNodes() ? Element.collectTextNodes(node) : ''));
+  }).flatten().join('');
+};
+
+Element.collectTextNodesIgnoreClass = function(element, className) {
+  return $A($(element).childNodes).collect( function(node) {
+    return (node.nodeType==3 ? node.nodeValue :
+      ((node.hasChildNodes() && !Element.hasClassName(node,className)) ?
+        Element.collectTextNodesIgnoreClass(node, className) : ''));
+  }).flatten().join('');
+};
+
+Element.setContentZoom = function(element, percent) {
+  element = $(element);
+  element.setStyle({fontSize: (percent/100) + 'em'});
+  if (Prototype.Browser.WebKit) window.scrollBy(0,0);
+  return element;
+};
+
+Element.getInlineOpacity = function(element){
+  return $(element).style.opacity || '';
+};
+
+Element.forceRerendering = function(element) {
+  try {
+    element = $(element);
+    var n = document.createTextNode(' ');
+    element.appendChild(n);
+    element.removeChild(n);
+  } catch(e) { }
+};
+
+/*--------------------------------------------------------------------------*/
+
+var Effect = {
+  _elementDoesNotExistError: {
+    name: 'ElementDoesNotExistError',
+    message: 'The specified DOM element does not exist, but is required for this effect to operate'
+  },
+  Transitions: {
+    linear: Prototype.K,
+    sinoidal: function(pos) {
+      return (-Math.cos(pos*Math.PI)/2) + .5;
+    },
+    reverse: function(pos) {
+      return 1-pos;
+    },
+    flicker: function(pos) {
+      var pos = ((-Math.cos(pos*Math.PI)/4) + .75) + Math.random()/4;
+      return pos > 1 ? 1 : pos;
+    },
+    wobble: function(pos) {
+      return (-Math.cos(pos*Math.PI*(9*pos))/2) + .5;
+    },
+    pulse: function(pos, pulses) {
+      return (-Math.cos((pos*((pulses||5)-.5)*2)*Math.PI)/2) + .5;
+    },
+    spring: function(pos) {
+      return 1 - (Math.cos(pos * 4.5 * Math.PI) * Math.exp(-pos * 6));
+    },
+    none: function(pos) {
+      return 0;
+    },
+    full: function(pos) {
+      return 1;
+    }
+  },
+  DefaultOptions: {
+    duration:   1.0,   // seconds
+    fps:        100,   // 100= assume 66fps max.
+    sync:       false, // true for combining
+    from:       0.0,
+    to:         1.0,
+    delay:      0.0,
+    queue:      'parallel'
+  },
+  tagifyText: function(element) {
+    var tagifyStyle = 'position:relative';
+    if (Prototype.Browser.IE) tagifyStyle += ';zoom:1';
+
+    element = $(element);
+    $A(element.childNodes).each( function(child) {
+      if (child.nodeType==3) {
+        child.nodeValue.toArray().each( function(character) {
+          element.insertBefore(
+            new Element('span', {style: tagifyStyle}).update(
+              character == ' ' ? String.fromCharCode(160) : character),
+              child);
+        });
+        Element.remove(child);
+      }
+    });
+  },
+  multiple: function(element, effect) {
+    var elements;
+    if (((typeof element == 'object') ||
+        Object.isFunction(element)) &&
+       (element.length))
+      elements = element;
+    else
+      elements = $(element).childNodes;
+
+    var options = Object.extend({
+      speed: 0.1,
+      delay: 0.0
+    }, arguments[2] || { });
+    var masterDelay = options.delay;
+
+    $A(elements).each( function(element, index) {
+      new effect(element, Object.extend(options, { delay: index * options.speed + masterDelay }));
+    });
+  },
+  PAIRS: {
+    'slide':  ['SlideDown','SlideUp'],
+    'blind':  ['BlindDown','BlindUp'],
+    'appear': ['Appear','Fade']
+  },
+  toggle: function(element, effect) {
+    element = $(element);
+    effect = (effect || 'appear').toLowerCase();
+    var options = Object.extend({
+      queue: { position:'end', scope:(element.id || 'global'), limit: 1 }
+    }, arguments[2] || { });
+    Effect[element.visible() ?
+      Effect.PAIRS[effect][1] : Effect.PAIRS[effect][0]](element, options);
+  }
+};
+
+Effect.DefaultOptions.transition = Effect.Transitions.sinoidal;
+
+/* ------------- core effects ------------- */
+
+Effect.ScopedQueue = Class.create(Enumerable, {
+  initialize: function() {
+    this.effects  = [];
+    this.interval = null;
+  },
+  _each: function(iterator) {
+    this.effects._each(iterator);
+  },
+  add: function(effect) {
+    var timestamp = new Date().getTime();
+
+    var position = Object.isString(effect.options.queue) ?
+      effect.options.queue : effect.options.queue.position;
+
+    switch(position) {
+      case 'front':
+        // move unstarted effects after this effect
+        this.effects.findAll(function(e){ return e.state=='idle' }).each( function(e) {
+            e.startOn  += effect.finishOn;
+            e.finishOn += effect.finishOn;
+          });
+        break;
+      case 'with-last':
+        timestamp = this.effects.pluck('startOn').max() || timestamp;
+        break;
+      case 'end':
+        // start effect after last queued effect has finished
+        timestamp = this.effects.pluck('finishOn').max() || timestamp;
+        break;
+    }
+
+    effect.startOn  += timestamp;
+    effect.finishOn += timestamp;
+
+    if (!effect.options.queue.limit || (this.effects.length < effect.options.queue.limit))
+      this.effects.push(effect);
+
+    if (!this.interval)
+      this.interval = setInterval(this.loop.bind(this), 15);
+  },
+  remove: function(effect) {
+    this.effects = this.effects.reject(function(e) { return e==effect });
+    if (this.effects.length == 0) {
+      clearInterval(this.interval);
+      this.interval = null;
+    }
+  },
+  loop: function() {
+    var timePos = new Date().getTime();
+    for(var i=0, len=this.effects.length;i<len;i++)
+      this.effects[i] && this.effects[i].loop(timePos);
+  }
+});
+
+Effect.Queues = {
+  instances: $H(),
+  get: function(queueName) {
+    if (!Object.isString(queueName)) return queueName;
+
+    return this.instances.get(queueName) ||
+      this.instances.set(queueName, new Effect.ScopedQueue());
+  }
+};
+Effect.Queue = Effect.Queues.get('global');
+
+Effect.Base = Class.create({
+  position: null,
+  start: function(options) {
+    function codeForEvent(options,eventName){
+      return (
+        (options[eventName+'Internal'] ? 'this.options.'+eventName+'Internal(this);' : '') +
+        (options[eventName] ? 'this.options.'+eventName+'(this);' : '')
+      );
+    }
+    if (options && options.transition === false) options.transition = Effect.Transitions.linear;
+    this.options      = Object.extend(Object.extend({ },Effect.DefaultOptions), options || { });
+    this.currentFrame = 0;
+    this.state        = 'idle';
+    this.startOn      = this.options.delay*1000;
+    this.finishOn     = this.startOn+(this.options.duration*1000);
+    this.fromToDelta  = this.options.to-this.options.from;
+    this.totalTime    = this.finishOn-this.startOn;
+    this.totalFrames  = this.options.fps*this.options.duration;
+
+    this.render = (function() {
+      function dispatch(effect, eventName) {
+        if (effect.options[eventName + 'Internal'])
+          effect.options[eventName + 'Internal'](effect);
+        if (effect.options[eventName])
+          effect.options[eventName](effect);
+      }
+
+      return function(pos) {
+        if (this.state === "idle") {
+          this.state = "running";
+          dispatch(this, 'beforeSetup');
+          if (this.setup) this.setup();
+          dispatch(this, 'afterSetup');
+        }
+        if (this.state === "running") {
+          pos = (this.options.transition(pos) * this.fromToDelta) + this.options.from;
+          this.position = pos;
+          dispatch(this, 'beforeUpdate');
+          if (this.update) this.update(pos);
+          dispatch(this, 'afterUpdate');
+        }
+      };
+    })();
+
+    this.event('beforeStart');
+    if (!this.options.sync)
+      Effect.Queues.get(Object.isString(this.options.queue) ?
+        'global' : this.options.queue.scope).add(this);
+  },
+  loop: function(timePos) {
+    if (timePos >= this.startOn) {
+      if (timePos >= this.finishOn) {
+        this.render(1.0);
+        this.cancel();
+        this.event('beforeFinish');
+        if (this.finish) this.finish();
+        this.event('afterFinish');
+        return;
+      }
+      var pos   = (timePos - this.startOn) / this.totalTime,
+          frame = (pos * this.totalFrames).round();
+      if (frame > this.currentFrame) {
+        this.render(pos);
+        this.currentFrame = frame;
+      }
+    }
+  },
+  cancel: function() {
+    if (!this.options.sync)
+      Effect.Queues.get(Object.isString(this.options.queue) ?
+        'global' : this.options.queue.scope).remove(this);
+    this.state = 'finished';
+  },
+  event: function(eventName) {
+    if (this.options[eventName + 'Internal']) this.options[eventName + 'Internal'](this);
+    if (this.options[eventName]) this.options[eventName](this);
+  },
+  inspect: function() {
+    var data = $H();
+    for(property in this)
+      if (!Object.isFunction(this[property])) data.set(property, this[property]);
+    return '#<Effect:' + data.inspect() + ',options:' + $H(this.options).inspect() + '>';
+  }
+});
+
+Effect.Parallel = Class.create(Effect.Base, {
+  initialize: function(effects) {
+    this.effects = effects || [];
+    this.start(arguments[1]);
+  },
+  update: function(position) {
+    this.effects.invoke('render', position);
+  },
+  finish: function(position) {
+    this.effects.each( function(effect) {
+      effect.render(1.0);
+      effect.cancel();
+      effect.event('beforeFinish');
+      if (effect.finish) effect.finish(position);
+      effect.event('afterFinish');
+    });
+  }
+});
+
+Effect.Tween = Class.create(Effect.Base, {
+  initialize: function(object, from, to) {
+    object = Object.isString(object) ? $(object) : object;
+    var args = $A(arguments), method = args.last(),
+      options = args.length == 5 ? args[3] : null;
+    this.method = Object.isFunction(method) ? method.bind(object) :
+      Object.isFunction(object[method]) ? object[method].bind(object) :
+      function(value) { object[method] = value };
+    this.start(Object.extend({ from: from, to: to }, options || { }));
+  },
+  update: function(position) {
+    this.method(position);
+  }
+});
+
+Effect.Event = Class.create(Effect.Base, {
+  initialize: function() {
+    this.start(Object.extend({ duration: 0 }, arguments[0] || { }));
+  },
+  update: Prototype.emptyFunction
+});
+
+Effect.Opacity = Class.create(Effect.Base, {
+  initialize: function(element) {
+    this.element = $(element);
+    if (!this.element) throw(Effect._elementDoesNotExistError);
+    // make this work on IE on elements without 'layout'
+    if (Prototype.Browser.IE && (!this.element.currentStyle.hasLayout))
+      this.element.setStyle({zoom: 1});
+    var options = Object.extend({
+      from: this.element.getOpacity() || 0.0,
+      to:   1.0
+    }, arguments[1] || { });
+    this.start(options);
+  },
+  update: function(position) {
+    this.element.setOpacity(position);
+  }
+});
+
+Effect.Move = Class.create(Effect.Base, {
+  initialize: function(element) {
+    this.element = $(element);
+    if (!this.element) throw(Effect._elementDoesNotExistError);
+    var options = Object.extend({
+      x:    0,
+      y:    0,
+      mode: 'relative'
+    }, arguments[1] || { });
+    this.start(options);
+  },
+  setup: function() {
+    this.element.makePositioned();
+    this.originalLeft = parseFloat(this.element.getStyle('left') || '0');
+    this.originalTop  = parseFloat(this.element.getStyle('top')  || '0');
+    if (this.options.mode == 'absolute') {
+      this.options.x = this.options.x - this.originalLeft;
+      this.options.y = this.options.y - this.originalTop;
+    }
+  },
+  update: function(position) {
+    this.element.setStyle({
+      left: (this.options.x  * position + this.originalLeft).round() + 'px',
+      top:  (this.options.y  * position + this.originalTop).round()  + 'px'
+    });
+  }
+});
+
+// for backwards compatibility
+Effect.MoveBy = function(element, toTop, toLeft) {
+  return new Effect.Move(element,
+    Object.extend({ x: toLeft, y: toTop }, arguments[3] || { }));
+};
+
+Effect.Scale = Class.create(Effect.Base, {
+  initialize: function(element, percent) {
+    this.element = $(element);
+    if (!this.element) throw(Effect._elementDoesNotExistError);
+    var options = Object.extend({
+      scaleX: true,
+      scaleY: true,
+      scaleContent: true,
+      scaleFromCenter: false,
+      scaleMode: 'box',        // 'box' or 'contents' or { } with provided values
+      scaleFrom: 100.0,
+      scaleTo:   percent
+    }, arguments[2] || { });
+    this.start(options);
+  },
+  setup: function() {
+    this.restoreAfterFinish = this.options.restoreAfterFinish || false;
+    this.elementPositioning = this.element.getStyle('position');
+
+    this.originalStyle = { };
+    ['top','left','width','height','fontSize'].each( function(k) {
+      this.originalStyle[k] = this.element.style[k];
+    }.bind(this));
+
+    this.originalTop  = this.element.offsetTop;
+    this.originalLeft = this.element.offsetLeft;
+
+    var fontSize = this.element.getStyle('font-size') || '100%';
+    ['em','px','%','pt'].each( function(fontSizeType) {
+      if (fontSize.indexOf(fontSizeType)>0) {
+        this.fontSize     = parseFloat(fontSize);
+        this.fontSizeType = fontSizeType;
+      }
+    }.bind(this));
+
+    this.factor = (this.options.scaleTo - this.options.scaleFrom)/100;
+
+    this.dims = null;
+    if (this.options.scaleMode=='box')
+      this.dims = [this.element.offsetHeight, this.element.offsetWidth];
+    if (/^content/.test(this.options.scaleMode))
+      this.dims = [this.element.scrollHeight, this.element.scrollWidth];
+    if (!this.dims)
+      this.dims = [this.options.scaleMode.originalHeight,
+                   this.options.scaleMode.originalWidth];
+  },
+  update: function(position) {
+    var currentScale = (this.options.scaleFrom/100.0) + (this.factor * position);
+    if (this.options.scaleContent && this.fontSize)
+      this.element.setStyle({fontSize: this.fontSize * currentScale + this.fontSizeType });
+    this.setDimensions(this.dims[0] * currentScale, this.dims[1] * currentScale);
+  },
+  finish: function(position) {
+    if (this.restoreAfterFinish) this.element.setStyle(this.originalStyle);
+  },
+  setDimensions: function(height, width) {
+    var d = { };
+    if (this.options.scaleX) d.width = width.round() + 'px';
+    if (this.options.scaleY) d.height = height.round() + 'px';
+    if (this.options.scaleFromCenter) {
+      var topd  = (height - this.dims[0])/2;
+      var leftd = (width  - this.dims[1])/2;
+      if (this.elementPositioning == 'absolute') {
+        if (this.options.scaleY) d.top = this.originalTop-topd + 'px';
+        if (this.options.scaleX) d.left = this.originalLeft-leftd + 'px';
+      } else {
+        if (this.options.scaleY) d.top = -topd + 'px';
+        if (this.options.scaleX) d.left = -leftd + 'px';
+      }
+    }
+    this.element.setStyle(d);
+  }
+});
+
+Effect.Highlight = Class.create(Effect.Base, {
+  initialize: function(element) {
+    this.element = $(element);
+    if (!this.element) throw(Effect._elementDoesNotExistError);
+    var options = Object.extend({ startcolor: '#ffff99' }, arguments[1] || { });
+    this.start(options);
+  },
+  setup: function() {
+    // Prevent executing on elements not in the layout flow
+    if (this.element.getStyle('display')=='none') { this.cancel(); return; }
+    // Disable background image during the effect
+    this.oldStyle = { };
+    if (!this.options.keepBackgroundImage) {
+      this.oldStyle.backgroundImage = this.element.getStyle('background-image');
+      this.element.setStyle({backgroundImage: 'none'});
+    }
+    if (!this.options.endcolor)
+      this.options.endcolor = this.element.getStyle('background-color').parseColor('#ffffff');
+    if (!this.options.restorecolor)
+      this.options.restorecolor = this.element.getStyle('background-color');
+    // init color calculations
+    this._base  = $R(0,2).map(function(i){ return parseInt(this.options.startcolor.slice(i*2+1,i*2+3),16) }.bind(this));
+    this._delta = $R(0,2).map(function(i){ return parseInt(this.options.endcolor.slice(i*2+1,i*2+3),16)-this._base[i] }.bind(this));
+  },
+  update: function(position) {
+    this.element.setStyle({backgroundColor: $R(0,2).inject('#',function(m,v,i){
+      return m+((this._base[i]+(this._delta[i]*position)).round().toColorPart()); }.bind(this)) });
+  },
+  finish: function() {
+    this.element.setStyle(Object.extend(this.oldStyle, {
+      backgroundColor: this.options.restorecolor
+    }));
+  }
+});
+
+Effect.ScrollTo = function(element) {
+  var options = arguments[1] || { },
+  scrollOffsets = document.viewport.getScrollOffsets(),
+  elementOffsets = $(element).cumulativeOffset();
+
+  if (options.offset) elementOffsets[1] += options.offset;
+
+  return new Effect.Tween(null,
+    scrollOffsets.top,
+    elementOffsets[1],
+    options,
+    function(p){ scrollTo(scrollOffsets.left, p.round()); }
+  );
+};
+
+/* ------------- combination effects ------------- */
+
+Effect.Fade = function(element) {
+  element = $(element);
+  var oldOpacity = element.getInlineOpacity();
+  var options = Object.extend({
+    from: element.getOpacity() || 1.0,
+    to:   0.0,
+    afterFinishInternal: function(effect) {
+      if (effect.options.to!=0) return;
+      effect.element.hide().setStyle({opacity: oldOpacity});
+    }
+  }, arguments[1] || { });
+  return new Effect.Opacity(element,options);
+};
+
+Effect.Appear = function(element) {
+  element = $(element);
+  var options = Object.extend({
+  from: (element.getStyle('display') == 'none' ? 0.0 : element.getOpacity() || 0.0),
+  to:   1.0,
+  // force Safari to render floated elements properly
+  afterFinishInternal: function(effect) {
+    effect.element.forceRerendering();
+  },
+  beforeSetup: function(effect) {
+    effect.element.setOpacity(effect.options.from).show();
+  }}, arguments[1] || { });
+  return new Effect.Opacity(element,options);
+};
+
+Effect.Puff = function(element) {
+  element = $(element);
+  var oldStyle = {
+    opacity: element.getInlineOpacity(),
+    position: element.getStyle('position'),
+    top:  element.style.top,
+    left: element.style.left,
+    width: element.style.width,
+    height: element.style.height
+  };
+  return new Effect.Parallel(
+   [ new Effect.Scale(element, 200,
+      { sync: true, scaleFromCenter: true, scaleContent: true, restoreAfterFinish: true }),
+     new Effect.Opacity(element, { sync: true, to: 0.0 } ) ],
+     Object.extend({ duration: 1.0,
+      beforeSetupInternal: function(effect) {
+        Position.absolutize(effect.effects[0].element);
+      },
+      afterFinishInternal: function(effect) {
+         effect.effects[0].element.hide().setStyle(oldStyle); }
+     }, arguments[1] || { })
+   );
+};
+
+Effect.BlindUp = function(element) {
+  element = $(element);
+  element.makeClipping();
+  return new Effect.Scale(element, 0,
+    Object.extend({ scaleContent: false,
+      scaleX: false,
+      restoreAfterFinish: true,
+      afterFinishInternal: function(effect) {
+        effect.element.hide().undoClipping();
+      }
+    }, arguments[1] || { })
+  );
+};
+
+Effect.BlindDown = function(element) {
+  element = $(element);
+  var elementDimensions = element.getDimensions();
+  return new Effect.Scale(element, 100, Object.extend({
+    scaleContent: false,
+    scaleX: false,
+    scaleFrom: 0,
+    scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
+    restoreAfterFinish: true,
+    afterSetup: function(effect) {
+      effect.element.makeClipping().setStyle({height: '0px'}).show();
+    },
+    afterFinishInternal: function(effect) {
+      effect.element.undoClipping();
+    }
+  }, arguments[1] || { }));
+};
+
+Effect.SwitchOff = function(element) {
+  element = $(element);
+  var oldOpacity = element.getInlineOpacity();
+  return new Effect.Appear(element, Object.extend({
+    duration: 0.4,
+    from: 0,
+    transition: Effect.Transitions.flicker,
+    afterFinishInternal: function(effect) {
+      new Effect.Scale(effect.element, 1, {
+        duration: 0.3, scaleFromCenter: true,
+        scaleX: false, scaleContent: false, restoreAfterFinish: true,
+        beforeSetup: function(effect) {
+          effect.element.makePositioned().makeClipping();
+        },
+        afterFinishInternal: function(effect) {
+          effect.element.hide().undoClipping().undoPositioned().setStyle({opacity: oldOpacity});
+        }
+      });
+    }
+  }, arguments[1] || { }));
+};
+
+Effect.DropOut = function(element) {
+  element = $(element);
+  var oldStyle = {
+    top: element.getStyle('top'),
+    left: element.getStyle('left'),
+    opacity: element.getInlineOpacity() };
+  return new Effect.Parallel(
+    [ new Effect.Move(element, {x: 0, y: 100, sync: true }),
+      new Effect.Opacity(element, { sync: true, to: 0.0 }) ],
+    Object.extend(
+      { duration: 0.5,
+        beforeSetup: function(effect) {
+          effect.effects[0].element.makePositioned();
+        },
+        afterFinishInternal: function(effect) {
+          effect.effects[0].element.hide().undoPositioned().setStyle(oldStyle);
+        }
+      }, arguments[1] || { }));
+};
+
+Effect.Shake = function(element) {
+  element = $(element);
+  var options = Object.extend({
+    distance: 20,
+    duration: 0.5
+  }, arguments[1] || {});
+  var distance = parseFloat(options.distance);
+  var split = parseFloat(options.duration) / 10.0;
+  var oldStyle = {
+    top: element.getStyle('top'),
+    left: element.getStyle('left') };
+    return new Effect.Move(element,
+      { x:  distance, y: 0, duration: split, afterFinishInternal: function(effect) {
+    new Effect.Move(effect.element,
+      { x: -distance*2, y: 0, duration: split*2,  afterFinishInternal: function(effect) {
+    new Effect.Move(effect.element,
+      { x:  distance*2, y: 0, duration: split*2,  afterFinishInternal: function(effect) {
+    new Effect.Move(effect.element,
+      { x: -distance*2, y: 0, duration: split*2,  afterFinishInternal: function(effect) {
+    new Effect.Move(effect.element,
+      { x:  distance*2, y: 0, duration: split*2,  afterFinishInternal: function(effect) {
+    new Effect.Move(effect.element,
+      { x: -distance, y: 0, duration: split, afterFinishInternal: function(effect) {
+        effect.element.undoPositioned().setStyle(oldStyle);
+  }}); }}); }}); }}); }}); }});
+};
+
+Effect.SlideDown = function(element) {
+  element = $(element).cleanWhitespace();
+  // SlideDown need to have the content of the element wrapped in a container element with fixed height!
+  var oldInnerBottom = element.down().getStyle('bottom');
+  var elementDimensions = element.getDimensions();
+  return new Effect.Scale(element, 100, Object.extend({
+    scaleContent: false,
+    scaleX: false,
+    scaleFrom: window.opera ? 0 : 1,
+    scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
+    restoreAfterFinish: true,
+    afterSetup: function(effect) {
+      effect.element.makePositioned();
+      effect.element.down().makePositioned();
+      if (window.opera) effect.element.setStyle({top: ''});
+      effect.element.makeClipping().setStyle({height: '0px'}).show();
+    },
+    afterUpdateInternal: function(effect) {
+      effect.element.down().setStyle({bottom:
+        (effect.dims[0] - effect.element.clientHeight) + 'px' });
+    },
+    afterFinishInternal: function(effect) {
+      effect.element.undoClipping().undoPositioned();
+      effect.element.down().undoPositioned().setStyle({bottom: oldInnerBottom}); }
+    }, arguments[1] || { })
+  );
+};
+
+Effect.SlideUp = function(element) {
+  element = $(element).cleanWhitespace();
+  var oldInnerBottom = element.down().getStyle('bottom');
+  var elementDimensions = element.getDimensions();
+  return new Effect.Scale(element, window.opera ? 0 : 1,
+   Object.extend({ scaleContent: false,
+    scaleX: false,
+    scaleMode: 'box',
+    scaleFrom: 100,
+    scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
+    restoreAfterFinish: true,
+    afterSetup: function(effect) {
+      effect.element.makePositioned();
+      effect.element.down().makePositioned();
+      if (window.opera) effect.element.setStyle({top: ''});
+      effect.element.makeClipping().show();
+    },
+    afterUpdateInternal: function(effect) {
+      effect.element.down().setStyle({bottom:
+        (effect.dims[0] - effect.element.clientHeight) + 'px' });
+    },
+    afterFinishInternal: function(effect) {
+      effect.element.hide().undoClipping().undoPositioned();
+      effect.element.down().undoPositioned().setStyle({bottom: oldInnerBottom});
+    }
+   }, arguments[1] || { })
+  );
+};
+
+// Bug in opera makes the TD containing this element expand for a instance after finish
+Effect.Squish = function(element) {
+  return new Effect.Scale(element, window.opera ? 1 : 0, {
+    restoreAfterFinish: true,
+    beforeSetup: function(effect) {
+      effect.element.makeClipping();
+    },
+    afterFinishInternal: function(effect) {
+      effect.element.hide().undoClipping();
+    }
+  });
+};
+
+Effect.Grow = function(element) {
+  element = $(element);
+  var options = Object.extend({
+    direction: 'center',
+    moveTransition: Effect.Transitions.sinoidal,
+    scaleTransition: Effect.Transitions.sinoidal,
+    opacityTransition: Effect.Transitions.full
+  }, arguments[1] || { });
+  var oldStyle = {
+    top: element.style.top,
+    left: element.style.left,
+    height: element.style.height,
+    width: element.style.width,
+    opacity: element.getInlineOpacity() };
+
+  var dims = element.getDimensions();
+  var initialMoveX, initialMoveY;
+  var moveX, moveY;
+
+  switch (options.direction) {
+    case 'top-left':
+      initialMoveX = initialMoveY = moveX = moveY = 0;
+      break;
+    case 'top-right':
+      initialMoveX = dims.width;
+      initialMoveY = moveY = 0;
+      moveX = -dims.width;
+      break;
+    case 'bottom-left':
+      initialMoveX = moveX = 0;
+      initialMoveY = dims.height;
+      moveY = -dims.height;
+      break;
+    case 'bottom-right':
+      initialMoveX = dims.width;
+      initialMoveY = dims.height;
+      moveX = -dims.width;
+      moveY = -dims.height;
+      break;
+    case 'center':
+      initialMoveX = dims.width / 2;
+      initialMoveY = dims.height / 2;
+      moveX = -dims.width / 2;
+      moveY = -dims.height / 2;
+      break;
+  }
+
+  return new Effect.Move(element, {
+    x: initialMoveX,
+    y: initialMoveY,
+    duration: 0.01,
+    beforeSetup: function(effect) {
+      effect.element.hide().makeClipping().makePositioned();
+    },
+    afterFinishInternal: function(effect) {
+      new Effect.Parallel(
+        [ new Effect.Opacity(effect.element, { sync: true, to: 1.0, from: 0.0, transition: options.opacityTransition }),
+          new Effect.Move(effect.element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition }),
+          new Effect.Scale(effect.element, 100, {
+            scaleMode: { originalHeight: dims.height, originalWidth: dims.width },
+            sync: true, scaleFrom: window.opera ? 1 : 0, transition: options.scaleTransition, restoreAfterFinish: true})
+        ], Object.extend({
+             beforeSetup: function(effect) {
+               effect.effects[0].element.setStyle({height: '0px'}).show();
+             },
+             afterFinishInternal: function(effect) {
+               effect.effects[0].element.undoClipping().undoPositioned().setStyle(oldStyle);
+             }
+           }, options)
+      );
+    }
+  });
+};
+
+Effect.Shrink = function(element) {
+  element = $(element);
+  var options = Object.extend({
+    direction: 'center',
+    moveTransition: Effect.Transitions.sinoidal,
+    scaleTransition: Effect.Transitions.sinoidal,
+    opacityTransition: Effect.Transitions.none
+  }, arguments[1] || { });
+  var oldStyle = {
+    top: element.style.top,
+    left: element.style.left,
+    height: element.style.height,
+    width: element.style.width,
+    opacity: element.getInlineOpacity() };
+
+  var dims = element.getDimensions();
+  var moveX, moveY;
+
+  switch (options.direction) {
+    case 'top-left':
+      moveX = moveY = 0;
+      break;
+    case 'top-right':
+      moveX = dims.width;
+      moveY = 0;
+      break;
+    case 'bottom-left':
+      moveX = 0;
+      moveY = dims.height;
+      break;
+    case 'bottom-right':
+      moveX = dims.width;
+      moveY = dims.height;
+      break;
+    case 'center':
+      moveX = dims.width / 2;
+      moveY = dims.height / 2;
+      break;
+  }
+
+  return new Effect.Parallel(
+    [ new Effect.Opacity(element, { sync: true, to: 0.0, from: 1.0, transition: options.opacityTransition }),
+      new Effect.Scale(element, window.opera ? 1 : 0, { sync: true, transition: options.scaleTransition, restoreAfterFinish: true}),
+      new Effect.Move(element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition })
+    ], Object.extend({
+         beforeStartInternal: function(effect) {
+           effect.effects[0].element.makePositioned().makeClipping();
+         },
+         afterFinishInternal: function(effect) {
+           effect.effects[0].element.hide().undoClipping().undoPositioned().setStyle(oldStyle); }
+       }, options)
+  );
+};
+
+Effect.Pulsate = function(element) {
+  element = $(element);
+  var options    = arguments[1] || { },
+    oldOpacity = element.getInlineOpacity(),
+    transition = options.transition || Effect.Transitions.linear,
+    reverser   = function(pos){
+      return 1 - transition((-Math.cos((pos*(options.pulses||5)*2)*Math.PI)/2) + .5);
+    };
+
+  return new Effect.Opacity(element,
+    Object.extend(Object.extend({  duration: 2.0, from: 0,
+      afterFinishInternal: function(effect) { effect.element.setStyle({opacity: oldOpacity}); }
+    }, options), {transition: reverser}));
+};
+
+Effect.Fold = function(element) {
+  element = $(element);
+  var oldStyle = {
+    top: element.style.top,
+    left: element.style.left,
+    width: element.style.width,
+    height: element.style.height };
+  element.makeClipping();
+  return new Effect.Scale(element, 5, Object.extend({
+    scaleContent: false,
+    scaleX: false,
+    afterFinishInternal: function(effect) {
+    new Effect.Scale(element, 1, {
+      scaleContent: false,
+      scaleY: false,
+      afterFinishInternal: function(effect) {
+        effect.element.hide().undoClipping().setStyle(oldStyle);
+      } });
+  }}, arguments[1] || { }));
+};
+
+Effect.Morph = Class.create(Effect.Base, {
+  initialize: function(element) {
+    this.element = $(element);
+    if (!this.element) throw(Effect._elementDoesNotExistError);
+    var options = Object.extend({
+      style: { }
+    }, arguments[1] || { });
+
+    if (!Object.isString(options.style)) this.style = $H(options.style);
+    else {
+      if (options.style.include(':'))
+        this.style = options.style.parseStyle();
+      else {
+        this.element.addClassName(options.style);
+        this.style = $H(this.element.getStyles());
+        this.element.removeClassName(options.style);
+        var css = this.element.getStyles();
+        this.style = this.style.reject(function(style) {
+          return style.value == css[style.key];
+        });
+        options.afterFinishInternal = function(effect) {
+          effect.element.addClassName(effect.options.style);
+          effect.transforms.each(function(transform) {
+            effect.element.style[transform.style] = '';
+          });
+        };
+      }
+    }
+    this.start(options);
+  },
+
+  setup: function(){
+    function parseColor(color){
+      if (!color || ['rgba(0, 0, 0, 0)','transparent'].include(color)) color = '#ffffff';
+      color = color.parseColor();
+      return $R(0,2).map(function(i){
+        return parseInt( color.slice(i*2+1,i*2+3), 16 );
+      });
+    }
+    this.transforms = this.style.map(function(pair){
+      var property = pair[0], value = pair[1], unit = null;
+
+      if (value.parseColor('#zzzzzz') != '#zzzzzz') {
+        value = value.parseColor();
+        unit  = 'color';
+      } else if (property == 'opacity') {
+        value = parseFloat(value);
+        if (Prototype.Browser.IE && (!this.element.currentStyle.hasLayout))
+          this.element.setStyle({zoom: 1});
+      } else if (Element.CSS_LENGTH.test(value)) {
+          var components = value.match(/^([\+\-]?[0-9\.]+)(.*)$/);
+          value = parseFloat(components[1]);
+          unit = (components.length == 3) ? components[2] : null;
+      }
+
+      var originalValue = this.element.getStyle(property);
+      return {
+        style: property.camelize(),
+        originalValue: unit=='color' ? parseColor(originalValue) : parseFloat(originalValue || 0),
+        targetValue: unit=='color' ? parseColor(value) : value,
+        unit: unit
+      };
+    }.bind(this)).reject(function(transform){
+      return (
+        (transform.originalValue == transform.targetValue) ||
+        (
+          transform.unit != 'color' &&
+          (isNaN(transform.originalValue) || isNaN(transform.targetValue))
+        )
+      );
+    });
+  },
+  update: function(position) {
+    var style = { }, transform, i = this.transforms.length;
+    while(i--)
+      style[(transform = this.transforms[i]).style] =
+        transform.unit=='color' ? '#'+
+          (Math.round(transform.originalValue[0]+
+            (transform.targetValue[0]-transform.originalValue[0])*position)).toColorPart() +
+          (Math.round(transform.originalValue[1]+
+            (transform.targetValue[1]-transform.originalValue[1])*position)).toColorPart() +
+          (Math.round(transform.originalValue[2]+
+            (transform.targetValue[2]-transform.originalValue[2])*position)).toColorPart() :
+        (transform.originalValue +
+          (transform.targetValue - transform.originalValue) * position).toFixed(3) +
+            (transform.unit === null ? '' : transform.unit);
+    this.element.setStyle(style, true);
+  }
+});
+
+Effect.Transform = Class.create({
+  initialize: function(tracks){
+    this.tracks  = [];
+    this.options = arguments[1] || { };
+    this.addTracks(tracks);
+  },
+  addTracks: function(tracks){
+    tracks.each(function(track){
+      track = $H(track);
+      var data = track.values().first();
+      this.tracks.push($H({
+        ids:     track.keys().first(),
+        effect:  Effect.Morph,
+        options: { style: data }
+      }));
+    }.bind(this));
+    return this;
+  },
+  play: function(){
+    return new Effect.Parallel(
+      this.tracks.map(function(track){
+        var ids = track.get('ids'), effect = track.get('effect'), options = track.get('options');
+        var elements = [$(ids) || $$(ids)].flatten();
+        return elements.map(function(e){ return new effect(e, Object.extend({ sync:true }, options)) });
+      }).flatten(),
+      this.options
+    );
+  }
+});
+
+Element.CSS_PROPERTIES = $w(
+  'backgroundColor backgroundPosition borderBottomColor borderBottomStyle ' +
+  'borderBottomWidth borderLeftColor borderLeftStyle borderLeftWidth ' +
+  'borderRightColor borderRightStyle borderRightWidth borderSpacing ' +
+  'borderTopColor borderTopStyle borderTopWidth bottom clip color ' +
+  'fontSize fontWeight height left letterSpacing lineHeight ' +
+  'marginBottom marginLeft marginRight marginTop markerOffset maxHeight '+
+  'maxWidth minHeight minWidth opacity outlineColor outlineOffset ' +
+  'outlineWidth paddingBottom paddingLeft paddingRight paddingTop ' +
+  'right textIndent top width wordSpacing zIndex');
+
+Element.CSS_LENGTH = /^(([\+\-]?[0-9\.]+)(em|ex|px|in|cm|mm|pt|pc|\%))|0$/;
+
+String.__parseStyleElement = document.createElement('div');
+String.prototype.parseStyle = function(){
+  var style, styleRules = $H();
+  if (Prototype.Browser.WebKit)
+    style = new Element('div',{style:this}).style;
+  else {
+    String.__parseStyleElement.innerHTML = '<div style="' + this + '"></div>';
+    style = String.__parseStyleElement.childNodes[0].style;
+  }
+
+  Element.CSS_PROPERTIES.each(function(property){
+    if (style[property]) styleRules.set(property, style[property]);
+  });
+
+  if (Prototype.Browser.IE && this.include('opacity'))
+    styleRules.set('opacity', this.match(/opacity:\s*((?:0|1)?(?:\.\d*)?)/)[1]);
+
+  return styleRules;
+};
+
+if (document.defaultView && document.defaultView.getComputedStyle) {
+  Element.getStyles = function(element) {
+    var css = document.defaultView.getComputedStyle($(element), null);
+    return Element.CSS_PROPERTIES.inject({ }, function(styles, property) {
+      styles[property] = css[property];
+      return styles;
+    });
+  };
+} else {
+  Element.getStyles = function(element) {
+    element = $(element);
+    var css = element.currentStyle, styles;
+    styles = Element.CSS_PROPERTIES.inject({ }, function(results, property) {
+      results[property] = css[property];
+      return results;
+    });
+    if (!styles.opacity) styles.opacity = element.getOpacity();
+    return styles;
+  };
+}
+
+Effect.Methods = {
+  morph: function(element, style) {
+    element = $(element);
+    new Effect.Morph(element, Object.extend({ style: style }, arguments[2] || { }));
+    return element;
+  },
+  visualEffect: function(element, effect, options) {
+    element = $(element);
+    var s = effect.dasherize().camelize(), klass = s.charAt(0).toUpperCase() + s.substring(1);
+    new Effect[klass](element, options);
+    return element;
+  },
+  highlight: function(element, options) {
+    element = $(element);
+    new Effect.Highlight(element, options);
+    return element;
+  }
+};
+
+$w('fade appear grow shrink fold blindUp blindDown slideUp slideDown '+
+  'pulsate shake puff squish switchOff dropOut').each(
+  function(effect) {
+    Effect.Methods[effect] = function(element, options){
+      element = $(element);
+      Effect[effect.charAt(0).toUpperCase() + effect.substring(1)](element, options);
+      return element;
+    };
+  }
+);
+
+$w('getInlineOpacity forceRerendering setContentZoom collectTextNodes collectTextNodesIgnoreClass getStyles').each(
+  function(f) { Effect.Methods[f] = Element[f]; }
+);
+
+Element.addMethods(Effect.Methods);
\ No newline at end of file
diff --git a/koward/www/htdocs/horde/js/horde.js b/koward/www/htdocs/horde/js/horde.js
new file mode 100644 (file)
index 0000000..e4378c8
--- /dev/null
@@ -0,0 +1,267 @@
+/**
+ * General Horde UI effects javascript.
+ *
+ * $Horde: horde/js/src/horde.js,v 1.10 2007/09/25 12:57:20 slusarz Exp $
+ *
+ * See the enclosed file COPYING for license information (LGPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
+ */
+
+var ToolTips = {
+    current: null,
+    timeout: null,
+    element: null,
+
+    attachBehavior: function()
+    {
+        links = document.getElementsByTagName('a');
+        for (var i = 0; i < links.length; i++) {
+            if (links[i].title) {
+                links[i].setAttribute('nicetitle', links[i].title);
+                links[i].removeAttribute('title');
+
+                addEvent(links[i], 'mouseover', ToolTips.onMouseover);
+                addEvent(links[i], 'mouseout', ToolTips.out);
+                addEvent(links[i], 'focus', ToolTips.onFocus);
+                addEvent(links[i], 'blur', ToolTips.out);
+            }
+        }
+    },
+
+    onMouseover: function(event)
+    {
+        if (typeof ToolTips == 'undefined') {
+            return;
+        }
+
+        if (ToolTips.timeout) {
+            clearTimeout(ToolTips.timeout);
+        }
+
+        if (event.srcElement) {
+            ToolTips.element = event.srcElement;
+        } else if (event.target) {
+            ToolTips.element = event.target;
+        }
+
+        var pos = mousePos(event);
+        ToolTips.timeout = setTimeout(function() { ToolTips.show(pos); }, 300)
+    },
+
+    onFocus: function(event)
+    {
+        if (typeof ToolTips == 'undefined') {
+            return;
+        }
+
+        if (ToolTips.timeout) {
+            clearTimeout(ToolTips.timeout);
+        }
+
+        if (event.srcElement) {
+            ToolTips.element = event.srcElement;
+        } else if (event.target) {
+            ToolTips.element = event.target;
+        }
+
+        var pos = eltPos(ToolTips.element);
+        ToolTips.timeout = setTimeout(function() { ToolTips.show(pos); }, 300)
+    },
+
+    out: function()
+    {
+        if (typeof ToolTips == 'undefined') {
+            return;
+        }
+
+        if (ToolTips.timeout) {
+            clearTimeout(ToolTips.timeout);
+        }
+
+        if (ToolTips.current) {
+            document.getElementsByTagName('body')[0].removeChild(ToolTips.current);
+            ToolTips.current = null;
+
+            var iframe = document.getElementById('iframe_tt');
+            if (iframe != null) {
+                iframe.style.display = 'none';
+            }
+        }
+    },
+
+    show: function(pos)
+    {
+        try {
+            if (ToolTips.current) {
+                ToolTips.out();
+            }
+
+            var link = ToolTips.element;
+            while (!link.getAttribute('nicetitle') && link.nodeName.toLowerCase() != 'body') {
+                link = link.parentNode;
+            }
+            var nicetitle = link.getAttribute('nicetitle');
+            if (!nicetitle) {
+                return;
+            }
+
+            var d = document.createElement('div');
+            d.className = 'nicetitle';
+            d.innerHTML = nicetitle;
+
+            var STD_WIDTH = 100;
+            var MAX_WIDTH = 600;
+            if (window.innerWidth) {
+                MAX_WIDTH = Math.min(MAX_WIDTH, window.innerWidth - 20);
+            }
+            if (document.body && document.body.scrollWidth) {
+                MAX_WIDTH = Math.min(MAX_WIDTH, document.body.scrollWidth - 20);
+            }
+
+            var nicetitle_length = 0;
+            var lines = nicetitle.replace(/<br ?\/>/g, "\n").split("\n");
+            for (var i = 0; i < lines.length; ++i) {
+                nicetitle_length = Math.max(nicetitle_length, lines[i].length);
+            }
+
+            var h_pixels = nicetitle_length * 7;
+            var t_pixels = nicetitle_length * 10;
+
+            var w;
+            if (h_pixels > STD_WIDTH) {
+                w = h_pixels;
+            } else if (STD_WIDTH > t_pixels) {
+                w = t_pixels;
+            } else {
+                w = STD_WIDTH;
+            }
+
+            // Make sure all of the tooltip is visible
+            var left = pos[0] + 20,
+                innerWidth = window.innerWidth || document.documentElement.clientWidth || document.body.offsetWidth,
+                pageXOffset = window.pageXOffset || document.documentElement.scrollLeft;
+            if (innerWidth && ((left + w) > (innerWidth + pageXOffset))) {
+                left = innerWidth - w - 40 + pageXOffset;
+            }
+            if (document.body.scrollWidth && ((left + w) > (document.body.scrollWidth + pageXOffset))) {
+                left = document.body.scrollWidth - w - 25 + pageXOffset;
+            }
+
+            d.id = 'toolTip';
+            d.style.left = left + 'px';
+            d.style.width = Math.min(w, MAX_WIDTH) + 'px';
+            d.style.top = (pos[1] + 10) + 'px';
+            d.style.display = '';
+
+            document.getElementsByTagName('body')[0].appendChild(d);
+            ToolTips.current = d;
+
+            if (typeof ToolTips_Option_Windowed_Controls != 'undefined') {
+                var iframe = document.getElementById('iframe_tt');
+                if (iframe == null) {
+                    iframe = document.createElement('<iframe src="javascript:false;" name="iframe_tt" id="iframe_tt" scrolling="no" frameborder="0" style="position:absolute;top:0;left:0;display:none"></iframe>');
+                    document.getElementsByTagName('body')[0].appendChild(iframe);
+                }
+                iframe.style.width = d.offsetWidth;
+                iframe.style.height = d.offsetHeight;
+                iframe.style.top = d.style.top;
+                iframe.style.left = d.style.left;
+                iframe.style.position = 'absolute';
+                iframe.style.display = 'block';
+                d.style.zIndex = 100;
+                iframe.style.zIndex = 99;
+            }
+        } catch (e) {}
+    }
+
+};
+
+/**
+ * Return the [x,y] position of the mouse.
+ */
+function mousePos(event)
+{
+    return [event.pageX || (event.clientX + (document.documentElement.scrollLeft || document.body.scrollLeft)),
+            event.pageY || (event.clientY + (document.documentElement.scrollTop || document.body.scrollTop))];
+}
+/**
+ * Return the [x,y] position of an element.
+ */
+function eltPos(elt)
+{
+    if (elt.offsetParent) {
+        for (posX = 0, posY = 0; elt.offsetParent; elt = elt.offsetParent) {
+            posX += elt.offsetLeft;
+            posY += elt.offsetTop;
+        }
+        return [posX, posY];
+    } else {
+        return [elt.x, elt.y];
+    }
+}
+
+/**
+ * Add an event listener as long as the browser supports it. Different
+ * browsers still handle these events slightly differently; in
+ * particular avoid using "this" in event functions.
+ *
+ * @author Scott Andrew
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ */
+function addEvent(obj, evType, fn)
+{
+    if (obj.addEventListener) {
+        obj.addEventListener(evType, fn, true);
+        return true;
+    } else if (obj.attachEvent) {
+        var r = obj.attachEvent('on' + evType, fn);
+        EventCache.add(obj, evType, fn);
+        return r;
+    } else {
+        return false;
+    }
+}
+
+var EventCache = function()
+{
+    var listEvents = [];
+
+    return {
+        listEvents: listEvents,
+
+        add: function(node, sEventName, fHandler, bCapture)
+        {
+            listEvents.push(arguments);
+        },
+
+        flush: function()
+        {
+            var i, item;
+            for (i = listEvents.length - 1; i >= 0; i = i - 1) {
+                item = listEvents[i];
+
+                if (item[0].removeEventListener) {
+                    item[0].removeEventListener(item[1], item[2], item[3]);
+                };
+
+                /* From this point on we need the event names to be
+                 * prefixed with 'on'. */
+                if (item[1].substring(0, 2) != 'on') {
+                    item[1] = 'on' + item[1];
+                }
+
+                if (item[0].detachEvent) {
+                    item[0].detachEvent(item[1], item[2]);
+                }
+
+                item[0][item[1]] = null;
+            }
+        }
+    };
+}();
+
+if (document.createElement && document.getElementsByTagName) {
+    addEvent(window, 'load', ToolTips.attachBehavior);
+    addEvent(window, 'unload', ToolTips.out);
+    addEvent(window, 'unload', EventCache.flush);
+}
diff --git a/koward/www/htdocs/horde/js/prototype.js b/koward/www/htdocs/horde/js/prototype.js
new file mode 100644 (file)
index 0000000..a7fd383
--- /dev/null
@@ -0,0 +1,4320 @@
+/*  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.
+ *  For details, see the Prototype web site: http://www.prototypejs.org/
+ *
+ *--------------------------------------------------------------------------*/
+
+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(x) { return x }
+};
+
+if (Prototype.Browser.MobileSafari)
+  Prototype.BrowserFeatures.SpecificElementExtensions = false;
+
+
+/* Based on Alex Arnell's inheritance implementation. */
+var Class = {
+  create: function() {
+    var parent = null, properties = $A(arguments);
+    if (Object.isFunction(properties[0]))
+      parent = properties.shift();
+
+    function klass() {
+      this.initialize.apply(this, arguments);
+    }
+
+    Object.extend(klass, Class.Methods);
+    klass.superclass = parent;
+    klass.subclasses = [];
+
+    if (parent) {
+      var subclass = function() { };
+      subclass.prototype = parent.prototype;
+      klass.prototype = new subclass;
+      parent.subclasses.push(klass);
+    }
+
+    for (var i = 0; i < properties.length; i++)
+      klass.addMethods(properties[i]);
+
+    if (!klass.prototype.initialize)
+      klass.prototype.initialize = Prototype.emptyFunction;
+
+    klass.prototype.constructor = klass;
+
+    return klass;
+  }
+};
+
+Class.Methods = {
+  addMethods: function(source) {
+    var ancestor   = this.superclass && this.superclass.prototype;
+    var properties = Object.keys(source);
+
+    if (!Object.keys({ toString: true }).length)
+      properties.push("toString", "valueOf");
+
+    for (var i = 0, length = properties.length; i < length; i++) {
+      var property = properties[i], value = source[property];
+      if (ancestor && Object.isFunction(value) &&
+          value.argumentNames().first() == "$super") {
+        var method = value;
+        value = (function(m) {
+          return function() { return ancestor[m].apply(this, arguments) };
+        })(property).wrap(method);
+
+        value.valueOf = method.valueOf.bind(method);
+        value.toString = method.toString.bind(method);
+      }
+      this.prototype[property] = value;
+    }
+
+    return this;
+  }
+};
+
+var Abstract = { };
+
+Object.extend = function(destination, source) {
+  for (var property in source)
+    destination[property] = source[property];
+  return destination;
+};
+
+Object.extend(Object, {
+  inspect: function(object) {
+    try {
+      if (Object.isUndefined(object)) return 'undefined';
+      if (object === null) return 'null';
+      return object.inspect ? object.inspect() : String(object);
+    } catch (e) {
+      if (e instanceof RangeError) return '...';
+      throw e;
+    }
+  },
+
+  toJSON: function(object) {
+    var type = typeof object;
+    switch (type) {
+      case 'undefined':
+      case 'function':
+      case 'unknown': return;
+      case 'boolean': return object.toString();
+    }
+
+    if (object === null) return 'null';
+    if (object.toJSON) return object.toJSON();
+    if (Object.isElement(object)) return;
+
+    var results = [];
+    for (var property in object) {
+      var value = Object.toJSON(object[property]);
+      if (!Object.isUndefined(value))
+        results.push(property.toJSON() + ': ' + value);
+    }
+
+    return '{' + results.join(', ') + '}';
+  },
+
+  toQueryString: function(object) {
+    return $H(object).toQueryString();
+  },
+
+  toHTML: function(object) {
+    return object && object.toHTML ? object.toHTML() : String.interpret(object);
+  },
+
+  keys: function(object) {
+    var keys = [];
+    for (var property in object)
+      keys.push(property);
+    return keys;
+  },
+
+  values: function(object) {
+    var values = [];
+    for (var property in object)
+      values.push(object[property]);
+    return values;
+  },
+
+  clone: function(object) {
+    return Object.extend({ }, object);
+  },
+
+  isElement: function(object) {
+    return !!(object && object.nodeType == 1);
+  },
+
+  isArray: function(object) {
+    return object != null && typeof object == "object" &&
+      'splice' in object && 'join' in object;
+  },
+
+  isHash: function(object) {
+    return object instanceof Hash;
+  },
+
+  isFunction: function(object) {
+    return typeof object == "function";
+  },
+
+  isString: function(object) {
+    return typeof object == "string";
+  },
+
+  isNumber: function(object) {
+    return typeof object == "number";
+  },
+
+  isUndefined: function(object) {
+    return typeof object == "undefined";
+  }
+});
+
+Object.extend(Function.prototype, {
+  argumentNames: function() {
+    var names = this.toString().match(/^[\s\(]*function[^(]*\(([^\)]*)\)/)[1]
+      .replace(/\s+/g, '').split(',');
+    return names.length == 1 && !names[0] ? [] : names;
+  },
+
+  bind: function() {
+    if (arguments.length < 2 && Object.isUndefined(arguments[0])) return this;
+    var __method = this, args = $A(arguments), object = args.shift();
+    return function() {
+      return __method.apply(object, args.concat($A(arguments)));
+    }
+  },
+
+  bindAsEventListener: function() {
+    var __method = this, args = $A(arguments), object = args.shift();
+    return function(event) {
+      return __method.apply(object, [event || window.event].concat(args));
+    }
+  },
+
+  curry: function() {
+    if (!arguments.length) return this;
+    var __method = this, args = $A(arguments);
+    return function() {
+      return __method.apply(this, args.concat($A(arguments)));
+    }
+  },
+
+  delay: function() {
+    var __method = this, args = $A(arguments), timeout = args.shift() * 1000;
+    return window.setTimeout(function() {
+      return __method.apply(__method, args);
+    }, timeout);
+  },
+
+  defer: function() {
+    var args = [0.01].concat($A(arguments));
+    return this.delay.apply(this, args);
+  },
+
+  wrap: function(wrapper) {
+    var __method = this;
+    return function() {
+      return wrapper.apply(this, [__method.bind(this)].concat($A(arguments)));
+    }
+  },
+
+  methodize: function() {
+    if (this._methodized) return this._methodized;
+    var __method = this;
+    return this._methodized = function() {
+      return __method.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 returnValue;
+
+    for (var i = 0, length = arguments.length; i < length; i++) {
+      var lambda = arguments[i];
+      try {
+        returnValue = lambda();
+        break;
+      } catch (e) { }
+    }
+
+    return returnValue;
+  }
+};
+
+RegExp.prototype.match = RegExp.prototype.test;
+
+RegExp.escape = function(str) {
+  return String(str).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1');
+};
+
+/*--------------------------------------------------------------------------*/
+
+var PeriodicalExecuter = Class.create({
+  initialize: function(callback, frequency) {
+    this.callback = callback;
+    this.frequency = frequency;
+    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(value) {
+    return value == null ? '' : String(value);
+  },
+  specialChar: {
+    '\b': '\\b',
+    '\t': '\\t',
+    '\n': '\\n',
+    '\f': '\\f',
+    '\r': '\\r',
+    '\\': '\\\\'
+  }
+});
+
+Object.extend(String.prototype, {
+  gsub: function(pattern, replacement) {
+    var result = '', source = this, match;
+    replacement = arguments.callee.prepareReplacement(replacement);
+
+    while (source.length > 0) {
+      if (match = source.match(pattern)) {
+        result += source.slice(0, match.index);
+        result += String.interpret(replacement(match));
+        source  = source.slice(match.index + match[0].length);
+      } else {
+        result += source, source = '';
+      }
+    }
+    return result;
+  },
+
+  sub: function(pattern, replacement, count) {
+    replacement = this.gsub.prepareReplacement(replacement);
+    count = Object.isUndefined(count) ? 1 : count;
+
+    return this.gsub(pattern, function(match) {
+      if (--count < 0) return match[0];
+      return replacement(match);
+    });
+  },
+
+  scan: function(pattern, iterator) {
+    this.gsub(pattern, iterator);
+    return String(this);
+  },
+
+  truncate: function(length, truncation) {
+    length = length || 30;
+    truncation = Object.isUndefined(truncation) ? '...' : truncation;
+    return this.length > length ?
+      this.slice(0, length - truncation.length) + truncation : 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 matchAll = new RegExp(Prototype.ScriptFragment, 'img');
+    var matchOne = new RegExp(Prototype.ScriptFragment, 'im');
+    return (this.match(matchAll) || []).map(function(scriptTag) {
+      return (scriptTag.match(matchOne) || ['', ''])[1];
+    });
+  },
+
+  evalScripts: function() {
+    return this.extractScripts().map(function(script) { return eval(script) });
+  },
+
+  escapeHTML: function() {
+    var self = arguments.callee;
+    self.text.data = this;
+    return self.div.innerHTML;
+  },
+
+  unescapeHTML: function() {
+    var div = new Element('div');
+    div.innerHTML = this.stripTags();
+    return div.childNodes[0] ? (div.childNodes.length > 1 ?
+      $A(div.childNodes).inject('', function(memo, node) { return memo+node.nodeValue }) :
+      div.childNodes[0].nodeValue) : '';
+  },
+
+  toQueryParams: function(separator) {
+    var match = this.strip().match(/([^?#]*)(#.*)?$/);
+    if (!match) return { };
+
+    return match[1].split(separator || '&').inject({ }, function(hash, pair) {
+      if ((pair = pair.split('='))[0]) {
+        var key = decodeURIComponent(pair.shift());
+        var value = pair.length > 1 ? pair.join('=') : pair[0];
+        if (value != undefined) value = decodeURIComponent(value);
+
+        if (key in hash) {
+          if (!Object.isArray(hash[key])) hash[key] = [hash[key]];
+          hash[key].push(value);
+        }
+        else hash[key] = value;
+      }
+      return hash;
+    });
+  },
+
+  toArray: function() {
+    return this.split('');
+  },
+
+  succ: function() {
+    return this.slice(0, this.length - 1) +
+      String.fromCharCode(this.charCodeAt(this.length - 1) + 1);
+  },
+
+  times: function(count) {
+    return count < 1 ? '' : new Array(count + 1).join(this);
+  },
+
+  camelize: function() {
+    var parts = this.split('-'), len = parts.length;
+    if (len == 1) return parts[0];
+
+    var camelized = this.charAt(0) == '-'
+      ? parts[0].charAt(0).toUpperCase() + parts[0].substring(1)
+      : parts[0];
+
+    for (var i = 1; i < len; i++)
+      camelized += parts[i].charAt(0).toUpperCase() + parts[i].substring(1);
+
+    return camelized;
+  },
+
+  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(useDoubleQuotes) {
+    var escapedString = this.gsub(/[\x00-\x1f\\]/, function(match) {
+      var character = String.specialChar[match[0]];
+      return character ? character : '\\u00' + match[0].charCodeAt().toPaddedString(2, 16);
+    });
+    if (useDoubleQuotes) return '"' + escapedString.replace(/"/g, '\\"') + '"';
+    return "'" + escapedString.replace(/'/g, '\\\'') + "'";
+  },
+
+  toJSON: function() {
+    return this.inspect(true);
+  },
+
+  unfilterJSON: function(filter) {
+    return this.sub(filter || Prototype.JSONFilter, '#{1}');
+  },
+
+  isJSON: function() {
+    var str = this;
+    if (str.blank()) return false;
+    str = this.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, '');
+    return (/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(str);
+  },
+
+  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(pattern) {
+    return this.indexOf(pattern) > -1;
+  },
+
+  startsWith: function(pattern) {
+    return this.indexOf(pattern) === 0;
+  },
+
+  endsWith: function(pattern) {
+    var d = this.length - pattern.length;
+    return d >= 0 && this.lastIndexOf(pattern) === d;
+  },
+
+  empty: function() {
+    return this == '';
+  },
+
+  blank: function() {
+    return /^\s*$/.test(this);
+  },
+
+  interpolate: function(object, pattern) {
+    return new Template(this, pattern).evaluate(object);
+  }
+});
+
+if (Prototype.Browser.WebKit || Prototype.Browser.IE) Object.extend(String.prototype, {
+  escapeHTML: function() {
+    return this.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
+  },
+  unescapeHTML: function() {
+    return this.stripTags().replace(/&amp;/g,'&').replace(/&lt;/g,'<').replace(/&gt;/g,'>');
+  }
+});
+
+String.prototype.gsub.prepareReplacement = function(replacement) {
+  if (Object.isFunction(replacement)) return replacement;
+  var template = new Template(replacement);
+  return function(match) { return template.evaluate(match) };
+};
+
+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(template, pattern) {
+    this.template = template.toString();
+    this.pattern = pattern || Template.Pattern;
+  },
+
+  evaluate: function(object) {
+    if (Object.isFunction(object.toTemplateReplacements))
+      object = object.toTemplateReplacements();
+
+    return this.template.gsub(this.pattern, function(match) {
+      if (object == null) return '';
+
+      var before = match[1] || '';
+      if (before == '\\') return match[2];
+
+      var ctx = object, expr = match[3];
+      var pattern = /^([^.[]+|\[((?:.*?[^\\])?)\])(\.|\[|$)/;
+      match = pattern.exec(expr);
+      if (match == null) return before;
+
+      while (match != null) {
+        var comp = match[1].startsWith('[') ? match[2].gsub('\\\\]', ']') : match[1];
+        ctx = ctx[comp];
+        if (null == ctx || '' == match[3]) break;
+        expr = expr.substring('[' == match[3] ? match[1].length : match[0].length);
+        match = pattern.exec(expr);
+      }
+
+      return before + String.interpret(ctx);
+    });
+  }
+});
+Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/;
+
+var $break = { };
+
+var Enumerable = {
+  each: function(iterator, context) {
+    var index = 0;
+    try {
+      this._each(function(value) {
+        iterator.call(context, value, index++);
+      });
+    } catch (e) {
+      if (e != $break) throw e;
+    }
+    return this;
+  },
+
+  eachSlice: function(number, iterator, context) {
+    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 || Prototype.K;
+    var result = true;
+    this.each(function(value, index) {
+      result = result && !!iterator.call(context, value, index);
+      if (!result) throw $break;
+    });
+    return result;
+  },
+
+  any: function(iterator, context) {
+    iterator = iterator || Prototype.K;
+    var result = false;
+    this.each(function(value, index) {
+      if (result = !!iterator.call(context, value, index))
+        throw $break;
+    });
+    return result;
+  },
+
+  collect: function(iterator, context) {
+    iterator = iterator || Prototype.K;
+    var results = [];
+    this.each(function(value, index) {
+      results.push(iterator.call(context, value, index));
+    });
+    return results;
+  },
+
+  detect: function(iterator, context) {
+    var result;
+    this.each(function(value, index) {
+      if (iterator.call(context, value, index)) {
+        result = value;
+        throw $break;
+      }
+    });
+    return result;
+  },
+
+  findAll: function(iterator, context) {
+    var results = [];
+    this.each(function(value, index) {
+      if (iterator.call(context, value, index))
+        results.push(value);
+    });
+    return results;
+  },
+
+  grep: function(filter, iterator, context) {
+    iterator = iterator || Prototype.K;
+    var results = [];
+
+    if (Object.isString(filter))
+      filter = new RegExp(filter);
+
+    this.each(function(value, index) {
+      if (filter.match(value))
+        results.push(iterator.call(context, value, index));
+    });
+    return results;
+  },
+
+  include: function(object) {
+    if (Object.isFunction(this.indexOf))
+      if (this.indexOf(object) != -1) return true;
+
+    var found = false;
+    this.each(function(value) {
+      if (value == object) {
+        found = true;
+        throw $break;
+      }
+    });
+    return found;
+  },
+
+  inGroupsOf: function(number, fillWith) {
+    fillWith = Object.isUndefined(fillWith) ? null : fillWith;
+    return this.eachSlice(number, function(slice) {
+      while(slice.length < number) slice.push(fillWith);
+      return slice;
+    });
+  },
+
+  inject: function(memo, iterator, context) {
+    this.each(function(value, index) {
+      memo = iterator.call(context, memo, value, index);
+    });
+    return memo;
+  },
+
+  invoke: function(method) {
+    var args = $A(arguments).slice(1);
+    return this.map(function(value) {
+      return value[method].apply(value, args);
+    });
+  },
+
+  max: function(iterator, context) {
+    iterator = iterator || Prototype.K;
+    var result;
+    this.each(function(value, index) {
+      value = iterator.call(context, value, index);
+      if (result == null || value >= result)
+        result = value;
+    });
+    return result;
+  },
+
+  min: function(iterator, context) {
+    iterator = iterator || Prototype.K;
+    var result;
+    this.each(function(value, index) {
+      value = iterator.call(context, value, index);
+      if (result == null || value < result)
+        result = value;
+    });
+    return result;
+  },
+
+  partition: function(iterator, context) {
+    iterator = iterator || Prototype.K;
+    var trues = [], falses = [];
+    this.each(function(value, index) {
+      (iterator.call(context, value, index) ?
+        trues : falses).push(value);
+    });
+    return [trues, falses];
+  },
+
+  pluck: function(property) {
+    var results = [];
+    this.each(function(value) {
+      results.push(value[property]);
+    });
+    return results;
+  },
+
+  reject: function(iterator, context) {
+    var results = [];
+    this.each(function(value, index) {
+      if (!iterator.call(context, value, index))
+        results.push(value);
+    });
+    return results;
+  },
+
+  sortBy: function(iterator, context) {
+    return this.map(function(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;
+    }).pluck('value');
+  },
+
+  toArray: function() {
+    return this.map();
+  },
+
+  zip: function() {
+    var iterator = Prototype.K, args = $A(arguments);
+    if (Object.isFunction(args.last()))
+      iterator = args.pop();
+
+    var collections = [this].concat(args).map($A);
+    return this.map(function(value, index) {
+      return iterator(collections.pluck(index));
+    });
+  },
+
+  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(iterable) {
+  if (!iterable) return [];
+  if (iterable.toArray) return iterable.toArray();
+  var length = iterable.length || 0, results = new Array(length);
+  while (length--) results[length] = iterable[length];
+  return results;
+}
+
+if (Prototype.Browser.WebKit) {
+  $A = function(iterable) {
+    if (!iterable) return [];
+    // 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;
+  };
+}
+
+Array.from = $A;
+
+Object.extend(Array.prototype, Enumerable);
+
+if (!Array.prototype._reverse) Array.prototype._reverse = Array.prototype.reverse;
+
+Object.extend(Array.prototype, {
+  _each: function(iterator) {
+    for (var i = 0, length = this.length; i < length; i++)
+      iterator(this[i]);
+  },
+
+  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(value) {
+      return value != null;
+    });
+  },
+
+  flatten: function() {
+    return this.inject([], function(array, value) {
+      return array.concat(Object.isArray(value) ?
+        value.flatten() : [value]);
+    });
+  },
+
+  without: function() {
+    var values = $A(arguments);
+    return this.select(function(value) {
+      return !values.include(value);
+    });
+  },
+
+  reverse: function(inline) {
+    return (inline !== false ? this : this.toArray())._reverse();
+  },
+
+  reduce: function() {
+    return this.length > 1 ? this : this[0];
+  },
+
+  uniq: function(sorted) {
+    return this.inject([], function(array, value, index) {
+      if (0 == index || (sorted ? array.last() != value : !array.include(value)))
+        array.push(value);
+      return array;
+    });
+  },
+
+  intersect: function(array) {
+    return this.uniq().findAll(function(item) {
+      return array.detect(function(value) { return item === value });
+    });
+  },
+
+  clone: function() {
+    return [].concat(this);
+  },
+
+  size: function() {
+    return this.length;
+  },
+
+  inspect: function() {
+    return '[' + this.map(Object.inspect).join(', ') + ']';
+  },
+
+  toJSON: function() {
+    var results = [];
+    this.each(function(object) {
+      var value = Object.toJSON(object);
+      if (!Object.isUndefined(value)) results.push(value);
+    });
+    return '[' + results.join(', ') + ']';
+  }
+});
+
+// use native browser JS 1.6 implementation if available
+if (Object.isFunction(Array.prototype.forEach))
+  Array.prototype._each = Array.prototype.forEach;
+
+if (!Array.prototype.indexOf) Array.prototype.indexOf = function(item, i) {
+  i || (i = 0);
+  var length = this.length;
+  if (i < 0) i = length + i;
+  for (; i < length; i++)
+    if (this[i] === item) return i;
+  return -1;
+};
+
+if (!Array.prototype.lastIndexOf) Array.prototype.lastIndexOf = function(item, i) {
+  i = isNaN(i) ? this.length : (i < 0 ? this.length + i : i) + 1;
+  var n = this.slice(0, i).reverse().indexOf(item);
+  return (n < 0) ? n : i - n - 1;
+};
+
+Array.prototype.toArray = Array.prototype.clone;
+
+function $w(string) {
+  if (!Object.isString(string)) return [];
+  string = string.strip();
+  return string ? string.split(/\s+/) : [];
+}
+
+if (Prototype.Browser.Opera){
+  Array.prototype.concat = function() {
+    var array = [];
+    for (var i = 0, length = this.length; i < length; i++) array.push(this[i]);
+    for (var i = 0, length = arguments.length; i < length; i++) {
+      if (Object.isArray(arguments[i])) {
+        for (var j = 0, arrayLength = arguments[i].length; j < arrayLength; j++)
+          array.push(arguments[i][j]);
+      } else {
+        array.push(arguments[i]);
+      }
+    }
+    return array;
+  };
+}
+Object.extend(Number.prototype, {
+  toColorPart: function() {
+    return this.toPaddedString(2, 16);
+  },
+
+  succ: function() {
+    return this + 1;
+  },
+
+  times: function(iterator, context) {
+    $R(0, this, true).each(iterator, context);
+    return this;
+  },
+
+  toPaddedString: function(length, radix) {
+    var string = this.toString(radix || 10);
+    return '0'.times(length - string.length) + string;
+  },
+
+  toJSON: function() {
+    return isFinite(this) ? this.toString() : 'null';
+  }
+});
+
+$w('abs round ceil floor').each(function(method){
+  Number.prototype[method] = Math[method].methodize();
+});
+function $H(object) {
+  return new Hash(object);
+};
+
+var Hash = Class.create(Enumerable, (function() {
+
+  function toQueryPair(key, value) {
+    if (Object.isUndefined(value)) return key;
+    return key + '=' + encodeURIComponent(String.interpret(value));
+  }
+
+  return {
+    initialize: function(object) {
+      this._object = Object.isHash(object) ? object.toObject() : Object.clone(object);
+    },
+
+    _each: function(iterator) {
+      for (var key in this._object) {
+        var value = this._object[key], pair = [key, value];
+        pair.key = key;
+        pair.value = value;
+        iterator(pair);
+      }
+    },
+
+    set: function(key, value) {
+      return this._object[key] = value;
+    },
+
+    get: function(key) {
+      // simulating poorly supported hasOwnProperty
+      if (this._object[key] !== Object.prototype[key])
+        return this._object[key];
+    },
+
+    unset: function(key) {
+      var value = this._object[key];
+      delete this._object[key];
+      return value;
+    },
+
+    toObject: function() {
+      return Object.clone(this._object);
+    },
+
+    keys: function() {
+      return this.pluck('key');
+    },
+
+    values: function() {
+      return this.pluck('value');
+    },
+
+    index: function(value) {
+      var match = this.detect(function(pair) {
+        return pair.value === value;
+      });
+      return match && match.key;
+    },
+
+    merge: function(object) {
+      return this.clone().update(object);
+    },
+
+    update: function(object) {
+      return new Hash(object).inject(this, function(result, pair) {
+        result.set(pair.key, pair.value);
+        return result;
+      });
+    },
+
+    toQueryString: function() {
+      return this.inject([], function(results, pair) {
+        var key = encodeURIComponent(pair.key), values = pair.value;
+
+        if (values && typeof values == 'object') {
+          if (Object.isArray(values))
+            return results.concat(values.map(toQueryPair.curry(key)));
+        } else results.push(toQueryPair(key, values));
+        return results;
+      }).join('&');
+    },
+
+    inspect: function() {
+      return '#<Hash:{' + this.map(function(pair) {
+        return pair.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(start, end, exclusive) {
+    this.start = start;
+    this.end = end;
+    this.exclusive = exclusive;
+  },
+
+  _each: function(iterator) {
+    var value = this.start;
+    while (this.include(value)) {
+      iterator(value);
+      value = value.succ();
+    }
+  },
+
+  include: function(value) {
+    if (value < this.start)
+      return false;
+    if (this.exclusive)
+      return value < this.end;
+    return value <= this.end;
+  }
+});
+
+var $R = function(start, end, exclusive) {
+  return new ObjectRange(start, end, exclusive);
+};
+
+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(iterator) {
+    this.responders._each(iterator);
+  },
+
+  register: function(responder) {
+    if (!this.include(responder))
+      this.responders.push(responder);
+  },
+
+  unregister: function(responder) {
+    this.responders = this.responders.without(responder);
+  },
+
+  dispatch: function(callback, request, transport, json) {
+    this.each(function(responder) {
+      if (Object.isFunction(responder[callback])) {
+        try {
+          responder[callback].apply(responder, [request, transport, json]);
+        } catch (e) { }
+      }
+    });
+  }
+};
+
+Object.extend(Ajax.Responders, Enumerable);
+
+Ajax.Responders.register({
+  onCreate:   function() { Ajax.activeRequestCount++ },
+  onComplete: function() { Ajax.activeRequestCount-- }
+});
+
+Ajax.Base = Class.create({
+  initialize: function(options) {
+    this.options = {
+      method:       'post',
+      asynchronous: true,
+      contentType:  'application/x-www-form-urlencoded',
+      encoding:     'UTF-8',
+      parameters:   '',
+      evalJSON:     true,
+      evalJS:       true
+    };
+    Object.extend(this.options, options || { });
+
+    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, url, options) {
+    $super(options);
+    this.transport = Ajax.getTransport();
+    this.request(url);
+  },
+
+  request: function(url) {
+    this.url = url;
+    this.method = this.options.method;
+    var params = Object.clone(this.options.parameters);
+
+    if (!['get', 'post'].include(this.method)) {
+      // simulate other verbs over post
+      params['_method'] = this.method;
+      this.method = 'post';
+    }
+
+    this.parameters = params;
+
+    if (params = Object.toQueryString(params)) {
+      // when GET, append parameters to URL
+      if (this.method == 'get')
+        this.url += (this.url.include('?') ? '&' : '?') + params;
+      else if (/Konqueror|Safari|KHTML/.test(navigator.userAgent))
+        params += '&_=';
+    }
+
+    try {
+      var response = new Ajax.Response(this);
+      if (this.options.onCreate) this.options.onCreate(response);
+      Ajax.Responders.dispatch('onCreate', this, response);
+
+      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 || params) : null;
+      this.transport.send(this.body);
+
+      /* Force Firefox to handle ready state 4 for synchronous requests */
+      if (!this.options.asynchronous && this.transport.overrideMimeType)
+        this.onStateChange();
+
+    }
+    catch (e) {
+      this.dispatchException(e);
+    }
+  },
+
+  onStateChange: function() {
+    var readyState = this.transport.readyState;
+    if (readyState > 1 && !((readyState == 4) && this._complete))
+      this.respondToReadyState(this.transport.readyState);
+  },
+
+  setRequestHeaders: function() {
+    var headers = {
+      'X-Requested-With': 'XMLHttpRequest',
+      'X-Prototype-Version': Prototype.Version,
+      'Accept': 'text/javascript, text/html, application/xml, text/xml, */*'
+    };
+
+    if (this.method == 'post') {
+      headers['Content-type'] = this.options.contentType +
+        (this.options.encoding ? '; charset=' + this.options.encoding : '');
+
+      /* Force "Connection: close" for older Mozilla browsers to work
+       * around a bug where XMLHttpRequest sends an incorrect
+       * Content-length header. See Mozilla Bugzilla #246651.
+       */
+      if (this.transport.overrideMimeType &&
+          (navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005)
+            headers['Connection'] = 'close';
+    }
+
+    // user-defined headers
+    if (typeof this.options.requestHeaders == 'object') {
+      var extras = this.options.requestHeaders;
+
+      if (Object.isFunction(extras.push))
+        for (var i = 0, length = extras.length; i < length; i += 2)
+          headers[extras[i]] = extras[i+1];
+      else
+        $H(extras).each(function(pair) { headers[pair.key] = pair.value });
+    }
+
+    for (var name in headers)
+      this.transport.setRequestHeader(name, headers[name]);
+  },
+
+  success: function() {
+    var status = this.getStatus();
+    return !status || (status >= 200 && status < 300);
+  },
+
+  getStatus: function() {
+    try {
+      return this.transport.status || 0;
+    } catch (e) { return 0 }
+  },
+
+  respondToReadyState: function(readyState) {
+    var state = Ajax.Request.Events[readyState], response = new Ajax.Response(this);
+
+    if (state == 'Complete') {
+      try {
+        this._complete = true;
+        (this.options['on' + response.status]
+         || this.options['on' + (this.success() ? 'Success' : 'Failure')]
+         || Prototype.emptyFunction)(response, response.headerJSON);
+      } catch (e) {
+        this.dispatchException(e);
+      }
+
+      var contentType = response.getHeader('Content-type');
+      if (this.options.evalJS == 'force'
+          || (this.options.evalJS && this.isSameOrigin() && contentType
+          && contentType.match(/^\s*(text|application)\/(x-)?(java|ecma)script(;.*)?\s*$/i)))
+        this.evalResponse();
+    }
+
+    try {
+      (this.options['on' + state] || Prototype.emptyFunction)(response, response.headerJSON);
+      Ajax.Responders.dispatch('on' + state, this, response, response.headerJSON);
+    } catch (e) {
+      this.dispatchException(e);
+    }
+
+    if (state == 'Complete') {
+      // avoid memory leak in MSIE: clean up
+      this.transport.onreadystatechange = Prototype.emptyFunction;
+    }
+  },
+
+  isSameOrigin: function() {
+    var m = this.url.match(/^\s*https?:\/\/[^\/]*/);
+    return !m || (m[0] == '#{protocol}//#{domain}#{port}'.interpolate({
+      protocol: location.protocol,
+      domain: document.domain,
+      port: location.port ? ':' + location.port : ''
+    }));
+  },
+
+  getHeader: function(name) {
+    try {
+      return this.transport.getResponseHeader(name) || null;
+    } catch (e) { return null }
+  },
+
+  evalResponse: function() {
+    try {
+      return eval((this.transport.responseText || '').unfilterJSON());
+    } catch (e) {
+      this.dispatchException(e);
+    }
+  },
+
+  dispatchException: function(exception) {
+    (this.options.onException || Prototype.emptyFunction)(this, exception);
+    Ajax.Responders.dispatch('onException', this, exception);
+  }
+});
+
+Ajax.Request.Events =
+  ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];
+
+Ajax.Response = Class.create({
+  initialize: function(request){
+    this.request = request;
+    var transport  = this.transport  = request.transport,
+        readyState = this.readyState = transport.readyState;
+
+    if((readyState > 2 && !Prototype.Browser.IE) || readyState == 4) {
+      this.status       = this.getStatus();
+      this.statusText   = this.getStatusText();
+      this.responseText = String.interpret(transport.responseText);
+      this.headerJSON   = this._getHeaderJSON();
+    }
+
+    if(readyState == 4) {
+      var xml = transport.responseXML;
+      this.responseXML  = Object.isUndefined(xml) ? null : xml;
+      this.responseJSON = this._getResponseJSON();
+    }
+  },
+
+  status:      0,
+  statusText: '',
+
+  getStatus: Ajax.Request.prototype.getStatus,
+
+  getStatusText: function() {
+    try {
+      return this.transport.statusText || '';
+    } catch (e) { return '' }
+  },
+
+  getHeader: Ajax.Request.prototype.getHeader,
+
+  getAllHeaders: function() {
+    try {
+      return this.getAllResponseHeaders();
+    } catch (e) { return null }
+  },
+
+  getResponseHeader: function(name) {
+    return this.transport.getResponseHeader(name);
+  },
+
+  getAllResponseHeaders: function() {
+    return this.transport.getAllResponseHeaders();
+  },
+
+  _getHeaderJSON: function() {
+    var json = this.getHeader('X-JSON');
+    if (!json) return null;
+    json = decodeURIComponent(escape(json));
+    try {
+      return json.evalJSON(this.request.options.sanitizeJSON ||
+        !this.request.isSameOrigin());
+    } catch (e) {
+      this.request.dispatchException(e);
+    }
+  },
+
+  _getResponseJSON: function() {
+    var options = this.request.options;
+    if (!options.evalJSON || (options.evalJSON != 'force' &&
+      !(this.getHeader('Content-type') || '').include('application/json')) ||
+        this.responseText.blank())
+          return null;
+    try {
+      return this.responseText.evalJSON(options.sanitizeJSON ||
+        !this.request.isSameOrigin());
+    } catch (e) {
+      this.request.dispatchException(e);
+    }
+  }
+});
+
+Ajax.Updater = Class.create(Ajax.Request, {
+  initialize: function($super, container, url, options) {
+    this.container = {
+      success: (container.success || container),
+      failure: (container.failure || (container.success ? null : container))
+    };
+
+    options = Object.clone(options);
+    var onComplete = options.onComplete;
+    options.onComplete = (function(response, json) {
+      this.updateContent(response.responseText);
+      if (Object.isFunction(onComplete)) onComplete(response, json);
+    }).bind(this);
+
+    $super(url, options);
+  },
+
+  updateContent: function(responseText) {
+    var receiver = this.container[this.success() ? 'success' : 'failure'],
+        options = this.options;
+
+    if (!options.evalScripts) responseText = responseText.stripScripts();
+
+    if (receiver = $(receiver)) {
+      if (options.insertion) {
+        if (Object.isString(options.insertion)) {
+          var insertion = { }; insertion[options.insertion] = responseText;
+          receiver.insert(insertion);
+        }
+        else options.insertion(receiver, responseText);
+      }
+      else receiver.update(responseText);
+    }
+  }
+});
+
+Ajax.PeriodicalUpdater = Class.create(Ajax.Base, {
+  initialize: function($super, container, url, options) {
+    $super(options);
+    this.onComplete = this.options.onComplete;
+
+    this.frequency = (this.options.frequency || 2);
+    this.decay = (this.options.decay || 1);
+
+    this.updater = { };
+    this.container = container;
+    this.url = url;
+
+    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(response) {
+    if (this.options.decay) {
+      this.decay = (response.responseText == this.lastText ?
+        this.decay * this.options.decay : 1);
+
+      this.lastText = response.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 $(element) {
+  if (arguments.length > 1) {
+    for (var i = 0, elements = [], length = arguments.length; i < length; i++)
+      elements.push($(arguments[i]));
+    return elements;
+  }
+  if (Object.isString(element))
+    element = document.getElementById(element);
+  return Element.extend(element);
+}
+
+if (Prototype.BrowserFeatures.XPath) {
+  document._getElementsByXPath = function(expression, parentElement) {
+    var results = [];
+    var query = document.evaluate(expression, $(parentElement) || document,
+      null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
+    for (var i = 0, length = query.snapshotLength; i < length; i++)
+      results.push(Element.extend(query.snapshotItem(i)));
+    return results;
+  };
+}
+
+/*--------------------------------------------------------------------------*/
+
+if (!window.Node) var Node = { };
+
+if (!Node.ELEMENT_NODE) {
+  // DOM level 2 ECMAScript Language Binding
+  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 element = this.Element;
+  this.Element = function(tagName, attributes) {
+    attributes = attributes || { };
+    tagName = tagName.toLowerCase();
+    var cache = Element.cache;
+    if (Prototype.Browser.IE && attributes.name) {
+      tagName = '<' + tagName + ' name="' + attributes.name + '">';
+      delete attributes.name;
+      return Element.writeAttribute(document.createElement(tagName), attributes);
+    }
+    if (!cache[tagName]) cache[tagName] = Element.extend(document.createElement(tagName));
+    return Element.writeAttribute(cache[tagName].cloneNode(false), attributes);
+  };
+  Object.extend(this.Element, element || { });
+  if (element) this.Element.prototype = element.prototype;
+}).call(window);
+
+Element.cache = { };
+
+Element.Methods = {
+  visible: function(element) {
+    return $(element).style.display != 'none';
+  },
+
+  toggle: function(element) {
+    element = $(element);
+    Element[Element.visible(element) ? 'hide' : 'show'](element);
+    return element;
+  },
+
+  hide: function(element) {
+    element = $(element);
+    element.style.display = 'none';
+    return element;
+  },
+
+  show: function(element) {
+    element = $(element);
+    element.style.display = '';
+    return element;
+  },
+
+  remove: function(element) {
+    element = $(element);
+    element.parentNode.removeChild(element);
+    return element;
+  },
+
+  update: function(element, content) {
+    element = $(element);
+    if (content && content.toElement) content = content.toElement();
+    if (Object.isElement(content)) return element.update().insert(content);
+    content = Object.toHTML(content);
+    element.innerHTML = content.stripScripts();
+    content.evalScripts.bind(content).defer();
+    return element;
+  },
+
+  replace: function(element, content) {
+    element = $(element);
+    if (content && content.toElement) content = content.toElement();
+    else if (!Object.isElement(content)) {
+      content = Object.toHTML(content);
+      var range = element.ownerDocument.createRange();
+      range.selectNode(element);
+      content.evalScripts.bind(content).defer();
+      content = range.createContextualFragment(content.stripScripts());
+    }
+    element.parentNode.replaceChild(content, element);
+    return element;
+  },
+
+  insert: function(element, insertions) {
+    element = $(element);
+
+    if (Object.isString(insertions) || Object.isNumber(insertions) ||
+        Object.isElement(insertions) || (insertions && (insertions.toElement || insertions.toHTML)))
+          insertions = {bottom:insertions};
+
+    var content, insert, tagName, childNodes;
+
+    for (var position in insertions) {
+      content  = insertions[position];
+      position = position.toLowerCase();
+      insert = Element._insertionTranslations[position];
+
+      if (content && content.toElement) content = content.toElement();
+      if (Object.isElement(content)) {
+        insert(element, content);
+        continue;
+      }
+
+      content = Object.toHTML(content);
+
+      tagName = ((position == 'before' || position == 'after')
+        ? element.parentNode : element).tagName.toUpperCase();
+
+      childNodes = Element._getContentFromAnonymousElement(tagName, content.stripScripts());
+
+      if (position == 'top' || position == 'after') childNodes.reverse();
+      childNodes.each(insert.curry(element));
+
+      content.evalScripts.bind(content).defer();
+    }
+
+    return element;
+  },
+
+  wrap: function(element, wrapper, attributes) {
+    element = $(element);
+    if (Object.isElement(wrapper))
+      $(wrapper).writeAttribute(attributes || { });
+    else if (Object.isString(wrapper)) wrapper = new Element(wrapper, attributes);
+    else wrapper = new Element('div', wrapper);
+    if (element.parentNode)
+      element.parentNode.replaceChild(wrapper, element);
+    wrapper.appendChild(element);
+    return wrapper;
+  },
+
+  inspect: function(element) {
+    element = $(element);
+    var result = '<' + element.tagName.toLowerCase();
+    $H({'id': 'id', 'className': 'class'}).each(function(pair) {
+      var property = pair.first(), attribute = pair.last();
+      var value = (element[property] || '').toString();
+      if (value) result += ' ' + attribute + '=' + value.inspect(true);
+    });
+    return result + '>';
+  },
+
+  recursivelyCollect: function(element, property) {
+    element = $(element);
+    var elements = [];
+    while (element = element[property])
+      if (element.nodeType == 1)
+        elements.push(Element.extend(element));
+    return elements;
+  },
+
+  ancestors: function(element) {
+    return $(element).recursivelyCollect('parentNode');
+  },
+
+  descendants: function(element) {
+    return $(element).select("*");
+  },
+
+  firstDescendant: function(element) {
+    element = $(element).firstChild;
+    while (element && element.nodeType != 1) element = element.nextSibling;
+    return $(element);
+  },
+
+  immediateDescendants: function(element) {
+    if (!(element = $(element).firstChild)) return [];
+    while (element && element.nodeType != 1) element = element.nextSibling;
+    if (element) return [element].concat($(element).nextSiblings());
+    return [];
+  },
+
+  previousSiblings: function(element) {
+    return $(element).recursivelyCollect('previousSibling');
+  },
+
+  nextSiblings: function(element) {
+    return $(element).recursivelyCollect('nextSibling');
+  },
+
+  siblings: function(element) {
+    element = $(element);
+    return element.previousSiblings().reverse().concat(element.nextSiblings());
+  },
+
+  match: function(element, selector) {
+    if (Object.isString(selector))
+      selector = new Selector(selector);
+    return selector.match($(element));
+  },
+
+  up: function(element, expression, index) {
+    element = $(element);
+    if (arguments.length == 1) return $(element.parentNode);
+    var ancestors = element.ancestors();
+    return Object.isNumber(expression) ? ancestors[expression] :
+      Selector.findElement(ancestors, expression, index);
+  },
+
+  down: function(element, expression, index) {
+    element = $(element);
+    if (arguments.length == 1) return element.firstDescendant();
+    return Object.isNumber(expression) ? element.descendants()[expression] :
+      Element.select(element, expression)[index || 0];
+  },
+
+  previous: function(element, expression, index) {
+    element = $(element);
+    if (arguments.length == 1) return $(Selector.handlers.previousElementSibling(element));
+    var previousSiblings = element.previousSiblings();
+    return Object.isNumber(expression) ? previousSiblings[expression] :
+      Selector.findElement(previousSiblings, expression, index);
+  },
+
+  next: function(element, expression, index) {
+    element = $(element);
+    if (arguments.length == 1) return $(Selector.handlers.nextElementSibling(element));
+    var nextSiblings = element.nextSiblings();
+    return Object.isNumber(expression) ? nextSiblings[expression] :
+      Selector.findElement(nextSiblings, expression, index);
+  },
+
+  select: function() {
+    var args = $A(arguments), element = $(args.shift());
+    return Selector.findChildElements(element, args);
+  },
+
+  adjacent: function() {
+    var args = $A(arguments), element = $(args.shift());
+    return Selector.findChildElements(element.parentNode, args).without(element);
+  },
+
+  identify: function(element) {
+    element = $(element);
+    var id = element.readAttribute('id'), self = arguments.callee;
+    if (id) return id;
+    do { id = 'anonymous_element_' + self.counter++ } while ($(id));
+    element.writeAttribute('id', id);
+    return id;
+  },
+
+  readAttribute: function(element, name) {
+    element = $(element);
+    if (Prototype.Browser.IE) {
+      var t = Element._attributeTranslations.read;
+      if (t.values[name]) return t.values[name](element, name);
+      if (t.names[name]) name = t.names[name];
+      if (name.include(':')) {
+        return (!element.attributes || !element.attributes[name]) ? null :
+         element.attributes[name].value;
+      }
+    }
+    return element.getAttribute(name);
+  },
+
+  writeAttribute: function(element, name, value) {
+    element = $(element);
+    var attributes = { }, t = Element._attributeTranslations.write;
+
+    if (typeof name == 'object') attributes = name;
+    else attributes[name] = Object.isUndefined(value) ? true : value;
+
+    for (var attr in attributes) {
+      name = t.names[attr] || attr;
+      value = attributes[attr];
+      if (t.values[attr]) name = t.values[attr](element, value);
+      if (value === false || value === null)
+        element.removeAttribute(name);
+      else if (value === true)
+        element.setAttribute(name, name);
+      else element.setAttribute(name, value);
+    }
+    return element;
+  },
+
+  getHeight: function(element) {
+    return $(element).getDimensions().height;
+  },
+
+  getWidth: function(element) {
+    return $(element).getDimensions().width;
+  },
+
+  classNames: function(element) {
+    return new Element.ClassNames(element);
+  },
+
+  hasClassName: function(element, className) {
+    if (!(element = $(element))) return;
+    var elementClassName = element.className;
+    return (elementClassName.length > 0 && (elementClassName == className ||
+      new RegExp("(^|\\s)" + className + "(\\s|$)").test(elementClassName)));
+  },
+
+  addClassName: function(element, className) {
+    if (!(element = $(element))) return;
+    if (!element.hasClassName(className))
+      element.className += (element.className ? ' ' : '') + className;
+    return element;
+  },
+
+  removeClassName: function(element, className) {
+    if (!(element = $(element))) return;
+    element.className = element.className.replace(
+      new RegExp("(^|\\s+)" + className + "(\\s+|$)"), ' ').strip();
+    return element;
+  },
+
+  toggleClassName: function(element, className) {
+    if (!(element = $(element))) return;
+    return element[element.hasClassName(className) ?
+      'removeClassName' : 'addClassName'](className);
+  },
+
+  // removes whitespace-only text node children
+  cleanWhitespace: function(element) {
+    element = $(element);
+    var node = element.firstChild;
+    while (node) {
+      var nextNode = node.nextSibling;
+      if (node.nodeType == 3 && !/\S/.test(node.nodeValue))
+        element.removeChild(node);
+      node = nextNode;
+    }
+    return element;
+  },
+
+  empty: function(element) {
+    return $(element).innerHTML.blank();
+  },
+
+  descendantOf: function(element, ancestor) {
+    element = $(element), ancestor = $(ancestor);
+
+    if (element.compareDocumentPosition)
+      return (element.compareDocumentPosition(ancestor) & 8) === 8;
+
+    if (ancestor.contains)
+      return ancestor.contains(element) && ancestor !== element;
+
+    while (element = element.parentNode)
+      if (element == ancestor) return true;
+
+    return false;
+  },
+
+  scrollTo: function(element) {
+    element = $(element);
+    var pos = element.cumulativeOffset();
+    window.scrollTo(pos[0], pos[1]);
+    return element;
+  },
+
+  getStyle: function(element, style) {
+    element = $(element);
+    style = style == 'float' ? 'cssFloat' : style.camelize();
+    var value = element.style[style];
+    if (!value || value == 'auto') {
+      var css = document.defaultView.getComputedStyle(element, null);
+      value = css ? css[style] : null;
+    }
+    if (style == 'opacity') return value ? parseFloat(value) : 1.0;
+    return value == 'auto' ? null : value;
+  },
+
+  getOpacity: function(element) {
+    return $(element).getStyle('opacity');
+  },
+
+  setStyle: function(element, styles) {
+    element = $(element);
+    var elementStyle = element.style, match;
+    if (Object.isString(styles)) {
+      element.style.cssText += ';' + styles;
+      return styles.include('opacity') ?
+        element.setOpacity(styles.match(/opacity:\s*(\d?\.?\d*)/)[1]) : element;
+    }
+    for (var property in styles)
+      if (property == 'opacity') element.setOpacity(styles[property]);
+      else
+        elementStyle[(property == 'float' || property == 'cssFloat') ?
+          (Object.isUndefined(elementStyle.styleFloat) ? 'cssFloat' : 'styleFloat') :
+            property] = styles[property];
+
+    return element;
+  },
+
+  setOpacity: function(element, value) {
+    element = $(element);
+    element.style.opacity = (value == 1 || value === '') ? '' :
+      (value < 0.00001) ? 0 : value;
+    return element;
+  },
+
+  getDimensions: function(element) {
+    element = $(element);
+    var display = element.getStyle('display');
+    if (display != 'none' && display != null) // Safari bug
+      return {width: element.offsetWidth, height: element.offsetHeight};
+
+    // All *Width and *Height properties give 0 on elements with display none,
+    // so enable the element temporarily
+    var els = element.style;
+    var originalVisibility = els.visibility;
+    var originalPosition = els.position;
+    var originalDisplay = els.display;
+    els.visibility = 'hidden';
+    els.position = 'absolute';
+    els.display = 'block';
+    var originalWidth = element.clientWidth;
+    var originalHeight = element.clientHeight;
+    els.display = originalDisplay;
+    els.position = originalPosition;
+    els.visibility = originalVisibility;
+    return {width: originalWidth, height: originalHeight};
+  },
+
+  makePositioned: function(element) {
+    element = $(element);
+    var pos = Element.getStyle(element, 'position');
+    if (pos == 'static' || !pos) {
+      element._madePositioned = true;
+      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 (Prototype.Browser.Opera) {
+        element.style.top = 0;
+        element.style.left = 0;
+      }
+    }
+    return element;
+  },
+
+  undoPositioned: function(element) {
+    element = $(element);
+    if (element._madePositioned) {
+      element._madePositioned = undefined;
+      element.style.position =
+        element.style.top =
+        element.style.left =
+        element.style.bottom =
+        element.style.right = '';
+    }
+    return element;
+  },
+
+  makeClipping: function(element) {
+    element = $(element);
+    if (element._overflow) return element;
+    element._overflow = Element.getStyle(element, 'overflow') || 'auto';
+    if (element._overflow !== 'hidden')
+      element.style.overflow = 'hidden';
+    return element;
+  },
+
+  undoClipping: function(element) {
+    element = $(element);
+    if (!element._overflow) return element;
+    element.style.overflow = element._overflow == 'auto' ? '' : element._overflow;
+    element._overflow = null;
+    return element;
+  },
+
+  cumulativeOffset: function(element) {
+    var valueT = 0, valueL = 0;
+    do {
+      valueT += element.offsetTop  || 0;
+      valueL += element.offsetLeft || 0;
+      element = element.offsetParent;
+    } while (element);
+    return Element._returnOffset(valueL, valueT);
+  },
+
+  positionedOffset: function(element) {
+    var valueT = 0, valueL = 0;
+    do {
+      valueT += element.offsetTop  || 0;
+      valueL += element.offsetLeft || 0;
+      element = element.offsetParent;
+      if (element) {
+        if (element.tagName.toUpperCase() == 'BODY') break;
+        var p = Element.getStyle(element, 'position');
+        if (p !== 'static') break;
+      }
+    } while (element);
+    return Element._returnOffset(valueL, valueT);
+  },
+
+  absolutize: function(element) {
+    element = $(element);
+    if (element.getStyle('position') == 'absolute') return element;
+    // Position.prepare(); // To be done manually by Scripty when it needs it.
+
+    var offsets = element.positionedOffset();
+    var top     = offsets[1];
+    var left    = offsets[0];
+    var width   = element.clientWidth;
+    var height  = element.clientHeight;
+
+    element._originalLeft   = left - parseFloat(element.style.left  || 0);
+    element._originalTop    = top  - parseFloat(element.style.top || 0);
+    element._originalWidth  = element.style.width;
+    element._originalHeight = element.style.height;
+
+    element.style.position = 'absolute';
+    element.style.top    = top + 'px';
+    element.style.left   = left + 'px';
+    element.style.width  = width + 'px';
+    element.style.height = height + 'px';
+    return element;
+  },
+
+  relativize: function(element) {
+    element = $(element);
+    if (element.getStyle('position') == 'relative') return element;
+    // Position.prepare(); // To be done manually by Scripty when it needs it.
+
+    element.style.position = 'relative';
+    var top  = parseFloat(element.style.top  || 0) - (element._originalTop || 0);
+    var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0);
+
+    element.style.top    = top + 'px';
+    element.style.left   = left + 'px';
+    element.style.height = element._originalHeight;
+    element.style.width  = element._originalWidth;
+    return element;
+  },
+
+  cumulativeScrollOffset: function(element) {
+    var valueT = 0, valueL = 0;
+    do {
+      valueT += element.scrollTop  || 0;
+      valueL += element.scrollLeft || 0;
+      element = element.parentNode;
+    } while (element);
+    return Element._returnOffset(valueL, valueT);
+  },
+
+  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)
+      if (Element.getStyle(element, 'position') != 'static')
+        return $(element);
+
+    return $(body);
+  },
+
+  viewportOffset: function(forElement) {
+    forElement = $(forElement);
+
+    var element = forElement, valueT = 0, valueL = 0;
+    do {
+      valueT += element.offsetTop  || 0;
+      valueL += element.offsetLeft || 0;
+    } while ((element = element.getOffsetParent()) != document.body);
+
+    element = forElement;
+    do {
+      if (!Prototype.Browser.Opera || (element.tagName && (element.tagName.toUpperCase() == 'BODY'))) {
+        valueT -= element.scrollTop  || 0;
+        valueL -= element.scrollLeft || 0;
+      }
+    } while (element = element.parentNode);
+
+    return Element._returnOffset(valueL, valueT);
+  },
+
+  clonePosition: function(element, source) {
+    var options = Object.extend({
+      setLeft:    true,
+      setTop:     true,
+      setWidth:   true,
+      setHeight:  true,
+      offsetTop:  0,
+      offsetLeft: 0
+    }, arguments[2] || { });
+
+    // find page position of source
+    source = $(source);
+    var p = source.viewportOffset();
+
+    // find coordinate system to use
+    element = $(element);
+    var delta = [0, 0];
+    var parent = null;
+    // delta [0,0] will do fine with position: fixed elements,
+    // position:absolute needs offsetParent deltas
+    if (Element.getStyle(element, 'position') == 'absolute') {
+      parent = element.getOffsetParent();
+      delta = parent.viewportOffset();
+    }
+
+    // correct by body offsets (fixes Safari)
+    if (parent == document.body) {
+      delta[0] -= document.body.offsetLeft;
+      delta[1] -= document.body.offsetTop;
+    }
+
+    // set position
+    if (options.setLeft)   element.style.left  = (p[0] - delta[0] + options.offsetLeft) + 'px';
+    if (options.setTop)    element.style.top   = (p[1] - delta[1] + options.offsetTop) + 'px';
+    if (options.setWidth)  element.style.width = source.offsetWidth + 'px';
+    if (options.setHeight) element.style.height = source.offsetHeight + 'px';
+    return element;
+  }
+};
+
+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(proceed, element, style) {
+      switch (style) {
+        case 'left': case 'top': case 'right': case 'bottom':
+          if (proceed(element, 'position') === 'static') return null;
+        case 'height': case 'width':
+          // returns '0px' for hidden elements; we want it to return null
+          if (!Element.visible(element)) return null;
+
+          // returns the border-box dimensions rather than the content-box
+          // dimensions, so we subtract padding and borders from the value
+          var dim = parseInt(proceed(element, style), 10);
+
+          if (dim !== element['offset' + style.capitalize()])
+            return dim + 'px';
+
+          var properties;
+          if (style === 'height') {
+            properties = ['border-top-width', 'padding-top',
+             'padding-bottom', 'border-bottom-width'];
+          }
+          else {
+            properties = ['border-left-width', 'padding-left',
+             'padding-right', 'border-right-width'];
+          }
+          return properties.inject(dim, function(memo, property) {
+            var val = proceed(element, property);
+            return val === null ? memo : memo - parseInt(val, 10);
+          }) + 'px';
+        default: return proceed(element, style);
+      }
+    }
+  );
+
+  Element.Methods.readAttribute = Element.Methods.readAttribute.wrap(
+    function(proceed, element, attribute) {
+      if (attribute === 'title') return element.title;
+      return proceed(element, attribute);
+    }
+  );
+}
+
+else if (Prototype.Browser.IE) {
+  // IE doesn't report offsets correctly for static elements, so we change them
+  // to "relative" to get the values, then change them back.
+  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' });
+      var value = proceed(element);
+      element.setStyle({ position: position });
+      return value;
+    }
+  );
+
+  $w('positionedOffset viewportOffset').each(function(method) {
+    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
+        // accurate offsetTop and offsetLeft values for position: fixed.
+        var offsetParent = element.getOffsetParent();
+        if (offsetParent && offsetParent.getStyle('position') === 'fixed')
+          offsetParent.setStyle({ zoom: 1 });
+        element.setStyle({ position: 'relative' });
+        var value = proceed(element);
+        element.setStyle({ position: position });
+        return value;
+      }
+    );
+  });
+
+  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();
+    var value = element.style[style];
+    if (!value && element.currentStyle) value = element.currentStyle[style];
+
+    if (style == 'opacity') {
+      if (value = (element.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/))
+        if (value[1]) return parseFloat(value[1]) / 100;
+      return 1.0;
+    }
+
+    if (value == 'auto') {
+      if ((style == 'width' || style == 'height') && (element.getStyle('display') != 'none'))
+        return element['offset' + style.capitalize()] + 'px';
+      return null;
+    }
+    return value;
+  };
+
+  Element.Methods.setOpacity = function(element, value) {
+    function stripAlpha(filter){
+      return filter.replace(/alpha\([^\)]*\)/gi,'');
+    }
+    element = $(element);
+    var currentStyle = element.currentStyle;
+    if ((currentStyle && !currentStyle.hasLayout) ||
+      (!currentStyle && element.style.zoom == 'normal'))
+        element.style.zoom = 1;
+
+    var filter = element.getStyle('filter'), style = element.style;
+    if (value == 1 || value === '') {
+      (filter = stripAlpha(filter)) ?
+        style.filter = filter : style.removeAttribute('filter');
+      return element;
+    } else if (value < 0.00001) value = 0;
+    style.filter = stripAlpha(filter) +
+      'alpha(opacity=' + (value * 100) + ')';
+    return element;
+  };
+
+  Element._attributeTranslations = {
+    read: {
+      names: {
+        'class': 'className',
+        'for':   'htmlFor'
+      },
+      values: {
+        _getAttr: function(element, attribute) {
+          return element.getAttribute(attribute, 2);
+        },
+        _getAttrNode: function(element, attribute) {
+          var node = element.getAttributeNode(attribute);
+          return node ? node.value : "";
+        },
+        _getEv: function(element, attribute) {
+          attribute = element.getAttribute(attribute);
+          return attribute ? attribute.toString().slice(23, -2) : null;
+        },
+        _flag: function(element, attribute) {
+          return $(element).hasAttribute(attribute) ? attribute : null;
+        },
+        style: function(element) {
+          return element.style.cssText.toLowerCase();
+        },
+        title: function(element) {
+          return element.title;
+        }
+      }
+    }
+  };
+
+  Element._attributeTranslations.write = {
+    names: Object.extend({
+      cellpadding: 'cellPadding',
+      cellspacing: 'cellSpacing'
+    }, Element._attributeTranslations.read.names),
+    values: {
+      checked: function(element, value) {
+        element.checked = !!value;
+      },
+
+      style: function(element, value) {
+        element.style.cssText = value ? value : '';
+      }
+    }
+  };
+
+  Element._attributeTranslations.has = {};
+
+  $w('colSpan rowSpan vAlign dateTime accessKey tabIndex ' +
+      'encType maxLength readOnly longDesc frameBorder').each(function(attr) {
+    Element._attributeTranslations.write.names[attr.toLowerCase()] = attr;
+    Element._attributeTranslations.has[attr.toLowerCase()] = attr;
+  });
+
+  (function(v) {
+    Object.extend(v, {
+      href:        v._getAttr,
+      src:         v._getAttr,
+      type:        v._getAttr,
+      action:      v._getAttrNode,
+      disabled:    v._flag,
+      checked:     v._flag,
+      readonly:    v._flag,
+      multiple:    v._flag,
+      onload:      v._getEv,
+      onunload:    v._getEv,
+      onclick:     v._getEv,
+      ondblclick:  v._getEv,
+      onmousedown: v._getEv,
+      onmouseup:   v._getEv,
+      onmouseover: v._getEv,
+      onmousemove: v._getEv,
+      onmouseout:  v._getEv,
+      onfocus:     v._getEv,
+      onblur:      v._getEv,
+      onkeypress:  v._getEv,
+      onkeydown:   v._getEv,
+      onkeyup:     v._getEv,
+      onsubmit:    v._getEv,
+      onreset:     v._getEv,
+      onselect:    v._getEv,
+      onchange:    v._getEv
+    });
+  })(Element._attributeTranslations.read.values);
+}
+
+else if (Prototype.Browser.Gecko && /rv:1\.8\.0/.test(navigator.userAgent)) {
+  Element.Methods.setOpacity = function(element, value) {
+    element = $(element);
+    element.style.opacity = (value == 1) ? 0.999999 :
+      (value === '') ? '' : (value < 0.00001) ? 0 : value;
+    return element;
+  };
+}
+
+else if (Prototype.Browser.WebKit) {
+  Element.Methods.setOpacity = function(element, value) {
+    element = $(element);
+    element.style.opacity = (value == 1 || value === '') ? '' :
+      (value < 0.00001) ? 0 : value;
+
+    if (value == 1)
+      if(element.tagName.toUpperCase() == 'IMG' && element.width) {
+        element.width++; element.width--;
+      } else try {
+        var n = document.createTextNode(' ');
+        element.appendChild(n);
+        element.removeChild(n);
+      } catch (e) { }
+
+    return element;
+  };
+
+  // Safari returns margins on body which is incorrect if the child is absolutely
+  // positioned.  For performance reasons, redefine Element#cumulativeOffset for
+  // KHTML/WebKit only.
+  Element.Methods.cumulativeOffset = function(element) {
+    var valueT = 0, valueL = 0;
+    do {
+      valueT += element.offsetTop  || 0;
+      valueL += element.offsetLeft || 0;
+      if (element.offsetParent == document.body)
+        if (Element.getStyle(element, 'position') == 'absolute') break;
+
+      element = element.offsetParent;
+    } while (element);
+
+    return Element._returnOffset(valueL, valueT);
+  };
+}
+
+if (Prototype.Browser.IE || Prototype.Browser.Opera) {
+  // IE and Opera are missing .innerHTML support for TABLE-related and SELECT elements
+  Element.Methods.update = function(element, content) {
+    element = $(element);
+
+    if (content && content.toElement) content = content.toElement();
+    if (Object.isElement(content)) return element.update().insert(content);
+
+    content = Object.toHTML(content);
+    var tagName = element.tagName.toUpperCase();
+
+    if (tagName in Element._insertionTranslations.tags) {
+      $A(element.childNodes).each(function(node) { element.removeChild(node) });
+      Element._getContentFromAnonymousElement(tagName, content.stripScripts())
+        .each(function(node) { element.appendChild(node) });
+    }
+    else element.innerHTML = content.stripScripts();
+
+    content.evalScripts.bind(content).defer();
+    return element;
+  };
+}
+
+if ('outerHTML' in document.createElement('div')) {
+  Element.Methods.replace = function(element, content) {
+    element = $(element);
+
+    if (content && content.toElement) content = content.toElement();
+    if (Object.isElement(content)) {
+      element.parentNode.replaceChild(content, element);
+      return element;
+    }
+
+    content = Object.toHTML(content);
+    var parent = element.parentNode, tagName = parent.tagName.toUpperCase();
+
+    if (Element._insertionTranslations.tags[tagName]) {
+      var nextSibling = element.next();
+      var fragments = Element._getContentFromAnonymousElement(tagName, content.stripScripts());
+      parent.removeChild(element);
+      if (nextSibling)
+        fragments.each(function(node) { parent.insertBefore(node, nextSibling) });
+      else
+        fragments.each(function(node) { parent.appendChild(node) });
+    }
+    else element.outerHTML = content.stripScripts();
+
+    content.evalScripts.bind(content).defer();
+    return element;
+  };
+}
+
+Element._returnOffset = function(l, t) {
+  var result = [l, t];
+  result.left = l;
+  result.top = t;
+  return result;
+};
+
+Element._getContentFromAnonymousElement = function(tagName, html) {
+  var div = new Element('div'), t = Element._insertionTranslations.tags[tagName];
+  if (t) {
+    div.innerHTML = t[0] + html + t[1];
+    t[2].times(function() { div = div.firstChild });
+  } else div.innerHTML = html;
+  return $A(div.childNodes);
+};
+
+Element._insertionTranslations = {
+  before: function(element, node) {
+    element.parentNode.insertBefore(node, element);
+  },
+  top: function(element, node) {
+    element.insertBefore(node, element.firstChild);
+  },
+  bottom: function(element, node) {
+    element.appendChild(node);
+  },
+  after: function(element, node) {
+    element.parentNode.insertBefore(node, element.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(element, attribute) {
+    attribute = Element._attributeTranslations.has[attribute] || attribute;
+    var node = $(element).getAttributeNode(attribute);
+    return !!(node && node.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 Methods = { }, ByTag = Element.Methods.ByTag;
+
+  var extend = Object.extend(function(element) {
+    if (!element || element._extendedByPrototype ||
+        element.nodeType != 1 || element == window) return element;
+
+    var methods = Object.clone(Methods),
+      tagName = element.tagName.toUpperCase(), property, value;
+
+    // extend methods for specific tags
+    if (ByTag[tagName]) Object.extend(methods, ByTag[tagName]);
+
+    for (property in methods) {
+      value = methods[property];
+      if (Object.isFunction(value) && !(property in element))
+        element[property] = value.methodize();
+    }
+
+    element._extendedByPrototype = Prototype.emptyFunction;
+    return element;
+
+  }, {
+    refresh: function() {
+      // extend methods for all tags (Safari doesn't need this)
+      if (!Prototype.BrowserFeatures.ElementExtensions) {
+        Object.extend(Methods, Element.Methods);
+        Object.extend(Methods, Element.Methods.Simulated);
+      }
+    }
+  });
+
+  extend.refresh();
+  return extend;
+})();
+
+Element.hasAttribute = function(element, attribute) {
+  if (element.hasAttribute) return element.hasAttribute(attribute);
+  return Element.Methods.Simulated.hasAttribute(element, attribute);
+};
+
+Element.addMethods = function(methods) {
+  var F = Prototype.BrowserFeatures, T = Element.Methods.ByTag;
+
+  if (!methods) {
+    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 tagName = methods;
+    methods = arguments[1];
+  }
+
+  if (!tagName) Object.extend(Element.Methods, methods || { });
+  else {
+    if (Object.isArray(tagName)) tagName.each(extend);
+    else extend(tagName);
+  }
+
+  function extend(tagName) {
+    tagName = tagName.toUpperCase();
+    if (!Element.Methods.ByTag[tagName])
+      Element.Methods.ByTag[tagName] = { };
+    Object.extend(Element.Methods.ByTag[tagName], methods);
+  }
+
+  function copy(methods, destination, onlyIfAbsent) {
+    onlyIfAbsent = onlyIfAbsent || false;
+    for (var property in methods) {
+      var value = methods[property];
+      if (!Object.isFunction(value)) continue;
+      if (!onlyIfAbsent || !(property in destination))
+        destination[property] = value.methodize();
+    }
+  }
+
+  function findDOMClass(tagName) {
+    var klass;
+    var trans = {
+      "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 (trans[tagName]) klass = 'HTML' + trans[tagName] + 'Element';
+    if (window[klass]) return window[klass];
+    klass = 'HTML' + tagName + 'Element';
+    if (window[klass]) return window[klass];
+    klass = 'HTML' + tagName.capitalize() + 'Element';
+    if (window[klass]) return window[klass];
+
+    window[klass] = { };
+    window[klass].prototype = document.createElement(tagName)['__proto__'];
+    return window[klass];
+  }
+
+  if (F.ElementExtensions) {
+    copy(Element.Methods, HTMLElement.prototype);
+    copy(Element.Methods.Simulated, HTMLElement.prototype, true);
+  }
+
+  if (F.SpecificElementExtensions) {
+    for (var tag in Element.Methods.ByTag) {
+      var klass = findDOMClass(tag);
+      if (Object.isUndefined(klass)) continue;
+      copy(T[tag], klass.prototype);
+    }
+  }
+
+  Object.extend(Element, Element.Methods);
+  delete Element.ByTag;
+
+  if (Element.extend.refresh) Element.extend.refresh();
+  Element.cache = { };
+};
+
+document.viewport = {
+  getDimensions: function() {
+    var dimensions = { }, B = Prototype.Browser;
+    $w('width height').each(function(d) {
+      var D = d.capitalize();
+      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;
+  },
+
+  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);
+  }
+};
+/* 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();
+
+    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 e = this.expression;
+
+    // Safari 3 chokes on :*-of-type and :empty
+    if (Prototype.Browser.WebKit &&
+     (e.include("-of-type") || e.include(":empty")))
+      return false;
+
+    // XPath can't do namespaced attributes, nor can it read
+    // the "checked" property from DOM nodes
+    if ((/(\[[\w-]*?:|:checked)/).test(e))
+      return false;
+
+    return true;
+  },
+
+  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;
+
+    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, ps = Selector.patterns,
+        x = Selector.xpath, le, m;
+
+    if (Selector._cache[e]) {
+      this.xpath = Selector._cache[e]; return;
+    }
+
+    this.matcher = ['.//*'];
+    while (e && le != e && (/\S/).test(e)) {
+      le = e;
+      for (var i in ps) {
+        if (m = e.match(ps[i])) {
+          this.matcher.push(Object.isFunction(x[i]) ? x[i](m) :
+            new Template(x[i]).evaluate(m));
+          e = e.replace(m[0], '');
+          break;
+        }
+      }
+    }
+
+    this.xpath = this.matcher.join('');
+    Selector._cache[this.expression] = this.xpath;
+  },
+
+  findElements: function(root) {
+    root = root || document;
+    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) {
+    this.tokens = [];
+
+    var e = this.expression, ps = Selector.patterns, as = Selector.assertions;
+    var le, p, m;
+
+    while (e && le !== e && (/\S/).test(e)) {
+      le = e;
+      for (var i in ps) {
+        p = ps[i];
+        if (m = e.match(p)) {
+          // use the Selector.assertions methods unless the selector
+          // is too complex.
+          if (as[i]) {
+            this.tokens.push([i, Object.clone(m)]);
+            e = e.replace(m[0], '');
+          } else {
+            // reluctantly do a document-wide search
+            // and look for a match in the array
+            return this.findElements(document).include(element);
+          }
+        }
+      }
+    }
+
+    var match = true, name, matches;
+    for (var i = 0, token; token = this.tokens[i]; i++) {
+      name = token[0], matches = token[1];
+      if (!Selector.assertions[name](element, matches)) {
+        match = false; break;
+      }
+    }
+
+    return match;
+  },
+
+  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(m) {
+      if (m[1] == '*') return '';
+      return "[local-name()='" + m[1].toLowerCase() +
+             "' or local-name()='" + m[1].toUpperCase() + "']";
+    },
+    className:    "[contains(concat(' ', @class, ' '), ' #{1} ')]",
+    id:           "[@id='#{1}']",
+    attrPresence: function(m) {
+      m[1] = m[1].toLowerCase();
+      return new Template("[@#{1}]").evaluate(m);
+    },
+    attr: function(m) {
+      m[1] = m[1].toLowerCase();
+      m[3] = m[5] || m[6];
+      return new Template(Selector.xpath.operators[m[2]]).evaluate(m);
+    },
+    pseudo: function(m) {
+      var h = Selector.xpath.pseudos[m[1]];
+      if (!h) return '';
+      if (Object.isFunction(h)) return h(m);
+      return new Template(Selector.xpath.pseudos[m[1]]).evaluate(m);
+    },
+    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(m) {
+        var e = m[6], p = Selector.patterns,
+            x = Selector.xpath, le, v;
+
+        var exclusion = [];
+        while (e && le != e && (/\S/).test(e)) {
+          le = e;
+          for (var i in p) {
+            if (m = e.match(p[i])) {
+              v = Object.isFunction(x[i]) ? x[i](m) : new Template(x[i]).evaluate(m);
+              exclusion.push("(" + v.substring(1, v.length - 1) + ")");
+              e = e.replace(m[0], '');
+              break;
+            }
+          }
+        }
+        return "[not(" + exclusion.join(" and ") + ")]";
+      },
+      'nth-child':      function(m) {
+        return Selector.xpath.pseudos.nth("(count(./preceding-sibling::*) + 1) ", m);
+      },
+      'nth-last-child': function(m) {
+        return Selector.xpath.pseudos.nth("(count(./following-sibling::*) + 1) ", m);
+      },
+      'nth-of-type':    function(m) {
+        return Selector.xpath.pseudos.nth("position() ", m);
+      },
+      'nth-last-of-type': function(m) {
+        return Selector.xpath.pseudos.nth("(last() + 1 - position()) ", m);
+      },
+      'first-of-type':  function(m) {
+        m[6] = "1"; return Selector.xpath.pseudos['nth-of-type'](m);
+      },
+      'last-of-type':   function(m) {
+        m[6] = "1"; return Selector.xpath.pseudos['nth-last-of-type'](m);
+      },
+      'only-of-type':   function(m) {
+        var p = Selector.xpath.pseudos; return p['first-of-type'](m) + p['last-of-type'](m);
+      },
+      nth: function(fragment, m) {
+        var mm, formula = m[6], predicate;
+        if (formula == 'even') formula = '2n+0';
+        if (formula == 'odd')  formula = '2n+1';
+        if (mm = formula.match(/^(\d+)$/)) // digit only
+          return '[' + fragment + "= " + mm[1] + ']';
+        if (mm = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b
+          if (mm[1] == "-") mm[1] = -1;
+          var a = mm[1] ? Number(mm[1]) : 1;
+          var b = mm[2] ? Number(mm[2]) : 0;
+          predicate = "[((#{fragment} - #{b}) mod #{a} = 0) and " +
+          "((#{fragment} - #{b}) div #{a} >= 0)]";
+          return new Template(predicate).evaluate({
+            fragment: fragment, a: a, b: b });
+        }
+      }
+    }
+  },
+
+  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(m) {
+      m[3] = (m[5] || m[6]);
+      return new Template('n = h.attr(n, r, "#{1}", "#{3}", "#{2}", c); c = false;').evaluate(m);
+    },
+    pseudo: function(m) {
+      if (m[6]) m[6] = m[6].replace(/"/g, '\\"');
+      return new Template('n = h.pseudo(n, "#{1}", "#{6}", r, c); c = false;').evaluate(m);
+    },
+    descendant:   'c = "descendant";',
+    child:        'c = "child";',
+    adjacent:     'c = "adjacent";',
+    laterSibling: 'c = "laterSibling";'
+  },
+
+  patterns: {
+    // combinators must be listed first
+    // (and descendant needs to be last combinator)
+    laterSibling: /^\s*~\s*/,
+    child:        /^\s*>\s*/,
+    adjacent:     /^\s*\+\s*/,
+    descendant:   /^\s/,
+
+    // selectors follow
+    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|([^'"][^\]]*?)))?\]/
+  },
+
+  // for Selector.match and Element#match
+  assertions: {
+    tagName: function(element, matches) {
+      return matches[1].toUpperCase() == element.tagName.toUpperCase();
+    },
+
+    className: function(element, matches) {
+      return Element.hasClassName(element, matches[1]);
+    },
+
+    id: function(element, matches) {
+      return element.id === matches[1];
+    },
+
+    attrPresence: function(element, matches) {
+      return Element.hasAttribute(element, matches[1]);
+    },
+
+    attr: function(element, matches) {
+      var nodeValue = Element.readAttribute(element, matches[1]);
+      return nodeValue && Selector.operators[matches[2]](nodeValue, matches[5] || matches[6]);
+    }
+  },
+
+  handlers: {
+    // UTILITY FUNCTIONS
+    // joins two collections
+    concat: function(a, b) {
+      for (var i = 0, node; node = b[i]; i++)
+        a.push(node);
+      return a;
+    },
+
+    // marks an array of nodes for counting
+    mark: function(nodes) {
+      var _true = Prototype.emptyFunction;
+      for (var i = 0, node; node = nodes[i]; i++)
+        node._countedByPrototype = _true;
+      return nodes;
+    },
+
+    unmark: function(nodes) {
+      for (var i = 0, node; node = nodes[i]; i++)
+        node._countedByPrototype = undefined;
+      return nodes;
+    },
+
+    // mark each child node with its position (for nth calls)
+    // "ofType" flag indicates whether we're indexing for nth-of-type
+    // rather than nth-child
+    index: function(parentNode, reverse, ofType) {
+      parentNode._countedByPrototype = Prototype.emptyFunction;
+      if (reverse) {
+        for (var nodes = parentNode.childNodes, i = nodes.length - 1, j = 1; i >= 0; i--) {
+          var node = nodes[i];
+          if (node.nodeType == 1 && (!ofType || node._countedByPrototype)) node.nodeIndex = j++;
+        }
+      } else {
+        for (var i = 0, j = 1, nodes = parentNode.childNodes; node = nodes[i]; i++)
+          if (node.nodeType == 1 && (!ofType || node._countedByPrototype)) node.nodeIndex = j++;
+      }
+    },
+
+    // filters out duplicates and extends all nodes
+    unique: function(nodes) {
+      if (nodes.length == 0) return nodes;
+      var results = [], n;
+      for (var i = 0, l = nodes.length; i < l; i++)
+        if (!(n = nodes[i])._countedByPrototype) {
+          n._countedByPrototype = Prototype.emptyFunction;
+          results.push(Element.extend(n));
+        }
+      return Selector.handlers.unmark(results);
+    },
+
+    // COMBINATOR FUNCTIONS
+    descendant: function(nodes) {
+      var h = Selector.handlers;
+      for (var i = 0, results = [], node; node = nodes[i]; i++)
+        h.concat(results, node.getElementsByTagName('*'));
+      return results;
+    },
+
+    child: function(nodes) {
+      var h = Selector.handlers;
+      for (var i = 0, results = [], node; node = nodes[i]; i++) {
+        for (var j = 0, child; child = node.childNodes[j]; j++)
+          if (child.nodeType == 1 && child.tagName != '!') results.push(child);
+      }
+      return results;
+    },
+
+    adjacent: function(nodes) {
+      for (var i = 0, results = [], node; node = nodes[i]; i++) {
+        var next = this.nextElementSibling(node);
+        if (next) results.push(next);
+      }
+      return results;
+    },
+
+    laterSibling: function(nodes) {
+      var h = Selector.handlers;
+      for (var i = 0, results = [], node; node = nodes[i]; i++)
+        h.concat(results, Element.nextSiblings(node));
+      return results;
+    },
+
+    nextElementSibling: function(node) {
+      while (node = node.nextSibling)
+        if (node.nodeType == 1) return node;
+      return null;
+    },
+
+    previousElementSibling: function(node) {
+      while (node = node.previousSibling)
+        if (node.nodeType == 1) return node;
+      return null;
+    },
+
+    // TOKEN FUNCTIONS
+    tagName: function(nodes, root, tagName, combinator) {
+      var uTagName = tagName.toUpperCase();
+      var results = [], h = Selector.handlers;
+      if (nodes) {
+        if (combinator) {
+          // fastlane for ordinary descendant combinators
+          if (combinator == "descendant") {
+            for (var i = 0, node; node = nodes[i]; i++)
+              h.concat(results, node.getElementsByTagName(tagName));
+            return results;
+          } else nodes = this[combinator](nodes);
+          if (tagName == "*") return nodes;
+        }
+        for (var i = 0, node; node = nodes[i]; i++)
+          if (node.tagName.toUpperCase() === uTagName) results.push(node);
+        return results;
+      } else return root.getElementsByTagName(tagName);
+    },
+
+    id: function(nodes, root, id, combinator) {
+      var targetNode = $(id), h = Selector.handlers;
+      if (!targetNode) return [];
+      if (!nodes && root == document) return [targetNode];
+      if (nodes) {
+        if (combinator) {
+          if (combinator == 'child') {
+            for (var i = 0, node; node = nodes[i]; i++)
+              if (targetNode.parentNode == node) return [targetNode];
+          } else if (combinator == 'descendant') {
+            for (var i = 0, node; node = nodes[i]; i++)
+              if (Element.descendantOf(targetNode, node)) return [targetNode];
+          } else if (combinator == 'adjacent') {
+            for (var i = 0, node; node = nodes[i]; i++)
+              if (Selector.handlers.previousElementSibling(targetNode) == node)
+                return [targetNode];
+          } else nodes = h[combinator](nodes);
+        }
+        for (var i = 0, node; node = nodes[i]; i++)
+          if (node == targetNode) return [targetNode];
+        return [];
+      }
+      return (targetNode && Element.descendantOf(targetNode, root)) ? [targetNode] : [];
+    },
+
+    className: function(nodes, root, className, combinator) {
+      if (nodes && combinator) nodes = this[combinator](nodes);
+      return Selector.handlers.byClassName(nodes, root, className);
+    },
+
+    byClassName: function(nodes, root, className) {
+      if (!nodes) nodes = Selector.handlers.descendant([root]);
+      var needle = ' ' + className + ' ';
+      for (var i = 0, results = [], node, nodeClassName; node = nodes[i]; i++) {
+        nodeClassName = node.className;
+        if (nodeClassName.length == 0) continue;
+        if (nodeClassName == className || (' ' + nodeClassName + ' ').include(needle))
+          results.push(node);
+      }
+      return results;
+    },
+
+    attrPresence: function(nodes, root, attr, combinator) {
+      if (!nodes) nodes = root.getElementsByTagName("*");
+      if (nodes && combinator) nodes = this[combinator](nodes);
+      var results = [];
+      for (var i = 0, node; node = nodes[i]; i++)
+        if (Element.hasAttribute(node, attr)) results.push(node);
+      return results;
+    },
+
+    attr: function(nodes, root, attr, value, operator, combinator) {
+      if (!nodes) nodes = root.getElementsByTagName("*");
+      if (nodes && combinator) nodes = this[combinator](nodes);
+      var handler = Selector.operators[operator], results = [];
+      for (var i = 0, node; node = nodes[i]; i++) {
+        var nodeValue = Element.readAttribute(node, attr);
+        if (nodeValue === null) continue;
+        if (handler(nodeValue, value)) results.push(node);
+      }
+      return results;
+    },
+
+    pseudo: function(nodes, name, value, root, combinator) {
+      if (nodes && combinator) nodes = this[combinator](nodes);
+      if (!nodes) nodes = root.getElementsByTagName("*");
+      return Selector.pseudos[name](nodes, value, root);
+    }
+  },
+
+  pseudos: {
+    'first-child': function(nodes, value, root) {
+      for (var i = 0, results = [], node; node = nodes[i]; i++) {
+        if (Selector.handlers.previousElementSibling(node)) continue;
+          results.push(node);
+      }
+      return results;
+    },
+    'last-child': function(nodes, value, root) {
+      for (var i = 0, results = [], node; node = nodes[i]; i++) {
+        if (Selector.handlers.nextElementSibling(node)) continue;
+          results.push(node);
+      }
+      return results;
+    },
+    'only-child': function(nodes, value, root) {
+      var h = Selector.handlers;
+      for (var i = 0, results = [], node; node = nodes[i]; i++)
+        if (!h.previousElementSibling(node) && !h.nextElementSibling(node))
+          results.push(node);
+      return results;
+    },
+    'nth-child':        function(nodes, formula, root) {
+      return Selector.pseudos.nth(nodes, formula, root);
+    },
+    'nth-last-child':   function(nodes, formula, root) {
+      return Selector.pseudos.nth(nodes, formula, root, true);
+    },
+    'nth-of-type':      function(nodes, formula, root) {
+      return Selector.pseudos.nth(nodes, formula, root, false, true);
+    },
+    'nth-last-of-type': function(nodes, formula, root) {
+      return Selector.pseudos.nth(nodes, formula, root, true, true);
+    },
+    'first-of-type':    function(nodes, formula, root) {
+      return Selector.pseudos.nth(nodes, "1", root, false, true);
+    },
+    'last-of-type':     function(nodes, formula, root) {
+      return Selector.pseudos.nth(nodes, "1", root, true, true);
+    },
+    'only-of-type':     function(nodes, formula, root) {
+      var p = Selector.pseudos;
+      return p['last-of-type'](p['first-of-type'](nodes, formula, root), formula, root);
+    },
+
+    // handles the an+b logic
+    getIndices: function(a, b, total) {
+      if (a == 0) return b > 0 ? [b] : [];
+      return $R(1, total).inject([], function(memo, i) {
+        if (0 == (i - b) % a && (i - b) / a >= 0) memo.push(i);
+        return memo;
+      });
+    },
+
+    // handles nth(-last)-child, nth(-last)-of-type, and (first|last)-of-type
+    nth: function(nodes, formula, root, reverse, ofType) {
+      if (nodes.length == 0) return [];
+      if (formula == 'even') formula = '2n+0';
+      if (formula == 'odd')  formula = '2n+1';
+      var h = Selector.handlers, results = [], indexed = [], m;
+      h.mark(nodes);
+      for (var i = 0, node; node = nodes[i]; i++) {
+        if (!node.parentNode._countedByPrototype) {
+          h.index(node.parentNode, reverse, ofType);
+          indexed.push(node.parentNode);
+        }
+      }
+      if (formula.match(/^\d+$/)) { // just a number
+        formula = Number(formula);
+        for (var i = 0, node; node = nodes[i]; i++)
+          if (node.nodeIndex == formula) results.push(node);
+      } else if (m = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b
+        if (m[1] == "-") m[1] = -1;
+        var a = m[1] ? Number(m[1]) : 1;
+        var b = m[2] ? Number(m[2]) : 0;
+        var indices = Selector.pseudos.getIndices(a, b, nodes.length);
+        for (var i = 0, node, l = indices.length; node = nodes[i]; i++) {
+          for (var j = 0; j < l; j++)
+            if (node.nodeIndex == indices[j]) results.push(node);
+        }
+      }
+      h.unmark(nodes);
+      h.unmark(indexed);
+      return results;
+    },
+
+    '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) continue;
+        results.push(node);
+      }
+      return results;
+    },
+
+    'not': function(nodes, selector, root) {
+      var h = Selector.handlers, selectorType, m;
+      var exclusions = new Selector(selector).findElements(root);
+      h.mark(exclusions);
+      for (var i = 0, results = [], node; node = nodes[i]; i++)
+        if (!node._countedByPrototype) results.push(node);
+      h.unmark(exclusions);
+      return results;
+    },
+
+    'enabled': function(nodes, value, root) {
+      for (var i = 0, results = [], node; node = nodes[i]; i++)
+        if (!node.disabled && (!node.type || node.type !== 'hidden'))
+          results.push(node);
+      return results;
+    },
+
+    'disabled': function(nodes, value, root) {
+      for (var i = 0, results = [], node; node = nodes[i]; i++)
+        if (node.disabled) results.push(node);
+      return results;
+    },
+
+    'checked': function(nodes, value, root) {
+      for (var i = 0, results = [], node; node = nodes[i]; i++)
+        if (node.checked) results.push(node);
+      return results;
+    }
+  },
+
+  operators: {
+    '=':  function(nv, v) { return nv == v; },
+    '!=': function(nv, v) { return nv != 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() + '-'); }
+  },
+
+  split: function(expression) {
+    var expressions = [];
+    expression.scan(/(([\w#:.~>+()\s-]+|\*|\[.*?\])+)\s*(,|$)/, function(m) {
+      expressions.push(m[1].strip());
+    });
+    return expressions;
+  },
+
+  matchElements: function(elements, expression) {
+    var matches = $$(expression), h = Selector.handlers;
+    h.mark(matches);
+    for (var i = 0, results = [], element; element = elements[i]; i++)
+      if (element._countedByPrototype) results.push(element);
+    h.unmark(matches);
+    return results;
+  },
+
+  findElement: function(elements, expression, index) {
+    if (Object.isNumber(expression)) {
+      index = expression; expression = false;
+    }
+    return Selector.matchElements(elements, expression || '*')[index || 0];
+  },
+
+  findChildElements: function(element, expressions) {
+    expressions = Selector.split(expressions.join(','));
+    var results = [], h = Selector.handlers;
+    for (var i = 0, l = expressions.length, selector; i < l; i++) {
+      selector = new Selector(expressions[i].strip());
+      h.concat(results, selector.findElements(element));
+    }
+    return (l > 1) ? h.unique(results) : results;
+  }
+});
+
+if (Prototype.Browser.IE) {
+  Object.extend(Selector.handlers, {
+    // IE returns comment nodes on getElementsByTagName("*").
+    // Filter them out.
+    concat: function(a, b) {
+      for (var i = 0, node; node = b[i]; i++)
+        if (node.tagName !== "!") a.push(node);
+      return a;
+    },
+
+    // IE improperly serializes _countedByPrototype in (inner|outer)HTML.
+    unmark: function(nodes) {
+      for (var i = 0, node; node = nodes[i]; i++)
+        node.removeAttribute('_countedByPrototype');
+      return nodes;
+    }
+  });
+}
+
+function $$() {
+  return Selector.findChildElements(document, $A(arguments));
+}
+var Form = {
+  reset: function(form) {
+    $(form).reset();
+    return form;
+  },
+
+  serializeElements: function(elements, options) {
+    if (typeof options != 'object') options = { hash: !!options };
+    else if (Object.isUndefined(options.hash)) options.hash = true;
+    var key, value, submitted = false, submit = options.submit;
+
+    var data = elements.inject({ }, function(result, element) {
+      if (!element.disabled && element.name) {
+        key = element.name; value = $(element).getValue();
+        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
+            if (!Object.isArray(result[key])) result[key] = [result[key]];
+            result[key].push(value);
+          }
+          else result[key] = value;
+        }
+      }
+      return result;
+    });
+
+    return options.hash ? data : Object.toQueryString(data);
+  }
+};
+
+Form.Methods = {
+  serialize: function(form, options) {
+    return Form.serializeElements(Form.getElements(form), options);
+  },
+
+  getElements: function(form) {
+    return $A($(form).getElementsByTagName('*')).inject([],
+      function(elements, child) {
+        if (Form.Element.Serializers[child.tagName.toLowerCase()])
+          elements.push(Element.extend(child));
+        return elements;
+      }
+    );
+  },
+
+  getInputs: function(form, typeName, name) {
+    form = $(form);
+    var inputs = form.getElementsByTagName('input');
+
+    if (!typeName && !name) return $A(inputs).map(Element.extend);
+
+    for (var i = 0, matchingInputs = [], length = inputs.length; i < length; i++) {
+      var input = inputs[i];
+      if ((typeName && input.type != typeName) || (name && input.name != name))
+        continue;
+      matchingInputs.push(Element.extend(input));
+    }
+
+    return matchingInputs;
+  },
+
+  disable: function(form) {
+    form = $(form);
+    Form.getElements(form).invoke('disable');
+    return form;
+  },
+
+  enable: function(form) {
+    form = $(form);
+    Form.getElements(form).invoke('enable');
+    return form;
+  },
+
+  findFirstElement: function(form) {
+    var elements = $(form).getElements().findAll(function(element) {
+      return 'hidden' != element.type && !element.disabled;
+    });
+    var firstByIndex = elements.findAll(function(element) {
+      return element.hasAttribute('tabIndex') && element.tabIndex >= 0;
+    }).sortBy(function(element) { return element.tabIndex }).first();
+
+    return firstByIndex ? firstByIndex : elements.find(function(element) {
+      return ['input', 'select', 'textarea'].include(element.tagName.toLowerCase());
+    });
+  },
+
+  focusFirstElement: function(form) {
+    form = $(form);
+    form.findFirstElement().activate();
+    return form;
+  },
+
+  request: function(form, options) {
+    form = $(form), options = Object.clone(options || { });
+
+    var params = options.parameters, action = form.readAttribute('action') || '';
+    if (action.blank()) action = window.location.href;
+    options.parameters = form.serialize(true);
+
+    if (params) {
+      if (Object.isString(params)) params = params.toQueryParams();
+      Object.extend(options.parameters, params);
+    }
+
+    if (form.hasAttribute('method') && !options.method)
+      options.method = form.method;
+
+    return new Ajax.Request(action, options);
+  }
+};
+
+/*--------------------------------------------------------------------------*/
+
+Form.Element = {
+  focus: function(element) {
+    $(element).focus();
+    return element;
+  },
+
+  select: function(element) {
+    $(element).select();
+    return element;
+  }
+};
+
+Form.Element.Methods = {
+  serialize: function(element) {
+    element = $(element);
+    if (!element.disabled && element.name) {
+      var value = element.getValue();
+      if (value != undefined) {
+        var pair = { };
+        pair[element.name] = value;
+        return Object.toQueryString(pair);
+      }
+    }
+    return '';
+  },
+
+  getValue: function(element) {
+    element = $(element);
+    var method = element.tagName.toLowerCase();
+    return Form.Element.Serializers[method](element);
+  },
+
+  setValue: function(element, value) {
+    element = $(element);
+    var method = element.tagName.toLowerCase();
+    Form.Element.Serializers[method](element, value);
+    return element;
+  },
+
+  clear: function(element) {
+    $(element).value = '';
+    return element;
+  },
+
+  present: function(element) {
+    return $(element).value != '';
+  },
+
+  activate: function(element) {
+    element = $(element);
+    try {
+      element.focus();
+      if (element.select && (element.tagName.toLowerCase() != 'input' ||
+          !['button', 'reset', 'submit'].include(element.type)))
+        element.select();
+    } catch (e) { }
+    return element;
+  },
+
+  disable: function(element) {
+    element = $(element);
+    element.disabled = true;
+    return element;
+  },
+
+  enable: function(element) {
+    element = $(element);
+    element.disabled = false;
+    return element;
+  }
+};
+
+/*--------------------------------------------------------------------------*/
+
+var Field = Form.Element;
+var $F = Form.Element.Methods.getValue;
+
+/*--------------------------------------------------------------------------*/
+
+Form.Element.Serializers = {
+  input: function(element, value) {
+    switch (element.type.toLowerCase()) {
+      case 'checkbox':
+      case 'radio':
+        return Form.Element.Serializers.inputSelector(element, value);
+      default:
+        return Form.Element.Serializers.textarea(element, value);
+    }
+  },
+
+  inputSelector: function(element, value) {
+    if (Object.isUndefined(value)) return element.checked ? element.value : null;
+    else element.checked = !!value;
+  },
+
+  textarea: function(element, value) {
+    if (Object.isUndefined(value)) return element.value;
+    else element.value = value;
+  },
+
+  select: function(element, value) {
+    if (Object.isUndefined(value))
+      return this[element.type == 'select-one' ?
+        'selectOne' : 'selectMany'](element);
+    else {
+      var opt, currentValue, single = !Object.isArray(value);
+      for (var i = 0, length = element.length; i < length; i++) {
+        opt = element.options[i];
+        currentValue = this.optionValue(opt);
+        if (single) {
+          if (currentValue == value) {
+            opt.selected = true;
+            return;
+          }
+        }
+        else opt.selected = value.include(currentValue);
+      }
+    }
+  },
+
+  selectOne: function(element) {
+    var index = element.selectedIndex;
+    return index >= 0 ? this.optionValue(element.options[index]) : null;
+  },
+
+  selectMany: function(element) {
+    var values, length = element.length;
+    if (!length) return null;
+
+    for (var i = 0, values = []; i < length; i++) {
+      var opt = element.options[i];
+      if (opt.selected) values.push(this.optionValue(opt));
+    }
+    return values;
+  },
+
+  optionValue: function(opt) {
+    // extend element because hasAttribute may not be native
+    return Element.extend(opt).hasAttribute('value') ? opt.value : opt.text;
+  }
+};
+
+/*--------------------------------------------------------------------------*/
+
+Abstract.TimedObserver = Class.create(PeriodicalExecuter, {
+  initialize: function($super, element, frequency, callback) {
+    $super(callback, frequency);
+    this.element   = $(element);
+    this.lastValue = this.getValue();
+  },
+
+  execute: function() {
+    var value = this.getValue();
+    if (Object.isString(this.lastValue) && Object.isString(value) ?
+        this.lastValue != value : String(this.lastValue) != String(value)) {
+      this.callback(this.element, value);
+      this.lastValue = value;
+    }
+  }
+});
+
+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(element, callback) {
+    this.element  = $(element);
+    this.callback = callback;
+
+    this.lastValue = this.getValue();
+    if (this.element.tagName.toLowerCase() == 'form')
+      this.registerFormCallbacks();
+    else
+      this.registerCallback(this.element);
+  },
+
+  onElementEvent: function() {
+    var value = this.getValue();
+    if (this.lastValue != value) {
+      this.callback(this.element, value);
+      this.lastValue = value;
+    }
+  },
+
+  registerFormCallbacks: function() {
+    Form.getElements(this.element).each(this.registerCallback, this);
+  },
+
+  registerCallback: function(element) {
+    if (element.type) {
+      switch (element.type.toLowerCase()) {
+        case 'checkbox':
+        case 'radio':
+          Event.observe(element, 'click', this.onElementEvent.bind(this));
+          break;
+        default:
+          Event.observe(element, '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(event) {
+    var element;
+    switch(event.type) {
+      case 'mouseover': element = event.fromElement; break;
+      case 'mouseout':  element = event.toElement;   break;
+      default: return null;
+    }
+    return Element.extend(element);
+  }
+});
+
+Event.Methods = (function() {
+  var isButton;
+
+  if (Prototype.Browser.IE) {
+    var buttonMap = { 0: 1, 1: 4, 2: 2 };
+    isButton = function(event, code) {
+      return event.button == buttonMap[code];
+    };
+
+  } else if (Prototype.Browser.WebKit) {
+    isButton = function(event, code) {
+      switch (code) {
+        case 0: return event.which == 1 && !event.metaKey;
+        case 1: return event.which == 1 && event.metaKey;
+        default: return false;
+      }
+    };
+
+  } else {
+    isButton = function(event, code) {
+      return event.which ? (event.which === code + 1) : (event.button === code);
+    };
+  }
+
+  return {
+    isLeftClick:   function(event) { return isButton(event, 0) },
+    isMiddleClick: function(event) { return isButton(event, 1) },
+    isRightClick:  function(event) { return isButton(event, 2) },
+
+    element: function(event) {
+      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) {
+      var element = Event.element(event);
+      if (!expression) return element;
+      var elements = [element].concat(element.ancestors());
+      return Selector.findElement(elements, expression, 0);
+    },
+
+    pointer: function(event) {
+      var docElement = document.documentElement,
+      body = document.body || { scrollLeft: 0, scrollTop: 0 };
+      return {
+        x: event.pageX || (event.clientX +
+          (docElement.scrollLeft || body.scrollLeft) -
+          (docElement.clientLeft || 0)),
+        y: event.pageY || (event.clientY +
+          (docElement.scrollTop || body.scrollTop) -
+          (docElement.clientTop || 0))
+      };
+    },
+
+    pointerX: function(event) { return Event.pointer(event).x },
+    pointerY: function(event) { return Event.pointer(event).y },
+
+    stop: function(event) {
+      Event.extend(event);
+      event.preventDefault();
+      event.stopPropagation();
+      event.stopped = true;
+    }
+  };
+})();
+
+Event.extend = (function() {
+  var methods = Object.keys(Event.Methods).inject({ }, function(m, name) {
+    m[name] = Event.Methods[name].methodize();
+    return m;
+  });
+
+  if (Prototype.Browser.IE) {
+    Object.extend(methods, {
+      stopPropagation: function() { this.cancelBubble = true },
+      preventDefault:  function() { this.returnValue = false },
+      inspect: function() { return "[object Event]" }
+    });
+
+    return function(event) {
+      if (!event) return false;
+      if (event._extendedByPrototype) return event;
+
+      event._extendedByPrototype = Prototype.emptyFunction;
+      var pointer = Event.pointer(event);
+      Object.extend(event, {
+        target: event.srcElement,
+        relatedTarget: Event.relatedTarget(event),
+        pageX:  pointer.x,
+        pageY:  pointer.y
+      });
+      return Object.extend(event, methods);
+    };
+
+  } else {
+    Event.prototype = Event.prototype || document.createEvent("HTMLEvents")['__proto__'];
+    Object.extend(Event.prototype, methods);
+    return Prototype.K;
+  }
+})();
+
+Object.extend(Event, (function() {
+  var cache = Event.cache;
+
+  function getEventID(element) {
+    if (element._prototypeEventID) return element._prototypeEventID[0];
+    arguments.callee.id = arguments.callee.id || 1;
+    return element._prototypeEventID = [++arguments.callee.id];
+  }
+
+  function getDOMEventName(eventName) {
+    if (eventName && eventName.include(':')) return "dataavailable";
+    return eventName;
+  }
+
+  function getCacheForID(id) {
+    return cache[id] = cache[id] || { };
+  }
+
+  function getWrappersForEventName(id, eventName) {
+    var c = getCacheForID(id);
+    return c[eventName] = c[eventName] || [];
+  }
+
+  function createWrapper(element, eventName, handler) {
+    var id = getEventID(element);
+    var c = getWrappersForEventName(id, eventName);
+    if (c.pluck("handler").include(handler)) return false;
+
+    var wrapper = function(event) {
+      if (!Event || !Event.extend ||
+        (event.eventName && event.eventName != eventName))
+          return false;
+
+      Event.extend(event);
+      handler.call(element, event);
+    };
+
+    wrapper.handler = handler;
+    c.push(wrapper);
+    return wrapper;
+  }
+
+  function findWrapper(id, eventName, handler) {
+    var c = getWrappersForEventName(id, eventName);
+    return c.find(function(wrapper) { return wrapper.handler == handler });
+  }
+
+  function destroyWrapper(id, eventName, handler) {
+    var c = getCacheForID(id);
+    if (!c[eventName]) return false;
+    c[eventName] = c[eventName].without(findWrapper(id, eventName, handler));
+  }
+
+  function destroyCache() {
+    for (var id in cache)
+      for (var eventName in cache[id])
+        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);
+      var name = getDOMEventName(eventName);
+
+      var wrapper = createWrapper(element, eventName, handler);
+      if (!wrapper) return element;
+
+      if (element.addEventListener) {
+        element.addEventListener(name, wrapper, false);
+      } else {
+        element.attachEvent("on" + name, wrapper);
+      }
+
+      return element;
+    },
+
+    stopObserving: function(element, eventName, handler) {
+      element = $(element);
+      var id = getEventID(element), name = getDOMEventName(eventName);
+
+      if (!handler && eventName) {
+        getWrappersForEventName(id, eventName).each(function(wrapper) {
+          element.stopObserving(eventName, wrapper.handler);
+        });
+        return element;
+
+      } else if (!eventName) {
+        Object.keys(getCacheForID(id)).each(function(eventName) {
+          element.stopObserving(eventName);
+        });
+        return element;
+      }
+
+      var wrapper = findWrapper(id, eventName, handler);
+      if (!wrapper) return element;
+
+      if (element.removeEventListener) {
+        element.removeEventListener(name, wrapper, false);
+      } else {
+        element.detachEvent("on" + name, wrapper);
+      }
+
+      destroyWrapper(id, eventName, handler);
+
+      return element;
+    },
+
+    fire: function(element, eventName, memo) {
+      element = $(element);
+      if (element == document && document.createEvent && !element.dispatchEvent)
+        element = document.documentElement;
+
+      var event;
+      if (document.createEvent) {
+        event = document.createEvent("HTMLEvents");
+        event.initEvent("dataavailable", true, true);
+      } else {
+        event = document.createEventObject();
+        event.eventType = "ondataavailable";
+      }
+
+      event.eventName = eventName;
+      event.memo = memo || { };
+
+      if (document.createEvent) {
+        element.dispatchEvent(event);
+      } else {
+        element.fireEvent(event.eventType, event);
+      }
+
+      return Event.extend(event);
+    }
+  };
+})());
+
+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() {
+  /* Support for the DOMContentLoaded event is based on work by Dan Webb,
+     Matthias Miller, Dean Edwards and John Resig. */
+
+  var timer;
+
+  function fireContentLoadedEvent() {
+    if (document.loaded) return;
+    if (timer) window.clearInterval(timer);
+    document.fire("dom:loaded");
+    document.loaded = true;
+  }
+
+  if (document.addEventListener) {
+    if (Prototype.Browser.WebKit) {
+      timer = window.setInterval(function() {
+        if (/loaded|complete/.test(document.readyState))
+          fireContentLoadedEvent();
+      }, 0);
+
+      Event.observe(window, "load", fireContentLoadedEvent);
+
+    } else {
+      document.addEventListener("DOMContentLoaded",
+        fireContentLoadedEvent, false);
+    }
+
+  } else {
+    document.write("<script id=__onDOMContentLoaded defer src=//:><\/script>");
+    $("__onDOMContentLoaded").onreadystatechange = function() {
+      if (this.readyState == "complete") {
+        this.onreadystatechange = null;
+        fireContentLoadedEvent();
+      }
+    };
+  }
+})();
+/*------------------------------- DEPRECATED -------------------------------*/
+
+Hash.toQueryString = Object.toQueryString;
+
+var Toggle = { display: Element.toggle };
+
+Element.Methods.childOf = Element.Methods.descendantOf;
+
+var Insertion = {
+  Before: function(element, content) {
+    return Element.insert(element, {before:content});
+  },
+
+  Top: function(element, content) {
+    return Element.insert(element, {top:content});
+  },
+
+  Bottom: function(element, content) {
+    return Element.insert(element, {bottom:content});
+  },
+
+  After: function(element, content) {
+    return Element.insert(element, {after:content});
+  }
+};
+
+var $continue = new Error('"throw $continue" is deprecated, use "return" instead');
+
+// This should be moved to script.aculo.us; notice the deprecated methods
+// further below, that map to the newer Element methods.
+var Position = {
+  // set to true if needed, warning: firefox performance problems
+  // NOT neeeded for page scrolling, only if draggable contained in
+  // scrollable elements
+  includeScrollOffsets: false,
+
+  // must be called before calling withinIncludingScrolloffset, every time the
+  // page is scrolled
+  prepare: function() {
+    this.deltaX =  window.pageXOffset
+                || document.documentElement.scrollLeft
+                || document.body.scrollLeft
+                || 0;
+    this.deltaY =  window.pageYOffset
+                || document.documentElement.scrollTop
+                || document.body.scrollTop
+                || 0;
+  },
+
+  // caches x/y coordinate pair to use with overlap
+  within: function(element, x, y) {
+    if (this.includeScrollOffsets)
+      return this.withinIncludingScrolloffsets(element, x, y);
+    this.xcomp = x;
+    this.ycomp = y;
+    this.offset = Element.cumulativeOffset(element);
+
+    return (y >= this.offset[1] &&
+            y <  this.offset[1] + element.offsetHeight &&
+            x >= this.offset[0] &&
+            x <  this.offset[0] + element.offsetWidth);
+  },
+
+  withinIncludingScrolloffsets: function(element, x, y) {
+    var offsetcache = Element.cumulativeScrollOffset(element);
+
+    this.xcomp = x + offsetcache[0] - this.deltaX;
+    this.ycomp = y + offsetcache[1] - this.deltaY;
+    this.offset = Element.cumulativeOffset(element);
+
+    return (this.ycomp >= this.offset[1] &&
+            this.ycomp <  this.offset[1] + element.offsetHeight &&
+            this.xcomp >= this.offset[0] &&
+            this.xcomp <  this.offset[0] + element.offsetWidth);
+  },
+
+  // within must be called directly before
+  overlap: function(mode, element) {
+    if (!mode) return 0;
+    if (mode == 'vertical')
+      return ((this.offset[1] + element.offsetHeight) - this.ycomp) /
+        element.offsetHeight;
+    if (mode == 'horizontal')
+      return ((this.offset[0] + element.offsetWidth) - this.xcomp) /
+        element.offsetWidth;
+  },
+
+  // Deprecation layer -- use newer Element methods now (1.5.2).
+
+  cumulativeOffset: Element.Methods.cumulativeOffset,
+
+  positionedOffset: Element.Methods.positionedOffset,
+
+  absolutize: function(element) {
+    Position.prepare();
+    return Element.absolutize(element);
+  },
+
+  relativize: function(element) {
+    Position.prepare();
+    return Element.relativize(element);
+  },
+
+  realOffset: Element.Methods.cumulativeScrollOffset,
+
+  offsetParent: Element.Methods.getOffsetParent,
+
+  page: Element.Methods.viewportOffset,
+
+  clone: function(source, target, options) {
+    options = options || { };
+    return Element.clonePosition(target, source, options);
+  }
+};
+
+/*--------------------------------------------------------------------------*/
+
+if (!document.getElementsByClassName) document.getElementsByClassName = function(instanceMethods){
+  function iter(name) {
+    return name.blank() ? null : "[contains(concat(' ', @class, ' '), ' " + name + " ')]";
+  }
+
+  instanceMethods.getElementsByClassName = Prototype.BrowserFeatures.XPath ?
+  function(element, className) {
+    className = className.toString().strip();
+    var cond = /\s/.test(className) ? $w(className).map(iter).join('') : iter(className);
+    return cond ? document._getElementsByXPath('.//*' + cond, element) : [];
+  } : function(element, className) {
+    className = className.toString().strip();
+    var elements = [], classNames = (/\s/.test(className) ? $w(className) : null);
+    if (!classNames && !className) return elements;
+
+    var nodes = $(element).getElementsByTagName('*');
+    className = ' ' + className + ' ';
+
+    for (var i = 0, child, cn; child = nodes[i]; i++) {
+      if (child.className && (cn = ' ' + child.className + ' ') && (cn.include(className) ||
+          (classNames && classNames.all(function(name) {
+            return !name.toString().blank() && cn.include(' ' + name + ' ');
+          }))))
+        elements.push(Element.extend(child));
+    }
+    return elements;
+  };
+
+  return function(className, parentElement) {
+    return $(parentElement || document.body).getElementsByClassName(className);
+  };
+}(Element.Methods);
+
+/*--------------------------------------------------------------------------*/
+
+Element.ClassNames = Class.create();
+Element.ClassNames.prototype = {
+  initialize: function(element) {
+    this.element = $(element);
+  },
+
+  _each: function(iterator) {
+    this.element.className.split(/\s+/).select(function(name) {
+      return name.length > 0;
+    })._each(iterator);
+  },
+
+  set: function(className) {
+    this.element.className = className;
+  },
+
+  add: function(classNameToAdd) {
+    if (this.include(classNameToAdd)) return;
+    this.set($A(this).concat(classNameToAdd).join(' '));
+  },
+
+  remove: function(classNameToRemove) {
+    if (!this.include(classNameToRemove)) return;
+    this.set($A(this).without(classNameToRemove).join(' '));
+  },
+
+  toString: function() {
+    return $A(this).join(' ');
+  }
+};
+
+Object.extend(Element.ClassNames.prototype, Enumerable);
+
+/*--------------------------------------------------------------------------*/
+
+Element.addMethods();
\ No newline at end of file
diff --git a/koward/www/htdocs/horde/js/redbox.js b/koward/www/htdocs/horde/js/redbox.js
new file mode 100644 (file)
index 0000000..b3a1439
--- /dev/null
@@ -0,0 +1,130 @@
+/**
+ * Redbox.js
+ *
+ * $Horde: horde/js/src/redbox.js,v 1.10 2008/02/06 09:02:37 slusarz Exp $
+ *
+ * See the enclosed file COPYING for license information (GPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
+ */
+
+var RedBox = {
+
+    overlay: true,
+    onDisplay: null,
+
+    showInline: function(id)
+    {
+        this.appearWindow();
+        this.cloneWindowContents(id);
+    },
+
+    showHtml: function(html)
+    {
+        this.appearWindow();
+        this.htmlWindowContents(html);
+    },
+
+    appearWindow: function()
+    {
+        var loading = $('RB_loading');
+        if (loading && loading.visible()) {
+            loading.hide();
+        } else {
+            this.showOverlay();
+        }
+        var opts = { duration: 0.4, queue: 'end' },
+            w = $('RB_window');
+        if (this.onDisplay) {
+            opts.afterFinish = this.onDisplay;
+        }
+        new Effect.Appear(w, opts);
+        w.scrollTo();
+    },
+
+    loading: function()
+    {
+        this.showOverlay();
+        var rl = $('RB_loading');
+        if (rl) {
+            rl.show();
+        }
+        this.setWindowPosition();
+    },
+
+    close: function()
+    {
+        new Effect.Fade('RB_window', { duration: 0.4 });
+        if (this.overlay) {
+            new Effect.Fade('RB_overlay', { duration: 0.4 });
+        }
+    },
+
+    showOverlay: function()
+    {
+        var rb = $('RB_redbox');
+        if (!rb) {
+            rb = new Element('DIV', { id: 'RB_redbox', align: 'center' });
+            $(document.body).insert(rb);
+
+            var ov = new Element('DIV', { id: 'RB_overlay' }).hide();
+            rb.insert({ top: new Element('DIV', { id: 'RB_window' }).hide() }).insert({ top: ov });
+
+            if (this.overlay) {
+                ov.insert({ top: new Element('DIV', { id: 'RB_loading' }).hide() });
+            }
+        }
+
+        if (this.overlay) {
+            this.setOverlaySize();
+            new Effect.Appear('RB_overlay', { duration: 0.4, to: 0.6, queue: 'end' });
+        }
+    },
+
+    setOverlaySize: function()
+    {
+        if (window.innerHeight && window.scrollMaxY) {
+            yScroll = window.innerHeight + window.scrollMaxY;
+        } else if (document.body.scrollHeight > document.body.offsetHeight) {
+            // all but Explorer Mac
+            yScroll = document.body.scrollHeight;
+        } else {
+            // Explorer Mac...would also work in Explorer 6 Strict, Mozilla
+            // and Safari
+            yScroll = document.body.offsetHeight;
+        }
+        Element.setStyle('RB_overlay', { height: yScroll + 'px' });
+    },
+
+    setWindowPosition: function()
+    {
+        var win = $('RB_window');
+        var d = win.getDimensions(),
+            v = document.viewport.getDimensions();
+        win.setStyle({ width: 'auto', height: 'auto', left: ((v.width - d.width) / 2) + 'px', top: ((v.height - d.height) / 2) + 'px' });
+    },
+
+    cloneWindowContents: function(id)
+    {
+        $('RB_window').appendChild($($(id).cloneNode(true)).setStyle({ display: 'block' }));
+        this.setWindowPosition();
+    },
+
+    htmlWindowContents: function(html)
+    {
+        $('RB_window').update(html);
+        this.setWindowPosition();
+    },
+
+    getWindowContents: function()
+    {
+        var w = $('RB_window');
+        return w.visible() ? w.down() : null;
+    },
+
+    overlayVisible: function()
+    {
+        var ov = $('RB_overlay');
+        return ov && ov.visible();
+    }
+
+}
diff --git a/koward/www/htdocs/horde/themes/graphics/favicon.ico b/koward/www/htdocs/horde/themes/graphics/favicon.ico
new file mode 100644 (file)
index 0000000..fe753dd
Binary files /dev/null and b/koward/www/htdocs/horde/themes/graphics/favicon.ico differ
diff --git a/koward/www/htdocs/horde/themes/graphics/logout.png b/koward/www/htdocs/horde/themes/graphics/logout.png
new file mode 100644 (file)
index 0000000..e40c2b5
Binary files /dev/null and b/koward/www/htdocs/horde/themes/graphics/logout.png differ
diff --git a/koward/www/htdocs/horde/themes/graphics/plus.png b/koward/www/htdocs/horde/themes/graphics/plus.png
new file mode 100644 (file)
index 0000000..263e356
Binary files /dev/null and b/koward/www/htdocs/horde/themes/graphics/plus.png differ
diff --git a/koward/www/htdocs/horde/themes/graphics/search.png b/koward/www/htdocs/horde/themes/graphics/search.png
new file mode 100644 (file)
index 0000000..8b7937d
Binary files /dev/null and b/koward/www/htdocs/horde/themes/graphics/search.png differ
diff --git a/koward/www/htdocs/horde/themes/graphics/tab_bottom.gif b/koward/www/htdocs/horde/themes/graphics/tab_bottom.gif
new file mode 100644 (file)
index 0000000..0de6e27
Binary files /dev/null and b/koward/www/htdocs/horde/themes/graphics/tab_bottom.gif differ
diff --git a/koward/www/htdocs/horde/themes/graphics/user.png b/koward/www/htdocs/horde/themes/graphics/user.png
new file mode 100644 (file)
index 0000000..8b2c994
Binary files /dev/null and b/koward/www/htdocs/horde/themes/graphics/user.png differ
diff --git a/koward/www/htdocs/horde/themes/ie5mac.css b/koward/www/htdocs/horde/themes/ie5mac.css
new file mode 100644 (file)
index 0000000..6343c9a
--- /dev/null
@@ -0,0 +1,25 @@
+/**
+ * $Horde: horde/themes/ie5mac.css,v 1.4 2005/05/10 13:53:40 chuck Exp $
+ *
+ * CSS corrections for IE5/Mac.
+ */
+
+#menu li {
+    width: 40px;
+}
+.tabset {
+    white-space: nowrap;
+}
+.tabset li a {
+    float: left;
+}
+#sidebarPanel {
+    padding-bottom: 30px;
+}
+.header {
+    clear: none;
+}
+.header ul {
+    width: 1%;
+    white-space: nowrap;
+}
diff --git a/koward/www/htdocs/horde/themes/ie6_or_less.css b/koward/www/htdocs/horde/themes/ie6_or_less.css
new file mode 100644 (file)
index 0000000..15c6d89
--- /dev/null
@@ -0,0 +1,23 @@
+/**
+ * $Horde: horde/themes/ie6_or_less.css,v 1.6 2009/04/14 03:47:30 slusarz Exp $
+ *
+ * CSS corrections for IE 6 and below.
+ */
+
+#sidebar-frame {
+    overflow-x: hidden;
+}
+
+.treeRow {
+    overflow: visible;
+    height: 20px;
+}
+
+#menu {
+    overflow: visible;
+    height: 50px;
+}
+
+.clear {
+    clear: none;
+}
diff --git a/koward/www/htdocs/horde/themes/moz14.css b/koward/www/htdocs/horde/themes/moz14.css
new file mode 100644 (file)
index 0000000..2ac1d2e
--- /dev/null
@@ -0,0 +1,10 @@
+/**
+ * $Horde: horde/themes/moz14.css,v 1.1 2005/03/16 11:42:56 jan Exp $
+ *
+ * CSS corrections for Mozilla <= 1.4.
+ */
+
+#menu {
+    overflow: visible;
+    height: 50px;
+}
diff --git a/koward/www/htdocs/horde/themes/opera.css b/koward/www/htdocs/horde/themes/opera.css
new file mode 100644 (file)
index 0000000..f3cc1bd
--- /dev/null
@@ -0,0 +1,15 @@
+/**
+ * $Horde: horde/themes/opera.css,v 1.3 2005/10/03 16:22:52 jan Exp $
+ *
+ * CSS corrections for Opera.
+ */
+
+.treeRow {
+    overflow: visible;
+    height: 20px;
+}
+
+#menu {
+    overflow: visible;
+    height: 50px;
+}
diff --git a/koward/www/htdocs/horde/themes/rtl.css b/koward/www/htdocs/horde/themes/rtl.css
new file mode 100644 (file)
index 0000000..65096ce
--- /dev/null
@@ -0,0 +1,177 @@
+/**
+ * $Horde: horde/themes/rtl.css,v 1.10 2009/03/24 22:47:05 slusarz Exp $
+ */
+
+/* Global default styles. */
+body {
+    direction: rtl;
+    font-family: Tahoma,Koodak,Homa,Nazli,Verdana,Geneva,Arial,"Bitstream Vera Sans",Helvetica,sans-serif;
+}
+
+body.scrollbar-quirk {
+    margin-left: 15px;
+}
+
+.header {
+    text-align: right;
+}
+.header ul {
+    float: left;
+    text-align: left;
+}
+.headerbox {
+    text-align: right;
+}
+
+/* Table styles. */
+td, th {
+    text-align: right;
+}
+
+.sortup, .sortdown {
+    padding-left: 1px;
+    background-position: center right;
+    padding-right: 10px;
+}
+
+/* Form styles. */
+form[action^="https://"] input[type="submit"] {
+    background-position: 5% center;
+    padding-right: 6px;
+    padding-left: 10%;
+}
+option {
+    padding: 0 3px 0 5px;
+}
+
+/* Styles for email-like messages. */
+.citation {
+    padding-left: 0;
+    border-left-width: 0;
+    padding-right: 1em;
+    border-right-width: 1px;
+    border-right-style: solid;
+}
+
+/* Various popup and status layers. */
+.notices {
+    text-align: right;
+}
+.notices li, .notice {
+    padding: 1px 5px 1px 1px;
+ }
+.notices img, .notice img {
+    margin-right: 0;
+    margin-left: .5em;
+}
+
+/* Menu styles. */
+#menu {
+    padding-right: 0;
+    padding-left: 8px;
+}
+#menu li {
+    float: right;
+}
+#menu li.rightFloat {
+    float: left;
+}
+#menuBottom {
+    float: left;
+    text-align: left;
+}
+
+/* Sidebar styles. */
+#sidebarPanel {
+    -moz-border-radius-bottomright: 0;
+    -moz-border-radius-bottomleft: 15px;
+    -webkit-border-bottom-right-radius: 0;
+    -webkit-border-bottom-left-radius: 15px;
+}
+
+/* Tab styles. */
+.tabset {
+    float: right;
+}
+.tabset ul {
+    padding-left: 0;
+    padding-right: 8px;
+}
+.tabset li {
+    float: right;
+    margin: -3px 0 0 2px;
+}
+.tabset img {
+    float: right;
+    padding-right: 0;
+    padding-left: 2px;
+}
+/* Preferences. */
+#services_prefs .header ul {
+    float: left;
+    text-align: left;
+}
+.prefsOverview div {
+    float: right;
+}
+.prefsOverview div div {
+    padding-left: 0;
+    padding-right: 10px;
+}
+
+/* MIME styles. */
+.download {
+    padding: 2px 0 2px 20px;
+    background-position: center left;
+}
+
+/* Calendar Popup. */
+.calendarPopup tbody {
+    text-align: left;
+}
+
+/* Redbox styles. */
+#RB_window {
+    text-align: right;
+}
+
+/* Color picker styles. */
+#color-picker .north div {
+    float: left;
+}
+#color-picker .south {
+    margin: 32px 0 0 10px;
+    margin: 32px 10px 0 0;
+}
+#color-picker .south img {
+    left: 0;
+    right: -1px;
+}
+#color-picker #color-picker-cursor img {
+    left: 0;
+    right: -1px;
+}
+#color-picker #color-picker-hex {
+    padding: 5px 7px 4px 0;
+    float: right;
+}
+#color-picker #color-picker-resize {
+    float: left;
+    left: 0;
+    right: 7px;
+    cursor: sw-resize;
+}
+
+.leftAlign {
+    text-align: right;
+}
+.rightAlign {
+    text-align: left;
+}
+.leftFloat {
+    float: right;
+}
+.rightFloat {
+    float: left;
+}
diff --git a/koward/www/htdocs/horde/themes/screen.css b/koward/www/htdocs/horde/themes/screen.css
new file mode 100644 (file)
index 0000000..2969973
--- /dev/null
@@ -0,0 +1,1024 @@
+/**
+ * $Horde: horde/themes/screen.css,v 1.207 2009/04/23 20:09:28 mrubinsk Exp $
+ */
+
+/* Global default styles. */
+* {
+    /* Zero out all padding and margins to start with for better
+     * cross-browser control. */
+    padding: 0;
+    margin: 0;
+}
+
+body, input, select, textarea, .inProgress {
+    font-family: Geneva,Arial,"Bitstream Vera Sans",Helvetica,sans-serif;
+}
+body {
+    font-size: 75%;
+    background: #fff;
+    color: #000;
+}
+
+body.scrollbar-quirk {
+    margin-right: 15px;
+}
+
+p {
+    margin-bottom: 10px;
+}
+
+img, .img, .img:active, .img:hover, .img:visited, .image {
+    border: none;
+    vertical-align: middle;
+    background: transparent;
+}
+/* This must be declared seperately or IE will ignore all of the selectors. */
+input[type=image] {
+    border: none;
+    vertical-align: middle;
+    background: transparent;
+}
+
+ins {
+    background: #cfc;
+}
+del {
+    background: #fcc;
+}
+
+br.spacer {
+    line-height: 8px;
+}
+
+.box {
+    padding: 3px;
+    border: 1px dashed #999;
+    background: #fff;
+}
+.solidbox {
+    border: 1px solid #000;
+}
+.greybox {
+    border: 1px solid #000;
+    background: #e9e9e9;
+}
+.headerbox {
+    border-left: 1px solid #000;
+    border-right: 1px solid #000;
+    border-bottom: 1px solid #000;
+    background: #fff;
+    vertical-align: top;
+}
+.roundedBox {
+    -moz-border-radius: 15px;
+    -webkit-border-radius: 15px;
+}
+.roundedTop {
+    -moz-border-radius-topright: 15px;
+    -moz-border-radius-topleft: 15px;
+    -webkit-border-top-right-radius: 15px;
+    -webkit-border-top-left-radius: 15px;
+}
+.roundedBottom {
+    -moz-border-radius-bottomright: 15px;
+    -moz-border-radius-bottomleft: 15px;
+    -webkit-border-bottom-right-radius: 15px;
+    -webkit-border-bottom-left-radius: 15px;
+}
+.header {
+    text-align: left;
+    font-weight: bold;
+    font-size: 125%;
+    padding: 3px;
+}
+.header a:hover, a.header:hover {
+    color: #333;
+}
+.header img {
+    vertical-align: bottom;
+}
+.header input, .header select {
+    font-size: 80%;
+}
+.header .smallheader input, .header .smallheader select {
+    font-size: 100%;
+}
+.header .button, .header .smallheader .button {
+    font-size: 72%;
+}
+
+.nowrap {
+    white-space: nowrap;
+}
+.clear {
+    clear: both;
+    line-height: 0;
+    height: 0;
+}
+
+a {
+    color: blue;
+    text-decoration: none;
+}
+a:hover {
+    text-decoration: underline;
+}
+.selected {
+    background: #bbcbff;
+}
+.selected-over {
+    background: #cef;
+}
+
+/* Table styles. */
+table {
+    border: none;
+}
+td, th {
+    padding: 1px;
+}
+th {
+    color: #333;
+}
+td {
+}
+ul.linedRow {
+    list-style-type: none;
+}
+.linedRow, tr.linedRow td, table.linedRow td, ul.linedRow li {
+    color: #000;
+    background: #fff;
+    border-bottom: 1px solid #ddd;
+}
+table.linedRow, ul.linedRow {
+    border-bottom: none;
+}
+.linedRowSelectedCol, td.linedRowSelectedCol, table.linedRow td.linedRowSelectedCol {
+    color: #000;
+    background: #f3f3f3;
+    border-bottom: 1px solid #ddd;
+}
+.selectedRow, tr.selectedRow td {
+    background: #ffc;
+}
+.selectedRow:hover, tr.selectedRow:hover td, .selectedRow-over, tr.selectedRow-over td {
+    background: #ffd;
+}
+table.nopadding td, table.nopadding th {
+    padding: 0;
+}
+.sortup {
+    background: #bbcbff url("graphics/za.png") center left no-repeat;
+    padding-left: 10px;
+}
+.sortdown {
+    background: #bbcbff url("graphics/az.png") center left no-repeat;
+    padding-left: 10px;
+}
+/* Horde UI standard tables */
+table.horde-table {
+    width: 99%;
+    margin: 0 0 8px 5px;
+    border-top: 1px solid #ddd;
+    border-left: 1px solid #ddd;
+}
+table.horde-table th {
+    padding: 3px;
+    background: #e9e9e9;
+    border-right: 1px solid #ccc;
+    text-align: left;
+}
+table.horde-table th.rightAlign {
+    text-align: right;
+}
+table.horde-table td {
+    padding: 3px;
+    border-right: 1px solid #ddd;
+    border-bottom: 1px solid #ddd;
+}
+table.horde-table th.sortup {
+    background: #bbcbff url("graphics/za.png") center left no-repeat;
+    padding-left: 10px;
+}
+table.horde-table th.sortdown {
+    background: #bbcbff url("graphics/az.png") center left no-repeat;
+    padding-left: 10px;
+}
+/* Alternating styles. item0, item1 are deprecated. */
+.striped, .rowEven, .item0 {
+    background-color: #eee;
+}
+.rowOdd, .item1 {
+    background-color: #ddd;
+}
+
+.widget {
+    font-size: 90%;
+}
+
+.light {
+}
+.smallheader {
+    font-size: 100%;
+    font-weight: bold;
+    padding: 2px;
+}
+.header .smallheader {
+    font-size: 80%;
+}
+.header .smallheader a.smallheader {
+    font-size: 100%;
+}
+small, .small {
+    font-size: 80%;
+}
+.control {
+    color: #000;
+    background: #ccc;
+    border-bottom: 1px solid #999;
+    padding: 1px;
+}
+.item {
+    color: #000;
+    background: #eee;
+}
+.accessKey {
+    text-decoration: underline;
+}
+.text {
+    color: #000;
+    background: #fff;
+}
+
+/* Form styles. */
+.form table {
+    width: 100%;
+    padding: 2px;
+    border-collapse: collapse;
+}
+form[action^="https://"] input[type="submit"] {
+    background-image: url("graphics/locked.png");
+    background-position: 95% center;
+    background-repeat: no-repeat;
+    padding-right: 10%;
+}
+input[disabled], textarea[disabled] {
+    background-color: #e9e9e9;
+    color: #a8a8a8;
+}
+.htmlarea .statusBar .statusBarTree a {
+    font: inherit;
+}
+.htmlarea table {
+    width: auto;
+}
+.form-error {
+    color: #f00;
+}
+input, select, textarea {
+    font-size: 100%;
+    font-weight: normal;
+}
+input {
+    padding: 1px;
+}
+option {
+    padding: 0 5px 0 3px;
+}
+.checkbox, .radio {
+    border: 0;
+    height: 14px;
+    width: 14px;
+    background: transparent;
+}
+.button {
+    cursor: pointer;
+    font-size: 90%;
+    padding: 1px 6px;
+}
+a.button {
+    padding: 2px 8px;
+    font-weight: normal;
+    text-decoration: none;
+}
+
+pre, code, .fixed, ol.code-listing, table.lineNumbered * {
+    font-size: 100%;
+    font-family: "Lucida Console","Bitstream Vera Sans Mono",Courier,"Courier New";
+}
+
+/* Styles for email-like messages. */
+.signature {
+    color: #ccc;
+}
+.signature .fixed {
+    color: #ccc;
+}
+.citation {
+    margin: 1em 0;
+    padding-left: 1em;
+    border-left-width: 1px;
+    border-left-style: solid;
+}
+.quoted1 {
+    color: #606;
+    border-color: #606;
+    background-color: #eee;
+}
+.quoted2 {
+    color: #077;
+    border-color: #077;
+}
+.quoted3 {
+    color: #900;
+    border-color: #900;
+}
+.quoted4 {
+    color: #009;
+    border-color: #009;
+}
+.quoted5 {
+    color: #b60;
+    border-color: #b60;
+}
+
+/* Various popup and status layers. */
+.notices {
+    text-align: left;
+    margin: .5em 8px;
+    list-style-type: none;
+}
+.notices li, .notice {
+    font-weight: bold;
+    color: #000;
+    background: #ffc;
+    border: 1px solid #aaa;
+    padding: 1px 1px 1px 5px;
+}
+.notices img, .notice img {
+    margin-right: .5em;
+}
+.tooltip, div.nicetitle {
+    color: #000;
+    background: #ffc;
+    border: 1px solid #000;
+    padding: 5px;
+    z-index: 1001;
+    -moz-border-radius: 3px;
+    -webkit-border-radius: 3px;
+}
+div.nicetitle {
+    position: absolute;
+    overflow: hidden;
+    opacity: .9;
+}
+.inProgress {
+    font-size: 80%;
+    padding: 2px;
+    color: #fff;
+    background: #f00;
+}
+
+/* Tree styles. */
+.treeRow {
+    overflow: hidden;
+    min-height: 20px;
+    clear: both;
+}
+
+/* Menu styles. */
+#menu {
+    overflow: hidden;
+    min-height: 50px;
+    margin-bottom: 8px;
+    padding-right: 8px;
+}
+#menu ul {
+    padding: 5px;
+}
+#menu li {
+    list-style-type: none;
+    text-align: center;
+    margin: 2px;
+    float: left;
+}
+#menu li.separator {
+    width: 40px;
+}
+#menu a {
+    display: block;
+    white-space: pre;
+    font-size: 90%;
+    text-decoration: none;
+    padding: 3px;
+    -moz-border-radius: 3px;
+    -webkit-border-radius: 3px;
+}
+#menu h1 {
+    font-weight: bold;
+    font-size: 150%;
+    line-height: 48px;
+    vertical-align: bottom;
+}
+#menu input, #menu select {
+    margin-top: 16px;
+}
+#menuBottom {
+    margin: -8px 0 0 0;
+    padding: 4px;
+    float: right;
+    text-align: right;
+    font-size: 90%;
+    background: #eee;
+}
+
+/* Sidebar styles. */
+.sidebar #menu {
+    margin: 0;
+}
+#sidebarPanel {
+    -moz-border-radius-bottomright: 15px;
+    -webkit-border-bottom-right-radius: 15px;
+    padding-top: 5px;
+    padding-bottom: 10px;
+    background: #eee;
+    white-space: nowrap;
+}
+#sidebarPanel a, #sidebarPanel span {
+    color: #000;
+    white-space: pre;
+    font-size: 90%;
+    text-decoration: none;
+}
+#sidebarPanel a a, #sidebarPanel a span, #sidebarPanel span a, #sidebarPanel span span {
+    font-size: 100%;
+}
+#sidebarPanel span.accessKey {
+    text-decoration: underline;
+}
+#sidebarPanel span.toggle {
+    cursor: pointer;
+}
+#sidebarPanel a:hover {
+    color: #000;
+}
+
+/* Pager. */
+.pager {
+    text-align: center;
+}
+
+/* Tab styles. */
+.tabset {
+    float: left;
+    width: 100%;
+    font-weight: bold;
+    background: url("graphics/tab_bottom.gif") repeat-x bottom;
+}
+.tabset ul {
+    margin-top: 4px;
+    padding-left: 8px;
+    list-style: none;
+}
+.tabset li {
+    float: left;
+    margin: -3px 2px 0 0;
+    white-space: nowrap;
+}
+.tabset li a {
+    color: #000;
+    background-color: #e9e9e9;
+    padding: 2px 0.5em;
+    display: block;
+    border: 1px solid #000;
+}
+.tabset li a:hover {
+    background-color: #fff;
+}
+.tabset li.activeTab a {
+    border-bottom: 1px solid #000;
+    background-color: #000;
+    color: #fff;
+}
+.tabset li.activeTab a:hover {
+}
+.tabset img {
+    display: block;
+    float: left;
+    padding-right: 2px;
+}
+
+/* Preferences. */
+#services_prefs .header ul {
+    float: right;
+    text-align: right;
+    font-size: 80%;
+}
+#services_prefs .header li {
+    list-style: none;
+    display: inline;
+}
+.prefsOverview div {
+    float: left;
+}
+.prefsOverview div div {
+    padding-left: 10px;
+    width: 95%;
+}
+.prefsOverview h2 {
+    font-size: 150%;
+    font-weight: bold;
+}
+.prefsOverview dt a {
+    display: block;
+    padding: 2px;
+    font-weight: bold;
+    border: 1px solid #000;
+    border-bottom: 1px solid #446;
+    background: #e9e9e9;
+}
+.prefsOverview dd {
+    padding: 2px;
+    margin-bottom: 10px;
+    color: #000;
+    background: #fff;
+    border-left: 1px solid #000;
+    border-right: 1px solid #000;
+    border-bottom: 1px solid #000;
+}
+div.prefsContainer {
+    padding: 1em;
+}
+div.prefsContainer p {
+    padding-top: 1em;
+}
+
+/* Block styles. */
+.currentBlock {
+    border: 2px solid red;
+}
+.blockIcons {
+    padding-top: 5px;
+    display:none;
+}
+.blockHeader:hover .blockIcons {
+    display: block;
+}
+#googlesearch {
+    padding: .3em;
+}
+
+/* Help styles. */
+body.help_about, body.help_entry {
+    margin: 0.5em;
+}
+.helplink {
+    cursor: help;
+}
+.help {
+    background: #fff;
+    color: #000;
+}
+.help h1 {
+    font-size: 125%;
+    padding-top: 0.5em;
+    padding-bottom: 0.5em;
+}
+.help h2 {
+    padding-top: 1em;
+    padding-bottom: 0.5em;
+    font-size: 110%;
+}
+.help p {
+    margin-left: 1em;
+    margin-right: 1em;
+    margin-bottom: 1em;
+}
+.help em {
+    display: block;
+    padding: 5px;
+    margin-left: 1em;
+    margin-right: 1em;
+    margin-bottom: 1em;
+}
+.help em.helpTip {
+    color: #090;
+    background: #e0f0e0;
+}
+.help em.helpWarn {
+    color: #900;
+    background: #f0e0e0;
+}
+
+/* Source markup styles. */
+ol.code-listing {
+    overflow: hidden;
+    color: #999;
+    background-color: #fff;
+    text-align: left;
+    list-style-position: inside;
+    list-style-type: decimal-leading-zero;
+    white-space: nowrap;
+}
+ol.code-listing li {
+    padding: 3px;
+    white-space: pre;
+    padding-left: .5em;
+}
+ol.code-listing .comment {
+    color: #666;
+}
+ol.code-listing .default {
+    color: #00b;
+}
+ol.code-listing .keyword {
+    color: #070;
+}
+ol.code-listing .string {
+    color: #d00;
+}
+
+table.lineNumbered * {
+    line-height: 16px;
+}
+.lineNumbered th {
+    background: #e9e9e9;
+    border-right: 1px solid #e0e0e0;
+    border-bottom: none;
+    padding-left: 10px;
+    padding-right: 10px;
+    text-align: right;
+}
+.lineNumbered td {
+    vertical-align: top;
+    width: 100%;
+    white-space: pre;
+    background: #fff;
+    padding-left: 10px;
+}
+.parentheses {
+    color: #2a6;
+    font-weight: bold;
+}
+.comment {
+    color: #aac;
+}
+.htag {
+    color: #569;
+    background: #d5d6da;
+    font-weight: bold;
+}
+.metac {
+    color: #0ff;
+    background: #d5d6da;
+}
+.id {
+    color: #e82;
+    background: #e4e4e0;
+}
+.attr {
+    color: #6af;
+}
+.value {
+    color: #d46;
+}
+.color {
+    color: #f57;
+}
+.eol {
+    color: #26e;
+}
+.url {
+    color: #962;
+}
+.file {
+    color: #444;
+    background: #fe4;
+}
+.class {
+    font-style: italic;
+}
+
+/* Sound selection. */
+ul.sound-list {
+    list-style: none;
+}
+.sound-list li {
+    height: 24px;
+}
+.sound-list embed {
+    vertical-align: middle;
+    height: 24px;
+}
+
+/* Calendar Popup. */
+table.calendarPopup {
+    border: 1px solid #ccc;
+    background: #fff;
+    width: 12em;
+}
+.calendarPopup thead {
+    font-weight: bold;
+}
+.calendarPopup th {
+    border-bottom: 1px solid #ccc;
+}
+.calendarPopup tbody {
+    text-align: right;
+}
+.calendarPopup a {
+    color: #000;
+    display: block;
+    padding: 2px;
+}
+.calendarPopup tbody a:hover {
+    background: #ffc;
+}
+.calendarPopup .current {
+    font-weight: bold;
+    background: #eef;
+}
+.calendarPopup .today {
+    font-weight: bold;
+}
+
+.hidden {
+    display: none;
+}
+
+/* Redbox styles. */
+#RB_overlay {
+    position: absolute;
+    z-index: 100;
+    width: 100%;
+    height: 100%;
+    top: 0;
+    left: 0;
+    right: 0;
+    bottom: 0;
+    min-height: 100%;
+    background-color: #000;
+    filter: alpha(opacity=60);
+    -moz-opacity: .6;
+    opacity: .6;
+}
+#RB_loading {
+    z-index: 101;
+    width: 66px;
+    margin-left: auto;
+    margin-right: auto;
+    margin-top: 200px;
+    padding-bottom: 66px;
+    text-align: center;
+    background: url("graphics/redbox_spinner.gif") no-repeat bottom center;
+}
+#RB_window {
+    z-index: 102;
+    background-color: #fff;
+    display: block;
+    text-align: left;
+    overflow: hidden;
+    margin: 20px auto 0 auto;
+    position: absolute;
+}
+
+/* Color picker styles. */
+#color-picker {
+    color: #999;
+    background: #000;
+    padding-bottom: 8px;
+    border: 1px solid #111;
+    width: 148px;
+    height: 155px;
+    z-index: 100;
+}
+#color-picker .north {
+    background: #111;
+    border-bottom: 1px solid #171717;
+    font-size: 11px;
+}
+#color-picker .north div {
+    color: #999;
+    float: right;
+    padding: 5px 7px;
+    cursor: pointer;
+    -moz-user-select: none;
+    -khtml-user-select: none;
+    user-select: none;
+}
+#color-picker .north div:hover {
+    color: #fff;
+}
+#color-picker .south {
+    margin: 32px 0 0 10px;
+    cursor: crosshair;
+    -moz-user-select: none;
+    -khtml-user-select: none;
+    user-select: none;
+}
+#color-picker .south img {
+    height: 100%;
+    width: 100%;
+    position: relative;
+    top: -8px;
+    left: -1px;
+}
+#color-picker #color-picker-cursor {
+    background: url("graphics/color-picker-cursor.gif") no-repeat;
+    position: absolute;
+    height: 9px;
+    width: 9px;
+    z-index: 101;
+}
+#color-picker #color-picker-cursor img {
+    height: 100%;
+    width: 100%;
+    position: relative;
+    top: -8px;
+    left: -1px;
+}
+#color-picker #color-picker-hex {
+    padding: 5px 0 4px 7px;
+    cursor: text;
+    float: left;
+}
+#color-picker #color-picker-hex:hover {
+    color: #fff;
+}
+#color-picker #color-picker-resize {
+    float: right;
+    top: -14px;
+    left: 7px;
+    height: 14px;
+    width: 14px;
+    cursor: se-resize;
+}
+#color-picker-palette-src {
+    background-image: url("graphics/color-picker-palette.png");
+}
+#color-picker-resize-src {
+    background-image: url("graphics/color-picker-resize.gif");
+}
+
+.leftAlign {
+    text-align: left;
+}
+.rightAlign {
+    text-align: right;
+}
+.leftFloat {
+    float: left;
+}
+.rightFloat {
+    float: right;
+}
+
+.toggleQuoteHide, .toggleQuoteShow {
+    font-size: 80%;
+    cursor: pointer;
+    background: #ddd;
+}
+.toggleQuoteHide:hover, .toggleQuoteShow:hover {
+    text-decoration: underline;
+}
+.toggleQuoteParent {
+    margin-bottom: 8px;
+}
+
+/* Growler notice styling. */
+#Growler {
+    width: 340px;
+}
+#Growler div.GrowlerNotice {
+    filter: alpha(opacity=80);
+    -moz-opacity: .8;
+    opacity: .8;
+    zoom: 1;
+    width: 300px;
+    padding: 10px 10px 10px 25px;
+    margin: 5px auto;
+    text-align: left;
+    display: none;
+    -moz-border-radius: 5px;
+    -webkit-border-radius: 5px;
+    min-height: 20px;
+    border: 1px #316600 solid;
+    background: 3px center #5db110 no-repeat;
+    color: #fff;
+}
+#Growler div.GrowlerNoticeHead {
+    font-weight: bold;
+}
+#Growler div.GrowlerNoticeExit {
+    float: right;
+    font-weight: bold;
+    cursor: pointer;
+}
+#Growler div.horde-error, #GrowlerLog li.horde-error {
+    background-color: #e81222;
+    background-image: url("graphics/alerts/error.png");
+    border-color: maroon;
+}
+#Growler div.horde-message, #GrowlerLog li.horde-message {
+    background-image: url("graphics/alerts/message.png");
+}
+#Growler div.horde-success, #GrowlerLog li.horde-success  {
+    background-image: url("graphics/alerts/success.png");
+}
+#Growler div.horde-warning, #GrowlerLog li.horde-warning {
+    background-color: #ebe20c;
+    background-image: url("graphics/alerts/warning.png");
+    border-color: #807b00;
+    color: #000;
+}
+
+#GrowlerLog {
+    position: fixed;
+    bottom: 0;
+    left: 0;
+    width: 100%;
+    max-height: 200px;
+    z-index: 10000;
+    overflow-y: auto;
+}
+#GrowlerLog ul {
+    overflow: auto;
+    filter: alpha(opacity=80);
+    -moz-opacity: .8;
+    opacity: .8;
+}
+#GrowlerLog ul li {
+    color: #333;
+    font-size: 12px;
+    list-style-type: none;
+    overflow: hidden;
+    padding: 10px 30px;
+    border-bottom: 1px dotted;
+    background: 3px center #5db110 no-repeat;
+}
+#GrowlerLog ul li:last-child {
+    border: 0;
+}
+#GrowlerLog li.NoAlerts {
+    font-weight: bold;
+    background: #999;
+}
+#GrowlerLog span.alertdate {
+    font-size: 90%;
+    font-style: italic;
+    padding-left: 10px;
+}
+.hordeACBox {
+    background:white none repeat scroll 0 0;
+    border:1px solid #666699;
+    cursor:default;
+    /*overflow:hidden;*/
+    text-align:left;
+    min-height: 58px;
+}
+
+.hordeACList {
+    display:block;
+    overflow:hidden;
+    width:100%;
+    cursor:default;
+    list-style-type:none;
+    margin:0;
+    padding:0;
+}
+
+.hordeACListMember {
+    display:inline-block;
+    font-size:90%;
+    padding:2px 1px 1px 2px;
+    height: 17px;
+    white-space:nowrap;
+}
+
+.hordeACListItem {
+    background-color:lightblue;
+    border:1px solid #C0C0C0;
+    -moz-border-radius-bottomleft:4px;
+    -moz-border-radius-bottomright:4px;
+    -moz-border-radius-topleft:4px;
+    -moz-border-radius-topright:4px;
+    margin:5px;
+}
+
+.hordeACTrigger, .hordeACTrigger:focus {
+    background:transparent none repeat scroll 0 0;
+    border:0 none;
+    display:inline;
+    position:static;
+    width:80px;
+}
+
+/*.hordeACContainer {
+    height:18px;
+    margin:2px;
+    padding:2px 2px 2px 0;
+}*/
+
+.hordeACItemRemove:hover {
+    cursor:pointer;
+}
\ No newline at end of file
diff --git a/koward/www/htdocs/horde/themes/silver/graphics/currentTab_left.png b/koward/www/htdocs/horde/themes/silver/graphics/currentTab_left.png
new file mode 100644 (file)
index 0000000..8fde2d5
Binary files /dev/null and b/koward/www/htdocs/horde/themes/silver/graphics/currentTab_left.png differ
diff --git a/koward/www/htdocs/horde/themes/silver/graphics/currentTab_right.png b/koward/www/htdocs/horde/themes/silver/graphics/currentTab_right.png
new file mode 100644 (file)
index 0000000..bd8721d
Binary files /dev/null and b/koward/www/htdocs/horde/themes/silver/graphics/currentTab_right.png differ
diff --git a/koward/www/htdocs/horde/themes/silver/graphics/delete.png b/koward/www/htdocs/horde/themes/silver/graphics/delete.png
new file mode 100644 (file)
index 0000000..afe22ba
Binary files /dev/null and b/koward/www/htdocs/horde/themes/silver/graphics/delete.png differ
diff --git a/koward/www/htdocs/horde/themes/silver/graphics/edit.png b/koward/www/htdocs/horde/themes/silver/graphics/edit.png
new file mode 100644 (file)
index 0000000..046811e
Binary files /dev/null and b/koward/www/htdocs/horde/themes/silver/graphics/edit.png differ
diff --git a/koward/www/htdocs/horde/themes/silver/graphics/logout.png b/koward/www/htdocs/horde/themes/silver/graphics/logout.png
new file mode 100644 (file)
index 0000000..41676a0
Binary files /dev/null and b/koward/www/htdocs/horde/themes/silver/graphics/logout.png differ
diff --git a/koward/www/htdocs/horde/themes/silver/graphics/plus.png b/koward/www/htdocs/horde/themes/silver/graphics/plus.png
new file mode 100644 (file)
index 0000000..6332fef
Binary files /dev/null and b/koward/www/htdocs/horde/themes/silver/graphics/plus.png differ
diff --git a/koward/www/htdocs/horde/themes/silver/graphics/search.png b/koward/www/htdocs/horde/themes/silver/graphics/search.png
new file mode 100644 (file)
index 0000000..908612e
Binary files /dev/null and b/koward/www/htdocs/horde/themes/silver/graphics/search.png differ
diff --git a/koward/www/htdocs/horde/themes/silver/graphics/tab_left.png b/koward/www/htdocs/horde/themes/silver/graphics/tab_left.png
new file mode 100644 (file)
index 0000000..b241091
Binary files /dev/null and b/koward/www/htdocs/horde/themes/silver/graphics/tab_left.png differ
diff --git a/koward/www/htdocs/horde/themes/silver/graphics/tab_right.png b/koward/www/htdocs/horde/themes/silver/graphics/tab_right.png
new file mode 100644 (file)
index 0000000..9cede9a
Binary files /dev/null and b/koward/www/htdocs/horde/themes/silver/graphics/tab_right.png differ
diff --git a/koward/www/htdocs/horde/themes/silver/graphics/user.png b/koward/www/htdocs/horde/themes/silver/graphics/user.png
new file mode 100644 (file)
index 0000000..30383c2
Binary files /dev/null and b/koward/www/htdocs/horde/themes/silver/graphics/user.png differ
diff --git a/koward/www/htdocs/horde/themes/silver/info.php b/koward/www/htdocs/horde/themes/silver/info.php
new file mode 100644 (file)
index 0000000..843dd73
--- /dev/null
@@ -0,0 +1,20 @@
+<?php
+/**
+ * Silver Surfer Theme
+ *
+ * Silk icons are from Mark James
+ * (http://www.famfamfam.com/lab/icons/silk/), used under a Creative
+ * Commons Attribution 2.5 License. [
+ * http://creativecommons.org/licenses/by/2.5/ ]. "This means you may
+ * use it for any purpose, and make any changes you like.  All I ask
+ * is that you include a link back to this page in your credits."
+ *
+ * Flag icons are from http://www.famfamfam.com/ and are in the public
+ * domain.
+ *
+ * @author Daniel Dembach http://blog.dembachco.de/
+ *
+ * $Horde: horde/themes/silver/info.php,v 1.2 2008/01/10 04:43:12 chuck Exp $
+ */
+
+$theme_name = ("Silver Surfer");
diff --git a/koward/www/htdocs/horde/themes/silver/screen.css b/koward/www/htdocs/horde/themes/silver/screen.css
new file mode 100644 (file)
index 0000000..515200d
--- /dev/null
@@ -0,0 +1,257 @@
+/**
+ * $Horde: horde/themes/silver/screen.css,v 1.35 2009/04/14 03:38:21 slusarz Exp $
+ */
+
+body, input, select, textarea, .inProgress {
+    font-family: Verdana,Geneva,Arial,"Bitstream Vera Sans",Helvetica,sans-serif;
+    color: #333;
+}
+.solidbox {
+    border: 1px solid #999;
+}
+.greybox {
+    border: 1px solid #999;
+}
+.headerbox {
+    border-left: 1px solid #999;
+    border-right: 1px solid #999;
+    border-bottom: 1px solid #999;
+}
+a, a.fixed {
+    color: #366;
+}
+a.widget {
+    color: #366;
+}
+.header, .smallheader {
+    background: #d7d7d7 url("graphics/menu.png") top center repeat-x;
+    border-top: 1px solid #999;
+    border-bottom: 1px solid #999;
+}
+.header {
+    padding: 2px;
+}
+.header a:hover {
+    color: #699;
+}
+.header .smallheader {
+    background: none;
+    border: none;
+}
+.light {
+    color: #666;
+}
+.smallheader {
+    color: #333;
+}
+.smallheader a {
+    color: #333;
+}
+.control {
+    background: #eee;
+}
+.item {
+    background: #eee;
+}
+
+.sortup {
+    background: #ccc url("graphics/za.png") center left no-repeat;
+}
+.sortdown {
+    background: #ccc url("graphics/az.png") center left no-repeat;
+}
+.linedRow, tr.linedRow td, table.linedRow td, ul.linedRow li {
+    color: #333;
+}
+.linedRowSelectedCol, td.linedRowSelectedCol, table.linedRow td.linedRowSelectedCol {
+    color: #333;
+}
+.control {
+    color: #333;
+}
+.item {
+    color: #333;
+}
+.text {
+    color: #333;
+    background: #fff;
+}
+
+/* Form styles. */
+input, select, textarea {
+    color: #000;
+    background: #f3f3f3;
+    border: 1px solid #999;
+}
+input:focus, textarea:focus {
+    background: #fff;
+}
+.button {
+    color: #333;
+    background: #d7d7d7 url("graphics/menu.png") repeat-x 0 -1px;
+    border: 1px solid #999;
+    padding: 1px 2px;
+    font-weight: bold;
+    cursor: pointer;
+}
+.button:hover {
+    color: #699;
+}
+a.button {
+    padding: 2px 4px;
+    font-weight: bold;
+}
+
+/* Alternating styles. item0, item1 are deprecated. */
+.rowEven, .item0 {
+    background-color: #eee;
+}
+.rowOdd, .item1 {
+    background-color: #fff;
+}
+
+.selected {
+    background: #ccc;
+}
+
+/* Various popup and status layers. */
+.notice {
+    color: #333;
+    background: #ffc;
+    border: 1px solid #aaa;
+}
+.tooltip, div.nicetitle {
+    color: #333;
+    background: #ffc;
+    border: 1px solid #333;
+}
+
+/* Menu styles. */
+#menu {
+    background: #d7d7d7 url("graphics/menu.png") repeat-x;
+}
+#menu h1 {
+    color: #333;
+}
+#menu a {
+    border: 1px solid transparent;
+    color: #333;
+    padding: 3px 3px 0 3px;
+    margin: 0;
+}
+#menu a:hover {
+    border: 1px solid transparent;
+    padding: 3px 3px 0 3px;
+    margin: 0;
+}
+#menu a.current {
+    border: 1px solid #aaa;
+    padding: 3px;
+    margin: 0;
+    background: url("graphics/menu-active.png") repeat-x;
+    -moz-border-radius: 0;
+    -webkit-border-radius: 0;
+}
+#menuBottom {
+    position: relative;
+    top: -1px;
+    background: #d7d7d7;
+    border: 1px solid #999;
+    border-right: none;
+    border-top: none;
+    padding-left: 6px;
+    -moz-border-radius-bottomleft: 10px;
+    -webkit-border-bottom-left-radius: 10px;
+}
+
+/* Sidebar styles. */
+#sidebarPanel {
+    background: #efefef;
+    margin-right: .5em;
+    border: 1px solid #999;
+    border-left: none;
+    border-top: none;
+}
+#sidebarPanel span, #sidebarPanel a {
+    color: #333;
+    font-family: Verdana,sans-serif;
+}
+#sidebarPanel a:hover {
+    color: #333;
+}
+#expandButton {
+    margin-right: .5em;
+}
+
+/* Tab styles. */
+.tabset {
+    background: none;
+}
+.tabset li {
+    background: url("graphics/tab_right.png") no-repeat right top;
+    margin-bottom: -1px;
+}
+.tabset li a {
+    color: #366;
+    background: url("graphics/tab_left.png") no-repeat left top;
+    border: 0;
+    border-bottom: 1px solid #999;
+    padding: 4px 0.8em 3px 0.8em;
+}
+.tabset li a:hover {
+    color: #999;
+    background: url("graphics/tab_left.png") no-repeat left top;
+}
+.tabset li.activeTab {
+    background: url("graphics/currentTab_right.png") no-repeat right top;
+}
+.tabset li.activeTab a {
+    color: #366;
+    background: url("graphics/currentTab_left.png") no-repeat left top;
+    border-bottom: 1px solid #999;
+}
+
+/* Preferences overview. */
+.prefsOverview dt a {
+    background: #d7d7d7 url("graphics/menu.png") repeat-x;
+    border: 1px solid #333;
+}
+.prefsOverview dd {
+    color: #333;
+    background: #fff;
+    border-left: 1px solid #333;
+    border-right: 1px solid #333;
+    border-bottom: 1px solid #333;
+}
+
+/* Help styles. */
+.help {
+    color: #333;
+}
+.help #sidebarPanel {
+    border-top: 1px solid #999;
+}
+
+/* Source markup styles. */
+table.lineNumbered {
+    border: 1px solid #333;
+}
+
+/* MIME styles. */
+.download {
+    background-image: url("graphics/download.png");
+}
+
+/* Growler notification styles. */
+#Growler div.horde-error, #GrowlerLog li.horde-error {
+    background-image: url("graphics/alerts/error.png");
+}
+#Growler div.horde-message, #GrowlerLog li.horde-message {
+    background-image: url("graphics/alerts/message.png");
+}
+#Growler div.horde-success, #GrowlerLog li.horde-success {
+    background-image: url("graphics/alerts/success.png");
+}
+#Growler div.horde-warning, #GrowlerLog li.horde-warning {
+    background-image: url("graphics/alerts/warning.png");
+}
diff --git a/koward/www/htdocs/horde/themes/silver/themed_graphics b/koward/www/htdocs/horde/themes/silver/themed_graphics
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/koward/www/htdocs/horde/themes/webkit.css b/koward/www/htdocs/horde/themes/webkit.css
new file mode 100644 (file)
index 0000000..5a8c2f0
--- /dev/null
@@ -0,0 +1,19 @@
+/**
+ * $Horde: horde/themes/webkit.css,v 1.2 2009/02/10 03:57:15 slusarz Exp $
+ *
+ * CSS corrections for Webkit.
+ */
+
+.treeRow {
+    overflow: visible;
+    height: 20px;
+}
+
+.treeRow img {
+    vertical-align: middle;
+}
+
+#menu {
+    overflow: visible;
+    height: 50px;
+}
diff --git a/koward/www/htdocs/koward/koward.php b/koward/www/htdocs/koward/koward.php
new file mode 100644 (file)
index 0000000..c327063
--- /dev/null
@@ -0,0 +1,22 @@
+<?php
+/**
+ * Identify the horde base application.
+ */
+require_once dirname(__FILE__) . '/../../koward/config/base.php';
+
+/**
+ * The Autoloader allows us to omit "require/include" statements.
+ */
+require_once 'Horde/Autoloader.php';
+
+/** Configure the Autoloader to handle the "Koward" pattern */
+Horde_Autoloader::addClassPattern('/^Koward_/', 'Koward/');
+
+/** Dispatch the request. */
+try {
+    Koward::dispatch(__FILE__);
+} catch (Exception $e) {
+    // @TODO Make nicer
+    echo '<h1>' . $e->getMessage() . '</h1>';
+    echo '<pre>'; var_dump($e); echo '</pre>';
+}
diff --git a/koward/www/htdocs/koward/themes/graphics/favicon.ico b/koward/www/htdocs/koward/themes/graphics/favicon.ico
new file mode 100644 (file)
index 0000000..0f8fa08
Binary files /dev/null and b/koward/www/htdocs/koward/themes/graphics/favicon.ico differ
diff --git a/koward/www/htdocs/koward/themes/graphics/query.png b/koward/www/htdocs/koward/themes/graphics/query.png
new file mode 100644 (file)
index 0000000..ef46d4a
Binary files /dev/null and b/koward/www/htdocs/koward/themes/graphics/query.png differ
diff --git a/koward/www/htdocs/koward/themes/kolab/screen.css b/koward/www/htdocs/koward/themes/kolab/screen.css
new file mode 100644 (file)
index 0000000..017e2a7
--- /dev/null
@@ -0,0 +1,212 @@
+/*
+  Local variables:
+  buffer-file-coding-system: utf-8
+  End:
+*/
+body {
+  color: black;
+  background-color: #F8FCF8;
+  font-family: verdana,arial,helvetica,sans-serif;
+  font-size: 95%;
+  border: 0;
+  margin: 0;
+}
+a, a:visited {
+  font-family: verdana,arial,helvetica,sans-serif;
+}
+
+a { color: #001155; }
+a:hover { color: #113399; }
+
+#page {
+  background-repeat: no-repeat;
+  background-position: top right;
+}
+
+#topbar {
+  display:block;
+  background-color: #B0BCD0;
+  height: 70px;
+  clear: both;
+}
+#toplogo {
+  display:block;
+  background-image: url(pics/kolab_logo.png);
+  background-color: #B0BCD0;
+  width: 245px;
+  height: 70px;
+  margin-left: 1em;
+  margin-top: 0.4em;
+  float: left;
+}
+#toptitle {
+  display:block;
+  text-align: right;
+  font-size: 200%;
+  padding-right: 1em;
+  padding-top: 0.5em;
+}
+#topuserinfo {
+  display:block;
+  background-color: #B0BCD0;
+  font-size: 80%;
+  padding: 0.1em;
+  border-bottom: solid 1px black;
+  text-align: right;
+}
+#topmenu {
+  background-color: #B0BCD0;
+  font-size: 90%;
+  border-bottom: solid 1px black;
+}
+#submenu {
+  background-color: #EEEEEE;
+  border-bottom: solid 1px black;
+  font-size: 90%;
+}
+
+.topmenuitem {
+  background-color: #B0BCD0;
+  border-right: solid 1px black;
+  padding-left: 0.5em;
+  padding-right: 0.5em;
+  margin: 0px;
+}
+.topmenuitemselected {
+  background-color: #EEEEEE;
+  border-right: solid 1px black;
+  padding-left: 0.5em;
+  padding-right: 0.5em;
+  margin: 0px;
+  border-bottom: solid 1px #EEEEEE;
+}
+.submenuitem {
+}
+.submenuitemselected {
+}
+.alphagroupitem {
+}
+.alphagroupitemselected {
+  font-weight:bold
+}
+#logout {
+  color: red;
+}
+#maintitle {
+  font-size: 200%;
+}
+#maincontent {
+  display:block;
+  padding: 1em;
+  margin: 1em;
+}
+#errorcontent {
+  display:block;
+  padding: 0.2em;
+  margin: 1em;
+  text-align: left;
+  color: red;
+  background-color: #EEEEEE;
+  border: solid 1px black;
+}
+#errorheader {
+  display:block;
+  text-align: left;
+  color: black;
+  background-color: #EEEEEE;
+  font-size: 150%;
+}
+#messagecontent {
+  display:block;
+  padding: 0.2em;
+  margin: 1em;
+  text-align: left;
+  color: green;
+  background-color: #EEEEEE;
+  border: solid 1px black;
+}
+#messageheader {
+  display:block;
+  text-align: left;
+  color: black;
+  background-color: #EEEEEE;
+  font-size: 150%;
+}
+.contenttext {
+  margin: 10px;
+}
+.contenttable {
+  width: 100%;
+  background-color: black;
+  border: 0px;
+}
+.contentroweven {
+  background-color: #C0CDE0;
+  margin: 0px;
+}
+.contentrowodd {
+  background-color: #D0DDF0;
+  margin: 0px;
+}
+.contentcell {
+  font-size: 90%;
+  padding: .1em .5em .1em .5em;
+  margin: 0px;
+/*  text-align: center; */
+}
+.actioncell {
+  font-size: 90%;
+  padding: .1em .5em .1em .5em;
+  width: 10%;
+  margin: 0px;
+  text-align: center;
+}
+.contentform {
+  /*float: left;*/
+  padding: .1em .5em .1em .5em;
+  background-color: #EEEEEE;
+  border: solid 1px black;
+}
+.contentformtable {
+  font-size: 90%;
+}
+.langcombo {
+  font-size: 80%;
+}
+
+#validators {
+  text-align: right;
+}
+
+th {
+  background-color: #EEEEEE;
+  border: 0px;
+}
+
+.ctrl {
+  background-color: #E0E3E0;
+  border: solid 1px black;
+  padding: .2em .5em .2em .5em;
+}
+
+.required_asterisk {
+  color: red;
+  font-size: 80%;
+  text-align: right;
+}
+
+label {
+  cursor: pointer;
+}
+
+.align_center {
+  text-align: center;
+}
+
+.align_right {
+  text-align: right;
+}
+
+.align_left {
+  text-align: left;
+}
diff --git a/koward/www/htdocs/koward/themes/screen.css b/koward/www/htdocs/koward/themes/screen.css
new file mode 100644 (file)
index 0000000..9075ea6
--- /dev/null
@@ -0,0 +1,3 @@
+/**
+ * Style for Koward.
+ */
diff --git a/koward/www/koward/config/.gitignore b/koward/www/koward/config/.gitignore
new file mode 100644 (file)
index 0000000..8713fda
--- /dev/null
@@ -0,0 +1,2 @@
+*.php
+*.local.php
diff --git a/koward/www/koward/config/attributes.php.dist b/koward/www/koward/config/attributes.php.dist
new file mode 100644 (file)
index 0000000..3a49086
--- /dev/null
@@ -0,0 +1,26 @@
+<?php
+
+$attributes['givenName'] = array(
+    'label' => _("First Name"),
+    'type' => 'text',
+    'required' => true,
+    'params' => array('regex' => '', 'size' => 40, 'maxlength' => 255)
+);
+$attributes['sn'] = array(
+    'label' => _("Last Name"),
+    'type' => 'text',
+    'required' => true,
+    'params' => array('regex' => '', 'size' => 40, 'maxlength' => 255)
+);
+$attributes['mail'] = array(
+    'label' => _("Mail address"),
+    'type' => 'text',
+    'required' => true,
+    'params' => array('regex' => '', 'size' => 40, 'maxlength' => 255)
+);
+$attributes['uid'] = array(
+    'label' => _("User ID"),
+    'type' => 'text',
+    'required' => true,
+    'params' => array('regex' => '', 'size' => 40, 'maxlength' => 255)
+);
diff --git a/koward/www/koward/config/base.php.dist b/koward/www/koward/config/base.php.dist
new file mode 100644 (file)
index 0000000..2b456ba
--- /dev/null
@@ -0,0 +1,5 @@
+<?php
+/** Tell the registry where our base lives. */
+if (!defined('HORDE_BASE')) {
+    define('HORDE_BASE', dirname(__FILE__) . '/../../horde');
+}
diff --git a/koward/www/koward/config/conf.php.dist b/koward/www/koward/config/conf.php.dist
new file mode 100644 (file)
index 0000000..656621c
--- /dev/null
@@ -0,0 +1,3 @@
+<?php
+
+$conf['koward']['theme'] = 'silver';
diff --git a/koward/www/koward/config/labels.php.dist b/koward/www/koward/config/labels.php.dist
new file mode 100644 (file)
index 0000000..a462447
--- /dev/null
@@ -0,0 +1,30 @@
+<?php
+
+$labels['cn'] = _("Common Name");
+$labels['kolabSalutation'] = _("Salutation");
+$labels['givenName'] = _("First Name");
+$labels['middleNames'] = _("Additional Names");
+$labels['sn'] = _("Last Name");
+$labels['snsuffix'] = _("Name Suffix");
+$labels['personalTitle'] = _("Title");
+$labels['userPassword'] = _("Password");
+$labels['telephoneNumber'] = _("Phone");
+$labels['postOfficeBox'] = _("Post Office Box");
+$labels['street'] = _("Street");
+$labels['title'] = _("Job Title");
+$labels['postalCode'] = _("Postal Code");
+$labels['facsimileTelephoneNumber'] = _("Fax");
+$labels['l'] = _("City");
+$labels['jpegPhoto'] = _("Photo");
+$labels['mail'] = _("Mail Address");
+$labels['mobile'] = _("Mobile Phone");
+$labels['homePhone'] = _("Home Phone");
+$labels['homePostalAddress'] = _("Home Postal Address");
+$labels['labeledURI'] = _("Website");
+$labels['o'] = _("Company");
+$labels['birthName'] = _("Birth Name");
+$labels['kolabMaritalStatus'] = _("Marital Status");
+$labels['dateOfBirth'] = _("Date Of Birth");
+$labels['placeOfBirth'] = _("Place Of Birth");
+$labels['gender'] = _("Gender");
+
diff --git a/koward/www/koward/config/objects.php.dist b/koward/www/koward/config/objects.php.dist
new file mode 100644 (file)
index 0000000..6c15803
--- /dev/null
@@ -0,0 +1,210 @@
+<?php
+
+/* $objects['object'] = array( */
+/*     'class'       => 'Horde_Kolab_Server_Object', */
+/*     'label'       => _("Object"), */
+/*     'list_label'  => _("Objects"), */
+/*     'list_attributes'  => array( */
+/*         'id' => array( */
+/*             'title' => _("Object id"), */
+/*             'width' => 80, */
+/*             'link_view'=> true, */
+/*         ), */
+/*     ), */
+/*     'attributes'  => array( */
+/*         'override' => true, */
+/*         'fields' => array( */
+/*             'id' => array( */
+/*                 'label' => _("Object ID"), */
+/*                 'type' => 'text', */
+/*                 'params' => array('regex' => '', 'size' => 40, 'maxlength' => 255) */
+/*             ), */
+/*         ), */
+/*     ), */
+/* ); */
+
+/* $objects['person'] = array( */
+/*     'class'       => 'Horde_Kolab_Server_Object_Person', */
+/*     'label'       => _("Person"), */
+/*     'list_label'  => _("Persons"), */
+/*     'list_attributes'  => array( */
+/*         'cn' => array( */
+/*             'title' => _("Common name"), */
+/*             'width' => 40, */
+/*             'link_view'=> true, */
+/*         ), */
+/*         'sn' => array( */
+/*             'title' => _("Last name"), */
+/*             'width' => 40, */
+/*         ), */
+/*     ), */
+/*     'attributes'  => array( */
+/*         'fields' => array( */
+/*             'cn' => array( */
+/*                 'required' => false, */
+/*             ), */
+/*             'userPassword' => array( */
+/*                 'required' => true, */
+/*             ), */
+/*         ), */
+/*     ), */
+/* ); */
+
+/* $objects['organizationalperson'] = array( */
+/*     'class'       => 'Horde_Kolab_Server_Object_Organizationalperson', */
+/*     'label'       => _("Organizational person"), */
+/*     'list_label'  => _("Organizational persons"), */
+/*     'list_attributes'  => array( */
+/*         'cn' => array( */
+/*             'title' => _("Common name"), */
+/*             'width' => 40, */
+/*             'link_view'=> true, */
+/*         ), */
+/*         'sn' => array( */
+/*             'title' => _("Last name"), */
+/*             'width' => 40, */
+/*         ), */
+/*     ), */
+/*     'attributes'  => array( */
+/*         'fields' => array( */
+/*             'cn' => array( */
+/*                 'required' => false, */
+/*             ), */
+/*             'userPassword' => array( */
+/*                 'required' => true, */
+/*             ), */
+/*         ), */
+/*     ), */
+/* ); */
+
+/* $objects['inetperson'] = array( */
+/*     'class'       => 'Horde_Kolab_Server_Object_Inetorgperson', */
+/*     'label'       => _("Inet person"), */
+/*     'list_label'  => _("Inet persons"), */
+/*     'list_attributes'  => array( */
+/*         'cn' => array( */
+/*             'title' => _("Common name"), */
+/*             'width' => 40, */
+/*             'link_view'=> true, */
+/*         ), */
+/*         'sn' => array( */
+/*             'title' => _("Last name"), */
+/*             'width' => 40, */
+/*         ), */
+/*     ), */
+/*     'attributes'  => array( */
+/*         'fields' => array( */
+/*             'cn' => array( */
+/*                 'required' => false, */
+/*             ), */
+/*             'userPassword' => array( */
+/*                 'required' => true, */
+/*             ), */
+/*         ), */
+/*     ), */
+/* ); */
+
+/* $objects['user'] = array( */
+/*     'class'       => 'Horde_Kolab_Server_Object_Kolab_User', */
+/*     'label'       => _("User"), */
+/*     'list_label'  => _("Users"), */
+/*     'list_attributes'  => array( */
+/*         'sn' => array( */
+/*             'title' => _("Last name"), */
+/*             'width' => 20, */
+/*         ), */
+/*         'givenName' => array( */
+/*             'title' => _("First name"), */
+/*             'width' => 20, */
+/*         ), */
+/*         'mail' => array( */
+/*             'title' => _("E-mail"), */
+/*             'width' => 20, */
+/*             'link_view'=> true, */
+/*         ), */
+/*         'uid' => array( */
+/*             'title' => _("User ID"), */
+/*             'width' => 20, */
+/*         ), */
+/*     ), */
+/* ); */
+
+/* $objects['admin'] = array( */
+/*     'class'       => 'Horde_Kolab_Server_Object_Kolab_Administrator', */
+/*     'label'       => _("Administrator"), */
+/*     'list_label'  => _("Administrators"), */
+/*     'attributes'  => array( */
+/*     ), */
+/* ); */
+
+/* $objects['kolabuser'] = array( */
+/*     'class'       => 'Horde_Kolab_Server_Object_Kolab_User', */
+/*     'preferred'   => true, */
+/*     'label'       => _("Kolab user"), */
+/*     'list_label'  => _("Kolab users"), */
+/*     'list_attributes'  => array( */
+/*         'sn' => array( */
+/*             'title' => _("Last name"), */
+/*             'width' => 20, */
+/*         ), */
+/*         'givenName' => array( */
+/*             'title' => _("First name"), */
+/*             'width' => 20, */
+/*         ), */
+/*         'mail' => array( */
+/*             'title' => _("E-mail"), */
+/*             'width' => 20, */
+/*             'link_view'=> true, */
+/*         ), */
+/*         'uid' => array( */
+/*             'title' => _("User ID"), */
+/*             'width' => 20, */
+/*         ), */
+/*     ), */
+/*     'attributes'  => array( */
+/*         'hide' => array( */
+/*             'objectClass', */
+/*             'seeAlso', */
+/*             'x121Address', */
+/*             'registeredAddress', */
+/*             'destinationIndicator', */
+/*             'preferredDeliveryMethod', */
+/*             'telexNumber', */
+/*             'teletexTerminalIdentifier', */
+/*             'internationaliSDNNumber', */
+/*             'kolabEncryptedPassword', */
+/*             'kolabHomeMTA', */
+/*             'kolabDelegate', */
+/*         ), */
+/*         'labels' => array( */
+/*             'mail' => _("Account ID"), */
+/*         ), */
+/*         'fields' => array( */
+/*             'kolabSalutation' => array( */
+/*                 'type' => 'enum', */
+/*                 'params' => array('values' => array(_("Mr.") => _("Mr."), */
+/*                                                     _("Mrs.") => _("Mrs.")), */
+/*                                   'prompt' => true), */
+/*             ), */
+/*             'gender' => array( */
+/*                 'type' => 'enum', */
+/*                 'params' => array('values' => array(_("1") => _("male"), */
+/*                                                     _("2") => _("female")), */
+/*                                   'prompt' => true), */
+/*             ), */
+/*             'kolabMaritalStatus' => array( */
+/*                 'type' => 'enum', */
+/*                 'params' => array('values' => array(_("0") => _("single"), */
+/*                                                     _("1") => _("married")), */
+/*                                   'prompt' => true), */
+/*             ), */
+/*             'userPassword' => array( */
+/*                 'type' => 'passwordconfirm', */
+/*             ), */
+/*         ), */
+/*     ), */
+/* ); */
+
+if (file_exists(dirname(__FILE__) . '/objects.local.php')) {
+    require_once(dirname(__FILE__) . '/objects.local.php');
+}
diff --git a/koward/www/koward/config/order.php.dist b/koward/www/koward/config/order.php.dist
new file mode 100644 (file)
index 0000000..74e0a28
--- /dev/null
@@ -0,0 +1,17 @@
+<?php
+$order['mail'] = 1;
+$order['kolabSalutation'] = 2;
+$order['givenName'] = 3;
+$order['middleNames'] = 4;
+$order['sn'] = 5;
+$order['snsuffix'] = 6;
+$order['gender'] = 7;
+$order['userPassword'] = 10;
+$order['dateOfBirth'] = 12;
+$order['placeOfBirth'] = 13;
+$order['kolabMaritalStatus'] = 14;
+$order['birthName'] = 15;
+$order['telephoneNumber'] = 30;
+$order['mobile'] = 31;
+$order['facsimileTelephoneNumber'] = 32;
+$order['homePhone'] = 33;
diff --git a/koward/www/koward/config/routes.php.dist b/koward/www/koward/config/routes.php.dist
new file mode 100644 (file)
index 0000000..1043478
--- /dev/null
@@ -0,0 +1,12 @@
+<?php
+
+$mapper->connect('index', array('controller' => 'index'));
+$mapper->connect('index.php', array('controller' => 'index'));
+
+$mapper->connect('check/:action/:id', array('controller' => 'check', 'action' => 'show'));
+$mapper->connect(':controller/:action/:id', array('controller' => 'object'));
+
+// Local route overrides
+if (file_exists(dirname(__FILE__) . '/routes.local.php')) {
+    include dirname(__FILE__) . '/routes.local.php';
+}
diff --git a/koward/www/koward/config/search.php.dist b/koward/www/koward/config/search.php.dist
new file mode 100644 (file)
index 0000000..fb6264f
--- /dev/null
@@ -0,0 +1,15 @@
+<?php
+
+$search = array(
+    'fields' => array(
+        'givenName' => array(
+            'label' => _("First Name"),
+            'type' => 'text',
+            'params' => array('regex' => '', 'size' => 40, 'maxlength' => 255)
+        ),
+    )
+);
+
+if (file_exists(dirname(__FILE__) . '/search.local.php')) {
+    require_once(dirname(__FILE__) . '/search.local.php');
+}
diff --git a/koward/www/koward/config/visible.php.dist b/koward/www/koward/config/visible.php.dist
new file mode 100644 (file)
index 0000000..d869909
--- /dev/null
@@ -0,0 +1,59 @@
+<?php
+$visible['hide'] = array(
+    'objectClass',
+    'id',
+    'lnfn',
+    'fnln',
+    'seeAlso',
+    'description',
+    'physicalDeliveryOfficeName',
+    'internationaliSDNNumber',
+    'x121Address',
+    'registeredAddress',
+    'destinationIndicator',
+    'preferredDeliveryMethod',
+    'telexNumber',
+    'teletexTerminalIdentifier',
+    'postalAddress',
+    'ou',
+    'st',
+    'manager',
+    'uid',
+    'employeeType',
+    'photo',
+    'x500uniqueIdentifier',
+    'secretary',
+    'userSMIMECertificate',
+    'employeeNumber',
+    'initials',
+    'audio',
+    'pager',
+    'businessCategory',
+    'roomNumber',
+    'carLicense',
+    'userCertificate',
+    'departmentNumber',
+    'preferredLanguage',
+    'displayName',
+    'userPKCS12',
+    'kolabVacationEndDateTime',
+    'kolabVacationReactDomain',
+    'kolabVacationAddress',
+    'kolabForwardKeepCopy',
+    'kolabDeleteflag',
+    'kolabVacationBeginDateTime',
+    'kolabVacationResendInterval',
+    'kolabVacationReplyToUCE',
+    'kolabForwardAddress',
+    'kolabForwardUCE',
+    'kolabAllowSMTPFrom',
+    'unrestrictedMailSize',
+    'kolabInvitationPolicy',
+    'kolabFreeBusyFuture',
+    'calFBURL',
+    'kolabComment',
+    'kolabImapServer',
+    'kolabFreeBusyServer',
+    'usertype',
+    'jpegPhoto',
+);
\ No newline at end of file
diff --git a/koward/www/koward/doc/INSTALL b/koward/www/koward/doc/INSTALL
new file mode 100644 (file)
index 0000000..93a5706
--- /dev/null
@@ -0,0 +1,13 @@
+To complete the installation of Koward for an apache server you need to add a
+small configuration section to your web server configuration:
+
+<IfModule mod_rewrite.c>
+    RewriteEngine On
+    RewriteCond   %{REQUEST_FILENAME}  !-d
+    RewriteCond   %{REQUEST_FILENAME}  !-f
+    RewriteRule ^(.*)$ koward.php [QSA,L]
+</IfModule>
+
+This configuration snippet must apply to the "koward/app" directory. The easiest
+option is to add an .htaccess file with the content provided above in that
+directory.