From c442f822fb9b961f7a92930e572edb52159391d3 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Thu, 8 Nov 2012 20:22:34 +0100 Subject: Simplify keep-alive action. Now the interval is based on session_lifetime, which means it's executed only if needed for session keeping (reset interval on every action). Temporarily remove check-recent request, it will be replaced by new global system refresh request in future. Use keep_alive setting as auto-refresh request interval (allow no-refresh mode) --- program/include/rcmail.php | 11 +++-------- program/include/rcube.php | 30 +++--------------------------- program/include/rcube_session.php | 20 +------------------- program/js/app.js | 29 +++++++++++++++-------------- 4 files changed, 22 insertions(+), 68 deletions(-) (limited to 'program') diff --git a/program/include/rcmail.php b/program/include/rcmail.php index 3728e5d19..a755aa846 100644 --- a/program/include/rcmail.php +++ b/program/include/rcmail.php @@ -94,9 +94,6 @@ class rcmail extends rcube // create user object $this->set_user(new rcube_user($_SESSION['user_id'])); - // configure session (after user config merge!) - $this->session_configure(); - // set task and action properties $this->set_task(rcube_utils::get_input_value('_task', rcube_utils::INPUT_GPC)); $this->action = asciiwords(rcube_utils::get_input_value('_action', rcube_utils::INPUT_GPC)); @@ -320,10 +317,9 @@ class rcmail extends rcube if (!($this->output instanceof rcube_output_html)) $this->output = new rcube_output_html($this->task, $framed); - // set keep-alive/check-recent interval - if ($this->session && ($keep_alive = $this->session->get_keep_alive())) { - $this->output->set_env('keep_alive', $keep_alive); - } + // set keep-alive interval + $this->output->set_env('keep_alive', $this->config->get('keep_alive', 0)); + $this->output->set_env('session_lifetime', $this->config->get('session_lifetime', 0) * 60); if ($framed) { $this->comm_path .= '&_framed=1'; @@ -522,7 +518,6 @@ class rcmail extends rcube // Configure environment $this->set_user($user); $this->set_storage_prop(); - $this->session_configure(); // fix some old settings according to namespace prefix $this->fix_namespace_settings($user); diff --git a/program/include/rcube.php b/program/include/rcube.php index 0e40b3c6b..9c1a6d84a 100644 --- a/program/include/rcube.php +++ b/program/include/rcube.php @@ -434,6 +434,9 @@ class rcube $this->session->register_gc_handler(array($this, 'temp_gc')); $this->session->register_gc_handler(array($this, 'cache_gc')); + $this->session->set_secret($this->config->get('des_key') . dirname($_SERVER['SCRIPT_NAME'])); + $this->session->set_ip_check($this->config->get('ip_check')); + // start PHP session (if not in CLI mode) if ($_SERVER['REMOTE_ADDR']) { session_start(); @@ -441,33 +444,6 @@ class rcube } - /** - * Configure session object internals - */ - public function session_configure() - { - if (!$this->session) { - return; - } - - $lifetime = $this->config->get('session_lifetime', 0) * 60; - $keep_alive = $this->config->get('keep_alive'); - - // set keep-alive/check-recent interval - if ($keep_alive) { - // be sure that it's less than session lifetime - if ($lifetime) { - $keep_alive = min($keep_alive, $lifetime - 30); - } - $keep_alive = max(60, $keep_alive); - $this->session->set_keep_alive($keep_alive); - } - - $this->session->set_secret($this->config->get('des_key') . dirname($_SERVER['SCRIPT_NAME'])); - $this->session->set_ip_check($this->config->get('ip_check')); - } - - /** * Garbage collector function for temp files. * Remove temp files older than two days diff --git a/program/include/rcube_session.php b/program/include/rcube_session.php index 6192466cd..c71efa2aa 100644 --- a/program/include/rcube_session.php +++ b/program/include/rcube_session.php @@ -43,7 +43,6 @@ class rcube_session private $secret = ''; private $ip_check = false; private $logging = false; - private $keep_alive = 0; private $memcache; /** @@ -525,24 +524,6 @@ class rcube_session $this->now = $now - ($now % ($this->lifetime / 2)); } - /** - * Setter for keep_alive interval - */ - public function set_keep_alive($keep_alive) - { - $this->keep_alive = $keep_alive; - - if ($this->lifetime < $keep_alive) - $this->set_lifetime($keep_alive + 30); - } - - /** - * Getter for keep_alive interval - */ - public function get_keep_alive() - { - return $this->keep_alive; - } /** * Getter for remote IP saved with this session @@ -552,6 +533,7 @@ class rcube_session return $this->ip; } + /** * Setter for cookie encryption secret */ diff --git a/program/js/app.js b/program/js/app.js index 7764c6c86..f372c0f9e 100644 --- a/program/js/app.js +++ b/program/js/app.js @@ -952,9 +952,6 @@ function rcube_webmail() break; } - // re-set keep-alive timeout - this.start_keepalive(); - this.submit_messageform(true); break; @@ -6077,6 +6074,9 @@ function rcube_webmail() $('').attr('href', url).appendTo(document.body).get(0).click(); else target.location.href = url; + + // reset keep-alive interval + this.start_keepalive(); }; // send a http request to the server @@ -6105,6 +6105,9 @@ function rcube_webmail() success: function(data){ ref.http_response(data); }, error: function(o, status, err) { ref.http_error(o, status, err, lock, action); } }); + + // reset keep-alive interval + this.start_keepalive(); }; // send a http POST request to the server @@ -6137,6 +6140,9 @@ function rcube_webmail() success: function(data){ ref.http_response(data); }, error: function(o, status, err) { ref.http_error(o, status, err, lock, action); } }); + + // reset keep-alive interval + this.start_keepalive(); }; // aborts ajax request @@ -6264,6 +6270,9 @@ function rcube_webmail() this.triggerEvent('responseafter', {response: response}); this.triggerEvent('responseafter'+response.action, {response: response}); + + // reset keep-alive interval + this.start_keepalive(); }; // handle HTTP request errors @@ -6288,8 +6297,6 @@ function rcube_webmail() // re-send keep-alive requests after 30 seconds if (action == 'keep-alive') setTimeout(function(){ ref.keep_alive(); ref.start_keepalive(); }, 30000); - else if (action == 'check-recent') - setTimeout(function(){ ref.check_for_recent(false); ref.start_keepalive(); }, 30000); }; // post the given form to a hidden iframe @@ -6459,20 +6466,16 @@ function rcube_webmail() } }; - - // starts interval for keep-alive/check-recent signal + // starts interval for keep-alive signal this.start_keepalive = function() { - if (!this.env.keep_alive || this.env.framed) + if (!this.env.session_lifetime || this.env.framed || this.task == 'login' || this.env.action == 'print') return; if (this._int) clearInterval(this._int); - if (this.task == 'mail' && this.gui_objects.mailboxlist) - this._int = setInterval(function(){ ref.check_for_recent(false); }, this.env.keep_alive * 1000); - else if (this.task != 'login' && this.env.action != 'print') - this._int = setInterval(function(){ ref.keep_alive(); }, this.env.keep_alive * 1000); + this._int = setInterval(function(){ ref.keep_alive(); }, this.env.session_lifetime * 0.5 * 1000); }; // sends keep-alive signal @@ -6493,8 +6496,6 @@ function rcube_webmail() if (refresh) { lock = this.set_busy(true, 'checkingmail'); url._refresh = 1; - // reset check-recent interval - this.start_keepalive(); } if (this.gui_objects.messagelist) -- cgit v1.2.3 From aa83596b0bec71af8d96ee346d7a625709bf0750 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Sat, 10 Nov 2012 12:13:53 +0100 Subject: Clarify keep-alive setting, move it to User Interface section, change label to "Refresh (check for new messages, etc.)", allow no-refresh mode. --- config/main.inc.php.dist | 7 +++---- program/localization/en_US/labels.inc | 2 +- program/steps/settings/func.inc | 35 ++++++++++++++++++----------------- program/steps/settings/save_prefs.inc | 28 +++++++++++++++------------- 4 files changed, 37 insertions(+), 35 deletions(-) (limited to 'program') diff --git a/config/main.inc.php.dist b/config/main.inc.php.dist index dafee72f1..64312b6a9 100644 --- a/config/main.inc.php.dist +++ b/config/main.inc.php.dist @@ -241,7 +241,6 @@ $rcmail_config['skin_include_php'] = false; $rcmail_config['display_version'] = false; // Session lifetime in minutes -// must be greater than 'keep_alive'/60 $rcmail_config['session_lifetime'] = 10; // Session domain: .example.org @@ -500,7 +499,6 @@ $rcmail_config['recipients_separator'] = ','; $rcmail_config['max_pagesize'] = 200; // Minimal value of user's 'keep_alive' setting (in seconds) -// Must be less than 'session_lifetime' $rcmail_config['min_keep_alive'] = 60; // Enables files upload indicator. Requires APC installed and enabled apc.rfc1867 option. @@ -780,8 +778,9 @@ $rcmail_config['read_when_deleted'] = true; // Use 'Purge' to remove messages marked as deleted $rcmail_config['flag_for_deletion'] = false; -// Default interval for keep-alive/check-recent requests (in seconds) -// Must be greater than or equal to 'min_keep_alive' and less than 'session_lifetime' +// Default interval for auto-refresh requests (in seconds) +// These are requests for system state updates e.g. checking for new messages, etc. +// Setting it to 0 disables the feature. $rcmail_config['keep_alive'] = 60; // If true all folders will be checked for recent messages diff --git a/program/localization/en_US/labels.inc b/program/localization/en_US/labels.inc index 2b1397f02..1999bad13 100644 --- a/program/localization/en_US/labels.inc +++ b/program/localization/en_US/labels.inc @@ -414,7 +414,7 @@ $labels['always'] = 'always'; $labels['showinlineimages'] = 'Display attached images below the message'; $labels['autosavedraft'] = 'Automatically save draft'; $labels['everynminutes'] = 'every $n minute(s)'; -$labels['keepalive'] = 'Check for new messages on'; +$labels['refreshinterval'] = 'Refresh (check for new messages, etc.)'; $labels['never'] = 'never'; $labels['immediately'] = 'immediately'; $labels['messagesdisplaying'] = 'Displaying Messages'; diff --git a/program/steps/settings/func.inc b/program/steps/settings/func.inc index 8bef2ff51..27e1e1346 100644 --- a/program/steps/settings/func.inc +++ b/program/steps/settings/func.inc @@ -237,6 +237,24 @@ function rcmail_user_prefs($current=null) ); } + if (!isset($no_override['keep_alive'])) { + $field_id = 'rcmfd_keep_alive'; + $select_keep_alive = new html_select(array('name' => '_keep_alive', 'id' => $field_id)); + + $select_keep_alive->add(rcube_label('never'), 0); + foreach (array(1, 3, 5, 10, 15, 30, 60) as $min) { + if (!$config['min_keep_alive'] || $config['min_keep_alive'] <= $min * 60) { + $label = rcube_label(array('name' => 'everynminutes', 'vars' => array('n' => $min))); + $select_keep_alive->add($label, $min); + } + } + + $blocks['main']['options']['keep_alive'] = array( + 'title' => html::label($field_id, Q(rcube_label('refreshinterval'))), + 'content' => $select_keep_alive->show($config['keep_alive']/60), + ); + } + // show drop-down for available skins if (!isset($no_override['skin'])) { $skins = rcmail_get_skins(); @@ -370,23 +388,6 @@ function rcmail_user_prefs($current=null) 'content' => $input_pagesize->show($size ? $size : 50), ); } - - if (!isset($no_override['keep_alive'])) { - $field_id = 'rcmfd_keep_alive'; - $select_keep_alive = new html_select(array('name' => '_keep_alive', 'id' => $field_id)); - - foreach(array(1, 3, 5, 10, 15, 30, 60) as $min) - if((!$config['min_keep_alive'] || $config['min_keep_alive'] <= $min * 60) - && (!$config['session_lifetime'] || $config['session_lifetime'] > $min)) { - $select_keep_alive->add(rcube_label(array('name' => 'everynminutes', 'vars' => array('n' => $min))), $min); - } - - $blocks['new_message']['options']['keep_alive'] = array( - 'title' => html::label($field_id, Q(rcube_label('keepalive'))), - 'content' => $select_keep_alive->show($config['keep_alive']/60), - ); - } - if (!isset($no_override['check_all_folders'])) { $field_id = 'rcmfd_check_all_folders'; $input_check_all = new html_checkbox(array('name' => '_check_all_folders', 'id' => $field_id, 'value' => 1)); diff --git a/program/steps/settings/save_prefs.inc b/program/steps/settings/save_prefs.inc index db7b134c4..2f22be7c4 100644 --- a/program/steps/settings/save_prefs.inc +++ b/program/steps/settings/save_prefs.inc @@ -33,7 +33,8 @@ switch ($CURR_SECTION) 'date_format' => isset($_POST['_date_format']) ? get_input_value('_date_format', RCUBE_INPUT_POST) : $CONFIG['date_format'], 'time_format' => isset($_POST['_time_format']) ? get_input_value('_time_format', RCUBE_INPUT_POST) : ($CONFIG['time_format'] ? $CONFIG['time_format'] : 'H:i'), 'prettydate' => isset($_POST['_pretty_date']) ? TRUE : FALSE, - 'skin' => isset($_POST['_skin']) ? get_input_value('_skin', RCUBE_INPUT_POST) : $CONFIG['skin'], + 'keep_alive' => isset($_POST['_keep_alive']) ? intval($_POST['_keep_alive'])*60 : $CONFIG['keep_alive'], + 'skin' => isset($_POST['_skin']) ? get_input_value('_skin', RCUBE_INPUT_POST) : $CONFIG['skin'], ); // compose derived date/time format strings @@ -50,7 +51,6 @@ switch ($CURR_SECTION) 'preview_pane_mark_read' => isset($_POST['_preview_pane_mark_read']) ? intval($_POST['_preview_pane_mark_read']) : $CONFIG['preview_pane_mark_read'], 'autoexpand_threads' => isset($_POST['_autoexpand_threads']) ? intval($_POST['_autoexpand_threads']) : 0, 'mdn_requests' => isset($_POST['_mdn_requests']) ? intval($_POST['_mdn_requests']) : 0, - 'keep_alive' => isset($_POST['_keep_alive']) ? intval($_POST['_keep_alive'])*60 : $CONFIG['keep_alive'], 'check_all_folders' => isset($_POST['_check_all_folders']) ? TRUE : FALSE, 'mail_pagesize' => is_numeric($_POST['_mail_pagesize']) ? max(2, intval($_POST['_mail_pagesize'])) : $CONFIG['mail_pagesize'], ); @@ -157,16 +157,16 @@ switch ($CURR_SECTION) $a_user_prefs['timezone'] = (string) $a_user_prefs['timezone']; - break; - case 'mailbox': - - // force keep_alive - if (isset($a_user_prefs['keep_alive'])) { - $a_user_prefs['keep_alive'] = max(60, $CONFIG['min_keep_alive'], $a_user_prefs['keep_alive']); - if (!empty($CONFIG['session_lifetime'])) - $a_user_prefs['keep_alive'] = min($CONFIG['session_lifetime']*60, $a_user_prefs['keep_alive']); + if (isset($a_user_prefs['keep_alive']) && !empty($CONFIG['min_keep_alive'])) { + if ($a_user_prefs['keep_alive'] > $CONFIG['min_keep_alive']) { + $a_user_prefs['keep_alive'] = $CONFIG['min_keep_alive']; + } } + break; + + case 'mailbox': + // force min size if ($a_user_prefs['mail_pagesize'] < 1) $a_user_prefs['mail_pagesize'] = 10; @@ -174,7 +174,8 @@ switch ($CURR_SECTION) if (isset($CONFIG['max_pagesize']) && ($a_user_prefs['mail_pagesize'] > $CONFIG['max_pagesize'])) $a_user_prefs['mail_pagesize'] = (int) $CONFIG['max_pagesize']; - break; + break; + case 'addressbook': // force min size @@ -184,7 +185,8 @@ switch ($CURR_SECTION) if (isset($CONFIG['max_pagesize']) && ($a_user_prefs['addressbook_pagesize'] > $CONFIG['max_pagesize'])) $a_user_prefs['addressbook_pagesize'] = (int) $CONFIG['max_pagesize']; - break; + break; + case 'folders': // special handling for 'default_folders' @@ -199,7 +201,7 @@ switch ($CURR_SECTION) } } - break; + break; } // Save preferences -- cgit v1.2.3 From 77de23fa939338546a3e049459ffd29edd9058c2 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Sun, 11 Nov 2012 10:32:05 +0100 Subject: Added cross-task 'refresh' request for system state updates --- CHANGELOG | 2 + index.php | 4 +- program/include/rcmail.php | 5 ++- program/js/app.js | 75 +++++++++++++++++++++++---------- program/localization/en_US/messages.inc | 1 + program/steps/mail/check_recent.inc | 10 +++-- program/steps/mail/func.inc | 1 + 7 files changed, 70 insertions(+), 28 deletions(-) (limited to 'program') diff --git a/CHANGELOG b/CHANGELOG index 02fe0e2ce..dea6c1993 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,8 @@ CHANGELOG Roundcube Webmail =========================== +- Improved keep-alive action. Now the interval is based on session_lifetime +- Added cross-task 'refresh' request for system state updates - Fix AREA links handling (#1488792) - Better client-side timezone detection using the jsTimezoneDetect library (#1488725) - Fix possible HTTP DoS on error in keep-alive requests (#1488782) diff --git a/index.php b/index.php index 0ad371a4a..05fc641b5 100644 --- a/index.php +++ b/index.php @@ -249,7 +249,6 @@ $plugin = $RCMAIL->plugins->exec_hook('ready', array('task' => $RCMAIL->task, 'a $RCMAIL->set_task($plugin['task']); $RCMAIL->action = $plugin['action']; - // handle special actions if ($RCMAIL->action == 'keep-alive') { $OUTPUT->reset(); @@ -282,7 +281,8 @@ while ($redirects < 5) { else if (($stepfile = $RCMAIL->get_action_file()) && is_file($incfile = INSTALL_PATH . 'program/steps/'.$RCMAIL->task.'/'.$stepfile) ) { - include $incfile; + // include action file only once (in case it don't exit) + include_once $incfile; $redirects++; } else { diff --git a/program/include/rcmail.php b/program/include/rcmail.php index a755aa846..04b87e48c 100644 --- a/program/include/rcmail.php +++ b/program/include/rcmail.php @@ -332,7 +332,7 @@ class rcmail extends rcube $this->output->set_charset(RCMAIL_CHARSET); // add some basic labels to client - $this->output->add_label('loading', 'servererror', 'requesttimedout'); + $this->output->add_label('loading', 'servererror', 'requesttimedout', 'refreshing'); return $this->output; } @@ -770,6 +770,7 @@ class rcmail extends rcube } } + /** * Registers action aliases for current task * @@ -784,6 +785,7 @@ class rcmail extends rcube } } + /** * Returns current action filename * @@ -798,6 +800,7 @@ class rcmail extends rcube return strtr($this->action, '-', '_') . '.inc'; } + /** * Fixes some user preferences according to namespace handling change. * Old Roundcube versions were using folder names with removed namespace prefix. diff --git a/program/js/app.js b/program/js/app.js index f372c0f9e..25fddf10c 100644 --- a/program/js/app.js +++ b/program/js/app.js @@ -482,7 +482,8 @@ function rcube_webmail() this.onloads[i](); } - // start keep-alive interval + // start keep-alive and refresh intervals + this.start_refresh(); this.start_keepalive(); }; @@ -880,10 +881,6 @@ function rcube_webmail() this.show_message(this.env.first_uid); break; - case 'checkmail': - this.check_for_recent(true); - break; - case 'compose': url = {}; @@ -2061,6 +2058,15 @@ function rcube_webmail() } }; + // sends request to check for recent messages + this.checkmail = function() + { + var lock = this.set_busy(true, 'checkingmail'), + params = this.check_recent_params(); + + this.http_request('check-recent', params, lock); + }; + // list messages of a specific mailbox using filter this.filter_mailbox = function(filter) { @@ -6125,7 +6131,7 @@ function rcube_webmail() // trigger plugin hook var result = this.triggerEvent('request'+action, postdata); if (result !== undefined) { - // abort if one the handlers returned false + // abort if one of the handlers returned false if (result === false) return false; else @@ -6237,6 +6243,7 @@ function rcube_webmail() } break; + case 'refresh': case 'check-recent': case 'getunread': case 'search': @@ -6469,13 +6476,25 @@ function rcube_webmail() // starts interval for keep-alive signal this.start_keepalive = function() { - if (!this.env.session_lifetime || this.env.framed || this.task == 'login' || this.env.action == 'print') + if (!this.env.session_lifetime || this.env.framed || this.env.extwin || this.task == 'login' || this.env.action == 'print') return; - if (this._int) - clearInterval(this._int); + if (this._keepalive) + clearInterval(this._keepalive); - this._int = setInterval(function(){ ref.keep_alive(); }, this.env.session_lifetime * 0.5 * 1000); + this._keepalive = setInterval(function(){ ref.keep_alive(); }, this.env.session_lifetime * 0.5 * 1000); + }; + + // starts interval for refresh signal + this.start_refresh = function() + { + if (!this.env.keep_alive || this.env.framed || this.env.extwin || this.task == 'login' || this.env.action == 'print') + return; + + if (this._refresh) + clearInterval(this._refresh); + + this._refresh = setInterval(function(){ ref.refresh(); }, this.env.keep_alive * 1000); }; // sends keep-alive signal @@ -6485,27 +6504,39 @@ function rcube_webmail() this.http_request('keep-alive'); }; - // sends request to check for recent messages - this.check_for_recent = function(refresh) + // sends refresh signal + this.refresh = function() { - if (this.busy) + if (this.busy) { + // try again after 10 seconds + setTimeout(function(){ ref.refresh(); ref.start_refresh(); }, 10000); return; + } - var lock, url = {_mbox: this.env.mailbox}; + var params = {}, lock = this.set_busy(true, 'refreshing'); - if (refresh) { - lock = this.set_busy(true, 'checkingmail'); - url._refresh = 1; - } + if (this.task == 'mail' && this.gui_objects.mailboxlist) + params = this.check_recent_params(); + + // plugins should bind to 'requestrefresh' event to add own params + this.http_request('refresh', params, lock); + }; + // returns check-recent request parameters + this.check_recent_params = function() + { + var params = {_mbox: this.env.mailbox}; + + if (this.gui_objects.mailboxlist) + params._folderlist = 1; if (this.gui_objects.messagelist) - url._list = 1; + params._list = 1; if (this.gui_objects.quotadisplay) - url._quota = 1; + params._quota = 1; if (this.env.search_request) - url._search = this.env.search_request; + params._search = this.env.search_request; - this.http_request('check-recent', url, lock); + return params; }; diff --git a/program/localization/en_US/messages.inc b/program/localization/en_US/messages.inc index cabc9998b..a858d0acf 100644 --- a/program/localization/en_US/messages.inc +++ b/program/localization/en_US/messages.inc @@ -37,6 +37,7 @@ $messages['invalidhost'] = 'Invalid server name.'; $messages['nomessagesfound'] = 'No messages found in this mailbox.'; $messages['loggedout'] = 'You have successfully terminated the session. Good bye!'; $messages['mailboxempty'] = 'Mailbox is empty.'; +$messages['refreshing'] = 'Refreshing...'; $messages['loading'] = 'Loading...'; $messages['uploading'] = 'Uploading file...'; $messages['uploadingmany'] = 'Uploading files...'; diff --git a/program/steps/mail/check_recent.inc b/program/steps/mail/check_recent.inc index 1a1b08c60..90d17c15b 100644 --- a/program/steps/mail/check_recent.inc +++ b/program/steps/mail/check_recent.inc @@ -19,8 +19,14 @@ +-----------------------------------------------------------------------+ */ +// If there's no folder or messages list, there's nothing to update +// This can happen on 'refresh' request +if (empty($_REQUEST['_folderlist']) && empty($_REQUEST['_list'])) { + return; +} + $current = $RCMAIL->storage->get_folder(); -$check_all = !empty($_GET['_refresh']) || (bool)$RCMAIL->config->get('check_all_folders'); +$check_all = $RCMAIL->action != 'refresh' || (bool)$RCMAIL->config->get('check_all_folders'); // list of folders to check if ($check_all) { @@ -102,6 +108,4 @@ foreach ($a_mailboxes as $mbox_name) { } } -$RCMAIL->plugins->exec_hook('keep_alive', array()); - $OUTPUT->send(); diff --git a/program/steps/mail/func.inc b/program/steps/mail/func.inc index f128a3834..374ab7571 100644 --- a/program/steps/mail/func.inc +++ b/program/steps/mail/func.inc @@ -1810,6 +1810,7 @@ $OUTPUT->add_handlers(array( // register action aliases $RCMAIL->register_action_map(array( + 'refresh' => 'check_recent.inc', 'preview' => 'show.inc', 'print' => 'show.inc', 'moveto' => 'move_del.inc', -- cgit v1.2.3 From 92eb10e7732716beec8b227693d62cb9a79b9db6 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Mon, 12 Nov 2012 14:30:19 +0100 Subject: Don't throw error when plugin doesn't register 'refresh' action handler --- program/include/rcube_plugin_api.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'program') diff --git a/program/include/rcube_plugin_api.php b/program/include/rcube_plugin_api.php index 107c81026..c473b0b17 100644 --- a/program/include/rcube_plugin_api.php +++ b/program/include/rcube_plugin_api.php @@ -327,7 +327,7 @@ class rcube_plugin_api if (isset($this->actions[$action])) { call_user_func($this->actions[$action]); } - else { + else if (rcube::get_instance()->action != 'refresh') { rcube::raise_error(array('code' => 524, 'type' => 'php', 'file' => __FILE__, 'line' => __LINE__, 'message' => "No handler found for action $action"), true, true); -- cgit v1.2.3 From f226549d4f8f258deca9e165ef857252b79d2ee0 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Mon, 12 Nov 2012 14:50:49 +0100 Subject: Renamed config options: keep_alive to refresh_interval, min_keep_alive to min_refresh_interval --- CHANGELOG | 1 + config/main.inc.php.dist | 6 +++--- installer/rcube_install.php | 3 --- program/include/rcmail.php | 4 ++-- program/include/rcube_config.php | 2 ++ program/js/app.js | 5 ++--- program/steps/settings/func.inc | 16 ++++++++-------- program/steps/settings/save_prefs.inc | 8 ++++---- 8 files changed, 22 insertions(+), 23 deletions(-) (limited to 'program') diff --git a/CHANGELOG b/CHANGELOG index 6c50340cc..d0473c675 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -3,6 +3,7 @@ CHANGELOG Roundcube Webmail - Improved keep-alive action. Now the interval is based on session_lifetime (#1488507) - Added cross-task 'refresh' request for system state updates (#1488507) +- Renamed config options: keep_alive to refresh_interval, min_keep_alive to min_refresh_interval - Fix AREA links handling (#1488792) - Better client-side timezone detection using the jsTimezoneDetect library (#1488725) - Fix possible HTTP DoS on error in keep-alive requests (#1488782) diff --git a/config/main.inc.php.dist b/config/main.inc.php.dist index 64312b6a9..1b7ae5a54 100644 --- a/config/main.inc.php.dist +++ b/config/main.inc.php.dist @@ -498,8 +498,8 @@ $rcmail_config['recipients_separator'] = ','; // don't let users set pagesize to more than this value if set $rcmail_config['max_pagesize'] = 200; -// Minimal value of user's 'keep_alive' setting (in seconds) -$rcmail_config['min_keep_alive'] = 60; +// Minimal value of user's 'refresh_interval' setting (in seconds) +$rcmail_config['min_refresh_interval'] = 60; // Enables files upload indicator. Requires APC installed and enabled apc.rfc1867 option. // By default refresh time is set to 1 second. You can set this value to true @@ -781,7 +781,7 @@ $rcmail_config['flag_for_deletion'] = false; // Default interval for auto-refresh requests (in seconds) // These are requests for system state updates e.g. checking for new messages, etc. // Setting it to 0 disables the feature. -$rcmail_config['keep_alive'] = 60; +$rcmail_config['refresh_interval'] = 60; // If true all folders will be checked for recent messages $rcmail_config['check_all_folders'] = false; diff --git a/installer/rcube_install.php b/installer/rcube_install.php index d1dce9d0e..06c57c0ac 100644 --- a/installer/rcube_install.php +++ b/installer/rcube_install.php @@ -342,9 +342,6 @@ class rcube_install } } - if ($current['keep_alive'] && $current['session_lifetime'] < $current['keep_alive']) - $current['session_lifetime'] = max(10, ceil($current['keep_alive'] / 60) * 2); - $this->config = array_merge($this->config, $current); foreach ((array)$current['ldap_public'] as $key => $values) { diff --git a/program/include/rcmail.php b/program/include/rcmail.php index 04b87e48c..99a68e81d 100644 --- a/program/include/rcmail.php +++ b/program/include/rcmail.php @@ -317,8 +317,8 @@ class rcmail extends rcube if (!($this->output instanceof rcube_output_html)) $this->output = new rcube_output_html($this->task, $framed); - // set keep-alive interval - $this->output->set_env('keep_alive', $this->config->get('keep_alive', 0)); + // set refresh interval + $this->output->set_env('refresh_interval', $this->config->get('refresh_interval', 0)); $this->output->set_env('session_lifetime', $this->config->get('session_lifetime', 0) * 60); if ($framed) { diff --git a/program/include/rcube_config.php b/program/include/rcube_config.php index 1f165ba4a..bbc3e9c6e 100644 --- a/program/include/rcube_config.php +++ b/program/include/rcube_config.php @@ -43,6 +43,8 @@ class rcube_config 'mail_pagesize' => 'pagesize', 'addressbook_pagesize' => 'pagesize', 'reply_mode' => 'top_posting', + 'refresh_interval' => 'keep_alive', + 'min_refresh_interval' => 'min_keep_alive', ); diff --git a/program/js/app.js b/program/js/app.js index 25fddf10c..fb9c299ec 100644 --- a/program/js/app.js +++ b/program/js/app.js @@ -44,7 +44,6 @@ function rcube_webmail() this.identifier_expr = new RegExp('[^0-9a-z\-_]', 'gi'); // default environment vars - this.env.keep_alive = 60; // seconds this.env.request_timeout = 180; // seconds this.env.draft_autosave = 0; // seconds this.env.comm_path = './'; @@ -6488,13 +6487,13 @@ function rcube_webmail() // starts interval for refresh signal this.start_refresh = function() { - if (!this.env.keep_alive || this.env.framed || this.env.extwin || this.task == 'login' || this.env.action == 'print') + if (!this.env.refresh_interval || this.env.framed || this.env.extwin || this.task == 'login' || this.env.action == 'print') return; if (this._refresh) clearInterval(this._refresh); - this._refresh = setInterval(function(){ ref.refresh(); }, this.env.keep_alive * 1000); + this._refresh = setInterval(function(){ ref.refresh(); }, this.env.refresh_interval * 1000); }; // sends keep-alive signal diff --git a/program/steps/settings/func.inc b/program/steps/settings/func.inc index 27e1e1346..876e02761 100644 --- a/program/steps/settings/func.inc +++ b/program/steps/settings/func.inc @@ -237,21 +237,21 @@ function rcmail_user_prefs($current=null) ); } - if (!isset($no_override['keep_alive'])) { - $field_id = 'rcmfd_keep_alive'; - $select_keep_alive = new html_select(array('name' => '_keep_alive', 'id' => $field_id)); + if (!isset($no_override['refresh_interval'])) { + $field_id = 'rcmfd_refresh_interval'; + $select_refresh_interval = new html_select(array('name' => '_refresh_interval', 'id' => $field_id)); - $select_keep_alive->add(rcube_label('never'), 0); + $select_refresh_interval->add(rcube_label('never'), 0); foreach (array(1, 3, 5, 10, 15, 30, 60) as $min) { - if (!$config['min_keep_alive'] || $config['min_keep_alive'] <= $min * 60) { + if (!$config['min_refresh_interval'] || $config['min_refresh_interval'] <= $min * 60) { $label = rcube_label(array('name' => 'everynminutes', 'vars' => array('n' => $min))); - $select_keep_alive->add($label, $min); + $select_refresh_interval->add($label, $min); } } - $blocks['main']['options']['keep_alive'] = array( + $blocks['main']['options']['refresh_interval'] = array( 'title' => html::label($field_id, Q(rcube_label('refreshinterval'))), - 'content' => $select_keep_alive->show($config['keep_alive']/60), + 'content' => $select_refresh_interval->show($config['refresh_interval']/60), ); } diff --git a/program/steps/settings/save_prefs.inc b/program/steps/settings/save_prefs.inc index 2f22be7c4..5daab0d24 100644 --- a/program/steps/settings/save_prefs.inc +++ b/program/steps/settings/save_prefs.inc @@ -33,7 +33,7 @@ switch ($CURR_SECTION) 'date_format' => isset($_POST['_date_format']) ? get_input_value('_date_format', RCUBE_INPUT_POST) : $CONFIG['date_format'], 'time_format' => isset($_POST['_time_format']) ? get_input_value('_time_format', RCUBE_INPUT_POST) : ($CONFIG['time_format'] ? $CONFIG['time_format'] : 'H:i'), 'prettydate' => isset($_POST['_pretty_date']) ? TRUE : FALSE, - 'keep_alive' => isset($_POST['_keep_alive']) ? intval($_POST['_keep_alive'])*60 : $CONFIG['keep_alive'], + 'refresh_interval' => isset($_POST['_refresh_interval']) ? intval($_POST['_refresh_interval'])*60 : $CONFIG['refresh_interval'], 'skin' => isset($_POST['_skin']) ? get_input_value('_skin', RCUBE_INPUT_POST) : $CONFIG['skin'], ); @@ -157,9 +157,9 @@ switch ($CURR_SECTION) $a_user_prefs['timezone'] = (string) $a_user_prefs['timezone']; - if (isset($a_user_prefs['keep_alive']) && !empty($CONFIG['min_keep_alive'])) { - if ($a_user_prefs['keep_alive'] > $CONFIG['min_keep_alive']) { - $a_user_prefs['keep_alive'] = $CONFIG['min_keep_alive']; + if (isset($a_user_prefs['refresh_interval']) && !empty($CONFIG['min_refresh_interval'])) { + if ($a_user_prefs['refresh_interval'] > $CONFIG['min_refresh_interval']) { + $a_user_prefs['refresh_interval'] = $CONFIG['min_refresh_interval']; } } -- cgit v1.2.3 From 7fac4dc87b2507227666db9b74d83090f38d62e7 Mon Sep 17 00:00:00 2001 From: jkornobis Date: Tue, 30 Oct 2012 15:08:49 +0100 Subject: Grancefully handle SSO redirections on Ajax requests On some SSO systems, when the SSO session is expired, the system intercept HTTP requests and send a 302 "Found" HTTP code to the login page. This patch handle this case in Roundcube Ajax requests, to redirect to the SSO login page. Note that request.status don't have the 302 code (at least on Firefox), so we have to check the response headers for a Location field and redirect manually. --- program/js/app.js | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'program') diff --git a/program/js/app.js b/program/js/app.js index 1aa008295..c748d497a 100644 --- a/program/js/app.js +++ b/program/js/app.js @@ -6271,6 +6271,11 @@ function rcube_webmail() else if (request.status == 0 && status != 'abort') this.display_message(this.get_label('servererror') + ' (No connection)', 'error'); + // redirect to url specified in location header if not empty + var location_url = request.getResponseHeader("Location"); + if (location_url) + this.redirect(location_url); + // re-send keep-alive requests after 30 seconds if (action == 'keep-alive') setTimeout(function(){ ref.keep_alive(); }, 30000); -- cgit v1.2.3 From 003b17e2384a3537ae2c724f41c7c4252a9dafd0 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Tue, 13 Nov 2012 14:54:31 +0100 Subject: jQuery-1.8.3 --- CHANGELOG | 2 +- program/js/jquery.min.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'program') diff --git a/CHANGELOG b/CHANGELOG index 19585aa43..0a6e1c9e4 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -4,7 +4,7 @@ CHANGELOG Roundcube Webmail - Fix excessive LFs at the end of composed message with top_posting=true (#1488797) - Option to display attached images as thumbnails below message body - Fix bug where leading blanks were stripped from quoted lines (#1488795) -- Upgraded to jQuery 1.8.2 and jQuery UI 1.9.1 +- Upgraded to jQuery 1.8.3 and jQuery UI 1.9.1 - Add config option to automatically generate LDAP attributes for new entries - Better client-side timezone detection using the jsTimezoneDetect library (#1488725) - Add option to disable saving sent mail in Sent folder - no_save_sent_messages (#1488686) diff --git a/program/js/jquery.min.js b/program/js/jquery.min.js index f65cf1dc4..83589daa7 100644 --- a/program/js/jquery.min.js +++ b/program/js/jquery.min.js @@ -1,2 +1,2 @@ -/*! jQuery v1.8.2 jquery.com | jquery.org/license */ -(function(a,b){function G(a){var b=F[a]={};return p.each(a.split(s),function(a,c){b[c]=!0}),b}function J(a,c,d){if(d===b&&a.nodeType===1){var e="data-"+c.replace(I,"-$1").toLowerCase();d=a.getAttribute(e);if(typeof d=="string"){try{d=d==="true"?!0:d==="false"?!1:d==="null"?null:+d+""===d?+d:H.test(d)?p.parseJSON(d):d}catch(f){}p.data(a,c,d)}else d=b}return d}function K(a){var b;for(b in a){if(b==="data"&&p.isEmptyObject(a[b]))continue;if(b!=="toJSON")return!1}return!0}function ba(){return!1}function bb(){return!0}function bh(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function bi(a,b){do a=a[b];while(a&&a.nodeType!==1);return a}function bj(a,b,c){b=b||0;if(p.isFunction(b))return p.grep(a,function(a,d){var e=!!b.call(a,d,a);return e===c});if(b.nodeType)return p.grep(a,function(a,d){return a===b===c});if(typeof b=="string"){var d=p.grep(a,function(a){return a.nodeType===1});if(be.test(b))return p.filter(b,d,!c);b=p.filter(b,d)}return p.grep(a,function(a,d){return p.inArray(a,b)>=0===c})}function bk(a){var b=bl.split("|"),c=a.createDocumentFragment();if(c.createElement)while(b.length)c.createElement(b.pop());return c}function bC(a,b){return a.getElementsByTagName(b)[0]||a.appendChild(a.ownerDocument.createElement(b))}function bD(a,b){if(b.nodeType!==1||!p.hasData(a))return;var c,d,e,f=p._data(a),g=p._data(b,f),h=f.events;if(h){delete g.handle,g.events={};for(c in h)for(d=0,e=h[c].length;d").appendTo(e.body),c=b.css("display");b.remove();if(c==="none"||c===""){bI=e.body.appendChild(bI||p.extend(e.createElement("iframe"),{frameBorder:0,width:0,height:0}));if(!bJ||!bI.createElement)bJ=(bI.contentWindow||bI.contentDocument).document,bJ.write(""),bJ.close();b=bJ.body.appendChild(bJ.createElement(a)),c=bH(b,"display"),e.body.removeChild(bI)}return bS[a]=c,c}function ci(a,b,c,d){var e;if(p.isArray(b))p.each(b,function(b,e){c||ce.test(a)?d(a,e):ci(a+"["+(typeof e=="object"?b:"")+"]",e,c,d)});else if(!c&&p.type(b)==="object")for(e in b)ci(a+"["+e+"]",b[e],c,d);else d(a,b)}function cz(a){return function(b,c){typeof b!="string"&&(c=b,b="*");var d,e,f,g=b.toLowerCase().split(s),h=0,i=g.length;if(p.isFunction(c))for(;h)[^>]*$|#([\w\-]*)$)/,v=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,w=/^[\],:{}\s]*$/,x=/(?:^|:|,)(?:\s*\[)+/g,y=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,z=/"[^"\\\r\n]*"|true|false|null|-?(?:\d\d*\.|)\d+(?:[eE][\-+]?\d+|)/g,A=/^-ms-/,B=/-([\da-z])/gi,C=function(a,b){return(b+"").toUpperCase()},D=function(){e.addEventListener?(e.removeEventListener("DOMContentLoaded",D,!1),p.ready()):e.readyState==="complete"&&(e.detachEvent("onreadystatechange",D),p.ready())},E={};p.fn=p.prototype={constructor:p,init:function(a,c,d){var f,g,h,i;if(!a)return this;if(a.nodeType)return this.context=this[0]=a,this.length=1,this;if(typeof a=="string"){a.charAt(0)==="<"&&a.charAt(a.length-1)===">"&&a.length>=3?f=[null,a,null]:f=u.exec(a);if(f&&(f[1]||!c)){if(f[1])return c=c instanceof p?c[0]:c,i=c&&c.nodeType?c.ownerDocument||c:e,a=p.parseHTML(f[1],i,!0),v.test(f[1])&&p.isPlainObject(c)&&this.attr.call(a,c,!0),p.merge(this,a);g=e.getElementById(f[2]);if(g&&g.parentNode){if(g.id!==f[2])return d.find(a);this.length=1,this[0]=g}return this.context=e,this.selector=a,this}return!c||c.jquery?(c||d).find(a):this.constructor(c).find(a)}return p.isFunction(a)?d.ready(a):(a.selector!==b&&(this.selector=a.selector,this.context=a.context),p.makeArray(a,this))},selector:"",jquery:"1.8.2",length:0,size:function(){return this.length},toArray:function(){return k.call(this)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var d=p.merge(this.constructor(),a);return d.prevObject=this,d.context=this.context,b==="find"?d.selector=this.selector+(this.selector?" ":"")+c:b&&(d.selector=this.selector+"."+b+"("+c+")"),d},each:function(a,b){return p.each(this,a,b)},ready:function(a){return p.ready.promise().done(a),this},eq:function(a){return a=+a,a===-1?this.slice(a):this.slice(a,a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(k.apply(this,arguments),"slice",k.call(arguments).join(","))},map:function(a){return this.pushStack(p.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:j,sort:[].sort,splice:[].splice},p.fn.init.prototype=p.fn,p.extend=p.fn.extend=function(){var a,c,d,e,f,g,h=arguments[0]||{},i=1,j=arguments.length,k=!1;typeof h=="boolean"&&(k=h,h=arguments[1]||{},i=2),typeof h!="object"&&!p.isFunction(h)&&(h={}),j===i&&(h=this,--i);for(;i0)return;d.resolveWith(e,[p]),p.fn.trigger&&p(e).trigger("ready").off("ready")},isFunction:function(a){return p.type(a)==="function"},isArray:Array.isArray||function(a){return p.type(a)==="array"},isWindow:function(a){return a!=null&&a==a.window},isNumeric:function(a){return!isNaN(parseFloat(a))&&isFinite(a)},type:function(a){return a==null?String(a):E[m.call(a)]||"object"},isPlainObject:function(a){if(!a||p.type(a)!=="object"||a.nodeType||p.isWindow(a))return!1;try{if(a.constructor&&!n.call(a,"constructor")&&!n.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}var d;for(d in a);return d===b||n.call(a,d)},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},error:function(a){throw new Error(a)},parseHTML:function(a,b,c){var d;return!a||typeof a!="string"?null:(typeof b=="boolean"&&(c=b,b=0),b=b||e,(d=v.exec(a))?[b.createElement(d[1])]:(d=p.buildFragment([a],b,c?null:[]),p.merge([],(d.cacheable?p.clone(d.fragment):d.fragment).childNodes)))},parseJSON:function(b){if(!b||typeof b!="string")return null;b=p.trim(b);if(a.JSON&&a.JSON.parse)return a.JSON.parse(b);if(w.test(b.replace(y,"@").replace(z,"]").replace(x,"")))return(new Function("return "+b))();p.error("Invalid JSON: "+b)},parseXML:function(c){var d,e;if(!c||typeof c!="string")return null;try{a.DOMParser?(e=new DOMParser,d=e.parseFromString(c,"text/xml")):(d=new ActiveXObject("Microsoft.XMLDOM"),d.async="false",d.loadXML(c))}catch(f){d=b}return(!d||!d.documentElement||d.getElementsByTagName("parsererror").length)&&p.error("Invalid XML: "+c),d},noop:function(){},globalEval:function(b){b&&r.test(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(A,"ms-").replace(B,C)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,c,d){var e,f=0,g=a.length,h=g===b||p.isFunction(a);if(d){if(h){for(e in a)if(c.apply(a[e],d)===!1)break}else for(;f0&&a[0]&&a[i-1]||i===0||p.isArray(a));if(j)for(;h-1)i.splice(c,1),e&&(c<=g&&g--,c<=h&&h--)}),this},has:function(a){return p.inArray(a,i)>-1},empty:function(){return i=[],this},disable:function(){return i=j=c=b,this},disabled:function(){return!i},lock:function(){return j=b,c||l.disable(),this},locked:function(){return!j},fireWith:function(a,b){return b=b||[],b=[a,b.slice?b.slice():b],i&&(!d||j)&&(e?j.push(b):k(b)),this},fire:function(){return l.fireWith(this,arguments),this},fired:function(){return!!d}};return l},p.extend({Deferred:function(a){var b=[["resolve","done",p.Callbacks("once memory"),"resolved"],["reject","fail",p.Callbacks("once memory"),"rejected"],["notify","progress",p.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return p.Deferred(function(c){p.each(b,function(b,d){var f=d[0],g=a[b];e[d[1]](p.isFunction(g)?function(){var a=g.apply(this,arguments);a&&p.isFunction(a.promise)?a.promise().done(c.resolve).fail(c.reject).progress(c.notify):c[f+"With"](this===e?c:this,[a])}:c[f])}),a=null}).promise()},promise:function(a){return a!=null?p.extend(a,d):d}},e={};return d.pipe=d.then,p.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[a^1][2].disable,b[2][2].lock),e[f[0]]=g.fire,e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=k.call(arguments),d=c.length,e=d!==1||a&&p.isFunction(a.promise)?d:0,f=e===1?a:p.Deferred(),g=function(a,b,c){return function(d){b[a]=this,c[a]=arguments.length>1?k.call(arguments):d,c===h?f.notifyWith(b,c):--e||f.resolveWith(b,c)}},h,i,j;if(d>1){h=new Array(d),i=new Array(d),j=new Array(d);for(;b
a",c=n.getElementsByTagName("*"),d=n.getElementsByTagName("a")[0],d.style.cssText="top:1px;float:left;opacity:.5";if(!c||!c.length)return{};f=e.createElement("select"),g=f.appendChild(e.createElement("option")),h=n.getElementsByTagName("input")[0],b={leadingWhitespace:n.firstChild.nodeType===3,tbody:!n.getElementsByTagName("tbody").length,htmlSerialize:!!n.getElementsByTagName("link").length,style:/top/.test(d.getAttribute("style")),hrefNormalized:d.getAttribute("href")==="/a",opacity:/^0.5/.test(d.style.opacity),cssFloat:!!d.style.cssFloat,checkOn:h.value==="on",optSelected:g.selected,getSetAttribute:n.className!=="t",enctype:!!e.createElement("form").enctype,html5Clone:e.createElement("nav").cloneNode(!0).outerHTML!=="<:nav>",boxModel:e.compatMode==="CSS1Compat",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0,boxSizingReliable:!0,pixelPosition:!1},h.checked=!0,b.noCloneChecked=h.cloneNode(!0).checked,f.disabled=!0,b.optDisabled=!g.disabled;try{delete n.test}catch(o){b.deleteExpando=!1}!n.addEventListener&&n.attachEvent&&n.fireEvent&&(n.attachEvent("onclick",m=function(){b.noCloneEvent=!1}),n.cloneNode(!0).fireEvent("onclick"),n.detachEvent("onclick",m)),h=e.createElement("input"),h.value="t",h.setAttribute("type","radio"),b.radioValue=h.value==="t",h.setAttribute("checked","checked"),h.setAttribute("name","t"),n.appendChild(h),i=e.createDocumentFragment(),i.appendChild(n.lastChild),b.checkClone=i.cloneNode(!0).cloneNode(!0).lastChild.checked,b.appendChecked=h.checked,i.removeChild(h),i.appendChild(n);if(n.attachEvent)for(k in{submit:!0,change:!0,focusin:!0})j="on"+k,l=j in n,l||(n.setAttribute(j,"return;"),l=typeof n[j]=="function"),b[k+"Bubbles"]=l;return p(function(){var c,d,f,g,h="padding:0;margin:0;border:0;display:block;overflow:hidden;",i=e.getElementsByTagName("body")[0];if(!i)return;c=e.createElement("div"),c.style.cssText="visibility:hidden;border:0;width:0;height:0;position:static;top:0;margin-top:1px",i.insertBefore(c,i.firstChild),d=e.createElement("div"),c.appendChild(d),d.innerHTML="
t
",f=d.getElementsByTagName("td"),f[0].style.cssText="padding:0;margin:0;border:0;display:none",l=f[0].offsetHeight===0,f[0].style.display="",f[1].style.display="none",b.reliableHiddenOffsets=l&&f[0].offsetHeight===0,d.innerHTML="",d.style.cssText="box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;",b.boxSizing=d.offsetWidth===4,b.doesNotIncludeMarginInBodyOffset=i.offsetTop!==1,a.getComputedStyle&&(b.pixelPosition=(a.getComputedStyle(d,null)||{}).top!=="1%",b.boxSizingReliable=(a.getComputedStyle(d,null)||{width:"4px"}).width==="4px",g=e.createElement("div"),g.style.cssText=d.style.cssText=h,g.style.marginRight=g.style.width="0",d.style.width="1px",d.appendChild(g),b.reliableMarginRight=!parseFloat((a.getComputedStyle(g,null)||{}).marginRight)),typeof d.style.zoom!="undefined"&&(d.innerHTML="",d.style.cssText=h+"width:1px;padding:1px;display:inline;zoom:1",b.inlineBlockNeedsLayout=d.offsetWidth===3,d.style.display="block",d.style.overflow="visible",d.innerHTML="
",d.firstChild.style.width="5px",b.shrinkWrapBlocks=d.offsetWidth!==3,c.style.zoom=1),i.removeChild(c),c=d=f=g=null}),i.removeChild(n),c=d=f=g=h=i=n=null,b}();var H=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,I=/([A-Z])/g;p.extend({cache:{},deletedIds:[],uuid:0,expando:"jQuery"+(p.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){return a=a.nodeType?p.cache[a[p.expando]]:a[p.expando],!!a&&!K(a)},data:function(a,c,d,e){if(!p.acceptData(a))return;var f,g,h=p.expando,i=typeof c=="string",j=a.nodeType,k=j?p.cache:a,l=j?a[h]:a[h]&&h;if((!l||!k[l]||!e&&!k[l].data)&&i&&d===b)return;l||(j?a[h]=l=p.deletedIds.pop()||p.guid++:l=h),k[l]||(k[l]={},j||(k[l].toJSON=p.noop));if(typeof c=="object"||typeof c=="function")e?k[l]=p.extend(k[l],c):k[l].data=p.extend(k[l].data,c);return f=k[l],e||(f.data||(f.data={}),f=f.data),d!==b&&(f[p.camelCase(c)]=d),i?(g=f[c],g==null&&(g=f[p.camelCase(c)])):g=f,g},removeData:function(a,b,c){if(!p.acceptData(a))return;var d,e,f,g=a.nodeType,h=g?p.cache:a,i=g?a[p.expando]:p.expando;if(!h[i])return;if(b){d=c?h[i]:h[i].data;if(d){p.isArray(b)||(b in d?b=[b]:(b=p.camelCase(b),b in d?b=[b]:b=b.split(" ")));for(e=0,f=b.length;e1,null,!1))},removeData:function(a){return this.each(function(){p.removeData(this,a)})}}),p.extend({queue:function(a,b,c){var d;if(a)return b=(b||"fx")+"queue",d=p._data(a,b),c&&(!d||p.isArray(c)?d=p._data(a,b,p.makeArray(c)):d.push(c)),d||[]},dequeue:function(a,b){b=b||"fx";var c=p.queue(a,b),d=c.length,e=c.shift(),f=p._queueHooks(a,b),g=function(){p.dequeue(a,b)};e==="inprogress"&&(e=c.shift(),d--),e&&(b==="fx"&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return p._data(a,c)||p._data(a,c,{empty:p.Callbacks("once memory").add(function(){p.removeData(a,b+"queue",!0),p.removeData(a,c,!0)})})}}),p.fn.extend({queue:function(a,c){var d=2;return typeof a!="string"&&(c=a,a="fx",d--),arguments.length1)},removeAttr:function(a){return this.each(function(){p.removeAttr(this,a)})},prop:function(a,b){return p.access(this,p.prop,a,b,arguments.length>1)},removeProp:function(a){return a=p.propFix[a]||a,this.each(function(){try{this[a]=b,delete this[a]}catch(c){}})},addClass:function(a){var b,c,d,e,f,g,h;if(p.isFunction(a))return this.each(function(b){p(this).addClass(a.call(this,b,this.className))});if(a&&typeof a=="string"){b=a.split(s);for(c=0,d=this.length;c=0)d=d.replace(" "+c[f]+" "," ");e.className=a?p.trim(d):""}}}return this},toggleClass:function(a,b){var c=typeof a,d=typeof b=="boolean";return p.isFunction(a)?this.each(function(c){p(this).toggleClass(a.call(this,c,this.className,b),b)}):this.each(function(){if(c==="string"){var e,f=0,g=p(this),h=b,i=a.split(s);while(e=i[f++])h=d?h:!g.hasClass(e),g[h?"addClass":"removeClass"](e)}else if(c==="undefined"||c==="boolean")this.className&&p._data(this,"__className__",this.className),this.className=this.className||a===!1?"":p._data(this,"__className__")||""})},hasClass:function(a){var b=" "+a+" ",c=0,d=this.length;for(;c=0)return!0;return!1},val:function(a){var c,d,e,f=this[0];if(!arguments.length){if(f)return c=p.valHooks[f.type]||p.valHooks[f.nodeName.toLowerCase()],c&&"get"in c&&(d=c.get(f,"value"))!==b?d:(d=f.value,typeof d=="string"?d.replace(P,""):d==null?"":d);return}return e=p.isFunction(a),this.each(function(d){var f,g=p(this);if(this.nodeType!==1)return;e?f=a.call(this,d,g.val()):f=a,f==null?f="":typeof f=="number"?f+="":p.isArray(f)&&(f=p.map(f,function(a){return a==null?"":a+""})),c=p.valHooks[this.type]||p.valHooks[this.nodeName.toLowerCase()];if(!c||!("set"in c)||c.set(this,f,"value")===b)this.value=f})}}),p.extend({valHooks:{option:{get:function(a){var b=a.attributes.value;return!b||b.specified?a.value:a.text}},select:{get:function(a){var b,c,d,e,f=a.selectedIndex,g=[],h=a.options,i=a.type==="select-one";if(f<0)return null;c=i?f:0,d=i?f+1:h.length;for(;c=0}),c.length||(a.selectedIndex=-1),c}}},attrFn:{},attr:function(a,c,d,e){var f,g,h,i=a.nodeType;if(!a||i===3||i===8||i===2)return;if(e&&p.isFunction(p.fn[c]))return p(a)[c](d);if(typeof a.getAttribute=="undefined")return p.prop(a,c,d);h=i!==1||!p.isXMLDoc(a),h&&(c=c.toLowerCase(),g=p.attrHooks[c]||(T.test(c)?M:L));if(d!==b){if(d===null){p.removeAttr(a,c);return}return g&&"set"in g&&h&&(f=g.set(a,d,c))!==b?f:(a.setAttribute(c,d+""),d)}return g&&"get"in g&&h&&(f=g.get(a,c))!==null?f:(f=a.getAttribute(c),f===null?b:f)},removeAttr:function(a,b){var c,d,e,f,g=0;if(b&&a.nodeType===1){d=b.split(s);for(;g=0}})});var V=/^(?:textarea|input|select)$/i,W=/^([^\.]*|)(?:\.(.+)|)$/,X=/(?:^|\s)hover(\.\S+|)\b/,Y=/^key/,Z=/^(?:mouse|contextmenu)|click/,$=/^(?:focusinfocus|focusoutblur)$/,_=function(a){return p.event.special.hover?a:a.replace(X,"mouseenter$1 mouseleave$1")};p.event={add:function(a,c,d,e,f){var g,h,i,j,k,l,m,n,o,q,r;if(a.nodeType===3||a.nodeType===8||!c||!d||!(g=p._data(a)))return;d.handler&&(o=d,d=o.handler,f=o.selector),d.guid||(d.guid=p.guid++),i=g.events,i||(g.events=i={}),h=g.handle,h||(g.handle=h=function(a){return typeof p!="undefined"&&(!a||p.event.triggered!==a.type)?p.event.dispatch.apply(h.elem,arguments):b},h.elem=a),c=p.trim(_(c)).split(" ");for(j=0;j=0&&(s=s.slice(0,-1),i=!0),s.indexOf(".")>=0&&(t=s.split("."),s=t.shift(),t.sort());if((!f||p.event.customEvent[s])&&!p.event.global[s])return;c=typeof c=="object"?c[p.expando]?c:new p.Event(s,c):new p.Event(s),c.type=s,c.isTrigger=!0,c.exclusive=i,c.namespace=t.join("."),c.namespace_re=c.namespace?new RegExp("(^|\\.)"+t.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,m=s.indexOf(":")<0?"on"+s:"";if(!f){h=p.cache;for(j in h)h[j].events&&h[j].events[s]&&p.event.trigger(c,d,h[j].handle.elem,!0);return}c.result=b,c.target||(c.target=f),d=d!=null?p.makeArray(d):[],d.unshift(c),n=p.event.special[s]||{};if(n.trigger&&n.trigger.apply(f,d)===!1)return;q=[[f,n.bindType||s]];if(!g&&!n.noBubble&&!p.isWindow(f)){r=n.delegateType||s,k=$.test(r+s)?f:f.parentNode;for(l=f;k;k=k.parentNode)q.push([k,r]),l=k;l===(f.ownerDocument||e)&&q.push([l.defaultView||l.parentWindow||a,r])}for(j=0;j=0:p.find(m,this,null,[f]).length),h[m]&&j.push(l);j.length&&u.push({elem:f,matches:j})}o.length>q&&u.push({elem:this,matches:o.slice(q)});for(d=0;d0?this.on(b,null,a,c):this.trigger(b)},Y.test(b)&&(p.event.fixHooks[b]=p.event.keyHooks),Z.test(b)&&(p.event.fixHooks[b]=p.event.mouseHooks)}),function(a,b){function bc(a,b,c,d){c=c||[],b=b||r;var e,f,i,j,k=b.nodeType;if(!a||typeof a!="string")return c;if(k!==1&&k!==9)return[];i=g(b);if(!i&&!d)if(e=P.exec(a))if(j=e[1]){if(k===9){f=b.getElementById(j);if(!f||!f.parentNode)return c;if(f.id===j)return c.push(f),c}else if(b.ownerDocument&&(f=b.ownerDocument.getElementById(j))&&h(b,f)&&f.id===j)return c.push(f),c}else{if(e[2])return w.apply(c,x.call(b.getElementsByTagName(a),0)),c;if((j=e[3])&&_&&b.getElementsByClassName)return w.apply(c,x.call(b.getElementsByClassName(j),0)),c}return bp(a.replace(L,"$1"),b,c,d,i)}function bd(a){return function(b){var c=b.nodeName.toLowerCase();return c==="input"&&b.type===a}}function be(a){return function(b){var c=b.nodeName.toLowerCase();return(c==="input"||c==="button")&&b.type===a}}function bf(a){return z(function(b){return b=+b,z(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function bg(a,b,c){if(a===b)return c;var d=a.nextSibling;while(d){if(d===b)return-1;d=d.nextSibling}return 1}function bh(a,b){var c,d,f,g,h,i,j,k=C[o][a];if(k)return b?0:k.slice(0);h=a,i=[],j=e.preFilter;while(h){if(!c||(d=M.exec(h)))d&&(h=h.slice(d[0].length)),i.push(f=[]);c=!1;if(d=N.exec(h))f.push(c=new q(d.shift())),h=h.slice(c.length),c.type=d[0].replace(L," ");for(g in e.filter)(d=W[g].exec(h))&&(!j[g]||(d=j[g](d,r,!0)))&&(f.push(c=new q(d.shift())),h=h.slice(c.length),c.type=g,c.matches=d);if(!c)break}return b?h.length:h?bc.error(a):C(a,i).slice(0)}function bi(a,b,d){var e=b.dir,f=d&&b.dir==="parentNode",g=u++;return b.first?function(b,c,d){while(b=b[e])if(f||b.nodeType===1)return a(b,c,d)}:function(b,d,h){if(!h){var i,j=t+" "+g+" ",k=j+c;while(b=b[e])if(f||b.nodeType===1){if((i=b[o])===k)return b.sizset;if(typeof i=="string"&&i.indexOf(j)===0){if(b.sizset)return b}else{b[o]=k;if(a(b,d,h))return b.sizset=!0,b;b.sizset=!1}}}else while(b=b[e])if(f||b.nodeType===1)if(a(b,d,h))return b}}function bj(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function bk(a,b,c,d,e){var f,g=[],h=0,i=a.length,j=b!=null;for(;h-1},h,!0),m=[function(a,c,d){return!g&&(d||c!==l)||((b=c).nodeType?j(a,c,d):k(a,c,d))}];for(;i1&&bj(m),i>1&&a.slice(0,i-1).join("").replace(L,"$1"),c,i0,f=a.length>0,g=function(h,i,j,k,m){var n,o,p,q=[],s=0,u="0",x=h&&[],y=m!=null,z=l,A=h||f&&e.find.TAG("*",m&&i.parentNode||i),B=t+=z==null?1:Math.E;y&&(l=i!==r&&i,c=g.el);for(;(n=A[u])!=null;u++){if(f&&n){for(o=0;p=a[o];o++)if(p(n,i,j)){k.push(n);break}y&&(t=B,c=++g.el)}d&&((n=!p&&n)&&s--,h&&x.push(n))}s+=u;if(d&&u!==s){for(o=0;p=b[o];o++)p(x,q,i,j);if(h){if(s>0)while(u--)!x[u]&&!q[u]&&(q[u]=v.call(k));q=bk(q)}w.apply(k,q),y&&!h&&q.length>0&&s+b.length>1&&bc.uniqueSort(k)}return y&&(t=B,l=z),x};return g.el=0,d?z(g):g}function bo(a,b,c,d){var e=0,f=b.length;for(;e2&&(j=h[0]).type==="ID"&&b.nodeType===9&&!f&&e.relative[h[1].type]){b=e.find.ID(j.matches[0].replace(V,""),b,f)[0];if(!b)return c;a=a.slice(h.shift().length)}for(g=W.POS.test(a)?-1:h.length-1;g>=0;g--){j=h[g];if(e.relative[k=j.type])break;if(l=e.find[k])if(d=l(j.matches[0].replace(V,""),R.test(h[0].type)&&b.parentNode||b,f)){h.splice(g,1),a=d.length&&h.join("");if(!a)return w.apply(c,x.call(d,0)),c;break}}}return i(a,m)(d,b,f,c,R.test(a)),c}function bq(){}var c,d,e,f,g,h,i,j,k,l,m=!0,n="undefined",o=("sizcache"+Math.random()).replace(".",""),q=String,r=a.document,s=r.documentElement,t=0,u=0,v=[].pop,w=[].push,x=[].slice,y=[].indexOf||function(a){var b=0,c=this.length;for(;be.cacheLength&&delete a[b.shift()],a[c]=d},a)},B=A(),C=A(),D=A(),E="[\\x20\\t\\r\\n\\f]",F="(?:\\\\.|[-\\w]|[^\\x00-\\xa0])+",G=F.replace("w","w#"),H="([*^$|!~]?=)",I="\\["+E+"*("+F+")"+E+"*(?:"+H+E+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+G+")|)|)"+E+"*\\]",J=":("+F+")(?:\\((?:(['\"])((?:\\\\.|[^\\\\])*?)\\2|([^()[\\]]*|(?:(?:"+I+")|[^:]|\\\\.)*|.*))\\)|)",K=":(even|odd|eq|gt|lt|nth|first|last)(?:\\("+E+"*((?:-\\d)?\\d*)"+E+"*\\)|)(?=[^-]|$)",L=new RegExp("^"+E+"+|((?:^|[^\\\\])(?:\\\\.)*)"+E+"+$","g"),M=new RegExp("^"+E+"*,"+E+"*"),N=new RegExp("^"+E+"*([\\x20\\t\\r\\n\\f>+~])"+E+"*"),O=new RegExp(J),P=/^(?:#([\w\-]+)|(\w+)|\.([\w\-]+))$/,Q=/^:not/,R=/[\x20\t\r\n\f]*[+~]/,S=/:not\($/,T=/h\d/i,U=/input|select|textarea|button/i,V=/\\(?!\\)/g,W={ID:new RegExp("^#("+F+")"),CLASS:new RegExp("^\\.("+F+")"),NAME:new RegExp("^\\[name=['\"]?("+F+")['\"]?\\]"),TAG:new RegExp("^("+F.replace("w","w*")+")"),ATTR:new RegExp("^"+I),PSEUDO:new RegExp("^"+J),POS:new RegExp(K,"i"),CHILD:new RegExp("^:(only|nth|first|last)-child(?:\\("+E+"*(even|odd|(([+-]|)(\\d*)n|)"+E+"*(?:([+-]|)"+E+"*(\\d+)|))"+E+"*\\)|)","i"),needsContext:new RegExp("^"+E+"*[>+~]|"+K,"i")},X=function(a){var b=r.createElement("div");try{return a(b)}catch(c){return!1}finally{b=null}},Y=X(function(a){return a.appendChild(r.createComment("")),!a.getElementsByTagName("*").length}),Z=X(function(a){return a.innerHTML="",a.firstChild&&typeof a.firstChild.getAttribute!==n&&a.firstChild.getAttribute("href")==="#"}),$=X(function(a){a.innerHTML="";var b=typeof a.lastChild.getAttribute("multiple");return b!=="boolean"&&b!=="string"}),_=X(function(a){return a.innerHTML="",!a.getElementsByClassName||!a.getElementsByClassName("e").length?!1:(a.lastChild.className="e",a.getElementsByClassName("e").length===2)}),ba=X(function(a){a.id=o+0,a.innerHTML="
",s.insertBefore(a,s.firstChild);var b=r.getElementsByName&&r.getElementsByName(o).length===2+r.getElementsByName(o+0).length;return d=!r.getElementById(o),s.removeChild(a),b});try{x.call(s.childNodes,0)[0].nodeType}catch(bb){x=function(a){var b,c=[];for(;b=this[a];a++)c.push(b);return c}}bc.matches=function(a,b){return bc(a,null,null,b)},bc.matchesSelector=function(a,b){return bc(b,null,null,[a]).length>0},f=bc.getText=function(a){var b,c="",d=0,e=a.nodeType;if(e){if(e===1||e===9||e===11){if(typeof a.textContent=="string")return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=f(a)}else if(e===3||e===4)return a.nodeValue}else for(;b=a[d];d++)c+=f(b);return c},g=bc.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?b.nodeName!=="HTML":!1},h=bc.contains=s.contains?function(a,b){var c=a.nodeType===9?a.documentElement:a,d=b&&b.parentNode;return a===d||!!(d&&d.nodeType===1&&c.contains&&c.contains(d))}:s.compareDocumentPosition?function(a,b){return b&&!!(a.compareDocumentPosition(b)&16)}:function(a,b){while(b=b.parentNode)if(b===a)return!0;return!1},bc.attr=function(a,b){var c,d=g(a);return d||(b=b.toLowerCase()),(c=e.attrHandle[b])?c(a):d||$?a.getAttribute(b):(c=a.getAttributeNode(b),c?typeof a[b]=="boolean"?a[b]?b:null:c.specified?c.value:null:null)},e=bc.selectors={cacheLength:50,createPseudo:z,match:W,attrHandle:Z?{}:{href:function(a){return a.getAttribute("href",2)},type:function(a){return a.getAttribute("type")}},find:{ID:d?function(a,b,c){if(typeof b.getElementById!==n&&!c){var d=b.getElementById(a);return d&&d.parentNode?[d]:[]}}:function(a,c,d){if(typeof c.getElementById!==n&&!d){var e=c.getElementById(a);return e?e.id===a||typeof e.getAttributeNode!==n&&e.getAttributeNode("id").value===a?[e]:b:[]}},TAG:Y?function(a,b){if(typeof b.getElementsByTagName!==n)return b.getElementsByTagName(a)}:function(a,b){var c=b.getElementsByTagName(a);if(a==="*"){var d,e=[],f=0;for(;d=c[f];f++)d.nodeType===1&&e.push(d);return e}return c},NAME:ba&&function(a,b){if(typeof b.getElementsByName!==n)return b.getElementsByName(name)},CLASS:_&&function(a,b,c){if(typeof b.getElementsByClassName!==n&&!c)return b.getElementsByClassName(a)}},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(V,""),a[3]=(a[4]||a[5]||"").replace(V,""),a[2]==="~="&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),a[1]==="nth"?(a[2]||bc.error(a[0]),a[3]=+(a[3]?a[4]+(a[5]||1):2*(a[2]==="even"||a[2]==="odd")),a[4]=+(a[6]+a[7]||a[2]==="odd")):a[2]&&bc.error(a[0]),a},PSEUDO:function(a){var b,c;if(W.CHILD.test(a[0]))return null;if(a[3])a[2]=a[3];else if(b=a[4])O.test(b)&&(c=bh(b,!0))&&(c=b.indexOf(")",b.length-c)-b.length)&&(b=b.slice(0,c),a[0]=a[0].slice(0,c)),a[2]=b;return a.slice(0,3)}},filter:{ID:d?function(a){return a=a.replace(V,""),function(b){return b.getAttribute("id")===a}}:function(a){return a=a.replace(V,""),function(b){var c=typeof b.getAttributeNode!==n&&b.getAttributeNode("id");return c&&c.value===a}},TAG:function(a){return a==="*"?function(){return!0}:(a=a.replace(V,"").toLowerCase(),function(b){return b.nodeName&&b.nodeName.toLowerCase()===a})},CLASS:function(a){var b=B[o][a];return b||(b=B(a,new RegExp("(^|"+E+")"+a+"("+E+"|$)"))),function(a){return b.test(a.className||typeof a.getAttribute!==n&&a.getAttribute("class")||"")}},ATTR:function(a,b,c){return function(d,e){var f=bc.attr(d,a);return f==null?b==="!=":b?(f+="",b==="="?f===c:b==="!="?f!==c:b==="^="?c&&f.indexOf(c)===0:b==="*="?c&&f.indexOf(c)>-1:b==="$="?c&&f.substr(f.length-c.length)===c:b==="~="?(" "+f+" ").indexOf(c)>-1:b==="|="?f===c||f.substr(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d){return a==="nth"?function(a){var b,e,f=a.parentNode;if(c===1&&d===0)return!0;if(f){e=0;for(b=f.firstChild;b;b=b.nextSibling)if(b.nodeType===1){e++;if(a===b)break}}return e-=d,e===c||e%c===0&&e/c>=0}:function(b){var c=b;switch(a){case"only":case"first":while(c=c.previousSibling)if(c.nodeType===1)return!1;if(a==="first")return!0;c=b;case"last":while(c=c.nextSibling)if(c.nodeType===1)return!1;return!0}}},PSEUDO:function(a,b){var c,d=e.pseudos[a]||e.setFilters[a.toLowerCase()]||bc.error("unsupported pseudo: "+a);return d[o]?d(b):d.length>1?(c=[a,a,"",b],e.setFilters.hasOwnProperty(a.toLowerCase())?z(function(a,c){var e,f=d(a,b),g=f.length;while(g--)e=y.call(a,f[g]),a[e]=!(c[e]=f[g])}):function(a){return d(a,0,c)}):d}},pseudos:{not:z(function(a){var b=[],c=[],d=i(a.replace(L,"$1"));return d[o]?z(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)if(f=g[h])a[h]=!(b[h]=f)}):function(a,e,f){return b[0]=a,d(b,null,f,c),!c.pop()}}),has:z(function(a){return function(b){return bc(a,b).length>0}}),contains:z(function(a){return function(b){return(b.textContent||b.innerText||f(b)).indexOf(a)>-1}}),enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&!!a.checked||b==="option"&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},parent:function(a){return!e.pseudos.empty(a)},empty:function(a){var b;a=a.firstChild;while(a){if(a.nodeName>"@"||(b=a.nodeType)===3||b===4)return!1;a=a.nextSibling}return!0},header:function(a){return T.test(a.nodeName)},text:function(a){var b,c;return a.nodeName.toLowerCase()==="input"&&(b=a.type)==="text"&&((c=a.getAttribute("type"))==null||c.toLowerCase()===b)},radio:bd("radio"),checkbox:bd("checkbox"),file:bd("file"),password:bd("password"),image:bd("image"),submit:be("submit"),reset:be("reset"),button:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&a.type==="button"||b==="button"},input:function(a){return U.test(a.nodeName)},focus:function(a){var b=a.ownerDocument;return a===b.activeElement&&(!b.hasFocus||b.hasFocus())&&(!!a.type||!!a.href)},active:function(a){return a===a.ownerDocument.activeElement},first:bf(function(a,b,c){return[0]}),last:bf(function(a,b,c){return[b-1]}),eq:bf(function(a,b,c){return[c<0?c+b:c]}),even:bf(function(a,b,c){for(var d=0;d=0;)a.push(d);return a}),gt:bf(function(a,b,c){for(var d=c<0?c+b:c;++d",a.querySelectorAll("[selected]").length||e.push("\\["+E+"*(?:checked|disabled|ismap|multiple|readonly|selected|value)"),a.querySelectorAll(":checked").length||e.push(":checked")}),X(function(a){a.innerHTML="

",a.querySelectorAll("[test^='']").length&&e.push("[*^$]="+E+"*(?:\"\"|'')"),a.innerHTML="",a.querySelectorAll(":enabled").length||e.push(":enabled",":disabled")}),e=new RegExp(e.join("|")),bp=function(a,d,f,g,h){if(!g&&!h&&(!e||!e.test(a))){var i,j,k=!0,l=o,m=d,n=d.nodeType===9&&a;if(d.nodeType===1&&d.nodeName.toLowerCase()!=="object"){i=bh(a),(k=d.getAttribute("id"))?l=k.replace(c,"\\$&"):d.setAttribute("id",l),l="[id='"+l+"'] ",j=i.length;while(j--)i[j]=l+i[j].join("");m=R.test(a)&&d.parentNode||d,n=i.join(",")}if(n)try{return w.apply(f,x.call(m.querySelectorAll(n),0)),f}catch(p){}finally{k||d.removeAttribute("id")}}return b(a,d,f,g,h)},h&&(X(function(b){a=h.call(b,"div");try{h.call(b,"[test!='']:sizzle"),f.push("!=",J)}catch(c){}}),f=new RegExp(f.join("|")),bc.matchesSelector=function(b,c){c=c.replace(d,"='$1']");if(!g(b)&&!f.test(c)&&(!e||!e.test(c)))try{var i=h.call(b,c);if(i||a||b.document&&b.document.nodeType!==11)return i}catch(j){}return bc(c,null,null,[b]).length>0})}(),e.pseudos.nth=e.pseudos.eq,e.filters=bq.prototype=e.pseudos,e.setFilters=new bq,bc.attr=p.attr,p.find=bc,p.expr=bc.selectors,p.expr[":"]=p.expr.pseudos,p.unique=bc.uniqueSort,p.text=bc.getText,p.isXMLDoc=bc.isXML,p.contains=bc.contains}(a);var bc=/Until$/,bd=/^(?:parents|prev(?:Until|All))/,be=/^.[^:#\[\.,]*$/,bf=p.expr.match.needsContext,bg={children:!0,contents:!0,next:!0,prev:!0};p.fn.extend({find:function(a){var b,c,d,e,f,g,h=this;if(typeof a!="string")return p(a).filter(function(){for(b=0,c=h.length;b0)for(e=d;e=0:p.filter(a,this).length>0:this.filter(a).length>0)},closest:function(a,b){var c,d=0,e=this.length,f=[],g=bf.test(a)||typeof a!="string"?p(a,b||this.context):0;for(;d-1:p.find.matchesSelector(c,a)){f.push(c);break}c=c.parentNode}}return f=f.length>1?p.unique(f):f,this.pushStack(f,"closest",a)},index:function(a){return a?typeof a=="string"?p.inArray(this[0],p(a)):p.inArray(a.jquery?a[0]:a,this):this[0]&&this[0].parentNode?this.prevAll().length:-1},add:function(a,b){var c=typeof a=="string"?p(a,b):p.makeArray(a&&a.nodeType?[a]:a),d=p.merge(this.get(),c);return this.pushStack(bh(c[0])||bh(d[0])?d:p.unique(d))},addBack:function(a){return this.add(a==null?this.prevObject:this.prevObject.filter(a))}}),p.fn.andSelf=p.fn.addBack,p.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return p.dir(a,"parentNode")},parentsUntil:function(a,b,c){return p.dir(a,"parentNode",c)},next:function(a){return bi(a,"nextSibling")},prev:function(a){return bi(a,"previousSibling")},nextAll:function(a){return p.dir(a,"nextSibling")},prevAll:function(a){return p.dir(a,"previousSibling")},nextUntil:function(a,b,c){return p.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return p.dir(a,"previousSibling",c)},siblings:function(a){return p.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return p.sibling(a.firstChild)},contents:function(a){return p.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:p.merge([],a.childNodes)}},function(a,b){p.fn[a]=function(c,d){var e=p.map(this,b,c);return bc.test(a)||(d=c),d&&typeof d=="string"&&(e=p.filter(d,e)),e=this.length>1&&!bg[a]?p.unique(e):e,this.length>1&&bd.test(a)&&(e=e.reverse()),this.pushStack(e,a,k.call(arguments).join(","))}}),p.extend({filter:function(a,b,c){return c&&(a=":not("+a+")"),b.length===1?p.find.matchesSelector(b[0],a)?[b[0]]:[]:p.find.matches(a,b)},dir:function(a,c,d){var e=[],f=a[c];while(f&&f.nodeType!==9&&(d===b||f.nodeType!==1||!p(f).is(d)))f.nodeType===1&&e.push(f),f=f[c];return e},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var bl="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",bm=/ jQuery\d+="(?:null|\d+)"/g,bn=/^\s+/,bo=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,bp=/<([\w:]+)/,bq=/]","i"),bv=/^(?:checkbox|radio)$/,bw=/checked\s*(?:[^=]|=\s*.checked.)/i,bx=/\/(java|ecma)script/i,by=/^\s*\s*$/g,bz={option:[1,""],legend:[1,"
","
"],thead:[1,"","
"],tr:[2,"","
"],td:[3,"","
"],col:[2,"","
"],area:[1,"",""],_default:[0,"",""]},bA=bk(e),bB=bA.appendChild(e.createElement("div"));bz.optgroup=bz.option,bz.tbody=bz.tfoot=bz.colgroup=bz.caption=bz.thead,bz.th=bz.td,p.support.htmlSerialize||(bz._default=[1,"X
","
"]),p.fn.extend({text:function(a){return p.access(this,function(a){return a===b?p.text(this):this.empty().append((this[0]&&this[0].ownerDocument||e).createTextNode(a))},null,a,arguments.length)},wrapAll:function(a){if(p.isFunction(a))return this.each(function(b){p(this).wrapAll(a.call(this,b))});if(this[0]){var b=p(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){return p.isFunction(a)?this.each(function(b){p(this).wrapInner(a.call(this,b))}):this.each(function(){var b=p(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=p.isFunction(a);return this.each(function(c){p(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){p.nodeName(this,"body")||p(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){(this.nodeType===1||this.nodeType===11)&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){(this.nodeType===1||this.nodeType===11)&&this.insertBefore(a,this.firstChild)})},before:function(){if(!bh(this[0]))return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=p.clean(arguments);return this.pushStack(p.merge(a,this),"before",this.selector)}},after:function(){if(!bh(this[0]))return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=p.clean(arguments);return this.pushStack(p.merge(this,a),"after",this.selector)}},remove:function(a,b){var c,d=0;for(;(c=this[d])!=null;d++)if(!a||p.filter(a,[c]).length)!b&&c.nodeType===1&&(p.cleanData(c.getElementsByTagName("*")),p.cleanData([c])),c.parentNode&&c.parentNode.removeChild(c);return this},empty:function(){var a,b=0;for(;(a=this[b])!=null;b++){a.nodeType===1&&p.cleanData(a.getElementsByTagName("*"));while(a.firstChild)a.removeChild(a.firstChild)}return this},clone:function(a,b){return a=a==null?!1:a,b=b==null?a:b,this.map(function(){return p.clone(this,a,b)})},html:function(a){return p.access(this,function(a){var c=this[0]||{},d=0,e=this.length;if(a===b)return c.nodeType===1?c.innerHTML.replace(bm,""):b;if(typeof a=="string"&&!bs.test(a)&&(p.support.htmlSerialize||!bu.test(a))&&(p.support.leadingWhitespace||!bn.test(a))&&!bz[(bp.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(bo,"<$1>");try{for(;d1&&typeof j=="string"&&bw.test(j))return this.each(function(){p(this).domManip(a,c,d)});if(p.isFunction(j))return this.each(function(e){var f=p(this);a[0]=j.call(this,e,c?f.html():b),f.domManip(a,c,d)});if(this[0]){e=p.buildFragment(a,this,k),g=e.fragment,f=g.firstChild,g.childNodes.length===1&&(g=f);if(f){c=c&&p.nodeName(f,"tr");for(h=e.cacheable||l-1;i0?this.clone(!0):this).get(),p(g[e])[b](d),f=f.concat(d);return this.pushStack(f,a,g.selector)}}),p.extend({clone:function(a,b,c){var d,e,f,g;p.support.html5Clone||p.isXMLDoc(a)||!bu.test("<"+a.nodeName+">")?g=a.cloneNode(!0):(bB.innerHTML=a.outerHTML,bB.removeChild(g=bB.firstChild));if((!p.support.noCloneEvent||!p.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!p.isXMLDoc(a)){bE(a,g),d=bF(a),e=bF(g);for(f=0;d[f];++f)e[f]&&bE(d[f],e[f])}if(b){bD(a,g);if(c){d=bF(a),e=bF(g);for(f=0;d[f];++f)bD(d[f],e[f])}}return d=e=null,g},clean:function(a,b,c,d){var f,g,h,i,j,k,l,m,n,o,q,r,s=b===e&&bA,t=[];if(!b||typeof b.createDocumentFragment=="undefined")b=e;for(f=0;(h=a[f])!=null;f++){typeof h=="number"&&(h+="");if(!h)continue;if(typeof h=="string")if(!br.test(h))h=b.createTextNode(h);else{s=s||bk(b),l=b.createElement("div"),s.appendChild(l),h=h.replace(bo,"<$1>"),i=(bp.exec(h)||["",""])[1].toLowerCase(),j=bz[i]||bz._default,k=j[0],l.innerHTML=j[1]+h+j[2];while(k--)l=l.lastChild;if(!p.support.tbody){m=bq.test(h),n=i==="table"&&!m?l.firstChild&&l.firstChild.childNodes:j[1]===""&&!m?l.childNodes:[];for(g=n.length-1;g>=0;--g)p.nodeName(n[g],"tbody")&&!n[g].childNodes.length&&n[g].parentNode.removeChild(n[g])}!p.support.leadingWhitespace&&bn.test(h)&&l.insertBefore(b.createTextNode(bn.exec(h)[0]),l.firstChild),h=l.childNodes,l.parentNode.removeChild(l)}h.nodeType?t.push(h):p.merge(t,h)}l&&(h=l=s=null);if(!p.support.appendChecked)for(f=0;(h=t[f])!=null;f++)p.nodeName(h,"input")?bG(h):typeof h.getElementsByTagName!="undefined"&&p.grep(h.getElementsByTagName("input"),bG);if(c){q=function(a){if(!a.type||bx.test(a.type))return d?d.push(a.parentNode?a.parentNode.removeChild(a):a):c.appendChild(a)};for(f=0;(h=t[f])!=null;f++)if(!p.nodeName(h,"script")||!q(h))c.appendChild(h),typeof h.getElementsByTagName!="undefined"&&(r=p.grep(p.merge([],h.getElementsByTagName("script")),q),t.splice.apply(t,[f+1,0].concat(r)),f+=r.length)}return t},cleanData:function(a,b){var c,d,e,f,g=0,h=p.expando,i=p.cache,j=p.support.deleteExpando,k=p.event.special;for(;(e=a[g])!=null;g++)if(b||p.acceptData(e)){d=e[h],c=d&&i[d];if(c){if(c.events)for(f in c.events)k[f]?p.event.remove(e,f):p.removeEvent(e,f,c.handle);i[d]&&(delete i[d],j?delete e[h]:e.removeAttribute?e.removeAttribute(h):e[h]=null,p.deletedIds.push(d))}}}}),function(){var a,b;p.uaMatch=function(a){a=a.toLowerCase();var b=/(chrome)[ \/]([\w.]+)/.exec(a)||/(webkit)[ \/]([\w.]+)/.exec(a)||/(opera)(?:.*version|)[ \/]([\w.]+)/.exec(a)||/(msie) ([\w.]+)/.exec(a)||a.indexOf("compatible")<0&&/(mozilla)(?:.*? rv:([\w.]+)|)/.exec(a)||[];return{browser:b[1]||"",version:b[2]||"0"}},a=p.uaMatch(g.userAgent),b={},a.browser&&(b[a.browser]=!0,b.version=a.version),b.chrome?b.webkit=!0:b.webkit&&(b.safari=!0),p.browser=b,p.sub=function(){function a(b,c){return new a.fn.init(b,c)}p.extend(!0,a,this),a.superclass=this,a.fn=a.prototype=this(),a.fn.constructor=a,a.sub=this.sub,a.fn.init=function c(c,d){return d&&d instanceof p&&!(d instanceof a)&&(d=a(d)),p.fn.init.call(this,c,d,b)},a.fn.init.prototype=a.fn;var b=a(e);return a}}();var bH,bI,bJ,bK=/alpha\([^)]*\)/i,bL=/opacity=([^)]*)/,bM=/^(top|right|bottom|left)$/,bN=/^(none|table(?!-c[ea]).+)/,bO=/^margin/,bP=new RegExp("^("+q+")(.*)$","i"),bQ=new RegExp("^("+q+")(?!px)[a-z%]+$","i"),bR=new RegExp("^([-+])=("+q+")","i"),bS={},bT={position:"absolute",visibility:"hidden",display:"block"},bU={letterSpacing:0,fontWeight:400},bV=["Top","Right","Bottom","Left"],bW=["Webkit","O","Moz","ms"],bX=p.fn.toggle;p.fn.extend({css:function(a,c){return p.access(this,function(a,c,d){return d!==b?p.style(a,c,d):p.css(a,c)},a,c,arguments.length>1)},show:function(){return b$(this,!0)},hide:function(){return b$(this)},toggle:function(a,b){var c=typeof a=="boolean";return p.isFunction(a)&&p.isFunction(b)?bX.apply(this,arguments):this.each(function(){(c?a:bZ(this))?p(this).show():p(this).hide()})}}),p.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=bH(a,"opacity");return c===""?"1":c}}}},cssNumber:{fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":p.support.cssFloat?"cssFloat":"styleFloat"},style:function(a,c,d,e){if(!a||a.nodeType===3||a.nodeType===8||!a.style)return;var f,g,h,i=p.camelCase(c),j=a.style;c=p.cssProps[i]||(p.cssProps[i]=bY(j,i)),h=p.cssHooks[c]||p.cssHooks[i];if(d===b)return h&&"get"in h&&(f=h.get(a,!1,e))!==b?f:j[c];g=typeof d,g==="string"&&(f=bR.exec(d))&&(d=(f[1]+1)*f[2]+parseFloat(p.css(a,c)),g="number");if(d==null||g==="number"&&isNaN(d))return;g==="number"&&!p.cssNumber[i]&&(d+="px");if(!h||!("set"in h)||(d=h.set(a,d,e))!==b)try{j[c]=d}catch(k){}},css:function(a,c,d,e){var f,g,h,i=p.camelCase(c);return c=p.cssProps[i]||(p.cssProps[i]=bY(a.style,i)),h=p.cssHooks[c]||p.cssHooks[i],h&&"get"in h&&(f=h.get(a,!0,e)),f===b&&(f=bH(a,c)),f==="normal"&&c in bU&&(f=bU[c]),d||e!==b?(g=parseFloat(f),d||p.isNumeric(g)?g||0:f):f},swap:function(a,b,c){var d,e,f={};for(e in b)f[e]=a.style[e],a.style[e]=b[e];d=c.call(a);for(e in b)a.style[e]=f[e];return d}}),a.getComputedStyle?bH=function(b,c){var d,e,f,g,h=a.getComputedStyle(b,null),i=b.style;return h&&(d=h[c],d===""&&!p.contains(b.ownerDocument,b)&&(d=p.style(b,c)),bQ.test(d)&&bO.test(c)&&(e=i.width,f=i.minWidth,g=i.maxWidth,i.minWidth=i.maxWidth=i.width=d,d=h.width,i.width=e,i.minWidth=f,i.maxWidth=g)),d}:e.documentElement.currentStyle&&(bH=function(a,b){var c,d,e=a.currentStyle&&a.currentStyle[b],f=a.style;return e==null&&f&&f[b]&&(e=f[b]),bQ.test(e)&&!bM.test(b)&&(c=f.left,d=a.runtimeStyle&&a.runtimeStyle.left,d&&(a.runtimeStyle.left=a.currentStyle.left),f.left=b==="fontSize"?"1em":e,e=f.pixelLeft+"px",f.left=c,d&&(a.runtimeStyle.left=d)),e===""?"auto":e}),p.each(["height","width"],function(a,b){p.cssHooks[b]={get:function(a,c,d){if(c)return a.offsetWidth===0&&bN.test(bH(a,"display"))?p.swap(a,bT,function(){return cb(a,b,d)}):cb(a,b,d)},set:function(a,c,d){return b_(a,c,d?ca(a,b,d,p.support.boxSizing&&p.css(a,"boxSizing")==="border-box"):0)}}}),p.support.opacity||(p.cssHooks.opacity={get:function(a,b){return bL.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?.01*parseFloat(RegExp.$1)+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle,e=p.isNumeric(b)?"alpha(opacity="+b*100+")":"",f=d&&d.filter||c.filter||"";c.zoom=1;if(b>=1&&p.trim(f.replace(bK,""))===""&&c.removeAttribute){c.removeAttribute("filter");if(d&&!d.filter)return}c.filter=bK.test(f)?f.replace(bK,e):f+" "+e}}),p(function(){p.support.reliableMarginRight||(p.cssHooks.marginRight={get:function(a,b){return p.swap(a,{display:"inline-block"},function(){if(b)return bH(a,"marginRight")})}}),!p.support.pixelPosition&&p.fn.position&&p.each(["top","left"],function(a,b){p.cssHooks[b]={get:function(a,c){if(c){var d=bH(a,b);return bQ.test(d)?p(a).position()[b]+"px":d}}}})}),p.expr&&p.expr.filters&&(p.expr.filters.hidden=function(a){return a.offsetWidth===0&&a.offsetHeight===0||!p.support.reliableHiddenOffsets&&(a.style&&a.style.display||bH(a,"display"))==="none"},p.expr.filters.visible=function(a){return!p.expr.filters.hidden(a)}),p.each({margin:"",padding:"",border:"Width"},function(a,b){p.cssHooks[a+b]={expand:function(c){var d,e=typeof c=="string"?c.split(" "):[c],f={};for(d=0;d<4;d++)f[a+bV[d]+b]=e[d]||e[d-2]||e[0];return f}},bO.test(a)||(p.cssHooks[a+b].set=b_)});var cd=/%20/g,ce=/\[\]$/,cf=/\r?\n/g,cg=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,ch=/^(?:select|textarea)/i;p.fn.extend({serialize:function(){return p.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?p.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||ch.test(this.nodeName)||cg.test(this.type))}).map(function(a,b){var c=p(this).val();return c==null?null:p.isArray(c)?p.map(c,function(a,c){return{name:b.name,value:a.replace(cf,"\r\n")}}):{name:b.name,value:c.replace(cf,"\r\n")}}).get()}}),p.param=function(a,c){var d,e=[],f=function(a,b){b=p.isFunction(b)?b():b==null?"":b,e[e.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};c===b&&(c=p.ajaxSettings&&p.ajaxSettings.traditional);if(p.isArray(a)||a.jquery&&!p.isPlainObject(a))p.each(a,function(){f(this.name,this.value)});else for(d in a)ci(d,a[d],c,f);return e.join("&").replace(cd,"+")};var cj,ck,cl=/#.*$/,cm=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,cn=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,co=/^(?:GET|HEAD)$/,cp=/^\/\//,cq=/\?/,cr=/)<[^<]*)*<\/script>/gi,cs=/([?&])_=[^&]*/,ct=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,cu=p.fn.load,cv={},cw={},cx=["*/"]+["*"];try{ck=f.href}catch(cy){ck=e.createElement("a"),ck.href="",ck=ck.href}cj=ct.exec(ck.toLowerCase())||[],p.fn.load=function(a,c,d){if(typeof a!="string"&&cu)return cu.apply(this,arguments);if(!this.length)return this;var e,f,g,h=this,i=a.indexOf(" ");return i>=0&&(e=a.slice(i,a.length),a=a.slice(0,i)),p.isFunction(c)?(d=c,c=b):c&&typeof c=="object"&&(f="POST"),p.ajax({url:a,type:f,dataType:"html",data:c,complete:function(a,b){d&&h.each(d,g||[a.responseText,b,a])}}).done(function(a){g=arguments,h.html(e?p("
").append(a.replace(cr,"")).find(e):a)}),this},p.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){p.fn[b]=function(a){return this.on(b,a)}}),p.each(["get","post"],function(a,c){p[c]=function(a,d,e,f){return p.isFunction(d)&&(f=f||e,e=d,d=b),p.ajax({type:c,url:a,data:d,success:e,dataType:f})}}),p.extend({getScript:function(a,c){return p.get(a,b,c,"script")},getJSON:function(a,b,c){return p.get(a,b,c,"json")},ajaxSetup:function(a,b){return b?cB(a,p.ajaxSettings):(b=a,a=p.ajaxSettings),cB(a,b),a},ajaxSettings:{url:ck,isLocal:cn.test(cj[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded; charset=UTF-8",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":cx},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":a.String,"text html":!0,"text json":p.parseJSON,"text xml":p.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:cz(cv),ajaxTransport:cz(cw),ajax:function(a,c){function y(a,c,f,i){var k,s,t,u,w,y=c;if(v===2)return;v=2,h&&clearTimeout(h),g=b,e=i||"",x.readyState=a>0?4:0,f&&(u=cC(l,x,f));if(a>=200&&a<300||a===304)l.ifModified&&(w=x.getResponseHeader("Last-Modified"),w&&(p.lastModified[d]=w),w=x.getResponseHeader("Etag"),w&&(p.etag[d]=w)),a===304?(y="notmodified",k=!0):(k=cD(l,u),y=k.state,s=k.data,t=k.error,k=!t);else{t=y;if(!y||a)y="error",a<0&&(a=0)}x.status=a,x.statusText=(c||y)+"",k?o.resolveWith(m,[s,y,x]):o.rejectWith(m,[x,y,t]),x.statusCode(r),r=b,j&&n.trigger("ajax"+(k?"Success":"Error"),[x,l,k?s:t]),q.fireWith(m,[x,y]),j&&(n.trigger("ajaxComplete",[x,l]),--p.active||p.event.trigger("ajaxStop"))}typeof a=="object"&&(c=a,a=b),c=c||{};var d,e,f,g,h,i,j,k,l=p.ajaxSetup({},c),m=l.context||l,n=m!==l&&(m.nodeType||m instanceof p)?p(m):p.event,o=p.Deferred(),q=p.Callbacks("once memory"),r=l.statusCode||{},t={},u={},v=0,w="canceled",x={readyState:0,setRequestHeader:function(a,b){if(!v){var c=a.toLowerCase();a=u[c]=u[c]||a,t[a]=b}return this},getAllResponseHeaders:function(){return v===2?e:null},getResponseHeader:function(a){var c;if(v===2){if(!f){f={};while(c=cm.exec(e))f[c[1].toLowerCase()]=c[2]}c=f[a.toLowerCase()]}return c===b?null:c},overrideMimeType:function(a){return v||(l.mimeType=a),this},abort:function(a){return a=a||w,g&&g.abort(a),y(0,a),this}};o.promise(x),x.success=x.done,x.error=x.fail,x.complete=q.add,x.statusCode=function(a){if(a){var b;if(v<2)for(b in a)r[b]=[r[b],a[b]];else b=a[x.status],x.always(b)}return this},l.url=((a||l.url)+"").replace(cl,"").replace(cp,cj[1]+"//"),l.dataTypes=p.trim(l.dataType||"*").toLowerCase().split(s),l.crossDomain==null&&(i=ct.exec(l.url.toLowerCase())||!1,l.crossDomain=i&&i.join(":")+(i[3]?"":i[1]==="http:"?80:443)!==cj.join(":")+(cj[3]?"":cj[1]==="http:"?80:443)),l.data&&l.processData&&typeof l.data!="string"&&(l.data=p.param(l.data,l.traditional)),cA(cv,l,c,x);if(v===2)return x;j=l.global,l.type=l.type.toUpperCase(),l.hasContent=!co.test(l.type),j&&p.active++===0&&p.event.trigger("ajaxStart");if(!l.hasContent){l.data&&(l.url+=(cq.test(l.url)?"&":"?")+l.data,delete l.data),d=l.url;if(l.cache===!1){var z=p.now(),A=l.url.replace(cs,"$1_="+z);l.url=A+(A===l.url?(cq.test(l.url)?"&":"?")+"_="+z:"")}}(l.data&&l.hasContent&&l.contentType!==!1||c.contentType)&&x.setRequestHeader("Content-Type",l.contentType),l.ifModified&&(d=d||l.url,p.lastModified[d]&&x.setRequestHeader("If-Modified-Since",p.lastModified[d]),p.etag[d]&&x.setRequestHeader("If-None-Match",p.etag[d])),x.setRequestHeader("Accept",l.dataTypes[0]&&l.accepts[l.dataTypes[0]]?l.accepts[l.dataTypes[0]]+(l.dataTypes[0]!=="*"?", "+cx+"; q=0.01":""):l.accepts["*"]);for(k in l.headers)x.setRequestHeader(k,l.headers[k]);if(!l.beforeSend||l.beforeSend.call(m,x,l)!==!1&&v!==2){w="abort";for(k in{success:1,error:1,complete:1})x[k](l[k]);g=cA(cw,l,c,x);if(!g)y(-1,"No Transport");else{x.readyState=1,j&&n.trigger("ajaxSend",[x,l]),l.async&&l.timeout>0&&(h=setTimeout(function(){x.abort("timeout")},l.timeout));try{v=1,g.send(t,y)}catch(B){if(v<2)y(-1,B);else throw B}}return x}return x.abort()},active:0,lastModified:{},etag:{}});var cE=[],cF=/\?/,cG=/(=)\?(?=&|$)|\?\?/,cH=p.now();p.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var a=cE.pop()||p.expando+"_"+cH++;return this[a]=!0,a}}),p.ajaxPrefilter("json jsonp",function(c,d,e){var f,g,h,i=c.data,j=c.url,k=c.jsonp!==!1,l=k&&cG.test(j),m=k&&!l&&typeof i=="string"&&!(c.contentType||"").indexOf("application/x-www-form-urlencoded")&&cG.test(i);if(c.dataTypes[0]==="jsonp"||l||m)return f=c.jsonpCallback=p.isFunction(c.jsonpCallback)?c.jsonpCallback():c.jsonpCallback,g=a[f],l?c.url=j.replace(cG,"$1"+f):m?c.data=i.replace(cG,"$1"+f):k&&(c.url+=(cF.test(j)?"&":"?")+c.jsonp+"="+f),c.converters["script json"]=function(){return h||p.error(f+" was not called"),h[0]},c.dataTypes[0]="json",a[f]=function(){h=arguments},e.always(function(){a[f]=g,c[f]&&(c.jsonpCallback=d.jsonpCallback,cE.push(f)),h&&p.isFunction(g)&&g(h[0]),h=g=b}),"script"}),p.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(a){return p.globalEval(a),a}}}),p.ajaxPrefilter("script",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),p.ajaxTransport("script",function(a){if(a.crossDomain){var c,d=e.head||e.getElementsByTagName("head")[0]||e.documentElement;return{send:function(f,g){c=e.createElement("script"),c.async="async",a.scriptCharset&&(c.charset=a.scriptCharset),c.src=a.url,c.onload=c.onreadystatechange=function(a,e){if(e||!c.readyState||/loaded|complete/.test(c.readyState))c.onload=c.onreadystatechange=null,d&&c.parentNode&&d.removeChild(c),c=b,e||g(200,"success")},d.insertBefore(c,d.firstChild)},abort:function(){c&&c.onload(0,1)}}}});var cI,cJ=a.ActiveXObject?function(){for(var a in cI)cI[a](0,1)}:!1,cK=0;p.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&cL()||cM()}:cL,function(a){p.extend(p.support,{ajax:!!a,cors:!!a&&"withCredentials"in a})}(p.ajaxSettings.xhr()),p.support.ajax&&p.ajaxTransport(function(c){if(!c.crossDomain||p.support.cors){var d;return{send:function(e,f){var g,h,i=c.xhr();c.username?i.open(c.type,c.url,c.async,c.username,c.password):i.open(c.type,c.url,c.async);if(c.xhrFields)for(h in c.xhrFields)i[h]=c.xhrFields[h];c.mimeType&&i.overrideMimeType&&i.overrideMimeType(c.mimeType),!c.crossDomain&&!e["X-Requested-With"]&&(e["X-Requested-With"]="XMLHttpRequest");try{for(h in e)i.setRequestHeader(h,e[h])}catch(j){}i.send(c.hasContent&&c.data||null),d=function(a,e){var h,j,k,l,m;try{if(d&&(e||i.readyState===4)){d=b,g&&(i.onreadystatechange=p.noop,cJ&&delete cI[g]);if(e)i.readyState!==4&&i.abort();else{h=i.status,k=i.getAllResponseHeaders(),l={},m=i.responseXML,m&&m.documentElement&&(l.xml=m);try{l.text=i.responseText}catch(a){}try{j=i.statusText}catch(n){j=""}!h&&c.isLocal&&!c.crossDomain?h=l.text?200:404:h===1223&&(h=204)}}}catch(o){e||f(-1,o)}l&&f(h,j,l,k)},c.async?i.readyState===4?setTimeout(d,0):(g=++cK,cJ&&(cI||(cI={},p(a).unload(cJ)),cI[g]=d),i.onreadystatechange=d):d()},abort:function(){d&&d(0,1)}}}});var cN,cO,cP=/^(?:toggle|show|hide)$/,cQ=new RegExp("^(?:([-+])=|)("+q+")([a-z%]*)$","i"),cR=/queueHooks$/,cS=[cY],cT={"*":[function(a,b){var c,d,e=this.createTween(a,b),f=cQ.exec(b),g=e.cur(),h=+g||0,i=1,j=20;if(f){c=+f[2],d=f[3]||(p.cssNumber[a]?"":"px");if(d!=="px"&&h){h=p.css(e.elem,a,!0)||c||1;do i=i||".5",h=h/i,p.style(e.elem,a,h+d);while(i!==(i=e.cur()/g)&&i!==1&&--j)}e.unit=d,e.start=h,e.end=f[1]?h+(f[1]+1)*c:c}return e}]};p.Animation=p.extend(cW,{tweener:function(a,b){p.isFunction(a)?(b=a,a=["*"]):a=a.split(" ");var c,d=0,e=a.length;for(;d-1,j={},k={},l,m;i?(k=e.position(),l=k.top,m=k.left):(l=parseFloat(g)||0,m=parseFloat(h)||0),p.isFunction(b)&&(b=b.call(a,c,f)),b.top!=null&&(j.top=b.top-f.top+l),b.left!=null&&(j.left=b.left-f.left+m),"using"in b?b.using.call(a,j):e.css(j)}},p.fn.extend({position:function(){if(!this[0])return;var a=this[0],b=this.offsetParent(),c=this.offset(),d=c_.test(b[0].nodeName)?{top:0,left:0}:b.offset();return c.top-=parseFloat(p.css(a,"marginTop"))||0,c.left-=parseFloat(p.css(a,"marginLeft"))||0,d.top+=parseFloat(p.css(b[0],"borderTopWidth"))||0,d.left+=parseFloat(p.css(b[0],"borderLeftWidth"))||0,{top:c.top-d.top,left:c.left-d.left}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||e.body;while(a&&!c_.test(a.nodeName)&&p.css(a,"position")==="static")a=a.offsetParent;return a||e.body})}}),p.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(a,c){var d=/Y/.test(c);p.fn[a]=function(e){return p.access(this,function(a,e,f){var g=da(a);if(f===b)return g?c in g?g[c]:g.document.documentElement[e]:a[e];g?g.scrollTo(d?p(g).scrollLeft():f,d?f:p(g).scrollTop()):a[e]=f},a,e,arguments.length,null)}}),p.each({Height:"height",Width:"width"},function(a,c){p.each({padding:"inner"+a,content:c,"":"outer"+a},function(d,e){p.fn[e]=function(e,f){var g=arguments.length&&(d||typeof e!="boolean"),h=d||(e===!0||f===!0?"margin":"border");return p.access(this,function(c,d,e){var f;return p.isWindow(c)?c.document.documentElement["client"+a]:c.nodeType===9?(f=c.documentElement,Math.max(c.body["scroll"+a],f["scroll"+a],c.body["offset"+a],f["offset"+a],f["client"+a])):e===b?p.css(c,d,e,h):p.style(c,d,e,h)},c,g?e:b,g,null)}})}),a.jQuery=a.$=p,typeof define=="function"&&define.amd&&define.amd.jQuery&&define("jquery",[],function(){return p})})(window); \ No newline at end of file +/*! jQuery v1.8.3 jquery.com | jquery.org/license */ +(function(e,t){function _(e){var t=M[e]={};return v.each(e.split(y),function(e,n){t[n]=!0}),t}function H(e,n,r){if(r===t&&e.nodeType===1){var i="data-"+n.replace(P,"-$1").toLowerCase();r=e.getAttribute(i);if(typeof r=="string"){try{r=r==="true"?!0:r==="false"?!1:r==="null"?null:+r+""===r?+r:D.test(r)?v.parseJSON(r):r}catch(s){}v.data(e,n,r)}else r=t}return r}function B(e){var t;for(t in e){if(t==="data"&&v.isEmptyObject(e[t]))continue;if(t!=="toJSON")return!1}return!0}function et(){return!1}function tt(){return!0}function ut(e){return!e||!e.parentNode||e.parentNode.nodeType===11}function at(e,t){do e=e[t];while(e&&e.nodeType!==1);return e}function ft(e,t,n){t=t||0;if(v.isFunction(t))return v.grep(e,function(e,r){var i=!!t.call(e,r,e);return i===n});if(t.nodeType)return v.grep(e,function(e,r){return e===t===n});if(typeof t=="string"){var r=v.grep(e,function(e){return e.nodeType===1});if(it.test(t))return v.filter(t,r,!n);t=v.filter(t,r)}return v.grep(e,function(e,r){return v.inArray(e,t)>=0===n})}function lt(e){var t=ct.split("|"),n=e.createDocumentFragment();if(n.createElement)while(t.length)n.createElement(t.pop());return n}function Lt(e,t){return e.getElementsByTagName(t)[0]||e.appendChild(e.ownerDocument.createElement(t))}function At(e,t){if(t.nodeType!==1||!v.hasData(e))return;var n,r,i,s=v._data(e),o=v._data(t,s),u=s.events;if(u){delete o.handle,o.events={};for(n in u)for(r=0,i=u[n].length;r").appendTo(i.body),n=t.css("display");t.remove();if(n==="none"||n===""){Pt=i.body.appendChild(Pt||v.extend(i.createElement("iframe"),{frameBorder:0,width:0,height:0}));if(!Ht||!Pt.createElement)Ht=(Pt.contentWindow||Pt.contentDocument).document,Ht.write(""),Ht.close();t=Ht.body.appendChild(Ht.createElement(e)),n=Dt(t,"display"),i.body.removeChild(Pt)}return Wt[e]=n,n}function fn(e,t,n,r){var i;if(v.isArray(t))v.each(t,function(t,i){n||sn.test(e)?r(e,i):fn(e+"["+(typeof i=="object"?t:"")+"]",i,n,r)});else if(!n&&v.type(t)==="object")for(i in t)fn(e+"["+i+"]",t[i],n,r);else r(e,t)}function Cn(e){return function(t,n){typeof t!="string"&&(n=t,t="*");var r,i,s,o=t.toLowerCase().split(y),u=0,a=o.length;if(v.isFunction(n))for(;u)[^>]*$|#([\w\-]*)$)/,E=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,S=/^[\],:{}\s]*$/,x=/(?:^|:|,)(?:\s*\[)+/g,T=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,N=/"[^"\\\r\n]*"|true|false|null|-?(?:\d\d*\.|)\d+(?:[eE][\-+]?\d+|)/g,C=/^-ms-/,k=/-([\da-z])/gi,L=function(e,t){return(t+"").toUpperCase()},A=function(){i.addEventListener?(i.removeEventListener("DOMContentLoaded",A,!1),v.ready()):i.readyState==="complete"&&(i.detachEvent("onreadystatechange",A),v.ready())},O={};v.fn=v.prototype={constructor:v,init:function(e,n,r){var s,o,u,a;if(!e)return this;if(e.nodeType)return this.context=this[0]=e,this.length=1,this;if(typeof e=="string"){e.charAt(0)==="<"&&e.charAt(e.length-1)===">"&&e.length>=3?s=[null,e,null]:s=w.exec(e);if(s&&(s[1]||!n)){if(s[1])return n=n instanceof v?n[0]:n,a=n&&n.nodeType?n.ownerDocument||n:i,e=v.parseHTML(s[1],a,!0),E.test(s[1])&&v.isPlainObject(n)&&this.attr.call(e,n,!0),v.merge(this,e);o=i.getElementById(s[2]);if(o&&o.parentNode){if(o.id!==s[2])return r.find(e);this.length=1,this[0]=o}return this.context=i,this.selector=e,this}return!n||n.jquery?(n||r).find(e):this.constructor(n).find(e)}return v.isFunction(e)?r.ready(e):(e.selector!==t&&(this.selector=e.selector,this.context=e.context),v.makeArray(e,this))},selector:"",jquery:"1.8.3",length:0,size:function(){return this.length},toArray:function(){return l.call(this)},get:function(e){return e==null?this.toArray():e<0?this[this.length+e]:this[e]},pushStack:function(e,t,n){var r=v.merge(this.constructor(),e);return r.prevObject=this,r.context=this.context,t==="find"?r.selector=this.selector+(this.selector?" ":"")+n:t&&(r.selector=this.selector+"."+t+"("+n+")"),r},each:function(e,t){return v.each(this,e,t)},ready:function(e){return v.ready.promise().done(e),this},eq:function(e){return e=+e,e===-1?this.slice(e):this.slice(e,e+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(l.apply(this,arguments),"slice",l.call(arguments).join(","))},map:function(e){return this.pushStack(v.map(this,function(t,n){return e.call(t,n,t)}))},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:[].sort,splice:[].splice},v.fn.init.prototype=v.fn,v.extend=v.fn.extend=function(){var e,n,r,i,s,o,u=arguments[0]||{},a=1,f=arguments.length,l=!1;typeof u=="boolean"&&(l=u,u=arguments[1]||{},a=2),typeof u!="object"&&!v.isFunction(u)&&(u={}),f===a&&(u=this,--a);for(;a0)return;r.resolveWith(i,[v]),v.fn.trigger&&v(i).trigger("ready").off("ready")},isFunction:function(e){return v.type(e)==="function"},isArray:Array.isArray||function(e){return v.type(e)==="array"},isWindow:function(e){return e!=null&&e==e.window},isNumeric:function(e){return!isNaN(parseFloat(e))&&isFinite(e)},type:function(e){return e==null?String(e):O[h.call(e)]||"object"},isPlainObject:function(e){if(!e||v.type(e)!=="object"||e.nodeType||v.isWindow(e))return!1;try{if(e.constructor&&!p.call(e,"constructor")&&!p.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(n){return!1}var r;for(r in e);return r===t||p.call(e,r)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},error:function(e){throw new Error(e)},parseHTML:function(e,t,n){var r;return!e||typeof e!="string"?null:(typeof t=="boolean"&&(n=t,t=0),t=t||i,(r=E.exec(e))?[t.createElement(r[1])]:(r=v.buildFragment([e],t,n?null:[]),v.merge([],(r.cacheable?v.clone(r.fragment):r.fragment).childNodes)))},parseJSON:function(t){if(!t||typeof t!="string")return null;t=v.trim(t);if(e.JSON&&e.JSON.parse)return e.JSON.parse(t);if(S.test(t.replace(T,"@").replace(N,"]").replace(x,"")))return(new Function("return "+t))();v.error("Invalid JSON: "+t)},parseXML:function(n){var r,i;if(!n||typeof n!="string")return null;try{e.DOMParser?(i=new DOMParser,r=i.parseFromString(n,"text/xml")):(r=new ActiveXObject("Microsoft.XMLDOM"),r.async="false",r.loadXML(n))}catch(s){r=t}return(!r||!r.documentElement||r.getElementsByTagName("parsererror").length)&&v.error("Invalid XML: "+n),r},noop:function(){},globalEval:function(t){t&&g.test(t)&&(e.execScript||function(t){e.eval.call(e,t)})(t)},camelCase:function(e){return e.replace(C,"ms-").replace(k,L)},nodeName:function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()},each:function(e,n,r){var i,s=0,o=e.length,u=o===t||v.isFunction(e);if(r){if(u){for(i in e)if(n.apply(e[i],r)===!1)break}else for(;s0&&e[0]&&e[a-1]||a===0||v.isArray(e));if(f)for(;u-1)a.splice(n,1),i&&(n<=o&&o--,n<=u&&u--)}),this},has:function(e){return v.inArray(e,a)>-1},empty:function(){return a=[],this},disable:function(){return a=f=n=t,this},disabled:function(){return!a},lock:function(){return f=t,n||c.disable(),this},locked:function(){return!f},fireWith:function(e,t){return t=t||[],t=[e,t.slice?t.slice():t],a&&(!r||f)&&(i?f.push(t):l(t)),this},fire:function(){return c.fireWith(this,arguments),this},fired:function(){return!!r}};return c},v.extend({Deferred:function(e){var t=[["resolve","done",v.Callbacks("once memory"),"resolved"],["reject","fail",v.Callbacks("once memory"),"rejected"],["notify","progress",v.Callbacks("memory")]],n="pending",r={state:function(){return n},always:function(){return i.done(arguments).fail(arguments),this},then:function(){var e=arguments;return v.Deferred(function(n){v.each(t,function(t,r){var s=r[0],o=e[t];i[r[1]](v.isFunction(o)?function(){var e=o.apply(this,arguments);e&&v.isFunction(e.promise)?e.promise().done(n.resolve).fail(n.reject).progress(n.notify):n[s+"With"](this===i?n:this,[e])}:n[s])}),e=null}).promise()},promise:function(e){return e!=null?v.extend(e,r):r}},i={};return r.pipe=r.then,v.each(t,function(e,s){var o=s[2],u=s[3];r[s[1]]=o.add,u&&o.add(function(){n=u},t[e^1][2].disable,t[2][2].lock),i[s[0]]=o.fire,i[s[0]+"With"]=o.fireWith}),r.promise(i),e&&e.call(i,i),i},when:function(e){var t=0,n=l.call(arguments),r=n.length,i=r!==1||e&&v.isFunction(e.promise)?r:0,s=i===1?e:v.Deferred(),o=function(e,t,n){return function(r){t[e]=this,n[e]=arguments.length>1?l.call(arguments):r,n===u?s.notifyWith(t,n):--i||s.resolveWith(t,n)}},u,a,f;if(r>1){u=new Array(r),a=new Array(r),f=new Array(r);for(;t
a",n=p.getElementsByTagName("*"),r=p.getElementsByTagName("a")[0];if(!n||!r||!n.length)return{};s=i.createElement("select"),o=s.appendChild(i.createElement("option")),u=p.getElementsByTagName("input")[0],r.style.cssText="top:1px;float:left;opacity:.5",t={leadingWhitespace:p.firstChild.nodeType===3,tbody:!p.getElementsByTagName("tbody").length,htmlSerialize:!!p.getElementsByTagName("link").length,style:/top/.test(r.getAttribute("style")),hrefNormalized:r.getAttribute("href")==="/a",opacity:/^0.5/.test(r.style.opacity),cssFloat:!!r.style.cssFloat,checkOn:u.value==="on",optSelected:o.selected,getSetAttribute:p.className!=="t",enctype:!!i.createElement("form").enctype,html5Clone:i.createElement("nav").cloneNode(!0).outerHTML!=="<:nav>",boxModel:i.compatMode==="CSS1Compat",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0,boxSizingReliable:!0,pixelPosition:!1},u.checked=!0,t.noCloneChecked=u.cloneNode(!0).checked,s.disabled=!0,t.optDisabled=!o.disabled;try{delete p.test}catch(d){t.deleteExpando=!1}!p.addEventListener&&p.attachEvent&&p.fireEvent&&(p.attachEvent("onclick",h=function(){t.noCloneEvent=!1}),p.cloneNode(!0).fireEvent("onclick"),p.detachEvent("onclick",h)),u=i.createElement("input"),u.value="t",u.setAttribute("type","radio"),t.radioValue=u.value==="t",u.setAttribute("checked","checked"),u.setAttribute("name","t"),p.appendChild(u),a=i.createDocumentFragment(),a.appendChild(p.lastChild),t.checkClone=a.cloneNode(!0).cloneNode(!0).lastChild.checked,t.appendChecked=u.checked,a.removeChild(u),a.appendChild(p);if(p.attachEvent)for(l in{submit:!0,change:!0,focusin:!0})f="on"+l,c=f in p,c||(p.setAttribute(f,"return;"),c=typeof p[f]=="function"),t[l+"Bubbles"]=c;return v(function(){var n,r,s,o,u="padding:0;margin:0;border:0;display:block;overflow:hidden;",a=i.getElementsByTagName("body")[0];if(!a)return;n=i.createElement("div"),n.style.cssText="visibility:hidden;border:0;width:0;height:0;position:static;top:0;margin-top:1px",a.insertBefore(n,a.firstChild),r=i.createElement("div"),n.appendChild(r),r.innerHTML="
t
",s=r.getElementsByTagName("td"),s[0].style.cssText="padding:0;margin:0;border:0;display:none",c=s[0].offsetHeight===0,s[0].style.display="",s[1].style.display="none",t.reliableHiddenOffsets=c&&s[0].offsetHeight===0,r.innerHTML="",r.style.cssText="box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;",t.boxSizing=r.offsetWidth===4,t.doesNotIncludeMarginInBodyOffset=a.offsetTop!==1,e.getComputedStyle&&(t.pixelPosition=(e.getComputedStyle(r,null)||{}).top!=="1%",t.boxSizingReliable=(e.getComputedStyle(r,null)||{width:"4px"}).width==="4px",o=i.createElement("div"),o.style.cssText=r.style.cssText=u,o.style.marginRight=o.style.width="0",r.style.width="1px",r.appendChild(o),t.reliableMarginRight=!parseFloat((e.getComputedStyle(o,null)||{}).marginRight)),typeof r.style.zoom!="undefined"&&(r.innerHTML="",r.style.cssText=u+"width:1px;padding:1px;display:inline;zoom:1",t.inlineBlockNeedsLayout=r.offsetWidth===3,r.style.display="block",r.style.overflow="visible",r.innerHTML="
",r.firstChild.style.width="5px",t.shrinkWrapBlocks=r.offsetWidth!==3,n.style.zoom=1),a.removeChild(n),n=r=s=o=null}),a.removeChild(p),n=r=s=o=u=a=p=null,t}();var D=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,P=/([A-Z])/g;v.extend({cache:{},deletedIds:[],uuid:0,expando:"jQuery"+(v.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(e){return e=e.nodeType?v.cache[e[v.expando]]:e[v.expando],!!e&&!B(e)},data:function(e,n,r,i){if(!v.acceptData(e))return;var s,o,u=v.expando,a=typeof n=="string",f=e.nodeType,l=f?v.cache:e,c=f?e[u]:e[u]&&u;if((!c||!l[c]||!i&&!l[c].data)&&a&&r===t)return;c||(f?e[u]=c=v.deletedIds.pop()||v.guid++:c=u),l[c]||(l[c]={},f||(l[c].toJSON=v.noop));if(typeof n=="object"||typeof n=="function")i?l[c]=v.extend(l[c],n):l[c].data=v.extend(l[c].data,n);return s=l[c],i||(s.data||(s.data={}),s=s.data),r!==t&&(s[v.camelCase(n)]=r),a?(o=s[n],o==null&&(o=s[v.camelCase(n)])):o=s,o},removeData:function(e,t,n){if(!v.acceptData(e))return;var r,i,s,o=e.nodeType,u=o?v.cache:e,a=o?e[v.expando]:v.expando;if(!u[a])return;if(t){r=n?u[a]:u[a].data;if(r){v.isArray(t)||(t in r?t=[t]:(t=v.camelCase(t),t in r?t=[t]:t=t.split(" ")));for(i=0,s=t.length;i1,null,!1))},removeData:function(e){return this.each(function(){v.removeData(this,e)})}}),v.extend({queue:function(e,t,n){var r;if(e)return t=(t||"fx")+"queue",r=v._data(e,t),n&&(!r||v.isArray(n)?r=v._data(e,t,v.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||"fx";var n=v.queue(e,t),r=n.length,i=n.shift(),s=v._queueHooks(e,t),o=function(){v.dequeue(e,t)};i==="inprogress"&&(i=n.shift(),r--),i&&(t==="fx"&&n.unshift("inprogress"),delete s.stop,i.call(e,o,s)),!r&&s&&s.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return v._data(e,n)||v._data(e,n,{empty:v.Callbacks("once memory").add(function(){v.removeData(e,t+"queue",!0),v.removeData(e,n,!0)})})}}),v.fn.extend({queue:function(e,n){var r=2;return typeof e!="string"&&(n=e,e="fx",r--),arguments.length1)},removeAttr:function(e){return this.each(function(){v.removeAttr(this,e)})},prop:function(e,t){return v.access(this,v.prop,e,t,arguments.length>1)},removeProp:function(e){return e=v.propFix[e]||e,this.each(function(){try{this[e]=t,delete this[e]}catch(n){}})},addClass:function(e){var t,n,r,i,s,o,u;if(v.isFunction(e))return this.each(function(t){v(this).addClass(e.call(this,t,this.className))});if(e&&typeof e=="string"){t=e.split(y);for(n=0,r=this.length;n=0)r=r.replace(" "+n[s]+" "," ");i.className=e?v.trim(r):""}}}return this},toggleClass:function(e,t){var n=typeof e,r=typeof t=="boolean";return v.isFunction(e)?this.each(function(n){v(this).toggleClass(e.call(this,n,this.className,t),t)}):this.each(function(){if(n==="string"){var i,s=0,o=v(this),u=t,a=e.split(y);while(i=a[s++])u=r?u:!o.hasClass(i),o[u?"addClass":"removeClass"](i)}else if(n==="undefined"||n==="boolean")this.className&&v._data(this,"__className__",this.className),this.className=this.className||e===!1?"":v._data(this,"__className__")||""})},hasClass:function(e){var t=" "+e+" ",n=0,r=this.length;for(;n=0)return!0;return!1},val:function(e){var n,r,i,s=this[0];if(!arguments.length){if(s)return n=v.valHooks[s.type]||v.valHooks[s.nodeName.toLowerCase()],n&&"get"in n&&(r=n.get(s,"value"))!==t?r:(r=s.value,typeof r=="string"?r.replace(R,""):r==null?"":r);return}return i=v.isFunction(e),this.each(function(r){var s,o=v(this);if(this.nodeType!==1)return;i?s=e.call(this,r,o.val()):s=e,s==null?s="":typeof s=="number"?s+="":v.isArray(s)&&(s=v.map(s,function(e){return e==null?"":e+""})),n=v.valHooks[this.type]||v.valHooks[this.nodeName.toLowerCase()];if(!n||!("set"in n)||n.set(this,s,"value")===t)this.value=s})}}),v.extend({valHooks:{option:{get:function(e){var t=e.attributes.value;return!t||t.specified?e.value:e.text}},select:{get:function(e){var t,n,r=e.options,i=e.selectedIndex,s=e.type==="select-one"||i<0,o=s?null:[],u=s?i+1:r.length,a=i<0?u:s?i:0;for(;a=0}),n.length||(e.selectedIndex=-1),n}}},attrFn:{},attr:function(e,n,r,i){var s,o,u,a=e.nodeType;if(!e||a===3||a===8||a===2)return;if(i&&v.isFunction(v.fn[n]))return v(e)[n](r);if(typeof e.getAttribute=="undefined")return v.prop(e,n,r);u=a!==1||!v.isXMLDoc(e),u&&(n=n.toLowerCase(),o=v.attrHooks[n]||(X.test(n)?F:j));if(r!==t){if(r===null){v.removeAttr(e,n);return}return o&&"set"in o&&u&&(s=o.set(e,r,n))!==t?s:(e.setAttribute(n,r+""),r)}return o&&"get"in o&&u&&(s=o.get(e,n))!==null?s:(s=e.getAttribute(n),s===null?t:s)},removeAttr:function(e,t){var n,r,i,s,o=0;if(t&&e.nodeType===1){r=t.split(y);for(;o=0}})});var $=/^(?:textarea|input|select)$/i,J=/^([^\.]*|)(?:\.(.+)|)$/,K=/(?:^|\s)hover(\.\S+|)\b/,Q=/^key/,G=/^(?:mouse|contextmenu)|click/,Y=/^(?:focusinfocus|focusoutblur)$/,Z=function(e){return v.event.special.hover?e:e.replace(K,"mouseenter$1 mouseleave$1")};v.event={add:function(e,n,r,i,s){var o,u,a,f,l,c,h,p,d,m,g;if(e.nodeType===3||e.nodeType===8||!n||!r||!(o=v._data(e)))return;r.handler&&(d=r,r=d.handler,s=d.selector),r.guid||(r.guid=v.guid++),a=o.events,a||(o.events=a={}),u=o.handle,u||(o.handle=u=function(e){return typeof v=="undefined"||!!e&&v.event.triggered===e.type?t:v.event.dispatch.apply(u.elem,arguments)},u.elem=e),n=v.trim(Z(n)).split(" ");for(f=0;f=0&&(y=y.slice(0,-1),a=!0),y.indexOf(".")>=0&&(b=y.split("."),y=b.shift(),b.sort());if((!s||v.event.customEvent[y])&&!v.event.global[y])return;n=typeof n=="object"?n[v.expando]?n:new v.Event(y,n):new v.Event(y),n.type=y,n.isTrigger=!0,n.exclusive=a,n.namespace=b.join("."),n.namespace_re=n.namespace?new RegExp("(^|\\.)"+b.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,h=y.indexOf(":")<0?"on"+y:"";if(!s){u=v.cache;for(f in u)u[f].events&&u[f].events[y]&&v.event.trigger(n,r,u[f].handle.elem,!0);return}n.result=t,n.target||(n.target=s),r=r!=null?v.makeArray(r):[],r.unshift(n),p=v.event.special[y]||{};if(p.trigger&&p.trigger.apply(s,r)===!1)return;m=[[s,p.bindType||y]];if(!o&&!p.noBubble&&!v.isWindow(s)){g=p.delegateType||y,l=Y.test(g+y)?s:s.parentNode;for(c=s;l;l=l.parentNode)m.push([l,g]),c=l;c===(s.ownerDocument||i)&&m.push([c.defaultView||c.parentWindow||e,g])}for(f=0;f=0:v.find(h,this,null,[s]).length),u[h]&&f.push(c);f.length&&w.push({elem:s,matches:f})}d.length>m&&w.push({elem:this,matches:d.slice(m)});for(r=0;r0?this.on(t,null,e,n):this.trigger(t)},Q.test(t)&&(v.event.fixHooks[t]=v.event.keyHooks),G.test(t)&&(v.event.fixHooks[t]=v.event.mouseHooks)}),function(e,t){function nt(e,t,n,r){n=n||[],t=t||g;var i,s,a,f,l=t.nodeType;if(!e||typeof e!="string")return n;if(l!==1&&l!==9)return[];a=o(t);if(!a&&!r)if(i=R.exec(e))if(f=i[1]){if(l===9){s=t.getElementById(f);if(!s||!s.parentNode)return n;if(s.id===f)return n.push(s),n}else if(t.ownerDocument&&(s=t.ownerDocument.getElementById(f))&&u(t,s)&&s.id===f)return n.push(s),n}else{if(i[2])return S.apply(n,x.call(t.getElementsByTagName(e),0)),n;if((f=i[3])&&Z&&t.getElementsByClassName)return S.apply(n,x.call(t.getElementsByClassName(f),0)),n}return vt(e.replace(j,"$1"),t,n,r,a)}function rt(e){return function(t){var n=t.nodeName.toLowerCase();return n==="input"&&t.type===e}}function it(e){return function(t){var n=t.nodeName.toLowerCase();return(n==="input"||n==="button")&&t.type===e}}function st(e){return N(function(t){return t=+t,N(function(n,r){var i,s=e([],n.length,t),o=s.length;while(o--)n[i=s[o]]&&(n[i]=!(r[i]=n[i]))})})}function ot(e,t,n){if(e===t)return n;var r=e.nextSibling;while(r){if(r===t)return-1;r=r.nextSibling}return 1}function ut(e,t){var n,r,s,o,u,a,f,l=L[d][e+" "];if(l)return t?0:l.slice(0);u=e,a=[],f=i.preFilter;while(u){if(!n||(r=F.exec(u)))r&&(u=u.slice(r[0].length)||u),a.push(s=[]);n=!1;if(r=I.exec(u))s.push(n=new m(r.shift())),u=u.slice(n.length),n.type=r[0].replace(j," ");for(o in i.filter)(r=J[o].exec(u))&&(!f[o]||(r=f[o](r)))&&(s.push(n=new m(r.shift())),u=u.slice(n.length),n.type=o,n.matches=r);if(!n)break}return t?u.length:u?nt.error(e):L(e,a).slice(0)}function at(e,t,r){var i=t.dir,s=r&&t.dir==="parentNode",o=w++;return t.first?function(t,n,r){while(t=t[i])if(s||t.nodeType===1)return e(t,n,r)}:function(t,r,u){if(!u){var a,f=b+" "+o+" ",l=f+n;while(t=t[i])if(s||t.nodeType===1){if((a=t[d])===l)return t.sizset;if(typeof a=="string"&&a.indexOf(f)===0){if(t.sizset)return t}else{t[d]=l;if(e(t,r,u))return t.sizset=!0,t;t.sizset=!1}}}else while(t=t[i])if(s||t.nodeType===1)if(e(t,r,u))return t}}function ft(e){return e.length>1?function(t,n,r){var i=e.length;while(i--)if(!e[i](t,n,r))return!1;return!0}:e[0]}function lt(e,t,n,r,i){var s,o=[],u=0,a=e.length,f=t!=null;for(;u-1&&(s[f]=!(o[f]=c))}}else g=lt(g===o?g.splice(d,g.length):g),i?i(null,o,g,a):S.apply(o,g)})}function ht(e){var t,n,r,s=e.length,o=i.relative[e[0].type],u=o||i.relative[" "],a=o?1:0,f=at(function(e){return e===t},u,!0),l=at(function(e){return T.call(t,e)>-1},u,!0),h=[function(e,n,r){return!o&&(r||n!==c)||((t=n).nodeType?f(e,n,r):l(e,n,r))}];for(;a1&&ft(h),a>1&&e.slice(0,a-1).join("").replace(j,"$1"),n,a0,s=e.length>0,o=function(u,a,f,l,h){var p,d,v,m=[],y=0,w="0",x=u&&[],T=h!=null,N=c,C=u||s&&i.find.TAG("*",h&&a.parentNode||a),k=b+=N==null?1:Math.E;T&&(c=a!==g&&a,n=o.el);for(;(p=C[w])!=null;w++){if(s&&p){for(d=0;v=e[d];d++)if(v(p,a,f)){l.push(p);break}T&&(b=k,n=++o.el)}r&&((p=!v&&p)&&y--,u&&x.push(p))}y+=w;if(r&&w!==y){for(d=0;v=t[d];d++)v(x,m,a,f);if(u){if(y>0)while(w--)!x[w]&&!m[w]&&(m[w]=E.call(l));m=lt(m)}S.apply(l,m),T&&!u&&m.length>0&&y+t.length>1&&nt.uniqueSort(l)}return T&&(b=k,c=N),x};return o.el=0,r?N(o):o}function dt(e,t,n){var r=0,i=t.length;for(;r2&&(f=u[0]).type==="ID"&&t.nodeType===9&&!s&&i.relative[u[1].type]){t=i.find.ID(f.matches[0].replace($,""),t,s)[0];if(!t)return n;e=e.slice(u.shift().length)}for(o=J.POS.test(e)?-1:u.length-1;o>=0;o--){f=u[o];if(i.relative[l=f.type])break;if(c=i.find[l])if(r=c(f.matches[0].replace($,""),z.test(u[0].type)&&t.parentNode||t,s)){u.splice(o,1),e=r.length&&u.join("");if(!e)return S.apply(n,x.call(r,0)),n;break}}}return a(e,h)(r,t,s,n,z.test(e)),n}function mt(){}var n,r,i,s,o,u,a,f,l,c,h=!0,p="undefined",d=("sizcache"+Math.random()).replace(".",""),m=String,g=e.document,y=g.documentElement,b=0,w=0,E=[].pop,S=[].push,x=[].slice,T=[].indexOf||function(e){var t=0,n=this.length;for(;ti.cacheLength&&delete e[t.shift()],e[n+" "]=r},e)},k=C(),L=C(),A=C(),O="[\\x20\\t\\r\\n\\f]",M="(?:\\\\.|[-\\w]|[^\\x00-\\xa0])+",_=M.replace("w","w#"),D="([*^$|!~]?=)",P="\\["+O+"*("+M+")"+O+"*(?:"+D+O+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+_+")|)|)"+O+"*\\]",H=":("+M+")(?:\\((?:(['\"])((?:\\\\.|[^\\\\])*?)\\2|([^()[\\]]*|(?:(?:"+P+")|[^:]|\\\\.)*|.*))\\)|)",B=":(even|odd|eq|gt|lt|nth|first|last)(?:\\("+O+"*((?:-\\d)?\\d*)"+O+"*\\)|)(?=[^-]|$)",j=new RegExp("^"+O+"+|((?:^|[^\\\\])(?:\\\\.)*)"+O+"+$","g"),F=new RegExp("^"+O+"*,"+O+"*"),I=new RegExp("^"+O+"*([\\x20\\t\\r\\n\\f>+~])"+O+"*"),q=new RegExp(H),R=/^(?:#([\w\-]+)|(\w+)|\.([\w\-]+))$/,U=/^:not/,z=/[\x20\t\r\n\f]*[+~]/,W=/:not\($/,X=/h\d/i,V=/input|select|textarea|button/i,$=/\\(?!\\)/g,J={ID:new RegExp("^#("+M+")"),CLASS:new RegExp("^\\.("+M+")"),NAME:new RegExp("^\\[name=['\"]?("+M+")['\"]?\\]"),TAG:new RegExp("^("+M.replace("w","w*")+")"),ATTR:new RegExp("^"+P),PSEUDO:new RegExp("^"+H),POS:new RegExp(B,"i"),CHILD:new RegExp("^:(only|nth|first|last)-child(?:\\("+O+"*(even|odd|(([+-]|)(\\d*)n|)"+O+"*(?:([+-]|)"+O+"*(\\d+)|))"+O+"*\\)|)","i"),needsContext:new RegExp("^"+O+"*[>+~]|"+B,"i")},K=function(e){var t=g.createElement("div");try{return e(t)}catch(n){return!1}finally{t=null}},Q=K(function(e){return e.appendChild(g.createComment("")),!e.getElementsByTagName("*").length}),G=K(function(e){return e.innerHTML="",e.firstChild&&typeof e.firstChild.getAttribute!==p&&e.firstChild.getAttribute("href")==="#"}),Y=K(function(e){e.innerHTML="";var t=typeof e.lastChild.getAttribute("multiple");return t!=="boolean"&&t!=="string"}),Z=K(function(e){return e.innerHTML="",!e.getElementsByClassName||!e.getElementsByClassName("e").length?!1:(e.lastChild.className="e",e.getElementsByClassName("e").length===2)}),et=K(function(e){e.id=d+0,e.innerHTML="
",y.insertBefore(e,y.firstChild);var t=g.getElementsByName&&g.getElementsByName(d).length===2+g.getElementsByName(d+0).length;return r=!g.getElementById(d),y.removeChild(e),t});try{x.call(y.childNodes,0)[0].nodeType}catch(tt){x=function(e){var t,n=[];for(;t=this[e];e++)n.push(t);return n}}nt.matches=function(e,t){return nt(e,null,null,t)},nt.matchesSelector=function(e,t){return nt(t,null,null,[e]).length>0},s=nt.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(i===1||i===9||i===11){if(typeof e.textContent=="string")return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=s(e)}else if(i===3||i===4)return e.nodeValue}else for(;t=e[r];r++)n+=s(t);return n},o=nt.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return t?t.nodeName!=="HTML":!1},u=nt.contains=y.contains?function(e,t){var n=e.nodeType===9?e.documentElement:e,r=t&&t.parentNode;return e===r||!!(r&&r.nodeType===1&&n.contains&&n.contains(r))}:y.compareDocumentPosition?function(e,t){return t&&!!(e.compareDocumentPosition(t)&16)}:function(e,t){while(t=t.parentNode)if(t===e)return!0;return!1},nt.attr=function(e,t){var n,r=o(e);return r||(t=t.toLowerCase()),(n=i.attrHandle[t])?n(e):r||Y?e.getAttribute(t):(n=e.getAttributeNode(t),n?typeof e[t]=="boolean"?e[t]?t:null:n.specified?n.value:null:null)},i=nt.selectors={cacheLength:50,createPseudo:N,match:J,attrHandle:G?{}:{href:function(e){return e.getAttribute("href",2)},type:function(e){return e.getAttribute("type")}},find:{ID:r?function(e,t,n){if(typeof t.getElementById!==p&&!n){var r=t.getElementById(e);return r&&r.parentNode?[r]:[]}}:function(e,n,r){if(typeof n.getElementById!==p&&!r){var i=n.getElementById(e);return i?i.id===e||typeof i.getAttributeNode!==p&&i.getAttributeNode("id").value===e?[i]:t:[]}},TAG:Q?function(e,t){if(typeof t.getElementsByTagName!==p)return t.getElementsByTagName(e)}:function(e,t){var n=t.getElementsByTagName(e);if(e==="*"){var r,i=[],s=0;for(;r=n[s];s++)r.nodeType===1&&i.push(r);return i}return n},NAME:et&&function(e,t){if(typeof t.getElementsByName!==p)return t.getElementsByName(name)},CLASS:Z&&function(e,t,n){if(typeof t.getElementsByClassName!==p&&!n)return t.getElementsByClassName(e)}},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace($,""),e[3]=(e[4]||e[5]||"").replace($,""),e[2]==="~="&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),e[1]==="nth"?(e[2]||nt.error(e[0]),e[3]=+(e[3]?e[4]+(e[5]||1):2*(e[2]==="even"||e[2]==="odd")),e[4]=+(e[6]+e[7]||e[2]==="odd")):e[2]&&nt.error(e[0]),e},PSEUDO:function(e){var t,n;if(J.CHILD.test(e[0]))return null;if(e[3])e[2]=e[3];else if(t=e[4])q.test(t)&&(n=ut(t,!0))&&(n=t.indexOf(")",t.length-n)-t.length)&&(t=t.slice(0,n),e[0]=e[0].slice(0,n)),e[2]=t;return e.slice(0,3)}},filter:{ID:r?function(e){return e=e.replace($,""),function(t){return t.getAttribute("id")===e}}:function(e){return e=e.replace($,""),function(t){var n=typeof t.getAttributeNode!==p&&t.getAttributeNode("id");return n&&n.value===e}},TAG:function(e){return e==="*"?function(){return!0}:(e=e.replace($,"").toLowerCase(),function(t){return t.nodeName&&t.nodeName.toLowerCase()===e})},CLASS:function(e){var t=k[d][e+" "];return t||(t=new RegExp("(^|"+O+")"+e+"("+O+"|$)"))&&k(e,function(e){return t.test(e.className||typeof e.getAttribute!==p&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r,i){var s=nt.attr(r,e);return s==null?t==="!=":t?(s+="",t==="="?s===n:t==="!="?s!==n:t==="^="?n&&s.indexOf(n)===0:t==="*="?n&&s.indexOf(n)>-1:t==="$="?n&&s.substr(s.length-n.length)===n:t==="~="?(" "+s+" ").indexOf(n)>-1:t==="|="?s===n||s.substr(0,n.length+1)===n+"-":!1):!0}},CHILD:function(e,t,n,r){return e==="nth"?function(e){var t,i,s=e.parentNode;if(n===1&&r===0)return!0;if(s){i=0;for(t=s.firstChild;t;t=t.nextSibling)if(t.nodeType===1){i++;if(e===t)break}}return i-=r,i===n||i%n===0&&i/n>=0}:function(t){var n=t;switch(e){case"only":case"first":while(n=n.previousSibling)if(n.nodeType===1)return!1;if(e==="first")return!0;n=t;case"last":while(n=n.nextSibling)if(n.nodeType===1)return!1;return!0}}},PSEUDO:function(e,t){var n,r=i.pseudos[e]||i.setFilters[e.toLowerCase()]||nt.error("unsupported pseudo: "+e);return r[d]?r(t):r.length>1?(n=[e,e,"",t],i.setFilters.hasOwnProperty(e.toLowerCase())?N(function(e,n){var i,s=r(e,t),o=s.length;while(o--)i=T.call(e,s[o]),e[i]=!(n[i]=s[o])}):function(e){return r(e,0,n)}):r}},pseudos:{not:N(function(e){var t=[],n=[],r=a(e.replace(j,"$1"));return r[d]?N(function(e,t,n,i){var s,o=r(e,null,i,[]),u=e.length;while(u--)if(s=o[u])e[u]=!(t[u]=s)}):function(e,i,s){return t[0]=e,r(t,null,s,n),!n.pop()}}),has:N(function(e){return function(t){return nt(e,t).length>0}}),contains:N(function(e){return function(t){return(t.textContent||t.innerText||s(t)).indexOf(e)>-1}}),enabled:function(e){return e.disabled===!1},disabled:function(e){return e.disabled===!0},checked:function(e){var t=e.nodeName.toLowerCase();return t==="input"&&!!e.checked||t==="option"&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,e.selected===!0},parent:function(e){return!i.pseudos.empty(e)},empty:function(e){var t;e=e.firstChild;while(e){if(e.nodeName>"@"||(t=e.nodeType)===3||t===4)return!1;e=e.nextSibling}return!0},header:function(e){return X.test(e.nodeName)},text:function(e){var t,n;return e.nodeName.toLowerCase()==="input"&&(t=e.type)==="text"&&((n=e.getAttribute("type"))==null||n.toLowerCase()===t)},radio:rt("radio"),checkbox:rt("checkbox"),file:rt("file"),password:rt("password"),image:rt("image"),submit:it("submit"),reset:it("reset"),button:function(e){var t=e.nodeName.toLowerCase();return t==="input"&&e.type==="button"||t==="button"},input:function(e){return V.test(e.nodeName)},focus:function(e){var t=e.ownerDocument;return e===t.activeElement&&(!t.hasFocus||t.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},active:function(e){return e===e.ownerDocument.activeElement},first:st(function(){return[0]}),last:st(function(e,t){return[t-1]}),eq:st(function(e,t,n){return[n<0?n+t:n]}),even:st(function(e,t){for(var n=0;n=0;)e.push(r);return e}),gt:st(function(e,t,n){for(var r=n<0?n+t:n;++r",e.querySelectorAll("[selected]").length||i.push("\\["+O+"*(?:checked|disabled|ismap|multiple|readonly|selected|value)"),e.querySelectorAll(":checked").length||i.push(":checked")}),K(function(e){e.innerHTML="

",e.querySelectorAll("[test^='']").length&&i.push("[*^$]="+O+"*(?:\"\"|'')"),e.innerHTML="",e.querySelectorAll(":enabled").length||i.push(":enabled",":disabled")}),i=new RegExp(i.join("|")),vt=function(e,r,s,o,u){if(!o&&!u&&!i.test(e)){var a,f,l=!0,c=d,h=r,p=r.nodeType===9&&e;if(r.nodeType===1&&r.nodeName.toLowerCase()!=="object"){a=ut(e),(l=r.getAttribute("id"))?c=l.replace(n,"\\$&"):r.setAttribute("id",c),c="[id='"+c+"'] ",f=a.length;while(f--)a[f]=c+a[f].join("");h=z.test(e)&&r.parentNode||r,p=a.join(",")}if(p)try{return S.apply(s,x.call(h.querySelectorAll(p),0)),s}catch(v){}finally{l||r.removeAttribute("id")}}return t(e,r,s,o,u)},u&&(K(function(t){e=u.call(t,"div");try{u.call(t,"[test!='']:sizzle"),s.push("!=",H)}catch(n){}}),s=new RegExp(s.join("|")),nt.matchesSelector=function(t,n){n=n.replace(r,"='$1']");if(!o(t)&&!s.test(n)&&!i.test(n))try{var a=u.call(t,n);if(a||e||t.document&&t.document.nodeType!==11)return a}catch(f){}return nt(n,null,null,[t]).length>0})}(),i.pseudos.nth=i.pseudos.eq,i.filters=mt.prototype=i.pseudos,i.setFilters=new mt,nt.attr=v.attr,v.find=nt,v.expr=nt.selectors,v.expr[":"]=v.expr.pseudos,v.unique=nt.uniqueSort,v.text=nt.getText,v.isXMLDoc=nt.isXML,v.contains=nt.contains}(e);var nt=/Until$/,rt=/^(?:parents|prev(?:Until|All))/,it=/^.[^:#\[\.,]*$/,st=v.expr.match.needsContext,ot={children:!0,contents:!0,next:!0,prev:!0};v.fn.extend({find:function(e){var t,n,r,i,s,o,u=this;if(typeof e!="string")return v(e).filter(function(){for(t=0,n=u.length;t0)for(i=r;i=0:v.filter(e,this).length>0:this.filter(e).length>0)},closest:function(e,t){var n,r=0,i=this.length,s=[],o=st.test(e)||typeof e!="string"?v(e,t||this.context):0;for(;r-1:v.find.matchesSelector(n,e)){s.push(n);break}n=n.parentNode}}return s=s.length>1?v.unique(s):s,this.pushStack(s,"closest",e)},index:function(e){return e?typeof e=="string"?v.inArray(this[0],v(e)):v.inArray(e.jquery?e[0]:e,this):this[0]&&this[0].parentNode?this.prevAll().length:-1},add:function(e,t){var n=typeof e=="string"?v(e,t):v.makeArray(e&&e.nodeType?[e]:e),r=v.merge(this.get(),n);return this.pushStack(ut(n[0])||ut(r[0])?r:v.unique(r))},addBack:function(e){return this.add(e==null?this.prevObject:this.prevObject.filter(e))}}),v.fn.andSelf=v.fn.addBack,v.each({parent:function(e){var t=e.parentNode;return t&&t.nodeType!==11?t:null},parents:function(e){return v.dir(e,"parentNode")},parentsUntil:function(e,t,n){return v.dir(e,"parentNode",n)},next:function(e){return at(e,"nextSibling")},prev:function(e){return at(e,"previousSibling")},nextAll:function(e){return v.dir(e,"nextSibling")},prevAll:function(e){return v.dir(e,"previousSibling")},nextUntil:function(e,t,n){return v.dir(e,"nextSibling",n)},prevUntil:function(e,t,n){return v.dir(e,"previousSibling",n)},siblings:function(e){return v.sibling((e.parentNode||{}).firstChild,e)},children:function(e){return v.sibling(e.firstChild)},contents:function(e){return v.nodeName(e,"iframe")?e.contentDocument||e.contentWindow.document:v.merge([],e.childNodes)}},function(e,t){v.fn[e]=function(n,r){var i=v.map(this,t,n);return nt.test(e)||(r=n),r&&typeof r=="string"&&(i=v.filter(r,i)),i=this.length>1&&!ot[e]?v.unique(i):i,this.length>1&&rt.test(e)&&(i=i.reverse()),this.pushStack(i,e,l.call(arguments).join(","))}}),v.extend({filter:function(e,t,n){return n&&(e=":not("+e+")"),t.length===1?v.find.matchesSelector(t[0],e)?[t[0]]:[]:v.find.matches(e,t)},dir:function(e,n,r){var i=[],s=e[n];while(s&&s.nodeType!==9&&(r===t||s.nodeType!==1||!v(s).is(r)))s.nodeType===1&&i.push(s),s=s[n];return i},sibling:function(e,t){var n=[];for(;e;e=e.nextSibling)e.nodeType===1&&e!==t&&n.push(e);return n}});var ct="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",ht=/ jQuery\d+="(?:null|\d+)"/g,pt=/^\s+/,dt=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,vt=/<([\w:]+)/,mt=/]","i"),Et=/^(?:checkbox|radio)$/,St=/checked\s*(?:[^=]|=\s*.checked.)/i,xt=/\/(java|ecma)script/i,Tt=/^\s*\s*$/g,Nt={option:[1,""],legend:[1,"
","
"],thead:[1,"","
"],tr:[2,"","
"],td:[3,"","
"],col:[2,"","
"],area:[1,"",""],_default:[0,"",""]},Ct=lt(i),kt=Ct.appendChild(i.createElement("div"));Nt.optgroup=Nt.option,Nt.tbody=Nt.tfoot=Nt.colgroup=Nt.caption=Nt.thead,Nt.th=Nt.td,v.support.htmlSerialize||(Nt._default=[1,"X
","
"]),v.fn.extend({text:function(e){return v.access(this,function(e){return e===t?v.text(this):this.empty().append((this[0]&&this[0].ownerDocument||i).createTextNode(e))},null,e,arguments.length)},wrapAll:function(e){if(v.isFunction(e))return this.each(function(t){v(this).wrapAll(e.call(this,t))});if(this[0]){var t=v(e,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstChild&&e.firstChild.nodeType===1)e=e.firstChild;return e}).append(this)}return this},wrapInner:function(e){return v.isFunction(e)?this.each(function(t){v(this).wrapInner(e.call(this,t))}):this.each(function(){var t=v(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=v.isFunction(e);return this.each(function(n){v(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(){return this.parent().each(function(){v.nodeName(this,"body")||v(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(e){(this.nodeType===1||this.nodeType===11)&&this.appendChild(e)})},prepend:function(){return this.domManip(arguments,!0,function(e){(this.nodeType===1||this.nodeType===11)&&this.insertBefore(e,this.firstChild)})},before:function(){if(!ut(this[0]))return this.domManip(arguments,!1,function(e){this.parentNode.insertBefore(e,this)});if(arguments.length){var e=v.clean(arguments);return this.pushStack(v.merge(e,this),"before",this.selector)}},after:function(){if(!ut(this[0]))return this.domManip(arguments,!1,function(e){this.parentNode.insertBefore(e,this.nextSibling)});if(arguments.length){var e=v.clean(arguments);return this.pushStack(v.merge(this,e),"after",this.selector)}},remove:function(e,t){var n,r=0;for(;(n=this[r])!=null;r++)if(!e||v.filter(e,[n]).length)!t&&n.nodeType===1&&(v.cleanData(n.getElementsByTagName("*")),v.cleanData([n])),n.parentNode&&n.parentNode.removeChild(n);return this},empty:function(){var e,t=0;for(;(e=this[t])!=null;t++){e.nodeType===1&&v.cleanData(e.getElementsByTagName("*"));while(e.firstChild)e.removeChild(e.firstChild)}return this},clone:function(e,t){return e=e==null?!1:e,t=t==null?e:t,this.map(function(){return v.clone(this,e,t)})},html:function(e){return v.access(this,function(e){var n=this[0]||{},r=0,i=this.length;if(e===t)return n.nodeType===1?n.innerHTML.replace(ht,""):t;if(typeof e=="string"&&!yt.test(e)&&(v.support.htmlSerialize||!wt.test(e))&&(v.support.leadingWhitespace||!pt.test(e))&&!Nt[(vt.exec(e)||["",""])[1].toLowerCase()]){e=e.replace(dt,"<$1>");try{for(;r1&&typeof f=="string"&&St.test(f))return this.each(function(){v(this).domManip(e,n,r)});if(v.isFunction(f))return this.each(function(i){var s=v(this);e[0]=f.call(this,i,n?s.html():t),s.domManip(e,n,r)});if(this[0]){i=v.buildFragment(e,this,l),o=i.fragment,s=o.firstChild,o.childNodes.length===1&&(o=s);if(s){n=n&&v.nodeName(s,"tr");for(u=i.cacheable||c-1;a0?this.clone(!0):this).get(),v(o[i])[t](r),s=s.concat(r);return this.pushStack(s,e,o.selector)}}),v.extend({clone:function(e,t,n){var r,i,s,o;v.support.html5Clone||v.isXMLDoc(e)||!wt.test("<"+e.nodeName+">")?o=e.cloneNode(!0):(kt.innerHTML=e.outerHTML,kt.removeChild(o=kt.firstChild));if((!v.support.noCloneEvent||!v.support.noCloneChecked)&&(e.nodeType===1||e.nodeType===11)&&!v.isXMLDoc(e)){Ot(e,o),r=Mt(e),i=Mt(o);for(s=0;r[s];++s)i[s]&&Ot(r[s],i[s])}if(t){At(e,o);if(n){r=Mt(e),i=Mt(o);for(s=0;r[s];++s)At(r[s],i[s])}}return r=i=null,o},clean:function(e,t,n,r){var s,o,u,a,f,l,c,h,p,d,m,g,y=t===i&&Ct,b=[];if(!t||typeof t.createDocumentFragment=="undefined")t=i;for(s=0;(u=e[s])!=null;s++){typeof u=="number"&&(u+="");if(!u)continue;if(typeof u=="string")if(!gt.test(u))u=t.createTextNode(u);else{y=y||lt(t),c=t.createElement("div"),y.appendChild(c),u=u.replace(dt,"<$1>"),a=(vt.exec(u)||["",""])[1].toLowerCase(),f=Nt[a]||Nt._default,l=f[0],c.innerHTML=f[1]+u+f[2];while(l--)c=c.lastChild;if(!v.support.tbody){h=mt.test(u),p=a==="table"&&!h?c.firstChild&&c.firstChild.childNodes:f[1]===""&&!h?c.childNodes:[];for(o=p.length-1;o>=0;--o)v.nodeName(p[o],"tbody")&&!p[o].childNodes.length&&p[o].parentNode.removeChild(p[o])}!v.support.leadingWhitespace&&pt.test(u)&&c.insertBefore(t.createTextNode(pt.exec(u)[0]),c.firstChild),u=c.childNodes,c.parentNode.removeChild(c)}u.nodeType?b.push(u):v.merge(b,u)}c&&(u=c=y=null);if(!v.support.appendChecked)for(s=0;(u=b[s])!=null;s++)v.nodeName(u,"input")?_t(u):typeof u.getElementsByTagName!="undefined"&&v.grep(u.getElementsByTagName("input"),_t);if(n){m=function(e){if(!e.type||xt.test(e.type))return r?r.push(e.parentNode?e.parentNode.removeChild(e):e):n.appendChild(e)};for(s=0;(u=b[s])!=null;s++)if(!v.nodeName(u,"script")||!m(u))n.appendChild(u),typeof u.getElementsByTagName!="undefined"&&(g=v.grep(v.merge([],u.getElementsByTagName("script")),m),b.splice.apply(b,[s+1,0].concat(g)),s+=g.length)}return b},cleanData:function(e,t){var n,r,i,s,o=0,u=v.expando,a=v.cache,f=v.support.deleteExpando,l=v.event.special;for(;(i=e[o])!=null;o++)if(t||v.acceptData(i)){r=i[u],n=r&&a[r];if(n){if(n.events)for(s in n.events)l[s]?v.event.remove(i,s):v.removeEvent(i,s,n.handle);a[r]&&(delete a[r],f?delete i[u]:i.removeAttribute?i.removeAttribute(u):i[u]=null,v.deletedIds.push(r))}}}}),function(){var e,t;v.uaMatch=function(e){e=e.toLowerCase();var t=/(chrome)[ \/]([\w.]+)/.exec(e)||/(webkit)[ \/]([\w.]+)/.exec(e)||/(opera)(?:.*version|)[ \/]([\w.]+)/.exec(e)||/(msie) ([\w.]+)/.exec(e)||e.indexOf("compatible")<0&&/(mozilla)(?:.*? rv:([\w.]+)|)/.exec(e)||[];return{browser:t[1]||"",version:t[2]||"0"}},e=v.uaMatch(o.userAgent),t={},e.browser&&(t[e.browser]=!0,t.version=e.version),t.chrome?t.webkit=!0:t.webkit&&(t.safari=!0),v.browser=t,v.sub=function(){function e(t,n){return new e.fn.init(t,n)}v.extend(!0,e,this),e.superclass=this,e.fn=e.prototype=this(),e.fn.constructor=e,e.sub=this.sub,e.fn.init=function(r,i){return i&&i instanceof v&&!(i instanceof e)&&(i=e(i)),v.fn.init.call(this,r,i,t)},e.fn.init.prototype=e.fn;var t=e(i);return e}}();var Dt,Pt,Ht,Bt=/alpha\([^)]*\)/i,jt=/opacity=([^)]*)/,Ft=/^(top|right|bottom|left)$/,It=/^(none|table(?!-c[ea]).+)/,qt=/^margin/,Rt=new RegExp("^("+m+")(.*)$","i"),Ut=new RegExp("^("+m+")(?!px)[a-z%]+$","i"),zt=new RegExp("^([-+])=("+m+")","i"),Wt={BODY:"block"},Xt={position:"absolute",visibility:"hidden",display:"block"},Vt={letterSpacing:0,fontWeight:400},$t=["Top","Right","Bottom","Left"],Jt=["Webkit","O","Moz","ms"],Kt=v.fn.toggle;v.fn.extend({css:function(e,n){return v.access(this,function(e,n,r){return r!==t?v.style(e,n,r):v.css(e,n)},e,n,arguments.length>1)},show:function(){return Yt(this,!0)},hide:function(){return Yt(this)},toggle:function(e,t){var n=typeof e=="boolean";return v.isFunction(e)&&v.isFunction(t)?Kt.apply(this,arguments):this.each(function(){(n?e:Gt(this))?v(this).show():v(this).hide()})}}),v.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Dt(e,"opacity");return n===""?"1":n}}}},cssNumber:{fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":v.support.cssFloat?"cssFloat":"styleFloat"},style:function(e,n,r,i){if(!e||e.nodeType===3||e.nodeType===8||!e.style)return;var s,o,u,a=v.camelCase(n),f=e.style;n=v.cssProps[a]||(v.cssProps[a]=Qt(f,a)),u=v.cssHooks[n]||v.cssHooks[a];if(r===t)return u&&"get"in u&&(s=u.get(e,!1,i))!==t?s:f[n];o=typeof r,o==="string"&&(s=zt.exec(r))&&(r=(s[1]+1)*s[2]+parseFloat(v.css(e,n)),o="number");if(r==null||o==="number"&&isNaN(r))return;o==="number"&&!v.cssNumber[a]&&(r+="px");if(!u||!("set"in u)||(r=u.set(e,r,i))!==t)try{f[n]=r}catch(l){}},css:function(e,n,r,i){var s,o,u,a=v.camelCase(n);return n=v.cssProps[a]||(v.cssProps[a]=Qt(e.style,a)),u=v.cssHooks[n]||v.cssHooks[a],u&&"get"in u&&(s=u.get(e,!0,i)),s===t&&(s=Dt(e,n)),s==="normal"&&n in Vt&&(s=Vt[n]),r||i!==t?(o=parseFloat(s),r||v.isNumeric(o)?o||0:s):s},swap:function(e,t,n){var r,i,s={};for(i in t)s[i]=e.style[i],e.style[i]=t[i];r=n.call(e);for(i in t)e.style[i]=s[i];return r}}),e.getComputedStyle?Dt=function(t,n){var r,i,s,o,u=e.getComputedStyle(t,null),a=t.style;return u&&(r=u.getPropertyValue(n)||u[n],r===""&&!v.contains(t.ownerDocument,t)&&(r=v.style(t,n)),Ut.test(r)&&qt.test(n)&&(i=a.width,s=a.minWidth,o=a.maxWidth,a.minWidth=a.maxWidth=a.width=r,r=u.width,a.width=i,a.minWidth=s,a.maxWidth=o)),r}:i.documentElement.currentStyle&&(Dt=function(e,t){var n,r,i=e.currentStyle&&e.currentStyle[t],s=e.style;return i==null&&s&&s[t]&&(i=s[t]),Ut.test(i)&&!Ft.test(t)&&(n=s.left,r=e.runtimeStyle&&e.runtimeStyle.left,r&&(e.runtimeStyle.left=e.currentStyle.left),s.left=t==="fontSize"?"1em":i,i=s.pixelLeft+"px",s.left=n,r&&(e.runtimeStyle.left=r)),i===""?"auto":i}),v.each(["height","width"],function(e,t){v.cssHooks[t]={get:function(e,n,r){if(n)return e.offsetWidth===0&&It.test(Dt(e,"display"))?v.swap(e,Xt,function(){return tn(e,t,r)}):tn(e,t,r)},set:function(e,n,r){return Zt(e,n,r?en(e,t,r,v.support.boxSizing&&v.css(e,"boxSizing")==="border-box"):0)}}}),v.support.opacity||(v.cssHooks.opacity={get:function(e,t){return jt.test((t&&e.currentStyle?e.currentStyle.filter:e.style.filter)||"")?.01*parseFloat(RegExp.$1)+"":t?"1":""},set:function(e,t){var n=e.style,r=e.currentStyle,i=v.isNumeric(t)?"alpha(opacity="+t*100+")":"",s=r&&r.filter||n.filter||"";n.zoom=1;if(t>=1&&v.trim(s.replace(Bt,""))===""&&n.removeAttribute){n.removeAttribute("filter");if(r&&!r.filter)return}n.filter=Bt.test(s)?s.replace(Bt,i):s+" "+i}}),v(function(){v.support.reliableMarginRight||(v.cssHooks.marginRight={get:function(e,t){return v.swap(e,{display:"inline-block"},function(){if(t)return Dt(e,"marginRight")})}}),!v.support.pixelPosition&&v.fn.position&&v.each(["top","left"],function(e,t){v.cssHooks[t]={get:function(e,n){if(n){var r=Dt(e,t);return Ut.test(r)?v(e).position()[t]+"px":r}}}})}),v.expr&&v.expr.filters&&(v.expr.filters.hidden=function(e){return e.offsetWidth===0&&e.offsetHeight===0||!v.support.reliableHiddenOffsets&&(e.style&&e.style.display||Dt(e,"display"))==="none"},v.expr.filters.visible=function(e){return!v.expr.filters.hidden(e)}),v.each({margin:"",padding:"",border:"Width"},function(e,t){v.cssHooks[e+t]={expand:function(n){var r,i=typeof n=="string"?n.split(" "):[n],s={};for(r=0;r<4;r++)s[e+$t[r]+t]=i[r]||i[r-2]||i[0];return s}},qt.test(e)||(v.cssHooks[e+t].set=Zt)});var rn=/%20/g,sn=/\[\]$/,on=/\r?\n/g,un=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,an=/^(?:select|textarea)/i;v.fn.extend({serialize:function(){return v.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?v.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||an.test(this.nodeName)||un.test(this.type))}).map(function(e,t){var n=v(this).val();return n==null?null:v.isArray(n)?v.map(n,function(e,n){return{name:t.name,value:e.replace(on,"\r\n")}}):{name:t.name,value:n.replace(on,"\r\n")}}).get()}}),v.param=function(e,n){var r,i=[],s=function(e,t){t=v.isFunction(t)?t():t==null?"":t,i[i.length]=encodeURIComponent(e)+"="+encodeURIComponent(t)};n===t&&(n=v.ajaxSettings&&v.ajaxSettings.traditional);if(v.isArray(e)||e.jquery&&!v.isPlainObject(e))v.each(e,function(){s(this.name,this.value)});else for(r in e)fn(r,e[r],n,s);return i.join("&").replace(rn,"+")};var ln,cn,hn=/#.*$/,pn=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,dn=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,vn=/^(?:GET|HEAD)$/,mn=/^\/\//,gn=/\?/,yn=/)<[^<]*)*<\/script>/gi,bn=/([?&])_=[^&]*/,wn=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,En=v.fn.load,Sn={},xn={},Tn=["*/"]+["*"];try{cn=s.href}catch(Nn){cn=i.createElement("a"),cn.href="",cn=cn.href}ln=wn.exec(cn.toLowerCase())||[],v.fn.load=function(e,n,r){if(typeof e!="string"&&En)return En.apply(this,arguments);if(!this.length)return this;var i,s,o,u=this,a=e.indexOf(" ");return a>=0&&(i=e.slice(a,e.length),e=e.slice(0,a)),v.isFunction(n)?(r=n,n=t):n&&typeof n=="object"&&(s="POST"),v.ajax({url:e,type:s,dataType:"html",data:n,complete:function(e,t){r&&u.each(r,o||[e.responseText,t,e])}}).done(function(e){o=arguments,u.html(i?v("
").append(e.replace(yn,"")).find(i):e)}),this},v.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(e,t){v.fn[t]=function(e){return this.on(t,e)}}),v.each(["get","post"],function(e,n){v[n]=function(e,r,i,s){return v.isFunction(r)&&(s=s||i,i=r,r=t),v.ajax({type:n,url:e,data:r,success:i,dataType:s})}}),v.extend({getScript:function(e,n){return v.get(e,t,n,"script")},getJSON:function(e,t,n){return v.get(e,t,n,"json")},ajaxSetup:function(e,t){return t?Ln(e,v.ajaxSettings):(t=e,e=v.ajaxSettings),Ln(e,t),e},ajaxSettings:{url:cn,isLocal:dn.test(ln[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded; charset=UTF-8",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":Tn},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":e.String,"text html":!0,"text json":v.parseJSON,"text xml":v.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:Cn(Sn),ajaxTransport:Cn(xn),ajax:function(e,n){function T(e,n,s,a){var l,y,b,w,S,T=n;if(E===2)return;E=2,u&&clearTimeout(u),o=t,i=a||"",x.readyState=e>0?4:0,s&&(w=An(c,x,s));if(e>=200&&e<300||e===304)c.ifModified&&(S=x.getResponseHeader("Last-Modified"),S&&(v.lastModified[r]=S),S=x.getResponseHeader("Etag"),S&&(v.etag[r]=S)),e===304?(T="notmodified",l=!0):(l=On(c,w),T=l.state,y=l.data,b=l.error,l=!b);else{b=T;if(!T||e)T="error",e<0&&(e=0)}x.status=e,x.statusText=(n||T)+"",l?d.resolveWith(h,[y,T,x]):d.rejectWith(h,[x,T,b]),x.statusCode(g),g=t,f&&p.trigger("ajax"+(l?"Success":"Error"),[x,c,l?y:b]),m.fireWith(h,[x,T]),f&&(p.trigger("ajaxComplete",[x,c]),--v.active||v.event.trigger("ajaxStop"))}typeof e=="object"&&(n=e,e=t),n=n||{};var r,i,s,o,u,a,f,l,c=v.ajaxSetup({},n),h=c.context||c,p=h!==c&&(h.nodeType||h instanceof v)?v(h):v.event,d=v.Deferred(),m=v.Callbacks("once memory"),g=c.statusCode||{},b={},w={},E=0,S="canceled",x={readyState:0,setRequestHeader:function(e,t){if(!E){var n=e.toLowerCase();e=w[n]=w[n]||e,b[e]=t}return this},getAllResponseHeaders:function(){return E===2?i:null},getResponseHeader:function(e){var n;if(E===2){if(!s){s={};while(n=pn.exec(i))s[n[1].toLowerCase()]=n[2]}n=s[e.toLowerCase()]}return n===t?null:n},overrideMimeType:function(e){return E||(c.mimeType=e),this},abort:function(e){return e=e||S,o&&o.abort(e),T(0,e),this}};d.promise(x),x.success=x.done,x.error=x.fail,x.complete=m.add,x.statusCode=function(e){if(e){var t;if(E<2)for(t in e)g[t]=[g[t],e[t]];else t=e[x.status],x.always(t)}return this},c.url=((e||c.url)+"").replace(hn,"").replace(mn,ln[1]+"//"),c.dataTypes=v.trim(c.dataType||"*").toLowerCase().split(y),c.crossDomain==null&&(a=wn.exec(c.url.toLowerCase()),c.crossDomain=!(!a||a[1]===ln[1]&&a[2]===ln[2]&&(a[3]||(a[1]==="http:"?80:443))==(ln[3]||(ln[1]==="http:"?80:443)))),c.data&&c.processData&&typeof c.data!="string"&&(c.data=v.param(c.data,c.traditional)),kn(Sn,c,n,x);if(E===2)return x;f=c.global,c.type=c.type.toUpperCase(),c.hasContent=!vn.test(c.type),f&&v.active++===0&&v.event.trigger("ajaxStart");if(!c.hasContent){c.data&&(c.url+=(gn.test(c.url)?"&":"?")+c.data,delete c.data),r=c.url;if(c.cache===!1){var N=v.now(),C=c.url.replace(bn,"$1_="+N);c.url=C+(C===c.url?(gn.test(c.url)?"&":"?")+"_="+N:"")}}(c.data&&c.hasContent&&c.contentType!==!1||n.contentType)&&x.setRequestHeader("Content-Type",c.contentType),c.ifModified&&(r=r||c.url,v.lastModified[r]&&x.setRequestHeader("If-Modified-Since",v.lastModified[r]),v.etag[r]&&x.setRequestHeader("If-None-Match",v.etag[r])),x.setRequestHeader("Accept",c.dataTypes[0]&&c.accepts[c.dataTypes[0]]?c.accepts[c.dataTypes[0]]+(c.dataTypes[0]!=="*"?", "+Tn+"; q=0.01":""):c.accepts["*"]);for(l in c.headers)x.setRequestHeader(l,c.headers[l]);if(!c.beforeSend||c.beforeSend.call(h,x,c)!==!1&&E!==2){S="abort";for(l in{success:1,error:1,complete:1})x[l](c[l]);o=kn(xn,c,n,x);if(!o)T(-1,"No Transport");else{x.readyState=1,f&&p.trigger("ajaxSend",[x,c]),c.async&&c.timeout>0&&(u=setTimeout(function(){x.abort("timeout")},c.timeout));try{E=1,o.send(b,T)}catch(k){if(!(E<2))throw k;T(-1,k)}}return x}return x.abort()},active:0,lastModified:{},etag:{}});var Mn=[],_n=/\?/,Dn=/(=)\?(?=&|$)|\?\?/,Pn=v.now();v.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Mn.pop()||v.expando+"_"+Pn++;return this[e]=!0,e}}),v.ajaxPrefilter("json jsonp",function(n,r,i){var s,o,u,a=n.data,f=n.url,l=n.jsonp!==!1,c=l&&Dn.test(f),h=l&&!c&&typeof a=="string"&&!(n.contentType||"").indexOf("application/x-www-form-urlencoded")&&Dn.test(a);if(n.dataTypes[0]==="jsonp"||c||h)return s=n.jsonpCallback=v.isFunction(n.jsonpCallback)?n.jsonpCallback():n.jsonpCallback,o=e[s],c?n.url=f.replace(Dn,"$1"+s):h?n.data=a.replace(Dn,"$1"+s):l&&(n.url+=(_n.test(f)?"&":"?")+n.jsonp+"="+s),n.converters["script json"]=function(){return u||v.error(s+" was not called"),u[0]},n.dataTypes[0]="json",e[s]=function(){u=arguments},i.always(function(){e[s]=o,n[s]&&(n.jsonpCallback=r.jsonpCallback,Mn.push(s)),u&&v.isFunction(o)&&o(u[0]),u=o=t}),"script"}),v.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(e){return v.globalEval(e),e}}}),v.ajaxPrefilter("script",function(e){e.cache===t&&(e.cache=!1),e.crossDomain&&(e.type="GET",e.global=!1)}),v.ajaxTransport("script",function(e){if(e.crossDomain){var n,r=i.head||i.getElementsByTagName("head")[0]||i.documentElement;return{send:function(s,o){n=i.createElement("script"),n.async="async",e.scriptCharset&&(n.charset=e.scriptCharset),n.src=e.url,n.onload=n.onreadystatechange=function(e,i){if(i||!n.readyState||/loaded|complete/.test(n.readyState))n.onload=n.onreadystatechange=null,r&&n.parentNode&&r.removeChild(n),n=t,i||o(200,"success")},r.insertBefore(n,r.firstChild)},abort:function(){n&&n.onload(0,1)}}}});var Hn,Bn=e.ActiveXObject?function(){for(var e in Hn)Hn[e](0,1)}:!1,jn=0;v.ajaxSettings.xhr=e.ActiveXObject?function(){return!this.isLocal&&Fn()||In()}:Fn,function(e){v.extend(v.support,{ajax:!!e,cors:!!e&&"withCredentials"in e})}(v.ajaxSettings.xhr()),v.support.ajax&&v.ajaxTransport(function(n){if(!n.crossDomain||v.support.cors){var r;return{send:function(i,s){var o,u,a=n.xhr();n.username?a.open(n.type,n.url,n.async,n.username,n.password):a.open(n.type,n.url,n.async);if(n.xhrFields)for(u in n.xhrFields)a[u]=n.xhrFields[u];n.mimeType&&a.overrideMimeType&&a.overrideMimeType(n.mimeType),!n.crossDomain&&!i["X-Requested-With"]&&(i["X-Requested-With"]="XMLHttpRequest");try{for(u in i)a.setRequestHeader(u,i[u])}catch(f){}a.send(n.hasContent&&n.data||null),r=function(e,i){var u,f,l,c,h;try{if(r&&(i||a.readyState===4)){r=t,o&&(a.onreadystatechange=v.noop,Bn&&delete Hn[o]);if(i)a.readyState!==4&&a.abort();else{u=a.status,l=a.getAllResponseHeaders(),c={},h=a.responseXML,h&&h.documentElement&&(c.xml=h);try{c.text=a.responseText}catch(p){}try{f=a.statusText}catch(p){f=""}!u&&n.isLocal&&!n.crossDomain?u=c.text?200:404:u===1223&&(u=204)}}}catch(d){i||s(-1,d)}c&&s(u,f,c,l)},n.async?a.readyState===4?setTimeout(r,0):(o=++jn,Bn&&(Hn||(Hn={},v(e).unload(Bn)),Hn[o]=r),a.onreadystatechange=r):r()},abort:function(){r&&r(0,1)}}}});var qn,Rn,Un=/^(?:toggle|show|hide)$/,zn=new RegExp("^(?:([-+])=|)("+m+")([a-z%]*)$","i"),Wn=/queueHooks$/,Xn=[Gn],Vn={"*":[function(e,t){var n,r,i=this.createTween(e,t),s=zn.exec(t),o=i.cur(),u=+o||0,a=1,f=20;if(s){n=+s[2],r=s[3]||(v.cssNumber[e]?"":"px");if(r!=="px"&&u){u=v.css(i.elem,e,!0)||n||1;do a=a||".5",u/=a,v.style(i.elem,e,u+r);while(a!==(a=i.cur()/o)&&a!==1&&--f)}i.unit=r,i.start=u,i.end=s[1]?u+(s[1]+1)*n:n}return i}]};v.Animation=v.extend(Kn,{tweener:function(e,t){v.isFunction(e)?(t=e,e=["*"]):e=e.split(" ");var n,r=0,i=e.length;for(;r-1,f={},l={},c,h;a?(l=i.position(),c=l.top,h=l.left):(c=parseFloat(o)||0,h=parseFloat(u)||0),v.isFunction(t)&&(t=t.call(e,n,s)),t.top!=null&&(f.top=t.top-s.top+c),t.left!=null&&(f.left=t.left-s.left+h),"using"in t?t.using.call(e,f):i.css(f)}},v.fn.extend({position:function(){if(!this[0])return;var e=this[0],t=this.offsetParent(),n=this.offset(),r=er.test(t[0].nodeName)?{top:0,left:0}:t.offset();return n.top-=parseFloat(v.css(e,"marginTop"))||0,n.left-=parseFloat(v.css(e,"marginLeft"))||0,r.top+=parseFloat(v.css(t[0],"borderTopWidth"))||0,r.left+=parseFloat(v.css(t[0],"borderLeftWidth"))||0,{top:n.top-r.top,left:n.left-r.left}},offsetParent:function(){return this.map(function(){var e=this.offsetParent||i.body;while(e&&!er.test(e.nodeName)&&v.css(e,"position")==="static")e=e.offsetParent;return e||i.body})}}),v.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(e,n){var r=/Y/.test(n);v.fn[e]=function(i){return v.access(this,function(e,i,s){var o=tr(e);if(s===t)return o?n in o?o[n]:o.document.documentElement[i]:e[i];o?o.scrollTo(r?v(o).scrollLeft():s,r?s:v(o).scrollTop()):e[i]=s},e,i,arguments.length,null)}}),v.each({Height:"height",Width:"width"},function(e,n){v.each({padding:"inner"+e,content:n,"":"outer"+e},function(r,i){v.fn[i]=function(i,s){var o=arguments.length&&(r||typeof i!="boolean"),u=r||(i===!0||s===!0?"margin":"border");return v.access(this,function(n,r,i){var s;return v.isWindow(n)?n.document.documentElement["client"+e]:n.nodeType===9?(s=n.documentElement,Math.max(n.body["scroll"+e],s["scroll"+e],n.body["offset"+e],s["offset"+e],s["client"+e])):i===t?v.css(n,r,i,u):v.style(n,r,i,u)},n,o?i:t,o,null)}})}),e.jQuery=e.$=v,typeof define=="function"&&define.amd&&define.amd.jQuery&&define("jquery",[],function(){return v})})(window); \ No newline at end of file -- cgit v1.2.3 From f410c902613e3e1f0d57c71b1065b69232ba92eb Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Tue, 13 Nov 2012 15:26:51 +0100 Subject: Cache identities data in memory for faster access when get_identity() is called more than once --- program/include/rcube_user.php | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) (limited to 'program') diff --git a/program/include/rcube_user.php b/program/include/rcube_user.php index b92187ad4..72b03cd15 100644 --- a/program/include/rcube_user.php +++ b/program/include/rcube_user.php @@ -47,6 +47,13 @@ class rcube_user */ private $rc; + /** + * Internal identities cache + * + * @var array + */ + private $identities = array(); + const SEARCH_ADDRESSBOOK = 1; const SEARCH_MAIL = 2; @@ -213,8 +220,14 @@ class rcube_user */ function get_identity($id = null) { - $result = $this->list_identities($id ? sprintf('AND identity_id = %d', $id) : ''); - return $result[0]; + $id = (int)$id; + // cache identities for better performance + if (!array_key_exists($id, $this->identities)) { + $result = $this->list_identities($id ? 'AND identity_id = ' . $id : ''); + $this->identities[$id] = $result[0]; + } + + return $this->identities[$id]; } @@ -273,6 +286,8 @@ class rcube_user call_user_func_array(array($this->db, 'query'), array_merge(array($sql), $query_params)); + $this->identities = array(); + return $this->db->affected_rows(); } @@ -305,6 +320,8 @@ class rcube_user call_user_func_array(array($this->db, 'query'), array_merge(array($sql), $insert_values)); + $this->identities = array(); + return $this->db->insert_id('identities'); } @@ -339,6 +356,8 @@ class rcube_user $this->ID, $iid); + $this->identities = array(); + return $this->db->affected_rows(); } @@ -359,6 +378,8 @@ class rcube_user " AND del <> 1", $this->ID, $iid); + + unset($this->identities[0]); } } -- cgit v1.2.3 From d9698de979f6d30b5126472edd4af60c43aba870 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Tue, 13 Nov 2012 18:08:52 +0100 Subject: Fix handling of 'media' attribute on linked css (#1488789) --- CHANGELOG | 1 + program/lib/washtml.php | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'program') diff --git a/CHANGELOG b/CHANGELOG index 0a6e1c9e4..dc2d182cf 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,7 @@ CHANGELOG Roundcube Webmail =========================== +- Fix handling of 'media' attribute on linked css (#1488789) - Fix excessive LFs at the end of composed message with top_posting=true (#1488797) - Option to display attached images as thumbnails below message body - Fix bug where leading blanks were stripped from quoted lines (#1488795) diff --git a/program/lib/washtml.php b/program/lib/washtml.php index d5cdb82f8..0d4ffdb4b 100644 --- a/program/lib/washtml.php +++ b/program/lib/washtml.php @@ -102,7 +102,7 @@ class washtml 'cellpadding', 'valign', 'bgcolor', 'color', 'border', 'bordercolorlight', 'bordercolordark', 'face', 'marginwidth', 'marginheight', 'axis', 'border', 'abbr', 'char', 'charoff', 'clear', 'compact', 'coords', 'vspace', 'hspace', - 'cellborder', 'size', 'lang', 'dir', 'usemap', 'shape', + 'cellborder', 'size', 'lang', 'dir', 'usemap', 'shape', 'media', // attributes of form elements 'type', 'rows', 'cols', 'disabled', 'readonly', 'checked', 'multiple', 'value' ); -- cgit v1.2.3 From 540e13b8d50a52e9cb479e36bc6d1e16275a2cd5 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Tue, 13 Nov 2012 19:44:52 +0100 Subject: Fix warning when 'autovalues' property isn't set --- program/include/rcube_ldap.php | 3 ++- program/steps/mail/func.inc | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'program') diff --git a/program/include/rcube_ldap.php b/program/include/rcube_ldap.php index 90ce73ae2..7cef25556 100644 --- a/program/include/rcube_ldap.php +++ b/program/include/rcube_ldap.php @@ -160,7 +160,8 @@ class rcube_ldap extends rcube_addressbook } // make sure LDAP_rdn field is required - if (!empty($this->prop['LDAP_rdn']) && !in_array($this->prop['LDAP_rdn'], $this->prop['required_fields']) && !in_array($this->prop['LDAP_rdn'], array_keys($this->prop['autovalues']))) { + if (!empty($this->prop['LDAP_rdn']) && !in_array($this->prop['LDAP_rdn'], $this->prop['required_fields']) + && !in_array($this->prop['LDAP_rdn'], array_keys((array)$this->prop['autovalues']))) { $this->prop['required_fields'][] = $this->prop['LDAP_rdn']; } diff --git a/program/steps/mail/func.inc b/program/steps/mail/func.inc index 5e24a4311..01d95e059 100644 --- a/program/steps/mail/func.inc +++ b/program/steps/mail/func.inc @@ -1110,6 +1110,7 @@ function rcmail_message_body($attrib) if (!empty($MESSAGE->parts)) { foreach ($MESSAGE->parts as $i => $part) { + console($part); if ($part->type == 'headers') $out .= rcmail_message_headers(sizeof($header_attrib) ? $header_attrib : NULL, $part->headers); else if ($part->type == 'content') { -- cgit v1.2.3 From 275728ab0511c5e89c372aaa5508dc0040c146b2 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Tue, 13 Nov 2012 19:47:16 +0100 Subject: Remove debug code from last commit --- program/steps/mail/func.inc | 1 - 1 file changed, 1 deletion(-) (limited to 'program') diff --git a/program/steps/mail/func.inc b/program/steps/mail/func.inc index 01d95e059..5e24a4311 100644 --- a/program/steps/mail/func.inc +++ b/program/steps/mail/func.inc @@ -1110,7 +1110,6 @@ function rcmail_message_body($attrib) if (!empty($MESSAGE->parts)) { foreach ($MESSAGE->parts as $i => $part) { - console($part); if ($part->type == 'headers') $out .= rcmail_message_headers(sizeof($header_attrib) ? $header_attrib : NULL, $part->headers); else if ($part->type == 'content') { -- cgit v1.2.3 From e30500643fbe0c9f9237570b73e59992f776cf0c Mon Sep 17 00:00:00 2001 From: Thomas Bruederli Date: Wed, 14 Nov 2012 10:28:34 +0100 Subject: Enable default behavior of the browser when shift/ctrl-click task links (e.g. open in new window/tab) --- program/include/rcube_output_html.php | 2 +- program/js/app.js | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) (limited to 'program') diff --git a/program/include/rcube_output_html.php b/program/include/rcube_output_html.php index db947bd2b..ac07d58e9 100644 --- a/program/include/rcube_output_html.php +++ b/program/include/rcube_output_html.php @@ -1087,7 +1087,7 @@ class rcube_output_html extends rcube_output // make valid href to specific buttons if (in_array($attrib['command'], rcmail::$main_tasks)) { $attrib['href'] = $this->app->url(array('task' => $attrib['command'])); - $attrib['onclick'] = sprintf("%s.command('switch-task','%s',null,event); return false", rcmail::JS_OBJECT_NAME, $attrib['command']); + $attrib['onclick'] = sprintf("return %s.command('switch-task','%s',this,event)", rcmail::JS_OBJECT_NAME, $attrib['command']); } else if ($attrib['task'] && in_array($attrib['task'], rcmail::$main_tasks)) { $attrib['href'] = $this->app->url(array('action' => $attrib['command'], 'task' => $attrib['task'])); diff --git a/program/js/app.js b/program/js/app.js index 0f5a60c6f..2a170b258 100644 --- a/program/js/app.js +++ b/program/js/app.js @@ -507,6 +507,11 @@ function rcube_webmail() if (this.busy) return false; + // let the browser handle this click (shift/ctrl usually opens the link in a new window/tab) + if ((obj && (obj.href.indexOf(location.href) < 0)) && rcube_event.get_modifier(event)) { + return true; + } + // command not supported or allowed if (!this.commands[command]) { // pass command to parent window @@ -562,7 +567,7 @@ function rcube_webmail() break; case 'about': - location.href = '?_task=settings&_action=about'; + this.redirect('?_task=settings&_action=about', false); break; case 'permaurl': -- cgit v1.2.3 From d15163ab6ecabde9d12e8674bee37cbe562bd850 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Wed, 14 Nov 2012 13:29:58 +0100 Subject: Fix XSS vulnerability in handling of text/enriched messages (#1488806) --- CHANGELOG | 1 + program/steps/mail/func.inc | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'program') diff --git a/CHANGELOG b/CHANGELOG index dc2d182cf..6ce469cd5 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,7 @@ CHANGELOG Roundcube Webmail =========================== +- Fix XSS vulnerability in handling of text/enriched messages (#1488806) - Fix handling of 'media' attribute on linked css (#1488789) - Fix excessive LFs at the end of composed message with top_posting=true (#1488797) - Option to display attached images as thumbnails below message body diff --git a/program/steps/mail/func.inc b/program/steps/mail/func.inc index 5e24a4311..3668cd7b2 100644 --- a/program/steps/mail/func.inc +++ b/program/steps/mail/func.inc @@ -753,7 +753,9 @@ function rcmail_print_body($part, $p = array()) else if ($data['type'] == 'enriched') { $part->ctype_secondary = 'html'; require_once(INSTALL_PATH . 'program/lib/enriched.inc'); - $body = Q(enriched_to_html($data['body']), 'show'); + $body = enriched_to_html($data['body']); + $body = rcmail_wash_html($body, $data, $part->replaces); + $part->ctype_secondary = 'html'; } else { // assert plaintext -- cgit v1.2.3 From 398238abf23ed74568c77d355c55a405fde730fe Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Wed, 14 Nov 2012 13:37:27 +0100 Subject: Remove redundant code --- program/steps/mail/func.inc | 1 - 1 file changed, 1 deletion(-) (limited to 'program') diff --git a/program/steps/mail/func.inc b/program/steps/mail/func.inc index 3668cd7b2..961a604a2 100644 --- a/program/steps/mail/func.inc +++ b/program/steps/mail/func.inc @@ -751,7 +751,6 @@ function rcmail_print_body($part, $p = array()) } // text/enriched else if ($data['type'] == 'enriched') { - $part->ctype_secondary = 'html'; require_once(INSTALL_PATH . 'program/lib/enriched.inc'); $body = enriched_to_html($data['body']); $body = rcmail_wash_html($body, $data, $part->replaces); -- cgit v1.2.3 From 0e8c6da864f3257e631659dc8834cb2c18854e37 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Wed, 14 Nov 2012 13:42:00 +0100 Subject: Fix "obj.href is undefined" error --- program/js/app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'program') diff --git a/program/js/app.js b/program/js/app.js index 2a170b258..1b4383480 100644 --- a/program/js/app.js +++ b/program/js/app.js @@ -508,7 +508,7 @@ function rcube_webmail() return false; // let the browser handle this click (shift/ctrl usually opens the link in a new window/tab) - if ((obj && (obj.href.indexOf(location.href) < 0)) && rcube_event.get_modifier(event)) { + if ((obj && obj.href && obj.href.indexOf(location.href) < 0) && rcube_event.get_modifier(event)) { return true; } -- cgit v1.2.3 From ce248f83e52092d264de23a0bd51a0233d6498e7 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Wed, 14 Nov 2012 13:52:23 +0100 Subject: Remove useless code --- program/include/rcube_message.php | 4 ---- 1 file changed, 4 deletions(-) (limited to 'program') diff --git a/program/include/rcube_message.php b/program/include/rcube_message.php index 47aa4493e..9b8484c15 100644 --- a/program/include/rcube_message.php +++ b/program/include/rcube_message.php @@ -270,10 +270,6 @@ class rcube_message else if ($part->mimetype == 'text/html') { $out = $this->get_part_content($mime_id); - // remove special chars encoding - $trans = array_flip(get_html_translation_table(HTML_ENTITIES)); - $out = strtr($out, $trans); - // create instance of html2text class $txt = new html2text($out); return $txt->get_text(); -- cgit v1.2.3 From 52d0d949104e6b43d8daa39dad64b20cc003440c Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Wed, 14 Nov 2012 13:58:15 +0100 Subject: Fix handling of text/enriched content on message reply/forward/edit --- CHANGELOG | 1 + program/include/rcube_message.php | 5 +++-- program/steps/mail/compose.inc | 20 +++++++++++++++++--- 3 files changed, 21 insertions(+), 5 deletions(-) (limited to 'program') diff --git a/CHANGELOG b/CHANGELOG index 6ce469cd5..9f8464c5f 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,7 @@ CHANGELOG Roundcube Webmail =========================== +- Fix handling of text/enriched content on message reply/forward/edit - Fix XSS vulnerability in handling of text/enriched messages (#1488806) - Fix handling of 'media' attribute on linked css (#1488789) - Fix excessive LFs at the end of composed message with top_posting=true (#1488797) diff --git a/program/include/rcube_message.php b/program/include/rcube_message.php index 9b8484c15..74bf4574f 100644 --- a/program/include/rcube_message.php +++ b/program/include/rcube_message.php @@ -198,14 +198,15 @@ class rcube_message * Determine if the message contains a HTML part * * @param bool $recursive Enables checking in all levels of the structure + * @param bool $enriched Enables checking for text/enriched parts too * * @return bool True if a HTML is available, False if not */ - function has_html_part($recursive = true) + function has_html_part($recursive = true, $enriched = false) { // check all message parts foreach ($this->parts as $part) { - if ($part->mimetype == 'text/html') { + if ($part->mimetype == 'text/html' || ($enriched && $part->mimetype == 'text/enriched')) { // Level check, we'll skip e.g. HTML attachments if (!$recursive) { $level = explode('.', $part->mime_id); diff --git a/program/steps/mail/compose.inc b/program/steps/mail/compose.inc index 87a06e10d..ffc1c7518 100644 --- a/program/steps/mail/compose.inc +++ b/program/steps/mail/compose.inc @@ -611,13 +611,13 @@ function rcmail_compose_editor_mode() $useHtml = !empty($_POST['_is_html']); } else if ($compose_mode == RCUBE_COMPOSE_DRAFT || $compose_mode == RCUBE_COMPOSE_EDIT) { - $useHtml = $MESSAGE->has_html_part(false); + $useHtml = $MESSAGE->has_html_part(false, true); } else if ($compose_mode == RCUBE_COMPOSE_REPLY) { - $useHtml = ($html_editor == 1 || ($html_editor >= 2 && $MESSAGE->has_html_part(false))); + $useHtml = ($html_editor == 1 || ($html_editor >= 2 && $MESSAGE->has_html_part(false, true))); } else if ($compose_mode == RCUBE_COMPOSE_FORWARD) { - $useHtml = ($html_editor == 1 || ($html_editor == 3 && $MESSAGE->has_html_part(false))); + $useHtml = ($html_editor == 1 || ($html_editor == 3 && $MESSAGE->has_html_part(false, true))); } else { $useHtml = ($html_editor == 1); @@ -730,6 +730,10 @@ function rcmail_compose_part_body($part, $isHtml = false) if ($isHtml) { if ($part->ctype_secondary == 'html') { } + else if ($part->ctype_secondary == 'enriched') { + require_once(INSTALL_PATH . 'program/lib/enriched.inc'); + $body = enriched_to_html($body); + } else { // try to remove the signature if ($RCMAIL->config->get('strip_existing_sig', true)) { @@ -743,6 +747,12 @@ function rcmail_compose_part_body($part, $isHtml = false) } } else { + if ($part->ctype_secondary == 'enriched') { + require_once(INSTALL_PATH . 'program/lib/enriched.inc'); + $body = enriched_to_html($body); + $part->ctype_secondary = 'html'; + } + if ($part->ctype_secondary == 'html') { // use html part if it has been used for message (pre)viewing // decrease line length for quoting @@ -750,6 +760,10 @@ function rcmail_compose_part_body($part, $isHtml = false) $txt = new html2text($body, false, true, $len); $body = $txt->get_text(); } + else if ($part->ctype_secondary == 'enriched') { + require_once(INSTALL_PATH . 'program/lib/enriched.inc'); + $body = enriched_to_html($body); + } else { if ($part->ctype_secondary == 'plain' && $part->ctype_parameters['format'] == 'flowed') { $body = rcube_mime::unfold_flowed($body); -- cgit v1.2.3 From 0f6e9f0bf692ae87be460eb3553e3f55349d725b Mon Sep 17 00:00:00 2001 From: Thomas Bruederli Date: Wed, 14 Nov 2012 16:18:27 +0100 Subject: Avoid errors with non-string objects --- program/js/app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'program') diff --git a/program/js/app.js b/program/js/app.js index 1b4383480..1891977a7 100644 --- a/program/js/app.js +++ b/program/js/app.js @@ -508,7 +508,7 @@ function rcube_webmail() return false; // let the browser handle this click (shift/ctrl usually opens the link in a new window/tab) - if ((obj && obj.href && obj.href.indexOf(location.href) < 0) && rcube_event.get_modifier(event)) { + if ((obj && obj.href && String(obj.href).indexOf(location.href) < 0) && rcube_event.get_modifier(event)) { return true; } -- cgit v1.2.3 From 3c047d0e87339e2eeb2d8784def2b270201f88ac Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Thu, 15 Nov 2012 09:56:41 +0100 Subject: Code improvements --- program/js/app.js | 64 +++++++++++++++++++++++++++---------------------------- 1 file changed, 31 insertions(+), 33 deletions(-) (limited to 'program') diff --git a/program/js/app.js b/program/js/app.js index 88e4606a7..90b4ebbcf 100644 --- a/program/js/app.js +++ b/program/js/app.js @@ -21,7 +21,6 @@ function rcube_webmail() { - this.env = { recipients_separator:',', recipients_delimiter:', ' }; this.labels = {}; this.buttons = {}; this.buttons_sel = {}; @@ -33,21 +32,24 @@ function rcube_webmail() this.messages = {}; this.group2expand = {}; - // create protected reference to myself - this.ref = 'rcmail'; - var ref = this; - // webmail client settings this.dblclick_time = 500; this.message_time = 4000; - this.identifier_expr = new RegExp('[^0-9a-z\-_]', 'gi'); - // default environment vars - this.env.request_timeout = 180; // seconds - this.env.draft_autosave = 0; // seconds - this.env.comm_path = './'; - this.env.blankpage = 'program/resources/blank.gif'; + // environment defaults + this.env = { + request_timeout: 180, // seconds + draft_autosave: 0, // seconds + comm_path: './', + blankpage: 'program/resources/blank.gif', + recipients_separator: ',', + recipients_delimiter: ', ' + }; + + // create protected reference to myself + this.ref = 'rcmail'; + var ref = this; // set jQuery ajax options $.ajaxSetup({ @@ -57,6 +59,7 @@ function rcube_webmail() beforeSend: function(xmlhttp){ xmlhttp.setRequestHeader('X-Roundcube-Request', ref.env.request_token); } }); + // unload fix $(window).bind('beforeunload', function() { rcmail.unload = true; }); // set environment variable(s) @@ -81,14 +84,15 @@ function rcube_webmail() // add a button to the button list this.register_button = function(command, id, type, act, sel, over) { - if (!this.buttons[command]) - this.buttons[command] = []; - var button_prop = {id:id, type:type}; + if (act) button_prop.act = act; if (sel) button_prop.sel = sel; if (over) button_prop.over = over; + if (!this.buttons[command]) + this.buttons[command] = []; + this.buttons[command].push(button_prop); if (this.loaded) @@ -187,7 +191,6 @@ function rcube_webmail() this.enable_command('list', 'checkmail', 'add-contact', 'search', 'reset-search', 'collapse-folder', true); if (this.gui_objects.messagelist) { - this.message_list = new rcube_list_widget(this.gui_objects.messagelist, { multiselect:true, multiexpand:true, draggable:true, keyboard:true, column_movable:this.env.col_movable, dblclick_time:this.dblclick_time @@ -214,9 +217,8 @@ function rcube_webmail() } if (this.gui_objects.qsearchbox) { - if (this.env.search_text != null) { + if (this.env.search_text != null) this.gui_objects.qsearchbox.value = this.env.search_text; - } $(this.gui_objects.qsearchbox).focusin(function() { rcmail.message_list.blur(); }); } @@ -322,7 +324,6 @@ function rcube_webmail() this.enable_command('list', 'listgroup', 'listsearch', 'advanced-search', true); if (this.gui_objects.contactslist) { - this.contact_list = new rcube_list_widget(this.gui_objects.contactslist, {multiselect:true, draggable:this.gui_objects.folderlist?true:false, keyboard:true}); this.contact_list.row_init = function(row){ p.triggerEvent('insertrow', { cid:row.uid, row:row }); }; @@ -338,9 +339,8 @@ function rcube_webmail() this.gui_objects.contactslist.parentNode.onmousedown = function(e){ return p.click_on_list(e); }; document.onmouseup = function(e){ return p.doc_mouse_up(e); }; - if (this.gui_objects.qsearchbox) { + if (this.gui_objects.qsearchbox) $(this.gui_objects.qsearchbox).focusin(function() { rcmail.contact_list.blur(); }); - } this.update_group_commands(); this.command('list'); @@ -364,9 +364,8 @@ function rcube_webmail() this.init_contact_form(); } - if (this.gui_objects.qsearchbox) { + if (this.gui_objects.qsearchbox) this.enable_command('search', 'reset-search', 'moveto', true); - } break; @@ -597,7 +596,7 @@ function rcube_webmail() case 'open': if (uid = this.get_single_uid()) { - obj.href = '?_task='+this.env.task+'&_action=show&_mbox='+urlencode(this.env.mailbox)+'&_uid='+uid; + obj.href = this.url('show', {_mbox: this.env.mailbox, _uid: uid}); return true; } break; @@ -610,9 +609,8 @@ function rcube_webmail() case 'list': if (props && props != '') this.reset_qsearch(); - if (this.env.action == 'compose' && this.env.extwin) { + if (this.env.action == 'compose' && this.env.extwin) window.close(); - } else if (this.task == 'mail') { this.list_mailbox(props); this.set_button_titles(); @@ -780,9 +778,8 @@ function rcube_webmail() uid = props._row.uid; // toggle read/unread - if (this.message_list.rows[uid].deleted) { + if (this.message_list.rows[uid].deleted) flag = 'undelete'; - } else if (!this.message_list.rows[uid].unread) flag = 'unread'; } @@ -801,7 +798,7 @@ function rcube_webmail() // toggle flagged/unflagged if (this.message_list.rows[uid].flagged) flag = 'unflagged'; - } + } this.mark_message(flag, uid); break; @@ -877,7 +874,7 @@ function rcube_webmail() case 'previousmessage': if (this.env.prev_uid) - this.show_message(this.env.prev_uid, false, this.env.action=='preview'); + this.show_message(this.env.prev_uid, false, this.env.action == 'preview'); break; case 'firstmessage': @@ -6570,7 +6567,8 @@ function rcube_webmail() { if (obj.selectionEnd !== undefined) return obj.selectionEnd; - else if (document.selection && document.selection.createRange) { + + if (document.selection && document.selection.createRange) { var range = document.selection.createRange(); if (range.parentElement() != obj) return 0; @@ -6584,10 +6582,10 @@ function rcube_webmail() gm.setEndPoint('EndToStart', range); var p = gm.text.length; - return p<=obj.value.length ? p : -1; + return p <= obj.value.length ? p : -1; } - else - return obj.value.length; + + return obj.value.length; }; // moves cursor to specified position -- cgit v1.2.3 From 0679b22150dfded4383d0729940a888fcc7a1b99 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Thu, 15 Nov 2012 13:55:42 +0100 Subject: Improved rcube_charset::detect() with BOM checks from rcube_vcard::detect_encoding() - removed code duplication --- program/include/rcube_charset.php | 57 ++++++++++++++++++++++++++++----------- program/include/rcube_vcard.php | 39 +++------------------------ 2 files changed, 45 insertions(+), 51 deletions(-) (limited to 'program') diff --git a/program/include/rcube_charset.php b/program/include/rcube_charset.php index ff4c2bbce..e6da882ac 100644 --- a/program/include/rcube_charset.php +++ b/program/include/rcube_charset.php @@ -655,22 +655,49 @@ class rcube_charset */ public static function detect($string, $failover='') { - if (!function_exists('mb_detect_encoding')) { - return $failover; - } - - // FIXME: the order is important, because sometimes - // iso string is detected as euc-jp and etc. - $enc = array( - 'UTF-8', 'SJIS', 'BIG5', 'GB2312', - 'ISO-8859-1', 'ISO-8859-2', 'ISO-8859-3', 'ISO-8859-4', - 'ISO-8859-5', 'ISO-8859-6', 'ISO-8859-7', 'ISO-8859-8', 'ISO-8859-9', - 'ISO-8859-10', 'ISO-8859-13', 'ISO-8859-14', 'ISO-8859-15', 'ISO-8859-16', - 'WINDOWS-1252', 'WINDOWS-1251', 'EUC-JP', 'EUC-TW', 'KOI8-R', - 'ISO-2022-KR', 'ISO-2022-JP' - ); + if (substr($string, 0, 4) == "\0\0\xFE\xFF") return 'UTF-32BE'; // Big Endian + if (substr($string, 0, 4) == "\xFF\xFE\0\0") return 'UTF-32LE'; // Little Endian + if (substr($string, 0, 2) == "\xFE\xFF") return 'UTF-16BE'; // Big Endian + if (substr($string, 0, 2) == "\xFF\xFE") return 'UTF-16LE'; // Little Endian + if (substr($string, 0, 3) == "\xEF\xBB\xBF") return 'UTF-8'; + + // heuristics + if ($string[0] == "\0" && $string[1] == "\0" && $string[2] == "\0" && $string[3] != "\0") return 'UTF-32BE'; + if ($string[0] != "\0" && $string[1] == "\0" && $string[2] == "\0" && $string[3] == "\0") return 'UTF-32LE'; + if ($string[0] == "\0" && $string[1] != "\0" && $string[2] == "\0" && $string[3] != "\0") return 'UTF-16BE'; + if ($string[0] != "\0" && $string[1] == "\0" && $string[2] != "\0" && $string[3] == "\0") return 'UTF-16LE'; + + if (function_exists('mb_detect_encoding')) { + // FIXME: the order is important, because sometimes + // iso string is detected as euc-jp and etc. + $enc = array( + 'UTF-8', 'SJIS', 'BIG5', 'GB2312', + 'ISO-8859-1', 'ISO-8859-2', 'ISO-8859-3', 'ISO-8859-4', + 'ISO-8859-5', 'ISO-8859-6', 'ISO-8859-7', 'ISO-8859-8', 'ISO-8859-9', + 'ISO-8859-10', 'ISO-8859-13', 'ISO-8859-14', 'ISO-8859-15', 'ISO-8859-16', + 'WINDOWS-1252', 'WINDOWS-1251', 'EUC-JP', 'EUC-TW', 'KOI8-R', + 'ISO-2022-KR', 'ISO-2022-JP' + ); - $result = mb_detect_encoding($string, join(',', $enc)); + $result = mb_detect_encoding($string, join(',', $enc)); + } + else { + // No match, check for UTF-8 + // from http://w3.org/International/questions/qa-forms-utf-8.html + if (preg_match('/\A( + [\x09\x0A\x0D\x20-\x7E] + | [\xC2-\xDF][\x80-\xBF] + | \xE0[\xA0-\xBF][\x80-\xBF] + | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} + | \xED[\x80-\x9F][\x80-\xBF] + | \xF0[\x90-\xBF][\x80-\xBF]{2} + | [\xF1-\xF3][\x80-\xBF]{3} + | \xF4[\x80-\x8F][\x80-\xBF]{2} + )*\z/xs', substr($string, 0, 2048)) + ) { + return 'UTF-8'; + } + } return $result ? $result : $failover; } diff --git a/program/include/rcube_vcard.php b/program/include/rcube_vcard.php index 00903c257..65598e735 100644 --- a/program/include/rcube_vcard.php +++ b/program/include/rcube_vcard.php @@ -784,42 +784,9 @@ class rcube_vcard */ private static function detect_encoding($string) { - if (substr($string, 0, 4) == "\0\0\xFE\xFF") return 'UTF-32BE'; // Big Endian - if (substr($string, 0, 4) == "\xFF\xFE\0\0") return 'UTF-32LE'; // Little Endian - if (substr($string, 0, 2) == "\xFE\xFF") return 'UTF-16BE'; // Big Endian - if (substr($string, 0, 2) == "\xFF\xFE") return 'UTF-16LE'; // Little Endian - if (substr($string, 0, 3) == "\xEF\xBB\xBF") return 'UTF-8'; - - // heuristics - if ($string[0] == "\0" && $string[1] == "\0" && $string[2] == "\0" && $string[3] != "\0") return 'UTF-32BE'; - if ($string[0] != "\0" && $string[1] == "\0" && $string[2] == "\0" && $string[3] == "\0") return 'UTF-32LE'; - if ($string[0] == "\0" && $string[1] != "\0" && $string[2] == "\0" && $string[3] != "\0") return 'UTF-16BE'; - if ($string[0] != "\0" && $string[1] == "\0" && $string[2] != "\0" && $string[3] == "\0") return 'UTF-16LE'; - - // use mb_detect_encoding() - $encodings = array('UTF-8', 'ISO-8859-1', 'ISO-8859-2', 'ISO-8859-3', - 'ISO-8859-4', 'ISO-8859-5', 'ISO-8859-6', 'ISO-8859-7', 'ISO-8859-8', 'ISO-8859-9', - 'ISO-8859-10', 'ISO-8859-13', 'ISO-8859-14', 'ISO-8859-15', 'ISO-8859-16', - 'WINDOWS-1252', 'WINDOWS-1251', 'BIG5', 'GB2312'); - - if (function_exists('mb_detect_encoding') && ($enc = mb_detect_encoding($string, $encodings))) - return $enc; - - // No match, check for UTF-8 - // from http://w3.org/International/questions/qa-forms-utf-8.html - if (preg_match('/\A( - [\x09\x0A\x0D\x20-\x7E] - | [\xC2-\xDF][\x80-\xBF] - | \xE0[\xA0-\xBF][\x80-\xBF] - | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} - | \xED[\x80-\x9F][\x80-\xBF] - | \xF0[\x90-\xBF][\x80-\xBF]{2} - | [\xF1-\xF3][\x80-\xBF]{3} - | \xF4[\x80-\x8F][\x80-\xBF]{2} - )*\z/xs', substr($string, 0, 2048))) - return 'UTF-8'; - - return rcube::get_instance()->config->get('default_charset', 'ISO-8859-1'); # fallback to Latin-1 + $fallback = rcube::get_instance()->config->get('default_charset', 'ISO-8859-1'); // fallback to Latin-1 + + return rcube_charset::detect($string, $fallback); } } -- cgit v1.2.3 From c8558a182cc218e4aba89f6c42a9e39de20bc0e6 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Thu, 15 Nov 2012 13:58:57 +0100 Subject: Move BIG5 at the end of charsets list in detect() --- program/include/rcube_charset.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'program') diff --git a/program/include/rcube_charset.php b/program/include/rcube_charset.php index e6da882ac..4d24ed135 100644 --- a/program/include/rcube_charset.php +++ b/program/include/rcube_charset.php @@ -671,12 +671,12 @@ class rcube_charset // FIXME: the order is important, because sometimes // iso string is detected as euc-jp and etc. $enc = array( - 'UTF-8', 'SJIS', 'BIG5', 'GB2312', + 'UTF-8', 'SJIS', 'GB2312', 'ISO-8859-1', 'ISO-8859-2', 'ISO-8859-3', 'ISO-8859-4', 'ISO-8859-5', 'ISO-8859-6', 'ISO-8859-7', 'ISO-8859-8', 'ISO-8859-9', 'ISO-8859-10', 'ISO-8859-13', 'ISO-8859-14', 'ISO-8859-15', 'ISO-8859-16', - 'WINDOWS-1252', 'WINDOWS-1251', 'EUC-JP', 'EUC-TW', 'KOI8-R', - 'ISO-2022-KR', 'ISO-2022-JP' + 'WINDOWS-1252', 'WINDOWS-1251', 'EUC-JP', 'EUC-TW', 'KOI8-R', 'BIG5', + 'ISO-2022-KR', 'ISO-2022-JP', ); $result = mb_detect_encoding($string, join(',', $enc)); -- cgit v1.2.3 From 3a54cc50134806cc8e53abf0efa6faf416182990 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Thu, 15 Nov 2012 15:36:10 +0100 Subject: Fix rcube_utils::explode_quoted_string() with explode(), added tests --- program/include/rcube_utils.php | 2 +- tests/Framework/Utils.php | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) (limited to 'program') diff --git a/program/include/rcube_utils.php b/program/include/rcube_utils.php index 2a4d4c482..5cfd8e70e 100644 --- a/program/include/rcube_utils.php +++ b/program/include/rcube_utils.php @@ -761,7 +761,7 @@ class rcube_utils } } - $result[] = substr($string, $p); + $result[] = (string) substr($string, $p); return $result; } diff --git a/tests/Framework/Utils.php b/tests/Framework/Utils.php index e58835956..ec61c5d4b 100644 --- a/tests/Framework/Utils.php +++ b/tests/Framework/Utils.php @@ -193,4 +193,17 @@ class Framework_Utils extends PHPUnit_Framework_TestCase $mod = rcube_utils::mod_css_styles("background:\\0075\\0072\\006c( javascript:alert('xss') )", 'rcmbody'); $this->assertEquals("/* evil! */", $mod, "Don't allow encoding quirks (2)"); } + + /** + * Check rcube_utils::explode_quoted_string() compat. with explode() + */ + function test_explode_quoted_string_compat() + { + $data = array('', 'a,b,c', 'a', ',', ',a'); + + foreach ($data as $text) { + $result = rcube_utils::explode_quoted_string(',', $text); + $this->assertSame(explode(',', $text), $result); + } + } } -- cgit v1.2.3 From c055587d4554d5317a4bb57eaf5acbd9d56789f6 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Fri, 16 Nov 2012 13:18:21 +0100 Subject: Properly set object properties in set() method, small perf. improvement --- program/include/rcube_vcard.php | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'program') diff --git a/program/include/rcube_vcard.php b/program/include/rcube_vcard.php index 65598e735..51a7fe71a 100644 --- a/program/include/rcube_vcard.php +++ b/program/include/rcube_vcard.php @@ -62,7 +62,6 @@ class rcube_vcard public $middlename; public $nickname; public $organization; - public $notes; public $email = array(); public static $eol = "\r\n"; @@ -265,26 +264,25 @@ class rcube_vcard */ public function set($field, $value, $type = 'HOME') { - $field = strtolower($field); + $field = strtolower($field); $type_uc = strtoupper($type); - $typemap = array_flip($this->typemap); switch ($field) { case 'name': case 'displayname': - $this->raw['FN'][0][0] = $value; + $this->raw['FN'][0][0] = $this->displayname = $value; break; case 'surname': - $this->raw['N'][0][0] = $value; + $this->raw['N'][0][0] = $this->surname = $value; break; case 'firstname': - $this->raw['N'][0][1] = $value; + $this->raw['N'][0][1] = $this->firstname = $value; break; case 'middlename': - $this->raw['N'][0][2] = $value; + $this->raw['N'][0][2] = $this->middlename = $value; break; case 'prefix': @@ -296,11 +294,11 @@ class rcube_vcard break; case 'nickname': - $this->raw['NICKNAME'][0][0] = $value; + $this->raw['NICKNAME'][0][0] = $this->nickname = $value; break; case 'organization': - $this->raw['ORG'][0][0] = $value; + $this->raw['ORG'][0][0] = $this->organization = $value; break; case 'photo': @@ -348,8 +346,10 @@ class rcube_vcard if (($tag = self::$fieldmap[$field]) && (is_array($value) || strlen($value))) { $index = count($this->raw[$tag]); $this->raw[$tag][$index] = (array)$value; - if ($type) + if ($type) { + $typemap = array_flip($this->typemap); $this->raw[$tag][$index]['type'] = explode(',', ($typemap[$type_uc] ? $typemap[$type_uc] : $type)); + } } break; } -- cgit v1.2.3 From 3833790db4dee8607b31c84f26eb0e95bae4c906 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Fri, 16 Nov 2012 13:22:10 +0100 Subject: Support contacts import from CSV file (#1486399) --- CHANGELOG | 1 + program/include/rcube_csv2vcard.php | 351 +++++++++++++++++++++++++++++++ program/localization/en_US/csv2vcard.inc | 93 ++++++++ program/localization/en_US/labels.inc | 2 +- program/localization/en_US/messages.inc | 8 +- program/steps/addressbook/import.inc | 17 +- tests/Framework/Csv2vcard.php | 57 +++++ tests/phpunit.xml | 1 + tests/src/Csv2vcard/email.csv | 5 + tests/src/Csv2vcard/email.vcf | 20 ++ tests/src/Csv2vcard/tb_plain.csv | 2 + tests/src/Csv2vcard/tb_plain.vcf | 18 ++ 12 files changed, 565 insertions(+), 10 deletions(-) create mode 100644 program/include/rcube_csv2vcard.php create mode 100644 program/localization/en_US/csv2vcard.inc create mode 100644 tests/Framework/Csv2vcard.php create mode 100644 tests/src/Csv2vcard/email.csv create mode 100644 tests/src/Csv2vcard/email.vcf create mode 100644 tests/src/Csv2vcard/tb_plain.csv create mode 100644 tests/src/Csv2vcard/tb_plain.vcf (limited to 'program') diff --git a/CHANGELOG b/CHANGELOG index 8a105e7a1..dea5cda51 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,7 @@ CHANGELOG Roundcube Webmail =========================== +- Support contacts import from CSV file (#1486399) - Improved keep-alive action. Now the interval is based on session_lifetime (#1488507) - Added cross-task 'refresh' request for system state updates (#1488507) - Renamed config options: keep_alive to refresh_interval, min_keep_alive to min_refresh_interval diff --git a/program/include/rcube_csv2vcard.php b/program/include/rcube_csv2vcard.php new file mode 100644 index 000000000..f84108ded --- /dev/null +++ b/program/include/rcube_csv2vcard.php @@ -0,0 +1,351 @@ + | + +-----------------------------------------------------------------------+ +*/ + +/** + * CSV to vCard data converter + * + * @package Roundcube Framework + * @author Aleksander Machniak + */ +class rcube_csv2vcard +{ + /** + * CSV to vCard fields mapping + * + * @var array + */ + protected $csv2vcard_map = array( + // MS Outlook 2010 + 'anniversary' => 'anniversary', + 'assistants_name' => 'assistant', + 'assistants_phone' => 'phone:assistant', + 'birthday' => 'birthday', + 'business_city' => 'locality:work', + 'business_countryregion' => 'country:work', + 'business_fax' => 'phone:work,fax', + 'business_phone' => 'phone:work', + 'business_phone_2' => 'phone:work2', + 'business_postal_code' => 'zipcode:work', + 'business_state' => 'region:work', + 'business_street' => 'street:work', + //'business_street_2' => '', + //'business_street_3' => '', + 'car_phone' => 'phone:car', + 'categories' => 'categories', + //'children' => '', + 'company' => 'organization', + //'company_main_phone' => '', + 'department' => 'department', + //'email_2_address' => '', //@TODO + //'email_2_type' => '', //@TODO + //'email_3_address' => '', //@TODO + //'email_3_type' => '', //@TODO + 'email_address' => 'email:main', + //'email_type' => '', //@TODO + 'first_name' => 'firstname', + 'gender' => 'gender', + 'home_city' => 'locality:home', + 'home_countryregion' => 'country:home', + 'home_fax' => 'phone:home,fax', + 'home_phone' => 'phone:home', + 'home_phone_2' => 'phone:home2', + 'home_postal_code' => 'zipcode:home', + 'home_state' => 'region:home', + 'home_street' => 'street:home', + //'home_street_2' => '', + //'home_street_3' => '', + //'initials' => '', + //'isdn' => '', + 'job_title' => 'jobtitle', + //'keywords' => '', + //'language' => '', + 'last_name' => 'surname', + //'location' => '', + 'managers_name' => 'manager', + 'middle_name' => 'middlename', + //'mileage' => '', + 'mobile_phone' => 'phone:cell', + 'notes' => 'notes', + //'office_location' => '', + 'other_city' => 'locality:other', + 'other_countryregion' => 'country:other', + 'other_fax' => 'phone:other,fax', + 'other_phone' => 'phone:other', + 'other_postal_code' => 'zipcode:other', + 'other_state' => 'region:other', + 'other_street' => 'street:other', + //'other_street_2' => '', + //'other_street_3' => '', + 'pager' => 'phone:pager', + 'primary_phone' => 'phone:pref', + //'profession' => '', + //'radio_phone' => '', + 'spouse' => 'spouse', + 'suffix' => 'suffix', + 'title' => 'title', + 'web_page' => 'website:homepage', + + // Thunderbird + 'birth_day' => 'birthday-d', + 'birth_month' => 'birthday-m', + 'birth_year' => 'birthday-y', + 'display_name' => 'displayname', + 'fax_number' => 'phone:fax', + 'home_address' => 'street:home', + //'home_address_2' => '', + 'home_country' => 'country:home', + 'home_zipcode' => 'zipcode:home', + 'mobile_number' => 'phone:cell', + 'nickname' => 'nickname', + 'organization' => 'organization', + 'pager_number' => 'phone:pager', + 'primary_email' => 'email:pref', + 'secondary_email' => 'email:other', + 'web_page_1' => 'website:homepage', + 'web_page_2' => 'website:other', + 'work_phone' => 'phone:work', + 'work_address' => 'street:work', + //'work_address_2' => '', + 'work_country' => 'country:work', + 'work_zipcode' => 'zipcode:work', + ); + + /** + * CSV label to text mapping for English + * + * @var array + */ + protected $label_map = array( + // MS Outlook 2010 + 'anniversary' => "Anniversary", + 'assistants_name' => "Assistant's Name", + 'assistants_phone' => "Assistant's Phone", + 'birthday' => "Birthday", + 'business_city' => "Business City", + 'business_countryregion' => "Business Country/Region", + 'business_fax' => "Business Fax", + 'business_phone' => "Business Phone", + 'business_phone_2' => "Business Phone 2", + 'business_postal_code' => "Business Postal Code", + 'business_state' => "Business State", + 'business_street' => "Business Street", + //'business_street_2' => "Business Street 2", + //'business_street_3' => "Business Street 3", + 'car_phone' => "Car Phone", + 'categories' => "Categories", + //'children' => "Children", + 'company' => "Company", + //'company_main_phone' => "Company Main Phone", + 'department' => "Department", + //'directory_server' => "Directory Server", + //'email_2_address' => "E-mail 2 Address", //@TODO + //'email_2_type' => "E-mail 2 Type", //@TODO + //'email_3_address' => "E-mail 3 Address", //@TODO + //'email_3_type' => "E-mail 3 Type", //@TODO + 'email_address' => "E-mail Address", + //'email_type' => "E-mail Type", //@TODO + 'first_name' => "First Name", + 'gender' => "Gender", + 'home_city' => "Home City", + 'home_countryregion' => "Home Country/Region", + 'home_fax' => "Home Fax", + 'home_phone' => "Home Phone", + 'home_phone_2' => "Home Phone 2", + 'home_postal_code' => "Home Postal Code", + 'home_state' => "Home State", + 'home_street' => "Home Street", + //'home_street_2' => "Home Street 2", + //'home_street_3' => "Home Street 3", + //'initials' => "Initials", + //'isdn' => "ISDN", + 'job_title' => "Job Title", + //'keywords' => "Keywords", + //'language' => "Language", + 'last_name' => "Last Name", + //'location' => "Location", + 'managers_name' => "Manager's Name", + 'middle_name' => "Middle Name", + //'mileage' => "Mileage", + 'mobile_phone' => "Mobile Phone", + 'notes' => "Notes", + //'office_location' => "Office Location", + 'other_city' => "Other City", + 'other_countryregion' => "Other Country/Region", + 'other_fax' => "Other Fax", + 'other_phone' => "Other Phone", + 'other_postal_code' => "Other Postal Code", + 'other_state' => "Other State", + 'other_street' => "Other Street", + //'other_street_2' => "Other Street 2", + //'other_street_3' => "Other Street 3", + 'pager' => "Pager", + 'primary_phone' => "Primary Phone", + //'profession' => "Profession", + //'radio_phone' => "Radio Phone", + 'spouse' => "Spouse", + 'suffix' => "Suffix", + 'title' => "Title", + 'web_page' => "Web Page", + + // Thunderbird + 'birth_day' => "Birth Day", + 'birth_month' => "Birth Month", + 'birth_year' => "Birth Year", + 'display_name' => "Display Name", + 'fax_number' => "Fax Number", + 'home_address' => "Home Address", + //'home_address_2' => "Home Address 2", + 'home_country' => "Home Country", + 'home_zipcode' => "Home ZipCode", + 'mobile_number' => "Mobile Number", + 'nickname' => "Nickname", + 'organization' => "Organization", + 'pager_number' => "Pager Namber", + 'primary_email' => "Primary Email", + 'secondary_email' => "Secondary Email", + 'web_page_1' => "Web Page 1", + 'web_page_2' => "Web Page 2", + 'work_phone' => "Work Phone", + 'work_address' => "Work Address", + //'work_address_2' => "Work Address 2", + 'work_country' => "Work Country", + 'work_zipcode' => "Work ZipCode", + ); + + protected $vcards = array(); + protected $map = array(); + + + /** + * Class constructor + * + * @param string $lang File language + */ + public function __construct($lang = 'en_US') + { + // Localize fields map + if ($lang && $lang != 'en_US') { + if (file_exists(INSTALL_PATH . "program/localization/$lang/csv2vcard.inc")) { + include INSTALL_PATH . "program/localization/$lang/csv2vcard.inc"; + } + + if (!empty($map)) { + $this->label_map = array_merge($this->label_map, $map); + } + } + + $this->label_map = array_flip($this->label_map); + } + + /** + * + */ + public function import($csv) + { + // convert to UTF-8 + $head = substr($csv, 0, 4096); + $fallback = rcube::get_instance()->config->get('default_charset', 'ISO-8859-1'); // fallback to Latin-1? + $charset = rcube_charset::detect($head, RCMAIL_CHARSET); + $csv = rcube_charset::convert($csv, $charset); + $head = ''; + + $this->map = array(); + + // Parse file + foreach (preg_split("/[\r\n]+/", $csv) as $i => $line) { + $line = trim($line); + if (empty($line)) { + continue; + } + + $elements = rcube_utils::explode_quoted_string(',', $line); + + if (empty($elements)) { + continue; + } + + // Parse header + if (empty($this->map)) { + $this->parse_header($elements); + if (empty($this->map)) { + break; + } + } + // Parse data row + else { + $this->csv_to_vcard($elements); + } + } + } + + /** + * @return array rcube_vcard List of vcards + */ + public function export() + { + return $this->vcards; + } + + /** + * Parse CSV header line, detect fields mapping + */ + protected function parse_header($elements) + { + for ($i = 0, $size = count($elements); $i<$size; $i++) { + $label = $this->label_map[$elements[$i]]; + if ($label && !empty($this->csv2vcard_map[$label])) { + $this->map[$i] = $this->csv2vcard_map[$label]; + } + } + } + + /** + * Convert CSV data row to vCard + */ + protected function csv_to_vcard($data) + { + $contact = array(); + foreach ($this->map as $idx => $name) { + $value = $data[$idx]; + if ($value !== null && $value !== '') { + $contact[$name] = $value; + } + } + + if (empty($contact)) { + return; + } + + // Handle special values + if (!empty($contact['birthday-d']) && !empty($contact['birthday-m']) && !empty($contact['birthday-y'])) { + $contact['birthday'] = $contact['birthday-y'] .'-' .$contact['birthday-m'] . '-' . $contact['birthday-d']; + } + + // Create vcard object + $vcard = new rcube_vcard(); + foreach ($contact as $name => $value) { + $name = explode(':', $name); + $vcard->set($name[0], $value, $name[1]); + } + + // add to the list + $this->vcards[] = $vcard; + } +} diff --git a/program/localization/en_US/csv2vcard.inc b/program/localization/en_US/csv2vcard.inc new file mode 100644 index 000000000..caf192aea --- /dev/null +++ b/program/localization/en_US/csv2vcard.inc @@ -0,0 +1,93 @@ + | + +-----------------------------------------------------------------------+ +*/ + +// This is a list of CSV column names specified in CSV file header +// These must be original texts used in Outlook/Thunderbird exported csv files +// Encoding UTF-8 + +$map = array(); + +// MS Outlook 2010 +$map['anniversary'] = "Anniversary"; +$map['assistants_name'] = "Assistant's Name"; +$map['assistants_phone'] = "Assistant's Phone"; +$map['birthday'] = "Birthday"; +$map['business_city'] = "Business City"; +$map['business_countryregion'] = "Business Country/Region"; +$map['business_fax'] = "Business Fax"; +$map['business_phone'] = "Business Phone"; +$map['business_phone_2'] = "Business Phone 2"; +$map['business_postal_code'] = "Business Postal Code"; +$map['business_state'] = "Business State"; +$map['business_street'] = "Business Street"; +$map['car_phone'] = "Car Phone"; +$map['categories'] = "Categories"; +$map['company'] = "Company"; +$map['department'] = "Department"; +$map['email_address'] = "E-mail Address"; +$map['first_name'] = "First Name"; +$map['gender'] = "Gender"; +$map['home_city'] = "Home City"; +$map['home_countryregion'] = "Home Country/Region"; +$map['home_fax'] = "Home Fax"; +$map['home_phone'] = "Home Phone"; +$map['home_phone_2'] = "Home Phone 2"; +$map['home_postal_code'] = "Home Postal Code"; +$map['home_state'] = "Home State"; +$map['home_street'] = "Home Street"; +$map['job_title'] = "Job Title"; +$map['last_name'] = "Last Name"; +$map['managers_name'] = "Manager's Name"; +$map['middle_name'] = "Middle Name"; +$map['mobile_phone'] = "Mobile Phone"; +$map['notes'] = "Notes"; +$map['other_city'] = "Other City"; +$map['other_countryregion'] = "Other Country/Region"; +$map['other_fax'] = "Other Fax"; +$map['other_phone'] = "Other Phone"; +$map['other_postal_code'] = "Other Postal Code"; +$map['other_state'] = "Other State"; +$map['other_street'] = "Other Street"; +$map['pager'] = "Pager"; +$map['primary_phone'] = "Primary Phone"; +$map['spouse'] = "Spouse"; +$map['suffix'] = "Suffix"; +$map['title'] = "Title"; +$map['web_page'] = "Web Page"; + +// Thunderbird +$map['birth_day'] = "Birth Day"; +$map['birth_month'] = "Birth Month"; +$map['birth_year'] = "Birth Year"; +$map['display_name'] = "Display Name"; +$map['fax_number'] = "Fax Number"; +$map['home_address'] = "Home Address"; +$map['home_country'] = "Home Country"; +$map['home_zipcode'] = "Home ZipCode"; +$map['mobile_number'] = "Mobile Number"; +$map['nickname'] = "Nickname"; +$map['organization'] = "Organization"; +$map['pager_number'] = "Pager Namber"; +$map['primary_email'] = "Primary Email"; +$map['secondary_email'] = "Secondary Email"; +$map['web_page_1'] = "Web Page 1"; +$map['web_page_2'] = "Web Page 2"; +$map['work_phone'] = "Work Phone"; +$map['work_address'] = "Work Address"; +$map['work_country'] = "Work Country"; +$map['work_zipcode'] = "Work ZipCode"; diff --git a/program/localization/en_US/labels.inc b/program/localization/en_US/labels.inc index 1999bad13..4dbe9f9a1 100644 --- a/program/localization/en_US/labels.inc +++ b/program/localization/en_US/labels.inc @@ -354,7 +354,7 @@ $labels['importcontacts'] = 'Import contacts'; $labels['importfromfile'] = 'Import from file:'; $labels['importtarget'] = 'Add new contacts to address book:'; $labels['importreplace'] = 'Replace the entire address book'; -$labels['importtext'] = 'You can upload contacts from an existing address book.
We currently support importing addresses from the vCard data format.'; +$labels['importdesc'] = 'You can upload contacts from an existing address book.
We currently support importing addresses from the vCard or CSV (comma-separated) data format.'; $labels['done'] = 'Done'; // settings diff --git a/program/localization/en_US/messages.inc b/program/localization/en_US/messages.inc index a858d0acf..a00eff8a4 100644 --- a/program/localization/en_US/messages.inc +++ b/program/localization/en_US/messages.inc @@ -1,12 +1,11 @@ | +-----------------------------------------------------------------------+ - - @version $Id$ - */ $messages = array(); @@ -125,7 +121,7 @@ $messages['contactaddedtogroup'] = 'Successfully added the contacts to this grou $messages['contactremovedfromgroup'] = 'Successfully removed contacts from this group.'; $messages['nogroupassignmentschanged'] = 'No group assignments changed.'; $messages['importwait'] = 'Importing, please wait...'; -$messages['importerror'] = 'Import failed! The uploaded file is not a valid vCard file.'; +$messages['importformaterror'] = 'Import failed! The uploaded file is not a valid import data file.'; $messages['importconfirm'] = 'Successfully imported $inserted contacts'; $messages['importconfirmskipped'] = 'Skipped $skipped existing entries'; $messages['opnotpermitted'] = 'Operation not permitted!'; diff --git a/program/steps/addressbook/import.inc b/program/steps/addressbook/import.inc index fb2251f18..6d60f829c 100644 --- a/program/steps/addressbook/import.inc +++ b/program/steps/addressbook/import.inc @@ -64,7 +64,7 @@ function rcmail_import_form($attrib) $OUTPUT->add_label('selectimportfile','importwait'); $OUTPUT->add_gui_object('importform', $attrib['id']); - $out = html::p(null, Q(rcube_label('importtext'), 'show')); + $out = html::p(null, Q(rcube_label('importdesc'), 'show')); $out .= $OUTPUT->form_tag(array( 'action' => $RCMAIL->url('import'), @@ -159,11 +159,22 @@ if (is_array($_FILES['_file'])) { $upload_error = $err; } else { + $file_content = file_get_contents($filepath); + // let rcube_vcard do the hard work :-) $vcard_o = new rcube_vcard(); $vcard_o->extend_fieldmap($CONTACTS->vcard_map); + $v_list = $vcard_o->import($file_content); + + if (!empty($v_list)) { + $vcards = array_merge($vcards, $v_list); + continue; + } - $v_list = $vcard_o->import(file_get_contents($filepath)); + // no vCards found, try CSV + $csv = new rcube_csv2vcard($_SESSION['language']); + $csv->import($file_content); + $v_list = $csv->export(); if (!empty($v_list)) { $vcards = array_merge($vcards, $v_list); @@ -181,7 +192,7 @@ if (is_array($_FILES['_file'])) { $OUTPUT->show_message('fileuploaderror', 'error'); } else { - $OUTPUT->show_message('importerror', 'error'); + $OUTPUT->show_message('importformaterror', 'error'); } } else { diff --git a/tests/Framework/Csv2vcard.php b/tests/Framework/Csv2vcard.php new file mode 100644 index 000000000..6fa3e163c --- /dev/null +++ b/tests/Framework/Csv2vcard.php @@ -0,0 +1,57 @@ +import(''); + $this->assertSame(array(), $csv->export()); + } + + function test_import_tb_plain() + { + $csv_text = file_get_contents(TESTS_DIR . '/src/Csv2vcard/tb_plain.csv'); + $vcf_text = file_get_contents(TESTS_DIR . '/src/Csv2vcard/tb_plain.vcf'); + + $csv = new rcube_csv2vcard; + $csv->import($csv_text); + $result = $csv->export(); + $vcard = $result[0]->export(false); + + $this->assertCount(1, $result); + + $vcf_text = trim(str_replace("\r\n", "\n", $vcf_text)); + $vcard = trim(str_replace("\r\n", "\n", $vcard)); + $this->assertEquals($vcf_text, $vcard); + } + + function test_import_email() + { + $csv_text = file_get_contents(TESTS_DIR . '/src/Csv2vcard/email.csv'); + $vcf_text = file_get_contents(TESTS_DIR . '/src/Csv2vcard/email.vcf'); + + $csv = new rcube_csv2vcard; + $csv->import($csv_text); + $result = $csv->export(); + + $this->assertCount(4, $result); + + $vcard = ''; + foreach ($result as $vcf) { + $vcard .= $vcf->export(false) . "\n"; + } + + $vcf_text = trim(str_replace("\r\n", "\n", $vcf_text)); + $vcard = trim(str_replace("\r\n", "\n", $vcard)); + $this->assertEquals($vcf_text, $vcard); + } +} diff --git a/tests/phpunit.xml b/tests/phpunit.xml index 43c3b767d..2e52b7795 100644 --- a/tests/phpunit.xml +++ b/tests/phpunit.xml @@ -8,6 +8,7 @@ Framework/Cache.php Framework/Charset.php Framework/ContentFilter.php + Framework/Csv2vcard.php Framework/Html.php Framework/Imap.php Framework/ImapGeneric.php diff --git a/tests/src/Csv2vcard/email.csv b/tests/src/Csv2vcard/email.csv new file mode 100644 index 000000000..1556d9142 --- /dev/null +++ b/tests/src/Csv2vcard/email.csv @@ -0,0 +1,5 @@ +Primary Email +test1@domain.tld +test2@domain.tld +test3@domain.tld +test4@domain.tld diff --git a/tests/src/Csv2vcard/email.vcf b/tests/src/Csv2vcard/email.vcf new file mode 100644 index 000000000..69912a639 --- /dev/null +++ b/tests/src/Csv2vcard/email.vcf @@ -0,0 +1,20 @@ +BEGIN:VCARD +VERSION:3.0 +FN:test1@domain.tld +EMAIL;TYPE=INTERNET;TYPE=PREF:test1@domain.tld +END:VCARD +BEGIN:VCARD +VERSION:3.0 +FN:test2@domain.tld +EMAIL;TYPE=INTERNET;TYPE=PREF:test2@domain.tld +END:VCARD +BEGIN:VCARD +VERSION:3.0 +FN:test3@domain.tld +EMAIL;TYPE=INTERNET;TYPE=PREF:test3@domain.tld +END:VCARD +BEGIN:VCARD +VERSION:3.0 +FN:test4@domain.tld +EMAIL;TYPE=INTERNET;TYPE=PREF:test4@domain.tld +END:VCARD diff --git a/tests/src/Csv2vcard/tb_plain.csv b/tests/src/Csv2vcard/tb_plain.csv new file mode 100644 index 000000000..94ea766c0 --- /dev/null +++ b/tests/src/Csv2vcard/tb_plain.csv @@ -0,0 +1,2 @@ +First Name,Last Name,Display Name,Nickname,Primary Email,Secondary Email,Screen Name,Work Phone,Home Phone,Fax Number,Pager Number,Mobile Number,Home Address,Home Address 2,Home City,Home State,Home ZipCode,Home Country,Work Address,Work Address 2,Work City,Work State,Work ZipCode,Work Country,Job Title,Department,Organization,Web Page 1,Web Page 2,Birth Year,Birth Month,Birth Day,Custom 1,Custom 2,Custom 3,Custom 4,Notes, +Firstname,Lastname,Displayname,Nick,test@domain.tld,next@domain.tld,,phone work,phone home,fax,pager,mobile,Priv address,,City,region,xx-xxx,USA,Addr work,,city,region,33-333,Poland,title,department,Organization,http://page.com,http://webpage.tld,1970,11,15,,,,,, diff --git a/tests/src/Csv2vcard/tb_plain.vcf b/tests/src/Csv2vcard/tb_plain.vcf new file mode 100644 index 000000000..aace259d8 --- /dev/null +++ b/tests/src/Csv2vcard/tb_plain.vcf @@ -0,0 +1,18 @@ +BEGIN:VCARD +VERSION:3.0 +FN:Displayname +N:Lastname;Firstname;;; +NICKNAME:Nick +EMAIL;TYPE=INTERNET;TYPE=PREF:test@domain.tld +EMAIL;TYPE=INTERNET;TYPE=OTHER:next@domain.tld +TEL;TYPE=work:phone work +TEL;TYPE=home:phone home +TEL;TYPE=fax:fax +TEL;TYPE=cell:mobile +TITLE:title +X-DEPARTMENT:department +ORG:Organization +URL;TYPE=homepage:http://page.com +URL;TYPE=other:http://webpage.tld +BDAY;VALUE=date:1970-11-15 +END:VCARD -- cgit v1.2.3 From c66b605435cae82f8d61329aed79f514d771ab7a Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Fri, 16 Nov 2012 14:45:02 +0100 Subject: Add more data validation --- program/include/rcube_csv2vcard.php | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) (limited to 'program') diff --git a/program/include/rcube_csv2vcard.php b/program/include/rcube_csv2vcard.php index f84108ded..bde8198ba 100644 --- a/program/include/rcube_csv2vcard.php +++ b/program/include/rcube_csv2vcard.php @@ -54,11 +54,11 @@ class rcube_csv2vcard //'company_main_phone' => '', 'department' => 'department', //'email_2_address' => '', //@TODO - //'email_2_type' => '', //@TODO + //'email_2_type' => '', //'email_3_address' => '', //@TODO - //'email_3_type' => '', //@TODO + //'email_3_type' => '', 'email_address' => 'email:main', - //'email_type' => '', //@TODO + //'email_type' => '', 'first_name' => 'firstname', 'gender' => 'gender', 'home_city' => 'locality:home', @@ -155,12 +155,12 @@ class rcube_csv2vcard //'company_main_phone' => "Company Main Phone", 'department' => "Department", //'directory_server' => "Directory Server", - //'email_2_address' => "E-mail 2 Address", //@TODO - //'email_2_type' => "E-mail 2 Type", //@TODO - //'email_3_address' => "E-mail 3 Address", //@TODO - //'email_3_type' => "E-mail 3 Type", //@TODO + //'email_2_address' => "E-mail 2 Address", + //'email_2_type' => "E-mail 2 Type", + //'email_3_address' => "E-mail 3 Address", + //'email_3_type' => "E-mail 3 Type", 'email_address' => "E-mail Address", - //'email_type' => "E-mail Type", //@TODO + //'email_type' => "E-mail Type", 'first_name' => "First Name", 'gender' => "Gender", 'home_city' => "Home City", @@ -338,6 +338,18 @@ class rcube_csv2vcard $contact['birthday'] = $contact['birthday-y'] .'-' .$contact['birthday-m'] . '-' . $contact['birthday-d']; } + foreach (array('birthday', 'anniversary') as $key) { + if (!empty($contact[$key]) && $contact[$key] == '0/0/00') { // @TODO: localization? + unset($contact[$key]); + } + } + + if (!empty($contact['gender']) && ($gender = strtolower($contact['gender']))) { + if (!in_array($gender, array('male', 'female'))) { + unset($contact['gender']); + } + } + // Create vcard object $vcard = new rcube_vcard(); foreach ($contact as $name => $value) { -- cgit v1.2.3 From b51eabe2cdc831611ea64f14693f8ea049482217 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Fri, 16 Nov 2012 15:02:41 +0100 Subject: Added Polish localization for csv2vcard feature --- program/localization/pl_PL/csv2vcard.inc | 62 ++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 program/localization/pl_PL/csv2vcard.inc (limited to 'program') diff --git a/program/localization/pl_PL/csv2vcard.inc b/program/localization/pl_PL/csv2vcard.inc new file mode 100644 index 000000000..ceb995517 --- /dev/null +++ b/program/localization/pl_PL/csv2vcard.inc @@ -0,0 +1,62 @@ + | + +-----------------------------------------------------------------------+ +*/ + +// This is a list of CSV column names specified in CSV file header +// These must be original texts used in Outlook/Thunderbird exported csv files +// Encoding UTF-8 + +$map = array(); + +// MS Outlook 2010 +$map['anniversary'] = "Rocznica"; +$map['assistants_name'] = "Asystent"; +$map['assistants_phone'] = "Telefon asystenta"; +$map['birthday'] = "Urodziny"; +$map['business_city'] = "Miasto (biuro)"; +$map['business_countryregion'] = "Kraj/region (biuro)"; +$map['business_fax'] = "Faks służbowy"; +$map['business_phone'] = "Telefon służbowy"; +$map['business_phone_2'] = "Telefon służbowy 2"; +$map['business_postal_code'] = "Kod pocztowy (biuro)"; +$map['business_state'] = "Województwo (biuro)"; +$map['business_street'] = "Ulica (biuro)"; +$map['categories'] = "Kategorie"; +$map['company'] = "Firma"; +$map['department'] = "Oddział"; +$map['email_address'] = "Adres e-mail"; +$map['first_name'] = "Imię"; +$map['gender'] = "Płeć"; +$map['home_city'] = "Miasto (dom)"; +$map['home_countryregion'] = "Kraj/region (dom)"; +$map['home_fax'] = "Faks domowy"; +$map['home_phone'] = "Telefon domowy"; +$map['home_phone_2'] = "Home Phone 2"; +$map['home_postal_code'] = "Kod pocztowy (dom)"; +$map['home_state'] = "Województwo (dom)"; +$map['home_street'] = "Ulica (dom)"; +$map['job_title'] = "Stanowisko"; +$map['last_name'] = "Nazwisko"; +$map['managers_name'] = "Menadżer"; +$map['middle_name'] = "Drugie imię"; +$map['mobile_phone'] = "Telefon komórkowy"; +$map['notes'] = "Notatki"; +$map['pager'] = "Pager"; +$map['primary_phone'] = "Telefon główny"; +$map['title'] = "Tytuł"; +$map['web_page'] = "Osobista strona sieci Web"; +$map['nickname'] = "Przydomek"; -- cgit v1.2.3 From 92bd3a7c3f60e56ec5055c96e7b2f25637d4b0ca Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Sat, 17 Nov 2012 09:04:45 +0100 Subject: Fix parsing header in English when localized map is defined --- program/include/rcube_csv2vcard.php | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) (limited to 'program') diff --git a/program/include/rcube_csv2vcard.php b/program/include/rcube_csv2vcard.php index bde8198ba..6ec2158be 100644 --- a/program/include/rcube_csv2vcard.php +++ b/program/include/rcube_csv2vcard.php @@ -229,8 +229,9 @@ class rcube_csv2vcard 'work_zipcode' => "Work ZipCode", ); + protected $local_label_map = array(); protected $vcards = array(); - protected $map = array(); + protected $map = array(); /** @@ -247,11 +248,12 @@ class rcube_csv2vcard } if (!empty($map)) { - $this->label_map = array_merge($this->label_map, $map); + $this->local_label_map = array_merge($this->label_map, $map); } } $this->label_map = array_flip($this->label_map); + $this->local_label_map = array_flip($this->local_label_map); } /** @@ -307,13 +309,29 @@ class rcube_csv2vcard * Parse CSV header line, detect fields mapping */ protected function parse_header($elements) - { - for ($i = 0, $size = count($elements); $i<$size; $i++) { + { + $map1 = array(); + $map2 = array(); + $size = count($elements); + + // check English labels + for ($i = 0; $i < $size; $i++) { $label = $this->label_map[$elements[$i]]; if ($label && !empty($this->csv2vcard_map[$label])) { - $this->map[$i] = $this->csv2vcard_map[$label]; + $map1[$i] = $this->csv2vcard_map[$label]; + } + } + // check localized labels + if (!empty($this->local_label_map)) { + for ($i = 0; $i < $size; $i++) { + $label = $this->local_label_map[$elements[$i]]; + if ($label && !empty($this->csv2vcard_map[$label])) { + $map2[$i] = $this->csv2vcard_map[$label]; + } } } + + $this->map = count($map1) >= count($map2) ? $map1 : $map2; } /** -- cgit v1.2.3 From 9ab34604d94270f6c1795c7dd7b615273d05db0c Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Sat, 17 Nov 2012 09:24:05 +0100 Subject: Define @package and @subpackage of Framework classes --- program/include/html.php | 3 ++- program/include/rcube_addressbook.php | 3 ++- program/include/rcube_base_replacer.php | 5 +++-- program/include/rcube_browser.php | 3 ++- program/include/rcube_cache.php | 4 ++-- program/include/rcube_charset.php | 9 +++++---- program/include/rcube_config.php | 3 ++- program/include/rcube_contacts.php | 3 ++- program/include/rcube_content_filter.php | 3 +++ program/include/rcube_csv2vcard.php | 5 +++-- program/include/rcube_db.php | 9 ++++----- program/include/rcube_db_mssql.php | 5 ++--- program/include/rcube_db_mysql.php | 4 ++-- program/include/rcube_db_pgsql.php | 5 ++--- program/include/rcube_db_sqlite.php | 5 ++--- program/include/rcube_db_sqlsrv.php | 5 ++--- program/include/rcube_image.php | 6 ++++++ program/include/rcube_imap.php | 4 ++-- program/include/rcube_imap_cache.php | 4 ++-- program/include/rcube_imap_generic.php | 4 ++-- program/include/rcube_ldap.php | 5 +++-- program/include/rcube_message.php | 3 ++- program/include/rcube_message_header.php | 5 +++-- program/include/rcube_message_part.php | 4 ++-- program/include/rcube_mime.php | 7 ++++--- program/include/rcube_output.php | 3 ++- program/include/rcube_output_html.php | 3 ++- program/include/rcube_output_json.php | 3 ++- program/include/rcube_plugin.php | 3 ++- program/include/rcube_plugin_api.php | 3 ++- program/include/rcube_result_index.php | 3 +++ program/include/rcube_result_set.php | 3 ++- program/include/rcube_result_thread.php | 3 +++ program/include/rcube_session.php | 3 ++- program/include/rcube_shared.inc | 3 ++- program/include/rcube_smtp.php | 3 ++- program/include/rcube_spellchecker.php | 3 ++- program/include/rcube_storage.php | 8 ++++---- program/include/rcube_string_replacer.php | 3 ++- program/include/rcube_user.php | 7 ++++--- program/include/rcube_utils.php | 3 ++- program/include/rcube_vcard.php | 7 ++++--- 42 files changed, 108 insertions(+), 72 deletions(-) (limited to 'program') diff --git a/program/include/html.php b/program/include/html.php index 0f93e969d..8ff685a84 100644 --- a/program/include/html.php +++ b/program/include/html.php @@ -23,7 +23,8 @@ /** * Class for HTML code creation * - * @package HTML + * @package Framework + * @subpackage HTML */ class html { diff --git a/program/include/rcube_addressbook.php b/program/include/rcube_addressbook.php index 892ae263a..b5fb8cf43 100644 --- a/program/include/rcube_addressbook.php +++ b/program/include/rcube_addressbook.php @@ -23,7 +23,8 @@ /** * Abstract skeleton of an address book/repository * - * @package Addressbook + * @package Framework + * @subpackage Addressbook */ abstract class rcube_addressbook { diff --git a/program/include/rcube_base_replacer.php b/program/include/rcube_base_replacer.php index 4ec367552..b2a0fc13c 100644 --- a/program/include/rcube_base_replacer.php +++ b/program/include/rcube_base_replacer.php @@ -23,8 +23,9 @@ * Helper class to turn relative urls into absolute ones * using a predefined base * - * @package Core - * @author Thomas Bruederli + * @package Framework + * @subpackage Core + * @author Thomas Bruederli */ class rcube_base_replacer { diff --git a/program/include/rcube_browser.php b/program/include/rcube_browser.php index 7cfae709d..154e7ef4e 100644 --- a/program/include/rcube_browser.php +++ b/program/include/rcube_browser.php @@ -22,7 +22,8 @@ /** * Provide details about the client's browser based on the User-Agent header * - * @package Core + * @package Framework + * @subpackage Core */ class rcube_browser { diff --git a/program/include/rcube_cache.php b/program/include/rcube_cache.php index 4e60deaff..3e1ce4fc8 100644 --- a/program/include/rcube_cache.php +++ b/program/include/rcube_cache.php @@ -25,10 +25,10 @@ /** * Interface class for accessing Roundcube cache * - * @package Cache + * @package Framework + * @subpackage Cache * @author Thomas Bruederli * @author Aleksander Machniak - * @version 1.1 */ class rcube_cache { diff --git a/program/include/rcube_charset.php b/program/include/rcube_charset.php index 4d24ed135..e8cce00e3 100644 --- a/program/include/rcube_charset.php +++ b/program/include/rcube_charset.php @@ -25,10 +25,11 @@ /** * Character sets conversion functionality * - * @package Core - * @author Thomas Bruederli - * @author Aleksander Machniak - * @author Edmund Grimley Evans + * @package Framework + * @subpackage Core + * @author Thomas Bruederli + * @author Aleksander Machniak + * @author Edmund Grimley Evans */ class rcube_charset { diff --git a/program/include/rcube_config.php b/program/include/rcube_config.php index bbc3e9c6e..dab539412 100644 --- a/program/include/rcube_config.php +++ b/program/include/rcube_config.php @@ -22,7 +22,8 @@ /** * Configuration class for Roundcube * - * @package Core + * @package Framework + * @subpackage Core */ class rcube_config { diff --git a/program/include/rcube_contacts.php b/program/include/rcube_contacts.php index 534a65cb9..e4500c744 100644 --- a/program/include/rcube_contacts.php +++ b/program/include/rcube_contacts.php @@ -23,7 +23,8 @@ /** * Model class for the local address book database * - * @package Addressbook + * @package Framework + * @subpackage Addressbook */ class rcube_contacts extends rcube_addressbook { diff --git a/program/include/rcube_content_filter.php b/program/include/rcube_content_filter.php index 36e61a271..99916a300 100644 --- a/program/include/rcube_content_filter.php +++ b/program/include/rcube_content_filter.php @@ -21,6 +21,9 @@ /** * PHP stream filter to detect html/javascript code in attachments + * + * @package Framework + * @subpackage Core */ class rcube_content_filter extends php_user_filter { diff --git a/program/include/rcube_csv2vcard.php b/program/include/rcube_csv2vcard.php index 6ec2158be..114d36d85 100644 --- a/program/include/rcube_csv2vcard.php +++ b/program/include/rcube_csv2vcard.php @@ -21,8 +21,9 @@ /** * CSV to vCard data converter * - * @package Roundcube Framework - * @author Aleksander Machniak + * @package Framework + * @subpackage Addressbook + * @author Aleksander Machniak */ class rcube_csv2vcard { diff --git a/program/include/rcube_db.php b/program/include/rcube_db.php index b066101b3..5d8c4a534 100644 --- a/program/include/rcube_db.php +++ b/program/include/rcube_db.php @@ -21,12 +21,11 @@ /** - * Database independent query interface + * Database independent query interface. + * This is a wrapper for the PHP PDO. * - * This is a wrapper for the PHP PDO - * - * @package Database - * @version 1.0 + * @package Framework + * @sbpackage Database */ class rcube_db { diff --git a/program/include/rcube_db_mssql.php b/program/include/rcube_db_mssql.php index 119647d95..c95663c74 100644 --- a/program/include/rcube_db_mssql.php +++ b/program/include/rcube_db_mssql.php @@ -23,11 +23,10 @@ /** * Database independent query interface - * * This is a wrapper for the PHP PDO * - * @package Database - * @version 1.0 + * @package Framework + * @subpackage Database */ class rcube_db_mssql extends rcube_db { diff --git a/program/include/rcube_db_mysql.php b/program/include/rcube_db_mysql.php index 6f0acba54..1c5ba1de7 100644 --- a/program/include/rcube_db_mysql.php +++ b/program/include/rcube_db_mysql.php @@ -26,8 +26,8 @@ * * This is a wrapper for the PHP PDO * - * @package Database - * @version 1.0 + * @package Framework + * @subpackage Database */ class rcube_db_mysql extends rcube_db { diff --git a/program/include/rcube_db_pgsql.php b/program/include/rcube_db_pgsql.php index 0d0caadde..797860a84 100644 --- a/program/include/rcube_db_pgsql.php +++ b/program/include/rcube_db_pgsql.php @@ -23,11 +23,10 @@ /** * Database independent query interface - * * This is a wrapper for the PHP PDO * - * @package Database - * @version 1.0 + * @package Framework + * @subpackage Database */ class rcube_db_pgsql extends rcube_db { diff --git a/program/include/rcube_db_sqlite.php b/program/include/rcube_db_sqlite.php index a7397674b..9aa67d0fd 100644 --- a/program/include/rcube_db_sqlite.php +++ b/program/include/rcube_db_sqlite.php @@ -23,11 +23,10 @@ /** * Database independent query interface - * * This is a wrapper for the PHP PDO * - * @package Database - * @version 1.0 + * @package Framework + * @subpackage Database */ class rcube_db_sqlite extends rcube_db { diff --git a/program/include/rcube_db_sqlsrv.php b/program/include/rcube_db_sqlsrv.php index e58bf0704..8b6ffe807 100644 --- a/program/include/rcube_db_sqlsrv.php +++ b/program/include/rcube_db_sqlsrv.php @@ -23,11 +23,10 @@ /** * Database independent query interface - * * This is a wrapper for the PHP PDO * - * @package Database - * @version 1.0 + * @package Framework + * @subpackage Database */ class rcube_db_sqlsrv extends rcube_db { diff --git a/program/include/rcube_image.php b/program/include/rcube_image.php index c0d4e878d..b72a24c51 100644 --- a/program/include/rcube_image.php +++ b/program/include/rcube_image.php @@ -21,6 +21,12 @@ +-----------------------------------------------------------------------+ */ +/** + * Image resizer and converter + * + * @package Framework + * @subpackage Utils + */ class rcube_image { private $image_file; diff --git a/program/include/rcube_imap.php b/program/include/rcube_imap.php index f2645f60f..9054b6bab 100644 --- a/program/include/rcube_imap.php +++ b/program/include/rcube_imap.php @@ -25,10 +25,10 @@ /** * Interface class for accessing an IMAP server * - * @package Mail + * @package Framework + * @subpackage Storage * @author Thomas Bruederli * @author Aleksander Machniak - * @version 2.0 */ class rcube_imap extends rcube_storage { diff --git a/program/include/rcube_imap_cache.php b/program/include/rcube_imap_cache.php index f36ace0eb..31214cfbf 100644 --- a/program/include/rcube_imap_cache.php +++ b/program/include/rcube_imap_cache.php @@ -24,10 +24,10 @@ /** * Interface class for accessing Roundcube messages cache * - * @package Cache + * @package Framework + * @subpackage Storage * @author Thomas Bruederli * @author Aleksander Machniak - * @version 1.0 */ class rcube_imap_cache { diff --git a/program/include/rcube_imap_generic.php b/program/include/rcube_imap_generic.php index bc7ecfc37..a0a8f3b77 100644 --- a/program/include/rcube_imap_generic.php +++ b/program/include/rcube_imap_generic.php @@ -30,8 +30,8 @@ /** * PHP based wrapper class to connect to an IMAP server * - * @package Mail - * @author Aleksander Machniak + * @package Framework + * @subpackage Storage */ class rcube_imap_generic { diff --git a/program/include/rcube_ldap.php b/program/include/rcube_ldap.php index 7cef25556..34e37e3b9 100644 --- a/program/include/rcube_ldap.php +++ b/program/include/rcube_ldap.php @@ -6,7 +6,7 @@ | | | This file is part of the Roundcube Webmail client | | Copyright (C) 2006-2012, The Roundcube Dev Team | - | Copyright (C) 2011, Kolab Systems AG | + | Copyright (C) 2011-2012, Kolab Systems AG | | | | Licensed under the GNU General Public License version 3 or | | any later version with exceptions for skins & plugins. | @@ -26,7 +26,8 @@ /** * Model class to access an LDAP address directory * - * @package Addressbook + * @package Framework + * @subpackage Addressbook */ class rcube_ldap extends rcube_addressbook { diff --git a/program/include/rcube_message.php b/program/include/rcube_message.php index 74bf4574f..87319f04f 100644 --- a/program/include/rcube_message.php +++ b/program/include/rcube_message.php @@ -24,7 +24,8 @@ * Logical representation of a mail message with all its data * and related functions * - * @package Mail + * @package Framework + * @subpackage Storage * @author Thomas Bruederli */ class rcube_message diff --git a/program/include/rcube_message_header.php b/program/include/rcube_message_header.php index 378fb98c9..db82247f9 100644 --- a/program/include/rcube_message_header.php +++ b/program/include/rcube_message_header.php @@ -23,8 +23,9 @@ /** * Struct representing an e-mail message header * - * @package Mail - * @author Aleksander Machniak + * @package Framework + * @subpackage Storage + * @author Aleksander Machniak */ class rcube_message_header { diff --git a/program/include/rcube_message_part.php b/program/include/rcube_message_part.php index 80a019e50..c9c9257eb 100644 --- a/program/include/rcube_message_part.php +++ b/program/include/rcube_message_part.php @@ -25,10 +25,10 @@ /** * Class representing a message part * - * @package Mail + * @package Framework + * @subpackage Storage * @author Thomas Bruederli * @author Aleksander Machniak - * @version 2.0 */ class rcube_message_part { diff --git a/program/include/rcube_mime.php b/program/include/rcube_mime.php index d8e04a97c..2dbeaf67a 100644 --- a/program/include/rcube_mime.php +++ b/program/include/rcube_mime.php @@ -25,9 +25,10 @@ /** * Class for parsing MIME messages * - * @package Mail - * @author Thomas Bruederli - * @author Aleksander Machniak + * @package Framework + * @subpackage Storage + * @author Thomas Bruederli + * @author Aleksander Machniak */ class rcube_mime { diff --git a/program/include/rcube_output.php b/program/include/rcube_output.php index 5c582e67c..f7ac3002f 100644 --- a/program/include/rcube_output.php +++ b/program/include/rcube_output.php @@ -22,7 +22,8 @@ /** * Class for output generation * - * @package HTML + * @package Framework + * @subpackage View */ abstract class rcube_output { diff --git a/program/include/rcube_output_html.php b/program/include/rcube_output_html.php index ac07d58e9..ffb5db4da 100644 --- a/program/include/rcube_output_html.php +++ b/program/include/rcube_output_html.php @@ -23,7 +23,8 @@ /** * Class to create HTML page output using a skin template * - * @package View + * @package Framework + * @subpackage View */ class rcube_output_html extends rcube_output { diff --git a/program/include/rcube_output_json.php b/program/include/rcube_output_json.php index eb1a9380d..fcd52c789 100644 --- a/program/include/rcube_output_json.php +++ b/program/include/rcube_output_json.php @@ -23,7 +23,8 @@ /** * View class to produce JSON responses * - * @package View + * @package Framework + * @subpackage View */ class rcube_output_json extends rcube_output { diff --git a/program/include/rcube_plugin.php b/program/include/rcube_plugin.php index 45088850a..dbb15e8be 100644 --- a/program/include/rcube_plugin.php +++ b/program/include/rcube_plugin.php @@ -22,7 +22,8 @@ /** * Plugin interface class * - * @package PluginAPI + * @package Framework + * @subpackage PluginAPI */ abstract class rcube_plugin { diff --git a/program/include/rcube_plugin_api.php b/program/include/rcube_plugin_api.php index c473b0b17..51daf2797 100644 --- a/program/include/rcube_plugin_api.php +++ b/program/include/rcube_plugin_api.php @@ -27,7 +27,8 @@ if (!defined('RCMAIL_PLUGINS_DIR')) /** * The plugin loader and global API * - * @package PluginAPI + * @package Framework + * @subpackage PluginAPI */ class rcube_plugin_api { diff --git a/program/include/rcube_result_index.php b/program/include/rcube_result_index.php index 334ec8530..4d1ae13b6 100644 --- a/program/include/rcube_result_index.php +++ b/program/include/rcube_result_index.php @@ -24,6 +24,9 @@ /** * Class for accessing IMAP's SORT/SEARCH/ESEARCH result + * + * @package Framework + * @subpackage Storage */ class rcube_result_index { diff --git a/program/include/rcube_result_set.php b/program/include/rcube_result_set.php index 809d8743f..456d1c9d6 100644 --- a/program/include/rcube_result_set.php +++ b/program/include/rcube_result_set.php @@ -24,7 +24,8 @@ * Roundcube result set class. * Representing an address directory result set. * - * @package Addressbook + * @package Framework + * @subpackage Addressbook */ class rcube_result_set { diff --git a/program/include/rcube_result_thread.php b/program/include/rcube_result_thread.php index b2325a499..c609bdc39 100644 --- a/program/include/rcube_result_thread.php +++ b/program/include/rcube_result_thread.php @@ -24,6 +24,9 @@ /** * Class for accessing IMAP's THREAD result + * + * @package Framework + * @subpackage Storage */ class rcube_result_thread { diff --git a/program/include/rcube_session.php b/program/include/rcube_session.php index c71efa2aa..fdbf668ca 100644 --- a/program/include/rcube_session.php +++ b/program/include/rcube_session.php @@ -24,7 +24,8 @@ /** * Class to provide database supported session storage * - * @package Core + * @package Framework + * @subpackage Core * @author Thomas Bruederli * @author Aleksander Machniak */ diff --git a/program/include/rcube_shared.inc b/program/include/rcube_shared.inc index 4577c6df5..5105fe22f 100644 --- a/program/include/rcube_shared.inc +++ b/program/include/rcube_shared.inc @@ -23,7 +23,8 @@ /** * Roundcube shared functions * - * @package Core + * @package Framework + * @subpackage Core */ diff --git a/program/include/rcube_smtp.php b/program/include/rcube_smtp.php index b28be5206..490ea8ad6 100644 --- a/program/include/rcube_smtp.php +++ b/program/include/rcube_smtp.php @@ -25,7 +25,8 @@ define('SMTP_MIME_CRLF', "\r\n"); /** * Class to provide SMTP functionality using PEAR Net_SMTP * - * @package Mail + * @package Framework + * @subpackage Mail * @author Thomas Bruederli * @author Aleksander Machniak */ diff --git a/program/include/rcube_spellchecker.php b/program/include/rcube_spellchecker.php index 219dca780..30d15d721 100644 --- a/program/include/rcube_spellchecker.php +++ b/program/include/rcube_spellchecker.php @@ -25,7 +25,8 @@ /** * Helper class for spellchecking with Googielspell and PSpell support. * - * @package Core + * @package Framework + * @subpackage Utils */ class rcube_spellchecker { diff --git a/program/include/rcube_storage.php b/program/include/rcube_storage.php index 933ebcc25..1556aae41 100644 --- a/program/include/rcube_storage.php +++ b/program/include/rcube_storage.php @@ -25,10 +25,10 @@ /** * Abstract class for accessing mail messages storage server * - * @package Mail - * @author Thomas Bruederli - * @author Aleksander Machniak - * @version 2.0 + * @package Framework + * @subpackage Storage + * @author Thomas Bruederli + * @author Aleksander Machniak */ abstract class rcube_storage { diff --git a/program/include/rcube_string_replacer.php b/program/include/rcube_string_replacer.php index edb2ac34f..9af6b33e0 100644 --- a/program/include/rcube_string_replacer.php +++ b/program/include/rcube_string_replacer.php @@ -23,7 +23,8 @@ /** * Helper class for string replacements based on preg_replace_callback * - * @package Core + * @package Framework + * @subpackage Utils */ class rcube_string_replacer { diff --git a/program/include/rcube_user.php b/program/include/rcube_user.php index 72b03cd15..5a8e9005e 100644 --- a/program/include/rcube_user.php +++ b/program/include/rcube_user.php @@ -5,7 +5,7 @@ | program/include/rcube_user.inc | | | | This file is part of the Roundcube Webmail client | - | Copyright (C) 2005-2010, The Roundcube Dev Team | + | Copyright (C) 2005-2012, The Roundcube Dev Team | | | | Licensed under the GNU General Public License version 3 or | | any later version with exceptions for skins & plugins. | @@ -17,6 +17,7 @@ | | +-----------------------------------------------------------------------+ | Author: Thomas Bruederli | + | Author: Aleksander Machniak | +-----------------------------------------------------------------------+ */ @@ -24,8 +25,8 @@ /** * Class representing a system user * - * @package Core - * @author Thomas Bruederli + * @package Framework + * @subpackage Core */ class rcube_user { diff --git a/program/include/rcube_utils.php b/program/include/rcube_utils.php index 5cfd8e70e..dfaa9b943 100644 --- a/program/include/rcube_utils.php +++ b/program/include/rcube_utils.php @@ -24,7 +24,8 @@ /** * Utility class providing common functions * - * @package Core + * @package Framework + * @subpackage Utils */ class rcube_utils { diff --git a/program/include/rcube_vcard.php b/program/include/rcube_vcard.php index 51a7fe71a..d0a341da1 100644 --- a/program/include/rcube_vcard.php +++ b/program/include/rcube_vcard.php @@ -5,7 +5,7 @@ | program/include/rcube_vcard.php | | | | This file is part of the Roundcube Webmail client | - | Copyright (C) 2008-2011, The Roundcube Dev Team | + | Copyright (C) 2008-2012, The Roundcube Dev Team | | | | Licensed under the GNU General Public License version 3 or | | any later version with exceptions for skins & plugins. | @@ -15,6 +15,7 @@ | Logical representation of a vcard address record | +-----------------------------------------------------------------------+ | Author: Thomas Bruederli | + | Author: Aleksander Machniak | +-----------------------------------------------------------------------+ */ @@ -23,8 +24,8 @@ * Logical representation of a vcard-based address record * Provides functions to parse and export vCard data format * - * @package Addressbook - * @author Thomas Bruederli + * @package Framework + * @subpackage Addressbook */ class rcube_vcard { -- cgit v1.2.3