From eb274bf3eeb34f70031e220941ee1340c75ac098 Mon Sep 17 00:00:00 2001 From: Jan Schumann Date: Mon, 2 Jan 2012 21:35:09 +0100 Subject: added plugin type 'auth' --- inc/init.php | 2 +- inc/load.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/inc/init.php b/inc/init.php index b3acf2e33..1d3588942 100644 --- a/inc/init.php +++ b/inc/init.php @@ -200,7 +200,7 @@ init_paths(); init_files(); // setup plugin controller class (can be overwritten in preload.php) -$plugin_types = array('admin','syntax','action','renderer', 'helper'); +$plugin_types = array('auth', 'admin','syntax','action','renderer', 'helper'); global $plugin_controller_class, $plugin_controller; if (empty($plugin_controller_class)) $plugin_controller_class = 'Doku_Plugin_Controller'; diff --git a/inc/load.php b/inc/load.php index d30397f6e..36de5b69a 100644 --- a/inc/load.php +++ b/inc/load.php @@ -89,7 +89,7 @@ function load_autoload($name){ } // Plugin loading - if(preg_match('/^(helper|syntax|action|admin|renderer)_plugin_([^_]+)(?:_([^_]+))?$/', + if(preg_match('/^(auth|helper|syntax|action|admin|renderer)_plugin_([^_]+)(?:_([^_]+))?$/', $name, $m)) { //try to load the wanted plugin file // include, but be silent. Maybe some other autoloader has an idea -- cgit v1.2.3 From 4ae475af3d062ad634677a93371703eadbfdf256 Mon Sep 17 00:00:00 2001 From: Jan Schumann Date: Tue, 3 Jan 2012 02:45:43 +0100 Subject: Added prototype for Auth-Plugins --- lib/plugins/auth.php | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 lib/plugins/auth.php diff --git a/lib/plugins/auth.php b/lib/plugins/auth.php new file mode 100644 index 000000000..3ec64018c --- /dev/null +++ b/lib/plugins/auth.php @@ -0,0 +1,25 @@ + + */ +// must be run within Dokuwiki +if(!defined('DOKU_INC')) die(); + +/** + * All plugins that provide Authentication should inherit from this class and implement + * the getAuth() method to make its Auth-System available. + * + * @author Jan Schumann + */ +class DokuWiki_Auth_Plugin extends DokuWiki_Plugin { + + /** + * Retrieves the authentication system + */ + function getAuth() { + trigger_error('getAuth() not implemented in '.get_class($this), E_USER_WARNING); + } +} -- cgit v1.2.3 From b4245126d64b378a4cb90821718983e27e943ebc Mon Sep 17 00:00:00 2001 From: Jan Schumann Date: Tue, 3 Jan 2012 02:46:36 +0100 Subject: Load auth types from plugins in settings_authtype class --- lib/plugins/config/settings/extra.class.php | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/plugins/config/settings/extra.class.php b/lib/plugins/config/settings/extra.class.php index b4e35b1cc..72b9755be 100644 --- a/lib/plugins/config/settings/extra.class.php +++ b/lib/plugins/config/settings/extra.class.php @@ -43,12 +43,19 @@ if (!class_exists('setting_authtype')) { class setting_authtype extends setting_multichoice { function initialize($default,$local,$protected) { + global $plugin_controller; // populate $this->_choices with a list of available auth mechanisms $authtypes = glob(DOKU_INC.'inc/auth/*.class.php'); $authtypes = preg_replace('#^.*/([^/]*)\.class\.php$#i','$1', $authtypes); $authtypes = array_diff($authtypes, array('basic')); - sort($authtypes); + + // retrive auth types provided by plugins + foreach ($plugin_controller->getList('auth') as $plugin) { + $authtypes = $plugin; + } + + $authtypes = array_unique($authtypes); $this->_choices = $authtypes; -- cgit v1.2.3 From 3cbcc6538357fd59d70eea92086e8bfcf0443200 Mon Sep 17 00:00:00 2001 From: Jan Schumann Date: Tue, 3 Jan 2012 02:54:05 +0100 Subject: Added Auth-Plugin-Prototype to autoload --- inc/load.php | 1 + 1 file changed, 1 insertion(+) diff --git a/inc/load.php b/inc/load.php index 36de5b69a..138118a2a 100644 --- a/inc/load.php +++ b/inc/load.php @@ -80,6 +80,7 @@ function load_autoload($name){ 'DokuWiki_Action_Plugin' => DOKU_PLUGIN.'action.php', 'DokuWiki_Admin_Plugin' => DOKU_PLUGIN.'admin.php', 'DokuWiki_Syntax_Plugin' => DOKU_PLUGIN.'syntax.php', + 'DokuWiki_Auth_Plugin' => DOKU_PLUGIN.'auth.php', ); -- cgit v1.2.3 From 9c29eea515b336b23187a86f5b55443571fcba01 Mon Sep 17 00:00:00 2001 From: Jan Schumann Date: Tue, 3 Jan 2012 02:56:20 +0100 Subject: Setup auth system from plugins --- inc/auth.php | 56 ++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 34 insertions(+), 22 deletions(-) diff --git a/inc/auth.php b/inc/auth.php index e0f58e5f2..b11a14d50 100644 --- a/inc/auth.php +++ b/inc/auth.php @@ -36,29 +36,41 @@ function auth_setup(){ global $AUTH_ACL; global $lang; global $config_cascade; + global $plugin_controller; $AUTH_ACL = array(); if(!$conf['useacl']) return false; - // load the the backend auth functions and instantiate the auth object XXX - if (@file_exists(DOKU_INC.'inc/auth/'.$conf['authtype'].'.class.php')) { - require_once(DOKU_INC.'inc/auth/basic.class.php'); - require_once(DOKU_INC.'inc/auth/'.$conf['authtype'].'.class.php'); - - $auth_class = "auth_".$conf['authtype']; - if (class_exists($auth_class)) { - $auth = new $auth_class(); - if ($auth->success == false) { - // degrade to unauthenticated user - unset($auth); - auth_logoff(); - msg($lang['authtempfail'], -1); - } - } else { - nice_die($lang['authmodfailed']); - } - } else { - nice_die($lang['authmodfailed']); + // try to load auth backend from plugins + $plugins = $plugin_controller->getList('auth'); + foreach ($plugin_controller->getList('auth') as $plugin) { + if ($conf['authtype'] === $plugin) { + $auth = $plugin_controller->load('auth', $plugin)->getAuth(); + break; + } + } + + if (!$auth) { + // load the the backend auth functions and instantiate the auth object XXX + if (@file_exists(DOKU_INC.'inc/auth/'.$conf['authtype'].'.class.php')) { + require_once(DOKU_INC.'inc/auth/basic.class.php'); + require_once(DOKU_INC.'inc/auth/'.$conf['authtype'].'.class.php'); + + $auth_class = "auth_".$conf['authtype']; + if (class_exists($auth_class)) { + $auth = new $auth_class(); + if ($auth->success == false) { + // degrade to unauthenticated user + unset($auth); + auth_logoff(); + msg($lang['authtempfail'], -1); + } + } else { + nice_die($lang['authmodfailed']); + } + } else { + nice_die($lang['authmodfailed']); + } } if(!$auth) return; @@ -675,7 +687,7 @@ function auth_sendPassword($user,$password){ if(empty($conf['mailprefix'])) { $subject = $lang['regpwmail']; - } else { + } else { $subject = '['.$conf['mailprefix'].'] '.$lang['regpwmail']; } @@ -920,10 +932,10 @@ function act_resendpwd(){ if(empty($conf['mailprefix'])) { $subject = $lang['regpwmail']; - } else { + } else { $subject = '['.$conf['mailprefix'].'] '.$lang['regpwmail']; } - + if(mail_send($userinfo['name'].' <'.$userinfo['mail'].'>', $subject, $text, -- cgit v1.2.3 From 396b87bebcb14765849b43a259a2b6cf2aff98f3 Mon Sep 17 00:00:00 2001 From: Jan Schumann Date: Tue, 3 Jan 2012 03:31:54 +0100 Subject: Bugfix: auth types are now correcty added --- lib/plugins/config/settings/extra.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/plugins/config/settings/extra.class.php b/lib/plugins/config/settings/extra.class.php index 72b9755be..cee3c6b20 100644 --- a/lib/plugins/config/settings/extra.class.php +++ b/lib/plugins/config/settings/extra.class.php @@ -52,7 +52,7 @@ if (!class_exists('setting_authtype')) { // retrive auth types provided by plugins foreach ($plugin_controller->getList('auth') as $plugin) { - $authtypes = $plugin; + $authtypes[] = $plugin; } $authtypes = array_unique($authtypes); -- cgit v1.2.3 From f4476bd9b5badd36cd0617d76538e47d9649986b Mon Sep 17 00:00:00 2001 From: Jan Schumann Date: Mon, 20 Feb 2012 19:51:26 +0100 Subject: Refactored auth system: All auth methods are now introduced as plugins. --- inc/auth.php | 37 +- inc/auth/ad.class.php | 351 ----------- inc/auth/basic.class.php | 403 ------------ inc/auth/ldap.class.php | 463 -------------- inc/auth/mysql.class.php | 939 --------------------------- inc/auth/pgsql.class.php | 410 ------------ inc/auth/plain.class.php | 328 ---------- lib/plugins/auth.php | 420 +++++++++++- lib/plugins/authad/auth.php | 359 +++++++++++ lib/plugins/authad/plugin.info.txt | 7 + lib/plugins/authldap/auth.php | 471 ++++++++++++++ lib/plugins/authldap/plugin.info.txt | 7 + lib/plugins/authmysql/auth.php | 946 ++++++++++++++++++++++++++++ lib/plugins/authmysql/plugin.info.txt | 7 + lib/plugins/authpgsql/auth.php | 331 ++++++++++ lib/plugins/authpgsql/plugin.info.txt | 7 + lib/plugins/authplain/auth.php | 335 ++++++++++ lib/plugins/authplain/plugin.info.txt | 7 + lib/plugins/config/settings/extra.class.php | 50 +- 19 files changed, 2941 insertions(+), 2937 deletions(-) delete mode 100644 inc/auth/ad.class.php delete mode 100644 inc/auth/basic.class.php delete mode 100644 inc/auth/ldap.class.php delete mode 100644 inc/auth/mysql.class.php delete mode 100644 inc/auth/pgsql.class.php delete mode 100644 inc/auth/plain.class.php create mode 100644 lib/plugins/authad/auth.php create mode 100644 lib/plugins/authad/plugin.info.txt create mode 100644 lib/plugins/authldap/auth.php create mode 100644 lib/plugins/authldap/plugin.info.txt create mode 100644 lib/plugins/authmysql/auth.php create mode 100644 lib/plugins/authmysql/plugin.info.txt create mode 100644 lib/plugins/authpgsql/auth.php create mode 100644 lib/plugins/authpgsql/plugin.info.txt create mode 100644 lib/plugins/authplain/auth.php create mode 100644 lib/plugins/authplain/plugin.info.txt diff --git a/inc/auth.php b/inc/auth.php index b11a14d50..aac7a2fca 100644 --- a/inc/auth.php +++ b/inc/auth.php @@ -45,35 +45,19 @@ function auth_setup(){ $plugins = $plugin_controller->getList('auth'); foreach ($plugin_controller->getList('auth') as $plugin) { if ($conf['authtype'] === $plugin) { - $auth = $plugin_controller->load('auth', $plugin)->getAuth(); + $auth = $plugin_controller->load('auth', $plugin); break; } } - if (!$auth) { - // load the the backend auth functions and instantiate the auth object XXX - if (@file_exists(DOKU_INC.'inc/auth/'.$conf['authtype'].'.class.php')) { - require_once(DOKU_INC.'inc/auth/basic.class.php'); - require_once(DOKU_INC.'inc/auth/'.$conf['authtype'].'.class.php'); - - $auth_class = "auth_".$conf['authtype']; - if (class_exists($auth_class)) { - $auth = new $auth_class(); - if ($auth->success == false) { - // degrade to unauthenticated user - unset($auth); - auth_logoff(); - msg($lang['authtempfail'], -1); - } - } else { - nice_die($lang['authmodfailed']); - } - } else { - nice_die($lang['authmodfailed']); - } - } + if(!$auth) return; - if(!$auth) return; + if ($auth && $auth->success == false) { + // degrade to unauthenticated user + unset($auth); + auth_logoff(); + msg($lang['authtempfail'], -1); + } // do the login either by cookie or provided credentials XXX if (!isset($_REQUEST['u'])) $_REQUEST['u'] = ''; @@ -102,7 +86,10 @@ function auth_setup(){ } // apply cleaning - $_REQUEST['u'] = $auth->cleanUser($_REQUEST['u']); + if (true === $auth->success) + { + $_REQUEST['u'] = $auth->cleanUser($_REQUEST['u']); + } if(isset($_REQUEST['authtok'])){ // when an authentication token is given, trust the session diff --git a/inc/auth/ad.class.php b/inc/auth/ad.class.php deleted file mode 100644 index 1fddad243..000000000 --- a/inc/auth/ad.class.php +++ /dev/null @@ -1,351 +0,0 @@ - - * @link http://www.nosq.com/blog/2005/08/ldap-activedirectory-and-dokuwiki/ - * @author Andreas Gohr - */ - -require_once(DOKU_INC.'inc/adLDAP.php'); - -class auth_ad extends auth_basic { - var $cnf = null; - var $opts = null; - var $adldap = null; - var $users = null; - - /** - * Constructor - */ - function auth_ad() { - global $conf; - $this->cnf = $conf['auth']['ad']; - - - // additional information fields - if (isset($this->cnf['additional'])) { - $this->cnf['additional'] = str_replace(' ', '', $this->cnf['additional']); - $this->cnf['additional'] = explode(',', $this->cnf['additional']); - } else $this->cnf['additional'] = array(); - - // ldap extension is needed - if (!function_exists('ldap_connect')) { - if ($this->cnf['debug']) - msg("AD Auth: PHP LDAP extension not found.",-1); - $this->success = false; - return; - } - - // Prepare SSO - if($_SERVER['REMOTE_USER'] && $this->cnf['sso']){ - // remove possible NTLM domain - list($dom,$usr) = explode('\\',$_SERVER['REMOTE_USER'],2); - if(!$usr) $usr = $dom; - - // remove possible Kerberos domain - list($usr,$dom) = explode('@',$usr); - - $dom = strtolower($dom); - $_SERVER['REMOTE_USER'] = $usr; - - // we need to simulate a login - if(empty($_COOKIE[DOKU_COOKIE])){ - $_REQUEST['u'] = $_SERVER['REMOTE_USER']; - $_REQUEST['p'] = 'sso_only'; - } - } - - // prepare adLDAP standard configuration - $this->opts = $this->cnf; - - // add possible domain specific configuration - if($dom && is_array($this->cnf[$dom])) foreach($this->cnf[$dom] as $key => $val){ - $this->opts[$key] = $val; - } - - // handle multiple AD servers - $this->opts['domain_controllers'] = explode(',',$this->opts['domain_controllers']); - $this->opts['domain_controllers'] = array_map('trim',$this->opts['domain_controllers']); - $this->opts['domain_controllers'] = array_filter($this->opts['domain_controllers']); - - // we can change the password if SSL is set - if($this->opts['use_ssl'] || $this->opts['use_tls']){ - $this->cando['modPass'] = true; - } - $this->cando['modName'] = true; - $this->cando['modMail'] = true; - } - - /** - * Check user+password [required auth function] - * - * Checks if the given user exists and the given - * plaintext password is correct by trying to bind - * to the LDAP server - * - * @author James Van Lommel - * @return bool - */ - function checkPass($user, $pass){ - if($_SERVER['REMOTE_USER'] && - $_SERVER['REMOTE_USER'] == $user && - $this->cnf['sso']) return true; - - if(!$this->_init()) return false; - return $this->adldap->authenticate($user, $pass); - } - - /** - * Return user info [required auth function] - * - * Returns info about the given user needs to contain - * at least these fields: - * - * name string full name of the user - * mail string email address of the user - * grps array list of groups the user is in - * - * This LDAP specific function returns the following - * addional fields: - * - * dn string distinguished name (DN) - * uid string Posix User ID - * - * @author James Van Lommel - */ - function getUserData($user){ - global $conf; - if(!$this->_init()) return false; - - $fields = array('mail','displayname','samaccountname'); - - // add additional fields to read - $fields = array_merge($fields, $this->cnf['additional']); - $fields = array_unique($fields); - - //get info for given user - $result = $this->adldap->user_info($user, $fields); - //general user info - $info['name'] = $result[0]['displayname'][0]; - $info['mail'] = $result[0]['mail'][0]; - $info['uid'] = $result[0]['samaccountname'][0]; - $info['dn'] = $result[0]['dn']; - - // additional information - foreach ($this->cnf['additional'] as $field) { - if (isset($result[0][strtolower($field)])) { - $info[$field] = $result[0][strtolower($field)][0]; - } - } - - // handle ActiveDirectory memberOf - $info['grps'] = $this->adldap->user_groups($user,(bool) $this->opts['recursive_groups']); - - if (is_array($info['grps'])) { - foreach ($info['grps'] as $ndx => $group) { - $info['grps'][$ndx] = $this->cleanGroup($group); - } - } - - // always add the default group to the list of groups - if(!is_array($info['grps']) || !in_array($conf['defaultgroup'],$info['grps'])){ - $info['grps'][] = $conf['defaultgroup']; - } - - return $info; - } - - /** - * Make AD group names usable by DokuWiki. - * - * Removes backslashes ('\'), pound signs ('#'), and converts spaces to underscores. - * - * @author James Van Lommel (jamesvl@gmail.com) - */ - function cleanGroup($name) { - $sName = str_replace('\\', '', $name); - $sName = str_replace('#', '', $sName); - $sName = preg_replace('[\s]', '_', $sName); - return $sName; - } - - /** - * Sanitize user names - */ - function cleanUser($name) { - return $this->cleanGroup($name); - } - - /** - * Most values in LDAP are case-insensitive - */ - function isCaseSensitive(){ - return false; - } - - /** - * Bulk retrieval of user data - * - * @author Dominik Eckelmann - * @param start index of first user to be returned - * @param limit max number of users to be returned - * @param filter array of field/pattern pairs, null for no filter - * @return array of userinfo (refer getUserData for internal userinfo details) - */ - function retrieveUsers($start=0,$limit=-1,$filter=array()) { - if(!$this->_init()) return false; - - if ($this->users === null) { - //get info for given user - $result = $this->adldap->all_users(); - if (!$result) return array(); - $this->users = array_fill_keys($result, false); - } - - $i = 0; - $count = 0; - $this->_constructPattern($filter); - $result = array(); - - foreach ($this->users as $user => &$info) { - if ($i++ < $start) { - continue; - } - if ($info === false) { - $info = $this->getUserData($user); - } - if ($this->_filter($user, $info)) { - $result[$user] = $info; - if (($limit >= 0) && (++$count >= $limit)) break; - } - } - return $result; - } - - /** - * Modify user data - * - * @param $user nick of the user to be changed - * @param $changes array of field/value pairs to be changed - * @return bool - */ - function modifyUser($user, $changes) { - $return = true; - - // password changing - if(isset($changes['pass'])){ - try { - $return = $this->adldap->user_password($user,$changes['pass']); - } catch (adLDAPException $e) { - if ($this->cnf['debug']) msg('AD Auth: '.$e->getMessage(), -1); - $return = false; - } - if(!$return) msg('AD Auth: failed to change the password. Maybe the password policy was not met?',-1); - } - - // changing user data - $adchanges = array(); - if(isset($changes['name'])){ - // get first and last name - $parts = explode(' ',$changes['name']); - $adchanges['surname'] = array_pop($parts); - $adchanges['firstname'] = join(' ',$parts); - $adchanges['display_name'] = $changes['name']; - } - if(isset($changes['mail'])){ - $adchanges['email'] = $changes['mail']; - } - if(count($adchanges)){ - try { - $return = $return & $this->adldap->user_modify($user,$adchanges); - } catch (adLDAPException $e) { - if ($this->cnf['debug']) msg('AD Auth: '.$e->getMessage(), -1); - $return = false; - } - } - - return $return; - } - - /** - * Initialize the AdLDAP library and connect to the server - */ - function _init(){ - if(!is_null($this->adldap)) return true; - - // connect - try { - $this->adldap = new adLDAP($this->opts); - if (isset($this->opts['ad_username']) && isset($this->opts['ad_password'])) { - $this->canDo['getUsers'] = true; - } - return true; - } catch (adLDAPException $e) { - if ($this->cnf['debug']) { - msg('AD Auth: '.$e->getMessage(), -1); - } - $this->success = false; - $this->adldap = null; - } - return false; - } - - /** - * return 1 if $user + $info match $filter criteria, 0 otherwise - * - * @author Chris Smith - */ - function _filter($user, $info) { - foreach ($this->_pattern as $item => $pattern) { - if ($item == 'user') { - if (!preg_match($pattern, $user)) return 0; - } else if ($item == 'grps') { - if (!count(preg_grep($pattern, $info['grps']))) return 0; - } else { - if (!preg_match($pattern, $info[$item])) return 0; - } - } - return 1; - } - - function _constructPattern($filter) { - $this->_pattern = array(); - foreach ($filter as $item => $pattern) { -// $this->_pattern[$item] = '/'.preg_quote($pattern,"/").'/i'; // don't allow regex characters - $this->_pattern[$item] = '/'.str_replace('/','\/',$pattern).'/i'; // allow regex characters - } - } -} - -//Setup VIM: ex: et ts=4 : diff --git a/inc/auth/basic.class.php b/inc/auth/basic.class.php deleted file mode 100644 index c7e7031bf..000000000 --- a/inc/auth/basic.class.php +++ /dev/null @@ -1,403 +0,0 @@ - - */ - -class auth_basic { - - var $success = true; - - - /** - * Posible things an auth backend module may be able to - * do. The things a backend can do need to be set to true - * in the constructor. - */ - var $cando = array ( - 'addUser' => false, // can Users be created? - 'delUser' => false, // can Users be deleted? - 'modLogin' => false, // can login names be changed? - 'modPass' => false, // can passwords be changed? - 'modName' => false, // can real names be changed? - 'modMail' => false, // can emails be changed? - 'modGroups' => false, // can groups be changed? - 'getUsers' => false, // can a (filtered) list of users be retrieved? - 'getUserCount'=> false, // can the number of users be retrieved? - 'getGroups' => false, // can a list of available groups be retrieved? - 'external' => false, // does the module do external auth checking? - 'logout' => true, // can the user logout again? (eg. not possible with HTTP auth) - ); - - - /** - * Constructor. - * - * Carry out sanity checks to ensure the object is - * able to operate. Set capabilities in $this->cando - * array here - * - * Set $this->success to false if checks fail - * - * @author Christopher Smith - */ - function auth_basic() { - // the base class constructor does nothing, derived class - // constructors do the real work - } - - /** - * Capability check. [ DO NOT OVERRIDE ] - * - * Checks the capabilities set in the $this->cando array and - * some pseudo capabilities (shortcutting access to multiple - * ones) - * - * ususal capabilities start with lowercase letter - * shortcut capabilities start with uppercase letter - * - * @author Andreas Gohr - * @return bool - */ - function canDo($cap) { - switch($cap){ - case 'Profile': - // can at least one of the user's properties be changed? - return ( $this->cando['modPass'] || - $this->cando['modName'] || - $this->cando['modMail'] ); - break; - case 'UserMod': - // can at least anything be changed? - return ( $this->cando['modPass'] || - $this->cando['modName'] || - $this->cando['modMail'] || - $this->cando['modLogin'] || - $this->cando['modGroups'] || - $this->cando['modMail'] ); - break; - default: - // print a helping message for developers - if(!isset($this->cando[$cap])){ - msg("Check for unknown capability '$cap' - Do you use an outdated Plugin?",-1); - } - return $this->cando[$cap]; - } - } - - /** - * Trigger the AUTH_USERDATA_CHANGE event and call the modification function. [ DO NOT OVERRIDE ] - * - * You should use this function instead of calling createUser, modifyUser or - * deleteUsers directly. The event handlers can prevent the modification, for - * example for enforcing a user name schema. - * - * @author Gabriel Birke - * @param string $type Modification type ('create', 'modify', 'delete') - * @param array $params Parameters for the createUser, modifyUser or deleteUsers method. The content of this array depends on the modification type - * @return mixed Result from the modification function or false if an event handler has canceled the action - */ - function triggerUserMod($type, $params) - { - $validTypes = array( - 'create' => 'createUser', - 'modify' => 'modifyUser', - 'delete' => 'deleteUsers' - ); - if(empty($validTypes[$type])) - return false; - $eventdata = array('type' => $type, 'params' => $params, 'modification_result' => null); - $evt = new Doku_Event('AUTH_USER_CHANGE', $eventdata); - if ($evt->advise_before(true)) { - $result = call_user_func_array(array($this, $validTypes[$type]), $params); - $evt->data['modification_result'] = $result; - } - $evt->advise_after(); - unset($evt); - return $result; - } - - /** - * Log off the current user [ OPTIONAL ] - * - * Is run in addition to the ususal logoff method. Should - * only be needed when trustExternal is implemented. - * - * @see auth_logoff() - * @author Andreas Gohr - */ - function logOff(){ - } - - /** - * Do all authentication [ OPTIONAL ] - * - * Set $this->cando['external'] = true when implemented - * - * If this function is implemented it will be used to - * authenticate a user - all other DokuWiki internals - * will not be used for authenticating, thus - * implementing the checkPass() function is not needed - * anymore. - * - * The function can be used to authenticate against third - * party cookies or Apache auth mechanisms and replaces - * the auth_login() function - * - * The function will be called with or without a set - * username. If the Username is given it was called - * from the login form and the given credentials might - * need to be checked. If no username was given it - * the function needs to check if the user is logged in - * by other means (cookie, environment). - * - * The function needs to set some globals needed by - * DokuWiki like auth_login() does. - * - * @see auth_login() - * @author Andreas Gohr - * - * @param string $user Username - * @param string $pass Cleartext Password - * @param bool $sticky Cookie should not expire - * @return bool true on successful auth - */ - function trustExternal($user,$pass,$sticky=false){ -# // some example: -# -# global $USERINFO; -# global $conf; -# $sticky ? $sticky = true : $sticky = false; //sanity check -# -# // do the checking here -# -# // set the globals if authed -# $USERINFO['name'] = 'FIXME'; -# $USERINFO['mail'] = 'FIXME'; -# $USERINFO['grps'] = array('FIXME'); -# $_SERVER['REMOTE_USER'] = $user; -# $_SESSION[DOKU_COOKIE]['auth']['user'] = $user; -# $_SESSION[DOKU_COOKIE]['auth']['pass'] = $pass; -# $_SESSION[DOKU_COOKIE]['auth']['info'] = $USERINFO; -# return true; - } - - /** - * Check user+password [ MUST BE OVERRIDDEN ] - * - * Checks if the given user exists and the given - * plaintext password is correct - * - * May be ommited if trustExternal is used. - * - * @author Andreas Gohr - * @return bool - */ - function checkPass($user,$pass){ - msg("no valid authorisation system in use", -1); - return false; - } - - /** - * Return user info [ MUST BE OVERRIDDEN ] - * - * Returns info about the given user needs to contain - * at least these fields: - * - * name string full name of the user - * mail string email addres of the user - * grps array list of groups the user is in - * - * @author Andreas Gohr - * @return array containing user data or false - */ - function getUserData($user) { - if(!$this->cando['external']) msg("no valid authorisation system in use", -1); - return false; - } - - /** - * Create a new User [implement only where required/possible] - * - * Returns false if the user already exists, null when an error - * occurred and true if everything went well. - * - * The new user HAS TO be added to the default group by this - * function! - * - * Set addUser capability when implemented - * - * @author Andreas Gohr - */ - function createUser($user,$pass,$name,$mail,$grps=null){ - msg("authorisation method does not allow creation of new users", -1); - return null; - } - - /** - * Modify user data [implement only where required/possible] - * - * Set the mod* capabilities according to the implemented features - * - * @author Chris Smith - * @param $user nick of the user to be changed - * @param $changes array of field/value pairs to be changed (password will be clear text) - * @return bool - */ - function modifyUser($user, $changes) { - msg("authorisation method does not allow modifying of user data", -1); - return false; - } - - /** - * Delete one or more users [implement only where required/possible] - * - * Set delUser capability when implemented - * - * @author Chris Smith - * @param array $users - * @return int number of users deleted - */ - function deleteUsers($users) { - msg("authorisation method does not allow deleting of users", -1); - return false; - } - - /** - * Return a count of the number of user which meet $filter criteria - * [should be implemented whenever retrieveUsers is implemented] - * - * Set getUserCount capability when implemented - * - * @author Chris Smith - */ - function getUserCount($filter=array()) { - msg("authorisation method does not provide user counts", -1); - return 0; - } - - /** - * Bulk retrieval of user data [implement only where required/possible] - * - * Set getUsers capability when implemented - * - * @author Chris Smith - * @param start index of first user to be returned - * @param limit max number of users to be returned - * @param filter array of field/pattern pairs, null for no filter - * @return array of userinfo (refer getUserData for internal userinfo details) - */ - function retrieveUsers($start=0,$limit=-1,$filter=null) { - msg("authorisation method does not support mass retrieval of user data", -1); - return array(); - } - - /** - * Define a group [implement only where required/possible] - * - * Set addGroup capability when implemented - * - * @author Chris Smith - * @return bool - */ - function addGroup($group) { - msg("authorisation method does not support independent group creation", -1); - return false; - } - - /** - * Retrieve groups [implement only where required/possible] - * - * Set getGroups capability when implemented - * - * @author Chris Smith - * @return array - */ - function retrieveGroups($start=0,$limit=0) { - msg("authorisation method does not support group list retrieval", -1); - return array(); - } - - /** - * Return case sensitivity of the backend [OPTIONAL] - * - * When your backend is caseinsensitive (eg. you can login with USER and - * user) then you need to overwrite this method and return false - */ - function isCaseSensitive(){ - return true; - } - - /** - * Sanitize a given username [OPTIONAL] - * - * This function is applied to any user name that is given to - * the backend and should also be applied to any user name within - * the backend before returning it somewhere. - * - * This should be used to enforce username restrictions. - * - * @author Andreas Gohr - * @param string $user - username - * @param string - the cleaned username - */ - function cleanUser($user){ - return $user; - } - - /** - * Sanitize a given groupname [OPTIONAL] - * - * This function is applied to any groupname that is given to - * the backend and should also be applied to any groupname within - * the backend before returning it somewhere. - * - * This should be used to enforce groupname restrictions. - * - * Groupnames are to be passed without a leading '@' here. - * - * @author Andreas Gohr - * @param string $group - groupname - * @param string - the cleaned groupname - */ - function cleanGroup($group){ - return $group; - } - - - /** - * Check Session Cache validity [implement only where required/possible] - * - * DokuWiki caches user info in the user's session for the timespan defined - * in $conf['auth_security_timeout']. - * - * This makes sure slow authentication backends do not slow down DokuWiki. - * This also means that changes to the user database will not be reflected - * on currently logged in users. - * - * To accommodate for this, the user manager plugin will touch a reference - * file whenever a change is submitted. This function compares the filetime - * of this reference file with the time stored in the session. - * - * This reference file mechanism does not reflect changes done directly in - * the backend's database through other means than the user manager plugin. - * - * Fast backends might want to return always false, to force rechecks on - * each page load. Others might want to use their own checking here. If - * unsure, do not override. - * - * @param string $user - The username - * @author Andreas Gohr - * @return bool - */ - function useSessionCache($user){ - global $conf; - return ($_SESSION[DOKU_COOKIE]['auth']['time'] >= @filemtime($conf['cachedir'].'/sessionpurge')); - } - -} -//Setup VIM: ex: et ts=2 : diff --git a/inc/auth/ldap.class.php b/inc/auth/ldap.class.php deleted file mode 100644 index 8eb411995..000000000 --- a/inc/auth/ldap.class.php +++ /dev/null @@ -1,463 +0,0 @@ - - * @author Chris Smith - */ - -class auth_ldap extends auth_basic { - var $cnf = null; - var $con = null; - var $bound = 0; // 0: anonymous, 1: user, 2: superuser - - /** - * Constructor - */ - function auth_ldap(){ - global $conf; - $this->cnf = $conf['auth']['ldap']; - - // ldap extension is needed - if(!function_exists('ldap_connect')) { - if ($this->cnf['debug']) - msg("LDAP err: PHP LDAP extension not found.",-1,__LINE__,__FILE__); - $this->success = false; - return; - } - - if(empty($this->cnf['groupkey'])) $this->cnf['groupkey'] = 'cn'; - if(empty($this->cnf['userscope'])) $this->cnf['userscope'] = 'sub'; - if(empty($this->cnf['groupscope'])) $this->cnf['groupscope'] = 'sub'; - - // auth_ldap currently just handles authentication, so no - // capabilities are set - } - - /** - * Check user+password - * - * Checks if the given user exists and the given - * plaintext password is correct by trying to bind - * to the LDAP server - * - * @author Andreas Gohr - * @return bool - */ - function checkPass($user,$pass){ - // reject empty password - if(empty($pass)) return false; - if(!$this->_openLDAP()) return false; - - // indirect user bind - if($this->cnf['binddn'] && $this->cnf['bindpw']){ - // use superuser credentials - if(!@ldap_bind($this->con,$this->cnf['binddn'],$this->cnf['bindpw'])){ - if($this->cnf['debug']) - msg('LDAP bind as superuser: '.htmlspecialchars(ldap_error($this->con)),0,__LINE__,__FILE__); - return false; - } - $this->bound = 2; - }else if($this->cnf['binddn'] && - $this->cnf['usertree'] && - $this->cnf['userfilter']) { - // special bind string - $dn = $this->_makeFilter($this->cnf['binddn'], - array('user'=>$user,'server'=>$this->cnf['server'])); - - }else if(strpos($this->cnf['usertree'], '%{user}')) { - // direct user bind - $dn = $this->_makeFilter($this->cnf['usertree'], - array('user'=>$user,'server'=>$this->cnf['server'])); - - }else{ - // Anonymous bind - if(!@ldap_bind($this->con)){ - msg("LDAP: can not bind anonymously",-1); - if($this->cnf['debug']) - msg('LDAP anonymous bind: '.htmlspecialchars(ldap_error($this->con)),0,__LINE__,__FILE__); - return false; - } - } - - // Try to bind to with the dn if we have one. - if(!empty($dn)) { - // User/Password bind - if(!@ldap_bind($this->con,$dn,$pass)){ - if($this->cnf['debug']){ - msg("LDAP: bind with $dn failed", -1,__LINE__,__FILE__); - msg('LDAP user dn bind: '.htmlspecialchars(ldap_error($this->con)),0); - } - return false; - } - $this->bound = 1; - return true; - }else{ - // See if we can find the user - $info = $this->getUserData($user,true); - if(empty($info['dn'])) { - return false; - } else { - $dn = $info['dn']; - } - - // Try to bind with the dn provided - if(!@ldap_bind($this->con,$dn,$pass)){ - if($this->cnf['debug']){ - msg("LDAP: bind with $dn failed", -1,__LINE__,__FILE__); - msg('LDAP user bind: '.htmlspecialchars(ldap_error($this->con)),0); - } - return false; - } - $this->bound = 1; - return true; - } - - return false; - } - - /** - * Return user info - * - * Returns info about the given user needs to contain - * at least these fields: - * - * name string full name of the user - * mail string email addres of the user - * grps array list of groups the user is in - * - * This LDAP specific function returns the following - * addional fields: - * - * dn string distinguished name (DN) - * uid string Posix User ID - * inbind bool for internal use - avoid loop in binding - * - * @author Andreas Gohr - * @author Trouble - * @author Dan Allen - * @author - * @author Stephane Chazelas - * @return array containing user data or false - */ - function getUserData($user,$inbind=false) { - global $conf; - if(!$this->_openLDAP()) return false; - - // force superuser bind if wanted and not bound as superuser yet - if($this->cnf['binddn'] && $this->cnf['bindpw'] && $this->bound < 2){ - // use superuser credentials - if(!@ldap_bind($this->con,$this->cnf['binddn'],$this->cnf['bindpw'])){ - if($this->cnf['debug']) - msg('LDAP bind as superuser: '.htmlspecialchars(ldap_error($this->con)),0,__LINE__,__FILE__); - return false; - } - $this->bound = 2; - }elseif($this->bound == 0 && !$inbind) { - // in some cases getUserData is called outside the authentication workflow - // eg. for sending email notification on subscribed pages. This data might not - // be accessible anonymously, so we try to rebind the current user here - list($loginuser,$loginsticky,$loginpass) = auth_getCookie(); - if($loginuser && $loginpass){ - $loginpass = PMA_blowfish_decrypt($loginpass, auth_cookiesalt(!$loginsticky)); - $this->checkPass($loginuser, $loginpass); - } - } - - $info['user'] = $user; - $info['server'] = $this->cnf['server']; - - //get info for given user - $base = $this->_makeFilter($this->cnf['usertree'], $info); - if(!empty($this->cnf['userfilter'])) { - $filter = $this->_makeFilter($this->cnf['userfilter'], $info); - } else { - $filter = "(ObjectClass=*)"; - } - - $sr = $this->_ldapsearch($this->con, $base, $filter, $this->cnf['userscope']); - $result = @ldap_get_entries($this->con, $sr); - if($this->cnf['debug']){ - msg('LDAP user search: '.htmlspecialchars(ldap_error($this->con)),0,__LINE__,__FILE__); - msg('LDAP search at: '.htmlspecialchars($base.' '.$filter),0,__LINE__,__FILE__); - } - - // Don't accept more or less than one response - if(!is_array($result) || $result['count'] != 1){ - return false; //user not found - } - - $user_result = $result[0]; - ldap_free_result($sr); - - // general user info - $info['dn'] = $user_result['dn']; - $info['gid'] = $user_result['gidnumber'][0]; - $info['mail'] = $user_result['mail'][0]; - $info['name'] = $user_result['cn'][0]; - $info['grps'] = array(); - - // overwrite if other attribs are specified. - if(is_array($this->cnf['mapping'])){ - foreach($this->cnf['mapping'] as $localkey => $key) { - if(is_array($key)) { - // use regexp to clean up user_result - list($key, $regexp) = each($key); - if($user_result[$key]) foreach($user_result[$key] as $grp){ - if (preg_match($regexp,$grp,$match)) { - if($localkey == 'grps') { - $info[$localkey][] = $match[1]; - } else { - $info[$localkey] = $match[1]; - } - } - } - } else { - $info[$localkey] = $user_result[$key][0]; - } - } - } - $user_result = array_merge($info,$user_result); - - //get groups for given user if grouptree is given - if ($this->cnf['grouptree'] || $this->cnf['groupfilter']) { - $base = $this->_makeFilter($this->cnf['grouptree'], $user_result); - $filter = $this->_makeFilter($this->cnf['groupfilter'], $user_result); - $sr = $this->_ldapsearch($this->con, $base, $filter, $this->cnf['groupscope'], array($this->cnf['groupkey'])); - if($this->cnf['debug']){ - msg('LDAP group search: '.htmlspecialchars(ldap_error($this->con)),0,__LINE__,__FILE__); - msg('LDAP search at: '.htmlspecialchars($base.' '.$filter),0,__LINE__,__FILE__); - } - if(!$sr){ - msg("LDAP: Reading group memberships failed",-1); - return false; - } - $result = ldap_get_entries($this->con, $sr); - ldap_free_result($sr); - - if(is_array($result)) foreach($result as $grp){ - if(!empty($grp[$this->cnf['groupkey']][0])){ - if($this->cnf['debug']) - msg('LDAP usergroup: '.htmlspecialchars($grp[$this->cnf['groupkey']][0]),0,__LINE__,__FILE__); - $info['grps'][] = $grp[$this->cnf['groupkey']][0]; - } - } - } - - // always add the default group to the list of groups - if(!in_array($conf['defaultgroup'],$info['grps'])){ - $info['grps'][] = $conf['defaultgroup']; - } - return $info; - } - - /** - * Most values in LDAP are case-insensitive - */ - function isCaseSensitive(){ - return false; - } - - /** - * Bulk retrieval of user data - * - * @author Dominik Eckelmann - * @param start index of first user to be returned - * @param limit max number of users to be returned - * @param filter array of field/pattern pairs, null for no filter - * @return array of userinfo (refer getUserData for internal userinfo details) - */ - function retrieveUsers($start=0,$limit=-1,$filter=array()) { - if(!$this->_openLDAP()) return false; - - if (!isset($this->users)) { - // Perform the search and grab all their details - if(!empty($this->cnf['userfilter'])) { - $all_filter = str_replace('%{user}', '*', $this->cnf['userfilter']); - } else { - $all_filter = "(ObjectClass=*)"; - } - $sr=ldap_search($this->con,$this->cnf['usertree'],$all_filter); - $entries = ldap_get_entries($this->con, $sr); - $users_array = array(); - for ($i=0; $i<$entries["count"]; $i++){ - array_push($users_array, $entries[$i]["uid"][0]); - } - asort($users_array); - $result = $users_array; - if (!$result) return array(); - $this->users = array_fill_keys($result, false); - } - $i = 0; - $count = 0; - $this->_constructPattern($filter); - $result = array(); - - foreach ($this->users as $user => &$info) { - if ($i++ < $start) { - continue; - } - if ($info === false) { - $info = $this->getUserData($user); - } - if ($this->_filter($user, $info)) { - $result[$user] = $info; - if (($limit >= 0) && (++$count >= $limit)) break; - } - } - return $result; - - - } - - /** - * Make LDAP filter strings. - * - * Used by auth_getUserData to make the filter - * strings for grouptree and groupfilter - * - * filter string ldap search filter with placeholders - * placeholders array array with the placeholders - * - * @author Troels Liebe Bentsen - * @return string - */ - function _makeFilter($filter, $placeholders) { - preg_match_all("/%{([^}]+)/", $filter, $matches, PREG_PATTERN_ORDER); - //replace each match - foreach ($matches[1] as $match) { - //take first element if array - if(is_array($placeholders[$match])) { - $value = $placeholders[$match][0]; - } else { - $value = $placeholders[$match]; - } - $value = $this->_filterEscape($value); - $filter = str_replace('%{'.$match.'}', $value, $filter); - } - return $filter; - } - - /** - * return 1 if $user + $info match $filter criteria, 0 otherwise - * - * @author Chris Smith - */ - function _filter($user, $info) { - foreach ($this->_pattern as $item => $pattern) { - if ($item == 'user') { - if (!preg_match($pattern, $user)) return 0; - } else if ($item == 'grps') { - if (!count(preg_grep($pattern, $info['grps']))) return 0; - } else { - if (!preg_match($pattern, $info[$item])) return 0; - } - } - return 1; - } - - function _constructPattern($filter) { - $this->_pattern = array(); - foreach ($filter as $item => $pattern) { -// $this->_pattern[$item] = '/'.preg_quote($pattern,"/").'/i'; // don't allow regex characters - $this->_pattern[$item] = '/'.str_replace('/','\/',$pattern).'/i'; // allow regex characters - } - } - - /** - * Escape a string to be used in a LDAP filter - * - * Ported from Perl's Net::LDAP::Util escape_filter_value - * - * @author Andreas Gohr - */ - function _filterEscape($string){ - return preg_replace('/([\x00-\x1F\*\(\)\\\\])/e', - '"\\\\\".join("",unpack("H2","$1"))', - $string); - } - - /** - * Opens a connection to the configured LDAP server and sets the wanted - * option on the connection - * - * @author Andreas Gohr - */ - function _openLDAP(){ - if($this->con) return true; // connection already established - - $this->bound = 0; - - $port = ($this->cnf['port']) ? $this->cnf['port'] : 389; - $this->con = @ldap_connect($this->cnf['server'],$port); - if(!$this->con){ - msg("LDAP: couldn't connect to LDAP server",-1); - return false; - } - - //set protocol version and dependend options - if($this->cnf['version']){ - if(!@ldap_set_option($this->con, LDAP_OPT_PROTOCOL_VERSION, - $this->cnf['version'])){ - msg('Setting LDAP Protocol version '.$this->cnf['version'].' failed',-1); - if($this->cnf['debug']) - msg('LDAP version set: '.htmlspecialchars(ldap_error($this->con)),0,__LINE__,__FILE__); - }else{ - //use TLS (needs version 3) - if($this->cnf['starttls']) { - if (!@ldap_start_tls($this->con)){ - msg('Starting TLS failed',-1); - if($this->cnf['debug']) - msg('LDAP TLS set: '.htmlspecialchars(ldap_error($this->con)),0,__LINE__,__FILE__); - } - } - // needs version 3 - if(isset($this->cnf['referrals'])) { - if(!@ldap_set_option($this->con, LDAP_OPT_REFERRALS, - $this->cnf['referrals'])){ - msg('Setting LDAP referrals to off failed',-1); - if($this->cnf['debug']) - msg('LDAP referal set: '.htmlspecialchars(ldap_error($this->con)),0,__LINE__,__FILE__); - } - } - } - } - - //set deref mode - if($this->cnf['deref']){ - if(!@ldap_set_option($this->con, LDAP_OPT_DEREF, $this->cnf['deref'])){ - msg('Setting LDAP Deref mode '.$this->cnf['deref'].' failed',-1); - if($this->cnf['debug']) - msg('LDAP deref set: '.htmlspecialchars(ldap_error($this->con)),0,__LINE__,__FILE__); - } - } - - $this->canDo['getUsers'] = true; - return true; - } - - /** - * Wraps around ldap_search, ldap_list or ldap_read depending on $scope - * - * @param $scope string - can be 'base', 'one' or 'sub' - * @author Andreas Gohr - */ - function _ldapsearch($link_identifier, $base_dn, $filter, $scope='sub', $attributes=null, - $attrsonly=0, $sizelimit=0, $timelimit=0, $deref=LDAP_DEREF_NEVER){ - if(is_null($attributes)) $attributes = array(); - - if($scope == 'base'){ - return @ldap_read($link_identifier, $base_dn, $filter, $attributes, - $attrsonly, $sizelimit, $timelimit, $deref); - }elseif($scope == 'one'){ - return @ldap_list($link_identifier, $base_dn, $filter, $attributes, - $attrsonly, $sizelimit, $timelimit, $deref); - }else{ - return @ldap_search($link_identifier, $base_dn, $filter, $attributes, - $attrsonly, $sizelimit, $timelimit, $deref); - } - } -} - -//Setup VIM: ex: et ts=4 : diff --git a/inc/auth/mysql.class.php b/inc/auth/mysql.class.php deleted file mode 100644 index 653c725a3..000000000 --- a/inc/auth/mysql.class.php +++ /dev/null @@ -1,939 +0,0 @@ - - * @author Chris Smith - * @author Matthias Grimm -*/ - -class auth_mysql extends auth_basic { - - var $dbcon = 0; - var $dbver = 0; // database version - var $dbrev = 0; // database revision - var $dbsub = 0; // database subrevision - var $cnf = null; - var $defaultgroup = ""; - - /** - * Constructor - * - * checks if the mysql interface is available, otherwise it will - * set the variable $success of the basis class to false - * - * @author Matthias Grimm - */ - function auth_mysql() { - global $conf; - $this->cnf = $conf['auth']['mysql']; - - if (method_exists($this, 'auth_basic')) - parent::auth_basic(); - - if(!function_exists('mysql_connect')) { - if ($this->cnf['debug']) - msg("MySQL err: PHP MySQL extension not found.",-1,__LINE__,__FILE__); - $this->success = false; - return; - } - - // default to UTF-8, you rarely want something else - if(!isset($this->cnf['charset'])) $this->cnf['charset'] = 'utf8'; - - $this->defaultgroup = $conf['defaultgroup']; - - // set capabilities based upon config strings set - if (empty($this->cnf['server']) || empty($this->cnf['user']) || - !isset($this->cnf['password']) || empty($this->cnf['database'])){ - if ($this->cnf['debug']) - msg("MySQL err: insufficient configuration.",-1,__LINE__,__FILE__); - $this->success = false; - return; - } - - $this->cando['addUser'] = $this->_chkcnf(array('getUserInfo', - 'getGroups', - 'addUser', - 'getUserID', - 'getGroupID', - 'addGroup', - 'addUserGroup'),true); - $this->cando['delUser'] = $this->_chkcnf(array('getUserID', - 'delUser', - 'delUserRefs'),true); - $this->cando['modLogin'] = $this->_chkcnf(array('getUserID', - 'updateUser', - 'UpdateTarget'),true); - $this->cando['modPass'] = $this->cando['modLogin']; - $this->cando['modName'] = $this->cando['modLogin']; - $this->cando['modMail'] = $this->cando['modLogin']; - $this->cando['modGroups'] = $this->_chkcnf(array('getUserID', - 'getGroups', - 'getGroupID', - 'addGroup', - 'addUserGroup', - 'delGroup', - 'getGroupID', - 'delUserGroup'),true); - /* getGroups is not yet supported - $this->cando['getGroups'] = $this->_chkcnf(array('getGroups', - 'getGroupID'),false); */ - $this->cando['getUsers'] = $this->_chkcnf(array('getUsers', - 'getUserInfo', - 'getGroups'),false); - $this->cando['getUserCount'] = $this->_chkcnf(array('getUsers'),false); - } - - /** - * Check if the given config strings are set - * - * @author Matthias Grimm - * @return bool - */ - function _chkcnf($keys, $wop=false){ - foreach ($keys as $key){ - if (empty($this->cnf[$key])) return false; - } - - /* write operation and lock array filled with tables names? */ - if ($wop && (!is_array($this->cnf['TablesToLock']) || - !count($this->cnf['TablesToLock']))){ - return false; - } - - return true; - } - - /** - * Checks if the given user exists and the given plaintext password - * is correct. Furtheron it might be checked wether the user is - * member of the right group - * - * Depending on which SQL string is defined in the config, password - * checking is done here (getpass) or by the database (passcheck) - * - * @param $user user who would like access - * @param $pass user's clear text password to check - * @return bool - * - * @author Andreas Gohr - * @author Matthias Grimm - */ - function checkPass($user,$pass){ - $rc = false; - - if($this->_openDB()) { - $sql = str_replace('%{user}',$this->_escape($user),$this->cnf['checkPass']); - $sql = str_replace('%{pass}',$this->_escape($pass),$sql); - $sql = str_replace('%{dgroup}',$this->_escape($this->defaultgroup),$sql); - $result = $this->_queryDB($sql); - - if($result !== false && count($result) == 1) { - if($this->cnf['forwardClearPass'] == 1) - $rc = true; - else - $rc = auth_verifyPassword($pass,$result[0]['pass']); - } - $this->_closeDB(); - } - return $rc; - } - - /** - * [public function] - * - * Returns info about the given user needs to contain - * at least these fields: - * name string full name of the user - * mail string email addres of the user - * grps array list of groups the user is in - * - * @param $user user's nick to get data for - * - * @author Andreas Gohr - * @author Matthias Grimm - */ - function getUserData($user){ - if($this->_openDB()) { - $this->_lockTables("READ"); - $info = $this->_getUserInfo($user); - $this->_unlockTables(); - $this->_closeDB(); - } else - $info = false; - return $info; - } - - /** - * [public function] - * - * Create a new User. Returns false if the user already exists, - * null when an error occurred and true if everything went well. - * - * The new user will be added to the default group by this - * function if grps are not specified (default behaviour). - * - * @param $user nick of the user - * @param $pwd clear text password - * @param $name full name of the user - * @param $mail email address - * @param $grps array of groups the user should become member of - * - * @author Andreas Gohr - * @author Chris Smith - * @author Matthias Grimm - */ - function createUser($user,$pwd,$name,$mail,$grps=null){ - if($this->_openDB()) { - if (($info = $this->_getUserInfo($user)) !== false) - return false; // user already exists - - // set defaultgroup if no groups were given - if ($grps == null) - $grps = array($this->defaultgroup); - - $this->_lockTables("WRITE"); - $pwd = $this->cnf['forwardClearPass'] ? $pwd : auth_cryptPassword($pwd); - $rc = $this->_addUser($user,$pwd,$name,$mail,$grps); - $this->_unlockTables(); - $this->_closeDB(); - if ($rc) return true; - } - return null; // return error - } - - /** - * Modify user data [public function] - * - * An existing user dataset will be modified. Changes are given in an array. - * - * The dataset update will be rejected if the user name should be changed - * to an already existing one. - * - * The password must be provides unencrypted. Pasword cryption is done - * automatically if configured. - * - * If one or more groups could't be updated, an error would be set. In - * this case the dataset might already be changed and we can't rollback - * the changes. Transactions would be really usefull here. - * - * modifyUser() may be called without SQL statements defined that are - * needed to change group membership (for example if only the user profile - * should be modified). In this case we asure that we don't touch groups - * even $changes['grps'] is set by mistake. - * - * @param $user nick of the user to be changed - * @param $changes array of field/value pairs to be changed (password - * will be clear text) - * @return bool true on success, false on error - * - * @author Chris Smith - * @author Matthias Grimm - */ - function modifyUser($user, $changes) { - $rc = false; - - if (!is_array($changes) || !count($changes)) - return true; // nothing to change - - if($this->_openDB()) { - $this->_lockTables("WRITE"); - - if (($uid = $this->_getUserID($user))) { - $rc = $this->_updateUserInfo($changes, $uid); - - if ($rc && isset($changes['grps']) && $this->cando['modGroups']) { - $groups = $this->_getGroups($user); - $grpadd = array_diff($changes['grps'], $groups); - $grpdel = array_diff($groups, $changes['grps']); - - foreach($grpadd as $group) - if (($this->_addUserToGroup($user, $group, 1)) == false) - $rc = false; - - foreach($grpdel as $group) - if (($this->_delUserFromGroup($user, $group)) == false) - $rc = false; - } - } - - $this->_unlockTables(); - $this->_closeDB(); - } - return $rc; - } - - /** - * [public function] - * - * Remove one or more users from the list of registered users - * - * @param array $users array of users to be deleted - * @return int the number of users deleted - * - * @author Christopher Smith - * @author Matthias Grimm - */ - function deleteUsers($users) { - $count = 0; - - if($this->_openDB()) { - if (is_array($users) && count($users)) { - $this->_lockTables("WRITE"); - foreach ($users as $user) { - if ($this->_delUser($user)) - $count++; - } - $this->_unlockTables(); - } - $this->_closeDB(); - } - return $count; - } - - /** - * [public function] - * - * Counts users which meet certain $filter criteria. - * - * @param array $filter filter criteria in item/pattern pairs - * @return count of found users. - * - * @author Matthias Grimm - */ - function getUserCount($filter=array()) { - $rc = 0; - - if($this->_openDB()) { - $sql = $this->_createSQLFilter($this->cnf['getUsers'], $filter); - - if ($this->dbver >= 4) { - $sql = substr($sql, 6); /* remove 'SELECT' or 'select' */ - $sql = "SELECT SQL_CALC_FOUND_ROWS".$sql." LIMIT 1"; - $this->_queryDB($sql); - $result = $this->_queryDB("SELECT FOUND_ROWS()"); - $rc = $result[0]['FOUND_ROWS()']; - } else if (($result = $this->_queryDB($sql))) - $rc = count($result); - - $this->_closeDB(); - } - return $rc; - } - - /** - * Bulk retrieval of user data. [public function] - * - * @param first index of first user to be returned - * @param limit max number of users to be returned - * @param filter array of field/pattern pairs - * @return array of userinfo (refer getUserData for internal userinfo details) - * - * @author Matthias Grimm - */ - function retrieveUsers($first=0,$limit=10,$filter=array()) { - $out = array(); - - if($this->_openDB()) { - $this->_lockTables("READ"); - $sql = $this->_createSQLFilter($this->cnf['getUsers'], $filter); - $sql .= " ".$this->cnf['SortOrder']." LIMIT $first, $limit"; - $result = $this->_queryDB($sql); - - if (!empty($result)) { - foreach ($result as $user) - if (($info = $this->_getUserInfo($user['user']))) - $out[$user['user']] = $info; - } - - $this->_unlockTables(); - $this->_closeDB(); - } - return $out; - } - - /** - * Give user membership of a group [public function] - * - * @param $user - * @param $group - * @return bool true on success, false on error - * - * @author Matthias Grimm - */ - function joinGroup($user, $group) { - $rc = false; - - if ($this->_openDB()) { - $this->_lockTables("WRITE"); - $rc = $this->_addUserToGroup($user, $group); - $this->_unlockTables(); - $this->_closeDB(); - } - return $rc; - } - - /** - * Remove user from a group [public function] - * - * @param $user user that leaves a group - * @param $group group to leave - * @return bool - * - * @author Matthias Grimm - */ - function leaveGroup($user, $group) { - $rc = false; - - if ($this->_openDB()) { - $this->_lockTables("WRITE"); - $uid = $this->_getUserID($user); - $rc = $this->_delUserFromGroup($user, $group); - $this->_unlockTables(); - $this->_closeDB(); - } - return $rc; - } - - /** - * MySQL is case-insensitive - */ - function isCaseSensitive(){ - return false; - } - - /** - * Adds a user to a group. - * - * If $force is set to '1' non existing groups would be created. - * - * The database connection must already be established. Otherwise - * this function does nothing and returns 'false'. It is strongly - * recommended to call this function only after all participating - * tables (group and usergroup) have been locked. - * - * @param $user user to add to a group - * @param $group name of the group - * @param $force '1' create missing groups - * @return bool 'true' on success, 'false' on error - * - * @author Matthias Grimm - */ - function _addUserToGroup($user, $group, $force=0) { - $newgroup = 0; - - if (($this->dbcon) && ($user)) { - $gid = $this->_getGroupID($group); - if (!$gid) { - if ($force) { // create missing groups - $sql = str_replace('%{group}',$this->_escape($group),$this->cnf['addGroup']); - $gid = $this->_modifyDB($sql); - $newgroup = 1; // group newly created - } - if (!$gid) return false; // group didn't exist and can't be created - } - - $sql = $this->cnf['addUserGroup']; - if(strpos($sql,'%{uid}') !== false){ - $uid = $this->_getUserID($user); - $sql = str_replace('%{uid}', $this->_escape($uid),$sql); - } - $sql = str_replace('%{user}', $this->_escape($user),$sql); - $sql = str_replace('%{gid}', $this->_escape($gid),$sql); - $sql = str_replace('%{group}',$this->_escape($group),$sql); - if ($this->_modifyDB($sql) !== false) return true; - - if ($newgroup) { // remove previously created group on error - $sql = str_replace('%{gid}', $this->_escape($gid),$this->cnf['delGroup']); - $sql = str_replace('%{group}',$this->_escape($group),$sql); - $this->_modifyDB($sql); - } - } - return false; - } - - /** - * Remove user from a group - * - * @param $user user that leaves a group - * @param $group group to leave - * @return bool true on success, false on error - * - * @author Matthias Grimm - */ - function _delUserFromGroup($user, $group) { - $rc = false; - - - if (($this->dbcon) && ($user)) { - $sql = $this->cnf['delUserGroup']; - if(strpos($sql,'%{uid}') !== false){ - $uid = $this->_getUserID($user); - $sql = str_replace('%{uid}', $this->_escape($uid),$sql); - } - $gid = $this->_getGroupID($group); - if ($gid) { - $sql = str_replace('%{user}', $this->_escape($user),$sql); - $sql = str_replace('%{gid}', $this->_escape($gid),$sql); - $sql = str_replace('%{group}',$this->_escape($group),$sql); - $rc = $this->_modifyDB($sql) == 0 ? true : false; - } - } - return $rc; - } - - /** - * Retrieves a list of groups the user is a member off. - * - * The database connection must already be established - * for this function to work. Otherwise it will return - * 'false'. - * - * @param $user user whose groups should be listed - * @return bool false on error - * @return array array containing all groups on success - * - * @author Matthias Grimm - */ - function _getGroups($user) { - $groups = array(); - - if($this->dbcon) { - $sql = str_replace('%{user}',$this->_escape($user),$this->cnf['getGroups']); - $result = $this->_queryDB($sql); - - if($result !== false && count($result)) { - foreach($result as $row) - $groups[] = $row['group']; - } - return $groups; - } - return false; - } - - /** - * Retrieves the user id of a given user name - * - * The database connection must already be established - * for this function to work. Otherwise it will return - * 'false'. - * - * @param $user user whose id is desired - * @return user id - * - * @author Matthias Grimm - */ - function _getUserID($user) { - if($this->dbcon) { - $sql = str_replace('%{user}',$this->_escape($user),$this->cnf['getUserID']); - $result = $this->_queryDB($sql); - return $result === false ? false : $result[0]['id']; - } - return false; - } - - /** - * Adds a new User to the database. - * - * The database connection must already be established - * for this function to work. Otherwise it will return - * 'false'. - * - * @param $user login of the user - * @param $pwd encrypted password - * @param $name full name of the user - * @param $mail email address - * @param $grps array of groups the user should become member of - * @return bool - * - * @author Andreas Gohr - * @author Chris Smith - * @author Matthias Grimm - */ - function _addUser($user,$pwd,$name,$mail,$grps){ - if($this->dbcon && is_array($grps)) { - $sql = str_replace('%{user}', $this->_escape($user),$this->cnf['addUser']); - $sql = str_replace('%{pass}', $this->_escape($pwd),$sql); - $sql = str_replace('%{name}', $this->_escape($name),$sql); - $sql = str_replace('%{email}',$this->_escape($mail),$sql); - $uid = $this->_modifyDB($sql); - - if ($uid) { - foreach($grps as $group) { - $gid = $this->_addUserToGroup($user, $group, 1); - if ($gid === false) break; - } - - if ($gid) return true; - else { - /* remove the new user and all group relations if a group can't - * be assigned. Newly created groups will remain in the database - * and won't be removed. This might create orphaned groups but - * is not a big issue so we ignore this problem here. - */ - $this->_delUser($user); - if ($this->cnf['debug']) - msg ("MySQL err: Adding user '$user' to group '$group' failed.",-1,__LINE__,__FILE__); - } - } - } - return false; - } - - /** - * Deletes a given user and all his group references. - * - * The database connection must already be established - * for this function to work. Otherwise it will return - * 'false'. - * - * @param $user user whose id is desired - * @return bool - * - * @author Matthias Grimm - */ - function _delUser($user) { - if($this->dbcon) { - $uid = $this->_getUserID($user); - if ($uid) { - $sql = str_replace('%{uid}',$this->_escape($uid),$this->cnf['delUserRefs']); - $this->_modifyDB($sql); - $sql = str_replace('%{uid}',$this->_escape($uid),$this->cnf['delUser']); - $sql = str_replace('%{user}', $this->_escape($user),$sql); - $this->_modifyDB($sql); - return true; - } - } - return false; - } - - /** - * getUserInfo - * - * Gets the data for a specific user The database connection - * must already be established for this function to work. - * Otherwise it will return 'false'. - * - * @param $user user's nick to get data for - * @return bool false on error - * @return array user info on success - * - * @author Matthias Grimm - */ - function _getUserInfo($user){ - $sql = str_replace('%{user}',$this->_escape($user),$this->cnf['getUserInfo']); - $result = $this->_queryDB($sql); - if($result !== false && count($result)) { - $info = $result[0]; - $info['grps'] = $this->_getGroups($user); - return $info; - } - return false; - } - - /** - * Updates the user info in the database - * - * Update a user data structure in the database according changes - * given in an array. The user name can only be changes if it didn't - * exists already. If the new user name exists the update procedure - * will be aborted. The database keeps unchanged. - * - * The database connection has already to be established for this - * function to work. Otherwise it will return 'false'. - * - * The password will be crypted if necessary. - * - * @param $changes array of items to change as pairs of item and value - * @param $uid user id of dataset to change, must be unique in DB - * @return true on success or false on error - * - * @author Matthias Grimm - */ - function _updateUserInfo($changes, $uid) { - $sql = $this->cnf['updateUser']." "; - $cnt = 0; - $err = 0; - - if($this->dbcon) { - foreach ($changes as $item => $value) { - if ($item == 'user') { - if (($this->_getUserID($changes['user']))) { - $err = 1; /* new username already exists */ - break; /* abort update */ - } - if ($cnt++ > 0) $sql .= ", "; - $sql .= str_replace('%{user}',$value,$this->cnf['UpdateLogin']); - } else if ($item == 'name') { - if ($cnt++ > 0) $sql .= ", "; - $sql .= str_replace('%{name}',$value,$this->cnf['UpdateName']); - } else if ($item == 'pass') { - if (!$this->cnf['forwardClearPass']) - $value = auth_cryptPassword($value); - if ($cnt++ > 0) $sql .= ", "; - $sql .= str_replace('%{pass}',$value,$this->cnf['UpdatePass']); - } else if ($item == 'mail') { - if ($cnt++ > 0) $sql .= ", "; - $sql .= str_replace('%{email}',$value,$this->cnf['UpdateEmail']); - } - } - - if ($err == 0) { - if ($cnt > 0) { - $sql .= " ".str_replace('%{uid}', $uid, $this->cnf['UpdateTarget']); - if(get_class($this) == 'auth_mysql') $sql .= " LIMIT 1"; //some PgSQL inheritance comp. - $this->_modifyDB($sql); - } - return true; - } - } - return false; - } - - /** - * Retrieves the group id of a given group name - * - * The database connection must already be established - * for this function to work. Otherwise it will return - * 'false'. - * - * @param $group group name which id is desired - * @return group id - * - * @author Matthias Grimm - */ - function _getGroupID($group) { - if($this->dbcon) { - $sql = str_replace('%{group}',$this->_escape($group),$this->cnf['getGroupID']); - $result = $this->_queryDB($sql); - return $result === false ? false : $result[0]['id']; - } - return false; - } - - /** - * Opens a connection to a database and saves the handle for further - * usage in the object. The successful call to this functions is - * essential for most functions in this object. - * - * @return bool - * - * @author Matthias Grimm - */ - function _openDB() { - if (!$this->dbcon) { - $con = @mysql_connect ($this->cnf['server'], $this->cnf['user'], $this->cnf['password']); - if ($con) { - if ((mysql_select_db($this->cnf['database'], $con))) { - if ((preg_match("/^(\d+)\.(\d+)\.(\d+).*/", mysql_get_server_info ($con), $result)) == 1) { - $this->dbver = $result[1]; - $this->dbrev = $result[2]; - $this->dbsub = $result[3]; - } - $this->dbcon = $con; - if(!empty($this->cnf['charset'])){ - mysql_query('SET CHARACTER SET "' . $this->cnf['charset'] . '"', $con); - } - return true; // connection and database successfully opened - } else { - mysql_close ($con); - if ($this->cnf['debug']) - msg("MySQL err: No access to database {$this->cnf['database']}.",-1,__LINE__,__FILE__); - } - } else if ($this->cnf['debug']) - msg ("MySQL err: Connection to {$this->cnf['user']}@{$this->cnf['server']} not possible.", - -1,__LINE__,__FILE__); - - return false; // connection failed - } - return true; // connection already open - } - - /** - * Closes a database connection. - * - * @author Matthias Grimm - */ - function _closeDB() { - if ($this->dbcon) { - mysql_close ($this->dbcon); - $this->dbcon = 0; - } - } - - /** - * Sends a SQL query to the database and transforms the result into - * an associative array. - * - * This function is only able to handle queries that returns a - * table such as SELECT. - * - * @param $query SQL string that contains the query - * @return array with the result table - * - * @author Matthias Grimm - */ - function _queryDB($query) { - if($this->cnf['debug'] >= 2){ - msg('MySQL query: '.hsc($query),0,__LINE__,__FILE__); - } - - $resultarray = array(); - if ($this->dbcon) { - $result = @mysql_query($query,$this->dbcon); - if ($result) { - while (($t = mysql_fetch_assoc($result)) !== false) - $resultarray[]=$t; - mysql_free_result ($result); - return $resultarray; - } - if ($this->cnf['debug']) - msg('MySQL err: '.mysql_error($this->dbcon),-1,__LINE__,__FILE__); - } - return false; - } - - /** - * Sends a SQL query to the database - * - * This function is only able to handle queries that returns - * either nothing or an id value such as INPUT, DELETE, UPDATE, etc. - * - * @param $query SQL string that contains the query - * @return insert id or 0, false on error - * - * @author Matthias Grimm - */ - function _modifyDB($query) { - if ($this->dbcon) { - $result = @mysql_query($query,$this->dbcon); - if ($result) { - $rc = mysql_insert_id($this->dbcon); //give back ID on insert - if ($rc !== false) return $rc; - } - if ($this->cnf['debug']) - msg('MySQL err: '.mysql_error($this->dbcon),-1,__LINE__,__FILE__); - } - return false; - } - - /** - * Locked a list of tables for exclusive access so that modifications - * to the database can't be disturbed by other threads. The list - * could be set with $conf['auth']['mysql']['TablesToLock'] = array() - * - * If aliases for tables are used in SQL statements, also this aliases - * must be locked. For eg. you use a table 'user' and the alias 'u' in - * some sql queries, the array must looks like this (order is important): - * array("user", "user AS u"); - * - * MySQL V3 is not able to handle transactions with COMMIT/ROLLBACK - * so that this functionality is simulated by this function. Nevertheless - * it is not as powerful as transactions, it is a good compromise in safty. - * - * @param $mode could be 'READ' or 'WRITE' - * - * @author Matthias Grimm - */ - function _lockTables($mode) { - if ($this->dbcon) { - if (is_array($this->cnf['TablesToLock']) && !empty($this->cnf['TablesToLock'])) { - if ($mode == "READ" || $mode == "WRITE") { - $sql = "LOCK TABLES "; - $cnt = 0; - foreach ($this->cnf['TablesToLock'] as $table) { - if ($cnt++ != 0) $sql .= ", "; - $sql .= "$table $mode"; - } - $this->_modifyDB($sql); - return true; - } - } - } - return false; - } - - /** - * Unlock locked tables. All existing locks of this thread will be - * abrogated. - * - * @author Matthias Grimm - */ - function _unlockTables() { - if ($this->dbcon) { - $this->_modifyDB("UNLOCK TABLES"); - return true; - } - return false; - } - - /** - * Transforms the filter settings in an filter string for a SQL database - * The database connection must already be established, otherwise the - * original SQL string without filter criteria will be returned. - * - * @param $sql SQL string to which the $filter criteria should be added - * @param $filter array of filter criteria as pairs of item and pattern - * @return SQL string with attached $filter criteria on success - * @return the original SQL string on error. - * - * @author Matthias Grimm - */ - function _createSQLFilter($sql, $filter) { - $SQLfilter = ""; - $cnt = 0; - - if ($this->dbcon) { - foreach ($filter as $item => $pattern) { - $tmp = '%'.$this->_escape($pattern).'%'; - if ($item == 'user') { - if ($cnt++ > 0) $SQLfilter .= " AND "; - $SQLfilter .= str_replace('%{user}',$tmp,$this->cnf['FilterLogin']); - } else if ($item == 'name') { - if ($cnt++ > 0) $SQLfilter .= " AND "; - $SQLfilter .= str_replace('%{name}',$tmp,$this->cnf['FilterName']); - } else if ($item == 'mail') { - if ($cnt++ > 0) $SQLfilter .= " AND "; - $SQLfilter .= str_replace('%{email}',$tmp,$this->cnf['FilterEmail']); - } else if ($item == 'grps') { - if ($cnt++ > 0) $SQLfilter .= " AND "; - $SQLfilter .= str_replace('%{group}',$tmp,$this->cnf['FilterGroup']); - } - } - - // we have to check SQLfilter here and must not use $cnt because if - // any of cnf['Filter????'] is not defined, a malformed SQL string - // would be generated. - - if (strlen($SQLfilter)) { - $glue = strpos(strtolower($sql),"where") ? " AND " : " WHERE "; - $sql = $sql.$glue.$SQLfilter; - } - } - - return $sql; - } - - /** - * Escape a string for insertion into the database - * - * @author Andreas Gohr - * @param string $string The string to escape - * @param boolean $like Escape wildcard chars as well? - */ - function _escape($string,$like=false){ - if($this->dbcon){ - $string = mysql_real_escape_string($string, $this->dbcon); - }else{ - $string = addslashes($string); - } - if($like){ - $string = addcslashes($string,'%_'); - } - return $string; - } -} - -//Setup VIM: ex: et ts=2 : diff --git a/inc/auth/pgsql.class.php b/inc/auth/pgsql.class.php deleted file mode 100644 index cf8bf7600..000000000 --- a/inc/auth/pgsql.class.php +++ /dev/null @@ -1,410 +0,0 @@ - - * @author Chris Smith - * @author Matthias Grimm -*/ - -require_once(DOKU_INC.'inc/auth/mysql.class.php'); - -class auth_pgsql extends auth_mysql { - - /** - * Constructor - * - * checks if the pgsql interface is available, otherwise it will - * set the variable $success of the basis class to false - * - * @author Matthias Grimm - * @author Andreas Gohr - */ - function auth_pgsql() { - global $conf; - $this->cnf = $conf['auth']['pgsql']; - if(!$this->cnf['port']) $this->cnf['port'] = 5432; - - if (method_exists($this, 'auth_basic')) - parent::auth_basic(); - - if(!function_exists('pg_connect')) { - if ($this->cnf['debug']) - msg("PgSQL err: PHP Postgres extension not found.",-1); - $this->success = false; - return; - } - - $this->defaultgroup = $conf['defaultgroup']; - - // set capabilities based upon config strings set - if (empty($this->cnf['user']) || - empty($this->cnf['password']) || empty($this->cnf['database'])){ - if ($this->cnf['debug']) - msg("PgSQL err: insufficient configuration.",-1,__LINE__,__FILE__); - $this->success = false; - return; - } - - $this->cando['addUser'] = $this->_chkcnf(array('getUserInfo', - 'getGroups', - 'addUser', - 'getUserID', - 'getGroupID', - 'addGroup', - 'addUserGroup')); - $this->cando['delUser'] = $this->_chkcnf(array('getUserID', - 'delUser', - 'delUserRefs')); - $this->cando['modLogin'] = $this->_chkcnf(array('getUserID', - 'updateUser', - 'UpdateTarget')); - $this->cando['modPass'] = $this->cando['modLogin']; - $this->cando['modName'] = $this->cando['modLogin']; - $this->cando['modMail'] = $this->cando['modLogin']; - $this->cando['modGroups'] = $this->_chkcnf(array('getUserID', - 'getGroups', - 'getGroupID', - 'addGroup', - 'addUserGroup', - 'delGroup', - 'getGroupID', - 'delUserGroup')); - /* getGroups is not yet supported - $this->cando['getGroups'] = $this->_chkcnf(array('getGroups', - 'getGroupID')); */ - $this->cando['getUsers'] = $this->_chkcnf(array('getUsers', - 'getUserInfo', - 'getGroups')); - $this->cando['getUserCount'] = $this->_chkcnf(array('getUsers')); - } - - /** - * Check if the given config strings are set - * - * @author Matthias Grimm - * @return bool - */ - function _chkcnf($keys, $wop=false){ - foreach ($keys as $key){ - if (empty($this->cnf[$key])) return false; - } - return true; - } - - // @inherit function checkPass($user,$pass) - // @inherit function getUserData($user) - // @inherit function createUser($user,$pwd,$name,$mail,$grps=null) - // @inherit function modifyUser($user, $changes) - // @inherit function deleteUsers($users) - - - /** - * [public function] - * - * Counts users which meet certain $filter criteria. - * - * @param array $filter filter criteria in item/pattern pairs - * @return count of found users. - * - * @author Matthias Grimm - */ - function getUserCount($filter=array()) { - $rc = 0; - - if($this->_openDB()) { - $sql = $this->_createSQLFilter($this->cnf['getUsers'], $filter); - - // no equivalent of SQL_CALC_FOUND_ROWS in pgsql? - if (($result = $this->_queryDB($sql))){ - $rc = count($result); - } - $this->_closeDB(); - } - return $rc; - } - - /** - * Bulk retrieval of user data. [public function] - * - * @param first index of first user to be returned - * @param limit max number of users to be returned - * @param filter array of field/pattern pairs - * @return array of userinfo (refer getUserData for internal userinfo details) - * - * @author Matthias Grimm - */ - function retrieveUsers($first=0,$limit=10,$filter=array()) { - $out = array(); - - if($this->_openDB()) { - $this->_lockTables("READ"); - $sql = $this->_createSQLFilter($this->cnf['getUsers'], $filter); - $sql .= " ".$this->cnf['SortOrder']." LIMIT $limit OFFSET $first"; - $result = $this->_queryDB($sql); - - foreach ($result as $user) - if (($info = $this->_getUserInfo($user['user']))) - $out[$user['user']] = $info; - - $this->_unlockTables(); - $this->_closeDB(); - } - return $out; - } - - // @inherit function joinGroup($user, $group) - // @inherit function leaveGroup($user, $group) { - - /** - * Adds a user to a group. - * - * If $force is set to '1' non existing groups would be created. - * - * The database connection must already be established. Otherwise - * this function does nothing and returns 'false'. - * - * @param $user user to add to a group - * @param $group name of the group - * @param $force '1' create missing groups - * @return bool 'true' on success, 'false' on error - * - * @author Matthias Grimm - * @author Andreas Gohr - */ - function _addUserToGroup($user, $group, $force=0) { - $newgroup = 0; - - if (($this->dbcon) && ($user)) { - $gid = $this->_getGroupID($group); - if (!$gid) { - if ($force) { // create missing groups - $sql = str_replace('%{group}',addslashes($group),$this->cnf['addGroup']); - $this->_modifyDB($sql); - //group should now exists try again to fetch it - $gid = $this->_getGroupID($group); - $newgroup = 1; // group newly created - } - } - if (!$gid) return false; // group didn't exist and can't be created - - $sql = $this->cnf['addUserGroup']; - if(strpos($sql,'%{uid}') !== false){ - $uid = $this->_getUserID($user); - $sql = str_replace('%{uid}', addslashes($uid), $sql); - } - $sql = str_replace('%{user}', addslashes($user),$sql); - $sql = str_replace('%{gid}', addslashes($gid),$sql); - $sql = str_replace('%{group}',addslashes($group),$sql); - if ($this->_modifyDB($sql) !== false) return true; - - if ($newgroup) { // remove previously created group on error - $sql = str_replace('%{gid}', addslashes($gid),$this->cnf['delGroup']); - $sql = str_replace('%{group}',addslashes($group),$sql); - $this->_modifyDB($sql); - } - } - return false; - } - - // @inherit function _delUserFromGroup($user $group) - // @inherit function _getGroups($user) - // @inherit function _getUserID($user) - - /** - * Adds a new User to the database. - * - * The database connection must already be established - * for this function to work. Otherwise it will return - * 'false'. - * - * @param $user login of the user - * @param $pwd encrypted password - * @param $name full name of the user - * @param $mail email address - * @param $grps array of groups the user should become member of - * @return bool - * - * @author Andreas Gohr - * @author Chris Smith - * @author Matthias Grimm - */ - function _addUser($user,$pwd,$name,$mail,$grps){ - if($this->dbcon && is_array($grps)) { - $sql = str_replace('%{user}', addslashes($user),$this->cnf['addUser']); - $sql = str_replace('%{pass}', addslashes($pwd),$sql); - $sql = str_replace('%{name}', addslashes($name),$sql); - $sql = str_replace('%{email}',addslashes($mail),$sql); - if($this->_modifyDB($sql)){ - $uid = $this->_getUserID($user); - }else{ - return false; - } - - if ($uid) { - foreach($grps as $group) { - $gid = $this->_addUserToGroup($user, $group, 1); - if ($gid === false) break; - } - - if ($gid) return true; - else { - /* remove the new user and all group relations if a group can't - * be assigned. Newly created groups will remain in the database - * and won't be removed. This might create orphaned groups but - * is not a big issue so we ignore this problem here. - */ - $this->_delUser($user); - if ($this->cnf['debug']) - msg("PgSQL err: Adding user '$user' to group '$group' failed.",-1,__LINE__,__FILE__); - } - } - } - return false; - } - - // @inherit function _delUser($user) - // @inherit function _getUserInfo($user) - // @inherit function _updateUserInfo($changes, $uid) - // @inherit function _getGroupID($group) - - /** - * Opens a connection to a database and saves the handle for further - * usage in the object. The successful call to this functions is - * essential for most functions in this object. - * - * @return bool - * - * @author Matthias Grimm - */ - function _openDB() { - if (!$this->dbcon) { - $dsn = $this->cnf['server'] ? 'host='.$this->cnf['server'] : ''; - $dsn .= ' port='.$this->cnf['port']; - $dsn .= ' dbname='.$this->cnf['database']; - $dsn .= ' user='.$this->cnf['user']; - $dsn .= ' password='.$this->cnf['password']; - - $con = @pg_connect($dsn); - if ($con) { - $this->dbcon = $con; - return true; // connection and database successfully opened - } else if ($this->cnf['debug']){ - msg ("PgSQL err: Connection to {$this->cnf['user']}@{$this->cnf['server']} not possible.", - -1,__LINE__,__FILE__); - } - return false; // connection failed - } - return true; // connection already open - } - - /** - * Closes a database connection. - * - * @author Matthias Grimm - */ - function _closeDB() { - if ($this->dbcon) { - pg_close ($this->dbcon); - $this->dbcon = 0; - } - } - - /** - * Sends a SQL query to the database and transforms the result into - * an associative array. - * - * This function is only able to handle queries that returns a - * table such as SELECT. - * - * @param $query SQL string that contains the query - * @return array with the result table - * - * @author Matthias Grimm - */ - function _queryDB($query) { - if ($this->dbcon) { - $result = @pg_query($this->dbcon,$query); - if ($result) { - while (($t = pg_fetch_assoc($result)) !== false) - $resultarray[]=$t; - pg_free_result ($result); - return $resultarray; - }elseif ($this->cnf['debug']) - msg('PgSQL err: '.pg_last_error($this->dbcon),-1,__LINE__,__FILE__); - } - return false; - } - - /** - * Executes an update or insert query. This differs from the - * MySQL one because it does NOT return the last insertID - * - * @author Andreas Gohr - */ - function _modifyDB($query) { - if ($this->dbcon) { - $result = @pg_query($this->dbcon,$query); - if ($result) { - pg_free_result ($result); - return true; - } - if ($this->cnf['debug']){ - msg('PgSQL err: '.pg_last_error($this->dbcon),-1,__LINE__,__FILE__); - } - } - return false; - } - - /** - * Start a transaction - * - * @param $mode could be 'READ' or 'WRITE' - * @author Matthias Grimm - */ - function _lockTables($mode) { - if ($this->dbcon) { - $this->_modifyDB('BEGIN'); - return true; - } - return false; - } - - /** - * Commit a transaction - * - * @author Matthias Grimm - */ - function _unlockTables() { - if ($this->dbcon) { - $this->_modifyDB('COMMIT'); - return true; - } - return false; - } - - // @inherit function _createSQLFilter($sql, $filter) - - - /** - * Escape a string for insertion into the database - * - * @author Andreas Gohr - * @param string $string The string to escape - * @param boolean $like Escape wildcard chars as well? - */ - function _escape($string,$like=false){ - $string = pg_escape_string($string); - if($like){ - $string = addcslashes($string,'%_'); - } - return $string; - } - -} - -//Setup VIM: ex: et ts=2 : diff --git a/inc/auth/plain.class.php b/inc/auth/plain.class.php deleted file mode 100644 index 3941190e9..000000000 --- a/inc/auth/plain.class.php +++ /dev/null @@ -1,328 +0,0 @@ - - * @author Chris Smith - */ - -class auth_plain extends auth_basic { - - var $users = null; - var $_pattern = array(); - - /** - * Constructor - * - * Carry out sanity checks to ensure the object is - * able to operate. Set capabilities. - * - * @author Christopher Smith - */ - function auth_plain() { - global $config_cascade; - - if (!@is_readable($config_cascade['plainauth.users']['default'])){ - $this->success = false; - }else{ - if(@is_writable($config_cascade['plainauth.users']['default'])){ - $this->cando['addUser'] = true; - $this->cando['delUser'] = true; - $this->cando['modLogin'] = true; - $this->cando['modPass'] = true; - $this->cando['modName'] = true; - $this->cando['modMail'] = true; - $this->cando['modGroups'] = true; - } - $this->cando['getUsers'] = true; - $this->cando['getUserCount'] = true; - } - } - - /** - * Check user+password [required auth function] - * - * Checks if the given user exists and the given - * plaintext password is correct - * - * @author Andreas Gohr - * @return bool - */ - function checkPass($user,$pass){ - - $userinfo = $this->getUserData($user); - if ($userinfo === false) return false; - - return auth_verifyPassword($pass,$this->users[$user]['pass']); - } - - /** - * Return user info - * - * Returns info about the given user needs to contain - * at least these fields: - * - * name string full name of the user - * mail string email addres of the user - * grps array list of groups the user is in - * - * @author Andreas Gohr - */ - function getUserData($user){ - - if($this->users === null) $this->_loadUserData(); - return isset($this->users[$user]) ? $this->users[$user] : false; - } - - /** - * Create a new User - * - * Returns false if the user already exists, null when an error - * occurred and true if everything went well. - * - * The new user will be added to the default group by this - * function if grps are not specified (default behaviour). - * - * @author Andreas Gohr - * @author Chris Smith - */ - function createUser($user,$pwd,$name,$mail,$grps=null){ - global $conf; - global $config_cascade; - - // user mustn't already exist - if ($this->getUserData($user) !== false) return false; - - $pass = auth_cryptPassword($pwd); - - // set default group if no groups specified - if (!is_array($grps)) $grps = array($conf['defaultgroup']); - - // prepare user line - $groups = join(',',$grps); - $userline = join(':',array($user,$pass,$name,$mail,$groups))."\n"; - - if (io_saveFile($config_cascade['plainauth.users']['default'],$userline,true)) { - $this->users[$user] = compact('pass','name','mail','grps'); - return $pwd; - } - - msg('The '.$config_cascade['plainauth.users']['default']. - ' file is not writable. Please inform the Wiki-Admin',-1); - return null; - } - - /** - * Modify user data - * - * @author Chris Smith - * @param $user nick of the user to be changed - * @param $changes array of field/value pairs to be changed (password will be clear text) - * @return bool - */ - function modifyUser($user, $changes) { - global $conf; - global $ACT; - global $INFO; - global $config_cascade; - - // sanity checks, user must already exist and there must be something to change - if (($userinfo = $this->getUserData($user)) === false) return false; - if (!is_array($changes) || !count($changes)) return true; - - // update userinfo with new data, remembering to encrypt any password - $newuser = $user; - foreach ($changes as $field => $value) { - if ($field == 'user') { - $newuser = $value; - continue; - } - if ($field == 'pass') $value = auth_cryptPassword($value); - $userinfo[$field] = $value; - } - - $groups = join(',',$userinfo['grps']); - $userline = join(':',array($newuser, $userinfo['pass'], $userinfo['name'], $userinfo['mail'], $groups))."\n"; - - if (!$this->deleteUsers(array($user))) { - msg('Unable to modify user data. Please inform the Wiki-Admin',-1); - return false; - } - - if (!io_saveFile($config_cascade['plainauth.users']['default'],$userline,true)) { - msg('There was an error modifying your user data. You should register again.',-1); - // FIXME, user has been deleted but not recreated, should force a logout and redirect to login page - $ACT == 'register'; - return false; - } - - $this->users[$newuser] = $userinfo; - return true; - } - - /** - * Remove one or more users from the list of registered users - * - * @author Christopher Smith - * @param array $users array of users to be deleted - * @return int the number of users deleted - */ - function deleteUsers($users) { - global $config_cascade; - - if (!is_array($users) || empty($users)) return 0; - - if ($this->users === null) $this->_loadUserData(); - - $deleted = array(); - foreach ($users as $user) { - if (isset($this->users[$user])) $deleted[] = preg_quote($user,'/'); - } - - if (empty($deleted)) return 0; - - $pattern = '/^('.join('|',$deleted).'):/'; - - if (io_deleteFromFile($config_cascade['plainauth.users']['default'],$pattern,true)) { - foreach ($deleted as $user) unset($this->users[$user]); - return count($deleted); - } - - // problem deleting, reload the user list and count the difference - $count = count($this->users); - $this->_loadUserData(); - $count -= count($this->users); - return $count; - } - - /** - * Return a count of the number of user which meet $filter criteria - * - * @author Chris Smith - */ - function getUserCount($filter=array()) { - - if($this->users === null) $this->_loadUserData(); - - if (!count($filter)) return count($this->users); - - $count = 0; - $this->_constructPattern($filter); - - foreach ($this->users as $user => $info) { - $count += $this->_filter($user, $info); - } - - return $count; - } - - /** - * Bulk retrieval of user data - * - * @author Chris Smith - * @param start index of first user to be returned - * @param limit max number of users to be returned - * @param filter array of field/pattern pairs - * @return array of userinfo (refer getUserData for internal userinfo details) - */ - function retrieveUsers($start=0,$limit=0,$filter=array()) { - - if ($this->users === null) $this->_loadUserData(); - - ksort($this->users); - - $i = 0; - $count = 0; - $out = array(); - $this->_constructPattern($filter); - - foreach ($this->users as $user => $info) { - if ($this->_filter($user, $info)) { - if ($i >= $start) { - $out[$user] = $info; - $count++; - if (($limit > 0) && ($count >= $limit)) break; - } - $i++; - } - } - - return $out; - } - - /** - * Only valid pageid's (no namespaces) for usernames - */ - function cleanUser($user){ - global $conf; - return cleanID(str_replace(':',$conf['sepchar'],$user)); - } - - /** - * Only valid pageid's (no namespaces) for groupnames - */ - function cleanGroup($group){ - global $conf; - return cleanID(str_replace(':',$conf['sepchar'],$group)); - } - - /** - * Load all user data - * - * loads the user file into a datastructure - * - * @author Andreas Gohr - */ - function _loadUserData(){ - global $config_cascade; - - $this->users = array(); - - if(!@file_exists($config_cascade['plainauth.users']['default'])) return; - - $lines = file($config_cascade['plainauth.users']['default']); - foreach($lines as $line){ - $line = preg_replace('/#.*$/','',$line); //ignore comments - $line = trim($line); - if(empty($line)) continue; - - $row = explode(":",$line,5); - $groups = array_values(array_filter(explode(",",$row[4]))); - - $this->users[$row[0]]['pass'] = $row[1]; - $this->users[$row[0]]['name'] = urldecode($row[2]); - $this->users[$row[0]]['mail'] = $row[3]; - $this->users[$row[0]]['grps'] = $groups; - } - } - - /** - * return 1 if $user + $info match $filter criteria, 0 otherwise - * - * @author Chris Smith - */ - function _filter($user, $info) { - // FIXME - foreach ($this->_pattern as $item => $pattern) { - if ($item == 'user') { - if (!preg_match($pattern, $user)) return 0; - } else if ($item == 'grps') { - if (!count(preg_grep($pattern, $info['grps']))) return 0; - } else { - if (!preg_match($pattern, $info[$item])) return 0; - } - } - return 1; - } - - function _constructPattern($filter) { - $this->_pattern = array(); - foreach ($filter as $item => $pattern) { -// $this->_pattern[$item] = '/'.preg_quote($pattern,"/").'/i'; // don't allow regex characters - $this->_pattern[$item] = '/'.str_replace('/','\/',$pattern).'/i'; // allow regex characters - } - } -} - -//Setup VIM: ex: et ts=2 : diff --git a/lib/plugins/auth.php b/lib/plugins/auth.php index 3ec64018c..59631143f 100644 --- a/lib/plugins/auth.php +++ b/lib/plugins/auth.php @@ -9,17 +9,421 @@ if(!defined('DOKU_INC')) die(); /** - * All plugins that provide Authentication should inherit from this class and implement - * the getAuth() method to make its Auth-System available. + * auth/basic.class.php * - * @author Jan Schumann + * foundation authorisation class + * all auth classes should inherit from this class + * + * @author Chris Smith + * @author Jan Schumann */ class DokuWiki_Auth_Plugin extends DokuWiki_Plugin { - /** - * Retrieves the authentication system - */ - function getAuth() { - trigger_error('getAuth() not implemented in '.get_class($this), E_USER_WARNING); + var $success = true; + + + /** + * Posible things an auth backend module may be able to + * do. The things a backend can do need to be set to true + * in the constructor. + */ + var $cando = array ( + 'addUser' => false, // can Users be created? + 'delUser' => false, // can Users be deleted? + 'modLogin' => false, // can login names be changed? + 'modPass' => false, // can passwords be changed? + 'modName' => false, // can real names be changed? + 'modMail' => false, // can emails be changed? + 'modGroups' => false, // can groups be changed? + 'getUsers' => false, // can a (filtered) list of users be retrieved? + 'getUserCount'=> false, // can the number of users be retrieved? + 'getGroups' => false, // can a list of available groups be retrieved? + 'external' => false, // does the module do external auth checking? + 'logout' => true, // can the user logout again? (eg. not possible with HTTP auth) + ); + + + /** + * Constructor. + * + * Carry out sanity checks to ensure the object is + * able to operate. Set capabilities in $this->cando + * array here + * + * Set $this->success to false if checks fail + * + * @author Christopher Smith + */ + function auth_basic() { + // the base class constructor does nothing, derived class + // constructors do the real work + } + + /** + * Capability check. [ DO NOT OVERRIDE ] + * + * Checks the capabilities set in the $this->cando array and + * some pseudo capabilities (shortcutting access to multiple + * ones) + * + * ususal capabilities start with lowercase letter + * shortcut capabilities start with uppercase letter + * + * @author Andreas Gohr + * @return bool + */ + function canDo($cap) { + switch($cap){ + case 'Profile': + // can at least one of the user's properties be changed? + return ( $this->cando['modPass'] || + $this->cando['modName'] || + $this->cando['modMail'] ); + break; + case 'UserMod': + // can at least anything be changed? + return ( $this->cando['modPass'] || + $this->cando['modName'] || + $this->cando['modMail'] || + $this->cando['modLogin'] || + $this->cando['modGroups'] || + $this->cando['modMail'] ); + break; + default: + // print a helping message for developers + if(!isset($this->cando[$cap])){ + msg("Check for unknown capability '$cap' - Do you use an outdated Plugin?",-1); + } + return $this->cando[$cap]; + } + } + + /** + * Trigger the AUTH_USERDATA_CHANGE event and call the modification function. [ DO NOT OVERRIDE ] + * + * You should use this function instead of calling createUser, modifyUser or + * deleteUsers directly. The event handlers can prevent the modification, for + * example for enforcing a user name schema. + * + * @author Gabriel Birke + * @param string $type Modification type ('create', 'modify', 'delete') + * @param array $params Parameters for the createUser, modifyUser or deleteUsers method. The content of this array depends on the modification type + * @return mixed Result from the modification function or false if an event handler has canceled the action + */ + function triggerUserMod($type, $params) + { + $validTypes = array( + 'create' => 'createUser', + 'modify' => 'modifyUser', + 'delete' => 'deleteUsers' + ); + if(empty($validTypes[$type])) + return false; + $eventdata = array('type' => $type, 'params' => $params, 'modification_result' => null); + $evt = new Doku_Event('AUTH_USER_CHANGE', $eventdata); + if ($evt->advise_before(true)) { + $result = call_user_func_array(array($this, $validTypes[$type]), $params); + $evt->data['modification_result'] = $result; } + $evt->advise_after(); + unset($evt); + return $result; + } + + /** + * Log off the current user [ OPTIONAL ] + * + * Is run in addition to the ususal logoff method. Should + * only be needed when trustExternal is implemented. + * + * @see auth_logoff() + * @author Andreas Gohr + */ + function logOff(){ + } + + /** + * Do all authentication [ OPTIONAL ] + * + * Set $this->cando['external'] = true when implemented + * + * If this function is implemented it will be used to + * authenticate a user - all other DokuWiki internals + * will not be used for authenticating, thus + * implementing the checkPass() function is not needed + * anymore. + * + * The function can be used to authenticate against third + * party cookies or Apache auth mechanisms and replaces + * the auth_login() function + * + * The function will be called with or without a set + * username. If the Username is given it was called + * from the login form and the given credentials might + * need to be checked. If no username was given it + * the function needs to check if the user is logged in + * by other means (cookie, environment). + * + * The function needs to set some globals needed by + * DokuWiki like auth_login() does. + * + * @see auth_login() + * @author Andreas Gohr + * + * @param string $user Username + * @param string $pass Cleartext Password + * @param bool $sticky Cookie should not expire + * @return bool true on successful auth + */ + function trustExternal($user,$pass,$sticky=false){ +# // some example: +# +# global $USERINFO; +# global $conf; +# $sticky ? $sticky = true : $sticky = false; //sanity check +# +# // do the checking here +# +# // set the globals if authed +# $USERINFO['name'] = 'FIXME'; +# $USERINFO['mail'] = 'FIXME'; +# $USERINFO['grps'] = array('FIXME'); +# $_SERVER['REMOTE_USER'] = $user; +# $_SESSION[DOKU_COOKIE]['auth']['user'] = $user; +# $_SESSION[DOKU_COOKIE]['auth']['pass'] = $pass; +# $_SESSION[DOKU_COOKIE]['auth']['info'] = $USERINFO; +# return true; + } + + /** + * Check user+password [ MUST BE OVERRIDDEN ] + * + * Checks if the given user exists and the given + * plaintext password is correct + * + * May be ommited if trustExternal is used. + * + * @author Andreas Gohr + * @return bool + */ + function checkPass($user,$pass){ + msg("no valid authorisation system in use", -1); + return false; + } + + /** + * Return user info [ MUST BE OVERRIDDEN ] + * + * Returns info about the given user needs to contain + * at least these fields: + * + * name string full name of the user + * mail string email addres of the user + * grps array list of groups the user is in + * + * @author Andreas Gohr + * @return array containing user data or false + */ + function getUserData($user) { + if(!$this->cando['external']) msg("no valid authorisation system in use", -1); + return false; + } + + /** + * Create a new User [implement only where required/possible] + * + * Returns false if the user already exists, null when an error + * occurred and true if everything went well. + * + * The new user HAS TO be added to the default group by this + * function! + * + * Set addUser capability when implemented + * + * @author Andreas Gohr + */ + function createUser($user,$pass,$name,$mail,$grps=null){ + msg("authorisation method does not allow creation of new users", -1); + return null; + } + + /** + * Modify user data [implement only where required/possible] + * + * Set the mod* capabilities according to the implemented features + * + * @author Chris Smith + * @param $user nick of the user to be changed + * @param $changes array of field/value pairs to be changed (password will be clear text) + * @return bool + */ + function modifyUser($user, $changes) { + msg("authorisation method does not allow modifying of user data", -1); + return false; + } + + /** + * Delete one or more users [implement only where required/possible] + * + * Set delUser capability when implemented + * + * @author Chris Smith + * @param array $users + * @return int number of users deleted + */ + function deleteUsers($users) { + msg("authorisation method does not allow deleting of users", -1); + return false; + } + + /** + * Return a count of the number of user which meet $filter criteria + * [should be implemented whenever retrieveUsers is implemented] + * + * Set getUserCount capability when implemented + * + * @author Chris Smith + */ + function getUserCount($filter=array()) { + msg("authorisation method does not provide user counts", -1); + return 0; + } + + /** + * Bulk retrieval of user data [implement only where required/possible] + * + * Set getUsers capability when implemented + * + * @author Chris Smith + * @param start index of first user to be returned + * @param limit max number of users to be returned + * @param filter array of field/pattern pairs, null for no filter + * @return array of userinfo (refer getUserData for internal userinfo details) + */ + function retrieveUsers($start=0,$limit=-1,$filter=null) { + msg("authorisation method does not support mass retrieval of user data", -1); + return array(); + } + + /** + * Define a group [implement only where required/possible] + * + * Set addGroup capability when implemented + * + * @author Chris Smith + * @return bool + */ + function addGroup($group) { + msg("authorisation method does not support independent group creation", -1); + return false; + } + + /** + * Retrieve groups [implement only where required/possible] + * + * Set getGroups capability when implemented + * + * @author Chris Smith + * @return array + */ + function retrieveGroups($start=0,$limit=0) { + msg("authorisation method does not support group list retrieval", -1); + return array(); + } + + /** + * Return case sensitivity of the backend [OPTIONAL] + * + * When your backend is caseinsensitive (eg. you can login with USER and + * user) then you need to overwrite this method and return false + */ + function isCaseSensitive(){ + return true; + } + + /** + * Sanitize a given username [OPTIONAL] + * + * This function is applied to any user name that is given to + * the backend and should also be applied to any user name within + * the backend before returning it somewhere. + * + * This should be used to enforce username restrictions. + * + * @author Andreas Gohr + * @param string $user - username + * @param string - the cleaned username + */ + function cleanUser($user){ + return $user; + } + + /** + * Sanitize a given groupname [OPTIONAL] + * + * This function is applied to any groupname that is given to + * the backend and should also be applied to any groupname within + * the backend before returning it somewhere. + * + * This should be used to enforce groupname restrictions. + * + * Groupnames are to be passed without a leading '@' here. + * + * @author Andreas Gohr + * @param string $group - groupname + * @param string - the cleaned groupname + */ + function cleanGroup($group){ + return $group; + } + + + /** + * Check Session Cache validity [implement only where required/possible] + * + * DokuWiki caches user info in the user's session for the timespan defined + * in $conf['auth_security_timeout']. + * + * This makes sure slow authentication backends do not slow down DokuWiki. + * This also means that changes to the user database will not be reflected + * on currently logged in users. + * + * To accommodate for this, the user manager plugin will touch a reference + * file whenever a change is submitted. This function compares the filetime + * of this reference file with the time stored in the session. + * + * This reference file mechanism does not reflect changes done directly in + * the backend's database through other means than the user manager plugin. + * + * Fast backends might want to return always false, to force rechecks on + * each page load. Others might want to use their own checking here. If + * unsure, do not override. + * + * @param string $user - The username + * @author Andreas Gohr + * @return bool + */ + function useSessionCache($user){ + global $conf; + return ($_SESSION[DOKU_COOKIE]['auth']['time'] >= @filemtime($conf['cachedir'].'/sessionpurge')); + } + + + /** + * loadConfig() + * merges the plugin's default settings with any local settings + * this function is automatically called through getConf() + */ + function loadConfig(){ + global $conf; + + parent::loadConfig(); + + $this->conf['debug'] = $conf['debug']; + $this->conf['useacl'] = $conf['useacl']; + $this->conf['disableactions'] = $conf['disableactions']; + $this->conf['autopasswd'] = $conf['autopasswd']; + $this->conf['passcrypt'] = $conf['ssha']; + } + } diff --git a/lib/plugins/authad/auth.php b/lib/plugins/authad/auth.php new file mode 100644 index 000000000..70d3cfb8c --- /dev/null +++ b/lib/plugins/authad/auth.php @@ -0,0 +1,359 @@ + + */ +// must be run within Dokuwiki +if(!defined('DOKU_INC')) die(); + +require_once(DOKU_INC.'inc/adLDAP.php'); + +/** + * Active Directory authentication backend for DokuWiki + * + * This makes authentication with a Active Directory server much easier + * than when using the normal LDAP backend by utilizing the adLDAP library + * + * Usage: + * Set DokuWiki's local.protected.php auth setting to read + * + * $conf['useacl'] = 1; + * $conf['disableactions'] = 'register'; + * $conf['autopasswd'] = 0; + * $conf['authtype'] = 'authad'; + * $conf['passcrypt'] = 'ssha'; + * + * $conf['plugin']['authad']['account_suffix'] = '@my.domain.org'; + * $conf['plugin']['authad']['base_dn'] = 'DC=my,DC=domain,DC=org'; + * $conf['plugin']['authad']['domain_controllers'] = 'srv1.domain.org,srv2.domain.org'; + * + * //optional: + * $conf['plugin']['authad']['sso'] = 1; + * $conf['plugin']['authad']['ad_username'] = 'root'; + * $conf['plugin']['authad']['ad_password'] = 'pass'; + * $conf['plugin']['authad']['real_primarygroup'] = 1; + * $conf['plugin']['authad']['use_ssl'] = 1; + * $conf['plugin']['authad']['use_tls'] = 1; + * $conf['plugin']['authad']['debug'] = 1; + * + * // get additional information to the userinfo array + * // add a list of comma separated ldap contact fields. + * $conf['plugin']['authad']['additional'] = 'field1,field2'; + * + * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) + * @author James Van Lommel + * @link http://www.nosq.com/blog/2005/08/ldap-activedirectory-and-dokuwiki/ + * @author Andreas Gohr + * @author Jan Schumann + */ +class auth_plugin_authad extends DokuWiki_Auth_Plugin +{ + var $cnf = null; + var $opts = null; + var $adldap = null; + var $users = null; + + /** + * Constructor + */ + function auth_plugin_authad() { + global $conf; + $this->cnf = $conf['auth']['ad']; + + + // additional information fields + if (isset($this->cnf['additional'])) { + $this->cnf['additional'] = str_replace(' ', '', $this->cnf['additional']); + $this->cnf['additional'] = explode(',', $this->cnf['additional']); + } else $this->cnf['additional'] = array(); + + // ldap extension is needed + if (!function_exists('ldap_connect')) { + if ($this->cnf['debug']) + msg("AD Auth: PHP LDAP extension not found.",-1); + $this->success = false; + return; + } + + // Prepare SSO + if($_SERVER['REMOTE_USER'] && $this->cnf['sso']){ + // remove possible NTLM domain + list($dom,$usr) = explode('\\',$_SERVER['REMOTE_USER'],2); + if(!$usr) $usr = $dom; + + // remove possible Kerberos domain + list($usr,$dom) = explode('@',$usr); + + $dom = strtolower($dom); + $_SERVER['REMOTE_USER'] = $usr; + + // we need to simulate a login + if(empty($_COOKIE[DOKU_COOKIE])){ + $_REQUEST['u'] = $_SERVER['REMOTE_USER']; + $_REQUEST['p'] = 'sso_only'; + } + } + + // prepare adLDAP standard configuration + $this->opts = $this->cnf; + + // add possible domain specific configuration + if($dom && is_array($this->cnf[$dom])) foreach($this->cnf[$dom] as $key => $val){ + $this->opts[$key] = $val; + } + + // handle multiple AD servers + $this->opts['domain_controllers'] = explode(',',$this->opts['domain_controllers']); + $this->opts['domain_controllers'] = array_map('trim',$this->opts['domain_controllers']); + $this->opts['domain_controllers'] = array_filter($this->opts['domain_controllers']); + + // we can change the password if SSL is set + if($this->opts['use_ssl'] || $this->opts['use_tls']){ + $this->cando['modPass'] = true; + } + $this->cando['modName'] = true; + $this->cando['modMail'] = true; + } + + /** + * Check user+password [required auth function] + * + * Checks if the given user exists and the given + * plaintext password is correct by trying to bind + * to the LDAP server + * + * @author James Van Lommel + * @return bool + */ + function checkPass($user, $pass){ + if($_SERVER['REMOTE_USER'] && + $_SERVER['REMOTE_USER'] == $user && + $this->cnf['sso']) return true; + + if(!$this->_init()) return false; + return $this->adldap->authenticate($user, $pass); + } + + /** + * Return user info [required auth function] + * + * Returns info about the given user needs to contain + * at least these fields: + * + * name string full name of the user + * mail string email address of the user + * grps array list of groups the user is in + * + * This LDAP specific function returns the following + * addional fields: + * + * dn string distinguished name (DN) + * uid string Posix User ID + * + * @author James Van Lommel + */ + function getUserData($user){ + global $conf; + if(!$this->_init()) return false; + + $fields = array('mail','displayname','samaccountname'); + + // add additional fields to read + $fields = array_merge($fields, $this->cnf['additional']); + $fields = array_unique($fields); + + //get info for given user + $result = $this->adldap->user_info($user, $fields); + //general user info + $info['name'] = $result[0]['displayname'][0]; + $info['mail'] = $result[0]['mail'][0]; + $info['uid'] = $result[0]['samaccountname'][0]; + $info['dn'] = $result[0]['dn']; + + // additional information + foreach ($this->cnf['additional'] as $field) { + if (isset($result[0][strtolower($field)])) { + $info[$field] = $result[0][strtolower($field)][0]; + } + } + + // handle ActiveDirectory memberOf + $info['grps'] = $this->adldap->user_groups($user,(bool) $this->opts['recursive_groups']); + + if (is_array($info['grps'])) { + foreach ($info['grps'] as $ndx => $group) { + $info['grps'][$ndx] = $this->cleanGroup($group); + } + } + + // always add the default group to the list of groups + if(!is_array($info['grps']) || !in_array($conf['defaultgroup'],$info['grps'])){ + $info['grps'][] = $conf['defaultgroup']; + } + + return $info; + } + + /** + * Make AD group names usable by DokuWiki. + * + * Removes backslashes ('\'), pound signs ('#'), and converts spaces to underscores. + * + * @author James Van Lommel (jamesvl@gmail.com) + */ + function cleanGroup($name) { + $sName = str_replace('\\', '', $name); + $sName = str_replace('#', '', $sName); + $sName = preg_replace('[\s]', '_', $sName); + return $sName; + } + + /** + * Sanitize user names + */ + function cleanUser($name) { + return $this->cleanGroup($name); + } + + /** + * Most values in LDAP are case-insensitive + */ + function isCaseSensitive(){ + return false; + } + + /** + * Bulk retrieval of user data + * + * @author Dominik Eckelmann + * @param start index of first user to be returned + * @param limit max number of users to be returned + * @param filter array of field/pattern pairs, null for no filter + * @return array of userinfo (refer getUserData for internal userinfo details) + */ + function retrieveUsers($start=0,$limit=-1,$filter=array()) { + if(!$this->_init()) return false; + + if ($this->users === null) { + //get info for given user + $result = $this->adldap->all_users(); + if (!$result) return array(); + $this->users = array_fill_keys($result, false); + } + + $i = 0; + $count = 0; + $this->_constructPattern($filter); + $result = array(); + + foreach ($this->users as $user => &$info) { + if ($i++ < $start) { + continue; + } + if ($info === false) { + $info = $this->getUserData($user); + } + if ($this->_filter($user, $info)) { + $result[$user] = $info; + if (($limit >= 0) && (++$count >= $limit)) break; + } + } + return $result; + } + + /** + * Modify user data + * + * @param $user nick of the user to be changed + * @param $changes array of field/value pairs to be changed + * @return bool + */ + function modifyUser($user, $changes) { + $return = true; + + // password changing + if(isset($changes['pass'])){ + try { + $return = $this->adldap->user_password($user,$changes['pass']); + } catch (adLDAPException $e) { + if ($this->cnf['debug']) msg('AD Auth: '.$e->getMessage(), -1); + $return = false; + } + if(!$return) msg('AD Auth: failed to change the password. Maybe the password policy was not met?',-1); + } + + // changing user data + $adchanges = array(); + if(isset($changes['name'])){ + // get first and last name + $parts = explode(' ',$changes['name']); + $adchanges['surname'] = array_pop($parts); + $adchanges['firstname'] = join(' ',$parts); + $adchanges['display_name'] = $changes['name']; + } + if(isset($changes['mail'])){ + $adchanges['email'] = $changes['mail']; + } + if(count($adchanges)){ + try { + $return = $return & $this->adldap->user_modify($user,$adchanges); + } catch (adLDAPException $e) { + if ($this->cnf['debug']) msg('AD Auth: '.$e->getMessage(), -1); + $return = false; + } + } + + return $return; + } + + /** + * Initialize the AdLDAP library and connect to the server + */ + function _init(){ + if(!is_null($this->adldap)) return true; + + // connect + try { + $this->adldap = new adLDAP($this->opts); + if (isset($this->opts['ad_username']) && isset($this->opts['ad_password'])) { + $this->canDo['getUsers'] = true; + } + return true; + } catch (adLDAPException $e) { + if ($this->cnf['debug']) { + msg('AD Auth: '.$e->getMessage(), -1); + } + $this->success = false; + $this->adldap = null; + } + return false; + } + + /** + * return 1 if $user + $info match $filter criteria, 0 otherwise + * + * @author Chris Smith + */ + function _filter($user, $info) { + foreach ($this->_pattern as $item => $pattern) { + if ($item == 'user') { + if (!preg_match($pattern, $user)) return 0; + } else if ($item == 'grps') { + if (!count(preg_grep($pattern, $info['grps']))) return 0; + } else { + if (!preg_match($pattern, $info[$item])) return 0; + } + } + return 1; + } + + function _constructPattern($filter) { + $this->_pattern = array(); + foreach ($filter as $item => $pattern) { +// $this->_pattern[$item] = '/'.preg_quote($pattern,"/").'/i'; // don't allow regex characters + $this->_pattern[$item] = '/'.str_replace('/','\/',$pattern).'/i'; // allow regex characters + } + } +} \ No newline at end of file diff --git a/lib/plugins/authad/plugin.info.txt b/lib/plugins/authad/plugin.info.txt new file mode 100644 index 000000000..ad565b853 --- /dev/null +++ b/lib/plugins/authad/plugin.info.txt @@ -0,0 +1,7 @@ +base authad +author +email +date +name active directory auth plugin +desc Provides authentication against a Microsoft Active Directory +url diff --git a/lib/plugins/authldap/auth.php b/lib/plugins/authldap/auth.php new file mode 100644 index 000000000..723685f94 --- /dev/null +++ b/lib/plugins/authldap/auth.php @@ -0,0 +1,471 @@ + + */ +// must be run within Dokuwiki +if(!defined('DOKU_INC')) die(); + +/** + * LDAP authentication backend + * + * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) + * @author Andreas Gohr + * @author Chris Smith + * @author Jan Schumann + */ +class auth_plugin_authldap extends DokuWiki_Auth_Plugin +{ + var $cnf = null; + var $con = null; + var $bound = 0; // 0: anonymous, 1: user, 2: superuser + + /** + * Constructor + */ + function auth_plugin_authldap(){ + global $conf; + $this->cnf = $conf['auth']['ldap']; + + // ldap extension is needed + if(!function_exists('ldap_connect')) { + if ($this->cnf['debug']) + msg("LDAP err: PHP LDAP extension not found.",-1,__LINE__,__FILE__); + $this->success = false; + return; + } + + if(empty($this->cnf['groupkey'])) $this->cnf['groupkey'] = 'cn'; + if(empty($this->cnf['userscope'])) $this->cnf['userscope'] = 'sub'; + if(empty($this->cnf['groupscope'])) $this->cnf['groupscope'] = 'sub'; + + // auth_ldap currently just handles authentication, so no + // capabilities are set + } + + /** + * Check user+password + * + * Checks if the given user exists and the given + * plaintext password is correct by trying to bind + * to the LDAP server + * + * @author Andreas Gohr + * @return bool + */ + function checkPass($user,$pass){ + // reject empty password + if(empty($pass)) return false; + if(!$this->_openLDAP()) return false; + + // indirect user bind + if($this->cnf['binddn'] && $this->cnf['bindpw']){ + // use superuser credentials + if(!@ldap_bind($this->con,$this->cnf['binddn'],$this->cnf['bindpw'])){ + if($this->cnf['debug']) + msg('LDAP bind as superuser: '.htmlspecialchars(ldap_error($this->con)),0,__LINE__,__FILE__); + return false; + } + $this->bound = 2; + }else if($this->cnf['binddn'] && + $this->cnf['usertree'] && + $this->cnf['userfilter']) { + // special bind string + $dn = $this->_makeFilter($this->cnf['binddn'], + array('user'=>$user,'server'=>$this->cnf['server'])); + + }else if(strpos($this->cnf['usertree'], '%{user}')) { + // direct user bind + $dn = $this->_makeFilter($this->cnf['usertree'], + array('user'=>$user,'server'=>$this->cnf['server'])); + + }else{ + // Anonymous bind + if(!@ldap_bind($this->con)){ + msg("LDAP: can not bind anonymously",-1); + if($this->cnf['debug']) + msg('LDAP anonymous bind: '.htmlspecialchars(ldap_error($this->con)),0,__LINE__,__FILE__); + return false; + } + } + + // Try to bind to with the dn if we have one. + if(!empty($dn)) { + // User/Password bind + if(!@ldap_bind($this->con,$dn,$pass)){ + if($this->cnf['debug']){ + msg("LDAP: bind with $dn failed", -1,__LINE__,__FILE__); + msg('LDAP user dn bind: '.htmlspecialchars(ldap_error($this->con)),0); + } + return false; + } + $this->bound = 1; + return true; + }else{ + // See if we can find the user + $info = $this->getUserData($user,true); + if(empty($info['dn'])) { + return false; + } else { + $dn = $info['dn']; + } + + // Try to bind with the dn provided + if(!@ldap_bind($this->con,$dn,$pass)){ + if($this->cnf['debug']){ + msg("LDAP: bind with $dn failed", -1,__LINE__,__FILE__); + msg('LDAP user bind: '.htmlspecialchars(ldap_error($this->con)),0); + } + return false; + } + $this->bound = 1; + return true; + } + + return false; + } + + /** + * Return user info + * + * Returns info about the given user needs to contain + * at least these fields: + * + * name string full name of the user + * mail string email addres of the user + * grps array list of groups the user is in + * + * This LDAP specific function returns the following + * addional fields: + * + * dn string distinguished name (DN) + * uid string Posix User ID + * inbind bool for internal use - avoid loop in binding + * + * @author Andreas Gohr + * @author Trouble + * @author Dan Allen + * @author + * @author Stephane Chazelas + * @return array containing user data or false + */ + function getUserData($user,$inbind=false) { + global $conf; + if(!$this->_openLDAP()) return false; + + // force superuser bind if wanted and not bound as superuser yet + if($this->cnf['binddn'] && $this->cnf['bindpw'] && $this->bound < 2){ + // use superuser credentials + if(!@ldap_bind($this->con,$this->cnf['binddn'],$this->cnf['bindpw'])){ + if($this->cnf['debug']) + msg('LDAP bind as superuser: '.htmlspecialchars(ldap_error($this->con)),0,__LINE__,__FILE__); + return false; + } + $this->bound = 2; + }elseif($this->bound == 0 && !$inbind) { + // in some cases getUserData is called outside the authentication workflow + // eg. for sending email notification on subscribed pages. This data might not + // be accessible anonymously, so we try to rebind the current user here + list($loginuser,$loginsticky,$loginpass) = auth_getCookie(); + if($loginuser && $loginpass){ + $loginpass = PMA_blowfish_decrypt($loginpass, auth_cookiesalt(!$loginsticky)); + $this->checkPass($loginuser, $loginpass); + } + } + + $info['user'] = $user; + $info['server'] = $this->cnf['server']; + + //get info for given user + $base = $this->_makeFilter($this->cnf['usertree'], $info); + if(!empty($this->cnf['userfilter'])) { + $filter = $this->_makeFilter($this->cnf['userfilter'], $info); + } else { + $filter = "(ObjectClass=*)"; + } + + $sr = $this->_ldapsearch($this->con, $base, $filter, $this->cnf['userscope']); + $result = @ldap_get_entries($this->con, $sr); + if($this->cnf['debug']){ + msg('LDAP user search: '.htmlspecialchars(ldap_error($this->con)),0,__LINE__,__FILE__); + msg('LDAP search at: '.htmlspecialchars($base.' '.$filter),0,__LINE__,__FILE__); + } + + // Don't accept more or less than one response + if(!is_array($result) || $result['count'] != 1){ + return false; //user not found + } + + $user_result = $result[0]; + ldap_free_result($sr); + + // general user info + $info['dn'] = $user_result['dn']; + $info['gid'] = $user_result['gidnumber'][0]; + $info['mail'] = $user_result['mail'][0]; + $info['name'] = $user_result['cn'][0]; + $info['grps'] = array(); + + // overwrite if other attribs are specified. + if(is_array($this->cnf['mapping'])){ + foreach($this->cnf['mapping'] as $localkey => $key) { + if(is_array($key)) { + // use regexp to clean up user_result + list($key, $regexp) = each($key); + if($user_result[$key]) foreach($user_result[$key] as $grp){ + if (preg_match($regexp,$grp,$match)) { + if($localkey == 'grps') { + $info[$localkey][] = $match[1]; + } else { + $info[$localkey] = $match[1]; + } + } + } + } else { + $info[$localkey] = $user_result[$key][0]; + } + } + } + $user_result = array_merge($info,$user_result); + + //get groups for given user if grouptree is given + if ($this->cnf['grouptree'] || $this->cnf['groupfilter']) { + $base = $this->_makeFilter($this->cnf['grouptree'], $user_result); + $filter = $this->_makeFilter($this->cnf['groupfilter'], $user_result); + $sr = $this->_ldapsearch($this->con, $base, $filter, $this->cnf['groupscope'], array($this->cnf['groupkey'])); + if($this->cnf['debug']){ + msg('LDAP group search: '.htmlspecialchars(ldap_error($this->con)),0,__LINE__,__FILE__); + msg('LDAP search at: '.htmlspecialchars($base.' '.$filter),0,__LINE__,__FILE__); + } + if(!$sr){ + msg("LDAP: Reading group memberships failed",-1); + return false; + } + $result = ldap_get_entries($this->con, $sr); + ldap_free_result($sr); + + if(is_array($result)) foreach($result as $grp){ + if(!empty($grp[$this->cnf['groupkey']][0])){ + if($this->cnf['debug']) + msg('LDAP usergroup: '.htmlspecialchars($grp[$this->cnf['groupkey']][0]),0,__LINE__,__FILE__); + $info['grps'][] = $grp[$this->cnf['groupkey']][0]; + } + } + } + + // always add the default group to the list of groups + if(!in_array($conf['defaultgroup'],$info['grps'])){ + $info['grps'][] = $conf['defaultgroup']; + } + return $info; + } + + /** + * Most values in LDAP are case-insensitive + */ + function isCaseSensitive(){ + return false; + } + + /** + * Bulk retrieval of user data + * + * @author Dominik Eckelmann + * @param start index of first user to be returned + * @param limit max number of users to be returned + * @param filter array of field/pattern pairs, null for no filter + * @return array of userinfo (refer getUserData for internal userinfo details) + */ + function retrieveUsers($start=0,$limit=-1,$filter=array()) { + if(!$this->_openLDAP()) return false; + + if (!isset($this->users)) { + // Perform the search and grab all their details + if(!empty($this->cnf['userfilter'])) { + $all_filter = str_replace('%{user}', '*', $this->cnf['userfilter']); + } else { + $all_filter = "(ObjectClass=*)"; + } + $sr=ldap_search($this->con,$this->cnf['usertree'],$all_filter); + $entries = ldap_get_entries($this->con, $sr); + $users_array = array(); + for ($i=0; $i<$entries["count"]; $i++){ + array_push($users_array, $entries[$i]["uid"][0]); + } + asort($users_array); + $result = $users_array; + if (!$result) return array(); + $this->users = array_fill_keys($result, false); + } + $i = 0; + $count = 0; + $this->_constructPattern($filter); + $result = array(); + + foreach ($this->users as $user => &$info) { + if ($i++ < $start) { + continue; + } + if ($info === false) { + $info = $this->getUserData($user); + } + if ($this->_filter($user, $info)) { + $result[$user] = $info; + if (($limit >= 0) && (++$count >= $limit)) break; + } + } + return $result; + + + } + + /** + * Make LDAP filter strings. + * + * Used by auth_getUserData to make the filter + * strings for grouptree and groupfilter + * + * filter string ldap search filter with placeholders + * placeholders array array with the placeholders + * + * @author Troels Liebe Bentsen + * @return string + */ + function _makeFilter($filter, $placeholders) { + preg_match_all("/%{([^}]+)/", $filter, $matches, PREG_PATTERN_ORDER); + //replace each match + foreach ($matches[1] as $match) { + //take first element if array + if(is_array($placeholders[$match])) { + $value = $placeholders[$match][0]; + } else { + $value = $placeholders[$match]; + } + $value = $this->_filterEscape($value); + $filter = str_replace('%{'.$match.'}', $value, $filter); + } + return $filter; + } + + /** + * return 1 if $user + $info match $filter criteria, 0 otherwise + * + * @author Chris Smith + */ + function _filter($user, $info) { + foreach ($this->_pattern as $item => $pattern) { + if ($item == 'user') { + if (!preg_match($pattern, $user)) return 0; + } else if ($item == 'grps') { + if (!count(preg_grep($pattern, $info['grps']))) return 0; + } else { + if (!preg_match($pattern, $info[$item])) return 0; + } + } + return 1; + } + + function _constructPattern($filter) { + $this->_pattern = array(); + foreach ($filter as $item => $pattern) { +// $this->_pattern[$item] = '/'.preg_quote($pattern,"/").'/i'; // don't allow regex characters + $this->_pattern[$item] = '/'.str_replace('/','\/',$pattern).'/i'; // allow regex characters + } + } + + /** + * Escape a string to be used in a LDAP filter + * + * Ported from Perl's Net::LDAP::Util escape_filter_value + * + * @author Andreas Gohr + */ + function _filterEscape($string){ + return preg_replace('/([\x00-\x1F\*\(\)\\\\])/e', + '"\\\\\".join("",unpack("H2","$1"))', + $string); + } + + /** + * Opens a connection to the configured LDAP server and sets the wanted + * option on the connection + * + * @author Andreas Gohr + */ + function _openLDAP(){ + if($this->con) return true; // connection already established + + $this->bound = 0; + + $port = ($this->cnf['port']) ? $this->cnf['port'] : 389; + $this->con = @ldap_connect($this->cnf['server'],$port); + if(!$this->con){ + msg("LDAP: couldn't connect to LDAP server",-1); + return false; + } + + //set protocol version and dependend options + if($this->cnf['version']){ + if(!@ldap_set_option($this->con, LDAP_OPT_PROTOCOL_VERSION, + $this->cnf['version'])){ + msg('Setting LDAP Protocol version '.$this->cnf['version'].' failed',-1); + if($this->cnf['debug']) + msg('LDAP version set: '.htmlspecialchars(ldap_error($this->con)),0,__LINE__,__FILE__); + }else{ + //use TLS (needs version 3) + if($this->cnf['starttls']) { + if (!@ldap_start_tls($this->con)){ + msg('Starting TLS failed',-1); + if($this->cnf['debug']) + msg('LDAP TLS set: '.htmlspecialchars(ldap_error($this->con)),0,__LINE__,__FILE__); + } + } + // needs version 3 + if(isset($this->cnf['referrals'])) { + if(!@ldap_set_option($this->con, LDAP_OPT_REFERRALS, + $this->cnf['referrals'])){ + msg('Setting LDAP referrals to off failed',-1); + if($this->cnf['debug']) + msg('LDAP referal set: '.htmlspecialchars(ldap_error($this->con)),0,__LINE__,__FILE__); + } + } + } + } + + //set deref mode + if($this->cnf['deref']){ + if(!@ldap_set_option($this->con, LDAP_OPT_DEREF, $this->cnf['deref'])){ + msg('Setting LDAP Deref mode '.$this->cnf['deref'].' failed',-1); + if($this->cnf['debug']) + msg('LDAP deref set: '.htmlspecialchars(ldap_error($this->con)),0,__LINE__,__FILE__); + } + } + + $this->canDo['getUsers'] = true; + return true; + } + + /** + * Wraps around ldap_search, ldap_list or ldap_read depending on $scope + * + * @param $scope string - can be 'base', 'one' or 'sub' + * @author Andreas Gohr + */ + function _ldapsearch($link_identifier, $base_dn, $filter, $scope='sub', $attributes=null, + $attrsonly=0, $sizelimit=0, $timelimit=0, $deref=LDAP_DEREF_NEVER){ + if(is_null($attributes)) $attributes = array(); + + if($scope == 'base'){ + return @ldap_read($link_identifier, $base_dn, $filter, $attributes, + $attrsonly, $sizelimit, $timelimit, $deref); + }elseif($scope == 'one'){ + return @ldap_list($link_identifier, $base_dn, $filter, $attributes, + $attrsonly, $sizelimit, $timelimit, $deref); + }else{ + return @ldap_search($link_identifier, $base_dn, $filter, $attributes, + $attrsonly, $sizelimit, $timelimit, $deref); + } + } +} \ No newline at end of file diff --git a/lib/plugins/authldap/plugin.info.txt b/lib/plugins/authldap/plugin.info.txt new file mode 100644 index 000000000..c36385224 --- /dev/null +++ b/lib/plugins/authldap/plugin.info.txt @@ -0,0 +1,7 @@ +base authldap +author +email +date +name ldap auth plugin +desc Provides authentication against am LDAP server +url diff --git a/lib/plugins/authmysql/auth.php b/lib/plugins/authmysql/auth.php new file mode 100644 index 000000000..9150d3939 --- /dev/null +++ b/lib/plugins/authmysql/auth.php @@ -0,0 +1,946 @@ + + */ +// must be run within Dokuwiki +if(!defined('DOKU_INC')) die(); + +/** + * MySQLP authentication backend + * + * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) + * @author Andreas Gohr + * @author Chris Smith + * @author Matthias Grimm + * @author Jan Schumann + */ +class auth_plugin_authmysql extends DokuWiki_Auth_Plugin +{ + var $dbcon = 0; + var $dbver = 0; // database version + var $dbrev = 0; // database revision + var $dbsub = 0; // database subrevision + var $cnf = null; + var $defaultgroup = ""; + + /** + * Constructor + * + * checks if the mysql interface is available, otherwise it will + * set the variable $success of the basis class to false + * + * @author Matthias Grimm + */ + function auth_plugin_authmysql() { + global $conf; + $this->cnf = $conf['auth']['mysql']; + + if (method_exists($this, 'auth_basic')) + parent::auth_basic(); + + if(!function_exists('mysql_connect')) { + if ($this->cnf['debug']) + msg("MySQL err: PHP MySQL extension not found.",-1,__LINE__,__FILE__); + $this->success = false; + return; + } + + // default to UTF-8, you rarely want something else + if(!isset($this->cnf['charset'])) $this->cnf['charset'] = 'utf8'; + + $this->defaultgroup = $conf['defaultgroup']; + + // set capabilities based upon config strings set + if (empty($this->cnf['server']) || empty($this->cnf['user']) || + !isset($this->cnf['password']) || empty($this->cnf['database'])){ + if ($this->cnf['debug']) + msg("MySQL err: insufficient configuration.",-1,__LINE__,__FILE__); + $this->success = false; + return; + } + + $this->cando['addUser'] = $this->_chkcnf(array('getUserInfo', + 'getGroups', + 'addUser', + 'getUserID', + 'getGroupID', + 'addGroup', + 'addUserGroup'),true); + $this->cando['delUser'] = $this->_chkcnf(array('getUserID', + 'delUser', + 'delUserRefs'),true); + $this->cando['modLogin'] = $this->_chkcnf(array('getUserID', + 'updateUser', + 'UpdateTarget'),true); + $this->cando['modPass'] = $this->cando['modLogin']; + $this->cando['modName'] = $this->cando['modLogin']; + $this->cando['modMail'] = $this->cando['modLogin']; + $this->cando['modGroups'] = $this->_chkcnf(array('getUserID', + 'getGroups', + 'getGroupID', + 'addGroup', + 'addUserGroup', + 'delGroup', + 'getGroupID', + 'delUserGroup'),true); + /* getGroups is not yet supported + $this->cando['getGroups'] = $this->_chkcnf(array('getGroups', + 'getGroupID'),false); */ + $this->cando['getUsers'] = $this->_chkcnf(array('getUsers', + 'getUserInfo', + 'getGroups'),false); + $this->cando['getUserCount'] = $this->_chkcnf(array('getUsers'),false); + } + + /** + * Check if the given config strings are set + * + * @author Matthias Grimm + * @return bool + */ + function _chkcnf($keys, $wop=false){ + foreach ($keys as $key){ + if (empty($this->cnf[$key])) return false; + } + + /* write operation and lock array filled with tables names? */ + if ($wop && (!is_array($this->cnf['TablesToLock']) || + !count($this->cnf['TablesToLock']))){ + return false; + } + + return true; + } + + /** + * Checks if the given user exists and the given plaintext password + * is correct. Furtheron it might be checked wether the user is + * member of the right group + * + * Depending on which SQL string is defined in the config, password + * checking is done here (getpass) or by the database (passcheck) + * + * @param $user user who would like access + * @param $pass user's clear text password to check + * @return bool + * + * @author Andreas Gohr + * @author Matthias Grimm + */ + function checkPass($user,$pass){ + $rc = false; + + if($this->_openDB()) { + $sql = str_replace('%{user}',$this->_escape($user),$this->cnf['checkPass']); + $sql = str_replace('%{pass}',$this->_escape($pass),$sql); + $sql = str_replace('%{dgroup}',$this->_escape($this->defaultgroup),$sql); + $result = $this->_queryDB($sql); + + if($result !== false && count($result) == 1) { + if($this->cnf['forwardClearPass'] == 1) + $rc = true; + else + $rc = auth_verifyPassword($pass,$result[0]['pass']); + } + $this->_closeDB(); + } + return $rc; + } + + /** + * [public function] + * + * Returns info about the given user needs to contain + * at least these fields: + * name string full name of the user + * mail string email addres of the user + * grps array list of groups the user is in + * + * @param $user user's nick to get data for + * + * @author Andreas Gohr + * @author Matthias Grimm + */ + function getUserData($user){ + if($this->_openDB()) { + $this->_lockTables("READ"); + $info = $this->_getUserInfo($user); + $this->_unlockTables(); + $this->_closeDB(); + } else + $info = false; + return $info; + } + + /** + * [public function] + * + * Create a new User. Returns false if the user already exists, + * null when an error occurred and true if everything went well. + * + * The new user will be added to the default group by this + * function if grps are not specified (default behaviour). + * + * @param $user nick of the user + * @param $pwd clear text password + * @param $name full name of the user + * @param $mail email address + * @param $grps array of groups the user should become member of + * + * @author Andreas Gohr + * @author Chris Smith + * @author Matthias Grimm + */ + function createUser($user,$pwd,$name,$mail,$grps=null){ + if($this->_openDB()) { + if (($info = $this->_getUserInfo($user)) !== false) + return false; // user already exists + + // set defaultgroup if no groups were given + if ($grps == null) + $grps = array($this->defaultgroup); + + $this->_lockTables("WRITE"); + $pwd = $this->cnf['forwardClearPass'] ? $pwd : auth_cryptPassword($pwd); + $rc = $this->_addUser($user,$pwd,$name,$mail,$grps); + $this->_unlockTables(); + $this->_closeDB(); + if ($rc) return true; + } + return null; // return error + } + + /** + * Modify user data [public function] + * + * An existing user dataset will be modified. Changes are given in an array. + * + * The dataset update will be rejected if the user name should be changed + * to an already existing one. + * + * The password must be provides unencrypted. Pasword cryption is done + * automatically if configured. + * + * If one or more groups could't be updated, an error would be set. In + * this case the dataset might already be changed and we can't rollback + * the changes. Transactions would be really usefull here. + * + * modifyUser() may be called without SQL statements defined that are + * needed to change group membership (for example if only the user profile + * should be modified). In this case we asure that we don't touch groups + * even $changes['grps'] is set by mistake. + * + * @param $user nick of the user to be changed + * @param $changes array of field/value pairs to be changed (password + * will be clear text) + * @return bool true on success, false on error + * + * @author Chris Smith + * @author Matthias Grimm + */ + function modifyUser($user, $changes) { + $rc = false; + + if (!is_array($changes) || !count($changes)) + return true; // nothing to change + + if($this->_openDB()) { + $this->_lockTables("WRITE"); + + if (($uid = $this->_getUserID($user))) { + $rc = $this->_updateUserInfo($changes, $uid); + + if ($rc && isset($changes['grps']) && $this->cando['modGroups']) { + $groups = $this->_getGroups($user); + $grpadd = array_diff($changes['grps'], $groups); + $grpdel = array_diff($groups, $changes['grps']); + + foreach($grpadd as $group) + if (($this->_addUserToGroup($user, $group, 1)) == false) + $rc = false; + + foreach($grpdel as $group) + if (($this->_delUserFromGroup($user, $group)) == false) + $rc = false; + } + } + + $this->_unlockTables(); + $this->_closeDB(); + } + return $rc; + } + + /** + * [public function] + * + * Remove one or more users from the list of registered users + * + * @param array $users array of users to be deleted + * @return int the number of users deleted + * + * @author Christopher Smith + * @author Matthias Grimm + */ + function deleteUsers($users) { + $count = 0; + + if($this->_openDB()) { + if (is_array($users) && count($users)) { + $this->_lockTables("WRITE"); + foreach ($users as $user) { + if ($this->_delUser($user)) + $count++; + } + $this->_unlockTables(); + } + $this->_closeDB(); + } + return $count; + } + + /** + * [public function] + * + * Counts users which meet certain $filter criteria. + * + * @param array $filter filter criteria in item/pattern pairs + * @return count of found users. + * + * @author Matthias Grimm + */ + function getUserCount($filter=array()) { + $rc = 0; + + if($this->_openDB()) { + $sql = $this->_createSQLFilter($this->cnf['getUsers'], $filter); + + if ($this->dbver >= 4) { + $sql = substr($sql, 6); /* remove 'SELECT' or 'select' */ + $sql = "SELECT SQL_CALC_FOUND_ROWS".$sql." LIMIT 1"; + $this->_queryDB($sql); + $result = $this->_queryDB("SELECT FOUND_ROWS()"); + $rc = $result[0]['FOUND_ROWS()']; + } else if (($result = $this->_queryDB($sql))) + $rc = count($result); + + $this->_closeDB(); + } + return $rc; + } + + /** + * Bulk retrieval of user data. [public function] + * + * @param first index of first user to be returned + * @param limit max number of users to be returned + * @param filter array of field/pattern pairs + * @return array of userinfo (refer getUserData for internal userinfo details) + * + * @author Matthias Grimm + */ + function retrieveUsers($first=0,$limit=10,$filter=array()) { + $out = array(); + + if($this->_openDB()) { + $this->_lockTables("READ"); + $sql = $this->_createSQLFilter($this->cnf['getUsers'], $filter); + $sql .= " ".$this->cnf['SortOrder']." LIMIT $first, $limit"; + $result = $this->_queryDB($sql); + + if (!empty($result)) { + foreach ($result as $user) + if (($info = $this->_getUserInfo($user['user']))) + $out[$user['user']] = $info; + } + + $this->_unlockTables(); + $this->_closeDB(); + } + return $out; + } + + /** + * Give user membership of a group [public function] + * + * @param $user + * @param $group + * @return bool true on success, false on error + * + * @author Matthias Grimm + */ + function joinGroup($user, $group) { + $rc = false; + + if ($this->_openDB()) { + $this->_lockTables("WRITE"); + $rc = $this->_addUserToGroup($user, $group); + $this->_unlockTables(); + $this->_closeDB(); + } + return $rc; + } + + /** + * Remove user from a group [public function] + * + * @param $user user that leaves a group + * @param $group group to leave + * @return bool + * + * @author Matthias Grimm + */ + function leaveGroup($user, $group) { + $rc = false; + + if ($this->_openDB()) { + $this->_lockTables("WRITE"); + $uid = $this->_getUserID($user); + $rc = $this->_delUserFromGroup($user, $group); + $this->_unlockTables(); + $this->_closeDB(); + } + return $rc; + } + + /** + * MySQL is case-insensitive + */ + function isCaseSensitive(){ + return false; + } + + /** + * Adds a user to a group. + * + * If $force is set to '1' non existing groups would be created. + * + * The database connection must already be established. Otherwise + * this function does nothing and returns 'false'. It is strongly + * recommended to call this function only after all participating + * tables (group and usergroup) have been locked. + * + * @param $user user to add to a group + * @param $group name of the group + * @param $force '1' create missing groups + * @return bool 'true' on success, 'false' on error + * + * @author Matthias Grimm + */ + function _addUserToGroup($user, $group, $force=0) { + $newgroup = 0; + + if (($this->dbcon) && ($user)) { + $gid = $this->_getGroupID($group); + if (!$gid) { + if ($force) { // create missing groups + $sql = str_replace('%{group}',$this->_escape($group),$this->cnf['addGroup']); + $gid = $this->_modifyDB($sql); + $newgroup = 1; // group newly created + } + if (!$gid) return false; // group didn't exist and can't be created + } + + $sql = $this->cnf['addUserGroup']; + if(strpos($sql,'%{uid}') !== false){ + $uid = $this->_getUserID($user); + $sql = str_replace('%{uid}', $this->_escape($uid),$sql); + } + $sql = str_replace('%{user}', $this->_escape($user),$sql); + $sql = str_replace('%{gid}', $this->_escape($gid),$sql); + $sql = str_replace('%{group}',$this->_escape($group),$sql); + if ($this->_modifyDB($sql) !== false) return true; + + if ($newgroup) { // remove previously created group on error + $sql = str_replace('%{gid}', $this->_escape($gid),$this->cnf['delGroup']); + $sql = str_replace('%{group}',$this->_escape($group),$sql); + $this->_modifyDB($sql); + } + } + return false; + } + + /** + * Remove user from a group + * + * @param $user user that leaves a group + * @param $group group to leave + * @return bool true on success, false on error + * + * @author Matthias Grimm + */ + function _delUserFromGroup($user, $group) { + $rc = false; + + + if (($this->dbcon) && ($user)) { + $sql = $this->cnf['delUserGroup']; + if(strpos($sql,'%{uid}') !== false){ + $uid = $this->_getUserID($user); + $sql = str_replace('%{uid}', $this->_escape($uid),$sql); + } + $gid = $this->_getGroupID($group); + if ($gid) { + $sql = str_replace('%{user}', $this->_escape($user),$sql); + $sql = str_replace('%{gid}', $this->_escape($gid),$sql); + $sql = str_replace('%{group}',$this->_escape($group),$sql); + $rc = $this->_modifyDB($sql) == 0 ? true : false; + } + } + return $rc; + } + + /** + * Retrieves a list of groups the user is a member off. + * + * The database connection must already be established + * for this function to work. Otherwise it will return + * 'false'. + * + * @param $user user whose groups should be listed + * @return bool false on error + * @return array array containing all groups on success + * + * @author Matthias Grimm + */ + function _getGroups($user) { + $groups = array(); + + if($this->dbcon) { + $sql = str_replace('%{user}',$this->_escape($user),$this->cnf['getGroups']); + $result = $this->_queryDB($sql); + + if($result !== false && count($result)) { + foreach($result as $row) + $groups[] = $row['group']; + } + return $groups; + } + return false; + } + + /** + * Retrieves the user id of a given user name + * + * The database connection must already be established + * for this function to work. Otherwise it will return + * 'false'. + * + * @param $user user whose id is desired + * @return user id + * + * @author Matthias Grimm + */ + function _getUserID($user) { + if($this->dbcon) { + $sql = str_replace('%{user}',$this->_escape($user),$this->cnf['getUserID']); + $result = $this->_queryDB($sql); + return $result === false ? false : $result[0]['id']; + } + return false; + } + + /** + * Adds a new User to the database. + * + * The database connection must already be established + * for this function to work. Otherwise it will return + * 'false'. + * + * @param $user login of the user + * @param $pwd encrypted password + * @param $name full name of the user + * @param $mail email address + * @param $grps array of groups the user should become member of + * @return bool + * + * @author Andreas Gohr + * @author Chris Smith + * @author Matthias Grimm + */ + function _addUser($user,$pwd,$name,$mail,$grps){ + if($this->dbcon && is_array($grps)) { + $sql = str_replace('%{user}', $this->_escape($user),$this->cnf['addUser']); + $sql = str_replace('%{pass}', $this->_escape($pwd),$sql); + $sql = str_replace('%{name}', $this->_escape($name),$sql); + $sql = str_replace('%{email}',$this->_escape($mail),$sql); + $uid = $this->_modifyDB($sql); + + if ($uid) { + foreach($grps as $group) { + $gid = $this->_addUserToGroup($user, $group, 1); + if ($gid === false) break; + } + + if ($gid) return true; + else { + /* remove the new user and all group relations if a group can't + * be assigned. Newly created groups will remain in the database + * and won't be removed. This might create orphaned groups but + * is not a big issue so we ignore this problem here. + */ + $this->_delUser($user); + if ($this->cnf['debug']) + msg ("MySQL err: Adding user '$user' to group '$group' failed.",-1,__LINE__,__FILE__); + } + } + } + return false; + } + + /** + * Deletes a given user and all his group references. + * + * The database connection must already be established + * for this function to work. Otherwise it will return + * 'false'. + * + * @param $user user whose id is desired + * @return bool + * + * @author Matthias Grimm + */ + function _delUser($user) { + if($this->dbcon) { + $uid = $this->_getUserID($user); + if ($uid) { + $sql = str_replace('%{uid}',$this->_escape($uid),$this->cnf['delUserRefs']); + $this->_modifyDB($sql); + $sql = str_replace('%{uid}',$this->_escape($uid),$this->cnf['delUser']); + $sql = str_replace('%{user}', $this->_escape($user),$sql); + $this->_modifyDB($sql); + return true; + } + } + return false; + } + + /** + * getUserInfo + * + * Gets the data for a specific user The database connection + * must already be established for this function to work. + * Otherwise it will return 'false'. + * + * @param $user user's nick to get data for + * @return bool false on error + * @return array user info on success + * + * @author Matthias Grimm + */ + function _getUserInfo($user){ + $sql = str_replace('%{user}',$this->_escape($user),$this->cnf['getUserInfo']); + $result = $this->_queryDB($sql); + if($result !== false && count($result)) { + $info = $result[0]; + $info['grps'] = $this->_getGroups($user); + return $info; + } + return false; + } + + /** + * Updates the user info in the database + * + * Update a user data structure in the database according changes + * given in an array. The user name can only be changes if it didn't + * exists already. If the new user name exists the update procedure + * will be aborted. The database keeps unchanged. + * + * The database connection has already to be established for this + * function to work. Otherwise it will return 'false'. + * + * The password will be crypted if necessary. + * + * @param $changes array of items to change as pairs of item and value + * @param $uid user id of dataset to change, must be unique in DB + * @return true on success or false on error + * + * @author Matthias Grimm + */ + function _updateUserInfo($changes, $uid) { + $sql = $this->cnf['updateUser']." "; + $cnt = 0; + $err = 0; + + if($this->dbcon) { + foreach ($changes as $item => $value) { + if ($item == 'user') { + if (($this->_getUserID($changes['user']))) { + $err = 1; /* new username already exists */ + break; /* abort update */ + } + if ($cnt++ > 0) $sql .= ", "; + $sql .= str_replace('%{user}',$value,$this->cnf['UpdateLogin']); + } else if ($item == 'name') { + if ($cnt++ > 0) $sql .= ", "; + $sql .= str_replace('%{name}',$value,$this->cnf['UpdateName']); + } else if ($item == 'pass') { + if (!$this->cnf['forwardClearPass']) + $value = auth_cryptPassword($value); + if ($cnt++ > 0) $sql .= ", "; + $sql .= str_replace('%{pass}',$value,$this->cnf['UpdatePass']); + } else if ($item == 'mail') { + if ($cnt++ > 0) $sql .= ", "; + $sql .= str_replace('%{email}',$value,$this->cnf['UpdateEmail']); + } + } + + if ($err == 0) { + if ($cnt > 0) { + $sql .= " ".str_replace('%{uid}', $uid, $this->cnf['UpdateTarget']); + if(get_class($this) == 'auth_mysql') $sql .= " LIMIT 1"; //some PgSQL inheritance comp. + $this->_modifyDB($sql); + } + return true; + } + } + return false; + } + + /** + * Retrieves the group id of a given group name + * + * The database connection must already be established + * for this function to work. Otherwise it will return + * 'false'. + * + * @param $group group name which id is desired + * @return group id + * + * @author Matthias Grimm + */ + function _getGroupID($group) { + if($this->dbcon) { + $sql = str_replace('%{group}',$this->_escape($group),$this->cnf['getGroupID']); + $result = $this->_queryDB($sql); + return $result === false ? false : $result[0]['id']; + } + return false; + } + + /** + * Opens a connection to a database and saves the handle for further + * usage in the object. The successful call to this functions is + * essential for most functions in this object. + * + * @return bool + * + * @author Matthias Grimm + */ + function _openDB() { + if (!$this->dbcon) { + $con = @mysql_connect ($this->cnf['server'], $this->cnf['user'], $this->cnf['password']); + if ($con) { + if ((mysql_select_db($this->cnf['database'], $con))) { + if ((preg_match("/^(\d+)\.(\d+)\.(\d+).*/", mysql_get_server_info ($con), $result)) == 1) { + $this->dbver = $result[1]; + $this->dbrev = $result[2]; + $this->dbsub = $result[3]; + } + $this->dbcon = $con; + if(!empty($this->cnf['charset'])){ + mysql_query('SET CHARACTER SET "' . $this->cnf['charset'] . '"', $con); + } + return true; // connection and database successfully opened + } else { + mysql_close ($con); + if ($this->cnf['debug']) + msg("MySQL err: No access to database {$this->cnf['database']}.",-1,__LINE__,__FILE__); + } + } else if ($this->cnf['debug']) + msg ("MySQL err: Connection to {$this->cnf['user']}@{$this->cnf['server']} not possible.", + -1,__LINE__,__FILE__); + + return false; // connection failed + } + return true; // connection already open + } + + /** + * Closes a database connection. + * + * @author Matthias Grimm + */ + function _closeDB() { + if ($this->dbcon) { + mysql_close ($this->dbcon); + $this->dbcon = 0; + } + } + + /** + * Sends a SQL query to the database and transforms the result into + * an associative array. + * + * This function is only able to handle queries that returns a + * table such as SELECT. + * + * @param $query SQL string that contains the query + * @return array with the result table + * + * @author Matthias Grimm + */ + function _queryDB($query) { + if($this->cnf['debug'] >= 2){ + msg('MySQL query: '.hsc($query),0,__LINE__,__FILE__); + } + + $resultarray = array(); + if ($this->dbcon) { + $result = @mysql_query($query,$this->dbcon); + if ($result) { + while (($t = mysql_fetch_assoc($result)) !== false) + $resultarray[]=$t; + mysql_free_result ($result); + return $resultarray; + } + if ($this->cnf['debug']) + msg('MySQL err: '.mysql_error($this->dbcon),-1,__LINE__,__FILE__); + } + return false; + } + + /** + * Sends a SQL query to the database + * + * This function is only able to handle queries that returns + * either nothing or an id value such as INPUT, DELETE, UPDATE, etc. + * + * @param $query SQL string that contains the query + * @return insert id or 0, false on error + * + * @author Matthias Grimm + */ + function _modifyDB($query) { + if ($this->dbcon) { + $result = @mysql_query($query,$this->dbcon); + if ($result) { + $rc = mysql_insert_id($this->dbcon); //give back ID on insert + if ($rc !== false) return $rc; + } + if ($this->cnf['debug']) + msg('MySQL err: '.mysql_error($this->dbcon),-1,__LINE__,__FILE__); + } + return false; + } + + /** + * Locked a list of tables for exclusive access so that modifications + * to the database can't be disturbed by other threads. The list + * could be set with $conf['auth']['mysql']['TablesToLock'] = array() + * + * If aliases for tables are used in SQL statements, also this aliases + * must be locked. For eg. you use a table 'user' and the alias 'u' in + * some sql queries, the array must looks like this (order is important): + * array("user", "user AS u"); + * + * MySQL V3 is not able to handle transactions with COMMIT/ROLLBACK + * so that this functionality is simulated by this function. Nevertheless + * it is not as powerful as transactions, it is a good compromise in safty. + * + * @param $mode could be 'READ' or 'WRITE' + * + * @author Matthias Grimm + */ + function _lockTables($mode) { + if ($this->dbcon) { + if (is_array($this->cnf['TablesToLock']) && !empty($this->cnf['TablesToLock'])) { + if ($mode == "READ" || $mode == "WRITE") { + $sql = "LOCK TABLES "; + $cnt = 0; + foreach ($this->cnf['TablesToLock'] as $table) { + if ($cnt++ != 0) $sql .= ", "; + $sql .= "$table $mode"; + } + $this->_modifyDB($sql); + return true; + } + } + } + return false; + } + + /** + * Unlock locked tables. All existing locks of this thread will be + * abrogated. + * + * @author Matthias Grimm + */ + function _unlockTables() { + if ($this->dbcon) { + $this->_modifyDB("UNLOCK TABLES"); + return true; + } + return false; + } + + /** + * Transforms the filter settings in an filter string for a SQL database + * The database connection must already be established, otherwise the + * original SQL string without filter criteria will be returned. + * + * @param $sql SQL string to which the $filter criteria should be added + * @param $filter array of filter criteria as pairs of item and pattern + * @return SQL string with attached $filter criteria on success + * @return the original SQL string on error. + * + * @author Matthias Grimm + */ + function _createSQLFilter($sql, $filter) { + $SQLfilter = ""; + $cnt = 0; + + if ($this->dbcon) { + foreach ($filter as $item => $pattern) { + $tmp = '%'.$this->_escape($pattern).'%'; + if ($item == 'user') { + if ($cnt++ > 0) $SQLfilter .= " AND "; + $SQLfilter .= str_replace('%{user}',$tmp,$this->cnf['FilterLogin']); + } else if ($item == 'name') { + if ($cnt++ > 0) $SQLfilter .= " AND "; + $SQLfilter .= str_replace('%{name}',$tmp,$this->cnf['FilterName']); + } else if ($item == 'mail') { + if ($cnt++ > 0) $SQLfilter .= " AND "; + $SQLfilter .= str_replace('%{email}',$tmp,$this->cnf['FilterEmail']); + } else if ($item == 'grps') { + if ($cnt++ > 0) $SQLfilter .= " AND "; + $SQLfilter .= str_replace('%{group}',$tmp,$this->cnf['FilterGroup']); + } + } + + // we have to check SQLfilter here and must not use $cnt because if + // any of cnf['Filter????'] is not defined, a malformed SQL string + // would be generated. + + if (strlen($SQLfilter)) { + $glue = strpos(strtolower($sql),"where") ? " AND " : " WHERE "; + $sql = $sql.$glue.$SQLfilter; + } + } + + return $sql; + } + + /** + * Escape a string for insertion into the database + * + * @author Andreas Gohr + * @param string $string The string to escape + * @param boolean $like Escape wildcard chars as well? + */ + function _escape($string,$like=false){ + if($this->dbcon){ + $string = mysql_real_escape_string($string, $this->dbcon); + }else{ + $string = addslashes($string); + } + if($like){ + $string = addcslashes($string,'%_'); + } + return $string; + } +} \ No newline at end of file diff --git a/lib/plugins/authmysql/plugin.info.txt b/lib/plugins/authmysql/plugin.info.txt new file mode 100644 index 000000000..d08d4a7ef --- /dev/null +++ b/lib/plugins/authmysql/plugin.info.txt @@ -0,0 +1,7 @@ +base authmysql +author +email +date +name mysql auth plugin +desc Provides authentication against a MySQL Server +url diff --git a/lib/plugins/authpgsql/auth.php b/lib/plugins/authpgsql/auth.php new file mode 100644 index 000000000..824a77882 --- /dev/null +++ b/lib/plugins/authpgsql/auth.php @@ -0,0 +1,331 @@ + + */ +// must be run within Dokuwiki +if(!defined('DOKU_INC')) die(); + +/** + * PgSQL authentication backend + * + * This class inherits much functionality from the MySQL class + * and just reimplements the Postgres specific parts. + * + * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) + * @author Andreas Gohr + * @author Chris Smith + * @author Matthias Grimm + * @author Jan Schumann +*/ +class auth_plugin_authpgsql extends auth_plugin_authmysql +{ + var $cnf = null; + var $opts = null; + var $adldap = null; + var $users = null; + + /** + * Constructor + */ + function auth_plugin_authpgsql() { + global $conf; + $this->cnf = $conf['auth']['ad']; + + + // additional information fields + if (isset($this->cnf['additional'])) { + $this->cnf['additional'] = str_replace(' ', '', $this->cnf['additional']); + $this->cnf['additional'] = explode(',', $this->cnf['additional']); + } else $this->cnf['additional'] = array(); + + // ldap extension is needed + if (!function_exists('ldap_connect')) { + if ($this->cnf['debug']) + msg("AD Auth: PHP LDAP extension not found.",-1); + $this->success = false; + return; + } + + // Prepare SSO + if($_SERVER['REMOTE_USER'] && $this->cnf['sso']){ + // remove possible NTLM domain + list($dom,$usr) = explode('\\',$_SERVER['REMOTE_USER'],2); + if(!$usr) $usr = $dom; + + // remove possible Kerberos domain + list($usr,$dom) = explode('@',$usr); + + $dom = strtolower($dom); + $_SERVER['REMOTE_USER'] = $usr; + + // we need to simulate a login + if(empty($_COOKIE[DOKU_COOKIE])){ + $_REQUEST['u'] = $_SERVER['REMOTE_USER']; + $_REQUEST['p'] = 'sso_only'; + } + } + + // prepare adLDAP standard configuration + $this->opts = $this->cnf; + + // add possible domain specific configuration + if($dom && is_array($this->cnf[$dom])) foreach($this->cnf[$dom] as $key => $val){ + $this->opts[$key] = $val; + } + + // handle multiple AD servers + $this->opts['domain_controllers'] = explode(',',$this->opts['domain_controllers']); + $this->opts['domain_controllers'] = array_map('trim',$this->opts['domain_controllers']); + $this->opts['domain_controllers'] = array_filter($this->opts['domain_controllers']); + + // we can change the password if SSL is set + if($this->opts['use_ssl'] || $this->opts['use_tls']){ + $this->cando['modPass'] = true; + } + $this->cando['modName'] = true; + $this->cando['modMail'] = true; + } + + /** + * Check user+password [required auth function] + * + * Checks if the given user exists and the given + * plaintext password is correct by trying to bind + * to the LDAP server + * + * @author James Van Lommel + * @return bool + */ + function checkPass($user, $pass){ + if($_SERVER['REMOTE_USER'] && + $_SERVER['REMOTE_USER'] == $user && + $this->cnf['sso']) return true; + + if(!$this->_init()) return false; + return $this->adldap->authenticate($user, $pass); + } + + /** + * Return user info [required auth function] + * + * Returns info about the given user needs to contain + * at least these fields: + * + * name string full name of the user + * mail string email address of the user + * grps array list of groups the user is in + * + * This LDAP specific function returns the following + * addional fields: + * + * dn string distinguished name (DN) + * uid string Posix User ID + * + * @author James Van Lommel + */ + function getUserData($user){ + global $conf; + if(!$this->_init()) return false; + + $fields = array('mail','displayname','samaccountname'); + + // add additional fields to read + $fields = array_merge($fields, $this->cnf['additional']); + $fields = array_unique($fields); + + //get info for given user + $result = $this->adldap->user_info($user, $fields); + //general user info + $info['name'] = $result[0]['displayname'][0]; + $info['mail'] = $result[0]['mail'][0]; + $info['uid'] = $result[0]['samaccountname'][0]; + $info['dn'] = $result[0]['dn']; + + // additional information + foreach ($this->cnf['additional'] as $field) { + if (isset($result[0][strtolower($field)])) { + $info[$field] = $result[0][strtolower($field)][0]; + } + } + + // handle ActiveDirectory memberOf + $info['grps'] = $this->adldap->user_groups($user,(bool) $this->opts['recursive_groups']); + + if (is_array($info['grps'])) { + foreach ($info['grps'] as $ndx => $group) { + $info['grps'][$ndx] = $this->cleanGroup($group); + } + } + + // always add the default group to the list of groups + if(!is_array($info['grps']) || !in_array($conf['defaultgroup'],$info['grps'])){ + $info['grps'][] = $conf['defaultgroup']; + } + + return $info; + } + + /** + * Make AD group names usable by DokuWiki. + * + * Removes backslashes ('\'), pound signs ('#'), and converts spaces to underscores. + * + * @author James Van Lommel (jamesvl@gmail.com) + */ + function cleanGroup($name) { + $sName = str_replace('\\', '', $name); + $sName = str_replace('#', '', $sName); + $sName = preg_replace('[\s]', '_', $sName); + return $sName; + } + + /** + * Sanitize user names + */ + function cleanUser($name) { + return $this->cleanGroup($name); + } + + /** + * Most values in LDAP are case-insensitive + */ + function isCaseSensitive(){ + return false; + } + + /** + * Bulk retrieval of user data + * + * @author Dominik Eckelmann + * @param start index of first user to be returned + * @param limit max number of users to be returned + * @param filter array of field/pattern pairs, null for no filter + * @return array of userinfo (refer getUserData for internal userinfo details) + */ + function retrieveUsers($start=0,$limit=-1,$filter=array()) { + if(!$this->_init()) return false; + + if ($this->users === null) { + //get info for given user + $result = $this->adldap->all_users(); + if (!$result) return array(); + $this->users = array_fill_keys($result, false); + } + + $i = 0; + $count = 0; + $this->_constructPattern($filter); + $result = array(); + + foreach ($this->users as $user => &$info) { + if ($i++ < $start) { + continue; + } + if ($info === false) { + $info = $this->getUserData($user); + } + if ($this->_filter($user, $info)) { + $result[$user] = $info; + if (($limit >= 0) && (++$count >= $limit)) break; + } + } + return $result; + } + + /** + * Modify user data + * + * @param $user nick of the user to be changed + * @param $changes array of field/value pairs to be changed + * @return bool + */ + function modifyUser($user, $changes) { + $return = true; + + // password changing + if(isset($changes['pass'])){ + try { + $return = $this->adldap->user_password($user,$changes['pass']); + } catch (adLDAPException $e) { + if ($this->cnf['debug']) msg('AD Auth: '.$e->getMessage(), -1); + $return = false; + } + if(!$return) msg('AD Auth: failed to change the password. Maybe the password policy was not met?',-1); + } + + // changing user data + $adchanges = array(); + if(isset($changes['name'])){ + // get first and last name + $parts = explode(' ',$changes['name']); + $adchanges['surname'] = array_pop($parts); + $adchanges['firstname'] = join(' ',$parts); + $adchanges['display_name'] = $changes['name']; + } + if(isset($changes['mail'])){ + $adchanges['email'] = $changes['mail']; + } + if(count($adchanges)){ + try { + $return = $return & $this->adldap->user_modify($user,$adchanges); + } catch (adLDAPException $e) { + if ($this->cnf['debug']) msg('AD Auth: '.$e->getMessage(), -1); + $return = false; + } + } + + return $return; + } + + /** + * Initialize the AdLDAP library and connect to the server + */ + function _init(){ + if(!is_null($this->adldap)) return true; + + // connect + try { + $this->adldap = new adLDAP($this->opts); + if (isset($this->opts['ad_username']) && isset($this->opts['ad_password'])) { + $this->canDo['getUsers'] = true; + } + return true; + } catch (adLDAPException $e) { + if ($this->cnf['debug']) { + msg('AD Auth: '.$e->getMessage(), -1); + } + $this->success = false; + $this->adldap = null; + } + return false; + } + + /** + * return 1 if $user + $info match $filter criteria, 0 otherwise + * + * @author Chris Smith + */ + function _filter($user, $info) { + foreach ($this->_pattern as $item => $pattern) { + if ($item == 'user') { + if (!preg_match($pattern, $user)) return 0; + } else if ($item == 'grps') { + if (!count(preg_grep($pattern, $info['grps']))) return 0; + } else { + if (!preg_match($pattern, $info[$item])) return 0; + } + } + return 1; + } + + function _constructPattern($filter) { + $this->_pattern = array(); + foreach ($filter as $item => $pattern) { +// $this->_pattern[$item] = '/'.preg_quote($pattern,"/").'/i'; // don't allow regex characters + $this->_pattern[$item] = '/'.str_replace('/','\/',$pattern).'/i'; // allow regex characters + } + } +} \ No newline at end of file diff --git a/lib/plugins/authpgsql/plugin.info.txt b/lib/plugins/authpgsql/plugin.info.txt new file mode 100644 index 000000000..ad565b853 --- /dev/null +++ b/lib/plugins/authpgsql/plugin.info.txt @@ -0,0 +1,7 @@ +base authad +author +email +date +name active directory auth plugin +desc Provides authentication against a Microsoft Active Directory +url diff --git a/lib/plugins/authplain/auth.php b/lib/plugins/authplain/auth.php new file mode 100644 index 000000000..4be0e0c19 --- /dev/null +++ b/lib/plugins/authplain/auth.php @@ -0,0 +1,335 @@ + + */ +// must be run within Dokuwiki +if(!defined('DOKU_INC')) die(); + +/** + * Plaintext authentication backend + * + * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) + * @author Andreas Gohr + * @author Chris Smith + * @author Jan Schumann + */ +class auth_plugin_authplain extends DokuWiki_Auth_Plugin +{ + var $users = null; + var $_pattern = array(); + + /** + * Constructor + * + * Carry out sanity checks to ensure the object is + * able to operate. Set capabilities. + * + * @author Christopher Smith + */ + function auth_plugin_authplain() { + global $config_cascade; + + if (!@is_readable($config_cascade['plainauth.users']['default'])){ + $this->success = false; + }else{ + if(@is_writable($config_cascade['plainauth.users']['default'])){ + $this->cando['addUser'] = true; + $this->cando['delUser'] = true; + $this->cando['modLogin'] = true; + $this->cando['modPass'] = true; + $this->cando['modName'] = true; + $this->cando['modMail'] = true; + $this->cando['modGroups'] = true; + } + $this->cando['getUsers'] = true; + $this->cando['getUserCount'] = true; + } + } + + /** + * Check user+password [required auth function] + * + * Checks if the given user exists and the given + * plaintext password is correct + * + * @author Andreas Gohr + * @return bool + */ + function checkPass($user,$pass){ + + $userinfo = $this->getUserData($user); + if ($userinfo === false) return false; + + return auth_verifyPassword($pass,$this->users[$user]['pass']); + } + + /** + * Return user info + * + * Returns info about the given user needs to contain + * at least these fields: + * + * name string full name of the user + * mail string email addres of the user + * grps array list of groups the user is in + * + * @author Andreas Gohr + */ + function getUserData($user){ + + if($this->users === null) $this->_loadUserData(); + return isset($this->users[$user]) ? $this->users[$user] : false; + } + + /** + * Create a new User + * + * Returns false if the user already exists, null when an error + * occurred and true if everything went well. + * + * The new user will be added to the default group by this + * function if grps are not specified (default behaviour). + * + * @author Andreas Gohr + * @author Chris Smith + */ + function createUser($user,$pwd,$name,$mail,$grps=null){ + global $conf; + global $config_cascade; + + // user mustn't already exist + if ($this->getUserData($user) !== false) return false; + + $pass = auth_cryptPassword($pwd); + + // set default group if no groups specified + if (!is_array($grps)) $grps = array($conf['defaultgroup']); + + // prepare user line + $groups = join(',',$grps); + $userline = join(':',array($user,$pass,$name,$mail,$groups))."\n"; + + if (io_saveFile($config_cascade['plainauth.users']['default'],$userline,true)) { + $this->users[$user] = compact('pass','name','mail','grps'); + return $pwd; + } + + msg('The '.$config_cascade['plainauth.users']['default']. + ' file is not writable. Please inform the Wiki-Admin',-1); + return null; + } + + /** + * Modify user data + * + * @author Chris Smith + * @param $user nick of the user to be changed + * @param $changes array of field/value pairs to be changed (password will be clear text) + * @return bool + */ + function modifyUser($user, $changes) { + global $conf; + global $ACT; + global $INFO; + global $config_cascade; + + // sanity checks, user must already exist and there must be something to change + if (($userinfo = $this->getUserData($user)) === false) return false; + if (!is_array($changes) || !count($changes)) return true; + + // update userinfo with new data, remembering to encrypt any password + $newuser = $user; + foreach ($changes as $field => $value) { + if ($field == 'user') { + $newuser = $value; + continue; + } + if ($field == 'pass') $value = auth_cryptPassword($value); + $userinfo[$field] = $value; + } + + $groups = join(',',$userinfo['grps']); + $userline = join(':',array($newuser, $userinfo['pass'], $userinfo['name'], $userinfo['mail'], $groups))."\n"; + + if (!$this->deleteUsers(array($user))) { + msg('Unable to modify user data. Please inform the Wiki-Admin',-1); + return false; + } + + if (!io_saveFile($config_cascade['plainauth.users']['default'],$userline,true)) { + msg('There was an error modifying your user data. You should register again.',-1); + // FIXME, user has been deleted but not recreated, should force a logout and redirect to login page + $ACT == 'register'; + return false; + } + + $this->users[$newuser] = $userinfo; + return true; + } + + /** + * Remove one or more users from the list of registered users + * + * @author Christopher Smith + * @param array $users array of users to be deleted + * @return int the number of users deleted + */ + function deleteUsers($users) { + global $config_cascade; + + if (!is_array($users) || empty($users)) return 0; + + if ($this->users === null) $this->_loadUserData(); + + $deleted = array(); + foreach ($users as $user) { + if (isset($this->users[$user])) $deleted[] = preg_quote($user,'/'); + } + + if (empty($deleted)) return 0; + + $pattern = '/^('.join('|',$deleted).'):/'; + + if (io_deleteFromFile($config_cascade['plainauth.users']['default'],$pattern,true)) { + foreach ($deleted as $user) unset($this->users[$user]); + return count($deleted); + } + + // problem deleting, reload the user list and count the difference + $count = count($this->users); + $this->_loadUserData(); + $count -= count($this->users); + return $count; + } + + /** + * Return a count of the number of user which meet $filter criteria + * + * @author Chris Smith + */ + function getUserCount($filter=array()) { + + if($this->users === null) $this->_loadUserData(); + + if (!count($filter)) return count($this->users); + + $count = 0; + $this->_constructPattern($filter); + + foreach ($this->users as $user => $info) { + $count += $this->_filter($user, $info); + } + + return $count; + } + + /** + * Bulk retrieval of user data + * + * @author Chris Smith + * @param start index of first user to be returned + * @param limit max number of users to be returned + * @param filter array of field/pattern pairs + * @return array of userinfo (refer getUserData for internal userinfo details) + */ + function retrieveUsers($start=0,$limit=0,$filter=array()) { + + if ($this->users === null) $this->_loadUserData(); + + ksort($this->users); + + $i = 0; + $count = 0; + $out = array(); + $this->_constructPattern($filter); + + foreach ($this->users as $user => $info) { + if ($this->_filter($user, $info)) { + if ($i >= $start) { + $out[$user] = $info; + $count++; + if (($limit > 0) && ($count >= $limit)) break; + } + $i++; + } + } + + return $out; + } + + /** + * Only valid pageid's (no namespaces) for usernames + */ + function cleanUser($user){ + global $conf; + return cleanID(str_replace(':',$conf['sepchar'],$user)); + } + + /** + * Only valid pageid's (no namespaces) for groupnames + */ + function cleanGroup($group){ + global $conf; + return cleanID(str_replace(':',$conf['sepchar'],$group)); + } + + /** + * Load all user data + * + * loads the user file into a datastructure + * + * @author Andreas Gohr + */ + function _loadUserData(){ + global $config_cascade; + + $this->users = array(); + + if(!@file_exists($config_cascade['plainauth.users']['default'])) return; + + $lines = file($config_cascade['plainauth.users']['default']); + foreach($lines as $line){ + $line = preg_replace('/#.*$/','',$line); //ignore comments + $line = trim($line); + if(empty($line)) continue; + + $row = explode(":",$line,5); + $groups = array_values(array_filter(explode(",",$row[4]))); + + $this->users[$row[0]]['pass'] = $row[1]; + $this->users[$row[0]]['name'] = urldecode($row[2]); + $this->users[$row[0]]['mail'] = $row[3]; + $this->users[$row[0]]['grps'] = $groups; + } + } + + /** + * return 1 if $user + $info match $filter criteria, 0 otherwise + * + * @author Chris Smith + */ + function _filter($user, $info) { + // FIXME + foreach ($this->_pattern as $item => $pattern) { + if ($item == 'user') { + if (!preg_match($pattern, $user)) return 0; + } else if ($item == 'grps') { + if (!count(preg_grep($pattern, $info['grps']))) return 0; + } else { + if (!preg_match($pattern, $info[$item])) return 0; + } + } + return 1; + } + + function _constructPattern($filter) { + $this->_pattern = array(); + foreach ($filter as $item => $pattern) { +// $this->_pattern[$item] = '/'.preg_quote($pattern,"/").'/i'; // don't allow regex characters + $this->_pattern[$item] = '/'.str_replace('/','\/',$pattern).'/i'; // allow regex characters + } + } +} \ No newline at end of file diff --git a/lib/plugins/authplain/plugin.info.txt b/lib/plugins/authplain/plugin.info.txt new file mode 100644 index 000000000..3273e21d7 --- /dev/null +++ b/lib/plugins/authplain/plugin.info.txt @@ -0,0 +1,7 @@ +base authplain +author +email +date +name auth plugin +desc Provides authentication against local password storage +url diff --git a/lib/plugins/config/settings/extra.class.php b/lib/plugins/config/settings/extra.class.php index cee3c6b20..f6adf1c18 100644 --- a/lib/plugins/config/settings/extra.class.php +++ b/lib/plugins/config/settings/extra.class.php @@ -45,22 +45,52 @@ if (!class_exists('setting_authtype')) { function initialize($default,$local,$protected) { global $plugin_controller; - // populate $this->_choices with a list of available auth mechanisms - $authtypes = glob(DOKU_INC.'inc/auth/*.class.php'); - $authtypes = preg_replace('#^.*/([^/]*)\.class\.php$#i','$1', $authtypes); - $authtypes = array_diff($authtypes, array('basic')); - // retrive auth types provided by plugins foreach ($plugin_controller->getList('auth') as $plugin) { - $authtypes[] = $plugin; + $this->_choices[] = $plugin; } - $authtypes = array_unique($authtypes); - - $this->_choices = $authtypes; - parent::initialize($default,$local,$protected); } + + function update($input) { + global $plugin_controller; + + // is an update posible? + $mayUpdate = parent::update($input); + + // is it an auth plugin? + if (in_array($input, $plugin_controller->getList('auth'))) { + // reject disabled plugins + if ($plugin_controller->isdisabled($input)) { + $this->_error = true; + msg('Auth type ' . $input . ' is disabled.'); + return false; + } + + // load the plugin + $auth_plugin = $plugin_controller->load('auth', $input); + + // @TODO: throw an error in plugin controller instead of returning null + if (is_null($auth_plugin)) { + $this->_error = true; + msg('Cannot load Auth Plugin "' . $input . '"'); + return false; + } + + // verify proper instanciation (is this really a plugin?) @TODO use instanceof? impement interface? + if (is_object($auth_plugin) && !method_exists($auth_plugin, 'getPluginName')) { + $this->_error = true; + msg('Cannot create Auth Plugin "' . $input . '"'); + return false; + } + } + + msg('Successfully changed auth system. Please re-login.'); + auth_logoff(); + + return true; + } } } -- cgit v1.2.3 From 7b0a749accedb4a6e1f6fb0115d59707f586ec9f Mon Sep 17 00:00:00 2001 From: Andreas Gohr Date: Wed, 22 Aug 2012 12:58:49 +0200 Subject: Better support for multi domain AD setups This changes how the AD auth backend handles multiple domains. It is now possible to configure multiple authentication domains even when not using SSO. USers can provide a domain in NTLM- and Kerberos-Style (prepended with a backslash, appended with a @-char). IMPORTANT: If you used AD auth before, you will need to adjust your ACLs and $conf['superuser'] settings. This patch changes how user names are cleaned. Spaces and other special chars are no longer removed. The only adjustment is lowercasing the username and streamlining the domain handling. User's login names will now contain the domain name in Kerberos style (user@yourdomain.com) when they logged in a non-default domain. You need to make sure your ACLs are setup accordingly. Domain names are always lowercased and need to be specified lowercased in the config. --- inc/auth/ad.class.php | 320 +++++++++++++++++++++++++++++++------------------- 1 file changed, 196 insertions(+), 124 deletions(-) diff --git a/inc/auth/ad.class.php b/inc/auth/ad.class.php index e161c2939..48f3b9247 100644 --- a/inc/auth/ad.class.php +++ b/inc/auth/ad.class.php @@ -42,11 +42,12 @@ require_once(DOKU_INC.'inc/adLDAP.php'); class auth_ad extends auth_basic { - var $cnf = null; - var $opts = null; - var $adldap = null; + var $cnf = array(); + var $opts = array(); + var $adldap = array(); var $users = null; var $msgshown = false; + var $_pattern = array(); /** * Constructor @@ -56,58 +57,34 @@ class auth_ad extends auth_basic { $this->cnf = $conf['auth']['ad']; // additional information fields - if (isset($this->cnf['additional'])) { + if(isset($this->cnf['additional'])) { $this->cnf['additional'] = str_replace(' ', '', $this->cnf['additional']); $this->cnf['additional'] = explode(',', $this->cnf['additional']); } else $this->cnf['additional'] = array(); // ldap extension is needed - if (!function_exists('ldap_connect')) { - if ($this->cnf['debug']) - msg("AD Auth: PHP LDAP extension not found.",-1); + if(!function_exists('ldap_connect')) { + if($this->cnf['debug']) + msg("AD Auth: PHP LDAP extension not found.", -1); $this->success = false; return; } // Prepare SSO - if(!utf8_check($_SERVER['REMOTE_USER'])){ + if(!utf8_check($_SERVER['REMOTE_USER'])) { $_SERVER['REMOTE_USER'] = utf8_encode($_SERVER['REMOTE_USER']); } - if($_SERVER['REMOTE_USER'] && $this->cnf['sso']){ - // remove possible NTLM domain - list($dom,$usr) = explode('\\',$_SERVER['REMOTE_USER'],2); - if(!$usr) $usr = $dom; - - // remove possible Kerberos domain - list($usr,$dom) = explode('@',$usr); - - $dom = strtolower($dom); - $_SERVER['REMOTE_USER'] = $usr; + if($_SERVER['REMOTE_USER'] && $this->cnf['sso']) { + $_SERVER['REMOTE_USER'] = $this->cleanUser($_SERVER['REMOTE_USER']); // we need to simulate a login - if(empty($_COOKIE[DOKU_COOKIE])){ + if(empty($_COOKIE[DOKU_COOKIE])) { $_REQUEST['u'] = $_SERVER['REMOTE_USER']; $_REQUEST['p'] = 'sso_only'; } } - // prepare adLDAP standard configuration - $this->opts = $this->cnf; - - // add possible domain specific configuration - if($dom && is_array($this->cnf[$dom])) foreach($this->cnf[$dom] as $key => $val){ - $this->opts[$key] = $val; - } - - // handle multiple AD servers - $this->opts['domain_controllers'] = explode(',',$this->opts['domain_controllers']); - $this->opts['domain_controllers'] = array_map('trim',$this->opts['domain_controllers']); - $this->opts['domain_controllers'] = array_filter($this->opts['domain_controllers']); - - // we can change the password if SSL is set - if($this->opts['use_ssl'] || $this->opts['use_tls']){ - $this->cando['modPass'] = true; - } + // other can do's are changed in $this->_loadServerConfig() base on domain setup $this->cando['modName'] = true; $this->cando['modMail'] = true; } @@ -120,15 +97,19 @@ class auth_ad extends auth_basic { * to the LDAP server * * @author James Van Lommel + * @param string $user + * @param string $pass * @return bool */ - function checkPass($user, $pass){ + function checkPass($user, $pass) { if($_SERVER['REMOTE_USER'] && - $_SERVER['REMOTE_USER'] == $user && - $this->cnf['sso']) return true; + $_SERVER['REMOTE_USER'] == $user && + $this->cnf['sso'] + ) return true; - if(!$this->_init()) return false; - return $this->adldap->authenticate($user, $pass); + $adldap = $this->_adldap($this->_userDomain($user)); + if(!$adldap) return false; + return $adldap->authenticate($user, $pass); } /** @@ -137,85 +118,92 @@ class auth_ad extends auth_basic { * Returns info about the given user needs to contain * at least these fields: * - * name string full name of the user - * mail string email address of the user - * grps array list of groups the user is in + * name string full name of the user + * mail string email address of the user + * grps array list of groups the user is in * - * This LDAP specific function returns the following + * This AD specific function returns the following * addional fields: * - * dn string distinguished name (DN) - * uid string Posix User ID + * dn string distinguished name (DN) + * uid string samaccountname + * lastpwd int timestamp of the date when the password was set + * expires true if the password expires + * expiresin int seconds until the password expires + * any fields specified in the 'additional' config option * * @author James Van Lommel + * @param string $user + * @return array */ - function getUserData($user){ + function getUserData($user) { global $conf; global $lang; global $ID; - if(!$this->_init()) return false; + $adldap = $this->_adldap($this->_userDomain($user)); + if(!$adldap) return false; if($user == '') return array(); - $fields = array('mail','displayname','samaccountname','lastpwd','pwdlastset','useraccountcontrol'); + $fields = array('mail', 'displayname', 'samaccountname', 'lastpwd', 'pwdlastset', 'useraccountcontrol'); // add additional fields to read $fields = array_merge($fields, $this->cnf['additional']); $fields = array_unique($fields); //get info for given user - $result = $this->adldap->user_info($user, $fields); - if($result == false){ + $result = $adldap->user_info($user, $fields); + if($result == false) { return array(); } //general user info - $info['name'] = $result[0]['displayname'][0]; - $info['mail'] = $result[0]['mail'][0]; - $info['uid'] = $result[0]['samaccountname'][0]; - $info['dn'] = $result[0]['dn']; + $info['name'] = $result[0]['displayname'][0]; + $info['mail'] = $result[0]['mail'][0]; + $info['uid'] = $result[0]['samaccountname'][0]; + $info['dn'] = $result[0]['dn']; //last password set (Windows counts from January 1st 1601) $info['lastpwd'] = $result[0]['pwdlastset'][0] / 10000000 - 11644473600; //will it expire? $info['expires'] = !($result[0]['useraccountcontrol'][0] & 0x10000); //ADS_UF_DONT_EXPIRE_PASSWD // additional information - foreach ($this->cnf['additional'] as $field) { - if (isset($result[0][strtolower($field)])) { + foreach($this->cnf['additional'] as $field) { + if(isset($result[0][strtolower($field)])) { $info[$field] = $result[0][strtolower($field)][0]; } } // handle ActiveDirectory memberOf - $info['grps'] = $this->adldap->user_groups($user,(bool) $this->opts['recursive_groups']); + $info['grps'] = $adldap->user_groups($user, (bool) $this->opts['recursive_groups']); - if (is_array($info['grps'])) { - foreach ($info['grps'] as $ndx => $group) { + if(is_array($info['grps'])) { + foreach($info['grps'] as $ndx => $group) { $info['grps'][$ndx] = $this->cleanGroup($group); } } // always add the default group to the list of groups - if(!is_array($info['grps']) || !in_array($conf['defaultgroup'],$info['grps'])){ + if(!is_array($info['grps']) || !in_array($conf['defaultgroup'], $info['grps'])) { $info['grps'][] = $conf['defaultgroup']; } // check expiry time - if($info['expires'] && $this->cnf['expirywarn']){ - $result = $this->adldap->domain_info(array('maxpwdage')); // maximum pass age - $maxage = -1 * $result['maxpwdage'][0] / 10000000; // negative 100 nanosecs - $timeleft = $maxage - (time() - $info['lastpwd']); - $timeleft = round($timeleft/(24*60*60)); + if($info['expires'] && $this->cnf['expirywarn']) { + $result = $adldap->domain_info(array('maxpwdage')); // maximum pass age + $maxage = -1 * $result['maxpwdage'][0] / 10000000; // negative 100 nanosecs + $timeleft = $maxage - (time() - $info['lastpwd']); + $timeleft = round($timeleft / (24 * 60 * 60)); $info['expiresin'] = $timeleft; // if this is the current user, warn him (once per request only) - if( ($_SERVER['REMOTE_USER'] == $user) && + if(($_SERVER['REMOTE_USER'] == $user) && ($timeleft <= $this->cnf['expirywarn']) && !$this->msgshown - ){ - $msg = sprintf($lang['authpwdexpire'],$timeleft); - if($this->canDo('modPass')){ - $url = wl($ID,array('do'=>'profile')); + ) { + $msg = sprintf($lang['authpwdexpire'], $timeleft); + if($this->canDo('modPass')) { + $url = wl($ID, array('do'=> 'profile')); $msg .= ' '.$lang['btn_profile'].''; } msg($msg); @@ -242,15 +230,38 @@ class auth_ad extends auth_basic { /** * Sanitize user names + * + * Normalizes domain parts, does not modify the user name itself (unlike cleanGroup) + * + * @author Andreas Gohr + * @param string $name + * @return string */ function cleanUser($name) { - return $this->cleanGroup($name); + // get NTLM or Kerberos domain part + list($dom, $name) = explode('\\', $name, 2); + if(!$name) $name = $dom; + list($name, $dom) = explode('@', $name, 2); + + // clean up both + $dom = strtolower(trim($dom)); + $name = strtolower(trim($name)); + + // is this a known, valid domain? if not discard + if(!is_array($this->cnf[$dom])) { + $dom = ''; + } + + // reattach domain + if($dom) $name = "$name@$dom"; + + return $name; } /** * Most values in LDAP are case-insensitive */ - function isCaseSensitive(){ + function isCaseSensitive() { return false; } @@ -258,36 +269,37 @@ class auth_ad extends auth_basic { * Bulk retrieval of user data * * @author Dominik Eckelmann - * @param start index of first user to be returned - * @param limit max number of users to be returned - * @param filter array of field/pattern pairs, null for no filter - * @return array of userinfo (refer getUserData for internal userinfo details) + * @param int $start index of first user to be returned + * @param int $limit max number of users to be returned + * @param array $filter array of field/pattern pairs, null for no filter + * @return array userinfo (refer getUserData for internal userinfo details) */ - function retrieveUsers($start=0,$limit=-1,$filter=array()) { - if(!$this->_init()) return false; + function retrieveUsers($start = 0, $limit = -1, $filter = array()) { + $adldap = $this->_adldap(null); + if(!$adldap) return false; - if ($this->users === null) { + if($this->users === null) { //get info for given user - $result = $this->adldap->all_users(); - if (!$result) return array(); + $result = $adldap->all_users(); + if(!$result) return array(); $this->users = array_fill_keys($result, false); } - $i = 0; + $i = 0; $count = 0; $this->_constructPattern($filter); $result = array(); - foreach ($this->users as $user => &$info) { - if ($i++ < $start) { + foreach($this->users as $user => &$info) { + if($i++ < $start) { continue; } - if ($info === false) { + if($info === false) { $info = $this->getUserData($user); } - if ($this->_filter($user, $info)) { + if($this->_filter($user, $info)) { $result[$user] = $info; - if (($limit >= 0) && (++$count >= $limit)) break; + if(($limit >= 0) && (++$count >= $limit)) break; } } return $result; @@ -296,41 +308,43 @@ class auth_ad extends auth_basic { /** * Modify user data * - * @param $user nick of the user to be changed - * @param $changes array of field/value pairs to be changed + * @param string $user nick of the user to be changed + * @param array $changes array of field/value pairs to be changed * @return bool */ function modifyUser($user, $changes) { $return = true; + $adldap = $this->_adldap($this->_userDomain($user)); + if(!$adldap) return false; // password changing - if(isset($changes['pass'])){ + if(isset($changes['pass'])) { try { - $return = $this->adldap->user_password($user,$changes['pass']); - } catch (adLDAPException $e) { - if ($this->cnf['debug']) msg('AD Auth: '.$e->getMessage(), -1); + $return = $adldap->user_password($user, $changes['pass']); + } catch(adLDAPException $e) { + if($this->cnf['debug']) msg('AD Auth: '.$e->getMessage(), -1); $return = false; } - if(!$return) msg('AD Auth: failed to change the password. Maybe the password policy was not met?',-1); + if(!$return) msg('AD Auth: failed to change the password. Maybe the password policy was not met?', -1); } // changing user data $adchanges = array(); - if(isset($changes['name'])){ + if(isset($changes['name'])) { // get first and last name - $parts = explode(' ',$changes['name']); - $adchanges['surname'] = array_pop($parts); - $adchanges['firstname'] = join(' ',$parts); + $parts = explode(' ', $changes['name']); + $adchanges['surname'] = array_pop($parts); + $adchanges['firstname'] = join(' ', $parts); $adchanges['display_name'] = $changes['name']; } - if(isset($changes['mail'])){ + if(isset($changes['mail'])) { $adchanges['email'] = $changes['mail']; } - if(count($adchanges)){ + if(count($adchanges)) { try { - $return = $return & $this->adldap->user_modify($user,$adchanges); - } catch (adLDAPException $e) { - if ($this->cnf['debug']) msg('AD Auth: '.$e->getMessage(), -1); + $return = $return & $adldap->user_modify($user, $adchanges); + } catch(adLDAPException $e) { + if($this->cnf['debug']) msg('AD Auth: '.$e->getMessage(), -1); $return = false; } } @@ -340,40 +354,98 @@ class auth_ad extends auth_basic { /** * Initialize the AdLDAP library and connect to the server + * + * When you pass null as domain, it will reuse any existing domain. + * Eg. the one of the logged in user. It falls back to the default + * domain if no current one is available. + * + * @param string|null $domain The AD domain to use + * @return adLDAP|bool true if a connection was established */ - function _init(){ - if(!is_null($this->adldap)) return true; + protected function _adldap($domain) { + if(is_null($domain) && is_array($this->opts)) { + $domain = $this->opts['domain']; + } + + $this->opts = $this->_loadServerConfig((string) $domain); + if(isset($this->adldap[$domain])) return $this->adldap[$domain]; // connect try { - $this->adldap = new adLDAP($this->opts); - if (isset($this->opts['ad_username']) && isset($this->opts['ad_password'])) { - $this->canDo['getUsers'] = true; - } - return true; - } catch (adLDAPException $e) { - if ($this->cnf['debug']) { + $this->adldap[$domain] = new adLDAP($this->opts); + return $this->adldap[$domain]; + } catch(adLDAPException $e) { + if($this->cnf['debug']) { msg('AD Auth: '.$e->getMessage(), -1); } - $this->success = false; - $this->adldap = null; + $this->success = false; + $this->adldap[$domain] = null; } return false; } + /** + * Get the domain part from a user + * + * @param $user + * @return string + */ + protected function _userDomain($user) { + list(, $domain) = explode('@', $user, 2); + return $domain; + } + + /** + * Fetch the configuration for the given AD domain + * + * @param string $domain current AD domain + * @return array + */ + protected function _loadServerConfig($domain) { + // prepare adLDAP standard configuration + $opts = $this->cnf; + + $opts['domain'] = $domain; + + // add possible domain specific configuration + if($domain && is_array($this->cnf[$domain])) foreach($this->cnf[$domain] as $key => $val) { + $opts[$key] = $val; + } + + // handle multiple AD servers + $opts['domain_controllers'] = explode(',', $opts['domain_controllers']); + $opts['domain_controllers'] = array_map('trim', $opts['domain_controllers']); + $opts['domain_controllers'] = array_filter($opts['domain_controllers']); + + // we can change the password if SSL is set + if($opts['use_ssl'] || $opts['use_tls']) { + $this->cando['modPass'] = true; + } else { + $this->cando['modPass'] = false; + } + + if(isset($opts['ad_username']) && isset($opts['ad_password'])) { + $this->cando['getUsers'] = true; + } else { + $this->cando['getUsers'] = true; + } + + return $opts; + } + /** * return 1 if $user + $info match $filter criteria, 0 otherwise * * @author Chris Smith */ function _filter($user, $info) { - foreach ($this->_pattern as $item => $pattern) { - if ($item == 'user') { - if (!preg_match($pattern, $user)) return 0; - } else if ($item == 'grps') { - if (!count(preg_grep($pattern, $info['grps']))) return 0; + foreach($this->_pattern as $item => $pattern) { + if($item == 'user') { + if(!preg_match($pattern, $user)) return 0; + } else if($item == 'grps') { + if(!count(preg_grep($pattern, $info['grps']))) return 0; } else { - if (!preg_match($pattern, $info[$item])) return 0; + if(!preg_match($pattern, $info[$item])) return 0; } } return 1; @@ -381,8 +453,8 @@ class auth_ad extends auth_basic { function _constructPattern($filter) { $this->_pattern = array(); - foreach ($filter as $item => $pattern) { - $this->_pattern[$item] = '/'.str_replace('/','\/',$pattern).'/i'; // allow regex characters + foreach($filter as $item => $pattern) { + $this->_pattern[$item] = '/'.str_replace('/', '\/', $pattern).'/i'; // allow regex characters } } } -- cgit v1.2.3 From e12ea8465c640702902f5a4d95793e0e980ca123 Mon Sep 17 00:00:00 2001 From: Andreas Gohr Date: Wed, 22 Aug 2012 13:07:23 +0200 Subject: use UTF-8 aware lower casing --- inc/auth/ad.class.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/inc/auth/ad.class.php b/inc/auth/ad.class.php index 48f3b9247..674726a7e 100644 --- a/inc/auth/ad.class.php +++ b/inc/auth/ad.class.php @@ -244,8 +244,8 @@ class auth_ad extends auth_basic { list($name, $dom) = explode('@', $name, 2); // clean up both - $dom = strtolower(trim($dom)); - $name = strtolower(trim($name)); + $dom = utf8_strtolower(trim($dom)); + $name = utf8_strtolower(trim($name)); // is this a known, valid domain? if not discard if(!is_array($this->cnf[$dom])) { -- cgit v1.2.3 From 33c5220c3b4d37bf0906689a301c48568195141d Mon Sep 17 00:00:00 2001 From: Andreas Gohr Date: Wed, 22 Aug 2012 13:19:50 +0200 Subject: some code cleanup/PHP5ization --- inc/auth/ad.class.php | 91 ++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 64 insertions(+), 27 deletions(-) diff --git a/inc/auth/ad.class.php b/inc/auth/ad.class.php index 674726a7e..363abe114 100644 --- a/inc/auth/ad.class.php +++ b/inc/auth/ad.class.php @@ -14,7 +14,8 @@ * $conf['authtype'] = 'ad'; * $conf['passcrypt'] = 'ssha'; * - * $conf['auth']['ad']['account_suffix'] = '@my.domain.org'; + * $conf['auth']['ad']['account_suffix'] = ' + * @my.domain.org'; * $conf['auth']['ad']['base_dn'] = 'DC=my,DC=domain,DC=org'; * $conf['auth']['ad']['domain_controllers'] = 'srv1.domain.org,srv2.domain.org'; * @@ -42,17 +43,38 @@ require_once(DOKU_INC.'inc/adLDAP.php'); class auth_ad extends auth_basic { - var $cnf = array(); - var $opts = array(); - var $adldap = array(); - var $users = null; - var $msgshown = false; - var $_pattern = array(); + /** + * @var array copy of the auth backend configuration + */ + protected $cnf = array(); + /** + * @var array hold connection data for a specific AD domain + */ + protected $opts = array(); + /** + * @var array open connections for each AD domain, as adLDAP objects + */ + protected $adldap = array(); + + /** + * @var bool message state + */ + protected $msgshown = false; + + /** + * @var array user listing cache + */ + protected $users = array(); + + /** + * @var array filter patterns for listing users + */ + protected $_pattern = array(); /** * Constructor */ - function __construct() { + public function __construct() { global $conf; $this->cnf = $conf['auth']['ad']; @@ -101,7 +123,7 @@ class auth_ad extends auth_basic { * @param string $pass * @return bool */ - function checkPass($user, $pass) { + public function checkPass($user, $pass) { if($_SERVER['REMOTE_USER'] && $_SERVER['REMOTE_USER'] == $user && $this->cnf['sso'] @@ -136,7 +158,7 @@ class auth_ad extends auth_basic { * @param string $user * @return array */ - function getUserData($user) { + public function getUserData($user) { global $conf; global $lang; global $ID; @@ -220,12 +242,14 @@ class auth_ad extends auth_basic { * Removes backslashes ('\'), pound signs ('#'), and converts spaces to underscores. * * @author James Van Lommel (jamesvl@gmail.com) + * @param string $group + * @return string */ - function cleanGroup($name) { - $sName = str_replace('\\', '', $name); - $sName = str_replace('#', '', $sName); - $sName = preg_replace('[\s]', '_', $sName); - return $sName; + public function cleanGroup($group) { + $group = str_replace('\\', '', $group); + $group = str_replace('#', '', $group); + $group = preg_replace('[\s]', '_', $group); + return $group; } /** @@ -237,7 +261,7 @@ class auth_ad extends auth_basic { * @param string $name * @return string */ - function cleanUser($name) { + public function cleanUser($name) { // get NTLM or Kerberos domain part list($dom, $name) = explode('\\', $name, 2); if(!$name) $name = $dom; @@ -260,8 +284,10 @@ class auth_ad extends auth_basic { /** * Most values in LDAP are case-insensitive + * + * @return bool */ - function isCaseSensitive() { + public function isCaseSensitive() { return false; } @@ -274,7 +300,7 @@ class auth_ad extends auth_basic { * @param array $filter array of field/pattern pairs, null for no filter * @return array userinfo (refer getUserData for internal userinfo details) */ - function retrieveUsers($start = 0, $limit = -1, $filter = array()) { + public function retrieveUsers($start = 0, $limit = -1, $filter = array()) { $adldap = $this->_adldap(null); if(!$adldap) return false; @@ -312,7 +338,7 @@ class auth_ad extends auth_basic { * @param array $changes array of field/value pairs to be changed * @return bool */ - function modifyUser($user, $changes) { + public function modifyUser($user, $changes) { $return = true; $adldap = $this->_adldap($this->_userDomain($user)); if(!$adldap) return false; @@ -434,24 +460,35 @@ class auth_ad extends auth_basic { } /** - * return 1 if $user + $info match $filter criteria, 0 otherwise + * Check provided user and userinfo for matching patterns * - * @author Chris Smith + * The patterns are set up with $this->_constructPattern() + * + * @author Chris Smith + * @param string $user + * @param array $info + * @return bool */ - function _filter($user, $info) { + protected function _filter($user, $info) { foreach($this->_pattern as $item => $pattern) { if($item == 'user') { - if(!preg_match($pattern, $user)) return 0; + if(!preg_match($pattern, $user)) return false; } else if($item == 'grps') { - if(!count(preg_grep($pattern, $info['grps']))) return 0; + if(!count(preg_grep($pattern, $info['grps']))) return false; } else { - if(!preg_match($pattern, $info[$item])) return 0; + if(!preg_match($pattern, $info[$item])) return false; } } - return 1; + return true; } - function _constructPattern($filter) { + /** + * Create a pattern for $this->_filter() + * + * @author Chris Smith + * @param array $filter + */ + protected function _constructPattern($filter) { $this->_pattern = array(); foreach($filter as $item => $pattern) { $this->_pattern[$item] = '/'.str_replace('/', '\/', $pattern).'/i'; // allow regex characters -- cgit v1.2.3 From 70d71ed8159c719aa35363d05cc1dea2a95144f0 Mon Sep 17 00:00:00 2001 From: Andreas Gohr Date: Wed, 22 Aug 2012 15:46:17 +0200 Subject: fixed domain handling in user names --- inc/auth/ad.class.php | 47 ++++++++++++++++++++++++++++++----------------- 1 file changed, 30 insertions(+), 17 deletions(-) diff --git a/inc/auth/ad.class.php b/inc/auth/ad.class.php index 363abe114..e3ea87654 100644 --- a/inc/auth/ad.class.php +++ b/inc/auth/ad.class.php @@ -131,7 +131,8 @@ class auth_ad extends auth_basic { $adldap = $this->_adldap($this->_userDomain($user)); if(!$adldap) return false; - return $adldap->authenticate($user, $pass); + + return $adldap->authenticate($this->_userName($user), $pass); } /** @@ -174,7 +175,7 @@ class auth_ad extends auth_basic { $fields = array_unique($fields); //get info for given user - $result = $adldap->user_info($user, $fields); + $result = $adldap->user_info($this->_userName($user), $fields); if($result == false) { return array(); } @@ -197,7 +198,7 @@ class auth_ad extends auth_basic { } // handle ActiveDirectory memberOf - $info['grps'] = $adldap->user_groups($user, (bool) $this->opts['recursive_groups']); + $info['grps'] = $adldap->user_groups($this->_userName($user), (bool) $this->opts['recursive_groups']); if(is_array($info['grps'])) { foreach($info['grps'] as $ndx => $group) { @@ -258,28 +259,29 @@ class auth_ad extends auth_basic { * Normalizes domain parts, does not modify the user name itself (unlike cleanGroup) * * @author Andreas Gohr - * @param string $name + * @param string $user * @return string */ - public function cleanUser($name) { + public function cleanUser($user) { // get NTLM or Kerberos domain part - list($dom, $name) = explode('\\', $name, 2); - if(!$name) $name = $dom; - list($name, $dom) = explode('@', $name, 2); + list($dom, $user) = explode('\\', $user, 2); + if(!$user) $user = $dom; + if($dom) $domain = $dom; + list($user, $dom) = explode('@', $user, 2); + if($dom) $domain = $dom; // clean up both - $dom = utf8_strtolower(trim($dom)); - $name = utf8_strtolower(trim($name)); + $domain = utf8_strtolower(trim($domain)); + $user = utf8_strtolower(trim($user)); // is this a known, valid domain? if not discard - if(!is_array($this->cnf[$dom])) { - $dom = ''; + if(!is_array($this->cnf[$domain])) { + $domain = ''; } // reattach domain - if($dom) $name = "$name@$dom"; - - return $name; + if($domain) $user = "$user@$domain"; + return $user; } /** @@ -346,7 +348,7 @@ class auth_ad extends auth_basic { // password changing if(isset($changes['pass'])) { try { - $return = $adldap->user_password($user, $changes['pass']); + $return = $adldap->user_password($this->_userName($user), $changes['pass']); } catch(adLDAPException $e) { if($this->cnf['debug']) msg('AD Auth: '.$e->getMessage(), -1); $return = false; @@ -368,7 +370,7 @@ class auth_ad extends auth_basic { } if(count($adchanges)) { try { - $return = $return & $adldap->user_modify($user, $adchanges); + $return = $return & $adldap->user_modify($this->_userName($user), $adchanges); } catch(adLDAPException $e) { if($this->cnf['debug']) msg('AD Auth: '.$e->getMessage(), -1); $return = false; @@ -421,6 +423,17 @@ class auth_ad extends auth_basic { return $domain; } + /** + * Get the user part from a user + * + * @param $user + * @return string + */ + protected function _userName($user) { + list($name) = explode('@', $user, 2); + return $name; + } + /** * Fetch the configuration for the given AD domain * -- cgit v1.2.3 From 86bd5c0df3ca48ea055bb3a47cc25a9c3eff23c3 Mon Sep 17 00:00:00 2001 From: Andreas Gohr Date: Wed, 22 Aug 2012 15:49:30 +0200 Subject: add user's domain to the list of groups --- inc/auth/ad.class.php | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/inc/auth/ad.class.php b/inc/auth/ad.class.php index e3ea87654..76b8924aa 100644 --- a/inc/auth/ad.class.php +++ b/inc/auth/ad.class.php @@ -15,6 +15,7 @@ * $conf['passcrypt'] = 'ssha'; * * $conf['auth']['ad']['account_suffix'] = ' + * * @my.domain.org'; * $conf['auth']['ad']['base_dn'] = 'DC=my,DC=domain,DC=org'; * $conf['auth']['ad']['domain_controllers'] = 'srv1.domain.org,srv2.domain.org'; @@ -211,6 +212,12 @@ class auth_ad extends auth_basic { $info['grps'][] = $conf['defaultgroup']; } + // add the user's domain to the groups + $domain = $this->_userDomain($user); + if($domain && !in_array("domain-$domain", (array) $info['grps'])) { + $info['grps'][] = $this->cleanGroup("domain-$domain"); + } + // check expiry time if($info['expires'] && $this->cnf['expirywarn']) { $result = $adldap->domain_info(array('maxpwdage')); // maximum pass age @@ -263,6 +270,8 @@ class auth_ad extends auth_basic { * @return string */ public function cleanUser($user) { + $domain = ''; + // get NTLM or Kerberos domain part list($dom, $user) = explode('\\', $user, 2); if(!$user) $user = $dom; @@ -271,8 +280,8 @@ class auth_ad extends auth_basic { if($dom) $domain = $dom; // clean up both - $domain = utf8_strtolower(trim($domain)); - $user = utf8_strtolower(trim($user)); + $domain = utf8_strtolower(trim($domain)); + $user = utf8_strtolower(trim($user)); // is this a known, valid domain? if not discard if(!is_array($this->cnf[$domain])) { -- cgit v1.2.3 From 496e18cda1b159f7e70345a4ee6204d80d815145 Mon Sep 17 00:00:00 2001 From: Andreas Gohr Date: Thu, 23 Aug 2012 11:33:39 +0200 Subject: make AD utilitiy functions public --- inc/auth/ad.class.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/inc/auth/ad.class.php b/inc/auth/ad.class.php index 76b8924aa..7919c71ac 100644 --- a/inc/auth/ad.class.php +++ b/inc/auth/ad.class.php @@ -427,7 +427,7 @@ class auth_ad extends auth_basic { * @param $user * @return string */ - protected function _userDomain($user) { + public function _userDomain($user) { list(, $domain) = explode('@', $user, 2); return $domain; } @@ -438,7 +438,7 @@ class auth_ad extends auth_basic { * @param $user * @return string */ - protected function _userName($user) { + public function _userName($user) { list($name) = explode('@', $user, 2); return $name; } -- cgit v1.2.3 From 006b89daf7868db73e9a046a3804e8e60345ab4c Mon Sep 17 00:00:00 2001 From: Andreas Gohr Date: Thu, 23 Aug 2012 13:55:54 +0200 Subject: lowercase groups --- inc/auth/ad.class.php | 1 + 1 file changed, 1 insertion(+) diff --git a/inc/auth/ad.class.php b/inc/auth/ad.class.php index 7919c71ac..f535556a8 100644 --- a/inc/auth/ad.class.php +++ b/inc/auth/ad.class.php @@ -257,6 +257,7 @@ class auth_ad extends auth_basic { $group = str_replace('\\', '', $group); $group = str_replace('#', '', $group); $group = preg_replace('[\s]', '_', $group); + $group = utf8_strtolower(trim($group)); return $group; } -- cgit v1.2.3 From 8e41425c93cd83ec484adf93d3ee91e22b4b2880 Mon Sep 17 00:00:00 2001 From: Rudolf Mayerhofer Date: Fri, 21 Sep 2012 12:00:52 +0200 Subject: make use of adLDAP 4.0.4 in AD backend The new version of adLDAP improves the speed in handling recursive group memberships dramatically --- inc/adLDAP.php | 2442 -------------------- inc/adLDAP/adLDAP.php | 951 ++++++++ inc/adLDAP/classes/adLDAPComputers.php | 153 ++ inc/adLDAP/classes/adLDAPContacts.php | 294 +++ inc/adLDAP/classes/adLDAPExchange.php | 390 ++++ inc/adLDAP/classes/adLDAPFolders.php | 179 ++ inc/adLDAP/classes/adLDAPGroups.php | 631 +++++ inc/adLDAP/classes/adLDAPUsers.php | 682 ++++++ inc/adLDAP/classes/adLDAPUtils.php | 264 +++ inc/adLDAP/collections/adLDAPCollection.php | 137 ++ .../collections/adLDAPComputerCollection.php | 46 + inc/adLDAP/collections/adLDAPContactCollection.php | 46 + inc/adLDAP/collections/adLDAPGroupCollection.php | 46 + inc/adLDAP/collections/adLDAPUserCollection.php | 46 + inc/auth/ad.class.php | 16 +- 15 files changed, 3872 insertions(+), 2451 deletions(-) delete mode 100644 inc/adLDAP.php create mode 100644 inc/adLDAP/adLDAP.php create mode 100644 inc/adLDAP/classes/adLDAPComputers.php create mode 100644 inc/adLDAP/classes/adLDAPContacts.php create mode 100644 inc/adLDAP/classes/adLDAPExchange.php create mode 100644 inc/adLDAP/classes/adLDAPFolders.php create mode 100644 inc/adLDAP/classes/adLDAPGroups.php create mode 100644 inc/adLDAP/classes/adLDAPUsers.php create mode 100644 inc/adLDAP/classes/adLDAPUtils.php create mode 100644 inc/adLDAP/collections/adLDAPCollection.php create mode 100644 inc/adLDAP/collections/adLDAPComputerCollection.php create mode 100644 inc/adLDAP/collections/adLDAPContactCollection.php create mode 100644 inc/adLDAP/collections/adLDAPGroupCollection.php create mode 100644 inc/adLDAP/collections/adLDAPUserCollection.php diff --git a/inc/adLDAP.php b/inc/adLDAP.php deleted file mode 100644 index 24be6e475..000000000 --- a/inc/adLDAP.php +++ /dev/null @@ -1,2442 +0,0 @@ -_account_suffix = $_account_suffix; - } - - /** - * Get the account suffix - * - * @return string - */ - public function get_account_suffix() - { - return $this->_account_suffix; - } - - /** - * Set the domain controllers array - * - * @param array $_domain_controllers - * @return void - */ - public function set_domain_controllers(array $_domain_controllers) - { - $this->_domain_controllers = $_domain_controllers; - } - - /** - * Get the list of domain controllers - * - * @return void - */ - public function get_domain_controllers() - { - return $this->_domain_controllers; - } - - /** - * Set the username of an account with higher priviledges - * - * @param string $_ad_username - * @return void - */ - public function set_ad_username($_ad_username) - { - $this->_ad_username = $_ad_username; - } - - /** - * Get the username of the account with higher priviledges - * - * This will throw an exception for security reasons - */ - public function get_ad_username() - { - throw new adLDAPException('For security reasons you cannot access the domain administrator account details'); - } - - /** - * Set the password of an account with higher priviledges - * - * @param string $_ad_password - * @return void - */ - public function set_ad_password($_ad_password) - { - $this->_ad_password = $_ad_password; - } - - /** - * Get the password of the account with higher priviledges - * - * This will throw an exception for security reasons - */ - public function get_ad_password() - { - throw new adLDAPException('For security reasons you cannot access the domain administrator account details'); - } - - /** - * Set whether to detect the true primary group - * - * @param bool $_real_primary_group - * @return void - */ - public function set_real_primarygroup($_real_primarygroup) - { - $this->_real_primarygroup = $_real_primarygroup; - } - - /** - * Get the real primary group setting - * - * @return bool - */ - public function get_real_primarygroup() - { - return $this->_real_primarygroup; - } - - /** - * Set whether to use SSL - * - * @param bool $_use_ssl - * @return void - */ - public function set_use_ssl($_use_ssl) - { - $this->_use_ssl = $_use_ssl; - } - - /** - * Get the SSL setting - * - * @return bool - */ - public function get_use_ssl() - { - return $this->_use_ssl; - } - - /** - * Set whether to use TLS - * - * @param bool $_use_tls - * @return void - */ - public function set_use_tls($_use_tls) - { - $this->_use_tls = $_use_tls; - } - - /** - * Get the TLS setting - * - * @return bool - */ - public function get_use_tls() - { - return $this->_use_tls; - } - - /** - * Set whether to lookup recursive groups - * - * @param bool $_recursive_groups - * @return void - */ - public function set_recursive_groups($_recursive_groups) - { - $this->_recursive_groups = $_recursive_groups; - } - - /** - * Get the recursive groups setting - * - * @return bool - */ - public function get_recursive_groups() - { - return $this->_recursive_groups; - } - - /** - * Default Constructor - * - * Tries to bind to the AD domain over LDAP or LDAPs - * - * @param array $options Array of options to pass to the constructor - * @throws Exception - if unable to bind to Domain Controller - * @return bool - */ - function __construct($options=array()){ - // You can specifically overide any of the default configuration options setup above - if (count($options)>0){ - if (array_key_exists("account_suffix",$options)){ $this->_account_suffix=$options["account_suffix"]; } - if (array_key_exists("base_dn",$options)){ $this->_base_dn=$options["base_dn"]; } - if (array_key_exists("domain_controllers",$options)){ $this->_domain_controllers=$options["domain_controllers"]; } - if (array_key_exists("ad_username",$options)){ $this->_ad_username=$options["ad_username"]; } - if (array_key_exists("ad_password",$options)){ $this->_ad_password=$options["ad_password"]; } - if (array_key_exists("real_primarygroup",$options)){ $this->_real_primarygroup=$options["real_primarygroup"]; } - if (array_key_exists("use_ssl",$options)){ $this->_use_ssl=$options["use_ssl"]; } - if (array_key_exists("use_tls",$options)){ $this->_use_tls=$options["use_tls"]; } - if (array_key_exists("recursive_groups",$options)){ $this->_recursive_groups=$options["recursive_groups"]; } - } - - if ($this->ldap_supported() === false) { - throw new adLDAPException('No LDAP support for PHP. See: http://www.php.net/ldap'); - } - - return $this->connect(); - } - - /** - * Default Destructor - * - * Closes the LDAP connection - * - * @return void - */ - function __destruct(){ $this->close(); } - - /** - * Connects and Binds to the Domain Controller - * - * @return bool - */ - public function connect() { - // Connect to the AD/LDAP server as the username/password - $dc=$this->random_controller(); - if ($this->_use_ssl){ - $this->_conn = ldap_connect("ldaps://".$dc, 636); - } else { - $this->_conn = ldap_connect($dc); - } - - // Set some ldap options for talking to AD - ldap_set_option($this->_conn, LDAP_OPT_PROTOCOL_VERSION, 3); - ldap_set_option($this->_conn, LDAP_OPT_REFERRALS, 0); - - if ($this->_use_tls) { - ldap_start_tls($this->_conn); - } - - // Bind as a domain admin if they've set it up - if ($this->_ad_username!=NULL && $this->_ad_password!=NULL){ - $this->_bind = @ldap_bind($this->_conn,$this->_ad_username.$this->_account_suffix,$this->_ad_password); - if (!$this->_bind){ - if ($this->_use_ssl && !$this->_use_tls){ - // If you have problems troubleshooting, remove the @ character from the ldap_bind command above to get the actual error message - throw new adLDAPException('Bind to Active Directory failed. Either the LDAPs connection failed or the login credentials are incorrect. AD said: ' . $this->get_last_error()); - } else { - throw new adLDAPException('Bind to Active Directory failed. Check the login credentials and/or server details. AD said: ' . $this->get_last_error()); - } - } - } - - if ($this->_base_dn == NULL) { - $this->_base_dn = $this->find_base_dn(); - } - - return (true); - } - - /** - * Closes the LDAP connection - * - * @return void - */ - public function close() { - ldap_close ($this->_conn); - } - - /** - * Validate a user's login credentials - * - * @param string $username A user's AD username - * @param string $password A user's AD password - * @param bool optional $prevent_rebind - * @return bool - */ - public function authenticate($username, $password, $prevent_rebind = false) { - // Prevent null binding - if ($username === NULL || $password === NULL) { return false; } - if (empty($username) || empty($password)) { return false; } - - // Bind as the user - $ret = true; - $this->_bind = @ldap_bind($this->_conn, $username . $this->_account_suffix, $password); - if (!$this->_bind){ $ret = false; } - - // Cnce we've checked their details, kick back into admin mode if we have it - if ($this->_ad_username !== NULL && !$prevent_rebind) { - $this->_bind = @ldap_bind($this->_conn, $this->_ad_username . $this->_account_suffix , $this->_ad_password); - if (!$this->_bind){ - // This should never happen in theory - throw new adLDAPException('Rebind to Active Directory failed. AD said: ' . $this->get_last_error()); - } - } - - return $ret; - } - - //***************************************************************************************************************** - // GROUP FUNCTIONS - - /** - * Add a group to a group - * - * @param string $parent The parent group name - * @param string $child The child group name - * @return bool - */ - public function group_add_group($parent,$child){ - - // Find the parent group's dn - $parent_group=$this->group_info($parent,array("cn")); - if ($parent_group[0]["dn"]===NULL){ return (false); } - $parent_dn=$parent_group[0]["dn"]; - - // Find the child group's dn - $child_group=$this->group_info($child,array("cn")); - if ($child_group[0]["dn"]===NULL){ return (false); } - $child_dn=$child_group[0]["dn"]; - - $add=array(); - $add["member"] = $child_dn; - - $result=@ldap_mod_add($this->_conn,$parent_dn,$add); - if ($result==false){ return (false); } - return (true); - } - - /** - * Add a user to a group - * - * @param string $group The group to add the user to - * @param string $user The user to add to the group - * @param bool $isGUID Is the username passed a GUID or a samAccountName - * @return bool - */ - public function group_add_user($group,$user,$isGUID=false){ - // Adding a user is a bit fiddly, we need to get the full DN of the user - // and add it using the full DN of the group - - // Find the user's dn - $user_dn=$this->user_dn($user,$isGUID); - if ($user_dn===false){ return (false); } - - // Find the group's dn - $group_info=$this->group_info($group,array("cn")); - if ($group_info[0]["dn"]===NULL){ return (false); } - $group_dn=$group_info[0]["dn"]; - - $add=array(); - $add["member"] = $user_dn; - - $result=@ldap_mod_add($this->_conn,$group_dn,$add); - if ($result==false){ return (false); } - return (true); - } - - /** - * Add a contact to a group - * - * @param string $group The group to add the contact to - * @param string $contact_dn The DN of the contact to add - * @return bool - */ - public function group_add_contact($group,$contact_dn){ - // To add a contact we take the contact's DN - // and add it using the full DN of the group - - // Find the group's dn - $group_info=$this->group_info($group,array("cn")); - if ($group_info[0]["dn"]===NULL){ return (false); } - $group_dn=$group_info[0]["dn"]; - - $add=array(); - $add["member"] = $contact_dn; - - $result=@ldap_mod_add($this->_conn,$group_dn,$add); - if ($result==false){ return (false); } - return (true); - } - - /** - * Create a group - * - * @param array $attributes Default attributes of the group - * @return bool - */ - public function group_create($attributes){ - if (!is_array($attributes)){ return ("Attributes must be an array"); } - if (!array_key_exists("group_name",$attributes)){ return ("Missing compulsory field [group_name]"); } - if (!array_key_exists("container",$attributes)){ return ("Missing compulsory field [container]"); } - if (!array_key_exists("description",$attributes)){ return ("Missing compulsory field [description]"); } - if (!is_array($attributes["container"])){ return ("Container attribute must be an array."); } - $attributes["container"]=array_reverse($attributes["container"]); - - //$member_array = array(); - //$member_array[0] = "cn=user1,cn=Users,dc=yourdomain,dc=com"; - //$member_array[1] = "cn=administrator,cn=Users,dc=yourdomain,dc=com"; - - $add=array(); - $add["cn"] = $attributes["group_name"]; - $add["samaccountname"] = $attributes["group_name"]; - $add["objectClass"] = "Group"; - $add["description"] = $attributes["description"]; - //$add["member"] = $member_array; UNTESTED - - $container="OU=".implode(",OU=",$attributes["container"]); - $result=ldap_add($this->_conn,"CN=".$add["cn"].", ".$container.",".$this->_base_dn,$add); - if ($result!=true){ return (false); } - - return (true); - } - - /** - * Remove a group from a group - * - * @param string $parent The parent group name - * @param string $child The child group name - * @return bool - */ - public function group_del_group($parent,$child){ - - // Find the parent dn - $parent_group=$this->group_info($parent,array("cn")); - if ($parent_group[0]["dn"]===NULL){ return (false); } - $parent_dn=$parent_group[0]["dn"]; - - // Find the child dn - $child_group=$this->group_info($child,array("cn")); - if ($child_group[0]["dn"]===NULL){ return (false); } - $child_dn=$child_group[0]["dn"]; - - $del=array(); - $del["member"] = $child_dn; - - $result=@ldap_mod_del($this->_conn,$parent_dn,$del); - if ($result==false){ return (false); } - return (true); - } - - /** - * Remove a user from a group - * - * @param string $group The group to remove a user from - * @param string $user The AD user to remove from the group - * @param bool $isGUID Is the username passed a GUID or a samAccountName - * @return bool - */ - public function group_del_user($group,$user,$isGUID=false){ - - // Find the parent dn - $group_info=$this->group_info($group,array("cn")); - if ($group_info[0]["dn"]===NULL){ return (false); } - $group_dn=$group_info[0]["dn"]; - - // Find the users dn - $user_dn=$this->user_dn($user,$isGUID); - if ($user_dn===false){ return (false); } - - $del=array(); - $del["member"] = $user_dn; - - $result=@ldap_mod_del($this->_conn,$group_dn,$del); - if ($result==false){ return (false); } - return (true); - } - - /** - * Remove a contact from a group - * - * @param string $group The group to remove a user from - * @param string $contact_dn The DN of a contact to remove from the group - * @return bool - */ - public function group_del_contact($group,$contact_dn){ - - // Find the parent dn - $group_info=$this->group_info($group,array("cn")); - if ($group_info[0]["dn"]===NULL){ return (false); } - $group_dn=$group_info[0]["dn"]; - - $del=array(); - $del["member"] = $contact_dn; - - $result=@ldap_mod_del($this->_conn,$group_dn,$del); - if ($result==false){ return (false); } - return (true); - } - - /** - * Return a list of groups in a group - * - * @param string $group The group to query - * @param bool $recursive Recursively get groups - * @return array - */ - public function groups_in_group($group, $recursive = NULL){ - if (!$this->_bind){ return (false); } - if ($recursive===NULL){ $recursive=$this->_recursive_groups; } // Use the default option if they haven't set it - - // Search the directory for the members of a group - $info=$this->group_info($group,array("member","cn")); - $groups=$info[0]["member"]; - if (!is_array($groups)) { - return (false); - } - - $group_array=array(); - - for ($i=0; $i<$groups["count"]; $i++){ - $filter="(&(objectCategory=group)(distinguishedName=".$this->ldap_slashes($groups[$i])."))"; - $fields = array("samaccountname", "distinguishedname", "objectClass"); - $sr=ldap_search($this->_conn,$this->_base_dn,$filter,$fields); - $entries = ldap_get_entries($this->_conn, $sr); - - // not a person, look for a group - if ($entries['count'] == 0 && $recursive == true) { - $filter="(&(objectCategory=group)(distinguishedName=".$this->ldap_slashes($groups[$i])."))"; - $fields = array("distinguishedname"); - $sr=ldap_search($this->_conn,$this->_base_dn,$filter,$fields); - $entries = ldap_get_entries($this->_conn, $sr); - if (!isset($entries[0]['distinguishedname'][0])) { - continue; - } - $sub_groups = $this->groups_in_group($entries[0]['distinguishedname'][0], $recursive); - if (is_array($sub_groups)) { - $group_array = array_merge($group_array, $sub_groups); - $group_array = array_unique($group_array); - } - continue; - } - - $group_array[] = $entries[0]['distinguishedname'][0]; - } - return ($group_array); - } - - /** - * Return a list of members in a group - * - * @param string $group The group to query - * @param bool $recursive Recursively get group members - * @return array - */ - public function group_members($group, $recursive = NULL){ - if (!$this->_bind){ return (false); } - if ($recursive===NULL){ $recursive=$this->_recursive_groups; } // Use the default option if they haven't set it - // Search the directory for the members of a group - $info=$this->group_info($group,array("member","cn")); - $users=$info[0]["member"]; - if (!is_array($users)) { - return (false); - } - - $user_array=array(); - - for ($i=0; $i<$users["count"]; $i++){ - $filter="(&(objectCategory=person)(distinguishedName=".$this->ldap_slashes($users[$i])."))"; - $fields = array("samaccountname", "distinguishedname", "objectClass"); - $sr=ldap_search($this->_conn,$this->_base_dn,$filter,$fields); - $entries = ldap_get_entries($this->_conn, $sr); - - // not a person, look for a group - if ($entries['count'] == 0 && $recursive == true) { - $filter="(&(objectCategory=group)(distinguishedName=".$this->ldap_slashes($users[$i])."))"; - $fields = array("samaccountname"); - $sr=ldap_search($this->_conn,$this->_base_dn,$filter,$fields); - $entries = ldap_get_entries($this->_conn, $sr); - if (!isset($entries[0]['samaccountname'][0])) { - continue; - } - $sub_users = $this->group_members($entries[0]['samaccountname'][0], $recursive); - if (is_array($sub_users)) { - $user_array = array_merge($user_array, $sub_users); - $user_array = array_unique($user_array); - } - continue; - } - - if ($entries[0]['samaccountname'][0] === NULL && $entries[0]['distinguishedname'][0] !== NULL) { - $user_array[] = $entries[0]['distinguishedname'][0]; - } - elseif ($entries[0]['samaccountname'][0] !== NULL) { - $user_array[] = $entries[0]['samaccountname'][0]; - } - } - return ($user_array); - } - - /** - * Group Information. Returns an array of information about a group. - * The group name is case sensitive - * - * @param string $group_name The group name to retrieve info about - * @param array $fields Fields to retrieve - * @return array - */ - public function group_info($group_name,$fields=NULL){ - if ($group_name===NULL){ return (false); } - if (!$this->_bind){ return (false); } - - if (stristr($group_name, '+')) { - $group_name=stripslashes($group_name); - } - - $filter="(&(objectCategory=group)(name=".$this->ldap_slashes($group_name)."))"; - //echo ($filter."!!!
"); - if ($fields===NULL){ $fields=array("member","memberof","cn","description","distinguishedname","objectcategory","samaccountname"); } - $sr=ldap_search($this->_conn,$this->_base_dn,$filter,$fields); - $entries = ldap_get_entries($this->_conn, $sr); - //print_r($entries); - return ($entries); - } - - /** - * Return a complete list of "groups in groups" - * - * @param string $group The group to get the list from - * @return array - */ - public function recursive_groups($group){ - if ($group===NULL){ return (false); } - - $ret_groups=array(); - - $groups=$this->group_info($group,array("memberof")); - if (isset($groups[0]["memberof"]) && is_array($groups[0]["memberof"])) { - $groups=$groups[0]["memberof"]; - - if ($groups){ - $group_names=$this->nice_names($groups); - $ret_groups=array_merge($ret_groups,$group_names); //final groups to return - - foreach ($group_names as $id => $group_name){ - $child_groups=$this->recursive_groups($group_name); - $ret_groups=array_merge($ret_groups,$child_groups); - } - } - } - - return ($ret_groups); - } - - /** - * Returns a complete list of the groups in AD based on a SAM Account Type - * - * @param string $samaccounttype The account type to return - * @param bool $include_desc Whether to return a description - * @param string $search Search parameters - * @param bool $sorted Whether to sort the results - * @return array - */ - public function search_groups($samaccounttype = ADLDAP_SECURITY_GLOBAL_GROUP, $include_desc = false, $search = "*", $sorted = true) { - if (!$this->_bind){ return (false); } - - $filter = '(&(objectCategory=group)'; - if ($samaccounttype !== null) { - $filter .= '(samaccounttype='. $samaccounttype .')'; - } - $filter .= '(cn='.$search.'))'; - // Perform the search and grab all their details - $fields=array("samaccountname","description"); - $sr=ldap_search($this->_conn,$this->_base_dn,$filter,$fields); - $entries = ldap_get_entries($this->_conn, $sr); - - $groups_array = array(); - for ($i=0; $i<$entries["count"]; $i++){ - if ($include_desc && strlen($entries[$i]["description"][0]) > 0 ){ - $groups_array[ $entries[$i]["samaccountname"][0] ] = $entries[$i]["description"][0]; - } elseif ($include_desc){ - $groups_array[ $entries[$i]["samaccountname"][0] ] = $entries[$i]["samaccountname"][0]; - } else { - array_push($groups_array, $entries[$i]["samaccountname"][0]); - } - } - if( $sorted ){ asort($groups_array); } - return ($groups_array); - } - - /** - * Returns a complete list of all groups in AD - * - * @param bool $include_desc Whether to return a description - * @param string $search Search parameters - * @param bool $sorted Whether to sort the results - * @return array - */ - public function all_groups($include_desc = false, $search = "*", $sorted = true){ - $groups_array = $this->search_groups(null, $include_desc, $search, $sorted); - return ($groups_array); - } - - /** - * Returns a complete list of security groups in AD - * - * @param bool $include_desc Whether to return a description - * @param string $search Search parameters - * @param bool $sorted Whether to sort the results - * @return array - */ - public function all_security_groups($include_desc = false, $search = "*", $sorted = true){ - $groups_array = $this->search_groups(ADLDAP_SECURITY_GLOBAL_GROUP, $include_desc, $search, $sorted); - return ($groups_array); - } - - /** - * Returns a complete list of distribution lists in AD - * - * @param bool $include_desc Whether to return a description - * @param string $search Search parameters - * @param bool $sorted Whether to sort the results - * @return array - */ - public function all_distribution_groups($include_desc = false, $search = "*", $sorted = true){ - $groups_array = $this->search_groups(ADLDAP_DISTRIBUTION_GROUP, $include_desc, $search, $sorted); - return ($groups_array); - } - - //***************************************************************************************************************** - // USER FUNCTIONS - - /** - * Create a user - * - * If you specify a password here, this can only be performed over SSL - * - * @param array $attributes The attributes to set to the user account - * @return bool - */ - public function user_create($attributes){ - // Check for compulsory fields - if (!array_key_exists("username",$attributes)){ return ("Missing compulsory field [username]"); } - if (!array_key_exists("firstname",$attributes)){ return ("Missing compulsory field [firstname]"); } - if (!array_key_exists("surname",$attributes)){ return ("Missing compulsory field [surname]"); } - if (!array_key_exists("email",$attributes)){ return ("Missing compulsory field [email]"); } - if (!array_key_exists("container",$attributes)){ return ("Missing compulsory field [container]"); } - if (!is_array($attributes["container"])){ return ("Container attribute must be an array."); } - - if (array_key_exists("password",$attributes) && (!$this->_use_ssl && !$this->_use_tls)){ - throw new adLDAPException('SSL must be configured on your webserver and enabled in the class to set passwords.'); - } - - if (!array_key_exists("display_name",$attributes)){ $attributes["display_name"]=$attributes["firstname"]." ".$attributes["surname"]; } - - // Translate the schema - $add=$this->adldap_schema($attributes); - - // Additional stuff only used for adding accounts - $add["cn"][0]=$attributes["display_name"]; - $add["samaccountname"][0]=$attributes["username"]; - $add["objectclass"][0]="top"; - $add["objectclass"][1]="person"; - $add["objectclass"][2]="organizationalPerson"; - $add["objectclass"][3]="user"; //person? - //$add["name"][0]=$attributes["firstname"]." ".$attributes["surname"]; - - // Set the account control attribute - $control_options=array("NORMAL_ACCOUNT"); - if (!$attributes["enabled"]){ $control_options[]="ACCOUNTDISABLE"; } - $add["userAccountControl"][0]=$this->account_control($control_options); - //echo ("
"); print_r($add);
-
-        // Determine the container
-        $attributes["container"]=array_reverse($attributes["container"]);
-        $container="OU=".implode(",OU=",$attributes["container"]);
-
-        // Add the entry
-        $result=@ldap_add($this->_conn, "CN=".$add["cn"][0].", ".$container.",".$this->_base_dn, $add);
-        if ($result!=true){ return (false); }
-
-        return (true);
-    }
-
-    /**
-    * Delete a user account
-    *
-    * @param string $username The username to delete (please be careful here!)
-    * @param bool $isGUID Is the username a GUID or a samAccountName
-    * @return array
-    */
-    public function user_delete($username,$isGUID=false) {
-        $userinfo = $this->user_info($username, array("*"),$isGUID);
-        $dn = $userinfo[0]['distinguishedname'][0];
-        $result=$this->dn_delete($dn);
-        if ($result!=true){ return (false); }
-        return (true);
-    }
-
-    /**
-    * Groups the user is a member of
-    *
-    * @param string $username The username to query
-    * @param bool $recursive Recursive list of groups
-    * @param bool $isGUID Is the username passed a GUID or a samAccountName
-    * @return array
-    */
-    public function user_groups($username,$recursive=NULL,$isGUID=false){
-        if ($username===NULL){ return (false); }
-        if ($recursive===NULL){ $recursive=$this->_recursive_groups; } // Use the default option if they haven't set it
-        if (!$this->_bind){ return (false); }
-
-        // Search the directory for their information
-        $info=@$this->user_info($username,array("memberof","primarygroupid"),$isGUID);
-        $groups=$this->nice_names($info[0]["memberof"]); // Presuming the entry returned is our guy (unique usernames)
-
-        if ($recursive === true){
-            foreach ($groups as $id => $group_name){
-                $extra_groups=$this->recursive_groups($group_name);
-                $groups=array_merge($groups,$extra_groups);
-            }
-        }
-
-        return ($groups);
-    }
-
-    /**
-    * Find information about the users
-    *
-    * @param string $username The username to query
-    * @param array $fields Array of parameters to query
-    * @param bool $isGUID Is the username passed a GUID or a samAccountName
-    * @return array
-    */
-    public function user_info($username,$fields=NULL,$isGUID=false){
-        if ($username===NULL){ return (false); }
-        if (!$this->_bind){ return (false); }
-
-        if ($isGUID === true) {
-            $username = $this->strguid2hex($username);
-            $filter="objectguid=".$username;
-        }
-        else if (strstr($username, "@")) {
-             $filter="userPrincipalName=".$username;
-        }
-        else {
-             $filter="samaccountname=".$username;
-        }
-        $filter = "(&(objectCategory=person)({$filter}))";
-        if ($fields===NULL){ $fields=array("samaccountname","mail","memberof","department","displayname","telephonenumber","primarygroupid","objectsid"); }
-        if (!in_array("objectsid",$fields)){
-            $fields[] = "objectsid";
-        }
-        $sr=ldap_search($this->_conn,$this->_base_dn,$filter,$fields);
-        $entries = ldap_get_entries($this->_conn, $sr);
-
-        if (isset($entries[0])) {
-            if ($entries[0]['count'] >= 1) {
-                if (in_array("memberof", $fields)) {
-                    // AD does not return the primary group in the ldap query, we may need to fudge it
-                    if ($this->_real_primarygroup && isset($entries[0]["primarygroupid"][0]) && isset($entries[0]["objectsid"][0])){
-                        //$entries[0]["memberof"][]=$this->group_cn($entries[0]["primarygroupid"][0]);
-                        $entries[0]["memberof"][]=$this->get_primary_group($entries[0]["primarygroupid"][0], $entries[0]["objectsid"][0]);
-                    } else {
-                        $entries[0]["memberof"][]="CN=Domain Users,CN=Users,".$this->_base_dn;
-                    }
-                    $entries[0]["memberof"]["count"]++;
-                }
-            }
-            return $entries;
-        }
-        return false;
-    }
-
-    /**
-    * Determine if a user is in a specific group
-    *
-    * @param string $username The username to query
-    * @param string $group The name of the group to check against
-    * @param bool $recursive Check groups recursively
-    * @param bool $isGUID Is the username passed a GUID or a samAccountName
-    * @return bool
-    */
-    public function user_ingroup($username,$group,$recursive=NULL,$isGUID=false){
-        if ($username===NULL){ return (false); }
-        if ($group===NULL){ return (false); }
-        if (!$this->_bind){ return (false); }
-        if ($recursive===NULL){ $recursive=$this->_recursive_groups; } // Use the default option if they haven't set it
-
-        // Get a list of the groups
-        $groups=$this->user_groups($username,$recursive,$isGUID);
-
-        // Return true if the specified group is in the group list
-        if (in_array($group,$groups)){ return (true); }
-
-        return (false);
-    }
-
-    /**
-     * Return info about the domain itself
-     *
-     * @authot Andreas Gohr 
-     * @param array $fields The fields to query
-     * @return array
-     */
-    public function domain_info($fields){
-        if (!$this->_bind){ return (false); }
-
-        $sr = ldap_read($this->_conn, $this->_base_dn, 'objectclass=*', $fields);
-        if (!$sr) {
-            return false;
-        }
-        $info = ldap_get_entries($this->_conn, $sr);
-        if(count($info)) return $info[0];
-
-        return false;
-    }
-
-    /**
-    * Determine a user's password expiry date
-    *
-    * @param string $username The username to query
-    * @param book $isGUID Is the username passed a GUID or a samAccountName
-    * @requires bcmath http://www.php.net/manual/en/book.bc.php
-    * @return array
-    */
-    public function user_password_expiry($username,$isGUID=false) {
-        if ($username===NULL){ return ("Missing compulsory field [username]"); }
-        if (!$this->_bind){ return (false); }
-        if (!function_exists('bcmod')) { return ("Missing function support [bcmod] http://www.php.net/manual/en/book.bc.php"); };
-
-        $userinfo = $this->user_info($username, array("pwdlastset", "useraccountcontrol"), $isGUID);
-        $pwdlastset = $userinfo[0]['pwdlastset'][0];
-        $status = array();
-
-        if ($userinfo[0]['useraccountcontrol'][0] == '66048') {
-            // Password does not expire
-            return "Does not expire";
-        }
-        if ($pwdlastset === '0') {
-            // Password has already expired
-            return "Password has expired";
-        }
-
-         // Password expiry in AD can be calculated from TWO values:
-         //   - User's own pwdLastSet attribute: stores the last time the password was changed
-         //   - Domain's maxPwdAge attribute: how long passwords last in the domain
-         //
-         // Although Microsoft chose to use a different base and unit for time measurements.
-         // This function will convert them to Unix timestamps
-         $sr = ldap_read($this->_conn, $this->_base_dn, 'objectclass=*', array('maxPwdAge'));
-         if (!$sr) {
-             return false;
-         }
-         $info = ldap_get_entries($this->_conn, $sr);
-         $maxpwdage = $info[0]['maxpwdage'][0];
-
-
-         // See MSDN: http://msdn.microsoft.com/en-us/library/ms974598.aspx
-         //
-         // pwdLastSet contains the number of 100 nanosecond intervals since January 1, 1601 (UTC),
-         // stored in a 64 bit integer.
-         //
-         // The number of seconds between this date and Unix epoch is 11644473600.
-         //
-         // maxPwdAge is stored as a large integer that represents the number of 100 nanosecond
-         // intervals from the time the password was set before the password expires.
-         //
-         // We also need to scale this to seconds but also this value is a _negative_ quantity!
-         //
-         // If the low 32 bits of maxPwdAge are equal to 0 passwords do not expire
-         //
-         // Unfortunately the maths involved are too big for PHP integers, so I've had to require
-         // BCMath functions to work with arbitrary precision numbers.
-         if (bcmod($maxpwdage, 4294967296) === '0') {
-            return "Domain does not expire passwords";
-        }
-
-        // Add maxpwdage and pwdlastset and we get password expiration time in Microsoft's
-        // time units.  Because maxpwd age is negative we need to subtract it.
-        $pwdexpire = bcsub($pwdlastset, $maxpwdage);
-
-        // Convert MS's time to Unix time
-        $status['expiryts'] = bcsub(bcdiv($pwdexpire, '10000000'), '11644473600');
-        $status['expiryformat'] = date('Y-m-d H:i:s', bcsub(bcdiv($pwdexpire, '10000000'), '11644473600'));
-
-        return $status;
-    }
-
-    /**
-    * Modify a user
-    *
-    * @param string $username The username to query
-    * @param array $attributes The attributes to modify.  Note if you set the enabled attribute you must not specify any other attributes
-    * @param bool $isGUID Is the username passed a GUID or a samAccountName
-    * @return bool
-    */
-    public function user_modify($username,$attributes,$isGUID=false){
-        if ($username===NULL){ return ("Missing compulsory field [username]"); }
-        if (array_key_exists("password",$attributes) && !$this->_use_ssl){
-            throw new adLDAPException('SSL must be configured on your webserver and enabled in the class to set passwords.');
-        }
-
-        // Find the dn of the user
-        $user_dn=$this->user_dn($username,$isGUID);
-        if ($user_dn===false){ return (false); }
-
-        // Translate the update to the LDAP schema
-        $mod=$this->adldap_schema($attributes);
-
-        // Check to see if this is an enabled status update
-        if (!$mod && !array_key_exists("enabled", $attributes)){ return (false); }
-
-        // Set the account control attribute (only if specified)
-        if (array_key_exists("enabled",$attributes)){
-            if ($attributes["enabled"]){ $control_options=array("NORMAL_ACCOUNT"); }
-            else { $control_options=array("NORMAL_ACCOUNT","ACCOUNTDISABLE"); }
-            $mod["userAccountControl"][0]=$this->account_control($control_options);
-        }
-
-        // Do the update
-        $result=@ldap_modify($this->_conn,$user_dn,$mod);
-        if ($result==false){ return (false); }
-
-        return (true);
-    }
-
-    /**
-    * Disable a user account
-    *
-    * @param string $username The username to disable
-    * @param bool $isGUID Is the username passed a GUID or a samAccountName
-    * @return bool
-    */
-    public function user_disable($username,$isGUID=false){
-        if ($username===NULL){ return ("Missing compulsory field [username]"); }
-        $attributes=array("enabled"=>0);
-        $result = $this->user_modify($username, $attributes, $isGUID);
-        if ($result==false){ return (false); }
-
-        return (true);
-    }
-
-    /**
-    * Enable a user account
-    *
-    * @param string $username The username to enable
-    * @param bool $isGUID Is the username passed a GUID or a samAccountName
-    * @return bool
-    */
-    public function user_enable($username,$isGUID=false){
-        if ($username===NULL){ return ("Missing compulsory field [username]"); }
-        $attributes=array("enabled"=>1);
-        $result = $this->user_modify($username, $attributes, $isGUID);
-        if ($result==false){ return (false); }
-
-        return (true);
-    }
-
-    /**
-    * Set the password of a user - This must be performed over SSL
-    *
-    * @param string $username The username to modify
-    * @param string $password The new password
-    * @param bool $isGUID Is the username passed a GUID or a samAccountName
-    * @return bool
-    */
-    public function user_password($username,$password,$isGUID=false){
-        if ($username===NULL){ return (false); }
-        if ($password===NULL){ return (false); }
-        if (!$this->_bind){ return (false); }
-        if (!$this->_use_ssl && !$this->_use_tls){
-            throw new adLDAPException('SSL must be configured on your webserver and enabled in the class to set passwords.');
-        }
-
-        $user_dn=$this->user_dn($username,$isGUID);
-        if ($user_dn===false){ return (false); }
-
-        $add=array();
-        $add["unicodePwd"][0]=$this->encode_password($password);
-
-        $result=@ldap_mod_replace($this->_conn,$user_dn,$add);
-        if ($result==false){
-            $err = ldap_errno($this->_conn);
-            if($err){
-                $msg = 'Error '.$err.': '.ldap_err2str($err).'.';
-                if($err == 53) $msg .= ' Your password might not match the password policy.';
-                throw new adLDAPException($msg);
-            }else{
-                return false;
-            }
-        }
-
-        return (true);
-    }
-
-    /**
-    * Return a list of all users in AD
-    *
-    * @param bool $include_desc Return a description of the user
-    * @param string $search Search parameter
-    * @param bool $sorted Sort the user accounts
-    * @return array
-    */
-    public function all_users($include_desc = false, $search = "*", $sorted = true){
-        if (!$this->_bind){ return (false); }
-
-        // Perform the search and grab all their details
-        $filter = "(&(objectClass=user)(samaccounttype=". ADLDAP_NORMAL_ACCOUNT .")(objectCategory=person)(cn=".$search."))";
-        $fields=array("samaccountname","displayname");
-        $sr=ldap_search($this->_conn,$this->_base_dn,$filter,$fields);
-        $entries = ldap_get_entries($this->_conn, $sr);
-
-        $users_array = array();
-        for ($i=0; $i<$entries["count"]; $i++){
-            if ($include_desc && strlen($entries[$i]["displayname"][0])>0){
-                $users_array[ $entries[$i]["samaccountname"][0] ] = $entries[$i]["displayname"][0];
-            } elseif ($include_desc){
-                $users_array[ $entries[$i]["samaccountname"][0] ] = $entries[$i]["samaccountname"][0];
-            } else {
-                array_push($users_array, $entries[$i]["samaccountname"][0]);
-            }
-        }
-        if ($sorted){ asort($users_array); }
-        return ($users_array);
-    }
-
-    /**
-    * Converts a username (samAccountName) to a GUID
-    *
-    * @param string $username The username to query
-    * @return string
-    */
-    public function username2guid($username) {
-        if (!$this->_bind){ return (false); }
-        if ($username === null){ return ("Missing compulsory field [username]"); }
-
-        $filter = "samaccountname=" . $username;
-        $fields = array("objectGUID");
-        $sr = @ldap_search($this->_conn, $this->_base_dn, $filter, $fields);
-        if (ldap_count_entries($this->_conn, $sr) > 0) {
-            $entry = @ldap_first_entry($this->_conn, $sr);
-            $guid = @ldap_get_values_len($this->_conn, $entry, 'objectGUID');
-            $strGUID = $this->binary2text($guid[0]);
-            return ($strGUID);
-        }
-        else {
-            return (false);
-        }
-    }
-
-    /**
-    * Move a user account to a different OU
-    *
-    * @param string $username The username to move (please be careful here!)
-    * @param array $container The container or containers to move the user to (please be careful here!).
-    * accepts containers in 1. parent 2. child order
-    * @return array
-    */
-    public function user_move($username, $container) {
-        if (!$this->_bind){ return (false); }
-        if ($username === null){ return ("Missing compulsory field [username]"); }
-        if ($container === null){ return ("Missing compulsory field [container]"); }
-        if (!is_array($container)){ return ("Container must be an array"); }
-
-        $userinfo = $this->user_info($username, array("*"));
-        $dn = $userinfo[0]['distinguishedname'][0];
-        $newrdn = "cn=" . $username;
-        $container = array_reverse($container);
-        $newcontainer = "ou=" . implode(",ou=",$container);
-        $newbasedn = strtolower($newcontainer) . "," . $this->_base_dn;
-        $result=@ldap_rename($this->_conn,$dn,$newrdn,$newbasedn,true);
-        if ($result !== true) {
-            return (false);
-        }
-        return (true);
-    }
-
-    //*****************************************************************************************************************
-    // CONTACT FUNCTIONS
-    // * Still work to do in this area, and new functions to write
-
-    /**
-    * Create a contact
-    *
-    * @param array $attributes The attributes to set to the contact
-    * @return bool
-    */
-    public function contact_create($attributes){
-        // Check for compulsory fields
-        if (!array_key_exists("display_name",$attributes)){ return ("Missing compulsory field [display_name]"); }
-        if (!array_key_exists("email",$attributes)){ return ("Missing compulsory field [email]"); }
-        if (!array_key_exists("container",$attributes)){ return ("Missing compulsory field [container]"); }
-        if (!is_array($attributes["container"])){ return ("Container attribute must be an array."); }
-
-        // Translate the schema
-        $add=$this->adldap_schema($attributes);
-
-        // Additional stuff only used for adding contacts
-        $add["cn"][0]=$attributes["display_name"];
-        $add["objectclass"][0]="top";
-        $add["objectclass"][1]="person";
-        $add["objectclass"][2]="organizationalPerson";
-        $add["objectclass"][3]="contact";
-        if (!isset($attributes['exchange_hidefromlists'])) {
-            $add["msExchHideFromAddressLists"][0]="TRUE";
-        }
-
-        // Determine the container
-        $attributes["container"]=array_reverse($attributes["container"]);
-        $container="OU=".implode(",OU=",$attributes["container"]);
-
-        // Add the entry
-        $result=@ldap_add($this->_conn, "CN=".$add["cn"][0].", ".$container.",".$this->_base_dn, $add);
-        if ($result!=true){ return (false); }
-
-        return (true);
-    }
-
-    /**
-    * Determine the list of groups a contact is a member of
-    *
-    * @param string $distinguisedname The full DN of a contact
-    * @param bool $recursive Recursively check groups
-    * @return array
-    */
-    public function contact_groups($distinguishedname,$recursive=NULL){
-        if ($distinguishedname===NULL){ return (false); }
-        if ($recursive===NULL){ $recursive=$this->_recursive_groups; } //use the default option if they haven't set it
-        if (!$this->_bind){ return (false); }
-
-        // Search the directory for their information
-        $info=@$this->contact_info($distinguishedname,array("memberof","primarygroupid"));
-        $groups=$this->nice_names($info[0]["memberof"]); //presuming the entry returned is our contact
-
-        if ($recursive === true){
-            foreach ($groups as $id => $group_name){
-                $extra_groups=$this->recursive_groups($group_name);
-                $groups=array_merge($groups,$extra_groups);
-            }
-        }
-
-        return ($groups);
-    }
-
-    /**
-    * Get contact information
-    *
-    * @param string $distinguisedname The full DN of a contact
-    * @param array $fields Attributes to be returned
-    * @return array
-    */
-    public function contact_info($distinguishedname,$fields=NULL){
-        if ($distinguishedname===NULL){ return (false); }
-        if (!$this->_bind){ return (false); }
-
-        $filter="distinguishedName=".$distinguishedname;
-        if ($fields===NULL){ $fields=array("distinguishedname","mail","memberof","department","displayname","telephonenumber","primarygroupid","objectsid"); }
-        $sr=ldap_search($this->_conn,$this->_base_dn,$filter,$fields);
-        $entries = ldap_get_entries($this->_conn, $sr);
-
-        if ($entries[0]['count'] >= 1) {
-            // AD does not return the primary group in the ldap query, we may need to fudge it
-            if ($this->_real_primarygroup && isset($entries[0]["primarygroupid"][0]) && isset($entries[0]["primarygroupid"][0])){
-                //$entries[0]["memberof"][]=$this->group_cn($entries[0]["primarygroupid"][0]);
-                $entries[0]["memberof"][]=$this->get_primary_group($entries[0]["primarygroupid"][0], $entries[0]["objectsid"][0]);
-            } else {
-                $entries[0]["memberof"][]="CN=Domain Users,CN=Users,".$this->_base_dn;
-            }
-        }
-
-        $entries[0]["memberof"]["count"]++;
-        return ($entries);
-    }
-
-    /**
-    * Determine if a contact is a member of a group
-    *
-    * @param string $distinguisedname The full DN of a contact
-    * @param string $group The group name to query
-    * @param bool $recursive Recursively check groups
-    * @return bool
-    */
-    public function contact_ingroup($distinguisedname,$group,$recursive=NULL){
-        if ($distinguisedname===NULL){ return (false); }
-        if ($group===NULL){ return (false); }
-        if (!$this->_bind){ return (false); }
-        if ($recursive===NULL){ $recursive=$this->_recursive_groups; } //use the default option if they haven't set it
-
-        // Get a list of the groups
-        $groups=$this->contact_groups($distinguisedname,array("memberof"),$recursive);
-
-        // Return true if the specified group is in the group list
-        if (in_array($group,$groups)){ return (true); }
-
-        return (false);
-    }
-
-    /**
-    * Modify a contact
-    *
-    * @param string $distinguishedname The contact to query
-    * @param array $attributes The attributes to modify.  Note if you set the enabled attribute you must not specify any other attributes
-    * @return bool
-    */
-    public function contact_modify($distinguishedname,$attributes){
-        if ($distinguishedname===NULL){ return ("Missing compulsory field [distinguishedname]"); }
-
-        // Translate the update to the LDAP schema
-        $mod=$this->adldap_schema($attributes);
-
-        // Check to see if this is an enabled status update
-        if (!$mod){ return (false); }
-
-        // Do the update
-        $result=ldap_modify($this->_conn,$distinguishedname,$mod);
-        if ($result==false){ return (false); }
-
-        return (true);
-    }
-
-    /**
-    * Delete a contact
-    *
-    * @param string $distinguishedname The contact dn to delete (please be careful here!)
-    * @return array
-    */
-    public function contact_delete($distinguishedname) {
-        $result = $this->dn_delete($distinguishedname);
-        if ($result!=true){ return (false); }
-        return (true);
-    }
-
-    /**
-    * Return a list of all contacts
-    *
-    * @param bool $include_desc Include a description of a contact
-    * @param string $search The search parameters
-    * @param bool $sorted Whether to sort the results
-    * @return array
-    */
-    public function all_contacts($include_desc = false, $search = "*", $sorted = true){
-        if (!$this->_bind){ return (false); }
-
-        // Perform the search and grab all their details
-        $filter = "(&(objectClass=contact)(cn=".$search."))";
-        $fields=array("displayname","distinguishedname");
-        $sr=ldap_search($this->_conn,$this->_base_dn,$filter,$fields);
-        $entries = ldap_get_entries($this->_conn, $sr);
-
-        $users_array = array();
-        for ($i=0; $i<$entries["count"]; $i++){
-            if ($include_desc && strlen($entries[$i]["displayname"][0])>0){
-                $users_array[ $entries[$i]["distinguishedname"][0] ] = $entries[$i]["displayname"][0];
-            } elseif ($include_desc){
-                $users_array[ $entries[$i]["distinguishedname"][0] ] = $entries[$i]["distinguishedname"][0];
-            } else {
-                array_push($users_array, $entries[$i]["distinguishedname"][0]);
-            }
-        }
-        if ($sorted){ asort($users_array); }
-        return ($users_array);
-    }
-
-    //*****************************************************************************************************************
-    // FOLDER FUNCTIONS
-
-    /**
-    * Returns a folder listing for a specific OU
-    * See http://adldap.sourceforge.net/wiki/doku.php?id=api_folder_functions
-    *
-    * @param array $folder_name An array to the OU you wish to list.
-    *                           If set to NULL will list the root, strongly recommended to set
-    *                           $recursive to false in that instance!
-    * @param string $dn_type The type of record to list.  This can be ADLDAP_FOLDER or ADLDAP_CONTAINER.
-    * @param bool $recursive Recursively search sub folders
-    * @param bool $type Specify a type of object to search for
-    * @return array
-    */
-    public function folder_list($folder_name = NULL, $dn_type = ADLDAP_FOLDER, $recursive = NULL, $type = NULL) {
-        if ($recursive===NULL){ $recursive=$this->_recursive_groups; } //use the default option if they haven't set it
-        if (!$this->_bind){ return (false); }
-
-        $filter = '(&';
-        if ($type !== NULL) {
-            switch ($type) {
-                case 'contact':
-                    $filter .= '(objectClass=contact)';
-                    break;
-                case 'computer':
-                    $filter .= '(objectClass=computer)';
-                    break;
-                case 'group':
-                    $filter .= '(objectClass=group)';
-                    break;
-                case 'folder':
-                    $filter .= '(objectClass=organizationalUnit)';
-                    break;
-                case 'container':
-                    $filter .= '(objectClass=container)';
-                    break;
-                case 'domain':
-                    $filter .= '(objectClass=builtinDomain)';
-                    break;
-                default:
-                    $filter .= '(objectClass=user)';
-                    break;
-            }
-        }
-        else {
-            $filter .= '(objectClass=*)';
-        }
-        // If the folder name is null then we will search the root level of AD
-        // This requires us to not have an OU= part, just the base_dn
-        $searchou = $this->_base_dn;
-        if (is_array($folder_name)) {
-            $ou = $dn_type . "=".implode("," . $dn_type . "=",$folder_name);
-            $filter .= '(!(distinguishedname=' . $ou . ',' . $this->_base_dn . ')))';
-            $searchou = $ou . ',' . $this->_base_dn;
-        }
-        else {
-            $filter .= '(!(distinguishedname=' . $this->_base_dn . ')))';
-        }
-
-        if ($recursive === true) {
-            $sr=ldap_search($this->_conn, $searchou, $filter, array('objectclass', 'distinguishedname', 'samaccountname'));
-            $entries = @ldap_get_entries($this->_conn, $sr);
-            if (is_array($entries)) {
-                return $entries;
-            }
-        }
-        else {
-            $sr=ldap_list($this->_conn, $searchou, $filter, array('objectclass', 'distinguishedname', 'samaccountname'));
-            $entries = @ldap_get_entries($this->_conn, $sr);
-            if (is_array($entries)) {
-                return $entries;
-            }
-        }
-
-        return false;
-    }
-
-    //*****************************************************************************************************************
-    // COMPUTER FUNCTIONS
-
-    /**
-    * Get information about a specific computer
-    *
-    * @param string $computer_name The name of the computer
-    * @param array $fields Attributes to return
-    * @return array
-    */
-    public function computer_info($computer_name,$fields=NULL){
-        if ($computer_name===NULL){ return (false); }
-        if (!$this->_bind){ return (false); }
-
-        $filter="(&(objectClass=computer)(cn=".$computer_name."))";
-        if ($fields===NULL){ $fields=array("memberof","cn","displayname","dnshostname","distinguishedname","objectcategory","operatingsystem","operatingsystemservicepack","operatingsystemversion"); }
-        $sr=ldap_search($this->_conn,$this->_base_dn,$filter,$fields);
-        $entries = ldap_get_entries($this->_conn, $sr);
-
-        return ($entries);
-    }
-
-    /**
-    * Check if a computer is in a group
-    *
-    * @param string $computer_name The name of the computer
-    * @param string $group The group to check
-    * @param bool $recursive Whether to check recursively
-    * @return array
-    */
-    public function computer_ingroup($computer_name,$group,$recursive=NULL){
-        if ($computer_name===NULL){ return (false); }
-        if ($group===NULL){ return (false); }
-        if (!$this->_bind){ return (false); }
-        if ($recursive===NULL){ $recursive=$this->_recursive_groups; } // use the default option if they haven't set it
-
-        //get a list of the groups
-        $groups=$this->computer_groups($computer_name,array("memberof"),$recursive);
-
-        //return true if the specified group is in the group list
-        if (in_array($group,$groups)){ return (true); }
-
-        return (false);
-    }
-
-    /**
-    * Get the groups a computer is in
-    *
-    * @param string $computer_name The name of the computer
-    * @param bool $recursive Whether to check recursively
-    * @return array
-    */
-    public function computer_groups($computer_name,$recursive=NULL){
-        if ($computer_name===NULL){ return (false); }
-        if ($recursive===NULL){ $recursive=$this->_recursive_groups; } //use the default option if they haven't set it
-        if (!$this->_bind){ return (false); }
-
-        //search the directory for their information
-        $info=@$this->computer_info($computer_name,array("memberof","primarygroupid"));
-        $groups=$this->nice_names($info[0]["memberof"]); //presuming the entry returned is our guy (unique usernames)
-
-        if ($recursive === true){
-            foreach ($groups as $id => $group_name){
-              $extra_groups=$this->recursive_groups($group_name);
-              $groups=array_merge($groups,$extra_groups);
-            }
-        }
-
-        return ($groups);
-    }
-
-    //************************************************************************************************************
-    //  ORGANIZATIONAL UNIT FUNCTIONS
-
-     /**
-    * Create an organizational unit
-    *
-    * @param array $attributes Default attributes of the ou
-    * @return bool
-    */
-    public function ou_create($attributes){
-        if (!is_array($attributes)){ return ("Attributes must be an array"); }
-        if (!array_key_exists("ou_name",$attributes)){ return ("Missing compulsory field [ou_name]"); }
-        if (!array_key_exists("container",$attributes)){ return ("Missing compulsory field [container]"); }
-        if (!is_array($attributes["container"])){ return ("Container attribute must be an array."); }
-        $attributes["container"]=array_reverse($attributes["container"]);
-
-        $add=array();
-        $add["objectClass"] = "organizationalUnit";
-
-        $container="OU=".implode(",OU=",$attributes["container"]);
-        $result=ldap_add($this->_conn,"CN=".$add["cn"].", ".$container.",".$this->_base_dn,$add);
-        if ($result!=true){ return (false); }
-
-        return (true);
-    }
-
-    //************************************************************************************************************
-    // EXCHANGE FUNCTIONS
-
-    /**
-    * Create an Exchange account
-    *
-    * @param string $username The username of the user to add the Exchange account to
-    * @param array $storagegroup The mailbox, Exchange Storage Group, for the user account, this must be a full CN
-    *                            If the storage group has a different base_dn to the adLDAP configuration, set it using $base_dn
-    * @param string $emailaddress The primary email address to add to this user
-    * @param string $mailnickname The mail nick name.  If mail nickname is blank, the username will be used
-    * @param bool $usedefaults Indicates whether the store should use the default quota, rather than the per-mailbox quota.
-    * @param string $base_dn Specify an alternative base_dn for the Exchange storage group
-    * @param bool $isGUID Is the username passed a GUID or a samAccountName
-    * @return bool
-    */
-    public function exchange_create_mailbox($username, $storagegroup, $emailaddress, $mailnickname=NULL, $usedefaults=TRUE, $base_dn=NULL, $isGUID=false){
-        if ($username===NULL){ return ("Missing compulsory field [username]"); }
-        if ($storagegroup===NULL){ return ("Missing compulsory array [storagegroup]"); }
-        if (!is_array($storagegroup)){ return ("[storagegroup] must be an array"); }
-        if ($emailaddress===NULL){ return ("Missing compulsory field [emailaddress]"); }
-
-        if ($base_dn===NULL) {
-            $base_dn = $this->_base_dn;
-        }
-
-        $container="CN=".implode(",CN=",$storagegroup);
-
-        if ($mailnickname===NULL) { $mailnickname=$username; }
-        $mdbUseDefaults = $this->bool2str($usedefaults);
-
-        $attributes = array(
-            'exchange_homemdb'=>$container.",".$base_dn,
-            'exchange_proxyaddress'=>'SMTP:' . $emailaddress,
-            'exchange_mailnickname'=>$mailnickname,
-            'exchange_usedefaults'=>$mdbUseDefaults
-        );
-        $result = $this->user_modify($username,$attributes,$isGUID);
-        if ($result==false){ return (false); }
-        return (true);
-    }
-
-    /**
-    * Add an X400 address to Exchange
-    * See http://tools.ietf.org/html/rfc1685 for more information.
-    * An X400 Address looks similar to this X400:c=US;a= ;p=Domain;o=Organization;s=Doe;g=John;
-    *
-    * @param string $username The username of the user to add the X400 to to
-    * @param string $country Country
-    * @param string $admd Administration Management Domain
-    * @param string $pdmd Private Management Domain (often your AD domain)
-    * @param string $org Organization
-    * @param string $surname Surname
-    * @param string $givenName Given name
-    * @param bool $isGUID Is the username passed a GUID or a samAccountName
-    * @return bool
-    */
-    public function exchange_add_X400($username, $country, $admd, $pdmd, $org, $surname, $givenname, $isGUID=false) {
-        if ($username===NULL){ return ("Missing compulsory field [username]"); }
-
-        $proxyvalue = 'X400:';
-
-        // Find the dn of the user
-        $user=$this->user_info($username,array("cn","proxyaddresses"), $isGUID);
-        if ($user[0]["dn"]===NULL){ return (false); }
-        $user_dn=$user[0]["dn"];
-
-        // We do not have to demote an email address from the default so we can just add the new proxy address
-        $attributes['exchange_proxyaddress'] = $proxyvalue . 'c=' . $country . ';a=' . $admd . ';p=' . $pdmd . ';o=' . $org . ';s=' . $surname . ';g=' . $givenname . ';';
-
-        // Translate the update to the LDAP schema
-        $add=$this->adldap_schema($attributes);
-
-        if (!$add){ return (false); }
-
-        // Do the update
-        // Take out the @ to see any errors, usually this error might occur because the address already
-        // exists in the list of proxyAddresses
-        $result=@ldap_mod_add($this->_conn,$user_dn,$add);
-        if ($result==false){ return (false); }
-
-        return (true);
-    }
-
-    /**
-    * Add an address to Exchange
-    *
-    * @param string $username The username of the user to add the Exchange account to
-    * @param string $emailaddress The email address to add to this user
-    * @param bool $default Make this email address the default address, this is a bit more intensive as we have to demote any existing default addresses
-    * @param bool $isGUID Is the username passed a GUID or a samAccountName
-    * @return bool
-    */
-    public function exchange_add_address($username, $emailaddress, $default=FALSE, $isGUID=false) {
-        if ($username===NULL){ return ("Missing compulsory field [username]"); }
-        if ($emailaddress===NULL) { return ("Missing compulsory fields [emailaddress]"); }
-
-        $proxyvalue = 'smtp:';
-        if ($default === true) {
-            $proxyvalue = 'SMTP:';
-        }
-
-        // Find the dn of the user
-        $user=$this->user_info($username,array("cn","proxyaddresses"),$isGUID);
-        if ($user[0]["dn"]===NULL){ return (false); }
-        $user_dn=$user[0]["dn"];
-
-        // We need to scan existing proxy addresses and demote the default one
-        if (is_array($user[0]["proxyaddresses"]) && $default===true) {
-            $modaddresses = array();
-            for ($i=0;$i_conn,$user_dn,$modaddresses);
-            if ($result==false){ return (false); }
-
-            return (true);
-        }
-        else {
-            // We do not have to demote an email address from the default so we can just add the new proxy address
-            $attributes['exchange_proxyaddress'] = $proxyvalue . $emailaddress;
-
-            // Translate the update to the LDAP schema
-            $add=$this->adldap_schema($attributes);
-
-            if (!$add){ return (false); }
-
-            // Do the update
-            // Take out the @ to see any errors, usually this error might occur because the address already
-            // exists in the list of proxyAddresses
-            $result=@ldap_mod_add($this->_conn,$user_dn,$add);
-            if ($result==false){ return (false); }
-
-            return (true);
-        }
-    }
-
-    /**
-    * Remove an address to Exchange
-    * If you remove a default address the account will no longer have a default,
-    * we recommend changing the default address first
-    *
-    * @param string $username The username of the user to add the Exchange account to
-    * @param string $emailaddress The email address to add to this user
-    * @param bool $isGUID Is the username passed a GUID or a samAccountName
-    * @return bool
-    */
-    public function exchange_del_address($username, $emailaddress, $isGUID=false) {
-        if ($username===NULL){ return ("Missing compulsory field [username]"); }
-        if ($emailaddress===NULL) { return ("Missing compulsory fields [emailaddress]"); }
-
-        // Find the dn of the user
-        $user=$this->user_info($username,array("cn","proxyaddresses"),$isGUID);
-        if ($user[0]["dn"]===NULL){ return (false); }
-        $user_dn=$user[0]["dn"];
-
-        if (is_array($user[0]["proxyaddresses"])) {
-            $mod = array();
-            for ($i=0;$i_conn,$user_dn,$mod);
-            if ($result==false){ return (false); }
-
-            return (true);
-        }
-        else {
-            return (false);
-        }
-    }
-    /**
-    * Change the default address
-    *
-    * @param string $username The username of the user to add the Exchange account to
-    * @param string $emailaddress The email address to make default
-    * @param bool $isGUID Is the username passed a GUID or a samAccountName
-    * @return bool
-    */
-    public function exchange_primary_address($username, $emailaddress, $isGUID=false) {
-        if ($username===NULL){ return ("Missing compulsory field [username]"); }
-        if ($emailaddress===NULL) { return ("Missing compulsory fields [emailaddress]"); }
-
-        // Find the dn of the user
-        $user=$this->user_info($username,array("cn","proxyaddresses"), $isGUID);
-        if ($user[0]["dn"]===NULL){ return (false); }
-        $user_dn=$user[0]["dn"];
-
-        if (is_array($user[0]["proxyaddresses"])) {
-            $modaddresses = array();
-            for ($i=0;$i_conn,$user_dn,$modaddresses);
-            if ($result==false){ return (false); }
-
-            return (true);
-        }
-
-    }
-
-    /**
-    * Mail enable a contact
-    * Allows email to be sent to them through Exchange
-    *
-    * @param string $distinguishedname The contact to mail enable
-    * @param string $emailaddress The email address to allow emails to be sent through
-    * @param string $mailnickname The mailnickname for the contact in Exchange.  If NULL this will be set to the display name
-    * @return bool
-    */
-    public function exchange_contact_mailenable($distinguishedname, $emailaddress, $mailnickname=NULL){
-        if ($distinguishedname===NULL){ return ("Missing compulsory field [distinguishedname]"); }
-        if ($emailaddress===NULL){ return ("Missing compulsory field [emailaddress]"); }
-
-        if ($mailnickname !== NULL) {
-            // Find the dn of the user
-            $user=$this->contact_info($distinguishedname,array("cn","displayname"));
-            if ($user[0]["displayname"]===NULL){ return (false); }
-            $mailnickname = $user[0]['displayname'][0];
-        }
-
-        $attributes = array("email"=>$emailaddress,"contact_email"=>"SMTP:" . $emailaddress,"exchange_proxyaddress"=>"SMTP:" . $emailaddress,"exchange_mailnickname"=>$mailnickname);
-
-        // Translate the update to the LDAP schema
-        $mod=$this->adldap_schema($attributes);
-
-        // Check to see if this is an enabled status update
-        if (!$mod){ return (false); }
-
-        // Do the update
-        $result=ldap_modify($this->_conn,$distinguishedname,$mod);
-        if ($result==false){ return (false); }
-
-        return (true);
-    }
-
-    /**
-    * Returns a list of Exchange Servers in the ConfigurationNamingContext of the domain
-    *
-    * @param array $attributes An array of the AD attributes you wish to return
-    * @return array
-    */
-    public function exchange_servers($attributes = array('cn','distinguishedname','serialnumber')) {
-        if (!$this->_bind){ return (false); }
-
-        $configurationNamingContext = $this->get_root_dse(array('configurationnamingcontext'));
-        $sr = @ldap_search($this->_conn,$configurationNamingContext[0]['configurationnamingcontext'][0],'(&(objectCategory=msExchExchangeServer))',$attributes);
-        $entries = @ldap_get_entries($this->_conn, $sr);
-        return $entries;
-    }
-
-    /**
-    * Returns a list of Storage Groups in Exchange for a given mail server
-    *
-    * @param string $exchangeServer The full DN of an Exchange server.  You can use exchange_servers() to find the DN for your server
-    * @param array $attributes An array of the AD attributes you wish to return
-    * @param bool $recursive If enabled this will automatically query the databases within a storage group
-    * @return array
-    */
-    public function exchange_storage_groups($exchangeServer, $attributes = array('cn','distinguishedname'), $recursive = NULL) {
-        if (!$this->_bind){ return (false); }
-        if ($exchangeServer===NULL){ return ("Missing compulsory field [exchangeServer]"); }
-        if ($recursive===NULL){ $recursive=$this->_recursive_groups; }
-
-        $filter = '(&(objectCategory=msExchStorageGroup))';
-        $sr=@ldap_search($this->_conn, $exchangeServer, $filter, $attributes);
-        $entries = @ldap_get_entries($this->_conn, $sr);
-
-        if ($recursive === true) {
-            for ($i=0; $i<$entries['count']; $i++) {
-                $entries[$i]['msexchprivatemdb'] = $this->exchange_storage_databases($entries[$i]['distinguishedname'][0]);
-            }
-        }
-
-        return $entries;
-    }
-
-    /**
-    * Returns a list of Databases within any given storage group in Exchange for a given mail server
-    *
-    * @param string $storageGroup The full DN of an Storage Group.  You can use exchange_storage_groups() to find the DN
-    * @param array $attributes An array of the AD attributes you wish to return
-    * @return array
-    */
-    public function exchange_storage_databases($storageGroup, $attributes = array('cn','distinguishedname','displayname')) {
-        if (!$this->_bind){ return (false); }
-        if ($storageGroup===NULL){ return ("Missing compulsory field [storageGroup]"); }
-
-        $filter = '(&(objectCategory=msExchPrivateMDB))';
-        $sr=@ldap_search($this->_conn, $storageGroup, $filter, $attributes);
-        $entries = @ldap_get_entries($this->_conn, $sr);
-        return $entries;
-    }
-
-    //************************************************************************************************************
-    // SERVER FUNCTIONS
-
-    /**
-    * Find the Base DN of your domain controller
-    *
-    * @return string
-    */
-    public function find_base_dn() {
-        $namingContext = $this->get_root_dse(array('defaultnamingcontext'));
-        return $namingContext[0]['defaultnamingcontext'][0];
-    }
-
-    /**
-    * Get the RootDSE properties from a domain controller
-    *
-    * @param array $attributes The attributes you wish to query e.g. defaultnamingcontext
-    * @return array
-    */
-    public function get_root_dse($attributes = array("*", "+")) {
-        if (!$this->_bind){ return (false); }
-
-        $sr = @ldap_read($this->_conn, NULL, 'objectClass=*', $attributes);
-        $entries = @ldap_get_entries($this->_conn, $sr);
-        return $entries;
-    }
-
-    //************************************************************************************************************
-    // UTILITY FUNCTIONS (Many of these functions are protected and can only be called from within the class)
-
-    /**
-    * Get last error from Active Directory
-    *
-    * This function gets the last message from Active Directory
-    * This may indeed be a 'Success' message but if you get an unknown error
-    * it might be worth calling this function to see what errors were raised
-    *
-    * return string
-    */
-    public function get_last_error() {
-        return @ldap_error($this->_conn);
-    }
-
-    /**
-    * Detect LDAP support in php
-    *
-    * @return bool
-    */
-    protected function ldap_supported() {
-        if (!function_exists('ldap_connect')) {
-            return (false);
-        }
-        return (true);
-    }
-
-    /**
-    * Schema
-    *
-    * @param array $attributes Attributes to be queried
-    * @return array
-    */
-    protected function adldap_schema($attributes){
-
-        // LDAP doesn't like NULL attributes, only set them if they have values
-        // If you wish to remove an attribute you should set it to a space
-        // TO DO: Adapt user_modify to use ldap_mod_delete to remove a NULL attribute
-        $mod=array();
-
-        // Check every attribute to see if it contains 8bit characters and then UTF8 encode them
-        array_walk($attributes, array($this, 'encode8bit'));
-
-        if ($attributes["address_city"]){ $mod["l"][0]=$attributes["address_city"]; }
-        if ($attributes["address_code"]){ $mod["postalCode"][0]=$attributes["address_code"]; }
-        //if ($attributes["address_country"]){ $mod["countryCode"][0]=$attributes["address_country"]; } // use country codes?
-        if ($attributes["address_country"]){ $mod["c"][0]=$attributes["address_country"]; }
-        if ($attributes["address_pobox"]){ $mod["postOfficeBox"][0]=$attributes["address_pobox"]; }
-        if ($attributes["address_state"]){ $mod["st"][0]=$attributes["address_state"]; }
-        if ($attributes["address_street"]){ $mod["streetAddress"][0]=$attributes["address_street"]; }
-        if ($attributes["company"]){ $mod["company"][0]=$attributes["company"]; }
-        if ($attributes["change_password"]){ $mod["pwdLastSet"][0]=0; }
-        if ($attributes["department"]){ $mod["department"][0]=$attributes["department"]; }
-        if ($attributes["description"]){ $mod["description"][0]=$attributes["description"]; }
-        if ($attributes["display_name"]){ $mod["displayName"][0]=$attributes["display_name"]; }
-        if ($attributes["email"]){ $mod["mail"][0]=$attributes["email"]; }
-        if ($attributes["expires"]){ $mod["accountExpires"][0]=$attributes["expires"]; } //unix epoch format?
-        if ($attributes["firstname"]){ $mod["givenName"][0]=$attributes["firstname"]; }
-        if ($attributes["home_directory"]){ $mod["homeDirectory"][0]=$attributes["home_directory"]; }
-        if ($attributes["home_drive"]){ $mod["homeDrive"][0]=$attributes["home_drive"]; }
-        if ($attributes["initials"]){ $mod["initials"][0]=$attributes["initials"]; }
-        if ($attributes["logon_name"]){ $mod["userPrincipalName"][0]=$attributes["logon_name"]; }
-        if ($attributes["manager"]){ $mod["manager"][0]=$attributes["manager"]; }  //UNTESTED ***Use DistinguishedName***
-        if ($attributes["office"]){ $mod["physicalDeliveryOfficeName"][0]=$attributes["office"]; }
-        if ($attributes["password"]){ $mod["unicodePwd"][0]=$this->encode_password($attributes["password"]); }
-        if ($attributes["profile_path"]){ $mod["profilepath"][0]=$attributes["profile_path"]; }
-        if ($attributes["script_path"]){ $mod["scriptPath"][0]=$attributes["script_path"]; }
-        if ($attributes["surname"]){ $mod["sn"][0]=$attributes["surname"]; }
-        if ($attributes["title"]){ $mod["title"][0]=$attributes["title"]; }
-        if ($attributes["telephone"]){ $mod["telephoneNumber"][0]=$attributes["telephone"]; }
-        if ($attributes["mobile"]){ $mod["mobile"][0]=$attributes["mobile"]; }
-        if ($attributes["pager"]){ $mod["pager"][0]=$attributes["pager"]; }
-        if ($attributes["ipphone"]){ $mod["ipphone"][0]=$attributes["ipphone"]; }
-        if ($attributes["web_page"]){ $mod["wWWHomePage"][0]=$attributes["web_page"]; }
-        if ($attributes["fax"]){ $mod["facsimileTelephoneNumber"][0]=$attributes["fax"]; }
-        if ($attributes["enabled"]){ $mod["userAccountControl"][0]=$attributes["enabled"]; }
-
-        // Distribution List specific schema
-        if ($attributes["group_sendpermission"]){ $mod["dlMemSubmitPerms"][0]=$attributes["group_sendpermission"]; }
-        if ($attributes["group_rejectpermission"]){ $mod["dlMemRejectPerms"][0]=$attributes["group_rejectpermission"]; }
-
-        // Exchange Schema
-        if ($attributes["exchange_homemdb"]){ $mod["homeMDB"][0]=$attributes["exchange_homemdb"]; }
-        if ($attributes["exchange_mailnickname"]){ $mod["mailNickname"][0]=$attributes["exchange_mailnickname"]; }
-        if ($attributes["exchange_proxyaddress"]){ $mod["proxyAddresses"][0]=$attributes["exchange_proxyaddress"]; }
-        if ($attributes["exchange_usedefaults"]){ $mod["mDBUseDefaults"][0]=$attributes["exchange_usedefaults"]; }
-        if ($attributes["exchange_policyexclude"]){ $mod["msExchPoliciesExcluded"][0]=$attributes["exchange_policyexclude"]; }
-        if ($attributes["exchange_policyinclude"]){ $mod["msExchPoliciesIncluded"][0]=$attributes["exchange_policyinclude"]; }
-        if ($attributes["exchange_addressbook"]){ $mod["showInAddressBook"][0]=$attributes["exchange_addressbook"]; }
-
-        // This schema is designed for contacts
-        if ($attributes["exchange_hidefromlists"]){ $mod["msExchHideFromAddressLists"][0]=$attributes["exchange_hidefromlists"]; }
-        if ($attributes["contact_email"]){ $mod["targetAddress"][0]=$attributes["contact_email"]; }
-
-        //echo ("
"); print_r($mod);
-        /*
-        // modifying a name is a bit fiddly
-        if ($attributes["firstname"] && $attributes["surname"]){
-            $mod["cn"][0]=$attributes["firstname"]." ".$attributes["surname"];
-            $mod["displayname"][0]=$attributes["firstname"]." ".$attributes["surname"];
-            $mod["name"][0]=$attributes["firstname"]." ".$attributes["surname"];
-        }
-        */
-
-        if (count($mod)==0){ return (false); }
-        return ($mod);
-    }
-
-    /**
-    * Coping with AD not returning the primary group
-    * http://support.microsoft.com/?kbid=321360
-    *
-    * For some reason it's not possible to search on primarygrouptoken=XXX
-    * If someone can show otherwise, I'd like to know about it :)
-    * this way is resource intensive and generally a pain in the @#%^
-    *
-    * @deprecated deprecated since version 3.1, see get get_primary_group
-    * @param string $gid Group ID
-    * @return string
-    */
-    protected function group_cn($gid){
-        if ($gid===NULL){ return (false); }
-        $r=false;
-
-        $filter="(&(objectCategory=group)(samaccounttype=". ADLDAP_SECURITY_GLOBAL_GROUP ."))";
-        $fields=array("primarygrouptoken","samaccountname","distinguishedname");
-        $sr=ldap_search($this->_conn,$this->_base_dn,$filter,$fields);
-        $entries = ldap_get_entries($this->_conn, $sr);
-
-        for ($i=0; $i<$entries["count"]; $i++){
-            if ($entries[$i]["primarygrouptoken"][0]==$gid){
-                $r=$entries[$i]["distinguishedname"][0];
-                $i=$entries["count"];
-            }
-        }
-
-        return ($r);
-    }
-
-    /**
-    * Coping with AD not returning the primary group
-    * http://support.microsoft.com/?kbid=321360
-    *
-    * This is a re-write based on code submitted by Bruce which prevents the
-    * need to search each security group to find the true primary group
-    *
-    * @param string $gid Group ID
-    * @param string $usersid User's Object SID
-    * @return string
-    */
-    protected function get_primary_group($gid, $usersid){
-        if ($gid===NULL || $usersid===NULL){ return (false); }
-        $r=false;
-
-        $gsid = substr_replace($usersid,pack('V',$gid),strlen($usersid)-4,4);
-        $filter='(objectsid='.$this->getTextSID($gsid).')';
-        $fields=array("samaccountname","distinguishedname");
-        $sr=ldap_search($this->_conn,$this->_base_dn,$filter,$fields);
-        $entries = ldap_get_entries($this->_conn, $sr);
-
-        return $entries[0]['distinguishedname'][0];
-     }
-
-    /**
-    * Convert a binary SID to a text SID
-    *
-    * @param string $binsid A Binary SID
-    * @return string
-    */
-     protected function getTextSID($binsid) {
-        $hex_sid = bin2hex($binsid);
-        $rev = hexdec(substr($hex_sid, 0, 2));
-        $subcount = hexdec(substr($hex_sid, 2, 2));
-        $auth = hexdec(substr($hex_sid, 4, 12));
-        $result = "$rev-$auth";
-
-        for ($x=0;$x < $subcount; $x++) {
-            $subauth[$x] =
-                hexdec($this->little_endian(substr($hex_sid, 16 + ($x * 8), 8)));
-                $result .= "-" . $subauth[$x];
-        }
-
-        // Cheat by tacking on the S-
-        return 'S-' . $result;
-     }
-
-    /**
-    * Converts a little-endian hex number to one that hexdec() can convert
-    *
-    * @param string $hex A hex code
-    * @return string
-    */
-     protected function little_endian($hex) {
-        $result = '';
-        for ($x = strlen($hex) - 2; $x >= 0; $x = $x - 2) {
-            $result .= substr($hex, $x, 2);
-        }
-        return $result;
-     }
-
-    /**
-    * Converts a binary attribute to a string
-    *
-    * @param string $bin A binary LDAP attribute
-    * @return string
-    */
-    protected function binary2text($bin) {
-        $hex_guid = bin2hex($bin);
-        $hex_guid_to_guid_str = '';
-        for($k = 1; $k <= 4; ++$k) {
-            $hex_guid_to_guid_str .= substr($hex_guid, 8 - 2 * $k, 2);
-        }
-        $hex_guid_to_guid_str .= '-';
-        for($k = 1; $k <= 2; ++$k) {
-            $hex_guid_to_guid_str .= substr($hex_guid, 12 - 2 * $k, 2);
-        }
-        $hex_guid_to_guid_str .= '-';
-        for($k = 1; $k <= 2; ++$k) {
-            $hex_guid_to_guid_str .= substr($hex_guid, 16 - 2 * $k, 2);
-        }
-        $hex_guid_to_guid_str .= '-' . substr($hex_guid, 16, 4);
-        $hex_guid_to_guid_str .= '-' . substr($hex_guid, 20);
-        return strtoupper($hex_guid_to_guid_str);
-    }
-
-    /**
-    * Converts a binary GUID to a string GUID
-    *
-    * @param string $binaryGuid The binary GUID attribute to convert
-    * @return string
-    */
-    public function decodeGuid($binaryGuid) {
-        if ($binaryGuid === null){ return ("Missing compulsory field [binaryGuid]"); }
-
-        $strGUID = $this->binary2text($binaryGuid);
-        return ($strGUID);
-    }
-
-    /**
-    * Converts a string GUID to a hexdecimal value so it can be queried
-    *
-    * @param string $strGUID A string representation of a GUID
-    * @return string
-    */
-    protected function strguid2hex($strGUID) {
-        $strGUID = str_replace('-', '', $strGUID);
-
-        $octet_str = '\\' . substr($strGUID, 6, 2);
-        $octet_str .= '\\' . substr($strGUID, 4, 2);
-        $octet_str .= '\\' . substr($strGUID, 2, 2);
-        $octet_str .= '\\' . substr($strGUID, 0, 2);
-        $octet_str .= '\\' . substr($strGUID, 10, 2);
-        $octet_str .= '\\' . substr($strGUID, 8, 2);
-        $octet_str .= '\\' . substr($strGUID, 14, 2);
-        $octet_str .= '\\' . substr($strGUID, 12, 2);
-        //$octet_str .= '\\' . substr($strGUID, 16, strlen($strGUID));
-        for ($i=16; $i<=(strlen($strGUID)-2); $i++) {
-            if (($i % 2) == 0) {
-                $octet_str .= '\\' . substr($strGUID, $i, 2);
-            }
-        }
-
-        return $octet_str;
-    }
-
-    /**
-    * Obtain the user's distinguished name based on their userid
-    *
-    *
-    * @param string $username The username
-    * @param bool $isGUID Is the username passed a GUID or a samAccountName
-    * @return string
-    */
-    protected function user_dn($username,$isGUID=false){
-        $user=$this->user_info($username,array("cn"),$isGUID);
-        if ($user[0]["dn"]===NULL){ return (false); }
-        $user_dn=$user[0]["dn"];
-        return ($user_dn);
-    }
-
-    /**
-    * Encode a password for transmission over LDAP
-    *
-    * @param string $password The password to encode
-    * @return string
-    */
-    protected function encode_password($password){
-        $password="\"".$password."\"";
-        $encoded="";
-        for ($i=0; $i 
-    * @return string
-    */
-    protected function ldap_slashes($str){
-        return preg_replace('/([\x00-\x1F\*\(\)\\\\])/e',
-                            '"\\\\\".join("",unpack("H2","$1"))',
-                            $str);
-    }
-
-    /**
-    * Select a random domain controller from your domain controller array
-    *
-    * @return string
-    */
-    protected function random_controller(){
-        mt_srand(doubleval(microtime()) * 100000000); // For older PHP versions
-        return ($this->_domain_controllers[array_rand($this->_domain_controllers)]);
-    }
-
-    /**
-    * Account control options
-    *
-    * @param array $options The options to convert to int
-    * @return int
-    */
-    protected function account_control($options){
-        $val=0;
-
-        if (is_array($options)){
-            if (in_array("SCRIPT",$options)){ $val=$val+1; }
-            if (in_array("ACCOUNTDISABLE",$options)){ $val=$val+2; }
-            if (in_array("HOMEDIR_REQUIRED",$options)){ $val=$val+8; }
-            if (in_array("LOCKOUT",$options)){ $val=$val+16; }
-            if (in_array("PASSWD_NOTREQD",$options)){ $val=$val+32; }
-            //PASSWD_CANT_CHANGE Note You cannot assign this permission by directly modifying the UserAccountControl attribute.
-            //For information about how to set the permission programmatically, see the "Property flag descriptions" section.
-            if (in_array("ENCRYPTED_TEXT_PWD_ALLOWED",$options)){ $val=$val+128; }
-            if (in_array("TEMP_DUPLICATE_ACCOUNT",$options)){ $val=$val+256; }
-            if (in_array("NORMAL_ACCOUNT",$options)){ $val=$val+512; }
-            if (in_array("INTERDOMAIN_TRUST_ACCOUNT",$options)){ $val=$val+2048; }
-            if (in_array("WORKSTATION_TRUST_ACCOUNT",$options)){ $val=$val+4096; }
-            if (in_array("SERVER_TRUST_ACCOUNT",$options)){ $val=$val+8192; }
-            if (in_array("DONT_EXPIRE_PASSWORD",$options)){ $val=$val+65536; }
-            if (in_array("MNS_LOGON_ACCOUNT",$options)){ $val=$val+131072; }
-            if (in_array("SMARTCARD_REQUIRED",$options)){ $val=$val+262144; }
-            if (in_array("TRUSTED_FOR_DELEGATION",$options)){ $val=$val+524288; }
-            if (in_array("NOT_DELEGATED",$options)){ $val=$val+1048576; }
-            if (in_array("USE_DES_KEY_ONLY",$options)){ $val=$val+2097152; }
-            if (in_array("DONT_REQ_PREAUTH",$options)){ $val=$val+4194304; }
-            if (in_array("PASSWORD_EXPIRED",$options)){ $val=$val+8388608; }
-            if (in_array("TRUSTED_TO_AUTH_FOR_DELEGATION",$options)){ $val=$val+16777216; }
-        }
-        return ($val);
-    }
-
-    /**
-    * Take an LDAP query and return the nice names, without all the LDAP prefixes (eg. CN, DN)
-    *
-    * @param array $groups
-    * @return array
-    */
-    protected function nice_names($groups){
-
-        $group_array=array();
-        for ($i=0; $i<$groups["count"]; $i++){ // For each group
-            $line=$groups[$i];
-
-            if (strlen($line)>0){
-                // More presumptions, they're all prefixed with CN=
-                // so we ditch the first three characters and the group
-                // name goes up to the first comma
-                $bits=explode(",",$line);
-                $group_array[]=substr($bits[0],3,(strlen($bits[0])-3));
-            }
-        }
-        return ($group_array);
-    }
-
-    /**
-    * Delete a distinguished name from Active Directory
-    * You should never need to call this yourself, just use the wrapper functions user_delete and contact_delete
-    *
-    * @param string $dn The distinguished name to delete
-    * @return bool
-    */
-    protected function dn_delete($dn){
-        $result=ldap_delete($this->_conn, $dn);
-        if ($result!=true){ return (false); }
-        return (true);
-    }
-
-    /**
-    * Convert a boolean value to a string
-    * You should never need to call this yourself
-    *
-    * @param bool $bool Boolean value
-    * @return string
-    */
-    protected function bool2str($bool) {
-        return ($bool) ? 'TRUE' : 'FALSE';
-    }
-
-    /**
-    * Convert 8bit characters e.g. accented characters to UTF8 encoded characters
-    */
-    protected function encode8bit(&$item, $key) {
-        $encode = false;
-        if (is_string($item)) {
-            for ($i=0; $i> 7) {
-                    $encode = true;
-                }
-            }
-        }
-        if ($encode === true && $key != 'password') {
-            $item = utf8_encode($item);
-        }
-    }
-}
-
-/**
-* adLDAP Exception Handler
-*
-* Exceptions of this type are thrown on bind failure or when SSL is required but not configured
-* Example:
-* try {
-*   $adldap = new adLDAP();
-* }
-* catch (adLDAPException $e) {
-*   echo $e;
-*   exit();
-* }
-*/
-class adLDAPException extends Exception {}
-
-?>
diff --git a/inc/adLDAP/adLDAP.php b/inc/adLDAP/adLDAP.php
new file mode 100644
index 000000000..a8f33b47e
--- /dev/null
+++ b/inc/adLDAP/adLDAP.php
@@ -0,0 +1,951 @@
+ldapConnection) {
+            return $this->ldapConnection;   
+        }
+        return false;
+    }
+    
+    /**
+    * Get the bind status
+    * 
+    * @return bool
+    */
+    public function getLdapBind() {
+        return $this->ldapBind;
+    }
+    
+    /**
+    * Get the current base DN
+    * 
+    * @return string
+    */
+    public function getBaseDn() {
+        return $this->baseDn;   
+    }
+    
+    /**
+    * The group class
+    * 
+    * @var adLDAPGroups
+    */
+    protected $groupClass;
+    
+    /**
+    * Get the group class interface
+    * 
+    * @return adLDAPGroups
+    */
+    public function group() {
+        if (!$this->groupClass) {
+            $this->groupClass = new adLDAPGroups($this);
+        }   
+        return $this->groupClass;
+    }
+    
+    /**
+    * The user class
+    * 
+    * @var adLDAPUsers
+    */
+    protected $userClass;
+    
+    /**
+    * Get the userclass interface
+    * 
+    * @return adLDAPUsers
+    */
+    public function user() {
+        if (!$this->userClass) {
+            $this->userClass = new adLDAPUsers($this);
+        }   
+        return $this->userClass;
+    }
+    
+    /**
+    * The folders class
+    * 
+    * @var adLDAPFolders
+    */
+    protected $folderClass;
+    
+    /**
+    * Get the folder class interface
+    * 
+    * @return adLDAPFolders
+    */
+    public function folder() {
+        if (!$this->folderClass) {
+            $this->folderClass = new adLDAPFolders($this);
+        }   
+        return $this->folderClass;
+    }
+    
+    /**
+    * The utils class
+    * 
+    * @var adLDAPUtils
+    */
+    protected $utilClass;
+    
+    /**
+    * Get the utils class interface
+    * 
+    * @return adLDAPUtils
+    */
+    public function utilities() {
+        if (!$this->utilClass) {
+            $this->utilClass = new adLDAPUtils($this);
+        }   
+        return $this->utilClass;
+    }
+    
+    /**
+    * The contacts class
+    * 
+    * @var adLDAPContacts
+    */
+    protected $contactClass;
+    
+    /**
+    * Get the contacts class interface
+    * 
+    * @return adLDAPContacts
+    */
+    public function contact() {
+        if (!$this->contactClass) {
+            $this->contactClass = new adLDAPContacts($this);
+        }   
+        return $this->contactClass;
+    }
+    
+    /**
+    * The exchange class
+    * 
+    * @var adLDAPExchange
+    */
+    protected $exchangeClass;
+    
+    /**
+    * Get the exchange class interface
+    * 
+    * @return adLDAPExchange
+    */
+    public function exchange() {
+        if (!$this->exchangeClass) {
+            $this->exchangeClass = new adLDAPExchange($this);
+        }   
+        return $this->exchangeClass;
+    }
+    
+    /**
+    * The computers class
+    * 
+    * @var adLDAPComputers
+    */
+    protected $computersClass;
+    
+    /**
+    * Get the computers class interface
+    * 
+    * @return adLDAPComputers
+    */
+    public function computer() {
+        if (!$this->computerClass) {
+            $this->computerClass = new adLDAPComputers($this);
+        }   
+        return $this->computerClass;
+    }
+
+    /**
+    * Getters and Setters
+    */
+    
+    /**
+    * Set the account suffix
+    * 
+    * @param string $accountSuffix
+    * @return void
+    */
+    public function setAccountSuffix($accountSuffix)
+    {
+          $this->accountSuffix = $accountSuffix;
+    }
+
+    /**
+    * Get the account suffix
+    * 
+    * @return string
+    */
+    public function getAccountSuffix()
+    {
+          return $this->accountSuffix;
+    }
+    
+    /**
+    * Set the domain controllers array
+    * 
+    * @param array $domainControllers
+    * @return void
+    */
+    public function setDomainControllers(array $domainControllers)
+    {
+          $this->domainControllers = $domainControllers;
+    }
+
+    /**
+    * Get the list of domain controllers
+    * 
+    * @return void
+    */
+    public function getDomainControllers()
+    {
+          return $this->domainControllers;
+    }
+    
+    /**
+    * Sets the port number your domain controller communicates over
+    * 
+    * @param int $adPort
+    */
+    public function setPort($adPort) 
+    { 
+        $this->adPort = $adPort; 
+    } 
+    
+    /**
+    * Gets the port number your domain controller communicates over
+    * 
+    * @return int
+    */
+    public function getPort() 
+    { 
+        return $this->adPort; 
+    } 
+    
+    /**
+    * Set the username of an account with higher priviledges
+    * 
+    * @param string $adminUsername
+    * @return void
+    */
+    public function setAdminUsername($adminUsername)
+    {
+          $this->adminUsername = $adminUsername;
+    }
+
+    /**
+    * Get the username of the account with higher priviledges
+    * 
+    * This will throw an exception for security reasons
+    */
+    public function getAdminUsername()
+    {
+          throw new adLDAPException('For security reasons you cannot access the domain administrator account details');
+    }
+    
+    /**
+    * Set the password of an account with higher priviledges
+    * 
+    * @param string $adminPassword
+    * @return void
+    */
+    public function setAdminPassword($adminPassword)
+    {
+          $this->adminPassword = $adminPassword;
+    }
+
+    /**
+    * Get the password of the account with higher priviledges
+    * 
+    * This will throw an exception for security reasons
+    */
+    public function getAdminPassword()
+    {
+          throw new adLDAPException('For security reasons you cannot access the domain administrator account details');
+    }
+    
+    /**
+    * Set whether to detect the true primary group
+    * 
+    * @param bool $realPrimaryGroup
+    * @return void
+    */
+    public function setRealPrimaryGroup($realPrimaryGroup)
+    {
+          $this->realPrimaryGroup = $realPrimaryGroup;
+    }
+
+    /**
+    * Get the real primary group setting
+    * 
+    * @return bool
+    */
+    public function getRealPrimaryGroup()
+    {
+          return $this->realPrimaryGroup;
+    }
+    
+    /**
+    * Set whether to use SSL
+    * 
+    * @param bool $useSSL
+    * @return void
+    */
+    public function setUseSSL($useSSL)
+    {
+          $this->useSSL = $useSSL;
+          // Set the default port correctly 
+          if($this->useSSL) { 
+            $this->setPort(self::ADLDAP_LDAPS_PORT); 
+          }
+          else { 
+            $this->setPort(self::ADLDAP_LDAP_PORT); 
+          } 
+    }
+
+    /**
+    * Get the SSL setting
+    * 
+    * @return bool
+    */
+    public function getUseSSL()
+    {
+          return $this->useSSL;
+    }
+    
+    /**
+    * Set whether to use TLS
+    * 
+    * @param bool $useTLS
+    * @return void
+    */
+    public function setUseTLS($useTLS)
+    {
+          $this->useTLS = $useTLS;
+    }
+
+    /**
+    * Get the TLS setting
+    * 
+    * @return bool
+    */
+    public function getUseTLS()
+    {
+          return $this->useTLS;
+    }
+    
+    /**
+    * Set whether to use SSO
+    * Requires ldap_sasl_bind support. Be sure --with-ldap-sasl is used when configuring PHP otherwise this function will be undefined. 
+    * 
+    * @param bool $useSSO
+    * @return void
+    */
+    public function setUseSSO($useSSO)
+    {
+          if ($useSSO === true && !$this->ldapSaslSupported()) {
+              throw new adLDAPException('No LDAP SASL support for PHP.  See: http://www.php.net/ldap_sasl_bind');
+          }
+          $this->useSSO = $useSSO;
+    }
+
+    /**
+    * Get the SSO setting
+    * 
+    * @return bool
+    */
+    public function getUseSSO()
+    {
+          return $this->useSSO;
+    }
+    
+    /**
+    * Set whether to lookup recursive groups
+    * 
+    * @param bool $recursiveGroups
+    * @return void
+    */
+    public function setRecursiveGroups($recursiveGroups)
+    {
+          $this->recursiveGroups = $recursiveGroups;
+    }
+
+    /**
+    * Get the recursive groups setting
+    * 
+    * @return bool
+    */
+    public function getRecursiveGroups()
+    {
+          return $this->recursiveGroups;
+    }
+
+    /**
+    * Default Constructor
+    * 
+    * Tries to bind to the AD domain over LDAP or LDAPs
+    * 
+    * @param array $options Array of options to pass to the constructor
+    * @throws Exception - if unable to bind to Domain Controller
+    * @return bool
+    */
+    function __construct($options = array()) {
+        // You can specifically overide any of the default configuration options setup above
+        if (count($options) > 0) {
+            if (array_key_exists("account_suffix",$options)){ $this->accountSuffix = $options["account_suffix"]; }
+            if (array_key_exists("base_dn",$options)){ $this->baseDn = $options["base_dn"]; }
+            if (array_key_exists("domain_controllers",$options)){ 
+                if (!is_array($options["domain_controllers"])) { 
+                    throw new adLDAPException('[domain_controllers] option must be an array');
+                }
+                $this->domainControllers = $options["domain_controllers"]; 
+            }
+            if (array_key_exists("admin_username",$options)){ $this->adminUsername = $options["admin_username"]; }
+            if (array_key_exists("admin_password",$options)){ $this->adminPassword = $options["admin_password"]; }
+            if (array_key_exists("real_primarygroup",$options)){ $this->realPrimaryGroup = $options["real_primarygroup"]; }
+            if (array_key_exists("use_ssl",$options)){ $this->setUseSSL($options["use_ssl"]); }
+            if (array_key_exists("use_tls",$options)){ $this->useTLS = $options["use_tls"]; }
+            if (array_key_exists("recursive_groups",$options)){ $this->recursiveGroups = $options["recursive_groups"]; }
+            if (array_key_exists("ad_port",$options)){ $this->setPort($options["ad_port"]); } 
+            if (array_key_exists("sso",$options)) { 
+                $this->setUseSSO($options["sso"]);
+                if (!$this->ldapSaslSupported()) {
+                    $this->setUseSSO(false);
+                }
+            } 
+        }
+        
+        if ($this->ldapSupported() === false) {
+            throw new adLDAPException('No LDAP support for PHP.  See: http://www.php.net/ldap');
+        }
+
+        return $this->connect();
+    }
+
+    /**
+    * Default Destructor
+    * 
+    * Closes the LDAP connection
+    * 
+    * @return void
+    */
+    function __destruct() { 
+        $this->close(); 
+    }
+
+    /**
+    * Connects and Binds to the Domain Controller
+    * 
+    * @return bool
+    */
+    public function connect() 
+    {
+        // Connect to the AD/LDAP server as the username/password
+        $domainController = $this->randomController();
+        if ($this->useSSL) {
+            $this->ldapConnection = ldap_connect("ldaps://" . $domainController, $this->adPort);
+        } else {
+            $this->ldapConnection = ldap_connect($domainController, $this->adPort);
+        }
+               
+        // Set some ldap options for talking to AD
+        ldap_set_option($this->ldapConnection, LDAP_OPT_PROTOCOL_VERSION, 3);
+        ldap_set_option($this->ldapConnection, LDAP_OPT_REFERRALS, 0);
+        
+        if ($this->useTLS) {
+            ldap_start_tls($this->ldapConnection);
+        }
+               
+        // Bind as a domain admin if they've set it up
+        if ($this->adminUsername !== NULL && $this->adminPassword !== NULL) {
+            $this->ldapBind = @ldap_bind($this->ldapConnection, $this->adminUsername . $this->accountSuffix, $this->adminPassword);
+            if (!$this->ldapBind) {
+                if ($this->useSSL && !$this->useTLS) {
+                    // If you have problems troubleshooting, remove the @ character from the ldapldapBind command above to get the actual error message
+                    throw new adLDAPException('Bind to Active Directory failed. Either the LDAPs connection failed or the login credentials are incorrect. AD said: ' . $this->getLastError());
+                }
+                else {
+                    throw new adLDAPException('Bind to Active Directory failed. Check the login credentials and/or server details. AD said: ' . $this->getLastError());
+                }
+            }
+        }
+        if ($this->useSSO && $_SERVER['REMOTE_USER'] && $this->adminUsername === null && $_SERVER['KRB5CCNAME']) {
+            putenv("KRB5CCNAME=" . $_SERVER['KRB5CCNAME']);  
+            $this->ldapBind = @ldap_sasl_bind($this->ldapConnection, NULL, NULL, "GSSAPI"); 
+            if (!$this->ldapBind){ 
+                throw new adLDAPException('Rebind to Active Directory failed. AD said: ' . $this->getLastError()); 
+            }
+            else {
+                return true;
+            }
+        }
+                
+        
+        if ($this->baseDn == NULL) {
+            $this->baseDn = $this->findBaseDn();   
+        }
+        
+        return true;
+    }
+    
+    /**
+    * Closes the LDAP connection
+    * 
+    * @return void
+    */
+    public function close() {
+        if ($this->ldapConnection) {
+            @ldap_close($this->ldapConnection);
+        }
+    }
+    
+    /**
+    * Validate a user's login credentials
+    * 
+    * @param string $username A user's AD username
+    * @param string $password A user's AD password
+    * @param bool optional $preventRebind
+    * @return bool
+    */
+    public function authenticate($username, $password, $preventRebind = false) {
+        // Prevent null binding
+        if ($username === NULL || $password === NULL) { return false; } 
+        if (empty($username) || empty($password)) { return false; }
+        
+        // Allow binding over SSO for Kerberos
+        if ($this->useSSO && $_SERVER['REMOTE_USER'] && $_SERVER['REMOTE_USER'] == $username && $this->adminUsername === NULL && $_SERVER['KRB5CCNAME']) { 
+            putenv("KRB5CCNAME=" . $_SERVER['KRB5CCNAME']);
+            $this->ldapBind = @ldap_sasl_bind($this->ldapConnection, NULL, NULL, "GSSAPI");
+            if (!$this->ldapBind) {
+                throw new adLDAPException('Rebind to Active Directory failed. AD said: ' . $this->getLastError());
+            }
+            else {
+                return true;
+            }
+        }
+        
+        // Bind as the user        
+        $ret = true;
+        $this->ldapBind = @ldap_bind($this->ldapConnection, $username . $this->accountSuffix, $password);
+        if (!$this->ldapBind){ 
+            $ret = false; 
+        }
+        
+        // Cnce we've checked their details, kick back into admin mode if we have it
+        if ($this->adminUsername !== NULL && !$preventRebind) {
+            $this->ldapBind = @ldap_bind($this->ldapConnection, $this->adminUsername . $this->accountSuffix , $this->adminPassword);
+            if (!$this->ldapBind){
+                // This should never happen in theory
+                throw new adLDAPException('Rebind to Active Directory failed. AD said: ' . $this->getLastError());
+            } 
+        } 
+        
+        return $ret;
+    }
+    
+    /**
+    * Find the Base DN of your domain controller
+    * 
+    * @return string
+    */
+    public function findBaseDn() 
+    {
+        $namingContext = $this->getRootDse(array('defaultnamingcontext'));   
+        return $namingContext[0]['defaultnamingcontext'][0];
+    }
+    
+    /**
+    * Get the RootDSE properties from a domain controller
+    * 
+    * @param array $attributes The attributes you wish to query e.g. defaultnamingcontext
+    * @return array
+    */
+    public function getRootDse($attributes = array("*", "+")) {
+        if (!$this->ldapBind){ return (false); }
+        
+        $sr = @ldap_read($this->ldapConnection, NULL, 'objectClass=*', $attributes);
+        $entries = @ldap_get_entries($this->ldapConnection, $sr);
+        return $entries;
+    }
+
+    /**
+    * Get last error from Active Directory
+    * 
+    * This function gets the last message from Active Directory
+    * This may indeed be a 'Success' message but if you get an unknown error
+    * it might be worth calling this function to see what errors were raised
+    * 
+    * return string
+    */
+    public function getLastError() {
+        return @ldap_error($this->ldapConnection);
+    }
+    
+    /**
+    * Detect LDAP support in php
+    * 
+    * @return bool
+    */    
+    protected function ldapSupported()
+    {
+        if (!function_exists('ldap_connect')) {
+            return false;   
+        }
+        return true;
+    }
+    
+    /**
+    * Detect ldap_sasl_bind support in PHP
+    * 
+    * @return bool
+    */
+    protected function ldapSaslSupported()
+    {
+        if (!function_exists('ldap_sasl_bind')) {
+            return false;
+        }
+        return true;
+    }
+    
+    /**
+    * Schema
+    * 
+    * @param array $attributes Attributes to be queried
+    * @return array
+    */    
+    public function adldap_schema($attributes){
+    
+        // LDAP doesn't like NULL attributes, only set them if they have values
+        // If you wish to remove an attribute you should set it to a space
+        // TO DO: Adapt user_modify to use ldap_mod_delete to remove a NULL attribute
+        $mod=array();
+        
+        // Check every attribute to see if it contains 8bit characters and then UTF8 encode them
+        array_walk($attributes, array($this, 'encode8bit'));
+
+        if ($attributes["address_city"]){ $mod["l"][0]=$attributes["address_city"]; }
+        if ($attributes["address_code"]){ $mod["postalCode"][0]=$attributes["address_code"]; }
+        //if ($attributes["address_country"]){ $mod["countryCode"][0]=$attributes["address_country"]; } // use country codes?
+        if ($attributes["address_country"]){ $mod["c"][0]=$attributes["address_country"]; }
+        if ($attributes["address_pobox"]){ $mod["postOfficeBox"][0]=$attributes["address_pobox"]; }
+        if ($attributes["address_state"]){ $mod["st"][0]=$attributes["address_state"]; }
+        if ($attributes["address_street"]){ $mod["streetAddress"][0]=$attributes["address_street"]; }
+        if ($attributes["company"]){ $mod["company"][0]=$attributes["company"]; }
+        if ($attributes["change_password"]){ $mod["pwdLastSet"][0]=0; }
+        if ($attributes["department"]){ $mod["department"][0]=$attributes["department"]; }
+        if ($attributes["description"]){ $mod["description"][0]=$attributes["description"]; }
+        if ($attributes["display_name"]){ $mod["displayName"][0]=$attributes["display_name"]; }
+        if ($attributes["email"]){ $mod["mail"][0]=$attributes["email"]; }
+        if ($attributes["expires"]){ $mod["accountExpires"][0]=$attributes["expires"]; } //unix epoch format?
+        if ($attributes["firstname"]){ $mod["givenName"][0]=$attributes["firstname"]; }
+        if ($attributes["home_directory"]){ $mod["homeDirectory"][0]=$attributes["home_directory"]; }
+        if ($attributes["home_drive"]){ $mod["homeDrive"][0]=$attributes["home_drive"]; }
+        if ($attributes["initials"]){ $mod["initials"][0]=$attributes["initials"]; }
+        if ($attributes["logon_name"]){ $mod["userPrincipalName"][0]=$attributes["logon_name"]; }
+        if ($attributes["manager"]){ $mod["manager"][0]=$attributes["manager"]; }  //UNTESTED ***Use DistinguishedName***
+        if ($attributes["office"]){ $mod["physicalDeliveryOfficeName"][0]=$attributes["office"]; }
+        if ($attributes["password"]){ $mod["unicodePwd"][0]=$this->user()->encodePassword($attributes["password"]); }
+        if ($attributes["profile_path"]){ $mod["profilepath"][0]=$attributes["profile_path"]; }
+        if ($attributes["script_path"]){ $mod["scriptPath"][0]=$attributes["script_path"]; }
+        if ($attributes["surname"]){ $mod["sn"][0]=$attributes["surname"]; }
+        if ($attributes["title"]){ $mod["title"][0]=$attributes["title"]; }
+        if ($attributes["telephone"]){ $mod["telephoneNumber"][0]=$attributes["telephone"]; }
+        if ($attributes["mobile"]){ $mod["mobile"][0]=$attributes["mobile"]; }
+        if ($attributes["pager"]){ $mod["pager"][0]=$attributes["pager"]; }
+        if ($attributes["ipphone"]){ $mod["ipphone"][0]=$attributes["ipphone"]; }
+        if ($attributes["web_page"]){ $mod["wWWHomePage"][0]=$attributes["web_page"]; }
+        if ($attributes["fax"]){ $mod["facsimileTelephoneNumber"][0]=$attributes["fax"]; }
+        if ($attributes["enabled"]){ $mod["userAccountControl"][0]=$attributes["enabled"]; }
+        if ($attributes["homephone"]){ $mod["homephone"][0]=$attributes["homephone"]; }
+        
+        // Distribution List specific schema
+        if ($attributes["group_sendpermission"]){ $mod["dlMemSubmitPerms"][0]=$attributes["group_sendpermission"]; }
+        if ($attributes["group_rejectpermission"]){ $mod["dlMemRejectPerms"][0]=$attributes["group_rejectpermission"]; }
+        
+        // Exchange Schema
+        if ($attributes["exchange_homemdb"]){ $mod["homeMDB"][0]=$attributes["exchange_homemdb"]; }
+        if ($attributes["exchange_mailnickname"]){ $mod["mailNickname"][0]=$attributes["exchange_mailnickname"]; }
+        if ($attributes["exchange_proxyaddress"]){ $mod["proxyAddresses"][0]=$attributes["exchange_proxyaddress"]; }
+        if ($attributes["exchange_usedefaults"]){ $mod["mDBUseDefaults"][0]=$attributes["exchange_usedefaults"]; }
+        if ($attributes["exchange_policyexclude"]){ $mod["msExchPoliciesExcluded"][0]=$attributes["exchange_policyexclude"]; }
+        if ($attributes["exchange_policyinclude"]){ $mod["msExchPoliciesIncluded"][0]=$attributes["exchange_policyinclude"]; }       
+        if ($attributes["exchange_addressbook"]){ $mod["showInAddressBook"][0]=$attributes["exchange_addressbook"]; }    
+        if ($attributes["exchange_altrecipient"]){ $mod["altRecipient"][0]=$attributes["exchange_altrecipient"]; } 
+        if ($attributes["exchange_deliverandredirect"]){ $mod["deliverAndRedirect"][0]=$attributes["exchange_deliverandredirect"]; }    
+        
+        // This schema is designed for contacts
+        if ($attributes["exchange_hidefromlists"]){ $mod["msExchHideFromAddressLists"][0]=$attributes["exchange_hidefromlists"]; }
+        if ($attributes["contact_email"]){ $mod["targetAddress"][0]=$attributes["contact_email"]; }
+        
+        //echo ("
"); print_r($mod);
+        /*
+        // modifying a name is a bit fiddly
+        if ($attributes["firstname"] && $attributes["surname"]){
+            $mod["cn"][0]=$attributes["firstname"]." ".$attributes["surname"];
+            $mod["displayname"][0]=$attributes["firstname"]." ".$attributes["surname"];
+            $mod["name"][0]=$attributes["firstname"]." ".$attributes["surname"];
+        }
+        */
+
+        if (count($mod)==0){ return (false); }
+        return ($mod);
+    }
+    
+    /**
+    * Convert 8bit characters e.g. accented characters to UTF8 encoded characters
+    */
+    protected function encode8Bit(&$item, $key) {
+        $encode = false;
+        if (is_string($item)) {
+            for ($i=0; $i> 7) {
+                    $encode = true;
+                }
+            }
+        }
+        if ($encode === true && $key != 'password') {
+            $item = utf8_encode($item);   
+        }
+    }
+    
+    /**
+    * Select a random domain controller from your domain controller array
+    * 
+    * @return string
+    */
+    protected function randomController() 
+    {
+        mt_srand(doubleval(microtime()) * 100000000); // For older PHP versions
+        /*if (sizeof($this->domainControllers) > 1) {
+            $adController = $this->domainControllers[array_rand($this->domainControllers)]; 
+            // Test if the controller is responding to pings
+            $ping = $this->pingController($adController); 
+            if ($ping === false) { 
+                // Find the current key in the domain controllers array
+                $key = array_search($adController, $this->domainControllers);
+                // Remove it so that we don't end up in a recursive loop
+                unset($this->domainControllers[$key]);
+                // Select a new controller
+                return $this->randomController(); 
+            }
+            else { 
+                return ($adController); 
+            }
+        } */
+        return $this->domainControllers[array_rand($this->domainControllers)];
+    }  
+    
+    /** 
+    * Test basic connectivity to controller 
+    * 
+    * @return bool
+    */ 
+    protected function pingController($host) {
+        $port = $this->adPort; 
+        fsockopen($host, $port, $errno, $errstr, 10); 
+        if ($errno > 0) {
+            return false;
+        }
+        return true;
+    }
+
+}
+
+/**
+* adLDAP Exception Handler
+* 
+* Exceptions of this type are thrown on bind failure or when SSL is required but not configured
+* Example:
+* try {
+*   $adldap = new adLDAP();
+* }
+* catch (adLDAPException $e) {
+*   echo $e;
+*   exit();
+* }
+*/
+class adLDAPException extends Exception {}
+
+?>
\ No newline at end of file
diff --git a/inc/adLDAP/classes/adLDAPComputers.php b/inc/adLDAP/classes/adLDAPComputers.php
new file mode 100644
index 000000000..71b24a04f
--- /dev/null
+++ b/inc/adLDAP/classes/adLDAPComputers.php
@@ -0,0 +1,153 @@
+adldap = $adldap;
+    }
+    
+    /**
+    * Get information about a specific computer. Returned in a raw array format from AD
+    * 
+    * @param string $computerName The name of the computer
+    * @param array $fields Attributes to return
+    * @return array
+    */
+    public function info($computerName, $fields = NULL)
+    {
+        if ($computerName === NULL) { return false; }
+        if (!$this->adldap->getLdapBind()) { return false; }
+
+        $filter = "(&(objectClass=computer)(cn=" . $computerName . "))";
+        if ($fields === NULL) { 
+            $fields = array("memberof","cn","displayname","dnshostname","distinguishedname","objectcategory","operatingsystem","operatingsystemservicepack","operatingsystemversion"); 
+        }
+        $sr = ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields);
+        $entries = ldap_get_entries($this->adldap->getLdapConnection(), $sr);
+        
+        return $entries;
+    }
+    
+    /**
+    * Find information about the computers. Returned in a raw array format from AD
+    * 
+    * @param string $computerName The name of the computer
+    * @param array $fields Array of parameters to query
+    * @return mixed
+    */
+    public function infoCollection($computerName, $fields = NULL)
+    {
+        if ($computerName === NULL) { return false; }
+        if (!$this->adldap->getLdapBind()) { return false; }
+        
+        $info = $this->info($computerName, $fields);
+        
+        if ($info !== false) {
+            $collection = new adLDAPComputerCollection($info, $this->adldap);
+            return $collection;
+        }
+        return false;
+    }
+    
+    /**
+    * Check if a computer is in a group
+    * 
+    * @param string $computerName The name of the computer
+    * @param string $group The group to check
+    * @param bool $recursive Whether to check recursively
+    * @return array
+    */
+    public function inGroup($computerName, $group, $recursive = NULL)
+    {
+        if ($computerName === NULL) { return false; }
+        if ($group === NULL) { return false; }
+        if (!$this->adldap->getLdapBind()) { return false; }
+        if ($recursive === NULL) { $recursive = $this->adldap->getRecursiveGroups(); } // use the default option if they haven't set it
+
+        //get a list of the groups
+        $groups = $this->groups($computerName, array("memberof"), $recursive);
+
+        //return true if the specified group is in the group list
+        if (in_array($group, $groups)){ 
+            return true; 
+        }
+
+        return false;
+    }
+    
+    /**
+    * Get the groups a computer is in
+    * 
+    * @param string $computerName The name of the computer
+    * @param bool $recursive Whether to check recursively
+    * @return array
+    */
+    public function groups($computerName, $recursive = NULL)
+    {
+        if ($computerName === NULL) { return false; }
+        if ($recursive === NULL) { $recursive = $this->adldap->getRecursiveGroups(); } //use the default option if they haven't set it
+        if (!$this->adldap->getLdapBind()){ return false; }
+
+        //search the directory for their information
+        $info = @$this->info($computerName, array("memberof", "primarygroupid"));
+        $groups = $this->adldap->utilities()->niceNames($info[0]["memberof"]); //presuming the entry returned is our guy (unique usernames)
+
+        if ($recursive === true) {
+            foreach ($groups as $id => $groupName){
+              $extraGroups = $this->adldap->group()->recursiveGroups($groupName);
+              $groups = array_merge($groups, $extraGroups);
+            }
+        }
+
+        return $groups;
+    }
+    
+}
+?>
\ No newline at end of file
diff --git a/inc/adLDAP/classes/adLDAPContacts.php b/inc/adLDAP/classes/adLDAPContacts.php
new file mode 100644
index 000000000..addd3e5f0
--- /dev/null
+++ b/inc/adLDAP/classes/adLDAPContacts.php
@@ -0,0 +1,294 @@
+adldap = $adldap;
+    }
+    
+    //*****************************************************************************************************************
+    // CONTACT FUNCTIONS
+    // * Still work to do in this area, and new functions to write
+    
+    /**
+    * Create a contact
+    * 
+    * @param array $attributes The attributes to set to the contact
+    * @return bool
+    */
+    public function create($attributes)
+    {
+        // Check for compulsory fields
+        if (!array_key_exists("display_name", $attributes)) { return "Missing compulsory field [display_name]"; }
+        if (!array_key_exists("email", $attributes)) { return "Missing compulsory field [email]"; }
+        if (!array_key_exists("container", $attributes)) { return "Missing compulsory field [container]"; }
+        if (!is_array($attributes["container"])) { return "Container attribute must be an array."; }
+
+        // Translate the schema
+        $add = $this->adldap->adldap_schema($attributes);
+        
+        // Additional stuff only used for adding contacts
+        $add["cn"][0] = $attributes["display_name"];
+        $add["objectclass"][0] = "top";
+        $add["objectclass"][1] = "person";
+        $add["objectclass"][2] = "organizationalPerson";
+        $add["objectclass"][3] = "contact"; 
+        if (!isset($attributes['exchange_hidefromlists'])) {
+            $add["msExchHideFromAddressLists"][0] = "TRUE";
+        }
+
+        // Determine the container
+        $attributes["container"] = array_reverse($attributes["container"]);
+        $container= "OU=" . implode(",OU=", $attributes["container"]);
+
+        // Add the entry
+        $result = @ldap_add($this->adldap->getLdapConnection(), "CN=" . $this->adldap->utilities()->escapeCharacters($add["cn"][0]) . ", " . $container . "," . $this->adldap->getBaseDn(), $add);
+        if ($result != true) { 
+            return false; 
+        }
+        
+        return true;
+    }  
+    
+    /**
+    * Determine the list of groups a contact is a member of
+    * 
+    * @param string $distinguisedname The full DN of a contact
+    * @param bool $recursive Recursively check groups
+    * @return array
+    */
+    public function groups($distinguishedName, $recursive = NULL)
+    {
+        if ($distinguishedName === NULL) { return false; }
+        if ($recursive === NULL) { $recursive = $this->adldap->getRecursiveGroups(); } //use the default option if they haven't set it
+        if (!$this->adldap->getLdapBind()){ return false; }
+        
+        // Search the directory for their information
+        $info = @$this->info($distinguishedName, array("memberof", "primarygroupid"));
+        $groups = $this->adldap->utilities()->niceNames($info[0]["memberof"]); //presuming the entry returned is our contact
+
+        if ($recursive === true){
+            foreach ($groups as $id => $groupName){
+                $extraGroups = $this->adldap->group()->recursiveGroups($groupName);
+                $groups = array_merge($groups, $extraGroups);
+            }
+        }
+        
+        return $groups;
+    }
+    
+    /**
+    * Get contact information. Returned in a raw array format from AD
+    * 
+    * @param string $distinguisedname The full DN of a contact
+    * @param array $fields Attributes to be returned
+    * @return array
+    */
+    public function info($distinguishedName, $fields = NULL)
+    {
+        if ($distinguishedName === NULL) { return false; }
+        if (!$this->adldap->getLdapBind()) { return false; }
+
+        $filter = "distinguishedName=" . $distinguishedName;
+        if ($fields === NULL) { 
+            $fields = array("distinguishedname", "mail", "memberof", "department", "displayname", "telephonenumber", "primarygroupid", "objectsid"); 
+        }
+        $sr = ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields);
+        $entries = ldap_get_entries($this->adldap->getLdapConnection(), $sr);
+        
+        if ($entries[0]['count'] >= 1) {
+            // AD does not return the primary group in the ldap query, we may need to fudge it
+            if ($this->adldap->getRealPrimaryGroup() && isset($entries[0]["primarygroupid"][0]) && isset($entries[0]["primarygroupid"][0])){
+                //$entries[0]["memberof"][]=$this->group_cn($entries[0]["primarygroupid"][0]);
+                $entries[0]["memberof"][] = $this->adldap->group()->getPrimaryGroup($entries[0]["primarygroupid"][0], $entries[0]["objectsid"][0]);
+            } else {
+                $entries[0]["memberof"][] = "CN=Domain Users,CN=Users," . $this->adldap->getBaseDn();
+            }
+        }
+        
+        $entries[0]["memberof"]["count"]++;
+        return $entries;
+    }
+    
+    /**
+    * Find information about the contacts. Returned in a raw array format from AD
+    * 
+    * @param string $distinguishedName The full DN of a contact 
+    * @param array $fields Array of parameters to query
+    * @return mixed
+    */
+    public function infoCollection($distinguishedName, $fields = NULL)
+    {
+        if ($distinguishedName === NULL) { return false; }
+        if (!$this->adldap->getLdapBind()) { return false; }
+        
+        $info = $this->info($distinguishedName, $fields);
+        
+        if ($info !== false) {
+            $collection = new adLDAPContactCollection($info, $this->adldap);
+            return $collection;
+        }
+        return false;
+    }
+    
+    /**
+    * Determine if a contact is a member of a group
+    * 
+    * @param string $distinguisedName The full DN of a contact
+    * @param string $group The group name to query
+    * @param bool $recursive Recursively check groups
+    * @return bool
+    */
+    public function inGroup($distinguisedName, $group, $recursive = NULL)
+    {
+        if ($distinguisedName === NULL) { return false; }
+        if ($group === NULL) { return false; }
+        if (!$this->adldap->getLdapBind()) { return false; }
+        if ($recursive === NULL) { $recursive = $this->adldap->getRecursiveGroups(); } //use the default option if they haven't set it
+        
+        // Get a list of the groups
+        $groups = $this->groups($distinguisedName, array("memberof"), $recursive);
+        
+        // Return true if the specified group is in the group list
+        if (in_array($group, $groups)){ 
+            return true; 
+        }
+
+        return false;
+    }          
+    
+    /**
+    * Modify a contact
+    * 
+    * @param string $distinguishedName The contact to query
+    * @param array $attributes The attributes to modify.  Note if you set the enabled attribute you must not specify any other attributes
+    * @return bool
+    */
+    public function modify($distinguishedName, $attributes) {
+        if ($distinguishedName === NULL) { return "Missing compulsory field [distinguishedname]"; }
+        
+        // Translate the update to the LDAP schema                
+        $mod = $this->adldap->adldap_schema($attributes);
+        
+        // Check to see if this is an enabled status update
+        if (!$mod) { 
+            return false; 
+        }
+        
+        // Do the update
+        $result = ldap_modify($this->adldap->getLdapConnection(), $distinguishedName, $mod);
+        if ($result == false) { 
+            return false; 
+        }
+        
+        return true;
+    }
+    
+    /**
+    * Delete a contact
+    * 
+    * @param string $distinguishedName The contact dn to delete (please be careful here!)
+    * @return array
+    */
+    public function delete($distinguishedName) 
+    {
+        $result = $this->folder()->delete($distinguishedName);
+        if ($result != true) { 
+            return false; 
+        }       
+        return true;
+    }
+    
+    /**
+    * Return a list of all contacts
+    * 
+    * @param bool $includeDescription Include a description of a contact
+    * @param string $search The search parameters
+    * @param bool $sorted Whether to sort the results
+    * @return array
+    */
+    public function all($includeDescription = false, $search = "*", $sorted = true) {
+        if (!$this->adldap->getLdapBind()) { return false; }
+        
+        // Perform the search and grab all their details
+        $filter = "(&(objectClass=contact)(cn=" . $search . "))";
+        $fields = array("displayname","distinguishedname");           
+        $sr = ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields);
+        $entries = ldap_get_entries($this->adldap->getLdapConnection(), $sr);
+
+        $usersArray = array();
+        for ($i=0; $i<$entries["count"]; $i++){
+            if ($includeDescription && strlen($entries[$i]["displayname"][0])>0){
+                $usersArray[$entries[$i]["distinguishedname"][0]] = $entries[$i]["displayname"][0];
+            } elseif ($includeDescription){
+                $usersArray[$entries[$i]["distinguishedname"][0]] = $entries[$i]["distinguishedname"][0];
+            } else {
+                array_push($usersArray, $entries[$i]["distinguishedname"][0]);
+            }
+        }
+        if ($sorted) { 
+            asort($usersArray); 
+        }
+        return $usersArray;
+    }
+    
+    /**
+    * Mail enable a contact
+    * Allows email to be sent to them through Exchange
+    * 
+    * @param string $distinguishedname The contact to mail enable
+    * @param string $emailaddress The email address to allow emails to be sent through
+    * @param string $mailnickname The mailnickname for the contact in Exchange.  If NULL this will be set to the display name
+    * @return bool
+    */
+    public function contactMailEnable($distinguishedName, $emailAddress, $mailNickname = NULL){
+        return $this->adldap->exchange()->contactMailEnable($distinguishedName, $emailAddress, $mailNickname);
+    }
+    
+    
+}
+?>
diff --git a/inc/adLDAP/classes/adLDAPExchange.php b/inc/adLDAP/classes/adLDAPExchange.php
new file mode 100644
index 000000000..dd0c6de05
--- /dev/null
+++ b/inc/adLDAP/classes/adLDAPExchange.php
@@ -0,0 +1,390 @@
+adldap = $adldap;
+    }
+    
+    /**
+    * Create an Exchange account
+    * 
+    * @param string $username The username of the user to add the Exchange account to
+    * @param array $storageGroup The mailbox, Exchange Storage Group, for the user account, this must be a full CN
+    *                            If the storage group has a different base_dn to the adLDAP configuration, set it using $base_dn
+    * @param string $emailAddress The primary email address to add to this user
+    * @param string $mailNickname The mail nick name.  If mail nickname is blank, the username will be used
+    * @param bool $mdbUseDefaults Indicates whether the store should use the default quota, rather than the per-mailbox quota.
+    * @param string $baseDn Specify an alternative base_dn for the Exchange storage group
+    * @param bool $isGUID Is the username passed a GUID or a samAccountName
+    * @return bool
+    */
+    public function createMailbox($username, $storageGroup, $emailAddress, $mailNickname=NULL, $useDefaults=TRUE, $baseDn=NULL, $isGUID=false)
+    {
+        if ($username === NULL){ return "Missing compulsory field [username]"; }     
+        if ($storageGroup === NULL) { return "Missing compulsory array [storagegroup]"; }
+        if (!is_array($storageGroup)) { return "[storagegroup] must be an array"; }
+        if ($emailAddress === NULL) { return "Missing compulsory field [emailAddress]"; }
+        
+        if ($baseDn === NULL) {
+            $baseDn = $this->adldap->getBaseDn();   
+        }
+        
+        $container = "CN=" . implode(",CN=", $storageGroup);
+        
+        if ($mailNickname === NULL) { 
+            $mailNickname = $username; 
+        }
+        $mdbUseDefaults = $this->adldap->utilities()->boolToString($useDefaults);
+        
+        $attributes = array(
+            'exchange_homemdb'=>$container.",".$baseDn,
+            'exchange_proxyaddress'=>'SMTP:' . $emailAddress,
+            'exchange_mailnickname'=>$mailNickname,
+            'exchange_usedefaults'=>$mdbUseDefaults
+        );
+        $result = $this->adldap->user()->modify($username, $attributes, $isGUID);
+        if ($result == false) { 
+            return false; 
+        }
+        return true;
+    }
+    
+    /**
+    * Add an X400 address to Exchange
+    * See http://tools.ietf.org/html/rfc1685 for more information.
+    * An X400 Address looks similar to this X400:c=US;a= ;p=Domain;o=Organization;s=Doe;g=John;
+    * 
+    * @param string $username The username of the user to add the X400 to to
+    * @param string $country Country
+    * @param string $admd Administration Management Domain
+    * @param string $pdmd Private Management Domain (often your AD domain)
+    * @param string $org Organization
+    * @param string $surname Surname
+    * @param string $givenName Given name
+    * @param bool $isGUID Is the username passed a GUID or a samAccountName
+    * @return bool
+    */
+    public function addX400($username, $country, $admd, $pdmd, $org, $surname, $givenName, $isGUID=false) 
+    {
+        if ($username === NULL){ return "Missing compulsory field [username]"; }     
+        
+        $proxyValue = 'X400:';
+            
+        // Find the dn of the user
+        $user = $this->adldap->user()->info($username, array("cn","proxyaddresses"), $isGUID);
+        if ($user[0]["dn"] === NULL) { return false; }
+        $userDn = $user[0]["dn"];
+        
+        // We do not have to demote an email address from the default so we can just add the new proxy address
+        $attributes['exchange_proxyaddress'] = $proxyValue . 'c=' . $country . ';a=' . $admd . ';p=' . $pdmd . ';o=' . $org . ';s=' . $surname . ';g=' . $givenName . ';';
+       
+        // Translate the update to the LDAP schema                
+        $add = $this->adldap->adldap_schema($attributes);
+        
+        if (!$add) { return false; }
+        
+        // Do the update
+        // Take out the @ to see any errors, usually this error might occur because the address already
+        // exists in the list of proxyAddresses
+        $result = @ldap_mod_add($this->adldap->getLdapConnection(), $userDn, $add);
+        if ($result == false) { 
+            return false; 
+        }
+        
+        return true;
+    }
+    
+    /**
+    * Add an address to Exchange
+    * 
+    * @param string $username The username of the user to add the Exchange account to
+    * @param string $emailAddress The email address to add to this user
+    * @param bool $default Make this email address the default address, this is a bit more intensive as we have to demote any existing default addresses
+    * @param bool $isGUID Is the username passed a GUID or a samAccountName
+    * @return bool
+    */
+    public function addAddress($username, $emailAddress, $default = FALSE, $isGUID = false) 
+    {
+        if ($username === NULL) { return "Missing compulsory field [username]"; }     
+        if ($emailAddress === NULL) { return "Missing compulsory fields [emailAddress]"; }
+        
+        $proxyValue = 'smtp:';
+        if ($default === true) {
+            $proxyValue = 'SMTP:';
+        }
+              
+        // Find the dn of the user
+        $user = $this->adldap->user()->info($username, array("cn","proxyaddresses"), $isGUID);
+        if ($user[0]["dn"] === NULL){ return false; }
+        $userDn = $user[0]["dn"];
+        
+        // We need to scan existing proxy addresses and demote the default one
+        if (is_array($user[0]["proxyaddresses"]) && $default === true) {
+            $modAddresses = array();
+            for ($i=0;$iadldap->getLdapConnection(), $userDn, $modAddresses);
+            if ($result == false) { 
+                return false; 
+            }
+            
+            return true;
+        }
+        else {
+            // We do not have to demote an email address from the default so we can just add the new proxy address
+            $attributes['exchange_proxyaddress'] = $proxyValue . $emailAddress;
+            
+            // Translate the update to the LDAP schema                
+            $add = $this->adldap->adldap_schema($attributes);
+            
+            if (!$add) { 
+                return false; 
+            }
+            
+            // Do the update
+            // Take out the @ to see any errors, usually this error might occur because the address already
+            // exists in the list of proxyAddresses
+            $result = @ldap_mod_add($this->adldap->getLdapConnection(), $userDn,$add);
+            if ($result == false) { 
+                return false; 
+            }
+            
+            return true;
+        }
+    }
+    
+    /**
+    * Remove an address to Exchange
+    * If you remove a default address the account will no longer have a default, 
+    * we recommend changing the default address first
+    * 
+    * @param string $username The username of the user to add the Exchange account to
+    * @param string $emailAddress The email address to add to this user
+    * @param bool $isGUID Is the username passed a GUID or a samAccountName
+    * @return bool
+    */
+    public function deleteAddress($username, $emailAddress, $isGUID=false) 
+    {
+        if ($username === NULL) { return "Missing compulsory field [username]"; }     
+        if ($emailAddress === NULL) { return "Missing compulsory fields [emailAddress]"; }
+        
+        // Find the dn of the user
+        $user = $this->adldap->user()->info($username, array("cn","proxyaddresses"), $isGUID);
+        if ($user[0]["dn"] === NULL) { return false; }
+        $userDn = $user[0]["dn"];
+        
+        if (is_array($user[0]["proxyaddresses"])) {
+            $mod = array();
+            for ($i=0;$iadldap->getLdapConnection(), $userDn,$mod);
+            if ($result == false) { 
+                return false; 
+            }
+            
+            return true;
+        }
+        else {
+            return false;
+        }
+    }
+    /**
+    * Change the default address
+    * 
+    * @param string $username The username of the user to add the Exchange account to
+    * @param string $emailAddress The email address to make default
+    * @param bool $isGUID Is the username passed a GUID or a samAccountName
+    * @return bool
+    */
+    public function primaryAddress($username, $emailAddress, $isGUID = false) 
+    {
+        if ($username === NULL) { return "Missing compulsory field [username]"; }     
+        if ($emailAddress === NULL) { return "Missing compulsory fields [emailAddress]"; }
+        
+        // Find the dn of the user
+        $user = $this->adldap->user()->info($username, array("cn","proxyaddresses"), $isGUID);
+        if ($user[0]["dn"] === NULL){ return false; }
+        $userDn = $user[0]["dn"];
+        
+        if (is_array($user[0]["proxyaddresses"])) {
+            $modAddresses = array();
+            for ($i=0;$iadldap->getLdapConnection(), $userDn, $modAddresses);
+            if ($result == false) { 
+                return false; 
+            }
+            
+            return true;
+        }
+        
+    }
+    
+    /**
+    * Mail enable a contact
+    * Allows email to be sent to them through Exchange
+    * 
+    * @param string $distinguishedName The contact to mail enable
+    * @param string $emailAddress The email address to allow emails to be sent through
+    * @param string $mailNickname The mailnickname for the contact in Exchange.  If NULL this will be set to the display name
+    * @return bool
+    */
+    public function contactMailEnable($distinguishedName, $emailAddress, $mailNickname = NULL)
+    {
+        if ($distinguishedName === NULL) { return "Missing compulsory field [distinguishedName]"; }   
+        if ($emailAddress === NULL) { return "Missing compulsory field [emailAddress]"; }  
+        
+        if ($mailNickname !== NULL) {
+            // Find the dn of the user
+            $user = $this->adldap->contact()->info($distinguishedName, array("cn","displayname"));
+            if ($user[0]["displayname"] === NULL) { return false; }
+            $mailNickname = $user[0]['displayname'][0];
+        }
+        
+        $attributes = array("email"=>$emailAddress,"contact_email"=>"SMTP:" . $emailAddress,"exchange_proxyaddress"=>"SMTP:" . $emailAddress,"exchange_mailnickname" => $mailNickname);
+         
+        // Translate the update to the LDAP schema                
+        $mod = $this->adldap->adldap_schema($attributes);
+        
+        // Check to see if this is an enabled status update
+        if (!$mod) { return false; }
+        
+        // Do the update
+        $result = ldap_modify($this->adldap->getLdapConnection(), $distinguishedName, $mod);
+        if ($result == false) { return false; }
+        
+        return true;
+    }
+    
+    /**
+    * Returns a list of Exchange Servers in the ConfigurationNamingContext of the domain
+    * 
+    * @param array $attributes An array of the AD attributes you wish to return
+    * @return array
+    */
+    public function servers($attributes = array('cn','distinguishedname','serialnumber')) 
+    {
+        if (!$this->adldap->getLdapBind()){ return false; }
+        
+        $configurationNamingContext = $this->adldap->getRootDse(array('configurationnamingcontext'));
+        $sr = @ldap_search($this->adldap->getLdapConnection(), $configurationNamingContext[0]['configurationnamingcontext'][0],'(&(objectCategory=msExchExchangeServer))', $attributes);
+        $entries = @ldap_get_entries($this->adldap->getLdapConnection(), $sr);
+        return $entries;
+    }
+    
+    /**
+    * Returns a list of Storage Groups in Exchange for a given mail server
+    * 
+    * @param string $exchangeServer The full DN of an Exchange server.  You can use exchange_servers() to find the DN for your server
+    * @param array $attributes An array of the AD attributes you wish to return
+    * @param bool $recursive If enabled this will automatically query the databases within a storage group
+    * @return array
+    */
+    public function storageGroups($exchangeServer, $attributes = array('cn','distinguishedname'), $recursive = NULL) 
+    {
+        if (!$this->adldap->getLdapBind()){ return false; }
+        if ($exchangeServer === NULL) { return "Missing compulsory field [exchangeServer]"; }
+        if ($recursive === NULL) { $recursive = $this->adldap->getRecursiveGroups(); }
+
+        $filter = '(&(objectCategory=msExchStorageGroup))';
+        $sr = @ldap_search($this->adldap->getLdapConnection(), $exchangeServer, $filter, $attributes);
+        $entries = @ldap_get_entries($this->adldap->getLdapConnection(), $sr);
+
+        if ($recursive === true) {
+            for ($i=0; $i<$entries['count']; $i++) {
+                $entries[$i]['msexchprivatemdb'] = $this->storageDatabases($entries[$i]['distinguishedname'][0]);       
+            }
+        }
+        
+        return $entries;
+    }
+    
+    /**
+    * Returns a list of Databases within any given storage group in Exchange for a given mail server
+    * 
+    * @param string $storageGroup The full DN of an Storage Group.  You can use exchange_storage_groups() to find the DN 
+    * @param array $attributes An array of the AD attributes you wish to return
+    * @return array
+    */
+    public function storageDatabases($storageGroup, $attributes = array('cn','distinguishedname','displayname')) {
+        if (!$this->adldap->getLdapBind()){ return false; }
+        if ($storageGroup === NULL) { return "Missing compulsory field [storageGroup]"; }
+        
+        $filter = '(&(objectCategory=msExchPrivateMDB))';
+        $sr = @ldap_search($this->adldap->getLdapConnection(), $storageGroup, $filter, $attributes);
+        $entries = @ldap_get_entries($this->adldap->getLdapConnection(), $sr);
+        return $entries;
+    }
+}
+?>
\ No newline at end of file
diff --git a/inc/adLDAP/classes/adLDAPFolders.php b/inc/adLDAP/classes/adLDAPFolders.php
new file mode 100644
index 000000000..55120152d
--- /dev/null
+++ b/inc/adLDAP/classes/adLDAPFolders.php
@@ -0,0 +1,179 @@
+adldap = $adldap;
+    }
+    
+    /**
+    * Delete a distinguished name from Active Directory
+    * You should never need to call this yourself, just use the wrapper functions user_delete and contact_delete
+    *
+    * @param string $dn The distinguished name to delete
+    * @return bool
+    */
+    public function delete($dn){ 
+        $result = ldap_delete($this->adldap->getLdapConnection(), $dn);
+        if ($result != true) { 
+            return false; 
+        }
+        return true;
+    }
+    
+    /**
+    * Returns a folder listing for a specific OU
+    * See http://adldap.sourceforge.net/wiki/doku.php?id=api_folder_functions
+    * 
+    * @param array $folderName An array to the OU you wish to list. 
+    *                           If set to NULL will list the root, strongly recommended to set 
+    *                           $recursive to false in that instance!
+    * @param string $dnType The type of record to list.  This can be ADLDAP_FOLDER or ADLDAP_CONTAINER.
+    * @param bool $recursive Recursively search sub folders
+    * @param bool $type Specify a type of object to search for
+    * @return array
+    */
+    public function listing($folderName = NULL, $dnType = adLDAP::ADLDAP_FOLDER, $recursive = NULL, $type = NULL) 
+    {
+        if ($recursive === NULL) { $recursive = $this->adldap->getRecursiveGroups(); } //use the default option if they haven't set it
+        if (!$this->adldap->getLdapBind()) { return false; }
+
+        $filter = '(&';
+        if ($type !== NULL) {
+            switch ($type) {
+                case 'contact':
+                    $filter .= '(objectClass=contact)';
+                    break;
+                case 'computer':
+                    $filter .= '(objectClass=computer)';
+                    break;
+                case 'group':
+                    $filter .= '(objectClass=group)';
+                    break;
+                case 'folder':
+                    $filter .= '(objectClass=organizationalUnit)';
+                    break;
+                case 'container':
+                    $filter .= '(objectClass=container)';
+                    break;
+                case 'domain':
+                    $filter .= '(objectClass=builtinDomain)';
+                    break;
+                default:
+                    $filter .= '(objectClass=user)';
+                    break;   
+            }
+        }
+        else {
+            $filter .= '(objectClass=*)';   
+        }
+        // If the folder name is null then we will search the root level of AD
+        // This requires us to not have an OU= part, just the base_dn
+        $searchOu = $this->adldap->getBaseDn();
+        if (is_array($folderName)) {
+            $ou = $dnType . "=" . implode("," . $dnType . "=", $folderName);
+            $filter .= '(!(distinguishedname=' . $ou . ',' . $this->adldap->getBaseDn() . ')))';
+            $searchOu = $ou . ',' . $this->adldap->getBaseDn();
+        }
+        else {
+            $filter .= '(!(distinguishedname=' . $this->adldap->getBaseDn() . ')))';
+        }
+
+        if ($recursive === true) {
+            $sr = ldap_search($this->adldap->getLdapConnection(), $searchOu, $filter, array('objectclass', 'distinguishedname', 'samaccountname'));
+            $entries = @ldap_get_entries($this->adldap->getLdapConnection(), $sr);
+            if (is_array($entries)) {
+                return $entries;
+            }
+        }
+        else {
+            $sr = ldap_list($this->adldap->getLdapConnection(), $searchOu, $filter, array('objectclass', 'distinguishedname', 'samaccountname'));
+            $entries = @ldap_get_entries($this->adldap->getLdapConnection(), $sr);
+            if (is_array($entries)) {
+                return $entries;
+            }
+        }
+        
+        return false;
+    }
+
+    /**
+    * Create an organizational unit
+    * 
+    * @param array $attributes Default attributes of the ou
+    * @return bool
+    */
+    public function create($attributes)
+    {
+        if (!is_array($attributes)){ return "Attributes must be an array"; }
+        if (!is_array($attributes["container"])) { return "Container attribute must be an array."; }
+        if (!array_key_exists("ou_name",$attributes)) { return "Missing compulsory field [ou_name]"; }
+        if (!array_key_exists("container",$attributes)) { return "Missing compulsory field [container]"; }
+        
+        $attributes["container"] = array_reverse($attributes["container"]);
+
+        $add=array();
+        $add["objectClass"] = "organizationalUnit";
+        $add["OU"] = $attributes['ou_name'];
+        $containers = "";
+        if (count($attributes['container']) > 0) {
+            $containers = "OU=" . implode(",OU=", $attributes["container"]) . ",";
+        }
+
+        $containers = "OU=" . implode(",OU=", $attributes["container"]);
+        $result = ldap_add($this->adldap->getLdapConnection(), "OU=" . $add["OU"] . ", " . $containers . $this->adldap->getBaseDn(), $add);
+        if ($result != true) { 
+            return false; 
+        }
+        
+        return true;
+    }
+    
+}
+
+?>
\ No newline at end of file
diff --git a/inc/adLDAP/classes/adLDAPGroups.php b/inc/adLDAP/classes/adLDAPGroups.php
new file mode 100644
index 000000000..05e4cc93b
--- /dev/null
+++ b/inc/adLDAP/classes/adLDAPGroups.php
@@ -0,0 +1,631 @@
+adldap = $adldap;
+    }
+    
+    /**
+    * Add a group to a group
+    * 
+    * @param string $parent The parent group name
+    * @param string $child The child group name
+    * @return bool
+    */
+    public function addGroup($parent,$child){
+
+        // Find the parent group's dn
+        $parentGroup = $this->ginfo($parent, array("cn"));
+        if ($parentGroup[0]["dn"] === NULL){
+            return false; 
+        }
+        $parentDn = $parentGroup[0]["dn"];
+        
+        // Find the child group's dn
+        $childGroup = $this->info($child, array("cn"));
+        if ($childGroup[0]["dn"] === NULL){ 
+            return false; 
+        }
+        $childDn = $childGroup[0]["dn"];
+                
+        $add = array();
+        $add["member"] = $childDn;
+        
+        $result = @ldap_mod_add($this->adldap->getLdapConnection(), $parentDn, $add);
+        if ($result == false) { 
+            return false; 
+        }
+        return true;
+    }
+    
+    /**
+    * Add a user to a group
+    * 
+    * @param string $group The group to add the user to
+    * @param string $user The user to add to the group
+    * @param bool $isGUID Is the username passed a GUID or a samAccountName
+    * @return bool
+    */
+    public function addUser($group, $user, $isGUID = false)
+    {
+        // Adding a user is a bit fiddly, we need to get the full DN of the user
+        // and add it using the full DN of the group
+        
+        // Find the user's dn
+        $userDn = $this->adldap->user()->dn($user, $isGUID);
+        if ($userDn === false) { 
+            return false; 
+        }
+        
+        // Find the group's dn
+        $groupInfo = $this->info($group, array("cn"));
+        if ($groupInfo[0]["dn"] === NULL) { 
+            return false; 
+        }
+        $groupDn = $groupInfo[0]["dn"];
+        
+        $add = array();
+        $add["member"] = $userDn;
+        
+        $result = @ldap_mod_add($this->adldap->getLdapConnection(), $groupDn, $add);
+        if ($result == false) { 
+            return false; 
+        }
+        return true;
+    }
+    
+    /**
+    * Add a contact to a group
+    * 
+    * @param string $group The group to add the contact to
+    * @param string $contactDn The DN of the contact to add
+    * @return bool
+    */
+    public function addContact($group, $contactDn)
+    {
+        // To add a contact we take the contact's DN
+        // and add it using the full DN of the group
+        
+        // Find the group's dn
+        $groupInfo = $this->info($group, array("cn"));
+        if ($groupInfo[0]["dn"] === NULL) { 
+            return false; 
+        }
+        $groupDn = $groupInfo[0]["dn"];
+        
+        $add = array();
+        $add["member"] = $contactDn;
+        
+        $result = @ldap_mod_add($this->adldap->getLdapConnection(), $groupDn, $add);
+        if ($result == false) { 
+            return false; 
+        }
+        return true;
+    }
+
+    /**
+    * Create a group
+    * 
+    * @param array $attributes Default attributes of the group
+    * @return bool
+    */
+    public function create($attributes)
+    {
+        if (!is_array($attributes)){ return "Attributes must be an array"; }
+        if (!array_key_exists("group_name", $attributes)){ return "Missing compulsory field [group_name]"; }
+        if (!array_key_exists("container", $attributes)){ return "Missing compulsory field [container]"; }
+        if (!array_key_exists("description", $attributes)){ return "Missing compulsory field [description]"; }
+        if (!is_array($attributes["container"])){ return "Container attribute must be an array."; }
+        $attributes["container"] = array_reverse($attributes["container"]);
+
+        //$member_array = array();
+        //$member_array[0] = "cn=user1,cn=Users,dc=yourdomain,dc=com";
+        //$member_array[1] = "cn=administrator,cn=Users,dc=yourdomain,dc=com";
+        
+        $add = array();
+        $add["cn"] = $attributes["group_name"];
+        $add["samaccountname"] = $attributes["group_name"];
+        $add["objectClass"] = "Group";
+        $add["description"] = $attributes["description"];
+        //$add["member"] = $member_array; UNTESTED
+
+        $container = "OU=" . implode(",OU=", $attributes["container"]);
+        $result = ldap_add($this->adldap->getLdapConnection(), "CN=" . $add["cn"] . ", " . $container . "," . $this->adldap->getBaseDn(), $add);
+        if ($result != true) { 
+            return false; 
+        }
+        return true;
+    }
+    
+    /**
+    * Delete a group account 
+    * 
+    * @param string $group The group to delete (please be careful here!) 
+    * 
+    * @return array 
+    */
+    public function delete($group) {
+        if (!$this->adldap->getLdapBind()){ return false; }
+        if ($group === null){ return "Missing compulsory field [group]"; }
+        
+        $groupInfo = $this->info($group, array("*"));
+        $dn = $groupInfo[0]['distinguishedname'][0]; 
+        $result = $this->adldap->folder()->delete($dn); 
+        if ($result !== true) { 
+            return false; 
+        } return true;   
+    }
+
+    /**
+    * Remove a group from a group
+    * 
+    * @param string $parent The parent group name
+    * @param string $child The child group name
+    * @return bool
+    */
+    public function removeGroup($parent , $child)
+    {
+    
+        // Find the parent dn
+        $parentGroup = $this->info($parent, array("cn"));
+        if ($parentGroup[0]["dn"] === NULL) { 
+            return false; 
+        }
+        $parentDn = $parentGroup[0]["dn"];
+        
+        // Find the child dn
+        $childGroup = $this->info($child, array("cn"));
+        if ($childGroup[0]["dn"] === NULL) { 
+            return false; 
+        }
+        $childDn = $childGroup[0]["dn"];
+        
+        $del = array();
+        $del["member"] = $childDn;
+        
+        $result = @ldap_mod_del($this->adldap->getLdapConnection(), $parentDn, $del);
+        if ($result == false) { 
+            return false; 
+        }
+        return true;
+    }
+    
+    /**
+    * Remove a user from a group
+    * 
+    * @param string $group The group to remove a user from
+    * @param string $user The AD user to remove from the group
+    * @param bool $isGUID Is the username passed a GUID or a samAccountName
+    * @return bool
+    */
+    public function removeUser($group, $user, $isGUID = false)
+    {
+    
+        // Find the parent dn
+        $groupInfo = $this->info($group, array("cn"));
+        if ($groupInfo[0]["dn"] === NULL){ 
+            return false; 
+        }
+        $groupDn = $groupInfo[0]["dn"];
+        
+        // Find the users dn
+        $userDn = $this->adldap->user()->dn($user, $isGUID);
+        if ($userDn === false) {
+            return false; 
+        }
+
+        $del = array();
+        $del["member"] = $userDn;
+        
+        $result = @ldap_mod_del($this->adldap->getLdapConnection(), $groupDn, $del);
+        if ($result == false) {
+            return false; 
+        }
+        return true;
+    }
+    
+    /**
+    * Remove a contact from a group
+    * 
+    * @param string $group The group to remove a user from
+    * @param string $contactDn The DN of a contact to remove from the group
+    * @return bool
+    */
+    public function removeContact($group, $contactDn)
+    {
+    
+        // Find the parent dn
+        $groupInfo = $this->info($group, array("cn"));
+        if ($groupInfo[0]["dn"] === NULL) { 
+            return false; 
+        }
+        $groupDn = $groupInfo[0]["dn"];
+    
+        $del = array();
+        $del["member"] = $contactDn;
+        
+        $result = @ldap_mod_del($this->adldap->getLdapConnection(), $groupDn, $del);
+        if ($result == false) { 
+            return false; 
+        }
+        return true;
+    }
+    
+    /**
+    * Return a list of groups in a group
+    * 
+    * @param string $group The group to query
+    * @param bool $recursive Recursively get groups
+    * @return array
+    */
+    public function inGroup($group, $recursive = NULL)
+    {
+        if (!$this->adldap->getLdapBind()){ return false; }
+        if ($recursive === NULL){ $recursive = $this->adldap->getRecursiveGroups(); } // Use the default option if they haven't set it 
+        
+        // Search the directory for the members of a group
+        $info = $this->info($group, array("member","cn"));
+        $groups = $info[0]["member"];
+        if (!is_array($groups)) {
+            return false;   
+        }
+ 
+        $groupArray = array();
+
+        for ($i=0; $i<$groups["count"]; $i++){ 
+             $filter = "(&(objectCategory=group)(distinguishedName=" . $this->adldap->utilities()->ldapSlashes($groups[$i]) . "))";
+             $fields = array("samaccountname", "distinguishedname", "objectClass");
+             $sr = ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields);
+             $entries = ldap_get_entries($this->adldap->getLdapConnection(), $sr);
+
+             // not a person, look for a group  
+             if ($entries['count'] == 0 && $recursive == true) {  
+                $filter = "(&(objectCategory=group)(distinguishedName=" . $this->adldap->utilities()->ldapSlashes($groups[$i]) . "))";  
+                $fields = array("distinguishedname");  
+                $sr = ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields);  
+                $entries = ldap_get_entries($this->adldap->getLdapConnection(), $sr);  
+                if (!isset($entries[0]['distinguishedname'][0])) {
+                    continue;  
+                }
+                $subGroups = $this->inGroup($entries[0]['distinguishedname'][0], $recursive);  
+                if (is_array($subGroups)) {
+                    $groupArray = array_merge($groupArray, $subGroups); 
+                    $groupArray = array_unique($groupArray);  
+                }
+                continue;  
+             } 
+
+             $groupArray[] = $entries[0]['distinguishedname'][0];
+        }
+        return $groupArray;
+    }
+    
+    /**
+    * Return a list of members in a group
+    * 
+    * @param string $group The group to query
+    * @param bool $recursive Recursively get group members
+    * @return array
+    */
+    public function members($group, $recursive = NULL)
+    {
+        if (!$this->adldap->getLdapBind()){ return false; }
+        if ($recursive === NULL){ $recursive = $this->adldap->getRecursiveGroups(); } // Use the default option if they haven't set it 
+        // Search the directory for the members of a group
+        $info = $this->info($group, array("member","cn"));
+        $users = $info[0]["member"];
+        if (!is_array($users)) {
+            return false;   
+        }
+ 
+        $userArray = array();
+
+        for ($i=0; $i<$users["count"]; $i++){ 
+             $filter = "(&(objectCategory=person)(distinguishedName=" . $this->adldap->utilities()->ldapSlashes($users[$i]) . "))";
+             $fields = array("samaccountname", "distinguishedname", "objectClass");
+             $sr = ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields);
+             $entries = ldap_get_entries($this->adldap->getLdapConnection(), $sr);
+
+             // not a person, look for a group  
+             if ($entries['count'] == 0 && $recursive == true) {  
+                $filter = "(&(objectCategory=group)(distinguishedName=" . $this->adldap->utilities()->ldapSlashes($users[$i]) . "))";  
+                $fields = array("samaccountname");  
+                $sr = ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields);  
+                $entries = ldap_get_entries($this->adldap->getLdapConnection(), $sr);  
+                if (!isset($entries[0]['samaccountname'][0])) {
+                    continue;  
+                }
+                $subUsers = $this->members($entries[0]['samaccountname'][0], $recursive);  
+                if (is_array($subUsers)) {
+                    $userArray = array_merge($userArray, $subUsers); 
+                    $userArray = array_unique($userArray);  
+                }
+                continue;  
+             } 
+             else if ($entries['count'] == 0) {   
+                continue; 
+             } 
+
+             if ((!isset($entries[0]['samaccountname'][0]) || $entries[0]['samaccountname'][0] === NULL) && $entries[0]['distinguishedname'][0] !== NULL) {
+                 $userArray[] = $entries[0]['distinguishedname'][0];
+             }
+             else if ($entries[0]['samaccountname'][0] !== NULL) {
+                $userArray[] = $entries[0]['samaccountname'][0];
+             }
+        }
+        return $userArray;
+    }
+    
+    /**
+    * Group Information.  Returns an array of raw information about a group.
+    * The group name is case sensitive
+    * 
+    * @param string $groupName The group name to retrieve info about
+    * @param array $fields Fields to retrieve
+    * @return array
+    */
+    public function info($groupName, $fields = NULL)
+    {
+        if ($groupName === NULL) { return false; }
+        if (!$this->adldap->getLdapBind()) { return false; }
+        
+        if (stristr($groupName, '+')) {
+            $groupName = stripslashes($groupName);   
+        }
+        
+        $filter = "(&(objectCategory=group)(name=" . $this->adldap->utilities()->ldapSlashes($groupName) . "))";
+        if ($fields === NULL) { 
+            $fields = array("member","memberof","cn","description","distinguishedname","objectcategory","samaccountname"); 
+        }
+        $sr = ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields);
+        $entries = ldap_get_entries($this->adldap->getLdapConnection(), $sr);
+
+        return $entries;
+    }
+    
+    /**
+    * Group Information.  Returns an collection
+    * The group name is case sensitive
+    * 
+    * @param string $groupName The group name to retrieve info about
+    * @param array $fields Fields to retrieve
+    * @return adLDAPGroupCollection
+    */
+    public function infoCollection($groupName, $fields = NULL)
+    {
+        if ($groupName === NULL) { return false; }
+        if (!$this->adldap->getLdapBind()) { return false; }
+        
+        $info = $this->info($groupName, $fields);
+        if ($info !== false) {
+            $collection = new adLDAPGroupCollection($info, $this->adldap);
+            return $collection;
+        }
+        return false;
+    }
+    
+    /**
+    * Return a complete list of "groups in groups"
+    * 
+    * @param string $group The group to get the list from
+    * @return array
+    */
+    public function recursiveGroups($group)
+    {
+        if ($group === NULL) { return false; }
+
+        $stack = array(); 
+        $processed = array(); 
+        $retGroups = array(); 
+     
+        array_push($stack, $group); // Initial Group to Start with 
+        while (count($stack) > 0) {
+            $parent = array_pop($stack);
+            array_push($processed, $parent);
+            
+            $info = $this->info($parent, array("memberof"));
+            
+            if (isset($info[0]["memberof"]) && is_array($info[0]["memberof"])) {
+                $groups = $info[0]["memberof"]; 
+                if ($groups) {
+                    $groupNames = $this->adldap->utilities()->niceNames($groups);  
+                    $retGroups = array_merge($retGroups, $groupNames); //final groups to return
+                    foreach ($groupNames as $id => $groupName) { 
+                        if (!in_array($groupName, $processed)) {
+                            array_push($stack, $groupName);
+                        }
+                    }
+                }
+            }
+        }
+        
+        return $retGroups;
+    }
+    
+    /**
+    * Returns a complete list of the groups in AD based on a SAM Account Type  
+    * 
+    * @param string $sAMAaccountType The account type to return
+    * @param bool $includeDescription Whether to return a description
+    * @param string $search Search parameters
+    * @param bool $sorted Whether to sort the results
+    * @return array
+    */
+    public function search($sAMAaccountType = adLDAP::ADLDAP_SECURITY_GLOBAL_GROUP, $includeDescription = false, $search = "*", $sorted = true) {
+        if (!$this->adldap->getLdapBind()) { return false; }
+        
+        $filter = '(&(objectCategory=group)';
+        if ($sAMAaccountType !== null) {
+            $filter .= '(samaccounttype='. $sAMAaccountType .')';
+        }
+        $filter .= '(cn=' . $search . '))';
+        // Perform the search and grab all their details
+        $fields = array("samaccountname", "description");
+        $sr = ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields);
+        $entries = ldap_get_entries($this->adldap->getLdapConnection(), $sr);
+
+        $groupsArray = array();        
+        for ($i=0; $i<$entries["count"]; $i++){
+            if ($includeDescription && strlen($entries[$i]["description"][0]) > 0 ) {
+                $groupsArray[$entries[$i]["samaccountname"][0]] = $entries[$i]["description"][0];
+            }
+            else if ($includeDescription){
+                $groupsArray[$entries[$i]["samaccountname"][0]] = $entries[$i]["samaccountname"][0];
+            }
+            else {
+                array_push($groupsArray, $entries[$i]["samaccountname"][0]);
+            }
+        }
+        if ($sorted) { 
+            asort($groupsArray); 
+        }
+        return $groupsArray;
+    }
+    
+    /**
+    * Returns a complete list of all groups in AD
+    * 
+    * @param bool $includeDescription Whether to return a description
+    * @param string $search Search parameters
+    * @param bool $sorted Whether to sort the results
+    * @return array
+    */
+    public function all($includeDescription = false, $search = "*", $sorted = true){
+        $groupsArray = $this->search(null, $includeDescription, $search, $sorted);
+        return $groupsArray;
+    }
+    
+    /**
+    * Returns a complete list of security groups in AD
+    * 
+    * @param bool $includeDescription Whether to return a description
+    * @param string $search Search parameters
+    * @param bool $sorted Whether to sort the results
+    * @return array
+    */
+    public function allSecurity($includeDescription = false, $search = "*", $sorted = true){
+        $groupsArray = $this->search(adLDAP::ADLDAP_SECURITY_GLOBAL_GROUP, $includeDescription, $search, $sorted);
+        return $groupsArray;
+    }
+    
+    /**
+    * Returns a complete list of distribution lists in AD
+    * 
+    * @param bool $includeDescription Whether to return a description
+    * @param string $search Search parameters
+    * @param bool $sorted Whether to sort the results
+    * @return array
+    */
+    public function allDistribution($includeDescription = false, $search = "*", $sorted = true){
+        $groupsArray = $this->search(adLDAP::ADLDAP_DISTRIBUTION_GROUP, $includeDescription, $search, $sorted);
+        return $groupsArray;
+    }
+    
+    /**
+    * Coping with AD not returning the primary group
+    * http://support.microsoft.com/?kbid=321360 
+    * 
+    * This is a re-write based on code submitted by Bruce which prevents the 
+    * need to search each security group to find the true primary group
+    * 
+    * @param string $gid Group ID
+    * @param string $usersid User's Object SID
+    * @return mixed
+    */
+    public function getPrimaryGroup($gid, $usersid)
+    {
+        if ($gid === NULL || $usersid === NULL) { return false; }
+        $sr = false;
+
+        $gsid = substr_replace($usersid, pack('V',$gid), strlen($usersid)-4,4);
+        $filter = '(objectsid=' . $this->adldap->utilities()->getTextSID($gsid).')';
+        $fields = array("samaccountname","distinguishedname");
+        $sr = ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields);
+        $entries = ldap_get_entries($this->adldap->getLdapConnection(), $sr);
+
+        if (isset($entries[0]['distinguishedname'][0])) {
+            return $entries[0]['distinguishedname'][0];
+        }
+        return false;
+     }
+     
+     /**
+    * Coping with AD not returning the primary group
+    * http://support.microsoft.com/?kbid=321360 
+    * 
+    * For some reason it's not possible to search on primarygrouptoken=XXX
+    * If someone can show otherwise, I'd like to know about it :)
+    * this way is resource intensive and generally a pain in the @#%^
+    * 
+    * @deprecated deprecated since version 3.1, see get get_primary_group
+    * @param string $gid Group ID
+    * @return string
+    */
+    public function cn($gid){    
+        if ($gid === NULL) { return false; }
+        $sr = false;
+        $r = '';
+        
+        $filter = "(&(objectCategory=group)(samaccounttype=" . adLDAP::ADLDAP_SECURITY_GLOBAL_GROUP . "))";
+        $fields = array("primarygrouptoken", "samaccountname", "distinguishedname");
+        $sr = ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields);
+        $entries = ldap_get_entries($this->adldap->getLdapConnection(), $sr);
+        
+        for ($i=0; $i<$entries["count"]; $i++){
+            if ($entries[$i]["primarygrouptoken"][0] == $gid) {
+                $r = $entries[$i]["distinguishedname"][0];
+                $i = $entries["count"];
+            }
+        }
+
+        return $r;
+    }
+}
+?>
diff --git a/inc/adLDAP/classes/adLDAPUsers.php b/inc/adLDAP/classes/adLDAPUsers.php
new file mode 100644
index 000000000..96a93b512
--- /dev/null
+++ b/inc/adLDAP/classes/adLDAPUsers.php
@@ -0,0 +1,682 @@
+adldap = $adldap;
+    }
+    
+    /**
+    * Validate a user's login credentials
+    * 
+    * @param string $username A user's AD username
+    * @param string $password A user's AD password
+    * @param bool optional $prevent_rebind
+    * @return bool
+    */
+    public function authenticate($username, $password, $preventRebind = false) {
+        return $this->adldap->authenticate($username, $password, $preventRebind);
+    }
+    
+    /**
+    * Create a user
+    * 
+    * If you specify a password here, this can only be performed over SSL
+    * 
+    * @param array $attributes The attributes to set to the user account
+    * @return bool
+    */
+    public function create($attributes)
+    {
+        // Check for compulsory fields
+        if (!array_key_exists("username", $attributes)){ return "Missing compulsory field [username]"; }
+        if (!array_key_exists("firstname", $attributes)){ return "Missing compulsory field [firstname]"; }
+        if (!array_key_exists("surname", $attributes)){ return "Missing compulsory field [surname]"; }
+        if (!array_key_exists("email", $attributes)){ return "Missing compulsory field [email]"; }
+        if (!array_key_exists("container", $attributes)){ return "Missing compulsory field [container]"; }
+        if (!is_array($attributes["container"])){ return "Container attribute must be an array."; }
+
+        if (array_key_exists("password",$attributes) && (!$this->adldap->getUseSSL() && !$this->adldap->getUseTLS())){ 
+            throw new adLDAPException('SSL must be configured on your webserver and enabled in the class to set passwords.');
+        }
+
+        if (!array_key_exists("display_name", $attributes)) { 
+            $attributes["display_name"] = $attributes["firstname"] . " " . $attributes["surname"]; 
+        }
+
+        // Translate the schema
+        $add = $this->adldap->adldap_schema($attributes);
+        
+        // Additional stuff only used for adding accounts
+        $add["cn"][0] = $attributes["display_name"];
+        $add["samaccountname"][0] = $attributes["username"];
+        $add["objectclass"][0] = "top";
+        $add["objectclass"][1] = "person";
+        $add["objectclass"][2] = "organizationalPerson";
+        $add["objectclass"][3] = "user"; //person?
+        //$add["name"][0]=$attributes["firstname"]." ".$attributes["surname"];
+
+        // Set the account control attribute
+        $control_options = array("NORMAL_ACCOUNT");
+        if (!$attributes["enabled"]) { 
+            $control_options[] = "ACCOUNTDISABLE"; 
+        }
+        $add["userAccountControl"][0] = $this->accountControl($control_options);
+        
+        // Determine the container
+        $attributes["container"] = array_reverse($attributes["container"]);
+        $container = "OU=" . implode(", OU=",$attributes["container"]);
+
+        // Add the entry
+        $result = @ldap_add($this->adldap->getLdapConnection(), "CN=" . $add["cn"][0] . ", " . $container . "," . $this->adldap->getBaseDn(), $add);
+        if ($result != true) { 
+            return false; 
+        }
+        
+        return true;
+    }
+    
+    /**
+    * Account control options
+    *
+    * @param array $options The options to convert to int 
+    * @return int
+    */
+    protected function accountControl($options)
+    {
+        $val=0;
+
+        if (is_array($options)) {
+            if (in_array("SCRIPT",$options)){ $val=$val+1; }
+            if (in_array("ACCOUNTDISABLE",$options)){ $val=$val+2; }
+            if (in_array("HOMEDIR_REQUIRED",$options)){ $val=$val+8; }
+            if (in_array("LOCKOUT",$options)){ $val=$val+16; }
+            if (in_array("PASSWD_NOTREQD",$options)){ $val=$val+32; }
+            //PASSWD_CANT_CHANGE Note You cannot assign this permission by directly modifying the UserAccountControl attribute.
+            //For information about how to set the permission programmatically, see the "Property flag descriptions" section.
+            if (in_array("ENCRYPTED_TEXT_PWD_ALLOWED",$options)){ $val=$val+128; }
+            if (in_array("TEMP_DUPLICATE_ACCOUNT",$options)){ $val=$val+256; }
+            if (in_array("NORMAL_ACCOUNT",$options)){ $val=$val+512; }
+            if (in_array("INTERDOMAIN_TRUST_ACCOUNT",$options)){ $val=$val+2048; }
+            if (in_array("WORKSTATION_TRUST_ACCOUNT",$options)){ $val=$val+4096; }
+            if (in_array("SERVER_TRUST_ACCOUNT",$options)){ $val=$val+8192; }
+            if (in_array("DONT_EXPIRE_PASSWORD",$options)){ $val=$val+65536; }
+            if (in_array("MNS_LOGON_ACCOUNT",$options)){ $val=$val+131072; }
+            if (in_array("SMARTCARD_REQUIRED",$options)){ $val=$val+262144; }
+            if (in_array("TRUSTED_FOR_DELEGATION",$options)){ $val=$val+524288; }
+            if (in_array("NOT_DELEGATED",$options)){ $val=$val+1048576; }
+            if (in_array("USE_DES_KEY_ONLY",$options)){ $val=$val+2097152; }
+            if (in_array("DONT_REQ_PREAUTH",$options)){ $val=$val+4194304; } 
+            if (in_array("PASSWORD_EXPIRED",$options)){ $val=$val+8388608; }
+            if (in_array("TRUSTED_TO_AUTH_FOR_DELEGATION",$options)){ $val=$val+16777216; }
+        }
+        return $val;
+    }
+    
+    /**
+    * Delete a user account
+    * 
+    * @param string $username The username to delete (please be careful here!)
+    * @param bool $isGUID Is the username a GUID or a samAccountName
+    * @return array
+    */
+    public function delete($username, $isGUID = false) 
+    {      
+        $userinfo = $this->info($username, array("*"), $isGUID);
+        $dn = $userinfo[0]['distinguishedname'][0];
+        $result = $this->adldap->folder()->delete($dn);
+        if ($result != true) { 
+            return false;
+        }        
+        return true;
+    }
+    
+    /**
+    * Groups the user is a member of
+    * 
+    * @param string $username The username to query
+    * @param bool $recursive Recursive list of groups
+    * @param bool $isGUID Is the username passed a GUID or a samAccountName
+    * @return array
+    */
+    public function groups($username, $recursive = NULL, $isGUID = false)
+    {
+        if ($username === NULL) { return false; }
+        if ($recursive === NULL) { $recursive = $this->adldap->getRecursiveGroups(); } // Use the default option if they haven't set it
+        if (!$this->adldap->getLdapBind()) { return false; }
+        
+        // Search the directory for their information
+        $info = @$this->info($username, array("memberof", "primarygroupid"), $isGUID);
+        $groups = $this->adldap->utilities()->niceNames($info[0]["memberof"]); // Presuming the entry returned is our guy (unique usernames)
+
+        if ($recursive === true){
+            foreach ($groups as $id => $groupName){
+                $extraGroups = $this->adldap->group()->recursiveGroups($groupName);
+                $groups = array_merge($groups, $extraGroups);
+            }
+        }
+        
+        return $groups;
+    }
+    
+    /**
+    * Find information about the users. Returned in a raw array format from AD
+    * 
+    * @param string $username The username to query
+    * @param array $fields Array of parameters to query
+    * @param bool $isGUID Is the username passed a GUID or a samAccountName
+    * @return array
+    */
+    public function info($username, $fields = NULL, $isGUID = false)
+    {
+        if ($username === NULL) { return false; }
+        if (!$this->adldap->getLdapBind()) { return false; }
+
+        if ($isGUID === true) {
+            $username = $this->adldap->utilities()->strGuidToHex($username);
+            $filter = "objectguid=" . $username;
+        }
+        else if (strstr($username, "@")) {
+             $filter = "userPrincipalName=" . $username;
+        }
+        else {
+             $filter = "samaccountname=" . $username;
+        }
+        $filter = "(&(objectCategory=person)({$filter}))";
+        if ($fields === NULL) { 
+            $fields = array("samaccountname","mail","memberof","department","displayname","telephonenumber","primarygroupid","objectsid"); 
+        }
+        if (!in_array("objectsid", $fields)) {
+            $fields[] = "objectsid";
+        }
+        $sr = ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields);
+        $entries = ldap_get_entries($this->adldap->getLdapConnection(), $sr);
+        
+        if (isset($entries[0])) {
+            if ($entries[0]['count'] >= 1) {
+                if (in_array("memberof", $fields)) {
+                    // AD does not return the primary group in the ldap query, we may need to fudge it
+                    if ($this->adldap->getRealPrimaryGroup() && isset($entries[0]["primarygroupid"][0]) && isset($entries[0]["objectsid"][0])){
+                        //$entries[0]["memberof"][]=$this->group_cn($entries[0]["primarygroupid"][0]);
+                        $entries[0]["memberof"][] = $this->adldap->group()->getPrimaryGroup($entries[0]["primarygroupid"][0], $entries[0]["objectsid"][0]);
+                    } else {
+                        $entries[0]["memberof"][] = "CN=Domain Users,CN=Users," . $this->adldap->getBaseDn();
+                    }
+                    if (!isset($entries[0]["memberof"]["count"])) {
+                        $entries[0]["memberof"]["count"] = 0;
+                    }
+                    $entries[0]["memberof"]["count"]++;
+                }
+            }
+            
+            return $entries;
+        }
+        return false;
+    }
+    
+    /**
+    * Find information about the users. Returned in a raw array format from AD
+    * 
+    * @param string $username The username to query
+    * @param array $fields Array of parameters to query
+    * @param bool $isGUID Is the username passed a GUID or a samAccountName
+    * @return mixed
+    */
+    public function infoCollection($username, $fields = NULL, $isGUID = false)
+    {
+        if ($username === NULL) { return false; }
+        if (!$this->adldap->getLdapBind()) { return false; }
+        
+        $info = $this->info($username, $fields, $isGUID);
+        
+        if ($info !== false) {
+            $collection = new adLDAPUserCollection($info, $this->adldap);
+            return $collection;
+        }
+        return false;
+    }
+    
+    /**
+    * Determine if a user is in a specific group
+    * 
+    * @param string $username The username to query
+    * @param string $group The name of the group to check against
+    * @param bool $recursive Check groups recursively
+    * @param bool $isGUID Is the username passed a GUID or a samAccountName
+    * @return bool
+    */
+    public function inGroup($username, $group, $recursive = NULL, $isGUID = false)
+    {
+        if ($username === NULL) { return false; }
+        if ($group === NULL) { return false; }
+        if (!$this->adldap->getLdapBind()) { return false; }
+        if ($recursive === NULL) { $recursive = $this->adldap->getRecursiveGroups(); } // Use the default option if they haven't set it
+        
+        // Get a list of the groups
+        $groups = $this->groups($username, $recursive, $isGUID);
+        
+        // Return true if the specified group is in the group list
+        if (in_array($group, $groups)) { 
+            return true; 
+        }
+
+        return false;
+    }
+    
+    /**
+    * Determine a user's password expiry date
+    * 
+    * @param string $username The username to query
+    * @param book $isGUID Is the username passed a GUID or a samAccountName
+    * @requires bcmath http://www.php.net/manual/en/book.bc.php
+    * @return array
+    */
+    public function passwordExpiry($username, $isGUID = false) 
+    {
+        if ($username === NULL) { return "Missing compulsory field [username]"; }
+        if (!$this->adldap->getLdapBind()) { return false; }
+        if (!function_exists('bcmod')) { throw new adLDAPException("Missing function support [bcmod] http://www.php.net/manual/en/book.bc.php"); };
+        
+        $userInfo = $this->info($username, array("pwdlastset", "useraccountcontrol"), $isGUID);
+        $pwdLastSet = $userInfo[0]['pwdlastset'][0];
+        $status = array();
+        
+        if ($userInfo[0]['useraccountcontrol'][0] == '66048') {
+            // Password does not expire
+            return "Does not expire";
+        }
+        if ($pwdLastSet === '0') {
+            // Password has already expired
+            return "Password has expired";
+        }
+        
+         // Password expiry in AD can be calculated from TWO values:
+         //   - User's own pwdLastSet attribute: stores the last time the password was changed
+         //   - Domain's maxPwdAge attribute: how long passwords last in the domain
+         //
+         // Although Microsoft chose to use a different base and unit for time measurements.
+         // This function will convert them to Unix timestamps
+         $sr = ldap_read($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), 'objectclass=*', array('maxPwdAge'));
+         if (!$sr) {
+             return false;
+         }
+         $info = ldap_get_entries($this->adldap->getLdapConnection(), $sr);
+         $maxPwdAge = $info[0]['maxpwdage'][0];
+         
+
+         // See MSDN: http://msdn.microsoft.com/en-us/library/ms974598.aspx
+         //
+         // pwdLastSet contains the number of 100 nanosecond intervals since January 1, 1601 (UTC), 
+         // stored in a 64 bit integer. 
+         //
+         // The number of seconds between this date and Unix epoch is 11644473600.
+         //
+         // maxPwdAge is stored as a large integer that represents the number of 100 nanosecond
+         // intervals from the time the password was set before the password expires.
+         //
+         // We also need to scale this to seconds but also this value is a _negative_ quantity!
+         //
+         // If the low 32 bits of maxPwdAge are equal to 0 passwords do not expire
+         //
+         // Unfortunately the maths involved are too big for PHP integers, so I've had to require
+         // BCMath functions to work with arbitrary precision numbers.
+         if (bcmod($maxPwdAge, 4294967296) === '0') {
+            return "Domain does not expire passwords";
+        }
+        
+        // Add maxpwdage and pwdlastset and we get password expiration time in Microsoft's
+        // time units.  Because maxpwd age is negative we need to subtract it.
+        $pwdExpire = bcsub($pwdLastSet, $maxPwdAge);
+    
+        // Convert MS's time to Unix time
+        $status['expiryts'] = bcsub(bcdiv($pwdExpire, '10000000'), '11644473600');
+        $status['expiryformat'] = date('Y-m-d H:i:s', bcsub(bcdiv($pwdExpire, '10000000'), '11644473600'));
+        
+        return $status;
+    }
+    
+    /**
+    * Modify a user
+    * 
+    * @param string $username The username to query
+    * @param array $attributes The attributes to modify.  Note if you set the enabled attribute you must not specify any other attributes
+    * @param bool $isGUID Is the username passed a GUID or a samAccountName
+    * @return bool
+    */
+    public function modify($username, $attributes, $isGUID = false)
+    {
+        if ($username === NULL) { return "Missing compulsory field [username]"; }
+        if (array_key_exists("password", $attributes) && !$this->adldap->getUseSSL() && !$this->adldap->getUseTLS()) { 
+            throw new adLDAPException('SSL/TLS must be configured on your webserver and enabled in the class to set passwords.');
+        }
+
+        // Find the dn of the user
+        $userDn = $this->dn($username, $isGUID);
+        if ($userDn === false) { 
+            return false; 
+        }
+        
+        // Translate the update to the LDAP schema                
+        $mod = $this->adldap->adldap_schema($attributes);
+        
+        // Check to see if this is an enabled status update
+        if (!$mod && !array_key_exists("enabled", $attributes)){ 
+            return false; 
+        }
+        
+        // Set the account control attribute (only if specified)
+        if (array_key_exists("enabled", $attributes)){
+            if ($attributes["enabled"]){ 
+                $controlOptions = array("NORMAL_ACCOUNT"); 
+            }
+            else { 
+                $controlOptions = array("NORMAL_ACCOUNT", "ACCOUNTDISABLE"); 
+            }
+            $mod["userAccountControl"][0] = $this->accountControl($controlOptions);
+        }
+
+        // Do the update
+        $result = @ldap_modify($this->adldap->getLdapConnection(), $userDn, $mod);
+        if ($result == false) { 
+            return false; 
+        }
+        
+        return true;
+    }
+    
+    /**
+    * Disable a user account
+    * 
+    * @param string $username The username to disable
+    * @param bool $isGUID Is the username passed a GUID or a samAccountName
+    * @return bool
+    */
+    public function disable($username, $isGUID = false)
+    {
+        if ($username === NULL) { return "Missing compulsory field [username]"; }
+        $attributes = array("enabled" => 0);
+        $result = $this->modify($username, $attributes, $isGUID);
+        if ($result == false) { return false; }
+        
+        return true;
+    }
+    
+    /**
+    * Enable a user account
+    * 
+    * @param string $username The username to enable
+    * @param bool $isGUID Is the username passed a GUID or a samAccountName
+    * @return bool
+    */
+    public function enable($username, $isGUID = false)
+    {
+        if ($username === NULL) { return "Missing compulsory field [username]"; }
+        $attributes = array("enabled" => 1);
+        $result = $this->modify($username, $attributes, $isGUID);
+        if ($result == false) { return false; }
+        
+        return true;
+    }
+    
+    /**
+    * Set the password of a user - This must be performed over SSL
+    * 
+    * @param string $username The username to modify
+    * @param string $password The new password
+    * @param bool $isGUID Is the username passed a GUID or a samAccountName
+    * @return bool
+    */
+    public function password($username, $password, $isGUID = false)
+    {
+        if ($username === NULL) { return false; }
+        if ($password === NULL) { return false; }
+        if (!$this->adldap->getLdapBind()) { return false; }
+        if (!$this->adldap->getUseSSL() && !$this->adldap->getUseTLS()) { 
+            throw new adLDAPException('SSL must be configured on your webserver and enabled in the class to set passwords.');
+        }
+        
+        $userDn = $this->dn($username, $isGUID);
+        if ($userDn === false) { 
+            return false; 
+        }
+                
+        $add=array();
+        $add["unicodePwd"][0] = $this->encodePassword($password);
+        
+        $result = @ldap_mod_replace($this->adldap->getLdapConnection(), $userDn, $add);
+        if ($result === false){
+            $err = ldap_errno($this->adldap->getLdapConnection());
+            if ($err) {
+                $msg = 'Error ' . $err . ': ' . ldap_err2str($err) . '.';
+                if($err == 53) {
+                    $msg .= ' Your password might not match the password policy.';
+                }
+                throw new adLDAPException($msg);
+            }
+            else {
+                return false;
+            }
+        }
+        
+        return true;
+    }
+    
+    /**
+    * Encode a password for transmission over LDAP
+    *
+    * @param string $password The password to encode
+    * @return string
+    */
+    public function encodePassword($password)
+    {
+        $password="\"".$password."\"";
+        $encoded="";
+        for ($i=0; $i info($username, array("cn"), $isGUID);
+        if ($user[0]["dn"] === NULL) { 
+            return false; 
+        }
+        $userDn = $user[0]["dn"];
+        return $userDn;
+    }
+    
+    /**
+    * Return a list of all users in AD
+    * 
+    * @param bool $includeDescription Return a description of the user
+    * @param string $search Search parameter
+    * @param bool $sorted Sort the user accounts
+    * @return array
+    */
+    public function all($includeDescription = false, $search = "*", $sorted = true)
+    {
+        if (!$this->adldap->getLdapBind()) { return false; }
+        
+        // Perform the search and grab all their details
+        $filter = "(&(objectClass=user)(samaccounttype=" . adLDAP::ADLDAP_NORMAL_ACCOUNT .")(objectCategory=person)(cn=" . $search . "))";
+        $fields = array("samaccountname","displayname");
+        $sr = ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields);
+        $entries = ldap_get_entries($this->adldap->getLdapConnection(), $sr);
+
+        $usersArray = array();
+        for ($i=0; $i<$entries["count"]; $i++){
+            if ($includeDescription && strlen($entries[$i]["displayname"][0])>0){
+                $usersArray[$entries[$i]["samaccountname"][0]] = $entries[$i]["displayname"][0];
+            } elseif ($includeDescription){
+                $usersArray[$entries[$i]["samaccountname"][0]] = $entries[$i]["samaccountname"][0];
+            } else {
+                array_push($usersArray, $entries[$i]["samaccountname"][0]);
+            }
+        }
+        if ($sorted) { 
+            asort($usersArray); 
+        }
+        return $usersArray;
+    }
+    
+    /**
+    * Converts a username (samAccountName) to a GUID
+    * 
+    * @param string $username The username to query
+    * @return string
+    */
+    public function usernameToGuid($username) 
+    {
+        if (!$this->adldap->getLdapBind()){ return false; }
+        if ($username === null){ return "Missing compulsory field [username]"; }
+        
+        $filter = "samaccountname=" . $username; 
+        $fields = array("objectGUID"); 
+        $sr = @ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields); 
+        if (ldap_count_entries($this->adldap->getLdapConnection(), $sr) > 0) { 
+            $entry = @ldap_first_entry($this->adldap->getLdapConnection(), $sr); 
+            $guid = @ldap_get_values_len($this->adldap->getLdapConnection(), $entry, 'objectGUID'); 
+            $strGUID = $this->adldap->utilities()->binaryToText($guid[0]);          
+            return $strGUID; 
+        }
+        return false; 
+    }
+    
+    /**
+    * Return a list of all users in AD that have a specific value in a field
+    *
+    * @param bool $includeDescription Return a description of the user
+    * @param string $searchField Field to search search for
+    * @param string $searchFilter Value to search for in the specified field
+    * @param bool $sorted Sort the user accounts
+    * @return array
+    */
+    public function find($includeDescription = false, $searchField = false, $searchFilter = false, $sorted = true){
+        if (!$this->adldap->getLdapBind()){ return false; }
+          
+        // Perform the search and grab all their details
+        $searchParams = "";
+        if ($searchField) {
+            $searchParams = "(" . $searchField . "=" . $searchFilter . ")";
+        }                           
+        $filter = "(&(objectClass=user)(samaccounttype=" . adLDAP::ADLDAP_NORMAL_ACCOUNT .")(objectCategory=person)" . $searchParams . ")";
+        $fields = array("samaccountname","displayname");
+        $sr = ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields);
+        $entries = ldap_get_entries($this->adldap->getLdapConnection(), $sr);
+
+        $usersArray = array();
+        for ($i=0; $i < $entries["count"]; $i++) {
+            if ($includeDescription && strlen($entries[$i]["displayname"][0]) > 0) {
+                $usersArray[$entries[$i]["samaccountname"][0]] = $entries[$i]["displayname"][0];
+            }
+            else if ($includeDescription) {
+                $usersArray[$entries[$i]["samaccountname"][0]] = $entries[$i]["samaccountname"][0];
+            }
+            else {
+                array_push($usersArray, $entries[$i]["samaccountname"][0]);
+            }
+        }
+        if ($sorted){ 
+          asort($usersArray); 
+        }
+        return ($usersArray);
+    }
+    
+    /**
+    * Move a user account to a different OU
+    *
+    * @param string $username The username to move (please be careful here!)
+    * @param array $container The container or containers to move the user to (please be careful here!).
+    * accepts containers in 1. parent 2. child order
+    * @return array
+    */
+    public function move($username, $container) 
+    {
+        if (!$this->adldap->getLdapBind()) { return false; }
+        if ($username === null) { return "Missing compulsory field [username]"; }
+        if ($container === null) { return "Missing compulsory field [container]"; }
+        if (!is_array($container)) { return "Container must be an array"; }
+        
+        $userInfo = $this->info($username, array("*"));
+        $dn = $userInfo[0]['distinguishedname'][0];
+        $newRDn = "cn=" . $username;
+        $container = array_reverse($container);
+        $newContainer = "ou=" . implode(",ou=",$container);
+        $newBaseDn = strtolower($newContainer) . "," . $this->adldap->getBaseDn();
+        $result = @ldap_rename($this->adldap->getLdapConnection(), $dn, $newRDn, $newBaseDn, true);
+        if ($result !== true) {
+            return false;
+        }
+        return true;
+    }
+    
+    /**
+    * Get the last logon time of any user as a Unix timestamp
+    * 
+    * @param string $username
+    * @return long $unixTimestamp
+    */
+    public function getLastLogon($username) {
+        if (!$this->adldap->getLdapBind()) { return false; }
+        if ($username === null) { return "Missing compulsory field [username]"; }
+        $userInfo = $this->info($username, array("lastLogonTimestamp"));
+        $lastLogon = adLDAPUtils::convertWindowsTimeToUnixTime($userInfo[0]['lastLogonTimestamp'][0]);
+        return $lastLogon;
+    }
+    
+}
+?>
diff --git a/inc/adLDAP/classes/adLDAPUtils.php b/inc/adLDAP/classes/adLDAPUtils.php
new file mode 100644
index 000000000..f039a4290
--- /dev/null
+++ b/inc/adLDAP/classes/adLDAPUtils.php
@@ -0,0 +1,264 @@
+adldap = $adldap;
+    }
+    
+    
+    /**
+    * Take an LDAP query and return the nice names, without all the LDAP prefixes (eg. CN, DN)
+    *
+    * @param array $groups
+    * @return array
+    */
+    public function niceNames($groups)
+    {
+
+        $groupArray = array();
+        for ($i=0; $i<$groups["count"]; $i++){ // For each group
+            $line = $groups[$i];
+            
+            if (strlen($line)>0) { 
+                // More presumptions, they're all prefixed with CN=
+                // so we ditch the first three characters and the group
+                // name goes up to the first comma
+                $bits=explode(",", $line);
+                $groupArray[] = substr($bits[0], 3, (strlen($bits[0])-3));
+            }
+        }
+        return $groupArray;    
+    }
+    
+    /**
+    * Escape characters for use in an ldap_create function
+    * 
+    * @param string $str
+    * @return string
+    */
+    public function escapeCharacters($str) {
+        $str = str_replace(",", "\,", $str);
+        return $str;
+    }
+    
+    /**
+    * Escape strings for the use in LDAP filters
+    * 
+    * DEVELOPERS SHOULD BE DOING PROPER FILTERING IF THEY'RE ACCEPTING USER INPUT
+    * Ported from Perl's Net::LDAP::Util escape_filter_value
+    *
+    * @param string $str The string the parse
+    * @author Port by Andreas Gohr 
+    * @return string
+    */
+    public function ldapSlashes($str){
+        return preg_replace('/([\x00-\x1F\*\(\)\\\\])/e',
+                            '"\\\\\".join("",unpack("H2","$1"))',
+                            $str);
+    }
+    
+    /**
+    * Converts a string GUID to a hexdecimal value so it can be queried
+    * 
+    * @param string $strGUID A string representation of a GUID
+    * @return string
+    */
+    public function strGuidToHex($strGUID) 
+    {
+        $strGUID = str_replace('-', '', $strGUID);
+
+        $octet_str = '\\' . substr($strGUID, 6, 2);
+        $octet_str .= '\\' . substr($strGUID, 4, 2);
+        $octet_str .= '\\' . substr($strGUID, 2, 2);
+        $octet_str .= '\\' . substr($strGUID, 0, 2);
+        $octet_str .= '\\' . substr($strGUID, 10, 2);
+        $octet_str .= '\\' . substr($strGUID, 8, 2);
+        $octet_str .= '\\' . substr($strGUID, 14, 2);
+        $octet_str .= '\\' . substr($strGUID, 12, 2);
+        //$octet_str .= '\\' . substr($strGUID, 16, strlen($strGUID));
+        for ($i=16; $i<=(strlen($strGUID)-2); $i++) {
+            if (($i % 2) == 0) {
+                $octet_str .= '\\' . substr($strGUID, $i, 2);
+            }
+        }
+        
+        return $octet_str;
+    }
+    
+    /**
+    * Convert a binary SID to a text SID
+    * 
+    * @param string $binsid A Binary SID
+    * @return string
+    */
+     public function getTextSID($binsid) {
+        $hex_sid = bin2hex($binsid);
+        $rev = hexdec(substr($hex_sid, 0, 2));
+        $subcount = hexdec(substr($hex_sid, 2, 2));
+        $auth = hexdec(substr($hex_sid, 4, 12));
+        $result = "$rev-$auth";
+
+        for ($x=0;$x < $subcount; $x++) {
+            $subauth[$x] =
+                hexdec($this->littleEndian(substr($hex_sid, 16 + ($x * 8), 8)));
+                $result .= "-" . $subauth[$x];
+        }
+
+        // Cheat by tacking on the S-
+        return 'S-' . $result;
+     }
+     
+    /**
+    * Converts a little-endian hex number to one that hexdec() can convert
+    * 
+    * @param string $hex A hex code
+    * @return string
+    */
+     public function littleEndian($hex) 
+     {
+        $result = '';
+        for ($x = strlen($hex) - 2; $x >= 0; $x = $x - 2) {
+            $result .= substr($hex, $x, 2);
+        }
+        return $result;
+     }
+     
+     /**
+    * Converts a binary attribute to a string
+    * 
+    * @param string $bin A binary LDAP attribute
+    * @return string
+    */
+    public function binaryToText($bin) 
+    {
+        $hex_guid = bin2hex($bin); 
+        $hex_guid_to_guid_str = ''; 
+        for($k = 1; $k <= 4; ++$k) { 
+            $hex_guid_to_guid_str .= substr($hex_guid, 8 - 2 * $k, 2); 
+        } 
+        $hex_guid_to_guid_str .= '-'; 
+        for($k = 1; $k <= 2; ++$k) { 
+            $hex_guid_to_guid_str .= substr($hex_guid, 12 - 2 * $k, 2); 
+        } 
+        $hex_guid_to_guid_str .= '-'; 
+        for($k = 1; $k <= 2; ++$k) { 
+            $hex_guid_to_guid_str .= substr($hex_guid, 16 - 2 * $k, 2); 
+        } 
+        $hex_guid_to_guid_str .= '-' . substr($hex_guid, 16, 4); 
+        $hex_guid_to_guid_str .= '-' . substr($hex_guid, 20); 
+        return strtoupper($hex_guid_to_guid_str);   
+    }
+    
+    /**
+    * Converts a binary GUID to a string GUID
+    * 
+    * @param string $binaryGuid The binary GUID attribute to convert
+    * @return string
+    */
+    public function decodeGuid($binaryGuid) 
+    {
+        if ($binaryGuid === null){ return "Missing compulsory field [binaryGuid]"; }
+        
+        $strGUID = $this->binaryToText($binaryGuid);          
+        return $strGUID; 
+    }
+    
+    /**
+    * Convert a boolean value to a string
+    * You should never need to call this yourself
+    *
+    * @param bool $bool Boolean value
+    * @return string
+    */
+    public function boolToStr($bool) 
+    {
+        return ($bool) ? 'TRUE' : 'FALSE';
+    }
+    
+    /**
+    * Convert 8bit characters e.g. accented characters to UTF8 encoded characters
+    */
+    public function encode8Bit(&$item, $key) {
+        $encode = false;
+        if (is_string($item)) {
+            for ($i=0; $i> 7) {
+                    $encode = true;
+                }
+            }
+        }
+        if ($encode === true && $key != 'password') {
+            $item = utf8_encode($item);   
+        }
+    }  
+    
+    /**
+    * Get the current class version number
+    * 
+    * @return string
+    */
+    public function getVersion() {
+        return self::ADLDAP_VERSION;
+    }
+    
+    /**
+    * Round a Windows timestamp down to seconds and remove the seconds between 1601-01-01 and 1970-01-01
+    * 
+    * @param long $windowsTime
+    * @return long $unixTime
+    */
+    public static function convertWindowsTimeToUnixTime($windowsTime) {
+      $unixTime = round($windowsTime / 10000000) - 11644477200; 
+      return $unixTime; 
+    }
+}
+
+?>
\ No newline at end of file
diff --git a/inc/adLDAP/collections/adLDAPCollection.php b/inc/adLDAP/collections/adLDAPCollection.php
new file mode 100644
index 000000000..c0a2eb2fa
--- /dev/null
+++ b/inc/adLDAP/collections/adLDAPCollection.php
@@ -0,0 +1,137 @@
+setInfo($info);   
+        $this->adldap = $adldap;
+    }
+    
+    /**
+    * Set the raw info array from Active Directory
+    * 
+    * @param array $info
+    */
+    public function setInfo(array $info) 
+    {
+        if ($this->info && sizeof($info) >= 1) {
+            unset($this->info);
+        }
+        $this->info = $info;   
+    }
+    
+    /**
+    * Magic get method to retrieve data from the raw array in a formatted way
+    * 
+    * @param string $attribute
+    * @return mixed
+    */
+    public function __get($attribute)
+    {
+        if (isset($this->info[0]) && is_array($this->info[0])) {
+            foreach ($this->info[0] as $keyAttr => $valueAttr) {
+                if (strtolower($keyAttr) == strtolower($attribute)) {
+                    if ($this->info[0][strtolower($attribute)]['count'] == 1) {
+                        return $this->info[0][strtolower($attribute)][0];   
+                    }
+                    else {
+                        $array = array();
+                        foreach ($this->info[0][strtolower($attribute)] as $key => $value) {
+                            if ((string)$key != 'count') {
+                                $array[$key] = $value;
+                            } 
+                        }  
+                        return $array;   
+                    }
+                }   
+            }
+        }
+        else {
+            return NULL;   
+        }
+    }    
+    
+    /**
+    * Magic set method to update an attribute
+    * 
+    * @param string $attribute
+    * @param string $value
+    * @return bool
+    */
+    abstract public function __set($attribute, $value);
+    
+    /** 
+    * Magic isset method to check for the existence of an attribute 
+    * 
+    * @param string $attribute 
+    * @return bool 
+    */ 
+    public function __isset($attribute) {
+        if (isset($this->info[0]) && is_array($this->info[0])) { 
+            foreach ($this->info[0] as $keyAttr => $valueAttr) { 
+                if (strtolower($keyAttr) == strtolower($attribute)) { 
+                    return true; 
+                } 
+            } 
+        } 
+        return false; 
+     } 
+}
+?>
diff --git a/inc/adLDAP/collections/adLDAPComputerCollection.php b/inc/adLDAP/collections/adLDAPComputerCollection.php
new file mode 100644
index 000000000..4f11d8f41
--- /dev/null
+++ b/inc/adLDAP/collections/adLDAPComputerCollection.php
@@ -0,0 +1,46 @@
+
diff --git a/inc/adLDAP/collections/adLDAPContactCollection.php b/inc/adLDAP/collections/adLDAPContactCollection.php
new file mode 100644
index 000000000..d42fe6d4c
--- /dev/null
+++ b/inc/adLDAP/collections/adLDAPContactCollection.php
@@ -0,0 +1,46 @@
+
diff --git a/inc/adLDAP/collections/adLDAPGroupCollection.php b/inc/adLDAP/collections/adLDAPGroupCollection.php
new file mode 100644
index 000000000..cff12fc20
--- /dev/null
+++ b/inc/adLDAP/collections/adLDAPGroupCollection.php
@@ -0,0 +1,46 @@
+
diff --git a/inc/adLDAP/collections/adLDAPUserCollection.php b/inc/adLDAP/collections/adLDAPUserCollection.php
new file mode 100644
index 000000000..801d90296
--- /dev/null
+++ b/inc/adLDAP/collections/adLDAPUserCollection.php
@@ -0,0 +1,46 @@
+
diff --git a/inc/auth/ad.class.php b/inc/auth/ad.class.php
index e161c2939..85db7ec39 100644
--- a/inc/auth/ad.class.php
+++ b/inc/auth/ad.class.php
@@ -39,7 +39,7 @@
  * @author  Andreas Gohr 
  */
 
-require_once(DOKU_INC.'inc/adLDAP.php');
+require_once(DOKU_INC.'inc/adLDAP/adLDAP.php');
 
 class auth_ad extends auth_basic {
     var $cnf = null;
@@ -164,7 +164,7 @@ class auth_ad extends auth_basic {
         $fields = array_unique($fields);
 
         //get info for given user
-        $result = $this->adldap->user_info($user, $fields);
+        $result = $this->adldap->user()->info($user, $fields);
         if($result == false){
             return array();
         }
@@ -187,7 +187,7 @@ class auth_ad extends auth_basic {
         }
 
         // handle ActiveDirectory memberOf
-        $info['grps'] = $this->adldap->user_groups($user,(bool) $this->opts['recursive_groups']);
+        $info['grps'] = $this->adldap->user()->groups($user,(bool) $this->opts['recursive_groups']);
 
         if (is_array($info['grps'])) {
             foreach ($info['grps'] as $ndx => $group) {
@@ -202,9 +202,7 @@ class auth_ad extends auth_basic {
 
         // check expiry time
         if($info['expires'] && $this->cnf['expirywarn']){
-            $result   = $this->adldap->domain_info(array('maxpwdage')); // maximum pass age
-            $maxage   = -1 * $result['maxpwdage'][0] / 10000000; // negative 100 nanosecs
-            $timeleft = $maxage - (time() - $info['lastpwd']);
+            $timeleft = $this->adldap->user()->passwordExpiry($user); // returns unixtime
             $timeleft = round($timeleft/(24*60*60));
             $info['expiresin'] = $timeleft;
 
@@ -268,7 +266,7 @@ class auth_ad extends auth_basic {
 
         if ($this->users === null) {
             //get info for given user
-            $result = $this->adldap->all_users();
+            $result = $this->adldap->user()->all();
             if (!$result) return array();
             $this->users = array_fill_keys($result, false);
         }
@@ -306,7 +304,7 @@ class auth_ad extends auth_basic {
         // password changing
         if(isset($changes['pass'])){
             try {
-                $return = $this->adldap->user_password($user,$changes['pass']);
+                $return = $this->adldap->user()->password($user,$changes['pass']);
             } catch (adLDAPException $e) {
                 if ($this->cnf['debug']) msg('AD Auth: '.$e->getMessage(), -1);
                 $return = false;
@@ -328,7 +326,7 @@ class auth_ad extends auth_basic {
         }
         if(count($adchanges)){
             try {
-                $return = $return & $this->adldap->user_modify($user,$adchanges);
+                $return = $return & $this->adldap->user()->modify($user,$adchanges);
             } catch (adLDAPException $e) {
                 if ($this->cnf['debug']) msg('AD Auth: '.$e->getMessage(), -1);
                 $return = false;
-- 
cgit v1.2.3


From d48e3de576477fd446f8e613d229deba484014bc Mon Sep 17 00:00:00 2001
From: Andreas Gohr 
Date: Sat, 6 Oct 2012 10:56:39 +0200
Subject: fixed auth related tests

---
 _test/tests/inc/auth_aclcheck.test.php   | 2 +-
 _test/tests/inc/auth_admincheck.test.php | 4 ++--
 _test/tests/inc/remote.test.php          | 2 +-
 3 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/_test/tests/inc/auth_aclcheck.test.php b/_test/tests/inc/auth_aclcheck.test.php
index 991f82da7..5dc0d7f60 100644
--- a/_test/tests/inc/auth_aclcheck.test.php
+++ b/_test/tests/inc/auth_aclcheck.test.php
@@ -11,7 +11,7 @@ class auth_acl_test extends DokuWikiTest {
         global $auth;
         $this->oldConf = $conf;
         $this->oldAuthAcl = $AUTH_ACL;
-        $auth = new auth_basic();
+        $auth = new DokuWiki_Auth_Plugin();
     }
 
     function teardown() {
diff --git a/_test/tests/inc/auth_admincheck.test.php b/_test/tests/inc/auth_admincheck.test.php
index d88399cbe..2fb5902d7 100644
--- a/_test/tests/inc/auth_admincheck.test.php
+++ b/_test/tests/inc/auth_admincheck.test.php
@@ -1,6 +1,6 @@
 
Date: Sat, 6 Oct 2012 11:11:50 +0200
Subject: changed default auth to authplain

We need to decide how to handle the renaming of the auth classes. Should
this be done automatically somehow? Or is an admin expected to fix this
manually when updating?
---
 conf/dokuwiki.php | 2 +-
 inc/auth.php      | 5 ++++-
 2 files changed, 5 insertions(+), 2 deletions(-)

diff --git a/conf/dokuwiki.php b/conf/dokuwiki.php
index cbd42115d..f5524de6b 100644
--- a/conf/dokuwiki.php
+++ b/conf/dokuwiki.php
@@ -54,7 +54,7 @@ $conf['hidepages']   = '';                //Regexp for pages to be skipped from
 /* Authentication Settings */
 $conf['useacl']      = 0;                //Use Access Control Lists to restrict access?
 $conf['autopasswd']  = 1;                //autogenerate passwords and email them to user
-$conf['authtype']    = 'plain';          //which authentication backend should be used
+$conf['authtype']    = 'authplain';      //which authentication backend should be used
 $conf['passcrypt']   = 'smd5';           //Used crypt method (smd5,md5,sha1,ssha,crypt,mysql,my411)
 $conf['defaultgroup']= 'user';           //Default groups new Users are added to
 $conf['superuser']   = '!!not set!!';    //The admin can be user or @group or comma separated list user1,@group1,user2
diff --git a/inc/auth.php b/inc/auth.php
index 25b9e4632..3fe465cbb 100644
--- a/inc/auth.php
+++ b/inc/auth.php
@@ -54,7 +54,10 @@ function auth_setup() {
     	}
     }
 
-	if(!$auth) return false;
+	if(!$auth){
+        msg($lang['authtempfail'], -1);
+        return false;
+    }
 
 	if ($auth && $auth->success == false) {
 		// degrade to unauthenticated user
-- 
cgit v1.2.3


From 94c0297d119ce52ad794c18f26220311e3c0ed8c Mon Sep 17 00:00:00 2001
From: Andreas Gohr 
Date: Sat, 6 Oct 2012 11:31:26 +0200
Subject: completed plugin.info.txt files

---
 lib/plugins/auth.php                  | 7 +++----
 lib/plugins/authad/plugin.info.txt    | 8 ++++----
 lib/plugins/authldap/plugin.info.txt  | 8 ++++----
 lib/plugins/authmysql/plugin.info.txt | 8 ++++----
 lib/plugins/authpgsql/plugin.info.txt | 8 ++++----
 lib/plugins/authplain/plugin.info.txt | 8 ++++----
 6 files changed, 23 insertions(+), 24 deletions(-)

diff --git a/lib/plugins/auth.php b/lib/plugins/auth.php
index 637435252..39d63d8a1 100644
--- a/lib/plugins/auth.php
+++ b/lib/plugins/auth.php
@@ -1,4 +1,7 @@
 
  * @author    Jan Schumann 
-
  */
-// must be run within Dokuwiki
-if(!defined('DOKU_INC')) die();
-
 class DokuWiki_Auth_Plugin extends DokuWiki_Plugin {
     var $success = true;
 
diff --git a/lib/plugins/authad/plugin.info.txt b/lib/plugins/authad/plugin.info.txt
index ad565b853..598eb848b 100644
--- a/lib/plugins/authad/plugin.info.txt
+++ b/lib/plugins/authad/plugin.info.txt
@@ -1,7 +1,7 @@
 base   authad
-author
-email
-date
+author Andreas Gohr
+email  andi@splitbrain.org
+date   2012-10-06
 name   active directory auth plugin
 desc   Provides authentication against a Microsoft Active Directory
-url
+url    http://www.dokuwiki.org/plugin:authad
diff --git a/lib/plugins/authldap/plugin.info.txt b/lib/plugins/authldap/plugin.info.txt
index c36385224..2af8cf00a 100644
--- a/lib/plugins/authldap/plugin.info.txt
+++ b/lib/plugins/authldap/plugin.info.txt
@@ -1,7 +1,7 @@
 base   authldap
-author
-email
-date
+author Andreas Gohr
+email  andi@splitbrain.org
+date   2012-10-06
 name   ldap auth plugin
 desc   Provides authentication against am LDAP server
-url
+url    http://www.dokuwiki.org/plugin:authldap
diff --git a/lib/plugins/authmysql/plugin.info.txt b/lib/plugins/authmysql/plugin.info.txt
index d08d4a7ef..c1e118427 100644
--- a/lib/plugins/authmysql/plugin.info.txt
+++ b/lib/plugins/authmysql/plugin.info.txt
@@ -1,7 +1,7 @@
 base   authmysql
-author
-email
-date
+author Andreas Gohr
+email  andi@splitbrain.org
+date   2012-10-06
 name   mysql auth plugin
 desc   Provides authentication against a MySQL Server
-url
+url    http://www.dokuwiki.org/plugin:authmysql
diff --git a/lib/plugins/authpgsql/plugin.info.txt b/lib/plugins/authpgsql/plugin.info.txt
index ad565b853..598eb848b 100644
--- a/lib/plugins/authpgsql/plugin.info.txt
+++ b/lib/plugins/authpgsql/plugin.info.txt
@@ -1,7 +1,7 @@
 base   authad
-author
-email
-date
+author Andreas Gohr
+email  andi@splitbrain.org
+date   2012-10-06
 name   active directory auth plugin
 desc   Provides authentication against a Microsoft Active Directory
-url
+url    http://www.dokuwiki.org/plugin:authad
diff --git a/lib/plugins/authplain/plugin.info.txt b/lib/plugins/authplain/plugin.info.txt
index 3273e21d7..cde38eaac 100644
--- a/lib/plugins/authplain/plugin.info.txt
+++ b/lib/plugins/authplain/plugin.info.txt
@@ -1,7 +1,7 @@
 base   authplain
-author
-email
-date
+author Andreas Gohr
+email  andi@splitbrain.org
+date   2012-10-06
 name   auth plugin
 desc   Provides authentication against local password storage
-url
+url    http://www.dokuwiki.org/plugin:authplain
-- 
cgit v1.2.3


From 7840324d1522858cf4a504321e3a341cd35e44b6 Mon Sep 17 00:00:00 2001
From: Andreas Gohr 
Date: Sat, 6 Oct 2012 16:54:44 +0200
Subject: enabled authplain plugin for testsuite

---
 _test/bootstrap.php | 1 +
 1 file changed, 1 insertion(+)

diff --git a/_test/bootstrap.php b/_test/bootstrap.php
index 310b3627a..732fef9ed 100644
--- a/_test/bootstrap.php
+++ b/_test/bootstrap.php
@@ -27,6 +27,7 @@ define('DOKU_TMP_DATA', TMP_DIR.'/data/');
 
 // default plugins
 $default_plugins = array(
+    'authplain',
     'acl',
     'config',
     'info',
-- 
cgit v1.2.3


From ecd445c000e4e54bf7228890848222312cffd3e3 Mon Sep 17 00:00:00 2001
From: Andreas Gohr 
Date: Sun, 7 Oct 2012 09:43:34 +0200
Subject: PHP5ized the auth plugin base

---
 lib/plugins/auth.php | 146 ++++++++++++++++++++++++++++-----------------------
 1 file changed, 80 insertions(+), 66 deletions(-)

diff --git a/lib/plugins/auth.php b/lib/plugins/auth.php
index 39d63d8a1..4c3c585cf 100644
--- a/lib/plugins/auth.php
+++ b/lib/plugins/auth.php
@@ -13,14 +13,14 @@ if(!defined('DOKU_INC')) die();
  * @author    Jan Schumann 
  */
 class DokuWiki_Auth_Plugin extends DokuWiki_Plugin {
-    var $success = true;
+    public $success = true;
 
     /**
-     * Posible things an auth backend module may be able to
+     * Possible things an auth backend module may be able to
      * do. The things a backend can do need to be set to true
      * in the constructor.
      */
-    var $cando = array (
+    protected $cando = array(
         'addUser'     => false, // can Users be created?
         'delUser'     => false, // can Users be deleted?
         'modLogin'    => false, // can login names be changed?
@@ -32,7 +32,7 @@ class DokuWiki_Auth_Plugin extends DokuWiki_Plugin {
         'getUserCount'=> false, // can the number of users be retrieved?
         'getGroups'   => false, // can a list of available groups be retrieved?
         'external'    => false, // does the module do external auth checking?
-        'logout'      => true,  // can the user logout again? (eg. not possible with HTTP auth)
+        'logout'      => true, // can the user logout again? (eg. not possible with HTTP auth)
     );
 
     /**
@@ -46,7 +46,7 @@ class DokuWiki_Auth_Plugin extends DokuWiki_Plugin {
      *
      * @author  Christopher Smith 
      */
-    function __construct() {
+    public function __construct() {
         // the base class constructor does nothing, derived class
         // constructors do the real work
     }
@@ -62,29 +62,30 @@ class DokuWiki_Auth_Plugin extends DokuWiki_Plugin {
      * shortcut capabilities start with uppercase letter
      *
      * @author  Andreas Gohr 
+     * @param   string $cap the capability to check
      * @return  bool
      */
-    function canDo($cap) {
-        switch($cap){
+    public function canDo($cap) {
+        switch($cap) {
             case 'Profile':
                 // can at least one of the user's properties be changed?
-                return ( $this->cando['modPass']  ||
-                        $this->cando['modName']  ||
-                        $this->cando['modMail'] );
+                return ($this->cando['modPass'] ||
+                    $this->cando['modName'] ||
+                    $this->cando['modMail']);
                 break;
             case 'UserMod':
                 // can at least anything be changed?
-                return ( $this->cando['modPass']   ||
-                        $this->cando['modName']   ||
-                        $this->cando['modMail']   ||
-                        $this->cando['modLogin']  ||
-                        $this->cando['modGroups'] ||
-                        $this->cando['modMail'] );
+                return ($this->cando['modPass'] ||
+                    $this->cando['modName'] ||
+                    $this->cando['modMail'] ||
+                    $this->cando['modLogin'] ||
+                    $this->cando['modGroups'] ||
+                    $this->cando['modMail']);
                 break;
             default:
                 // print a helping message for developers
-                if(!isset($this->cando[$cap])){
-                    msg("Check for unknown capability '$cap' - Do you use an outdated Plugin?",-1);
+                if(!isset($this->cando[$cap])) {
+                    msg("Check for unknown capability '$cap' - Do you use an outdated Plugin?", -1);
                 }
                 return $this->cando[$cap];
         }
@@ -99,10 +100,10 @@ class DokuWiki_Auth_Plugin extends DokuWiki_Plugin {
      *
      * @author Gabriel Birke 
      * @param string $type Modification type ('create', 'modify', 'delete')
-     * @param array $params Parameters for the createUser, modifyUser or deleteUsers method. The content of this array depends on the modification type
+     * @param array  $params Parameters for the createUser, modifyUser or deleteUsers method. The content of this array depends on the modification type
      * @return mixed Result from the modification function or false if an event handler has canceled the action
      */
-    function triggerUserMod($type, $params) {
+    public function triggerUserMod($type, $params) {
         $validTypes = array(
             'create' => 'createUser',
             'modify' => 'modifyUser',
@@ -111,9 +112,9 @@ class DokuWiki_Auth_Plugin extends DokuWiki_Plugin {
         if(empty($validTypes[$type]))
             return false;
         $eventdata = array('type' => $type, 'params' => $params, 'modification_result' => null);
-        $evt = new Doku_Event('AUTH_USER_CHANGE', $eventdata);
-        if ($evt->advise_before(true)) {
-            $result = call_user_func_array(array($this, $validTypes[$type]), $params);
+        $evt       = new Doku_Event('AUTH_USER_CHANGE', $eventdata);
+        if($evt->advise_before(true)) {
+            $result                           = call_user_func_array(array($this, $validTypes[$type]), $params);
             $evt->data['modification_result'] = $result;
         }
         $evt->advise_after();
@@ -130,7 +131,7 @@ class DokuWiki_Auth_Plugin extends DokuWiki_Plugin {
      * @see     auth_logoff()
      * @author  Andreas Gohr 
      */
-    function logOff(){
+    public function logOff() {
     }
 
     /**
@@ -166,7 +167,7 @@ class DokuWiki_Auth_Plugin extends DokuWiki_Plugin {
      * @param   bool    $sticky  Cookie should not expire
      * @return  bool             true on successful auth
      */
-    function trustExternal($user,$pass,$sticky=false){
+    public function trustExternal($user, $pass, $sticky = false) {
         /* some example:
 
         global $USERINFO;
@@ -197,9 +198,11 @@ class DokuWiki_Auth_Plugin extends DokuWiki_Plugin {
      * May be ommited if trustExternal is used.
      *
      * @author  Andreas Gohr 
+     * @param   string $user the user name
+     * @param   string $pass the clear text password
      * @return  bool
      */
-    function checkPass($user,$pass){
+    public function checkPass($user, $pass) {
         msg("no valid authorisation system in use", -1);
         return false;
     }
@@ -215,9 +218,10 @@ class DokuWiki_Auth_Plugin extends DokuWiki_Plugin {
      * grps array   list of groups the user is in
      *
      * @author  Andreas Gohr 
+     * @param   string $user the user name
      * @return  array containing user data or false
      */
-    function getUserData($user) {
+    public function getUserData($user) {
         if(!$this->cando['external']) msg("no valid authorisation system in use", -1);
         return false;
     }
@@ -234,8 +238,14 @@ class DokuWiki_Auth_Plugin extends DokuWiki_Plugin {
      * Set addUser capability when implemented
      *
      * @author  Andreas Gohr 
+     * @param  string     $user
+     * @param  string     $pass
+     * @param  string     $name
+     * @param  string     $mail
+     * @param  null|array $grps
+     * @return bool|null
      */
-    function createUser($user,$pass,$name,$mail,$grps=null){
+    public function createUser($user, $pass, $name, $mail, $grps = null) {
         msg("authorisation method does not allow creation of new users", -1);
         return null;
     }
@@ -246,11 +256,11 @@ class DokuWiki_Auth_Plugin extends DokuWiki_Plugin {
      * Set the mod* capabilities according to the implemented features
      *
      * @author  Chris Smith 
-     * @param   $user      nick of the user to be changed
-     * @param   $changes   array of field/value pairs to be changed (password will be clear text)
+     * @param   string $user    nick of the user to be changed
+     * @param   array  $changes array of field/value pairs to be changed (password will be clear text)
      * @return  bool
      */
-    function modifyUser($user, $changes) {
+    public function modifyUser($user, $changes) {
         msg("authorisation method does not allow modifying of user data", -1);
         return false;
     }
@@ -264,7 +274,7 @@ class DokuWiki_Auth_Plugin extends DokuWiki_Plugin {
      * @param   array  $users
      * @return  int    number of users deleted
      */
-    function deleteUsers($users) {
+    public function deleteUsers($users) {
         msg("authorisation method does not allow deleting of users", -1);
         return false;
     }
@@ -275,9 +285,11 @@ class DokuWiki_Auth_Plugin extends DokuWiki_Plugin {
      *
      * Set getUserCount capability when implemented
      *
-     * @author  Chris Smith 
+     * @author Chris Smith 
+     * @param  array $filter array of field/pattern pairs, empty array for no filter
+     * @return int
      */
-    function getUserCount($filter=array()) {
+    public function getUserCount($filter = array()) {
         msg("authorisation method does not provide user counts", -1);
         return 0;
     }
@@ -288,12 +300,12 @@ class DokuWiki_Auth_Plugin extends DokuWiki_Plugin {
      * Set getUsers capability when implemented
      *
      * @author  Chris Smith 
-     * @param   start     index of first user to be returned
-     * @param   limit     max number of users to be returned
-     * @param   filter    array of field/pattern pairs, null for no filter
-     * @return  array of userinfo (refer getUserData for internal userinfo details)
+     * @param   int   $start     index of first user to be returned
+     * @param   int   $limit     max number of users to be returned
+     * @param   array $filter    array of field/pattern pairs, null for no filter
+     * @return  array list of userinfo (refer getUserData for internal userinfo details)
      */
-    function retrieveUsers($start=0,$limit=-1,$filter=null) {
+    public function retrieveUsers($start = 0, $limit = -1, $filter = null) {
         msg("authorisation method does not support mass retrieval of user data", -1);
         return array();
     }
@@ -304,9 +316,10 @@ class DokuWiki_Auth_Plugin extends DokuWiki_Plugin {
      * Set addGroup capability when implemented
      *
      * @author  Chris Smith 
+     * @param   string $group
      * @return  bool
      */
-    function addGroup($group) {
+    public function addGroup($group) {
         msg("authorisation method does not support independent group creation", -1);
         return false;
     }
@@ -317,9 +330,11 @@ class DokuWiki_Auth_Plugin extends DokuWiki_Plugin {
      * Set getGroups capability when implemented
      *
      * @author  Chris Smith 
+     * @param   int $start
+     * @param   int $limit
      * @return  array
      */
-    function retrieveGroups($start=0,$limit=0) {
+    public function retrieveGroups($start = 0, $limit = 0) {
         msg("authorisation method does not support group list retrieval", -1);
         return array();
     }
@@ -329,8 +344,10 @@ class DokuWiki_Auth_Plugin extends DokuWiki_Plugin {
      *
      * When your backend is caseinsensitive (eg. you can login with USER and
      * user) then you need to overwrite this method and return false
+     *
+     * @return bool
      */
-    function isCaseSensitive(){
+    public function isCaseSensitive() {
         return true;
     }
 
@@ -344,10 +361,10 @@ class DokuWiki_Auth_Plugin extends DokuWiki_Plugin {
      * This should be used to enforce username restrictions.
      *
      * @author Andreas Gohr 
-     * @param string $user - username
-     * @param string - the cleaned username
+     * @param string $user username
+     * @return string the cleaned username
      */
-    function cleanUser($user){
+    public function cleanUser($user) {
         return $user;
     }
 
@@ -363,14 +380,13 @@ class DokuWiki_Auth_Plugin extends DokuWiki_Plugin {
      * Groupnames are to be passed without a leading '@' here.
      *
      * @author Andreas Gohr 
-     * @param string $group - groupname
-     * @param string - the cleaned groupname
+     * @param  string $group groupname
+     * @return string the cleaned groupname
      */
-    function cleanGroup($group){
+    public function cleanGroup($group) {
         return $group;
     }
 
-
     /**
      * Check Session Cache validity [implement only where required/possible]
      *
@@ -396,27 +412,25 @@ class DokuWiki_Auth_Plugin extends DokuWiki_Plugin {
      * @author Andreas Gohr 
      * @return bool
      */
-    function useSessionCache($user){
+    public function useSessionCache($user) {
         global $conf;
         return ($_SESSION[DOKU_COOKIE]['auth']['time'] >= @filemtime($conf['cachedir'].'/sessionpurge'));
     }
 
+    /**
+     * loadConfig()
+     * merges the plugin's default settings with any local settings
+     * this function is automatically called through getConf()
+     */
+    function loadConfig() {
+        global $conf;
 
-  /**
-   * loadConfig()
-   * merges the plugin's default settings with any local settings
-   * this function is automatically called through getConf()
-   */
-    function loadConfig(){
-      global $conf;
-
-      parent::loadConfig();
-
-      $this->conf['debug'] = $conf['debug'];
-      $this->conf['useacl'] = $conf['useacl'];
-      $this->conf['disableactions'] = $conf['disableactions'];
-      $this->conf['autopasswd'] = $conf['autopasswd'];
-      $this->conf['passcrypt'] = $conf['ssha'];
-  }
+        parent::loadConfig();
 
+        $this->conf['debug']          = $conf['debug'];
+        $this->conf['useacl']         = $conf['useacl'];
+        $this->conf['disableactions'] = $conf['disableactions'];
+        $this->conf['autopasswd']     = $conf['autopasswd'];
+        $this->conf['passcrypt']      = $conf['ssha'];
+    }
 }
-- 
cgit v1.2.3


From 4d390d4260c028ff110151e305e93b80f3eb13eb Mon Sep 17 00:00:00 2001
From: Andreas Gohr 
Date: Fri, 9 Nov 2012 14:00:14 +0100
Subject: don't merge any global confs into auth plugin configs

---
 lib/plugins/auth.php | 17 -----------------
 1 file changed, 17 deletions(-)

diff --git a/lib/plugins/auth.php b/lib/plugins/auth.php
index 4c3c585cf..cd2f9ac12 100644
--- a/lib/plugins/auth.php
+++ b/lib/plugins/auth.php
@@ -416,21 +416,4 @@ class DokuWiki_Auth_Plugin extends DokuWiki_Plugin {
         global $conf;
         return ($_SESSION[DOKU_COOKIE]['auth']['time'] >= @filemtime($conf['cachedir'].'/sessionpurge'));
     }
-
-    /**
-     * loadConfig()
-     * merges the plugin's default settings with any local settings
-     * this function is automatically called through getConf()
-     */
-    function loadConfig() {
-        global $conf;
-
-        parent::loadConfig();
-
-        $this->conf['debug']          = $conf['debug'];
-        $this->conf['useacl']         = $conf['useacl'];
-        $this->conf['disableactions'] = $conf['disableactions'];
-        $this->conf['autopasswd']     = $conf['autopasswd'];
-        $this->conf['passcrypt']      = $conf['ssha'];
-    }
 }
-- 
cgit v1.2.3


From 454d868b911059adb8889a2d6afefa016d6a21f5 Mon Sep 17 00:00:00 2001
From: Andreas Gohr 
Date: Fri, 9 Nov 2012 14:04:41 +0100
Subject: make all sub auth classes call the parent constructor

This does nothing currently but allows us adding certain things
to the base class later.
---
 lib/plugins/auth.php           | 3 +++
 lib/plugins/authad/auth.php    | 2 ++
 lib/plugins/authldap/auth.php  | 2 ++
 lib/plugins/authmysql/auth.php | 2 ++
 lib/plugins/authpgsql/auth.php | 2 ++
 lib/plugins/authplain/auth.php | 1 +
 6 files changed, 12 insertions(+)

diff --git a/lib/plugins/auth.php b/lib/plugins/auth.php
index cd2f9ac12..cce2370d9 100644
--- a/lib/plugins/auth.php
+++ b/lib/plugins/auth.php
@@ -42,6 +42,9 @@ class DokuWiki_Auth_Plugin extends DokuWiki_Plugin {
      * able to operate. Set capabilities in $this->cando
      * array here
      *
+     * For future compatibility, sub classes should always include a call
+     * to parent::__constructor() in their constructors!
+     *
      * Set $this->success to false if checks fail
      *
      * @author  Christopher Smith 
diff --git a/lib/plugins/authad/auth.php b/lib/plugins/authad/auth.php
index 35c19f471..0900a3f87 100644
--- a/lib/plugins/authad/auth.php
+++ b/lib/plugins/authad/auth.php
@@ -82,6 +82,8 @@ class auth_plugin_authad extends DokuWiki_Auth_Plugin {
      * Constructor
      */
     public function __construct() {
+        parent::__construct();
+
         global $conf;
         $this->cnf = $conf['auth']['ad'];
 
diff --git a/lib/plugins/authldap/auth.php b/lib/plugins/authldap/auth.php
index 721abb48e..93683bc16 100644
--- a/lib/plugins/authldap/auth.php
+++ b/lib/plugins/authldap/auth.php
@@ -19,6 +19,8 @@ class auth_plugin_authldap extends DokuWiki_Auth_Plugin {
      * Constructor
      */
     function __construct(){
+        parent::__construct();
+
         global $conf;
         $this->cnf = $conf['auth']['ldap'];
 
diff --git a/lib/plugins/authmysql/auth.php b/lib/plugins/authmysql/auth.php
index 8a8f9a488..368bd74a2 100644
--- a/lib/plugins/authmysql/auth.php
+++ b/lib/plugins/authmysql/auth.php
@@ -28,6 +28,8 @@ class auth_plugin_authmysql extends DokuWiki_Auth_Plugin {
      * @author Matthias Grimm 
      */
     function __construct() {
+        parent::__construct();
+
         global $conf;
         $this->cnf = $conf['auth']['mysql'];
 
diff --git a/lib/plugins/authpgsql/auth.php b/lib/plugins/authpgsql/auth.php
index 824a77882..46154b6ca 100644
--- a/lib/plugins/authpgsql/auth.php
+++ b/lib/plugins/authpgsql/auth.php
@@ -31,6 +31,8 @@ class auth_plugin_authpgsql extends auth_plugin_authmysql
      * Constructor
      */
     function auth_plugin_authpgsql() {
+        parent::__construct();
+
         global $conf;
         $this->cnf = $conf['auth']['ad'];
 
diff --git a/lib/plugins/authplain/auth.php b/lib/plugins/authplain/auth.php
index 570d029ff..2e72bbd79 100644
--- a/lib/plugins/authplain/auth.php
+++ b/lib/plugins/authplain/auth.php
@@ -23,6 +23,7 @@ class auth_plugin_authplain extends DokuWiki_Auth_Plugin {
      * @author  Christopher Smith 
      */
     function __construct() {
+        parent::__construct();
         global $config_cascade;
 
         if (!@is_readable($config_cascade['plainauth.users']['default'])){
-- 
cgit v1.2.3


From 5a65cc7f5700c1a96e469b9f5a57bbe1ca879f53 Mon Sep 17 00:00:00 2001
From: Andreas Gohr 
Date: Fri, 9 Nov 2012 14:07:17 +0100
Subject: some comment cleanup in authad

---
 lib/plugins/authad/auth.php | 8 +-------
 1 file changed, 1 insertion(+), 7 deletions(-)

diff --git a/lib/plugins/authad/auth.php b/lib/plugins/authad/auth.php
index 0900a3f87..e82610327 100644
--- a/lib/plugins/authad/auth.php
+++ b/lib/plugins/authad/auth.php
@@ -13,15 +13,9 @@ require_once(DOKU_INC.'inc/adLDAP.php');
  * Usage:
  *   Set DokuWiki's local.protected.php auth setting to read
  *
- *   $conf['useacl']         = 1;
- *   $conf['disableactions'] = 'register';
- *   $conf['autopasswd']     = 0;
  *   $conf['authtype']       = 'authad';
- *   $conf['passcrypt']      = 'ssha';
  *
- *   $conf['auth']['ad']['account_suffix']     = '
- *
- * @my.domain.org';
+ *   $conf['auth']['ad']['account_suffix']     = '@my.domain.org';
  *   $conf['auth']['ad']['base_dn']            = 'DC=my,DC=domain,DC=org';
  *   $conf['auth']['ad']['domain_controllers'] = 'srv1.domain.org,srv2.domain.org';
  *
-- 
cgit v1.2.3


From 76ce1169a0c8cbb18423b1581800b9aa1050ccd5 Mon Sep 17 00:00:00 2001
From: Andreas Gohr 
Date: Fri, 9 Nov 2012 14:13:32 +0100
Subject: moved adLDAP to authad plugin and fixed includes

---
 inc/adLDAP/adLDAP.php                              | 951 ---------------------
 inc/adLDAP/classes/adLDAPComputers.php             | 153 ----
 inc/adLDAP/classes/adLDAPContacts.php              | 294 -------
 inc/adLDAP/classes/adLDAPExchange.php              | 390 ---------
 inc/adLDAP/classes/adLDAPFolders.php               | 179 ----
 inc/adLDAP/classes/adLDAPGroups.php                | 631 --------------
 inc/adLDAP/classes/adLDAPUsers.php                 | 682 ---------------
 inc/adLDAP/classes/adLDAPUtils.php                 | 264 ------
 inc/adLDAP/collections/adLDAPCollection.php        | 137 ---
 .../collections/adLDAPComputerCollection.php       |  46 -
 inc/adLDAP/collections/adLDAPContactCollection.php |  46 -
 inc/adLDAP/collections/adLDAPGroupCollection.php   |  46 -
 inc/adLDAP/collections/adLDAPUserCollection.php    |  46 -
 inc/load.php                                       |   1 -
 lib/plugins/authad/adLDAP/adLDAP.php               | 951 +++++++++++++++++++++
 .../authad/adLDAP/classes/adLDAPComputers.php      | 153 ++++
 .../authad/adLDAP/classes/adLDAPContacts.php       | 294 +++++++
 .../authad/adLDAP/classes/adLDAPExchange.php       | 390 +++++++++
 .../authad/adLDAP/classes/adLDAPFolders.php        | 179 ++++
 lib/plugins/authad/adLDAP/classes/adLDAPGroups.php | 631 ++++++++++++++
 lib/plugins/authad/adLDAP/classes/adLDAPUsers.php  | 682 +++++++++++++++
 lib/plugins/authad/adLDAP/classes/adLDAPUtils.php  | 264 ++++++
 .../authad/adLDAP/collections/adLDAPCollection.php | 137 +++
 .../collections/adLDAPComputerCollection.php       |  46 +
 .../adLDAP/collections/adLDAPContactCollection.php |  46 +
 .../adLDAP/collections/adLDAPGroupCollection.php   |  46 +
 .../adLDAP/collections/adLDAPUserCollection.php    |  46 +
 lib/plugins/authad/auth.php                        |   4 +-
 28 files changed, 3866 insertions(+), 3869 deletions(-)
 delete mode 100644 inc/adLDAP/adLDAP.php
 delete mode 100644 inc/adLDAP/classes/adLDAPComputers.php
 delete mode 100644 inc/adLDAP/classes/adLDAPContacts.php
 delete mode 100644 inc/adLDAP/classes/adLDAPExchange.php
 delete mode 100644 inc/adLDAP/classes/adLDAPFolders.php
 delete mode 100644 inc/adLDAP/classes/adLDAPGroups.php
 delete mode 100644 inc/adLDAP/classes/adLDAPUsers.php
 delete mode 100644 inc/adLDAP/classes/adLDAPUtils.php
 delete mode 100644 inc/adLDAP/collections/adLDAPCollection.php
 delete mode 100644 inc/adLDAP/collections/adLDAPComputerCollection.php
 delete mode 100644 inc/adLDAP/collections/adLDAPContactCollection.php
 delete mode 100644 inc/adLDAP/collections/adLDAPGroupCollection.php
 delete mode 100644 inc/adLDAP/collections/adLDAPUserCollection.php
 create mode 100644 lib/plugins/authad/adLDAP/adLDAP.php
 create mode 100644 lib/plugins/authad/adLDAP/classes/adLDAPComputers.php
 create mode 100644 lib/plugins/authad/adLDAP/classes/adLDAPContacts.php
 create mode 100644 lib/plugins/authad/adLDAP/classes/adLDAPExchange.php
 create mode 100644 lib/plugins/authad/adLDAP/classes/adLDAPFolders.php
 create mode 100644 lib/plugins/authad/adLDAP/classes/adLDAPGroups.php
 create mode 100644 lib/plugins/authad/adLDAP/classes/adLDAPUsers.php
 create mode 100644 lib/plugins/authad/adLDAP/classes/adLDAPUtils.php
 create mode 100644 lib/plugins/authad/adLDAP/collections/adLDAPCollection.php
 create mode 100644 lib/plugins/authad/adLDAP/collections/adLDAPComputerCollection.php
 create mode 100644 lib/plugins/authad/adLDAP/collections/adLDAPContactCollection.php
 create mode 100644 lib/plugins/authad/adLDAP/collections/adLDAPGroupCollection.php
 create mode 100644 lib/plugins/authad/adLDAP/collections/adLDAPUserCollection.php

diff --git a/inc/adLDAP/adLDAP.php b/inc/adLDAP/adLDAP.php
deleted file mode 100644
index a8f33b47e..000000000
--- a/inc/adLDAP/adLDAP.php
+++ /dev/null
@@ -1,951 +0,0 @@
-ldapConnection) {
-            return $this->ldapConnection;   
-        }
-        return false;
-    }
-    
-    /**
-    * Get the bind status
-    * 
-    * @return bool
-    */
-    public function getLdapBind() {
-        return $this->ldapBind;
-    }
-    
-    /**
-    * Get the current base DN
-    * 
-    * @return string
-    */
-    public function getBaseDn() {
-        return $this->baseDn;   
-    }
-    
-    /**
-    * The group class
-    * 
-    * @var adLDAPGroups
-    */
-    protected $groupClass;
-    
-    /**
-    * Get the group class interface
-    * 
-    * @return adLDAPGroups
-    */
-    public function group() {
-        if (!$this->groupClass) {
-            $this->groupClass = new adLDAPGroups($this);
-        }   
-        return $this->groupClass;
-    }
-    
-    /**
-    * The user class
-    * 
-    * @var adLDAPUsers
-    */
-    protected $userClass;
-    
-    /**
-    * Get the userclass interface
-    * 
-    * @return adLDAPUsers
-    */
-    public function user() {
-        if (!$this->userClass) {
-            $this->userClass = new adLDAPUsers($this);
-        }   
-        return $this->userClass;
-    }
-    
-    /**
-    * The folders class
-    * 
-    * @var adLDAPFolders
-    */
-    protected $folderClass;
-    
-    /**
-    * Get the folder class interface
-    * 
-    * @return adLDAPFolders
-    */
-    public function folder() {
-        if (!$this->folderClass) {
-            $this->folderClass = new adLDAPFolders($this);
-        }   
-        return $this->folderClass;
-    }
-    
-    /**
-    * The utils class
-    * 
-    * @var adLDAPUtils
-    */
-    protected $utilClass;
-    
-    /**
-    * Get the utils class interface
-    * 
-    * @return adLDAPUtils
-    */
-    public function utilities() {
-        if (!$this->utilClass) {
-            $this->utilClass = new adLDAPUtils($this);
-        }   
-        return $this->utilClass;
-    }
-    
-    /**
-    * The contacts class
-    * 
-    * @var adLDAPContacts
-    */
-    protected $contactClass;
-    
-    /**
-    * Get the contacts class interface
-    * 
-    * @return adLDAPContacts
-    */
-    public function contact() {
-        if (!$this->contactClass) {
-            $this->contactClass = new adLDAPContacts($this);
-        }   
-        return $this->contactClass;
-    }
-    
-    /**
-    * The exchange class
-    * 
-    * @var adLDAPExchange
-    */
-    protected $exchangeClass;
-    
-    /**
-    * Get the exchange class interface
-    * 
-    * @return adLDAPExchange
-    */
-    public function exchange() {
-        if (!$this->exchangeClass) {
-            $this->exchangeClass = new adLDAPExchange($this);
-        }   
-        return $this->exchangeClass;
-    }
-    
-    /**
-    * The computers class
-    * 
-    * @var adLDAPComputers
-    */
-    protected $computersClass;
-    
-    /**
-    * Get the computers class interface
-    * 
-    * @return adLDAPComputers
-    */
-    public function computer() {
-        if (!$this->computerClass) {
-            $this->computerClass = new adLDAPComputers($this);
-        }   
-        return $this->computerClass;
-    }
-
-    /**
-    * Getters and Setters
-    */
-    
-    /**
-    * Set the account suffix
-    * 
-    * @param string $accountSuffix
-    * @return void
-    */
-    public function setAccountSuffix($accountSuffix)
-    {
-          $this->accountSuffix = $accountSuffix;
-    }
-
-    /**
-    * Get the account suffix
-    * 
-    * @return string
-    */
-    public function getAccountSuffix()
-    {
-          return $this->accountSuffix;
-    }
-    
-    /**
-    * Set the domain controllers array
-    * 
-    * @param array $domainControllers
-    * @return void
-    */
-    public function setDomainControllers(array $domainControllers)
-    {
-          $this->domainControllers = $domainControllers;
-    }
-
-    /**
-    * Get the list of domain controllers
-    * 
-    * @return void
-    */
-    public function getDomainControllers()
-    {
-          return $this->domainControllers;
-    }
-    
-    /**
-    * Sets the port number your domain controller communicates over
-    * 
-    * @param int $adPort
-    */
-    public function setPort($adPort) 
-    { 
-        $this->adPort = $adPort; 
-    } 
-    
-    /**
-    * Gets the port number your domain controller communicates over
-    * 
-    * @return int
-    */
-    public function getPort() 
-    { 
-        return $this->adPort; 
-    } 
-    
-    /**
-    * Set the username of an account with higher priviledges
-    * 
-    * @param string $adminUsername
-    * @return void
-    */
-    public function setAdminUsername($adminUsername)
-    {
-          $this->adminUsername = $adminUsername;
-    }
-
-    /**
-    * Get the username of the account with higher priviledges
-    * 
-    * This will throw an exception for security reasons
-    */
-    public function getAdminUsername()
-    {
-          throw new adLDAPException('For security reasons you cannot access the domain administrator account details');
-    }
-    
-    /**
-    * Set the password of an account with higher priviledges
-    * 
-    * @param string $adminPassword
-    * @return void
-    */
-    public function setAdminPassword($adminPassword)
-    {
-          $this->adminPassword = $adminPassword;
-    }
-
-    /**
-    * Get the password of the account with higher priviledges
-    * 
-    * This will throw an exception for security reasons
-    */
-    public function getAdminPassword()
-    {
-          throw new adLDAPException('For security reasons you cannot access the domain administrator account details');
-    }
-    
-    /**
-    * Set whether to detect the true primary group
-    * 
-    * @param bool $realPrimaryGroup
-    * @return void
-    */
-    public function setRealPrimaryGroup($realPrimaryGroup)
-    {
-          $this->realPrimaryGroup = $realPrimaryGroup;
-    }
-
-    /**
-    * Get the real primary group setting
-    * 
-    * @return bool
-    */
-    public function getRealPrimaryGroup()
-    {
-          return $this->realPrimaryGroup;
-    }
-    
-    /**
-    * Set whether to use SSL
-    * 
-    * @param bool $useSSL
-    * @return void
-    */
-    public function setUseSSL($useSSL)
-    {
-          $this->useSSL = $useSSL;
-          // Set the default port correctly 
-          if($this->useSSL) { 
-            $this->setPort(self::ADLDAP_LDAPS_PORT); 
-          }
-          else { 
-            $this->setPort(self::ADLDAP_LDAP_PORT); 
-          } 
-    }
-
-    /**
-    * Get the SSL setting
-    * 
-    * @return bool
-    */
-    public function getUseSSL()
-    {
-          return $this->useSSL;
-    }
-    
-    /**
-    * Set whether to use TLS
-    * 
-    * @param bool $useTLS
-    * @return void
-    */
-    public function setUseTLS($useTLS)
-    {
-          $this->useTLS = $useTLS;
-    }
-
-    /**
-    * Get the TLS setting
-    * 
-    * @return bool
-    */
-    public function getUseTLS()
-    {
-          return $this->useTLS;
-    }
-    
-    /**
-    * Set whether to use SSO
-    * Requires ldap_sasl_bind support. Be sure --with-ldap-sasl is used when configuring PHP otherwise this function will be undefined. 
-    * 
-    * @param bool $useSSO
-    * @return void
-    */
-    public function setUseSSO($useSSO)
-    {
-          if ($useSSO === true && !$this->ldapSaslSupported()) {
-              throw new adLDAPException('No LDAP SASL support for PHP.  See: http://www.php.net/ldap_sasl_bind');
-          }
-          $this->useSSO = $useSSO;
-    }
-
-    /**
-    * Get the SSO setting
-    * 
-    * @return bool
-    */
-    public function getUseSSO()
-    {
-          return $this->useSSO;
-    }
-    
-    /**
-    * Set whether to lookup recursive groups
-    * 
-    * @param bool $recursiveGroups
-    * @return void
-    */
-    public function setRecursiveGroups($recursiveGroups)
-    {
-          $this->recursiveGroups = $recursiveGroups;
-    }
-
-    /**
-    * Get the recursive groups setting
-    * 
-    * @return bool
-    */
-    public function getRecursiveGroups()
-    {
-          return $this->recursiveGroups;
-    }
-
-    /**
-    * Default Constructor
-    * 
-    * Tries to bind to the AD domain over LDAP or LDAPs
-    * 
-    * @param array $options Array of options to pass to the constructor
-    * @throws Exception - if unable to bind to Domain Controller
-    * @return bool
-    */
-    function __construct($options = array()) {
-        // You can specifically overide any of the default configuration options setup above
-        if (count($options) > 0) {
-            if (array_key_exists("account_suffix",$options)){ $this->accountSuffix = $options["account_suffix"]; }
-            if (array_key_exists("base_dn",$options)){ $this->baseDn = $options["base_dn"]; }
-            if (array_key_exists("domain_controllers",$options)){ 
-                if (!is_array($options["domain_controllers"])) { 
-                    throw new adLDAPException('[domain_controllers] option must be an array');
-                }
-                $this->domainControllers = $options["domain_controllers"]; 
-            }
-            if (array_key_exists("admin_username",$options)){ $this->adminUsername = $options["admin_username"]; }
-            if (array_key_exists("admin_password",$options)){ $this->adminPassword = $options["admin_password"]; }
-            if (array_key_exists("real_primarygroup",$options)){ $this->realPrimaryGroup = $options["real_primarygroup"]; }
-            if (array_key_exists("use_ssl",$options)){ $this->setUseSSL($options["use_ssl"]); }
-            if (array_key_exists("use_tls",$options)){ $this->useTLS = $options["use_tls"]; }
-            if (array_key_exists("recursive_groups",$options)){ $this->recursiveGroups = $options["recursive_groups"]; }
-            if (array_key_exists("ad_port",$options)){ $this->setPort($options["ad_port"]); } 
-            if (array_key_exists("sso",$options)) { 
-                $this->setUseSSO($options["sso"]);
-                if (!$this->ldapSaslSupported()) {
-                    $this->setUseSSO(false);
-                }
-            } 
-        }
-        
-        if ($this->ldapSupported() === false) {
-            throw new adLDAPException('No LDAP support for PHP.  See: http://www.php.net/ldap');
-        }
-
-        return $this->connect();
-    }
-
-    /**
-    * Default Destructor
-    * 
-    * Closes the LDAP connection
-    * 
-    * @return void
-    */
-    function __destruct() { 
-        $this->close(); 
-    }
-
-    /**
-    * Connects and Binds to the Domain Controller
-    * 
-    * @return bool
-    */
-    public function connect() 
-    {
-        // Connect to the AD/LDAP server as the username/password
-        $domainController = $this->randomController();
-        if ($this->useSSL) {
-            $this->ldapConnection = ldap_connect("ldaps://" . $domainController, $this->adPort);
-        } else {
-            $this->ldapConnection = ldap_connect($domainController, $this->adPort);
-        }
-               
-        // Set some ldap options for talking to AD
-        ldap_set_option($this->ldapConnection, LDAP_OPT_PROTOCOL_VERSION, 3);
-        ldap_set_option($this->ldapConnection, LDAP_OPT_REFERRALS, 0);
-        
-        if ($this->useTLS) {
-            ldap_start_tls($this->ldapConnection);
-        }
-               
-        // Bind as a domain admin if they've set it up
-        if ($this->adminUsername !== NULL && $this->adminPassword !== NULL) {
-            $this->ldapBind = @ldap_bind($this->ldapConnection, $this->adminUsername . $this->accountSuffix, $this->adminPassword);
-            if (!$this->ldapBind) {
-                if ($this->useSSL && !$this->useTLS) {
-                    // If you have problems troubleshooting, remove the @ character from the ldapldapBind command above to get the actual error message
-                    throw new adLDAPException('Bind to Active Directory failed. Either the LDAPs connection failed or the login credentials are incorrect. AD said: ' . $this->getLastError());
-                }
-                else {
-                    throw new adLDAPException('Bind to Active Directory failed. Check the login credentials and/or server details. AD said: ' . $this->getLastError());
-                }
-            }
-        }
-        if ($this->useSSO && $_SERVER['REMOTE_USER'] && $this->adminUsername === null && $_SERVER['KRB5CCNAME']) {
-            putenv("KRB5CCNAME=" . $_SERVER['KRB5CCNAME']);  
-            $this->ldapBind = @ldap_sasl_bind($this->ldapConnection, NULL, NULL, "GSSAPI"); 
-            if (!$this->ldapBind){ 
-                throw new adLDAPException('Rebind to Active Directory failed. AD said: ' . $this->getLastError()); 
-            }
-            else {
-                return true;
-            }
-        }
-                
-        
-        if ($this->baseDn == NULL) {
-            $this->baseDn = $this->findBaseDn();   
-        }
-        
-        return true;
-    }
-    
-    /**
-    * Closes the LDAP connection
-    * 
-    * @return void
-    */
-    public function close() {
-        if ($this->ldapConnection) {
-            @ldap_close($this->ldapConnection);
-        }
-    }
-    
-    /**
-    * Validate a user's login credentials
-    * 
-    * @param string $username A user's AD username
-    * @param string $password A user's AD password
-    * @param bool optional $preventRebind
-    * @return bool
-    */
-    public function authenticate($username, $password, $preventRebind = false) {
-        // Prevent null binding
-        if ($username === NULL || $password === NULL) { return false; } 
-        if (empty($username) || empty($password)) { return false; }
-        
-        // Allow binding over SSO for Kerberos
-        if ($this->useSSO && $_SERVER['REMOTE_USER'] && $_SERVER['REMOTE_USER'] == $username && $this->adminUsername === NULL && $_SERVER['KRB5CCNAME']) { 
-            putenv("KRB5CCNAME=" . $_SERVER['KRB5CCNAME']);
-            $this->ldapBind = @ldap_sasl_bind($this->ldapConnection, NULL, NULL, "GSSAPI");
-            if (!$this->ldapBind) {
-                throw new adLDAPException('Rebind to Active Directory failed. AD said: ' . $this->getLastError());
-            }
-            else {
-                return true;
-            }
-        }
-        
-        // Bind as the user        
-        $ret = true;
-        $this->ldapBind = @ldap_bind($this->ldapConnection, $username . $this->accountSuffix, $password);
-        if (!$this->ldapBind){ 
-            $ret = false; 
-        }
-        
-        // Cnce we've checked their details, kick back into admin mode if we have it
-        if ($this->adminUsername !== NULL && !$preventRebind) {
-            $this->ldapBind = @ldap_bind($this->ldapConnection, $this->adminUsername . $this->accountSuffix , $this->adminPassword);
-            if (!$this->ldapBind){
-                // This should never happen in theory
-                throw new adLDAPException('Rebind to Active Directory failed. AD said: ' . $this->getLastError());
-            } 
-        } 
-        
-        return $ret;
-    }
-    
-    /**
-    * Find the Base DN of your domain controller
-    * 
-    * @return string
-    */
-    public function findBaseDn() 
-    {
-        $namingContext = $this->getRootDse(array('defaultnamingcontext'));   
-        return $namingContext[0]['defaultnamingcontext'][0];
-    }
-    
-    /**
-    * Get the RootDSE properties from a domain controller
-    * 
-    * @param array $attributes The attributes you wish to query e.g. defaultnamingcontext
-    * @return array
-    */
-    public function getRootDse($attributes = array("*", "+")) {
-        if (!$this->ldapBind){ return (false); }
-        
-        $sr = @ldap_read($this->ldapConnection, NULL, 'objectClass=*', $attributes);
-        $entries = @ldap_get_entries($this->ldapConnection, $sr);
-        return $entries;
-    }
-
-    /**
-    * Get last error from Active Directory
-    * 
-    * This function gets the last message from Active Directory
-    * This may indeed be a 'Success' message but if you get an unknown error
-    * it might be worth calling this function to see what errors were raised
-    * 
-    * return string
-    */
-    public function getLastError() {
-        return @ldap_error($this->ldapConnection);
-    }
-    
-    /**
-    * Detect LDAP support in php
-    * 
-    * @return bool
-    */    
-    protected function ldapSupported()
-    {
-        if (!function_exists('ldap_connect')) {
-            return false;   
-        }
-        return true;
-    }
-    
-    /**
-    * Detect ldap_sasl_bind support in PHP
-    * 
-    * @return bool
-    */
-    protected function ldapSaslSupported()
-    {
-        if (!function_exists('ldap_sasl_bind')) {
-            return false;
-        }
-        return true;
-    }
-    
-    /**
-    * Schema
-    * 
-    * @param array $attributes Attributes to be queried
-    * @return array
-    */    
-    public function adldap_schema($attributes){
-    
-        // LDAP doesn't like NULL attributes, only set them if they have values
-        // If you wish to remove an attribute you should set it to a space
-        // TO DO: Adapt user_modify to use ldap_mod_delete to remove a NULL attribute
-        $mod=array();
-        
-        // Check every attribute to see if it contains 8bit characters and then UTF8 encode them
-        array_walk($attributes, array($this, 'encode8bit'));
-
-        if ($attributes["address_city"]){ $mod["l"][0]=$attributes["address_city"]; }
-        if ($attributes["address_code"]){ $mod["postalCode"][0]=$attributes["address_code"]; }
-        //if ($attributes["address_country"]){ $mod["countryCode"][0]=$attributes["address_country"]; } // use country codes?
-        if ($attributes["address_country"]){ $mod["c"][0]=$attributes["address_country"]; }
-        if ($attributes["address_pobox"]){ $mod["postOfficeBox"][0]=$attributes["address_pobox"]; }
-        if ($attributes["address_state"]){ $mod["st"][0]=$attributes["address_state"]; }
-        if ($attributes["address_street"]){ $mod["streetAddress"][0]=$attributes["address_street"]; }
-        if ($attributes["company"]){ $mod["company"][0]=$attributes["company"]; }
-        if ($attributes["change_password"]){ $mod["pwdLastSet"][0]=0; }
-        if ($attributes["department"]){ $mod["department"][0]=$attributes["department"]; }
-        if ($attributes["description"]){ $mod["description"][0]=$attributes["description"]; }
-        if ($attributes["display_name"]){ $mod["displayName"][0]=$attributes["display_name"]; }
-        if ($attributes["email"]){ $mod["mail"][0]=$attributes["email"]; }
-        if ($attributes["expires"]){ $mod["accountExpires"][0]=$attributes["expires"]; } //unix epoch format?
-        if ($attributes["firstname"]){ $mod["givenName"][0]=$attributes["firstname"]; }
-        if ($attributes["home_directory"]){ $mod["homeDirectory"][0]=$attributes["home_directory"]; }
-        if ($attributes["home_drive"]){ $mod["homeDrive"][0]=$attributes["home_drive"]; }
-        if ($attributes["initials"]){ $mod["initials"][0]=$attributes["initials"]; }
-        if ($attributes["logon_name"]){ $mod["userPrincipalName"][0]=$attributes["logon_name"]; }
-        if ($attributes["manager"]){ $mod["manager"][0]=$attributes["manager"]; }  //UNTESTED ***Use DistinguishedName***
-        if ($attributes["office"]){ $mod["physicalDeliveryOfficeName"][0]=$attributes["office"]; }
-        if ($attributes["password"]){ $mod["unicodePwd"][0]=$this->user()->encodePassword($attributes["password"]); }
-        if ($attributes["profile_path"]){ $mod["profilepath"][0]=$attributes["profile_path"]; }
-        if ($attributes["script_path"]){ $mod["scriptPath"][0]=$attributes["script_path"]; }
-        if ($attributes["surname"]){ $mod["sn"][0]=$attributes["surname"]; }
-        if ($attributes["title"]){ $mod["title"][0]=$attributes["title"]; }
-        if ($attributes["telephone"]){ $mod["telephoneNumber"][0]=$attributes["telephone"]; }
-        if ($attributes["mobile"]){ $mod["mobile"][0]=$attributes["mobile"]; }
-        if ($attributes["pager"]){ $mod["pager"][0]=$attributes["pager"]; }
-        if ($attributes["ipphone"]){ $mod["ipphone"][0]=$attributes["ipphone"]; }
-        if ($attributes["web_page"]){ $mod["wWWHomePage"][0]=$attributes["web_page"]; }
-        if ($attributes["fax"]){ $mod["facsimileTelephoneNumber"][0]=$attributes["fax"]; }
-        if ($attributes["enabled"]){ $mod["userAccountControl"][0]=$attributes["enabled"]; }
-        if ($attributes["homephone"]){ $mod["homephone"][0]=$attributes["homephone"]; }
-        
-        // Distribution List specific schema
-        if ($attributes["group_sendpermission"]){ $mod["dlMemSubmitPerms"][0]=$attributes["group_sendpermission"]; }
-        if ($attributes["group_rejectpermission"]){ $mod["dlMemRejectPerms"][0]=$attributes["group_rejectpermission"]; }
-        
-        // Exchange Schema
-        if ($attributes["exchange_homemdb"]){ $mod["homeMDB"][0]=$attributes["exchange_homemdb"]; }
-        if ($attributes["exchange_mailnickname"]){ $mod["mailNickname"][0]=$attributes["exchange_mailnickname"]; }
-        if ($attributes["exchange_proxyaddress"]){ $mod["proxyAddresses"][0]=$attributes["exchange_proxyaddress"]; }
-        if ($attributes["exchange_usedefaults"]){ $mod["mDBUseDefaults"][0]=$attributes["exchange_usedefaults"]; }
-        if ($attributes["exchange_policyexclude"]){ $mod["msExchPoliciesExcluded"][0]=$attributes["exchange_policyexclude"]; }
-        if ($attributes["exchange_policyinclude"]){ $mod["msExchPoliciesIncluded"][0]=$attributes["exchange_policyinclude"]; }       
-        if ($attributes["exchange_addressbook"]){ $mod["showInAddressBook"][0]=$attributes["exchange_addressbook"]; }    
-        if ($attributes["exchange_altrecipient"]){ $mod["altRecipient"][0]=$attributes["exchange_altrecipient"]; } 
-        if ($attributes["exchange_deliverandredirect"]){ $mod["deliverAndRedirect"][0]=$attributes["exchange_deliverandredirect"]; }    
-        
-        // This schema is designed for contacts
-        if ($attributes["exchange_hidefromlists"]){ $mod["msExchHideFromAddressLists"][0]=$attributes["exchange_hidefromlists"]; }
-        if ($attributes["contact_email"]){ $mod["targetAddress"][0]=$attributes["contact_email"]; }
-        
-        //echo ("
"); print_r($mod);
-        /*
-        // modifying a name is a bit fiddly
-        if ($attributes["firstname"] && $attributes["surname"]){
-            $mod["cn"][0]=$attributes["firstname"]." ".$attributes["surname"];
-            $mod["displayname"][0]=$attributes["firstname"]." ".$attributes["surname"];
-            $mod["name"][0]=$attributes["firstname"]." ".$attributes["surname"];
-        }
-        */
-
-        if (count($mod)==0){ return (false); }
-        return ($mod);
-    }
-    
-    /**
-    * Convert 8bit characters e.g. accented characters to UTF8 encoded characters
-    */
-    protected function encode8Bit(&$item, $key) {
-        $encode = false;
-        if (is_string($item)) {
-            for ($i=0; $i> 7) {
-                    $encode = true;
-                }
-            }
-        }
-        if ($encode === true && $key != 'password') {
-            $item = utf8_encode($item);   
-        }
-    }
-    
-    /**
-    * Select a random domain controller from your domain controller array
-    * 
-    * @return string
-    */
-    protected function randomController() 
-    {
-        mt_srand(doubleval(microtime()) * 100000000); // For older PHP versions
-        /*if (sizeof($this->domainControllers) > 1) {
-            $adController = $this->domainControllers[array_rand($this->domainControllers)]; 
-            // Test if the controller is responding to pings
-            $ping = $this->pingController($adController); 
-            if ($ping === false) { 
-                // Find the current key in the domain controllers array
-                $key = array_search($adController, $this->domainControllers);
-                // Remove it so that we don't end up in a recursive loop
-                unset($this->domainControllers[$key]);
-                // Select a new controller
-                return $this->randomController(); 
-            }
-            else { 
-                return ($adController); 
-            }
-        } */
-        return $this->domainControllers[array_rand($this->domainControllers)];
-    }  
-    
-    /** 
-    * Test basic connectivity to controller 
-    * 
-    * @return bool
-    */ 
-    protected function pingController($host) {
-        $port = $this->adPort; 
-        fsockopen($host, $port, $errno, $errstr, 10); 
-        if ($errno > 0) {
-            return false;
-        }
-        return true;
-    }
-
-}
-
-/**
-* adLDAP Exception Handler
-* 
-* Exceptions of this type are thrown on bind failure or when SSL is required but not configured
-* Example:
-* try {
-*   $adldap = new adLDAP();
-* }
-* catch (adLDAPException $e) {
-*   echo $e;
-*   exit();
-* }
-*/
-class adLDAPException extends Exception {}
-
-?>
\ No newline at end of file
diff --git a/inc/adLDAP/classes/adLDAPComputers.php b/inc/adLDAP/classes/adLDAPComputers.php
deleted file mode 100644
index 71b24a04f..000000000
--- a/inc/adLDAP/classes/adLDAPComputers.php
+++ /dev/null
@@ -1,153 +0,0 @@
-adldap = $adldap;
-    }
-    
-    /**
-    * Get information about a specific computer. Returned in a raw array format from AD
-    * 
-    * @param string $computerName The name of the computer
-    * @param array $fields Attributes to return
-    * @return array
-    */
-    public function info($computerName, $fields = NULL)
-    {
-        if ($computerName === NULL) { return false; }
-        if (!$this->adldap->getLdapBind()) { return false; }
-
-        $filter = "(&(objectClass=computer)(cn=" . $computerName . "))";
-        if ($fields === NULL) { 
-            $fields = array("memberof","cn","displayname","dnshostname","distinguishedname","objectcategory","operatingsystem","operatingsystemservicepack","operatingsystemversion"); 
-        }
-        $sr = ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields);
-        $entries = ldap_get_entries($this->adldap->getLdapConnection(), $sr);
-        
-        return $entries;
-    }
-    
-    /**
-    * Find information about the computers. Returned in a raw array format from AD
-    * 
-    * @param string $computerName The name of the computer
-    * @param array $fields Array of parameters to query
-    * @return mixed
-    */
-    public function infoCollection($computerName, $fields = NULL)
-    {
-        if ($computerName === NULL) { return false; }
-        if (!$this->adldap->getLdapBind()) { return false; }
-        
-        $info = $this->info($computerName, $fields);
-        
-        if ($info !== false) {
-            $collection = new adLDAPComputerCollection($info, $this->adldap);
-            return $collection;
-        }
-        return false;
-    }
-    
-    /**
-    * Check if a computer is in a group
-    * 
-    * @param string $computerName The name of the computer
-    * @param string $group The group to check
-    * @param bool $recursive Whether to check recursively
-    * @return array
-    */
-    public function inGroup($computerName, $group, $recursive = NULL)
-    {
-        if ($computerName === NULL) { return false; }
-        if ($group === NULL) { return false; }
-        if (!$this->adldap->getLdapBind()) { return false; }
-        if ($recursive === NULL) { $recursive = $this->adldap->getRecursiveGroups(); } // use the default option if they haven't set it
-
-        //get a list of the groups
-        $groups = $this->groups($computerName, array("memberof"), $recursive);
-
-        //return true if the specified group is in the group list
-        if (in_array($group, $groups)){ 
-            return true; 
-        }
-
-        return false;
-    }
-    
-    /**
-    * Get the groups a computer is in
-    * 
-    * @param string $computerName The name of the computer
-    * @param bool $recursive Whether to check recursively
-    * @return array
-    */
-    public function groups($computerName, $recursive = NULL)
-    {
-        if ($computerName === NULL) { return false; }
-        if ($recursive === NULL) { $recursive = $this->adldap->getRecursiveGroups(); } //use the default option if they haven't set it
-        if (!$this->adldap->getLdapBind()){ return false; }
-
-        //search the directory for their information
-        $info = @$this->info($computerName, array("memberof", "primarygroupid"));
-        $groups = $this->adldap->utilities()->niceNames($info[0]["memberof"]); //presuming the entry returned is our guy (unique usernames)
-
-        if ($recursive === true) {
-            foreach ($groups as $id => $groupName){
-              $extraGroups = $this->adldap->group()->recursiveGroups($groupName);
-              $groups = array_merge($groups, $extraGroups);
-            }
-        }
-
-        return $groups;
-    }
-    
-}
-?>
\ No newline at end of file
diff --git a/inc/adLDAP/classes/adLDAPContacts.php b/inc/adLDAP/classes/adLDAPContacts.php
deleted file mode 100644
index addd3e5f0..000000000
--- a/inc/adLDAP/classes/adLDAPContacts.php
+++ /dev/null
@@ -1,294 +0,0 @@
-adldap = $adldap;
-    }
-    
-    //*****************************************************************************************************************
-    // CONTACT FUNCTIONS
-    // * Still work to do in this area, and new functions to write
-    
-    /**
-    * Create a contact
-    * 
-    * @param array $attributes The attributes to set to the contact
-    * @return bool
-    */
-    public function create($attributes)
-    {
-        // Check for compulsory fields
-        if (!array_key_exists("display_name", $attributes)) { return "Missing compulsory field [display_name]"; }
-        if (!array_key_exists("email", $attributes)) { return "Missing compulsory field [email]"; }
-        if (!array_key_exists("container", $attributes)) { return "Missing compulsory field [container]"; }
-        if (!is_array($attributes["container"])) { return "Container attribute must be an array."; }
-
-        // Translate the schema
-        $add = $this->adldap->adldap_schema($attributes);
-        
-        // Additional stuff only used for adding contacts
-        $add["cn"][0] = $attributes["display_name"];
-        $add["objectclass"][0] = "top";
-        $add["objectclass"][1] = "person";
-        $add["objectclass"][2] = "organizationalPerson";
-        $add["objectclass"][3] = "contact"; 
-        if (!isset($attributes['exchange_hidefromlists'])) {
-            $add["msExchHideFromAddressLists"][0] = "TRUE";
-        }
-
-        // Determine the container
-        $attributes["container"] = array_reverse($attributes["container"]);
-        $container= "OU=" . implode(",OU=", $attributes["container"]);
-
-        // Add the entry
-        $result = @ldap_add($this->adldap->getLdapConnection(), "CN=" . $this->adldap->utilities()->escapeCharacters($add["cn"][0]) . ", " . $container . "," . $this->adldap->getBaseDn(), $add);
-        if ($result != true) { 
-            return false; 
-        }
-        
-        return true;
-    }  
-    
-    /**
-    * Determine the list of groups a contact is a member of
-    * 
-    * @param string $distinguisedname The full DN of a contact
-    * @param bool $recursive Recursively check groups
-    * @return array
-    */
-    public function groups($distinguishedName, $recursive = NULL)
-    {
-        if ($distinguishedName === NULL) { return false; }
-        if ($recursive === NULL) { $recursive = $this->adldap->getRecursiveGroups(); } //use the default option if they haven't set it
-        if (!$this->adldap->getLdapBind()){ return false; }
-        
-        // Search the directory for their information
-        $info = @$this->info($distinguishedName, array("memberof", "primarygroupid"));
-        $groups = $this->adldap->utilities()->niceNames($info[0]["memberof"]); //presuming the entry returned is our contact
-
-        if ($recursive === true){
-            foreach ($groups as $id => $groupName){
-                $extraGroups = $this->adldap->group()->recursiveGroups($groupName);
-                $groups = array_merge($groups, $extraGroups);
-            }
-        }
-        
-        return $groups;
-    }
-    
-    /**
-    * Get contact information. Returned in a raw array format from AD
-    * 
-    * @param string $distinguisedname The full DN of a contact
-    * @param array $fields Attributes to be returned
-    * @return array
-    */
-    public function info($distinguishedName, $fields = NULL)
-    {
-        if ($distinguishedName === NULL) { return false; }
-        if (!$this->adldap->getLdapBind()) { return false; }
-
-        $filter = "distinguishedName=" . $distinguishedName;
-        if ($fields === NULL) { 
-            $fields = array("distinguishedname", "mail", "memberof", "department", "displayname", "telephonenumber", "primarygroupid", "objectsid"); 
-        }
-        $sr = ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields);
-        $entries = ldap_get_entries($this->adldap->getLdapConnection(), $sr);
-        
-        if ($entries[0]['count'] >= 1) {
-            // AD does not return the primary group in the ldap query, we may need to fudge it
-            if ($this->adldap->getRealPrimaryGroup() && isset($entries[0]["primarygroupid"][0]) && isset($entries[0]["primarygroupid"][0])){
-                //$entries[0]["memberof"][]=$this->group_cn($entries[0]["primarygroupid"][0]);
-                $entries[0]["memberof"][] = $this->adldap->group()->getPrimaryGroup($entries[0]["primarygroupid"][0], $entries[0]["objectsid"][0]);
-            } else {
-                $entries[0]["memberof"][] = "CN=Domain Users,CN=Users," . $this->adldap->getBaseDn();
-            }
-        }
-        
-        $entries[0]["memberof"]["count"]++;
-        return $entries;
-    }
-    
-    /**
-    * Find information about the contacts. Returned in a raw array format from AD
-    * 
-    * @param string $distinguishedName The full DN of a contact 
-    * @param array $fields Array of parameters to query
-    * @return mixed
-    */
-    public function infoCollection($distinguishedName, $fields = NULL)
-    {
-        if ($distinguishedName === NULL) { return false; }
-        if (!$this->adldap->getLdapBind()) { return false; }
-        
-        $info = $this->info($distinguishedName, $fields);
-        
-        if ($info !== false) {
-            $collection = new adLDAPContactCollection($info, $this->adldap);
-            return $collection;
-        }
-        return false;
-    }
-    
-    /**
-    * Determine if a contact is a member of a group
-    * 
-    * @param string $distinguisedName The full DN of a contact
-    * @param string $group The group name to query
-    * @param bool $recursive Recursively check groups
-    * @return bool
-    */
-    public function inGroup($distinguisedName, $group, $recursive = NULL)
-    {
-        if ($distinguisedName === NULL) { return false; }
-        if ($group === NULL) { return false; }
-        if (!$this->adldap->getLdapBind()) { return false; }
-        if ($recursive === NULL) { $recursive = $this->adldap->getRecursiveGroups(); } //use the default option if they haven't set it
-        
-        // Get a list of the groups
-        $groups = $this->groups($distinguisedName, array("memberof"), $recursive);
-        
-        // Return true if the specified group is in the group list
-        if (in_array($group, $groups)){ 
-            return true; 
-        }
-
-        return false;
-    }          
-    
-    /**
-    * Modify a contact
-    * 
-    * @param string $distinguishedName The contact to query
-    * @param array $attributes The attributes to modify.  Note if you set the enabled attribute you must not specify any other attributes
-    * @return bool
-    */
-    public function modify($distinguishedName, $attributes) {
-        if ($distinguishedName === NULL) { return "Missing compulsory field [distinguishedname]"; }
-        
-        // Translate the update to the LDAP schema                
-        $mod = $this->adldap->adldap_schema($attributes);
-        
-        // Check to see if this is an enabled status update
-        if (!$mod) { 
-            return false; 
-        }
-        
-        // Do the update
-        $result = ldap_modify($this->adldap->getLdapConnection(), $distinguishedName, $mod);
-        if ($result == false) { 
-            return false; 
-        }
-        
-        return true;
-    }
-    
-    /**
-    * Delete a contact
-    * 
-    * @param string $distinguishedName The contact dn to delete (please be careful here!)
-    * @return array
-    */
-    public function delete($distinguishedName) 
-    {
-        $result = $this->folder()->delete($distinguishedName);
-        if ($result != true) { 
-            return false; 
-        }       
-        return true;
-    }
-    
-    /**
-    * Return a list of all contacts
-    * 
-    * @param bool $includeDescription Include a description of a contact
-    * @param string $search The search parameters
-    * @param bool $sorted Whether to sort the results
-    * @return array
-    */
-    public function all($includeDescription = false, $search = "*", $sorted = true) {
-        if (!$this->adldap->getLdapBind()) { return false; }
-        
-        // Perform the search and grab all their details
-        $filter = "(&(objectClass=contact)(cn=" . $search . "))";
-        $fields = array("displayname","distinguishedname");           
-        $sr = ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields);
-        $entries = ldap_get_entries($this->adldap->getLdapConnection(), $sr);
-
-        $usersArray = array();
-        for ($i=0; $i<$entries["count"]; $i++){
-            if ($includeDescription && strlen($entries[$i]["displayname"][0])>0){
-                $usersArray[$entries[$i]["distinguishedname"][0]] = $entries[$i]["displayname"][0];
-            } elseif ($includeDescription){
-                $usersArray[$entries[$i]["distinguishedname"][0]] = $entries[$i]["distinguishedname"][0];
-            } else {
-                array_push($usersArray, $entries[$i]["distinguishedname"][0]);
-            }
-        }
-        if ($sorted) { 
-            asort($usersArray); 
-        }
-        return $usersArray;
-    }
-    
-    /**
-    * Mail enable a contact
-    * Allows email to be sent to them through Exchange
-    * 
-    * @param string $distinguishedname The contact to mail enable
-    * @param string $emailaddress The email address to allow emails to be sent through
-    * @param string $mailnickname The mailnickname for the contact in Exchange.  If NULL this will be set to the display name
-    * @return bool
-    */
-    public function contactMailEnable($distinguishedName, $emailAddress, $mailNickname = NULL){
-        return $this->adldap->exchange()->contactMailEnable($distinguishedName, $emailAddress, $mailNickname);
-    }
-    
-    
-}
-?>
diff --git a/inc/adLDAP/classes/adLDAPExchange.php b/inc/adLDAP/classes/adLDAPExchange.php
deleted file mode 100644
index dd0c6de05..000000000
--- a/inc/adLDAP/classes/adLDAPExchange.php
+++ /dev/null
@@ -1,390 +0,0 @@
-adldap = $adldap;
-    }
-    
-    /**
-    * Create an Exchange account
-    * 
-    * @param string $username The username of the user to add the Exchange account to
-    * @param array $storageGroup The mailbox, Exchange Storage Group, for the user account, this must be a full CN
-    *                            If the storage group has a different base_dn to the adLDAP configuration, set it using $base_dn
-    * @param string $emailAddress The primary email address to add to this user
-    * @param string $mailNickname The mail nick name.  If mail nickname is blank, the username will be used
-    * @param bool $mdbUseDefaults Indicates whether the store should use the default quota, rather than the per-mailbox quota.
-    * @param string $baseDn Specify an alternative base_dn for the Exchange storage group
-    * @param bool $isGUID Is the username passed a GUID or a samAccountName
-    * @return bool
-    */
-    public function createMailbox($username, $storageGroup, $emailAddress, $mailNickname=NULL, $useDefaults=TRUE, $baseDn=NULL, $isGUID=false)
-    {
-        if ($username === NULL){ return "Missing compulsory field [username]"; }     
-        if ($storageGroup === NULL) { return "Missing compulsory array [storagegroup]"; }
-        if (!is_array($storageGroup)) { return "[storagegroup] must be an array"; }
-        if ($emailAddress === NULL) { return "Missing compulsory field [emailAddress]"; }
-        
-        if ($baseDn === NULL) {
-            $baseDn = $this->adldap->getBaseDn();   
-        }
-        
-        $container = "CN=" . implode(",CN=", $storageGroup);
-        
-        if ($mailNickname === NULL) { 
-            $mailNickname = $username; 
-        }
-        $mdbUseDefaults = $this->adldap->utilities()->boolToString($useDefaults);
-        
-        $attributes = array(
-            'exchange_homemdb'=>$container.",".$baseDn,
-            'exchange_proxyaddress'=>'SMTP:' . $emailAddress,
-            'exchange_mailnickname'=>$mailNickname,
-            'exchange_usedefaults'=>$mdbUseDefaults
-        );
-        $result = $this->adldap->user()->modify($username, $attributes, $isGUID);
-        if ($result == false) { 
-            return false; 
-        }
-        return true;
-    }
-    
-    /**
-    * Add an X400 address to Exchange
-    * See http://tools.ietf.org/html/rfc1685 for more information.
-    * An X400 Address looks similar to this X400:c=US;a= ;p=Domain;o=Organization;s=Doe;g=John;
-    * 
-    * @param string $username The username of the user to add the X400 to to
-    * @param string $country Country
-    * @param string $admd Administration Management Domain
-    * @param string $pdmd Private Management Domain (often your AD domain)
-    * @param string $org Organization
-    * @param string $surname Surname
-    * @param string $givenName Given name
-    * @param bool $isGUID Is the username passed a GUID or a samAccountName
-    * @return bool
-    */
-    public function addX400($username, $country, $admd, $pdmd, $org, $surname, $givenName, $isGUID=false) 
-    {
-        if ($username === NULL){ return "Missing compulsory field [username]"; }     
-        
-        $proxyValue = 'X400:';
-            
-        // Find the dn of the user
-        $user = $this->adldap->user()->info($username, array("cn","proxyaddresses"), $isGUID);
-        if ($user[0]["dn"] === NULL) { return false; }
-        $userDn = $user[0]["dn"];
-        
-        // We do not have to demote an email address from the default so we can just add the new proxy address
-        $attributes['exchange_proxyaddress'] = $proxyValue . 'c=' . $country . ';a=' . $admd . ';p=' . $pdmd . ';o=' . $org . ';s=' . $surname . ';g=' . $givenName . ';';
-       
-        // Translate the update to the LDAP schema                
-        $add = $this->adldap->adldap_schema($attributes);
-        
-        if (!$add) { return false; }
-        
-        // Do the update
-        // Take out the @ to see any errors, usually this error might occur because the address already
-        // exists in the list of proxyAddresses
-        $result = @ldap_mod_add($this->adldap->getLdapConnection(), $userDn, $add);
-        if ($result == false) { 
-            return false; 
-        }
-        
-        return true;
-    }
-    
-    /**
-    * Add an address to Exchange
-    * 
-    * @param string $username The username of the user to add the Exchange account to
-    * @param string $emailAddress The email address to add to this user
-    * @param bool $default Make this email address the default address, this is a bit more intensive as we have to demote any existing default addresses
-    * @param bool $isGUID Is the username passed a GUID or a samAccountName
-    * @return bool
-    */
-    public function addAddress($username, $emailAddress, $default = FALSE, $isGUID = false) 
-    {
-        if ($username === NULL) { return "Missing compulsory field [username]"; }     
-        if ($emailAddress === NULL) { return "Missing compulsory fields [emailAddress]"; }
-        
-        $proxyValue = 'smtp:';
-        if ($default === true) {
-            $proxyValue = 'SMTP:';
-        }
-              
-        // Find the dn of the user
-        $user = $this->adldap->user()->info($username, array("cn","proxyaddresses"), $isGUID);
-        if ($user[0]["dn"] === NULL){ return false; }
-        $userDn = $user[0]["dn"];
-        
-        // We need to scan existing proxy addresses and demote the default one
-        if (is_array($user[0]["proxyaddresses"]) && $default === true) {
-            $modAddresses = array();
-            for ($i=0;$iadldap->getLdapConnection(), $userDn, $modAddresses);
-            if ($result == false) { 
-                return false; 
-            }
-            
-            return true;
-        }
-        else {
-            // We do not have to demote an email address from the default so we can just add the new proxy address
-            $attributes['exchange_proxyaddress'] = $proxyValue . $emailAddress;
-            
-            // Translate the update to the LDAP schema                
-            $add = $this->adldap->adldap_schema($attributes);
-            
-            if (!$add) { 
-                return false; 
-            }
-            
-            // Do the update
-            // Take out the @ to see any errors, usually this error might occur because the address already
-            // exists in the list of proxyAddresses
-            $result = @ldap_mod_add($this->adldap->getLdapConnection(), $userDn,$add);
-            if ($result == false) { 
-                return false; 
-            }
-            
-            return true;
-        }
-    }
-    
-    /**
-    * Remove an address to Exchange
-    * If you remove a default address the account will no longer have a default, 
-    * we recommend changing the default address first
-    * 
-    * @param string $username The username of the user to add the Exchange account to
-    * @param string $emailAddress The email address to add to this user
-    * @param bool $isGUID Is the username passed a GUID or a samAccountName
-    * @return bool
-    */
-    public function deleteAddress($username, $emailAddress, $isGUID=false) 
-    {
-        if ($username === NULL) { return "Missing compulsory field [username]"; }     
-        if ($emailAddress === NULL) { return "Missing compulsory fields [emailAddress]"; }
-        
-        // Find the dn of the user
-        $user = $this->adldap->user()->info($username, array("cn","proxyaddresses"), $isGUID);
-        if ($user[0]["dn"] === NULL) { return false; }
-        $userDn = $user[0]["dn"];
-        
-        if (is_array($user[0]["proxyaddresses"])) {
-            $mod = array();
-            for ($i=0;$iadldap->getLdapConnection(), $userDn,$mod);
-            if ($result == false) { 
-                return false; 
-            }
-            
-            return true;
-        }
-        else {
-            return false;
-        }
-    }
-    /**
-    * Change the default address
-    * 
-    * @param string $username The username of the user to add the Exchange account to
-    * @param string $emailAddress The email address to make default
-    * @param bool $isGUID Is the username passed a GUID or a samAccountName
-    * @return bool
-    */
-    public function primaryAddress($username, $emailAddress, $isGUID = false) 
-    {
-        if ($username === NULL) { return "Missing compulsory field [username]"; }     
-        if ($emailAddress === NULL) { return "Missing compulsory fields [emailAddress]"; }
-        
-        // Find the dn of the user
-        $user = $this->adldap->user()->info($username, array("cn","proxyaddresses"), $isGUID);
-        if ($user[0]["dn"] === NULL){ return false; }
-        $userDn = $user[0]["dn"];
-        
-        if (is_array($user[0]["proxyaddresses"])) {
-            $modAddresses = array();
-            for ($i=0;$iadldap->getLdapConnection(), $userDn, $modAddresses);
-            if ($result == false) { 
-                return false; 
-            }
-            
-            return true;
-        }
-        
-    }
-    
-    /**
-    * Mail enable a contact
-    * Allows email to be sent to them through Exchange
-    * 
-    * @param string $distinguishedName The contact to mail enable
-    * @param string $emailAddress The email address to allow emails to be sent through
-    * @param string $mailNickname The mailnickname for the contact in Exchange.  If NULL this will be set to the display name
-    * @return bool
-    */
-    public function contactMailEnable($distinguishedName, $emailAddress, $mailNickname = NULL)
-    {
-        if ($distinguishedName === NULL) { return "Missing compulsory field [distinguishedName]"; }   
-        if ($emailAddress === NULL) { return "Missing compulsory field [emailAddress]"; }  
-        
-        if ($mailNickname !== NULL) {
-            // Find the dn of the user
-            $user = $this->adldap->contact()->info($distinguishedName, array("cn","displayname"));
-            if ($user[0]["displayname"] === NULL) { return false; }
-            $mailNickname = $user[0]['displayname'][0];
-        }
-        
-        $attributes = array("email"=>$emailAddress,"contact_email"=>"SMTP:" . $emailAddress,"exchange_proxyaddress"=>"SMTP:" . $emailAddress,"exchange_mailnickname" => $mailNickname);
-         
-        // Translate the update to the LDAP schema                
-        $mod = $this->adldap->adldap_schema($attributes);
-        
-        // Check to see if this is an enabled status update
-        if (!$mod) { return false; }
-        
-        // Do the update
-        $result = ldap_modify($this->adldap->getLdapConnection(), $distinguishedName, $mod);
-        if ($result == false) { return false; }
-        
-        return true;
-    }
-    
-    /**
-    * Returns a list of Exchange Servers in the ConfigurationNamingContext of the domain
-    * 
-    * @param array $attributes An array of the AD attributes you wish to return
-    * @return array
-    */
-    public function servers($attributes = array('cn','distinguishedname','serialnumber')) 
-    {
-        if (!$this->adldap->getLdapBind()){ return false; }
-        
-        $configurationNamingContext = $this->adldap->getRootDse(array('configurationnamingcontext'));
-        $sr = @ldap_search($this->adldap->getLdapConnection(), $configurationNamingContext[0]['configurationnamingcontext'][0],'(&(objectCategory=msExchExchangeServer))', $attributes);
-        $entries = @ldap_get_entries($this->adldap->getLdapConnection(), $sr);
-        return $entries;
-    }
-    
-    /**
-    * Returns a list of Storage Groups in Exchange for a given mail server
-    * 
-    * @param string $exchangeServer The full DN of an Exchange server.  You can use exchange_servers() to find the DN for your server
-    * @param array $attributes An array of the AD attributes you wish to return
-    * @param bool $recursive If enabled this will automatically query the databases within a storage group
-    * @return array
-    */
-    public function storageGroups($exchangeServer, $attributes = array('cn','distinguishedname'), $recursive = NULL) 
-    {
-        if (!$this->adldap->getLdapBind()){ return false; }
-        if ($exchangeServer === NULL) { return "Missing compulsory field [exchangeServer]"; }
-        if ($recursive === NULL) { $recursive = $this->adldap->getRecursiveGroups(); }
-
-        $filter = '(&(objectCategory=msExchStorageGroup))';
-        $sr = @ldap_search($this->adldap->getLdapConnection(), $exchangeServer, $filter, $attributes);
-        $entries = @ldap_get_entries($this->adldap->getLdapConnection(), $sr);
-
-        if ($recursive === true) {
-            for ($i=0; $i<$entries['count']; $i++) {
-                $entries[$i]['msexchprivatemdb'] = $this->storageDatabases($entries[$i]['distinguishedname'][0]);       
-            }
-        }
-        
-        return $entries;
-    }
-    
-    /**
-    * Returns a list of Databases within any given storage group in Exchange for a given mail server
-    * 
-    * @param string $storageGroup The full DN of an Storage Group.  You can use exchange_storage_groups() to find the DN 
-    * @param array $attributes An array of the AD attributes you wish to return
-    * @return array
-    */
-    public function storageDatabases($storageGroup, $attributes = array('cn','distinguishedname','displayname')) {
-        if (!$this->adldap->getLdapBind()){ return false; }
-        if ($storageGroup === NULL) { return "Missing compulsory field [storageGroup]"; }
-        
-        $filter = '(&(objectCategory=msExchPrivateMDB))';
-        $sr = @ldap_search($this->adldap->getLdapConnection(), $storageGroup, $filter, $attributes);
-        $entries = @ldap_get_entries($this->adldap->getLdapConnection(), $sr);
-        return $entries;
-    }
-}
-?>
\ No newline at end of file
diff --git a/inc/adLDAP/classes/adLDAPFolders.php b/inc/adLDAP/classes/adLDAPFolders.php
deleted file mode 100644
index 55120152d..000000000
--- a/inc/adLDAP/classes/adLDAPFolders.php
+++ /dev/null
@@ -1,179 +0,0 @@
-adldap = $adldap;
-    }
-    
-    /**
-    * Delete a distinguished name from Active Directory
-    * You should never need to call this yourself, just use the wrapper functions user_delete and contact_delete
-    *
-    * @param string $dn The distinguished name to delete
-    * @return bool
-    */
-    public function delete($dn){ 
-        $result = ldap_delete($this->adldap->getLdapConnection(), $dn);
-        if ($result != true) { 
-            return false; 
-        }
-        return true;
-    }
-    
-    /**
-    * Returns a folder listing for a specific OU
-    * See http://adldap.sourceforge.net/wiki/doku.php?id=api_folder_functions
-    * 
-    * @param array $folderName An array to the OU you wish to list. 
-    *                           If set to NULL will list the root, strongly recommended to set 
-    *                           $recursive to false in that instance!
-    * @param string $dnType The type of record to list.  This can be ADLDAP_FOLDER or ADLDAP_CONTAINER.
-    * @param bool $recursive Recursively search sub folders
-    * @param bool $type Specify a type of object to search for
-    * @return array
-    */
-    public function listing($folderName = NULL, $dnType = adLDAP::ADLDAP_FOLDER, $recursive = NULL, $type = NULL) 
-    {
-        if ($recursive === NULL) { $recursive = $this->adldap->getRecursiveGroups(); } //use the default option if they haven't set it
-        if (!$this->adldap->getLdapBind()) { return false; }
-
-        $filter = '(&';
-        if ($type !== NULL) {
-            switch ($type) {
-                case 'contact':
-                    $filter .= '(objectClass=contact)';
-                    break;
-                case 'computer':
-                    $filter .= '(objectClass=computer)';
-                    break;
-                case 'group':
-                    $filter .= '(objectClass=group)';
-                    break;
-                case 'folder':
-                    $filter .= '(objectClass=organizationalUnit)';
-                    break;
-                case 'container':
-                    $filter .= '(objectClass=container)';
-                    break;
-                case 'domain':
-                    $filter .= '(objectClass=builtinDomain)';
-                    break;
-                default:
-                    $filter .= '(objectClass=user)';
-                    break;   
-            }
-        }
-        else {
-            $filter .= '(objectClass=*)';   
-        }
-        // If the folder name is null then we will search the root level of AD
-        // This requires us to not have an OU= part, just the base_dn
-        $searchOu = $this->adldap->getBaseDn();
-        if (is_array($folderName)) {
-            $ou = $dnType . "=" . implode("," . $dnType . "=", $folderName);
-            $filter .= '(!(distinguishedname=' . $ou . ',' . $this->adldap->getBaseDn() . ')))';
-            $searchOu = $ou . ',' . $this->adldap->getBaseDn();
-        }
-        else {
-            $filter .= '(!(distinguishedname=' . $this->adldap->getBaseDn() . ')))';
-        }
-
-        if ($recursive === true) {
-            $sr = ldap_search($this->adldap->getLdapConnection(), $searchOu, $filter, array('objectclass', 'distinguishedname', 'samaccountname'));
-            $entries = @ldap_get_entries($this->adldap->getLdapConnection(), $sr);
-            if (is_array($entries)) {
-                return $entries;
-            }
-        }
-        else {
-            $sr = ldap_list($this->adldap->getLdapConnection(), $searchOu, $filter, array('objectclass', 'distinguishedname', 'samaccountname'));
-            $entries = @ldap_get_entries($this->adldap->getLdapConnection(), $sr);
-            if (is_array($entries)) {
-                return $entries;
-            }
-        }
-        
-        return false;
-    }
-
-    /**
-    * Create an organizational unit
-    * 
-    * @param array $attributes Default attributes of the ou
-    * @return bool
-    */
-    public function create($attributes)
-    {
-        if (!is_array($attributes)){ return "Attributes must be an array"; }
-        if (!is_array($attributes["container"])) { return "Container attribute must be an array."; }
-        if (!array_key_exists("ou_name",$attributes)) { return "Missing compulsory field [ou_name]"; }
-        if (!array_key_exists("container",$attributes)) { return "Missing compulsory field [container]"; }
-        
-        $attributes["container"] = array_reverse($attributes["container"]);
-
-        $add=array();
-        $add["objectClass"] = "organizationalUnit";
-        $add["OU"] = $attributes['ou_name'];
-        $containers = "";
-        if (count($attributes['container']) > 0) {
-            $containers = "OU=" . implode(",OU=", $attributes["container"]) . ",";
-        }
-
-        $containers = "OU=" . implode(",OU=", $attributes["container"]);
-        $result = ldap_add($this->adldap->getLdapConnection(), "OU=" . $add["OU"] . ", " . $containers . $this->adldap->getBaseDn(), $add);
-        if ($result != true) { 
-            return false; 
-        }
-        
-        return true;
-    }
-    
-}
-
-?>
\ No newline at end of file
diff --git a/inc/adLDAP/classes/adLDAPGroups.php b/inc/adLDAP/classes/adLDAPGroups.php
deleted file mode 100644
index 05e4cc93b..000000000
--- a/inc/adLDAP/classes/adLDAPGroups.php
+++ /dev/null
@@ -1,631 +0,0 @@
-adldap = $adldap;
-    }
-    
-    /**
-    * Add a group to a group
-    * 
-    * @param string $parent The parent group name
-    * @param string $child The child group name
-    * @return bool
-    */
-    public function addGroup($parent,$child){
-
-        // Find the parent group's dn
-        $parentGroup = $this->ginfo($parent, array("cn"));
-        if ($parentGroup[0]["dn"] === NULL){
-            return false; 
-        }
-        $parentDn = $parentGroup[0]["dn"];
-        
-        // Find the child group's dn
-        $childGroup = $this->info($child, array("cn"));
-        if ($childGroup[0]["dn"] === NULL){ 
-            return false; 
-        }
-        $childDn = $childGroup[0]["dn"];
-                
-        $add = array();
-        $add["member"] = $childDn;
-        
-        $result = @ldap_mod_add($this->adldap->getLdapConnection(), $parentDn, $add);
-        if ($result == false) { 
-            return false; 
-        }
-        return true;
-    }
-    
-    /**
-    * Add a user to a group
-    * 
-    * @param string $group The group to add the user to
-    * @param string $user The user to add to the group
-    * @param bool $isGUID Is the username passed a GUID or a samAccountName
-    * @return bool
-    */
-    public function addUser($group, $user, $isGUID = false)
-    {
-        // Adding a user is a bit fiddly, we need to get the full DN of the user
-        // and add it using the full DN of the group
-        
-        // Find the user's dn
-        $userDn = $this->adldap->user()->dn($user, $isGUID);
-        if ($userDn === false) { 
-            return false; 
-        }
-        
-        // Find the group's dn
-        $groupInfo = $this->info($group, array("cn"));
-        if ($groupInfo[0]["dn"] === NULL) { 
-            return false; 
-        }
-        $groupDn = $groupInfo[0]["dn"];
-        
-        $add = array();
-        $add["member"] = $userDn;
-        
-        $result = @ldap_mod_add($this->adldap->getLdapConnection(), $groupDn, $add);
-        if ($result == false) { 
-            return false; 
-        }
-        return true;
-    }
-    
-    /**
-    * Add a contact to a group
-    * 
-    * @param string $group The group to add the contact to
-    * @param string $contactDn The DN of the contact to add
-    * @return bool
-    */
-    public function addContact($group, $contactDn)
-    {
-        // To add a contact we take the contact's DN
-        // and add it using the full DN of the group
-        
-        // Find the group's dn
-        $groupInfo = $this->info($group, array("cn"));
-        if ($groupInfo[0]["dn"] === NULL) { 
-            return false; 
-        }
-        $groupDn = $groupInfo[0]["dn"];
-        
-        $add = array();
-        $add["member"] = $contactDn;
-        
-        $result = @ldap_mod_add($this->adldap->getLdapConnection(), $groupDn, $add);
-        if ($result == false) { 
-            return false; 
-        }
-        return true;
-    }
-
-    /**
-    * Create a group
-    * 
-    * @param array $attributes Default attributes of the group
-    * @return bool
-    */
-    public function create($attributes)
-    {
-        if (!is_array($attributes)){ return "Attributes must be an array"; }
-        if (!array_key_exists("group_name", $attributes)){ return "Missing compulsory field [group_name]"; }
-        if (!array_key_exists("container", $attributes)){ return "Missing compulsory field [container]"; }
-        if (!array_key_exists("description", $attributes)){ return "Missing compulsory field [description]"; }
-        if (!is_array($attributes["container"])){ return "Container attribute must be an array."; }
-        $attributes["container"] = array_reverse($attributes["container"]);
-
-        //$member_array = array();
-        //$member_array[0] = "cn=user1,cn=Users,dc=yourdomain,dc=com";
-        //$member_array[1] = "cn=administrator,cn=Users,dc=yourdomain,dc=com";
-        
-        $add = array();
-        $add["cn"] = $attributes["group_name"];
-        $add["samaccountname"] = $attributes["group_name"];
-        $add["objectClass"] = "Group";
-        $add["description"] = $attributes["description"];
-        //$add["member"] = $member_array; UNTESTED
-
-        $container = "OU=" . implode(",OU=", $attributes["container"]);
-        $result = ldap_add($this->adldap->getLdapConnection(), "CN=" . $add["cn"] . ", " . $container . "," . $this->adldap->getBaseDn(), $add);
-        if ($result != true) { 
-            return false; 
-        }
-        return true;
-    }
-    
-    /**
-    * Delete a group account 
-    * 
-    * @param string $group The group to delete (please be careful here!) 
-    * 
-    * @return array 
-    */
-    public function delete($group) {
-        if (!$this->adldap->getLdapBind()){ return false; }
-        if ($group === null){ return "Missing compulsory field [group]"; }
-        
-        $groupInfo = $this->info($group, array("*"));
-        $dn = $groupInfo[0]['distinguishedname'][0]; 
-        $result = $this->adldap->folder()->delete($dn); 
-        if ($result !== true) { 
-            return false; 
-        } return true;   
-    }
-
-    /**
-    * Remove a group from a group
-    * 
-    * @param string $parent The parent group name
-    * @param string $child The child group name
-    * @return bool
-    */
-    public function removeGroup($parent , $child)
-    {
-    
-        // Find the parent dn
-        $parentGroup = $this->info($parent, array("cn"));
-        if ($parentGroup[0]["dn"] === NULL) { 
-            return false; 
-        }
-        $parentDn = $parentGroup[0]["dn"];
-        
-        // Find the child dn
-        $childGroup = $this->info($child, array("cn"));
-        if ($childGroup[0]["dn"] === NULL) { 
-            return false; 
-        }
-        $childDn = $childGroup[0]["dn"];
-        
-        $del = array();
-        $del["member"] = $childDn;
-        
-        $result = @ldap_mod_del($this->adldap->getLdapConnection(), $parentDn, $del);
-        if ($result == false) { 
-            return false; 
-        }
-        return true;
-    }
-    
-    /**
-    * Remove a user from a group
-    * 
-    * @param string $group The group to remove a user from
-    * @param string $user The AD user to remove from the group
-    * @param bool $isGUID Is the username passed a GUID or a samAccountName
-    * @return bool
-    */
-    public function removeUser($group, $user, $isGUID = false)
-    {
-    
-        // Find the parent dn
-        $groupInfo = $this->info($group, array("cn"));
-        if ($groupInfo[0]["dn"] === NULL){ 
-            return false; 
-        }
-        $groupDn = $groupInfo[0]["dn"];
-        
-        // Find the users dn
-        $userDn = $this->adldap->user()->dn($user, $isGUID);
-        if ($userDn === false) {
-            return false; 
-        }
-
-        $del = array();
-        $del["member"] = $userDn;
-        
-        $result = @ldap_mod_del($this->adldap->getLdapConnection(), $groupDn, $del);
-        if ($result == false) {
-            return false; 
-        }
-        return true;
-    }
-    
-    /**
-    * Remove a contact from a group
-    * 
-    * @param string $group The group to remove a user from
-    * @param string $contactDn The DN of a contact to remove from the group
-    * @return bool
-    */
-    public function removeContact($group, $contactDn)
-    {
-    
-        // Find the parent dn
-        $groupInfo = $this->info($group, array("cn"));
-        if ($groupInfo[0]["dn"] === NULL) { 
-            return false; 
-        }
-        $groupDn = $groupInfo[0]["dn"];
-    
-        $del = array();
-        $del["member"] = $contactDn;
-        
-        $result = @ldap_mod_del($this->adldap->getLdapConnection(), $groupDn, $del);
-        if ($result == false) { 
-            return false; 
-        }
-        return true;
-    }
-    
-    /**
-    * Return a list of groups in a group
-    * 
-    * @param string $group The group to query
-    * @param bool $recursive Recursively get groups
-    * @return array
-    */
-    public function inGroup($group, $recursive = NULL)
-    {
-        if (!$this->adldap->getLdapBind()){ return false; }
-        if ($recursive === NULL){ $recursive = $this->adldap->getRecursiveGroups(); } // Use the default option if they haven't set it 
-        
-        // Search the directory for the members of a group
-        $info = $this->info($group, array("member","cn"));
-        $groups = $info[0]["member"];
-        if (!is_array($groups)) {
-            return false;   
-        }
- 
-        $groupArray = array();
-
-        for ($i=0; $i<$groups["count"]; $i++){ 
-             $filter = "(&(objectCategory=group)(distinguishedName=" . $this->adldap->utilities()->ldapSlashes($groups[$i]) . "))";
-             $fields = array("samaccountname", "distinguishedname", "objectClass");
-             $sr = ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields);
-             $entries = ldap_get_entries($this->adldap->getLdapConnection(), $sr);
-
-             // not a person, look for a group  
-             if ($entries['count'] == 0 && $recursive == true) {  
-                $filter = "(&(objectCategory=group)(distinguishedName=" . $this->adldap->utilities()->ldapSlashes($groups[$i]) . "))";  
-                $fields = array("distinguishedname");  
-                $sr = ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields);  
-                $entries = ldap_get_entries($this->adldap->getLdapConnection(), $sr);  
-                if (!isset($entries[0]['distinguishedname'][0])) {
-                    continue;  
-                }
-                $subGroups = $this->inGroup($entries[0]['distinguishedname'][0], $recursive);  
-                if (is_array($subGroups)) {
-                    $groupArray = array_merge($groupArray, $subGroups); 
-                    $groupArray = array_unique($groupArray);  
-                }
-                continue;  
-             } 
-
-             $groupArray[] = $entries[0]['distinguishedname'][0];
-        }
-        return $groupArray;
-    }
-    
-    /**
-    * Return a list of members in a group
-    * 
-    * @param string $group The group to query
-    * @param bool $recursive Recursively get group members
-    * @return array
-    */
-    public function members($group, $recursive = NULL)
-    {
-        if (!$this->adldap->getLdapBind()){ return false; }
-        if ($recursive === NULL){ $recursive = $this->adldap->getRecursiveGroups(); } // Use the default option if they haven't set it 
-        // Search the directory for the members of a group
-        $info = $this->info($group, array("member","cn"));
-        $users = $info[0]["member"];
-        if (!is_array($users)) {
-            return false;   
-        }
- 
-        $userArray = array();
-
-        for ($i=0; $i<$users["count"]; $i++){ 
-             $filter = "(&(objectCategory=person)(distinguishedName=" . $this->adldap->utilities()->ldapSlashes($users[$i]) . "))";
-             $fields = array("samaccountname", "distinguishedname", "objectClass");
-             $sr = ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields);
-             $entries = ldap_get_entries($this->adldap->getLdapConnection(), $sr);
-
-             // not a person, look for a group  
-             if ($entries['count'] == 0 && $recursive == true) {  
-                $filter = "(&(objectCategory=group)(distinguishedName=" . $this->adldap->utilities()->ldapSlashes($users[$i]) . "))";  
-                $fields = array("samaccountname");  
-                $sr = ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields);  
-                $entries = ldap_get_entries($this->adldap->getLdapConnection(), $sr);  
-                if (!isset($entries[0]['samaccountname'][0])) {
-                    continue;  
-                }
-                $subUsers = $this->members($entries[0]['samaccountname'][0], $recursive);  
-                if (is_array($subUsers)) {
-                    $userArray = array_merge($userArray, $subUsers); 
-                    $userArray = array_unique($userArray);  
-                }
-                continue;  
-             } 
-             else if ($entries['count'] == 0) {   
-                continue; 
-             } 
-
-             if ((!isset($entries[0]['samaccountname'][0]) || $entries[0]['samaccountname'][0] === NULL) && $entries[0]['distinguishedname'][0] !== NULL) {
-                 $userArray[] = $entries[0]['distinguishedname'][0];
-             }
-             else if ($entries[0]['samaccountname'][0] !== NULL) {
-                $userArray[] = $entries[0]['samaccountname'][0];
-             }
-        }
-        return $userArray;
-    }
-    
-    /**
-    * Group Information.  Returns an array of raw information about a group.
-    * The group name is case sensitive
-    * 
-    * @param string $groupName The group name to retrieve info about
-    * @param array $fields Fields to retrieve
-    * @return array
-    */
-    public function info($groupName, $fields = NULL)
-    {
-        if ($groupName === NULL) { return false; }
-        if (!$this->adldap->getLdapBind()) { return false; }
-        
-        if (stristr($groupName, '+')) {
-            $groupName = stripslashes($groupName);   
-        }
-        
-        $filter = "(&(objectCategory=group)(name=" . $this->adldap->utilities()->ldapSlashes($groupName) . "))";
-        if ($fields === NULL) { 
-            $fields = array("member","memberof","cn","description","distinguishedname","objectcategory","samaccountname"); 
-        }
-        $sr = ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields);
-        $entries = ldap_get_entries($this->adldap->getLdapConnection(), $sr);
-
-        return $entries;
-    }
-    
-    /**
-    * Group Information.  Returns an collection
-    * The group name is case sensitive
-    * 
-    * @param string $groupName The group name to retrieve info about
-    * @param array $fields Fields to retrieve
-    * @return adLDAPGroupCollection
-    */
-    public function infoCollection($groupName, $fields = NULL)
-    {
-        if ($groupName === NULL) { return false; }
-        if (!$this->adldap->getLdapBind()) { return false; }
-        
-        $info = $this->info($groupName, $fields);
-        if ($info !== false) {
-            $collection = new adLDAPGroupCollection($info, $this->adldap);
-            return $collection;
-        }
-        return false;
-    }
-    
-    /**
-    * Return a complete list of "groups in groups"
-    * 
-    * @param string $group The group to get the list from
-    * @return array
-    */
-    public function recursiveGroups($group)
-    {
-        if ($group === NULL) { return false; }
-
-        $stack = array(); 
-        $processed = array(); 
-        $retGroups = array(); 
-     
-        array_push($stack, $group); // Initial Group to Start with 
-        while (count($stack) > 0) {
-            $parent = array_pop($stack);
-            array_push($processed, $parent);
-            
-            $info = $this->info($parent, array("memberof"));
-            
-            if (isset($info[0]["memberof"]) && is_array($info[0]["memberof"])) {
-                $groups = $info[0]["memberof"]; 
-                if ($groups) {
-                    $groupNames = $this->adldap->utilities()->niceNames($groups);  
-                    $retGroups = array_merge($retGroups, $groupNames); //final groups to return
-                    foreach ($groupNames as $id => $groupName) { 
-                        if (!in_array($groupName, $processed)) {
-                            array_push($stack, $groupName);
-                        }
-                    }
-                }
-            }
-        }
-        
-        return $retGroups;
-    }
-    
-    /**
-    * Returns a complete list of the groups in AD based on a SAM Account Type  
-    * 
-    * @param string $sAMAaccountType The account type to return
-    * @param bool $includeDescription Whether to return a description
-    * @param string $search Search parameters
-    * @param bool $sorted Whether to sort the results
-    * @return array
-    */
-    public function search($sAMAaccountType = adLDAP::ADLDAP_SECURITY_GLOBAL_GROUP, $includeDescription = false, $search = "*", $sorted = true) {
-        if (!$this->adldap->getLdapBind()) { return false; }
-        
-        $filter = '(&(objectCategory=group)';
-        if ($sAMAaccountType !== null) {
-            $filter .= '(samaccounttype='. $sAMAaccountType .')';
-        }
-        $filter .= '(cn=' . $search . '))';
-        // Perform the search and grab all their details
-        $fields = array("samaccountname", "description");
-        $sr = ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields);
-        $entries = ldap_get_entries($this->adldap->getLdapConnection(), $sr);
-
-        $groupsArray = array();        
-        for ($i=0; $i<$entries["count"]; $i++){
-            if ($includeDescription && strlen($entries[$i]["description"][0]) > 0 ) {
-                $groupsArray[$entries[$i]["samaccountname"][0]] = $entries[$i]["description"][0];
-            }
-            else if ($includeDescription){
-                $groupsArray[$entries[$i]["samaccountname"][0]] = $entries[$i]["samaccountname"][0];
-            }
-            else {
-                array_push($groupsArray, $entries[$i]["samaccountname"][0]);
-            }
-        }
-        if ($sorted) { 
-            asort($groupsArray); 
-        }
-        return $groupsArray;
-    }
-    
-    /**
-    * Returns a complete list of all groups in AD
-    * 
-    * @param bool $includeDescription Whether to return a description
-    * @param string $search Search parameters
-    * @param bool $sorted Whether to sort the results
-    * @return array
-    */
-    public function all($includeDescription = false, $search = "*", $sorted = true){
-        $groupsArray = $this->search(null, $includeDescription, $search, $sorted);
-        return $groupsArray;
-    }
-    
-    /**
-    * Returns a complete list of security groups in AD
-    * 
-    * @param bool $includeDescription Whether to return a description
-    * @param string $search Search parameters
-    * @param bool $sorted Whether to sort the results
-    * @return array
-    */
-    public function allSecurity($includeDescription = false, $search = "*", $sorted = true){
-        $groupsArray = $this->search(adLDAP::ADLDAP_SECURITY_GLOBAL_GROUP, $includeDescription, $search, $sorted);
-        return $groupsArray;
-    }
-    
-    /**
-    * Returns a complete list of distribution lists in AD
-    * 
-    * @param bool $includeDescription Whether to return a description
-    * @param string $search Search parameters
-    * @param bool $sorted Whether to sort the results
-    * @return array
-    */
-    public function allDistribution($includeDescription = false, $search = "*", $sorted = true){
-        $groupsArray = $this->search(adLDAP::ADLDAP_DISTRIBUTION_GROUP, $includeDescription, $search, $sorted);
-        return $groupsArray;
-    }
-    
-    /**
-    * Coping with AD not returning the primary group
-    * http://support.microsoft.com/?kbid=321360 
-    * 
-    * This is a re-write based on code submitted by Bruce which prevents the 
-    * need to search each security group to find the true primary group
-    * 
-    * @param string $gid Group ID
-    * @param string $usersid User's Object SID
-    * @return mixed
-    */
-    public function getPrimaryGroup($gid, $usersid)
-    {
-        if ($gid === NULL || $usersid === NULL) { return false; }
-        $sr = false;
-
-        $gsid = substr_replace($usersid, pack('V',$gid), strlen($usersid)-4,4);
-        $filter = '(objectsid=' . $this->adldap->utilities()->getTextSID($gsid).')';
-        $fields = array("samaccountname","distinguishedname");
-        $sr = ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields);
-        $entries = ldap_get_entries($this->adldap->getLdapConnection(), $sr);
-
-        if (isset($entries[0]['distinguishedname'][0])) {
-            return $entries[0]['distinguishedname'][0];
-        }
-        return false;
-     }
-     
-     /**
-    * Coping with AD not returning the primary group
-    * http://support.microsoft.com/?kbid=321360 
-    * 
-    * For some reason it's not possible to search on primarygrouptoken=XXX
-    * If someone can show otherwise, I'd like to know about it :)
-    * this way is resource intensive and generally a pain in the @#%^
-    * 
-    * @deprecated deprecated since version 3.1, see get get_primary_group
-    * @param string $gid Group ID
-    * @return string
-    */
-    public function cn($gid){    
-        if ($gid === NULL) { return false; }
-        $sr = false;
-        $r = '';
-        
-        $filter = "(&(objectCategory=group)(samaccounttype=" . adLDAP::ADLDAP_SECURITY_GLOBAL_GROUP . "))";
-        $fields = array("primarygrouptoken", "samaccountname", "distinguishedname");
-        $sr = ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields);
-        $entries = ldap_get_entries($this->adldap->getLdapConnection(), $sr);
-        
-        for ($i=0; $i<$entries["count"]; $i++){
-            if ($entries[$i]["primarygrouptoken"][0] == $gid) {
-                $r = $entries[$i]["distinguishedname"][0];
-                $i = $entries["count"];
-            }
-        }
-
-        return $r;
-    }
-}
-?>
diff --git a/inc/adLDAP/classes/adLDAPUsers.php b/inc/adLDAP/classes/adLDAPUsers.php
deleted file mode 100644
index 96a93b512..000000000
--- a/inc/adLDAP/classes/adLDAPUsers.php
+++ /dev/null
@@ -1,682 +0,0 @@
-adldap = $adldap;
-    }
-    
-    /**
-    * Validate a user's login credentials
-    * 
-    * @param string $username A user's AD username
-    * @param string $password A user's AD password
-    * @param bool optional $prevent_rebind
-    * @return bool
-    */
-    public function authenticate($username, $password, $preventRebind = false) {
-        return $this->adldap->authenticate($username, $password, $preventRebind);
-    }
-    
-    /**
-    * Create a user
-    * 
-    * If you specify a password here, this can only be performed over SSL
-    * 
-    * @param array $attributes The attributes to set to the user account
-    * @return bool
-    */
-    public function create($attributes)
-    {
-        // Check for compulsory fields
-        if (!array_key_exists("username", $attributes)){ return "Missing compulsory field [username]"; }
-        if (!array_key_exists("firstname", $attributes)){ return "Missing compulsory field [firstname]"; }
-        if (!array_key_exists("surname", $attributes)){ return "Missing compulsory field [surname]"; }
-        if (!array_key_exists("email", $attributes)){ return "Missing compulsory field [email]"; }
-        if (!array_key_exists("container", $attributes)){ return "Missing compulsory field [container]"; }
-        if (!is_array($attributes["container"])){ return "Container attribute must be an array."; }
-
-        if (array_key_exists("password",$attributes) && (!$this->adldap->getUseSSL() && !$this->adldap->getUseTLS())){ 
-            throw new adLDAPException('SSL must be configured on your webserver and enabled in the class to set passwords.');
-        }
-
-        if (!array_key_exists("display_name", $attributes)) { 
-            $attributes["display_name"] = $attributes["firstname"] . " " . $attributes["surname"]; 
-        }
-
-        // Translate the schema
-        $add = $this->adldap->adldap_schema($attributes);
-        
-        // Additional stuff only used for adding accounts
-        $add["cn"][0] = $attributes["display_name"];
-        $add["samaccountname"][0] = $attributes["username"];
-        $add["objectclass"][0] = "top";
-        $add["objectclass"][1] = "person";
-        $add["objectclass"][2] = "organizationalPerson";
-        $add["objectclass"][3] = "user"; //person?
-        //$add["name"][0]=$attributes["firstname"]." ".$attributes["surname"];
-
-        // Set the account control attribute
-        $control_options = array("NORMAL_ACCOUNT");
-        if (!$attributes["enabled"]) { 
-            $control_options[] = "ACCOUNTDISABLE"; 
-        }
-        $add["userAccountControl"][0] = $this->accountControl($control_options);
-        
-        // Determine the container
-        $attributes["container"] = array_reverse($attributes["container"]);
-        $container = "OU=" . implode(", OU=",$attributes["container"]);
-
-        // Add the entry
-        $result = @ldap_add($this->adldap->getLdapConnection(), "CN=" . $add["cn"][0] . ", " . $container . "," . $this->adldap->getBaseDn(), $add);
-        if ($result != true) { 
-            return false; 
-        }
-        
-        return true;
-    }
-    
-    /**
-    * Account control options
-    *
-    * @param array $options The options to convert to int 
-    * @return int
-    */
-    protected function accountControl($options)
-    {
-        $val=0;
-
-        if (is_array($options)) {
-            if (in_array("SCRIPT",$options)){ $val=$val+1; }
-            if (in_array("ACCOUNTDISABLE",$options)){ $val=$val+2; }
-            if (in_array("HOMEDIR_REQUIRED",$options)){ $val=$val+8; }
-            if (in_array("LOCKOUT",$options)){ $val=$val+16; }
-            if (in_array("PASSWD_NOTREQD",$options)){ $val=$val+32; }
-            //PASSWD_CANT_CHANGE Note You cannot assign this permission by directly modifying the UserAccountControl attribute.
-            //For information about how to set the permission programmatically, see the "Property flag descriptions" section.
-            if (in_array("ENCRYPTED_TEXT_PWD_ALLOWED",$options)){ $val=$val+128; }
-            if (in_array("TEMP_DUPLICATE_ACCOUNT",$options)){ $val=$val+256; }
-            if (in_array("NORMAL_ACCOUNT",$options)){ $val=$val+512; }
-            if (in_array("INTERDOMAIN_TRUST_ACCOUNT",$options)){ $val=$val+2048; }
-            if (in_array("WORKSTATION_TRUST_ACCOUNT",$options)){ $val=$val+4096; }
-            if (in_array("SERVER_TRUST_ACCOUNT",$options)){ $val=$val+8192; }
-            if (in_array("DONT_EXPIRE_PASSWORD",$options)){ $val=$val+65536; }
-            if (in_array("MNS_LOGON_ACCOUNT",$options)){ $val=$val+131072; }
-            if (in_array("SMARTCARD_REQUIRED",$options)){ $val=$val+262144; }
-            if (in_array("TRUSTED_FOR_DELEGATION",$options)){ $val=$val+524288; }
-            if (in_array("NOT_DELEGATED",$options)){ $val=$val+1048576; }
-            if (in_array("USE_DES_KEY_ONLY",$options)){ $val=$val+2097152; }
-            if (in_array("DONT_REQ_PREAUTH",$options)){ $val=$val+4194304; } 
-            if (in_array("PASSWORD_EXPIRED",$options)){ $val=$val+8388608; }
-            if (in_array("TRUSTED_TO_AUTH_FOR_DELEGATION",$options)){ $val=$val+16777216; }
-        }
-        return $val;
-    }
-    
-    /**
-    * Delete a user account
-    * 
-    * @param string $username The username to delete (please be careful here!)
-    * @param bool $isGUID Is the username a GUID or a samAccountName
-    * @return array
-    */
-    public function delete($username, $isGUID = false) 
-    {      
-        $userinfo = $this->info($username, array("*"), $isGUID);
-        $dn = $userinfo[0]['distinguishedname'][0];
-        $result = $this->adldap->folder()->delete($dn);
-        if ($result != true) { 
-            return false;
-        }        
-        return true;
-    }
-    
-    /**
-    * Groups the user is a member of
-    * 
-    * @param string $username The username to query
-    * @param bool $recursive Recursive list of groups
-    * @param bool $isGUID Is the username passed a GUID or a samAccountName
-    * @return array
-    */
-    public function groups($username, $recursive = NULL, $isGUID = false)
-    {
-        if ($username === NULL) { return false; }
-        if ($recursive === NULL) { $recursive = $this->adldap->getRecursiveGroups(); } // Use the default option if they haven't set it
-        if (!$this->adldap->getLdapBind()) { return false; }
-        
-        // Search the directory for their information
-        $info = @$this->info($username, array("memberof", "primarygroupid"), $isGUID);
-        $groups = $this->adldap->utilities()->niceNames($info[0]["memberof"]); // Presuming the entry returned is our guy (unique usernames)
-
-        if ($recursive === true){
-            foreach ($groups as $id => $groupName){
-                $extraGroups = $this->adldap->group()->recursiveGroups($groupName);
-                $groups = array_merge($groups, $extraGroups);
-            }
-        }
-        
-        return $groups;
-    }
-    
-    /**
-    * Find information about the users. Returned in a raw array format from AD
-    * 
-    * @param string $username The username to query
-    * @param array $fields Array of parameters to query
-    * @param bool $isGUID Is the username passed a GUID or a samAccountName
-    * @return array
-    */
-    public function info($username, $fields = NULL, $isGUID = false)
-    {
-        if ($username === NULL) { return false; }
-        if (!$this->adldap->getLdapBind()) { return false; }
-
-        if ($isGUID === true) {
-            $username = $this->adldap->utilities()->strGuidToHex($username);
-            $filter = "objectguid=" . $username;
-        }
-        else if (strstr($username, "@")) {
-             $filter = "userPrincipalName=" . $username;
-        }
-        else {
-             $filter = "samaccountname=" . $username;
-        }
-        $filter = "(&(objectCategory=person)({$filter}))";
-        if ($fields === NULL) { 
-            $fields = array("samaccountname","mail","memberof","department","displayname","telephonenumber","primarygroupid","objectsid"); 
-        }
-        if (!in_array("objectsid", $fields)) {
-            $fields[] = "objectsid";
-        }
-        $sr = ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields);
-        $entries = ldap_get_entries($this->adldap->getLdapConnection(), $sr);
-        
-        if (isset($entries[0])) {
-            if ($entries[0]['count'] >= 1) {
-                if (in_array("memberof", $fields)) {
-                    // AD does not return the primary group in the ldap query, we may need to fudge it
-                    if ($this->adldap->getRealPrimaryGroup() && isset($entries[0]["primarygroupid"][0]) && isset($entries[0]["objectsid"][0])){
-                        //$entries[0]["memberof"][]=$this->group_cn($entries[0]["primarygroupid"][0]);
-                        $entries[0]["memberof"][] = $this->adldap->group()->getPrimaryGroup($entries[0]["primarygroupid"][0], $entries[0]["objectsid"][0]);
-                    } else {
-                        $entries[0]["memberof"][] = "CN=Domain Users,CN=Users," . $this->adldap->getBaseDn();
-                    }
-                    if (!isset($entries[0]["memberof"]["count"])) {
-                        $entries[0]["memberof"]["count"] = 0;
-                    }
-                    $entries[0]["memberof"]["count"]++;
-                }
-            }
-            
-            return $entries;
-        }
-        return false;
-    }
-    
-    /**
-    * Find information about the users. Returned in a raw array format from AD
-    * 
-    * @param string $username The username to query
-    * @param array $fields Array of parameters to query
-    * @param bool $isGUID Is the username passed a GUID or a samAccountName
-    * @return mixed
-    */
-    public function infoCollection($username, $fields = NULL, $isGUID = false)
-    {
-        if ($username === NULL) { return false; }
-        if (!$this->adldap->getLdapBind()) { return false; }
-        
-        $info = $this->info($username, $fields, $isGUID);
-        
-        if ($info !== false) {
-            $collection = new adLDAPUserCollection($info, $this->adldap);
-            return $collection;
-        }
-        return false;
-    }
-    
-    /**
-    * Determine if a user is in a specific group
-    * 
-    * @param string $username The username to query
-    * @param string $group The name of the group to check against
-    * @param bool $recursive Check groups recursively
-    * @param bool $isGUID Is the username passed a GUID or a samAccountName
-    * @return bool
-    */
-    public function inGroup($username, $group, $recursive = NULL, $isGUID = false)
-    {
-        if ($username === NULL) { return false; }
-        if ($group === NULL) { return false; }
-        if (!$this->adldap->getLdapBind()) { return false; }
-        if ($recursive === NULL) { $recursive = $this->adldap->getRecursiveGroups(); } // Use the default option if they haven't set it
-        
-        // Get a list of the groups
-        $groups = $this->groups($username, $recursive, $isGUID);
-        
-        // Return true if the specified group is in the group list
-        if (in_array($group, $groups)) { 
-            return true; 
-        }
-
-        return false;
-    }
-    
-    /**
-    * Determine a user's password expiry date
-    * 
-    * @param string $username The username to query
-    * @param book $isGUID Is the username passed a GUID or a samAccountName
-    * @requires bcmath http://www.php.net/manual/en/book.bc.php
-    * @return array
-    */
-    public function passwordExpiry($username, $isGUID = false) 
-    {
-        if ($username === NULL) { return "Missing compulsory field [username]"; }
-        if (!$this->adldap->getLdapBind()) { return false; }
-        if (!function_exists('bcmod')) { throw new adLDAPException("Missing function support [bcmod] http://www.php.net/manual/en/book.bc.php"); };
-        
-        $userInfo = $this->info($username, array("pwdlastset", "useraccountcontrol"), $isGUID);
-        $pwdLastSet = $userInfo[0]['pwdlastset'][0];
-        $status = array();
-        
-        if ($userInfo[0]['useraccountcontrol'][0] == '66048') {
-            // Password does not expire
-            return "Does not expire";
-        }
-        if ($pwdLastSet === '0') {
-            // Password has already expired
-            return "Password has expired";
-        }
-        
-         // Password expiry in AD can be calculated from TWO values:
-         //   - User's own pwdLastSet attribute: stores the last time the password was changed
-         //   - Domain's maxPwdAge attribute: how long passwords last in the domain
-         //
-         // Although Microsoft chose to use a different base and unit for time measurements.
-         // This function will convert them to Unix timestamps
-         $sr = ldap_read($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), 'objectclass=*', array('maxPwdAge'));
-         if (!$sr) {
-             return false;
-         }
-         $info = ldap_get_entries($this->adldap->getLdapConnection(), $sr);
-         $maxPwdAge = $info[0]['maxpwdage'][0];
-         
-
-         // See MSDN: http://msdn.microsoft.com/en-us/library/ms974598.aspx
-         //
-         // pwdLastSet contains the number of 100 nanosecond intervals since January 1, 1601 (UTC), 
-         // stored in a 64 bit integer. 
-         //
-         // The number of seconds between this date and Unix epoch is 11644473600.
-         //
-         // maxPwdAge is stored as a large integer that represents the number of 100 nanosecond
-         // intervals from the time the password was set before the password expires.
-         //
-         // We also need to scale this to seconds but also this value is a _negative_ quantity!
-         //
-         // If the low 32 bits of maxPwdAge are equal to 0 passwords do not expire
-         //
-         // Unfortunately the maths involved are too big for PHP integers, so I've had to require
-         // BCMath functions to work with arbitrary precision numbers.
-         if (bcmod($maxPwdAge, 4294967296) === '0') {
-            return "Domain does not expire passwords";
-        }
-        
-        // Add maxpwdage and pwdlastset and we get password expiration time in Microsoft's
-        // time units.  Because maxpwd age is negative we need to subtract it.
-        $pwdExpire = bcsub($pwdLastSet, $maxPwdAge);
-    
-        // Convert MS's time to Unix time
-        $status['expiryts'] = bcsub(bcdiv($pwdExpire, '10000000'), '11644473600');
-        $status['expiryformat'] = date('Y-m-d H:i:s', bcsub(bcdiv($pwdExpire, '10000000'), '11644473600'));
-        
-        return $status;
-    }
-    
-    /**
-    * Modify a user
-    * 
-    * @param string $username The username to query
-    * @param array $attributes The attributes to modify.  Note if you set the enabled attribute you must not specify any other attributes
-    * @param bool $isGUID Is the username passed a GUID or a samAccountName
-    * @return bool
-    */
-    public function modify($username, $attributes, $isGUID = false)
-    {
-        if ($username === NULL) { return "Missing compulsory field [username]"; }
-        if (array_key_exists("password", $attributes) && !$this->adldap->getUseSSL() && !$this->adldap->getUseTLS()) { 
-            throw new adLDAPException('SSL/TLS must be configured on your webserver and enabled in the class to set passwords.');
-        }
-
-        // Find the dn of the user
-        $userDn = $this->dn($username, $isGUID);
-        if ($userDn === false) { 
-            return false; 
-        }
-        
-        // Translate the update to the LDAP schema                
-        $mod = $this->adldap->adldap_schema($attributes);
-        
-        // Check to see if this is an enabled status update
-        if (!$mod && !array_key_exists("enabled", $attributes)){ 
-            return false; 
-        }
-        
-        // Set the account control attribute (only if specified)
-        if (array_key_exists("enabled", $attributes)){
-            if ($attributes["enabled"]){ 
-                $controlOptions = array("NORMAL_ACCOUNT"); 
-            }
-            else { 
-                $controlOptions = array("NORMAL_ACCOUNT", "ACCOUNTDISABLE"); 
-            }
-            $mod["userAccountControl"][0] = $this->accountControl($controlOptions);
-        }
-
-        // Do the update
-        $result = @ldap_modify($this->adldap->getLdapConnection(), $userDn, $mod);
-        if ($result == false) { 
-            return false; 
-        }
-        
-        return true;
-    }
-    
-    /**
-    * Disable a user account
-    * 
-    * @param string $username The username to disable
-    * @param bool $isGUID Is the username passed a GUID or a samAccountName
-    * @return bool
-    */
-    public function disable($username, $isGUID = false)
-    {
-        if ($username === NULL) { return "Missing compulsory field [username]"; }
-        $attributes = array("enabled" => 0);
-        $result = $this->modify($username, $attributes, $isGUID);
-        if ($result == false) { return false; }
-        
-        return true;
-    }
-    
-    /**
-    * Enable a user account
-    * 
-    * @param string $username The username to enable
-    * @param bool $isGUID Is the username passed a GUID or a samAccountName
-    * @return bool
-    */
-    public function enable($username, $isGUID = false)
-    {
-        if ($username === NULL) { return "Missing compulsory field [username]"; }
-        $attributes = array("enabled" => 1);
-        $result = $this->modify($username, $attributes, $isGUID);
-        if ($result == false) { return false; }
-        
-        return true;
-    }
-    
-    /**
-    * Set the password of a user - This must be performed over SSL
-    * 
-    * @param string $username The username to modify
-    * @param string $password The new password
-    * @param bool $isGUID Is the username passed a GUID or a samAccountName
-    * @return bool
-    */
-    public function password($username, $password, $isGUID = false)
-    {
-        if ($username === NULL) { return false; }
-        if ($password === NULL) { return false; }
-        if (!$this->adldap->getLdapBind()) { return false; }
-        if (!$this->adldap->getUseSSL() && !$this->adldap->getUseTLS()) { 
-            throw new adLDAPException('SSL must be configured on your webserver and enabled in the class to set passwords.');
-        }
-        
-        $userDn = $this->dn($username, $isGUID);
-        if ($userDn === false) { 
-            return false; 
-        }
-                
-        $add=array();
-        $add["unicodePwd"][0] = $this->encodePassword($password);
-        
-        $result = @ldap_mod_replace($this->adldap->getLdapConnection(), $userDn, $add);
-        if ($result === false){
-            $err = ldap_errno($this->adldap->getLdapConnection());
-            if ($err) {
-                $msg = 'Error ' . $err . ': ' . ldap_err2str($err) . '.';
-                if($err == 53) {
-                    $msg .= ' Your password might not match the password policy.';
-                }
-                throw new adLDAPException($msg);
-            }
-            else {
-                return false;
-            }
-        }
-        
-        return true;
-    }
-    
-    /**
-    * Encode a password for transmission over LDAP
-    *
-    * @param string $password The password to encode
-    * @return string
-    */
-    public function encodePassword($password)
-    {
-        $password="\"".$password."\"";
-        $encoded="";
-        for ($i=0; $i info($username, array("cn"), $isGUID);
-        if ($user[0]["dn"] === NULL) { 
-            return false; 
-        }
-        $userDn = $user[0]["dn"];
-        return $userDn;
-    }
-    
-    /**
-    * Return a list of all users in AD
-    * 
-    * @param bool $includeDescription Return a description of the user
-    * @param string $search Search parameter
-    * @param bool $sorted Sort the user accounts
-    * @return array
-    */
-    public function all($includeDescription = false, $search = "*", $sorted = true)
-    {
-        if (!$this->adldap->getLdapBind()) { return false; }
-        
-        // Perform the search and grab all their details
-        $filter = "(&(objectClass=user)(samaccounttype=" . adLDAP::ADLDAP_NORMAL_ACCOUNT .")(objectCategory=person)(cn=" . $search . "))";
-        $fields = array("samaccountname","displayname");
-        $sr = ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields);
-        $entries = ldap_get_entries($this->adldap->getLdapConnection(), $sr);
-
-        $usersArray = array();
-        for ($i=0; $i<$entries["count"]; $i++){
-            if ($includeDescription && strlen($entries[$i]["displayname"][0])>0){
-                $usersArray[$entries[$i]["samaccountname"][0]] = $entries[$i]["displayname"][0];
-            } elseif ($includeDescription){
-                $usersArray[$entries[$i]["samaccountname"][0]] = $entries[$i]["samaccountname"][0];
-            } else {
-                array_push($usersArray, $entries[$i]["samaccountname"][0]);
-            }
-        }
-        if ($sorted) { 
-            asort($usersArray); 
-        }
-        return $usersArray;
-    }
-    
-    /**
-    * Converts a username (samAccountName) to a GUID
-    * 
-    * @param string $username The username to query
-    * @return string
-    */
-    public function usernameToGuid($username) 
-    {
-        if (!$this->adldap->getLdapBind()){ return false; }
-        if ($username === null){ return "Missing compulsory field [username]"; }
-        
-        $filter = "samaccountname=" . $username; 
-        $fields = array("objectGUID"); 
-        $sr = @ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields); 
-        if (ldap_count_entries($this->adldap->getLdapConnection(), $sr) > 0) { 
-            $entry = @ldap_first_entry($this->adldap->getLdapConnection(), $sr); 
-            $guid = @ldap_get_values_len($this->adldap->getLdapConnection(), $entry, 'objectGUID'); 
-            $strGUID = $this->adldap->utilities()->binaryToText($guid[0]);          
-            return $strGUID; 
-        }
-        return false; 
-    }
-    
-    /**
-    * Return a list of all users in AD that have a specific value in a field
-    *
-    * @param bool $includeDescription Return a description of the user
-    * @param string $searchField Field to search search for
-    * @param string $searchFilter Value to search for in the specified field
-    * @param bool $sorted Sort the user accounts
-    * @return array
-    */
-    public function find($includeDescription = false, $searchField = false, $searchFilter = false, $sorted = true){
-        if (!$this->adldap->getLdapBind()){ return false; }
-          
-        // Perform the search and grab all their details
-        $searchParams = "";
-        if ($searchField) {
-            $searchParams = "(" . $searchField . "=" . $searchFilter . ")";
-        }                           
-        $filter = "(&(objectClass=user)(samaccounttype=" . adLDAP::ADLDAP_NORMAL_ACCOUNT .")(objectCategory=person)" . $searchParams . ")";
-        $fields = array("samaccountname","displayname");
-        $sr = ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields);
-        $entries = ldap_get_entries($this->adldap->getLdapConnection(), $sr);
-
-        $usersArray = array();
-        for ($i=0; $i < $entries["count"]; $i++) {
-            if ($includeDescription && strlen($entries[$i]["displayname"][0]) > 0) {
-                $usersArray[$entries[$i]["samaccountname"][0]] = $entries[$i]["displayname"][0];
-            }
-            else if ($includeDescription) {
-                $usersArray[$entries[$i]["samaccountname"][0]] = $entries[$i]["samaccountname"][0];
-            }
-            else {
-                array_push($usersArray, $entries[$i]["samaccountname"][0]);
-            }
-        }
-        if ($sorted){ 
-          asort($usersArray); 
-        }
-        return ($usersArray);
-    }
-    
-    /**
-    * Move a user account to a different OU
-    *
-    * @param string $username The username to move (please be careful here!)
-    * @param array $container The container or containers to move the user to (please be careful here!).
-    * accepts containers in 1. parent 2. child order
-    * @return array
-    */
-    public function move($username, $container) 
-    {
-        if (!$this->adldap->getLdapBind()) { return false; }
-        if ($username === null) { return "Missing compulsory field [username]"; }
-        if ($container === null) { return "Missing compulsory field [container]"; }
-        if (!is_array($container)) { return "Container must be an array"; }
-        
-        $userInfo = $this->info($username, array("*"));
-        $dn = $userInfo[0]['distinguishedname'][0];
-        $newRDn = "cn=" . $username;
-        $container = array_reverse($container);
-        $newContainer = "ou=" . implode(",ou=",$container);
-        $newBaseDn = strtolower($newContainer) . "," . $this->adldap->getBaseDn();
-        $result = @ldap_rename($this->adldap->getLdapConnection(), $dn, $newRDn, $newBaseDn, true);
-        if ($result !== true) {
-            return false;
-        }
-        return true;
-    }
-    
-    /**
-    * Get the last logon time of any user as a Unix timestamp
-    * 
-    * @param string $username
-    * @return long $unixTimestamp
-    */
-    public function getLastLogon($username) {
-        if (!$this->adldap->getLdapBind()) { return false; }
-        if ($username === null) { return "Missing compulsory field [username]"; }
-        $userInfo = $this->info($username, array("lastLogonTimestamp"));
-        $lastLogon = adLDAPUtils::convertWindowsTimeToUnixTime($userInfo[0]['lastLogonTimestamp'][0]);
-        return $lastLogon;
-    }
-    
-}
-?>
diff --git a/inc/adLDAP/classes/adLDAPUtils.php b/inc/adLDAP/classes/adLDAPUtils.php
deleted file mode 100644
index f039a4290..000000000
--- a/inc/adLDAP/classes/adLDAPUtils.php
+++ /dev/null
@@ -1,264 +0,0 @@
-adldap = $adldap;
-    }
-    
-    
-    /**
-    * Take an LDAP query and return the nice names, without all the LDAP prefixes (eg. CN, DN)
-    *
-    * @param array $groups
-    * @return array
-    */
-    public function niceNames($groups)
-    {
-
-        $groupArray = array();
-        for ($i=0; $i<$groups["count"]; $i++){ // For each group
-            $line = $groups[$i];
-            
-            if (strlen($line)>0) { 
-                // More presumptions, they're all prefixed with CN=
-                // so we ditch the first three characters and the group
-                // name goes up to the first comma
-                $bits=explode(",", $line);
-                $groupArray[] = substr($bits[0], 3, (strlen($bits[0])-3));
-            }
-        }
-        return $groupArray;    
-    }
-    
-    /**
-    * Escape characters for use in an ldap_create function
-    * 
-    * @param string $str
-    * @return string
-    */
-    public function escapeCharacters($str) {
-        $str = str_replace(",", "\,", $str);
-        return $str;
-    }
-    
-    /**
-    * Escape strings for the use in LDAP filters
-    * 
-    * DEVELOPERS SHOULD BE DOING PROPER FILTERING IF THEY'RE ACCEPTING USER INPUT
-    * Ported from Perl's Net::LDAP::Util escape_filter_value
-    *
-    * @param string $str The string the parse
-    * @author Port by Andreas Gohr 
-    * @return string
-    */
-    public function ldapSlashes($str){
-        return preg_replace('/([\x00-\x1F\*\(\)\\\\])/e',
-                            '"\\\\\".join("",unpack("H2","$1"))',
-                            $str);
-    }
-    
-    /**
-    * Converts a string GUID to a hexdecimal value so it can be queried
-    * 
-    * @param string $strGUID A string representation of a GUID
-    * @return string
-    */
-    public function strGuidToHex($strGUID) 
-    {
-        $strGUID = str_replace('-', '', $strGUID);
-
-        $octet_str = '\\' . substr($strGUID, 6, 2);
-        $octet_str .= '\\' . substr($strGUID, 4, 2);
-        $octet_str .= '\\' . substr($strGUID, 2, 2);
-        $octet_str .= '\\' . substr($strGUID, 0, 2);
-        $octet_str .= '\\' . substr($strGUID, 10, 2);
-        $octet_str .= '\\' . substr($strGUID, 8, 2);
-        $octet_str .= '\\' . substr($strGUID, 14, 2);
-        $octet_str .= '\\' . substr($strGUID, 12, 2);
-        //$octet_str .= '\\' . substr($strGUID, 16, strlen($strGUID));
-        for ($i=16; $i<=(strlen($strGUID)-2); $i++) {
-            if (($i % 2) == 0) {
-                $octet_str .= '\\' . substr($strGUID, $i, 2);
-            }
-        }
-        
-        return $octet_str;
-    }
-    
-    /**
-    * Convert a binary SID to a text SID
-    * 
-    * @param string $binsid A Binary SID
-    * @return string
-    */
-     public function getTextSID($binsid) {
-        $hex_sid = bin2hex($binsid);
-        $rev = hexdec(substr($hex_sid, 0, 2));
-        $subcount = hexdec(substr($hex_sid, 2, 2));
-        $auth = hexdec(substr($hex_sid, 4, 12));
-        $result = "$rev-$auth";
-
-        for ($x=0;$x < $subcount; $x++) {
-            $subauth[$x] =
-                hexdec($this->littleEndian(substr($hex_sid, 16 + ($x * 8), 8)));
-                $result .= "-" . $subauth[$x];
-        }
-
-        // Cheat by tacking on the S-
-        return 'S-' . $result;
-     }
-     
-    /**
-    * Converts a little-endian hex number to one that hexdec() can convert
-    * 
-    * @param string $hex A hex code
-    * @return string
-    */
-     public function littleEndian($hex) 
-     {
-        $result = '';
-        for ($x = strlen($hex) - 2; $x >= 0; $x = $x - 2) {
-            $result .= substr($hex, $x, 2);
-        }
-        return $result;
-     }
-     
-     /**
-    * Converts a binary attribute to a string
-    * 
-    * @param string $bin A binary LDAP attribute
-    * @return string
-    */
-    public function binaryToText($bin) 
-    {
-        $hex_guid = bin2hex($bin); 
-        $hex_guid_to_guid_str = ''; 
-        for($k = 1; $k <= 4; ++$k) { 
-            $hex_guid_to_guid_str .= substr($hex_guid, 8 - 2 * $k, 2); 
-        } 
-        $hex_guid_to_guid_str .= '-'; 
-        for($k = 1; $k <= 2; ++$k) { 
-            $hex_guid_to_guid_str .= substr($hex_guid, 12 - 2 * $k, 2); 
-        } 
-        $hex_guid_to_guid_str .= '-'; 
-        for($k = 1; $k <= 2; ++$k) { 
-            $hex_guid_to_guid_str .= substr($hex_guid, 16 - 2 * $k, 2); 
-        } 
-        $hex_guid_to_guid_str .= '-' . substr($hex_guid, 16, 4); 
-        $hex_guid_to_guid_str .= '-' . substr($hex_guid, 20); 
-        return strtoupper($hex_guid_to_guid_str);   
-    }
-    
-    /**
-    * Converts a binary GUID to a string GUID
-    * 
-    * @param string $binaryGuid The binary GUID attribute to convert
-    * @return string
-    */
-    public function decodeGuid($binaryGuid) 
-    {
-        if ($binaryGuid === null){ return "Missing compulsory field [binaryGuid]"; }
-        
-        $strGUID = $this->binaryToText($binaryGuid);          
-        return $strGUID; 
-    }
-    
-    /**
-    * Convert a boolean value to a string
-    * You should never need to call this yourself
-    *
-    * @param bool $bool Boolean value
-    * @return string
-    */
-    public function boolToStr($bool) 
-    {
-        return ($bool) ? 'TRUE' : 'FALSE';
-    }
-    
-    /**
-    * Convert 8bit characters e.g. accented characters to UTF8 encoded characters
-    */
-    public function encode8Bit(&$item, $key) {
-        $encode = false;
-        if (is_string($item)) {
-            for ($i=0; $i> 7) {
-                    $encode = true;
-                }
-            }
-        }
-        if ($encode === true && $key != 'password') {
-            $item = utf8_encode($item);   
-        }
-    }  
-    
-    /**
-    * Get the current class version number
-    * 
-    * @return string
-    */
-    public function getVersion() {
-        return self::ADLDAP_VERSION;
-    }
-    
-    /**
-    * Round a Windows timestamp down to seconds and remove the seconds between 1601-01-01 and 1970-01-01
-    * 
-    * @param long $windowsTime
-    * @return long $unixTime
-    */
-    public static function convertWindowsTimeToUnixTime($windowsTime) {
-      $unixTime = round($windowsTime / 10000000) - 11644477200; 
-      return $unixTime; 
-    }
-}
-
-?>
\ No newline at end of file
diff --git a/inc/adLDAP/collections/adLDAPCollection.php b/inc/adLDAP/collections/adLDAPCollection.php
deleted file mode 100644
index c0a2eb2fa..000000000
--- a/inc/adLDAP/collections/adLDAPCollection.php
+++ /dev/null
@@ -1,137 +0,0 @@
-setInfo($info);   
-        $this->adldap = $adldap;
-    }
-    
-    /**
-    * Set the raw info array from Active Directory
-    * 
-    * @param array $info
-    */
-    public function setInfo(array $info) 
-    {
-        if ($this->info && sizeof($info) >= 1) {
-            unset($this->info);
-        }
-        $this->info = $info;   
-    }
-    
-    /**
-    * Magic get method to retrieve data from the raw array in a formatted way
-    * 
-    * @param string $attribute
-    * @return mixed
-    */
-    public function __get($attribute)
-    {
-        if (isset($this->info[0]) && is_array($this->info[0])) {
-            foreach ($this->info[0] as $keyAttr => $valueAttr) {
-                if (strtolower($keyAttr) == strtolower($attribute)) {
-                    if ($this->info[0][strtolower($attribute)]['count'] == 1) {
-                        return $this->info[0][strtolower($attribute)][0];   
-                    }
-                    else {
-                        $array = array();
-                        foreach ($this->info[0][strtolower($attribute)] as $key => $value) {
-                            if ((string)$key != 'count') {
-                                $array[$key] = $value;
-                            } 
-                        }  
-                        return $array;   
-                    }
-                }   
-            }
-        }
-        else {
-            return NULL;   
-        }
-    }    
-    
-    /**
-    * Magic set method to update an attribute
-    * 
-    * @param string $attribute
-    * @param string $value
-    * @return bool
-    */
-    abstract public function __set($attribute, $value);
-    
-    /** 
-    * Magic isset method to check for the existence of an attribute 
-    * 
-    * @param string $attribute 
-    * @return bool 
-    */ 
-    public function __isset($attribute) {
-        if (isset($this->info[0]) && is_array($this->info[0])) { 
-            foreach ($this->info[0] as $keyAttr => $valueAttr) { 
-                if (strtolower($keyAttr) == strtolower($attribute)) { 
-                    return true; 
-                } 
-            } 
-        } 
-        return false; 
-     } 
-}
-?>
diff --git a/inc/adLDAP/collections/adLDAPComputerCollection.php b/inc/adLDAP/collections/adLDAPComputerCollection.php
deleted file mode 100644
index 4f11d8f41..000000000
--- a/inc/adLDAP/collections/adLDAPComputerCollection.php
+++ /dev/null
@@ -1,46 +0,0 @@
-
diff --git a/inc/adLDAP/collections/adLDAPContactCollection.php b/inc/adLDAP/collections/adLDAPContactCollection.php
deleted file mode 100644
index d42fe6d4c..000000000
--- a/inc/adLDAP/collections/adLDAPContactCollection.php
+++ /dev/null
@@ -1,46 +0,0 @@
-
diff --git a/inc/adLDAP/collections/adLDAPGroupCollection.php b/inc/adLDAP/collections/adLDAPGroupCollection.php
deleted file mode 100644
index cff12fc20..000000000
--- a/inc/adLDAP/collections/adLDAPGroupCollection.php
+++ /dev/null
@@ -1,46 +0,0 @@
-
diff --git a/inc/adLDAP/collections/adLDAPUserCollection.php b/inc/adLDAP/collections/adLDAPUserCollection.php
deleted file mode 100644
index 801d90296..000000000
--- a/inc/adLDAP/collections/adLDAPUserCollection.php
+++ /dev/null
@@ -1,46 +0,0 @@
-
diff --git a/inc/load.php b/inc/load.php
index fbbf020fd..008613b2a 100644
--- a/inc/load.php
+++ b/inc/load.php
@@ -51,7 +51,6 @@ function load_autoload($name){
         'DokuHTTPClient'        => DOKU_INC.'inc/HTTPClient.php',
         'HTTPClient'            => DOKU_INC.'inc/HTTPClient.php',
         'JSON'                  => DOKU_INC.'inc/JSON.php',
-        'adLDAP'                => DOKU_INC.'inc/adLDAP.php',
         'Diff'                  => DOKU_INC.'inc/DifferenceEngine.php',
         'UnifiedDiffFormatter'  => DOKU_INC.'inc/DifferenceEngine.php',
         'TableDiffFormatter'    => DOKU_INC.'inc/DifferenceEngine.php',
diff --git a/lib/plugins/authad/adLDAP/adLDAP.php b/lib/plugins/authad/adLDAP/adLDAP.php
new file mode 100644
index 000000000..a8f33b47e
--- /dev/null
+++ b/lib/plugins/authad/adLDAP/adLDAP.php
@@ -0,0 +1,951 @@
+ldapConnection) {
+            return $this->ldapConnection;   
+        }
+        return false;
+    }
+    
+    /**
+    * Get the bind status
+    * 
+    * @return bool
+    */
+    public function getLdapBind() {
+        return $this->ldapBind;
+    }
+    
+    /**
+    * Get the current base DN
+    * 
+    * @return string
+    */
+    public function getBaseDn() {
+        return $this->baseDn;   
+    }
+    
+    /**
+    * The group class
+    * 
+    * @var adLDAPGroups
+    */
+    protected $groupClass;
+    
+    /**
+    * Get the group class interface
+    * 
+    * @return adLDAPGroups
+    */
+    public function group() {
+        if (!$this->groupClass) {
+            $this->groupClass = new adLDAPGroups($this);
+        }   
+        return $this->groupClass;
+    }
+    
+    /**
+    * The user class
+    * 
+    * @var adLDAPUsers
+    */
+    protected $userClass;
+    
+    /**
+    * Get the userclass interface
+    * 
+    * @return adLDAPUsers
+    */
+    public function user() {
+        if (!$this->userClass) {
+            $this->userClass = new adLDAPUsers($this);
+        }   
+        return $this->userClass;
+    }
+    
+    /**
+    * The folders class
+    * 
+    * @var adLDAPFolders
+    */
+    protected $folderClass;
+    
+    /**
+    * Get the folder class interface
+    * 
+    * @return adLDAPFolders
+    */
+    public function folder() {
+        if (!$this->folderClass) {
+            $this->folderClass = new adLDAPFolders($this);
+        }   
+        return $this->folderClass;
+    }
+    
+    /**
+    * The utils class
+    * 
+    * @var adLDAPUtils
+    */
+    protected $utilClass;
+    
+    /**
+    * Get the utils class interface
+    * 
+    * @return adLDAPUtils
+    */
+    public function utilities() {
+        if (!$this->utilClass) {
+            $this->utilClass = new adLDAPUtils($this);
+        }   
+        return $this->utilClass;
+    }
+    
+    /**
+    * The contacts class
+    * 
+    * @var adLDAPContacts
+    */
+    protected $contactClass;
+    
+    /**
+    * Get the contacts class interface
+    * 
+    * @return adLDAPContacts
+    */
+    public function contact() {
+        if (!$this->contactClass) {
+            $this->contactClass = new adLDAPContacts($this);
+        }   
+        return $this->contactClass;
+    }
+    
+    /**
+    * The exchange class
+    * 
+    * @var adLDAPExchange
+    */
+    protected $exchangeClass;
+    
+    /**
+    * Get the exchange class interface
+    * 
+    * @return adLDAPExchange
+    */
+    public function exchange() {
+        if (!$this->exchangeClass) {
+            $this->exchangeClass = new adLDAPExchange($this);
+        }   
+        return $this->exchangeClass;
+    }
+    
+    /**
+    * The computers class
+    * 
+    * @var adLDAPComputers
+    */
+    protected $computersClass;
+    
+    /**
+    * Get the computers class interface
+    * 
+    * @return adLDAPComputers
+    */
+    public function computer() {
+        if (!$this->computerClass) {
+            $this->computerClass = new adLDAPComputers($this);
+        }   
+        return $this->computerClass;
+    }
+
+    /**
+    * Getters and Setters
+    */
+    
+    /**
+    * Set the account suffix
+    * 
+    * @param string $accountSuffix
+    * @return void
+    */
+    public function setAccountSuffix($accountSuffix)
+    {
+          $this->accountSuffix = $accountSuffix;
+    }
+
+    /**
+    * Get the account suffix
+    * 
+    * @return string
+    */
+    public function getAccountSuffix()
+    {
+          return $this->accountSuffix;
+    }
+    
+    /**
+    * Set the domain controllers array
+    * 
+    * @param array $domainControllers
+    * @return void
+    */
+    public function setDomainControllers(array $domainControllers)
+    {
+          $this->domainControllers = $domainControllers;
+    }
+
+    /**
+    * Get the list of domain controllers
+    * 
+    * @return void
+    */
+    public function getDomainControllers()
+    {
+          return $this->domainControllers;
+    }
+    
+    /**
+    * Sets the port number your domain controller communicates over
+    * 
+    * @param int $adPort
+    */
+    public function setPort($adPort) 
+    { 
+        $this->adPort = $adPort; 
+    } 
+    
+    /**
+    * Gets the port number your domain controller communicates over
+    * 
+    * @return int
+    */
+    public function getPort() 
+    { 
+        return $this->adPort; 
+    } 
+    
+    /**
+    * Set the username of an account with higher priviledges
+    * 
+    * @param string $adminUsername
+    * @return void
+    */
+    public function setAdminUsername($adminUsername)
+    {
+          $this->adminUsername = $adminUsername;
+    }
+
+    /**
+    * Get the username of the account with higher priviledges
+    * 
+    * This will throw an exception for security reasons
+    */
+    public function getAdminUsername()
+    {
+          throw new adLDAPException('For security reasons you cannot access the domain administrator account details');
+    }
+    
+    /**
+    * Set the password of an account with higher priviledges
+    * 
+    * @param string $adminPassword
+    * @return void
+    */
+    public function setAdminPassword($adminPassword)
+    {
+          $this->adminPassword = $adminPassword;
+    }
+
+    /**
+    * Get the password of the account with higher priviledges
+    * 
+    * This will throw an exception for security reasons
+    */
+    public function getAdminPassword()
+    {
+          throw new adLDAPException('For security reasons you cannot access the domain administrator account details');
+    }
+    
+    /**
+    * Set whether to detect the true primary group
+    * 
+    * @param bool $realPrimaryGroup
+    * @return void
+    */
+    public function setRealPrimaryGroup($realPrimaryGroup)
+    {
+          $this->realPrimaryGroup = $realPrimaryGroup;
+    }
+
+    /**
+    * Get the real primary group setting
+    * 
+    * @return bool
+    */
+    public function getRealPrimaryGroup()
+    {
+          return $this->realPrimaryGroup;
+    }
+    
+    /**
+    * Set whether to use SSL
+    * 
+    * @param bool $useSSL
+    * @return void
+    */
+    public function setUseSSL($useSSL)
+    {
+          $this->useSSL = $useSSL;
+          // Set the default port correctly 
+          if($this->useSSL) { 
+            $this->setPort(self::ADLDAP_LDAPS_PORT); 
+          }
+          else { 
+            $this->setPort(self::ADLDAP_LDAP_PORT); 
+          } 
+    }
+
+    /**
+    * Get the SSL setting
+    * 
+    * @return bool
+    */
+    public function getUseSSL()
+    {
+          return $this->useSSL;
+    }
+    
+    /**
+    * Set whether to use TLS
+    * 
+    * @param bool $useTLS
+    * @return void
+    */
+    public function setUseTLS($useTLS)
+    {
+          $this->useTLS = $useTLS;
+    }
+
+    /**
+    * Get the TLS setting
+    * 
+    * @return bool
+    */
+    public function getUseTLS()
+    {
+          return $this->useTLS;
+    }
+    
+    /**
+    * Set whether to use SSO
+    * Requires ldap_sasl_bind support. Be sure --with-ldap-sasl is used when configuring PHP otherwise this function will be undefined. 
+    * 
+    * @param bool $useSSO
+    * @return void
+    */
+    public function setUseSSO($useSSO)
+    {
+          if ($useSSO === true && !$this->ldapSaslSupported()) {
+              throw new adLDAPException('No LDAP SASL support for PHP.  See: http://www.php.net/ldap_sasl_bind');
+          }
+          $this->useSSO = $useSSO;
+    }
+
+    /**
+    * Get the SSO setting
+    * 
+    * @return bool
+    */
+    public function getUseSSO()
+    {
+          return $this->useSSO;
+    }
+    
+    /**
+    * Set whether to lookup recursive groups
+    * 
+    * @param bool $recursiveGroups
+    * @return void
+    */
+    public function setRecursiveGroups($recursiveGroups)
+    {
+          $this->recursiveGroups = $recursiveGroups;
+    }
+
+    /**
+    * Get the recursive groups setting
+    * 
+    * @return bool
+    */
+    public function getRecursiveGroups()
+    {
+          return $this->recursiveGroups;
+    }
+
+    /**
+    * Default Constructor
+    * 
+    * Tries to bind to the AD domain over LDAP or LDAPs
+    * 
+    * @param array $options Array of options to pass to the constructor
+    * @throws Exception - if unable to bind to Domain Controller
+    * @return bool
+    */
+    function __construct($options = array()) {
+        // You can specifically overide any of the default configuration options setup above
+        if (count($options) > 0) {
+            if (array_key_exists("account_suffix",$options)){ $this->accountSuffix = $options["account_suffix"]; }
+            if (array_key_exists("base_dn",$options)){ $this->baseDn = $options["base_dn"]; }
+            if (array_key_exists("domain_controllers",$options)){ 
+                if (!is_array($options["domain_controllers"])) { 
+                    throw new adLDAPException('[domain_controllers] option must be an array');
+                }
+                $this->domainControllers = $options["domain_controllers"]; 
+            }
+            if (array_key_exists("admin_username",$options)){ $this->adminUsername = $options["admin_username"]; }
+            if (array_key_exists("admin_password",$options)){ $this->adminPassword = $options["admin_password"]; }
+            if (array_key_exists("real_primarygroup",$options)){ $this->realPrimaryGroup = $options["real_primarygroup"]; }
+            if (array_key_exists("use_ssl",$options)){ $this->setUseSSL($options["use_ssl"]); }
+            if (array_key_exists("use_tls",$options)){ $this->useTLS = $options["use_tls"]; }
+            if (array_key_exists("recursive_groups",$options)){ $this->recursiveGroups = $options["recursive_groups"]; }
+            if (array_key_exists("ad_port",$options)){ $this->setPort($options["ad_port"]); } 
+            if (array_key_exists("sso",$options)) { 
+                $this->setUseSSO($options["sso"]);
+                if (!$this->ldapSaslSupported()) {
+                    $this->setUseSSO(false);
+                }
+            } 
+        }
+        
+        if ($this->ldapSupported() === false) {
+            throw new adLDAPException('No LDAP support for PHP.  See: http://www.php.net/ldap');
+        }
+
+        return $this->connect();
+    }
+
+    /**
+    * Default Destructor
+    * 
+    * Closes the LDAP connection
+    * 
+    * @return void
+    */
+    function __destruct() { 
+        $this->close(); 
+    }
+
+    /**
+    * Connects and Binds to the Domain Controller
+    * 
+    * @return bool
+    */
+    public function connect() 
+    {
+        // Connect to the AD/LDAP server as the username/password
+        $domainController = $this->randomController();
+        if ($this->useSSL) {
+            $this->ldapConnection = ldap_connect("ldaps://" . $domainController, $this->adPort);
+        } else {
+            $this->ldapConnection = ldap_connect($domainController, $this->adPort);
+        }
+               
+        // Set some ldap options for talking to AD
+        ldap_set_option($this->ldapConnection, LDAP_OPT_PROTOCOL_VERSION, 3);
+        ldap_set_option($this->ldapConnection, LDAP_OPT_REFERRALS, 0);
+        
+        if ($this->useTLS) {
+            ldap_start_tls($this->ldapConnection);
+        }
+               
+        // Bind as a domain admin if they've set it up
+        if ($this->adminUsername !== NULL && $this->adminPassword !== NULL) {
+            $this->ldapBind = @ldap_bind($this->ldapConnection, $this->adminUsername . $this->accountSuffix, $this->adminPassword);
+            if (!$this->ldapBind) {
+                if ($this->useSSL && !$this->useTLS) {
+                    // If you have problems troubleshooting, remove the @ character from the ldapldapBind command above to get the actual error message
+                    throw new adLDAPException('Bind to Active Directory failed. Either the LDAPs connection failed or the login credentials are incorrect. AD said: ' . $this->getLastError());
+                }
+                else {
+                    throw new adLDAPException('Bind to Active Directory failed. Check the login credentials and/or server details. AD said: ' . $this->getLastError());
+                }
+            }
+        }
+        if ($this->useSSO && $_SERVER['REMOTE_USER'] && $this->adminUsername === null && $_SERVER['KRB5CCNAME']) {
+            putenv("KRB5CCNAME=" . $_SERVER['KRB5CCNAME']);  
+            $this->ldapBind = @ldap_sasl_bind($this->ldapConnection, NULL, NULL, "GSSAPI"); 
+            if (!$this->ldapBind){ 
+                throw new adLDAPException('Rebind to Active Directory failed. AD said: ' . $this->getLastError()); 
+            }
+            else {
+                return true;
+            }
+        }
+                
+        
+        if ($this->baseDn == NULL) {
+            $this->baseDn = $this->findBaseDn();   
+        }
+        
+        return true;
+    }
+    
+    /**
+    * Closes the LDAP connection
+    * 
+    * @return void
+    */
+    public function close() {
+        if ($this->ldapConnection) {
+            @ldap_close($this->ldapConnection);
+        }
+    }
+    
+    /**
+    * Validate a user's login credentials
+    * 
+    * @param string $username A user's AD username
+    * @param string $password A user's AD password
+    * @param bool optional $preventRebind
+    * @return bool
+    */
+    public function authenticate($username, $password, $preventRebind = false) {
+        // Prevent null binding
+        if ($username === NULL || $password === NULL) { return false; } 
+        if (empty($username) || empty($password)) { return false; }
+        
+        // Allow binding over SSO for Kerberos
+        if ($this->useSSO && $_SERVER['REMOTE_USER'] && $_SERVER['REMOTE_USER'] == $username && $this->adminUsername === NULL && $_SERVER['KRB5CCNAME']) { 
+            putenv("KRB5CCNAME=" . $_SERVER['KRB5CCNAME']);
+            $this->ldapBind = @ldap_sasl_bind($this->ldapConnection, NULL, NULL, "GSSAPI");
+            if (!$this->ldapBind) {
+                throw new adLDAPException('Rebind to Active Directory failed. AD said: ' . $this->getLastError());
+            }
+            else {
+                return true;
+            }
+        }
+        
+        // Bind as the user        
+        $ret = true;
+        $this->ldapBind = @ldap_bind($this->ldapConnection, $username . $this->accountSuffix, $password);
+        if (!$this->ldapBind){ 
+            $ret = false; 
+        }
+        
+        // Cnce we've checked their details, kick back into admin mode if we have it
+        if ($this->adminUsername !== NULL && !$preventRebind) {
+            $this->ldapBind = @ldap_bind($this->ldapConnection, $this->adminUsername . $this->accountSuffix , $this->adminPassword);
+            if (!$this->ldapBind){
+                // This should never happen in theory
+                throw new adLDAPException('Rebind to Active Directory failed. AD said: ' . $this->getLastError());
+            } 
+        } 
+        
+        return $ret;
+    }
+    
+    /**
+    * Find the Base DN of your domain controller
+    * 
+    * @return string
+    */
+    public function findBaseDn() 
+    {
+        $namingContext = $this->getRootDse(array('defaultnamingcontext'));   
+        return $namingContext[0]['defaultnamingcontext'][0];
+    }
+    
+    /**
+    * Get the RootDSE properties from a domain controller
+    * 
+    * @param array $attributes The attributes you wish to query e.g. defaultnamingcontext
+    * @return array
+    */
+    public function getRootDse($attributes = array("*", "+")) {
+        if (!$this->ldapBind){ return (false); }
+        
+        $sr = @ldap_read($this->ldapConnection, NULL, 'objectClass=*', $attributes);
+        $entries = @ldap_get_entries($this->ldapConnection, $sr);
+        return $entries;
+    }
+
+    /**
+    * Get last error from Active Directory
+    * 
+    * This function gets the last message from Active Directory
+    * This may indeed be a 'Success' message but if you get an unknown error
+    * it might be worth calling this function to see what errors were raised
+    * 
+    * return string
+    */
+    public function getLastError() {
+        return @ldap_error($this->ldapConnection);
+    }
+    
+    /**
+    * Detect LDAP support in php
+    * 
+    * @return bool
+    */    
+    protected function ldapSupported()
+    {
+        if (!function_exists('ldap_connect')) {
+            return false;   
+        }
+        return true;
+    }
+    
+    /**
+    * Detect ldap_sasl_bind support in PHP
+    * 
+    * @return bool
+    */
+    protected function ldapSaslSupported()
+    {
+        if (!function_exists('ldap_sasl_bind')) {
+            return false;
+        }
+        return true;
+    }
+    
+    /**
+    * Schema
+    * 
+    * @param array $attributes Attributes to be queried
+    * @return array
+    */    
+    public function adldap_schema($attributes){
+    
+        // LDAP doesn't like NULL attributes, only set them if they have values
+        // If you wish to remove an attribute you should set it to a space
+        // TO DO: Adapt user_modify to use ldap_mod_delete to remove a NULL attribute
+        $mod=array();
+        
+        // Check every attribute to see if it contains 8bit characters and then UTF8 encode them
+        array_walk($attributes, array($this, 'encode8bit'));
+
+        if ($attributes["address_city"]){ $mod["l"][0]=$attributes["address_city"]; }
+        if ($attributes["address_code"]){ $mod["postalCode"][0]=$attributes["address_code"]; }
+        //if ($attributes["address_country"]){ $mod["countryCode"][0]=$attributes["address_country"]; } // use country codes?
+        if ($attributes["address_country"]){ $mod["c"][0]=$attributes["address_country"]; }
+        if ($attributes["address_pobox"]){ $mod["postOfficeBox"][0]=$attributes["address_pobox"]; }
+        if ($attributes["address_state"]){ $mod["st"][0]=$attributes["address_state"]; }
+        if ($attributes["address_street"]){ $mod["streetAddress"][0]=$attributes["address_street"]; }
+        if ($attributes["company"]){ $mod["company"][0]=$attributes["company"]; }
+        if ($attributes["change_password"]){ $mod["pwdLastSet"][0]=0; }
+        if ($attributes["department"]){ $mod["department"][0]=$attributes["department"]; }
+        if ($attributes["description"]){ $mod["description"][0]=$attributes["description"]; }
+        if ($attributes["display_name"]){ $mod["displayName"][0]=$attributes["display_name"]; }
+        if ($attributes["email"]){ $mod["mail"][0]=$attributes["email"]; }
+        if ($attributes["expires"]){ $mod["accountExpires"][0]=$attributes["expires"]; } //unix epoch format?
+        if ($attributes["firstname"]){ $mod["givenName"][0]=$attributes["firstname"]; }
+        if ($attributes["home_directory"]){ $mod["homeDirectory"][0]=$attributes["home_directory"]; }
+        if ($attributes["home_drive"]){ $mod["homeDrive"][0]=$attributes["home_drive"]; }
+        if ($attributes["initials"]){ $mod["initials"][0]=$attributes["initials"]; }
+        if ($attributes["logon_name"]){ $mod["userPrincipalName"][0]=$attributes["logon_name"]; }
+        if ($attributes["manager"]){ $mod["manager"][0]=$attributes["manager"]; }  //UNTESTED ***Use DistinguishedName***
+        if ($attributes["office"]){ $mod["physicalDeliveryOfficeName"][0]=$attributes["office"]; }
+        if ($attributes["password"]){ $mod["unicodePwd"][0]=$this->user()->encodePassword($attributes["password"]); }
+        if ($attributes["profile_path"]){ $mod["profilepath"][0]=$attributes["profile_path"]; }
+        if ($attributes["script_path"]){ $mod["scriptPath"][0]=$attributes["script_path"]; }
+        if ($attributes["surname"]){ $mod["sn"][0]=$attributes["surname"]; }
+        if ($attributes["title"]){ $mod["title"][0]=$attributes["title"]; }
+        if ($attributes["telephone"]){ $mod["telephoneNumber"][0]=$attributes["telephone"]; }
+        if ($attributes["mobile"]){ $mod["mobile"][0]=$attributes["mobile"]; }
+        if ($attributes["pager"]){ $mod["pager"][0]=$attributes["pager"]; }
+        if ($attributes["ipphone"]){ $mod["ipphone"][0]=$attributes["ipphone"]; }
+        if ($attributes["web_page"]){ $mod["wWWHomePage"][0]=$attributes["web_page"]; }
+        if ($attributes["fax"]){ $mod["facsimileTelephoneNumber"][0]=$attributes["fax"]; }
+        if ($attributes["enabled"]){ $mod["userAccountControl"][0]=$attributes["enabled"]; }
+        if ($attributes["homephone"]){ $mod["homephone"][0]=$attributes["homephone"]; }
+        
+        // Distribution List specific schema
+        if ($attributes["group_sendpermission"]){ $mod["dlMemSubmitPerms"][0]=$attributes["group_sendpermission"]; }
+        if ($attributes["group_rejectpermission"]){ $mod["dlMemRejectPerms"][0]=$attributes["group_rejectpermission"]; }
+        
+        // Exchange Schema
+        if ($attributes["exchange_homemdb"]){ $mod["homeMDB"][0]=$attributes["exchange_homemdb"]; }
+        if ($attributes["exchange_mailnickname"]){ $mod["mailNickname"][0]=$attributes["exchange_mailnickname"]; }
+        if ($attributes["exchange_proxyaddress"]){ $mod["proxyAddresses"][0]=$attributes["exchange_proxyaddress"]; }
+        if ($attributes["exchange_usedefaults"]){ $mod["mDBUseDefaults"][0]=$attributes["exchange_usedefaults"]; }
+        if ($attributes["exchange_policyexclude"]){ $mod["msExchPoliciesExcluded"][0]=$attributes["exchange_policyexclude"]; }
+        if ($attributes["exchange_policyinclude"]){ $mod["msExchPoliciesIncluded"][0]=$attributes["exchange_policyinclude"]; }       
+        if ($attributes["exchange_addressbook"]){ $mod["showInAddressBook"][0]=$attributes["exchange_addressbook"]; }    
+        if ($attributes["exchange_altrecipient"]){ $mod["altRecipient"][0]=$attributes["exchange_altrecipient"]; } 
+        if ($attributes["exchange_deliverandredirect"]){ $mod["deliverAndRedirect"][0]=$attributes["exchange_deliverandredirect"]; }    
+        
+        // This schema is designed for contacts
+        if ($attributes["exchange_hidefromlists"]){ $mod["msExchHideFromAddressLists"][0]=$attributes["exchange_hidefromlists"]; }
+        if ($attributes["contact_email"]){ $mod["targetAddress"][0]=$attributes["contact_email"]; }
+        
+        //echo ("
"); print_r($mod);
+        /*
+        // modifying a name is a bit fiddly
+        if ($attributes["firstname"] && $attributes["surname"]){
+            $mod["cn"][0]=$attributes["firstname"]." ".$attributes["surname"];
+            $mod["displayname"][0]=$attributes["firstname"]." ".$attributes["surname"];
+            $mod["name"][0]=$attributes["firstname"]." ".$attributes["surname"];
+        }
+        */
+
+        if (count($mod)==0){ return (false); }
+        return ($mod);
+    }
+    
+    /**
+    * Convert 8bit characters e.g. accented characters to UTF8 encoded characters
+    */
+    protected function encode8Bit(&$item, $key) {
+        $encode = false;
+        if (is_string($item)) {
+            for ($i=0; $i> 7) {
+                    $encode = true;
+                }
+            }
+        }
+        if ($encode === true && $key != 'password') {
+            $item = utf8_encode($item);   
+        }
+    }
+    
+    /**
+    * Select a random domain controller from your domain controller array
+    * 
+    * @return string
+    */
+    protected function randomController() 
+    {
+        mt_srand(doubleval(microtime()) * 100000000); // For older PHP versions
+        /*if (sizeof($this->domainControllers) > 1) {
+            $adController = $this->domainControllers[array_rand($this->domainControllers)]; 
+            // Test if the controller is responding to pings
+            $ping = $this->pingController($adController); 
+            if ($ping === false) { 
+                // Find the current key in the domain controllers array
+                $key = array_search($adController, $this->domainControllers);
+                // Remove it so that we don't end up in a recursive loop
+                unset($this->domainControllers[$key]);
+                // Select a new controller
+                return $this->randomController(); 
+            }
+            else { 
+                return ($adController); 
+            }
+        } */
+        return $this->domainControllers[array_rand($this->domainControllers)];
+    }  
+    
+    /** 
+    * Test basic connectivity to controller 
+    * 
+    * @return bool
+    */ 
+    protected function pingController($host) {
+        $port = $this->adPort; 
+        fsockopen($host, $port, $errno, $errstr, 10); 
+        if ($errno > 0) {
+            return false;
+        }
+        return true;
+    }
+
+}
+
+/**
+* adLDAP Exception Handler
+* 
+* Exceptions of this type are thrown on bind failure or when SSL is required but not configured
+* Example:
+* try {
+*   $adldap = new adLDAP();
+* }
+* catch (adLDAPException $e) {
+*   echo $e;
+*   exit();
+* }
+*/
+class adLDAPException extends Exception {}
+
+?>
\ No newline at end of file
diff --git a/lib/plugins/authad/adLDAP/classes/adLDAPComputers.php b/lib/plugins/authad/adLDAP/classes/adLDAPComputers.php
new file mode 100644
index 000000000..71b24a04f
--- /dev/null
+++ b/lib/plugins/authad/adLDAP/classes/adLDAPComputers.php
@@ -0,0 +1,153 @@
+adldap = $adldap;
+    }
+    
+    /**
+    * Get information about a specific computer. Returned in a raw array format from AD
+    * 
+    * @param string $computerName The name of the computer
+    * @param array $fields Attributes to return
+    * @return array
+    */
+    public function info($computerName, $fields = NULL)
+    {
+        if ($computerName === NULL) { return false; }
+        if (!$this->adldap->getLdapBind()) { return false; }
+
+        $filter = "(&(objectClass=computer)(cn=" . $computerName . "))";
+        if ($fields === NULL) { 
+            $fields = array("memberof","cn","displayname","dnshostname","distinguishedname","objectcategory","operatingsystem","operatingsystemservicepack","operatingsystemversion"); 
+        }
+        $sr = ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields);
+        $entries = ldap_get_entries($this->adldap->getLdapConnection(), $sr);
+        
+        return $entries;
+    }
+    
+    /**
+    * Find information about the computers. Returned in a raw array format from AD
+    * 
+    * @param string $computerName The name of the computer
+    * @param array $fields Array of parameters to query
+    * @return mixed
+    */
+    public function infoCollection($computerName, $fields = NULL)
+    {
+        if ($computerName === NULL) { return false; }
+        if (!$this->adldap->getLdapBind()) { return false; }
+        
+        $info = $this->info($computerName, $fields);
+        
+        if ($info !== false) {
+            $collection = new adLDAPComputerCollection($info, $this->adldap);
+            return $collection;
+        }
+        return false;
+    }
+    
+    /**
+    * Check if a computer is in a group
+    * 
+    * @param string $computerName The name of the computer
+    * @param string $group The group to check
+    * @param bool $recursive Whether to check recursively
+    * @return array
+    */
+    public function inGroup($computerName, $group, $recursive = NULL)
+    {
+        if ($computerName === NULL) { return false; }
+        if ($group === NULL) { return false; }
+        if (!$this->adldap->getLdapBind()) { return false; }
+        if ($recursive === NULL) { $recursive = $this->adldap->getRecursiveGroups(); } // use the default option if they haven't set it
+
+        //get a list of the groups
+        $groups = $this->groups($computerName, array("memberof"), $recursive);
+
+        //return true if the specified group is in the group list
+        if (in_array($group, $groups)){ 
+            return true; 
+        }
+
+        return false;
+    }
+    
+    /**
+    * Get the groups a computer is in
+    * 
+    * @param string $computerName The name of the computer
+    * @param bool $recursive Whether to check recursively
+    * @return array
+    */
+    public function groups($computerName, $recursive = NULL)
+    {
+        if ($computerName === NULL) { return false; }
+        if ($recursive === NULL) { $recursive = $this->adldap->getRecursiveGroups(); } //use the default option if they haven't set it
+        if (!$this->adldap->getLdapBind()){ return false; }
+
+        //search the directory for their information
+        $info = @$this->info($computerName, array("memberof", "primarygroupid"));
+        $groups = $this->adldap->utilities()->niceNames($info[0]["memberof"]); //presuming the entry returned is our guy (unique usernames)
+
+        if ($recursive === true) {
+            foreach ($groups as $id => $groupName){
+              $extraGroups = $this->adldap->group()->recursiveGroups($groupName);
+              $groups = array_merge($groups, $extraGroups);
+            }
+        }
+
+        return $groups;
+    }
+    
+}
+?>
\ No newline at end of file
diff --git a/lib/plugins/authad/adLDAP/classes/adLDAPContacts.php b/lib/plugins/authad/adLDAP/classes/adLDAPContacts.php
new file mode 100644
index 000000000..addd3e5f0
--- /dev/null
+++ b/lib/plugins/authad/adLDAP/classes/adLDAPContacts.php
@@ -0,0 +1,294 @@
+adldap = $adldap;
+    }
+    
+    //*****************************************************************************************************************
+    // CONTACT FUNCTIONS
+    // * Still work to do in this area, and new functions to write
+    
+    /**
+    * Create a contact
+    * 
+    * @param array $attributes The attributes to set to the contact
+    * @return bool
+    */
+    public function create($attributes)
+    {
+        // Check for compulsory fields
+        if (!array_key_exists("display_name", $attributes)) { return "Missing compulsory field [display_name]"; }
+        if (!array_key_exists("email", $attributes)) { return "Missing compulsory field [email]"; }
+        if (!array_key_exists("container", $attributes)) { return "Missing compulsory field [container]"; }
+        if (!is_array($attributes["container"])) { return "Container attribute must be an array."; }
+
+        // Translate the schema
+        $add = $this->adldap->adldap_schema($attributes);
+        
+        // Additional stuff only used for adding contacts
+        $add["cn"][0] = $attributes["display_name"];
+        $add["objectclass"][0] = "top";
+        $add["objectclass"][1] = "person";
+        $add["objectclass"][2] = "organizationalPerson";
+        $add["objectclass"][3] = "contact"; 
+        if (!isset($attributes['exchange_hidefromlists'])) {
+            $add["msExchHideFromAddressLists"][0] = "TRUE";
+        }
+
+        // Determine the container
+        $attributes["container"] = array_reverse($attributes["container"]);
+        $container= "OU=" . implode(",OU=", $attributes["container"]);
+
+        // Add the entry
+        $result = @ldap_add($this->adldap->getLdapConnection(), "CN=" . $this->adldap->utilities()->escapeCharacters($add["cn"][0]) . ", " . $container . "," . $this->adldap->getBaseDn(), $add);
+        if ($result != true) { 
+            return false; 
+        }
+        
+        return true;
+    }  
+    
+    /**
+    * Determine the list of groups a contact is a member of
+    * 
+    * @param string $distinguisedname The full DN of a contact
+    * @param bool $recursive Recursively check groups
+    * @return array
+    */
+    public function groups($distinguishedName, $recursive = NULL)
+    {
+        if ($distinguishedName === NULL) { return false; }
+        if ($recursive === NULL) { $recursive = $this->adldap->getRecursiveGroups(); } //use the default option if they haven't set it
+        if (!$this->adldap->getLdapBind()){ return false; }
+        
+        // Search the directory for their information
+        $info = @$this->info($distinguishedName, array("memberof", "primarygroupid"));
+        $groups = $this->adldap->utilities()->niceNames($info[0]["memberof"]); //presuming the entry returned is our contact
+
+        if ($recursive === true){
+            foreach ($groups as $id => $groupName){
+                $extraGroups = $this->adldap->group()->recursiveGroups($groupName);
+                $groups = array_merge($groups, $extraGroups);
+            }
+        }
+        
+        return $groups;
+    }
+    
+    /**
+    * Get contact information. Returned in a raw array format from AD
+    * 
+    * @param string $distinguisedname The full DN of a contact
+    * @param array $fields Attributes to be returned
+    * @return array
+    */
+    public function info($distinguishedName, $fields = NULL)
+    {
+        if ($distinguishedName === NULL) { return false; }
+        if (!$this->adldap->getLdapBind()) { return false; }
+
+        $filter = "distinguishedName=" . $distinguishedName;
+        if ($fields === NULL) { 
+            $fields = array("distinguishedname", "mail", "memberof", "department", "displayname", "telephonenumber", "primarygroupid", "objectsid"); 
+        }
+        $sr = ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields);
+        $entries = ldap_get_entries($this->adldap->getLdapConnection(), $sr);
+        
+        if ($entries[0]['count'] >= 1) {
+            // AD does not return the primary group in the ldap query, we may need to fudge it
+            if ($this->adldap->getRealPrimaryGroup() && isset($entries[0]["primarygroupid"][0]) && isset($entries[0]["primarygroupid"][0])){
+                //$entries[0]["memberof"][]=$this->group_cn($entries[0]["primarygroupid"][0]);
+                $entries[0]["memberof"][] = $this->adldap->group()->getPrimaryGroup($entries[0]["primarygroupid"][0], $entries[0]["objectsid"][0]);
+            } else {
+                $entries[0]["memberof"][] = "CN=Domain Users,CN=Users," . $this->adldap->getBaseDn();
+            }
+        }
+        
+        $entries[0]["memberof"]["count"]++;
+        return $entries;
+    }
+    
+    /**
+    * Find information about the contacts. Returned in a raw array format from AD
+    * 
+    * @param string $distinguishedName The full DN of a contact 
+    * @param array $fields Array of parameters to query
+    * @return mixed
+    */
+    public function infoCollection($distinguishedName, $fields = NULL)
+    {
+        if ($distinguishedName === NULL) { return false; }
+        if (!$this->adldap->getLdapBind()) { return false; }
+        
+        $info = $this->info($distinguishedName, $fields);
+        
+        if ($info !== false) {
+            $collection = new adLDAPContactCollection($info, $this->adldap);
+            return $collection;
+        }
+        return false;
+    }
+    
+    /**
+    * Determine if a contact is a member of a group
+    * 
+    * @param string $distinguisedName The full DN of a contact
+    * @param string $group The group name to query
+    * @param bool $recursive Recursively check groups
+    * @return bool
+    */
+    public function inGroup($distinguisedName, $group, $recursive = NULL)
+    {
+        if ($distinguisedName === NULL) { return false; }
+        if ($group === NULL) { return false; }
+        if (!$this->adldap->getLdapBind()) { return false; }
+        if ($recursive === NULL) { $recursive = $this->adldap->getRecursiveGroups(); } //use the default option if they haven't set it
+        
+        // Get a list of the groups
+        $groups = $this->groups($distinguisedName, array("memberof"), $recursive);
+        
+        // Return true if the specified group is in the group list
+        if (in_array($group, $groups)){ 
+            return true; 
+        }
+
+        return false;
+    }          
+    
+    /**
+    * Modify a contact
+    * 
+    * @param string $distinguishedName The contact to query
+    * @param array $attributes The attributes to modify.  Note if you set the enabled attribute you must not specify any other attributes
+    * @return bool
+    */
+    public function modify($distinguishedName, $attributes) {
+        if ($distinguishedName === NULL) { return "Missing compulsory field [distinguishedname]"; }
+        
+        // Translate the update to the LDAP schema                
+        $mod = $this->adldap->adldap_schema($attributes);
+        
+        // Check to see if this is an enabled status update
+        if (!$mod) { 
+            return false; 
+        }
+        
+        // Do the update
+        $result = ldap_modify($this->adldap->getLdapConnection(), $distinguishedName, $mod);
+        if ($result == false) { 
+            return false; 
+        }
+        
+        return true;
+    }
+    
+    /**
+    * Delete a contact
+    * 
+    * @param string $distinguishedName The contact dn to delete (please be careful here!)
+    * @return array
+    */
+    public function delete($distinguishedName) 
+    {
+        $result = $this->folder()->delete($distinguishedName);
+        if ($result != true) { 
+            return false; 
+        }       
+        return true;
+    }
+    
+    /**
+    * Return a list of all contacts
+    * 
+    * @param bool $includeDescription Include a description of a contact
+    * @param string $search The search parameters
+    * @param bool $sorted Whether to sort the results
+    * @return array
+    */
+    public function all($includeDescription = false, $search = "*", $sorted = true) {
+        if (!$this->adldap->getLdapBind()) { return false; }
+        
+        // Perform the search and grab all their details
+        $filter = "(&(objectClass=contact)(cn=" . $search . "))";
+        $fields = array("displayname","distinguishedname");           
+        $sr = ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields);
+        $entries = ldap_get_entries($this->adldap->getLdapConnection(), $sr);
+
+        $usersArray = array();
+        for ($i=0; $i<$entries["count"]; $i++){
+            if ($includeDescription && strlen($entries[$i]["displayname"][0])>0){
+                $usersArray[$entries[$i]["distinguishedname"][0]] = $entries[$i]["displayname"][0];
+            } elseif ($includeDescription){
+                $usersArray[$entries[$i]["distinguishedname"][0]] = $entries[$i]["distinguishedname"][0];
+            } else {
+                array_push($usersArray, $entries[$i]["distinguishedname"][0]);
+            }
+        }
+        if ($sorted) { 
+            asort($usersArray); 
+        }
+        return $usersArray;
+    }
+    
+    /**
+    * Mail enable a contact
+    * Allows email to be sent to them through Exchange
+    * 
+    * @param string $distinguishedname The contact to mail enable
+    * @param string $emailaddress The email address to allow emails to be sent through
+    * @param string $mailnickname The mailnickname for the contact in Exchange.  If NULL this will be set to the display name
+    * @return bool
+    */
+    public function contactMailEnable($distinguishedName, $emailAddress, $mailNickname = NULL){
+        return $this->adldap->exchange()->contactMailEnable($distinguishedName, $emailAddress, $mailNickname);
+    }
+    
+    
+}
+?>
diff --git a/lib/plugins/authad/adLDAP/classes/adLDAPExchange.php b/lib/plugins/authad/adLDAP/classes/adLDAPExchange.php
new file mode 100644
index 000000000..dd0c6de05
--- /dev/null
+++ b/lib/plugins/authad/adLDAP/classes/adLDAPExchange.php
@@ -0,0 +1,390 @@
+adldap = $adldap;
+    }
+    
+    /**
+    * Create an Exchange account
+    * 
+    * @param string $username The username of the user to add the Exchange account to
+    * @param array $storageGroup The mailbox, Exchange Storage Group, for the user account, this must be a full CN
+    *                            If the storage group has a different base_dn to the adLDAP configuration, set it using $base_dn
+    * @param string $emailAddress The primary email address to add to this user
+    * @param string $mailNickname The mail nick name.  If mail nickname is blank, the username will be used
+    * @param bool $mdbUseDefaults Indicates whether the store should use the default quota, rather than the per-mailbox quota.
+    * @param string $baseDn Specify an alternative base_dn for the Exchange storage group
+    * @param bool $isGUID Is the username passed a GUID or a samAccountName
+    * @return bool
+    */
+    public function createMailbox($username, $storageGroup, $emailAddress, $mailNickname=NULL, $useDefaults=TRUE, $baseDn=NULL, $isGUID=false)
+    {
+        if ($username === NULL){ return "Missing compulsory field [username]"; }     
+        if ($storageGroup === NULL) { return "Missing compulsory array [storagegroup]"; }
+        if (!is_array($storageGroup)) { return "[storagegroup] must be an array"; }
+        if ($emailAddress === NULL) { return "Missing compulsory field [emailAddress]"; }
+        
+        if ($baseDn === NULL) {
+            $baseDn = $this->adldap->getBaseDn();   
+        }
+        
+        $container = "CN=" . implode(",CN=", $storageGroup);
+        
+        if ($mailNickname === NULL) { 
+            $mailNickname = $username; 
+        }
+        $mdbUseDefaults = $this->adldap->utilities()->boolToString($useDefaults);
+        
+        $attributes = array(
+            'exchange_homemdb'=>$container.",".$baseDn,
+            'exchange_proxyaddress'=>'SMTP:' . $emailAddress,
+            'exchange_mailnickname'=>$mailNickname,
+            'exchange_usedefaults'=>$mdbUseDefaults
+        );
+        $result = $this->adldap->user()->modify($username, $attributes, $isGUID);
+        if ($result == false) { 
+            return false; 
+        }
+        return true;
+    }
+    
+    /**
+    * Add an X400 address to Exchange
+    * See http://tools.ietf.org/html/rfc1685 for more information.
+    * An X400 Address looks similar to this X400:c=US;a= ;p=Domain;o=Organization;s=Doe;g=John;
+    * 
+    * @param string $username The username of the user to add the X400 to to
+    * @param string $country Country
+    * @param string $admd Administration Management Domain
+    * @param string $pdmd Private Management Domain (often your AD domain)
+    * @param string $org Organization
+    * @param string $surname Surname
+    * @param string $givenName Given name
+    * @param bool $isGUID Is the username passed a GUID or a samAccountName
+    * @return bool
+    */
+    public function addX400($username, $country, $admd, $pdmd, $org, $surname, $givenName, $isGUID=false) 
+    {
+        if ($username === NULL){ return "Missing compulsory field [username]"; }     
+        
+        $proxyValue = 'X400:';
+            
+        // Find the dn of the user
+        $user = $this->adldap->user()->info($username, array("cn","proxyaddresses"), $isGUID);
+        if ($user[0]["dn"] === NULL) { return false; }
+        $userDn = $user[0]["dn"];
+        
+        // We do not have to demote an email address from the default so we can just add the new proxy address
+        $attributes['exchange_proxyaddress'] = $proxyValue . 'c=' . $country . ';a=' . $admd . ';p=' . $pdmd . ';o=' . $org . ';s=' . $surname . ';g=' . $givenName . ';';
+       
+        // Translate the update to the LDAP schema                
+        $add = $this->adldap->adldap_schema($attributes);
+        
+        if (!$add) { return false; }
+        
+        // Do the update
+        // Take out the @ to see any errors, usually this error might occur because the address already
+        // exists in the list of proxyAddresses
+        $result = @ldap_mod_add($this->adldap->getLdapConnection(), $userDn, $add);
+        if ($result == false) { 
+            return false; 
+        }
+        
+        return true;
+    }
+    
+    /**
+    * Add an address to Exchange
+    * 
+    * @param string $username The username of the user to add the Exchange account to
+    * @param string $emailAddress The email address to add to this user
+    * @param bool $default Make this email address the default address, this is a bit more intensive as we have to demote any existing default addresses
+    * @param bool $isGUID Is the username passed a GUID or a samAccountName
+    * @return bool
+    */
+    public function addAddress($username, $emailAddress, $default = FALSE, $isGUID = false) 
+    {
+        if ($username === NULL) { return "Missing compulsory field [username]"; }     
+        if ($emailAddress === NULL) { return "Missing compulsory fields [emailAddress]"; }
+        
+        $proxyValue = 'smtp:';
+        if ($default === true) {
+            $proxyValue = 'SMTP:';
+        }
+              
+        // Find the dn of the user
+        $user = $this->adldap->user()->info($username, array("cn","proxyaddresses"), $isGUID);
+        if ($user[0]["dn"] === NULL){ return false; }
+        $userDn = $user[0]["dn"];
+        
+        // We need to scan existing proxy addresses and demote the default one
+        if (is_array($user[0]["proxyaddresses"]) && $default === true) {
+            $modAddresses = array();
+            for ($i=0;$iadldap->getLdapConnection(), $userDn, $modAddresses);
+            if ($result == false) { 
+                return false; 
+            }
+            
+            return true;
+        }
+        else {
+            // We do not have to demote an email address from the default so we can just add the new proxy address
+            $attributes['exchange_proxyaddress'] = $proxyValue . $emailAddress;
+            
+            // Translate the update to the LDAP schema                
+            $add = $this->adldap->adldap_schema($attributes);
+            
+            if (!$add) { 
+                return false; 
+            }
+            
+            // Do the update
+            // Take out the @ to see any errors, usually this error might occur because the address already
+            // exists in the list of proxyAddresses
+            $result = @ldap_mod_add($this->adldap->getLdapConnection(), $userDn,$add);
+            if ($result == false) { 
+                return false; 
+            }
+            
+            return true;
+        }
+    }
+    
+    /**
+    * Remove an address to Exchange
+    * If you remove a default address the account will no longer have a default, 
+    * we recommend changing the default address first
+    * 
+    * @param string $username The username of the user to add the Exchange account to
+    * @param string $emailAddress The email address to add to this user
+    * @param bool $isGUID Is the username passed a GUID or a samAccountName
+    * @return bool
+    */
+    public function deleteAddress($username, $emailAddress, $isGUID=false) 
+    {
+        if ($username === NULL) { return "Missing compulsory field [username]"; }     
+        if ($emailAddress === NULL) { return "Missing compulsory fields [emailAddress]"; }
+        
+        // Find the dn of the user
+        $user = $this->adldap->user()->info($username, array("cn","proxyaddresses"), $isGUID);
+        if ($user[0]["dn"] === NULL) { return false; }
+        $userDn = $user[0]["dn"];
+        
+        if (is_array($user[0]["proxyaddresses"])) {
+            $mod = array();
+            for ($i=0;$iadldap->getLdapConnection(), $userDn,$mod);
+            if ($result == false) { 
+                return false; 
+            }
+            
+            return true;
+        }
+        else {
+            return false;
+        }
+    }
+    /**
+    * Change the default address
+    * 
+    * @param string $username The username of the user to add the Exchange account to
+    * @param string $emailAddress The email address to make default
+    * @param bool $isGUID Is the username passed a GUID or a samAccountName
+    * @return bool
+    */
+    public function primaryAddress($username, $emailAddress, $isGUID = false) 
+    {
+        if ($username === NULL) { return "Missing compulsory field [username]"; }     
+        if ($emailAddress === NULL) { return "Missing compulsory fields [emailAddress]"; }
+        
+        // Find the dn of the user
+        $user = $this->adldap->user()->info($username, array("cn","proxyaddresses"), $isGUID);
+        if ($user[0]["dn"] === NULL){ return false; }
+        $userDn = $user[0]["dn"];
+        
+        if (is_array($user[0]["proxyaddresses"])) {
+            $modAddresses = array();
+            for ($i=0;$iadldap->getLdapConnection(), $userDn, $modAddresses);
+            if ($result == false) { 
+                return false; 
+            }
+            
+            return true;
+        }
+        
+    }
+    
+    /**
+    * Mail enable a contact
+    * Allows email to be sent to them through Exchange
+    * 
+    * @param string $distinguishedName The contact to mail enable
+    * @param string $emailAddress The email address to allow emails to be sent through
+    * @param string $mailNickname The mailnickname for the contact in Exchange.  If NULL this will be set to the display name
+    * @return bool
+    */
+    public function contactMailEnable($distinguishedName, $emailAddress, $mailNickname = NULL)
+    {
+        if ($distinguishedName === NULL) { return "Missing compulsory field [distinguishedName]"; }   
+        if ($emailAddress === NULL) { return "Missing compulsory field [emailAddress]"; }  
+        
+        if ($mailNickname !== NULL) {
+            // Find the dn of the user
+            $user = $this->adldap->contact()->info($distinguishedName, array("cn","displayname"));
+            if ($user[0]["displayname"] === NULL) { return false; }
+            $mailNickname = $user[0]['displayname'][0];
+        }
+        
+        $attributes = array("email"=>$emailAddress,"contact_email"=>"SMTP:" . $emailAddress,"exchange_proxyaddress"=>"SMTP:" . $emailAddress,"exchange_mailnickname" => $mailNickname);
+         
+        // Translate the update to the LDAP schema                
+        $mod = $this->adldap->adldap_schema($attributes);
+        
+        // Check to see if this is an enabled status update
+        if (!$mod) { return false; }
+        
+        // Do the update
+        $result = ldap_modify($this->adldap->getLdapConnection(), $distinguishedName, $mod);
+        if ($result == false) { return false; }
+        
+        return true;
+    }
+    
+    /**
+    * Returns a list of Exchange Servers in the ConfigurationNamingContext of the domain
+    * 
+    * @param array $attributes An array of the AD attributes you wish to return
+    * @return array
+    */
+    public function servers($attributes = array('cn','distinguishedname','serialnumber')) 
+    {
+        if (!$this->adldap->getLdapBind()){ return false; }
+        
+        $configurationNamingContext = $this->adldap->getRootDse(array('configurationnamingcontext'));
+        $sr = @ldap_search($this->adldap->getLdapConnection(), $configurationNamingContext[0]['configurationnamingcontext'][0],'(&(objectCategory=msExchExchangeServer))', $attributes);
+        $entries = @ldap_get_entries($this->adldap->getLdapConnection(), $sr);
+        return $entries;
+    }
+    
+    /**
+    * Returns a list of Storage Groups in Exchange for a given mail server
+    * 
+    * @param string $exchangeServer The full DN of an Exchange server.  You can use exchange_servers() to find the DN for your server
+    * @param array $attributes An array of the AD attributes you wish to return
+    * @param bool $recursive If enabled this will automatically query the databases within a storage group
+    * @return array
+    */
+    public function storageGroups($exchangeServer, $attributes = array('cn','distinguishedname'), $recursive = NULL) 
+    {
+        if (!$this->adldap->getLdapBind()){ return false; }
+        if ($exchangeServer === NULL) { return "Missing compulsory field [exchangeServer]"; }
+        if ($recursive === NULL) { $recursive = $this->adldap->getRecursiveGroups(); }
+
+        $filter = '(&(objectCategory=msExchStorageGroup))';
+        $sr = @ldap_search($this->adldap->getLdapConnection(), $exchangeServer, $filter, $attributes);
+        $entries = @ldap_get_entries($this->adldap->getLdapConnection(), $sr);
+
+        if ($recursive === true) {
+            for ($i=0; $i<$entries['count']; $i++) {
+                $entries[$i]['msexchprivatemdb'] = $this->storageDatabases($entries[$i]['distinguishedname'][0]);       
+            }
+        }
+        
+        return $entries;
+    }
+    
+    /**
+    * Returns a list of Databases within any given storage group in Exchange for a given mail server
+    * 
+    * @param string $storageGroup The full DN of an Storage Group.  You can use exchange_storage_groups() to find the DN 
+    * @param array $attributes An array of the AD attributes you wish to return
+    * @return array
+    */
+    public function storageDatabases($storageGroup, $attributes = array('cn','distinguishedname','displayname')) {
+        if (!$this->adldap->getLdapBind()){ return false; }
+        if ($storageGroup === NULL) { return "Missing compulsory field [storageGroup]"; }
+        
+        $filter = '(&(objectCategory=msExchPrivateMDB))';
+        $sr = @ldap_search($this->adldap->getLdapConnection(), $storageGroup, $filter, $attributes);
+        $entries = @ldap_get_entries($this->adldap->getLdapConnection(), $sr);
+        return $entries;
+    }
+}
+?>
\ No newline at end of file
diff --git a/lib/plugins/authad/adLDAP/classes/adLDAPFolders.php b/lib/plugins/authad/adLDAP/classes/adLDAPFolders.php
new file mode 100644
index 000000000..55120152d
--- /dev/null
+++ b/lib/plugins/authad/adLDAP/classes/adLDAPFolders.php
@@ -0,0 +1,179 @@
+adldap = $adldap;
+    }
+    
+    /**
+    * Delete a distinguished name from Active Directory
+    * You should never need to call this yourself, just use the wrapper functions user_delete and contact_delete
+    *
+    * @param string $dn The distinguished name to delete
+    * @return bool
+    */
+    public function delete($dn){ 
+        $result = ldap_delete($this->adldap->getLdapConnection(), $dn);
+        if ($result != true) { 
+            return false; 
+        }
+        return true;
+    }
+    
+    /**
+    * Returns a folder listing for a specific OU
+    * See http://adldap.sourceforge.net/wiki/doku.php?id=api_folder_functions
+    * 
+    * @param array $folderName An array to the OU you wish to list. 
+    *                           If set to NULL will list the root, strongly recommended to set 
+    *                           $recursive to false in that instance!
+    * @param string $dnType The type of record to list.  This can be ADLDAP_FOLDER or ADLDAP_CONTAINER.
+    * @param bool $recursive Recursively search sub folders
+    * @param bool $type Specify a type of object to search for
+    * @return array
+    */
+    public function listing($folderName = NULL, $dnType = adLDAP::ADLDAP_FOLDER, $recursive = NULL, $type = NULL) 
+    {
+        if ($recursive === NULL) { $recursive = $this->adldap->getRecursiveGroups(); } //use the default option if they haven't set it
+        if (!$this->adldap->getLdapBind()) { return false; }
+
+        $filter = '(&';
+        if ($type !== NULL) {
+            switch ($type) {
+                case 'contact':
+                    $filter .= '(objectClass=contact)';
+                    break;
+                case 'computer':
+                    $filter .= '(objectClass=computer)';
+                    break;
+                case 'group':
+                    $filter .= '(objectClass=group)';
+                    break;
+                case 'folder':
+                    $filter .= '(objectClass=organizationalUnit)';
+                    break;
+                case 'container':
+                    $filter .= '(objectClass=container)';
+                    break;
+                case 'domain':
+                    $filter .= '(objectClass=builtinDomain)';
+                    break;
+                default:
+                    $filter .= '(objectClass=user)';
+                    break;   
+            }
+        }
+        else {
+            $filter .= '(objectClass=*)';   
+        }
+        // If the folder name is null then we will search the root level of AD
+        // This requires us to not have an OU= part, just the base_dn
+        $searchOu = $this->adldap->getBaseDn();
+        if (is_array($folderName)) {
+            $ou = $dnType . "=" . implode("," . $dnType . "=", $folderName);
+            $filter .= '(!(distinguishedname=' . $ou . ',' . $this->adldap->getBaseDn() . ')))';
+            $searchOu = $ou . ',' . $this->adldap->getBaseDn();
+        }
+        else {
+            $filter .= '(!(distinguishedname=' . $this->adldap->getBaseDn() . ')))';
+        }
+
+        if ($recursive === true) {
+            $sr = ldap_search($this->adldap->getLdapConnection(), $searchOu, $filter, array('objectclass', 'distinguishedname', 'samaccountname'));
+            $entries = @ldap_get_entries($this->adldap->getLdapConnection(), $sr);
+            if (is_array($entries)) {
+                return $entries;
+            }
+        }
+        else {
+            $sr = ldap_list($this->adldap->getLdapConnection(), $searchOu, $filter, array('objectclass', 'distinguishedname', 'samaccountname'));
+            $entries = @ldap_get_entries($this->adldap->getLdapConnection(), $sr);
+            if (is_array($entries)) {
+                return $entries;
+            }
+        }
+        
+        return false;
+    }
+
+    /**
+    * Create an organizational unit
+    * 
+    * @param array $attributes Default attributes of the ou
+    * @return bool
+    */
+    public function create($attributes)
+    {
+        if (!is_array($attributes)){ return "Attributes must be an array"; }
+        if (!is_array($attributes["container"])) { return "Container attribute must be an array."; }
+        if (!array_key_exists("ou_name",$attributes)) { return "Missing compulsory field [ou_name]"; }
+        if (!array_key_exists("container",$attributes)) { return "Missing compulsory field [container]"; }
+        
+        $attributes["container"] = array_reverse($attributes["container"]);
+
+        $add=array();
+        $add["objectClass"] = "organizationalUnit";
+        $add["OU"] = $attributes['ou_name'];
+        $containers = "";
+        if (count($attributes['container']) > 0) {
+            $containers = "OU=" . implode(",OU=", $attributes["container"]) . ",";
+        }
+
+        $containers = "OU=" . implode(",OU=", $attributes["container"]);
+        $result = ldap_add($this->adldap->getLdapConnection(), "OU=" . $add["OU"] . ", " . $containers . $this->adldap->getBaseDn(), $add);
+        if ($result != true) { 
+            return false; 
+        }
+        
+        return true;
+    }
+    
+}
+
+?>
\ No newline at end of file
diff --git a/lib/plugins/authad/adLDAP/classes/adLDAPGroups.php b/lib/plugins/authad/adLDAP/classes/adLDAPGroups.php
new file mode 100644
index 000000000..05e4cc93b
--- /dev/null
+++ b/lib/plugins/authad/adLDAP/classes/adLDAPGroups.php
@@ -0,0 +1,631 @@
+adldap = $adldap;
+    }
+    
+    /**
+    * Add a group to a group
+    * 
+    * @param string $parent The parent group name
+    * @param string $child The child group name
+    * @return bool
+    */
+    public function addGroup($parent,$child){
+
+        // Find the parent group's dn
+        $parentGroup = $this->ginfo($parent, array("cn"));
+        if ($parentGroup[0]["dn"] === NULL){
+            return false; 
+        }
+        $parentDn = $parentGroup[0]["dn"];
+        
+        // Find the child group's dn
+        $childGroup = $this->info($child, array("cn"));
+        if ($childGroup[0]["dn"] === NULL){ 
+            return false; 
+        }
+        $childDn = $childGroup[0]["dn"];
+                
+        $add = array();
+        $add["member"] = $childDn;
+        
+        $result = @ldap_mod_add($this->adldap->getLdapConnection(), $parentDn, $add);
+        if ($result == false) { 
+            return false; 
+        }
+        return true;
+    }
+    
+    /**
+    * Add a user to a group
+    * 
+    * @param string $group The group to add the user to
+    * @param string $user The user to add to the group
+    * @param bool $isGUID Is the username passed a GUID or a samAccountName
+    * @return bool
+    */
+    public function addUser($group, $user, $isGUID = false)
+    {
+        // Adding a user is a bit fiddly, we need to get the full DN of the user
+        // and add it using the full DN of the group
+        
+        // Find the user's dn
+        $userDn = $this->adldap->user()->dn($user, $isGUID);
+        if ($userDn === false) { 
+            return false; 
+        }
+        
+        // Find the group's dn
+        $groupInfo = $this->info($group, array("cn"));
+        if ($groupInfo[0]["dn"] === NULL) { 
+            return false; 
+        }
+        $groupDn = $groupInfo[0]["dn"];
+        
+        $add = array();
+        $add["member"] = $userDn;
+        
+        $result = @ldap_mod_add($this->adldap->getLdapConnection(), $groupDn, $add);
+        if ($result == false) { 
+            return false; 
+        }
+        return true;
+    }
+    
+    /**
+    * Add a contact to a group
+    * 
+    * @param string $group The group to add the contact to
+    * @param string $contactDn The DN of the contact to add
+    * @return bool
+    */
+    public function addContact($group, $contactDn)
+    {
+        // To add a contact we take the contact's DN
+        // and add it using the full DN of the group
+        
+        // Find the group's dn
+        $groupInfo = $this->info($group, array("cn"));
+        if ($groupInfo[0]["dn"] === NULL) { 
+            return false; 
+        }
+        $groupDn = $groupInfo[0]["dn"];
+        
+        $add = array();
+        $add["member"] = $contactDn;
+        
+        $result = @ldap_mod_add($this->adldap->getLdapConnection(), $groupDn, $add);
+        if ($result == false) { 
+            return false; 
+        }
+        return true;
+    }
+
+    /**
+    * Create a group
+    * 
+    * @param array $attributes Default attributes of the group
+    * @return bool
+    */
+    public function create($attributes)
+    {
+        if (!is_array($attributes)){ return "Attributes must be an array"; }
+        if (!array_key_exists("group_name", $attributes)){ return "Missing compulsory field [group_name]"; }
+        if (!array_key_exists("container", $attributes)){ return "Missing compulsory field [container]"; }
+        if (!array_key_exists("description", $attributes)){ return "Missing compulsory field [description]"; }
+        if (!is_array($attributes["container"])){ return "Container attribute must be an array."; }
+        $attributes["container"] = array_reverse($attributes["container"]);
+
+        //$member_array = array();
+        //$member_array[0] = "cn=user1,cn=Users,dc=yourdomain,dc=com";
+        //$member_array[1] = "cn=administrator,cn=Users,dc=yourdomain,dc=com";
+        
+        $add = array();
+        $add["cn"] = $attributes["group_name"];
+        $add["samaccountname"] = $attributes["group_name"];
+        $add["objectClass"] = "Group";
+        $add["description"] = $attributes["description"];
+        //$add["member"] = $member_array; UNTESTED
+
+        $container = "OU=" . implode(",OU=", $attributes["container"]);
+        $result = ldap_add($this->adldap->getLdapConnection(), "CN=" . $add["cn"] . ", " . $container . "," . $this->adldap->getBaseDn(), $add);
+        if ($result != true) { 
+            return false; 
+        }
+        return true;
+    }
+    
+    /**
+    * Delete a group account 
+    * 
+    * @param string $group The group to delete (please be careful here!) 
+    * 
+    * @return array 
+    */
+    public function delete($group) {
+        if (!$this->adldap->getLdapBind()){ return false; }
+        if ($group === null){ return "Missing compulsory field [group]"; }
+        
+        $groupInfo = $this->info($group, array("*"));
+        $dn = $groupInfo[0]['distinguishedname'][0]; 
+        $result = $this->adldap->folder()->delete($dn); 
+        if ($result !== true) { 
+            return false; 
+        } return true;   
+    }
+
+    /**
+    * Remove a group from a group
+    * 
+    * @param string $parent The parent group name
+    * @param string $child The child group name
+    * @return bool
+    */
+    public function removeGroup($parent , $child)
+    {
+    
+        // Find the parent dn
+        $parentGroup = $this->info($parent, array("cn"));
+        if ($parentGroup[0]["dn"] === NULL) { 
+            return false; 
+        }
+        $parentDn = $parentGroup[0]["dn"];
+        
+        // Find the child dn
+        $childGroup = $this->info($child, array("cn"));
+        if ($childGroup[0]["dn"] === NULL) { 
+            return false; 
+        }
+        $childDn = $childGroup[0]["dn"];
+        
+        $del = array();
+        $del["member"] = $childDn;
+        
+        $result = @ldap_mod_del($this->adldap->getLdapConnection(), $parentDn, $del);
+        if ($result == false) { 
+            return false; 
+        }
+        return true;
+    }
+    
+    /**
+    * Remove a user from a group
+    * 
+    * @param string $group The group to remove a user from
+    * @param string $user The AD user to remove from the group
+    * @param bool $isGUID Is the username passed a GUID or a samAccountName
+    * @return bool
+    */
+    public function removeUser($group, $user, $isGUID = false)
+    {
+    
+        // Find the parent dn
+        $groupInfo = $this->info($group, array("cn"));
+        if ($groupInfo[0]["dn"] === NULL){ 
+            return false; 
+        }
+        $groupDn = $groupInfo[0]["dn"];
+        
+        // Find the users dn
+        $userDn = $this->adldap->user()->dn($user, $isGUID);
+        if ($userDn === false) {
+            return false; 
+        }
+
+        $del = array();
+        $del["member"] = $userDn;
+        
+        $result = @ldap_mod_del($this->adldap->getLdapConnection(), $groupDn, $del);
+        if ($result == false) {
+            return false; 
+        }
+        return true;
+    }
+    
+    /**
+    * Remove a contact from a group
+    * 
+    * @param string $group The group to remove a user from
+    * @param string $contactDn The DN of a contact to remove from the group
+    * @return bool
+    */
+    public function removeContact($group, $contactDn)
+    {
+    
+        // Find the parent dn
+        $groupInfo = $this->info($group, array("cn"));
+        if ($groupInfo[0]["dn"] === NULL) { 
+            return false; 
+        }
+        $groupDn = $groupInfo[0]["dn"];
+    
+        $del = array();
+        $del["member"] = $contactDn;
+        
+        $result = @ldap_mod_del($this->adldap->getLdapConnection(), $groupDn, $del);
+        if ($result == false) { 
+            return false; 
+        }
+        return true;
+    }
+    
+    /**
+    * Return a list of groups in a group
+    * 
+    * @param string $group The group to query
+    * @param bool $recursive Recursively get groups
+    * @return array
+    */
+    public function inGroup($group, $recursive = NULL)
+    {
+        if (!$this->adldap->getLdapBind()){ return false; }
+        if ($recursive === NULL){ $recursive = $this->adldap->getRecursiveGroups(); } // Use the default option if they haven't set it 
+        
+        // Search the directory for the members of a group
+        $info = $this->info($group, array("member","cn"));
+        $groups = $info[0]["member"];
+        if (!is_array($groups)) {
+            return false;   
+        }
+ 
+        $groupArray = array();
+
+        for ($i=0; $i<$groups["count"]; $i++){ 
+             $filter = "(&(objectCategory=group)(distinguishedName=" . $this->adldap->utilities()->ldapSlashes($groups[$i]) . "))";
+             $fields = array("samaccountname", "distinguishedname", "objectClass");
+             $sr = ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields);
+             $entries = ldap_get_entries($this->adldap->getLdapConnection(), $sr);
+
+             // not a person, look for a group  
+             if ($entries['count'] == 0 && $recursive == true) {  
+                $filter = "(&(objectCategory=group)(distinguishedName=" . $this->adldap->utilities()->ldapSlashes($groups[$i]) . "))";  
+                $fields = array("distinguishedname");  
+                $sr = ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields);  
+                $entries = ldap_get_entries($this->adldap->getLdapConnection(), $sr);  
+                if (!isset($entries[0]['distinguishedname'][0])) {
+                    continue;  
+                }
+                $subGroups = $this->inGroup($entries[0]['distinguishedname'][0], $recursive);  
+                if (is_array($subGroups)) {
+                    $groupArray = array_merge($groupArray, $subGroups); 
+                    $groupArray = array_unique($groupArray);  
+                }
+                continue;  
+             } 
+
+             $groupArray[] = $entries[0]['distinguishedname'][0];
+        }
+        return $groupArray;
+    }
+    
+    /**
+    * Return a list of members in a group
+    * 
+    * @param string $group The group to query
+    * @param bool $recursive Recursively get group members
+    * @return array
+    */
+    public function members($group, $recursive = NULL)
+    {
+        if (!$this->adldap->getLdapBind()){ return false; }
+        if ($recursive === NULL){ $recursive = $this->adldap->getRecursiveGroups(); } // Use the default option if they haven't set it 
+        // Search the directory for the members of a group
+        $info = $this->info($group, array("member","cn"));
+        $users = $info[0]["member"];
+        if (!is_array($users)) {
+            return false;   
+        }
+ 
+        $userArray = array();
+
+        for ($i=0; $i<$users["count"]; $i++){ 
+             $filter = "(&(objectCategory=person)(distinguishedName=" . $this->adldap->utilities()->ldapSlashes($users[$i]) . "))";
+             $fields = array("samaccountname", "distinguishedname", "objectClass");
+             $sr = ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields);
+             $entries = ldap_get_entries($this->adldap->getLdapConnection(), $sr);
+
+             // not a person, look for a group  
+             if ($entries['count'] == 0 && $recursive == true) {  
+                $filter = "(&(objectCategory=group)(distinguishedName=" . $this->adldap->utilities()->ldapSlashes($users[$i]) . "))";  
+                $fields = array("samaccountname");  
+                $sr = ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields);  
+                $entries = ldap_get_entries($this->adldap->getLdapConnection(), $sr);  
+                if (!isset($entries[0]['samaccountname'][0])) {
+                    continue;  
+                }
+                $subUsers = $this->members($entries[0]['samaccountname'][0], $recursive);  
+                if (is_array($subUsers)) {
+                    $userArray = array_merge($userArray, $subUsers); 
+                    $userArray = array_unique($userArray);  
+                }
+                continue;  
+             } 
+             else if ($entries['count'] == 0) {   
+                continue; 
+             } 
+
+             if ((!isset($entries[0]['samaccountname'][0]) || $entries[0]['samaccountname'][0] === NULL) && $entries[0]['distinguishedname'][0] !== NULL) {
+                 $userArray[] = $entries[0]['distinguishedname'][0];
+             }
+             else if ($entries[0]['samaccountname'][0] !== NULL) {
+                $userArray[] = $entries[0]['samaccountname'][0];
+             }
+        }
+        return $userArray;
+    }
+    
+    /**
+    * Group Information.  Returns an array of raw information about a group.
+    * The group name is case sensitive
+    * 
+    * @param string $groupName The group name to retrieve info about
+    * @param array $fields Fields to retrieve
+    * @return array
+    */
+    public function info($groupName, $fields = NULL)
+    {
+        if ($groupName === NULL) { return false; }
+        if (!$this->adldap->getLdapBind()) { return false; }
+        
+        if (stristr($groupName, '+')) {
+            $groupName = stripslashes($groupName);   
+        }
+        
+        $filter = "(&(objectCategory=group)(name=" . $this->adldap->utilities()->ldapSlashes($groupName) . "))";
+        if ($fields === NULL) { 
+            $fields = array("member","memberof","cn","description","distinguishedname","objectcategory","samaccountname"); 
+        }
+        $sr = ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields);
+        $entries = ldap_get_entries($this->adldap->getLdapConnection(), $sr);
+
+        return $entries;
+    }
+    
+    /**
+    * Group Information.  Returns an collection
+    * The group name is case sensitive
+    * 
+    * @param string $groupName The group name to retrieve info about
+    * @param array $fields Fields to retrieve
+    * @return adLDAPGroupCollection
+    */
+    public function infoCollection($groupName, $fields = NULL)
+    {
+        if ($groupName === NULL) { return false; }
+        if (!$this->adldap->getLdapBind()) { return false; }
+        
+        $info = $this->info($groupName, $fields);
+        if ($info !== false) {
+            $collection = new adLDAPGroupCollection($info, $this->adldap);
+            return $collection;
+        }
+        return false;
+    }
+    
+    /**
+    * Return a complete list of "groups in groups"
+    * 
+    * @param string $group The group to get the list from
+    * @return array
+    */
+    public function recursiveGroups($group)
+    {
+        if ($group === NULL) { return false; }
+
+        $stack = array(); 
+        $processed = array(); 
+        $retGroups = array(); 
+     
+        array_push($stack, $group); // Initial Group to Start with 
+        while (count($stack) > 0) {
+            $parent = array_pop($stack);
+            array_push($processed, $parent);
+            
+            $info = $this->info($parent, array("memberof"));
+            
+            if (isset($info[0]["memberof"]) && is_array($info[0]["memberof"])) {
+                $groups = $info[0]["memberof"]; 
+                if ($groups) {
+                    $groupNames = $this->adldap->utilities()->niceNames($groups);  
+                    $retGroups = array_merge($retGroups, $groupNames); //final groups to return
+                    foreach ($groupNames as $id => $groupName) { 
+                        if (!in_array($groupName, $processed)) {
+                            array_push($stack, $groupName);
+                        }
+                    }
+                }
+            }
+        }
+        
+        return $retGroups;
+    }
+    
+    /**
+    * Returns a complete list of the groups in AD based on a SAM Account Type  
+    * 
+    * @param string $sAMAaccountType The account type to return
+    * @param bool $includeDescription Whether to return a description
+    * @param string $search Search parameters
+    * @param bool $sorted Whether to sort the results
+    * @return array
+    */
+    public function search($sAMAaccountType = adLDAP::ADLDAP_SECURITY_GLOBAL_GROUP, $includeDescription = false, $search = "*", $sorted = true) {
+        if (!$this->adldap->getLdapBind()) { return false; }
+        
+        $filter = '(&(objectCategory=group)';
+        if ($sAMAaccountType !== null) {
+            $filter .= '(samaccounttype='. $sAMAaccountType .')';
+        }
+        $filter .= '(cn=' . $search . '))';
+        // Perform the search and grab all their details
+        $fields = array("samaccountname", "description");
+        $sr = ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields);
+        $entries = ldap_get_entries($this->adldap->getLdapConnection(), $sr);
+
+        $groupsArray = array();        
+        for ($i=0; $i<$entries["count"]; $i++){
+            if ($includeDescription && strlen($entries[$i]["description"][0]) > 0 ) {
+                $groupsArray[$entries[$i]["samaccountname"][0]] = $entries[$i]["description"][0];
+            }
+            else if ($includeDescription){
+                $groupsArray[$entries[$i]["samaccountname"][0]] = $entries[$i]["samaccountname"][0];
+            }
+            else {
+                array_push($groupsArray, $entries[$i]["samaccountname"][0]);
+            }
+        }
+        if ($sorted) { 
+            asort($groupsArray); 
+        }
+        return $groupsArray;
+    }
+    
+    /**
+    * Returns a complete list of all groups in AD
+    * 
+    * @param bool $includeDescription Whether to return a description
+    * @param string $search Search parameters
+    * @param bool $sorted Whether to sort the results
+    * @return array
+    */
+    public function all($includeDescription = false, $search = "*", $sorted = true){
+        $groupsArray = $this->search(null, $includeDescription, $search, $sorted);
+        return $groupsArray;
+    }
+    
+    /**
+    * Returns a complete list of security groups in AD
+    * 
+    * @param bool $includeDescription Whether to return a description
+    * @param string $search Search parameters
+    * @param bool $sorted Whether to sort the results
+    * @return array
+    */
+    public function allSecurity($includeDescription = false, $search = "*", $sorted = true){
+        $groupsArray = $this->search(adLDAP::ADLDAP_SECURITY_GLOBAL_GROUP, $includeDescription, $search, $sorted);
+        return $groupsArray;
+    }
+    
+    /**
+    * Returns a complete list of distribution lists in AD
+    * 
+    * @param bool $includeDescription Whether to return a description
+    * @param string $search Search parameters
+    * @param bool $sorted Whether to sort the results
+    * @return array
+    */
+    public function allDistribution($includeDescription = false, $search = "*", $sorted = true){
+        $groupsArray = $this->search(adLDAP::ADLDAP_DISTRIBUTION_GROUP, $includeDescription, $search, $sorted);
+        return $groupsArray;
+    }
+    
+    /**
+    * Coping with AD not returning the primary group
+    * http://support.microsoft.com/?kbid=321360 
+    * 
+    * This is a re-write based on code submitted by Bruce which prevents the 
+    * need to search each security group to find the true primary group
+    * 
+    * @param string $gid Group ID
+    * @param string $usersid User's Object SID
+    * @return mixed
+    */
+    public function getPrimaryGroup($gid, $usersid)
+    {
+        if ($gid === NULL || $usersid === NULL) { return false; }
+        $sr = false;
+
+        $gsid = substr_replace($usersid, pack('V',$gid), strlen($usersid)-4,4);
+        $filter = '(objectsid=' . $this->adldap->utilities()->getTextSID($gsid).')';
+        $fields = array("samaccountname","distinguishedname");
+        $sr = ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields);
+        $entries = ldap_get_entries($this->adldap->getLdapConnection(), $sr);
+
+        if (isset($entries[0]['distinguishedname'][0])) {
+            return $entries[0]['distinguishedname'][0];
+        }
+        return false;
+     }
+     
+     /**
+    * Coping with AD not returning the primary group
+    * http://support.microsoft.com/?kbid=321360 
+    * 
+    * For some reason it's not possible to search on primarygrouptoken=XXX
+    * If someone can show otherwise, I'd like to know about it :)
+    * this way is resource intensive and generally a pain in the @#%^
+    * 
+    * @deprecated deprecated since version 3.1, see get get_primary_group
+    * @param string $gid Group ID
+    * @return string
+    */
+    public function cn($gid){    
+        if ($gid === NULL) { return false; }
+        $sr = false;
+        $r = '';
+        
+        $filter = "(&(objectCategory=group)(samaccounttype=" . adLDAP::ADLDAP_SECURITY_GLOBAL_GROUP . "))";
+        $fields = array("primarygrouptoken", "samaccountname", "distinguishedname");
+        $sr = ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields);
+        $entries = ldap_get_entries($this->adldap->getLdapConnection(), $sr);
+        
+        for ($i=0; $i<$entries["count"]; $i++){
+            if ($entries[$i]["primarygrouptoken"][0] == $gid) {
+                $r = $entries[$i]["distinguishedname"][0];
+                $i = $entries["count"];
+            }
+        }
+
+        return $r;
+    }
+}
+?>
diff --git a/lib/plugins/authad/adLDAP/classes/adLDAPUsers.php b/lib/plugins/authad/adLDAP/classes/adLDAPUsers.php
new file mode 100644
index 000000000..96a93b512
--- /dev/null
+++ b/lib/plugins/authad/adLDAP/classes/adLDAPUsers.php
@@ -0,0 +1,682 @@
+adldap = $adldap;
+    }
+    
+    /**
+    * Validate a user's login credentials
+    * 
+    * @param string $username A user's AD username
+    * @param string $password A user's AD password
+    * @param bool optional $prevent_rebind
+    * @return bool
+    */
+    public function authenticate($username, $password, $preventRebind = false) {
+        return $this->adldap->authenticate($username, $password, $preventRebind);
+    }
+    
+    /**
+    * Create a user
+    * 
+    * If you specify a password here, this can only be performed over SSL
+    * 
+    * @param array $attributes The attributes to set to the user account
+    * @return bool
+    */
+    public function create($attributes)
+    {
+        // Check for compulsory fields
+        if (!array_key_exists("username", $attributes)){ return "Missing compulsory field [username]"; }
+        if (!array_key_exists("firstname", $attributes)){ return "Missing compulsory field [firstname]"; }
+        if (!array_key_exists("surname", $attributes)){ return "Missing compulsory field [surname]"; }
+        if (!array_key_exists("email", $attributes)){ return "Missing compulsory field [email]"; }
+        if (!array_key_exists("container", $attributes)){ return "Missing compulsory field [container]"; }
+        if (!is_array($attributes["container"])){ return "Container attribute must be an array."; }
+
+        if (array_key_exists("password",$attributes) && (!$this->adldap->getUseSSL() && !$this->adldap->getUseTLS())){ 
+            throw new adLDAPException('SSL must be configured on your webserver and enabled in the class to set passwords.');
+        }
+
+        if (!array_key_exists("display_name", $attributes)) { 
+            $attributes["display_name"] = $attributes["firstname"] . " " . $attributes["surname"]; 
+        }
+
+        // Translate the schema
+        $add = $this->adldap->adldap_schema($attributes);
+        
+        // Additional stuff only used for adding accounts
+        $add["cn"][0] = $attributes["display_name"];
+        $add["samaccountname"][0] = $attributes["username"];
+        $add["objectclass"][0] = "top";
+        $add["objectclass"][1] = "person";
+        $add["objectclass"][2] = "organizationalPerson";
+        $add["objectclass"][3] = "user"; //person?
+        //$add["name"][0]=$attributes["firstname"]." ".$attributes["surname"];
+
+        // Set the account control attribute
+        $control_options = array("NORMAL_ACCOUNT");
+        if (!$attributes["enabled"]) { 
+            $control_options[] = "ACCOUNTDISABLE"; 
+        }
+        $add["userAccountControl"][0] = $this->accountControl($control_options);
+        
+        // Determine the container
+        $attributes["container"] = array_reverse($attributes["container"]);
+        $container = "OU=" . implode(", OU=",$attributes["container"]);
+
+        // Add the entry
+        $result = @ldap_add($this->adldap->getLdapConnection(), "CN=" . $add["cn"][0] . ", " . $container . "," . $this->adldap->getBaseDn(), $add);
+        if ($result != true) { 
+            return false; 
+        }
+        
+        return true;
+    }
+    
+    /**
+    * Account control options
+    *
+    * @param array $options The options to convert to int 
+    * @return int
+    */
+    protected function accountControl($options)
+    {
+        $val=0;
+
+        if (is_array($options)) {
+            if (in_array("SCRIPT",$options)){ $val=$val+1; }
+            if (in_array("ACCOUNTDISABLE",$options)){ $val=$val+2; }
+            if (in_array("HOMEDIR_REQUIRED",$options)){ $val=$val+8; }
+            if (in_array("LOCKOUT",$options)){ $val=$val+16; }
+            if (in_array("PASSWD_NOTREQD",$options)){ $val=$val+32; }
+            //PASSWD_CANT_CHANGE Note You cannot assign this permission by directly modifying the UserAccountControl attribute.
+            //For information about how to set the permission programmatically, see the "Property flag descriptions" section.
+            if (in_array("ENCRYPTED_TEXT_PWD_ALLOWED",$options)){ $val=$val+128; }
+            if (in_array("TEMP_DUPLICATE_ACCOUNT",$options)){ $val=$val+256; }
+            if (in_array("NORMAL_ACCOUNT",$options)){ $val=$val+512; }
+            if (in_array("INTERDOMAIN_TRUST_ACCOUNT",$options)){ $val=$val+2048; }
+            if (in_array("WORKSTATION_TRUST_ACCOUNT",$options)){ $val=$val+4096; }
+            if (in_array("SERVER_TRUST_ACCOUNT",$options)){ $val=$val+8192; }
+            if (in_array("DONT_EXPIRE_PASSWORD",$options)){ $val=$val+65536; }
+            if (in_array("MNS_LOGON_ACCOUNT",$options)){ $val=$val+131072; }
+            if (in_array("SMARTCARD_REQUIRED",$options)){ $val=$val+262144; }
+            if (in_array("TRUSTED_FOR_DELEGATION",$options)){ $val=$val+524288; }
+            if (in_array("NOT_DELEGATED",$options)){ $val=$val+1048576; }
+            if (in_array("USE_DES_KEY_ONLY",$options)){ $val=$val+2097152; }
+            if (in_array("DONT_REQ_PREAUTH",$options)){ $val=$val+4194304; } 
+            if (in_array("PASSWORD_EXPIRED",$options)){ $val=$val+8388608; }
+            if (in_array("TRUSTED_TO_AUTH_FOR_DELEGATION",$options)){ $val=$val+16777216; }
+        }
+        return $val;
+    }
+    
+    /**
+    * Delete a user account
+    * 
+    * @param string $username The username to delete (please be careful here!)
+    * @param bool $isGUID Is the username a GUID or a samAccountName
+    * @return array
+    */
+    public function delete($username, $isGUID = false) 
+    {      
+        $userinfo = $this->info($username, array("*"), $isGUID);
+        $dn = $userinfo[0]['distinguishedname'][0];
+        $result = $this->adldap->folder()->delete($dn);
+        if ($result != true) { 
+            return false;
+        }        
+        return true;
+    }
+    
+    /**
+    * Groups the user is a member of
+    * 
+    * @param string $username The username to query
+    * @param bool $recursive Recursive list of groups
+    * @param bool $isGUID Is the username passed a GUID or a samAccountName
+    * @return array
+    */
+    public function groups($username, $recursive = NULL, $isGUID = false)
+    {
+        if ($username === NULL) { return false; }
+        if ($recursive === NULL) { $recursive = $this->adldap->getRecursiveGroups(); } // Use the default option if they haven't set it
+        if (!$this->adldap->getLdapBind()) { return false; }
+        
+        // Search the directory for their information
+        $info = @$this->info($username, array("memberof", "primarygroupid"), $isGUID);
+        $groups = $this->adldap->utilities()->niceNames($info[0]["memberof"]); // Presuming the entry returned is our guy (unique usernames)
+
+        if ($recursive === true){
+            foreach ($groups as $id => $groupName){
+                $extraGroups = $this->adldap->group()->recursiveGroups($groupName);
+                $groups = array_merge($groups, $extraGroups);
+            }
+        }
+        
+        return $groups;
+    }
+    
+    /**
+    * Find information about the users. Returned in a raw array format from AD
+    * 
+    * @param string $username The username to query
+    * @param array $fields Array of parameters to query
+    * @param bool $isGUID Is the username passed a GUID or a samAccountName
+    * @return array
+    */
+    public function info($username, $fields = NULL, $isGUID = false)
+    {
+        if ($username === NULL) { return false; }
+        if (!$this->adldap->getLdapBind()) { return false; }
+
+        if ($isGUID === true) {
+            $username = $this->adldap->utilities()->strGuidToHex($username);
+            $filter = "objectguid=" . $username;
+        }
+        else if (strstr($username, "@")) {
+             $filter = "userPrincipalName=" . $username;
+        }
+        else {
+             $filter = "samaccountname=" . $username;
+        }
+        $filter = "(&(objectCategory=person)({$filter}))";
+        if ($fields === NULL) { 
+            $fields = array("samaccountname","mail","memberof","department","displayname","telephonenumber","primarygroupid","objectsid"); 
+        }
+        if (!in_array("objectsid", $fields)) {
+            $fields[] = "objectsid";
+        }
+        $sr = ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields);
+        $entries = ldap_get_entries($this->adldap->getLdapConnection(), $sr);
+        
+        if (isset($entries[0])) {
+            if ($entries[0]['count'] >= 1) {
+                if (in_array("memberof", $fields)) {
+                    // AD does not return the primary group in the ldap query, we may need to fudge it
+                    if ($this->adldap->getRealPrimaryGroup() && isset($entries[0]["primarygroupid"][0]) && isset($entries[0]["objectsid"][0])){
+                        //$entries[0]["memberof"][]=$this->group_cn($entries[0]["primarygroupid"][0]);
+                        $entries[0]["memberof"][] = $this->adldap->group()->getPrimaryGroup($entries[0]["primarygroupid"][0], $entries[0]["objectsid"][0]);
+                    } else {
+                        $entries[0]["memberof"][] = "CN=Domain Users,CN=Users," . $this->adldap->getBaseDn();
+                    }
+                    if (!isset($entries[0]["memberof"]["count"])) {
+                        $entries[0]["memberof"]["count"] = 0;
+                    }
+                    $entries[0]["memberof"]["count"]++;
+                }
+            }
+            
+            return $entries;
+        }
+        return false;
+    }
+    
+    /**
+    * Find information about the users. Returned in a raw array format from AD
+    * 
+    * @param string $username The username to query
+    * @param array $fields Array of parameters to query
+    * @param bool $isGUID Is the username passed a GUID or a samAccountName
+    * @return mixed
+    */
+    public function infoCollection($username, $fields = NULL, $isGUID = false)
+    {
+        if ($username === NULL) { return false; }
+        if (!$this->adldap->getLdapBind()) { return false; }
+        
+        $info = $this->info($username, $fields, $isGUID);
+        
+        if ($info !== false) {
+            $collection = new adLDAPUserCollection($info, $this->adldap);
+            return $collection;
+        }
+        return false;
+    }
+    
+    /**
+    * Determine if a user is in a specific group
+    * 
+    * @param string $username The username to query
+    * @param string $group The name of the group to check against
+    * @param bool $recursive Check groups recursively
+    * @param bool $isGUID Is the username passed a GUID or a samAccountName
+    * @return bool
+    */
+    public function inGroup($username, $group, $recursive = NULL, $isGUID = false)
+    {
+        if ($username === NULL) { return false; }
+        if ($group === NULL) { return false; }
+        if (!$this->adldap->getLdapBind()) { return false; }
+        if ($recursive === NULL) { $recursive = $this->adldap->getRecursiveGroups(); } // Use the default option if they haven't set it
+        
+        // Get a list of the groups
+        $groups = $this->groups($username, $recursive, $isGUID);
+        
+        // Return true if the specified group is in the group list
+        if (in_array($group, $groups)) { 
+            return true; 
+        }
+
+        return false;
+    }
+    
+    /**
+    * Determine a user's password expiry date
+    * 
+    * @param string $username The username to query
+    * @param book $isGUID Is the username passed a GUID or a samAccountName
+    * @requires bcmath http://www.php.net/manual/en/book.bc.php
+    * @return array
+    */
+    public function passwordExpiry($username, $isGUID = false) 
+    {
+        if ($username === NULL) { return "Missing compulsory field [username]"; }
+        if (!$this->adldap->getLdapBind()) { return false; }
+        if (!function_exists('bcmod')) { throw new adLDAPException("Missing function support [bcmod] http://www.php.net/manual/en/book.bc.php"); };
+        
+        $userInfo = $this->info($username, array("pwdlastset", "useraccountcontrol"), $isGUID);
+        $pwdLastSet = $userInfo[0]['pwdlastset'][0];
+        $status = array();
+        
+        if ($userInfo[0]['useraccountcontrol'][0] == '66048') {
+            // Password does not expire
+            return "Does not expire";
+        }
+        if ($pwdLastSet === '0') {
+            // Password has already expired
+            return "Password has expired";
+        }
+        
+         // Password expiry in AD can be calculated from TWO values:
+         //   - User's own pwdLastSet attribute: stores the last time the password was changed
+         //   - Domain's maxPwdAge attribute: how long passwords last in the domain
+         //
+         // Although Microsoft chose to use a different base and unit for time measurements.
+         // This function will convert them to Unix timestamps
+         $sr = ldap_read($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), 'objectclass=*', array('maxPwdAge'));
+         if (!$sr) {
+             return false;
+         }
+         $info = ldap_get_entries($this->adldap->getLdapConnection(), $sr);
+         $maxPwdAge = $info[0]['maxpwdage'][0];
+         
+
+         // See MSDN: http://msdn.microsoft.com/en-us/library/ms974598.aspx
+         //
+         // pwdLastSet contains the number of 100 nanosecond intervals since January 1, 1601 (UTC), 
+         // stored in a 64 bit integer. 
+         //
+         // The number of seconds between this date and Unix epoch is 11644473600.
+         //
+         // maxPwdAge is stored as a large integer that represents the number of 100 nanosecond
+         // intervals from the time the password was set before the password expires.
+         //
+         // We also need to scale this to seconds but also this value is a _negative_ quantity!
+         //
+         // If the low 32 bits of maxPwdAge are equal to 0 passwords do not expire
+         //
+         // Unfortunately the maths involved are too big for PHP integers, so I've had to require
+         // BCMath functions to work with arbitrary precision numbers.
+         if (bcmod($maxPwdAge, 4294967296) === '0') {
+            return "Domain does not expire passwords";
+        }
+        
+        // Add maxpwdage and pwdlastset and we get password expiration time in Microsoft's
+        // time units.  Because maxpwd age is negative we need to subtract it.
+        $pwdExpire = bcsub($pwdLastSet, $maxPwdAge);
+    
+        // Convert MS's time to Unix time
+        $status['expiryts'] = bcsub(bcdiv($pwdExpire, '10000000'), '11644473600');
+        $status['expiryformat'] = date('Y-m-d H:i:s', bcsub(bcdiv($pwdExpire, '10000000'), '11644473600'));
+        
+        return $status;
+    }
+    
+    /**
+    * Modify a user
+    * 
+    * @param string $username The username to query
+    * @param array $attributes The attributes to modify.  Note if you set the enabled attribute you must not specify any other attributes
+    * @param bool $isGUID Is the username passed a GUID or a samAccountName
+    * @return bool
+    */
+    public function modify($username, $attributes, $isGUID = false)
+    {
+        if ($username === NULL) { return "Missing compulsory field [username]"; }
+        if (array_key_exists("password", $attributes) && !$this->adldap->getUseSSL() && !$this->adldap->getUseTLS()) { 
+            throw new adLDAPException('SSL/TLS must be configured on your webserver and enabled in the class to set passwords.');
+        }
+
+        // Find the dn of the user
+        $userDn = $this->dn($username, $isGUID);
+        if ($userDn === false) { 
+            return false; 
+        }
+        
+        // Translate the update to the LDAP schema                
+        $mod = $this->adldap->adldap_schema($attributes);
+        
+        // Check to see if this is an enabled status update
+        if (!$mod && !array_key_exists("enabled", $attributes)){ 
+            return false; 
+        }
+        
+        // Set the account control attribute (only if specified)
+        if (array_key_exists("enabled", $attributes)){
+            if ($attributes["enabled"]){ 
+                $controlOptions = array("NORMAL_ACCOUNT"); 
+            }
+            else { 
+                $controlOptions = array("NORMAL_ACCOUNT", "ACCOUNTDISABLE"); 
+            }
+            $mod["userAccountControl"][0] = $this->accountControl($controlOptions);
+        }
+
+        // Do the update
+        $result = @ldap_modify($this->adldap->getLdapConnection(), $userDn, $mod);
+        if ($result == false) { 
+            return false; 
+        }
+        
+        return true;
+    }
+    
+    /**
+    * Disable a user account
+    * 
+    * @param string $username The username to disable
+    * @param bool $isGUID Is the username passed a GUID or a samAccountName
+    * @return bool
+    */
+    public function disable($username, $isGUID = false)
+    {
+        if ($username === NULL) { return "Missing compulsory field [username]"; }
+        $attributes = array("enabled" => 0);
+        $result = $this->modify($username, $attributes, $isGUID);
+        if ($result == false) { return false; }
+        
+        return true;
+    }
+    
+    /**
+    * Enable a user account
+    * 
+    * @param string $username The username to enable
+    * @param bool $isGUID Is the username passed a GUID or a samAccountName
+    * @return bool
+    */
+    public function enable($username, $isGUID = false)
+    {
+        if ($username === NULL) { return "Missing compulsory field [username]"; }
+        $attributes = array("enabled" => 1);
+        $result = $this->modify($username, $attributes, $isGUID);
+        if ($result == false) { return false; }
+        
+        return true;
+    }
+    
+    /**
+    * Set the password of a user - This must be performed over SSL
+    * 
+    * @param string $username The username to modify
+    * @param string $password The new password
+    * @param bool $isGUID Is the username passed a GUID or a samAccountName
+    * @return bool
+    */
+    public function password($username, $password, $isGUID = false)
+    {
+        if ($username === NULL) { return false; }
+        if ($password === NULL) { return false; }
+        if (!$this->adldap->getLdapBind()) { return false; }
+        if (!$this->adldap->getUseSSL() && !$this->adldap->getUseTLS()) { 
+            throw new adLDAPException('SSL must be configured on your webserver and enabled in the class to set passwords.');
+        }
+        
+        $userDn = $this->dn($username, $isGUID);
+        if ($userDn === false) { 
+            return false; 
+        }
+                
+        $add=array();
+        $add["unicodePwd"][0] = $this->encodePassword($password);
+        
+        $result = @ldap_mod_replace($this->adldap->getLdapConnection(), $userDn, $add);
+        if ($result === false){
+            $err = ldap_errno($this->adldap->getLdapConnection());
+            if ($err) {
+                $msg = 'Error ' . $err . ': ' . ldap_err2str($err) . '.';
+                if($err == 53) {
+                    $msg .= ' Your password might not match the password policy.';
+                }
+                throw new adLDAPException($msg);
+            }
+            else {
+                return false;
+            }
+        }
+        
+        return true;
+    }
+    
+    /**
+    * Encode a password for transmission over LDAP
+    *
+    * @param string $password The password to encode
+    * @return string
+    */
+    public function encodePassword($password)
+    {
+        $password="\"".$password."\"";
+        $encoded="";
+        for ($i=0; $i info($username, array("cn"), $isGUID);
+        if ($user[0]["dn"] === NULL) { 
+            return false; 
+        }
+        $userDn = $user[0]["dn"];
+        return $userDn;
+    }
+    
+    /**
+    * Return a list of all users in AD
+    * 
+    * @param bool $includeDescription Return a description of the user
+    * @param string $search Search parameter
+    * @param bool $sorted Sort the user accounts
+    * @return array
+    */
+    public function all($includeDescription = false, $search = "*", $sorted = true)
+    {
+        if (!$this->adldap->getLdapBind()) { return false; }
+        
+        // Perform the search and grab all their details
+        $filter = "(&(objectClass=user)(samaccounttype=" . adLDAP::ADLDAP_NORMAL_ACCOUNT .")(objectCategory=person)(cn=" . $search . "))";
+        $fields = array("samaccountname","displayname");
+        $sr = ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields);
+        $entries = ldap_get_entries($this->adldap->getLdapConnection(), $sr);
+
+        $usersArray = array();
+        for ($i=0; $i<$entries["count"]; $i++){
+            if ($includeDescription && strlen($entries[$i]["displayname"][0])>0){
+                $usersArray[$entries[$i]["samaccountname"][0]] = $entries[$i]["displayname"][0];
+            } elseif ($includeDescription){
+                $usersArray[$entries[$i]["samaccountname"][0]] = $entries[$i]["samaccountname"][0];
+            } else {
+                array_push($usersArray, $entries[$i]["samaccountname"][0]);
+            }
+        }
+        if ($sorted) { 
+            asort($usersArray); 
+        }
+        return $usersArray;
+    }
+    
+    /**
+    * Converts a username (samAccountName) to a GUID
+    * 
+    * @param string $username The username to query
+    * @return string
+    */
+    public function usernameToGuid($username) 
+    {
+        if (!$this->adldap->getLdapBind()){ return false; }
+        if ($username === null){ return "Missing compulsory field [username]"; }
+        
+        $filter = "samaccountname=" . $username; 
+        $fields = array("objectGUID"); 
+        $sr = @ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields); 
+        if (ldap_count_entries($this->adldap->getLdapConnection(), $sr) > 0) { 
+            $entry = @ldap_first_entry($this->adldap->getLdapConnection(), $sr); 
+            $guid = @ldap_get_values_len($this->adldap->getLdapConnection(), $entry, 'objectGUID'); 
+            $strGUID = $this->adldap->utilities()->binaryToText($guid[0]);          
+            return $strGUID; 
+        }
+        return false; 
+    }
+    
+    /**
+    * Return a list of all users in AD that have a specific value in a field
+    *
+    * @param bool $includeDescription Return a description of the user
+    * @param string $searchField Field to search search for
+    * @param string $searchFilter Value to search for in the specified field
+    * @param bool $sorted Sort the user accounts
+    * @return array
+    */
+    public function find($includeDescription = false, $searchField = false, $searchFilter = false, $sorted = true){
+        if (!$this->adldap->getLdapBind()){ return false; }
+          
+        // Perform the search and grab all their details
+        $searchParams = "";
+        if ($searchField) {
+            $searchParams = "(" . $searchField . "=" . $searchFilter . ")";
+        }                           
+        $filter = "(&(objectClass=user)(samaccounttype=" . adLDAP::ADLDAP_NORMAL_ACCOUNT .")(objectCategory=person)" . $searchParams . ")";
+        $fields = array("samaccountname","displayname");
+        $sr = ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields);
+        $entries = ldap_get_entries($this->adldap->getLdapConnection(), $sr);
+
+        $usersArray = array();
+        for ($i=0; $i < $entries["count"]; $i++) {
+            if ($includeDescription && strlen($entries[$i]["displayname"][0]) > 0) {
+                $usersArray[$entries[$i]["samaccountname"][0]] = $entries[$i]["displayname"][0];
+            }
+            else if ($includeDescription) {
+                $usersArray[$entries[$i]["samaccountname"][0]] = $entries[$i]["samaccountname"][0];
+            }
+            else {
+                array_push($usersArray, $entries[$i]["samaccountname"][0]);
+            }
+        }
+        if ($sorted){ 
+          asort($usersArray); 
+        }
+        return ($usersArray);
+    }
+    
+    /**
+    * Move a user account to a different OU
+    *
+    * @param string $username The username to move (please be careful here!)
+    * @param array $container The container or containers to move the user to (please be careful here!).
+    * accepts containers in 1. parent 2. child order
+    * @return array
+    */
+    public function move($username, $container) 
+    {
+        if (!$this->adldap->getLdapBind()) { return false; }
+        if ($username === null) { return "Missing compulsory field [username]"; }
+        if ($container === null) { return "Missing compulsory field [container]"; }
+        if (!is_array($container)) { return "Container must be an array"; }
+        
+        $userInfo = $this->info($username, array("*"));
+        $dn = $userInfo[0]['distinguishedname'][0];
+        $newRDn = "cn=" . $username;
+        $container = array_reverse($container);
+        $newContainer = "ou=" . implode(",ou=",$container);
+        $newBaseDn = strtolower($newContainer) . "," . $this->adldap->getBaseDn();
+        $result = @ldap_rename($this->adldap->getLdapConnection(), $dn, $newRDn, $newBaseDn, true);
+        if ($result !== true) {
+            return false;
+        }
+        return true;
+    }
+    
+    /**
+    * Get the last logon time of any user as a Unix timestamp
+    * 
+    * @param string $username
+    * @return long $unixTimestamp
+    */
+    public function getLastLogon($username) {
+        if (!$this->adldap->getLdapBind()) { return false; }
+        if ($username === null) { return "Missing compulsory field [username]"; }
+        $userInfo = $this->info($username, array("lastLogonTimestamp"));
+        $lastLogon = adLDAPUtils::convertWindowsTimeToUnixTime($userInfo[0]['lastLogonTimestamp'][0]);
+        return $lastLogon;
+    }
+    
+}
+?>
diff --git a/lib/plugins/authad/adLDAP/classes/adLDAPUtils.php b/lib/plugins/authad/adLDAP/classes/adLDAPUtils.php
new file mode 100644
index 000000000..f039a4290
--- /dev/null
+++ b/lib/plugins/authad/adLDAP/classes/adLDAPUtils.php
@@ -0,0 +1,264 @@
+adldap = $adldap;
+    }
+    
+    
+    /**
+    * Take an LDAP query and return the nice names, without all the LDAP prefixes (eg. CN, DN)
+    *
+    * @param array $groups
+    * @return array
+    */
+    public function niceNames($groups)
+    {
+
+        $groupArray = array();
+        for ($i=0; $i<$groups["count"]; $i++){ // For each group
+            $line = $groups[$i];
+            
+            if (strlen($line)>0) { 
+                // More presumptions, they're all prefixed with CN=
+                // so we ditch the first three characters and the group
+                // name goes up to the first comma
+                $bits=explode(",", $line);
+                $groupArray[] = substr($bits[0], 3, (strlen($bits[0])-3));
+            }
+        }
+        return $groupArray;    
+    }
+    
+    /**
+    * Escape characters for use in an ldap_create function
+    * 
+    * @param string $str
+    * @return string
+    */
+    public function escapeCharacters($str) {
+        $str = str_replace(",", "\,", $str);
+        return $str;
+    }
+    
+    /**
+    * Escape strings for the use in LDAP filters
+    * 
+    * DEVELOPERS SHOULD BE DOING PROPER FILTERING IF THEY'RE ACCEPTING USER INPUT
+    * Ported from Perl's Net::LDAP::Util escape_filter_value
+    *
+    * @param string $str The string the parse
+    * @author Port by Andreas Gohr 
+    * @return string
+    */
+    public function ldapSlashes($str){
+        return preg_replace('/([\x00-\x1F\*\(\)\\\\])/e',
+                            '"\\\\\".join("",unpack("H2","$1"))',
+                            $str);
+    }
+    
+    /**
+    * Converts a string GUID to a hexdecimal value so it can be queried
+    * 
+    * @param string $strGUID A string representation of a GUID
+    * @return string
+    */
+    public function strGuidToHex($strGUID) 
+    {
+        $strGUID = str_replace('-', '', $strGUID);
+
+        $octet_str = '\\' . substr($strGUID, 6, 2);
+        $octet_str .= '\\' . substr($strGUID, 4, 2);
+        $octet_str .= '\\' . substr($strGUID, 2, 2);
+        $octet_str .= '\\' . substr($strGUID, 0, 2);
+        $octet_str .= '\\' . substr($strGUID, 10, 2);
+        $octet_str .= '\\' . substr($strGUID, 8, 2);
+        $octet_str .= '\\' . substr($strGUID, 14, 2);
+        $octet_str .= '\\' . substr($strGUID, 12, 2);
+        //$octet_str .= '\\' . substr($strGUID, 16, strlen($strGUID));
+        for ($i=16; $i<=(strlen($strGUID)-2); $i++) {
+            if (($i % 2) == 0) {
+                $octet_str .= '\\' . substr($strGUID, $i, 2);
+            }
+        }
+        
+        return $octet_str;
+    }
+    
+    /**
+    * Convert a binary SID to a text SID
+    * 
+    * @param string $binsid A Binary SID
+    * @return string
+    */
+     public function getTextSID($binsid) {
+        $hex_sid = bin2hex($binsid);
+        $rev = hexdec(substr($hex_sid, 0, 2));
+        $subcount = hexdec(substr($hex_sid, 2, 2));
+        $auth = hexdec(substr($hex_sid, 4, 12));
+        $result = "$rev-$auth";
+
+        for ($x=0;$x < $subcount; $x++) {
+            $subauth[$x] =
+                hexdec($this->littleEndian(substr($hex_sid, 16 + ($x * 8), 8)));
+                $result .= "-" . $subauth[$x];
+        }
+
+        // Cheat by tacking on the S-
+        return 'S-' . $result;
+     }
+     
+    /**
+    * Converts a little-endian hex number to one that hexdec() can convert
+    * 
+    * @param string $hex A hex code
+    * @return string
+    */
+     public function littleEndian($hex) 
+     {
+        $result = '';
+        for ($x = strlen($hex) - 2; $x >= 0; $x = $x - 2) {
+            $result .= substr($hex, $x, 2);
+        }
+        return $result;
+     }
+     
+     /**
+    * Converts a binary attribute to a string
+    * 
+    * @param string $bin A binary LDAP attribute
+    * @return string
+    */
+    public function binaryToText($bin) 
+    {
+        $hex_guid = bin2hex($bin); 
+        $hex_guid_to_guid_str = ''; 
+        for($k = 1; $k <= 4; ++$k) { 
+            $hex_guid_to_guid_str .= substr($hex_guid, 8 - 2 * $k, 2); 
+        } 
+        $hex_guid_to_guid_str .= '-'; 
+        for($k = 1; $k <= 2; ++$k) { 
+            $hex_guid_to_guid_str .= substr($hex_guid, 12 - 2 * $k, 2); 
+        } 
+        $hex_guid_to_guid_str .= '-'; 
+        for($k = 1; $k <= 2; ++$k) { 
+            $hex_guid_to_guid_str .= substr($hex_guid, 16 - 2 * $k, 2); 
+        } 
+        $hex_guid_to_guid_str .= '-' . substr($hex_guid, 16, 4); 
+        $hex_guid_to_guid_str .= '-' . substr($hex_guid, 20); 
+        return strtoupper($hex_guid_to_guid_str);   
+    }
+    
+    /**
+    * Converts a binary GUID to a string GUID
+    * 
+    * @param string $binaryGuid The binary GUID attribute to convert
+    * @return string
+    */
+    public function decodeGuid($binaryGuid) 
+    {
+        if ($binaryGuid === null){ return "Missing compulsory field [binaryGuid]"; }
+        
+        $strGUID = $this->binaryToText($binaryGuid);          
+        return $strGUID; 
+    }
+    
+    /**
+    * Convert a boolean value to a string
+    * You should never need to call this yourself
+    *
+    * @param bool $bool Boolean value
+    * @return string
+    */
+    public function boolToStr($bool) 
+    {
+        return ($bool) ? 'TRUE' : 'FALSE';
+    }
+    
+    /**
+    * Convert 8bit characters e.g. accented characters to UTF8 encoded characters
+    */
+    public function encode8Bit(&$item, $key) {
+        $encode = false;
+        if (is_string($item)) {
+            for ($i=0; $i> 7) {
+                    $encode = true;
+                }
+            }
+        }
+        if ($encode === true && $key != 'password') {
+            $item = utf8_encode($item);   
+        }
+    }  
+    
+    /**
+    * Get the current class version number
+    * 
+    * @return string
+    */
+    public function getVersion() {
+        return self::ADLDAP_VERSION;
+    }
+    
+    /**
+    * Round a Windows timestamp down to seconds and remove the seconds between 1601-01-01 and 1970-01-01
+    * 
+    * @param long $windowsTime
+    * @return long $unixTime
+    */
+    public static function convertWindowsTimeToUnixTime($windowsTime) {
+      $unixTime = round($windowsTime / 10000000) - 11644477200; 
+      return $unixTime; 
+    }
+}
+
+?>
\ No newline at end of file
diff --git a/lib/plugins/authad/adLDAP/collections/adLDAPCollection.php b/lib/plugins/authad/adLDAP/collections/adLDAPCollection.php
new file mode 100644
index 000000000..c0a2eb2fa
--- /dev/null
+++ b/lib/plugins/authad/adLDAP/collections/adLDAPCollection.php
@@ -0,0 +1,137 @@
+setInfo($info);   
+        $this->adldap = $adldap;
+    }
+    
+    /**
+    * Set the raw info array from Active Directory
+    * 
+    * @param array $info
+    */
+    public function setInfo(array $info) 
+    {
+        if ($this->info && sizeof($info) >= 1) {
+            unset($this->info);
+        }
+        $this->info = $info;   
+    }
+    
+    /**
+    * Magic get method to retrieve data from the raw array in a formatted way
+    * 
+    * @param string $attribute
+    * @return mixed
+    */
+    public function __get($attribute)
+    {
+        if (isset($this->info[0]) && is_array($this->info[0])) {
+            foreach ($this->info[0] as $keyAttr => $valueAttr) {
+                if (strtolower($keyAttr) == strtolower($attribute)) {
+                    if ($this->info[0][strtolower($attribute)]['count'] == 1) {
+                        return $this->info[0][strtolower($attribute)][0];   
+                    }
+                    else {
+                        $array = array();
+                        foreach ($this->info[0][strtolower($attribute)] as $key => $value) {
+                            if ((string)$key != 'count') {
+                                $array[$key] = $value;
+                            } 
+                        }  
+                        return $array;   
+                    }
+                }   
+            }
+        }
+        else {
+            return NULL;   
+        }
+    }    
+    
+    /**
+    * Magic set method to update an attribute
+    * 
+    * @param string $attribute
+    * @param string $value
+    * @return bool
+    */
+    abstract public function __set($attribute, $value);
+    
+    /** 
+    * Magic isset method to check for the existence of an attribute 
+    * 
+    * @param string $attribute 
+    * @return bool 
+    */ 
+    public function __isset($attribute) {
+        if (isset($this->info[0]) && is_array($this->info[0])) { 
+            foreach ($this->info[0] as $keyAttr => $valueAttr) { 
+                if (strtolower($keyAttr) == strtolower($attribute)) { 
+                    return true; 
+                } 
+            } 
+        } 
+        return false; 
+     } 
+}
+?>
diff --git a/lib/plugins/authad/adLDAP/collections/adLDAPComputerCollection.php b/lib/plugins/authad/adLDAP/collections/adLDAPComputerCollection.php
new file mode 100644
index 000000000..4f11d8f41
--- /dev/null
+++ b/lib/plugins/authad/adLDAP/collections/adLDAPComputerCollection.php
@@ -0,0 +1,46 @@
+
diff --git a/lib/plugins/authad/adLDAP/collections/adLDAPContactCollection.php b/lib/plugins/authad/adLDAP/collections/adLDAPContactCollection.php
new file mode 100644
index 000000000..d42fe6d4c
--- /dev/null
+++ b/lib/plugins/authad/adLDAP/collections/adLDAPContactCollection.php
@@ -0,0 +1,46 @@
+
diff --git a/lib/plugins/authad/adLDAP/collections/adLDAPGroupCollection.php b/lib/plugins/authad/adLDAP/collections/adLDAPGroupCollection.php
new file mode 100644
index 000000000..cff12fc20
--- /dev/null
+++ b/lib/plugins/authad/adLDAP/collections/adLDAPGroupCollection.php
@@ -0,0 +1,46 @@
+
diff --git a/lib/plugins/authad/adLDAP/collections/adLDAPUserCollection.php b/lib/plugins/authad/adLDAP/collections/adLDAPUserCollection.php
new file mode 100644
index 000000000..801d90296
--- /dev/null
+++ b/lib/plugins/authad/adLDAP/collections/adLDAPUserCollection.php
@@ -0,0 +1,46 @@
+
diff --git a/lib/plugins/authad/auth.php b/lib/plugins/authad/auth.php
index e82610327..5c566195e 100644
--- a/lib/plugins/authad/auth.php
+++ b/lib/plugins/authad/auth.php
@@ -2,8 +2,6 @@
 // must be run within Dokuwiki
 if(!defined('DOKU_INC')) die();
 
-require_once(DOKU_INC.'inc/adLDAP.php');
-
 /**
  * Active Directory authentication backend for DokuWiki
  *
@@ -41,7 +39,7 @@ require_once(DOKU_INC.'inc/adLDAP.php');
  * @author  Jan Schumann 
  */
 
-require_once(DOKU_INC.'inc/adLDAP/adLDAP.php');
+require_once(DOKU_PLUGIN.'authad/adLDAP/adLDAP.php');
 
 class auth_plugin_authad extends DokuWiki_Auth_Plugin {
     /**
-- 
cgit v1.2.3


From 46b991a30bc4c7dab4e06bdd3f9a70a34204e005 Mon Sep 17 00:00:00 2001
From: Andreas Gohr 
Date: Fri, 9 Nov 2012 14:32:33 +0100
Subject: merge old auth style configs with plugin config

---
 inc/plugin.php       |  1 +
 lib/plugins/auth.php | 17 +++++++++++++++++
 2 files changed, 18 insertions(+)

diff --git a/inc/plugin.php b/inc/plugin.php
index d2fe3818d..0e17dc417 100644
--- a/inc/plugin.php
+++ b/inc/plugin.php
@@ -22,6 +22,7 @@ class DokuWiki_Plugin {
      *
      * Needs to return a associative array with the following values:
      *
+     * base   - the plugin's base name (eg. the directory it needs to be installed in)
      * author - Author of the plugin
      * email  - Email address to contact the author
      * date   - Last modified date of the plugin in YYYY-MM-DD format
diff --git a/lib/plugins/auth.php b/lib/plugins/auth.php
index cce2370d9..42dbf1859 100644
--- a/lib/plugins/auth.php
+++ b/lib/plugins/auth.php
@@ -419,4 +419,21 @@ class DokuWiki_Auth_Plugin extends DokuWiki_Plugin {
         global $conf;
         return ($_SESSION[DOKU_COOKIE]['auth']['time'] >= @filemtime($conf['cachedir'].'/sessionpurge'));
     }
+
+    /**
+     * Overrides the standard config loading to integrate old auth module style configs
+     *
+     * @deprecated 2012-11-09
+     */
+    public function loadConfig(){
+        global $conf;
+        $plugin = $this->getPluginName();
+
+        $default = $this->readDefaultSettings();
+        $oldconf = array();
+        if(isset($conf['auth'][$plugin])) $oldconf = (array) $conf['auth'][$plugin];
+
+        $conf['plugin'][$plugin] = array_merge($default, $oldconf, $conf['plugin'][$plugin]);
+        $this->configloaded = true;
+    }
 }
-- 
cgit v1.2.3


From 5d8f5686917e646cfee82985aa02c377edc97ddf Mon Sep 17 00:00:00 2001
From: Andreas Gohr 
Date: Fri, 9 Nov 2012 14:46:55 +0100
Subject: adjusted gitignore for auth plugins

---
 .gitignore | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/.gitignore b/.gitignore
index 1daf647bf..d05f82856 100644
--- a/.gitignore
+++ b/.gitignore
@@ -31,6 +31,10 @@
 !/lib/tpl/dokuwiki
 !/lib/tpl/index.php
 /lib/plugins/*
+!/lib/plugins/authad
+!/lib/plugins/authldap
+!/lib/plugins/authmysql
+!/lib/plugins/authpgsql
 !/lib/plugins/acl
 !/lib/plugins/config
 !/lib/plugins/info
-- 
cgit v1.2.3


From 32fd494aaeb28179d8823354e07c1399e7443c90 Mon Sep 17 00:00:00 2001
From: Andreas Gohr 
Date: Fri, 9 Nov 2012 14:54:48 +0100
Subject: authad fixes

* fixes incorrect $this->adldap calls
* makes use of correct plugin config
---
 lib/plugins/authad/auth.php        | 83 ++++++++++++++++++--------------------
 lib/plugins/authad/plugin.info.txt |  4 +-
 2 files changed, 42 insertions(+), 45 deletions(-)

diff --git a/lib/plugins/authad/auth.php b/lib/plugins/authad/auth.php
index 5c566195e..f651d87a1 100644
--- a/lib/plugins/authad/auth.php
+++ b/lib/plugins/authad/auth.php
@@ -2,6 +2,8 @@
 // must be run within Dokuwiki
 if(!defined('DOKU_INC')) die();
 
+require_once(DOKU_PLUGIN.'authad/adLDAP/adLDAP.php');
+
 /**
  * Active Directory authentication backend for DokuWiki
  *
@@ -13,20 +15,20 @@ if(!defined('DOKU_INC')) die();
  *
  *   $conf['authtype']       = 'authad';
  *
- *   $conf['auth']['ad']['account_suffix']     = '@my.domain.org';
- *   $conf['auth']['ad']['base_dn']            = 'DC=my,DC=domain,DC=org';
- *   $conf['auth']['ad']['domain_controllers'] = 'srv1.domain.org,srv2.domain.org';
+ *   $conf['plugin']['authad']['account_suffix']     = '@my.domain.org';
+ *   $conf['plugin']['authad']['base_dn']            = 'DC=my,DC=domain,DC=org';
+ *   $conf['plugin']['authad']['domain_controllers'] = 'srv1.domain.org,srv2.domain.org';
  *
  *   //optional:
- *   $conf['auth']['ad']['sso']                = 1;
- *   $conf['auth']['ad']['ad_username']        = 'root';
- *   $conf['auth']['ad']['ad_password']        = 'pass';
- *   $conf['auth']['ad']['real_primarygroup']  = 1;
- *   $conf['auth']['ad']['use_ssl']            = 1;
- *   $conf['auth']['ad']['use_tls']            = 1;
- *   $conf['auth']['ad']['debug']              = 1;
+ *   $conf['plugin']['authad']['sso']                = 1;
+ *   $conf['plugin']['authad']['ad_username']        = 'root';
+ *   $conf['plugin']['authad']['ad_password']        = 'pass';
+ *   $conf['plugin']['authad']['real_primarygroup']  = 1;
+ *   $conf['plugin']['authad']['use_ssl']            = 1;
+ *   $conf['plugin']['authad']['use_tls']            = 1;
+ *   $conf['plugin']['authad']['debug']              = 1;
  *   // warn user about expiring password this many days in advance:
- *   $conf['auth']['ad']['expirywarn']         = 5;
+ *   $conf['plugin']['authad']['expirywarn']         = 5;
  *
  *   // get additional information to the userinfo array
  *   // add a list of comma separated ldap contact fields.
@@ -38,18 +40,13 @@ if(!defined('DOKU_INC')) die();
  * @author  Andreas Gohr 
  * @author  Jan Schumann 
  */
-
-require_once(DOKU_PLUGIN.'authad/adLDAP/adLDAP.php');
-
 class auth_plugin_authad extends DokuWiki_Auth_Plugin {
-    /**
-     * @var array copy of the auth backend configuration
-     */
-    protected $cnf = array();
+
     /**
      * @var array hold connection data for a specific AD domain
      */
     protected $opts = array();
+
     /**
      * @var array open connections for each AD domain, as adLDAP objects
      */
@@ -76,18 +73,18 @@ class auth_plugin_authad extends DokuWiki_Auth_Plugin {
     public function __construct() {
         parent::__construct();
 
-        global $conf;
-        $this->cnf = $conf['auth']['ad'];
+        // we load the config early to modify it a bit here
+        $this->loadConfig();
 
         // additional information fields
-        if(isset($this->cnf['additional'])) {
-            $this->cnf['additional'] = str_replace(' ', '', $this->cnf['additional']);
-            $this->cnf['additional'] = explode(',', $this->cnf['additional']);
-        } else $this->cnf['additional'] = array();
+        if(isset($this->conf['additional'])) {
+            $this->conf['additional'] = str_replace(' ', '', $this->conf['additional']);
+            $this->conf['additional'] = explode(',', $this->conf['additional']);
+        } else $this->conf['additional'] = array();
 
         // ldap extension is needed
         if(!function_exists('ldap_connect')) {
-            if($this->cnf['debug'])
+            if($this->conf['debug'])
                 msg("AD Auth: PHP LDAP extension not found.", -1);
             $this->success = false;
             return;
@@ -97,7 +94,7 @@ class auth_plugin_authad extends DokuWiki_Auth_Plugin {
         if(!utf8_check($_SERVER['REMOTE_USER'])) {
             $_SERVER['REMOTE_USER'] = utf8_encode($_SERVER['REMOTE_USER']);
         }
-        if($_SERVER['REMOTE_USER'] && $this->cnf['sso']) {
+        if($_SERVER['REMOTE_USER'] && $this->conf['sso']) {
             $_SERVER['REMOTE_USER'] = $this->cleanUser($_SERVER['REMOTE_USER']);
 
             // we need to simulate a login
@@ -127,7 +124,7 @@ class auth_plugin_authad extends DokuWiki_Auth_Plugin {
     public function checkPass($user, $pass) {
         if($_SERVER['REMOTE_USER'] &&
             $_SERVER['REMOTE_USER'] == $user &&
-            $this->cnf['sso']
+            $this->conf['sso']
         ) return true;
 
         $adldap = $this->_adldap($this->_userDomain($user));
@@ -172,11 +169,11 @@ class auth_plugin_authad extends DokuWiki_Auth_Plugin {
         $fields = array('mail', 'displayname', 'samaccountname', 'lastpwd', 'pwdlastset', 'useraccountcontrol');
 
         // add additional fields to read
-        $fields = array_merge($fields, $this->cnf['additional']);
+        $fields = array_merge($fields, $this->conf['additional']);
         $fields = array_unique($fields);
 
         //get info for given user
-        $result = $this->adldap->user()->info($this->_userName($user), $fields);
+        $result = $adldap->user()->info($this->_userName($user), $fields);
         if($result == false){
             return array();
         }
@@ -192,14 +189,14 @@ class auth_plugin_authad extends DokuWiki_Auth_Plugin {
         $info['expires'] = !($result[0]['useraccountcontrol'][0] & 0x10000); //ADS_UF_DONT_EXPIRE_PASSWD
 
         // additional information
-        foreach($this->cnf['additional'] as $field) {
+        foreach($this->conf['additional'] as $field) {
             if(isset($result[0][strtolower($field)])) {
                 $info[$field] = $result[0][strtolower($field)][0];
             }
         }
 
         // handle ActiveDirectory memberOf
-        $info['grps'] = $this->adldap->user()->groups($this->_userName($user),(bool) $this->opts['recursive_groups']);
+        $info['grps'] = $adldap->user()->groups($this->_userName($user),(bool) $this->opts['recursive_groups']);
 
         if(is_array($info['grps'])) {
             foreach($info['grps'] as $ndx => $group) {
@@ -219,14 +216,14 @@ class auth_plugin_authad extends DokuWiki_Auth_Plugin {
         }
 
         // check expiry time
-        if($info['expires'] && $this->cnf['expirywarn']){
-            $timeleft = $this->adldap->user()->passwordExpiry($user); // returns unixtime
+        if($info['expires'] && $this->conf['expirywarn']){
+            $timeleft = $adldap->user()->passwordExpiry($user); // returns unixtime
             $timeleft = round($timeleft/(24*60*60));
             $info['expiresin'] = $timeleft;
 
             // if this is the current user, warn him (once per request only)
             if(($_SERVER['REMOTE_USER'] == $user) &&
-                ($timeleft <= $this->cnf['expirywarn']) &&
+                ($timeleft <= $this->conf['expirywarn']) &&
                 !$this->msgshown
             ) {
                 $msg = sprintf($lang['authpwdexpire'], $timeleft);
@@ -283,7 +280,7 @@ class auth_plugin_authad extends DokuWiki_Auth_Plugin {
         $user   = utf8_strtolower(trim($user));
 
         // is this a known, valid domain? if not discard
-        if(!is_array($this->cnf[$domain])) {
+        if(!is_array($this->conf[$domain])) {
             $domain = '';
         }
 
@@ -316,7 +313,7 @@ class auth_plugin_authad extends DokuWiki_Auth_Plugin {
 
         if($this->users === null) {
             //get info for given user
-            $result = $this->adldap->user()->all();
+            $result = $adldap->user()->all();
             if (!$result) return array();
             $this->users = array_fill_keys($result, false);
         }
@@ -356,9 +353,9 @@ class auth_plugin_authad extends DokuWiki_Auth_Plugin {
         // password changing
         if(isset($changes['pass'])) {
             try {
-                $return = $this->adldap->user()->password($this->_userName($user),$changes['pass']);
+                $return = $adldap->user()->password($this->_userName($user),$changes['pass']);
             } catch (adLDAPException $e) {
-                if ($this->cnf['debug']) msg('AD Auth: '.$e->getMessage(), -1);
+                if ($this->conf['debug']) msg('AD Auth: '.$e->getMessage(), -1);
                 $return = false;
             }
             if(!$return) msg('AD Auth: failed to change the password. Maybe the password policy was not met?', -1);
@@ -378,9 +375,9 @@ class auth_plugin_authad extends DokuWiki_Auth_Plugin {
         }
         if(count($adchanges)) {
             try {
-                $return = $return & $this->adldap->user()->modify($this->_userName($user),$adchanges);
+                $return = $return & $adldap->user()->modify($this->_userName($user),$adchanges);
             } catch (adLDAPException $e) {
-                if ($this->cnf['debug']) msg('AD Auth: '.$e->getMessage(), -1);
+                if ($this->conf['debug']) msg('AD Auth: '.$e->getMessage(), -1);
                 $return = false;
             }
         }
@@ -411,7 +408,7 @@ class auth_plugin_authad extends DokuWiki_Auth_Plugin {
             $this->adldap[$domain] = new adLDAP($this->opts);
             return $this->adldap[$domain];
         } catch(adLDAPException $e) {
-            if($this->cnf['debug']) {
+            if($this->conf['debug']) {
                 msg('AD Auth: '.$e->getMessage(), -1);
             }
             $this->success         = false;
@@ -450,12 +447,12 @@ class auth_plugin_authad extends DokuWiki_Auth_Plugin {
      */
     protected function _loadServerConfig($domain) {
         // prepare adLDAP standard configuration
-        $opts = $this->cnf;
+        $opts = $this->conf;
 
         $opts['domain'] = $domain;
 
         // add possible domain specific configuration
-        if($domain && is_array($this->cnf[$domain])) foreach($this->cnf[$domain] as $key => $val) {
+        if($domain && is_array($this->conf[$domain])) foreach($this->conf[$domain] as $key => $val) {
             $opts[$key] = $val;
         }
 
diff --git a/lib/plugins/authad/plugin.info.txt b/lib/plugins/authad/plugin.info.txt
index 598eb848b..f02b5118c 100644
--- a/lib/plugins/authad/plugin.info.txt
+++ b/lib/plugins/authad/plugin.info.txt
@@ -1,7 +1,7 @@
 base   authad
 author Andreas Gohr
 email  andi@splitbrain.org
-date   2012-10-06
-name   active directory auth plugin
+date   2012-11-09
+name   Active Directory auth plugin
 desc   Provides authentication against a Microsoft Active Directory
 url    http://www.dokuwiki.org/plugin:authad
-- 
cgit v1.2.3


From 70e4a085e6a861a12a7b927ba9dfa10d5961f958 Mon Sep 17 00:00:00 2001
From: Andreas Gohr 
Date: Fri, 9 Nov 2012 15:36:35 +0100
Subject: fixes for authldap

* makes proper use of plugin config
* adds a few first defaults, but the whole config metadata is still
  missing
* proper PHP5 use and comments
---
 lib/plugins/authldap/auth.php         | 389 +++++++++++++++++++---------------
 lib/plugins/authldap/conf/default.php |   7 +
 2 files changed, 224 insertions(+), 172 deletions(-)
 create mode 100644 lib/plugins/authldap/conf/default.php

diff --git a/lib/plugins/authldap/auth.php b/lib/plugins/authldap/auth.php
index 93683bc16..6e7bde1f0 100644
--- a/lib/plugins/authldap/auth.php
+++ b/lib/plugins/authldap/auth.php
@@ -11,31 +11,31 @@ if(!defined('DOKU_INC')) die();
  * @author    Jan Schumann 
  */
 class auth_plugin_authldap extends DokuWiki_Auth_Plugin {
-    var $cnf = null;
-    var $con = null;
-    var $bound = 0; // 0: anonymous, 1: user, 2: superuser
+    /* @var resource $con holds the LDAP connection*/
+    protected $con = null;
+
+    /* @var int $bound What type of connection does already exist? */
+    protected $bound = 0; // 0: anonymous, 1: user, 2: superuser
+
+    /* @var array $users User data cache */
+    protected $users = null;
+
+    /* @var array $_pattern User filter pattern */
+    protected $_pattern = null;
 
     /**
      * Constructor
      */
-    function __construct(){
+    public function __construct() {
         parent::__construct();
 
-        global $conf;
-        $this->cnf = $conf['auth']['ldap'];
-
         // ldap extension is needed
         if(!function_exists('ldap_connect')) {
-            if ($this->cnf['debug'])
-                msg("LDAP err: PHP LDAP extension not found.",-1,__LINE__,__FILE__);
+            $this->_debug("LDAP err: PHP LDAP extension not found.", -1, __LINE__, __FILE__);
             $this->success = false;
             return;
         }
 
-        if(empty($this->cnf['groupkey']))   $this->cnf['groupkey']   = 'cn';
-        if(empty($this->cnf['userscope']))  $this->cnf['userscope']  = 'sub';
-        if(empty($this->cnf['groupscope'])) $this->cnf['groupscope'] = 'sub';
-
         // auth_ldap currently just handles authentication, so no
         // capabilities are set
     }
@@ -48,40 +48,45 @@ class auth_plugin_authldap extends DokuWiki_Auth_Plugin {
      * to the LDAP server
      *
      * @author  Andreas Gohr 
+     * @param string $user
+     * @param string $pass
      * @return  bool
      */
-    function checkPass($user,$pass){
+    public function checkPass($user, $pass) {
         // reject empty password
         if(empty($pass)) return false;
         if(!$this->_openLDAP()) return false;
 
         // indirect user bind
-        if($this->cnf['binddn'] && $this->cnf['bindpw']){
+        if($this->getConf('binddn') && $this->getConf('bindpw')) {
             // use superuser credentials
-            if(!@ldap_bind($this->con,$this->cnf['binddn'],$this->cnf['bindpw'])){
-                if($this->cnf['debug'])
-                    msg('LDAP bind as superuser: '.htmlspecialchars(ldap_error($this->con)),0,__LINE__,__FILE__);
+            if(!@ldap_bind($this->con, $this->getConf('binddn'), $this->getConf('bindpw'))) {
+                $this->_debug('LDAP bind as superuser: '.htmlspecialchars(ldap_error($this->con)), 0, __LINE__, __FILE__);
                 return false;
             }
             $this->bound = 2;
-        }else if($this->cnf['binddn'] &&
-                 $this->cnf['usertree'] &&
-                 $this->cnf['userfilter']) {
+        } else if($this->getConf('binddn') &&
+            $this->getConf('usertree') &&
+            $this->getConf('userfilter')
+        ) {
             // special bind string
-            $dn = $this->_makeFilter($this->cnf['binddn'],
-                                     array('user'=>$user,'server'=>$this->cnf['server']));
+            $dn = $this->_makeFilter(
+                $this->getConf('binddn'),
+                array('user'=> $user, 'server'=> $this->getConf('server'))
+            );
 
-        }else if(strpos($this->cnf['usertree'], '%{user}')) {
+        } else if(strpos($this->getConf('usertree'), '%{user}')) {
             // direct user bind
-            $dn = $this->_makeFilter($this->cnf['usertree'],
-                                     array('user'=>$user,'server'=>$this->cnf['server']));
+            $dn = $this->_makeFilter(
+                $this->getConf('usertree'),
+                array('user'=> $user, 'server'=> $this->getConf('server'))
+            );
 
-        }else{
+        } else {
             // Anonymous bind
-            if(!@ldap_bind($this->con)){
-                msg("LDAP: can not bind anonymously",-1);
-                if($this->cnf['debug'])
-                    msg('LDAP anonymous bind: '.htmlspecialchars(ldap_error($this->con)),0,__LINE__,__FILE__);
+            if(!@ldap_bind($this->con)) {
+                msg("LDAP: can not bind anonymously", -1);
+                $this->_debug('LDAP anonymous bind: '.htmlspecialchars(ldap_error($this->con)), 0, __LINE__, __FILE__);
                 return false;
             }
         }
@@ -89,18 +94,16 @@ class auth_plugin_authldap extends DokuWiki_Auth_Plugin {
         // Try to bind to with the dn if we have one.
         if(!empty($dn)) {
             // User/Password bind
-            if(!@ldap_bind($this->con,$dn,$pass)){
-                if($this->cnf['debug']){
-                    msg("LDAP: bind with $dn failed", -1,__LINE__,__FILE__);
-                    msg('LDAP user dn bind: '.htmlspecialchars(ldap_error($this->con)),0);
-                }
+            if(!@ldap_bind($this->con, $dn, $pass)) {
+                $this->_debug("LDAP: bind with $dn failed", -1, __LINE__, __FILE__);
+                $this->_debug('LDAP user dn bind: '.htmlspecialchars(ldap_error($this->con)), 0, __LINE__, __FILE__);
                 return false;
             }
             $this->bound = 1;
             return true;
-        }else{
+        } else {
             // See if we can find the user
-            $info = $this->getUserData($user,true);
+            $info = $this->getUserData($user, true);
             if(empty($info['dn'])) {
                 return false;
             } else {
@@ -108,18 +111,14 @@ class auth_plugin_authldap extends DokuWiki_Auth_Plugin {
             }
 
             // Try to bind with the dn provided
-            if(!@ldap_bind($this->con,$dn,$pass)){
-                if($this->cnf['debug']){
-                    msg("LDAP: bind with $dn failed", -1,__LINE__,__FILE__);
-                    msg('LDAP user bind: '.htmlspecialchars(ldap_error($this->con)),0);
-                }
+            if(!@ldap_bind($this->con, $dn, $pass)) {
+                $this->_debug("LDAP: bind with $dn failed", -1, __LINE__, __FILE__);
+                $this->_debug('LDAP user bind: '.htmlspecialchars(ldap_error($this->con)), 0, __LINE__, __FILE__);
                 return false;
             }
             $this->bound = 1;
             return true;
         }
-
-        return false;
     }
 
     /**
@@ -144,52 +143,52 @@ class auth_plugin_authldap extends DokuWiki_Auth_Plugin {
      * @author  Dan Allen 
      * @author  
      * @author  Stephane Chazelas 
+     *
+     * @param   string $user
+     * @param   bool   $inbind authldap specific, true if in bind phase
      * @return  array containing user data or false
      */
-    function getUserData($user,$inbind=false) {
+    public function getUserData($user, $inbind = false) {
         global $conf;
         if(!$this->_openLDAP()) return false;
 
         // force superuser bind if wanted and not bound as superuser yet
-        if($this->cnf['binddn'] && $this->cnf['bindpw'] && $this->bound < 2){
+        if($this->getConf('binddn') && $this->getConf('bindpw') && $this->bound < 2) {
             // use superuser credentials
-            if(!@ldap_bind($this->con,$this->cnf['binddn'],$this->cnf['bindpw'])){
-                if($this->cnf['debug'])
-                    msg('LDAP bind as superuser: '.htmlspecialchars(ldap_error($this->con)),0,__LINE__,__FILE__);
+            if(!@ldap_bind($this->con, $this->getConf('binddn'), $this->getConf('bindpw'))) {
+                $this->_debug('LDAP bind as superuser: '.htmlspecialchars(ldap_error($this->con)), 0, __LINE__, __FILE__);
                 return false;
             }
             $this->bound = 2;
-        }elseif($this->bound == 0 && !$inbind) {
+        } elseif($this->bound == 0 && !$inbind) {
             // in some cases getUserData is called outside the authentication workflow
             // eg. for sending email notification on subscribed pages. This data might not
             // be accessible anonymously, so we try to rebind the current user here
-            list($loginuser,$loginsticky,$loginpass) = auth_getCookie();
-            if($loginuser && $loginpass){
+            list($loginuser, $loginsticky, $loginpass) = auth_getCookie();
+            if($loginuser && $loginpass) {
                 $loginpass = PMA_blowfish_decrypt($loginpass, auth_cookiesalt(!$loginsticky));
                 $this->checkPass($loginuser, $loginpass);
             }
         }
 
         $info['user']   = $user;
-        $info['server'] = $this->cnf['server'];
+        $info['server'] = $this->getConf('server');
 
         //get info for given user
-        $base = $this->_makeFilter($this->cnf['usertree'], $info);
-        if(!empty($this->cnf['userfilter'])) {
-            $filter = $this->_makeFilter($this->cnf['userfilter'], $info);
+        $base = $this->_makeFilter($this->getConf('usertree'), $info);
+        if($this->getConf('userfilter')) {
+            $filter = $this->_makeFilter($this->getConf('userfilter'), $info);
         } else {
             $filter = "(ObjectClass=*)";
         }
 
-        $sr     = $this->_ldapsearch($this->con, $base, $filter, $this->cnf['userscope']);
+        $sr     = $this->_ldapsearch($this->con, $base, $filter, $this->getConf('userscope'));
         $result = @ldap_get_entries($this->con, $sr);
-        if($this->cnf['debug']){
-            msg('LDAP user search: '.htmlspecialchars(ldap_error($this->con)),0,__LINE__,__FILE__);
-            msg('LDAP search at: '.htmlspecialchars($base.' '.$filter),0,__LINE__,__FILE__);
-        }
+        $this->_debug('LDAP user search: '.htmlspecialchars(ldap_error($this->con)), 0, __LINE__, __FILE__);
+        $this->_debug('LDAP search at: '.htmlspecialchars($base.' '.$filter), 0, __LINE__, __FILE__);
 
         // Don't accept more or less than one response
-        if(!is_array($result) || $result['count'] != 1){
+        if(!is_array($result) || $result['count'] != 1) {
             return false; //user not found
         }
 
@@ -204,13 +203,13 @@ class auth_plugin_authldap extends DokuWiki_Auth_Plugin {
         $info['grps'] = array();
 
         // overwrite if other attribs are specified.
-        if(is_array($this->cnf['mapping'])){
-            foreach($this->cnf['mapping'] as $localkey => $key) {
+        if(is_array($this->getConf('mapping'))) {
+            foreach($this->getConf('mapping') as $localkey => $key) {
                 if(is_array($key)) {
                     // use regexp to clean up user_result
                     list($key, $regexp) = each($key);
-                    if($user_result[$key]) foreach($user_result[$key] as $grp){
-                        if (preg_match($regexp,$grp,$match)) {
+                    if($user_result[$key]) foreach($user_result[$key] as $grp) {
+                        if(preg_match($regexp, $grp, $match)) {
                             if($localkey == 'grps') {
                                 $info[$localkey][] = $match[1];
                             } else {
@@ -223,35 +222,33 @@ class auth_plugin_authldap extends DokuWiki_Auth_Plugin {
                 }
             }
         }
-        $user_result = array_merge($info,$user_result);
+        $user_result = array_merge($info, $user_result);
 
         //get groups for given user if grouptree is given
-        if ($this->cnf['grouptree'] || $this->cnf['groupfilter']) {
-            $base   = $this->_makeFilter($this->cnf['grouptree'], $user_result);
-            $filter = $this->_makeFilter($this->cnf['groupfilter'], $user_result);
-            $sr = $this->_ldapsearch($this->con, $base, $filter, $this->cnf['groupscope'], array($this->cnf['groupkey']));
-            if($this->cnf['debug']){
-                msg('LDAP group search: '.htmlspecialchars(ldap_error($this->con)),0,__LINE__,__FILE__);
-                msg('LDAP search at: '.htmlspecialchars($base.' '.$filter),0,__LINE__,__FILE__);
-            }
-            if(!$sr){
-                msg("LDAP: Reading group memberships failed",-1);
+        if($this->getConf('grouptree') || $this->getConf('groupfilter')) {
+            $base   = $this->_makeFilter($this->getConf('grouptree'), $user_result);
+            $filter = $this->_makeFilter($this->getConf('groupfilter'), $user_result);
+            $sr     = $this->_ldapsearch($this->con, $base, $filter, $this->getConf('groupscope'), array($this->getConf('groupkey')));
+            $this->_debug('LDAP group search: '.htmlspecialchars(ldap_error($this->con)), 0, __LINE__, __FILE__);
+            $this->_debug('LDAP search at: '.htmlspecialchars($base.' '.$filter), 0, __LINE__, __FILE__);
+
+            if(!$sr) {
+                msg("LDAP: Reading group memberships failed", -1);
                 return false;
             }
             $result = ldap_get_entries($this->con, $sr);
             ldap_free_result($sr);
 
-            if(is_array($result)) foreach($result as $grp){
-                if(!empty($grp[$this->cnf['groupkey']][0])){
-                    if($this->cnf['debug'])
-                        msg('LDAP usergroup: '.htmlspecialchars($grp[$this->cnf['groupkey']][0]),0,__LINE__,__FILE__);
-                    $info['grps'][] = $grp[$this->cnf['groupkey']][0];
+            if(is_array($result)) foreach($result as $grp) {
+                if(!empty($grp[$this->getConf('groupkey')][0])) {
+                    $this->_debug('LDAP usergroup: '.htmlspecialchars($grp[$this->getConf('groupkey')][0]), 0, __LINE__, __FILE__);
+                    $info['grps'][] = $grp[$this->getConf('groupkey')][0];
                 }
             }
         }
 
         // always add the default group to the list of groups
-        if(!in_array($conf['defaultgroup'],$info['grps'])){
+        if(!in_array($conf['defaultgroup'], $info['grps'])) {
             $info['grps'][] = $conf['defaultgroup'];
         }
         return $info;
@@ -259,8 +256,10 @@ class auth_plugin_authldap extends DokuWiki_Auth_Plugin {
 
     /**
      * Most values in LDAP are case-insensitive
+     *
+     * @return bool
      */
-    function isCaseSensitive(){
+    public function isCaseSensitive() {
         return false;
     }
 
@@ -268,47 +267,47 @@ class auth_plugin_authldap extends DokuWiki_Auth_Plugin {
      * Bulk retrieval of user data
      *
      * @author  Dominik Eckelmann 
-     * @param   start     index of first user to be returned
-     * @param   limit     max number of users to be returned
-     * @param   filter    array of field/pattern pairs, null for no filter
+     * @param   int   $start     index of first user to be returned
+     * @param   int   $limit     max number of users to be returned
+     * @param   array $filter  array of field/pattern pairs, null for no filter
      * @return  array of userinfo (refer getUserData for internal userinfo details)
      */
-    function retrieveUsers($start=0,$limit=-1,$filter=array()) {
+    function retrieveUsers($start = 0, $limit = -1, $filter = array()) {
         if(!$this->_openLDAP()) return false;
 
-        if (!isset($this->users)) {
+        if(is_null($this->users)) {
             // Perform the search and grab all their details
-            if(!empty($this->cnf['userfilter'])) {
-                $all_filter = str_replace('%{user}', '*', $this->cnf['userfilter']);
+            if($this->getConf('userfilter')) {
+                $all_filter = str_replace('%{user}', '*', $this->getConf('userfilter'));
             } else {
                 $all_filter = "(ObjectClass=*)";
             }
-            $sr=ldap_search($this->con,$this->cnf['usertree'],$all_filter);
-            $entries = ldap_get_entries($this->con, $sr);
+            $sr          = ldap_search($this->con, $this->getConf('usertree'), $all_filter);
+            $entries     = ldap_get_entries($this->con, $sr);
             $users_array = array();
-            for ($i=0; $i<$entries["count"]; $i++){
+            for($i = 0; $i < $entries["count"]; $i++) {
                 array_push($users_array, $entries[$i]["uid"][0]);
             }
             asort($users_array);
             $result = $users_array;
-            if (!$result) return array();
+            if(!$result) return array();
             $this->users = array_fill_keys($result, false);
         }
-        $i = 0;
+        $i     = 0;
         $count = 0;
         $this->_constructPattern($filter);
         $result = array();
 
-        foreach ($this->users as $user => &$info) {
-            if ($i++ < $start) {
+        foreach($this->users as $user => &$info) {
+            if($i++ < $start) {
                 continue;
             }
-            if ($info === false) {
+            if($info === false) {
                 $info = $this->getUserData($user);
             }
-            if ($this->_filter($user, $info)) {
+            if($this->_filter($user, $info)) {
                 $result[$user] = $info;
-                if (($limit >= 0) && (++$count >= $limit)) break;
+                if(($limit >= 0) && (++$count >= $limit)) break;
             }
         }
         return $result;
@@ -320,50 +319,61 @@ class auth_plugin_authldap extends DokuWiki_Auth_Plugin {
      * Used by auth_getUserData to make the filter
      * strings for grouptree and groupfilter
      *
-     * filter      string  ldap search filter with placeholders
-     * placeholders array   array with the placeholders
-     *
      * @author  Troels Liebe Bentsen 
+     * @param   string $filter ldap search filter with placeholders
+     * @param   array  $placeholders placeholders to fill in
      * @return  string
      */
-    function _makeFilter($filter, $placeholders) {
+    protected function _makeFilter($filter, $placeholders) {
         preg_match_all("/%{([^}]+)/", $filter, $matches, PREG_PATTERN_ORDER);
         //replace each match
-        foreach ($matches[1] as $match) {
+        foreach($matches[1] as $match) {
             //take first element if array
             if(is_array($placeholders[$match])) {
                 $value = $placeholders[$match][0];
             } else {
                 $value = $placeholders[$match];
             }
-            $value = $this->_filterEscape($value);
+            $value  = $this->_filterEscape($value);
             $filter = str_replace('%{'.$match.'}', $value, $filter);
         }
         return $filter;
     }
 
     /**
-     * return 1 if $user + $info match $filter criteria, 0 otherwise
+     * return true if $user + $info match $filter criteria, false otherwise
+     *
+     * @author Chris Smith 
      *
-     * @author   Chris Smith 
+     * @param  string $user the user's login name
+     * @param  array  $info the user's userinfo array
+     * @return bool
      */
-    function _filter($user, $info) {
-        foreach ($this->_pattern as $item => $pattern) {
-            if ($item == 'user') {
-                if (!preg_match($pattern, $user)) return 0;
-            } else if ($item == 'grps') {
-                if (!count(preg_grep($pattern, $info['grps']))) return 0;
+    protected  function _filter($user, $info) {
+        foreach($this->_pattern as $item => $pattern) {
+            if($item == 'user') {
+                if(!preg_match($pattern, $user)) return false;
+            } else if($item == 'grps') {
+                if(!count(preg_grep($pattern, $info['grps']))) return false;
             } else {
-                if (!preg_match($pattern, $info[$item])) return 0;
+                if(!preg_match($pattern, $info[$item])) return false;
             }
         }
-        return 1;
+        return true;
     }
 
-    function _constructPattern($filter) {
+    /**
+     * Set the filter pattern
+     *
+     * @author Chris Smith 
+     *
+     * @param $filter
+     * @return void
+     */
+    protected function _constructPattern($filter) {
         $this->_pattern = array();
-        foreach ($filter as $item => $pattern) {
-            $this->_pattern[$item] = '/'.str_replace('/','\/',$pattern).'/i';    // allow regex characters
+        foreach($filter as $item => $pattern) {
+            $this->_pattern[$item] = '/'.str_replace('/', '\/', $pattern).'/i'; // allow regex characters
         }
     }
 
@@ -373,11 +383,15 @@ class auth_plugin_authldap extends DokuWiki_Auth_Plugin {
      * Ported from Perl's Net::LDAP::Util escape_filter_value
      *
      * @author Andreas Gohr
+     * @param  string $string
+     * @return string
      */
-    function _filterEscape($string){
-        return preg_replace('/([\x00-\x1F\*\(\)\\\\])/e',
-                            '"\\\\\".join("",unpack("H2","$1"))',
-                            $string);
+    protected function _filterEscape($string) {
+        return preg_replace(
+            '/([\x00-\x1F\*\(\)\\\\])/e',
+            '"\\\\\".join("",unpack("H2","$1"))',
+            $string
+        );
     }
 
     /**
@@ -386,18 +400,18 @@ class auth_plugin_authldap extends DokuWiki_Auth_Plugin {
      *
      * @author  Andreas Gohr 
      */
-    function _openLDAP(){
+    protected function _openLDAP() {
         if($this->con) return true; // connection already established
 
         $this->bound = 0;
 
-        $port = ($this->cnf['port']) ? $this->cnf['port'] : 389;
-        $bound = false;
-        $servers = explode(',', $this->cnf['server']);
-        foreach ($servers as $server) {
-            $server = trim($server);
+        $port    = $this->getConf('port');
+        $bound   = false;
+        $servers = explode(',', $this->getConf('server'));
+        foreach($servers as $server) {
+            $server    = trim($server);
             $this->con = @ldap_connect($server, $port);
-            if (!$this->con) {
+            if(!$this->con) {
                 continue;
             }
 
@@ -410,80 +424,111 @@ class auth_plugin_authldap extends DokuWiki_Auth_Plugin {
              */
 
             //set protocol version and dependend options
-            if($this->cnf['version']){
-                if(!@ldap_set_option($this->con, LDAP_OPT_PROTOCOL_VERSION,
-                                     $this->cnf['version'])){
-                    msg('Setting LDAP Protocol version '.$this->cnf['version'].' failed',-1);
-                    if($this->cnf['debug'])
-                        msg('LDAP version set: '.htmlspecialchars(ldap_error($this->con)),0,__LINE__,__FILE__);
-                }else{
+            if($this->getConf('version')) {
+                if(!@ldap_set_option(
+                    $this->con, LDAP_OPT_PROTOCOL_VERSION,
+                    $this->getConf('version')
+                )
+                ) {
+                    msg('Setting LDAP Protocol version '.$this->getConf('version').' failed', -1);
+                    $this->_debug('LDAP version set: '.htmlspecialchars(ldap_error($this->con)), 0, __LINE__, __FILE__);
+                } else {
                     //use TLS (needs version 3)
-                    if($this->cnf['starttls']) {
-                        if (!@ldap_start_tls($this->con)){
-                            msg('Starting TLS failed',-1);
-                            if($this->cnf['debug'])
-                                msg('LDAP TLS set: '.htmlspecialchars(ldap_error($this->con)),0,__LINE__,__FILE__);
+                    if($this->getConf('starttls')) {
+                        if(!@ldap_start_tls($this->con)) {
+                            msg('Starting TLS failed', -1);
+                            $this->_debug('LDAP TLS set: '.htmlspecialchars(ldap_error($this->con)), 0, __LINE__, __FILE__);
                         }
                     }
                     // needs version 3
-                    if(isset($this->cnf['referrals'])) {
-                        if(!@ldap_set_option($this->con, LDAP_OPT_REFERRALS,
-                           $this->cnf['referrals'])){
-                            msg('Setting LDAP referrals to off failed',-1);
-                            if($this->cnf['debug'])
-                                msg('LDAP referal set: '.htmlspecialchars(ldap_error($this->con)),0,__LINE__,__FILE__);
+                    if($this->getConf('referrals')) {
+                        if(!@ldap_set_option(
+                            $this->con, LDAP_OPT_REFERRALS,
+                            $this->getConf('referrals')
+                        )
+                        ) {
+                            msg('Setting LDAP referrals to off failed', -1);
+                            $this->_debug('LDAP referal set: '.htmlspecialchars(ldap_error($this->con)), 0, __LINE__, __FILE__);
                         }
                     }
                 }
             }
 
             //set deref mode
-            if($this->cnf['deref']){
-                if(!@ldap_set_option($this->con, LDAP_OPT_DEREF, $this->cnf['deref'])){
-                    msg('Setting LDAP Deref mode '.$this->cnf['deref'].' failed',-1);
-                    if($this->cnf['debug'])
-                        msg('LDAP deref set: '.htmlspecialchars(ldap_error($this->con)),0,__LINE__,__FILE__);
+            if($this->getConf('deref')) {
+                if(!@ldap_set_option($this->con, LDAP_OPT_DEREF, $this->getConf('deref'))) {
+                    msg('Setting LDAP Deref mode '.$this->getConf('deref').' failed', -1);
+                    $this->_debug('LDAP deref set: '.htmlspecialchars(ldap_error($this->con)), 0, __LINE__, __FILE__);
                 }
             }
             /* As of PHP 5.3.0 we can set timeout to speedup skipping of invalid servers */
-            if (defined('LDAP_OPT_NETWORK_TIMEOUT')) {
+            if(defined('LDAP_OPT_NETWORK_TIMEOUT')) {
                 ldap_set_option($this->con, LDAP_OPT_NETWORK_TIMEOUT, 1);
             }
             $bound = @ldap_bind($this->con);
-            if ($bound) {
+            if($bound) {
                 break;
             }
         }
 
         if(!$bound) {
-            msg("LDAP: couldn't connect to LDAP server",-1);
+            msg("LDAP: couldn't connect to LDAP server", -1);
             return false;
         }
 
-
-        $this->canDo['getUsers'] = true;
+        $this->cando['getUsers'] = true;
         return true;
     }
 
     /**
      * Wraps around ldap_search, ldap_list or ldap_read depending on $scope
      *
-     * @param  $scope string - can be 'base', 'one' or 'sub'
      * @author Andreas Gohr 
+     * @param resource $link_identifier
+     * @param string   $base_dn
+     * @param string   $filter
+     * @param string   $scope can be 'base', 'one' or 'sub'
+     * @param null     $attributes
+     * @param int      $attrsonly
+     * @param int      $sizelimit
+     * @param int      $timelimit
+     * @param int      $deref
+     * @return resource
      */
-    function _ldapsearch($link_identifier, $base_dn, $filter, $scope='sub', $attributes=null,
-                         $attrsonly=0, $sizelimit=0, $timelimit=0, $deref=LDAP_DEREF_NEVER){
+    protected function _ldapsearch($link_identifier, $base_dn, $filter, $scope = 'sub', $attributes = null,
+                         $attrsonly = 0, $sizelimit = 0, $timelimit = 0, $deref = LDAP_DEREF_NEVER) {
         if(is_null($attributes)) $attributes = array();
 
-        if($scope == 'base'){
-            return @ldap_read($link_identifier, $base_dn, $filter, $attributes,
-                             $attrsonly, $sizelimit, $timelimit, $deref);
-        }elseif($scope == 'one'){
-            return @ldap_list($link_identifier, $base_dn, $filter, $attributes,
-                             $attrsonly, $sizelimit, $timelimit, $deref);
-        }else{
-            return @ldap_search($link_identifier, $base_dn, $filter, $attributes,
-                                $attrsonly, $sizelimit, $timelimit, $deref);
+        if($scope == 'base') {
+            return @ldap_read(
+                $link_identifier, $base_dn, $filter, $attributes,
+                $attrsonly, $sizelimit, $timelimit, $deref
+            );
+        } elseif($scope == 'one') {
+            return @ldap_list(
+                $link_identifier, $base_dn, $filter, $attributes,
+                $attrsonly, $sizelimit, $timelimit, $deref
+            );
+        } else {
+            return @ldap_search(
+                $link_identifier, $base_dn, $filter, $attributes,
+                $attrsonly, $sizelimit, $timelimit, $deref
+            );
         }
     }
+
+    /**
+     * Wrapper around msg() but outputs only when debug is enabled
+     *
+     * @param string $message
+     * @param int    $err
+     * @param int    $line
+     * @param string $file
+     * @return void
+     */
+    protected function _debug($message, $err, $line, $file) {
+        if(!$this->getConf('debug')) return;
+        msg($message, $err, $line, $file);
+    }
+
 }
diff --git a/lib/plugins/authldap/conf/default.php b/lib/plugins/authldap/conf/default.php
new file mode 100644
index 000000000..35971d41d
--- /dev/null
+++ b/lib/plugins/authldap/conf/default.php
@@ -0,0 +1,7 @@
+
Date: Fri, 9 Nov 2012 16:31:57 +0100
Subject: authmysql fixes

* use proper plugin config
* code/PHP5 cleanup
---
 inc/plugin.php                         |  12 +-
 lib/plugins/authmysql/auth.php         | 732 +++++++++++++++++----------------
 lib/plugins/authmysql/conf/default.php |   3 +
 3 files changed, 385 insertions(+), 362 deletions(-)
 create mode 100644 lib/plugins/authmysql/conf/default.php

diff --git a/inc/plugin.php b/inc/plugin.php
index 0e17dc417..2b4111fe1 100644
--- a/inc/plugin.php
+++ b/inc/plugin.php
@@ -134,12 +134,20 @@ class DokuWiki_Plugin {
      * getConf($setting)
      *
      * use this function to access plugin configuration variables
+     *
+     * @param string $setting the setting to access
+     * @param mixed  $notset  what to return if the setting is not available
+     * @return mixed
      */
-    function getConf($setting){
+    function getConf($setting, $notset=false){
 
         if (!$this->configloaded){ $this->loadConfig(); }
 
-        return $this->conf[$setting];
+        if(isset($this->conf[$setting])){
+            return $this->conf[$setting];
+        }else{
+            return $notset;
+        }
     }
 
     /**
diff --git a/lib/plugins/authmysql/auth.php b/lib/plugins/authmysql/auth.php
index 368bd74a2..7d303726b 100644
--- a/lib/plugins/authmysql/auth.php
+++ b/lib/plugins/authmysql/auth.php
@@ -3,7 +3,7 @@
 if(!defined('DOKU_INC')) die();
 
 /**
- * MySQLP authentication backend
+ * MySQL authentication backend
  *
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
  * @author     Andreas Gohr 
@@ -12,12 +12,14 @@ if(!defined('DOKU_INC')) die();
  * @author     Jan Schumann 
  */
 class auth_plugin_authmysql extends DokuWiki_Auth_Plugin {
-    var $dbcon        = 0;
-    var $dbver        = 0;    // database version
-    var $dbrev        = 0;    // database revision
-    var $dbsub        = 0;    // database subrevision
-    var $cnf          = null;
-    var $defaultgroup = "";
+    /** @var resource holds the database connection */
+    protected $dbcon = 0;
+    /** @var int database version*/
+    protected $dbver = 0;
+    /** @var int database revision */
+    protected $dbrev = 0;
+    /** @var int database subrevision */
+    protected $dbsub = 0;
 
     /**
      * Constructor
@@ -27,92 +29,93 @@ class auth_plugin_authmysql extends DokuWiki_Auth_Plugin {
      *
      * @author Matthias Grimm 
      */
-    function __construct() {
+    public function __construct() {
         parent::__construct();
 
-        global $conf;
-        $this->cnf = $conf['auth']['mysql'];
-
-        if (method_exists($this, 'auth_basic')){
-            parent::__construct();
-        }
-
         if(!function_exists('mysql_connect')) {
-            if ($this->cnf['debug']){
-                msg("MySQL err: PHP MySQL extension not found.",-1,__LINE__,__FILE__);
-            }
+            $this->_debug("MySQL err: PHP MySQL extension not found.", -1, __LINE__, __FILE__);
             $this->success = false;
             return;
         }
 
-        // default to UTF-8, you rarely want something else
-        if(!isset($this->cnf['charset'])) $this->cnf['charset'] = 'utf8';
-
-        $this->defaultgroup = $conf['defaultgroup'];
-
         // set capabilities based upon config strings set
-        if (empty($this->cnf['server']) || empty($this->cnf['user']) ||
-            !isset($this->cnf['password']) || empty($this->cnf['database'])){
+        if(!$this->getConf('server') || !$this->getConf('user') || !$this->getConf('database')) {
+            $this->_debug("MySQL err: insufficient configuration.", -1, __LINE__, __FILE__);
 
-            if ($this->cnf['debug']){
-                msg("MySQL err: insufficient configuration.",-1,__LINE__,__FILE__);
-            }
             $this->success = false;
             return;
         }
 
-        $this->cando['addUser']      = $this->_chkcnf(array(
-                                            'getUserInfo',
-                                            'getGroups',
-                                            'addUser',
-                                            'getUserID',
-                                            'getGroupID',
-                                            'addGroup',
-                                            'addUserGroup'),true);
-        $this->cando['delUser']      = $this->_chkcnf(array(
-                                            'getUserID',
-                                            'delUser',
-                                            'delUserRefs'),true);
-        $this->cando['modLogin']     = $this->_chkcnf(array(
-                                            'getUserID',
-                                            'updateUser',
-                                            'UpdateTarget'),true);
-        $this->cando['modPass']      = $this->cando['modLogin'];
-        $this->cando['modName']      = $this->cando['modLogin'];
-        $this->cando['modMail']      = $this->cando['modLogin'];
-        $this->cando['modGroups']    = $this->_chkcnf(array(
-                                            'getUserID',
-                                            'getGroups',
-                                            'getGroupID',
-                                            'addGroup',
-                                            'addUserGroup',
-                                            'delGroup',
-                                            'getGroupID',
-                                            'delUserGroup'),true);
+        $this->cando['addUser']   = $this->_chkcnf(
+            array(
+                 'getUserInfo',
+                 'getGroups',
+                 'addUser',
+                 'getUserID',
+                 'getGroupID',
+                 'addGroup',
+                 'addUserGroup'
+            ), true
+        );
+        $this->cando['delUser']   = $this->_chkcnf(
+            array(
+                 'getUserID',
+                 'delUser',
+                 'delUserRefs'
+            ), true
+        );
+        $this->cando['modLogin']  = $this->_chkcnf(
+            array(
+                 'getUserID',
+                 'updateUser',
+                 'UpdateTarget'
+            ), true
+        );
+        $this->cando['modPass']   = $this->cando['modLogin'];
+        $this->cando['modName']   = $this->cando['modLogin'];
+        $this->cando['modMail']   = $this->cando['modLogin'];
+        $this->cando['modGroups'] = $this->_chkcnf(
+            array(
+                 'getUserID',
+                 'getGroups',
+                 'getGroupID',
+                 'addGroup',
+                 'addUserGroup',
+                 'delGroup',
+                 'getGroupID',
+                 'delUserGroup'
+            ), true
+        );
         /* getGroups is not yet supported
            $this->cando['getGroups']    = $this->_chkcnf(array('getGroups',
            'getGroupID'),false); */
-        $this->cando['getUsers']     = $this->_chkcnf(array(
-                                            'getUsers',
-                                            'getUserInfo',
-                                            'getGroups'),false);
-        $this->cando['getUserCount'] = $this->_chkcnf(array('getUsers'),false);
+        $this->cando['getUsers']     = $this->_chkcnf(
+            array(
+                 'getUsers',
+                 'getUserInfo',
+                 'getGroups'
+            ), false
+        );
+        $this->cando['getUserCount'] = $this->_chkcnf(array('getUsers'), false);
     }
 
     /**
      * Check if the given config strings are set
      *
      * @author  Matthias Grimm 
+     * @param   array $keys
+     * @param   bool  $wop is this a check for a write operation?
      * @return  bool
      */
-    function _chkcnf($keys, $wop=false){
-        foreach ($keys as $key){
-            if (empty($this->cnf[$key])) return false;
+    protected function _chkcnf($keys, $wop = false) {
+        foreach($keys as $key) {
+            if(!$this->getConf($key)) return false;
         }
 
         /* write operation and lock array filled with tables names? */
-        if ($wop && (!is_array($this->cnf['TablesToLock']) ||
-                    !count($this->cnf['TablesToLock']))){
+        if($wop && (!is_array($this->getConf('TablesToLock')) ||
+            !count($this->getConf('TablesToLock')))
+        ) {
             return false;
         }
 
@@ -127,27 +130,28 @@ class auth_plugin_authmysql extends DokuWiki_Auth_Plugin {
      * Depending on which SQL string is defined in the config, password
      * checking is done here (getpass) or by the database (passcheck)
      *
-     * @param  $user  user who would like access
-     * @param  $pass  user's clear text password to check
+     * @param  string $user user who would like access
+     * @param  string $pass user's clear text password to check
      * @return bool
      *
      * @author  Andreas Gohr 
      * @author  Matthias Grimm 
      */
-    function checkPass($user,$pass){
-        $rc  = false;
+    public function checkPass($user, $pass) {
+        global $conf;
+        $rc = false;
 
         if($this->_openDB()) {
-            $sql    = str_replace('%{user}',$this->_escape($user),$this->cnf['checkPass']);
-            $sql    = str_replace('%{pass}',$this->_escape($pass),$sql);
-            $sql    = str_replace('%{dgroup}',$this->_escape($this->defaultgroup),$sql);
+            $sql    = str_replace('%{user}', $this->_escape($user), $this->getConf('checkPass'));
+            $sql    = str_replace('%{pass}', $this->_escape($pass), $sql);
+            $sql    = str_replace('%{dgroup}', $this->_escape($conf['defaultgroup']), $sql);
             $result = $this->_queryDB($sql);
 
             if($result !== false && count($result) == 1) {
-                if($this->cnf['forwardClearPass'] == 1)
+                if($this->getConf('forwardClearPass') == 1)
                     $rc = true;
                 else
-                    $rc = auth_verifyPassword($pass,$result[0]['pass']);
+                    $rc = auth_verifyPassword($pass, $result[0]['pass']);
             }
             $this->_closeDB();
         }
@@ -155,20 +159,15 @@ class auth_plugin_authmysql extends DokuWiki_Auth_Plugin {
     }
 
     /**
-     * [public function]
-     *
-     * Returns info about the given user needs to contain
-     * at least these fields:
-     *   name  string  full name of the user
-     *   mail  string  email addres of the user
-     *   grps  array   list of groups the user is in
-     *
-     * @param $user   user's nick to get data for
+     * Return user info
      *
      * @author  Andreas Gohr 
      * @author  Matthias Grimm 
+     *
+     * @param string $user user login to get data for
+     * @return array|bool
      */
-    function getUserData($user){
+    public function getUserData($user) {
         if($this->_openDB()) {
             $this->_lockTables("READ");
             $info = $this->_getUserInfo($user);
@@ -180,45 +179,46 @@ class auth_plugin_authmysql extends DokuWiki_Auth_Plugin {
     }
 
     /**
-     * [public function]
-     *
      * Create a new User. Returns false if the user already exists,
      * null when an error occurred and true if everything went well.
      *
      * The new user will be added to the default group by this
      * function if grps are not specified (default behaviour).
      *
-     * @param $user  nick of the user
-     * @param $pwd   clear text password
-     * @param $name  full name of the user
-     * @param $mail  email address
-     * @param $grps  array of groups the user should become member of
-     *
      * @author  Andreas Gohr 
      * @author  Chris Smith 
      * @author  Matthias Grimm 
+     *
+     * @param string $user  nick of the user
+     * @param string $pwd   clear text password
+     * @param string $name  full name of the user
+     * @param string $mail  email address
+     * @param array  $grps  array of groups the user should become member of
+     * @return bool|null
      */
-    function createUser($user,$pwd,$name,$mail,$grps=null){
+    public function createUser($user, $pwd, $name, $mail, $grps = null) {
+        global $conf;
+
         if($this->_openDB()) {
-            if (($info = $this->_getUserInfo($user)) !== false)
-                return false;  // user already exists
+            if(($info = $this->_getUserInfo($user)) !== false)
+                return false; // user already exists
 
             // set defaultgroup if no groups were given
-            if ($grps == null)
-                $grps = array($this->defaultgroup);
+            if($grps == null)
+                $grps = array($conf['defaultgroup']);
 
             $this->_lockTables("WRITE");
-            $pwd = $this->cnf['forwardClearPass'] ? $pwd : auth_cryptPassword($pwd);
-            $rc = $this->_addUser($user,$pwd,$name,$mail,$grps);
+            $pwd = $this->getConf('forwardClearPass') ? $pwd : auth_cryptPassword($pwd);
+            $rc  = $this->_addUser($user, $pwd, $name, $mail, $grps);
             $this->_unlockTables();
             $this->_closeDB();
-            if ($rc) return true;
+            if($rc) return true;
         }
-        return null;  // return error
+        return null; // return error
     }
 
     /**
-     * Modify user data [public function]
+     * Modify user data
      *
      * An existing user dataset will be modified. Changes are given in an array.
      *
@@ -237,37 +237,36 @@ class auth_plugin_authmysql extends DokuWiki_Auth_Plugin {
      * should be modified). In this case we asure that we don't touch groups
      * even $changes['grps'] is set by mistake.
      *
-     * @param   $user     nick of the user to be changed
-     * @param   $changes  array of field/value pairs to be changed (password
-     *                    will be clear text)
-     * @return  bool      true on success, false on error
-     *
      * @author  Chris Smith 
      * @author  Matthias Grimm 
+     *
+     * @param   string $user    nick of the user to be changed
+     * @param   array  $changes array of field/value pairs to be changed (password will be clear text)
+     * @return  bool   true on success, false on error
      */
-    function modifyUser($user, $changes) {
+    public function modifyUser($user, $changes) {
         $rc = false;
 
-        if (!is_array($changes) || !count($changes))
-            return true;  // nothing to change
+        if(!is_array($changes) || !count($changes))
+            return true; // nothing to change
 
         if($this->_openDB()) {
             $this->_lockTables("WRITE");
 
-            if (($uid = $this->_getUserID($user))) {
+            if(($uid = $this->_getUserID($user))) {
                 $rc = $this->_updateUserInfo($changes, $uid);
 
-                if ($rc && isset($changes['grps']) && $this->cando['modGroups']) {
+                if($rc && isset($changes['grps']) && $this->cando['modGroups']) {
                     $groups = $this->_getGroups($user);
                     $grpadd = array_diff($changes['grps'], $groups);
                     $grpdel = array_diff($groups, $changes['grps']);
 
                     foreach($grpadd as $group)
-                        if (($this->_addUserToGroup($user, $group, 1)) == false)
+                        if(($this->_addUserToGroup($user, $group, 1)) == false)
                             $rc = false;
 
                     foreach($grpdel as $group)
-                        if (($this->_delUserFromGroup($user, $group)) == false)
+                        if(($this->_delUserFromGroup($user, $group)) == false)
                             $rc = false;
                 }
             }
@@ -293,10 +292,10 @@ class auth_plugin_authmysql extends DokuWiki_Auth_Plugin {
         $count = 0;
 
         if($this->_openDB()) {
-            if (is_array($users) && count($users)) {
+            if(is_array($users) && count($users)) {
                 $this->_lockTables("WRITE");
-                foreach ($users as $user) {
-                    if ($this->_delUser($user))
+                foreach($users as $user) {
+                    if($this->_delUser($user))
                         $count++;
                 }
                 $this->_unlockTables();
@@ -307,28 +306,26 @@ class auth_plugin_authmysql extends DokuWiki_Auth_Plugin {
     }
 
     /**
-     * [public function]
-     *
      * Counts users which meet certain $filter criteria.
      *
-     * @param  array  $filter  filter criteria in item/pattern pairs
-     * @return count of found users.
-     *
      * @author  Matthias Grimm 
+     *
+     * @param  array $filter  filter criteria in item/pattern pairs
+     * @return int count of found users
      */
-    function getUserCount($filter=array()) {
+    public function getUserCount($filter = array()) {
         $rc = 0;
 
         if($this->_openDB()) {
-            $sql = $this->_createSQLFilter($this->cnf['getUsers'], $filter);
+            $sql = $this->_createSQLFilter($this->getConf('getUsers'), $filter);
 
-            if ($this->dbver >= 4) {
-                $sql = substr($sql, 6);  /* remove 'SELECT' or 'select' */
+            if($this->dbver >= 4) {
+                $sql = substr($sql, 6); /* remove 'SELECT' or 'select' */
                 $sql = "SELECT SQL_CALC_FOUND_ROWS".$sql." LIMIT 1";
                 $this->_queryDB($sql);
                 $result = $this->_queryDB("SELECT FOUND_ROWS()");
-                $rc = $result[0]['FOUND_ROWS()'];
-            } else if (($result = $this->_queryDB($sql)))
+                $rc     = $result[0]['FOUND_ROWS()'];
+            } else if(($result = $this->_queryDB($sql)))
                 $rc = count($result);
 
             $this->_closeDB();
@@ -337,27 +334,27 @@ class auth_plugin_authmysql extends DokuWiki_Auth_Plugin {
     }
 
     /**
-     * Bulk retrieval of user data. [public function]
-     *
-     * @param   first     index of first user to be returned
-     * @param   limit     max number of users to be returned
-     * @param   filter    array of field/pattern pairs
-     * @return  array of userinfo (refer getUserData for internal userinfo details)
+     * Bulk retrieval of user data
      *
      * @author  Matthias Grimm 
+     *
+     * @param  int          $first  index of first user to be returned
+     * @param  int          $limit  max number of users to be returned
+     * @param  array|string $filter array of field/pattern pairs
+     * @return  array userinfo (refer getUserData for internal userinfo details)
      */
-    function retrieveUsers($first=0,$limit=10,$filter=array()) {
-        $out   = array();
+    public function retrieveUsers($first = 0, $limit = 10, $filter = array()) {
+        $out = array();
 
         if($this->_openDB()) {
             $this->_lockTables("READ");
-            $sql  = $this->_createSQLFilter($this->cnf['getUsers'], $filter);
-            $sql .= " ".$this->cnf['SortOrder']." LIMIT $first, $limit";
+            $sql = $this->_createSQLFilter($this->getConf('getUsers'), $filter);
+            $sql .= " ".$this->getConf('SortOrder')." LIMIT $first, $limit";
             $result = $this->_queryDB($sql);
 
-            if (!empty($result)) {
-                foreach ($result as $user)
-                    if (($info = $this->_getUserInfo($user['user'])))
+            if(!empty($result)) {
+                foreach($result as $user)
+                    if(($info = $this->_getUserInfo($user['user'])))
                         $out[$user['user']] = $info;
             }
 
@@ -368,20 +365,20 @@ class auth_plugin_authmysql extends DokuWiki_Auth_Plugin {
     }
 
     /**
-     * Give user membership of a group [public function]
-     *
-     * @param   $user
-     * @param   $group
-     * @return  bool    true on success, false on error
+     * Give user membership of a group
      *
      * @author  Matthias Grimm 
+     *
+     * @param   string $user
+     * @param   string $group
+     * @return  bool   true on success, false on error
      */
-    function joinGroup($user, $group) {
+    protected function joinGroup($user, $group) {
         $rc = false;
 
-        if ($this->_openDB()) {
+        if($this->_openDB()) {
             $this->_lockTables("WRITE");
-            $rc  = $this->_addUserToGroup($user, $group);
+            $rc = $this->_addUserToGroup($user, $group);
             $this->_unlockTables();
             $this->_closeDB();
         }
@@ -389,20 +386,19 @@ class auth_plugin_authmysql extends DokuWiki_Auth_Plugin {
     }
 
     /**
-     * Remove user from a group [public function]
-     *
-     * @param   $user    user that leaves a group
-     * @param   $group   group to leave
-     * @return  bool
+     * Remove user from a group
      *
      * @author  Matthias Grimm 
+     *
+     * @param   string $user  user that leaves a group
+     * @param   string $group group to leave
+     * @return  bool
      */
-    function leaveGroup($user, $group) {
+    protected function leaveGroup($user, $group) {
         $rc = false;
 
-        if ($this->_openDB()) {
+        if($this->_openDB()) {
             $this->_lockTables("WRITE");
-            $uid = $this->_getUserID($user);
             $rc  = $this->_delUserFromGroup($user, $group);
             $this->_unlockTables();
             $this->_closeDB();
@@ -413,54 +409,54 @@ class auth_plugin_authmysql extends DokuWiki_Auth_Plugin {
     /**
      * MySQL is case-insensitive
      */
-    function isCaseSensitive(){
+    public function isCaseSensitive() {
         return false;
     }
 
     /**
      * Adds a user to a group.
      *
-     * If $force is set to '1' non existing groups would be created.
+     * If $force is set to true non existing groups would be created.
      *
      * The database connection must already be established. Otherwise
      * this function does nothing and returns 'false'. It is strongly
      * recommended to call this function only after all participating
      * tables (group and usergroup) have been locked.
      *
-     * @param   $user    user to add to a group
-     * @param   $group   name of the group
-     * @param   $force   '1' create missing groups
-     * @return  bool     'true' on success, 'false' on error
-     *
      * @author Matthias Grimm 
+     *
+     * @param   string $user    user to add to a group
+     * @param   string $group   name of the group
+     * @param   bool   $force   create missing groups
+     * @return  bool   true on success, false on error
      */
-    function _addUserToGroup($user, $group, $force=0) {
+    protected function _addUserToGroup($user, $group, $force = false) {
         $newgroup = 0;
 
-        if (($this->dbcon) && ($user)) {
+        if(($this->dbcon) && ($user)) {
             $gid = $this->_getGroupID($group);
-            if (!$gid) {
-                if ($force) {  // create missing groups
-                    $sql = str_replace('%{group}',$this->_escape($group),$this->cnf['addGroup']);
-                    $gid = $this->_modifyDB($sql);
-                    $newgroup = 1;  // group newly created
+            if(!$gid) {
+                if($force) { // create missing groups
+                    $sql      = str_replace('%{group}', $this->_escape($group), $this->getConf('addGroup'));
+                    $gid      = $this->_modifyDB($sql);
+                    $newgroup = 1; // group newly created
                 }
-                if (!$gid) return false; // group didn't exist and can't be created
+                if(!$gid) return false; // group didn't exist and can't be created
             }
 
-            $sql = $this->cnf['addUserGroup'];
-            if(strpos($sql,'%{uid}') !== false){
+            $sql = $this->getConf('addUserGroup');
+            if(strpos($sql, '%{uid}') !== false) {
                 $uid = $this->_getUserID($user);
-                $sql = str_replace('%{uid}',  $this->_escape($uid),$sql);
+                $sql = str_replace('%{uid}', $this->_escape($uid), $sql);
             }
-            $sql = str_replace('%{user}', $this->_escape($user),$sql);
-            $sql = str_replace('%{gid}',  $this->_escape($gid),$sql);
-            $sql = str_replace('%{group}',$this->_escape($group),$sql);
-            if ($this->_modifyDB($sql) !== false) return true;
-
-            if ($newgroup) { // remove previously created group on error
-                $sql = str_replace('%{gid}',  $this->_escape($gid),$this->cnf['delGroup']);
-                $sql = str_replace('%{group}',$this->_escape($group),$sql);
+            $sql = str_replace('%{user}', $this->_escape($user), $sql);
+            $sql = str_replace('%{gid}', $this->_escape($gid), $sql);
+            $sql = str_replace('%{group}', $this->_escape($group), $sql);
+            if($this->_modifyDB($sql) !== false) return true;
+
+            if($newgroup) { // remove previously created group on error
+                $sql = str_replace('%{gid}', $this->_escape($gid), $this->getConf('delGroup'));
+                $sql = str_replace('%{group}', $this->_escape($group), $sql);
                 $this->_modifyDB($sql);
             }
         }
@@ -470,26 +466,26 @@ class auth_plugin_authmysql extends DokuWiki_Auth_Plugin {
     /**
      * Remove user from a group
      *
-     * @param   $user    user that leaves a group
-     * @param   $group   group to leave
-     * @return  bool     true on success, false on error
-     *
      * @author  Matthias Grimm 
+     *
+     * @param   string $user  user that leaves a group
+     * @param   string $group group to leave
+     * @return  bool   true on success, false on error
      */
-    function _delUserFromGroup($user, $group) {
+    protected function _delUserFromGroup($user, $group) {
         $rc = false;
 
-        if (($this->dbcon) && ($user)) {
-            $sql = $this->cnf['delUserGroup'];
-            if(strpos($sql,'%{uid}') !== false){
+        if(($this->dbcon) && ($user)) {
+            $sql = $this->getConf('delUserGroup');
+            if(strpos($sql, '%{uid}') !== false) {
                 $uid = $this->_getUserID($user);
-                $sql = str_replace('%{uid}',  $this->_escape($uid),$sql);
+                $sql = str_replace('%{uid}', $this->_escape($uid), $sql);
             }
             $gid = $this->_getGroupID($group);
-            if ($gid) {
-                $sql = str_replace('%{user}', $this->_escape($user),$sql);
-                $sql = str_replace('%{gid}',  $this->_escape($gid),$sql);
-                $sql = str_replace('%{group}',$this->_escape($group),$sql);
+            if($gid) {
+                $sql = str_replace('%{user}', $this->_escape($user), $sql);
+                $sql = str_replace('%{gid}', $this->_escape($gid), $sql);
+                $sql = str_replace('%{group}', $this->_escape($group), $sql);
                 $rc  = $this->_modifyDB($sql) == 0 ? true : false;
             }
         }
@@ -501,19 +497,18 @@ class auth_plugin_authmysql extends DokuWiki_Auth_Plugin {
      *
      * The database connection must already be established
      * for this function to work. Otherwise it will return
-     * 'false'.
-     *
-     * @param  $user  user whose groups should be listed
-     * @return bool   false on error
-     * @return array  array containing all groups on success
+     * false.
      *
      * @author Matthias Grimm 
+     *
+     * @param  string $user user whose groups should be listed
+     * @return bool|array false on error, all groups on success
      */
-    function _getGroups($user) {
+    protected function _getGroups($user) {
         $groups = array();
 
         if($this->dbcon) {
-            $sql = str_replace('%{user}',$this->_escape($user),$this->cnf['getGroups']);
+            $sql    = str_replace('%{user}', $this->_escape($user), $this->getConf('getGroups'));
             $result = $this->_queryDB($sql);
 
             if($result !== false && count($result)) {
@@ -530,16 +525,16 @@ class auth_plugin_authmysql extends DokuWiki_Auth_Plugin {
      *
      * The database connection must already be established
      * for this function to work. Otherwise it will return
-     * 'false'.
-     *
-     * @param  $user   user whose id is desired
-     * @return user id
+     * false.
      *
      * @author Matthias Grimm 
+     *
+     * @param  string $user user whose id is desired
+     * @return mixed  user id
      */
-    function _getUserID($user) {
+    protected function _getUserID($user) {
         if($this->dbcon) {
-            $sql = str_replace('%{user}',$this->_escape($user),$this->cnf['getUserID']);
+            $sql    = str_replace('%{user}', $this->_escape($user), $this->getConf('getUserID'));
             $result = $this->_queryDB($sql);
             return $result === false ? false : $result[0]['id'];
         }
@@ -551,43 +546,45 @@ class auth_plugin_authmysql extends DokuWiki_Auth_Plugin {
      *
      * The database connection must already be established
      * for this function to work. Otherwise it will return
-     * 'false'.
-     *
-     * @param  $user  login of the user
-     * @param  $pwd   encrypted password
-     * @param  $name  full name of the user
-     * @param  $mail  email address
-     * @param  $grps  array of groups the user should become member of
-     * @return bool
+     * false.
      *
      * @author  Andreas Gohr 
      * @author  Chris Smith 
      * @author  Matthias Grimm 
+     *
+     * @param  string $user  login of the user
+     * @param  string $pwd   encrypted password
+     * @param  string $name  full name of the user
+     * @param  string $mail  email address
+     * @param  array  $grps  array of groups the user should become member of
+     * @return bool
      */
-    function _addUser($user,$pwd,$name,$mail,$grps){
+    protected function _addUser($user, $pwd, $name, $mail, $grps) {
         if($this->dbcon && is_array($grps)) {
-            $sql = str_replace('%{user}', $this->_escape($user),$this->cnf['addUser']);
-            $sql = str_replace('%{pass}', $this->_escape($pwd),$sql);
-            $sql = str_replace('%{name}', $this->_escape($name),$sql);
-            $sql = str_replace('%{email}',$this->_escape($mail),$sql);
+            $sql = str_replace('%{user}', $this->_escape($user), $this->getConf('addUser'));
+            $sql = str_replace('%{pass}', $this->_escape($pwd), $sql);
+            $sql = str_replace('%{name}', $this->_escape($name), $sql);
+            $sql = str_replace('%{email}', $this->_escape($mail), $sql);
             $uid = $this->_modifyDB($sql);
+            $gid = false;
+            $group = '';
 
-            if ($uid) {
+            if($uid) {
                 foreach($grps as $group) {
                     $gid = $this->_addUserToGroup($user, $group, 1);
-                    if ($gid === false) break;
+                    if($gid === false) break;
                 }
 
-                if ($gid) return true;
-                else {
+                if($gid !== false){
+                    return true;
+                } else {
                     /* remove the new user and all group relations if a group can't
                      * be assigned. Newly created groups will remain in the database
                      * and won't be removed. This might create orphaned groups but
                      * is not a big issue so we ignore this problem here.
                      */
                     $this->_delUser($user);
-                    if ($this->cnf['debug'])
-                        msg ("MySQL err: Adding user '$user' to group '$group' failed.",-1,__LINE__,__FILE__);
+                    $this->_debug("MySQL err: Adding user '$user' to group '$group' failed.", -1, __LINE__, __FILE__);
                 }
             }
         }
@@ -599,21 +596,21 @@ class auth_plugin_authmysql extends DokuWiki_Auth_Plugin {
      *
      * The database connection must already be established
      * for this function to work. Otherwise it will return
-     * 'false'.
-     *
-     * @param  $user   user whose id is desired
-     * @return bool
+     * false.
      *
      * @author Matthias Grimm 
+     *
+     * @param  string $user user whose id is desired
+     * @return bool
      */
-    function _delUser($user) {
+    protected function _delUser($user) {
         if($this->dbcon) {
             $uid = $this->_getUserID($user);
-            if ($uid) {
-                $sql = str_replace('%{uid}',$this->_escape($uid),$this->cnf['delUserRefs']);
+            if($uid) {
+                $sql = str_replace('%{uid}', $this->_escape($uid), $this->getConf('delUserRefs'));
                 $this->_modifyDB($sql);
-                $sql = str_replace('%{uid}',$this->_escape($uid),$this->cnf['delUser']);
-                $sql = str_replace('%{user}',  $this->_escape($user),$sql);
+                $sql = str_replace('%{uid}', $this->_escape($uid), $this->getConf('delUser'));
+                $sql = str_replace('%{user}', $this->_escape($user), $sql);
                 $this->_modifyDB($sql);
                 return true;
             }
@@ -628,17 +625,16 @@ class auth_plugin_authmysql extends DokuWiki_Auth_Plugin {
      * must already be established for this function to work.
      * Otherwise it will return 'false'.
      *
-     * @param  $user  user's nick to get data for
-     * @return bool   false on error
-     * @return array  user info on success
-     *
      * @author Matthias Grimm 
+     *
+     * @param  string $user  user's nick to get data for
+     * @return bool|array false on error, user info on success
      */
-    function _getUserInfo($user){
-        $sql = str_replace('%{user}',$this->_escape($user),$this->cnf['getUserInfo']);
+    protected function _getUserInfo($user) {
+        $sql    = str_replace('%{user}', $this->_escape($user), $this->getConf('getUserInfo'));
         $result = $this->_queryDB($sql);
         if($result !== false && count($result)) {
-            $info = $result[0];
+            $info         = $result[0];
             $info['grps'] = $this->_getGroups($user);
             return $info;
         }
@@ -658,43 +654,43 @@ class auth_plugin_authmysql extends DokuWiki_Auth_Plugin {
      *
      * The password will be crypted if necessary.
      *
-     * @param  $changes  array of items to change as pairs of item and value
-     * @param  $uid      user id of dataset to change, must be unique in DB
-     * @return true on success or false on error
+     * @param  array $changes  array of items to change as pairs of item and value
+     * @param  mixed $uid      user id of dataset to change, must be unique in DB
+     * @return bool true on success or false on error
      *
      * @author Matthias Grimm 
      */
-    function _updateUserInfo($changes, $uid) {
-        $sql  = $this->cnf['updateUser']." ";
+    protected function _updateUserInfo($changes, $uid) {
+        $sql = $this->getConf('updateUser')." ";
         $cnt = 0;
         $err = 0;
 
         if($this->dbcon) {
-            foreach ($changes as $item => $value) {
-                if ($item == 'user') {
-                    if (($this->_getUserID($changes['user']))) {
+            foreach($changes as $item => $value) {
+                if($item == 'user') {
+                    if(($this->_getUserID($changes['user']))) {
                         $err = 1; /* new username already exists */
-                        break;    /* abort update */
+                        break; /* abort update */
                     }
-                    if ($cnt++ > 0) $sql .= ", ";
-                    $sql .= str_replace('%{user}',$value,$this->cnf['UpdateLogin']);
-                } else if ($item == 'name') {
-                    if ($cnt++ > 0) $sql .= ", ";
-                    $sql .= str_replace('%{name}',$value,$this->cnf['UpdateName']);
-                } else if ($item == 'pass') {
-                    if (!$this->cnf['forwardClearPass'])
+                    if($cnt++ > 0) $sql .= ", ";
+                    $sql .= str_replace('%{user}', $value, $this->getConf('UpdateLogin'));
+                } else if($item == 'name') {
+                    if($cnt++ > 0) $sql .= ", ";
+                    $sql .= str_replace('%{name}', $value, $this->getConf('UpdateName'));
+                } else if($item == 'pass') {
+                    if(!$this->getConf('forwardClearPass'))
                         $value = auth_cryptPassword($value);
-                    if ($cnt++ > 0) $sql .= ", ";
-                    $sql .= str_replace('%{pass}',$value,$this->cnf['UpdatePass']);
-                } else if ($item == 'mail') {
-                    if ($cnt++ > 0) $sql .= ", ";
-                    $sql .= str_replace('%{email}',$value,$this->cnf['UpdateEmail']);
+                    if($cnt++ > 0) $sql .= ", ";
+                    $sql .= str_replace('%{pass}', $value, $this->getConf('UpdatePass'));
+                } else if($item == 'mail') {
+                    if($cnt++ > 0) $sql .= ", ";
+                    $sql .= str_replace('%{email}', $value, $this->getConf('UpdateEmail'));
                 }
             }
 
-            if ($err == 0) {
-                if ($cnt > 0) {
-                    $sql .= " ".str_replace('%{uid}', $uid, $this->cnf['UpdateTarget']);
+            if($err == 0) {
+                if($cnt > 0) {
+                    $sql .= " ".str_replace('%{uid}', $uid, $this->getConf('UpdateTarget'));
                     if(get_class($this) == 'auth_mysql') $sql .= " LIMIT 1"; //some PgSQL inheritance comp.
                     $this->_modifyDB($sql);
                 }
@@ -709,16 +705,16 @@ class auth_plugin_authmysql extends DokuWiki_Auth_Plugin {
      *
      * The database connection must already be established
      * for this function to work. Otherwise it will return
-     * 'false'.
-     *
-     * @param  $group   group name which id is desired
-     * @return group id
+     * false.
      *
      * @author Matthias Grimm 
+     *
+     * @param  string $group   group name which id is desired
+     * @return mixed group id
      */
-    function _getGroupID($group) {
+    protected function _getGroupID($group) {
         if($this->dbcon) {
-            $sql = str_replace('%{group}',$this->_escape($group),$this->cnf['getGroupID']);
+            $sql    = str_replace('%{group}', $this->_escape($group), $this->getConf('getGroupID'));
             $result = $this->_queryDB($sql);
             return $result === false ? false : $result[0]['id'];
         }
@@ -730,37 +726,39 @@ class auth_plugin_authmysql extends DokuWiki_Auth_Plugin {
      * usage in the object. The successful call to this functions is
      * essential for most functions in this object.
      *
-     * @return bool
-     *
      * @author Matthias Grimm 
+     *
+     * @return bool
      */
-    function _openDB() {
-        if (!$this->dbcon) {
-            $con = @mysql_connect ($this->cnf['server'], $this->cnf['user'], $this->cnf['password']);
-            if ($con) {
-                if ((mysql_select_db($this->cnf['database'], $con))) {
-                    if ((preg_match("/^(\d+)\.(\d+)\.(\d+).*/", mysql_get_server_info ($con), $result)) == 1) {
+    protected function _openDB() {
+        if(!$this->dbcon) {
+            $con = @mysql_connect($this->getConf('server'), $this->getConf('user'), $this->getConf('password'));
+            if($con) {
+                if((mysql_select_db($this->getConf('database'), $con))) {
+                    if((preg_match('/^(\d+)\.(\d+)\.(\d+).*/', mysql_get_server_info($con), $result)) == 1) {
                         $this->dbver = $result[1];
                         $this->dbrev = $result[2];
                         $this->dbsub = $result[3];
                     }
                     $this->dbcon = $con;
-                    if(!empty($this->cnf['charset'])){
-                        mysql_query('SET CHARACTER SET "' . $this->cnf['charset'] . '"', $con);
+                    if($this->getConf('charset')) {
+                        mysql_query('SET CHARACTER SET "'.$this->getConf('charset').'"', $con);
                     }
-                    return true;   // connection and database successfully opened
+                    return true; // connection and database successfully opened
                 } else {
-                    mysql_close ($con);
-                    if ($this->cnf['debug'])
-                        msg("MySQL err: No access to database {$this->cnf['database']}.",-1,__LINE__,__FILE__);
+                    mysql_close($con);
+                    $this->_debug("MySQL err: No access to database {$this->getConf('database')}.", -1, __LINE__, __FILE__);
                 }
-            } else if ($this->cnf['debug'])
-                msg ("MySQL err: Connection to {$this->cnf['user']}@{$this->cnf['server']} not possible.",
-                        -1,__LINE__,__FILE__);
+            } else {
+                $this->_debug(
+                    "MySQL err: Connection to {$this->getConf('user')}@{$this->getConf('server')} not possible.",
+                    -1, __LINE__, __FILE__
+                );
+            }
 
-            return false;  // connection failed
+            return false; // connection failed
         }
-        return true;  // connection already open
+        return true; // connection already open
     }
 
     /**
@@ -768,9 +766,9 @@ class auth_plugin_authmysql extends DokuWiki_Auth_Plugin {
      *
      * @author Matthias Grimm 
      */
-    function _closeDB() {
-        if ($this->dbcon) {
-            mysql_close ($this->dbcon);
+    protected function _closeDB() {
+        if($this->dbcon) {
+            mysql_close($this->dbcon);
             $this->dbcon = 0;
         }
     }
@@ -782,27 +780,26 @@ class auth_plugin_authmysql extends DokuWiki_Auth_Plugin {
      * This function is only able to handle queries that returns a
      * table such as SELECT.
      *
-     * @param $query  SQL string that contains the query
-     * @return array with the result table
-     *
      * @author Matthias Grimm 
+     *
+     * @param string $query  SQL string that contains the query
+     * @return array with the result table
      */
-    function _queryDB($query) {
-        if($this->cnf['debug'] >= 2){
-            msg('MySQL query: '.hsc($query),0,__LINE__,__FILE__);
+    protected function _queryDB($query) {
+        if($this->getConf('debug') >= 2) {
+            msg('MySQL query: '.hsc($query), 0, __LINE__, __FILE__);
         }
 
         $resultarray = array();
-        if ($this->dbcon) {
-            $result = @mysql_query($query,$this->dbcon);
-            if ($result) {
-                while (($t = mysql_fetch_assoc($result)) !== false)
-                    $resultarray[]=$t;
-                mysql_free_result ($result);
+        if($this->dbcon) {
+            $result = @mysql_query($query, $this->dbcon);
+            if($result) {
+                while(($t = mysql_fetch_assoc($result)) !== false)
+                    $resultarray[] = $t;
+                mysql_free_result($result);
                 return $resultarray;
             }
-            if ($this->cnf['debug'])
-                msg('MySQL err: '.mysql_error($this->dbcon),-1,__LINE__,__FILE__);
+            $this->_debug('MySQL err: '.mysql_error($this->dbcon), -1, __LINE__, __FILE__);
         }
         return false;
     }
@@ -813,20 +810,19 @@ class auth_plugin_authmysql extends DokuWiki_Auth_Plugin {
      * This function is only able to handle queries that returns
      * either nothing or an id value such as INPUT, DELETE, UPDATE, etc.
      *
-     * @param $query  SQL string that contains the query
-     * @return insert id or 0, false on error
-     *
      * @author Matthias Grimm 
+     *
+     * @param string $query  SQL string that contains the query
+     * @return int|bool insert id or 0, false on error
      */
-    function _modifyDB($query) {
-        if ($this->dbcon) {
-            $result = @mysql_query($query,$this->dbcon);
-            if ($result) {
+    protected function _modifyDB($query) {
+        if($this->dbcon) {
+            $result = @mysql_query($query, $this->dbcon);
+            if($result) {
                 $rc = mysql_insert_id($this->dbcon); //give back ID on insert
-                if ($rc !== false) return $rc;
+                if($rc !== false) return $rc;
             }
-            if ($this->cnf['debug'])
-                msg('MySQL err: '.mysql_error($this->dbcon),-1,__LINE__,__FILE__);
+            $this->_debug('MySQL err: '.mysql_error($this->dbcon), -1, __LINE__, __FILE__);
         }
         return false;
     }
@@ -845,18 +841,19 @@ class auth_plugin_authmysql extends DokuWiki_Auth_Plugin {
      * so that this functionality is simulated by this function. Nevertheless
      * it is not as powerful as transactions, it is a good compromise in safty.
      *
-     * @param $mode  could be 'READ' or 'WRITE'
-     *
      * @author Matthias Grimm 
+     *
+     * @param string $mode  could be 'READ' or 'WRITE'
+     * @return bool
      */
-    function _lockTables($mode) {
-        if ($this->dbcon) {
-            if (is_array($this->cnf['TablesToLock']) && !empty($this->cnf['TablesToLock'])) {
-                if ($mode == "READ" || $mode == "WRITE") {
+    protected function _lockTables($mode) {
+        if($this->dbcon) {
+            if(is_array($this->getConf('TablesToLock'))) {
+                if($mode == "READ" || $mode == "WRITE") {
                     $sql = "LOCK TABLES ";
                     $cnt = 0;
-                    foreach ($this->cnf['TablesToLock'] as $table) {
-                        if ($cnt++ != 0) $sql .= ", ";
+                    foreach($this->getConf('TablesToLock') as $table) {
+                        if($cnt++ != 0) $sql .= ", ";
                         $sql .= "$table $mode";
                     }
                     $this->_modifyDB($sql);
@@ -873,8 +870,8 @@ class auth_plugin_authmysql extends DokuWiki_Auth_Plugin {
      *
      * @author Matthias Grimm 
      */
-    function _unlockTables() {
-        if ($this->dbcon) {
+    protected function _unlockTables() {
+        if($this->dbcon) {
             $this->_modifyDB("UNLOCK TABLES");
             return true;
         }
@@ -886,32 +883,31 @@ class auth_plugin_authmysql extends DokuWiki_Auth_Plugin {
      * The database connection must already be established, otherwise the
      * original SQL string without filter criteria will be returned.
      *
-     * @param  $sql     SQL string to which the $filter criteria should be added
-     * @param  $filter  array of filter criteria as pairs of item and pattern
-     * @return SQL string with attached $filter criteria on success
-     * @return the original SQL string on error.
-     *
      * @author Matthias Grimm 
+     *
+     * @param  string $sql     SQL string to which the $filter criteria should be added
+     * @param  array $filter  array of filter criteria as pairs of item and pattern
+     * @return string SQL string with attached $filter criteria on success, original SQL string on error
      */
-    function _createSQLFilter($sql, $filter) {
+    protected function _createSQLFilter($sql, $filter) {
         $SQLfilter = "";
-        $cnt = 0;
+        $cnt       = 0;
 
-        if ($this->dbcon) {
-            foreach ($filter as $item => $pattern) {
+        if($this->dbcon) {
+            foreach($filter as $item => $pattern) {
                 $tmp = '%'.$this->_escape($pattern).'%';
-                if ($item == 'user') {
-                    if ($cnt++ > 0) $SQLfilter .= " AND ";
-                    $SQLfilter .= str_replace('%{user}',$tmp,$this->cnf['FilterLogin']);
-                } else if ($item == 'name') {
-                    if ($cnt++ > 0) $SQLfilter .= " AND ";
-                    $SQLfilter .= str_replace('%{name}',$tmp,$this->cnf['FilterName']);
-                } else if ($item == 'mail') {
-                    if ($cnt++ > 0) $SQLfilter .= " AND ";
-                    $SQLfilter .= str_replace('%{email}',$tmp,$this->cnf['FilterEmail']);
-                } else if ($item == 'grps') {
-                    if ($cnt++ > 0) $SQLfilter .= " AND ";
-                    $SQLfilter .= str_replace('%{group}',$tmp,$this->cnf['FilterGroup']);
+                if($item == 'user') {
+                    if($cnt++ > 0) $SQLfilter .= " AND ";
+                    $SQLfilter .= str_replace('%{user}', $tmp, $this->getConf('FilterLogin'));
+                } else if($item == 'name') {
+                    if($cnt++ > 0) $SQLfilter .= " AND ";
+                    $SQLfilter .= str_replace('%{name}', $tmp, $this->getConf('FilterName'));
+                } else if($item == 'mail') {
+                    if($cnt++ > 0) $SQLfilter .= " AND ";
+                    $SQLfilter .= str_replace('%{email}', $tmp, $this->getConf('FilterEmail'));
+                } else if($item == 'grps') {
+                    if($cnt++ > 0) $SQLfilter .= " AND ";
+                    $SQLfilter .= str_replace('%{group}', $tmp, $this->getConf('FilterGroup'));
                 }
             }
 
@@ -919,9 +915,9 @@ class auth_plugin_authmysql extends DokuWiki_Auth_Plugin {
             // any of cnf['Filter????'] is not defined, a malformed SQL string
             // would be generated.
 
-            if (strlen($SQLfilter)) {
-                $glue = strpos(strtolower($sql),"where") ? " AND " : " WHERE ";
-                $sql = $sql.$glue.$SQLfilter;
+            if(strlen($SQLfilter)) {
+                $glue = strpos(strtolower($sql), "where") ? " AND " : " WHERE ";
+                $sql  = $sql.$glue.$SQLfilter;
             }
         }
 
@@ -932,18 +928,34 @@ class auth_plugin_authmysql extends DokuWiki_Auth_Plugin {
      * Escape a string for insertion into the database
      *
      * @author Andreas Gohr 
+     *
      * @param  string  $string The string to escape
      * @param  boolean $like   Escape wildcard chars as well?
+     * @return string
      */
-    function _escape($string,$like=false){
-        if($this->dbcon){
+    protected function _escape($string, $like = false) {
+        if($this->dbcon) {
             $string = mysql_real_escape_string($string, $this->dbcon);
-        }else{
+        } else {
             $string = addslashes($string);
         }
-        if($like){
-            $string = addcslashes($string,'%_');
+        if($like) {
+            $string = addcslashes($string, '%_');
         }
         return $string;
     }
+
+    /**
+     * Wrapper around msg() but outputs only when debug is enabled
+     *
+     * @param string $message
+     * @param int    $err
+     * @param int    $line
+     * @param string $file
+     * @return void
+     */
+    protected function _debug($message, $err, $line, $file) {
+        if(!$this->getConf('debug')) return;
+        msg($message, $err, $line, $file);
+    }
 }
diff --git a/lib/plugins/authmysql/conf/default.php b/lib/plugins/authmysql/conf/default.php
new file mode 100644
index 000000000..ea2cdad72
--- /dev/null
+++ b/lib/plugins/authmysql/conf/default.php
@@ -0,0 +1,3 @@
+
Date: Fri, 9 Nov 2012 17:11:10 +0100
Subject: authpgsql fixes

* fixes merge messup (code was made up from parts of authad)
* code and PHP5 cleanup
---
 lib/plugins/authpgsql/auth.php         | 561 +++++++++++++++++++--------------
 lib/plugins/authpgsql/conf/default.php |   3 +
 2 files changed, 326 insertions(+), 238 deletions(-)
 create mode 100644 lib/plugins/authpgsql/conf/default.php

diff --git a/lib/plugins/authpgsql/auth.php b/lib/plugins/authpgsql/auth.php
index 46154b6ca..3f8ff3249 100644
--- a/lib/plugins/authpgsql/auth.php
+++ b/lib/plugins/authpgsql/auth.php
@@ -1,15 +1,9 @@
 
- */
 // must be run within Dokuwiki
 if(!defined('DOKU_INC')) die();
 
 /**
- * PgSQL authentication backend
+ * PostgreSQL authentication backend
  *
  * This class inherits much functionality from the MySQL class
  * and just reimplements the Postgres specific parts.
@@ -19,315 +13,406 @@ if(!defined('DOKU_INC')) die();
  * @author     Chris Smith 
  * @author     Matthias Grimm 
  * @author     Jan Schumann 
-*/
-class auth_plugin_authpgsql extends auth_plugin_authmysql
-{
-    var $cnf = null;
-    var $opts = null;
-    var $adldap = null;
-    var $users = null;
+ */
+class auth_plugin_authpgsql extends auth_plugin_authmysql {
 
     /**
      * Constructor
+     *
+     * checks if the pgsql interface is available, otherwise it will
+     * set the variable $success of the basis class to false
+     *
+     * @author Matthias Grimm 
+     * @author Andreas Gohr 
      */
-    function auth_plugin_authpgsql() {
-        parent::__construct();
-
-        global $conf;
-        $this->cnf = $conf['auth']['ad'];
+    public function __construct() {
+        // we don't want the stuff the MySQL constructor does, but the grandparent might do something
+        DokuWiki_Auth_Plugin::__construct();
 
-
-        // additional information fields
-        if (isset($this->cnf['additional'])) {
-            $this->cnf['additional'] = str_replace(' ', '', $this->cnf['additional']);
-            $this->cnf['additional'] = explode(',', $this->cnf['additional']);
-        } else $this->cnf['additional'] = array();
-
-        // ldap extension is needed
-        if (!function_exists('ldap_connect')) {
-            if ($this->cnf['debug'])
-                msg("AD Auth: PHP LDAP extension not found.",-1);
+        if(!function_exists('pg_connect')) {
+            $this->_debug("PgSQL err: PHP Postgres extension not found.", -1, __LINE__, __FILE__);
             $this->success = false;
             return;
         }
 
-        // Prepare SSO
-        if($_SERVER['REMOTE_USER'] && $this->cnf['sso']){
-             // remove possible NTLM domain
-             list($dom,$usr) = explode('\\',$_SERVER['REMOTE_USER'],2);
-             if(!$usr) $usr = $dom;
-
-             // remove possible Kerberos domain
-             list($usr,$dom) = explode('@',$usr);
+        $this->loadConfig();
 
-             $dom = strtolower($dom);
-             $_SERVER['REMOTE_USER'] = $usr;
-
-             // we need to simulate a login
-             if(empty($_COOKIE[DOKU_COOKIE])){
-                 $_REQUEST['u'] = $_SERVER['REMOTE_USER'];
-                 $_REQUEST['p'] = 'sso_only';
-             }
+        // set capabilities based upon config strings set
+        if(empty($this->conf['user']) ||
+            empty($this->conf['password']) || empty($this->conf['database'])
+        ) {
+            $this->_debug("PgSQL err: insufficient configuration.", -1, __LINE__, __FILE__);
+            $this->success = false;
+            return;
         }
 
-        // prepare adLDAP standard configuration
-        $this->opts = $this->cnf;
+        $this->cando['addUser']   = $this->_chkcnf(
+            array(
+                 'getUserInfo',
+                 'getGroups',
+                 'addUser',
+                 'getUserID',
+                 'getGroupID',
+                 'addGroup',
+                 'addUserGroup'
+            )
+        );
+        $this->cando['delUser']   = $this->_chkcnf(
+            array(
+                 'getUserID',
+                 'delUser',
+                 'delUserRefs'
+            )
+        );
+        $this->cando['modLogin']  = $this->_chkcnf(
+            array(
+                 'getUserID',
+                 'updateUser',
+                 'UpdateTarget'
+            )
+        );
+        $this->cando['modPass']   = $this->cando['modLogin'];
+        $this->cando['modName']   = $this->cando['modLogin'];
+        $this->cando['modMail']   = $this->cando['modLogin'];
+        $this->cando['modGroups'] = $this->_chkcnf(
+            array(
+                 'getUserID',
+                 'getGroups',
+                 'getGroupID',
+                 'addGroup',
+                 'addUserGroup',
+                 'delGroup',
+                 'getGroupID',
+                 'delUserGroup'
+            )
+        );
+        /* getGroups is not yet supported
+           $this->cando['getGroups']    = $this->_chkcnf(array('getGroups',
+           'getGroupID')); */
+        $this->cando['getUsers']     = $this->_chkcnf(
+            array(
+                 'getUsers',
+                 'getUserInfo',
+                 'getGroups'
+            )
+        );
+        $this->cando['getUserCount'] = $this->_chkcnf(array('getUsers'));
+    }
 
-        // add possible domain specific configuration
-        if($dom && is_array($this->cnf[$dom])) foreach($this->cnf[$dom] as $key => $val){
-            $this->opts[$key] = $val;
+    /**
+     * Check if the given config strings are set
+     *
+     * @author  Matthias Grimm 
+     *
+     * @param   array $keys
+     * @param   bool  $wop
+     * @return  bool
+     */
+    protected function _chkcnf($keys, $wop = false) {
+        foreach($keys as $key) {
+            if(empty($this->conf[$key])) return false;
         }
+        return true;
+    }
 
-        // handle multiple AD servers
-        $this->opts['domain_controllers'] = explode(',',$this->opts['domain_controllers']);
-        $this->opts['domain_controllers'] = array_map('trim',$this->opts['domain_controllers']);
-        $this->opts['domain_controllers'] = array_filter($this->opts['domain_controllers']);
+    /**
+     * Counts users which meet certain $filter criteria.
+     *
+     * @author  Matthias Grimm 
+     *
+     * @param  array  $filter  filter criteria in item/pattern pairs
+     * @return int count of found users.
+     */
+    public function getUserCount($filter = array()) {
+        $rc = 0;
 
-        // we can change the password if SSL is set
-        if($this->opts['use_ssl'] || $this->opts['use_tls']){
-            $this->cando['modPass'] = true;
+        if($this->_openDB()) {
+            $sql = $this->_createSQLFilter($this->conf['getUsers'], $filter);
+
+            // no equivalent of SQL_CALC_FOUND_ROWS in pgsql?
+            if(($result = $this->_queryDB($sql))) {
+                $rc = count($result);
+            }
+            $this->_closeDB();
         }
-        $this->cando['modName'] = true;
-        $this->cando['modMail'] = true;
+        return $rc;
     }
 
     /**
-     * Check user+password [required auth function]
+     * Bulk retrieval of user data
      *
-     * Checks if the given user exists and the given
-     * plaintext password is correct by trying to bind
-     * to the LDAP server
+     * @author  Matthias Grimm 
      *
-     * @author  James Van Lommel 
-     * @return  bool
+     * @param   int   $first     index of first user to be returned
+     * @param   int   $limit     max number of users to be returned
+     * @param   array $filter    array of field/pattern pairs
+     * @return  array userinfo (refer getUserData for internal userinfo details)
      */
-    function checkPass($user, $pass){
-        if($_SERVER['REMOTE_USER'] &&
-           $_SERVER['REMOTE_USER'] == $user &&
-           $this->cnf['sso']) return true;
+    public function retrieveUsers($first = 0, $limit = 10, $filter = array()) {
+        $out = array();
+
+        if($this->_openDB()) {
+            $this->_lockTables("READ");
+            $sql = $this->_createSQLFilter($this->conf['getUsers'], $filter);
+            $sql .= " ".$this->conf['SortOrder']." LIMIT $limit OFFSET $first";
+            $result = $this->_queryDB($sql);
+
+            foreach($result as $user)
+                if(($info = $this->_getUserInfo($user['user'])))
+                    $out[$user['user']] = $info;
 
-        if(!$this->_init()) return false;
-        return $this->adldap->authenticate($user, $pass);
+            $this->_unlockTables();
+            $this->_closeDB();
+        }
+        return $out;
     }
 
+    // @inherit function joinGroup($user, $group)
+    // @inherit function leaveGroup($user, $group) {
+
     /**
-     * Return user info [required auth function]
+     * Adds a user to a group.
      *
-     * Returns info about the given user needs to contain
-     * at least these fields:
+     * If $force is set to true non existing groups would be created.
      *
-     * name string  full name of the user
-     * mail string  email address of the user
-     * grps array   list of groups the user is in
+     * The database connection must already be established. Otherwise
+     * this function does nothing and returns 'false'.
      *
-     * This LDAP specific function returns the following
-     * addional fields:
+     * @author Matthias Grimm 
+     * @author Andreas Gohr   
      *
-     * dn   string  distinguished name (DN)
-     * uid  string  Posix User ID
-     *
-     * @author  James Van Lommel 
+     * @param   string $user    user to add to a group
+     * @param   string $group   name of the group
+     * @param   bool   $force   create missing groups
+     * @return  bool   true on success, false on error
      */
-   function getUserData($user){
-        global $conf;
-        if(!$this->_init()) return false;
-
-        $fields = array('mail','displayname','samaccountname');
-
-        // add additional fields to read
-        $fields = array_merge($fields, $this->cnf['additional']);
-        $fields = array_unique($fields);
-
-        //get info for given user
-        $result = $this->adldap->user_info($user, $fields);
-        //general user info
-        $info['name'] = $result[0]['displayname'][0];
-        $info['mail'] = $result[0]['mail'][0];
-        $info['uid']  = $result[0]['samaccountname'][0];
-        $info['dn']   = $result[0]['dn'];
-
-        // additional information
-        foreach ($this->cnf['additional'] as $field) {
-            if (isset($result[0][strtolower($field)])) {
-                $info[$field] = $result[0][strtolower($field)][0];
+    protected function _addUserToGroup($user, $group, $force = false) {
+        $newgroup = 0;
+
+        if(($this->dbcon) && ($user)) {
+            $gid = $this->_getGroupID($group);
+            if(!$gid) {
+                if($force) { // create missing groups
+                    $sql = str_replace('%{group}', addslashes($group), $this->conf['addGroup']);
+                    $this->_modifyDB($sql);
+                    //group should now exists try again to fetch it
+                    $gid      = $this->_getGroupID($group);
+                    $newgroup = 1; // group newly created
+                }
             }
-        }
-
-        // handle ActiveDirectory memberOf
-        $info['grps'] = $this->adldap->user_groups($user,(bool) $this->opts['recursive_groups']);
+            if(!$gid) return false; // group didn't exist and can't be created
 
-        if (is_array($info['grps'])) {
-            foreach ($info['grps'] as $ndx => $group) {
-                $info['grps'][$ndx] = $this->cleanGroup($group);
+            $sql = $this->conf['addUserGroup'];
+            if(strpos($sql, '%{uid}') !== false) {
+                $uid = $this->_getUserID($user);
+                $sql = str_replace('%{uid}', addslashes($uid), $sql);
+            }
+            $sql = str_replace('%{user}', addslashes($user), $sql);
+            $sql = str_replace('%{gid}', addslashes($gid), $sql);
+            $sql = str_replace('%{group}', addslashes($group), $sql);
+            if($this->_modifyDB($sql) !== false) return true;
+
+            if($newgroup) { // remove previously created group on error
+                $sql = str_replace('%{gid}', addslashes($gid), $this->conf['delGroup']);
+                $sql = str_replace('%{group}', addslashes($group), $sql);
+                $this->_modifyDB($sql);
             }
         }
-
-        // always add the default group to the list of groups
-        if(!is_array($info['grps']) || !in_array($conf['defaultgroup'],$info['grps'])){
-            $info['grps'][] = $conf['defaultgroup'];
-        }
-
-        return $info;
+        return false;
     }
 
+    // @inherit function _delUserFromGroup($user $group)
+    // @inherit function _getGroups($user)
+    // @inherit function _getUserID($user)
+
     /**
-     * Make AD group names usable by DokuWiki.
+     * Adds a new User to the database.
      *
-     * Removes backslashes ('\'), pound signs ('#'), and converts spaces to underscores.
+     * The database connection must already be established
+     * for this function to work. Otherwise it will return
+     * 'false'.
      *
-     * @author  James Van Lommel (jamesvl@gmail.com)
+     * @param  string $user  login of the user
+     * @param  string $pwd   encrypted password
+     * @param  string $name  full name of the user
+     * @param  string $mail  email address
+     * @param  array  $grps  array of groups the user should become member of
+     * @return bool
+     *
+     * @author  Andreas Gohr 
+     * @author  Chris Smith 
+     * @author  Matthias Grimm 
      */
-    function cleanGroup($name) {
-        $sName = str_replace('\\', '', $name);
-        $sName = str_replace('#', '', $sName);
-        $sName = preg_replace('[\s]', '_', $sName);
-        return $sName;
+    protected function _addUser($user, $pwd, $name, $mail, $grps) {
+        if($this->dbcon && is_array($grps)) {
+            $sql = str_replace('%{user}', addslashes($user), $this->conf['addUser']);
+            $sql = str_replace('%{pass}', addslashes($pwd), $sql);
+            $sql = str_replace('%{name}', addslashes($name), $sql);
+            $sql = str_replace('%{email}', addslashes($mail), $sql);
+            if($this->_modifyDB($sql)) {
+                $uid = $this->_getUserID($user);
+            } else {
+                return false;
+            }
+
+            $group = '';
+            $gid = false;
+
+            if($uid) {
+                foreach($grps as $group) {
+                    $gid = $this->_addUserToGroup($user, $group, 1);
+                    if($gid === false) break;
+                }
+
+                if($gid !== false){
+                    return true;
+                } else {
+                    /* remove the new user and all group relations if a group can't
+                     * be assigned. Newly created groups will remain in the database
+                     * and won't be removed. This might create orphaned groups but
+                     * is not a big issue so we ignore this problem here.
+                     */
+                    $this->_delUser($user);
+                    $this->_debug("PgSQL err: Adding user '$user' to group '$group' failed.", -1, __LINE__, __FILE__);
+                }
+            }
+        }
+        return false;
     }
 
     /**
-     * Sanitize user names
+     * Opens a connection to a database and saves the handle for further
+     * usage in the object. The successful call to this functions is
+     * essential for most functions in this object.
+     *
+     * @author Matthias Grimm 
+     *
+     * @return bool
      */
-    function cleanUser($name) {
-        return $this->cleanGroup($name);
+    protected function _openDB() {
+        if(!$this->dbcon) {
+            $dsn = $this->conf['server'] ? 'host='.$this->conf['server'] : '';
+            $dsn .= ' port='.$this->conf['port'];
+            $dsn .= ' dbname='.$this->conf['database'];
+            $dsn .= ' user='.$this->conf['user'];
+            $dsn .= ' password='.$this->conf['password'];
+
+            $con = @pg_connect($dsn);
+            if($con) {
+                $this->dbcon = $con;
+                return true; // connection and database successfully opened
+            } else {
+                $this->_debug(
+                        "PgSQL err: Connection to {$this->conf['user']}@{$this->conf['server']} not possible.",
+                        -1, __LINE__, __FILE__
+                    );
+            }
+            return false; // connection failed
+        }
+        return true; // connection already open
     }
 
     /**
-     * Most values in LDAP are case-insensitive
+     * Closes a database connection.
+     *
+     * @author Matthias Grimm 
      */
-    function isCaseSensitive(){
-        return false;
+    protected function _closeDB() {
+        if($this->dbcon) {
+            pg_close($this->dbcon);
+            $this->dbcon = 0;
+        }
     }
 
     /**
-     * Bulk retrieval of user data
+     * Sends a SQL query to the database and transforms the result into
+     * an associative array.
      *
-     * @author  Dominik Eckelmann 
-     * @param   start     index of first user to be returned
-     * @param   limit     max number of users to be returned
-     * @param   filter    array of field/pattern pairs, null for no filter
-     * @return  array of userinfo (refer getUserData for internal userinfo details)
+     * This function is only able to handle queries that returns a
+     * table such as SELECT.
+     *
+     * @author Matthias Grimm 
+     *
+     * @param  string $query  SQL string that contains the query
+     * @return array the result table
      */
-    function retrieveUsers($start=0,$limit=-1,$filter=array()) {
-        if(!$this->_init()) return false;
-
-        if ($this->users === null) {
-            //get info for given user
-            $result = $this->adldap->all_users();
-            if (!$result) return array();
-            $this->users = array_fill_keys($result, false);
-        }
-
-        $i = 0;
-        $count = 0;
-        $this->_constructPattern($filter);
-        $result = array();
-
-        foreach ($this->users as $user => &$info) {
-            if ($i++ < $start) {
-                continue;
-            }
-            if ($info === false) {
-                $info = $this->getUserData($user);
-            }
-            if ($this->_filter($user, $info)) {
-                $result[$user] = $info;
-                if (($limit >= 0) && (++$count >= $limit)) break;
+    protected function _queryDB($query) {
+        $resultarray = array();
+        if($this->dbcon) {
+            $result = @pg_query($this->dbcon, $query);
+            if($result) {
+                while(($t = pg_fetch_assoc($result)) !== false)
+                    $resultarray[] = $t;
+                pg_free_result($result);
+                return $resultarray;
+            } else{
+                $this->_debug('PgSQL err: '.pg_last_error($this->dbcon), -1, __LINE__, __FILE__);
             }
         }
-        return $result;
+        return false;
     }
 
     /**
-     * Modify user data
+     * Executes an update or insert query. This differs from the
+     * MySQL one because it does NOT return the last insertID
      *
-     * @param   $user      nick of the user to be changed
-     * @param   $changes   array of field/value pairs to be changed
-     * @return  bool
-    */
-    function modifyUser($user, $changes) {
-        $return = true;
-
-        // password changing
-        if(isset($changes['pass'])){
-            try {
-                $return = $this->adldap->user_password($user,$changes['pass']);
-            } catch (adLDAPException $e) {
-                if ($this->cnf['debug']) msg('AD Auth: '.$e->getMessage(), -1);
-                $return = false;
-            }
-            if(!$return) msg('AD Auth: failed to change the password. Maybe the password policy was not met?',-1);
-        }
-
-        // changing user data
-        $adchanges = array();
-        if(isset($changes['name'])){
-            // get first and last name
-            $parts = explode(' ',$changes['name']);
-            $adchanges['surname']   = array_pop($parts);
-            $adchanges['firstname'] = join(' ',$parts);
-            $adchanges['display_name'] = $changes['name'];
-        }
-        if(isset($changes['mail'])){
-            $adchanges['email'] = $changes['mail'];
-        }
-        if(count($adchanges)){
-            try {
-                $return = $return & $this->adldap->user_modify($user,$adchanges);
-            } catch (adLDAPException $e) {
-                if ($this->cnf['debug']) msg('AD Auth: '.$e->getMessage(), -1);
-                $return = false;
+     * @author Andreas Gohr 
+     */
+    protected function _modifyDB($query) {
+        if($this->dbcon) {
+            $result = @pg_query($this->dbcon, $query);
+            if($result) {
+                pg_free_result($result);
+                return true;
             }
+            $this->_debug('PgSQL err: '.pg_last_error($this->dbcon), -1, __LINE__, __FILE__);
         }
-
-        return $return;
+        return false;
     }
 
     /**
-     * Initialize the AdLDAP library and connect to the server
+     * Start a transaction
+     *
+     * @author Matthias Grimm 
+     *
+     * @param string $mode  could be 'READ' or 'WRITE'
+     * @return bool
      */
-    function _init(){
-        if(!is_null($this->adldap)) return true;
-
-        // connect
-        try {
-            $this->adldap = new adLDAP($this->opts);
-            if (isset($this->opts['ad_username']) && isset($this->opts['ad_password'])) {
-                $this->canDo['getUsers'] = true;
-            }
+    protected function _lockTables($mode) {
+        if($this->dbcon) {
+            $this->_modifyDB('BEGIN');
             return true;
-        } catch (adLDAPException $e) {
-            if ($this->cnf['debug']) {
-                msg('AD Auth: '.$e->getMessage(), -1);
-            }
-            $this->success = false;
-            $this->adldap  = null;
         }
         return false;
     }
 
     /**
-     * return 1 if $user + $info match $filter criteria, 0 otherwise
+     * Commit a transaction
      *
-     * @author   Chris Smith 
+     * @author Matthias Grimm 
      */
-    function _filter($user, $info) {
-        foreach ($this->_pattern as $item => $pattern) {
-            if ($item == 'user') {
-                if (!preg_match($pattern, $user)) return 0;
-            } else if ($item == 'grps') {
-                if (!count(preg_grep($pattern, $info['grps']))) return 0;
-            } else {
-                if (!preg_match($pattern, $info[$item])) return 0;
-            }
+    protected function _unlockTables() {
+        if($this->dbcon) {
+            $this->_modifyDB('COMMIT');
+            return true;
         }
-        return 1;
+        return false;
     }
 
-    function _constructPattern($filter) {
-        $this->_pattern = array();
-        foreach ($filter as $item => $pattern) {
-//          $this->_pattern[$item] = '/'.preg_quote($pattern,"/").'/i';          // don't allow regex characters
-            $this->_pattern[$item] = '/'.str_replace('/','\/',$pattern).'/i';    // allow regex characters
+    /**
+     * Escape a string for insertion into the database
+     *
+     * @author Andreas Gohr 
+     *
+     * @param  string  $string The string to escape
+     * @param  bool    $like   Escape wildcard chars as well?
+     * @return string
+     */
+    protected function _escape($string, $like = false) {
+        $string = pg_escape_string($string);
+        if($like) {
+            $string = addcslashes($string, '%_');
         }
+        return $string;
     }
 }
\ No newline at end of file
diff --git a/lib/plugins/authpgsql/conf/default.php b/lib/plugins/authpgsql/conf/default.php
new file mode 100644
index 000000000..401da80b7
--- /dev/null
+++ b/lib/plugins/authpgsql/conf/default.php
@@ -0,0 +1,3 @@
+
Date: Fri, 9 Nov 2012 17:29:24 +0100
Subject: fixed authplain

* code/PHP5 cleanup
---
 lib/plugins/authplain/auth.php | 215 +++++++++++++++++++++++------------------
 1 file changed, 122 insertions(+), 93 deletions(-)

diff --git a/lib/plugins/authplain/auth.php b/lib/plugins/authplain/auth.php
index 2e72bbd79..3416ede89 100644
--- a/lib/plugins/authplain/auth.php
+++ b/lib/plugins/authplain/auth.php
@@ -11,8 +11,11 @@ if(!defined('DOKU_INC')) die();
  * @author     Jan Schumann 
  */
 class auth_plugin_authplain extends DokuWiki_Auth_Plugin {
-    var $users = null;
-    var $_pattern = array();
+    /** @var array user cache */
+    protected $users = null;
+
+    /** @var array filter pattern */
+    protected $_pattern = array();
 
     /**
      * Constructor
@@ -22,21 +25,21 @@ class auth_plugin_authplain extends DokuWiki_Auth_Plugin {
      *
      * @author  Christopher Smith 
      */
-    function __construct() {
+    public function __construct() {
         parent::__construct();
         global $config_cascade;
 
-        if (!@is_readable($config_cascade['plainauth.users']['default'])){
+        if(!@is_readable($config_cascade['plainauth.users']['default'])) {
             $this->success = false;
-        }else{
-            if(@is_writable($config_cascade['plainauth.users']['default'])){
-                $this->cando['addUser']      = true;
-                $this->cando['delUser']      = true;
-                $this->cando['modLogin']     = true;
-                $this->cando['modPass']      = true;
-                $this->cando['modName']      = true;
-                $this->cando['modMail']      = true;
-                $this->cando['modGroups']    = true;
+        } else {
+            if(@is_writable($config_cascade['plainauth.users']['default'])) {
+                $this->cando['addUser']   = true;
+                $this->cando['delUser']   = true;
+                $this->cando['modLogin']  = true;
+                $this->cando['modPass']   = true;
+                $this->cando['modName']   = true;
+                $this->cando['modMail']   = true;
+                $this->cando['modGroups'] = true;
             }
             $this->cando['getUsers']     = true;
             $this->cando['getUserCount'] = true;
@@ -44,20 +47,21 @@ class auth_plugin_authplain extends DokuWiki_Auth_Plugin {
     }
 
     /**
-     * Check user+password [required auth function]
+     * Check user+password
      *
      * Checks if the given user exists and the given
      * plaintext password is correct
      *
      * @author  Andreas Gohr 
+     * @param string $user
+     * @param string $pass
      * @return  bool
      */
-    function checkPass($user,$pass){
-
+    public function checkPass($user, $pass) {
         $userinfo = $this->getUserData($user);
-        if ($userinfo === false) return false;
+        if($userinfo === false) return false;
 
-        return auth_verifyPassword($pass,$this->users[$user]['pass']);
+        return auth_verifyPassword($pass, $this->users[$user]['pass']);
     }
 
     /**
@@ -71,9 +75,10 @@ class auth_plugin_authplain extends DokuWiki_Auth_Plugin {
      * grps array   list of groups the user is in
      *
      * @author  Andreas Gohr 
+     * @param string $user
+     * @return array|bool
      */
-    function getUserData($user){
-
+    public function getUserData($user) {
         if($this->users === null) $this->_loadUserData();
         return isset($this->users[$user]) ? $this->users[$user] : false;
     }
@@ -89,30 +94,39 @@ class auth_plugin_authplain extends DokuWiki_Auth_Plugin {
      *
      * @author  Andreas Gohr 
      * @author  Chris Smith 
+     *
+     * @param string $user
+     * @param string $pwd
+     * @param string $name
+     * @param string $mail
+     * @param array  $grps
+     * @return bool|null|string
      */
-    function createUser($user,$pwd,$name,$mail,$grps=null){
+    public function createUser($user, $pwd, $name, $mail, $grps = null) {
         global $conf;
         global $config_cascade;
 
         // user mustn't already exist
-        if ($this->getUserData($user) !== false) return false;
+        if($this->getUserData($user) !== false) return false;
 
         $pass = auth_cryptPassword($pwd);
 
         // set default group if no groups specified
-        if (!is_array($grps)) $grps = array($conf['defaultgroup']);
+        if(!is_array($grps)) $grps = array($conf['defaultgroup']);
 
         // prepare user line
-        $groups = join(',',$grps);
-        $userline = join(':',array($user,$pass,$name,$mail,$groups))."\n";
+        $groups   = join(',', $grps);
+        $userline = join(':', array($user, $pass, $name, $mail, $groups))."\n";
 
-        if (io_saveFile($config_cascade['plainauth.users']['default'],$userline,true)) {
-            $this->users[$user] = compact('pass','name','mail','grps');
+        if(io_saveFile($config_cascade['plainauth.users']['default'], $userline, true)) {
+            $this->users[$user] = compact('pass', 'name', 'mail', 'grps');
             return $pwd;
         }
 
-        msg('The '.$config_cascade['plainauth.users']['default'].
-                ' file is not writable. Please inform the Wiki-Admin',-1);
+        msg(
+            'The '.$config_cascade['plainauth.users']['default'].
+                ' file is not writable. Please inform the Wiki-Admin', -1
+        );
         return null;
     }
 
@@ -120,43 +134,41 @@ class auth_plugin_authplain extends DokuWiki_Auth_Plugin {
      * Modify user data
      *
      * @author  Chris Smith 
-     * @param   $user      nick of the user to be changed
-     * @param   $changes   array of field/value pairs to be changed (password will be clear text)
+     * @param   string $user      nick of the user to be changed
+     * @param   array  $changes   array of field/value pairs to be changed (password will be clear text)
      * @return  bool
      */
-    function modifyUser($user, $changes) {
-        global $conf;
+    public function modifyUser($user, $changes) {
         global $ACT;
-        global $INFO;
         global $config_cascade;
 
         // sanity checks, user must already exist and there must be something to change
-        if (($userinfo = $this->getUserData($user)) === false) return false;
-        if (!is_array($changes) || !count($changes)) return true;
+        if(($userinfo = $this->getUserData($user)) === false) return false;
+        if(!is_array($changes) || !count($changes)) return true;
 
         // update userinfo with new data, remembering to encrypt any password
         $newuser = $user;
-        foreach ($changes as $field => $value) {
-            if ($field == 'user') {
+        foreach($changes as $field => $value) {
+            if($field == 'user') {
                 $newuser = $value;
                 continue;
             }
-            if ($field == 'pass') $value = auth_cryptPassword($value);
+            if($field == 'pass') $value = auth_cryptPassword($value);
             $userinfo[$field] = $value;
         }
 
-        $groups = join(',',$userinfo['grps']);
-        $userline = join(':',array($newuser, $userinfo['pass'], $userinfo['name'], $userinfo['mail'], $groups))."\n";
+        $groups   = join(',', $userinfo['grps']);
+        $userline = join(':', array($newuser, $userinfo['pass'], $userinfo['name'], $userinfo['mail'], $groups))."\n";
 
-        if (!$this->deleteUsers(array($user))) {
-            msg('Unable to modify user data. Please inform the Wiki-Admin',-1);
+        if(!$this->deleteUsers(array($user))) {
+            msg('Unable to modify user data. Please inform the Wiki-Admin', -1);
             return false;
         }
 
-        if (!io_saveFile($config_cascade['plainauth.users']['default'],$userline,true)) {
-            msg('There was an error modifying your user data. You should register again.',-1);
+        if(!io_saveFile($config_cascade['plainauth.users']['default'], $userline, true)) {
+            msg('There was an error modifying your user data. You should register again.', -1);
             // FIXME, user has been deleted but not recreated, should force a logout and redirect to login page
-            $ACT == 'register';
+            $ACT = 'register';
             return false;
         }
 
@@ -171,24 +183,24 @@ class auth_plugin_authplain extends DokuWiki_Auth_Plugin {
      * @param   array  $users   array of users to be deleted
      * @return  int             the number of users deleted
      */
-    function deleteUsers($users) {
+    public function deleteUsers($users) {
         global $config_cascade;
 
-        if (!is_array($users) || empty($users)) return 0;
+        if(!is_array($users) || empty($users)) return 0;
 
-        if ($this->users === null) $this->_loadUserData();
+        if($this->users === null) $this->_loadUserData();
 
         $deleted = array();
-        foreach ($users as $user) {
-            if (isset($this->users[$user])) $deleted[] = preg_quote($user,'/');
+        foreach($users as $user) {
+            if(isset($this->users[$user])) $deleted[] = preg_quote($user, '/');
         }
 
-        if (empty($deleted)) return 0;
+        if(empty($deleted)) return 0;
 
-        $pattern = '/^('.join('|',$deleted).'):/';
+        $pattern = '/^('.join('|', $deleted).'):/';
 
-        if (io_deleteFromFile($config_cascade['plainauth.users']['default'],$pattern,true)) {
-            foreach ($deleted as $user) unset($this->users[$user]);
+        if(io_deleteFromFile($config_cascade['plainauth.users']['default'], $pattern, true)) {
+            foreach($deleted as $user) unset($this->users[$user]);
             return count($deleted);
         }
 
@@ -203,17 +215,20 @@ class auth_plugin_authplain extends DokuWiki_Auth_Plugin {
      * Return a count of the number of user which meet $filter criteria
      *
      * @author  Chris Smith 
+     *
+     * @param array $filter
+     * @return int
      */
-    function getUserCount($filter=array()) {
+    public function getUserCount($filter = array()) {
 
         if($this->users === null) $this->_loadUserData();
 
-        if (!count($filter)) return count($this->users);
+        if(!count($filter)) return count($this->users);
 
         $count = 0;
         $this->_constructPattern($filter);
 
-        foreach ($this->users as $user => $info) {
+        foreach($this->users as $user => $info) {
             $count += $this->_filter($user, $info);
         }
 
@@ -224,28 +239,29 @@ class auth_plugin_authplain extends DokuWiki_Auth_Plugin {
      * Bulk retrieval of user data
      *
      * @author  Chris Smith 
-     * @param   start     index of first user to be returned
-     * @param   limit     max number of users to be returned
-     * @param   filter    array of field/pattern pairs
-     * @return  array of userinfo (refer getUserData for internal userinfo details)
+     *
+     * @param   int   $start index of first user to be returned
+     * @param   int   $limit max number of users to be returned
+     * @param   array $filter array of field/pattern pairs
+     * @return  array userinfo (refer getUserData for internal userinfo details)
      */
-    function retrieveUsers($start=0,$limit=0,$filter=array()) {
+    public function retrieveUsers($start = 0, $limit = 0, $filter = array()) {
 
-        if ($this->users === null) $this->_loadUserData();
+        if($this->users === null) $this->_loadUserData();
 
         ksort($this->users);
 
-        $i = 0;
+        $i     = 0;
         $count = 0;
-        $out = array();
+        $out   = array();
         $this->_constructPattern($filter);
 
-        foreach ($this->users as $user => $info) {
-            if ($this->_filter($user, $info)) {
-                if ($i >= $start) {
+        foreach($this->users as $user => $info) {
+            if($this->_filter($user, $info)) {
+                if($i >= $start) {
                     $out[$user] = $info;
                     $count++;
-                    if (($limit > 0) && ($count >= $limit)) break;
+                    if(($limit > 0) && ($count >= $limit)) break;
                 }
                 $i++;
             }
@@ -256,18 +272,24 @@ class auth_plugin_authplain extends DokuWiki_Auth_Plugin {
 
     /**
      * Only valid pageid's (no namespaces) for usernames
+     *
+     * @param string $user
+     * @return string
      */
-    function cleanUser($user){
+    public function cleanUser($user) {
         global $conf;
-        return cleanID(str_replace(':',$conf['sepchar'],$user));
+        return cleanID(str_replace(':', $conf['sepchar'], $user));
     }
 
     /**
      * Only valid pageid's (no namespaces) for groupnames
+     *
+     * @param string $group
+     * @return string
      */
-    function cleanGroup($group){
+    public function cleanGroup($group) {
         global $conf;
-        return cleanID(str_replace(':',$conf['sepchar'],$group));
+        return cleanID(str_replace(':', $conf['sepchar'], $group));
     }
 
     /**
@@ -277,7 +299,7 @@ class auth_plugin_authplain extends DokuWiki_Auth_Plugin {
      *
      * @author  Andreas Gohr 
      */
-    function _loadUserData(){
+    protected function _loadUserData() {
         global $config_cascade;
 
         $this->users = array();
@@ -285,13 +307,13 @@ class auth_plugin_authplain extends DokuWiki_Auth_Plugin {
         if(!@file_exists($config_cascade['plainauth.users']['default'])) return;
 
         $lines = file($config_cascade['plainauth.users']['default']);
-        foreach($lines as $line){
-            $line = preg_replace('/#.*$/','',$line); //ignore comments
+        foreach($lines as $line) {
+            $line = preg_replace('/#.*$/', '', $line); //ignore comments
             $line = trim($line);
             if(empty($line)) continue;
 
-            $row    = explode(":",$line,5);
-            $groups = array_values(array_filter(explode(",",$row[4])));
+            $row    = explode(":", $line, 5);
+            $groups = array_values(array_filter(explode(",", $row[4])));
 
             $this->users[$row[0]]['pass'] = $row[1];
             $this->users[$row[0]]['name'] = urldecode($row[2]);
@@ -301,29 +323,36 @@ class auth_plugin_authplain extends DokuWiki_Auth_Plugin {
     }
 
     /**
-     * return 1 if $user + $info match $filter criteria, 0 otherwise
+     * return true if $user + $info match $filter criteria, false otherwise
      *
      * @author   Chris Smith 
+     *
+     * @param string $user User login
+     * @param array  $info User's userinfo array
+     * @return bool
      */
-    function _filter($user, $info) {
-        // FIXME
-        foreach ($this->_pattern as $item => $pattern) {
-            if ($item == 'user') {
-                if (!preg_match($pattern, $user)) return 0;
-            } else if ($item == 'grps') {
-                if (!count(preg_grep($pattern, $info['grps']))) return 0;
+    protected function _filter($user, $info) {
+        foreach($this->_pattern as $item => $pattern) {
+            if($item == 'user') {
+                if(!preg_match($pattern, $user)) return false;
+            } else if($item == 'grps') {
+                if(!count(preg_grep($pattern, $info['grps']))) return false;
             } else {
-                if (!preg_match($pattern, $info[$item])) return 0;
+                if(!preg_match($pattern, $info[$item])) return false;
             }
         }
-        return 1;
+        return true;
     }
 
-    function _constructPattern($filter) {
+    /**
+     * construct a filter pattern
+     *
+     * @param array $filter
+     */
+    protected function _constructPattern($filter) {
         $this->_pattern = array();
-        foreach ($filter as $item => $pattern) {
-            //        $this->_pattern[$item] = '/'.preg_quote($pattern,"/").'/i';          // don't allow regex characters
-            $this->_pattern[$item] = '/'.str_replace('/','\/',$pattern).'/i';    // allow regex characters
+        foreach($filter as $item => $pattern) {
+            $this->_pattern[$item] = '/'.str_replace('/', '\/', $pattern).'/i'; // allow regex characters
         }
     }
 }
\ No newline at end of file
-- 
cgit v1.2.3


From c189f40b497af53aa16c5ff8f01383d848bc9ac3 Mon Sep 17 00:00:00 2001
From: Andreas Gohr 
Date: Fri, 9 Nov 2012 17:29:47 +0100
Subject: another gitignore path

---
 .gitignore | 1 +
 1 file changed, 1 insertion(+)

diff --git a/.gitignore b/.gitignore
index d05f82856..c725108c4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -35,6 +35,7 @@
 !/lib/plugins/authldap
 !/lib/plugins/authmysql
 !/lib/plugins/authpgsql
+!/lib/plugins/authplain
 !/lib/plugins/acl
 !/lib/plugins/config
 !/lib/plugins/info
-- 
cgit v1.2.3


From 23e8f02b8aa3a74fed70f1a496bdb5423908133a Mon Sep 17 00:00:00 2001
From: Andreas Gohr 
Date: Sat, 10 Nov 2012 16:11:30 +0100
Subject: added 'text' to config plugin for multi line text configs

---
 lib/plugins/config/settings/config.class.php    | 33 ++++++++++++++++++++++---
 lib/plugins/config/settings/config.metadata.php |  1 +
 2 files changed, 31 insertions(+), 3 deletions(-)

diff --git a/lib/plugins/config/settings/config.class.php b/lib/plugins/config/settings/config.class.php
index 8c48018d7..9f98231e3 100644
--- a/lib/plugins/config/settings/config.class.php
+++ b/lib/plugins/config/settings/config.class.php
@@ -35,6 +35,7 @@ if (!class_exists('configuration')) {
           msg('No configuration metadata found at - '.htmlspecialchars($datafile),-1);
           return;
         }
+        $meta = array();
         include($datafile);
 
         if (isset($config['varname'])) $this->_name = $config['varname'];
@@ -68,6 +69,7 @@ if (!class_exists('configuration')) {
           $keys = array_merge(array_keys($this->_metadata),array_keys($default), array_keys($local), array_keys($protected));
           $keys = array_unique($keys);
 
+          $param = null;
           foreach ($keys as $key) {
             if (isset($this->_metadata[$key])) {
               $class = $this->_metadata[$key][0];
@@ -425,11 +427,9 @@ if (!class_exists('setting')) {
       $out = '';
 
       if ($fmt=='php') {
-        // translation string needs to be improved FIXME
-        $tr = array("\n"=>'\n', "\r"=>'\r', "\t"=>'\t', "\\" => '\\\\', "'" => '\\\'');
         $tr = array("\\" => '\\\\', "'" => '\\\'');
 
-        $out =  '$'.$var."['".$this->_out_key()."'] = '".strtr($this->_local, $tr)."';\n";
+        $out =  '$'.$var."['".$this->_out_key()."'] = '".strtr( cleanText($this->_local), $tr)."';\n";
       }
 
       return $out;
@@ -494,6 +494,33 @@ if (!class_exists('setting_string')) {
   }
 }
 
+if (!class_exists('setting_text')) {
+    class setting_text extends setting {
+        function html(&$plugin, $echo=false) {
+            $value = '';
+            $disable = '';
+
+            if ($this->is_protected()) {
+                $value = $this->_protected;
+                $disable = 'disabled="disabled"';
+            } else {
+                if ($echo && $this->_error) {
+                    $value = $this->_input;
+                } else {
+                    $value = is_null($this->_local) ? $this->_default : $this->_local;
+                }
+            }
+
+            $key = htmlspecialchars($this->_key);
+            $value = formText($value);
+
+            $label = '';
+            $input = '';
+            return array($label,$input);
+        }
+    }
+}
+
 if (!class_exists('setting_password')) {
   class setting_password extends setting_string {
 
diff --git a/lib/plugins/config/settings/config.metadata.php b/lib/plugins/config/settings/config.metadata.php
index 3607f56c6..33ebb7fd8 100644
--- a/lib/plugins/config/settings/config.metadata.php
+++ b/lib/plugins/config/settings/config.metadata.php
@@ -15,6 +15,7 @@
  *   -------------------------------------------
  *   ''             - default class ('setting'), textarea, minimal input validation, setting output in quotes
  *   'string'       - single line text input, minimal input validation, setting output in quotes
+ *   'text'         - multi line text input, minimal input validation, setting output in quotes
  *   'numeric'      - text input, accepts numbers and arithmetic operators, setting output without quotes
  *                    if given the '_min' and '_max' parameters are used for validation
  *   'numericopt'   - like above, but accepts empty values
-- 
cgit v1.2.3


From 7e29378446eeb33892837048b31b4180e26ccd1f Mon Sep 17 00:00:00 2001
From: Andreas Gohr 
Date: Sat, 10 Nov 2012 16:22:34 +0100
Subject: partial revert of 23e8f02b8aa3a74fed70f1a496bdb5423908133a

okay. I can't read. we already had a multiline config. It's the default.
So I reverted my change, except for making use of formText/cleanText for
proper line ending handling and I added made focused textareas a bit
larger.
---
 lib/plugins/config/settings/config.class.php    | 29 +------------------------
 lib/plugins/config/settings/config.metadata.php |  1 -
 lib/plugins/config/style.css                    |  4 ++++
 3 files changed, 5 insertions(+), 29 deletions(-)

diff --git a/lib/plugins/config/settings/config.class.php b/lib/plugins/config/settings/config.class.php
index 9f98231e3..e6d085bcb 100644
--- a/lib/plugins/config/settings/config.class.php
+++ b/lib/plugins/config/settings/config.class.php
@@ -409,7 +409,7 @@ if (!class_exists('setting')) {
         }
 
         $key = htmlspecialchars($this->_key);
-        $value = htmlspecialchars($value);
+        $value = formText($value);
 
         $label = '';
         $input = '';
@@ -494,33 +494,6 @@ if (!class_exists('setting_string')) {
   }
 }
 
-if (!class_exists('setting_text')) {
-    class setting_text extends setting {
-        function html(&$plugin, $echo=false) {
-            $value = '';
-            $disable = '';
-
-            if ($this->is_protected()) {
-                $value = $this->_protected;
-                $disable = 'disabled="disabled"';
-            } else {
-                if ($echo && $this->_error) {
-                    $value = $this->_input;
-                } else {
-                    $value = is_null($this->_local) ? $this->_default : $this->_local;
-                }
-            }
-
-            $key = htmlspecialchars($this->_key);
-            $value = formText($value);
-
-            $label = '';
-            $input = '';
-            return array($label,$input);
-        }
-    }
-}
-
 if (!class_exists('setting_password')) {
   class setting_password extends setting_string {
 
diff --git a/lib/plugins/config/settings/config.metadata.php b/lib/plugins/config/settings/config.metadata.php
index 33ebb7fd8..3607f56c6 100644
--- a/lib/plugins/config/settings/config.metadata.php
+++ b/lib/plugins/config/settings/config.metadata.php
@@ -15,7 +15,6 @@
  *   -------------------------------------------
  *   ''             - default class ('setting'), textarea, minimal input validation, setting output in quotes
  *   'string'       - single line text input, minimal input validation, setting output in quotes
- *   'text'         - multi line text input, minimal input validation, setting output in quotes
  *   'numeric'      - text input, accepts numbers and arithmetic operators, setting output without quotes
  *                    if given the '_min' and '_max' parameters are used for validation
  *   'numericopt'   - like above, but accepts empty values
diff --git a/lib/plugins/config/style.css b/lib/plugins/config/style.css
index 1be94feb9..397328937 100644
--- a/lib/plugins/config/style.css
+++ b/lib/plugins/config/style.css
@@ -104,6 +104,10 @@
     height: 4em;
 }
 
+#config__manager td textarea.edit:focus {
+    height: 10em;
+}
+
 #config__manager tr .input,
 #config__manager tr input,
 #config__manager tr textarea,
-- 
cgit v1.2.3


From 3295f40a380553bb3f7f3018cee2e4462e0be417 Mon Sep 17 00:00:00 2001
From: Andreas Gohr 
Date: Sat, 10 Nov 2012 16:35:16 +0100
Subject: fixed saving in config plugin

Saving worked, but did you log out everytime. Now it is checked if the
auth mechanism was actually changed before assuming the login is
invalid.
---
 lib/plugins/config/admin.php                |  3 +--
 lib/plugins/config/settings/extra.class.php | 15 +++++++++------
 2 files changed, 10 insertions(+), 8 deletions(-)

diff --git a/lib/plugins/config/admin.php b/lib/plugins/config/admin.php
index 0d314d2e6..4d15bfd85 100644
--- a/lib/plugins/config/admin.php
+++ b/lib/plugins/config/admin.php
@@ -65,8 +65,7 @@ class admin_plugin_config extends DokuWiki_Admin_Plugin {
         // save state & force a page reload to get the new settings to take effect
         $_SESSION['PLUGIN_CONFIG'] = array('state' => 'updated', 'time' => time());
         $this->_close_session();
-        header("Location: ".wl($ID,array('do'=>'admin','page'=>'config'),true,'&'));
-        exit();
+        send_redirect(wl($ID,array('do'=>'admin','page'=>'config'),true,'&'));
       }
 
       $this->_close_session();
diff --git a/lib/plugins/config/settings/extra.class.php b/lib/plugins/config/settings/extra.class.php
index f6adf1c18..6998e1fbf 100644
--- a/lib/plugins/config/settings/extra.class.php
+++ b/lib/plugins/config/settings/extra.class.php
@@ -64,7 +64,7 @@ if (!class_exists('setting_authtype')) {
     		// reject disabled plugins
     		if ($plugin_controller->isdisabled($input)) {
 	    		$this->_error = true;
-	    		msg('Auth type ' . $input . ' is disabled.');
+	    		msg('Auth type ' . $input . ' is disabled.', -1);
 	    		return false;
     		}
 
@@ -74,21 +74,24 @@ if (!class_exists('setting_authtype')) {
 	    	// @TODO: throw an error in plugin controller instead of returning null
 	    	if (is_null($auth_plugin)) {
 	    		$this->_error = true;
-	    		msg('Cannot load Auth Plugin "' . $input . '"');
+	    		msg('Cannot load Auth Plugin "' . $input . '"', -1);
 	    		return false;
 	    	}
 
 	    	// verify proper instanciation (is this really a plugin?) @TODO use instanceof? impement interface?
 	    	if (is_object($auth_plugin) && !method_exists($auth_plugin, 'getPluginName')) {
 	    		$this->_error = true;
-				msg('Cannot create Auth Plugin "' . $input . '"');
+				msg('Cannot create Auth Plugin "' . $input . '"', -1);
 	    		return false;
 	    	}
     	}
 
-    	msg('Successfully changed auth system. Please re-login.');
-    	auth_logoff();
-
+        // did we change the auth type? logout
+        global $conf;
+        if($conf['authtype'] != $input) {
+    	    msg('Authentication system changed. Please re-login.');
+    	    auth_logoff();
+        }
     	return true;
     }
   }
-- 
cgit v1.2.3


From 89d02586756515c9fb68a348e99a787d95e999a2 Mon Sep 17 00:00:00 2001
From: Andreas Gohr 
Date: Sat, 10 Nov 2012 18:12:39 +0100
Subject: config manager: removed dead/commented code

---
 lib/plugins/config/settings/config.class.php | 13 -------------
 1 file changed, 13 deletions(-)

diff --git a/lib/plugins/config/settings/config.class.php b/lib/plugins/config/settings/config.class.php
index 8c48018d7..ebf638526 100644
--- a/lib/plugins/config/settings/config.class.php
+++ b/lib/plugins/config/settings/config.class.php
@@ -45,14 +45,8 @@ if (!class_exists('configuration')) {
         $this->_local_files = $config_cascade['main']['local'];
         $this->_protected_files = $config_cascade['main']['protected'];
 
-#        if (isset($file['default'])) $this->_default_file = $file['default'];
-#        if (isset($file['local'])) $this->_local_file = $file['local'];
-#        if (isset($file['protected'])) $this->_protected_file = $file['protected'];
-
         $this->locked = $this->_is_locked();
-
         $this->_metadata = array_merge($meta, $this->get_plugintpl_metadata($conf['template']));
-
         $this->retrieve_settings();
     }
 
@@ -147,7 +141,6 @@ if (!class_exists('configuration')) {
       if (!$file) return array();
 
       $config = array();
-#      $file = eval('return '.$file.';');
 
       if ($this->_format == 'php') {
 
@@ -195,9 +188,6 @@ if (!class_exists('configuration')) {
     function _out_footer() {
       $out = '';
       if ($this->_format == 'php') {
- #         if ($this->_protected_file) {
- #           $out .= "\n@include(".$this->_protected_file.");\n";
- #         }
           $out .= "\n// end auto-generated content\n";
       }
 
@@ -209,7 +199,6 @@ if (!class_exists('configuration')) {
     function _is_locked() {
       if (!$this->_local_files) return true;
 
-#      $local = eval('return '.$this->_local_file.';');
       $local = $this->_local_files[0];
 
       if (!is_writable(dirname($local))) return true;
@@ -425,8 +414,6 @@ if (!class_exists('setting')) {
       $out = '';
 
       if ($fmt=='php') {
-        // translation string needs to be improved FIXME
-        $tr = array("\n"=>'\n', "\r"=>'\r', "\t"=>'\t', "\\" => '\\\\', "'" => '\\\'');
         $tr = array("\\" => '\\\\', "'" => '\\\'');
 
         $out =  '$'.$var."['".$this->_out_key()."'] = '".strtr($this->_local, $tr)."';\n";
-- 
cgit v1.2.3


From b8f41ef0bac4e82cb3b02cd318efaddbaaeb1a78 Mon Sep 17 00:00:00 2001
From: Andreas Gohr 
Date: Sat, 10 Nov 2012 18:13:09 +0100
Subject: config manager: let PHP parse the config file

Until now, the config manager did read and parse the various PHP config
files itself. This fails for more complex setups like arrays.

I'm not really sure why this was done. This patch replaces the parsing
with a simple include() call. Everything still seems to work.
---
 lib/plugins/config/settings/config.class.php | 25 +++----------------------
 1 file changed, 3 insertions(+), 22 deletions(-)

diff --git a/lib/plugins/config/settings/config.class.php b/lib/plugins/config/settings/config.class.php
index ebf638526..722c8df7b 100644
--- a/lib/plugins/config/settings/config.class.php
+++ b/lib/plugins/config/settings/config.class.php
@@ -139,32 +139,13 @@ if (!class_exists('configuration')) {
     function _read_config($file) {
 
       if (!$file) return array();
+      if (!file_exists($file)) return array();
 
       $config = array();
 
       if ($this->_format == 'php') {
-
-        if(@file_exists($file)){
-            $contents = @php_strip_whitespace($file);
-        }else{
-            $contents = '';
-        }
-        $pattern = '/\$'.$this->_name.'\[[\'"]([^=]+)[\'"]\] ?= ?(.*?);(?=[^;]*(?:\$'.$this->_name.'|$))/s';
-        $matches=array();
-        preg_match_all($pattern,$contents,$matches,PREG_SET_ORDER);
-
-        for ($i=0; $i'\\','\\\''=>'\'','\\"'=>'"'));
-
-          $config[$key] = $value;
-        }
+          include($file);
+          $config = ${$this->_name};
       }
 
       return $config;
-- 
cgit v1.2.3


From 60dd32d957e6c4ce2d969c45cc60497f55a39abe Mon Sep 17 00:00:00 2001
From: Andreas Gohr 
Date: Sat, 10 Nov 2012 18:18:05 +0100
Subject: added 'array' type for config manager

This allows to use simple arrays in the config file but have a comma
separated list in the config manager.
---
 lib/plugins/config/settings/config.class.php    | 104 ++++++++++++++++++++++++
 lib/plugins/config/settings/config.metadata.php |   3 +
 2 files changed, 107 insertions(+)

diff --git a/lib/plugins/config/settings/config.class.php b/lib/plugins/config/settings/config.class.php
index 722c8df7b..e4a638eb0 100644
--- a/lib/plugins/config/settings/config.class.php
+++ b/lib/plugins/config/settings/config.class.php
@@ -435,6 +435,110 @@ if (!class_exists('setting')) {
   }
 }
 
+
+if (!class_exists('setting_array')) {
+    class setting_array extends setting {
+
+        /**
+         * Create an array from a string
+         *
+         * @param $string
+         * @return array
+         */
+        protected function _from_string($string){
+            $array = explode(',', $string);
+            $array = array_map('trim', $array);
+            $array = array_filter($array);
+            $array = array_unique($array);
+            return $array;
+        }
+
+        /**
+         * Create a string from an array
+         *
+         * @param $array
+         * @return string
+         */
+        protected function _from_array($array){
+            return join(', ', (array) $array);
+        }
+
+        /**
+         * update setting with user provided value $input
+         * if value fails error check, save it
+         *
+         * @param string $input
+         * @return bool true if changed, false otherwise (incl. on error)
+         */
+        function update($input) {
+            if (is_null($input)) return false;
+            if ($this->is_protected()) return false;
+
+            $input = $this->_from_string($input);
+
+            $value = is_null($this->_local) ? $this->_default : $this->_local;
+            if ($value == $input) return false;
+
+            foreach($input as $item){
+                if ($this->_pattern && !preg_match($this->_pattern,$item)) {
+                    $this->_error = true;
+                    $this->_input = $input;
+                    return false;
+                }
+            }
+
+            $this->_local = $input;
+            return true;
+        }
+
+        protected function _escape($string) {
+            $tr = array("\\" => '\\\\', "'" => '\\\'');
+            return "'".strtr( cleanText($string), $tr)."'";
+        }
+
+        /**
+         * generate string to save setting value to file according to $fmt
+         */
+        function out($var, $fmt='php') {
+
+            if ($this->is_protected()) return '';
+            if (is_null($this->_local) || ($this->_default == $this->_local)) return '';
+
+            $out = '';
+
+            if ($fmt=='php') {
+                $vals = array_map(array($this, '_escape'), $this->_local);
+                $out =  '$'.$var."['".$this->_out_key()."'] = array(".join(', ',$vals).");\n";
+            }
+
+            return $out;
+        }
+
+        function html(&$plugin, $echo=false) {
+            $value = '';
+            $disable = '';
+
+            if ($this->is_protected()) {
+                $value = $this->_protected;
+                $disable = 'disabled="disabled"';
+            } else {
+                if ($echo && $this->_error) {
+                    $value = $this->_input;
+                } else {
+                    $value = is_null($this->_local) ? $this->_default : $this->_local;
+                }
+            }
+
+            $key = htmlspecialchars($this->_key);
+            $value = htmlspecialchars($this->_from_array($value));
+
+            $label = '';
+            $input = '';
+            return array($label,$input);
+        }
+    }
+}
+
 if (!class_exists('setting_string')) {
   class setting_string extends setting {
     function html(&$plugin, $echo=false) {
diff --git a/lib/plugins/config/settings/config.metadata.php b/lib/plugins/config/settings/config.metadata.php
index 3607f56c6..582452917 100644
--- a/lib/plugins/config/settings/config.metadata.php
+++ b/lib/plugins/config/settings/config.metadata.php
@@ -32,6 +32,9 @@
  *                    separated list of checked choices
  *   'fieldset'     - used to group configuration settings, but is not itself a setting. To make this clear in
  *                    the language files the keys for this type should start with '_'.
+ *   'array'        - a simple (one dimensional) array of string values, shown as comma separated list in the
+ *                    config manager but saved as PHP array(). Values may not contain commas themselves.
+ *                    _pattern matching on the array values supported.
  *
  *  Single Setting (source: settings/extra.class.php)
  *  -------------------------------------------------
-- 
cgit v1.2.3


From d30b165d18ab3a6868d3b3e96e7bac782fb58441 Mon Sep 17 00:00:00 2001
From: Andreas Gohr 
Date: Fri, 16 Nov 2012 13:28:15 +0100
Subject: Revert "config manager: let PHP parse the config file"

This reverts commit b8f41ef0bac4e82cb3b02cd318efaddbaaeb1a78.

We had good reasons for parsing the file ourselves. For example to keep
expressions like 7*60*60*24 intact.
---
 lib/plugins/config/settings/config.class.php | 25 ++++++++++++++++++++++---
 1 file changed, 22 insertions(+), 3 deletions(-)

diff --git a/lib/plugins/config/settings/config.class.php b/lib/plugins/config/settings/config.class.php
index e4a638eb0..e71a7e5f9 100644
--- a/lib/plugins/config/settings/config.class.php
+++ b/lib/plugins/config/settings/config.class.php
@@ -139,13 +139,32 @@ if (!class_exists('configuration')) {
     function _read_config($file) {
 
       if (!$file) return array();
-      if (!file_exists($file)) return array();
 
       $config = array();
 
       if ($this->_format == 'php') {
-          include($file);
-          $config = ${$this->_name};
+
+        if(@file_exists($file)){
+            $contents = @php_strip_whitespace($file);
+        }else{
+            $contents = '';
+        }
+        $pattern = '/\$'.$this->_name.'\[[\'"]([^=]+)[\'"]\] ?= ?(.*?);(?=[^;]*(?:\$'.$this->_name.'|$))/s';
+        $matches=array();
+        preg_match_all($pattern,$contents,$matches,PREG_SET_ORDER);
+
+        for ($i=0; $i'\\','\\\''=>'\'','\\"'=>'"'));
+
+          $config[$key] = $value;
+        }
       }
 
       return $config;
-- 
cgit v1.2.3


From cba21baacb4880eefd35279b0589e035c5a5c78e Mon Sep 17 00:00:00 2001
From: Andreas Gohr 
Date: Fri, 16 Nov 2012 13:59:17 +0100
Subject: started to add some unit tests to config manager

Parsing the config file should be completely tested before we can rely
on it and safely extend it. This just adds the first very basic tests.
---
 lib/plugins/config/_test/configuration.test.php | 31 +++++++++++++++++++++++++
 lib/plugins/config/_test/data/config.php        | 14 +++++++++++
 lib/plugins/config/_test/data/metadata.php      | 11 +++++++++
 lib/plugins/config/settings/config.class.php    |  3 +++
 4 files changed, 59 insertions(+)
 create mode 100644 lib/plugins/config/_test/configuration.test.php
 create mode 100644 lib/plugins/config/_test/data/config.php
 create mode 100644 lib/plugins/config/_test/data/metadata.php

diff --git a/lib/plugins/config/_test/configuration.test.php b/lib/plugins/config/_test/configuration.test.php
new file mode 100644
index 000000000..eeeff61a3
--- /dev/null
+++ b/lib/plugins/config/_test/configuration.test.php
@@ -0,0 +1,31 @@
+config = dirname(__FILE__).'/data/config.php';
+        $this->meta   = dirname(__FILE__).'/data/metadata.php';
+        require_once(dirname(__FILE__).'/../settings/config.class.php');
+    }
+
+    function test_readconfig() {
+        $confmgr = new configuration($this->meta);
+
+        $conf = $confmgr->_read_config($this->config);
+
+        //print_r($conf);
+
+        $this->assertEquals('42', $conf['int1']);
+        $this->assertEquals('6*7', $conf['int2']);
+
+        $this->assertEquals('Hello World', $conf['str1']);
+        $this->assertEquals('G\'day World', $conf['str2']);
+        $this->assertEquals('Hello World', $conf['str3']);
+        $this->assertEquals("Hello 'World'", $conf['str4']);
+        $this->assertEquals('Hello "World"', $conf['str5']);
+    }
+
+}
\ No newline at end of file
diff --git a/lib/plugins/config/_test/data/config.php b/lib/plugins/config/_test/data/config.php
new file mode 100644
index 000000000..4ed450e93
--- /dev/null
+++ b/lib/plugins/config/_test/data/config.php
@@ -0,0 +1,14 @@
+
  */
 
+
+if(!defined('CM_KEYMARKER')) define('CM_KEYMARKER','____');
+
 if (!class_exists('configuration')) {
 
   class configuration {
-- 
cgit v1.2.3


From a24fc53e2623640cf5e2d00de741c1b67c9bb294 Mon Sep 17 00:00:00 2001
From: Andreas Gohr 
Date: Fri, 16 Nov 2012 14:48:14 +0100
Subject: added failing test for array type

---
 lib/plugins/config/_test/configuration.test.php | 2 ++
 lib/plugins/config/_test/data/config.php        | 2 ++
 lib/plugins/config/_test/data/metadata.php      | 2 ++
 3 files changed, 6 insertions(+)

diff --git a/lib/plugins/config/_test/configuration.test.php b/lib/plugins/config/_test/configuration.test.php
index eeeff61a3..ee03f3849 100644
--- a/lib/plugins/config/_test/configuration.test.php
+++ b/lib/plugins/config/_test/configuration.test.php
@@ -26,6 +26,8 @@ class plugin_config_configuration_test extends DokuWikiTest {
         $this->assertEquals('Hello World', $conf['str3']);
         $this->assertEquals("Hello 'World'", $conf['str4']);
         $this->assertEquals('Hello "World"', $conf['str5']);
+
+        $this->assertEquals(array('foo', 'bar', 'baz'), $conf['arr1']);
     }
 
 }
\ No newline at end of file
diff --git a/lib/plugins/config/_test/data/config.php b/lib/plugins/config/_test/data/config.php
index 4ed450e93..15d6359ad 100644
--- a/lib/plugins/config/_test/data/config.php
+++ b/lib/plugins/config/_test/data/config.php
@@ -10,5 +10,7 @@ $conf['str3']  = "Hello World";
 $conf['str4']  = "Hello 'World'";
 $conf['str5']  = "Hello \"World\"";
 
+$conf['arr1']  = array('foo','bar','baz');
+
 $conf['foo']['bar'] = 'x1';
 $conf['foo']['baz'] = 'x2';
diff --git a/lib/plugins/config/_test/data/metadata.php b/lib/plugins/config/_test/data/metadata.php
index 34ab42be7..12902e525 100644
--- a/lib/plugins/config/_test/data/metadata.php
+++ b/lib/plugins/config/_test/data/metadata.php
@@ -9,3 +9,5 @@ $meta['str3'] = array('string');
 $meta['str4'] = array('string');
 $meta['str5'] = array('string');
 
+$meta['arr1'] = array('array');
+
-- 
cgit v1.2.3


From 741c52751f7b22a3167d9475b2adb1a79f5eeea6 Mon Sep 17 00:00:00 2001
From: Andreas Gohr 
Date: Wed, 16 Jan 2013 13:41:42 +0100
Subject: parse arrays from config file

---
 lib/plugins/config/_test/configuration.test.php |  2 +-
 lib/plugins/config/settings/config.class.php    | 23 ++++++++++++++++++++---
 2 files changed, 21 insertions(+), 4 deletions(-)

diff --git a/lib/plugins/config/_test/configuration.test.php b/lib/plugins/config/_test/configuration.test.php
index ee03f3849..b808ad505 100644
--- a/lib/plugins/config/_test/configuration.test.php
+++ b/lib/plugins/config/_test/configuration.test.php
@@ -30,4 +30,4 @@ class plugin_config_configuration_test extends DokuWikiTest {
         $this->assertEquals(array('foo', 'bar', 'baz'), $conf['arr1']);
     }
 
-}
\ No newline at end of file
+}
diff --git a/lib/plugins/config/settings/config.class.php b/lib/plugins/config/settings/config.class.php
index 5a2aa2980..7f15df6fb 100644
--- a/lib/plugins/config/settings/config.class.php
+++ b/lib/plugins/config/settings/config.class.php
@@ -157,14 +157,31 @@ if (!class_exists('configuration')) {
         preg_match_all($pattern,$contents,$matches,PREG_SET_ORDER);
 
         for ($i=0; $i'\\','\\\''=>'\'','\\"'=>'"'));
+
+          // handle arrays
+          if(preg_match('/array ?\((.*)\)/', $value, $match)){
+            $arr = explode(',', $match[1]);
+
+            // remove quotes from quoted strings & unescape escaped data
+            $len = count($arr);
+            for($j=0; $j<$len; $j++){
+                $arr[$j] = preg_replace('/^(\'|")(.*)(?'\\','\\\''=>'\'','\\"'=>'"'));
+            }
+
+            $value = $arr;
+          }else{
+            // remove quotes from quoted strings & unescape escaped data
+            $value = preg_replace('/^(\'|")(.*)(?'\\','\\\''=>'\'','\\"'=>'"'));
+          }
 
           $config[$key] = $value;
         }
-- 
cgit v1.2.3


From d12150d88f5fe8d5718313ab6c14ab8c907c61ff Mon Sep 17 00:00:00 2001
From: Andreas Gohr 
Date: Wed, 16 Jan 2013 13:59:41 +0100
Subject: fixed problems with spaced arrays

---
 lib/plugins/config/_test/data/config.php     | 2 +-
 lib/plugins/config/settings/config.class.php | 3 ++-
 2 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/lib/plugins/config/_test/data/config.php b/lib/plugins/config/_test/data/config.php
index 15d6359ad..83255f937 100644
--- a/lib/plugins/config/_test/data/config.php
+++ b/lib/plugins/config/_test/data/config.php
@@ -10,7 +10,7 @@ $conf['str3']  = "Hello World";
 $conf['str4']  = "Hello 'World'";
 $conf['str5']  = "Hello \"World\"";
 
-$conf['arr1']  = array('foo','bar','baz');
+$conf['arr1']  = array('foo','bar', 'baz');
 
 $conf['foo']['bar'] = 'x1';
 $conf['foo']['baz'] = 'x2';
diff --git a/lib/plugins/config/settings/config.class.php b/lib/plugins/config/settings/config.class.php
index 7f15df6fb..7ff310b20 100644
--- a/lib/plugins/config/settings/config.class.php
+++ b/lib/plugins/config/settings/config.class.php
@@ -166,12 +166,13 @@ if (!class_exists('configuration')) {
 
 
           // handle arrays
-          if(preg_match('/array ?\((.*)\)/', $value, $match)){
+          if(preg_match('/^array ?\((.*)\)/', $value, $match)){
             $arr = explode(',', $match[1]);
 
             // remove quotes from quoted strings & unescape escaped data
             $len = count($arr);
             for($j=0; $j<$len; $j++){
+                $arr[$j] = trim($arr[$j]);
                 $arr[$j] = preg_replace('/^(\'|")(.*)(?'\\','\\\''=>'\'','\\"'=>'"'));
             }
-- 
cgit v1.2.3


From 9fd5ca2ec2955ee29404be1a39ddd9affcd0c78f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Stefan=20Gro=CC=88nke?= 
Date: Sat, 19 Jan 2013 16:30:42 +0100
Subject: jQuery latest

* jQuery 1.9.0
* jQuery-UI v1.9.2
* jQuery.fn.live > jQuery.fn.on
* jQuery.fn.browser replacement (jquery.mb.browser.js)
---
 lib/exe/js.php                                     |     1 +
 lib/scripts/behaviour.js                           |    74 +-
 .../images/ui-bg_flat_0_aaaaaa_40x100.png          |   Bin
 .../images/ui-bg_flat_75_ffffff_40x100.png         |   Bin
 .../images/ui-bg_glass_55_fbf9ee_1x400.png         |   Bin
 .../images/ui-bg_glass_65_ffffff_1x400.png         |   Bin
 .../images/ui-bg_glass_75_dadada_1x400.png         |   Bin
 .../images/ui-bg_glass_75_e6e6e6_1x400.png         |   Bin
 .../images/ui-bg_glass_95_fef1ec_1x400.png         |   Bin
 .../ui-bg_highlight-soft_75_cccccc_1x100.png       |   Bin
 .../images/ui-icons_222222_256x240.png             |   Bin
 .../images/ui-icons_2e83ff_256x240.png             |   Bin
 .../images/ui-icons_454545_256x240.png             |   Bin
 .../images/ui-icons_888888_256x240.png             |   Bin
 .../images/ui-icons_cd0a0a_256x240.png             |   Bin
 .../jquery-ui-theme/jquery-ui-1.9.2.custom.css     |   462 +
 .../jquery-ui-theme/jquery-ui-1.9.2.custom.min.css |     5 +
 lib/scripts/jquery/jquery-ui-theme/smoothness.css  |   568 -
 lib/scripts/jquery/jquery-ui.js                    | 21842 +++++++++++--------
 lib/scripts/jquery/jquery-ui.min.js                |   420 +-
 lib/scripts/jquery/jquery.cookie.js                |   107 +-
 lib/scripts/jquery/jquery.js                       |  9046 --------
 lib/scripts/jquery/jquery.mb.browser.js            |   104 +
 lib/scripts/jquery/jquery.mb.browser.min.js        |    21 +
 lib/scripts/jquery/jquery.min.js                   |     8 +-
 lib/scripts/jquery/update.sh                       |    28 -
 26 files changed, 13186 insertions(+), 19500 deletions(-)
 mode change 100644 => 100755 lib/scripts/jquery/jquery-ui-theme/images/ui-bg_flat_0_aaaaaa_40x100.png
 mode change 100644 => 100755 lib/scripts/jquery/jquery-ui-theme/images/ui-bg_flat_75_ffffff_40x100.png
 mode change 100644 => 100755 lib/scripts/jquery/jquery-ui-theme/images/ui-bg_glass_55_fbf9ee_1x400.png
 mode change 100644 => 100755 lib/scripts/jquery/jquery-ui-theme/images/ui-bg_glass_65_ffffff_1x400.png
 mode change 100644 => 100755 lib/scripts/jquery/jquery-ui-theme/images/ui-bg_glass_75_dadada_1x400.png
 mode change 100644 => 100755 lib/scripts/jquery/jquery-ui-theme/images/ui-bg_glass_75_e6e6e6_1x400.png
 mode change 100644 => 100755 lib/scripts/jquery/jquery-ui-theme/images/ui-bg_glass_95_fef1ec_1x400.png
 mode change 100644 => 100755 lib/scripts/jquery/jquery-ui-theme/images/ui-bg_highlight-soft_75_cccccc_1x100.png
 mode change 100644 => 100755 lib/scripts/jquery/jquery-ui-theme/images/ui-icons_222222_256x240.png
 mode change 100644 => 100755 lib/scripts/jquery/jquery-ui-theme/images/ui-icons_2e83ff_256x240.png
 mode change 100644 => 100755 lib/scripts/jquery/jquery-ui-theme/images/ui-icons_454545_256x240.png
 mode change 100644 => 100755 lib/scripts/jquery/jquery-ui-theme/images/ui-icons_888888_256x240.png
 mode change 100644 => 100755 lib/scripts/jquery/jquery-ui-theme/images/ui-icons_cd0a0a_256x240.png
 create mode 100755 lib/scripts/jquery/jquery-ui-theme/jquery-ui-1.9.2.custom.css
 create mode 100755 lib/scripts/jquery/jquery-ui-theme/jquery-ui-1.9.2.custom.min.css
 delete mode 100644 lib/scripts/jquery/jquery-ui-theme/smoothness.css
 mode change 100644 => 100755 lib/scripts/jquery/jquery-ui.js
 mode change 100644 => 100755 lib/scripts/jquery/jquery-ui.min.js
 delete mode 100644 lib/scripts/jquery/jquery.js
 create mode 100644 lib/scripts/jquery/jquery.mb.browser.js
 create mode 100644 lib/scripts/jquery/jquery.mb.browser.min.js
 delete mode 100755 lib/scripts/jquery/update.sh

diff --git a/lib/exe/js.php b/lib/exe/js.php
index 42979eeed..7c1c27138 100644
--- a/lib/exe/js.php
+++ b/lib/exe/js.php
@@ -43,6 +43,7 @@ function js_out(){
                 DOKU_INC."lib/scripts/jquery/jquery$min.js",
                 DOKU_INC.'lib/scripts/jquery/jquery.cookie.js',
                 DOKU_INC."lib/scripts/jquery/jquery-ui$min.js",
+                DOKU_INC."lib/scripts/jquery/jquery.mb.browser.js",
                 DOKU_INC."lib/scripts/fileuploader.js",
                 DOKU_INC."lib/scripts/fileuploaderextended.js",
                 DOKU_INC.'lib/scripts/helpers.js',
diff --git a/lib/scripts/behaviour.js b/lib/scripts/behaviour.js
index cffdde042..6878b0b96 100644
--- a/lib/scripts/behaviour.js
+++ b/lib/scripts/behaviour.js
@@ -1,3 +1,38 @@
+/**
+ * Hides elements with a slide animation
+ *
+ * @param fn optional callback to run after hiding
+ * @author Adrian Lang 
+ */
+jQuery.fn.dw_hide = function(fn) {
+    return this.slideUp('fast', fn);
+};
+
+/**
+ * Unhides elements with a slide animation
+ *
+ * @param fn optional callback to run after hiding
+ * @author Adrian Lang 
+ */
+jQuery.fn.dw_show = function(fn) {
+    return this.slideDown('fast', fn);
+};
+
+/**
+ * Toggles visibility of an element using a slide element
+ *
+ * @param bool the current state of the element (optional)
+ */
+jQuery.fn.dw_toggle = function(bool, fn) {
+    return this.each(function() {
+        var $this = jQuery(this);
+        if (typeof bool === 'undefined') {
+            bool = $this.is(':hidden');
+        }
+        $this[bool ? "dw_show" : "dw_hide" ](fn);
+    });
+};
+
 /**
  * Automatic behaviours
  *
@@ -16,7 +51,7 @@ var dw_behaviour = {
         dw_behaviour.subscription();
 
         dw_behaviour.revisionBoxHandler();
-        jQuery('#page__revisions input[type=checkbox]').live('click',
+        jQuery('#page__revisions input[type=checkbox]').on('click',
             dw_behaviour.revisionBoxHandler
         );
     },
@@ -77,7 +112,7 @@ var dw_behaviour = {
             return;
         }
 
-        jQuery('a.windows').live('click', function(){
+        jQuery('a.windows').on('click', function(){
             alert(LANG.nosmblinks.replace(/\\n/,"\n"));
         });
     },
@@ -142,39 +177,4 @@ var dw_behaviour = {
 
 };
 
-/**
- * Hides elements with a slide animation
- *
- * @param fn optional callback to run after hiding
- * @author Adrian Lang 
- */
-jQuery.fn.dw_hide = function(fn) {
-    return this.slideUp('fast', fn);
-};
-
-/**
- * Unhides elements with a slide animation
- *
- * @param fn optional callback to run after hiding
- * @author Adrian Lang 
- */
-jQuery.fn.dw_show = function(fn) {
-    return this.slideDown('fast', fn);
-};
-
-/**
- * Toggles visibility of an element using a slide element
- *
- * @param bool the current state of the element (optional)
- */
-jQuery.fn.dw_toggle = function(bool, fn) {
-    return this.each(function() {
-        var $this = jQuery(this);
-        if (typeof bool === 'undefined') {
-            bool = $this.is(':hidden');
-        }
-        $this[bool ? "dw_show" : "dw_hide" ](fn);
-    });
-};
-
 jQuery(dw_behaviour.init);
diff --git a/lib/scripts/jquery/jquery-ui-theme/images/ui-bg_flat_0_aaaaaa_40x100.png b/lib/scripts/jquery/jquery-ui-theme/images/ui-bg_flat_0_aaaaaa_40x100.png
old mode 100644
new mode 100755
diff --git a/lib/scripts/jquery/jquery-ui-theme/images/ui-bg_flat_75_ffffff_40x100.png b/lib/scripts/jquery/jquery-ui-theme/images/ui-bg_flat_75_ffffff_40x100.png
old mode 100644
new mode 100755
diff --git a/lib/scripts/jquery/jquery-ui-theme/images/ui-bg_glass_55_fbf9ee_1x400.png b/lib/scripts/jquery/jquery-ui-theme/images/ui-bg_glass_55_fbf9ee_1x400.png
old mode 100644
new mode 100755
diff --git a/lib/scripts/jquery/jquery-ui-theme/images/ui-bg_glass_65_ffffff_1x400.png b/lib/scripts/jquery/jquery-ui-theme/images/ui-bg_glass_65_ffffff_1x400.png
old mode 100644
new mode 100755
diff --git a/lib/scripts/jquery/jquery-ui-theme/images/ui-bg_glass_75_dadada_1x400.png b/lib/scripts/jquery/jquery-ui-theme/images/ui-bg_glass_75_dadada_1x400.png
old mode 100644
new mode 100755
diff --git a/lib/scripts/jquery/jquery-ui-theme/images/ui-bg_glass_75_e6e6e6_1x400.png b/lib/scripts/jquery/jquery-ui-theme/images/ui-bg_glass_75_e6e6e6_1x400.png
old mode 100644
new mode 100755
diff --git a/lib/scripts/jquery/jquery-ui-theme/images/ui-bg_glass_95_fef1ec_1x400.png b/lib/scripts/jquery/jquery-ui-theme/images/ui-bg_glass_95_fef1ec_1x400.png
old mode 100644
new mode 100755
diff --git a/lib/scripts/jquery/jquery-ui-theme/images/ui-bg_highlight-soft_75_cccccc_1x100.png b/lib/scripts/jquery/jquery-ui-theme/images/ui-bg_highlight-soft_75_cccccc_1x100.png
old mode 100644
new mode 100755
diff --git a/lib/scripts/jquery/jquery-ui-theme/images/ui-icons_222222_256x240.png b/lib/scripts/jquery/jquery-ui-theme/images/ui-icons_222222_256x240.png
old mode 100644
new mode 100755
diff --git a/lib/scripts/jquery/jquery-ui-theme/images/ui-icons_2e83ff_256x240.png b/lib/scripts/jquery/jquery-ui-theme/images/ui-icons_2e83ff_256x240.png
old mode 100644
new mode 100755
diff --git a/lib/scripts/jquery/jquery-ui-theme/images/ui-icons_454545_256x240.png b/lib/scripts/jquery/jquery-ui-theme/images/ui-icons_454545_256x240.png
old mode 100644
new mode 100755
diff --git a/lib/scripts/jquery/jquery-ui-theme/images/ui-icons_888888_256x240.png b/lib/scripts/jquery/jquery-ui-theme/images/ui-icons_888888_256x240.png
old mode 100644
new mode 100755
diff --git a/lib/scripts/jquery/jquery-ui-theme/images/ui-icons_cd0a0a_256x240.png b/lib/scripts/jquery/jquery-ui-theme/images/ui-icons_cd0a0a_256x240.png
old mode 100644
new mode 100755
diff --git a/lib/scripts/jquery/jquery-ui-theme/jquery-ui-1.9.2.custom.css b/lib/scripts/jquery/jquery-ui-theme/jquery-ui-1.9.2.custom.css
new file mode 100755
index 000000000..9fa4a2d2a
--- /dev/null
+++ b/lib/scripts/jquery/jquery-ui-theme/jquery-ui-1.9.2.custom.css
@@ -0,0 +1,462 @@
+/*! jQuery UI - v1.9.2 - 2012-11-23
+* http://jqueryui.com
+* Includes: jquery.ui.core.css, jquery.ui.accordion.css, jquery.ui.autocomplete.css, jquery.ui.button.css, jquery.ui.datepicker.css, jquery.ui.dialog.css, jquery.ui.menu.css, jquery.ui.progressbar.css, jquery.ui.resizable.css, jquery.ui.selectable.css, jquery.ui.slider.css, jquery.ui.spinner.css, jquery.ui.tabs.css, jquery.ui.tooltip.css
+* To view and modify this theme, visit http://jqueryui.com/themeroller/
+* Copyright (c) 2012 jQuery Foundation and other contributors Licensed MIT */
+
+/* Layout helpers
+----------------------------------*/
+.ui-helper-hidden { display: none; }
+.ui-helper-hidden-accessible { border: 0; clip: rect(0 0 0 0); height: 1px; margin: -1px; overflow: hidden; padding: 0; position: absolute; width: 1px; }
+.ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; }
+.ui-helper-clearfix:before, .ui-helper-clearfix:after { content: ""; display: table; }
+.ui-helper-clearfix:after { clear: both; }
+.ui-helper-clearfix { zoom: 1; }
+.ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); }
+
+
+/* Interaction Cues
+----------------------------------*/
+.ui-state-disabled { cursor: default !important; }
+
+
+/* Icons
+----------------------------------*/
+
+/* states and images */
+.ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; }
+
+
+/* Misc visuals
+----------------------------------*/
+
+/* Overlays */
+.ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; }
+.ui-accordion .ui-accordion-header { display: block; cursor: pointer; position: relative; margin-top: 2px; padding: .5em .5em .5em .7em; zoom: 1; }
+.ui-accordion .ui-accordion-icons { padding-left: 2.2em; }
+.ui-accordion .ui-accordion-noicons { padding-left: .7em; }
+.ui-accordion .ui-accordion-icons .ui-accordion-icons { padding-left: 2.2em; }
+.ui-accordion .ui-accordion-header .ui-accordion-header-icon { position: absolute; left: .5em; top: 50%; margin-top: -8px; }
+.ui-accordion .ui-accordion-content { padding: 1em 2.2em; border-top: 0; overflow: auto; zoom: 1; }
+.ui-autocomplete {
+	position: absolute;
+	top: 0;
+	left: 0;
+	cursor: default;
+}
+
+/* workarounds */
+* html .ui-autocomplete { width:1px; } /* without this, the menu expands to 100% in IE6 */
+.ui-button { display: inline-block; position: relative; padding: 0; margin-right: .1em; cursor: pointer; text-align: center; zoom: 1; overflow: visible; } /* the overflow property removes extra width in IE */
+.ui-button, .ui-button:link, .ui-button:visited, .ui-button:hover, .ui-button:active { text-decoration: none; }
+.ui-button-icon-only { width: 2.2em; } /* to make room for the icon, a width needs to be set here */
+button.ui-button-icon-only { width: 2.4em; } /* button elements seem to need a little more width */
+.ui-button-icons-only { width: 3.4em; } 
+button.ui-button-icons-only { width: 3.7em; } 
+
+/*button text element */
+.ui-button .ui-button-text { display: block; line-height: 1.4;  }
+.ui-button-text-only .ui-button-text { padding: .4em 1em; }
+.ui-button-icon-only .ui-button-text, .ui-button-icons-only .ui-button-text { padding: .4em; text-indent: -9999999px; }
+.ui-button-text-icon-primary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 1em .4em 2.1em; }
+.ui-button-text-icon-secondary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 2.1em .4em 1em; }
+.ui-button-text-icons .ui-button-text { padding-left: 2.1em; padding-right: 2.1em; }
+/* no icon support for input elements, provide padding by default */
+input.ui-button { padding: .4em 1em; }
+
+/*button icon element(s) */
+.ui-button-icon-only .ui-icon, .ui-button-text-icon-primary .ui-icon, .ui-button-text-icon-secondary .ui-icon, .ui-button-text-icons .ui-icon, .ui-button-icons-only .ui-icon { position: absolute; top: 50%; margin-top: -8px; }
+.ui-button-icon-only .ui-icon { left: 50%; margin-left: -8px; }
+.ui-button-text-icon-primary .ui-button-icon-primary, .ui-button-text-icons .ui-button-icon-primary, .ui-button-icons-only .ui-button-icon-primary { left: .5em; }
+.ui-button-text-icon-secondary .ui-button-icon-secondary, .ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; }
+.ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; }
+
+/*button sets*/
+.ui-buttonset { margin-right: 7px; }
+.ui-buttonset .ui-button { margin-left: 0; margin-right: -.3em; }
+
+/* workarounds */
+button.ui-button::-moz-focus-inner { border: 0; padding: 0; } /* reset extra padding in Firefox */
+.ui-datepicker { width: 17em; padding: .2em .2em 0; display: none; }
+.ui-datepicker .ui-datepicker-header { position:relative; padding:.2em 0; }
+.ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next { position:absolute; top: 2px; width: 1.8em; height: 1.8em; }
+.ui-datepicker .ui-datepicker-prev-hover, .ui-datepicker .ui-datepicker-next-hover { top: 1px; }
+.ui-datepicker .ui-datepicker-prev { left:2px; }
+.ui-datepicker .ui-datepicker-next { right:2px; }
+.ui-datepicker .ui-datepicker-prev-hover { left:1px; }
+.ui-datepicker .ui-datepicker-next-hover { right:1px; }
+.ui-datepicker .ui-datepicker-prev span, .ui-datepicker .ui-datepicker-next span { display: block; position: absolute; left: 50%; margin-left: -8px; top: 50%; margin-top: -8px;  }
+.ui-datepicker .ui-datepicker-title { margin: 0 2.3em; line-height: 1.8em; text-align: center; }
+.ui-datepicker .ui-datepicker-title select { font-size:1em; margin:1px 0; }
+.ui-datepicker select.ui-datepicker-month-year {width: 100%;}
+.ui-datepicker select.ui-datepicker-month, 
+.ui-datepicker select.ui-datepicker-year { width: 49%;}
+.ui-datepicker table {width: 100%; font-size: .9em; border-collapse: collapse; margin:0 0 .4em; }
+.ui-datepicker th { padding: .7em .3em; text-align: center; font-weight: bold; border: 0;  }
+.ui-datepicker td { border: 0; padding: 1px; }
+.ui-datepicker td span, .ui-datepicker td a { display: block; padding: .2em; text-align: right; text-decoration: none; }
+.ui-datepicker .ui-datepicker-buttonpane { background-image: none; margin: .7em 0 0 0; padding:0 .2em; border-left: 0; border-right: 0; border-bottom: 0; }
+.ui-datepicker .ui-datepicker-buttonpane button { float: right; margin: .5em .2em .4em; cursor: pointer; padding: .2em .6em .3em .6em; width:auto; overflow:visible; }
+.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { float:left; }
+
+/* with multiple calendars */
+.ui-datepicker.ui-datepicker-multi { width:auto; }
+.ui-datepicker-multi .ui-datepicker-group { float:left; }
+.ui-datepicker-multi .ui-datepicker-group table { width:95%; margin:0 auto .4em; }
+.ui-datepicker-multi-2 .ui-datepicker-group { width:50%; }
+.ui-datepicker-multi-3 .ui-datepicker-group { width:33.3%; }
+.ui-datepicker-multi-4 .ui-datepicker-group { width:25%; }
+.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header { border-left-width:0; }
+.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { border-left-width:0; }
+.ui-datepicker-multi .ui-datepicker-buttonpane { clear:left; }
+.ui-datepicker-row-break { clear:both; width:100%; font-size:0em; }
+
+/* RTL support */
+.ui-datepicker-rtl { direction: rtl; }
+.ui-datepicker-rtl .ui-datepicker-prev { right: 2px; left: auto; }
+.ui-datepicker-rtl .ui-datepicker-next { left: 2px; right: auto; }
+.ui-datepicker-rtl .ui-datepicker-prev:hover { right: 1px; left: auto; }
+.ui-datepicker-rtl .ui-datepicker-next:hover { left: 1px; right: auto; }
+.ui-datepicker-rtl .ui-datepicker-buttonpane { clear:right; }
+.ui-datepicker-rtl .ui-datepicker-buttonpane button { float: left; }
+.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current { float:right; }
+.ui-datepicker-rtl .ui-datepicker-group { float:right; }
+.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header { border-right-width:0; border-left-width:1px; }
+.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { border-right-width:0; border-left-width:1px; }
+
+/* IE6 IFRAME FIX (taken from datepicker 1.5.3 */
+.ui-datepicker-cover {
+    position: absolute; /*must have*/
+    z-index: -1; /*must have*/
+    filter: mask(); /*must have*/
+    top: -4px; /*must have*/
+    left: -4px; /*must have*/
+    width: 200px; /*must have*/
+    height: 200px; /*must have*/
+}.ui-dialog { position: absolute; top: 0; left: 0; padding: .2em; width: 300px; overflow: hidden; }
+.ui-dialog .ui-dialog-titlebar { padding: .4em 1em; position: relative;  }
+.ui-dialog .ui-dialog-title { float: left; margin: .1em 16px .1em 0; }
+.ui-dialog .ui-dialog-titlebar-close { position: absolute; right: .3em; top: 50%; width: 19px; margin: -10px 0 0 0; padding: 1px; height: 18px; }
+.ui-dialog .ui-dialog-titlebar-close span { display: block; margin: 1px; }
+.ui-dialog .ui-dialog-titlebar-close:hover, .ui-dialog .ui-dialog-titlebar-close:focus { padding: 0; }
+.ui-dialog .ui-dialog-content { position: relative; border: 0; padding: .5em 1em; background: none; overflow: auto; zoom: 1; }
+.ui-dialog .ui-dialog-buttonpane { text-align: left; border-width: 1px 0 0 0; background-image: none; margin: .5em 0 0 0; padding: .3em 1em .5em .4em; }
+.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset { float: right; }
+.ui-dialog .ui-dialog-buttonpane button { margin: .5em .4em .5em 0; cursor: pointer; }
+.ui-dialog .ui-resizable-se { width: 14px; height: 14px; right: 3px; bottom: 3px; }
+.ui-draggable .ui-dialog-titlebar { cursor: move; }
+.ui-menu { list-style:none; padding: 2px; margin: 0; display:block; outline: none; }
+.ui-menu .ui-menu { margin-top: -3px; position: absolute; }
+.ui-menu .ui-menu-item { margin: 0; padding: 0; zoom: 1; width: 100%; }
+.ui-menu .ui-menu-divider { margin: 5px -2px 5px -2px; height: 0; font-size: 0; line-height: 0; border-width: 1px 0 0 0; }
+.ui-menu .ui-menu-item a { text-decoration: none; display: block; padding: 2px .4em; line-height: 1.5; zoom: 1; font-weight: normal; }
+.ui-menu .ui-menu-item a.ui-state-focus,
+.ui-menu .ui-menu-item a.ui-state-active { font-weight: normal; margin: -1px; }
+
+.ui-menu .ui-state-disabled { font-weight: normal; margin: .4em 0 .2em; line-height: 1.5; }
+.ui-menu .ui-state-disabled a { cursor: default; }
+
+/* icon support */
+.ui-menu-icons { position: relative; }
+.ui-menu-icons .ui-menu-item a { position: relative; padding-left: 2em; }
+
+/* left-aligned */
+.ui-menu .ui-icon { position: absolute; top: .2em; left: .2em; }
+
+/* right-aligned */
+.ui-menu .ui-menu-icon { position: static; float: right; }
+.ui-progressbar { height:2em; text-align: left; overflow: hidden; }
+.ui-progressbar .ui-progressbar-value {margin: -1px; height:100%; }.ui-resizable { position: relative;}
+.ui-resizable-handle { position: absolute;font-size: 0.1px; display: block; }
+.ui-resizable-disabled .ui-resizable-handle, .ui-resizable-autohide .ui-resizable-handle { display: none; }
+.ui-resizable-n { cursor: n-resize; height: 7px; width: 100%; top: -5px; left: 0; }
+.ui-resizable-s { cursor: s-resize; height: 7px; width: 100%; bottom: -5px; left: 0; }
+.ui-resizable-e { cursor: e-resize; width: 7px; right: -5px; top: 0; height: 100%; }
+.ui-resizable-w { cursor: w-resize; width: 7px; left: -5px; top: 0; height: 100%; }
+.ui-resizable-se { cursor: se-resize; width: 12px; height: 12px; right: 1px; bottom: 1px; }
+.ui-resizable-sw { cursor: sw-resize; width: 9px; height: 9px; left: -5px; bottom: -5px; }
+.ui-resizable-nw { cursor: nw-resize; width: 9px; height: 9px; left: -5px; top: -5px; }
+.ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: -5px; top: -5px;}.ui-selectable-helper { position: absolute; z-index: 100; border:1px dotted black; }
+.ui-slider { position: relative; text-align: left; }
+.ui-slider .ui-slider-handle { position: absolute; z-index: 2; width: 1.2em; height: 1.2em; cursor: default; }
+.ui-slider .ui-slider-range { position: absolute; z-index: 1; font-size: .7em; display: block; border: 0; background-position: 0 0; }
+
+.ui-slider-horizontal { height: .8em; }
+.ui-slider-horizontal .ui-slider-handle { top: -.3em; margin-left: -.6em; }
+.ui-slider-horizontal .ui-slider-range { top: 0; height: 100%; }
+.ui-slider-horizontal .ui-slider-range-min { left: 0; }
+.ui-slider-horizontal .ui-slider-range-max { right: 0; }
+
+.ui-slider-vertical { width: .8em; height: 100px; }
+.ui-slider-vertical .ui-slider-handle { left: -.3em; margin-left: 0; margin-bottom: -.6em; }
+.ui-slider-vertical .ui-slider-range { left: 0; width: 100%; }
+.ui-slider-vertical .ui-slider-range-min { bottom: 0; }
+.ui-slider-vertical .ui-slider-range-max { top: 0; }.ui-spinner { position:relative; display: inline-block; overflow: hidden; padding: 0; vertical-align: middle; }
+.ui-spinner-input { border: none; background: none; padding: 0; margin: .2em 0; vertical-align: middle; margin-left: .4em; margin-right: 22px; }
+.ui-spinner-button { width: 16px; height: 50%; font-size: .5em; padding: 0; margin: 0; text-align: center; position: absolute; cursor: default; display: block; overflow: hidden; right: 0; }
+.ui-spinner a.ui-spinner-button { border-top: none; border-bottom: none; border-right: none; } /* more specificity required here to overide default borders */
+.ui-spinner .ui-icon { position: absolute; margin-top: -8px; top: 50%; left: 0; } /* vertical centre icon */
+.ui-spinner-up { top: 0; }
+.ui-spinner-down { bottom: 0; }
+
+/* TR overrides */
+.ui-spinner .ui-icon-triangle-1-s {
+	/* need to fix icons sprite */
+	background-position:-65px -16px;
+}
+.ui-tabs { position: relative; padding: .2em; zoom: 1; } /* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */
+.ui-tabs .ui-tabs-nav { margin: 0; padding: .2em .2em 0; }
+.ui-tabs .ui-tabs-nav li { list-style: none; float: left; position: relative; top: 0; margin: 1px .2em 0 0; border-bottom: 0; padding: 0; white-space: nowrap; }
+.ui-tabs .ui-tabs-nav li a { float: left; padding: .5em 1em; text-decoration: none; }
+.ui-tabs .ui-tabs-nav li.ui-tabs-active { margin-bottom: -1px; padding-bottom: 1px; }
+.ui-tabs .ui-tabs-nav li.ui-tabs-active a, .ui-tabs .ui-tabs-nav li.ui-state-disabled a, .ui-tabs .ui-tabs-nav li.ui-tabs-loading a { cursor: text; }
+.ui-tabs .ui-tabs-nav li a, .ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-active a { cursor: pointer; } /* first selector in group seems obsolete, but required to overcome bug in Opera applying cursor: text overall if defined elsewhere... */
+.ui-tabs .ui-tabs-panel { display: block; border-width: 0; padding: 1em 1.4em; background: none; }
+.ui-tooltip {
+	padding: 8px;
+	position: absolute;
+	z-index: 9999;
+	max-width: 300px;
+	-webkit-box-shadow: 0 0 5px #aaa;
+	box-shadow: 0 0 5px #aaa;
+}
+/* Fades and background-images don't work well together in IE6, drop the image */
+* html .ui-tooltip {
+	background-image: none;
+}
+body .ui-tooltip { border-width: 2px; }
+
+/* Component containers
+----------------------------------*/
+.ui-widget { font-family: Verdana,Arial,sans-serif; font-size: 1.1em; }
+.ui-widget .ui-widget { font-size: 1em; }
+.ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: Verdana,Arial,sans-serif; font-size: 1em; }
+.ui-widget-content { border: 1px solid #aaaaaa; background: #ffffff url(images/ui-bg_flat_75_ffffff_40x100.png) 50% 50% repeat-x; color: #222222; }
+.ui-widget-content a { color: #222222; }
+.ui-widget-header { border: 1px solid #aaaaaa; background: #cccccc url(images/ui-bg_highlight-soft_75_cccccc_1x100.png) 50% 50% repeat-x; color: #222222; font-weight: bold; }
+.ui-widget-header a { color: #222222; }
+
+/* Interaction states
+----------------------------------*/
+.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { border: 1px solid #d3d3d3; background: #e6e6e6 url(images/ui-bg_glass_75_e6e6e6_1x400.png) 50% 50% repeat-x; font-weight: normal; color: #555555; }
+.ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #555555; text-decoration: none; }
+.ui-state-hover, .ui-widget-content .ui-state-hover, .ui-widget-header .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus, .ui-widget-header .ui-state-focus { border: 1px solid #999999; background: #dadada url(images/ui-bg_glass_75_dadada_1x400.png) 50% 50% repeat-x; font-weight: normal; color: #212121; }
+.ui-state-hover a, .ui-state-hover a:hover, .ui-state-hover a:link, .ui-state-hover a:visited { color: #212121; text-decoration: none; }
+.ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active { border: 1px solid #aaaaaa; background: #ffffff url(images/ui-bg_glass_65_ffffff_1x400.png) 50% 50% repeat-x; font-weight: normal; color: #212121; }
+.ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #212121; text-decoration: none; }
+
+/* Interaction Cues
+----------------------------------*/
+.ui-state-highlight, .ui-widget-content .ui-state-highlight, .ui-widget-header .ui-state-highlight  {border: 1px solid #fcefa1; background: #fbf9ee url(images/ui-bg_glass_55_fbf9ee_1x400.png) 50% 50% repeat-x; color: #363636; }
+.ui-state-highlight a, .ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a { color: #363636; }
+.ui-state-error, .ui-widget-content .ui-state-error, .ui-widget-header .ui-state-error {border: 1px solid #cd0a0a; background: #fef1ec url(images/ui-bg_glass_95_fef1ec_1x400.png) 50% 50% repeat-x; color: #cd0a0a; }
+.ui-state-error a, .ui-widget-content .ui-state-error a, .ui-widget-header .ui-state-error a { color: #cd0a0a; }
+.ui-state-error-text, .ui-widget-content .ui-state-error-text, .ui-widget-header .ui-state-error-text { color: #cd0a0a; }
+.ui-priority-primary, .ui-widget-content .ui-priority-primary, .ui-widget-header .ui-priority-primary { font-weight: bold; }
+.ui-priority-secondary, .ui-widget-content .ui-priority-secondary,  .ui-widget-header .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; }
+.ui-state-disabled, .ui-widget-content .ui-state-disabled, .ui-widget-header .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; }
+.ui-state-disabled .ui-icon { filter:Alpha(Opacity=35); } /* For IE8 - See #6059 */
+
+/* Icons
+----------------------------------*/
+
+/* states and images */
+.ui-icon { width: 16px; height: 16px; background-image: url(images/ui-icons_222222_256x240.png); }
+.ui-widget-content .ui-icon {background-image: url(images/ui-icons_222222_256x240.png); }
+.ui-widget-header .ui-icon {background-image: url(images/ui-icons_222222_256x240.png); }
+.ui-state-default .ui-icon { background-image: url(images/ui-icons_888888_256x240.png); }
+.ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url(images/ui-icons_454545_256x240.png); }
+.ui-state-active .ui-icon {background-image: url(images/ui-icons_454545_256x240.png); }
+.ui-state-highlight .ui-icon {background-image: url(images/ui-icons_2e83ff_256x240.png); }
+.ui-state-error .ui-icon, .ui-state-error-text .ui-icon {background-image: url(images/ui-icons_cd0a0a_256x240.png); }
+
+/* positioning */
+.ui-icon-carat-1-n { background-position: 0 0; }
+.ui-icon-carat-1-ne { background-position: -16px 0; }
+.ui-icon-carat-1-e { background-position: -32px 0; }
+.ui-icon-carat-1-se { background-position: -48px 0; }
+.ui-icon-carat-1-s { background-position: -64px 0; }
+.ui-icon-carat-1-sw { background-position: -80px 0; }
+.ui-icon-carat-1-w { background-position: -96px 0; }
+.ui-icon-carat-1-nw { background-position: -112px 0; }
+.ui-icon-carat-2-n-s { background-position: -128px 0; }
+.ui-icon-carat-2-e-w { background-position: -144px 0; }
+.ui-icon-triangle-1-n { background-position: 0 -16px; }
+.ui-icon-triangle-1-ne { background-position: -16px -16px; }
+.ui-icon-triangle-1-e { background-position: -32px -16px; }
+.ui-icon-triangle-1-se { background-position: -48px -16px; }
+.ui-icon-triangle-1-s { background-position: -64px -16px; }
+.ui-icon-triangle-1-sw { background-position: -80px -16px; }
+.ui-icon-triangle-1-w { background-position: -96px -16px; }
+.ui-icon-triangle-1-nw { background-position: -112px -16px; }
+.ui-icon-triangle-2-n-s { background-position: -128px -16px; }
+.ui-icon-triangle-2-e-w { background-position: -144px -16px; }
+.ui-icon-arrow-1-n { background-position: 0 -32px; }
+.ui-icon-arrow-1-ne { background-position: -16px -32px; }
+.ui-icon-arrow-1-e { background-position: -32px -32px; }
+.ui-icon-arrow-1-se { background-position: -48px -32px; }
+.ui-icon-arrow-1-s { background-position: -64px -32px; }
+.ui-icon-arrow-1-sw { background-position: -80px -32px; }
+.ui-icon-arrow-1-w { background-position: -96px -32px; }
+.ui-icon-arrow-1-nw { background-position: -112px -32px; }
+.ui-icon-arrow-2-n-s { background-position: -128px -32px; }
+.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; }
+.ui-icon-arrow-2-e-w { background-position: -160px -32px; }
+.ui-icon-arrow-2-se-nw { background-position: -176px -32px; }
+.ui-icon-arrowstop-1-n { background-position: -192px -32px; }
+.ui-icon-arrowstop-1-e { background-position: -208px -32px; }
+.ui-icon-arrowstop-1-s { background-position: -224px -32px; }
+.ui-icon-arrowstop-1-w { background-position: -240px -32px; }
+.ui-icon-arrowthick-1-n { background-position: 0 -48px; }
+.ui-icon-arrowthick-1-ne { background-position: -16px -48px; }
+.ui-icon-arrowthick-1-e { background-position: -32px -48px; }
+.ui-icon-arrowthick-1-se { background-position: -48px -48px; }
+.ui-icon-arrowthick-1-s { background-position: -64px -48px; }
+.ui-icon-arrowthick-1-sw { background-position: -80px -48px; }
+.ui-icon-arrowthick-1-w { background-position: -96px -48px; }
+.ui-icon-arrowthick-1-nw { background-position: -112px -48px; }
+.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; }
+.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; }
+.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; }
+.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; }
+.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; }
+.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; }
+.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; }
+.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; }
+.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; }
+.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; }
+.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; }
+.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; }
+.ui-icon-arrowreturn-1-w { background-position: -64px -64px; }
+.ui-icon-arrowreturn-1-n { background-position: -80px -64px; }
+.ui-icon-arrowreturn-1-e { background-position: -96px -64px; }
+.ui-icon-arrowreturn-1-s { background-position: -112px -64px; }
+.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; }
+.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; }
+.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; }
+.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; }
+.ui-icon-arrow-4 { background-position: 0 -80px; }
+.ui-icon-arrow-4-diag { background-position: -16px -80px; }
+.ui-icon-extlink { background-position: -32px -80px; }
+.ui-icon-newwin { background-position: -48px -80px; }
+.ui-icon-refresh { background-position: -64px -80px; }
+.ui-icon-shuffle { background-position: -80px -80px; }
+.ui-icon-transfer-e-w { background-position: -96px -80px; }
+.ui-icon-transferthick-e-w { background-position: -112px -80px; }
+.ui-icon-folder-collapsed { background-position: 0 -96px; }
+.ui-icon-folder-open { background-position: -16px -96px; }
+.ui-icon-document { background-position: -32px -96px; }
+.ui-icon-document-b { background-position: -48px -96px; }
+.ui-icon-note { background-position: -64px -96px; }
+.ui-icon-mail-closed { background-position: -80px -96px; }
+.ui-icon-mail-open { background-position: -96px -96px; }
+.ui-icon-suitcase { background-position: -112px -96px; }
+.ui-icon-comment { background-position: -128px -96px; }
+.ui-icon-person { background-position: -144px -96px; }
+.ui-icon-print { background-position: -160px -96px; }
+.ui-icon-trash { background-position: -176px -96px; }
+.ui-icon-locked { background-position: -192px -96px; }
+.ui-icon-unlocked { background-position: -208px -96px; }
+.ui-icon-bookmark { background-position: -224px -96px; }
+.ui-icon-tag { background-position: -240px -96px; }
+.ui-icon-home { background-position: 0 -112px; }
+.ui-icon-flag { background-position: -16px -112px; }
+.ui-icon-calendar { background-position: -32px -112px; }
+.ui-icon-cart { background-position: -48px -112px; }
+.ui-icon-pencil { background-position: -64px -112px; }
+.ui-icon-clock { background-position: -80px -112px; }
+.ui-icon-disk { background-position: -96px -112px; }
+.ui-icon-calculator { background-position: -112px -112px; }
+.ui-icon-zoomin { background-position: -128px -112px; }
+.ui-icon-zoomout { background-position: -144px -112px; }
+.ui-icon-search { background-position: -160px -112px; }
+.ui-icon-wrench { background-position: -176px -112px; }
+.ui-icon-gear { background-position: -192px -112px; }
+.ui-icon-heart { background-position: -208px -112px; }
+.ui-icon-star { background-position: -224px -112px; }
+.ui-icon-link { background-position: -240px -112px; }
+.ui-icon-cancel { background-position: 0 -128px; }
+.ui-icon-plus { background-position: -16px -128px; }
+.ui-icon-plusthick { background-position: -32px -128px; }
+.ui-icon-minus { background-position: -48px -128px; }
+.ui-icon-minusthick { background-position: -64px -128px; }
+.ui-icon-close { background-position: -80px -128px; }
+.ui-icon-closethick { background-position: -96px -128px; }
+.ui-icon-key { background-position: -112px -128px; }
+.ui-icon-lightbulb { background-position: -128px -128px; }
+.ui-icon-scissors { background-position: -144px -128px; }
+.ui-icon-clipboard { background-position: -160px -128px; }
+.ui-icon-copy { background-position: -176px -128px; }
+.ui-icon-contact { background-position: -192px -128px; }
+.ui-icon-image { background-position: -208px -128px; }
+.ui-icon-video { background-position: -224px -128px; }
+.ui-icon-script { background-position: -240px -128px; }
+.ui-icon-alert { background-position: 0 -144px; }
+.ui-icon-info { background-position: -16px -144px; }
+.ui-icon-notice { background-position: -32px -144px; }
+.ui-icon-help { background-position: -48px -144px; }
+.ui-icon-check { background-position: -64px -144px; }
+.ui-icon-bullet { background-position: -80px -144px; }
+.ui-icon-radio-on { background-position: -96px -144px; }
+.ui-icon-radio-off { background-position: -112px -144px; }
+.ui-icon-pin-w { background-position: -128px -144px; }
+.ui-icon-pin-s { background-position: -144px -144px; }
+.ui-icon-play { background-position: 0 -160px; }
+.ui-icon-pause { background-position: -16px -160px; }
+.ui-icon-seek-next { background-position: -32px -160px; }
+.ui-icon-seek-prev { background-position: -48px -160px; }
+.ui-icon-seek-end { background-position: -64px -160px; }
+.ui-icon-seek-start { background-position: -80px -160px; }
+/* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */
+.ui-icon-seek-first { background-position: -80px -160px; }
+.ui-icon-stop { background-position: -96px -160px; }
+.ui-icon-eject { background-position: -112px -160px; }
+.ui-icon-volume-off { background-position: -128px -160px; }
+.ui-icon-volume-on { background-position: -144px -160px; }
+.ui-icon-power { background-position: 0 -176px; }
+.ui-icon-signal-diag { background-position: -16px -176px; }
+.ui-icon-signal { background-position: -32px -176px; }
+.ui-icon-battery-0 { background-position: -48px -176px; }
+.ui-icon-battery-1 { background-position: -64px -176px; }
+.ui-icon-battery-2 { background-position: -80px -176px; }
+.ui-icon-battery-3 { background-position: -96px -176px; }
+.ui-icon-circle-plus { background-position: 0 -192px; }
+.ui-icon-circle-minus { background-position: -16px -192px; }
+.ui-icon-circle-close { background-position: -32px -192px; }
+.ui-icon-circle-triangle-e { background-position: -48px -192px; }
+.ui-icon-circle-triangle-s { background-position: -64px -192px; }
+.ui-icon-circle-triangle-w { background-position: -80px -192px; }
+.ui-icon-circle-triangle-n { background-position: -96px -192px; }
+.ui-icon-circle-arrow-e { background-position: -112px -192px; }
+.ui-icon-circle-arrow-s { background-position: -128px -192px; }
+.ui-icon-circle-arrow-w { background-position: -144px -192px; }
+.ui-icon-circle-arrow-n { background-position: -160px -192px; }
+.ui-icon-circle-zoomin { background-position: -176px -192px; }
+.ui-icon-circle-zoomout { background-position: -192px -192px; }
+.ui-icon-circle-check { background-position: -208px -192px; }
+.ui-icon-circlesmall-plus { background-position: 0 -208px; }
+.ui-icon-circlesmall-minus { background-position: -16px -208px; }
+.ui-icon-circlesmall-close { background-position: -32px -208px; }
+.ui-icon-squaresmall-plus { background-position: -48px -208px; }
+.ui-icon-squaresmall-minus { background-position: -64px -208px; }
+.ui-icon-squaresmall-close { background-position: -80px -208px; }
+.ui-icon-grip-dotted-vertical { background-position: 0 -224px; }
+.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; }
+.ui-icon-grip-solid-vertical { background-position: -32px -224px; }
+.ui-icon-grip-solid-horizontal { background-position: -48px -224px; }
+.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; }
+.ui-icon-grip-diagonal-se { background-position: -80px -224px; }
+
+
+/* Misc visuals
+----------------------------------*/
+
+/* Corner radius */
+.ui-corner-all, .ui-corner-top, .ui-corner-left, .ui-corner-tl { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; -khtml-border-top-left-radius: 4px; border-top-left-radius: 4px; }
+.ui-corner-all, .ui-corner-top, .ui-corner-right, .ui-corner-tr { -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; -khtml-border-top-right-radius: 4px; border-top-right-radius: 4px; }
+.ui-corner-all, .ui-corner-bottom, .ui-corner-left, .ui-corner-bl { -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; -khtml-border-bottom-left-radius: 4px; border-bottom-left-radius: 4px; }
+.ui-corner-all, .ui-corner-bottom, .ui-corner-right, .ui-corner-br { -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; -khtml-border-bottom-right-radius: 4px; border-bottom-right-radius: 4px; }
+
+/* Overlays */
+.ui-widget-overlay { background: #aaaaaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x; opacity: .3;filter:Alpha(Opacity=30); }
+.ui-widget-shadow { margin: -8px 0 0 -8px; padding: 8px; background: #aaaaaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x; opacity: .3;filter:Alpha(Opacity=30); -moz-border-radius: 8px; -khtml-border-radius: 8px; -webkit-border-radius: 8px; border-radius: 8px; }
\ No newline at end of file
diff --git a/lib/scripts/jquery/jquery-ui-theme/jquery-ui-1.9.2.custom.min.css b/lib/scripts/jquery/jquery-ui-theme/jquery-ui-1.9.2.custom.min.css
new file mode 100755
index 000000000..e96496989
--- /dev/null
+++ b/lib/scripts/jquery/jquery-ui-theme/jquery-ui-1.9.2.custom.min.css
@@ -0,0 +1,5 @@
+/*! jQuery UI - v1.9.2 - 2012-11-23
+* http://jqueryui.com
+* Includes: jquery.ui.core.css, jquery.ui.accordion.css, jquery.ui.autocomplete.css, jquery.ui.button.css, jquery.ui.datepicker.css, jquery.ui.dialog.css, jquery.ui.menu.css, jquery.ui.progressbar.css, jquery.ui.resizable.css, jquery.ui.selectable.css, jquery.ui.slider.css, jquery.ui.spinner.css, jquery.ui.tabs.css, jquery.ui.tooltip.css
+* To view and modify this theme, visit http://jqueryui.com/themeroller/
+* Copyright (c) 2012 jQuery Foundation and other contributors Licensed MIT */.ui-helper-hidden{display:none}.ui-helper-hidden-accessible{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.ui-helper-reset{margin:0;padding:0;border:0;outline:0;line-height:1.3;text-decoration:none;font-size:100%;list-style:none}.ui-helper-clearfix:before,.ui-helper-clearfix:after{content:"";display:table}.ui-helper-clearfix:after{clear:both}.ui-helper-clearfix{zoom:1}.ui-helper-zfix{width:100%;height:100%;top:0;left:0;position:absolute;opacity:0;filter:Alpha(Opacity=0)}.ui-state-disabled{cursor:default!important}.ui-icon{display:block;text-indent:-99999px;overflow:hidden;background-repeat:no-repeat}.ui-widget-overlay{position:absolute;top:0;left:0;width:100%;height:100%}.ui-accordion .ui-accordion-header{display:block;cursor:pointer;position:relative;margin-top:2px;padding:.5em .5em .5em .7em;zoom:1}.ui-accordion .ui-accordion-icons{padding-left:2.2em}.ui-accordion .ui-accordion-noicons{padding-left:.7em}.ui-accordion .ui-accordion-icons .ui-accordion-icons{padding-left:2.2em}.ui-accordion .ui-accordion-header .ui-accordion-header-icon{position:absolute;left:.5em;top:50%;margin-top:-8px}.ui-accordion .ui-accordion-content{padding:1em 2.2em;border-top:0;overflow:auto;zoom:1}.ui-autocomplete{position:absolute;top:0;left:0;cursor:default}* html .ui-autocomplete{width:1px}.ui-button{display:inline-block;position:relative;padding:0;margin-right:.1em;cursor:pointer;text-align:center;zoom:1;overflow:visible}.ui-button,.ui-button:link,.ui-button:visited,.ui-button:hover,.ui-button:active{text-decoration:none}.ui-button-icon-only{width:2.2em}button.ui-button-icon-only{width:2.4em}.ui-button-icons-only{width:3.4em}button.ui-button-icons-only{width:3.7em}.ui-button .ui-button-text{display:block;line-height:1.4}.ui-button-text-only .ui-button-text{padding:.4em 1em}.ui-button-icon-only .ui-button-text,.ui-button-icons-only .ui-button-text{padding:.4em;text-indent:-9999999px}.ui-button-text-icon-primary .ui-button-text,.ui-button-text-icons .ui-button-text{padding:.4em 1em .4em 2.1em}.ui-button-text-icon-secondary .ui-button-text,.ui-button-text-icons .ui-button-text{padding:.4em 2.1em .4em 1em}.ui-button-text-icons .ui-button-text{padding-left:2.1em;padding-right:2.1em}input.ui-button{padding:.4em 1em}.ui-button-icon-only .ui-icon,.ui-button-text-icon-primary .ui-icon,.ui-button-text-icon-secondary .ui-icon,.ui-button-text-icons .ui-icon,.ui-button-icons-only .ui-icon{position:absolute;top:50%;margin-top:-8px}.ui-button-icon-only .ui-icon{left:50%;margin-left:-8px}.ui-button-text-icon-primary .ui-button-icon-primary,.ui-button-text-icons .ui-button-icon-primary,.ui-button-icons-only .ui-button-icon-primary{left:.5em}.ui-button-text-icon-secondary .ui-button-icon-secondary,.ui-button-text-icons .ui-button-icon-secondary,.ui-button-icons-only .ui-button-icon-secondary{right:.5em}.ui-button-text-icons .ui-button-icon-secondary,.ui-button-icons-only .ui-button-icon-secondary{right:.5em}.ui-buttonset{margin-right:7px}.ui-buttonset .ui-button{margin-left:0;margin-right:-.3em}button.ui-button::-moz-focus-inner{border:0;padding:0}.ui-datepicker{width:17em;padding:.2em .2em 0;display:none}.ui-datepicker .ui-datepicker-header{position:relative;padding:.2em 0}.ui-datepicker .ui-datepicker-prev,.ui-datepicker .ui-datepicker-next{position:absolute;top:2px;width:1.8em;height:1.8em}.ui-datepicker .ui-datepicker-prev-hover,.ui-datepicker .ui-datepicker-next-hover{top:1px}.ui-datepicker .ui-datepicker-prev{left:2px}.ui-datepicker .ui-datepicker-next{right:2px}.ui-datepicker .ui-datepicker-prev-hover{left:1px}.ui-datepicker .ui-datepicker-next-hover{right:1px}.ui-datepicker .ui-datepicker-prev span,.ui-datepicker .ui-datepicker-next span{display:block;position:absolute;left:50%;margin-left:-8px;top:50%;margin-top:-8px}.ui-datepicker .ui-datepicker-title{margin:0 2.3em;line-height:1.8em;text-align:center}.ui-datepicker .ui-datepicker-title select{font-size:1em;margin:1px 0}.ui-datepicker select.ui-datepicker-month-year{width:100%}.ui-datepicker select.ui-datepicker-month,.ui-datepicker select.ui-datepicker-year{width:49%}.ui-datepicker table{width:100%;font-size:.9em;border-collapse:collapse;margin:0 0 .4em}.ui-datepicker th{padding:.7em .3em;text-align:center;font-weight:bold;border:0}.ui-datepicker td{border:0;padding:1px}.ui-datepicker td span,.ui-datepicker td a{display:block;padding:.2em;text-align:right;text-decoration:none}.ui-datepicker .ui-datepicker-buttonpane{background-image:none;margin:.7em 0 0 0;padding:0 .2em;border-left:0;border-right:0;border-bottom:0}.ui-datepicker .ui-datepicker-buttonpane button{float:right;margin:.5em .2em .4em;cursor:pointer;padding:.2em .6em .3em .6em;width:auto;overflow:visible}.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current{float:left}.ui-datepicker.ui-datepicker-multi{width:auto}.ui-datepicker-multi .ui-datepicker-group{float:left}.ui-datepicker-multi .ui-datepicker-group table{width:95%;margin:0 auto .4em}.ui-datepicker-multi-2 .ui-datepicker-group{width:50%}.ui-datepicker-multi-3 .ui-datepicker-group{width:33.3%}.ui-datepicker-multi-4 .ui-datepicker-group{width:25%}.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header{border-left-width:0}.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header{border-left-width:0}.ui-datepicker-multi .ui-datepicker-buttonpane{clear:left}.ui-datepicker-row-break{clear:both;width:100%;font-size:0em}.ui-datepicker-rtl{direction:rtl}.ui-datepicker-rtl .ui-datepicker-prev{right:2px;left:auto}.ui-datepicker-rtl .ui-datepicker-next{left:2px;right:auto}.ui-datepicker-rtl .ui-datepicker-prev:hover{right:1px;left:auto}.ui-datepicker-rtl .ui-datepicker-next:hover{left:1px;right:auto}.ui-datepicker-rtl .ui-datepicker-buttonpane{clear:right}.ui-datepicker-rtl .ui-datepicker-buttonpane button{float:left}.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current{float:right}.ui-datepicker-rtl .ui-datepicker-group{float:right}.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header{border-right-width:0;border-left-width:1px}.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header{border-right-width:0;border-left-width:1px}.ui-datepicker-cover{position:absolute;z-index:-1;filter:mask();top:-4px;left:-4px;width:200px;height:200px}.ui-dialog{position:absolute;top:0;left:0;padding:.2em;width:300px;overflow:hidden}.ui-dialog .ui-dialog-titlebar{padding:.4em 1em;position:relative}.ui-dialog .ui-dialog-title{float:left;margin:.1em 16px .1em 0}.ui-dialog .ui-dialog-titlebar-close{position:absolute;right:.3em;top:50%;width:19px;margin:-10px 0 0 0;padding:1px;height:18px}.ui-dialog .ui-dialog-titlebar-close span{display:block;margin:1px}.ui-dialog .ui-dialog-titlebar-close:hover,.ui-dialog .ui-dialog-titlebar-close:focus{padding:0}.ui-dialog .ui-dialog-content{position:relative;border:0;padding:.5em 1em;background:none;overflow:auto;zoom:1}.ui-dialog .ui-dialog-buttonpane{text-align:left;border-width:1px 0 0 0;background-image:none;margin:.5em 0 0 0;padding:.3em 1em .5em .4em}.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset{float:right}.ui-dialog .ui-dialog-buttonpane button{margin:.5em .4em .5em 0;cursor:pointer}.ui-dialog .ui-resizable-se{width:14px;height:14px;right:3px;bottom:3px}.ui-draggable .ui-dialog-titlebar{cursor:move}.ui-menu{list-style:none;padding:2px;margin:0;display:block;outline:none}.ui-menu .ui-menu{margin-top:-3px;position:absolute}.ui-menu .ui-menu-item{margin:0;padding:0;zoom:1;width:100%}.ui-menu .ui-menu-divider{margin:5px -2px 5px -2px;height:0;font-size:0;line-height:0;border-width:1px 0 0 0}.ui-menu .ui-menu-item a{text-decoration:none;display:block;padding:2px .4em;line-height:1.5;zoom:1;font-weight:normal}.ui-menu .ui-menu-item a.ui-state-focus,.ui-menu .ui-menu-item a.ui-state-active{font-weight:normal;margin:-1px}.ui-menu .ui-state-disabled{font-weight:normal;margin:.4em 0 .2em;line-height:1.5}.ui-menu .ui-state-disabled a{cursor:default}.ui-menu-icons{position:relative}.ui-menu-icons .ui-menu-item a{position:relative;padding-left:2em}.ui-menu .ui-icon{position:absolute;top:.2em;left:.2em}.ui-menu .ui-menu-icon{position:static;float:right}.ui-progressbar{height:2em;text-align:left;overflow:hidden}.ui-progressbar .ui-progressbar-value{margin:-1px;height:100%}.ui-resizable{position:relative}.ui-resizable-handle{position:absolute;font-size:0.1px;display:block}.ui-resizable-disabled .ui-resizable-handle,.ui-resizable-autohide .ui-resizable-handle{display:none}.ui-resizable-n{cursor:n-resize;height:7px;width:100%;top:-5px;left:0}.ui-resizable-s{cursor:s-resize;height:7px;width:100%;bottom:-5px;left:0}.ui-resizable-e{cursor:e-resize;width:7px;right:-5px;top:0;height:100%}.ui-resizable-w{cursor:w-resize;width:7px;left:-5px;top:0;height:100%}.ui-resizable-se{cursor:se-resize;width:12px;height:12px;right:1px;bottom:1px}.ui-resizable-sw{cursor:sw-resize;width:9px;height:9px;left:-5px;bottom:-5px}.ui-resizable-nw{cursor:nw-resize;width:9px;height:9px;left:-5px;top:-5px}.ui-resizable-ne{cursor:ne-resize;width:9px;height:9px;right:-5px;top:-5px}.ui-selectable-helper{position:absolute;z-index:100;border:1px dotted black}.ui-slider{position:relative;text-align:left}.ui-slider .ui-slider-handle{position:absolute;z-index:2;width:1.2em;height:1.2em;cursor:default}.ui-slider .ui-slider-range{position:absolute;z-index:1;font-size:.7em;display:block;border:0;background-position:0 0}.ui-slider-horizontal{height:.8em}.ui-slider-horizontal .ui-slider-handle{top:-.3em;margin-left:-.6em}.ui-slider-horizontal .ui-slider-range{top:0;height:100%}.ui-slider-horizontal .ui-slider-range-min{left:0}.ui-slider-horizontal .ui-slider-range-max{right:0}.ui-slider-vertical{width:.8em;height:100px}.ui-slider-vertical .ui-slider-handle{left:-.3em;margin-left:0;margin-bottom:-.6em}.ui-slider-vertical .ui-slider-range{left:0;width:100%}.ui-slider-vertical .ui-slider-range-min{bottom:0}.ui-slider-vertical .ui-slider-range-max{top:0}.ui-spinner{position:relative;display:inline-block;overflow:hidden;padding:0;vertical-align:middle}.ui-spinner-input{border:none;background:none;padding:0;margin:.2em 0;vertical-align:middle;margin-left:.4em;margin-right:22px}.ui-spinner-button{width:16px;height:50%;font-size:.5em;padding:0;margin:0;text-align:center;position:absolute;cursor:default;display:block;overflow:hidden;right:0}.ui-spinner a.ui-spinner-button{border-top:none;border-bottom:none;border-right:none}.ui-spinner .ui-icon{position:absolute;margin-top:-8px;top:50%;left:0}.ui-spinner-up{top:0}.ui-spinner-down{bottom:0}.ui-spinner .ui-icon-triangle-1-s{background-position:-65px -16px}.ui-tabs{position:relative;padding:.2em;zoom:1}.ui-tabs .ui-tabs-nav{margin:0;padding:.2em .2em 0}.ui-tabs .ui-tabs-nav li{list-style:none;float:left;position:relative;top:0;margin:1px .2em 0 0;border-bottom:0;padding:0;white-space:nowrap}.ui-tabs .ui-tabs-nav li a{float:left;padding:.5em 1em;text-decoration:none}.ui-tabs .ui-tabs-nav li.ui-tabs-active{margin-bottom:-1px;padding-bottom:1px}.ui-tabs .ui-tabs-nav li.ui-tabs-active a,.ui-tabs .ui-tabs-nav li.ui-state-disabled a,.ui-tabs .ui-tabs-nav li.ui-tabs-loading a{cursor:text}.ui-tabs .ui-tabs-nav li a,.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-active a{cursor:pointer}.ui-tabs .ui-tabs-panel{display:block;border-width:0;padding:1em 1.4em;background:none}.ui-tooltip{padding:8px;position:absolute;z-index:9999;max-width:300px;-webkit-box-shadow:0 0 5px #aaa;box-shadow:0 0 5px #aaa}* html .ui-tooltip{background-image:none}body .ui-tooltip{border-width:2px}.ui-widget{font-family:Verdana,Arial,sans-serif;font-size:1.1em}.ui-widget .ui-widget{font-size:1em}.ui-widget input,.ui-widget select,.ui-widget textarea,.ui-widget button{font-family:Verdana,Arial,sans-serif;font-size:1em}.ui-widget-content{border:1px solid #aaa;background:#fff url(images/ui-bg_flat_75_ffffff_40x100.png) 50% 50% repeat-x;color:#222}.ui-widget-content a{color:#222}.ui-widget-header{border:1px solid #aaa;background:#ccc url(images/ui-bg_highlight-soft_75_cccccc_1x100.png) 50% 50% repeat-x;color:#222;font-weight:bold}.ui-widget-header a{color:#222}.ui-state-default,.ui-widget-content .ui-state-default,.ui-widget-header .ui-state-default{border:1px solid #d3d3d3;background:#e6e6e6 url(images/ui-bg_glass_75_e6e6e6_1x400.png) 50% 50% repeat-x;font-weight:normal;color:#555}.ui-state-default a,.ui-state-default a:link,.ui-state-default a:visited{color:#555;text-decoration:none}.ui-state-hover,.ui-widget-content .ui-state-hover,.ui-widget-header .ui-state-hover,.ui-state-focus,.ui-widget-content .ui-state-focus,.ui-widget-header .ui-state-focus{border:1px solid #999;background:#dadada url(images/ui-bg_glass_75_dadada_1x400.png) 50% 50% repeat-x;font-weight:normal;color:#212121}.ui-state-hover a,.ui-state-hover a:hover,.ui-state-hover a:link,.ui-state-hover a:visited{color:#212121;text-decoration:none}.ui-state-active,.ui-widget-content .ui-state-active,.ui-widget-header .ui-state-active{border:1px solid #aaa;background:#fff url(images/ui-bg_glass_65_ffffff_1x400.png) 50% 50% repeat-x;font-weight:normal;color:#212121}.ui-state-active a,.ui-state-active a:link,.ui-state-active a:visited{color:#212121;text-decoration:none}.ui-state-highlight,.ui-widget-content .ui-state-highlight,.ui-widget-header .ui-state-highlight{border:1px solid #fcefa1;background:#fbf9ee url(images/ui-bg_glass_55_fbf9ee_1x400.png) 50% 50% repeat-x;color:#363636}.ui-state-highlight a,.ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a{color:#363636}.ui-state-error,.ui-widget-content .ui-state-error,.ui-widget-header .ui-state-error{border:1px solid #cd0a0a;background:#fef1ec url(images/ui-bg_glass_95_fef1ec_1x400.png) 50% 50% repeat-x;color:#cd0a0a}.ui-state-error a,.ui-widget-content .ui-state-error a,.ui-widget-header .ui-state-error a{color:#cd0a0a}.ui-state-error-text,.ui-widget-content .ui-state-error-text,.ui-widget-header .ui-state-error-text{color:#cd0a0a}.ui-priority-primary,.ui-widget-content .ui-priority-primary,.ui-widget-header .ui-priority-primary{font-weight:bold}.ui-priority-secondary,.ui-widget-content .ui-priority-secondary,.ui-widget-header .ui-priority-secondary{opacity:.7;filter:Alpha(Opacity=70);font-weight:normal}.ui-state-disabled,.ui-widget-content .ui-state-disabled,.ui-widget-header .ui-state-disabled{opacity:.35;filter:Alpha(Opacity=35);background-image:none}.ui-state-disabled .ui-icon{filter:Alpha(Opacity=35)}.ui-icon{width:16px;height:16px;background-image:url(images/ui-icons_222222_256x240.png)}.ui-widget-content .ui-icon{background-image:url(images/ui-icons_222222_256x240.png)}.ui-widget-header .ui-icon{background-image:url(images/ui-icons_222222_256x240.png)}.ui-state-default .ui-icon{background-image:url(images/ui-icons_888888_256x240.png)}.ui-state-hover .ui-icon,.ui-state-focus .ui-icon{background-image:url(images/ui-icons_454545_256x240.png)}.ui-state-active .ui-icon{background-image:url(images/ui-icons_454545_256x240.png)}.ui-state-highlight .ui-icon{background-image:url(images/ui-icons_2e83ff_256x240.png)}.ui-state-error .ui-icon,.ui-state-error-text .ui-icon{background-image:url(images/ui-icons_cd0a0a_256x240.png)}.ui-icon-carat-1-n{background-position:0 0}.ui-icon-carat-1-ne{background-position:-16px 0}.ui-icon-carat-1-e{background-position:-32px 0}.ui-icon-carat-1-se{background-position:-48px 0}.ui-icon-carat-1-s{background-position:-64px 0}.ui-icon-carat-1-sw{background-position:-80px 0}.ui-icon-carat-1-w{background-position:-96px 0}.ui-icon-carat-1-nw{background-position:-112px 0}.ui-icon-carat-2-n-s{background-position:-128px 0}.ui-icon-carat-2-e-w{background-position:-144px 0}.ui-icon-triangle-1-n{background-position:0 -16px}.ui-icon-triangle-1-ne{background-position:-16px -16px}.ui-icon-triangle-1-e{background-position:-32px -16px}.ui-icon-triangle-1-se{background-position:-48px -16px}.ui-icon-triangle-1-s{background-position:-64px -16px}.ui-icon-triangle-1-sw{background-position:-80px -16px}.ui-icon-triangle-1-w{background-position:-96px -16px}.ui-icon-triangle-1-nw{background-position:-112px -16px}.ui-icon-triangle-2-n-s{background-position:-128px -16px}.ui-icon-triangle-2-e-w{background-position:-144px -16px}.ui-icon-arrow-1-n{background-position:0 -32px}.ui-icon-arrow-1-ne{background-position:-16px -32px}.ui-icon-arrow-1-e{background-position:-32px -32px}.ui-icon-arrow-1-se{background-position:-48px -32px}.ui-icon-arrow-1-s{background-position:-64px -32px}.ui-icon-arrow-1-sw{background-position:-80px -32px}.ui-icon-arrow-1-w{background-position:-96px -32px}.ui-icon-arrow-1-nw{background-position:-112px -32px}.ui-icon-arrow-2-n-s{background-position:-128px -32px}.ui-icon-arrow-2-ne-sw{background-position:-144px -32px}.ui-icon-arrow-2-e-w{background-position:-160px -32px}.ui-icon-arrow-2-se-nw{background-position:-176px -32px}.ui-icon-arrowstop-1-n{background-position:-192px -32px}.ui-icon-arrowstop-1-e{background-position:-208px -32px}.ui-icon-arrowstop-1-s{background-position:-224px -32px}.ui-icon-arrowstop-1-w{background-position:-240px -32px}.ui-icon-arrowthick-1-n{background-position:0 -48px}.ui-icon-arrowthick-1-ne{background-position:-16px -48px}.ui-icon-arrowthick-1-e{background-position:-32px -48px}.ui-icon-arrowthick-1-se{background-position:-48px -48px}.ui-icon-arrowthick-1-s{background-position:-64px -48px}.ui-icon-arrowthick-1-sw{background-position:-80px -48px}.ui-icon-arrowthick-1-w{background-position:-96px -48px}.ui-icon-arrowthick-1-nw{background-position:-112px -48px}.ui-icon-arrowthick-2-n-s{background-position:-128px -48px}.ui-icon-arrowthick-2-ne-sw{background-position:-144px -48px}.ui-icon-arrowthick-2-e-w{background-position:-160px -48px}.ui-icon-arrowthick-2-se-nw{background-position:-176px -48px}.ui-icon-arrowthickstop-1-n{background-position:-192px -48px}.ui-icon-arrowthickstop-1-e{background-position:-208px -48px}.ui-icon-arrowthickstop-1-s{background-position:-224px -48px}.ui-icon-arrowthickstop-1-w{background-position:-240px -48px}.ui-icon-arrowreturnthick-1-w{background-position:0 -64px}.ui-icon-arrowreturnthick-1-n{background-position:-16px -64px}.ui-icon-arrowreturnthick-1-e{background-position:-32px -64px}.ui-icon-arrowreturnthick-1-s{background-position:-48px -64px}.ui-icon-arrowreturn-1-w{background-position:-64px -64px}.ui-icon-arrowreturn-1-n{background-position:-80px -64px}.ui-icon-arrowreturn-1-e{background-position:-96px -64px}.ui-icon-arrowreturn-1-s{background-position:-112px -64px}.ui-icon-arrowrefresh-1-w{background-position:-128px -64px}.ui-icon-arrowrefresh-1-n{background-position:-144px -64px}.ui-icon-arrowrefresh-1-e{background-position:-160px -64px}.ui-icon-arrowrefresh-1-s{background-position:-176px -64px}.ui-icon-arrow-4{background-position:0 -80px}.ui-icon-arrow-4-diag{background-position:-16px -80px}.ui-icon-extlink{background-position:-32px -80px}.ui-icon-newwin{background-position:-48px -80px}.ui-icon-refresh{background-position:-64px -80px}.ui-icon-shuffle{background-position:-80px -80px}.ui-icon-transfer-e-w{background-position:-96px -80px}.ui-icon-transferthick-e-w{background-position:-112px -80px}.ui-icon-folder-collapsed{background-position:0 -96px}.ui-icon-folder-open{background-position:-16px -96px}.ui-icon-document{background-position:-32px -96px}.ui-icon-document-b{background-position:-48px -96px}.ui-icon-note{background-position:-64px -96px}.ui-icon-mail-closed{background-position:-80px -96px}.ui-icon-mail-open{background-position:-96px -96px}.ui-icon-suitcase{background-position:-112px -96px}.ui-icon-comment{background-position:-128px -96px}.ui-icon-person{background-position:-144px -96px}.ui-icon-print{background-position:-160px -96px}.ui-icon-trash{background-position:-176px -96px}.ui-icon-locked{background-position:-192px -96px}.ui-icon-unlocked{background-position:-208px -96px}.ui-icon-bookmark{background-position:-224px -96px}.ui-icon-tag{background-position:-240px -96px}.ui-icon-home{background-position:0 -112px}.ui-icon-flag{background-position:-16px -112px}.ui-icon-calendar{background-position:-32px -112px}.ui-icon-cart{background-position:-48px -112px}.ui-icon-pencil{background-position:-64px -112px}.ui-icon-clock{background-position:-80px -112px}.ui-icon-disk{background-position:-96px -112px}.ui-icon-calculator{background-position:-112px -112px}.ui-icon-zoomin{background-position:-128px -112px}.ui-icon-zoomout{background-position:-144px -112px}.ui-icon-search{background-position:-160px -112px}.ui-icon-wrench{background-position:-176px -112px}.ui-icon-gear{background-position:-192px -112px}.ui-icon-heart{background-position:-208px -112px}.ui-icon-star{background-position:-224px -112px}.ui-icon-link{background-position:-240px -112px}.ui-icon-cancel{background-position:0 -128px}.ui-icon-plus{background-position:-16px -128px}.ui-icon-plusthick{background-position:-32px -128px}.ui-icon-minus{background-position:-48px -128px}.ui-icon-minusthick{background-position:-64px -128px}.ui-icon-close{background-position:-80px -128px}.ui-icon-closethick{background-position:-96px -128px}.ui-icon-key{background-position:-112px -128px}.ui-icon-lightbulb{background-position:-128px -128px}.ui-icon-scissors{background-position:-144px -128px}.ui-icon-clipboard{background-position:-160px -128px}.ui-icon-copy{background-position:-176px -128px}.ui-icon-contact{background-position:-192px -128px}.ui-icon-image{background-position:-208px -128px}.ui-icon-video{background-position:-224px -128px}.ui-icon-script{background-position:-240px -128px}.ui-icon-alert{background-position:0 -144px}.ui-icon-info{background-position:-16px -144px}.ui-icon-notice{background-position:-32px -144px}.ui-icon-help{background-position:-48px -144px}.ui-icon-check{background-position:-64px -144px}.ui-icon-bullet{background-position:-80px -144px}.ui-icon-radio-on{background-position:-96px -144px}.ui-icon-radio-off{background-position:-112px -144px}.ui-icon-pin-w{background-position:-128px -144px}.ui-icon-pin-s{background-position:-144px -144px}.ui-icon-play{background-position:0 -160px}.ui-icon-pause{background-position:-16px -160px}.ui-icon-seek-next{background-position:-32px -160px}.ui-icon-seek-prev{background-position:-48px -160px}.ui-icon-seek-end{background-position:-64px -160px}.ui-icon-seek-start{background-position:-80px -160px}.ui-icon-seek-first{background-position:-80px -160px}.ui-icon-stop{background-position:-96px -160px}.ui-icon-eject{background-position:-112px -160px}.ui-icon-volume-off{background-position:-128px -160px}.ui-icon-volume-on{background-position:-144px -160px}.ui-icon-power{background-position:0 -176px}.ui-icon-signal-diag{background-position:-16px -176px}.ui-icon-signal{background-position:-32px -176px}.ui-icon-battery-0{background-position:-48px -176px}.ui-icon-battery-1{background-position:-64px -176px}.ui-icon-battery-2{background-position:-80px -176px}.ui-icon-battery-3{background-position:-96px -176px}.ui-icon-circle-plus{background-position:0 -192px}.ui-icon-circle-minus{background-position:-16px -192px}.ui-icon-circle-close{background-position:-32px -192px}.ui-icon-circle-triangle-e{background-position:-48px -192px}.ui-icon-circle-triangle-s{background-position:-64px -192px}.ui-icon-circle-triangle-w{background-position:-80px -192px}.ui-icon-circle-triangle-n{background-position:-96px -192px}.ui-icon-circle-arrow-e{background-position:-112px -192px}.ui-icon-circle-arrow-s{background-position:-128px -192px}.ui-icon-circle-arrow-w{background-position:-144px -192px}.ui-icon-circle-arrow-n{background-position:-160px -192px}.ui-icon-circle-zoomin{background-position:-176px -192px}.ui-icon-circle-zoomout{background-position:-192px -192px}.ui-icon-circle-check{background-position:-208px -192px}.ui-icon-circlesmall-plus{background-position:0 -208px}.ui-icon-circlesmall-minus{background-position:-16px -208px}.ui-icon-circlesmall-close{background-position:-32px -208px}.ui-icon-squaresmall-plus{background-position:-48px -208px}.ui-icon-squaresmall-minus{background-position:-64px -208px}.ui-icon-squaresmall-close{background-position:-80px -208px}.ui-icon-grip-dotted-vertical{background-position:0 -224px}.ui-icon-grip-dotted-horizontal{background-position:-16px -224px}.ui-icon-grip-solid-vertical{background-position:-32px -224px}.ui-icon-grip-solid-horizontal{background-position:-48px -224px}.ui-icon-gripsmall-diagonal-se{background-position:-64px -224px}.ui-icon-grip-diagonal-se{background-position:-80px -224px}.ui-corner-all,.ui-corner-top,.ui-corner-left,.ui-corner-tl{-moz-border-radius-topleft:4px;-webkit-border-top-left-radius:4px;-khtml-border-top-left-radius:4px;border-top-left-radius:4px}.ui-corner-all,.ui-corner-top,.ui-corner-right,.ui-corner-tr{-moz-border-radius-topright:4px;-webkit-border-top-right-radius:4px;-khtml-border-top-right-radius:4px;border-top-right-radius:4px}.ui-corner-all,.ui-corner-bottom,.ui-corner-left,.ui-corner-bl{-moz-border-radius-bottomleft:4px;-webkit-border-bottom-left-radius:4px;-khtml-border-bottom-left-radius:4px;border-bottom-left-radius:4px}.ui-corner-all,.ui-corner-bottom,.ui-corner-right,.ui-corner-br{-moz-border-radius-bottomright:4px;-webkit-border-bottom-right-radius:4px;-khtml-border-bottom-right-radius:4px;border-bottom-right-radius:4px}.ui-widget-overlay{background:#aaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x;opacity:.3;filter:Alpha(Opacity=30)}.ui-widget-shadow{margin:-8px 0 0 -8px;padding:8px;background:#aaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x;opacity:.3;filter:Alpha(Opacity=30);-moz-border-radius:8px;-khtml-border-radius:8px;-webkit-border-radius:8px;border-radius:8px}
\ No newline at end of file
diff --git a/lib/scripts/jquery/jquery-ui-theme/smoothness.css b/lib/scripts/jquery/jquery-ui-theme/smoothness.css
deleted file mode 100644
index 910d24b95..000000000
--- a/lib/scripts/jquery/jquery-ui-theme/smoothness.css
+++ /dev/null
@@ -1,568 +0,0 @@
-/*
- * jQuery UI CSS Framework 1.8.16
- *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Theming/API
- */
-
-/* Layout helpers
-----------------------------------*/
-.ui-helper-hidden { display: none; }
-.ui-helper-hidden-accessible { position: absolute !important; clip: rect(1px 1px 1px 1px); clip: rect(1px,1px,1px,1px); }
-.ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; }
-.ui-helper-clearfix:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; }
-.ui-helper-clearfix { display: inline-block; }
-/* required comment for clearfix to work in Opera \*/
-* html .ui-helper-clearfix { height:1%; }
-.ui-helper-clearfix { display:block; }
-/* end clearfix */
-.ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); }
-
-
-/* Interaction Cues
-----------------------------------*/
-.ui-state-disabled { cursor: default !important; }
-
-
-/* Icons
-----------------------------------*/
-
-/* states and images */
-.ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; }
-
-
-/* Misc visuals
-----------------------------------*/
-
-/* Overlays */
-.ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; }
-
-
-/*
- * jQuery UI CSS Framework 1.8.16
- *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Theming/API
- *
- * To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Verdana,Arial,sans-serif&fwDefault=normal&fsDefault=1.1em&cornerRadius=4px&bgColorHeader=cccccc&bgTextureHeader=03_highlight_soft.png&bgImgOpacityHeader=75&borderColorHeader=aaaaaa&fcHeader=222222&iconColorHeader=222222&bgColorContent=ffffff&bgTextureContent=01_flat.png&bgImgOpacityContent=75&borderColorContent=aaaaaa&fcContent=222222&iconColorContent=222222&bgColorDefault=e6e6e6&bgTextureDefault=02_glass.png&bgImgOpacityDefault=75&borderColorDefault=d3d3d3&fcDefault=555555&iconColorDefault=888888&bgColorHover=dadada&bgTextureHover=02_glass.png&bgImgOpacityHover=75&borderColorHover=999999&fcHover=212121&iconColorHover=454545&bgColorActive=ffffff&bgTextureActive=02_glass.png&bgImgOpacityActive=65&borderColorActive=aaaaaa&fcActive=212121&iconColorActive=454545&bgColorHighlight=fbf9ee&bgTextureHighlight=02_glass.png&bgImgOpacityHighlight=55&borderColorHighlight=fcefa1&fcHighlight=363636&iconColorHighlight=2e83ff&bgColorError=fef1ec&bgTextureError=02_glass.png&bgImgOpacityError=95&borderColorError=cd0a0a&fcError=cd0a0a&iconColorError=cd0a0a&bgColorOverlay=aaaaaa&bgTextureOverlay=01_flat.png&bgImgOpacityOverlay=0&opacityOverlay=30&bgColorShadow=aaaaaa&bgTextureShadow=01_flat.png&bgImgOpacityShadow=0&opacityShadow=30&thicknessShadow=8px&offsetTopShadow=-8px&offsetLeftShadow=-8px&cornerRadiusShadow=8px
- */
-
-
-/* Component containers
-----------------------------------*/
-.ui-widget { font-size: 1.1em; }
-.ui-widget .ui-widget { font-size: 1em; }
-.ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-size: 1em; }
-.ui-widget-content { border: 1px solid #aaaaaa; background: #ffffff url(images/ui-bg_flat_75_ffffff_40x100.png) 50% 50% repeat-x; color: #222222; }
-.ui-widget-content a { color: #222222; }
-.ui-widget-header { border: 1px solid #aaaaaa; background: #cccccc url(images/ui-bg_highlight-soft_75_cccccc_1x100.png) 50% 50% repeat-x; color: #222222; font-weight: bold; }
-.ui-widget-header a { color: #222222; }
-
-/* Interaction states
-----------------------------------*/
-.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { border: 1px solid #d3d3d3; background: #e6e6e6 url(images/ui-bg_glass_75_e6e6e6_1x400.png) 50% 50% repeat-x; font-weight: normal; color: #555555; }
-.ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #555555; text-decoration: none; }
-.ui-state-hover, .ui-widget-content .ui-state-hover, .ui-widget-header .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus, .ui-widget-header .ui-state-focus { border: 1px solid #999999; background: #dadada url(images/ui-bg_glass_75_dadada_1x400.png) 50% 50% repeat-x; font-weight: normal; color: #212121; }
-.ui-state-hover a, .ui-state-hover a:hover { color: #212121; text-decoration: none; }
-.ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active { border: 1px solid #aaaaaa; background: #ffffff url(images/ui-bg_glass_65_ffffff_1x400.png) 50% 50% repeat-x; font-weight: normal; color: #212121; }
-.ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #212121; text-decoration: none; }
-.ui-widget :active { outline: none; }
-
-/* Interaction Cues
-----------------------------------*/
-.ui-state-highlight, .ui-widget-content .ui-state-highlight, .ui-widget-header .ui-state-highlight  {border: 1px solid #fcefa1; background: #fbf9ee url(images/ui-bg_glass_55_fbf9ee_1x400.png) 50% 50% repeat-x; color: #363636; }
-.ui-state-highlight a, .ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a { color: #363636; }
-.ui-state-error, .ui-widget-content .ui-state-error, .ui-widget-header .ui-state-error {border: 1px solid #cd0a0a; background: #fef1ec url(images/ui-bg_glass_95_fef1ec_1x400.png) 50% 50% repeat-x; color: #cd0a0a; }
-.ui-state-error a, .ui-widget-content .ui-state-error a, .ui-widget-header .ui-state-error a { color: #cd0a0a; }
-.ui-state-error-text, .ui-widget-content .ui-state-error-text, .ui-widget-header .ui-state-error-text { color: #cd0a0a; }
-.ui-priority-primary, .ui-widget-content .ui-priority-primary, .ui-widget-header .ui-priority-primary { font-weight: bold; }
-.ui-priority-secondary, .ui-widget-content .ui-priority-secondary,  .ui-widget-header .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; }
-.ui-state-disabled, .ui-widget-content .ui-state-disabled, .ui-widget-header .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; }
-
-/* Icons
-----------------------------------*/
-
-/* states and images */
-.ui-icon { width: 16px; height: 16px; background-image: url(images/ui-icons_222222_256x240.png); }
-.ui-widget-content .ui-icon {background-image: url(images/ui-icons_222222_256x240.png); }
-.ui-widget-header .ui-icon {background-image: url(images/ui-icons_222222_256x240.png); }
-.ui-state-default .ui-icon { background-image: url(images/ui-icons_888888_256x240.png); }
-.ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url(images/ui-icons_454545_256x240.png); }
-.ui-state-active .ui-icon {background-image: url(images/ui-icons_454545_256x240.png); }
-.ui-state-highlight .ui-icon {background-image: url(images/ui-icons_2e83ff_256x240.png); }
-.ui-state-error .ui-icon, .ui-state-error-text .ui-icon {background-image: url(images/ui-icons_cd0a0a_256x240.png); }
-
-/* positioning */
-.ui-icon-carat-1-n { background-position: 0 0; }
-.ui-icon-carat-1-ne { background-position: -16px 0; }
-.ui-icon-carat-1-e { background-position: -32px 0; }
-.ui-icon-carat-1-se { background-position: -48px 0; }
-.ui-icon-carat-1-s { background-position: -64px 0; }
-.ui-icon-carat-1-sw { background-position: -80px 0; }
-.ui-icon-carat-1-w { background-position: -96px 0; }
-.ui-icon-carat-1-nw { background-position: -112px 0; }
-.ui-icon-carat-2-n-s { background-position: -128px 0; }
-.ui-icon-carat-2-e-w { background-position: -144px 0; }
-.ui-icon-triangle-1-n { background-position: 0 -16px; }
-.ui-icon-triangle-1-ne { background-position: -16px -16px; }
-.ui-icon-triangle-1-e { background-position: -32px -16px; }
-.ui-icon-triangle-1-se { background-position: -48px -16px; }
-.ui-icon-triangle-1-s { background-position: -64px -16px; }
-.ui-icon-triangle-1-sw { background-position: -80px -16px; }
-.ui-icon-triangle-1-w { background-position: -96px -16px; }
-.ui-icon-triangle-1-nw { background-position: -112px -16px; }
-.ui-icon-triangle-2-n-s { background-position: -128px -16px; }
-.ui-icon-triangle-2-e-w { background-position: -144px -16px; }
-.ui-icon-arrow-1-n { background-position: 0 -32px; }
-.ui-icon-arrow-1-ne { background-position: -16px -32px; }
-.ui-icon-arrow-1-e { background-position: -32px -32px; }
-.ui-icon-arrow-1-se { background-position: -48px -32px; }
-.ui-icon-arrow-1-s { background-position: -64px -32px; }
-.ui-icon-arrow-1-sw { background-position: -80px -32px; }
-.ui-icon-arrow-1-w { background-position: -96px -32px; }
-.ui-icon-arrow-1-nw { background-position: -112px -32px; }
-.ui-icon-arrow-2-n-s { background-position: -128px -32px; }
-.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; }
-.ui-icon-arrow-2-e-w { background-position: -160px -32px; }
-.ui-icon-arrow-2-se-nw { background-position: -176px -32px; }
-.ui-icon-arrowstop-1-n { background-position: -192px -32px; }
-.ui-icon-arrowstop-1-e { background-position: -208px -32px; }
-.ui-icon-arrowstop-1-s { background-position: -224px -32px; }
-.ui-icon-arrowstop-1-w { background-position: -240px -32px; }
-.ui-icon-arrowthick-1-n { background-position: 0 -48px; }
-.ui-icon-arrowthick-1-ne { background-position: -16px -48px; }
-.ui-icon-arrowthick-1-e { background-position: -32px -48px; }
-.ui-icon-arrowthick-1-se { background-position: -48px -48px; }
-.ui-icon-arrowthick-1-s { background-position: -64px -48px; }
-.ui-icon-arrowthick-1-sw { background-position: -80px -48px; }
-.ui-icon-arrowthick-1-w { background-position: -96px -48px; }
-.ui-icon-arrowthick-1-nw { background-position: -112px -48px; }
-.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; }
-.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; }
-.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; }
-.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; }
-.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; }
-.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; }
-.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; }
-.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; }
-.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; }
-.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; }
-.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; }
-.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; }
-.ui-icon-arrowreturn-1-w { background-position: -64px -64px; }
-.ui-icon-arrowreturn-1-n { background-position: -80px -64px; }
-.ui-icon-arrowreturn-1-e { background-position: -96px -64px; }
-.ui-icon-arrowreturn-1-s { background-position: -112px -64px; }
-.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; }
-.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; }
-.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; }
-.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; }
-.ui-icon-arrow-4 { background-position: 0 -80px; }
-.ui-icon-arrow-4-diag { background-position: -16px -80px; }
-.ui-icon-extlink { background-position: -32px -80px; }
-.ui-icon-newwin { background-position: -48px -80px; }
-.ui-icon-refresh { background-position: -64px -80px; }
-.ui-icon-shuffle { background-position: -80px -80px; }
-.ui-icon-transfer-e-w { background-position: -96px -80px; }
-.ui-icon-transferthick-e-w { background-position: -112px -80px; }
-.ui-icon-folder-collapsed { background-position: 0 -96px; }
-.ui-icon-folder-open { background-position: -16px -96px; }
-.ui-icon-document { background-position: -32px -96px; }
-.ui-icon-document-b { background-position: -48px -96px; }
-.ui-icon-note { background-position: -64px -96px; }
-.ui-icon-mail-closed { background-position: -80px -96px; }
-.ui-icon-mail-open { background-position: -96px -96px; }
-.ui-icon-suitcase { background-position: -112px -96px; }
-.ui-icon-comment { background-position: -128px -96px; }
-.ui-icon-person { background-position: -144px -96px; }
-.ui-icon-print { background-position: -160px -96px; }
-.ui-icon-trash { background-position: -176px -96px; }
-.ui-icon-locked { background-position: -192px -96px; }
-.ui-icon-unlocked { background-position: -208px -96px; }
-.ui-icon-bookmark { background-position: -224px -96px; }
-.ui-icon-tag { background-position: -240px -96px; }
-.ui-icon-home { background-position: 0 -112px; }
-.ui-icon-flag { background-position: -16px -112px; }
-.ui-icon-calendar { background-position: -32px -112px; }
-.ui-icon-cart { background-position: -48px -112px; }
-.ui-icon-pencil { background-position: -64px -112px; }
-.ui-icon-clock { background-position: -80px -112px; }
-.ui-icon-disk { background-position: -96px -112px; }
-.ui-icon-calculator { background-position: -112px -112px; }
-.ui-icon-zoomin { background-position: -128px -112px; }
-.ui-icon-zoomout { background-position: -144px -112px; }
-.ui-icon-search { background-position: -160px -112px; }
-.ui-icon-wrench { background-position: -176px -112px; }
-.ui-icon-gear { background-position: -192px -112px; }
-.ui-icon-heart { background-position: -208px -112px; }
-.ui-icon-star { background-position: -224px -112px; }
-.ui-icon-link { background-position: -240px -112px; }
-.ui-icon-cancel { background-position: 0 -128px; }
-.ui-icon-plus { background-position: -16px -128px; }
-.ui-icon-plusthick { background-position: -32px -128px; }
-.ui-icon-minus { background-position: -48px -128px; }
-.ui-icon-minusthick { background-position: -64px -128px; }
-.ui-icon-close { background-position: -80px -128px; }
-.ui-icon-closethick { background-position: -96px -128px; }
-.ui-icon-key { background-position: -112px -128px; }
-.ui-icon-lightbulb { background-position: -128px -128px; }
-.ui-icon-scissors { background-position: -144px -128px; }
-.ui-icon-clipboard { background-position: -160px -128px; }
-.ui-icon-copy { background-position: -176px -128px; }
-.ui-icon-contact { background-position: -192px -128px; }
-.ui-icon-image { background-position: -208px -128px; }
-.ui-icon-video { background-position: -224px -128px; }
-.ui-icon-script { background-position: -240px -128px; }
-.ui-icon-alert { background-position: 0 -144px; }
-.ui-icon-info { background-position: -16px -144px; }
-.ui-icon-notice { background-position: -32px -144px; }
-.ui-icon-help { background-position: -48px -144px; }
-.ui-icon-check { background-position: -64px -144px; }
-.ui-icon-bullet { background-position: -80px -144px; }
-.ui-icon-radio-off { background-position: -96px -144px; }
-.ui-icon-radio-on { background-position: -112px -144px; }
-.ui-icon-pin-w { background-position: -128px -144px; }
-.ui-icon-pin-s { background-position: -144px -144px; }
-.ui-icon-play { background-position: 0 -160px; }
-.ui-icon-pause { background-position: -16px -160px; }
-.ui-icon-seek-next { background-position: -32px -160px; }
-.ui-icon-seek-prev { background-position: -48px -160px; }
-.ui-icon-seek-end { background-position: -64px -160px; }
-.ui-icon-seek-start { background-position: -80px -160px; }
-/* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */
-.ui-icon-seek-first { background-position: -80px -160px; }
-.ui-icon-stop { background-position: -96px -160px; }
-.ui-icon-eject { background-position: -112px -160px; }
-.ui-icon-volume-off { background-position: -128px -160px; }
-.ui-icon-volume-on { background-position: -144px -160px; }
-.ui-icon-power { background-position: 0 -176px; }
-.ui-icon-signal-diag { background-position: -16px -176px; }
-.ui-icon-signal { background-position: -32px -176px; }
-.ui-icon-battery-0 { background-position: -48px -176px; }
-.ui-icon-battery-1 { background-position: -64px -176px; }
-.ui-icon-battery-2 { background-position: -80px -176px; }
-.ui-icon-battery-3 { background-position: -96px -176px; }
-.ui-icon-circle-plus { background-position: 0 -192px; }
-.ui-icon-circle-minus { background-position: -16px -192px; }
-.ui-icon-circle-close { background-position: -32px -192px; }
-.ui-icon-circle-triangle-e { background-position: -48px -192px; }
-.ui-icon-circle-triangle-s { background-position: -64px -192px; }
-.ui-icon-circle-triangle-w { background-position: -80px -192px; }
-.ui-icon-circle-triangle-n { background-position: -96px -192px; }
-.ui-icon-circle-arrow-e { background-position: -112px -192px; }
-.ui-icon-circle-arrow-s { background-position: -128px -192px; }
-.ui-icon-circle-arrow-w { background-position: -144px -192px; }
-.ui-icon-circle-arrow-n { background-position: -160px -192px; }
-.ui-icon-circle-zoomin { background-position: -176px -192px; }
-.ui-icon-circle-zoomout { background-position: -192px -192px; }
-.ui-icon-circle-check { background-position: -208px -192px; }
-.ui-icon-circlesmall-plus { background-position: 0 -208px; }
-.ui-icon-circlesmall-minus { background-position: -16px -208px; }
-.ui-icon-circlesmall-close { background-position: -32px -208px; }
-.ui-icon-squaresmall-plus { background-position: -48px -208px; }
-.ui-icon-squaresmall-minus { background-position: -64px -208px; }
-.ui-icon-squaresmall-close { background-position: -80px -208px; }
-.ui-icon-grip-dotted-vertical { background-position: 0 -224px; }
-.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; }
-.ui-icon-grip-solid-vertical { background-position: -32px -224px; }
-.ui-icon-grip-solid-horizontal { background-position: -48px -224px; }
-.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; }
-.ui-icon-grip-diagonal-se { background-position: -80px -224px; }
-
-
-/* Misc visuals
-----------------------------------*/
-
-/* Corner radius */
-.ui-corner-all, .ui-corner-top, .ui-corner-left, .ui-corner-tl { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; -khtml-border-top-left-radius: 4px; border-top-left-radius: 4px; }
-.ui-corner-all, .ui-corner-top, .ui-corner-right, .ui-corner-tr { -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; -khtml-border-top-right-radius: 4px; border-top-right-radius: 4px; }
-.ui-corner-all, .ui-corner-bottom, .ui-corner-left, .ui-corner-bl { -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; -khtml-border-bottom-left-radius: 4px; border-bottom-left-radius: 4px; }
-.ui-corner-all, .ui-corner-bottom, .ui-corner-right, .ui-corner-br { -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; -khtml-border-bottom-right-radius: 4px; border-bottom-right-radius: 4px; }
-
-/* Overlays */
-.ui-widget-overlay { background: #aaaaaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x; opacity: .30;filter:Alpha(Opacity=30); }
-.ui-widget-shadow { margin: -8px 0 0 -8px; padding: 8px; background: #aaaaaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x; opacity: .30;filter:Alpha(Opacity=30); -moz-border-radius: 8px; -khtml-border-radius: 8px; -webkit-border-radius: 8px; border-radius: 8px; }/*
- * jQuery UI Resizable 1.8.16
- *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Resizable#theming
- */
-.ui-resizable { position: relative;}
-.ui-resizable-handle { position: absolute;font-size: 0.1px;z-index: 99999; display: block; }
-.ui-resizable-disabled .ui-resizable-handle, .ui-resizable-autohide .ui-resizable-handle { display: none; }
-.ui-resizable-n { cursor: n-resize; height: 7px; width: 100%; top: -5px; left: 0; }
-.ui-resizable-s { cursor: s-resize; height: 7px; width: 100%; bottom: -5px; left: 0; }
-.ui-resizable-e { cursor: e-resize; width: 7px; right: -5px; top: 0; height: 100%; }
-.ui-resizable-w { cursor: w-resize; width: 7px; left: -5px; top: 0; height: 100%; }
-.ui-resizable-se { cursor: se-resize; width: 12px; height: 12px; right: 1px; bottom: 1px; }
-.ui-resizable-sw { cursor: sw-resize; width: 9px; height: 9px; left: -5px; bottom: -5px; }
-.ui-resizable-nw { cursor: nw-resize; width: 9px; height: 9px; left: -5px; top: -5px; }
-.ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: -5px; top: -5px;}/*
- * jQuery UI Selectable 1.8.16
- *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Selectable#theming
- */
-.ui-selectable-helper { position: absolute; z-index: 100; border:1px dotted black; }
-/*
- * jQuery UI Accordion 1.8.16
- *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Accordion#theming
- */
-/* IE/Win - Fix animation bug - #4615 */
-.ui-accordion { width: 100%; }
-.ui-accordion .ui-accordion-header { cursor: pointer; position: relative; margin-top: 1px; zoom: 1; }
-.ui-accordion .ui-accordion-li-fix { display: inline; }
-.ui-accordion .ui-accordion-header-active { border-bottom: 0 !important; }
-.ui-accordion .ui-accordion-header a { display: block; font-size: 1em; padding: .5em .5em .5em .7em; }
-.ui-accordion-icons .ui-accordion-header a { padding-left: 2.2em; }
-.ui-accordion .ui-accordion-header .ui-icon { position: absolute; left: .5em; top: 50%; margin-top: -8px; }
-.ui-accordion .ui-accordion-content { padding: 1em 2.2em; border-top: 0; margin-top: -2px; position: relative; top: 1px; margin-bottom: 2px; overflow: auto; display: none; zoom: 1; }
-.ui-accordion .ui-accordion-content-active { display: block; }
-/*
- * jQuery UI Autocomplete 1.8.16
- *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Autocomplete#theming
- */
-.ui-autocomplete { position: absolute; cursor: default; }	
-
-/* workarounds */
-* html .ui-autocomplete { width:1px; } /* without this, the menu expands to 100% in IE6 */
-
-/*
- * jQuery UI Menu 1.8.16
- *
- * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Menu#theming
- */
-.ui-menu {
-	list-style:none;
-	padding: 2px;
-	margin: 0;
-	display:block;
-	float: left;
-}
-.ui-menu .ui-menu {
-	margin-top: -3px;
-}
-.ui-menu .ui-menu-item {
-	margin:0;
-	padding: 0;
-	zoom: 1;
-	float: left;
-	clear: left;
-	width: 100%;
-}
-.ui-menu .ui-menu-item a {
-	text-decoration:none;
-	display:block;
-	padding:.2em .4em;
-	line-height:1.5;
-	zoom:1;
-}
-.ui-menu .ui-menu-item a.ui-state-hover,
-.ui-menu .ui-menu-item a.ui-state-active {
-	font-weight: normal;
-	margin: -1px;
-}
-/*
- * jQuery UI Button 1.8.16
- *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Button#theming
- */
-.ui-button { display: inline-block; position: relative; padding: 0; margin-right: .1em; text-decoration: none !important; cursor: pointer; text-align: center; zoom: 1; overflow: visible; } /* the overflow property removes extra width in IE */
-.ui-button-icon-only { width: 2.2em; } /* to make room for the icon, a width needs to be set here */
-button.ui-button-icon-only { width: 2.4em; } /* button elements seem to need a little more width */
-.ui-button-icons-only { width: 3.4em; } 
-button.ui-button-icons-only { width: 3.7em; } 
-
-/*button text element */
-.ui-button .ui-button-text { display: block; line-height: 1.4;  }
-.ui-button-text-only .ui-button-text { padding: .4em 1em; }
-.ui-button-icon-only .ui-button-text, .ui-button-icons-only .ui-button-text { padding: .4em; text-indent: -9999999px; }
-.ui-button-text-icon-primary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 1em .4em 2.1em; }
-.ui-button-text-icon-secondary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 2.1em .4em 1em; }
-.ui-button-text-icons .ui-button-text { padding-left: 2.1em; padding-right: 2.1em; }
-/* no icon support for input elements, provide padding by default */
-input.ui-button { padding: .4em 1em; }
-
-/*button icon element(s) */
-.ui-button-icon-only .ui-icon, .ui-button-text-icon-primary .ui-icon, .ui-button-text-icon-secondary .ui-icon, .ui-button-text-icons .ui-icon, .ui-button-icons-only .ui-icon { position: absolute; top: 50%; margin-top: -8px; }
-.ui-button-icon-only .ui-icon { left: 50%; margin-left: -8px; }
-.ui-button-text-icon-primary .ui-button-icon-primary, .ui-button-text-icons .ui-button-icon-primary, .ui-button-icons-only .ui-button-icon-primary { left: .5em; }
-.ui-button-text-icon-secondary .ui-button-icon-secondary, .ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; }
-.ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; }
-
-/*button sets*/
-.ui-buttonset { margin-right: 7px; }
-.ui-buttonset .ui-button { margin-left: 0; margin-right: -.3em; }
-
-/* workarounds */
-button.ui-button::-moz-focus-inner { border: 0; padding: 0; } /* reset extra padding in Firefox */
-/*
- * jQuery UI Dialog 1.8.16
- *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Dialog#theming
- */
-.ui-dialog { position: absolute; padding: .2em; width: 300px; overflow: hidden; }
-.ui-dialog .ui-dialog-titlebar { padding: .4em 1em; position: relative;  }
-.ui-dialog .ui-dialog-title { float: left; margin: .1em 16px .1em 0; } 
-.ui-dialog .ui-dialog-titlebar-close { position: absolute; right: .3em; top: 50%; width: 19px; margin: -10px 0 0 0; padding: 1px; height: 18px; }
-.ui-dialog .ui-dialog-titlebar-close span { display: block; margin: 1px; }
-.ui-dialog .ui-dialog-titlebar-close:hover, .ui-dialog .ui-dialog-titlebar-close:focus { padding: 0; }
-.ui-dialog .ui-dialog-content { position: relative; border: 0; padding: .5em 1em; background: none; overflow: auto; zoom: 1; }
-.ui-dialog .ui-dialog-buttonpane { text-align: left; border-width: 1px 0 0 0; background-image: none; margin: .5em 0 0 0; padding: .3em 1em .5em .4em; }
-.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset { float: right; }
-.ui-dialog .ui-dialog-buttonpane button { margin: .5em .4em .5em 0; cursor: pointer; }
-.ui-dialog .ui-resizable-se { width: 14px; height: 14px; right: 3px; bottom: 3px; }
-.ui-draggable .ui-dialog-titlebar { cursor: move; }
-/*
- * jQuery UI Slider 1.8.16
- *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Slider#theming
- */
-.ui-slider { position: relative; text-align: left; }
-.ui-slider .ui-slider-handle { position: absolute; z-index: 2; width: 1.2em; height: 1.2em; cursor: default; }
-.ui-slider .ui-slider-range { position: absolute; z-index: 1; font-size: .7em; display: block; border: 0; background-position: 0 0; }
-
-.ui-slider-horizontal { height: .8em; }
-.ui-slider-horizontal .ui-slider-handle { top: -.3em; margin-left: -.6em; }
-.ui-slider-horizontal .ui-slider-range { top: 0; height: 100%; }
-.ui-slider-horizontal .ui-slider-range-min { left: 0; }
-.ui-slider-horizontal .ui-slider-range-max { right: 0; }
-
-.ui-slider-vertical { width: .8em; height: 100px; }
-.ui-slider-vertical .ui-slider-handle { left: -.3em; margin-left: 0; margin-bottom: -.6em; }
-.ui-slider-vertical .ui-slider-range { left: 0; width: 100%; }
-.ui-slider-vertical .ui-slider-range-min { bottom: 0; }
-.ui-slider-vertical .ui-slider-range-max { top: 0; }/*
- * jQuery UI Tabs 1.8.16
- *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Tabs#theming
- */
-.ui-tabs { position: relative; padding: .2em; zoom: 1; } /* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */
-.ui-tabs .ui-tabs-nav { margin: 0; padding: .2em .2em 0; }
-.ui-tabs .ui-tabs-nav li { list-style: none; float: left; position: relative; top: 1px; margin: 0 .2em 1px 0; border-bottom: 0 !important; padding: 0; white-space: nowrap; }
-.ui-tabs .ui-tabs-nav li a { float: left; padding: .5em 1em; text-decoration: none; }
-.ui-tabs .ui-tabs-nav li.ui-tabs-selected { margin-bottom: 0; padding-bottom: 1px; }
-.ui-tabs .ui-tabs-nav li.ui-tabs-selected a, .ui-tabs .ui-tabs-nav li.ui-state-disabled a, .ui-tabs .ui-tabs-nav li.ui-state-processing a { cursor: text; }
-.ui-tabs .ui-tabs-nav li a, .ui-tabs.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-selected a { cursor: pointer; } /* first selector in group seems obsolete, but required to overcome bug in Opera applying cursor: text overall if defined elsewhere... */
-.ui-tabs .ui-tabs-panel { display: block; border-width: 0; padding: 1em 1.4em; background: none; }
-.ui-tabs .ui-tabs-hide { display: none !important; }
-/*
- * jQuery UI Datepicker 1.8.16
- *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Datepicker#theming
- */
-.ui-datepicker { width: 17em; padding: .2em .2em 0; display: none; }
-.ui-datepicker .ui-datepicker-header { position:relative; padding:.2em 0; }
-.ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next { position:absolute; top: 2px; width: 1.8em; height: 1.8em; }
-.ui-datepicker .ui-datepicker-prev-hover, .ui-datepicker .ui-datepicker-next-hover { top: 1px; }
-.ui-datepicker .ui-datepicker-prev { left:2px; }
-.ui-datepicker .ui-datepicker-next { right:2px; }
-.ui-datepicker .ui-datepicker-prev-hover { left:1px; }
-.ui-datepicker .ui-datepicker-next-hover { right:1px; }
-.ui-datepicker .ui-datepicker-prev span, .ui-datepicker .ui-datepicker-next span { display: block; position: absolute; left: 50%; margin-left: -8px; top: 50%; margin-top: -8px;  }
-.ui-datepicker .ui-datepicker-title { margin: 0 2.3em; line-height: 1.8em; text-align: center; }
-.ui-datepicker .ui-datepicker-title select { font-size:1em; margin:1px 0; }
-.ui-datepicker select.ui-datepicker-month-year {width: 100%;}
-.ui-datepicker select.ui-datepicker-month, 
-.ui-datepicker select.ui-datepicker-year { width: 49%;}
-.ui-datepicker table {width: 100%; font-size: .9em; border-collapse: collapse; margin:0 0 .4em; }
-.ui-datepicker th { padding: .7em .3em; text-align: center; font-weight: bold; border: 0;  }
-.ui-datepicker td { border: 0; padding: 1px; }
-.ui-datepicker td span, .ui-datepicker td a { display: block; padding: .2em; text-align: right; text-decoration: none; }
-.ui-datepicker .ui-datepicker-buttonpane { background-image: none; margin: .7em 0 0 0; padding:0 .2em; border-left: 0; border-right: 0; border-bottom: 0; }
-.ui-datepicker .ui-datepicker-buttonpane button { float: right; margin: .5em .2em .4em; cursor: pointer; padding: .2em .6em .3em .6em; width:auto; overflow:visible; }
-.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { float:left; }
-
-/* with multiple calendars */
-.ui-datepicker.ui-datepicker-multi { width:auto; }
-.ui-datepicker-multi .ui-datepicker-group { float:left; }
-.ui-datepicker-multi .ui-datepicker-group table { width:95%; margin:0 auto .4em; }
-.ui-datepicker-multi-2 .ui-datepicker-group { width:50%; }
-.ui-datepicker-multi-3 .ui-datepicker-group { width:33.3%; }
-.ui-datepicker-multi-4 .ui-datepicker-group { width:25%; }
-.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header { border-left-width:0; }
-.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { border-left-width:0; }
-.ui-datepicker-multi .ui-datepicker-buttonpane { clear:left; }
-.ui-datepicker-row-break { clear:both; width:100%; font-size:0em; }
-
-/* RTL support */
-.ui-datepicker-rtl { direction: rtl; }
-.ui-datepicker-rtl .ui-datepicker-prev { right: 2px; left: auto; }
-.ui-datepicker-rtl .ui-datepicker-next { left: 2px; right: auto; }
-.ui-datepicker-rtl .ui-datepicker-prev:hover { right: 1px; left: auto; }
-.ui-datepicker-rtl .ui-datepicker-next:hover { left: 1px; right: auto; }
-.ui-datepicker-rtl .ui-datepicker-buttonpane { clear:right; }
-.ui-datepicker-rtl .ui-datepicker-buttonpane button { float: left; }
-.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current { float:right; }
-.ui-datepicker-rtl .ui-datepicker-group { float:right; }
-.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header { border-right-width:0; border-left-width:1px; }
-.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { border-right-width:0; border-left-width:1px; }
-
-/* IE6 IFRAME FIX (taken from datepicker 1.5.3 */
-.ui-datepicker-cover {
-    display: none; /*sorry for IE5*/
-    display/**/: block; /*sorry for IE5*/
-    position: absolute; /*must have*/
-    z-index: -1; /*must have*/
-    filter: mask(); /*must have*/
-    top: -4px; /*must have*/
-    left: -4px; /*must have*/
-    width: 200px; /*must have*/
-    height: 200px; /*must have*/
-}/*
- * jQuery UI Progressbar 1.8.16
- *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Progressbar#theming
- */
-.ui-progressbar { height:2em; text-align: left; }
-.ui-progressbar .ui-progressbar-value {margin: -1px; height:100%; }
\ No newline at end of file
diff --git a/lib/scripts/jquery/jquery-ui.js b/lib/scripts/jquery/jquery-ui.js
old mode 100644
new mode 100755
index cd515f361..6dc062e6a
--- a/lib/scripts/jquery/jquery-ui.js
+++ b/lib/scripts/jquery/jquery-ui.js
@@ -1,14 +1,13 @@
-/*!
- * jQuery UI 1.8.16
- *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI
- */
+/*! jQuery UI - v1.9.2 - 2012-11-23
+* http://jqueryui.com
+* Includes: jquery.ui.core.js, jquery.ui.widget.js, jquery.ui.mouse.js, jquery.ui.position.js, jquery.ui.accordion.js, jquery.ui.autocomplete.js, jquery.ui.button.js, jquery.ui.datepicker.js, jquery.ui.dialog.js, jquery.ui.draggable.js, jquery.ui.droppable.js, jquery.ui.effect.js, jquery.ui.effect-blind.js, jquery.ui.effect-bounce.js, jquery.ui.effect-clip.js, jquery.ui.effect-drop.js, jquery.ui.effect-explode.js, jquery.ui.effect-fade.js, jquery.ui.effect-fold.js, jquery.ui.effect-highlight.js, jquery.ui.effect-pulsate.js, jquery.ui.effect-scale.js, jquery.ui.effect-shake.js, jquery.ui.effect-slide.js, jquery.ui.effect-transfer.js, jquery.ui.menu.js, jquery.ui.progressbar.js, jquery.ui.resizable.js, jquery.ui.selectable.js, jquery.ui.slider.js, jquery.ui.sortable.js, jquery.ui.spinner.js, jquery.ui.tabs.js, jquery.ui.tooltip.js
+* Copyright (c) 2012 jQuery Foundation and other contributors Licensed MIT */
+
 (function( $, undefined ) {
 
+var uuid = 0,
+	runiqueId = /^ui-id-\d+$/;
+
 // prevent duplicate loading
 // this is only a problem because we proxy existing functions
 // and we don't want to double proxy them
@@ -18,26 +17,18 @@ if ( $.ui.version ) {
 }
 
 $.extend( $.ui, {
-	version: "1.8.16",
+	version: "1.9.2",
 
 	keyCode: {
-		ALT: 18,
 		BACKSPACE: 8,
-		CAPS_LOCK: 20,
 		COMMA: 188,
-		COMMAND: 91,
-		COMMAND_LEFT: 91, // COMMAND
-		COMMAND_RIGHT: 93,
-		CONTROL: 17,
 		DELETE: 46,
 		DOWN: 40,
 		END: 35,
 		ENTER: 13,
 		ESCAPE: 27,
 		HOME: 36,
-		INSERT: 45,
 		LEFT: 37,
-		MENU: 93, // COMMAND_RIGHT
 		NUMPAD_ADD: 107,
 		NUMPAD_DECIMAL: 110,
 		NUMPAD_DIVIDE: 111,
@@ -48,18 +39,14 @@ $.extend( $.ui, {
 		PAGE_UP: 33,
 		PERIOD: 190,
 		RIGHT: 39,
-		SHIFT: 16,
 		SPACE: 32,
 		TAB: 9,
-		UP: 38,
-		WINDOWS: 91 // COMMAND
+		UP: 38
 	}
 });
 
 // plugins
 $.fn.extend({
-	propAttr: $.fn.prop || $.fn.attr,
-
 	_focus: $.fn.focus,
 	focus: function( delay, fn ) {
 		return typeof delay === "number" ?
@@ -77,13 +64,13 @@ $.fn.extend({
 
 	scrollParent: function() {
 		var scrollParent;
-		if (($.browser.msie && (/(static|relative)/).test(this.css('position'))) || (/absolute/).test(this.css('position'))) {
+		if (($.ui.ie && (/(static|relative)/).test(this.css('position'))) || (/absolute/).test(this.css('position'))) {
 			scrollParent = this.parents().filter(function() {
-				return (/(relative|absolute|fixed)/).test($.curCSS(this,'position',1)) && (/(auto|scroll)/).test($.curCSS(this,'overflow',1)+$.curCSS(this,'overflow-y',1)+$.curCSS(this,'overflow-x',1));
+				return (/(relative|absolute|fixed)/).test($.css(this,'position')) && (/(auto|scroll)/).test($.css(this,'overflow')+$.css(this,'overflow-y')+$.css(this,'overflow-x'));
 			}).eq(0);
 		} else {
 			scrollParent = this.parents().filter(function() {
-				return (/(auto|scroll)/).test($.curCSS(this,'overflow',1)+$.curCSS(this,'overflow-y',1)+$.curCSS(this,'overflow-x',1));
+				return (/(auto|scroll)/).test($.css(this,'overflow')+$.css(this,'overflow-y')+$.css(this,'overflow-x'));
 			}).eq(0);
 		}
 
@@ -119,95 +106,63 @@ $.fn.extend({
 		return 0;
 	},
 
-	disableSelection: function() {
-		return this.bind( ( $.support.selectstart ? "selectstart" : "mousedown" ) +
-			".ui-disableSelection", function( event ) {
-				event.preventDefault();
-			});
-	},
-
-	enableSelection: function() {
-		return this.unbind( ".ui-disableSelection" );
-	}
-});
-
-$.each( [ "Width", "Height" ], function( i, name ) {
-	var side = name === "Width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ],
-		type = name.toLowerCase(),
-		orig = {
-			innerWidth: $.fn.innerWidth,
-			innerHeight: $.fn.innerHeight,
-			outerWidth: $.fn.outerWidth,
-			outerHeight: $.fn.outerHeight
-		};
-
-	function reduce( elem, size, border, margin ) {
-		$.each( side, function() {
-			size -= parseFloat( $.curCSS( elem, "padding" + this, true) ) || 0;
-			if ( border ) {
-				size -= parseFloat( $.curCSS( elem, "border" + this + "Width", true) ) || 0;
-			}
-			if ( margin ) {
-				size -= parseFloat( $.curCSS( elem, "margin" + this, true) ) || 0;
-			}
-		});
-		return size;
-	}
-
-	$.fn[ "inner" + name ] = function( size ) {
-		if ( size === undefined ) {
-			return orig[ "inner" + name ].call( this );
-		}
-
+	uniqueId: function() {
 		return this.each(function() {
-			$( this ).css( type, reduce( this, size ) + "px" );
+			if ( !this.id ) {
+				this.id = "ui-id-" + (++uuid);
+			}
 		});
-	};
-
-	$.fn[ "outer" + name] = function( size, margin ) {
-		if ( typeof size !== "number" ) {
-			return orig[ "outer" + name ].call( this, size );
-		}
+	},
 
+	removeUniqueId: function() {
 		return this.each(function() {
-			$( this).css( type, reduce( this, size, true, margin ) + "px" );
+			if ( runiqueId.test( this.id ) ) {
+				$( this ).removeAttr( "id" );
+			}
 		});
-	};
+	}
 });
 
 // selectors
 function focusable( element, isTabIndexNotNaN ) {
-	var nodeName = element.nodeName.toLowerCase();
+	var map, mapName, img,
+		nodeName = element.nodeName.toLowerCase();
 	if ( "area" === nodeName ) {
-		var map = element.parentNode,
-			mapName = map.name,
-			img;
+		map = element.parentNode;
+		mapName = map.name;
 		if ( !element.href || !mapName || map.nodeName.toLowerCase() !== "map" ) {
 			return false;
 		}
 		img = $( "img[usemap=#" + mapName + "]" )[0];
 		return !!img && visible( img );
 	}
-	return ( /input|select|textarea|button|object/.test( nodeName )
-		? !element.disabled
-		: "a" == nodeName
-			? element.href || isTabIndexNotNaN
-			: isTabIndexNotNaN)
+	return ( /input|select|textarea|button|object/.test( nodeName ) ?
+		!element.disabled :
+		"a" === nodeName ?
+			element.href || isTabIndexNotNaN :
+			isTabIndexNotNaN) &&
 		// the element and all of its ancestors must be visible
-		&& visible( element );
+		visible( element );
 }
 
 function visible( element ) {
-	return !$( element ).parents().andSelf().filter(function() {
-		return $.curCSS( this, "visibility" ) === "hidden" ||
-			$.expr.filters.hidden( this );
-	}).length;
+	return $.expr.filters.visible( element ) &&
+		!$( element ).parents().andSelf().filter(function() {
+			return $.css( this, "visibility" ) === "hidden";
+		}).length;
 }
 
 $.extend( $.expr[ ":" ], {
-	data: function( elem, i, match ) {
-		return !!$.data( elem, match[ 3 ] );
-	},
+	data: $.expr.createPseudo ?
+		$.expr.createPseudo(function( dataName ) {
+			return function( elem ) {
+				return !!$.data( elem, dataName );
+			};
+		}) :
+		// support: jQuery <1.8
+		function( elem, i, match ) {
+			return !!$.data( elem, match[ 3 ] );
+		},
 
 	focusable: function( element ) {
 		return focusable( element, !isNaN( $.attr( element, "tabindex" ) ) );
@@ -225,6 +180,11 @@ $(function() {
 	var body = document.body,
 		div = body.appendChild( div = document.createElement( "div" ) );
 
+	// access offsetHeight before setting the style to prevent a layout bug
+	// in IE 9 which causes the element to continue to take up space even
+	// after it is removed from the DOM (#8026)
+	div.offsetHeight;
+
 	$.extend( div.style, {
 		minHeight: "100px",
 		height: "auto",
@@ -240,57 +200,134 @@ $(function() {
 	body.removeChild( div ).style.display = "none";
 });
 
+// support: jQuery <1.8
+if ( !$( "" ).outerWidth( 1 ).jquery ) {
+	$.each( [ "Width", "Height" ], function( i, name ) {
+		var side = name === "Width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ],
+			type = name.toLowerCase(),
+			orig = {
+				innerWidth: $.fn.innerWidth,
+				innerHeight: $.fn.innerHeight,
+				outerWidth: $.fn.outerWidth,
+				outerHeight: $.fn.outerHeight
+			};
+
+		function reduce( elem, size, border, margin ) {
+			$.each( side, function() {
+				size -= parseFloat( $.css( elem, "padding" + this ) ) || 0;
+				if ( border ) {
+					size -= parseFloat( $.css( elem, "border" + this + "Width" ) ) || 0;
+				}
+				if ( margin ) {
+					size -= parseFloat( $.css( elem, "margin" + this ) ) || 0;
+				}
+			});
+			return size;
+		}
+
+		$.fn[ "inner" + name ] = function( size ) {
+			if ( size === undefined ) {
+				return orig[ "inner" + name ].call( this );
+			}
+
+			return this.each(function() {
+				$( this ).css( type, reduce( this, size ) + "px" );
+			});
+		};
+
+		$.fn[ "outer" + name] = function( size, margin ) {
+			if ( typeof size !== "number" ) {
+				return orig[ "outer" + name ].call( this, size );
+			}
+
+			return this.each(function() {
+				$( this).css( type, reduce( this, size, true, margin ) + "px" );
+			});
+		};
+	});
+}
+
+// support: jQuery 1.6.1, 1.6.2 (http://bugs.jquery.com/ticket/9413)
+if ( $( "" ).data( "a-b", "a" ).removeData( "a-b" ).data( "a-b" ) ) {
+	$.fn.removeData = (function( removeData ) {
+		return function( key ) {
+			if ( arguments.length ) {
+				return removeData.call( this, $.camelCase( key ) );
+			} else {
+				return removeData.call( this );
+			}
+		};
+	})( $.fn.removeData );
+}
+
 
 
 
 
 // deprecated
+
+(function() {
+	var uaMatch = /msie ([\w.]+)/.exec( navigator.userAgent.toLowerCase() ) || [];
+	$.ui.ie = uaMatch.length ? true : false;
+	$.ui.ie6 = parseFloat( uaMatch[ 1 ], 10 ) === 6;
+})();
+
+$.fn.extend({
+	disableSelection: function() {
+		return this.bind( ( $.support.selectstart ? "selectstart" : "mousedown" ) +
+			".ui-disableSelection", function( event ) {
+				event.preventDefault();
+			});
+	},
+
+	enableSelection: function() {
+		return this.unbind( ".ui-disableSelection" );
+	}
+});
+
 $.extend( $.ui, {
 	// $.ui.plugin is deprecated.  Use the proxy pattern instead.
 	plugin: {
 		add: function( module, option, set ) {
-			var proto = $.ui[ module ].prototype;
-			for ( var i in set ) {
+			var i,
+				proto = $.ui[ module ].prototype;
+			for ( i in set ) {
 				proto.plugins[ i ] = proto.plugins[ i ] || [];
 				proto.plugins[ i ].push( [ option, set[ i ] ] );
 			}
 		},
 		call: function( instance, name, args ) {
-			var set = instance.plugins[ name ];
-			if ( !set || !instance.element[ 0 ].parentNode ) {
+			var i,
+				set = instance.plugins[ name ];
+			if ( !set || !instance.element[ 0 ].parentNode || instance.element[ 0 ].parentNode.nodeType === 11 ) {
 				return;
 			}
-	
-			for ( var i = 0; i < set.length; i++ ) {
+
+			for ( i = 0; i < set.length; i++ ) {
 				if ( instance.options[ set[ i ][ 0 ] ] ) {
 					set[ i ][ 1 ].apply( instance.element, args );
 				}
 			}
 		}
 	},
-	
-	// will be deprecated when we switch to jQuery 1.4 - use jQuery.contains()
-	contains: function( a, b ) {
-		return document.compareDocumentPosition ?
-			a.compareDocumentPosition( b ) & 16 :
-			a !== b && a.contains( b );
-	},
-	
+
+	contains: $.contains,
+
 	// only used by resizable
 	hasScroll: function( el, a ) {
-	
+
 		//If overflow is hidden, the element might have extra content, but the user wants to hide it
 		if ( $( el ).css( "overflow" ) === "hidden") {
 			return false;
 		}
-	
+
 		var scroll = ( a && a === "left" ) ? "scrollLeft" : "scrollTop",
 			has = false;
-	
+
 		if ( el[ scroll ] > 0 ) {
 			return true;
 		}
-	
+
 		// TODO: determine which cases actually cause this to happen
 		// if the element doesn't have the scroll set, see if it's possible to
 		// set the scroll
@@ -299,7 +336,7 @@ $.extend( $.ui, {
 		el[ scroll ] = 0;
 		return has;
 	},
-	
+
 	// these are odd functions, fix the API or move into individual plugins
 	isOverAxis: function( x, reference, size ) {
 		//Determines when x coordinate is over "b" element axis
@@ -312,51 +349,25 @@ $.extend( $.ui, {
 });
 
 })( jQuery );
-/*!
- * jQuery UI Widget 1.8.16
- *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Widget
- */
 (function( $, undefined ) {
 
-// jQuery 1.4+
-if ( $.cleanData ) {
-	var _cleanData = $.cleanData;
-	$.cleanData = function( elems ) {
-		for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
-			try {
-				$( elem ).triggerHandler( "remove" );
-			// http://bugs.jquery.com/ticket/8235
-			} catch( e ) {}
-		}
-		_cleanData( elems );
-	};
-} else {
-	var _remove = $.fn.remove;
-	$.fn.remove = function( selector, keepData ) {
-		return this.each(function() {
-			if ( !keepData ) {
-				if ( !selector || $.filter( selector, [ this ] ).length ) {
-					$( "*", this ).add( [ this ] ).each(function() {
-						try {
-							$( this ).triggerHandler( "remove" );
-						// http://bugs.jquery.com/ticket/8235
-						} catch( e ) {}
-					});
-				}
-			}
-			return _remove.call( $(this), selector, keepData );
-		});
-	};
-}
+var uuid = 0,
+	slice = Array.prototype.slice,
+	_cleanData = $.cleanData;
+$.cleanData = function( elems ) {
+	for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
+		try {
+			$( elem ).triggerHandler( "remove" );
+		// http://bugs.jquery.com/ticket/8235
+		} catch( e ) {}
+	}
+	_cleanData( elems );
+};
 
 $.widget = function( name, base, prototype ) {
-	var namespace = name.split( "." )[ 0 ],
-		fullName;
+	var fullName, existingConstructor, constructor, basePrototype,
+		namespace = name.split( "." )[ 0 ];
+
 	name = name.split( "." )[ 1 ];
 	fullName = namespace + "-" + name;
 
@@ -366,81 +377,167 @@ $.widget = function( name, base, prototype ) {
 	}
 
 	// create selector for plugin
-	$.expr[ ":" ][ fullName ] = function( elem ) {
-		return !!$.data( elem, name );
+	$.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) {
+		return !!$.data( elem, fullName );
 	};
 
 	$[ namespace ] = $[ namespace ] || {};
-	$[ namespace ][ name ] = function( options, element ) {
+	existingConstructor = $[ namespace ][ name ];
+	constructor = $[ namespace ][ name ] = function( options, element ) {
+		// allow instantiation without "new" keyword
+		if ( !this._createWidget ) {
+			return new constructor( options, element );
+		}
+
 		// allow instantiation without initializing for simple inheritance
+		// must use "new" keyword (the code above always passes args)
 		if ( arguments.length ) {
 			this._createWidget( options, element );
 		}
 	};
+	// extend with the existing constructor to carry over any static properties
+	$.extend( constructor, existingConstructor, {
+		version: prototype.version,
+		// copy the object used to create the prototype in case we need to
+		// redefine the widget later
+		_proto: $.extend( {}, prototype ),
+		// track widgets that inherit from this widget in case this widget is
+		// redefined after a widget inherits from it
+		_childConstructors: []
+	});
 
-	var basePrototype = new base();
+	basePrototype = new base();
 	// we need to make the options hash a property directly on the new instance
 	// otherwise we'll modify the options hash on the prototype that we're
 	// inheriting from
-//	$.each( basePrototype, function( key, val ) {
-//		if ( $.isPlainObject(val) ) {
-//			basePrototype[ key ] = $.extend( {}, val );
-//		}
-//	});
-	basePrototype.options = $.extend( true, {}, basePrototype.options );
-	$[ namespace ][ name ].prototype = $.extend( true, basePrototype, {
+	basePrototype.options = $.widget.extend( {}, basePrototype.options );
+	$.each( prototype, function( prop, value ) {
+		if ( $.isFunction( value ) ) {
+			prototype[ prop ] = (function() {
+				var _super = function() {
+						return base.prototype[ prop ].apply( this, arguments );
+					},
+					_superApply = function( args ) {
+						return base.prototype[ prop ].apply( this, args );
+					};
+				return function() {
+					var __super = this._super,
+						__superApply = this._superApply,
+						returnValue;
+
+					this._super = _super;
+					this._superApply = _superApply;
+
+					returnValue = value.apply( this, arguments );
+
+					this._super = __super;
+					this._superApply = __superApply;
+
+					return returnValue;
+				};
+			})();
+		}
+	});
+	constructor.prototype = $.widget.extend( basePrototype, {
+		// TODO: remove support for widgetEventPrefix
+		// always use the name + a colon as the prefix, e.g., draggable:start
+		// don't prefix for widgets that aren't DOM-based
+		widgetEventPrefix: existingConstructor ? basePrototype.widgetEventPrefix : name
+	}, prototype, {
+		constructor: constructor,
 		namespace: namespace,
 		widgetName: name,
-		widgetEventPrefix: $[ namespace ][ name ].prototype.widgetEventPrefix || name,
-		widgetBaseClass: fullName
-	}, prototype );
+		// TODO remove widgetBaseClass, see #8155
+		widgetBaseClass: fullName,
+		widgetFullName: fullName
+	});
+
+	// If this widget is being redefined then we need to find all widgets that
+	// are inheriting from it and redefine all of them so that they inherit from
+	// the new version of this widget. We're essentially trying to replace one
+	// level in the prototype chain.
+	if ( existingConstructor ) {
+		$.each( existingConstructor._childConstructors, function( i, child ) {
+			var childPrototype = child.prototype;
+
+			// redefine the child widget using the same prototype that was
+			// originally used, but inherit from the new version of the base
+			$.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor, child._proto );
+		});
+		// remove the list of existing child constructors from the old constructor
+		// so the old child constructors can be garbage collected
+		delete existingConstructor._childConstructors;
+	} else {
+		base._childConstructors.push( constructor );
+	}
 
-	$.widget.bridge( name, $[ namespace ][ name ] );
+	$.widget.bridge( name, constructor );
+};
+
+$.widget.extend = function( target ) {
+	var input = slice.call( arguments, 1 ),
+		inputIndex = 0,
+		inputLength = input.length,
+		key,
+		value;
+	for ( ; inputIndex < inputLength; inputIndex++ ) {
+		for ( key in input[ inputIndex ] ) {
+			value = input[ inputIndex ][ key ];
+			if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) {
+				// Clone objects
+				if ( $.isPlainObject( value ) ) {
+					target[ key ] = $.isPlainObject( target[ key ] ) ?
+						$.widget.extend( {}, target[ key ], value ) :
+						// Don't extend strings, arrays, etc. with objects
+						$.widget.extend( {}, value );
+				// Copy everything else by reference
+				} else {
+					target[ key ] = value;
+				}
+			}
+		}
+	}
+	return target;
 };
 
 $.widget.bridge = function( name, object ) {
+	var fullName = object.prototype.widgetFullName || name;
 	$.fn[ name ] = function( options ) {
 		var isMethodCall = typeof options === "string",
-			args = Array.prototype.slice.call( arguments, 1 ),
+			args = slice.call( arguments, 1 ),
 			returnValue = this;
 
 		// allow multiple hashes to be passed on init
 		options = !isMethodCall && args.length ?
-			$.extend.apply( null, [ true, options ].concat(args) ) :
+			$.widget.extend.apply( null, [ options ].concat(args) ) :
 			options;
 
-		// prevent calls to internal methods
-		if ( isMethodCall && options.charAt( 0 ) === "_" ) {
-			return returnValue;
-		}
-
 		if ( isMethodCall ) {
 			this.each(function() {
-				var instance = $.data( this, name ),
-					methodValue = instance && $.isFunction( instance[options] ) ?
-						instance[ options ].apply( instance, args ) :
-						instance;
-				// TODO: add this back in 1.9 and use $.error() (see #5972)
-//				if ( !instance ) {
-//					throw "cannot call methods on " + name + " prior to initialization; " +
-//						"attempted to call method '" + options + "'";
-//				}
-//				if ( !$.isFunction( instance[options] ) ) {
-//					throw "no such method '" + options + "' for " + name + " widget instance";
-//				}
-//				var methodValue = instance[ options ].apply( instance, args );
+				var methodValue,
+					instance = $.data( this, fullName );
+				if ( !instance ) {
+					return $.error( "cannot call methods on " + name + " prior to initialization; " +
+						"attempted to call method '" + options + "'" );
+				}
+				if ( !$.isFunction( instance[options] ) || options.charAt( 0 ) === "_" ) {
+					return $.error( "no such method '" + options + "' for " + name + " widget instance" );
+				}
+				methodValue = instance[ options ].apply( instance, args );
 				if ( methodValue !== instance && methodValue !== undefined ) {
-					returnValue = methodValue;
+					returnValue = methodValue && methodValue.jquery ?
+						returnValue.pushStack( methodValue.get() ) :
+						methodValue;
 					return false;
 				}
 			});
 		} else {
 			this.each(function() {
-				var instance = $.data( this, name );
+				var instance = $.data( this, fullName );
 				if ( instance ) {
 					instance.option( options || {} )._init();
 				} else {
-					$.data( this, name, new object( options, this ) );
+					$.data( this, fullName, new object( options, this ) );
 				}
 			});
 		}
@@ -449,74 +546,126 @@ $.widget.bridge = function( name, object ) {
 	};
 };
 
-$.Widget = function( options, element ) {
-	// allow instantiation without initializing for simple inheritance
-	if ( arguments.length ) {
-		this._createWidget( options, element );
-	}
-};
+$.Widget = function( /* options, element */ ) {};
+$.Widget._childConstructors = [];
 
 $.Widget.prototype = {
 	widgetName: "widget",
 	widgetEventPrefix: "",
+	defaultElement: "
", options: { - disabled: false + disabled: false, + + // callbacks + create: null }, _createWidget: function( options, element ) { - // $.widget.bridge stores the plugin instance, but we do it anyway - // so that it's stored even before the _create function runs - $.data( element, this.widgetName, this ); + element = $( element || this.defaultElement || this )[ 0 ]; this.element = $( element ); - this.options = $.extend( true, {}, + this.uuid = uuid++; + this.eventNamespace = "." + this.widgetName + this.uuid; + this.options = $.widget.extend( {}, this.options, this._getCreateOptions(), options ); - var self = this; - this.element.bind( "remove." + this.widgetName, function() { - self.destroy(); - }); + this.bindings = $(); + this.hoverable = $(); + this.focusable = $(); + + if ( element !== this ) { + // 1.9 BC for #7810 + // TODO remove dual storage + $.data( element, this.widgetName, this ); + $.data( element, this.widgetFullName, this ); + this._on( true, this.element, { + remove: function( event ) { + if ( event.target === element ) { + this.destroy(); + } + } + }); + this.document = $( element.style ? + // element within the document + element.ownerDocument : + // element is window or document + element.document || element ); + this.window = $( this.document[0].defaultView || this.document[0].parentWindow ); + } this._create(); - this._trigger( "create" ); + this._trigger( "create", null, this._getCreateEventData() ); this._init(); }, - _getCreateOptions: function() { - return $.metadata && $.metadata.get( this.element[0] )[ this.widgetName ]; - }, - _create: function() {}, - _init: function() {}, + _getCreateOptions: $.noop, + _getCreateEventData: $.noop, + _create: $.noop, + _init: $.noop, destroy: function() { + this._destroy(); + // we can probably remove the unbind calls in 2.0 + // all event bindings should go through this._on() this.element - .unbind( "." + this.widgetName ) - .removeData( this.widgetName ); + .unbind( this.eventNamespace ) + // 1.9 BC for #7810 + // TODO remove dual storage + .removeData( this.widgetName ) + .removeData( this.widgetFullName ) + // support: jquery <1.6.3 + // http://bugs.jquery.com/ticket/9413 + .removeData( $.camelCase( this.widgetFullName ) ); this.widget() - .unbind( "." + this.widgetName ) + .unbind( this.eventNamespace ) .removeAttr( "aria-disabled" ) .removeClass( - this.widgetBaseClass + "-disabled " + + this.widgetFullName + "-disabled " + "ui-state-disabled" ); + + // clean up events and states + this.bindings.unbind( this.eventNamespace ); + this.hoverable.removeClass( "ui-state-hover" ); + this.focusable.removeClass( "ui-state-focus" ); }, + _destroy: $.noop, widget: function() { return this.element; }, option: function( key, value ) { - var options = key; + var options = key, + parts, + curOption, + i; if ( arguments.length === 0 ) { // don't return a reference to the internal hash - return $.extend( {}, this.options ); + return $.widget.extend( {}, this.options ); } - if (typeof key === "string" ) { - if ( value === undefined ) { - return this.options[ key ]; - } + if ( typeof key === "string" ) { + // handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } } options = {}; - options[ key ] = value; + parts = key.split( "." ); + key = parts.shift(); + if ( parts.length ) { + curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] ); + for ( i = 0; i < parts.length - 1; i++ ) { + curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {}; + curOption = curOption[ parts[ i ] ]; + } + key = parts.pop(); + if ( value === undefined ) { + return curOption[ key ] === undefined ? null : curOption[ key ]; + } + curOption[ key ] = value; + } else { + if ( value === undefined ) { + return this.options[ key ] === undefined ? null : this.options[ key ]; + } + options[ key ] = value; + } } this._setOptions( options ); @@ -524,10 +673,11 @@ $.Widget.prototype = { return this; }, _setOptions: function( options ) { - var self = this; - $.each( options, function( key, value ) { - self._setOption( key, value ); - }); + var key; + + for ( key in options ) { + this._setOption( key, options[ key ] ); + } return this; }, @@ -536,10 +686,10 @@ $.Widget.prototype = { if ( key === "disabled" ) { this.widget() - [ value ? "addClass" : "removeClass"]( - this.widgetBaseClass + "-disabled" + " " + - "ui-state-disabled" ) + .toggleClass( this.widgetFullName + "-disabled ui-state-disabled", !!value ) .attr( "aria-disabled", value ); + this.hoverable.removeClass( "ui-state-hover" ); + this.focusable.removeClass( "ui-state-focus" ); } return this; @@ -552,46 +702,171 @@ $.Widget.prototype = { return this._setOption( "disabled", true ); }, + _on: function( suppressDisabledCheck, element, handlers ) { + var delegateElement, + instance = this; + + // no suppressDisabledCheck flag, shuffle arguments + if ( typeof suppressDisabledCheck !== "boolean" ) { + handlers = element; + element = suppressDisabledCheck; + suppressDisabledCheck = false; + } + + // no element argument, shuffle and use this.element + if ( !handlers ) { + handlers = element; + element = this.element; + delegateElement = this.widget(); + } else { + // accept selectors, DOM elements + element = delegateElement = $( element ); + this.bindings = this.bindings.add( element ); + } + + $.each( handlers, function( event, handler ) { + function handlerProxy() { + // allow widgets to customize the disabled handling + // - disabled as an array instead of boolean + // - disabled class as method for disabling individual parts + if ( !suppressDisabledCheck && + ( instance.options.disabled === true || + $( this ).hasClass( "ui-state-disabled" ) ) ) { + return; + } + return ( typeof handler === "string" ? instance[ handler ] : handler ) + .apply( instance, arguments ); + } + + // copy the guid so direct unbinding works + if ( typeof handler !== "string" ) { + handlerProxy.guid = handler.guid = + handler.guid || handlerProxy.guid || $.guid++; + } + + var match = event.match( /^(\w+)\s*(.*)$/ ), + eventName = match[1] + instance.eventNamespace, + selector = match[2]; + if ( selector ) { + delegateElement.delegate( selector, eventName, handlerProxy ); + } else { + element.bind( eventName, handlerProxy ); + } + }); + }, + + _off: function( element, eventName ) { + eventName = (eventName || "").split( " " ).join( this.eventNamespace + " " ) + this.eventNamespace; + element.unbind( eventName ).undelegate( eventName ); + }, + + _delay: function( handler, delay ) { + function handlerProxy() { + return ( typeof handler === "string" ? instance[ handler ] : handler ) + .apply( instance, arguments ); + } + var instance = this; + return setTimeout( handlerProxy, delay || 0 ); + }, + + _hoverable: function( element ) { + this.hoverable = this.hoverable.add( element ); + this._on( element, { + mouseenter: function( event ) { + $( event.currentTarget ).addClass( "ui-state-hover" ); + }, + mouseleave: function( event ) { + $( event.currentTarget ).removeClass( "ui-state-hover" ); + } + }); + }, + + _focusable: function( element ) { + this.focusable = this.focusable.add( element ); + this._on( element, { + focusin: function( event ) { + $( event.currentTarget ).addClass( "ui-state-focus" ); + }, + focusout: function( event ) { + $( event.currentTarget ).removeClass( "ui-state-focus" ); + } + }); + }, + _trigger: function( type, event, data ) { - var callback = this.options[ type ]; + var prop, orig, + callback = this.options[ type ]; + data = data || {}; event = $.Event( event ); event.type = ( type === this.widgetEventPrefix ? type : this.widgetEventPrefix + type ).toLowerCase(); - data = data || {}; + // the original event may come from any element + // so we need to reset the target on the new event + event.target = this.element[ 0 ]; // copy original event properties over to the new event - // this would happen if we could call $.event.fix instead of $.Event - // but we don't have a way to force an event to be fixed multiple times - if ( event.originalEvent ) { - for ( var i = $.event.props.length, prop; i; ) { - prop = $.event.props[ --i ]; - event[ prop ] = event.originalEvent[ prop ]; + orig = event.originalEvent; + if ( orig ) { + for ( prop in orig ) { + if ( !( prop in event ) ) { + event[ prop ] = orig[ prop ]; + } } } this.element.trigger( event, data ); - - return !( $.isFunction(callback) && - callback.call( this.element[0], event, data ) === false || + return !( $.isFunction( callback ) && + callback.apply( this.element[0], [ event ].concat( data ) ) === false || event.isDefaultPrevented() ); } }; +$.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) { + $.Widget.prototype[ "_" + method ] = function( element, options, callback ) { + if ( typeof options === "string" ) { + options = { effect: options }; + } + var hasOptions, + effectName = !options ? + method : + options === true || typeof options === "number" ? + defaultEffect : + options.effect || defaultEffect; + options = options || {}; + if ( typeof options === "number" ) { + options = { duration: options }; + } + hasOptions = !$.isEmptyObject( options ); + options.complete = callback; + if ( options.delay ) { + element.delay( options.delay ); + } + if ( hasOptions && $.effects && ( $.effects.effect[ effectName ] || $.uiBackCompat !== false && $.effects[ effectName ] ) ) { + element[ method ]( options ); + } else if ( effectName !== method && element[ effectName ] ) { + element[ effectName ]( options.duration, options.easing, callback ); + } else { + element.queue(function( next ) { + $( this )[ method ](); + if ( callback ) { + callback.call( element[ 0 ] ); + } + next(); + }); + } + }; +}); + +// DEPRECATED +if ( $.uiBackCompat !== false ) { + $.Widget.prototype._getCreateOptions = function() { + return $.metadata && $.metadata.get( this.element[0] )[ this.widgetName ]; + }; +} + })( jQuery ); -/*! - * jQuery UI Mouse 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Mouse - * - * Depends: - * jquery.ui.widget.js - */ (function( $, undefined ) { var mouseHandled = false; @@ -600,21 +875,22 @@ $( document ).mouseup( function( e ) { }); $.widget("ui.mouse", { + version: "1.9.2", options: { - cancel: ':input,option', + cancel: 'input,textarea,button,select,option', distance: 1, delay: 0 }, _mouseInit: function() { - var self = this; + var that = this; this.element .bind('mousedown.'+this.widgetName, function(event) { - return self._mouseDown(event); + return that._mouseDown(event); }) .bind('click.'+this.widgetName, function(event) { - if (true === $.data(event.target, self.widgetName + '.preventClickEvent')) { - $.removeData(event.target, self.widgetName + '.preventClickEvent'); + if (true === $.data(event.target, that.widgetName + '.preventClickEvent')) { + $.removeData(event.target, that.widgetName + '.preventClickEvent'); event.stopImmediatePropagation(); return false; } @@ -627,22 +903,27 @@ $.widget("ui.mouse", { // other instances of mouse _mouseDestroy: function() { this.element.unbind('.'+this.widgetName); + if ( this._mouseMoveDelegate ) { + $(document) + .unbind('mousemove.'+this.widgetName, this._mouseMoveDelegate) + .unbind('mouseup.'+this.widgetName, this._mouseUpDelegate); + } }, _mouseDown: function(event) { // don't let more than one widget handle mouseStart - if( mouseHandled ) { return }; + if( mouseHandled ) { return; } // we may have missed mouseup (out of window) (this._mouseStarted && this._mouseUp(event)); this._mouseDownEvent = event; - var self = this, - btnIsLeft = (event.which == 1), + var that = this, + btnIsLeft = (event.which === 1), // event.target.nodeName works around a bug in IE 8 with // disabled inputs (#7620) - elIsCancel = (typeof this.options.cancel == "string" && event.target.nodeName ? $(event.target).closest(this.options.cancel).length : false); + elIsCancel = (typeof this.options.cancel === "string" && event.target.nodeName ? $(event.target).closest(this.options.cancel).length : false); if (!btnIsLeft || elIsCancel || !this._mouseCapture(event)) { return true; } @@ -650,7 +931,7 @@ $.widget("ui.mouse", { this.mouseDelayMet = !this.options.delay; if (!this.mouseDelayMet) { this._mouseDelayTimer = setTimeout(function() { - self.mouseDelayMet = true; + that.mouseDelayMet = true; }, this.options.delay); } @@ -669,24 +950,24 @@ $.widget("ui.mouse", { // these delegates are required to keep context this._mouseMoveDelegate = function(event) { - return self._mouseMove(event); + return that._mouseMove(event); }; this._mouseUpDelegate = function(event) { - return self._mouseUp(event); + return that._mouseUp(event); }; $(document) .bind('mousemove.'+this.widgetName, this._mouseMoveDelegate) .bind('mouseup.'+this.widgetName, this._mouseUpDelegate); event.preventDefault(); - + mouseHandled = true; return true; }, _mouseMove: function(event) { // IE mouseup check - mouseup happened when mouse was out of window - if ($.browser.msie && !(document.documentMode >= 9) && !event.button) { + if ($.ui.ie && !(document.documentMode >= 9) && !event.button) { return this._mouseUp(event); } @@ -712,8 +993,8 @@ $.widget("ui.mouse", { if (this._mouseStarted) { this._mouseStarted = false; - if (event.target == this._mouseDownEvent.target) { - $.data(event.target, this.widgetName + '.preventClickEvent', true); + if (event.target === this._mouseDownEvent.target) { + $.data(event.target, this.widgetName + '.preventClickEvent', true); } this._mouseStop(event); @@ -742,2370 +1023,4983 @@ $.widget("ui.mouse", { }); })(jQuery); -/* - * jQuery UI Draggable 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Draggables - * - * Depends: - * jquery.ui.core.js - * jquery.ui.mouse.js - * jquery.ui.widget.js - */ (function( $, undefined ) { -$.widget("ui.draggable", $.ui.mouse, { - widgetEventPrefix: "drag", - options: { - addClasses: true, - appendTo: "parent", - axis: false, - connectToSortable: false, - containment: false, - cursor: "auto", - cursorAt: false, - grid: false, - handle: false, - helper: "original", - iframeFix: false, - opacity: false, - refreshPositions: false, - revert: false, - revertDuration: 500, - scope: "default", - scroll: true, - scrollSensitivity: 20, - scrollSpeed: 20, - snap: false, - snapMode: "both", - snapTolerance: 20, - stack: false, - zIndex: false - }, - _create: function() { - - if (this.options.helper == 'original' && !(/^(?:r|a|f)/).test(this.element.css("position"))) - this.element[0].style.position = 'relative'; +$.ui = $.ui || {}; - (this.options.addClasses && this.element.addClass("ui-draggable")); - (this.options.disabled && this.element.addClass("ui-draggable-disabled")); - - this._mouseInit(); - - }, - - destroy: function() { - if(!this.element.data('draggable')) return; - this.element - .removeData("draggable") - .unbind(".draggable") - .removeClass("ui-draggable" - + " ui-draggable-dragging" - + " ui-draggable-disabled"); - this._mouseDestroy(); - - return this; - }, +var cachedScrollbarWidth, + max = Math.max, + abs = Math.abs, + round = Math.round, + rhorizontal = /left|center|right/, + rvertical = /top|center|bottom/, + roffset = /[\+\-]\d+%?/, + rposition = /^\w+/, + rpercent = /%$/, + _position = $.fn.position; + +function getOffsets( offsets, width, height ) { + return [ + parseInt( offsets[ 0 ], 10 ) * ( rpercent.test( offsets[ 0 ] ) ? width / 100 : 1 ), + parseInt( offsets[ 1 ], 10 ) * ( rpercent.test( offsets[ 1 ] ) ? height / 100 : 1 ) + ]; +} +function parseCss( element, property ) { + return parseInt( $.css( element, property ), 10 ) || 0; +} - _mouseCapture: function(event) { +$.position = { + scrollbarWidth: function() { + if ( cachedScrollbarWidth !== undefined ) { + return cachedScrollbarWidth; + } + var w1, w2, + div = $( "
" ), + innerDiv = div.children()[0]; - var o = this.options; + $( "body" ).append( div ); + w1 = innerDiv.offsetWidth; + div.css( "overflow", "scroll" ); - // among others, prevent a drag on a resizable-handle - if (this.helper || o.disabled || $(event.target).is('.ui-resizable-handle')) - return false; + w2 = innerDiv.offsetWidth; - //Quit if we're not on a valid handle - this.handle = this._getHandle(event); - if (!this.handle) - return false; - - if ( o.iframeFix ) { - $(o.iframeFix === true ? "iframe" : o.iframeFix).each(function() { - $('
') - .css({ - width: this.offsetWidth+"px", height: this.offsetHeight+"px", - position: "absolute", opacity: "0.001", zIndex: 1000 - }) - .css($(this).offset()) - .appendTo("body"); - }); + if ( w1 === w2 ) { + w2 = div[0].clientWidth; } - return true; + div.remove(); + return (cachedScrollbarWidth = w1 - w2); }, + getScrollInfo: function( within ) { + var overflowX = within.isWindow ? "" : within.element.css( "overflow-x" ), + overflowY = within.isWindow ? "" : within.element.css( "overflow-y" ), + hasOverflowX = overflowX === "scroll" || + ( overflowX === "auto" && within.width < within.element[0].scrollWidth ), + hasOverflowY = overflowY === "scroll" || + ( overflowY === "auto" && within.height < within.element[0].scrollHeight ); + return { + width: hasOverflowX ? $.position.scrollbarWidth() : 0, + height: hasOverflowY ? $.position.scrollbarWidth() : 0 + }; + }, + getWithinInfo: function( element ) { + var withinElement = $( element || window ), + isWindow = $.isWindow( withinElement[0] ); + return { + element: withinElement, + isWindow: isWindow, + offset: withinElement.offset() || { left: 0, top: 0 }, + scrollLeft: withinElement.scrollLeft(), + scrollTop: withinElement.scrollTop(), + width: isWindow ? withinElement.width() : withinElement.outerWidth(), + height: isWindow ? withinElement.height() : withinElement.outerHeight() + }; + } +}; - _mouseStart: function(event) { - - var o = this.options; +$.fn.position = function( options ) { + if ( !options || !options.of ) { + return _position.apply( this, arguments ); + } - //Create and append the visible helper - this.helper = this._createHelper(event); + // make a copy, we don't want to modify arguments + options = $.extend( {}, options ); - //Cache the helper size - this._cacheHelperProportions(); + var atOffset, targetWidth, targetHeight, targetOffset, basePosition, + target = $( options.of ), + within = $.position.getWithinInfo( options.within ), + scrollInfo = $.position.getScrollInfo( within ), + targetElem = target[0], + collision = ( options.collision || "flip" ).split( " " ), + offsets = {}; - //If ddmanager is used for droppables, set the global draggable - if($.ui.ddmanager) - $.ui.ddmanager.current = this; + if ( targetElem.nodeType === 9 ) { + targetWidth = target.width(); + targetHeight = target.height(); + targetOffset = { top: 0, left: 0 }; + } else if ( $.isWindow( targetElem ) ) { + targetWidth = target.width(); + targetHeight = target.height(); + targetOffset = { top: target.scrollTop(), left: target.scrollLeft() }; + } else if ( targetElem.preventDefault ) { + // force left top to allow flipping + options.at = "left top"; + targetWidth = targetHeight = 0; + targetOffset = { top: targetElem.pageY, left: targetElem.pageX }; + } else { + targetWidth = target.outerWidth(); + targetHeight = target.outerHeight(); + targetOffset = target.offset(); + } + // clone to reuse original targetOffset later + basePosition = $.extend( {}, targetOffset ); - /* - * - Position generation - - * This block generates everything position related - it's the core of draggables. - */ + // force my and at to have valid horizontal and vertical positions + // if a value is missing or invalid, it will be converted to center + $.each( [ "my", "at" ], function() { + var pos = ( options[ this ] || "" ).split( " " ), + horizontalOffset, + verticalOffset; - //Cache the margins of the original element - this._cacheMargins(); + if ( pos.length === 1) { + pos = rhorizontal.test( pos[ 0 ] ) ? + pos.concat( [ "center" ] ) : + rvertical.test( pos[ 0 ] ) ? + [ "center" ].concat( pos ) : + [ "center", "center" ]; + } + pos[ 0 ] = rhorizontal.test( pos[ 0 ] ) ? pos[ 0 ] : "center"; + pos[ 1 ] = rvertical.test( pos[ 1 ] ) ? pos[ 1 ] : "center"; + + // calculate offsets + horizontalOffset = roffset.exec( pos[ 0 ] ); + verticalOffset = roffset.exec( pos[ 1 ] ); + offsets[ this ] = [ + horizontalOffset ? horizontalOffset[ 0 ] : 0, + verticalOffset ? verticalOffset[ 0 ] : 0 + ]; - //Store the helper's css position - this.cssPosition = this.helper.css("position"); - this.scrollParent = this.helper.scrollParent(); + // reduce to just the positions without the offsets + options[ this ] = [ + rposition.exec( pos[ 0 ] )[ 0 ], + rposition.exec( pos[ 1 ] )[ 0 ] + ]; + }); - //The element's absolute position on the page minus margins - this.offset = this.positionAbs = this.element.offset(); - this.offset = { - top: this.offset.top - this.margins.top, - left: this.offset.left - this.margins.left - }; + // normalize collision option + if ( collision.length === 1 ) { + collision[ 1 ] = collision[ 0 ]; + } - $.extend(this.offset, { - click: { //Where the click happened, relative to the element - left: event.pageX - this.offset.left, - top: event.pageY - this.offset.top - }, - parent: this._getParentOffset(), - relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper - }); + if ( options.at[ 0 ] === "right" ) { + basePosition.left += targetWidth; + } else if ( options.at[ 0 ] === "center" ) { + basePosition.left += targetWidth / 2; + } - //Generate the original position - this.originalPosition = this.position = this._generatePosition(event); - this.originalPageX = event.pageX; - this.originalPageY = event.pageY; + if ( options.at[ 1 ] === "bottom" ) { + basePosition.top += targetHeight; + } else if ( options.at[ 1 ] === "center" ) { + basePosition.top += targetHeight / 2; + } - //Adjust the mouse offset relative to the helper if 'cursorAt' is supplied - (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt)); + atOffset = getOffsets( offsets.at, targetWidth, targetHeight ); + basePosition.left += atOffset[ 0 ]; + basePosition.top += atOffset[ 1 ]; - //Set a containment if given in the options - if(o.containment) - this._setContainment(); + return this.each(function() { + var collisionPosition, using, + elem = $( this ), + elemWidth = elem.outerWidth(), + elemHeight = elem.outerHeight(), + marginLeft = parseCss( this, "marginLeft" ), + marginTop = parseCss( this, "marginTop" ), + collisionWidth = elemWidth + marginLeft + parseCss( this, "marginRight" ) + scrollInfo.width, + collisionHeight = elemHeight + marginTop + parseCss( this, "marginBottom" ) + scrollInfo.height, + position = $.extend( {}, basePosition ), + myOffset = getOffsets( offsets.my, elem.outerWidth(), elem.outerHeight() ); - //Trigger event + callbacks - if(this._trigger("start", event) === false) { - this._clear(); - return false; + if ( options.my[ 0 ] === "right" ) { + position.left -= elemWidth; + } else if ( options.my[ 0 ] === "center" ) { + position.left -= elemWidth / 2; } - //Recache the helper size - this._cacheHelperProportions(); - - //Prepare the droppable offsets - if ($.ui.ddmanager && !o.dropBehaviour) - $.ui.ddmanager.prepareOffsets(this, event); - - this.helper.addClass("ui-draggable-dragging"); - this._mouseDrag(event, true); //Execute the drag once - this causes the helper not to be visible before getting its correct position - - //If the ddmanager is used for droppables, inform the manager that dragging has started (see #5003) - if ( $.ui.ddmanager ) $.ui.ddmanager.dragStart(this, event); - - return true; - }, - - _mouseDrag: function(event, noPropagation) { + if ( options.my[ 1 ] === "bottom" ) { + position.top -= elemHeight; + } else if ( options.my[ 1 ] === "center" ) { + position.top -= elemHeight / 2; + } - //Compute the helpers position - this.position = this._generatePosition(event); - this.positionAbs = this._convertPositionTo("absolute"); + position.left += myOffset[ 0 ]; + position.top += myOffset[ 1 ]; - //Call plugins and callbacks and use the resulting position if something is returned - if (!noPropagation) { - var ui = this._uiHash(); - if(this._trigger('drag', event, ui) === false) { - this._mouseUp({}); - return false; - } - this.position = ui.position; + // if the browser doesn't support fractions, then round for consistent results + if ( !$.support.offsetFractions ) { + position.left = round( position.left ); + position.top = round( position.top ); } - if(!this.options.axis || this.options.axis != "y") this.helper[0].style.left = this.position.left+'px'; - if(!this.options.axis || this.options.axis != "x") this.helper[0].style.top = this.position.top+'px'; - if($.ui.ddmanager) $.ui.ddmanager.drag(this, event); - - return false; - }, + collisionPosition = { + marginLeft: marginLeft, + marginTop: marginTop + }; - _mouseStop: function(event) { + $.each( [ "left", "top" ], function( i, dir ) { + if ( $.ui.position[ collision[ i ] ] ) { + $.ui.position[ collision[ i ] ][ dir ]( position, { + targetWidth: targetWidth, + targetHeight: targetHeight, + elemWidth: elemWidth, + elemHeight: elemHeight, + collisionPosition: collisionPosition, + collisionWidth: collisionWidth, + collisionHeight: collisionHeight, + offset: [ atOffset[ 0 ] + myOffset[ 0 ], atOffset [ 1 ] + myOffset[ 1 ] ], + my: options.my, + at: options.at, + within: within, + elem : elem + }); + } + }); - //If we are using droppables, inform the manager about the drop - var dropped = false; - if ($.ui.ddmanager && !this.options.dropBehaviour) - dropped = $.ui.ddmanager.drop(this, event); + if ( $.fn.bgiframe ) { + elem.bgiframe(); + } - //if a drop comes from outside (a sortable) - if(this.dropped) { - dropped = this.dropped; - this.dropped = false; + if ( options.using ) { + // adds feedback as second argument to using callback, if present + using = function( props ) { + var left = targetOffset.left - position.left, + right = left + targetWidth - elemWidth, + top = targetOffset.top - position.top, + bottom = top + targetHeight - elemHeight, + feedback = { + target: { + element: target, + left: targetOffset.left, + top: targetOffset.top, + width: targetWidth, + height: targetHeight + }, + element: { + element: elem, + left: position.left, + top: position.top, + width: elemWidth, + height: elemHeight + }, + horizontal: right < 0 ? "left" : left > 0 ? "right" : "center", + vertical: bottom < 0 ? "top" : top > 0 ? "bottom" : "middle" + }; + if ( targetWidth < elemWidth && abs( left + right ) < targetWidth ) { + feedback.horizontal = "center"; + } + if ( targetHeight < elemHeight && abs( top + bottom ) < targetHeight ) { + feedback.vertical = "middle"; + } + if ( max( abs( left ), abs( right ) ) > max( abs( top ), abs( bottom ) ) ) { + feedback.important = "horizontal"; + } else { + feedback.important = "vertical"; + } + options.using.call( this, props, feedback ); + }; } - - //if the original element is removed, don't bother to continue if helper is set to "original" - if((!this.element[0] || !this.element[0].parentNode) && this.options.helper == "original") - return false; - if((this.options.revert == "invalid" && !dropped) || (this.options.revert == "valid" && dropped) || this.options.revert === true || ($.isFunction(this.options.revert) && this.options.revert.call(this.element, dropped))) { - var self = this; - $(this.helper).animate(this.originalPosition, parseInt(this.options.revertDuration, 10), function() { - if(self._trigger("stop", event) !== false) { - self._clear(); + elem.offset( $.extend( position, { using: using } ) ); + }); +}; + +$.ui.position = { + fit: { + left: function( position, data ) { + var within = data.within, + withinOffset = within.isWindow ? within.scrollLeft : within.offset.left, + outerWidth = within.width, + collisionPosLeft = position.left - data.collisionPosition.marginLeft, + overLeft = withinOffset - collisionPosLeft, + overRight = collisionPosLeft + data.collisionWidth - outerWidth - withinOffset, + newOverRight; + + // element is wider than within + if ( data.collisionWidth > outerWidth ) { + // element is initially over the left side of within + if ( overLeft > 0 && overRight <= 0 ) { + newOverRight = position.left + overLeft + data.collisionWidth - outerWidth - withinOffset; + position.left += overLeft - newOverRight; + // element is initially over right side of within + } else if ( overRight > 0 && overLeft <= 0 ) { + position.left = withinOffset; + // element is initially over both left and right sides of within + } else { + if ( overLeft > overRight ) { + position.left = withinOffset + outerWidth - data.collisionWidth; + } else { + position.left = withinOffset; + } } - }); - } else { - if(this._trigger("stop", event) !== false) { - this._clear(); + // too far left -> align with left edge + } else if ( overLeft > 0 ) { + position.left += overLeft; + // too far right -> align with right edge + } else if ( overRight > 0 ) { + position.left -= overRight; + // adjust based on position and margin + } else { + position.left = max( position.left - collisionPosLeft, position.left ); + } + }, + top: function( position, data ) { + var within = data.within, + withinOffset = within.isWindow ? within.scrollTop : within.offset.top, + outerHeight = data.within.height, + collisionPosTop = position.top - data.collisionPosition.marginTop, + overTop = withinOffset - collisionPosTop, + overBottom = collisionPosTop + data.collisionHeight - outerHeight - withinOffset, + newOverBottom; + + // element is taller than within + if ( data.collisionHeight > outerHeight ) { + // element is initially over the top of within + if ( overTop > 0 && overBottom <= 0 ) { + newOverBottom = position.top + overTop + data.collisionHeight - outerHeight - withinOffset; + position.top += overTop - newOverBottom; + // element is initially over bottom of within + } else if ( overBottom > 0 && overTop <= 0 ) { + position.top = withinOffset; + // element is initially over both top and bottom of within + } else { + if ( overTop > overBottom ) { + position.top = withinOffset + outerHeight - data.collisionHeight; + } else { + position.top = withinOffset; + } + } + // too far up -> align with top + } else if ( overTop > 0 ) { + position.top += overTop; + // too far down -> align with bottom edge + } else if ( overBottom > 0 ) { + position.top -= overBottom; + // adjust based on position and margin + } else { + position.top = max( position.top - collisionPosTop, position.top ); } } - - return false; }, - - _mouseUp: function(event) { - if (this.options.iframeFix === true) { - $("div.ui-draggable-iframeFix").each(function() { - this.parentNode.removeChild(this); - }); //Remove frame helpers + flip: { + left: function( position, data ) { + var within = data.within, + withinOffset = within.offset.left + within.scrollLeft, + outerWidth = within.width, + offsetLeft = within.isWindow ? within.scrollLeft : within.offset.left, + collisionPosLeft = position.left - data.collisionPosition.marginLeft, + overLeft = collisionPosLeft - offsetLeft, + overRight = collisionPosLeft + data.collisionWidth - outerWidth - offsetLeft, + myOffset = data.my[ 0 ] === "left" ? + -data.elemWidth : + data.my[ 0 ] === "right" ? + data.elemWidth : + 0, + atOffset = data.at[ 0 ] === "left" ? + data.targetWidth : + data.at[ 0 ] === "right" ? + -data.targetWidth : + 0, + offset = -2 * data.offset[ 0 ], + newOverRight, + newOverLeft; + + if ( overLeft < 0 ) { + newOverRight = position.left + myOffset + atOffset + offset + data.collisionWidth - outerWidth - withinOffset; + if ( newOverRight < 0 || newOverRight < abs( overLeft ) ) { + position.left += myOffset + atOffset + offset; + } + } + else if ( overRight > 0 ) { + newOverLeft = position.left - data.collisionPosition.marginLeft + myOffset + atOffset + offset - offsetLeft; + if ( newOverLeft > 0 || abs( newOverLeft ) < overRight ) { + position.left += myOffset + atOffset + offset; + } + } + }, + top: function( position, data ) { + var within = data.within, + withinOffset = within.offset.top + within.scrollTop, + outerHeight = within.height, + offsetTop = within.isWindow ? within.scrollTop : within.offset.top, + collisionPosTop = position.top - data.collisionPosition.marginTop, + overTop = collisionPosTop - offsetTop, + overBottom = collisionPosTop + data.collisionHeight - outerHeight - offsetTop, + top = data.my[ 1 ] === "top", + myOffset = top ? + -data.elemHeight : + data.my[ 1 ] === "bottom" ? + data.elemHeight : + 0, + atOffset = data.at[ 1 ] === "top" ? + data.targetHeight : + data.at[ 1 ] === "bottom" ? + -data.targetHeight : + 0, + offset = -2 * data.offset[ 1 ], + newOverTop, + newOverBottom; + if ( overTop < 0 ) { + newOverBottom = position.top + myOffset + atOffset + offset + data.collisionHeight - outerHeight - withinOffset; + if ( ( position.top + myOffset + atOffset + offset) > overTop && ( newOverBottom < 0 || newOverBottom < abs( overTop ) ) ) { + position.top += myOffset + atOffset + offset; + } + } + else if ( overBottom > 0 ) { + newOverTop = position.top - data.collisionPosition.marginTop + myOffset + atOffset + offset - offsetTop; + if ( ( position.top + myOffset + atOffset + offset) > overBottom && ( newOverTop > 0 || abs( newOverTop ) < overBottom ) ) { + position.top += myOffset + atOffset + offset; + } + } } - - //If the ddmanager is used for droppables, inform the manager that dragging has stopped (see #5003) - if( $.ui.ddmanager ) $.ui.ddmanager.dragStop(this, event); - - return $.ui.mouse.prototype._mouseUp.call(this, event); }, - - cancel: function() { - - if(this.helper.is(".ui-draggable-dragging")) { - this._mouseUp({}); - } else { - this._clear(); + flipfit: { + left: function() { + $.ui.position.flip.left.apply( this, arguments ); + $.ui.position.fit.left.apply( this, arguments ); + }, + top: function() { + $.ui.position.flip.top.apply( this, arguments ); + $.ui.position.fit.top.apply( this, arguments ); } - - return this; - - }, + } +}; - _getHandle: function(event) { +// fraction support test +(function () { + var testElement, testElementParent, testElementStyle, offsetLeft, i, + body = document.getElementsByTagName( "body" )[ 0 ], + div = document.createElement( "div" ); + + //Create a "fake body" for testing based on method used in jQuery.support + testElement = document.createElement( body ? "div" : "body" ); + testElementStyle = { + visibility: "hidden", + width: 0, + height: 0, + border: 0, + margin: 0, + background: "none" + }; + if ( body ) { + $.extend( testElementStyle, { + position: "absolute", + left: "-1000px", + top: "-1000px" + }); + } + for ( i in testElementStyle ) { + testElement.style[ i ] = testElementStyle[ i ]; + } + testElement.appendChild( div ); + testElementParent = body || document.documentElement; + testElementParent.insertBefore( testElement, testElementParent.firstChild ); + + div.style.cssText = "position: absolute; left: 10.7432222px;"; + + offsetLeft = $( div ).offset().left; + $.support.offsetFractions = offsetLeft > 10 && offsetLeft < 11; + + testElement.innerHTML = ""; + testElementParent.removeChild( testElement ); +})(); + +// DEPRECATED +if ( $.uiBackCompat !== false ) { + // offset option + (function( $ ) { + var _position = $.fn.position; + $.fn.position = function( options ) { + if ( !options || !options.offset ) { + return _position.call( this, options ); + } + var offset = options.offset.split( " " ), + at = options.at.split( " " ); + if ( offset.length === 1 ) { + offset[ 1 ] = offset[ 0 ]; + } + if ( /^\d/.test( offset[ 0 ] ) ) { + offset[ 0 ] = "+" + offset[ 0 ]; + } + if ( /^\d/.test( offset[ 1 ] ) ) { + offset[ 1 ] = "+" + offset[ 1 ]; + } + if ( at.length === 1 ) { + if ( /left|center|right/.test( at[ 0 ] ) ) { + at[ 1 ] = "center"; + } else { + at[ 1 ] = at[ 0 ]; + at[ 0 ] = "center"; + } + } + return _position.call( this, $.extend( options, { + at: at[ 0 ] + offset[ 0 ] + " " + at[ 1 ] + offset[ 1 ], + offset: undefined + } ) ); + }; + }( jQuery ) ); +} - var handle = !this.options.handle || !$(this.options.handle, this.element).length ? true : false; - $(this.options.handle, this.element) - .find("*") - .andSelf() - .each(function() { - if(this == event.target) handle = true; - }); +}( jQuery ) ); +(function( $, undefined ) { - return handle; +var uid = 0, + hideProps = {}, + showProps = {}; + +hideProps.height = hideProps.paddingTop = hideProps.paddingBottom = + hideProps.borderTopWidth = hideProps.borderBottomWidth = "hide"; +showProps.height = showProps.paddingTop = showProps.paddingBottom = + showProps.borderTopWidth = showProps.borderBottomWidth = "show"; + +$.widget( "ui.accordion", { + version: "1.9.2", + options: { + active: 0, + animate: {}, + collapsible: false, + event: "click", + header: "> li > :first-child,> :not(li):even", + heightStyle: "auto", + icons: { + activeHeader: "ui-icon-triangle-1-s", + header: "ui-icon-triangle-1-e" + }, + // callbacks + activate: null, + beforeActivate: null }, - _createHelper: function(event) { + _create: function() { + var accordionId = this.accordionId = "ui-accordion-" + + (this.element.attr( "id" ) || ++uid), + options = this.options; + + this.prevShow = this.prevHide = $(); + this.element.addClass( "ui-accordion ui-widget ui-helper-reset" ); + + this.headers = this.element.find( options.header ) + .addClass( "ui-accordion-header ui-helper-reset ui-state-default ui-corner-all" ); + this._hoverable( this.headers ); + this._focusable( this.headers ); + + this.headers.next() + .addClass( "ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom" ) + .hide(); + + // don't allow collapsible: false and active: false / null + if ( !options.collapsible && (options.active === false || options.active == null) ) { + options.active = 0; + } + // handle negative values + if ( options.active < 0 ) { + options.active += this.headers.length; + } + this.active = this._findActive( options.active ) + .addClass( "ui-accordion-header-active ui-state-active" ) + .toggleClass( "ui-corner-all ui-corner-top" ); + this.active.next() + .addClass( "ui-accordion-content-active" ) + .show(); + + this._createIcons(); + this.refresh(); - var o = this.options; - var helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event])) : (o.helper == 'clone' ? this.element.clone().removeAttr('id') : this.element); + // ARIA + this.element.attr( "role", "tablist" ); - if(!helper.parents('body').length) - helper.appendTo((o.appendTo == 'parent' ? this.element[0].parentNode : o.appendTo)); + this.headers + .attr( "role", "tab" ) + .each(function( i ) { + var header = $( this ), + headerId = header.attr( "id" ), + panel = header.next(), + panelId = panel.attr( "id" ); + if ( !headerId ) { + headerId = accordionId + "-header-" + i; + header.attr( "id", headerId ); + } + if ( !panelId ) { + panelId = accordionId + "-panel-" + i; + panel.attr( "id", panelId ); + } + header.attr( "aria-controls", panelId ); + panel.attr( "aria-labelledby", headerId ); + }) + .next() + .attr( "role", "tabpanel" ); - if(helper[0] != this.element[0] && !(/(fixed|absolute)/).test(helper.css("position"))) - helper.css("position", "absolute"); + this.headers + .not( this.active ) + .attr({ + "aria-selected": "false", + tabIndex: -1 + }) + .next() + .attr({ + "aria-expanded": "false", + "aria-hidden": "true" + }) + .hide(); - return helper; + // make sure at least one header is in the tab order + if ( !this.active.length ) { + this.headers.eq( 0 ).attr( "tabIndex", 0 ); + } else { + this.active.attr({ + "aria-selected": "true", + tabIndex: 0 + }) + .next() + .attr({ + "aria-expanded": "true", + "aria-hidden": "false" + }); + } + this._on( this.headers, { keydown: "_keydown" }); + this._on( this.headers.next(), { keydown: "_panelKeyDown" }); + this._setupEvents( options.event ); }, - _adjustOffsetFromHelper: function(obj) { - if (typeof obj == 'string') { - obj = obj.split(' '); + _getCreateEventData: function() { + return { + header: this.active, + content: !this.active.length ? $() : this.active.next() + }; + }, + + _createIcons: function() { + var icons = this.options.icons; + if ( icons ) { + $( "" ) + .addClass( "ui-accordion-header-icon ui-icon " + icons.header ) + .prependTo( this.headers ); + this.active.children( ".ui-accordion-header-icon" ) + .removeClass( icons.header ) + .addClass( icons.activeHeader ); + this.headers.addClass( "ui-accordion-icons" ); } - if ($.isArray(obj)) { - obj = {left: +obj[0], top: +obj[1] || 0}; + }, + + _destroyIcons: function() { + this.headers + .removeClass( "ui-accordion-icons" ) + .children( ".ui-accordion-header-icon" ) + .remove(); + }, + + _destroy: function() { + var contents; + + // clean up main element + this.element + .removeClass( "ui-accordion ui-widget ui-helper-reset" ) + .removeAttr( "role" ); + + // clean up headers + this.headers + .removeClass( "ui-accordion-header ui-accordion-header-active ui-helper-reset ui-state-default ui-corner-all ui-state-active ui-state-disabled ui-corner-top" ) + .removeAttr( "role" ) + .removeAttr( "aria-selected" ) + .removeAttr( "aria-controls" ) + .removeAttr( "tabIndex" ) + .each(function() { + if ( /^ui-accordion/.test( this.id ) ) { + this.removeAttribute( "id" ); + } + }); + this._destroyIcons(); + + // clean up content panels + contents = this.headers.next() + .css( "display", "" ) + .removeAttr( "role" ) + .removeAttr( "aria-expanded" ) + .removeAttr( "aria-hidden" ) + .removeAttr( "aria-labelledby" ) + .removeClass( "ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active ui-state-disabled" ) + .each(function() { + if ( /^ui-accordion/.test( this.id ) ) { + this.removeAttribute( "id" ); + } + }); + if ( this.options.heightStyle !== "content" ) { + contents.css( "height", "" ); } - if ('left' in obj) { - this.offset.click.left = obj.left + this.margins.left; + }, + + _setOption: function( key, value ) { + if ( key === "active" ) { + // _activate() will handle invalid values and update this.options + this._activate( value ); + return; } - if ('right' in obj) { - this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left; + + if ( key === "event" ) { + if ( this.options.event ) { + this._off( this.headers, this.options.event ); + } + this._setupEvents( value ); } - if ('top' in obj) { - this.offset.click.top = obj.top + this.margins.top; + + this._super( key, value ); + + // setting collapsible: false while collapsed; open first panel + if ( key === "collapsible" && !value && this.options.active === false ) { + this._activate( 0 ); } - if ('bottom' in obj) { - this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top; + + if ( key === "icons" ) { + this._destroyIcons(); + if ( value ) { + this._createIcons(); + } + } + + // #5332 - opacity doesn't cascade to positioned elements in IE + // so we need to add the disabled class to the headers and panels + if ( key === "disabled" ) { + this.headers.add( this.headers.next() ) + .toggleClass( "ui-state-disabled", !!value ); } }, - _getParentOffset: function() { + _keydown: function( event ) { + if ( event.altKey || event.ctrlKey ) { + return; + } - //Get the offsetParent and cache its position - this.offsetParent = this.helper.offsetParent(); - var po = this.offsetParent.offset(); + var keyCode = $.ui.keyCode, + length = this.headers.length, + currentIndex = this.headers.index( event.target ), + toFocus = false; - // This is a special case where we need to modify a offset calculated on start, since the following happened: - // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent - // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that - // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag - if(this.cssPosition == 'absolute' && this.scrollParent[0] != document && $.ui.contains(this.scrollParent[0], this.offsetParent[0])) { - po.left += this.scrollParent.scrollLeft(); - po.top += this.scrollParent.scrollTop(); + switch ( event.keyCode ) { + case keyCode.RIGHT: + case keyCode.DOWN: + toFocus = this.headers[ ( currentIndex + 1 ) % length ]; + break; + case keyCode.LEFT: + case keyCode.UP: + toFocus = this.headers[ ( currentIndex - 1 + length ) % length ]; + break; + case keyCode.SPACE: + case keyCode.ENTER: + this._eventHandler( event ); + break; + case keyCode.HOME: + toFocus = this.headers[ 0 ]; + break; + case keyCode.END: + toFocus = this.headers[ length - 1 ]; + break; } - if((this.offsetParent[0] == document.body) //This needs to be actually done for all browsers, since pageX/pageY includes this information - || (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() == 'html' && $.browser.msie)) //Ugly IE fix - po = { top: 0, left: 0 }; + if ( toFocus ) { + $( event.target ).attr( "tabIndex", -1 ); + $( toFocus ).attr( "tabIndex", 0 ); + toFocus.focus(); + event.preventDefault(); + } + }, - return { - top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0), - left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0) - }; + _panelKeyDown : function( event ) { + if ( event.keyCode === $.ui.keyCode.UP && event.ctrlKey ) { + $( event.currentTarget ).prev().focus(); + } + }, + + refresh: function() { + var maxHeight, overflow, + heightStyle = this.options.heightStyle, + parent = this.element.parent(); + + + if ( heightStyle === "fill" ) { + // IE 6 treats height like minHeight, so we need to turn off overflow + // in order to get a reliable height + // we use the minHeight support test because we assume that only + // browsers that don't support minHeight will treat height as minHeight + if ( !$.support.minHeight ) { + overflow = parent.css( "overflow" ); + parent.css( "overflow", "hidden"); + } + maxHeight = parent.height(); + this.element.siblings( ":visible" ).each(function() { + var elem = $( this ), + position = elem.css( "position" ); + + if ( position === "absolute" || position === "fixed" ) { + return; + } + maxHeight -= elem.outerHeight( true ); + }); + if ( overflow ) { + parent.css( "overflow", overflow ); + } + + this.headers.each(function() { + maxHeight -= $( this ).outerHeight( true ); + }); + this.headers.next() + .each(function() { + $( this ).height( Math.max( 0, maxHeight - + $( this ).innerHeight() + $( this ).height() ) ); + }) + .css( "overflow", "auto" ); + } else if ( heightStyle === "auto" ) { + maxHeight = 0; + this.headers.next() + .each(function() { + maxHeight = Math.max( maxHeight, $( this ).css( "height", "" ).height() ); + }) + .height( maxHeight ); + } }, - _getRelativeOffset: function() { + _activate: function( index ) { + var active = this._findActive( index )[ 0 ]; - if(this.cssPosition == "relative") { - var p = this.element.position(); - return { - top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(), - left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft() - }; - } else { - return { top: 0, left: 0 }; + // trying to activate the already active panel + if ( active === this.active[ 0 ] ) { + return; } + // trying to collapse, simulate a click on the currently active header + active = active || this.active[ 0 ]; + + this._eventHandler({ + target: active, + currentTarget: active, + preventDefault: $.noop + }); }, - _cacheMargins: function() { - this.margins = { - left: (parseInt(this.element.css("marginLeft"),10) || 0), - top: (parseInt(this.element.css("marginTop"),10) || 0), - right: (parseInt(this.element.css("marginRight"),10) || 0), - bottom: (parseInt(this.element.css("marginBottom"),10) || 0) - }; + _findActive: function( selector ) { + return typeof selector === "number" ? this.headers.eq( selector ) : $(); }, - _cacheHelperProportions: function() { - this.helperProportions = { - width: this.helper.outerWidth(), - height: this.helper.outerHeight() - }; + _setupEvents: function( event ) { + var events = {}; + if ( !event ) { + return; + } + $.each( event.split(" "), function( index, eventName ) { + events[ eventName ] = "_eventHandler"; + }); + this._on( this.headers, events ); }, - _setContainment: function() { + _eventHandler: function( event ) { + var options = this.options, + active = this.active, + clicked = $( event.currentTarget ), + clickedIsActive = clicked[ 0 ] === active[ 0 ], + collapsing = clickedIsActive && options.collapsible, + toShow = collapsing ? $() : clicked.next(), + toHide = active.next(), + eventData = { + oldHeader: active, + oldPanel: toHide, + newHeader: collapsing ? $() : clicked, + newPanel: toShow + }; - var o = this.options; - if(o.containment == 'parent') o.containment = this.helper[0].parentNode; - if(o.containment == 'document' || o.containment == 'window') this.containment = [ - o.containment == 'document' ? 0 : $(window).scrollLeft() - this.offset.relative.left - this.offset.parent.left, - o.containment == 'document' ? 0 : $(window).scrollTop() - this.offset.relative.top - this.offset.parent.top, - (o.containment == 'document' ? 0 : $(window).scrollLeft()) + $(o.containment == 'document' ? document : window).width() - this.helperProportions.width - this.margins.left, - (o.containment == 'document' ? 0 : $(window).scrollTop()) + ($(o.containment == 'document' ? document : window).height() || document.body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top - ]; + event.preventDefault(); - if(!(/^(document|window|parent)$/).test(o.containment) && o.containment.constructor != Array) { - var c = $(o.containment); - var ce = c[0]; if(!ce) return; - var co = c.offset(); - var over = ($(ce).css("overflow") != 'hidden'); + if ( + // click on active header, but not collapsible + ( clickedIsActive && !options.collapsible ) || + // allow canceling activation + ( this._trigger( "beforeActivate", event, eventData ) === false ) ) { + return; + } - this.containment = [ - (parseInt($(ce).css("borderLeftWidth"),10) || 0) + (parseInt($(ce).css("paddingLeft"),10) || 0), - (parseInt($(ce).css("borderTopWidth"),10) || 0) + (parseInt($(ce).css("paddingTop"),10) || 0), - (over ? Math.max(ce.scrollWidth,ce.offsetWidth) : ce.offsetWidth) - (parseInt($(ce).css("borderLeftWidth"),10) || 0) - (parseInt($(ce).css("paddingRight"),10) || 0) - this.helperProportions.width - this.margins.left - this.margins.right, - (over ? Math.max(ce.scrollHeight,ce.offsetHeight) : ce.offsetHeight) - (parseInt($(ce).css("borderTopWidth"),10) || 0) - (parseInt($(ce).css("paddingBottom"),10) || 0) - this.helperProportions.height - this.margins.top - this.margins.bottom - ]; - this.relative_container = c; + options.active = collapsing ? false : this.headers.index( clicked ); - } else if(o.containment.constructor == Array) { - this.containment = o.containment; - } - - }, - - _convertPositionTo: function(d, pos) { + // when the call to ._toggle() comes after the class changes + // it causes a very odd bug in IE 8 (see #6720) + this.active = clickedIsActive ? $() : clicked; + this._toggle( eventData ); - if(!pos) pos = this.position; - var mod = d == "absolute" ? 1 : -1; - var o = this.options, scroll = this.cssPosition == 'absolute' && !(this.scrollParent[0] != document && $.ui.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName); + // switch classes + // corner classes on the previously active header stay after the animation + active.removeClass( "ui-accordion-header-active ui-state-active" ); + if ( options.icons ) { + active.children( ".ui-accordion-header-icon" ) + .removeClass( options.icons.activeHeader ) + .addClass( options.icons.header ); + } - return { - top: ( - pos.top // The absolute mouse position - + this.offset.relative.top * mod // Only for relative positioned nodes: Relative offset from element to offset parent - + this.offset.parent.top * mod // The offsetParent's offset without borders (offset + border) - - ($.browser.safari && $.browser.version < 526 && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod) - ), - left: ( - pos.left // The absolute mouse position - + this.offset.relative.left * mod // Only for relative positioned nodes: Relative offset from element to offset parent - + this.offset.parent.left * mod // The offsetParent's offset without borders (offset + border) - - ($.browser.safari && $.browser.version < 526 && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) * mod) - ) - }; + if ( !clickedIsActive ) { + clicked + .removeClass( "ui-corner-all" ) + .addClass( "ui-accordion-header-active ui-state-active ui-corner-top" ); + if ( options.icons ) { + clicked.children( ".ui-accordion-header-icon" ) + .removeClass( options.icons.header ) + .addClass( options.icons.activeHeader ); + } + clicked + .next() + .addClass( "ui-accordion-content-active" ); + } }, - _generatePosition: function(event) { - - var o = this.options, scroll = this.cssPosition == 'absolute' && !(this.scrollParent[0] != document && $.ui.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName); - var pageX = event.pageX; - var pageY = event.pageY; + _toggle: function( data ) { + var toShow = data.newPanel, + toHide = this.prevShow.length ? this.prevShow : data.oldPanel; - /* - * - Position constraining - - * Constrain the position to a mix of grid, containment. - */ + // handle activating a panel during the animation for another activation + this.prevShow.add( this.prevHide ).stop( true, true ); + this.prevShow = toShow; + this.prevHide = toHide; - if(this.originalPosition) { //If we are not dragging yet, we won't check for options - var containment; - if(this.containment) { - if (this.relative_container){ - var co = this.relative_container.offset(); - containment = [ this.containment[0] + co.left, - this.containment[1] + co.top, - this.containment[2] + co.left, - this.containment[3] + co.top ]; - } - else { - containment = this.containment; - } + if ( this.options.animate ) { + this._animate( toShow, toHide, data ); + } else { + toHide.hide(); + toShow.show(); + this._toggleComplete( data ); + } - if(event.pageX - this.offset.click.left < containment[0]) pageX = containment[0] + this.offset.click.left; - if(event.pageY - this.offset.click.top < containment[1]) pageY = containment[1] + this.offset.click.top; - if(event.pageX - this.offset.click.left > containment[2]) pageX = containment[2] + this.offset.click.left; - if(event.pageY - this.offset.click.top > containment[3]) pageY = containment[3] + this.offset.click.top; - } + toHide.attr({ + "aria-expanded": "false", + "aria-hidden": "true" + }); + toHide.prev().attr( "aria-selected", "false" ); + // if we're switching panels, remove the old header from the tab order + // if we're opening from collapsed state, remove the previous header from the tab order + // if we're collapsing, then keep the collapsing header in the tab order + if ( toShow.length && toHide.length ) { + toHide.prev().attr( "tabIndex", -1 ); + } else if ( toShow.length ) { + this.headers.filter(function() { + return $( this ).attr( "tabIndex" ) === 0; + }) + .attr( "tabIndex", -1 ); + } - if(o.grid) { - //Check for grid elements set to 0 to prevent divide by 0 error causing invalid argument errors in IE (see ticket #6950) - var top = o.grid[1] ? this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1] : this.originalPageY; - pageY = containment ? (!(top - this.offset.click.top < containment[1] || top - this.offset.click.top > containment[3]) ? top : (!(top - this.offset.click.top < containment[1]) ? top - o.grid[1] : top + o.grid[1])) : top; + toShow + .attr({ + "aria-expanded": "true", + "aria-hidden": "false" + }) + .prev() + .attr({ + "aria-selected": "true", + tabIndex: 0 + }); + }, - var left = o.grid[0] ? this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0] : this.originalPageX; - pageX = containment ? (!(left - this.offset.click.left < containment[0] || left - this.offset.click.left > containment[2]) ? left : (!(left - this.offset.click.left < containment[0]) ? left - o.grid[0] : left + o.grid[0])) : left; - } + _animate: function( toShow, toHide, data ) { + var total, easing, duration, + that = this, + adjust = 0, + down = toShow.length && + ( !toHide.length || ( toShow.index() < toHide.index() ) ), + animate = this.options.animate || {}, + options = down && animate.down || animate, + complete = function() { + that._toggleComplete( data ); + }; + if ( typeof options === "number" ) { + duration = options; } + if ( typeof options === "string" ) { + easing = options; + } + // fall back from options to animation in case of partial down settings + easing = easing || options.easing || animate.easing; + duration = duration || options.duration || animate.duration; - return { - top: ( - pageY // The absolute mouse position - - this.offset.click.top // Click offset (relative to the element) - - this.offset.relative.top // Only for relative positioned nodes: Relative offset from element to offset parent - - this.offset.parent.top // The offsetParent's offset without borders (offset + border) - + ($.browser.safari && $.browser.version < 526 && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) )) - ), - left: ( - pageX // The absolute mouse position - - this.offset.click.left // Click offset (relative to the element) - - this.offset.relative.left // Only for relative positioned nodes: Relative offset from element to offset parent - - this.offset.parent.left // The offsetParent's offset without borders (offset + border) - + ($.browser.safari && $.browser.version < 526 && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() )) - ) - }; - - }, + if ( !toHide.length ) { + return toShow.animate( showProps, duration, easing, complete ); + } + if ( !toShow.length ) { + return toHide.animate( hideProps, duration, easing, complete ); + } - _clear: function() { - this.helper.removeClass("ui-draggable-dragging"); - if(this.helper[0] != this.element[0] && !this.cancelHelperRemoval) this.helper.remove(); - //if($.ui.ddmanager) $.ui.ddmanager.current = null; - this.helper = null; - this.cancelHelperRemoval = false; + total = toShow.show().outerHeight(); + toHide.animate( hideProps, { + duration: duration, + easing: easing, + step: function( now, fx ) { + fx.now = Math.round( now ); + } + }); + toShow + .hide() + .animate( showProps, { + duration: duration, + easing: easing, + complete: complete, + step: function( now, fx ) { + fx.now = Math.round( now ); + if ( fx.prop !== "height" ) { + adjust += fx.now; + } else if ( that.options.heightStyle !== "content" ) { + fx.now = Math.round( total - toHide.outerHeight() - adjust ); + adjust = 0; + } + } + }); }, - // From now on bulk stuff - mainly helpers + _toggleComplete: function( data ) { + var toHide = data.oldPanel; - _trigger: function(type, event, ui) { - ui = ui || this._uiHash(); - $.ui.plugin.call(this, type, [event, ui]); - if(type == "drag") this.positionAbs = this._convertPositionTo("absolute"); //The absolute position has to be recalculated after plugins - return $.Widget.prototype._trigger.call(this, type, event, ui); - }, + toHide + .removeClass( "ui-accordion-content-active" ) + .prev() + .removeClass( "ui-corner-top" ) + .addClass( "ui-corner-all" ); - plugins: {}, + // Work around for rendering bug in IE (#5421) + if ( toHide.length ) { + toHide.parent()[0].className = toHide.parent()[0].className; + } - _uiHash: function(event) { - return { - helper: this.helper, - position: this.position, - originalPosition: this.originalPosition, - offset: this.positionAbs - }; + this._trigger( "activate", null, data ); } - }); -$.extend($.ui.draggable, { - version: "1.8.16" -}); -$.ui.plugin.add("draggable", "connectToSortable", { - start: function(event, ui) { - var inst = $(this).data("draggable"), o = inst.options, - uiSortable = $.extend({}, ui, { item: inst.element }); - inst.sortables = []; - $(o.connectToSortable).each(function() { - var sortable = $.data(this, 'sortable'); - if (sortable && !sortable.options.disabled) { - inst.sortables.push({ - instance: sortable, - shouldRevert: sortable.options.revert - }); - sortable.refreshPositions(); // Call the sortable's refreshPositions at drag start to refresh the containerCache since the sortable container cache is used in drag and needs to be up to date (this will ensure it's initialised as well as being kept in step with any changes that might have happened on the page). - sortable._trigger("activate", event, uiSortable); +// DEPRECATED +if ( $.uiBackCompat !== false ) { + // navigation options + (function( $, prototype ) { + $.extend( prototype.options, { + navigation: false, + navigationFilter: function() { + return this.href.toLowerCase() === location.href.toLowerCase(); } }); - }, - stop: function(event, ui) { - - //If we are still over the sortable, we fake the stop event of the sortable, but also remove helper - var inst = $(this).data("draggable"), - uiSortable = $.extend({}, ui, { item: inst.element }); + var _create = prototype._create; + prototype._create = function() { + if ( this.options.navigation ) { + var that = this, + headers = this.element.find( this.options.header ), + content = headers.next(), + current = headers.add( content ) + .find( "a" ) + .filter( this.options.navigationFilter ) + [ 0 ]; + if ( current ) { + headers.add( content ).each( function( index ) { + if ( $.contains( this, current ) ) { + that.options.active = Math.floor( index / 2 ); + return false; + } + }); + } + } + _create.call( this ); + }; + }( jQuery, jQuery.ui.accordion.prototype ) ); + + // height options + (function( $, prototype ) { + $.extend( prototype.options, { + heightStyle: null, // remove default so we fall back to old values + autoHeight: true, // use heightStyle: "auto" + clearStyle: false, // use heightStyle: "content" + fillSpace: false // use heightStyle: "fill" + }); - $.each(inst.sortables, function() { - if(this.instance.isOver) { + var _create = prototype._create, + _setOption = prototype._setOption; - this.instance.isOver = 0; + $.extend( prototype, { + _create: function() { + this.options.heightStyle = this.options.heightStyle || + this._mergeHeightStyle(); - inst.cancelHelperRemoval = true; //Don't remove the helper in the draggable instance - this.instance.cancelHelperRemoval = false; //Remove it in the sortable instance (so sortable plugins like revert still work) + _create.call( this ); + }, - //The sortable revert is supported, and we have to set a temporary dropped variable on the draggable to support revert: 'valid/invalid' - if(this.shouldRevert) this.instance.options.revert = true; + _setOption: function( key ) { + if ( key === "autoHeight" || key === "clearStyle" || key === "fillSpace" ) { + this.options.heightStyle = this._mergeHeightStyle(); + } + _setOption.apply( this, arguments ); + }, - //Trigger the stop of the sortable - this.instance._mouseStop(event); + _mergeHeightStyle: function() { + var options = this.options; - this.instance.options.helper = this.instance.options._helper; + if ( options.fillSpace ) { + return "fill"; + } - //If the helper has been the original item, restore properties in the sortable - if(inst.options.helper == 'original') - this.instance.currentItem.css({ top: 'auto', left: 'auto' }); + if ( options.clearStyle ) { + return "content"; + } - } else { - this.instance.cancelHelperRemoval = false; //Remove the helper in the sortable instance - this.instance._trigger("deactivate", event, uiSortable); + if ( options.autoHeight ) { + return "auto"; + } } - }); + }( jQuery, jQuery.ui.accordion.prototype ) ); - }, - drag: function(event, ui) { + // icon options + (function( $, prototype ) { + $.extend( prototype.options.icons, { + activeHeader: null, // remove default so we fall back to old values + headerSelected: "ui-icon-triangle-1-s" + }); - var inst = $(this).data("draggable"), self = this; + var _createIcons = prototype._createIcons; + prototype._createIcons = function() { + if ( this.options.icons ) { + this.options.icons.activeHeader = this.options.icons.activeHeader || + this.options.icons.headerSelected; + } + _createIcons.call( this ); + }; + }( jQuery, jQuery.ui.accordion.prototype ) ); - var checkPos = function(o) { - var dyClick = this.offset.click.top, dxClick = this.offset.click.left; - var helperTop = this.positionAbs.top, helperLeft = this.positionAbs.left; - var itemHeight = o.height, itemWidth = o.width; - var itemTop = o.top, itemLeft = o.left; + // expanded active option, activate method + (function( $, prototype ) { + prototype.activate = prototype._activate; - return $.ui.isOver(helperTop + dyClick, helperLeft + dxClick, itemTop, itemLeft, itemHeight, itemWidth); + var _findActive = prototype._findActive; + prototype._findActive = function( index ) { + if ( index === -1 ) { + index = false; + } + if ( index && typeof index !== "number" ) { + index = this.headers.index( this.headers.filter( index ) ); + if ( index === -1 ) { + index = false; + } + } + return _findActive.call( this, index ); }; + }( jQuery, jQuery.ui.accordion.prototype ) ); - $.each(inst.sortables, function(i) { - - //Copy over some variables to allow calling the sortable's native _intersectsWith - this.instance.positionAbs = inst.positionAbs; - this.instance.helperProportions = inst.helperProportions; - this.instance.offset.click = inst.offset.click; - - if(this.instance._intersectsWith(this.instance.containerCache)) { + // resize method + jQuery.ui.accordion.prototype.resize = jQuery.ui.accordion.prototype.refresh; - //If it intersects, we use a little isOver variable and set it once, so our move-in stuff gets fired only once - if(!this.instance.isOver) { + // change events + (function( $, prototype ) { + $.extend( prototype.options, { + change: null, + changestart: null + }); - this.instance.isOver = 1; - //Now we fake the start of dragging for the sortable instance, - //by cloning the list group item, appending it to the sortable and using it as inst.currentItem - //We can then fire the start event of the sortable with our passed browser event, and our own helper (so it doesn't create a new one) - this.instance.currentItem = $(self).clone().removeAttr('id').appendTo(this.instance.element).data("sortable-item", true); - this.instance.options._helper = this.instance.options.helper; //Store helper option to later restore it - this.instance.options.helper = function() { return ui.helper[0]; }; + var _trigger = prototype._trigger; + prototype._trigger = function( type, event, data ) { + var ret = _trigger.apply( this, arguments ); + if ( !ret ) { + return false; + } - event.target = this.instance.currentItem[0]; - this.instance._mouseCapture(event, true); - this.instance._mouseStart(event, true, true); + if ( type === "beforeActivate" ) { + ret = _trigger.call( this, "changestart", event, { + oldHeader: data.oldHeader, + oldContent: data.oldPanel, + newHeader: data.newHeader, + newContent: data.newPanel + }); + } else if ( type === "activate" ) { + ret = _trigger.call( this, "change", event, { + oldHeader: data.oldHeader, + oldContent: data.oldPanel, + newHeader: data.newHeader, + newContent: data.newPanel + }); + } + return ret; + }; + }( jQuery, jQuery.ui.accordion.prototype ) ); + + // animated option + // NOTE: this only provides support for "slide", "bounceslide", and easings + // not the full $.ui.accordion.animations API + (function( $, prototype ) { + $.extend( prototype.options, { + animate: null, + animated: "slide" + }); - //Because the browser event is way off the new appended portlet, we modify a couple of variables to reflect the changes - this.instance.offset.click.top = inst.offset.click.top; - this.instance.offset.click.left = inst.offset.click.left; - this.instance.offset.parent.left -= inst.offset.parent.left - this.instance.offset.parent.left; - this.instance.offset.parent.top -= inst.offset.parent.top - this.instance.offset.parent.top; + var _create = prototype._create; + prototype._create = function() { + var options = this.options; + if ( options.animate === null ) { + if ( !options.animated ) { + options.animate = false; + } else if ( options.animated === "slide" ) { + options.animate = 300; + } else if ( options.animated === "bounceslide" ) { + options.animate = { + duration: 200, + down: { + easing: "easeOutBounce", + duration: 1000 + } + }; + } else { + options.animate = options.animated; + } + } - inst._trigger("toSortable", event); - inst.dropped = this.instance.element; //draggable revert needs that - //hack so receive/update callbacks work (mostly) - inst.currentItem = inst.element; - this.instance.fromOutside = inst; + _create.call( this ); + }; + }( jQuery, jQuery.ui.accordion.prototype ) ); +} - } +})( jQuery ); +(function( $, undefined ) { - //Provided we did all the previous steps, we can fire the drag event of the sortable on every draggable drag, when it intersects with the sortable - if(this.instance.currentItem) this.instance._mouseDrag(event); +// used to prevent race conditions with remote data sources +var requestIndex = 0; - } else { +$.widget( "ui.autocomplete", { + version: "1.9.2", + defaultElement: "", + options: { + appendTo: "body", + autoFocus: false, + delay: 300, + minLength: 1, + position: { + my: "left top", + at: "left bottom", + collision: "none" + }, + source: null, - //If it doesn't intersect with the sortable, and it intersected before, - //we fake the drag stop of the sortable, but make sure it doesn't remove the helper by using cancelHelperRemoval - if(this.instance.isOver) { + // callbacks + change: null, + close: null, + focus: null, + open: null, + response: null, + search: null, + select: null + }, - this.instance.isOver = 0; - this.instance.cancelHelperRemoval = true; - - //Prevent reverting on this forced stop - this.instance.options.revert = false; - - // The out event needs to be triggered independently - this.instance._trigger('out', event, this.instance._uiHash(this.instance)); - - this.instance._mouseStop(event, true); - this.instance.options.helper = this.instance.options._helper; + pending: 0, - //Now we remove our currentItem, the list group clone again, and the placeholder, and animate the helper back to it's original size - this.instance.currentItem.remove(); - if(this.instance.placeholder) this.instance.placeholder.remove(); + _create: function() { + // Some browsers only repeat keydown events, not keypress events, + // so we use the suppressKeyPress flag to determine if we've already + // handled the keydown event. #7269 + // Unfortunately the code for & in keypress is the same as the up arrow, + // so we use the suppressKeyPressRepeat flag to avoid handling keypress + // events when we know the keydown event was used to modify the + // search term. #7799 + var suppressKeyPress, suppressKeyPressRepeat, suppressInput; + + this.isMultiLine = this._isMultiLine(); + this.valueMethod = this.element[ this.element.is( "input,textarea" ) ? "val" : "text" ]; + this.isNewMenu = true; - inst._trigger("fromSortable", event); - inst.dropped = false; //draggable revert needs that + this.element + .addClass( "ui-autocomplete-input" ) + .attr( "autocomplete", "off" ); + + this._on( this.element, { + keydown: function( event ) { + if ( this.element.prop( "readOnly" ) ) { + suppressKeyPress = true; + suppressInput = true; + suppressKeyPressRepeat = true; + return; } - }; + suppressKeyPress = false; + suppressInput = false; + suppressKeyPressRepeat = false; + var keyCode = $.ui.keyCode; + switch( event.keyCode ) { + case keyCode.PAGE_UP: + suppressKeyPress = true; + this._move( "previousPage", event ); + break; + case keyCode.PAGE_DOWN: + suppressKeyPress = true; + this._move( "nextPage", event ); + break; + case keyCode.UP: + suppressKeyPress = true; + this._keyEvent( "previous", event ); + break; + case keyCode.DOWN: + suppressKeyPress = true; + this._keyEvent( "next", event ); + break; + case keyCode.ENTER: + case keyCode.NUMPAD_ENTER: + // when menu is open and has focus + if ( this.menu.active ) { + // #6055 - Opera still allows the keypress to occur + // which causes forms to submit + suppressKeyPress = true; + event.preventDefault(); + this.menu.select( event ); + } + break; + case keyCode.TAB: + if ( this.menu.active ) { + this.menu.select( event ); + } + break; + case keyCode.ESCAPE: + if ( this.menu.element.is( ":visible" ) ) { + this._value( this.term ); + this.close( event ); + // Different browsers have different default behavior for escape + // Single press can mean undo or clear + // Double press in IE means clear the whole form + event.preventDefault(); + } + break; + default: + suppressKeyPressRepeat = true; + // search timeout should be triggered before the input value is changed + this._searchTimeout( event ); + break; + } + }, + keypress: function( event ) { + if ( suppressKeyPress ) { + suppressKeyPress = false; + event.preventDefault(); + return; + } + if ( suppressKeyPressRepeat ) { + return; + } + + // replicate some key handlers to allow them to repeat in Firefox and Opera + var keyCode = $.ui.keyCode; + switch( event.keyCode ) { + case keyCode.PAGE_UP: + this._move( "previousPage", event ); + break; + case keyCode.PAGE_DOWN: + this._move( "nextPage", event ); + break; + case keyCode.UP: + this._keyEvent( "previous", event ); + break; + case keyCode.DOWN: + this._keyEvent( "next", event ); + break; + } + }, + input: function( event ) { + if ( suppressInput ) { + suppressInput = false; + event.preventDefault(); + return; + } + this._searchTimeout( event ); + }, + focus: function() { + this.selectedItem = null; + this.previous = this._value(); + }, + blur: function( event ) { + if ( this.cancelBlur ) { + delete this.cancelBlur; + return; + } + clearTimeout( this.searching ); + this.close( event ); + this._change( event ); + } }); - } -}); + this._initSource(); + this.menu = $( "
    " ) + .addClass( "ui-autocomplete" ) + .appendTo( this.document.find( this.options.appendTo || "body" )[ 0 ] ) + .menu({ + // custom key handling for now + input: $(), + // disable ARIA support, the live region takes care of that + role: null + }) + .zIndex( this.element.zIndex() + 1 ) + .hide() + .data( "menu" ); -$.ui.plugin.add("draggable", "cursor", { - start: function(event, ui) { - var t = $('body'), o = $(this).data('draggable').options; - if (t.css("cursor")) o._cursor = t.css("cursor"); - t.css("cursor", o.cursor); - }, - stop: function(event, ui) { - var o = $(this).data('draggable').options; - if (o._cursor) $('body').css("cursor", o._cursor); - } -}); + this._on( this.menu.element, { + mousedown: function( event ) { + // prevent moving focus out of the text field + event.preventDefault(); -$.ui.plugin.add("draggable", "opacity", { - start: function(event, ui) { - var t = $(ui.helper), o = $(this).data('draggable').options; - if(t.css("opacity")) o._opacity = t.css("opacity"); - t.css('opacity', o.opacity); - }, - stop: function(event, ui) { - var o = $(this).data('draggable').options; - if(o._opacity) $(ui.helper).css('opacity', o._opacity); - } -}); + // IE doesn't prevent moving focus even with event.preventDefault() + // so we set a flag to know when we should ignore the blur event + this.cancelBlur = true; + this._delay(function() { + delete this.cancelBlur; + }); -$.ui.plugin.add("draggable", "scroll", { - start: function(event, ui) { - var i = $(this).data("draggable"); - if(i.scrollParent[0] != document && i.scrollParent[0].tagName != 'HTML') i.overflowOffset = i.scrollParent.offset(); - }, - drag: function(event, ui) { + // clicking on the scrollbar causes focus to shift to the body + // but we can't detect a mouseup or a click immediately afterward + // so we have to track the next mousedown and close the menu if + // the user clicks somewhere outside of the autocomplete + var menuElement = this.menu.element[ 0 ]; + if ( !$( event.target ).closest( ".ui-menu-item" ).length ) { + this._delay(function() { + var that = this; + this.document.one( "mousedown", function( event ) { + if ( event.target !== that.element[ 0 ] && + event.target !== menuElement && + !$.contains( menuElement, event.target ) ) { + that.close(); + } + }); + }); + } + }, + menufocus: function( event, ui ) { + // #7024 - Prevent accidental activation of menu items in Firefox + if ( this.isNewMenu ) { + this.isNewMenu = false; + if ( event.originalEvent && /^mouse/.test( event.originalEvent.type ) ) { + this.menu.blur(); + + this.document.one( "mousemove", function() { + $( event.target ).trigger( event.originalEvent ); + }); - var i = $(this).data("draggable"), o = i.options, scrolled = false; + return; + } + } - if(i.scrollParent[0] != document && i.scrollParent[0].tagName != 'HTML') { + // back compat for _renderItem using item.autocomplete, via #7810 + // TODO remove the fallback, see #8156 + var item = ui.item.data( "ui-autocomplete-item" ) || ui.item.data( "item.autocomplete" ); + if ( false !== this._trigger( "focus", event, { item: item } ) ) { + // use value to match what will end up in the input, if it was a key event + if ( event.originalEvent && /^key/.test( event.originalEvent.type ) ) { + this._value( item.value ); + } + } else { + // Normally the input is populated with the item's value as the + // menu is navigated, causing screen readers to notice a change and + // announce the item. Since the focus event was canceled, this doesn't + // happen, so we update the live region so that screen readers can + // still notice the change and announce it. + this.liveRegion.text( item.value ); + } + }, + menuselect: function( event, ui ) { + // back compat for _renderItem using item.autocomplete, via #7810 + // TODO remove the fallback, see #8156 + var item = ui.item.data( "ui-autocomplete-item" ) || ui.item.data( "item.autocomplete" ), + previous = this.previous; + + // only trigger when focus was lost (click on menu) + if ( this.element[0] !== this.document[0].activeElement ) { + this.element.focus(); + this.previous = previous; + // #6109 - IE triggers two focus events and the second + // is asynchronous, so we need to reset the previous + // term synchronously and asynchronously :-( + this._delay(function() { + this.previous = previous; + this.selectedItem = item; + }); + } - if(!o.axis || o.axis != 'x') { - if((i.overflowOffset.top + i.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity) - i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop + o.scrollSpeed; - else if(event.pageY - i.overflowOffset.top < o.scrollSensitivity) - i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop - o.scrollSpeed; - } + if ( false !== this._trigger( "select", event, { item: item } ) ) { + this._value( item.value ); + } + // reset the term after the select event + // this allows custom select handling to work properly + this.term = this._value(); - if(!o.axis || o.axis != 'y') { - if((i.overflowOffset.left + i.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity) - i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft + o.scrollSpeed; - else if(event.pageX - i.overflowOffset.left < o.scrollSensitivity) - i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft - o.scrollSpeed; + this.close( event ); + this.selectedItem = item; } + }); - } else { + this.liveRegion = $( "", { + role: "status", + "aria-live": "polite" + }) + .addClass( "ui-helper-hidden-accessible" ) + .insertAfter( this.element ); - if(!o.axis || o.axis != 'x') { - if(event.pageY - $(document).scrollTop() < o.scrollSensitivity) - scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed); - else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity) - scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed); - } + if ( $.fn.bgiframe ) { + this.menu.element.bgiframe(); + } - if(!o.axis || o.axis != 'y') { - if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity) - scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed); - else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity) - scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed); + // turning off autocomplete prevents the browser from remembering the + // value when navigating through history, so we re-enable autocomplete + // if the page is unloaded before the widget is destroyed. #7790 + this._on( this.window, { + beforeunload: function() { + this.element.removeAttr( "autocomplete" ); } + }); + }, + + _destroy: function() { + clearTimeout( this.searching ); + this.element + .removeClass( "ui-autocomplete-input" ) + .removeAttr( "autocomplete" ); + this.menu.element.remove(); + this.liveRegion.remove(); + }, + _setOption: function( key, value ) { + this._super( key, value ); + if ( key === "source" ) { + this._initSource(); + } + if ( key === "appendTo" ) { + this.menu.element.appendTo( this.document.find( value || "body" )[0] ); + } + if ( key === "disabled" && value && this.xhr ) { + this.xhr.abort(); } + }, - if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) - $.ui.ddmanager.prepareOffsets(i, event); + _isMultiLine: function() { + // Textareas are always multi-line + if ( this.element.is( "textarea" ) ) { + return true; + } + // Inputs are always single-line, even if inside a contentEditable element + // IE also treats inputs as contentEditable + if ( this.element.is( "input" ) ) { + return false; + } + // All other element types are determined by whether or not they're contentEditable + return this.element.prop( "isContentEditable" ); + }, - } -}); + _initSource: function() { + var array, url, + that = this; + if ( $.isArray(this.options.source) ) { + array = this.options.source; + this.source = function( request, response ) { + response( $.ui.autocomplete.filter( array, request.term ) ); + }; + } else if ( typeof this.options.source === "string" ) { + url = this.options.source; + this.source = function( request, response ) { + if ( that.xhr ) { + that.xhr.abort(); + } + that.xhr = $.ajax({ + url: url, + data: request, + dataType: "json", + success: function( data ) { + response( data ); + }, + error: function() { + response( [] ); + } + }); + }; + } else { + this.source = this.options.source; + } + }, -$.ui.plugin.add("draggable", "snap", { - start: function(event, ui) { + _searchTimeout: function( event ) { + clearTimeout( this.searching ); + this.searching = this._delay(function() { + // only search if the value has changed + if ( this.term !== this._value() ) { + this.selectedItem = null; + this.search( null, event ); + } + }, this.options.delay ); + }, - var i = $(this).data("draggable"), o = i.options; - i.snapElements = []; + search: function( value, event ) { + value = value != null ? value : this._value(); - $(o.snap.constructor != String ? ( o.snap.items || ':data(draggable)' ) : o.snap).each(function() { - var $t = $(this); var $o = $t.offset(); - if(this != i.element[0]) i.snapElements.push({ - item: this, - width: $t.outerWidth(), height: $t.outerHeight(), - top: $o.top, left: $o.left - }); - }); + // always save the actual value, not the one passed as an argument + this.term = this._value(); + + if ( value.length < this.options.minLength ) { + return this.close( event ); + } + + if ( this._trigger( "search", event ) === false ) { + return; + } + return this._search( value ); }, - drag: function(event, ui) { - var inst = $(this).data("draggable"), o = inst.options; - var d = o.snapTolerance; + _search: function( value ) { + this.pending++; + this.element.addClass( "ui-autocomplete-loading" ); + this.cancelSearch = false; - var x1 = ui.offset.left, x2 = x1 + inst.helperProportions.width, - y1 = ui.offset.top, y2 = y1 + inst.helperProportions.height; + this.source( { term: value }, this._response() ); + }, - for (var i = inst.snapElements.length - 1; i >= 0; i--){ + _response: function() { + var that = this, + index = ++requestIndex; - var l = inst.snapElements[i].left, r = l + inst.snapElements[i].width, - t = inst.snapElements[i].top, b = t + inst.snapElements[i].height; + return function( content ) { + if ( index === requestIndex ) { + that.__response( content ); + } - //Yes, I know, this is insane ;) - if(!((l-d < x1 && x1 < r+d && t-d < y1 && y1 < b+d) || (l-d < x1 && x1 < r+d && t-d < y2 && y2 < b+d) || (l-d < x2 && x2 < r+d && t-d < y1 && y1 < b+d) || (l-d < x2 && x2 < r+d && t-d < y2 && y2 < b+d))) { - if(inst.snapElements[i].snapping) (inst.options.snap.release && inst.options.snap.release.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item }))); - inst.snapElements[i].snapping = false; - continue; + that.pending--; + if ( !that.pending ) { + that.element.removeClass( "ui-autocomplete-loading" ); } + }; + }, - if(o.snapMode != 'inner') { - var ts = Math.abs(t - y2) <= d; - var bs = Math.abs(b - y1) <= d; - var ls = Math.abs(l - x2) <= d; - var rs = Math.abs(r - x1) <= d; - if(ts) ui.position.top = inst._convertPositionTo("relative", { top: t - inst.helperProportions.height, left: 0 }).top - inst.margins.top; - if(bs) ui.position.top = inst._convertPositionTo("relative", { top: b, left: 0 }).top - inst.margins.top; - if(ls) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l - inst.helperProportions.width }).left - inst.margins.left; - if(rs) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r }).left - inst.margins.left; - } - - var first = (ts || bs || ls || rs); - - if(o.snapMode != 'outer') { - var ts = Math.abs(t - y1) <= d; - var bs = Math.abs(b - y2) <= d; - var ls = Math.abs(l - x1) <= d; - var rs = Math.abs(r - x2) <= d; - if(ts) ui.position.top = inst._convertPositionTo("relative", { top: t, left: 0 }).top - inst.margins.top; - if(bs) ui.position.top = inst._convertPositionTo("relative", { top: b - inst.helperProportions.height, left: 0 }).top - inst.margins.top; - if(ls) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l }).left - inst.margins.left; - if(rs) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r - inst.helperProportions.width }).left - inst.margins.left; - } - - if(!inst.snapElements[i].snapping && (ts || bs || ls || rs || first)) - (inst.options.snap.snap && inst.options.snap.snap.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item }))); - inst.snapElements[i].snapping = (ts || bs || ls || rs || first); - - }; + __response: function( content ) { + if ( content ) { + content = this._normalize( content ); + } + this._trigger( "response", null, { content: content } ); + if ( !this.options.disabled && content && content.length && !this.cancelSearch ) { + this._suggest( content ); + this._trigger( "open" ); + } else { + // use ._close() instead of .close() so we don't cancel future searches + this._close(); + } + }, - } -}); + close: function( event ) { + this.cancelSearch = true; + this._close( event ); + }, -$.ui.plugin.add("draggable", "stack", { - start: function(event, ui) { + _close: function( event ) { + if ( this.menu.element.is( ":visible" ) ) { + this.menu.element.hide(); + this.menu.blur(); + this.isNewMenu = true; + this._trigger( "close", event ); + } + }, - var o = $(this).data("draggable").options; + _change: function( event ) { + if ( this.previous !== this._value() ) { + this._trigger( "change", event, { item: this.selectedItem } ); + } + }, - var group = $.makeArray($(o.stack)).sort(function(a,b) { - return (parseInt($(a).css("zIndex"),10) || 0) - (parseInt($(b).css("zIndex"),10) || 0); - }); - if (!group.length) { return; } - - var min = parseInt(group[0].style.zIndex) || 0; - $(group).each(function(i) { - this.style.zIndex = min + i; + _normalize: function( items ) { + // assume all items have the right format when the first item is complete + if ( items.length && items[0].label && items[0].value ) { + return items; + } + return $.map( items, function( item ) { + if ( typeof item === "string" ) { + return { + label: item, + value: item + }; + } + return $.extend({ + label: item.label || item.value, + value: item.value || item.label + }, item ); }); + }, - this[0].style.zIndex = min + group.length; + _suggest: function( items ) { + var ul = this.menu.element + .empty() + .zIndex( this.element.zIndex() + 1 ); + this._renderMenu( ul, items ); + this.menu.refresh(); - } -}); + // size and position menu + ul.show(); + this._resizeMenu(); + ul.position( $.extend({ + of: this.element + }, this.options.position )); -$.ui.plugin.add("draggable", "zIndex", { - start: function(event, ui) { - var t = $(ui.helper), o = $(this).data("draggable").options; - if(t.css("zIndex")) o._zIndex = t.css("zIndex"); - t.css('zIndex', o.zIndex); + if ( this.options.autoFocus ) { + this.menu.next(); + } }, - stop: function(event, ui) { - var o = $(this).data("draggable").options; - if(o._zIndex) $(ui.helper).css('zIndex', o._zIndex); - } -}); - -})(jQuery); -/* - * jQuery UI Droppable 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Droppables - * - * Depends: - * jquery.ui.core.js - * jquery.ui.widget.js - * jquery.ui.mouse.js - * jquery.ui.draggable.js - */ -(function( $, undefined ) { -$.widget("ui.droppable", { - widgetEventPrefix: "drop", - options: { - accept: '*', - activeClass: false, - addClasses: true, - greedy: false, - hoverClass: false, - scope: 'default', - tolerance: 'intersect' + _resizeMenu: function() { + var ul = this.menu.element; + ul.outerWidth( Math.max( + // Firefox wraps long text (possibly a rounding bug) + // so we add 1px to avoid the wrapping (#7513) + ul.width( "" ).outerWidth() + 1, + this.element.outerWidth() + ) ); }, - _create: function() { - - var o = this.options, accept = o.accept; - this.isover = 0; this.isout = 1; - - this.accept = $.isFunction(accept) ? accept : function(d) { - return d.is(accept); - }; - - //Store the droppable's proportions - this.proportions = { width: this.element[0].offsetWidth, height: this.element[0].offsetHeight }; - - // Add the reference and positions to the manager - $.ui.ddmanager.droppables[o.scope] = $.ui.ddmanager.droppables[o.scope] || []; - $.ui.ddmanager.droppables[o.scope].push(this); - - (o.addClasses && this.element.addClass("ui-droppable")); + _renderMenu: function( ul, items ) { + var that = this; + $.each( items, function( index, item ) { + that._renderItemData( ul, item ); + }); }, - destroy: function() { - var drop = $.ui.ddmanager.droppables[this.options.scope]; - for ( var i = 0; i < drop.length; i++ ) - if ( drop[i] == this ) - drop.splice(i, 1); - - this.element - .removeClass("ui-droppable ui-droppable-disabled") - .removeData("droppable") - .unbind(".droppable"); - - return this; + _renderItemData: function( ul, item ) { + return this._renderItem( ul, item ).data( "ui-autocomplete-item", item ); }, - _setOption: function(key, value) { + _renderItem: function( ul, item ) { + return $( "
  • " ) + .append( $( "" ).text( item.label ) ) + .appendTo( ul ); + }, - if(key == 'accept') { - this.accept = $.isFunction(value) ? value : function(d) { - return d.is(value); - }; + _move: function( direction, event ) { + if ( !this.menu.element.is( ":visible" ) ) { + this.search( null, event ); + return; } - $.Widget.prototype._setOption.apply(this, arguments); + if ( this.menu.isFirstItem() && /^previous/.test( direction ) || + this.menu.isLastItem() && /^next/.test( direction ) ) { + this._value( this.term ); + this.menu.blur(); + return; + } + this.menu[ direction ]( event ); }, - _activate: function(event) { - var draggable = $.ui.ddmanager.current; - if(this.options.activeClass) this.element.addClass(this.options.activeClass); - (draggable && this._trigger('activate', event, this.ui(draggable))); + widget: function() { + return this.menu.element; }, - _deactivate: function(event) { - var draggable = $.ui.ddmanager.current; - if(this.options.activeClass) this.element.removeClass(this.options.activeClass); - (draggable && this._trigger('deactivate', event, this.ui(draggable))); + _value: function() { + return this.valueMethod.apply( this.element, arguments ); }, - _over: function(event) { - - var draggable = $.ui.ddmanager.current; - if (!draggable || (draggable.currentItem || draggable.element)[0] == this.element[0]) return; // Bail if draggable and droppable are same element + _keyEvent: function( keyEvent, event ) { + if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) { + this._move( keyEvent, event ); - if (this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) { - if(this.options.hoverClass) this.element.addClass(this.options.hoverClass); - this._trigger('over', event, this.ui(draggable)); + // prevents moving cursor to beginning/end of the text field in some browsers + event.preventDefault(); } + } +}); +$.extend( $.ui.autocomplete, { + escapeRegex: function( value ) { + return value.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&"); }, + filter: function(array, term) { + var matcher = new RegExp( $.ui.autocomplete.escapeRegex(term), "i" ); + return $.grep( array, function(value) { + return matcher.test( value.label || value.value || value ); + }); + } +}); - _out: function(event) { - - var draggable = $.ui.ddmanager.current; - if (!draggable || (draggable.currentItem || draggable.element)[0] == this.element[0]) return; // Bail if draggable and droppable are same element - if (this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) { - if(this.options.hoverClass) this.element.removeClass(this.options.hoverClass); - this._trigger('out', event, this.ui(draggable)); +// live region extension, adding a `messages` option +// NOTE: This is an experimental API. We are still investigating +// a full solution for string manipulation and internationalization. +$.widget( "ui.autocomplete", $.ui.autocomplete, { + options: { + messages: { + noResults: "No search results.", + results: function( amount ) { + return amount + ( amount > 1 ? " results are" : " result is" ) + + " available, use up and down arrow keys to navigate."; + } } - }, - _drop: function(event,custom) { - - var draggable = custom || $.ui.ddmanager.current; - if (!draggable || (draggable.currentItem || draggable.element)[0] == this.element[0]) return false; // Bail if draggable and droppable are same element - - var childrenIntersection = false; - this.element.find(":data(droppable)").not(".ui-draggable-dragging").each(function() { - var inst = $.data(this, 'droppable'); - if( - inst.options.greedy - && !inst.options.disabled - && inst.options.scope == draggable.options.scope - && inst.accept.call(inst.element[0], (draggable.currentItem || draggable.element)) - && $.ui.intersect(draggable, $.extend(inst, { offset: inst.element.offset() }), inst.options.tolerance) - ) { childrenIntersection = true; return false; } - }); - if(childrenIntersection) return false; - - if(this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) { - if(this.options.activeClass) this.element.removeClass(this.options.activeClass); - if(this.options.hoverClass) this.element.removeClass(this.options.hoverClass); - this._trigger('drop', event, this.ui(draggable)); - return this.element; + __response: function( content ) { + var message; + this._superApply( arguments ); + if ( this.options.disabled || this.cancelSearch ) { + return; } - - return false; - - }, - - ui: function(c) { - return { - draggable: (c.currentItem || c.element), - helper: c.helper, - position: c.position, - offset: c.positionAbs - }; + if ( content && content.length ) { + message = this.options.messages.results( content.length ); + } else { + message = this.options.messages.noResults; + } + this.liveRegion.text( message ); } - -}); - -$.extend($.ui.droppable, { - version: "1.8.16" }); -$.ui.intersect = function(draggable, droppable, toleranceMode) { - - if (!droppable.offset) return false; - var x1 = (draggable.positionAbs || draggable.position.absolute).left, x2 = x1 + draggable.helperProportions.width, - y1 = (draggable.positionAbs || draggable.position.absolute).top, y2 = y1 + draggable.helperProportions.height; - var l = droppable.offset.left, r = l + droppable.proportions.width, - t = droppable.offset.top, b = t + droppable.proportions.height; +}( jQuery )); +(function( $, undefined ) { - switch (toleranceMode) { - case 'fit': - return (l <= x1 && x2 <= r - && t <= y1 && y2 <= b); - break; - case 'intersect': - return (l < x1 + (draggable.helperProportions.width / 2) // Right Half - && x2 - (draggable.helperProportions.width / 2) < r // Left Half - && t < y1 + (draggable.helperProportions.height / 2) // Bottom Half - && y2 - (draggable.helperProportions.height / 2) < b ); // Top Half - break; - case 'pointer': - var draggableLeft = ((draggable.positionAbs || draggable.position.absolute).left + (draggable.clickOffset || draggable.offset.click).left), - draggableTop = ((draggable.positionAbs || draggable.position.absolute).top + (draggable.clickOffset || draggable.offset.click).top), - isOver = $.ui.isOver(draggableTop, draggableLeft, t, l, droppable.proportions.height, droppable.proportions.width); - return isOver; - break; - case 'touch': - return ( - (y1 >= t && y1 <= b) || // Top edge touching - (y2 >= t && y2 <= b) || // Bottom edge touching - (y1 < t && y2 > b) // Surrounded vertically - ) && ( - (x1 >= l && x1 <= r) || // Left edge touching - (x2 >= l && x2 <= r) || // Right edge touching - (x1 < l && x2 > r) // Surrounded horizontally - ); - break; - default: - return false; - break; +var lastActive, startXPos, startYPos, clickDragged, + baseClasses = "ui-button ui-widget ui-state-default ui-corner-all", + stateClasses = "ui-state-hover ui-state-active ", + typeClasses = "ui-button-icons-only ui-button-icon-only ui-button-text-icons ui-button-text-icon-primary ui-button-text-icon-secondary ui-button-text-only", + formResetHandler = function() { + var buttons = $( this ).find( ":ui-button" ); + setTimeout(function() { + buttons.button( "refresh" ); + }, 1 ); + }, + radioGroup = function( radio ) { + var name = radio.name, + form = radio.form, + radios = $( [] ); + if ( name ) { + if ( form ) { + radios = $( form ).find( "[name='" + name + "']" ); + } else { + radios = $( "[name='" + name + "']", radio.ownerDocument ) + .filter(function() { + return !this.form; + }); + } } + return radios; + }; -}; +$.widget( "ui.button", { + version: "1.9.2", + defaultElement: "').addClass(this._triggerClass). + html(buttonImage == '' ? buttonText : $('').attr( + { src:buttonImage, alt:buttonText, title:buttonText }))); + input[isRTL ? 'before' : 'after'](inst.trigger); + inst.trigger.click(function() { + if ($.datepicker._datepickerShowing && $.datepicker._lastInput == input[0]) + $.datepicker._hideDatepicker(); + else if ($.datepicker._datepickerShowing && $.datepicker._lastInput != input[0]) { + $.datepicker._hideDatepicker(); + $.datepicker._showDatepicker(input[0]); + } else + $.datepicker._showDatepicker(input[0]); + return false; + }); } - - //Store needed variables - this.offset = this.helper.offset(); - this.position = { left: curleft, top: curtop }; - this.size = this._helper ? { width: el.outerWidth(), height: el.outerHeight() } : { width: el.width(), height: el.height() }; - this.originalSize = this._helper ? { width: el.outerWidth(), height: el.outerHeight() } : { width: el.width(), height: el.height() }; - this.originalPosition = { left: curleft, top: curtop }; - this.sizeDiff = { width: el.outerWidth() - el.width(), height: el.outerHeight() - el.height() }; - this.originalMousePosition = { left: event.pageX, top: event.pageY }; - - //Aspect Ratio - this.aspectRatio = (typeof o.aspectRatio == 'number') ? o.aspectRatio : ((this.originalSize.width / this.originalSize.height) || 1); - - var cursor = $('.ui-resizable-' + this.axis).css('cursor'); - $('body').css('cursor', cursor == 'auto' ? this.axis + '-resize' : cursor); - - el.addClass("ui-resizable-resizing"); - this._propagate("start", event); - return true; }, - _mouseDrag: function(event) { - - //Increase performance, avoid regex - var el = this.helper, o = this.options, props = {}, - self = this, smp = this.originalMousePosition, a = this.axis; - - var dx = (event.pageX-smp.left)||0, dy = (event.pageY-smp.top)||0; - var trigger = this._change[a]; - if (!trigger) return false; - - // Calculate the attrs that will be change - var data = trigger.apply(this, [event, dx, dy]), ie6 = $.browser.msie && $.browser.version < 7, csdif = this.sizeDiff; - - // Put this in the mouseDrag handler since the user can start pressing shift while resizing - this._updateVirtualBoundaries(event.shiftKey); - if (this._aspectRatio || event.shiftKey) - data = this._updateRatio(data, event); - - data = this._respectSize(data, event); - - // plugins callbacks need to be called first - this._propagate("resize", event); - - el.css({ - top: this.position.top + "px", left: this.position.left + "px", - width: this.size.width + "px", height: this.size.height + "px" - }); - - if (!this._helper && this._proportionallyResizeElements.length) - this._proportionallyResize(); - - this._updateCache(data); - - // calling the user callback at the end - this._trigger('resize', event, this.ui()); - - return false; + /* Apply the maximum length for the date format. */ + _autoSize: function(inst) { + if (this._get(inst, 'autoSize') && !inst.inline) { + var date = new Date(2009, 12 - 1, 20); // Ensure double digits + var dateFormat = this._get(inst, 'dateFormat'); + if (dateFormat.match(/[DM]/)) { + var findMax = function(names) { + var max = 0; + var maxI = 0; + for (var i = 0; i < names.length; i++) { + if (names[i].length > max) { + max = names[i].length; + maxI = i; + } + } + return maxI; + }; + date.setMonth(findMax(this._get(inst, (dateFormat.match(/MM/) ? + 'monthNames' : 'monthNamesShort')))); + date.setDate(findMax(this._get(inst, (dateFormat.match(/DD/) ? + 'dayNames' : 'dayNamesShort'))) + 20 - date.getDay()); + } + inst.input.attr('size', this._formatDate(inst, date).length); + } }, - _mouseStop: function(event) { - - this.resizing = false; - var o = this.options, self = this; - - if(this._helper) { - var pr = this._proportionallyResizeElements, ista = pr.length && (/textarea/i).test(pr[0].nodeName), - soffseth = ista && $.ui.hasScroll(pr[0], 'left') /* TODO - jump height */ ? 0 : self.sizeDiff.height, - soffsetw = ista ? 0 : self.sizeDiff.width; - - var s = { width: (self.helper.width() - soffsetw), height: (self.helper.height() - soffseth) }, - left = (parseInt(self.element.css('left'), 10) + (self.position.left - self.originalPosition.left)) || null, - top = (parseInt(self.element.css('top'), 10) + (self.position.top - self.originalPosition.top)) || null; - - if (!o.animate) - this.element.css($.extend(s, { top: top, left: left })); - - self.helper.height(self.size.height); - self.helper.width(self.size.width); - - if (this._helper && !o.animate) this._proportionallyResize(); + /* Attach an inline date picker to a div. */ + _inlineDatepicker: function(target, inst) { + var divSpan = $(target); + if (divSpan.hasClass(this.markerClassName)) + return; + divSpan.addClass(this.markerClassName).append(inst.dpDiv). + bind("setData.datepicker", function(event, key, value){ + inst.settings[key] = value; + }).bind("getData.datepicker", function(event, key){ + return this._get(inst, key); + }); + $.data(target, PROP_NAME, inst); + this._setDate(inst, this._getDefaultDate(inst), true); + this._updateDatepicker(inst); + this._updateAlternate(inst); + //If disabled option is true, disable the datepicker before showing it (see ticket #5665) + if( inst.settings.disabled ) { + this._disableDatepicker( target ); } - - $('body').css('cursor', 'auto'); - - this.element.removeClass("ui-resizable-resizing"); - - this._propagate("stop", event); - - if (this._helper) this.helper.remove(); - return false; - + // Set display:block in place of inst.dpDiv.show() which won't work on disconnected elements + // http://bugs.jqueryui.com/ticket/7552 - A Datepicker created on a detached div has zero height + inst.dpDiv.css( "display", "block" ); }, - _updateVirtualBoundaries: function(forceAspectRatio) { - var o = this.options, pMinWidth, pMaxWidth, pMinHeight, pMaxHeight, b; - - b = { - minWidth: isNumber(o.minWidth) ? o.minWidth : 0, - maxWidth: isNumber(o.maxWidth) ? o.maxWidth : Infinity, - minHeight: isNumber(o.minHeight) ? o.minHeight : 0, - maxHeight: isNumber(o.maxHeight) ? o.maxHeight : Infinity - }; - - if(this._aspectRatio || forceAspectRatio) { - // We want to create an enclosing box whose aspect ration is the requested one - // First, compute the "projected" size for each dimension based on the aspect ratio and other dimension - pMinWidth = b.minHeight * this.aspectRatio; - pMinHeight = b.minWidth / this.aspectRatio; - pMaxWidth = b.maxHeight * this.aspectRatio; - pMaxHeight = b.maxWidth / this.aspectRatio; + /* Pop-up the date picker in a "dialog" box. + @param input element - ignored + @param date string or Date - the initial date to display + @param onSelect function - the function to call when a date is selected + @param settings object - update the dialog date picker instance's settings (anonymous object) + @param pos int[2] - coordinates for the dialog's position within the screen or + event - with x/y coordinates or + leave empty for default (screen centre) + @return the manager object */ + _dialogDatepicker: function(input, date, onSelect, settings, pos) { + var inst = this._dialogInst; // internal instance + if (!inst) { + this.uuid += 1; + var id = 'dp' + this.uuid; + this._dialogInput = $(''); + this._dialogInput.keydown(this._doKeyDown); + $('body').append(this._dialogInput); + inst = this._dialogInst = this._newInst(this._dialogInput, false); + inst.settings = {}; + $.data(this._dialogInput[0], PROP_NAME, inst); + } + extendRemove(inst.settings, settings || {}); + date = (date && date.constructor == Date ? this._formatDate(inst, date) : date); + this._dialogInput.val(date); - if(pMinWidth > b.minWidth) b.minWidth = pMinWidth; - if(pMinHeight > b.minHeight) b.minHeight = pMinHeight; - if(pMaxWidth < b.maxWidth) b.maxWidth = pMaxWidth; - if(pMaxHeight < b.maxHeight) b.maxHeight = pMaxHeight; - } - this._vBoundaries = b; - }, + this._pos = (pos ? (pos.length ? pos : [pos.pageX, pos.pageY]) : null); + if (!this._pos) { + var browserWidth = document.documentElement.clientWidth; + var browserHeight = document.documentElement.clientHeight; + var scrollX = document.documentElement.scrollLeft || document.body.scrollLeft; + var scrollY = document.documentElement.scrollTop || document.body.scrollTop; + this._pos = // should use actual width/height below + [(browserWidth / 2) - 100 + scrollX, (browserHeight / 2) - 150 + scrollY]; + } - _updateCache: function(data) { - var o = this.options; - this.offset = this.helper.offset(); - if (isNumber(data.left)) this.position.left = data.left; - if (isNumber(data.top)) this.position.top = data.top; - if (isNumber(data.height)) this.size.height = data.height; - if (isNumber(data.width)) this.size.width = data.width; + // move input on screen for focus, but hidden behind dialog + this._dialogInput.css('left', (this._pos[0] + 20) + 'px').css('top', this._pos[1] + 'px'); + inst.settings.onSelect = onSelect; + this._inDialog = true; + this.dpDiv.addClass(this._dialogClass); + this._showDatepicker(this._dialogInput[0]); + if ($.blockUI) + $.blockUI(this.dpDiv); + $.data(this._dialogInput[0], PROP_NAME, inst); + return this; }, - _updateRatio: function(data, event) { - - var o = this.options, cpos = this.position, csize = this.size, a = this.axis; - - if (isNumber(data.height)) data.width = (data.height * this.aspectRatio); - else if (isNumber(data.width)) data.height = (data.width / this.aspectRatio); + /* Detach a datepicker from its control. + @param target element - the target input field or division or span */ + _destroyDatepicker: function(target) { + var $target = $(target); + var inst = $.data(target, PROP_NAME); + if (!$target.hasClass(this.markerClassName)) { + return; + } + var nodeName = target.nodeName.toLowerCase(); + $.removeData(target, PROP_NAME); + if (nodeName == 'input') { + inst.append.remove(); + inst.trigger.remove(); + $target.removeClass(this.markerClassName). + unbind('focus', this._showDatepicker). + unbind('keydown', this._doKeyDown). + unbind('keypress', this._doKeyPress). + unbind('keyup', this._doKeyUp); + } else if (nodeName == 'div' || nodeName == 'span') + $target.removeClass(this.markerClassName).empty(); + }, - if (a == 'sw') { - data.left = cpos.left + (csize.width - data.width); - data.top = null; + /* Enable the date picker to a jQuery selection. + @param target element - the target input field or division or span */ + _enableDatepicker: function(target) { + var $target = $(target); + var inst = $.data(target, PROP_NAME); + if (!$target.hasClass(this.markerClassName)) { + return; } - if (a == 'nw') { - data.top = cpos.top + (csize.height - data.height); - data.left = cpos.left + (csize.width - data.width); + var nodeName = target.nodeName.toLowerCase(); + if (nodeName == 'input') { + target.disabled = false; + inst.trigger.filter('button'). + each(function() { this.disabled = false; }).end(). + filter('img').css({opacity: '1.0', cursor: ''}); } - - return data; + else if (nodeName == 'div' || nodeName == 'span') { + var inline = $target.children('.' + this._inlineClass); + inline.children().removeClass('ui-state-disabled'); + inline.find("select.ui-datepicker-month, select.ui-datepicker-year"). + prop("disabled", false); + } + this._disabledInputs = $.map(this._disabledInputs, + function(value) { return (value == target ? null : value); }); // delete entry }, - _respectSize: function(data, event) { - - var el = this.helper, o = this._vBoundaries, pRatio = this._aspectRatio || event.shiftKey, a = this.axis, - ismaxw = isNumber(data.width) && o.maxWidth && (o.maxWidth < data.width), ismaxh = isNumber(data.height) && o.maxHeight && (o.maxHeight < data.height), - isminw = isNumber(data.width) && o.minWidth && (o.minWidth > data.width), isminh = isNumber(data.height) && o.minHeight && (o.minHeight > data.height); - - if (isminw) data.width = o.minWidth; - if (isminh) data.height = o.minHeight; - if (ismaxw) data.width = o.maxWidth; - if (ismaxh) data.height = o.maxHeight; - - var dw = this.originalPosition.left + this.originalSize.width, dh = this.position.top + this.size.height; - var cw = /sw|nw|w/.test(a), ch = /nw|ne|n/.test(a); - - if (isminw && cw) data.left = dw - o.minWidth; - if (ismaxw && cw) data.left = dw - o.maxWidth; - if (isminh && ch) data.top = dh - o.minHeight; - if (ismaxh && ch) data.top = dh - o.maxHeight; - - // fixing jump error on top/left - bug #2330 - var isNotwh = !data.width && !data.height; - if (isNotwh && !data.left && data.top) data.top = null; - else if (isNotwh && !data.top && data.left) data.left = null; - - return data; + /* Disable the date picker to a jQuery selection. + @param target element - the target input field or division or span */ + _disableDatepicker: function(target) { + var $target = $(target); + var inst = $.data(target, PROP_NAME); + if (!$target.hasClass(this.markerClassName)) { + return; + } + var nodeName = target.nodeName.toLowerCase(); + if (nodeName == 'input') { + target.disabled = true; + inst.trigger.filter('button'). + each(function() { this.disabled = true; }).end(). + filter('img').css({opacity: '0.5', cursor: 'default'}); + } + else if (nodeName == 'div' || nodeName == 'span') { + var inline = $target.children('.' + this._inlineClass); + inline.children().addClass('ui-state-disabled'); + inline.find("select.ui-datepicker-month, select.ui-datepicker-year"). + prop("disabled", true); + } + this._disabledInputs = $.map(this._disabledInputs, + function(value) { return (value == target ? null : value); }); // delete entry + this._disabledInputs[this._disabledInputs.length] = target; }, - _proportionallyResize: function() { - - var o = this.options; - if (!this._proportionallyResizeElements.length) return; - var element = this.helper || this.element; - - for (var i=0; i < this._proportionallyResizeElements.length; i++) { - - var prel = this._proportionallyResizeElements[i]; + /* Is the first field in a jQuery collection disabled as a datepicker? + @param target element - the target input field or division or span + @return boolean - true if disabled, false if enabled */ + _isDisabledDatepicker: function(target) { + if (!target) { + return false; + } + for (var i = 0; i < this._disabledInputs.length; i++) { + if (this._disabledInputs[i] == target) + return true; + } + return false; + }, - if (!this.borderDif) { - var b = [prel.css('borderTopWidth'), prel.css('borderRightWidth'), prel.css('borderBottomWidth'), prel.css('borderLeftWidth')], - p = [prel.css('paddingTop'), prel.css('paddingRight'), prel.css('paddingBottom'), prel.css('paddingLeft')]; + /* Retrieve the instance data for the target control. + @param target element - the target input field or division or span + @return object - the associated instance data + @throws error if a jQuery problem getting data */ + _getInst: function(target) { + try { + return $.data(target, PROP_NAME); + } + catch (err) { + throw 'Missing instance data for this datepicker'; + } + }, - this.borderDif = $.map(b, function(v, i) { - var border = parseInt(v,10)||0, padding = parseInt(p[i],10)||0; - return border + padding; - }); + /* Update or retrieve the settings for a date picker attached to an input field or division. + @param target element - the target input field or division or span + @param name object - the new settings to update or + string - the name of the setting to change or retrieve, + when retrieving also 'all' for all instance settings or + 'defaults' for all global defaults + @param value any - the new value for the setting + (omit if above is an object or to retrieve a value) */ + _optionDatepicker: function(target, name, value) { + var inst = this._getInst(target); + if (arguments.length == 2 && typeof name == 'string') { + return (name == 'defaults' ? $.extend({}, $.datepicker._defaults) : + (inst ? (name == 'all' ? $.extend({}, inst.settings) : + this._get(inst, name)) : null)); + } + var settings = name || {}; + if (typeof name == 'string') { + settings = {}; + settings[name] = value; + } + if (inst) { + if (this._curInst == inst) { + this._hideDatepicker(); } - - if ($.browser.msie && !(!($(element).is(':hidden') || $(element).parents(':hidden').length))) - continue; - - prel.css({ - height: (element.height() - this.borderDif[0] - this.borderDif[2]) || 0, - width: (element.width() - this.borderDif[1] - this.borderDif[3]) || 0 - }); - - }; - + var date = this._getDateDatepicker(target, true); + var minDate = this._getMinMaxDate(inst, 'min'); + var maxDate = this._getMinMaxDate(inst, 'max'); + extendRemove(inst.settings, settings); + // reformat the old minDate/maxDate values if dateFormat changes and a new minDate/maxDate isn't provided + if (minDate !== null && settings['dateFormat'] !== undefined && settings['minDate'] === undefined) + inst.settings.minDate = this._formatDate(inst, minDate); + if (maxDate !== null && settings['dateFormat'] !== undefined && settings['maxDate'] === undefined) + inst.settings.maxDate = this._formatDate(inst, maxDate); + this._attachments($(target), inst); + this._autoSize(inst); + this._setDate(inst, date); + this._updateAlternate(inst); + this._updateDatepicker(inst); + } }, - _renderProxy: function() { - - var el = this.element, o = this.options; - this.elementOffset = el.offset(); - - if(this._helper) { - - this.helper = this.helper || $('
    '); - - // fix ie6 offset TODO: This seems broken - var ie6 = $.browser.msie && $.browser.version < 7, ie6offset = (ie6 ? 1 : 0), - pxyoffset = ( ie6 ? 2 : -1 ); - - this.helper.addClass(this._helper).css({ - width: this.element.outerWidth() + pxyoffset, - height: this.element.outerHeight() + pxyoffset, - position: 'absolute', - left: this.elementOffset.left - ie6offset +'px', - top: this.elementOffset.top - ie6offset +'px', - zIndex: ++o.zIndex //TODO: Don't modify option - }); - - this.helper - .appendTo("body") - .disableSelection(); + // change method deprecated + _changeDatepicker: function(target, name, value) { + this._optionDatepicker(target, name, value); + }, - } else { - this.helper = this.element; + /* Redraw the date picker attached to an input field or division. + @param target element - the target input field or division or span */ + _refreshDatepicker: function(target) { + var inst = this._getInst(target); + if (inst) { + this._updateDatepicker(inst); } - }, - _change: { - e: function(event, dx, dy) { - return { width: this.originalSize.width + dx }; - }, - w: function(event, dx, dy) { - var o = this.options, cs = this.originalSize, sp = this.originalPosition; - return { left: sp.left + dx, width: cs.width - dx }; - }, - n: function(event, dx, dy) { - var o = this.options, cs = this.originalSize, sp = this.originalPosition; - return { top: sp.top + dy, height: cs.height - dy }; - }, - s: function(event, dx, dy) { - return { height: this.originalSize.height + dy }; - }, - se: function(event, dx, dy) { - return $.extend(this._change.s.apply(this, arguments), this._change.e.apply(this, [event, dx, dy])); - }, - sw: function(event, dx, dy) { - return $.extend(this._change.s.apply(this, arguments), this._change.w.apply(this, [event, dx, dy])); - }, - ne: function(event, dx, dy) { - return $.extend(this._change.n.apply(this, arguments), this._change.e.apply(this, [event, dx, dy])); - }, - nw: function(event, dx, dy) { - return $.extend(this._change.n.apply(this, arguments), this._change.w.apply(this, [event, dx, dy])); + /* Set the dates for a jQuery selection. + @param target element - the target input field or division or span + @param date Date - the new date */ + _setDateDatepicker: function(target, date) { + var inst = this._getInst(target); + if (inst) { + this._setDate(inst, date); + this._updateDatepicker(inst); + this._updateAlternate(inst); } }, - _propagate: function(n, event) { - $.ui.plugin.call(this, n, [event, this.ui()]); - (n != "resize" && this._trigger(n, event, this.ui())); + /* Get the date(s) for the first entry in a jQuery selection. + @param target element - the target input field or division or span + @param noDefault boolean - true if no default date is to be used + @return Date - the current date */ + _getDateDatepicker: function(target, noDefault) { + var inst = this._getInst(target); + if (inst && !inst.inline) + this._setDateFromField(inst, noDefault); + return (inst ? this._getDate(inst) : null); }, - plugins: {}, - - ui: function() { - return { - originalElement: this.originalElement, - element: this.element, - helper: this.helper, - position: this.position, - size: this.size, - originalSize: this.originalSize, - originalPosition: this.originalPosition - }; - } - -}); - -$.extend($.ui.resizable, { - version: "1.8.16" -}); - -/* - * Resizable Extensions - */ - -$.ui.plugin.add("resizable", "alsoResize", { + /* Handle keystrokes. */ + _doKeyDown: function(event) { + var inst = $.datepicker._getInst(event.target); + var handled = true; + var isRTL = inst.dpDiv.is('.ui-datepicker-rtl'); + inst._keyEvent = true; + if ($.datepicker._datepickerShowing) + switch (event.keyCode) { + case 9: $.datepicker._hideDatepicker(); + handled = false; + break; // hide on tab out + case 13: var sel = $('td.' + $.datepicker._dayOverClass + ':not(.' + + $.datepicker._currentClass + ')', inst.dpDiv); + if (sel[0]) + $.datepicker._selectDay(event.target, inst.selectedMonth, inst.selectedYear, sel[0]); + var onSelect = $.datepicker._get(inst, 'onSelect'); + if (onSelect) { + var dateStr = $.datepicker._formatDate(inst); - start: function (event, ui) { - var self = $(this).data("resizable"), o = self.options; - - var _store = function (exp) { - $(exp).each(function() { - var el = $(this); - el.data("resizable-alsoresize", { - width: parseInt(el.width(), 10), height: parseInt(el.height(), 10), - left: parseInt(el.css('left'), 10), top: parseInt(el.css('top'), 10), - position: el.css('position') // to reset Opera on stop() - }); - }); - }; - - if (typeof(o.alsoResize) == 'object' && !o.alsoResize.parentNode) { - if (o.alsoResize.length) { o.alsoResize = o.alsoResize[0]; _store(o.alsoResize); } - else { $.each(o.alsoResize, function (exp) { _store(exp); }); } - }else{ - _store(o.alsoResize); + // trigger custom callback + onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]); + } + else + $.datepicker._hideDatepicker(); + return false; // don't submit the form + break; // select the value on enter + case 27: $.datepicker._hideDatepicker(); + break; // hide on escape + case 33: $.datepicker._adjustDate(event.target, (event.ctrlKey ? + -$.datepicker._get(inst, 'stepBigMonths') : + -$.datepicker._get(inst, 'stepMonths')), 'M'); + break; // previous month/year on page up/+ ctrl + case 34: $.datepicker._adjustDate(event.target, (event.ctrlKey ? + +$.datepicker._get(inst, 'stepBigMonths') : + +$.datepicker._get(inst, 'stepMonths')), 'M'); + break; // next month/year on page down/+ ctrl + case 35: if (event.ctrlKey || event.metaKey) $.datepicker._clearDate(event.target); + handled = event.ctrlKey || event.metaKey; + break; // clear on ctrl or command +end + case 36: if (event.ctrlKey || event.metaKey) $.datepicker._gotoToday(event.target); + handled = event.ctrlKey || event.metaKey; + break; // current on ctrl or command +home + case 37: if (event.ctrlKey || event.metaKey) $.datepicker._adjustDate(event.target, (isRTL ? +1 : -1), 'D'); + handled = event.ctrlKey || event.metaKey; + // -1 day on ctrl or command +left + if (event.originalEvent.altKey) $.datepicker._adjustDate(event.target, (event.ctrlKey ? + -$.datepicker._get(inst, 'stepBigMonths') : + -$.datepicker._get(inst, 'stepMonths')), 'M'); + // next month/year on alt +left on Mac + break; + case 38: if (event.ctrlKey || event.metaKey) $.datepicker._adjustDate(event.target, -7, 'D'); + handled = event.ctrlKey || event.metaKey; + break; // -1 week on ctrl or command +up + case 39: if (event.ctrlKey || event.metaKey) $.datepicker._adjustDate(event.target, (isRTL ? -1 : +1), 'D'); + handled = event.ctrlKey || event.metaKey; + // +1 day on ctrl or command +right + if (event.originalEvent.altKey) $.datepicker._adjustDate(event.target, (event.ctrlKey ? + +$.datepicker._get(inst, 'stepBigMonths') : + +$.datepicker._get(inst, 'stepMonths')), 'M'); + // next month/year on alt +right + break; + case 40: if (event.ctrlKey || event.metaKey) $.datepicker._adjustDate(event.target, +7, 'D'); + handled = event.ctrlKey || event.metaKey; + break; // +1 week on ctrl or command +down + default: handled = false; + } + else if (event.keyCode == 36 && event.ctrlKey) // display the date picker on ctrl+home + $.datepicker._showDatepicker(this); + else { + handled = false; } - }, - - resize: function (event, ui) { - var self = $(this).data("resizable"), o = self.options, os = self.originalSize, op = self.originalPosition; - - var delta = { - height: (self.size.height - os.height) || 0, width: (self.size.width - os.width) || 0, - top: (self.position.top - op.top) || 0, left: (self.position.left - op.left) || 0 - }, - - _alsoResize = function (exp, c) { - $(exp).each(function() { - var el = $(this), start = $(this).data("resizable-alsoresize"), style = {}, - css = c && c.length ? c : el.parents(ui.originalElement[0]).length ? ['width', 'height'] : ['width', 'height', 'top', 'left']; - - $.each(css, function (i, prop) { - var sum = (start[prop]||0) + (delta[prop]||0); - if (sum && sum >= 0) - style[prop] = sum || null; - }); - - // Opera fixing relative position - if ($.browser.opera && /relative/.test(el.css('position'))) { - self._revertToRelativePosition = true; - el.css({ position: 'absolute', top: 'auto', left: 'auto' }); - } - - el.css(style); - }); - }; - - if (typeof(o.alsoResize) == 'object' && !o.alsoResize.nodeType) { - $.each(o.alsoResize, function (exp, c) { _alsoResize(exp, c); }); - }else{ - _alsoResize(o.alsoResize); + if (handled) { + event.preventDefault(); + event.stopPropagation(); } }, - stop: function (event, ui) { - var self = $(this).data("resizable"), o = self.options; - - var _reset = function (exp) { - $(exp).each(function() { - var el = $(this); - // reset position for Opera - no need to verify it was changed - el.css({ position: el.data("resizable-alsoresize").position }); - }); - }; - - if (self._revertToRelativePosition) { - self._revertToRelativePosition = false; - if (typeof(o.alsoResize) == 'object' && !o.alsoResize.nodeType) { - $.each(o.alsoResize, function (exp) { _reset(exp); }); - }else{ - _reset(o.alsoResize); - } + /* Filter entered characters - based on date format. */ + _doKeyPress: function(event) { + var inst = $.datepicker._getInst(event.target); + if ($.datepicker._get(inst, 'constrainInput')) { + var chars = $.datepicker._possibleChars($.datepicker._get(inst, 'dateFormat')); + var chr = String.fromCharCode(event.charCode == undefined ? event.keyCode : event.charCode); + return event.ctrlKey || event.metaKey || (chr < ' ' || !chars || chars.indexOf(chr) > -1); } + }, - $(this).removeData("resizable-alsoresize"); - } -}); - -$.ui.plugin.add("resizable", "animate", { - - stop: function(event, ui) { - var self = $(this).data("resizable"), o = self.options; - - var pr = self._proportionallyResizeElements, ista = pr.length && (/textarea/i).test(pr[0].nodeName), - soffseth = ista && $.ui.hasScroll(pr[0], 'left') /* TODO - jump height */ ? 0 : self.sizeDiff.height, - soffsetw = ista ? 0 : self.sizeDiff.width; - - var style = { width: (self.size.width - soffsetw), height: (self.size.height - soffseth) }, - left = (parseInt(self.element.css('left'), 10) + (self.position.left - self.originalPosition.left)) || null, - top = (parseInt(self.element.css('top'), 10) + (self.position.top - self.originalPosition.top)) || null; - - self.element.animate( - $.extend(style, top && left ? { top: top, left: left } : {}), { - duration: o.animateDuration, - easing: o.animateEasing, - step: function() { - - var data = { - width: parseInt(self.element.css('width'), 10), - height: parseInt(self.element.css('height'), 10), - top: parseInt(self.element.css('top'), 10), - left: parseInt(self.element.css('left'), 10) - }; - - if (pr && pr.length) $(pr[0]).css({ width: data.width, height: data.height }); - - // propagating resize, and updating values for each animation step - self._updateCache(data); - self._propagate("resize", event); - + /* Synchronise manual entry and field/alternate field. */ + _doKeyUp: function(event) { + var inst = $.datepicker._getInst(event.target); + if (inst.input.val() != inst.lastVal) { + try { + var date = $.datepicker.parseDate($.datepicker._get(inst, 'dateFormat'), + (inst.input ? inst.input.val() : null), + $.datepicker._getFormatConfig(inst)); + if (date) { // only if valid + $.datepicker._setDateFromField(inst); + $.datepicker._updateAlternate(inst); + $.datepicker._updateDatepicker(inst); } } - ); - } - -}); - -$.ui.plugin.add("resizable", "containment", { - - start: function(event, ui) { - var self = $(this).data("resizable"), o = self.options, el = self.element; - var oc = o.containment, ce = (oc instanceof $) ? oc.get(0) : (/parent/.test(oc)) ? el.parent().get(0) : oc; - if (!ce) return; - - self.containerElement = $(ce); - - if (/document/.test(oc) || oc == document) { - self.containerOffset = { left: 0, top: 0 }; - self.containerPosition = { left: 0, top: 0 }; - - self.parentData = { - element: $(document), left: 0, top: 0, - width: $(document).width(), height: $(document).height() || document.body.parentNode.scrollHeight - }; - } - - // i'm a node, so compute top, left, right, bottom - else { - var element = $(ce), p = []; - $([ "Top", "Right", "Left", "Bottom" ]).each(function(i, name) { p[i] = num(element.css("padding" + name)); }); - - self.containerOffset = element.offset(); - self.containerPosition = element.position(); - self.containerSize = { height: (element.innerHeight() - p[3]), width: (element.innerWidth() - p[1]) }; - - var co = self.containerOffset, ch = self.containerSize.height, cw = self.containerSize.width, - width = ($.ui.hasScroll(ce, "left") ? ce.scrollWidth : cw ), height = ($.ui.hasScroll(ce) ? ce.scrollHeight : ch); - - self.parentData = { - element: ce, left: co.left, top: co.top, width: width, height: height - }; + catch (err) { + $.datepicker.log(err); + } } + return true; }, - resize: function(event, ui) { - var self = $(this).data("resizable"), o = self.options, - ps = self.containerSize, co = self.containerOffset, cs = self.size, cp = self.position, - pRatio = self._aspectRatio || event.shiftKey, cop = { top:0, left:0 }, ce = self.containerElement; - - if (ce[0] != document && (/static/).test(ce.css('position'))) cop = co; - - if (cp.left < (self._helper ? co.left : 0)) { - self.size.width = self.size.width + (self._helper ? (self.position.left - co.left) : (self.position.left - cop.left)); - if (pRatio) self.size.height = self.size.width / o.aspectRatio; - self.position.left = o.helper ? co.left : 0; + /* Pop-up the date picker for a given input field. + If false returned from beforeShow event handler do not show. + @param input element - the input field attached to the date picker or + event - if triggered by focus */ + _showDatepicker: function(input) { + input = input.target || input; + if (input.nodeName.toLowerCase() != 'input') // find from button/image trigger + input = $('input', input.parentNode)[0]; + if ($.datepicker._isDisabledDatepicker(input) || $.datepicker._lastInput == input) // already here + return; + var inst = $.datepicker._getInst(input); + if ($.datepicker._curInst && $.datepicker._curInst != inst) { + $.datepicker._curInst.dpDiv.stop(true, true); + if ( inst && $.datepicker._datepickerShowing ) { + $.datepicker._hideDatepicker( $.datepicker._curInst.input[0] ); + } } - - if (cp.top < (self._helper ? co.top : 0)) { - self.size.height = self.size.height + (self._helper ? (self.position.top - co.top) : self.position.top); - if (pRatio) self.size.width = self.size.height * o.aspectRatio; - self.position.top = self._helper ? co.top : 0; + var beforeShow = $.datepicker._get(inst, 'beforeShow'); + var beforeShowSettings = beforeShow ? beforeShow.apply(input, [input, inst]) : {}; + if(beforeShowSettings === false){ + //false + return; } - - self.offset.left = self.parentData.left+self.position.left; - self.offset.top = self.parentData.top+self.position.top; - - var woset = Math.abs( (self._helper ? self.offset.left - cop.left : (self.offset.left - cop.left)) + self.sizeDiff.width ), - hoset = Math.abs( (self._helper ? self.offset.top - cop.top : (self.offset.top - co.top)) + self.sizeDiff.height ); - - var isParent = self.containerElement.get(0) == self.element.parent().get(0), - isOffsetRelative = /relative|absolute/.test(self.containerElement.css('position')); - - if(isParent && isOffsetRelative) woset -= self.parentData.left; - - if (woset + self.size.width >= self.parentData.width) { - self.size.width = self.parentData.width - woset; - if (pRatio) self.size.height = self.size.width / self.aspectRatio; + extendRemove(inst.settings, beforeShowSettings); + inst.lastVal = null; + $.datepicker._lastInput = input; + $.datepicker._setDateFromField(inst); + if ($.datepicker._inDialog) // hide cursor + input.value = ''; + if (!$.datepicker._pos) { // position below input + $.datepicker._pos = $.datepicker._findPos(input); + $.datepicker._pos[1] += input.offsetHeight; // add the height } + var isFixed = false; + $(input).parents().each(function() { + isFixed |= $(this).css('position') == 'fixed'; + return !isFixed; + }); + var offset = {left: $.datepicker._pos[0], top: $.datepicker._pos[1]}; + $.datepicker._pos = null; + //to avoid flashes on Firefox + inst.dpDiv.empty(); + // determine sizing offscreen + inst.dpDiv.css({position: 'absolute', display: 'block', top: '-1000px'}); + $.datepicker._updateDatepicker(inst); + // fix width for dynamic number of date pickers + // and adjust position before showing + offset = $.datepicker._checkOffset(inst, offset, isFixed); + inst.dpDiv.css({position: ($.datepicker._inDialog && $.blockUI ? + 'static' : (isFixed ? 'fixed' : 'absolute')), display: 'none', + left: offset.left + 'px', top: offset.top + 'px'}); + if (!inst.inline) { + var showAnim = $.datepicker._get(inst, 'showAnim'); + var duration = $.datepicker._get(inst, 'duration'); + var postProcess = function() { + var cover = inst.dpDiv.find('iframe.ui-datepicker-cover'); // IE6- only + if( !! cover.length ){ + var borders = $.datepicker._getBorders(inst.dpDiv); + cover.css({left: -borders[0], top: -borders[1], + width: inst.dpDiv.outerWidth(), height: inst.dpDiv.outerHeight()}); + } + }; + inst.dpDiv.zIndex($(input).zIndex()+1); + $.datepicker._datepickerShowing = true; - if (hoset + self.size.height >= self.parentData.height) { - self.size.height = self.parentData.height - hoset; - if (pRatio) self.size.width = self.size.height * self.aspectRatio; + // DEPRECATED: after BC for 1.8.x $.effects[ showAnim ] is not needed + if ( $.effects && ( $.effects.effect[ showAnim ] || $.effects[ showAnim ] ) ) + inst.dpDiv.show(showAnim, $.datepicker._get(inst, 'showOptions'), duration, postProcess); + else + inst.dpDiv[showAnim || 'show']((showAnim ? duration : null), postProcess); + if (!showAnim || !duration) + postProcess(); + if (inst.input.is(':visible') && !inst.input.is(':disabled')) + inst.input.focus(); + $.datepicker._curInst = inst; } }, - stop: function(event, ui){ - var self = $(this).data("resizable"), o = self.options, cp = self.position, - co = self.containerOffset, cop = self.containerPosition, ce = self.containerElement; - - var helper = $(self.helper), ho = helper.offset(), w = helper.outerWidth() - self.sizeDiff.width, h = helper.outerHeight() - self.sizeDiff.height; - - if (self._helper && !o.animate && (/relative/).test(ce.css('position'))) - $(this).css({ left: ho.left - cop.left - co.left, width: w, height: h }); + /* Generate the date picker content. */ + _updateDatepicker: function(inst) { + this.maxRows = 4; //Reset the max number of rows being displayed (see #7043) + var borders = $.datepicker._getBorders(inst.dpDiv); + instActive = inst; // for delegate hover events + inst.dpDiv.empty().append(this._generateHTML(inst)); + this._attachHandlers(inst); + var cover = inst.dpDiv.find('iframe.ui-datepicker-cover'); // IE6- only + if( !!cover.length ){ //avoid call to outerXXXX() when not in IE6 + cover.css({left: -borders[0], top: -borders[1], width: inst.dpDiv.outerWidth(), height: inst.dpDiv.outerHeight()}) + } + inst.dpDiv.find('.' + this._dayOverClass + ' a').mouseover(); + var numMonths = this._getNumberOfMonths(inst); + var cols = numMonths[1]; + var width = 17; + inst.dpDiv.removeClass('ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4').width(''); + if (cols > 1) + inst.dpDiv.addClass('ui-datepicker-multi-' + cols).css('width', (width * cols) + 'em'); + inst.dpDiv[(numMonths[0] != 1 || numMonths[1] != 1 ? 'add' : 'remove') + + 'Class']('ui-datepicker-multi'); + inst.dpDiv[(this._get(inst, 'isRTL') ? 'add' : 'remove') + + 'Class']('ui-datepicker-rtl'); + if (inst == $.datepicker._curInst && $.datepicker._datepickerShowing && inst.input && + // #6694 - don't focus the input if it's already focused + // this breaks the change event in IE + inst.input.is(':visible') && !inst.input.is(':disabled') && inst.input[0] != document.activeElement) + inst.input.focus(); + // deffered render of the years select (to avoid flashes on Firefox) + if( inst.yearshtml ){ + var origyearshtml = inst.yearshtml; + setTimeout(function(){ + //assure that inst.yearshtml didn't change. + if( origyearshtml === inst.yearshtml && inst.yearshtml ){ + inst.dpDiv.find('select.ui-datepicker-year:first').replaceWith(inst.yearshtml); + } + origyearshtml = inst.yearshtml = null; + }, 0); + } + }, - if (self._helper && !o.animate && (/static/).test(ce.css('position'))) - $(this).css({ left: ho.left - cop.left - co.left, width: w, height: h }); + /* Retrieve the size of left and top borders for an element. + @param elem (jQuery object) the element of interest + @return (number[2]) the left and top borders */ + _getBorders: function(elem) { + var convert = function(value) { + return {thin: 1, medium: 2, thick: 3}[value] || value; + }; + return [parseFloat(convert(elem.css('border-left-width'))), + parseFloat(convert(elem.css('border-top-width')))]; + }, - } -}); + /* Check positioning to remain on screen. */ + _checkOffset: function(inst, offset, isFixed) { + var dpWidth = inst.dpDiv.outerWidth(); + var dpHeight = inst.dpDiv.outerHeight(); + var inputWidth = inst.input ? inst.input.outerWidth() : 0; + var inputHeight = inst.input ? inst.input.outerHeight() : 0; + var viewWidth = document.documentElement.clientWidth + (isFixed ? 0 : $(document).scrollLeft()); + var viewHeight = document.documentElement.clientHeight + (isFixed ? 0 : $(document).scrollTop()); -$.ui.plugin.add("resizable", "ghost", { + offset.left -= (this._get(inst, 'isRTL') ? (dpWidth - inputWidth) : 0); + offset.left -= (isFixed && offset.left == inst.input.offset().left) ? $(document).scrollLeft() : 0; + offset.top -= (isFixed && offset.top == (inst.input.offset().top + inputHeight)) ? $(document).scrollTop() : 0; - start: function(event, ui) { + // now check if datepicker is showing outside window viewport - move to a better place if so. + offset.left -= Math.min(offset.left, (offset.left + dpWidth > viewWidth && viewWidth > dpWidth) ? + Math.abs(offset.left + dpWidth - viewWidth) : 0); + offset.top -= Math.min(offset.top, (offset.top + dpHeight > viewHeight && viewHeight > dpHeight) ? + Math.abs(dpHeight + inputHeight) : 0); - var self = $(this).data("resizable"), o = self.options, cs = self.size; + return offset; + }, - self.ghost = self.originalElement.clone(); - self.ghost - .css({ opacity: .25, display: 'block', position: 'relative', height: cs.height, width: cs.width, margin: 0, left: 0, top: 0 }) - .addClass('ui-resizable-ghost') - .addClass(typeof o.ghost == 'string' ? o.ghost : ''); + /* Find an object's position on the screen. */ + _findPos: function(obj) { + var inst = this._getInst(obj); + var isRTL = this._get(inst, 'isRTL'); + while (obj && (obj.type == 'hidden' || obj.nodeType != 1 || $.expr.filters.hidden(obj))) { + obj = obj[isRTL ? 'previousSibling' : 'nextSibling']; + } + var position = $(obj).offset(); + return [position.left, position.top]; + }, - self.ghost.appendTo(self.helper); + /* Hide the date picker from view. + @param input element - the input field attached to the date picker */ + _hideDatepicker: function(input) { + var inst = this._curInst; + if (!inst || (input && inst != $.data(input, PROP_NAME))) + return; + if (this._datepickerShowing) { + var showAnim = this._get(inst, 'showAnim'); + var duration = this._get(inst, 'duration'); + var postProcess = function() { + $.datepicker._tidyDialog(inst); + }; + // DEPRECATED: after BC for 1.8.x $.effects[ showAnim ] is not needed + if ( $.effects && ( $.effects.effect[ showAnim ] || $.effects[ showAnim ] ) ) + inst.dpDiv.hide(showAnim, $.datepicker._get(inst, 'showOptions'), duration, postProcess); + else + inst.dpDiv[(showAnim == 'slideDown' ? 'slideUp' : + (showAnim == 'fadeIn' ? 'fadeOut' : 'hide'))]((showAnim ? duration : null), postProcess); + if (!showAnim) + postProcess(); + this._datepickerShowing = false; + var onClose = this._get(inst, 'onClose'); + if (onClose) + onClose.apply((inst.input ? inst.input[0] : null), + [(inst.input ? inst.input.val() : ''), inst]); + this._lastInput = null; + if (this._inDialog) { + this._dialogInput.css({ position: 'absolute', left: '0', top: '-100px' }); + if ($.blockUI) { + $.unblockUI(); + $('body').append(this.dpDiv); + } + } + this._inDialog = false; + } }, - resize: function(event, ui){ - var self = $(this).data("resizable"), o = self.options; - if (self.ghost) self.ghost.css({ position: 'relative', height: self.size.height, width: self.size.width }); + /* Tidy up after a dialog display. */ + _tidyDialog: function(inst) { + inst.dpDiv.removeClass(this._dialogClass).unbind('.ui-datepicker-calendar'); }, - stop: function(event, ui){ - var self = $(this).data("resizable"), o = self.options; - if (self.ghost && self.helper) self.helper.get(0).removeChild(self.ghost.get(0)); - } - -}); + /* Close date picker if clicked elsewhere. */ + _checkExternalClick: function(event) { + if (!$.datepicker._curInst) + return; -$.ui.plugin.add("resizable", "grid", { + var $target = $(event.target), + inst = $.datepicker._getInst($target[0]); - resize: function(event, ui) { - var self = $(this).data("resizable"), o = self.options, cs = self.size, os = self.originalSize, op = self.originalPosition, a = self.axis, ratio = o._aspectRatio || event.shiftKey; - o.grid = typeof o.grid == "number" ? [o.grid, o.grid] : o.grid; - var ox = Math.round((cs.width - os.width) / (o.grid[0]||1)) * (o.grid[0]||1), oy = Math.round((cs.height - os.height) / (o.grid[1]||1)) * (o.grid[1]||1); + if ( ( ( $target[0].id != $.datepicker._mainDivId && + $target.parents('#' + $.datepicker._mainDivId).length == 0 && + !$target.hasClass($.datepicker.markerClassName) && + !$target.closest("." + $.datepicker._triggerClass).length && + $.datepicker._datepickerShowing && !($.datepicker._inDialog && $.blockUI) ) ) || + ( $target.hasClass($.datepicker.markerClassName) && $.datepicker._curInst != inst ) ) + $.datepicker._hideDatepicker(); + }, - if (/^(se|s|e)$/.test(a)) { - self.size.width = os.width + ox; - self.size.height = os.height + oy; - } - else if (/^(ne)$/.test(a)) { - self.size.width = os.width + ox; - self.size.height = os.height + oy; - self.position.top = op.top - oy; + /* Adjust one of the date sub-fields. */ + _adjustDate: function(id, offset, period) { + var target = $(id); + var inst = this._getInst(target[0]); + if (this._isDisabledDatepicker(target[0])) { + return; } - else if (/^(sw)$/.test(a)) { - self.size.width = os.width + ox; - self.size.height = os.height + oy; - self.position.left = op.left - ox; + this._adjustInstDate(inst, offset + + (period == 'M' ? this._get(inst, 'showCurrentAtPos') : 0), // undo positioning + period); + this._updateDatepicker(inst); + }, + + /* Action for current link. */ + _gotoToday: function(id) { + var target = $(id); + var inst = this._getInst(target[0]); + if (this._get(inst, 'gotoCurrent') && inst.currentDay) { + inst.selectedDay = inst.currentDay; + inst.drawMonth = inst.selectedMonth = inst.currentMonth; + inst.drawYear = inst.selectedYear = inst.currentYear; } else { - self.size.width = os.width + ox; - self.size.height = os.height + oy; - self.position.top = op.top - oy; - self.position.left = op.left - ox; + var date = new Date(); + inst.selectedDay = date.getDate(); + inst.drawMonth = inst.selectedMonth = date.getMonth(); + inst.drawYear = inst.selectedYear = date.getFullYear(); } - } - -}); + this._notifyChange(inst); + this._adjustDate(target); + }, -var num = function(v) { - return parseInt(v, 10) || 0; -}; + /* Action for selecting a new month/year. */ + _selectMonthYear: function(id, select, period) { + var target = $(id); + var inst = this._getInst(target[0]); + inst['selected' + (period == 'M' ? 'Month' : 'Year')] = + inst['draw' + (period == 'M' ? 'Month' : 'Year')] = + parseInt(select.options[select.selectedIndex].value,10); + this._notifyChange(inst); + this._adjustDate(target); + }, -var isNumber = function(value) { - return !isNaN(parseInt(value, 10)); -}; + /* Action for selecting a day. */ + _selectDay: function(id, month, year, td) { + var target = $(id); + if ($(td).hasClass(this._unselectableClass) || this._isDisabledDatepicker(target[0])) { + return; + } + var inst = this._getInst(target[0]); + inst.selectedDay = inst.currentDay = $('a', td).html(); + inst.selectedMonth = inst.currentMonth = month; + inst.selectedYear = inst.currentYear = year; + this._selectDate(id, this._formatDate(inst, + inst.currentDay, inst.currentMonth, inst.currentYear)); + }, -})(jQuery); -/* - * jQuery UI Selectable 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Selectables - * - * Depends: - * jquery.ui.core.js - * jquery.ui.mouse.js - * jquery.ui.widget.js - */ -(function( $, undefined ) { + /* Erase the input field and hide the date picker. */ + _clearDate: function(id) { + var target = $(id); + var inst = this._getInst(target[0]); + this._selectDate(target, ''); + }, -$.widget("ui.selectable", $.ui.mouse, { - options: { - appendTo: 'body', - autoRefresh: true, - distance: 0, - filter: '*', - tolerance: 'touch' + /* Update the input field with the selected date. */ + _selectDate: function(id, dateStr) { + var target = $(id); + var inst = this._getInst(target[0]); + dateStr = (dateStr != null ? dateStr : this._formatDate(inst)); + if (inst.input) + inst.input.val(dateStr); + this._updateAlternate(inst); + var onSelect = this._get(inst, 'onSelect'); + if (onSelect) + onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]); // trigger custom callback + else if (inst.input) + inst.input.trigger('change'); // fire the change event + if (inst.inline) + this._updateDatepicker(inst); + else { + this._hideDatepicker(); + this._lastInput = inst.input[0]; + if (typeof(inst.input[0]) != 'object') + inst.input.focus(); // restore focus + this._lastInput = null; + } }, - _create: function() { - var self = this; - this.element.addClass("ui-selectable"); + /* Update any alternate field to synchronise with the main field. */ + _updateAlternate: function(inst) { + var altField = this._get(inst, 'altField'); + if (altField) { // update alternate field too + var altFormat = this._get(inst, 'altFormat') || this._get(inst, 'dateFormat'); + var date = this._getDate(inst); + var dateStr = this.formatDate(altFormat, date, this._getFormatConfig(inst)); + $(altField).each(function() { $(this).val(dateStr); }); + } + }, - this.dragged = false; + /* Set as beforeShowDay function to prevent selection of weekends. + @param date Date - the date to customise + @return [boolean, string] - is this date selectable?, what is its CSS class? */ + noWeekends: function(date) { + var day = date.getDay(); + return [(day > 0 && day < 6), '']; + }, - // cache selectee children based on filter - var selectees; - this.refresh = function() { - selectees = $(self.options.filter, self.element[0]); - selectees.each(function() { - var $this = $(this); - var pos = $this.offset(); - $.data(this, "selectable-item", { - element: this, - $element: $this, - left: pos.left, - top: pos.top, - right: pos.left + $this.outerWidth(), - bottom: pos.top + $this.outerHeight(), - startselected: false, - selected: $this.hasClass('ui-selected'), - selecting: $this.hasClass('ui-selecting'), - unselecting: $this.hasClass('ui-unselecting') - }); + /* Set as calculateWeek to determine the week of the year based on the ISO 8601 definition. + @param date Date - the date to get the week for + @return number - the number of the week within the year that contains this date */ + iso8601Week: function(date) { + var checkDate = new Date(date.getTime()); + // Find Thursday of this week starting on Monday + checkDate.setDate(checkDate.getDate() + 4 - (checkDate.getDay() || 7)); + var time = checkDate.getTime(); + checkDate.setMonth(0); // Compare with Jan 1 + checkDate.setDate(1); + return Math.floor(Math.round((time - checkDate) / 86400000) / 7) + 1; + }, + + /* Parse a string value into a date object. + See formatDate below for the possible formats. + + @param format string - the expected format of the date + @param value string - the date in the above format + @param settings Object - attributes include: + shortYearCutoff number - the cutoff year for determining the century (optional) + dayNamesShort string[7] - abbreviated names of the days from Sunday (optional) + dayNames string[7] - names of the days from Sunday (optional) + monthNamesShort string[12] - abbreviated names of the months (optional) + monthNames string[12] - names of the months (optional) + @return Date - the extracted date value or null if value is blank */ + parseDate: function (format, value, settings) { + if (format == null || value == null) + throw 'Invalid arguments'; + value = (typeof value == 'object' ? value.toString() : value + ''); + if (value == '') + return null; + var shortYearCutoff = (settings ? settings.shortYearCutoff : null) || this._defaults.shortYearCutoff; + shortYearCutoff = (typeof shortYearCutoff != 'string' ? shortYearCutoff : + new Date().getFullYear() % 100 + parseInt(shortYearCutoff, 10)); + var dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort; + var dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames; + var monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort; + var monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames; + var year = -1; + var month = -1; + var day = -1; + var doy = -1; + var literal = false; + // Check whether a format character is doubled + var lookAhead = function(match) { + var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) == match); + if (matches) + iFormat++; + return matches; + }; + // Extract a number from the string value + var getNumber = function(match) { + var isDoubled = lookAhead(match); + var size = (match == '@' ? 14 : (match == '!' ? 20 : + (match == 'y' && isDoubled ? 4 : (match == 'o' ? 3 : 2)))); + var digits = new RegExp('^\\d{1,' + size + '}'); + var num = value.substring(iValue).match(digits); + if (!num) + throw 'Missing number at position ' + iValue; + iValue += num[0].length; + return parseInt(num[0], 10); + }; + // Extract a name from the string value and convert to an index + var getName = function(match, shortNames, longNames) { + var names = $.map(lookAhead(match) ? longNames : shortNames, function (v, k) { + return [ [k, v] ]; + }).sort(function (a, b) { + return -(a[1].length - b[1].length); + }); + var index = -1; + $.each(names, function (i, pair) { + var name = pair[1]; + if (value.substr(iValue, name.length).toLowerCase() == name.toLowerCase()) { + index = pair[0]; + iValue += name.length; + return false; + } + }); + if (index != -1) + return index + 1; + else + throw 'Unknown name at position ' + iValue; + }; + // Confirm that a literal character matches the string value + var checkLiteral = function() { + if (value.charAt(iValue) != format.charAt(iFormat)) + throw 'Unexpected literal at position ' + iValue; + iValue++; + }; + var iValue = 0; + for (var iFormat = 0; iFormat < format.length; iFormat++) { + if (literal) + if (format.charAt(iFormat) == "'" && !lookAhead("'")) + literal = false; + else + checkLiteral(); + else + switch (format.charAt(iFormat)) { + case 'd': + day = getNumber('d'); + break; + case 'D': + getName('D', dayNamesShort, dayNames); + break; + case 'o': + doy = getNumber('o'); + break; + case 'm': + month = getNumber('m'); + break; + case 'M': + month = getName('M', monthNamesShort, monthNames); + break; + case 'y': + year = getNumber('y'); + break; + case '@': + var date = new Date(getNumber('@')); + year = date.getFullYear(); + month = date.getMonth() + 1; + day = date.getDate(); + break; + case '!': + var date = new Date((getNumber('!') - this._ticksTo1970) / 10000); + year = date.getFullYear(); + month = date.getMonth() + 1; + day = date.getDate(); + break; + case "'": + if (lookAhead("'")) + checkLiteral(); + else + literal = true; + break; + default: + checkLiteral(); + } + } + if (iValue < value.length){ + var extra = value.substr(iValue); + if (!/^\s+/.test(extra)) { + throw "Extra/unparsed characters found in date: " + extra; + } + } + if (year == -1) + year = new Date().getFullYear(); + else if (year < 100) + year += new Date().getFullYear() - new Date().getFullYear() % 100 + + (year <= shortYearCutoff ? 0 : -100); + if (doy > -1) { + month = 1; + day = doy; + do { + var dim = this._getDaysInMonth(year, month - 1); + if (day <= dim) + break; + month++; + day -= dim; + } while (true); + } + var date = this._daylightSavingAdjust(new Date(year, month - 1, day)); + if (date.getFullYear() != year || date.getMonth() + 1 != month || date.getDate() != day) + throw 'Invalid date'; // E.g. 31/02/00 + return date; + }, + + /* Standard date formats. */ + ATOM: 'yy-mm-dd', // RFC 3339 (ISO 8601) + COOKIE: 'D, dd M yy', + ISO_8601: 'yy-mm-dd', + RFC_822: 'D, d M y', + RFC_850: 'DD, dd-M-y', + RFC_1036: 'D, d M y', + RFC_1123: 'D, d M yy', + RFC_2822: 'D, d M yy', + RSS: 'D, d M y', // RFC 822 + TICKS: '!', + TIMESTAMP: '@', + W3C: 'yy-mm-dd', // ISO 8601 + + _ticksTo1970: (((1970 - 1) * 365 + Math.floor(1970 / 4) - Math.floor(1970 / 100) + + Math.floor(1970 / 400)) * 24 * 60 * 60 * 10000000), + + /* Format a date object into a string value. + The format can be combinations of the following: + d - day of month (no leading zero) + dd - day of month (two digit) + o - day of year (no leading zeros) + oo - day of year (three digit) + D - day name short + DD - day name long + m - month of year (no leading zero) + mm - month of year (two digit) + M - month name short + MM - month name long + y - year (two digit) + yy - year (four digit) + @ - Unix timestamp (ms since 01/01/1970) + ! - Windows ticks (100ns since 01/01/0001) + '...' - literal text + '' - single quote + + @param format string - the desired format of the date + @param date Date - the date value to format + @param settings Object - attributes include: + dayNamesShort string[7] - abbreviated names of the days from Sunday (optional) + dayNames string[7] - names of the days from Sunday (optional) + monthNamesShort string[12] - abbreviated names of the months (optional) + monthNames string[12] - names of the months (optional) + @return string - the date in the above format */ + formatDate: function (format, date, settings) { + if (!date) + return ''; + var dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort; + var dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames; + var monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort; + var monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames; + // Check whether a format character is doubled + var lookAhead = function(match) { + var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) == match); + if (matches) + iFormat++; + return matches; + }; + // Format a number, with leading zero if necessary + var formatNumber = function(match, value, len) { + var num = '' + value; + if (lookAhead(match)) + while (num.length < len) + num = '0' + num; + return num; + }; + // Format a name, short or long as requested + var formatName = function(match, value, shortNames, longNames) { + return (lookAhead(match) ? longNames[value] : shortNames[value]); + }; + var output = ''; + var literal = false; + if (date) + for (var iFormat = 0; iFormat < format.length; iFormat++) { + if (literal) + if (format.charAt(iFormat) == "'" && !lookAhead("'")) + literal = false; + else + output += format.charAt(iFormat); + else + switch (format.charAt(iFormat)) { + case 'd': + output += formatNumber('d', date.getDate(), 2); + break; + case 'D': + output += formatName('D', date.getDay(), dayNamesShort, dayNames); + break; + case 'o': + output += formatNumber('o', + Math.round((new Date(date.getFullYear(), date.getMonth(), date.getDate()).getTime() - new Date(date.getFullYear(), 0, 0).getTime()) / 86400000), 3); + break; + case 'm': + output += formatNumber('m', date.getMonth() + 1, 2); + break; + case 'M': + output += formatName('M', date.getMonth(), monthNamesShort, monthNames); + break; + case 'y': + output += (lookAhead('y') ? date.getFullYear() : + (date.getYear() % 100 < 10 ? '0' : '') + date.getYear() % 100); + break; + case '@': + output += date.getTime(); + break; + case '!': + output += date.getTime() * 10000 + this._ticksTo1970; + break; + case "'": + if (lookAhead("'")) + output += "'"; + else + literal = true; + break; + default: + output += format.charAt(iFormat); + } + } + return output; + }, + + /* Extract all possible characters from the date format. */ + _possibleChars: function (format) { + var chars = ''; + var literal = false; + // Check whether a format character is doubled + var lookAhead = function(match) { + var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) == match); + if (matches) + iFormat++; + return matches; + }; + for (var iFormat = 0; iFormat < format.length; iFormat++) + if (literal) + if (format.charAt(iFormat) == "'" && !lookAhead("'")) + literal = false; + else + chars += format.charAt(iFormat); + else + switch (format.charAt(iFormat)) { + case 'd': case 'm': case 'y': case '@': + chars += '0123456789'; + break; + case 'D': case 'M': + return null; // Accept anything + case "'": + if (lookAhead("'")) + chars += "'"; + else + literal = true; + break; + default: + chars += format.charAt(iFormat); + } + return chars; + }, + + /* Get a setting value, defaulting if necessary. */ + _get: function(inst, name) { + return inst.settings[name] !== undefined ? + inst.settings[name] : this._defaults[name]; + }, + + /* Parse existing date and initialise date picker. */ + _setDateFromField: function(inst, noDefault) { + if (inst.input.val() == inst.lastVal) { + return; + } + var dateFormat = this._get(inst, 'dateFormat'); + var dates = inst.lastVal = inst.input ? inst.input.val() : null; + var date, defaultDate; + date = defaultDate = this._getDefaultDate(inst); + var settings = this._getFormatConfig(inst); + try { + date = this.parseDate(dateFormat, dates, settings) || defaultDate; + } catch (event) { + this.log(event); + dates = (noDefault ? '' : dates); + } + inst.selectedDay = date.getDate(); + inst.drawMonth = inst.selectedMonth = date.getMonth(); + inst.drawYear = inst.selectedYear = date.getFullYear(); + inst.currentDay = (dates ? date.getDate() : 0); + inst.currentMonth = (dates ? date.getMonth() : 0); + inst.currentYear = (dates ? date.getFullYear() : 0); + this._adjustInstDate(inst); + }, + + /* Retrieve the default date shown on opening. */ + _getDefaultDate: function(inst) { + return this._restrictMinMax(inst, + this._determineDate(inst, this._get(inst, 'defaultDate'), new Date())); + }, + + /* A date may be specified as an exact value or a relative one. */ + _determineDate: function(inst, date, defaultDate) { + var offsetNumeric = function(offset) { + var date = new Date(); + date.setDate(date.getDate() + offset); + return date; + }; + var offsetString = function(offset) { + try { + return $.datepicker.parseDate($.datepicker._get(inst, 'dateFormat'), + offset, $.datepicker._getFormatConfig(inst)); + } + catch (e) { + // Ignore + } + var date = (offset.toLowerCase().match(/^c/) ? + $.datepicker._getDate(inst) : null) || new Date(); + var year = date.getFullYear(); + var month = date.getMonth(); + var day = date.getDate(); + var pattern = /([+-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g; + var matches = pattern.exec(offset); + while (matches) { + switch (matches[2] || 'd') { + case 'd' : case 'D' : + day += parseInt(matches[1],10); break; + case 'w' : case 'W' : + day += parseInt(matches[1],10) * 7; break; + case 'm' : case 'M' : + month += parseInt(matches[1],10); + day = Math.min(day, $.datepicker._getDaysInMonth(year, month)); + break; + case 'y': case 'Y' : + year += parseInt(matches[1],10); + day = Math.min(day, $.datepicker._getDaysInMonth(year, month)); + break; + } + matches = pattern.exec(offset); + } + return new Date(year, month, day); + }; + var newDate = (date == null || date === '' ? defaultDate : (typeof date == 'string' ? offsetString(date) : + (typeof date == 'number' ? (isNaN(date) ? defaultDate : offsetNumeric(date)) : new Date(date.getTime())))); + newDate = (newDate && newDate.toString() == 'Invalid Date' ? defaultDate : newDate); + if (newDate) { + newDate.setHours(0); + newDate.setMinutes(0); + newDate.setSeconds(0); + newDate.setMilliseconds(0); + } + return this._daylightSavingAdjust(newDate); + }, + + /* Handle switch to/from daylight saving. + Hours may be non-zero on daylight saving cut-over: + > 12 when midnight changeover, but then cannot generate + midnight datetime, so jump to 1AM, otherwise reset. + @param date (Date) the date to check + @return (Date) the corrected date */ + _daylightSavingAdjust: function(date) { + if (!date) return null; + date.setHours(date.getHours() > 12 ? date.getHours() + 2 : 0); + return date; + }, + + /* Set the date(s) directly. */ + _setDate: function(inst, date, noChange) { + var clear = !date; + var origMonth = inst.selectedMonth; + var origYear = inst.selectedYear; + var newDate = this._restrictMinMax(inst, this._determineDate(inst, date, new Date())); + inst.selectedDay = inst.currentDay = newDate.getDate(); + inst.drawMonth = inst.selectedMonth = inst.currentMonth = newDate.getMonth(); + inst.drawYear = inst.selectedYear = inst.currentYear = newDate.getFullYear(); + if ((origMonth != inst.selectedMonth || origYear != inst.selectedYear) && !noChange) + this._notifyChange(inst); + this._adjustInstDate(inst); + if (inst.input) { + inst.input.val(clear ? '' : this._formatDate(inst)); + } + }, + + /* Retrieve the date(s) directly. */ + _getDate: function(inst) { + var startDate = (!inst.currentYear || (inst.input && inst.input.val() == '') ? null : + this._daylightSavingAdjust(new Date( + inst.currentYear, inst.currentMonth, inst.currentDay))); + return startDate; + }, + + /* Attach the onxxx handlers. These are declared statically so + * they work with static code transformers like Caja. + */ + _attachHandlers: function(inst) { + var stepMonths = this._get(inst, 'stepMonths'); + var id = '#' + inst.id.replace( /\\\\/g, "\\" ); + inst.dpDiv.find('[data-handler]').map(function () { + var handler = { + prev: function () { + window['DP_jQuery_' + dpuuid].datepicker._adjustDate(id, -stepMonths, 'M'); + }, + next: function () { + window['DP_jQuery_' + dpuuid].datepicker._adjustDate(id, +stepMonths, 'M'); + }, + hide: function () { + window['DP_jQuery_' + dpuuid].datepicker._hideDatepicker(); + }, + today: function () { + window['DP_jQuery_' + dpuuid].datepicker._gotoToday(id); + }, + selectDay: function () { + window['DP_jQuery_' + dpuuid].datepicker._selectDay(id, +this.getAttribute('data-month'), +this.getAttribute('data-year'), this); + return false; + }, + selectMonth: function () { + window['DP_jQuery_' + dpuuid].datepicker._selectMonthYear(id, this, 'M'); + return false; + }, + selectYear: function () { + window['DP_jQuery_' + dpuuid].datepicker._selectMonthYear(id, this, 'Y'); + return false; + } + }; + $(this).bind(this.getAttribute('data-event'), handler[this.getAttribute('data-handler')]); + }); + }, + + /* Generate the HTML for the current state of the date picker. */ + _generateHTML: function(inst) { + var today = new Date(); + today = this._daylightSavingAdjust( + new Date(today.getFullYear(), today.getMonth(), today.getDate())); // clear time + var isRTL = this._get(inst, 'isRTL'); + var showButtonPanel = this._get(inst, 'showButtonPanel'); + var hideIfNoPrevNext = this._get(inst, 'hideIfNoPrevNext'); + var navigationAsDateFormat = this._get(inst, 'navigationAsDateFormat'); + var numMonths = this._getNumberOfMonths(inst); + var showCurrentAtPos = this._get(inst, 'showCurrentAtPos'); + var stepMonths = this._get(inst, 'stepMonths'); + var isMultiMonth = (numMonths[0] != 1 || numMonths[1] != 1); + var currentDate = this._daylightSavingAdjust((!inst.currentDay ? new Date(9999, 9, 9) : + new Date(inst.currentYear, inst.currentMonth, inst.currentDay))); + var minDate = this._getMinMaxDate(inst, 'min'); + var maxDate = this._getMinMaxDate(inst, 'max'); + var drawMonth = inst.drawMonth - showCurrentAtPos; + var drawYear = inst.drawYear; + if (drawMonth < 0) { + drawMonth += 12; + drawYear--; + } + if (maxDate) { + var maxDraw = this._daylightSavingAdjust(new Date(maxDate.getFullYear(), + maxDate.getMonth() - (numMonths[0] * numMonths[1]) + 1, maxDate.getDate())); + maxDraw = (minDate && maxDraw < minDate ? minDate : maxDraw); + while (this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1)) > maxDraw) { + drawMonth--; + if (drawMonth < 0) { + drawMonth = 11; + drawYear--; + } + } + } + inst.drawMonth = drawMonth; + inst.drawYear = drawYear; + var prevText = this._get(inst, 'prevText'); + prevText = (!navigationAsDateFormat ? prevText : this.formatDate(prevText, + this._daylightSavingAdjust(new Date(drawYear, drawMonth - stepMonths, 1)), + this._getFormatConfig(inst))); + var prev = (this._canAdjustMonth(inst, -1, drawYear, drawMonth) ? + '
    ' + prevText + '' : + (hideIfNoPrevNext ? '' : '' + prevText + '')); + var nextText = this._get(inst, 'nextText'); + nextText = (!navigationAsDateFormat ? nextText : this.formatDate(nextText, + this._daylightSavingAdjust(new Date(drawYear, drawMonth + stepMonths, 1)), + this._getFormatConfig(inst))); + var next = (this._canAdjustMonth(inst, +1, drawYear, drawMonth) ? + '' + nextText + '' : + (hideIfNoPrevNext ? '' : '' + nextText + '')); + var currentText = this._get(inst, 'currentText'); + var gotoDate = (this._get(inst, 'gotoCurrent') && inst.currentDay ? currentDate : today); + currentText = (!navigationAsDateFormat ? currentText : + this.formatDate(currentText, gotoDate, this._getFormatConfig(inst))); + var controls = (!inst.inline ? '' : ''); + var buttonPanel = (showButtonPanel) ? '
    ' + (isRTL ? controls : '') + + (this._isInRange(inst, gotoDate) ? '' : '') + (isRTL ? '' : controls) + '
    ' : ''; + var firstDay = parseInt(this._get(inst, 'firstDay'),10); + firstDay = (isNaN(firstDay) ? 0 : firstDay); + var showWeek = this._get(inst, 'showWeek'); + var dayNames = this._get(inst, 'dayNames'); + var dayNamesShort = this._get(inst, 'dayNamesShort'); + var dayNamesMin = this._get(inst, 'dayNamesMin'); + var monthNames = this._get(inst, 'monthNames'); + var monthNamesShort = this._get(inst, 'monthNamesShort'); + var beforeShowDay = this._get(inst, 'beforeShowDay'); + var showOtherMonths = this._get(inst, 'showOtherMonths'); + var selectOtherMonths = this._get(inst, 'selectOtherMonths'); + var calculateWeek = this._get(inst, 'calculateWeek') || this.iso8601Week; + var defaultDate = this._getDefaultDate(inst); + var html = ''; + for (var row = 0; row < numMonths[0]; row++) { + var group = ''; + this.maxRows = 4; + for (var col = 0; col < numMonths[1]; col++) { + var selectedDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, inst.selectedDay)); + var cornerClass = ' ui-corner-all'; + var calender = ''; + if (isMultiMonth) { + calender += '
    '; + } + calender += '
    ' + + (/all|left/.test(cornerClass) && row == 0 ? (isRTL ? next : prev) : '') + + (/all|right/.test(cornerClass) && row == 0 ? (isRTL ? prev : next) : '') + + this._generateMonthYearHeader(inst, drawMonth, drawYear, minDate, maxDate, + row > 0 || col > 0, monthNames, monthNamesShort) + // draw month headers + '
    ' + + ''; + var thead = (showWeek ? '' : ''); + for (var dow = 0; dow < 7; dow++) { // days of the week + var day = (dow + firstDay) % 7; + thead += '= 5 ? ' class="ui-datepicker-week-end"' : '') + '>' + + '' + dayNamesMin[day] + ''; + } + calender += thead + ''; + var daysInMonth = this._getDaysInMonth(drawYear, drawMonth); + if (drawYear == inst.selectedYear && drawMonth == inst.selectedMonth) + inst.selectedDay = Math.min(inst.selectedDay, daysInMonth); + var leadDays = (this._getFirstDayOfMonth(drawYear, drawMonth) - firstDay + 7) % 7; + var curRows = Math.ceil((leadDays + daysInMonth) / 7); // calculate the number of rows to generate + var numRows = (isMultiMonth ? this.maxRows > curRows ? this.maxRows : curRows : curRows); //If multiple months, use the higher number of rows (see #7043) + this.maxRows = numRows; + var printDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1 - leadDays)); + for (var dRow = 0; dRow < numRows; dRow++) { // create date picker rows + calender += ''; + var tbody = (!showWeek ? '' : ''); + for (var dow = 0; dow < 7; dow++) { // create date picker days + var daySettings = (beforeShowDay ? + beforeShowDay.apply((inst.input ? inst.input[0] : null), [printDate]) : [true, '']); + var otherMonth = (printDate.getMonth() != drawMonth); + var unselectable = (otherMonth && !selectOtherMonths) || !daySettings[0] || + (minDate && printDate < minDate) || (maxDate && printDate > maxDate); + tbody += ''; // display selectable date + printDate.setDate(printDate.getDate() + 1); + printDate = this._daylightSavingAdjust(printDate); + } + calender += tbody + ''; + } + drawMonth++; + if (drawMonth > 11) { + drawMonth = 0; + drawYear++; + } + calender += '
    ' + this._get(inst, 'weekHeader') + '
    ' + + this._get(inst, 'calculateWeek')(printDate) + '' + // actions + (otherMonth && !showOtherMonths ? ' ' : // display for other months + (unselectable ? '' + printDate.getDate() + '' : '' + printDate.getDate() + '')) + '
    ' + (isMultiMonth ? '
    ' + + ((numMonths[0] > 0 && col == numMonths[1]-1) ? '
    ' : '') : ''); + group += calender; + } + html += group; + } + html += buttonPanel + ($.ui.ie6 && !inst.inline ? + '' : ''); + inst._keyEvent = false; + return html; + }, + + /* Generate the month and year header. */ + _generateMonthYearHeader: function(inst, drawMonth, drawYear, minDate, maxDate, + secondary, monthNames, monthNamesShort) { + var changeMonth = this._get(inst, 'changeMonth'); + var changeYear = this._get(inst, 'changeYear'); + var showMonthAfterYear = this._get(inst, 'showMonthAfterYear'); + var html = '
    '; + var monthHtml = ''; + // month selection + if (secondary || !changeMonth) + monthHtml += '' + monthNames[drawMonth] + ''; + else { + var inMinYear = (minDate && minDate.getFullYear() == drawYear); + var inMaxYear = (maxDate && maxDate.getFullYear() == drawYear); + monthHtml += ''; + } + if (!showMonthAfterYear) + html += monthHtml + (secondary || !(changeMonth && changeYear) ? ' ' : ''); + // year selection + if ( !inst.yearshtml ) { + inst.yearshtml = ''; + if (secondary || !changeYear) + html += '' + drawYear + ''; + else { + // determine range of years to display + var years = this._get(inst, 'yearRange').split(':'); + var thisYear = new Date().getFullYear(); + var determineYear = function(value) { + var year = (value.match(/c[+-].*/) ? drawYear + parseInt(value.substring(1), 10) : + (value.match(/[+-].*/) ? thisYear + parseInt(value, 10) : + parseInt(value, 10))); + return (isNaN(year) ? thisYear : year); + }; + var year = determineYear(years[0]); + var endYear = Math.max(year, determineYear(years[1] || '')); + year = (minDate ? Math.max(year, minDate.getFullYear()) : year); + endYear = (maxDate ? Math.min(endYear, maxDate.getFullYear()) : endYear); + inst.yearshtml += ''; + + html += inst.yearshtml; + inst.yearshtml = null; + } + } + html += this._get(inst, 'yearSuffix'); + if (showMonthAfterYear) + html += (secondary || !(changeMonth && changeYear) ? ' ' : '') + monthHtml; + html += '
    '; // Close datepicker_header + return html; + }, + + /* Adjust one of the date sub-fields. */ + _adjustInstDate: function(inst, offset, period) { + var year = inst.drawYear + (period == 'Y' ? offset : 0); + var month = inst.drawMonth + (period == 'M' ? offset : 0); + var day = Math.min(inst.selectedDay, this._getDaysInMonth(year, month)) + + (period == 'D' ? offset : 0); + var date = this._restrictMinMax(inst, + this._daylightSavingAdjust(new Date(year, month, day))); + inst.selectedDay = date.getDate(); + inst.drawMonth = inst.selectedMonth = date.getMonth(); + inst.drawYear = inst.selectedYear = date.getFullYear(); + if (period == 'M' || period == 'Y') + this._notifyChange(inst); + }, + + /* Ensure a date is within any min/max bounds. */ + _restrictMinMax: function(inst, date) { + var minDate = this._getMinMaxDate(inst, 'min'); + var maxDate = this._getMinMaxDate(inst, 'max'); + var newDate = (minDate && date < minDate ? minDate : date); + newDate = (maxDate && newDate > maxDate ? maxDate : newDate); + return newDate; + }, + + /* Notify change of month/year. */ + _notifyChange: function(inst) { + var onChange = this._get(inst, 'onChangeMonthYear'); + if (onChange) + onChange.apply((inst.input ? inst.input[0] : null), + [inst.selectedYear, inst.selectedMonth + 1, inst]); + }, + + /* Determine the number of months to show. */ + _getNumberOfMonths: function(inst) { + var numMonths = this._get(inst, 'numberOfMonths'); + return (numMonths == null ? [1, 1] : (typeof numMonths == 'number' ? [1, numMonths] : numMonths)); + }, + + /* Determine the current maximum date - ensure no time components are set. */ + _getMinMaxDate: function(inst, minMax) { + return this._determineDate(inst, this._get(inst, minMax + 'Date'), null); + }, + + /* Find the number of days in a given month. */ + _getDaysInMonth: function(year, month) { + return 32 - this._daylightSavingAdjust(new Date(year, month, 32)).getDate(); + }, + + /* Find the day of the week of the first of a month. */ + _getFirstDayOfMonth: function(year, month) { + return new Date(year, month, 1).getDay(); + }, + + /* Determines if we should allow a "next/prev" month display change. */ + _canAdjustMonth: function(inst, offset, curYear, curMonth) { + var numMonths = this._getNumberOfMonths(inst); + var date = this._daylightSavingAdjust(new Date(curYear, + curMonth + (offset < 0 ? offset : numMonths[0] * numMonths[1]), 1)); + if (offset < 0) + date.setDate(this._getDaysInMonth(date.getFullYear(), date.getMonth())); + return this._isInRange(inst, date); + }, + + /* Is the given date in the accepted range? */ + _isInRange: function(inst, date) { + var minDate = this._getMinMaxDate(inst, 'min'); + var maxDate = this._getMinMaxDate(inst, 'max'); + return ((!minDate || date.getTime() >= minDate.getTime()) && + (!maxDate || date.getTime() <= maxDate.getTime())); + }, + + /* Provide the configuration settings for formatting/parsing. */ + _getFormatConfig: function(inst) { + var shortYearCutoff = this._get(inst, 'shortYearCutoff'); + shortYearCutoff = (typeof shortYearCutoff != 'string' ? shortYearCutoff : + new Date().getFullYear() % 100 + parseInt(shortYearCutoff, 10)); + return {shortYearCutoff: shortYearCutoff, + dayNamesShort: this._get(inst, 'dayNamesShort'), dayNames: this._get(inst, 'dayNames'), + monthNamesShort: this._get(inst, 'monthNamesShort'), monthNames: this._get(inst, 'monthNames')}; + }, + + /* Format the given date for display. */ + _formatDate: function(inst, day, month, year) { + if (!day) { + inst.currentDay = inst.selectedDay; + inst.currentMonth = inst.selectedMonth; + inst.currentYear = inst.selectedYear; + } + var date = (day ? (typeof day == 'object' ? day : + this._daylightSavingAdjust(new Date(year, month, day))) : + this._daylightSavingAdjust(new Date(inst.currentYear, inst.currentMonth, inst.currentDay))); + return this.formatDate(this._get(inst, 'dateFormat'), date, this._getFormatConfig(inst)); + } +}); + +/* + * Bind hover events for datepicker elements. + * Done via delegate so the binding only occurs once in the lifetime of the parent div. + * Global instActive, set by _updateDatepicker allows the handlers to find their way back to the active picker. + */ +function bindHover(dpDiv) { + var selector = 'button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a'; + return dpDiv.delegate(selector, 'mouseout', function() { + $(this).removeClass('ui-state-hover'); + if (this.className.indexOf('ui-datepicker-prev') != -1) $(this).removeClass('ui-datepicker-prev-hover'); + if (this.className.indexOf('ui-datepicker-next') != -1) $(this).removeClass('ui-datepicker-next-hover'); + }) + .delegate(selector, 'mouseover', function(){ + if (!$.datepicker._isDisabledDatepicker( instActive.inline ? dpDiv.parent()[0] : instActive.input[0])) { + $(this).parents('.ui-datepicker-calendar').find('a').removeClass('ui-state-hover'); + $(this).addClass('ui-state-hover'); + if (this.className.indexOf('ui-datepicker-prev') != -1) $(this).addClass('ui-datepicker-prev-hover'); + if (this.className.indexOf('ui-datepicker-next') != -1) $(this).addClass('ui-datepicker-next-hover'); + } + }); +} + +/* jQuery extend now ignores nulls! */ +function extendRemove(target, props) { + $.extend(target, props); + for (var name in props) + if (props[name] == null || props[name] == undefined) + target[name] = props[name]; + return target; +}; + +/* Invoke the datepicker functionality. + @param options string - a command, optionally followed by additional parameters or + Object - settings for attaching new datepicker functionality + @return jQuery object */ +$.fn.datepicker = function(options){ + + /* Verify an empty collection wasn't passed - Fixes #6976 */ + if ( !this.length ) { + return this; + } + + /* Initialise the date picker. */ + if (!$.datepicker.initialized) { + $(document).mousedown($.datepicker._checkExternalClick). + find(document.body).append($.datepicker.dpDiv); + $.datepicker.initialized = true; + } + + var otherArgs = Array.prototype.slice.call(arguments, 1); + if (typeof options == 'string' && (options == 'isDisabled' || options == 'getDate' || options == 'widget')) + return $.datepicker['_' + options + 'Datepicker']. + apply($.datepicker, [this[0]].concat(otherArgs)); + if (options == 'option' && arguments.length == 2 && typeof arguments[1] == 'string') + return $.datepicker['_' + options + 'Datepicker']. + apply($.datepicker, [this[0]].concat(otherArgs)); + return this.each(function() { + typeof options == 'string' ? + $.datepicker['_' + options + 'Datepicker']. + apply($.datepicker, [this].concat(otherArgs)) : + $.datepicker._attachDatepicker(this, options); + }); +}; + +$.datepicker = new Datepicker(); // singleton instance +$.datepicker.initialized = false; +$.datepicker.uuid = new Date().getTime(); +$.datepicker.version = "1.9.2"; + +// Workaround for #4055 +// Add another global to avoid noConflict issues with inline event handlers +window['DP_jQuery_' + dpuuid] = $; + +})(jQuery); +(function( $, undefined ) { + +var uiDialogClasses = "ui-dialog ui-widget ui-widget-content ui-corner-all ", + sizeRelatedOptions = { + buttons: true, + height: true, + maxHeight: true, + maxWidth: true, + minHeight: true, + minWidth: true, + width: true + }, + resizableRelatedOptions = { + maxHeight: true, + maxWidth: true, + minHeight: true, + minWidth: true + }; + +$.widget("ui.dialog", { + version: "1.9.2", + options: { + autoOpen: true, + buttons: {}, + closeOnEscape: true, + closeText: "close", + dialogClass: "", + draggable: true, + hide: null, + height: "auto", + maxHeight: false, + maxWidth: false, + minHeight: 150, + minWidth: 150, + modal: false, + position: { + my: "center", + at: "center", + of: window, + collision: "fit", + // ensure that the titlebar is never outside the document + using: function( pos ) { + var topOffset = $( this ).css( pos ).offset().top; + if ( topOffset < 0 ) { + $( this ).css( "top", pos.top - topOffset ); + } + } + }, + resizable: true, + show: null, + stack: true, + title: "", + width: 300, + zIndex: 1000 + }, + + _create: function() { + this.originalTitle = this.element.attr( "title" ); + // #5742 - .attr() might return a DOMElement + if ( typeof this.originalTitle !== "string" ) { + this.originalTitle = ""; + } + this.oldPosition = { + parent: this.element.parent(), + index: this.element.parent().children().index( this.element ) + }; + this.options.title = this.options.title || this.originalTitle; + var that = this, + options = this.options, + + title = options.title || " ", + uiDialog, + uiDialogTitlebar, + uiDialogTitlebarClose, + uiDialogTitle, + uiDialogButtonPane; + + uiDialog = ( this.uiDialog = $( "
    " ) ) + .addClass( uiDialogClasses + options.dialogClass ) + .css({ + display: "none", + outline: 0, // TODO: move to stylesheet + zIndex: options.zIndex + }) + // setting tabIndex makes the div focusable + .attr( "tabIndex", -1) + .keydown(function( event ) { + if ( options.closeOnEscape && !event.isDefaultPrevented() && event.keyCode && + event.keyCode === $.ui.keyCode.ESCAPE ) { + that.close( event ); + event.preventDefault(); + } + }) + .mousedown(function( event ) { + that.moveToTop( false, event ); + }) + .appendTo( "body" ); + + this.element + .show() + .removeAttr( "title" ) + .addClass( "ui-dialog-content ui-widget-content" ) + .appendTo( uiDialog ); + + uiDialogTitlebar = ( this.uiDialogTitlebar = $( "
    " ) ) + .addClass( "ui-dialog-titlebar ui-widget-header " + + "ui-corner-all ui-helper-clearfix" ) + .bind( "mousedown", function() { + // Dialog isn't getting focus when dragging (#8063) + uiDialog.focus(); + }) + .prependTo( uiDialog ); + + uiDialogTitlebarClose = $( "" ) + .addClass( "ui-dialog-titlebar-close ui-corner-all" ) + .attr( "role", "button" ) + .click(function( event ) { + event.preventDefault(); + that.close( event ); + }) + .appendTo( uiDialogTitlebar ); + + ( this.uiDialogTitlebarCloseText = $( "" ) ) + .addClass( "ui-icon ui-icon-closethick" ) + .text( options.closeText ) + .appendTo( uiDialogTitlebarClose ); + + uiDialogTitle = $( "" ) + .uniqueId() + .addClass( "ui-dialog-title" ) + .html( title ) + .prependTo( uiDialogTitlebar ); + + uiDialogButtonPane = ( this.uiDialogButtonPane = $( "
    " ) ) + .addClass( "ui-dialog-buttonpane ui-widget-content ui-helper-clearfix" ); + + ( this.uiButtonSet = $( "
    " ) ) + .addClass( "ui-dialog-buttonset" ) + .appendTo( uiDialogButtonPane ); + + uiDialog.attr({ + role: "dialog", + "aria-labelledby": uiDialogTitle.attr( "id" ) + }); + + uiDialogTitlebar.find( "*" ).add( uiDialogTitlebar ).disableSelection(); + this._hoverable( uiDialogTitlebarClose ); + this._focusable( uiDialogTitlebarClose ); + + if ( options.draggable && $.fn.draggable ) { + this._makeDraggable(); + } + if ( options.resizable && $.fn.resizable ) { + this._makeResizable(); + } + + this._createButtons( options.buttons ); + this._isOpen = false; + + if ( $.fn.bgiframe ) { + uiDialog.bgiframe(); + } + + // prevent tabbing out of modal dialogs + this._on( uiDialog, { keydown: function( event ) { + if ( !options.modal || event.keyCode !== $.ui.keyCode.TAB ) { + return; + } + + var tabbables = $( ":tabbable", uiDialog ), + first = tabbables.filter( ":first" ), + last = tabbables.filter( ":last" ); + + if ( event.target === last[0] && !event.shiftKey ) { + first.focus( 1 ); + return false; + } else if ( event.target === first[0] && event.shiftKey ) { + last.focus( 1 ); + return false; + } + }}); + }, + + _init: function() { + if ( this.options.autoOpen ) { + this.open(); + } + }, + + _destroy: function() { + var next, + oldPosition = this.oldPosition; + + if ( this.overlay ) { + this.overlay.destroy(); + } + this.uiDialog.hide(); + this.element + .removeClass( "ui-dialog-content ui-widget-content" ) + .hide() + .appendTo( "body" ); + this.uiDialog.remove(); + + if ( this.originalTitle ) { + this.element.attr( "title", this.originalTitle ); + } + + next = oldPosition.parent.children().eq( oldPosition.index ); + // Don't try to place the dialog next to itself (#8613) + if ( next.length && next[ 0 ] !== this.element[ 0 ] ) { + next.before( this.element ); + } else { + oldPosition.parent.append( this.element ); + } + }, + + widget: function() { + return this.uiDialog; + }, + + close: function( event ) { + var that = this, + maxZ, thisZ; + + if ( !this._isOpen ) { + return; + } + + if ( false === this._trigger( "beforeClose", event ) ) { + return; + } + + this._isOpen = false; + + if ( this.overlay ) { + this.overlay.destroy(); + } + + if ( this.options.hide ) { + this._hide( this.uiDialog, this.options.hide, function() { + that._trigger( "close", event ); + }); + } else { + this.uiDialog.hide(); + this._trigger( "close", event ); + } + + $.ui.dialog.overlay.resize(); + + // adjust the maxZ to allow other modal dialogs to continue to work (see #4309) + if ( this.options.modal ) { + maxZ = 0; + $( ".ui-dialog" ).each(function() { + if ( this !== that.uiDialog[0] ) { + thisZ = $( this ).css( "z-index" ); + if ( !isNaN( thisZ ) ) { + maxZ = Math.max( maxZ, thisZ ); + } + } + }); + $.ui.dialog.maxZ = maxZ; + } + + return this; + }, + + isOpen: function() { + return this._isOpen; + }, + + // the force parameter allows us to move modal dialogs to their correct + // position on open + moveToTop: function( force, event ) { + var options = this.options, + saveScroll; + + if ( ( options.modal && !force ) || + ( !options.stack && !options.modal ) ) { + return this._trigger( "focus", event ); + } + + if ( options.zIndex > $.ui.dialog.maxZ ) { + $.ui.dialog.maxZ = options.zIndex; + } + if ( this.overlay ) { + $.ui.dialog.maxZ += 1; + $.ui.dialog.overlay.maxZ = $.ui.dialog.maxZ; + this.overlay.$el.css( "z-index", $.ui.dialog.overlay.maxZ ); + } + + // Save and then restore scroll + // Opera 9.5+ resets when parent z-index is changed. + // http://bugs.jqueryui.com/ticket/3193 + saveScroll = { + scrollTop: this.element.scrollTop(), + scrollLeft: this.element.scrollLeft() + }; + $.ui.dialog.maxZ += 1; + this.uiDialog.css( "z-index", $.ui.dialog.maxZ ); + this.element.attr( saveScroll ); + this._trigger( "focus", event ); + + return this; + }, + + open: function() { + if ( this._isOpen ) { + return; + } + + var hasFocus, + options = this.options, + uiDialog = this.uiDialog; + + this._size(); + this._position( options.position ); + uiDialog.show( options.show ); + this.overlay = options.modal ? new $.ui.dialog.overlay( this ) : null; + this.moveToTop( true ); + + // set focus to the first tabbable element in the content area or the first button + // if there are no tabbable elements, set focus on the dialog itself + hasFocus = this.element.find( ":tabbable" ); + if ( !hasFocus.length ) { + hasFocus = this.uiDialogButtonPane.find( ":tabbable" ); + if ( !hasFocus.length ) { + hasFocus = uiDialog; + } + } + hasFocus.eq( 0 ).focus(); + + this._isOpen = true; + this._trigger( "open" ); + + return this; + }, + + _createButtons: function( buttons ) { + var that = this, + hasButtons = false; + + // if we already have a button pane, remove it + this.uiDialogButtonPane.remove(); + this.uiButtonSet.empty(); + + if ( typeof buttons === "object" && buttons !== null ) { + $.each( buttons, function() { + return !(hasButtons = true); }); - }; - this.refresh(); + } + if ( hasButtons ) { + $.each( buttons, function( name, props ) { + var button, click; + props = $.isFunction( props ) ? + { click: props, text: name } : + props; + // Default to a non-submitting button + props = $.extend( { type: "button" }, props ); + // Change the context for the click callback to be the main element + click = props.click; + props.click = function() { + click.apply( that.element[0], arguments ); + }; + button = $( "", props ) + .appendTo( that.uiButtonSet ); + if ( $.fn.button ) { + button.button(); + } + }); + this.uiDialog.addClass( "ui-dialog-buttons" ); + this.uiDialogButtonPane.appendTo( this.uiDialog ); + } else { + this.uiDialog.removeClass( "ui-dialog-buttons" ); + } + }, - this.selectees = selectees.addClass("ui-selectee"); + _makeDraggable: function() { + var that = this, + options = this.options; - this._mouseInit(); + function filteredUi( ui ) { + return { + position: ui.position, + offset: ui.offset + }; + } - this.helper = $("
    "); + this.uiDialog.draggable({ + cancel: ".ui-dialog-content, .ui-dialog-titlebar-close", + handle: ".ui-dialog-titlebar", + containment: "document", + start: function( event, ui ) { + $( this ) + .addClass( "ui-dialog-dragging" ); + that._trigger( "dragStart", event, filteredUi( ui ) ); + }, + drag: function( event, ui ) { + that._trigger( "drag", event, filteredUi( ui ) ); + }, + stop: function( event, ui ) { + options.position = [ + ui.position.left - that.document.scrollLeft(), + ui.position.top - that.document.scrollTop() + ]; + $( this ) + .removeClass( "ui-dialog-dragging" ); + that._trigger( "dragStop", event, filteredUi( ui ) ); + $.ui.dialog.overlay.resize(); + } + }); }, - destroy: function() { - this.selectees - .removeClass("ui-selectee") - .removeData("selectable-item"); - this.element - .removeClass("ui-selectable ui-selectable-disabled") - .removeData("selectable") - .unbind(".selectable"); - this._mouseDestroy(); + _makeResizable: function( handles ) { + handles = (handles === undefined ? this.options.resizable : handles); + var that = this, + options = this.options, + // .ui-resizable has position: relative defined in the stylesheet + // but dialogs have to use absolute or fixed positioning + position = this.uiDialog.css( "position" ), + resizeHandles = typeof handles === 'string' ? + handles : + "n,e,s,w,se,sw,ne,nw"; - return this; + function filteredUi( ui ) { + return { + originalPosition: ui.originalPosition, + originalSize: ui.originalSize, + position: ui.position, + size: ui.size + }; + } + + this.uiDialog.resizable({ + cancel: ".ui-dialog-content", + containment: "document", + alsoResize: this.element, + maxWidth: options.maxWidth, + maxHeight: options.maxHeight, + minWidth: options.minWidth, + minHeight: this._minHeight(), + handles: resizeHandles, + start: function( event, ui ) { + $( this ).addClass( "ui-dialog-resizing" ); + that._trigger( "resizeStart", event, filteredUi( ui ) ); + }, + resize: function( event, ui ) { + that._trigger( "resize", event, filteredUi( ui ) ); + }, + stop: function( event, ui ) { + $( this ).removeClass( "ui-dialog-resizing" ); + options.height = $( this ).height(); + options.width = $( this ).width(); + that._trigger( "resizeStop", event, filteredUi( ui ) ); + $.ui.dialog.overlay.resize(); + } + }) + .css( "position", position ) + .find( ".ui-resizable-se" ) + .addClass( "ui-icon ui-icon-grip-diagonal-se" ); }, - _mouseStart: function(event) { - var self = this; + _minHeight: function() { + var options = this.options; - this.opos = [event.pageX, event.pageY]; + if ( options.height === "auto" ) { + return options.minHeight; + } else { + return Math.min( options.minHeight, options.height ); + } + }, - if (this.options.disabled) - return; + _position: function( position ) { + var myAt = [], + offset = [ 0, 0 ], + isVisible; - var options = this.options; + if ( position ) { + // deep extending converts arrays to objects in jQuery <= 1.3.2 :-( + // if (typeof position == 'string' || $.isArray(position)) { + // myAt = $.isArray(position) ? position : position.split(' '); - this.selectees = $(options.filter, this.element[0]); + if ( typeof position === "string" || (typeof position === "object" && "0" in position ) ) { + myAt = position.split ? position.split( " " ) : [ position[ 0 ], position[ 1 ] ]; + if ( myAt.length === 1 ) { + myAt[ 1 ] = myAt[ 0 ]; + } - this._trigger("start", event); + $.each( [ "left", "top" ], function( i, offsetPosition ) { + if ( +myAt[ i ] === myAt[ i ] ) { + offset[ i ] = myAt[ i ]; + myAt[ i ] = offsetPosition; + } + }); - $(options.appendTo).append(this.helper); - // position helper (lasso) - this.helper.css({ - "left": event.clientX, - "top": event.clientY, - "width": 0, - "height": 0 - }); + position = { + my: myAt[0] + (offset[0] < 0 ? offset[0] : "+" + offset[0]) + " " + + myAt[1] + (offset[1] < 0 ? offset[1] : "+" + offset[1]), + at: myAt.join( " " ) + }; + } - if (options.autoRefresh) { - this.refresh(); + position = $.extend( {}, $.ui.dialog.prototype.options.position, position ); + } else { + position = $.ui.dialog.prototype.options.position; } - this.selectees.filter('.ui-selected').each(function() { - var selectee = $.data(this, "selectable-item"); - selectee.startselected = true; - if (!event.metaKey) { - selectee.$element.removeClass('ui-selected'); - selectee.selected = false; - selectee.$element.addClass('ui-unselecting'); - selectee.unselecting = true; - // selectable UNSELECTING callback - self._trigger("unselecting", event, { - unselecting: selectee.element - }); + // need to show the dialog to get the actual offset in the position plugin + isVisible = this.uiDialog.is( ":visible" ); + if ( !isVisible ) { + this.uiDialog.show(); + } + this.uiDialog.position( position ); + if ( !isVisible ) { + this.uiDialog.hide(); + } + }, + + _setOptions: function( options ) { + var that = this, + resizableOptions = {}, + resize = false; + + $.each( options, function( key, value ) { + that._setOption( key, value ); + + if ( key in sizeRelatedOptions ) { + resize = true; + } + if ( key in resizableRelatedOptions ) { + resizableOptions[ key ] = value; } }); - $(event.target).parents().andSelf().each(function() { - var selectee = $.data(this, "selectable-item"); - if (selectee) { - var doSelect = !event.metaKey || !selectee.$element.hasClass('ui-selected'); - selectee.$element - .removeClass(doSelect ? "ui-unselecting" : "ui-selected") - .addClass(doSelect ? "ui-selecting" : "ui-unselecting"); - selectee.unselecting = !doSelect; - selectee.selecting = doSelect; - selectee.selected = doSelect; - // selectable (UN)SELECTING callback - if (doSelect) { - self._trigger("selecting", event, { - selecting: selectee.element - }); + if ( resize ) { + this._size(); + } + if ( this.uiDialog.is( ":data(resizable)" ) ) { + this.uiDialog.resizable( "option", resizableOptions ); + } + }, + + _setOption: function( key, value ) { + var isDraggable, isResizable, + uiDialog = this.uiDialog; + + switch ( key ) { + case "buttons": + this._createButtons( value ); + break; + case "closeText": + // ensure that we always pass a string + this.uiDialogTitlebarCloseText.text( "" + value ); + break; + case "dialogClass": + uiDialog + .removeClass( this.options.dialogClass ) + .addClass( uiDialogClasses + value ); + break; + case "disabled": + if ( value ) { + uiDialog.addClass( "ui-dialog-disabled" ); } else { - self._trigger("unselecting", event, { - unselecting: selectee.element + uiDialog.removeClass( "ui-dialog-disabled" ); + } + break; + case "draggable": + isDraggable = uiDialog.is( ":data(draggable)" ); + if ( isDraggable && !value ) { + uiDialog.draggable( "destroy" ); + } + + if ( !isDraggable && value ) { + this._makeDraggable(); + } + break; + case "position": + this._position( value ); + break; + case "resizable": + // currently resizable, becoming non-resizable + isResizable = uiDialog.is( ":data(resizable)" ); + if ( isResizable && !value ) { + uiDialog.resizable( "destroy" ); + } + + // currently resizable, changing handles + if ( isResizable && typeof value === "string" ) { + uiDialog.resizable( "option", "handles", value ); + } + + // currently non-resizable, becoming resizable + if ( !isResizable && value !== false ) { + this._makeResizable( value ); + } + break; + case "title": + // convert whatever was passed in o a string, for html() to not throw up + $( ".ui-dialog-title", this.uiDialogTitlebar ) + .html( "" + ( value || " " ) ); + break; + } + + this._super( key, value ); + }, + + _size: function() { + /* If the user has resized the dialog, the .ui-dialog and .ui-dialog-content + * divs will both have width and height set, so we need to reset them + */ + var nonContentHeight, minContentHeight, autoHeight, + options = this.options, + isVisible = this.uiDialog.is( ":visible" ); + + // reset content sizing + this.element.show().css({ + width: "auto", + minHeight: 0, + height: 0 + }); + + if ( options.minWidth > options.width ) { + options.width = options.minWidth; + } + + // reset wrapper sizing + // determine the height of all the non-content elements + nonContentHeight = this.uiDialog.css({ + height: "auto", + width: options.width + }) + .outerHeight(); + minContentHeight = Math.max( 0, options.minHeight - nonContentHeight ); + + if ( options.height === "auto" ) { + // only needed for IE6 support + if ( $.support.minHeight ) { + this.element.css({ + minHeight: minContentHeight, + height: "auto" + }); + } else { + this.uiDialog.show(); + autoHeight = this.element.css( "height", "auto" ).height(); + if ( !isVisible ) { + this.uiDialog.hide(); + } + this.element.height( Math.max( autoHeight, minContentHeight ) ); + } + } else { + this.element.height( Math.max( options.height - nonContentHeight, 0 ) ); + } + + if (this.uiDialog.is( ":data(resizable)" ) ) { + this.uiDialog.resizable( "option", "minHeight", this._minHeight() ); + } + } +}); + +$.extend($.ui.dialog, { + uuid: 0, + maxZ: 0, + + getTitleId: function($el) { + var id = $el.attr( "id" ); + if ( !id ) { + this.uuid += 1; + id = this.uuid; + } + return "ui-dialog-title-" + id; + }, + + overlay: function( dialog ) { + this.$el = $.ui.dialog.overlay.create( dialog ); + } +}); + +$.extend( $.ui.dialog.overlay, { + instances: [], + // reuse old instances due to IE memory leak with alpha transparency (see #5185) + oldInstances: [], + maxZ: 0, + events: $.map( + "focus,mousedown,mouseup,keydown,keypress,click".split( "," ), + function( event ) { + return event + ".dialog-overlay"; + } + ).join( " " ), + create: function( dialog ) { + if ( this.instances.length === 0 ) { + // prevent use of anchors and inputs + // we use a setTimeout in case the overlay is created from an + // event that we're going to be cancelling (see #2804) + setTimeout(function() { + // handle $(el).dialog().dialog('close') (see #4065) + if ( $.ui.dialog.overlay.instances.length ) { + $( document ).bind( $.ui.dialog.overlay.events, function( event ) { + // stop events if the z-index of the target is < the z-index of the overlay + // we cannot return true when we don't want to cancel the event (#3523) + if ( $( event.target ).zIndex() < $.ui.dialog.overlay.maxZ ) { + return false; + } }); } - return false; + }, 1 ); + + // handle window resize + $( window ).bind( "resize.dialog-overlay", $.ui.dialog.overlay.resize ); + } + + var $el = ( this.oldInstances.pop() || $( "
    " ).addClass( "ui-widget-overlay" ) ); + + // allow closing by pressing the escape key + $( document ).bind( "keydown.dialog-overlay", function( event ) { + var instances = $.ui.dialog.overlay.instances; + // only react to the event if we're the top overlay + if ( instances.length !== 0 && instances[ instances.length - 1 ] === $el && + dialog.options.closeOnEscape && !event.isDefaultPrevented() && event.keyCode && + event.keyCode === $.ui.keyCode.ESCAPE ) { + + dialog.close( event ); + event.preventDefault(); } }); - }, + $el.appendTo( document.body ).css({ + width: this.width(), + height: this.height() + }); - _mouseDrag: function(event) { - var self = this; - this.dragged = true; + if ( $.fn.bgiframe ) { + $el.bgiframe(); + } - if (this.options.disabled) - return; + this.instances.push( $el ); + return $el; + }, - var options = this.options; + destroy: function( $el ) { + var indexOf = $.inArray( $el, this.instances ), + maxZ = 0; - var x1 = this.opos[0], y1 = this.opos[1], x2 = event.pageX, y2 = event.pageY; - if (x1 > x2) { var tmp = x2; x2 = x1; x1 = tmp; } - if (y1 > y2) { var tmp = y2; y2 = y1; y1 = tmp; } - this.helper.css({left: x1, top: y1, width: x2-x1, height: y2-y1}); + if ( indexOf !== -1 ) { + this.oldInstances.push( this.instances.splice( indexOf, 1 )[ 0 ] ); + } - this.selectees.each(function() { - var selectee = $.data(this, "selectable-item"); - //prevent helper from being selected if appendTo: selectable - if (!selectee || selectee.element == self.element[0]) - return; - var hit = false; - if (options.tolerance == 'touch') { - hit = ( !(selectee.left > x2 || selectee.right < x1 || selectee.top > y2 || selectee.bottom < y1) ); - } else if (options.tolerance == 'fit') { - hit = (selectee.left > x1 && selectee.right < x2 && selectee.top > y1 && selectee.bottom < y2); - } + if ( this.instances.length === 0 ) { + $( [ document, window ] ).unbind( ".dialog-overlay" ); + } - if (hit) { - // SELECT - if (selectee.selected) { - selectee.$element.removeClass('ui-selected'); - selectee.selected = false; - } - if (selectee.unselecting) { - selectee.$element.removeClass('ui-unselecting'); - selectee.unselecting = false; - } - if (!selectee.selecting) { - selectee.$element.addClass('ui-selecting'); - selectee.selecting = true; - // selectable SELECTING callback - self._trigger("selecting", event, { - selecting: selectee.element - }); - } - } else { - // UNSELECT - if (selectee.selecting) { - if (event.metaKey && selectee.startselected) { - selectee.$element.removeClass('ui-selecting'); - selectee.selecting = false; - selectee.$element.addClass('ui-selected'); - selectee.selected = true; - } else { - selectee.$element.removeClass('ui-selecting'); - selectee.selecting = false; - if (selectee.startselected) { - selectee.$element.addClass('ui-unselecting'); - selectee.unselecting = true; - } - // selectable UNSELECTING callback - self._trigger("unselecting", event, { - unselecting: selectee.element - }); - } - } - if (selectee.selected) { - if (!event.metaKey && !selectee.startselected) { - selectee.$element.removeClass('ui-selected'); - selectee.selected = false; + $el.height( 0 ).width( 0 ).remove(); - selectee.$element.addClass('ui-unselecting'); - selectee.unselecting = true; - // selectable UNSELECTING callback - self._trigger("unselecting", event, { - unselecting: selectee.element - }); - } - } - } + // adjust the maxZ to allow other modal dialogs to continue to work (see #4309) + $.each( this.instances, function() { + maxZ = Math.max( maxZ, this.css( "z-index" ) ); }); - - return false; + this.maxZ = maxZ; }, - _mouseStop: function(event) { - var self = this; + height: function() { + var scrollHeight, + offsetHeight; + // handle IE + if ( $.ui.ie ) { + scrollHeight = Math.max( + document.documentElement.scrollHeight, + document.body.scrollHeight + ); + offsetHeight = Math.max( + document.documentElement.offsetHeight, + document.body.offsetHeight + ); - this.dragged = false; + if ( scrollHeight < offsetHeight ) { + return $( window ).height() + "px"; + } else { + return scrollHeight + "px"; + } + // handle "good" browsers + } else { + return $( document ).height() + "px"; + } + }, - var options = this.options; + width: function() { + var scrollWidth, + offsetWidth; + // handle IE + if ( $.ui.ie ) { + scrollWidth = Math.max( + document.documentElement.scrollWidth, + document.body.scrollWidth + ); + offsetWidth = Math.max( + document.documentElement.offsetWidth, + document.body.offsetWidth + ); - $('.ui-unselecting', this.element[0]).each(function() { - var selectee = $.data(this, "selectable-item"); - selectee.$element.removeClass('ui-unselecting'); - selectee.unselecting = false; - selectee.startselected = false; - self._trigger("unselected", event, { - unselected: selectee.element - }); - }); - $('.ui-selecting', this.element[0]).each(function() { - var selectee = $.data(this, "selectable-item"); - selectee.$element.removeClass('ui-selecting').addClass('ui-selected'); - selectee.selecting = false; - selectee.selected = true; - selectee.startselected = true; - self._trigger("selected", event, { - selected: selectee.element - }); - }); - this._trigger("stop", event); + if ( scrollWidth < offsetWidth ) { + return $( window ).width() + "px"; + } else { + return scrollWidth + "px"; + } + // handle "good" browsers + } else { + return $( document ).width() + "px"; + } + }, - this.helper.remove(); + resize: function() { + /* If the dialog is draggable and the user drags it past the + * right edge of the window, the document becomes wider so we + * need to stretch the overlay. If the user then drags the + * dialog back to the left, the document will become narrower, + * so we need to shrink the overlay to the appropriate size. + * This is handled by shrinking the overlay before setting it + * to the full document size. + */ + var $overlays = $( [] ); + $.each( $.ui.dialog.overlay.instances, function() { + $overlays = $overlays.add( this ); + }); - return false; + $overlays.css({ + width: 0, + height: 0 + }).css({ + width: $.ui.dialog.overlay.width(), + height: $.ui.dialog.overlay.height() + }); } - }); -$.extend($.ui.selectable, { - version: "1.8.16" +$.extend( $.ui.dialog.overlay.prototype, { + destroy: function() { + $.ui.dialog.overlay.destroy( this.$el ); + } }); -})(jQuery); -/* - * jQuery UI Sortable 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Sortables - * - * Depends: - * jquery.ui.core.js - * jquery.ui.mouse.js - * jquery.ui.widget.js - */ +}( jQuery ) ); (function( $, undefined ) { -$.widget("ui.sortable", $.ui.mouse, { - widgetEventPrefix: "sort", +$.widget("ui.draggable", $.ui.mouse, { + version: "1.9.2", + widgetEventPrefix: "drag", options: { + addClasses: true, appendTo: "parent", axis: false, - connectWith: false, + connectToSortable: false, containment: false, - cursor: 'auto', + cursor: "auto", cursorAt: false, - dropOnEmpty: true, - forcePlaceholderSize: false, - forceHelperSize: false, grid: false, handle: false, helper: "original", - items: '> *', + iframeFix: false, opacity: false, - placeholder: false, + refreshPositions: false, revert: false, + revertDuration: 500, + scope: "default", scroll: true, scrollSensitivity: 20, scrollSpeed: 20, - scope: "default", - tolerance: "intersect", - zIndex: 1000 + snap: false, + snapMode: "both", + snapTolerance: 20, + stack: false, + zIndex: false }, _create: function() { - var o = this.options; - this.containerCache = {}; - this.element.addClass("ui-sortable"); - - //Get the items - this.refresh(); - - //Let's determine if the items are being displayed horizontally - this.floating = this.items.length ? o.axis === 'x' || (/left|right/).test(this.items[0].item.css('float')) || (/inline|table-cell/).test(this.items[0].item.css('display')) : false; + if (this.options.helper == 'original' && !(/^(?:r|a|f)/).test(this.element.css("position"))) + this.element[0].style.position = 'relative'; - //Let's determine the parent's offset - this.offset = this.element.offset(); + (this.options.addClasses && this.element.addClass("ui-draggable")); + (this.options.disabled && this.element.addClass("ui-draggable-disabled")); - //Initialize mouse events for interaction this._mouseInit(); }, - destroy: function() { - this.element - .removeClass("ui-sortable ui-sortable-disabled") - .removeData("sortable") - .unbind(".sortable"); + _destroy: function() { + this.element.removeClass( "ui-draggable ui-draggable-dragging ui-draggable-disabled" ); this._mouseDestroy(); - - for ( var i = this.items.length - 1; i >= 0; i-- ) - this.items[i].item.removeData("sortable-item"); - - return this; }, - _setOption: function(key, value){ - if ( key === "disabled" ) { - this.options[ key ] = value; - - this.widget() - [ value ? "addClass" : "removeClass"]( "ui-sortable-disabled" ); - } else { - // Don't call widget base _setOption for disable as it adds ui-state-disabled class - $.Widget.prototype._setOption.apply(this, arguments); - } - }, - - _mouseCapture: function(event, overrideHandle) { - - if (this.reverting) { - return false; - } - - if(this.options.disabled || this.options.type == 'static') return false; - - //We have to refresh the items data once first - this._refreshItems(event); + _mouseCapture: function(event) { - //Find out if the clicked node (or one of its parents) is a actual item in this.items - var currentItem = null, self = this, nodes = $(event.target).parents().each(function() { - if($.data(this, 'sortable-item') == self) { - currentItem = $(this); - return false; - } - }); - if($.data(event.target, 'sortable-item') == self) currentItem = $(event.target); + var o = this.options; - if(!currentItem) return false; - if(this.options.handle && !overrideHandle) { - var validHandle = false; + // among others, prevent a drag on a resizable-handle + if (this.helper || o.disabled || $(event.target).is('.ui-resizable-handle')) + return false; - $(this.options.handle, currentItem).find("*").andSelf().each(function() { if(this == event.target) validHandle = true; }); - if(!validHandle) return false; - } + //Quit if we're not on a valid handle + this.handle = this._getHandle(event); + if (!this.handle) + return false; + + $(o.iframeFix === true ? "iframe" : o.iframeFix).each(function() { + $('
    ') + .css({ + width: this.offsetWidth+"px", height: this.offsetHeight+"px", + position: "absolute", opacity: "0.001", zIndex: 1000 + }) + .css($(this).offset()) + .appendTo("body"); + }); - this.currentItem = currentItem; - this._removeCurrentsFromItems(); return true; }, - _mouseStart: function(event, overrideHandle, noActivation) { - - var o = this.options, self = this; - this.currentContainer = this; + _mouseStart: function(event) { - //We only need to call refreshPositions, because the refreshItems call has been moved to mouseCapture - this.refreshPositions(); + var o = this.options; //Create and append the visible helper this.helper = this._createHelper(event); + this.helper.addClass("ui-draggable-dragging"); + //Cache the helper size this._cacheHelperProportions(); + //If ddmanager is used for droppables, set the global draggable + if($.ui.ddmanager) + $.ui.ddmanager.current = this; + /* * - Position generation - * This block generates everything position related - it's the core of draggables. @@ -3114,21 +6008,17 @@ $.widget("ui.sortable", $.ui.mouse, { //Cache the margins of the original element this._cacheMargins(); - //Get the next scrolling parent + //Store the helper's css position + this.cssPosition = this.helper.css("position"); this.scrollParent = this.helper.scrollParent(); //The element's absolute position on the page minus margins - this.offset = this.currentItem.offset(); + this.offset = this.positionAbs = this.element.offset(); this.offset = { top: this.offset.top - this.margins.top, left: this.offset.left - this.margins.left }; - // Only after we got the offset, we can change the helper's position to absolute - // TODO: Still need to figure out a way to make relative sorting possible - this.helper.css("position", "absolute"); - this.cssPosition = this.helper.css("position"); - $.extend(this.offset, { click: { //Where the click happened, relative to the element left: event.pageX - this.offset.left, @@ -3139,1062 +6029,1658 @@ $.widget("ui.sortable", $.ui.mouse, { }); //Generate the original position - this.originalPosition = this._generatePosition(event); + this.originalPosition = this.position = this._generatePosition(event); this.originalPageX = event.pageX; this.originalPageY = event.pageY; //Adjust the mouse offset relative to the helper if 'cursorAt' is supplied (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt)); - //Cache the former DOM position - this.domPosition = { prev: this.currentItem.prev()[0], parent: this.currentItem.parent()[0] }; + //Set a containment if given in the options + if(o.containment) + this._setContainment(); - //If the helper is not the original, hide the original so it's not playing any role during the drag, won't cause anything bad this way - if(this.helper[0] != this.currentItem[0]) { - this.currentItem.hide(); + //Trigger event + callbacks + if(this._trigger("start", event) === false) { + this._clear(); + return false; } - //Create the placeholder - this._createPlaceholder(); + //Recache the helper size + this._cacheHelperProportions(); - //Set a containment if given in the options - if(o.containment) - this._setContainment(); + //Prepare the droppable offsets + if ($.ui.ddmanager && !o.dropBehaviour) + $.ui.ddmanager.prepareOffsets(this, event); + + + this._mouseDrag(event, true); //Execute the drag once - this causes the helper not to be visible before getting its correct position + + //If the ddmanager is used for droppables, inform the manager that dragging has started (see #5003) + if ( $.ui.ddmanager ) $.ui.ddmanager.dragStart(this, event); + + return true; + }, + + _mouseDrag: function(event, noPropagation) { + + //Compute the helpers position + this.position = this._generatePosition(event); + this.positionAbs = this._convertPositionTo("absolute"); + + //Call plugins and callbacks and use the resulting position if something is returned + if (!noPropagation) { + var ui = this._uiHash(); + if(this._trigger('drag', event, ui) === false) { + this._mouseUp({}); + return false; + } + this.position = ui.position; + } + + if(!this.options.axis || this.options.axis != "y") this.helper[0].style.left = this.position.left+'px'; + if(!this.options.axis || this.options.axis != "x") this.helper[0].style.top = this.position.top+'px'; + if($.ui.ddmanager) $.ui.ddmanager.drag(this, event); + + return false; + }, + + _mouseStop: function(event) { + + //If we are using droppables, inform the manager about the drop + var dropped = false; + if ($.ui.ddmanager && !this.options.dropBehaviour) + dropped = $.ui.ddmanager.drop(this, event); + + //if a drop comes from outside (a sortable) + if(this.dropped) { + dropped = this.dropped; + this.dropped = false; + } + + //if the original element is no longer in the DOM don't bother to continue (see #8269) + var element = this.element[0], elementInDom = false; + while ( element && (element = element.parentNode) ) { + if (element == document ) { + elementInDom = true; + } + } + if ( !elementInDom && this.options.helper === "original" ) + return false; + + if((this.options.revert == "invalid" && !dropped) || (this.options.revert == "valid" && dropped) || this.options.revert === true || ($.isFunction(this.options.revert) && this.options.revert.call(this.element, dropped))) { + var that = this; + $(this.helper).animate(this.originalPosition, parseInt(this.options.revertDuration, 10), function() { + if(that._trigger("stop", event) !== false) { + that._clear(); + } + }); + } else { + if(this._trigger("stop", event) !== false) { + this._clear(); + } + } + + return false; + }, + + _mouseUp: function(event) { + //Remove frame helpers + $("div.ui-draggable-iframeFix").each(function() { + this.parentNode.removeChild(this); + }); + + //If the ddmanager is used for droppables, inform the manager that dragging has stopped (see #5003) + if( $.ui.ddmanager ) $.ui.ddmanager.dragStop(this, event); + + return $.ui.mouse.prototype._mouseUp.call(this, event); + }, + + cancel: function() { + + if(this.helper.is(".ui-draggable-dragging")) { + this._mouseUp({}); + } else { + this._clear(); + } + + return this; + + }, + + _getHandle: function(event) { + + var handle = !this.options.handle || !$(this.options.handle, this.element).length ? true : false; + $(this.options.handle, this.element) + .find("*") + .andSelf() + .each(function() { + if(this == event.target) handle = true; + }); + + return handle; + + }, + + _createHelper: function(event) { + + var o = this.options; + var helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event])) : (o.helper == 'clone' ? this.element.clone().removeAttr('id') : this.element); + + if(!helper.parents('body').length) + helper.appendTo((o.appendTo == 'parent' ? this.element[0].parentNode : o.appendTo)); + + if(helper[0] != this.element[0] && !(/(fixed|absolute)/).test(helper.css("position"))) + helper.css("position", "absolute"); + + return helper; + + }, + + _adjustOffsetFromHelper: function(obj) { + if (typeof obj == 'string') { + obj = obj.split(' '); + } + if ($.isArray(obj)) { + obj = {left: +obj[0], top: +obj[1] || 0}; + } + if ('left' in obj) { + this.offset.click.left = obj.left + this.margins.left; + } + if ('right' in obj) { + this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left; + } + if ('top' in obj) { + this.offset.click.top = obj.top + this.margins.top; + } + if ('bottom' in obj) { + this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top; + } + }, + + _getParentOffset: function() { + + //Get the offsetParent and cache its position + this.offsetParent = this.helper.offsetParent(); + var po = this.offsetParent.offset(); + + // This is a special case where we need to modify a offset calculated on start, since the following happened: + // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent + // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that + // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag + if(this.cssPosition == 'absolute' && this.scrollParent[0] != document && $.contains(this.scrollParent[0], this.offsetParent[0])) { + po.left += this.scrollParent.scrollLeft(); + po.top += this.scrollParent.scrollTop(); + } + + if((this.offsetParent[0] == document.body) //This needs to be actually done for all browsers, since pageX/pageY includes this information + || (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() == 'html' && $.ui.ie)) //Ugly IE fix + po = { top: 0, left: 0 }; + + return { + top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0), + left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0) + }; + + }, + + _getRelativeOffset: function() { + + if(this.cssPosition == "relative") { + var p = this.element.position(); + return { + top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(), + left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft() + }; + } else { + return { top: 0, left: 0 }; + } + + }, + + _cacheMargins: function() { + this.margins = { + left: (parseInt(this.element.css("marginLeft"),10) || 0), + top: (parseInt(this.element.css("marginTop"),10) || 0), + right: (parseInt(this.element.css("marginRight"),10) || 0), + bottom: (parseInt(this.element.css("marginBottom"),10) || 0) + }; + }, + + _cacheHelperProportions: function() { + this.helperProportions = { + width: this.helper.outerWidth(), + height: this.helper.outerHeight() + }; + }, + + _setContainment: function() { + + var o = this.options; + if(o.containment == 'parent') o.containment = this.helper[0].parentNode; + if(o.containment == 'document' || o.containment == 'window') this.containment = [ + o.containment == 'document' ? 0 : $(window).scrollLeft() - this.offset.relative.left - this.offset.parent.left, + o.containment == 'document' ? 0 : $(window).scrollTop() - this.offset.relative.top - this.offset.parent.top, + (o.containment == 'document' ? 0 : $(window).scrollLeft()) + $(o.containment == 'document' ? document : window).width() - this.helperProportions.width - this.margins.left, + (o.containment == 'document' ? 0 : $(window).scrollTop()) + ($(o.containment == 'document' ? document : window).height() || document.body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top + ]; - if(o.cursor) { // cursor option - if ($('body').css("cursor")) this._storedCursor = $('body').css("cursor"); - $('body').css("cursor", o.cursor); - } + if(!(/^(document|window|parent)$/).test(o.containment) && o.containment.constructor != Array) { + var c = $(o.containment); + var ce = c[0]; if(!ce) return; + var co = c.offset(); + var over = ($(ce).css("overflow") != 'hidden'); - if(o.opacity) { // opacity option - if (this.helper.css("opacity")) this._storedOpacity = this.helper.css("opacity"); - this.helper.css("opacity", o.opacity); - } + this.containment = [ + (parseInt($(ce).css("borderLeftWidth"),10) || 0) + (parseInt($(ce).css("paddingLeft"),10) || 0), + (parseInt($(ce).css("borderTopWidth"),10) || 0) + (parseInt($(ce).css("paddingTop"),10) || 0), + (over ? Math.max(ce.scrollWidth,ce.offsetWidth) : ce.offsetWidth) - (parseInt($(ce).css("borderLeftWidth"),10) || 0) - (parseInt($(ce).css("paddingRight"),10) || 0) - this.helperProportions.width - this.margins.left - this.margins.right, + (over ? Math.max(ce.scrollHeight,ce.offsetHeight) : ce.offsetHeight) - (parseInt($(ce).css("borderTopWidth"),10) || 0) - (parseInt($(ce).css("paddingBottom"),10) || 0) - this.helperProportions.height - this.margins.top - this.margins.bottom + ]; + this.relative_container = c; - if(o.zIndex) { // zIndex option - if (this.helper.css("zIndex")) this._storedZIndex = this.helper.css("zIndex"); - this.helper.css("zIndex", o.zIndex); + } else if(o.containment.constructor == Array) { + this.containment = o.containment; } - //Prepare scrolling - if(this.scrollParent[0] != document && this.scrollParent[0].tagName != 'HTML') - this.overflowOffset = this.scrollParent.offset(); + }, - //Call callbacks - this._trigger("start", event, this._uiHash()); + _convertPositionTo: function(d, pos) { - //Recache the helper size - if(!this._preserveHelperProportions) - this._cacheHelperProportions(); + if(!pos) pos = this.position; + var mod = d == "absolute" ? 1 : -1; + var o = this.options, scroll = this.cssPosition == 'absolute' && !(this.scrollParent[0] != document && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName); + return { + top: ( + pos.top // The absolute mouse position + + this.offset.relative.top * mod // Only for relative positioned nodes: Relative offset from element to offset parent + + this.offset.parent.top * mod // The offsetParent's offset without borders (offset + border) + - ( ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod) + ), + left: ( + pos.left // The absolute mouse position + + this.offset.relative.left * mod // Only for relative positioned nodes: Relative offset from element to offset parent + + this.offset.parent.left * mod // The offsetParent's offset without borders (offset + border) + - ( ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) * mod) + ) + }; - //Post 'activate' events to possible containers - if(!noActivation) { - for (var i = this.containers.length - 1; i >= 0; i--) { this.containers[i]._trigger("activate", event, self._uiHash(this)); } - } + }, - //Prepare possible droppables - if($.ui.ddmanager) - $.ui.ddmanager.current = this; + _generatePosition: function(event) { - if ($.ui.ddmanager && !o.dropBehaviour) - $.ui.ddmanager.prepareOffsets(this, event); + var o = this.options, scroll = this.cssPosition == 'absolute' && !(this.scrollParent[0] != document && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName); + var pageX = event.pageX; + var pageY = event.pageY; - this.dragging = true; + /* + * - Position constraining - + * Constrain the position to a mix of grid, containment. + */ - this.helper.addClass("ui-sortable-helper"); - this._mouseDrag(event); //Execute the drag once - this causes the helper not to be visible before getting its correct position - return true; + if(this.originalPosition) { //If we are not dragging yet, we won't check for options + var containment; + if(this.containment) { + if (this.relative_container){ + var co = this.relative_container.offset(); + containment = [ this.containment[0] + co.left, + this.containment[1] + co.top, + this.containment[2] + co.left, + this.containment[3] + co.top ]; + } + else { + containment = this.containment; + } - }, + if(event.pageX - this.offset.click.left < containment[0]) pageX = containment[0] + this.offset.click.left; + if(event.pageY - this.offset.click.top < containment[1]) pageY = containment[1] + this.offset.click.top; + if(event.pageX - this.offset.click.left > containment[2]) pageX = containment[2] + this.offset.click.left; + if(event.pageY - this.offset.click.top > containment[3]) pageY = containment[3] + this.offset.click.top; + } - _mouseDrag: function(event) { + if(o.grid) { + //Check for grid elements set to 0 to prevent divide by 0 error causing invalid argument errors in IE (see ticket #6950) + var top = o.grid[1] ? this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1] : this.originalPageY; + pageY = containment ? (!(top - this.offset.click.top < containment[1] || top - this.offset.click.top > containment[3]) ? top : (!(top - this.offset.click.top < containment[1]) ? top - o.grid[1] : top + o.grid[1])) : top; - //Compute the helpers position - this.position = this._generatePosition(event); - this.positionAbs = this._convertPositionTo("absolute"); + var left = o.grid[0] ? this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0] : this.originalPageX; + pageX = containment ? (!(left - this.offset.click.left < containment[0] || left - this.offset.click.left > containment[2]) ? left : (!(left - this.offset.click.left < containment[0]) ? left - o.grid[0] : left + o.grid[0])) : left; + } - if (!this.lastPositionAbs) { - this.lastPositionAbs = this.positionAbs; } - //Do scrolling - if(this.options.scroll) { - var o = this.options, scrolled = false; - if(this.scrollParent[0] != document && this.scrollParent[0].tagName != 'HTML') { + return { + top: ( + pageY // The absolute mouse position + - this.offset.click.top // Click offset (relative to the element) + - this.offset.relative.top // Only for relative positioned nodes: Relative offset from element to offset parent + - this.offset.parent.top // The offsetParent's offset without borders (offset + border) + + ( ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) )) + ), + left: ( + pageX // The absolute mouse position + - this.offset.click.left // Click offset (relative to the element) + - this.offset.relative.left // Only for relative positioned nodes: Relative offset from element to offset parent + - this.offset.parent.left // The offsetParent's offset without borders (offset + border) + + ( ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() )) + ) + }; - if((this.overflowOffset.top + this.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity) - this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop + o.scrollSpeed; - else if(event.pageY - this.overflowOffset.top < o.scrollSensitivity) - this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop - o.scrollSpeed; + }, - if((this.overflowOffset.left + this.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity) - this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft + o.scrollSpeed; - else if(event.pageX - this.overflowOffset.left < o.scrollSensitivity) - this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft - o.scrollSpeed; + _clear: function() { + this.helper.removeClass("ui-draggable-dragging"); + if(this.helper[0] != this.element[0] && !this.cancelHelperRemoval) this.helper.remove(); + //if($.ui.ddmanager) $.ui.ddmanager.current = null; + this.helper = null; + this.cancelHelperRemoval = false; + }, - } else { + // From now on bulk stuff - mainly helpers - if(event.pageY - $(document).scrollTop() < o.scrollSensitivity) - scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed); - else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity) - scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed); + _trigger: function(type, event, ui) { + ui = ui || this._uiHash(); + $.ui.plugin.call(this, type, [event, ui]); + if(type == "drag") this.positionAbs = this._convertPositionTo("absolute"); //The absolute position has to be recalculated after plugins + return $.Widget.prototype._trigger.call(this, type, event, ui); + }, - if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity) - scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed); - else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity) - scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed); + plugins: {}, - } + _uiHash: function(event) { + return { + helper: this.helper, + position: this.position, + originalPosition: this.originalPosition, + offset: this.positionAbs + }; + } - if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) - $.ui.ddmanager.prepareOffsets(this, event); - } +}); - //Regenerate the absolute position used for position checks - this.positionAbs = this._convertPositionTo("absolute"); +$.ui.plugin.add("draggable", "connectToSortable", { + start: function(event, ui) { - //Set the helper position - if(!this.options.axis || this.options.axis != "y") this.helper[0].style.left = this.position.left+'px'; - if(!this.options.axis || this.options.axis != "x") this.helper[0].style.top = this.position.top+'px'; + var inst = $(this).data("draggable"), o = inst.options, + uiSortable = $.extend({}, ui, { item: inst.element }); + inst.sortables = []; + $(o.connectToSortable).each(function() { + var sortable = $.data(this, 'sortable'); + if (sortable && !sortable.options.disabled) { + inst.sortables.push({ + instance: sortable, + shouldRevert: sortable.options.revert + }); + sortable.refreshPositions(); // Call the sortable's refreshPositions at drag start to refresh the containerCache since the sortable container cache is used in drag and needs to be up to date (this will ensure it's initialised as well as being kept in step with any changes that might have happened on the page). + sortable._trigger("activate", event, uiSortable); + } + }); - //Rearrange - for (var i = this.items.length - 1; i >= 0; i--) { + }, + stop: function(event, ui) { - //Cache variables and intersection, continue if no intersection - var item = this.items[i], itemElement = item.item[0], intersection = this._intersectsWithPointer(item); - if (!intersection) continue; + //If we are still over the sortable, we fake the stop event of the sortable, but also remove helper + var inst = $(this).data("draggable"), + uiSortable = $.extend({}, ui, { item: inst.element }); - if(itemElement != this.currentItem[0] //cannot intersect with itself - && this.placeholder[intersection == 1 ? "next" : "prev"]()[0] != itemElement //no useless actions that have been done before - && !$.ui.contains(this.placeholder[0], itemElement) //no action if the item moved is the parent of the item checked - && (this.options.type == 'semi-dynamic' ? !$.ui.contains(this.element[0], itemElement) : true) - //&& itemElement.parentNode == this.placeholder[0].parentNode // only rearrange items within the same container - ) { + $.each(inst.sortables, function() { + if(this.instance.isOver) { - this.direction = intersection == 1 ? "down" : "up"; + this.instance.isOver = 0; - if (this.options.tolerance == "pointer" || this._intersectsWithSides(item)) { - this._rearrange(event, item); - } else { - break; - } + inst.cancelHelperRemoval = true; //Don't remove the helper in the draggable instance + this.instance.cancelHelperRemoval = false; //Remove it in the sortable instance (so sortable plugins like revert still work) - this._trigger("change", event, this._uiHash()); - break; - } - } + //The sortable revert is supported, and we have to set a temporary dropped variable on the draggable to support revert: 'valid/invalid' + if(this.shouldRevert) this.instance.options.revert = true; - //Post events to containers - this._contactContainers(event); + //Trigger the stop of the sortable + this.instance._mouseStop(event); - //Interconnect with droppables - if($.ui.ddmanager) $.ui.ddmanager.drag(this, event); + this.instance.options.helper = this.instance.options._helper; - //Call callbacks - this._trigger('sort', event, this._uiHash()); + //If the helper has been the original item, restore properties in the sortable + if(inst.options.helper == 'original') + this.instance.currentItem.css({ top: 'auto', left: 'auto' }); - this.lastPositionAbs = this.positionAbs; - return false; + } else { + this.instance.cancelHelperRemoval = false; //Remove the helper in the sortable instance + this.instance._trigger("deactivate", event, uiSortable); + } - }, + }); - _mouseStop: function(event, noPropagation) { + }, + drag: function(event, ui) { - if(!event) return; + var inst = $(this).data("draggable"), that = this; - //If we are using droppables, inform the manager about the drop - if ($.ui.ddmanager && !this.options.dropBehaviour) - $.ui.ddmanager.drop(this, event); + var checkPos = function(o) { + var dyClick = this.offset.click.top, dxClick = this.offset.click.left; + var helperTop = this.positionAbs.top, helperLeft = this.positionAbs.left; + var itemHeight = o.height, itemWidth = o.width; + var itemTop = o.top, itemLeft = o.left; - if(this.options.revert) { - var self = this; - var cur = self.placeholder.offset(); + return $.ui.isOver(helperTop + dyClick, helperLeft + dxClick, itemTop, itemLeft, itemHeight, itemWidth); + }; - self.reverting = true; + $.each(inst.sortables, function(i) { - $(this.helper).animate({ - left: cur.left - this.offset.parent.left - self.margins.left + (this.offsetParent[0] == document.body ? 0 : this.offsetParent[0].scrollLeft), - top: cur.top - this.offset.parent.top - self.margins.top + (this.offsetParent[0] == document.body ? 0 : this.offsetParent[0].scrollTop) - }, parseInt(this.options.revert, 10) || 500, function() { - self._clear(event); - }); - } else { - this._clear(event, noPropagation); - } + var innermostIntersecting = false; + var thisSortable = this; + //Copy over some variables to allow calling the sortable's native _intersectsWith + this.instance.positionAbs = inst.positionAbs; + this.instance.helperProportions = inst.helperProportions; + this.instance.offset.click = inst.offset.click; - return false; + if(this.instance._intersectsWith(this.instance.containerCache)) { + innermostIntersecting = true; + $.each(inst.sortables, function () { + this.instance.positionAbs = inst.positionAbs; + this.instance.helperProportions = inst.helperProportions; + this.instance.offset.click = inst.offset.click; + if (this != thisSortable + && this.instance._intersectsWith(this.instance.containerCache) + && $.ui.contains(thisSortable.instance.element[0], this.instance.element[0])) + innermostIntersecting = false; + return innermostIntersecting; + }); + } - }, - cancel: function() { + if(innermostIntersecting) { + //If it intersects, we use a little isOver variable and set it once, so our move-in stuff gets fired only once + if(!this.instance.isOver) { - var self = this; + this.instance.isOver = 1; + //Now we fake the start of dragging for the sortable instance, + //by cloning the list group item, appending it to the sortable and using it as inst.currentItem + //We can then fire the start event of the sortable with our passed browser event, and our own helper (so it doesn't create a new one) + this.instance.currentItem = $(that).clone().removeAttr('id').appendTo(this.instance.element).data("sortable-item", true); + this.instance.options._helper = this.instance.options.helper; //Store helper option to later restore it + this.instance.options.helper = function() { return ui.helper[0]; }; - if(this.dragging) { + event.target = this.instance.currentItem[0]; + this.instance._mouseCapture(event, true); + this.instance._mouseStart(event, true, true); - this._mouseUp({ target: null }); + //Because the browser event is way off the new appended portlet, we modify a couple of variables to reflect the changes + this.instance.offset.click.top = inst.offset.click.top; + this.instance.offset.click.left = inst.offset.click.left; + this.instance.offset.parent.left -= inst.offset.parent.left - this.instance.offset.parent.left; + this.instance.offset.parent.top -= inst.offset.parent.top - this.instance.offset.parent.top; - if(this.options.helper == "original") - this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"); - else - this.currentItem.show(); + inst._trigger("toSortable", event); + inst.dropped = this.instance.element; //draggable revert needs that + //hack so receive/update callbacks work (mostly) + inst.currentItem = inst.element; + this.instance.fromOutside = inst; - //Post deactivating events to containers - for (var i = this.containers.length - 1; i >= 0; i--){ - this.containers[i]._trigger("deactivate", null, self._uiHash(this)); - if(this.containers[i].containerCache.over) { - this.containers[i]._trigger("out", null, self._uiHash(this)); - this.containers[i].containerCache.over = 0; } - } - - } - if (this.placeholder) { - //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node! - if(this.placeholder[0].parentNode) this.placeholder[0].parentNode.removeChild(this.placeholder[0]); - if(this.options.helper != "original" && this.helper && this.helper[0].parentNode) this.helper.remove(); - - $.extend(this, { - helper: null, - dragging: false, - reverting: false, - _noFinalSort: null - }); + //Provided we did all the previous steps, we can fire the drag event of the sortable on every draggable drag, when it intersects with the sortable + if(this.instance.currentItem) this.instance._mouseDrag(event); - if(this.domPosition.prev) { - $(this.domPosition.prev).after(this.currentItem); } else { - $(this.domPosition.parent).prepend(this.currentItem); - } - } - return this; + //If it doesn't intersect with the sortable, and it intersected before, + //we fake the drag stop of the sortable, but make sure it doesn't remove the helper by using cancelHelperRemoval + if(this.instance.isOver) { - }, + this.instance.isOver = 0; + this.instance.cancelHelperRemoval = true; - serialize: function(o) { + //Prevent reverting on this forced stop + this.instance.options.revert = false; - var items = this._getItemsAsjQuery(o && o.connected); - var str = []; o = o || {}; + // The out event needs to be triggered independently + this.instance._trigger('out', event, this.instance._uiHash(this.instance)); - $(items).each(function() { - var res = ($(o.item || this).attr(o.attribute || 'id') || '').match(o.expression || (/(.+)[-=_](.+)/)); - if(res) str.push((o.key || res[1]+'[]')+'='+(o.key && o.expression ? res[1] : res[2])); - }); + this.instance._mouseStop(event, true); + this.instance.options.helper = this.instance.options._helper; - if(!str.length && o.key) { - str.push(o.key + '='); - } + //Now we remove our currentItem, the list group clone again, and the placeholder, and animate the helper back to it's original size + this.instance.currentItem.remove(); + if(this.instance.placeholder) this.instance.placeholder.remove(); - return str.join('&'); + inst._trigger("fromSortable", event); + inst.dropped = false; //draggable revert needs that + } - }, + }; - toArray: function(o) { + }); - var items = this._getItemsAsjQuery(o && o.connected); - var ret = []; o = o || {}; + } +}); - items.each(function() { ret.push($(o.item || this).attr(o.attribute || 'id') || ''); }); - return ret; +$.ui.plugin.add("draggable", "cursor", { + start: function(event, ui) { + var t = $('body'), o = $(this).data('draggable').options; + if (t.css("cursor")) o._cursor = t.css("cursor"); + t.css("cursor", o.cursor); + }, + stop: function(event, ui) { + var o = $(this).data('draggable').options; + if (o._cursor) $('body').css("cursor", o._cursor); + } +}); +$.ui.plugin.add("draggable", "opacity", { + start: function(event, ui) { + var t = $(ui.helper), o = $(this).data('draggable').options; + if(t.css("opacity")) o._opacity = t.css("opacity"); + t.css('opacity', o.opacity); }, + stop: function(event, ui) { + var o = $(this).data('draggable').options; + if(o._opacity) $(ui.helper).css('opacity', o._opacity); + } +}); - /* Be careful with the following core functions */ - _intersectsWith: function(item) { +$.ui.plugin.add("draggable", "scroll", { + start: function(event, ui) { + var i = $(this).data("draggable"); + if(i.scrollParent[0] != document && i.scrollParent[0].tagName != 'HTML') i.overflowOffset = i.scrollParent.offset(); + }, + drag: function(event, ui) { - var x1 = this.positionAbs.left, - x2 = x1 + this.helperProportions.width, - y1 = this.positionAbs.top, - y2 = y1 + this.helperProportions.height; + var i = $(this).data("draggable"), o = i.options, scrolled = false; - var l = item.left, - r = l + item.width, - t = item.top, - b = t + item.height; + if(i.scrollParent[0] != document && i.scrollParent[0].tagName != 'HTML') { - var dyClick = this.offset.click.top, - dxClick = this.offset.click.left; + if(!o.axis || o.axis != 'x') { + if((i.overflowOffset.top + i.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity) + i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop + o.scrollSpeed; + else if(event.pageY - i.overflowOffset.top < o.scrollSensitivity) + i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop - o.scrollSpeed; + } - var isOverElement = (y1 + dyClick) > t && (y1 + dyClick) < b && (x1 + dxClick) > l && (x1 + dxClick) < r; + if(!o.axis || o.axis != 'y') { + if((i.overflowOffset.left + i.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity) + i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft + o.scrollSpeed; + else if(event.pageX - i.overflowOffset.left < o.scrollSensitivity) + i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft - o.scrollSpeed; + } - if( this.options.tolerance == "pointer" - || this.options.forcePointerForContainers - || (this.options.tolerance != "pointer" && this.helperProportions[this.floating ? 'width' : 'height'] > item[this.floating ? 'width' : 'height']) - ) { - return isOverElement; } else { - return (l < x1 + (this.helperProportions.width / 2) // Right Half - && x2 - (this.helperProportions.width / 2) < r // Left Half - && t < y1 + (this.helperProportions.height / 2) // Bottom Half - && y2 - (this.helperProportions.height / 2) < b ); // Top Half + if(!o.axis || o.axis != 'x') { + if(event.pageY - $(document).scrollTop() < o.scrollSensitivity) + scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed); + else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity) + scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed); + } + + if(!o.axis || o.axis != 'y') { + if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity) + scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed); + else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity) + scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed); + } } - }, - _intersectsWithPointer: function(item) { + if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) + $.ui.ddmanager.prepareOffsets(i, event); - var isOverElementHeight = $.ui.isOverAxis(this.positionAbs.top + this.offset.click.top, item.top, item.height), - isOverElementWidth = $.ui.isOverAxis(this.positionAbs.left + this.offset.click.left, item.left, item.width), - isOverElement = isOverElementHeight && isOverElementWidth, - verticalDirection = this._getDragVerticalDirection(), - horizontalDirection = this._getDragHorizontalDirection(); + } +}); - if (!isOverElement) - return false; +$.ui.plugin.add("draggable", "snap", { + start: function(event, ui) { - return this.floating ? - ( ((horizontalDirection && horizontalDirection == "right") || verticalDirection == "down") ? 2 : 1 ) - : ( verticalDirection && (verticalDirection == "down" ? 2 : 1) ); + var i = $(this).data("draggable"), o = i.options; + i.snapElements = []; + + $(o.snap.constructor != String ? ( o.snap.items || ':data(draggable)' ) : o.snap).each(function() { + var $t = $(this); var $o = $t.offset(); + if(this != i.element[0]) i.snapElements.push({ + item: this, + width: $t.outerWidth(), height: $t.outerHeight(), + top: $o.top, left: $o.left + }); + }); }, + drag: function(event, ui) { - _intersectsWithSides: function(item) { + var inst = $(this).data("draggable"), o = inst.options; + var d = o.snapTolerance; - var isOverBottomHalf = $.ui.isOverAxis(this.positionAbs.top + this.offset.click.top, item.top + (item.height/2), item.height), - isOverRightHalf = $.ui.isOverAxis(this.positionAbs.left + this.offset.click.left, item.left + (item.width/2), item.width), - verticalDirection = this._getDragVerticalDirection(), - horizontalDirection = this._getDragHorizontalDirection(); + var x1 = ui.offset.left, x2 = x1 + inst.helperProportions.width, + y1 = ui.offset.top, y2 = y1 + inst.helperProportions.height; - if (this.floating && horizontalDirection) { - return ((horizontalDirection == "right" && isOverRightHalf) || (horizontalDirection == "left" && !isOverRightHalf)); - } else { - return verticalDirection && ((verticalDirection == "down" && isOverBottomHalf) || (verticalDirection == "up" && !isOverBottomHalf)); - } + for (var i = inst.snapElements.length - 1; i >= 0; i--){ - }, + var l = inst.snapElements[i].left, r = l + inst.snapElements[i].width, + t = inst.snapElements[i].top, b = t + inst.snapElements[i].height; + + //Yes, I know, this is insane ;) + if(!((l-d < x1 && x1 < r+d && t-d < y1 && y1 < b+d) || (l-d < x1 && x1 < r+d && t-d < y2 && y2 < b+d) || (l-d < x2 && x2 < r+d && t-d < y1 && y1 < b+d) || (l-d < x2 && x2 < r+d && t-d < y2 && y2 < b+d))) { + if(inst.snapElements[i].snapping) (inst.options.snap.release && inst.options.snap.release.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item }))); + inst.snapElements[i].snapping = false; + continue; + } + + if(o.snapMode != 'inner') { + var ts = Math.abs(t - y2) <= d; + var bs = Math.abs(b - y1) <= d; + var ls = Math.abs(l - x2) <= d; + var rs = Math.abs(r - x1) <= d; + if(ts) ui.position.top = inst._convertPositionTo("relative", { top: t - inst.helperProportions.height, left: 0 }).top - inst.margins.top; + if(bs) ui.position.top = inst._convertPositionTo("relative", { top: b, left: 0 }).top - inst.margins.top; + if(ls) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l - inst.helperProportions.width }).left - inst.margins.left; + if(rs) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r }).left - inst.margins.left; + } + + var first = (ts || bs || ls || rs); + + if(o.snapMode != 'outer') { + var ts = Math.abs(t - y1) <= d; + var bs = Math.abs(b - y2) <= d; + var ls = Math.abs(l - x1) <= d; + var rs = Math.abs(r - x2) <= d; + if(ts) ui.position.top = inst._convertPositionTo("relative", { top: t, left: 0 }).top - inst.margins.top; + if(bs) ui.position.top = inst._convertPositionTo("relative", { top: b - inst.helperProportions.height, left: 0 }).top - inst.margins.top; + if(ls) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l }).left - inst.margins.left; + if(rs) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r - inst.helperProportions.width }).left - inst.margins.left; + } + + if(!inst.snapElements[i].snapping && (ts || bs || ls || rs || first)) + (inst.options.snap.snap && inst.options.snap.snap.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item }))); + inst.snapElements[i].snapping = (ts || bs || ls || rs || first); + + }; - _getDragVerticalDirection: function() { - var delta = this.positionAbs.top - this.lastPositionAbs.top; - return delta != 0 && (delta > 0 ? "down" : "up"); - }, + } +}); - _getDragHorizontalDirection: function() { - var delta = this.positionAbs.left - this.lastPositionAbs.left; - return delta != 0 && (delta > 0 ? "right" : "left"); - }, +$.ui.plugin.add("draggable", "stack", { + start: function(event, ui) { - refresh: function(event) { - this._refreshItems(event); - this.refreshPositions(); - return this; - }, + var o = $(this).data("draggable").options; - _connectWith: function() { - var options = this.options; - return options.connectWith.constructor == String - ? [options.connectWith] - : options.connectWith; - }, - - _getItemsAsjQuery: function(connected) { + var group = $.makeArray($(o.stack)).sort(function(a,b) { + return (parseInt($(a).css("zIndex"),10) || 0) - (parseInt($(b).css("zIndex"),10) || 0); + }); + if (!group.length) { return; } - var self = this; - var items = []; - var queries = []; - var connectWith = this._connectWith(); + var min = parseInt(group[0].style.zIndex) || 0; + $(group).each(function(i) { + this.style.zIndex = min + i; + }); - if(connectWith && connected) { - for (var i = connectWith.length - 1; i >= 0; i--){ - var cur = $(connectWith[i]); - for (var j = cur.length - 1; j >= 0; j--){ - var inst = $.data(cur[j], 'sortable'); - if(inst && inst != this && !inst.options.disabled) { - queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element) : $(inst.options.items, inst.element).not(".ui-sortable-helper").not('.ui-sortable-placeholder'), inst]); - } - }; - }; - } + this[0].style.zIndex = min + group.length; - queries.push([$.isFunction(this.options.items) ? this.options.items.call(this.element, null, { options: this.options, item: this.currentItem }) : $(this.options.items, this.element).not(".ui-sortable-helper").not('.ui-sortable-placeholder'), this]); + } +}); - for (var i = queries.length - 1; i >= 0; i--){ - queries[i][0].each(function() { - items.push(this); - }); - }; +$.ui.plugin.add("draggable", "zIndex", { + start: function(event, ui) { + var t = $(ui.helper), o = $(this).data("draggable").options; + if(t.css("zIndex")) o._zIndex = t.css("zIndex"); + t.css('zIndex', o.zIndex); + }, + stop: function(event, ui) { + var o = $(this).data("draggable").options; + if(o._zIndex) $(ui.helper).css('zIndex', o._zIndex); + } +}); - return $(items); +})(jQuery); +(function( $, undefined ) { +$.widget("ui.droppable", { + version: "1.9.2", + widgetEventPrefix: "drop", + options: { + accept: '*', + activeClass: false, + addClasses: true, + greedy: false, + hoverClass: false, + scope: 'default', + tolerance: 'intersect' }, + _create: function() { - _removeCurrentsFromItems: function() { + var o = this.options, accept = o.accept; + this.isover = 0; this.isout = 1; - var list = this.currentItem.find(":data(sortable-item)"); + this.accept = $.isFunction(accept) ? accept : function(d) { + return d.is(accept); + }; - for (var i=0; i < this.items.length; i++) { + //Store the droppable's proportions + this.proportions = { width: this.element[0].offsetWidth, height: this.element[0].offsetHeight }; - for (var j=0; j < list.length; j++) { - if(list[j] == this.items[i].item[0]) - this.items.splice(i,1); - }; + // Add the reference and positions to the manager + $.ui.ddmanager.droppables[o.scope] = $.ui.ddmanager.droppables[o.scope] || []; + $.ui.ddmanager.droppables[o.scope].push(this); - }; + (o.addClasses && this.element.addClass("ui-droppable")); }, - _refreshItems: function(event) { + _destroy: function() { + var drop = $.ui.ddmanager.droppables[this.options.scope]; + for ( var i = 0; i < drop.length; i++ ) + if ( drop[i] == this ) + drop.splice(i, 1); - this.items = []; - this.containers = [this]; - var items = this.items; - var self = this; - var queries = [[$.isFunction(this.options.items) ? this.options.items.call(this.element[0], event, { item: this.currentItem }) : $(this.options.items, this.element), this]]; - var connectWith = this._connectWith(); + this.element.removeClass("ui-droppable ui-droppable-disabled"); + }, - if(connectWith) { - for (var i = connectWith.length - 1; i >= 0; i--){ - var cur = $(connectWith[i]); - for (var j = cur.length - 1; j >= 0; j--){ - var inst = $.data(cur[j], 'sortable'); - if(inst && inst != this && !inst.options.disabled) { - queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element[0], event, { item: this.currentItem }) : $(inst.options.items, inst.element), inst]); - this.containers.push(inst); - } - }; + _setOption: function(key, value) { + + if(key == 'accept') { + this.accept = $.isFunction(value) ? value : function(d) { + return d.is(value); }; } + $.Widget.prototype._setOption.apply(this, arguments); + }, - for (var i = queries.length - 1; i >= 0; i--) { - var targetData = queries[i][1]; - var _queries = queries[i][0]; + _activate: function(event) { + var draggable = $.ui.ddmanager.current; + if(this.options.activeClass) this.element.addClass(this.options.activeClass); + (draggable && this._trigger('activate', event, this.ui(draggable))); + }, - for (var j=0, queriesLength = _queries.length; j < queriesLength; j++) { - var item = $(_queries[j]); + _deactivate: function(event) { + var draggable = $.ui.ddmanager.current; + if(this.options.activeClass) this.element.removeClass(this.options.activeClass); + (draggable && this._trigger('deactivate', event, this.ui(draggable))); + }, - item.data('sortable-item', targetData); // Data for target checking (mouse manager) + _over: function(event) { - items.push({ - item: item, - instance: targetData, - width: 0, height: 0, - left: 0, top: 0 - }); - }; - }; + var draggable = $.ui.ddmanager.current; + if (!draggable || (draggable.currentItem || draggable.element)[0] == this.element[0]) return; // Bail if draggable and droppable are same element + + if (this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) { + if(this.options.hoverClass) this.element.addClass(this.options.hoverClass); + this._trigger('over', event, this.ui(draggable)); + } }, - refreshPositions: function(fast) { + _out: function(event) { - //This has to be redone because due to the item being moved out/into the offsetParent, the offsetParent's position will change - if(this.offsetParent && this.helper) { - this.offset.parent = this._getParentOffset(); - } + var draggable = $.ui.ddmanager.current; + if (!draggable || (draggable.currentItem || draggable.element)[0] == this.element[0]) return; // Bail if draggable and droppable are same element - for (var i = this.items.length - 1; i >= 0; i--){ - var item = this.items[i]; + if (this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) { + if(this.options.hoverClass) this.element.removeClass(this.options.hoverClass); + this._trigger('out', event, this.ui(draggable)); + } - //We ignore calculating positions of all connected containers when we're not over them - if(item.instance != this.currentContainer && this.currentContainer && item.item[0] != this.currentItem[0]) - continue; + }, - var t = this.options.toleranceElement ? $(this.options.toleranceElement, item.item) : item.item; + _drop: function(event,custom) { - if (!fast) { - item.width = t.outerWidth(); - item.height = t.outerHeight(); - } + var draggable = custom || $.ui.ddmanager.current; + if (!draggable || (draggable.currentItem || draggable.element)[0] == this.element[0]) return false; // Bail if draggable and droppable are same element - var p = t.offset(); - item.left = p.left; - item.top = p.top; - }; + var childrenIntersection = false; + this.element.find(":data(droppable)").not(".ui-draggable-dragging").each(function() { + var inst = $.data(this, 'droppable'); + if( + inst.options.greedy + && !inst.options.disabled + && inst.options.scope == draggable.options.scope + && inst.accept.call(inst.element[0], (draggable.currentItem || draggable.element)) + && $.ui.intersect(draggable, $.extend(inst, { offset: inst.element.offset() }), inst.options.tolerance) + ) { childrenIntersection = true; return false; } + }); + if(childrenIntersection) return false; - if(this.options.custom && this.options.custom.refreshContainers) { - this.options.custom.refreshContainers.call(this); - } else { - for (var i = this.containers.length - 1; i >= 0; i--){ - var p = this.containers[i].element.offset(); - this.containers[i].containerCache.left = p.left; - this.containers[i].containerCache.top = p.top; - this.containers[i].containerCache.width = this.containers[i].element.outerWidth(); - this.containers[i].containerCache.height = this.containers[i].element.outerHeight(); - }; + if(this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) { + if(this.options.activeClass) this.element.removeClass(this.options.activeClass); + if(this.options.hoverClass) this.element.removeClass(this.options.hoverClass); + this._trigger('drop', event, this.ui(draggable)); + return this.element; } - return this; - }, - - _createPlaceholder: function(that) { + return false; - var self = that || this, o = self.options; + }, - if(!o.placeholder || o.placeholder.constructor == String) { - var className = o.placeholder; - o.placeholder = { - element: function() { + ui: function(c) { + return { + draggable: (c.currentItem || c.element), + helper: c.helper, + position: c.position, + offset: c.positionAbs + }; + } - var el = $(document.createElement(self.currentItem[0].nodeName)) - .addClass(className || self.currentItem[0].className+" ui-sortable-placeholder") - .removeClass("ui-sortable-helper")[0]; +}); - if(!className) - el.style.visibility = "hidden"; +$.ui.intersect = function(draggable, droppable, toleranceMode) { - return el; - }, - update: function(container, p) { + if (!droppable.offset) return false; - // 1. If a className is set as 'placeholder option, we don't force sizes - the class is responsible for that - // 2. The option 'forcePlaceholderSize can be enabled to force it even if a class name is specified - if(className && !o.forcePlaceholderSize) return; + var x1 = (draggable.positionAbs || draggable.position.absolute).left, x2 = x1 + draggable.helperProportions.width, + y1 = (draggable.positionAbs || draggable.position.absolute).top, y2 = y1 + draggable.helperProportions.height; + var l = droppable.offset.left, r = l + droppable.proportions.width, + t = droppable.offset.top, b = t + droppable.proportions.height; - //If the element doesn't have a actual height by itself (without styles coming from a stylesheet), it receives the inline height from the dragged item - if(!p.height()) { p.height(self.currentItem.innerHeight() - parseInt(self.currentItem.css('paddingTop')||0, 10) - parseInt(self.currentItem.css('paddingBottom')||0, 10)); }; - if(!p.width()) { p.width(self.currentItem.innerWidth() - parseInt(self.currentItem.css('paddingLeft')||0, 10) - parseInt(self.currentItem.css('paddingRight')||0, 10)); }; - } - }; + switch (toleranceMode) { + case 'fit': + return (l <= x1 && x2 <= r + && t <= y1 && y2 <= b); + break; + case 'intersect': + return (l < x1 + (draggable.helperProportions.width / 2) // Right Half + && x2 - (draggable.helperProportions.width / 2) < r // Left Half + && t < y1 + (draggable.helperProportions.height / 2) // Bottom Half + && y2 - (draggable.helperProportions.height / 2) < b ); // Top Half + break; + case 'pointer': + var draggableLeft = ((draggable.positionAbs || draggable.position.absolute).left + (draggable.clickOffset || draggable.offset.click).left), + draggableTop = ((draggable.positionAbs || draggable.position.absolute).top + (draggable.clickOffset || draggable.offset.click).top), + isOver = $.ui.isOver(draggableTop, draggableLeft, t, l, droppable.proportions.height, droppable.proportions.width); + return isOver; + break; + case 'touch': + return ( + (y1 >= t && y1 <= b) || // Top edge touching + (y2 >= t && y2 <= b) || // Bottom edge touching + (y1 < t && y2 > b) // Surrounded vertically + ) && ( + (x1 >= l && x1 <= r) || // Left edge touching + (x2 >= l && x2 <= r) || // Right edge touching + (x1 < l && x2 > r) // Surrounded horizontally + ); + break; + default: + return false; + break; } - //Create the placeholder - self.placeholder = $(o.placeholder.element.call(self.element, self.currentItem)); - - //Append it after the actual current item - self.currentItem.after(self.placeholder); - - //Update the size of the placeholder (TODO: Logic to fuzzy, see line 316/317) - o.placeholder.update(self, self.placeholder); +}; - }, +/* + This manager tracks offsets of draggables and droppables +*/ +$.ui.ddmanager = { + current: null, + droppables: { 'default': [] }, + prepareOffsets: function(t, event) { - _contactContainers: function(event) { - - // get innermost container that intersects with item - var innermostContainer = null, innermostIndex = null; - - - for (var i = this.containers.length - 1; i >= 0; i--){ + var m = $.ui.ddmanager.droppables[t.options.scope] || []; + var type = event ? event.type : null; // workaround for #2317 + var list = (t.currentItem || t.element).find(":data(droppable)").andSelf(); - // never consider a container that's located within the item itself - if($.ui.contains(this.currentItem[0], this.containers[i].element[0])) - continue; + droppablesLoop: for (var i = 0; i < m.length; i++) { - if(this._intersectsWith(this.containers[i].containerCache)) { + if(m[i].options.disabled || (t && !m[i].accept.call(m[i].element[0],(t.currentItem || t.element)))) continue; //No disabled and non-accepted + for (var j=0; j < list.length; j++) { if(list[j] == m[i].element[0]) { m[i].proportions.height = 0; continue droppablesLoop; } }; //Filter out elements in the current dragged item + m[i].visible = m[i].element.css("display") != "none"; if(!m[i].visible) continue; //If the element is not visible, continue - // if we've already found a container and it's more "inner" than this, then continue - if(innermostContainer && $.ui.contains(this.containers[i].element[0], innermostContainer.element[0])) - continue; + if(type == "mousedown") m[i]._activate.call(m[i], event); //Activate the droppable if used directly from draggables - innermostContainer = this.containers[i]; - innermostIndex = i; - - } else { - // container doesn't intersect. trigger "out" event if necessary - if(this.containers[i].containerCache.over) { - this.containers[i]._trigger("out", event, this._uiHash(this)); - this.containers[i].containerCache.over = 0; - } - } + m[i].offset = m[i].element.offset(); + m[i].proportions = { width: m[i].element[0].offsetWidth, height: m[i].element[0].offsetHeight }; } - - // if no intersecting containers found, return - if(!innermostContainer) return; - // move the item into the container if it's not there already - if(this.containers.length === 1) { - this.containers[innermostIndex]._trigger("over", event, this._uiHash(this)); - this.containers[innermostIndex].containerCache.over = 1; - } else if(this.currentContainer != this.containers[innermostIndex]) { - - //When entering a new container, we will find the item with the least distance and append our item near it - var dist = 10000; var itemWithLeastDistance = null; var base = this.positionAbs[this.containers[innermostIndex].floating ? 'left' : 'top']; - for (var j = this.items.length - 1; j >= 0; j--) { - if(!$.ui.contains(this.containers[innermostIndex].element[0], this.items[j].item[0])) continue; - var cur = this.items[j][this.containers[innermostIndex].floating ? 'left' : 'top']; - if(Math.abs(cur - base) < dist) { - dist = Math.abs(cur - base); itemWithLeastDistance = this.items[j]; - } - } - - if(!itemWithLeastDistance && !this.options.dropOnEmpty) //Check if dropOnEmpty is enabled - return; - - this.currentContainer = this.containers[innermostIndex]; - itemWithLeastDistance ? this._rearrange(event, itemWithLeastDistance, null, true) : this._rearrange(event, null, this.containers[innermostIndex].element, true); - this._trigger("change", event, this._uiHash()); - this.containers[innermostIndex]._trigger("change", event, this._uiHash(this)); - - //Update the placeholder - this.options.placeholder.update(this.currentContainer, this.placeholder); - - this.containers[innermostIndex]._trigger("over", event, this._uiHash(this)); - this.containers[innermostIndex].containerCache.over = 1; - } - - }, + drop: function(draggable, event) { - _createHelper: function(event) { - - var o = this.options; - var helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event, this.currentItem])) : (o.helper == 'clone' ? this.currentItem.clone() : this.currentItem); - - if(!helper.parents('body').length) //Add the helper to the DOM if that didn't happen already - $(o.appendTo != 'parent' ? o.appendTo : this.currentItem[0].parentNode)[0].appendChild(helper[0]); + var dropped = false; + $.each($.ui.ddmanager.droppables[draggable.options.scope] || [], function() { - if(helper[0] == this.currentItem[0]) - this._storedCSS = { width: this.currentItem[0].style.width, height: this.currentItem[0].style.height, position: this.currentItem.css("position"), top: this.currentItem.css("top"), left: this.currentItem.css("left") }; + if(!this.options) return; + if (!this.options.disabled && this.visible && $.ui.intersect(draggable, this, this.options.tolerance)) + dropped = this._drop.call(this, event) || dropped; - if(helper[0].style.width == '' || o.forceHelperSize) helper.width(this.currentItem.width()); - if(helper[0].style.height == '' || o.forceHelperSize) helper.height(this.currentItem.height()); + if (!this.options.disabled && this.visible && this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) { + this.isout = 1; this.isover = 0; + this._deactivate.call(this, event); + } - return helper; + }); + return dropped; }, - - _adjustOffsetFromHelper: function(obj) { - if (typeof obj == 'string') { - obj = obj.split(' '); - } - if ($.isArray(obj)) { - obj = {left: +obj[0], top: +obj[1] || 0}; - } - if ('left' in obj) { - this.offset.click.left = obj.left + this.margins.left; - } - if ('right' in obj) { - this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left; - } - if ('top' in obj) { - this.offset.click.top = obj.top + this.margins.top; - } - if ('bottom' in obj) { - this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top; - } + dragStart: function( draggable, event ) { + //Listen for scrolling so that if the dragging causes scrolling the position of the droppables can be recalculated (see #5003) + draggable.element.parentsUntil( "body" ).bind( "scroll.droppable", function() { + if( !draggable.options.refreshPositions ) $.ui.ddmanager.prepareOffsets( draggable, event ); + }); }, + drag: function(draggable, event) { - _getParentOffset: function() { - + //If you have a highly dynamic page, you might try this option. It renders positions every time you move the mouse. + if(draggable.options.refreshPositions) $.ui.ddmanager.prepareOffsets(draggable, event); - //Get the offsetParent and cache its position - this.offsetParent = this.helper.offsetParent(); - var po = this.offsetParent.offset(); + //Run through all droppables and check their positions based on specific tolerance options + $.each($.ui.ddmanager.droppables[draggable.options.scope] || [], function() { - // This is a special case where we need to modify a offset calculated on start, since the following happened: - // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent - // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that - // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag - if(this.cssPosition == 'absolute' && this.scrollParent[0] != document && $.ui.contains(this.scrollParent[0], this.offsetParent[0])) { - po.left += this.scrollParent.scrollLeft(); - po.top += this.scrollParent.scrollTop(); - } + if(this.options.disabled || this.greedyChild || !this.visible) return; + var intersects = $.ui.intersect(draggable, this, this.options.tolerance); - if((this.offsetParent[0] == document.body) //This needs to be actually done for all browsers, since pageX/pageY includes this information - || (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() == 'html' && $.browser.msie)) //Ugly IE fix - po = { top: 0, left: 0 }; + var c = !intersects && this.isover == 1 ? 'isout' : (intersects && this.isover == 0 ? 'isover' : null); + if(!c) return; - return { - top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0), - left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0) - }; + var parentInstance; + if (this.options.greedy) { + // find droppable parents with same scope + var scope = this.options.scope; + var parent = this.element.parents(':data(droppable)').filter(function () { + return $.data(this, 'droppable').options.scope === scope; + }); - }, + if (parent.length) { + parentInstance = $.data(parent[0], 'droppable'); + parentInstance.greedyChild = (c == 'isover' ? 1 : 0); + } + } - _getRelativeOffset: function() { + // we just moved into a greedy child + if (parentInstance && c == 'isover') { + parentInstance['isover'] = 0; + parentInstance['isout'] = 1; + parentInstance._out.call(parentInstance, event); + } - if(this.cssPosition == "relative") { - var p = this.currentItem.position(); - return { - top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(), - left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft() - }; - } else { - return { top: 0, left: 0 }; - } + this[c] = 1; this[c == 'isout' ? 'isover' : 'isout'] = 0; + this[c == "isover" ? "_over" : "_out"].call(this, event); - }, + // we just moved out of a greedy child + if (parentInstance && c == 'isout') { + parentInstance['isout'] = 0; + parentInstance['isover'] = 1; + parentInstance._over.call(parentInstance, event); + } + }); - _cacheMargins: function() { - this.margins = { - left: (parseInt(this.currentItem.css("marginLeft"),10) || 0), - top: (parseInt(this.currentItem.css("marginTop"),10) || 0) - }; }, + dragStop: function( draggable, event ) { + draggable.element.parentsUntil( "body" ).unbind( "scroll.droppable" ); + //Call prepareOffsets one final time since IE does not fire return scroll events when overflow was caused by drag (see #5003) + if( !draggable.options.refreshPositions ) $.ui.ddmanager.prepareOffsets( draggable, event ); + } +}; - _cacheHelperProportions: function() { - this.helperProportions = { - width: this.helper.outerWidth(), - height: this.helper.outerHeight() - }; - }, +})(jQuery); +;(jQuery.effects || (function($, undefined) { - _setContainment: function() { +var backCompat = $.uiBackCompat !== false, + // prefix used for storing data on .data() + dataSpace = "ui-effects-"; - var o = this.options; - if(o.containment == 'parent') o.containment = this.helper[0].parentNode; - if(o.containment == 'document' || o.containment == 'window') this.containment = [ - 0 - this.offset.relative.left - this.offset.parent.left, - 0 - this.offset.relative.top - this.offset.parent.top, - $(o.containment == 'document' ? document : window).width() - this.helperProportions.width - this.margins.left, - ($(o.containment == 'document' ? document : window).height() || document.body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top - ]; +$.effects = { + effect: {} +}; - if(!(/^(document|window|parent)$/).test(o.containment)) { - var ce = $(o.containment)[0]; - var co = $(o.containment).offset(); - var over = ($(ce).css("overflow") != 'hidden'); +/*! + * jQuery Color Animations v2.0.0 + * http://jquery.com/ + * + * Copyright 2012 jQuery Foundation and other contributors + * Released under the MIT license. + * http://jquery.org/license + * + * Date: Mon Aug 13 13:41:02 2012 -0500 + */ +(function( jQuery, undefined ) { + + var stepHooks = "backgroundColor borderBottomColor borderLeftColor borderRightColor borderTopColor color columnRuleColor outlineColor textDecorationColor textEmphasisColor".split(" "), + + // plusequals test for += 100 -= 100 + rplusequals = /^([\-+])=\s*(\d+\.?\d*)/, + // a set of RE's that can match strings and generate color tuples. + stringParsers = [{ + re: /rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d+(?:\.\d+)?)\s*)?\)/, + parse: function( execResult ) { + return [ + execResult[ 1 ], + execResult[ 2 ], + execResult[ 3 ], + execResult[ 4 ] + ]; + } + }, { + re: /rgba?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d+(?:\.\d+)?)\s*)?\)/, + parse: function( execResult ) { + return [ + execResult[ 1 ] * 2.55, + execResult[ 2 ] * 2.55, + execResult[ 3 ] * 2.55, + execResult[ 4 ] + ]; + } + }, { + // this regex ignores A-F because it's compared against an already lowercased string + re: /#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})/, + parse: function( execResult ) { + return [ + parseInt( execResult[ 1 ], 16 ), + parseInt( execResult[ 2 ], 16 ), + parseInt( execResult[ 3 ], 16 ) + ]; + } + }, { + // this regex ignores A-F because it's compared against an already lowercased string + re: /#([a-f0-9])([a-f0-9])([a-f0-9])/, + parse: function( execResult ) { + return [ + parseInt( execResult[ 1 ] + execResult[ 1 ], 16 ), + parseInt( execResult[ 2 ] + execResult[ 2 ], 16 ), + parseInt( execResult[ 3 ] + execResult[ 3 ], 16 ) + ]; + } + }, { + re: /hsla?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d+(?:\.\d+)?)\s*)?\)/, + space: "hsla", + parse: function( execResult ) { + return [ + execResult[ 1 ], + execResult[ 2 ] / 100, + execResult[ 3 ] / 100, + execResult[ 4 ] + ]; + } + }], + + // jQuery.Color( ) + color = jQuery.Color = function( color, green, blue, alpha ) { + return new jQuery.Color.fn.parse( color, green, blue, alpha ); + }, + spaces = { + rgba: { + props: { + red: { + idx: 0, + type: "byte" + }, + green: { + idx: 1, + type: "byte" + }, + blue: { + idx: 2, + type: "byte" + } + } + }, - this.containment = [ - co.left + (parseInt($(ce).css("borderLeftWidth"),10) || 0) + (parseInt($(ce).css("paddingLeft"),10) || 0) - this.margins.left, - co.top + (parseInt($(ce).css("borderTopWidth"),10) || 0) + (parseInt($(ce).css("paddingTop"),10) || 0) - this.margins.top, - co.left+(over ? Math.max(ce.scrollWidth,ce.offsetWidth) : ce.offsetWidth) - (parseInt($(ce).css("borderLeftWidth"),10) || 0) - (parseInt($(ce).css("paddingRight"),10) || 0) - this.helperProportions.width - this.margins.left, - co.top+(over ? Math.max(ce.scrollHeight,ce.offsetHeight) : ce.offsetHeight) - (parseInt($(ce).css("borderTopWidth"),10) || 0) - (parseInt($(ce).css("paddingBottom"),10) || 0) - this.helperProportions.height - this.margins.top - ]; + hsla: { + props: { + hue: { + idx: 0, + type: "degrees" + }, + saturation: { + idx: 1, + type: "percent" + }, + lightness: { + idx: 2, + type: "percent" + } + } } - }, + propTypes = { + "byte": { + floor: true, + max: 255 + }, + "percent": { + max: 1 + }, + "degrees": { + mod: 360, + floor: true + } + }, + support = color.support = {}, - _convertPositionTo: function(d, pos) { - - if(!pos) pos = this.position; - var mod = d == "absolute" ? 1 : -1; - var o = this.options, scroll = this.cssPosition == 'absolute' && !(this.scrollParent[0] != document && $.ui.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName); - - return { - top: ( - pos.top // The absolute mouse position - + this.offset.relative.top * mod // Only for relative positioned nodes: Relative offset from element to offset parent - + this.offset.parent.top * mod // The offsetParent's offset without borders (offset + border) - - ($.browser.safari && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod) - ), - left: ( - pos.left // The absolute mouse position - + this.offset.relative.left * mod // Only for relative positioned nodes: Relative offset from element to offset parent - + this.offset.parent.left * mod // The offsetParent's offset without borders (offset + border) - - ($.browser.safari && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) * mod) - ) - }; + // element for support tests + supportElem = jQuery( "

    " )[ 0 ], - }, + // colors = jQuery.Color.names + colors, - _generatePosition: function(event) { + // local aliases of functions called often + each = jQuery.each; - var o = this.options, scroll = this.cssPosition == 'absolute' && !(this.scrollParent[0] != document && $.ui.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName); +// determine rgba support immediately +supportElem.style.cssText = "background-color:rgba(1,1,1,.5)"; +support.rgba = supportElem.style.backgroundColor.indexOf( "rgba" ) > -1; - // This is another very weird special case that only happens for relative elements: - // 1. If the css position is relative - // 2. and the scroll parent is the document or similar to the offset parent - // we have to refresh the relative offset during the scroll so there are no jumps - if(this.cssPosition == 'relative' && !(this.scrollParent[0] != document && this.scrollParent[0] != this.offsetParent[0])) { - this.offset.relative = this._getRelativeOffset(); - } +// define cache name and alpha properties +// for rgba and hsla spaces +each( spaces, function( spaceName, space ) { + space.cache = "_" + spaceName; + space.props.alpha = { + idx: 3, + type: "percent", + def: 1 + }; +}); - var pageX = event.pageX; - var pageY = event.pageY; +function clamp( value, prop, allowEmpty ) { + var type = propTypes[ prop.type ] || {}; - /* - * - Position constraining - - * Constrain the position to a mix of grid, containment. - */ + if ( value == null ) { + return (allowEmpty || !prop.def) ? null : prop.def; + } - if(this.originalPosition) { //If we are not dragging yet, we won't check for options + // ~~ is an short way of doing floor for positive numbers + value = type.floor ? ~~value : parseFloat( value ); - if(this.containment) { - if(event.pageX - this.offset.click.left < this.containment[0]) pageX = this.containment[0] + this.offset.click.left; - if(event.pageY - this.offset.click.top < this.containment[1]) pageY = this.containment[1] + this.offset.click.top; - if(event.pageX - this.offset.click.left > this.containment[2]) pageX = this.containment[2] + this.offset.click.left; - if(event.pageY - this.offset.click.top > this.containment[3]) pageY = this.containment[3] + this.offset.click.top; - } + // IE will pass in empty strings as value for alpha, + // which will hit this case + if ( isNaN( value ) ) { + return prop.def; + } - if(o.grid) { - var top = this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1]; - pageY = this.containment ? (!(top - this.offset.click.top < this.containment[1] || top - this.offset.click.top > this.containment[3]) ? top : (!(top - this.offset.click.top < this.containment[1]) ? top - o.grid[1] : top + o.grid[1])) : top; + if ( type.mod ) { + // we add mod before modding to make sure that negatives values + // get converted properly: -10 -> 350 + return (value + type.mod) % type.mod; + } - var left = this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0]; - pageX = this.containment ? (!(left - this.offset.click.left < this.containment[0] || left - this.offset.click.left > this.containment[2]) ? left : (!(left - this.offset.click.left < this.containment[0]) ? left - o.grid[0] : left + o.grid[0])) : left; - } + // for now all property types without mod have min and max + return 0 > value ? 0 : type.max < value ? type.max : value; +} - } +function stringParse( string ) { + var inst = color(), + rgba = inst._rgba = []; - return { - top: ( - pageY // The absolute mouse position - - this.offset.click.top // Click offset (relative to the element) - - this.offset.relative.top // Only for relative positioned nodes: Relative offset from element to offset parent - - this.offset.parent.top // The offsetParent's offset without borders (offset + border) - + ($.browser.safari && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) )) - ), - left: ( - pageX // The absolute mouse position - - this.offset.click.left // Click offset (relative to the element) - - this.offset.relative.left // Only for relative positioned nodes: Relative offset from element to offset parent - - this.offset.parent.left // The offsetParent's offset without borders (offset + border) - + ($.browser.safari && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() )) - ) - }; + string = string.toLowerCase(); - }, + each( stringParsers, function( i, parser ) { + var parsed, + match = parser.re.exec( string ), + values = match && parser.parse( match ), + spaceName = parser.space || "rgba"; - _rearrange: function(event, i, a, hardRefresh) { + if ( values ) { + parsed = inst[ spaceName ]( values ); - a ? a[0].appendChild(this.placeholder[0]) : i.item[0].parentNode.insertBefore(this.placeholder[0], (this.direction == 'down' ? i.item[0] : i.item[0].nextSibling)); + // if this was an rgba parse the assignment might happen twice + // oh well.... + inst[ spaces[ spaceName ].cache ] = parsed[ spaces[ spaceName ].cache ]; + rgba = inst._rgba = parsed._rgba; - //Various things done here to improve the performance: - // 1. we create a setTimeout, that calls refreshPositions - // 2. on the instance, we have a counter variable, that get's higher after every append - // 3. on the local scope, we copy the counter variable, and check in the timeout, if it's still the same - // 4. this lets only the last addition to the timeout stack through - this.counter = this.counter ? ++this.counter : 1; - var self = this, counter = this.counter; + // exit each( stringParsers ) here because we matched + return false; + } + }); - window.setTimeout(function() { - if(counter == self.counter) self.refreshPositions(!hardRefresh); //Precompute after each DOM insertion, NOT on mousemove - },0); + // Found a stringParser that handled it + if ( rgba.length ) { - }, + // if this came from a parsed string, force "transparent" when alpha is 0 + // chrome, (and maybe others) return "transparent" as rgba(0,0,0,0) + if ( rgba.join() === "0,0,0,0" ) { + jQuery.extend( rgba, colors.transparent ); + } + return inst; + } - _clear: function(event, noPropagation) { + // named colors + return colors[ string ]; +} - this.reverting = false; - // We delay all events that have to be triggered to after the point where the placeholder has been removed and - // everything else normalized again - var delayedTriggers = [], self = this; +color.fn = jQuery.extend( color.prototype, { + parse: function( red, green, blue, alpha ) { + if ( red === undefined ) { + this._rgba = [ null, null, null, null ]; + return this; + } + if ( red.jquery || red.nodeType ) { + red = jQuery( red ).css( green ); + green = undefined; + } - // We first have to update the dom position of the actual currentItem - // Note: don't do it if the current item is already removed (by a user), or it gets reappended (see #4088) - if(!this._noFinalSort && this.currentItem.parent().length) this.placeholder.before(this.currentItem); - this._noFinalSort = null; + var inst = this, + type = jQuery.type( red ), + rgba = this._rgba = []; - if(this.helper[0] == this.currentItem[0]) { - for(var i in this._storedCSS) { - if(this._storedCSS[i] == 'auto' || this._storedCSS[i] == 'static') this._storedCSS[i] = ''; - } - this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"); - } else { - this.currentItem.show(); + // more than 1 argument specified - assume ( red, green, blue, alpha ) + if ( green !== undefined ) { + red = [ red, green, blue, alpha ]; + type = "array"; } - if(this.fromOutside && !noPropagation) delayedTriggers.push(function(event) { this._trigger("receive", event, this._uiHash(this.fromOutside)); }); - if((this.fromOutside || this.domPosition.prev != this.currentItem.prev().not(".ui-sortable-helper")[0] || this.domPosition.parent != this.currentItem.parent()[0]) && !noPropagation) delayedTriggers.push(function(event) { this._trigger("update", event, this._uiHash()); }); //Trigger update callback if the DOM position has changed - if(!$.ui.contains(this.element[0], this.currentItem[0])) { //Node was moved out of the current element - if(!noPropagation) delayedTriggers.push(function(event) { this._trigger("remove", event, this._uiHash()); }); - for (var i = this.containers.length - 1; i >= 0; i--){ - if($.ui.contains(this.containers[i].element[0], this.currentItem[0]) && !noPropagation) { - delayedTriggers.push((function(c) { return function(event) { c._trigger("receive", event, this._uiHash(this)); }; }).call(this, this.containers[i])); - delayedTriggers.push((function(c) { return function(event) { c._trigger("update", event, this._uiHash(this)); }; }).call(this, this.containers[i])); - } - }; - }; + if ( type === "string" ) { + return this.parse( stringParse( red ) || colors._default ); + } - //Post events to containers - for (var i = this.containers.length - 1; i >= 0; i--){ - if(!noPropagation) delayedTriggers.push((function(c) { return function(event) { c._trigger("deactivate", event, this._uiHash(this)); }; }).call(this, this.containers[i])); - if(this.containers[i].containerCache.over) { - delayedTriggers.push((function(c) { return function(event) { c._trigger("out", event, this._uiHash(this)); }; }).call(this, this.containers[i])); - this.containers[i].containerCache.over = 0; - } + if ( type === "array" ) { + each( spaces.rgba.props, function( key, prop ) { + rgba[ prop.idx ] = clamp( red[ prop.idx ], prop ); + }); + return this; } - //Do what was originally in plugins - if(this._storedCursor) $('body').css("cursor", this._storedCursor); //Reset cursor - if(this._storedOpacity) this.helper.css("opacity", this._storedOpacity); //Reset opacity - if(this._storedZIndex) this.helper.css("zIndex", this._storedZIndex == 'auto' ? '' : this._storedZIndex); //Reset z-index + if ( type === "object" ) { + if ( red instanceof color ) { + each( spaces, function( spaceName, space ) { + if ( red[ space.cache ] ) { + inst[ space.cache ] = red[ space.cache ].slice(); + } + }); + } else { + each( spaces, function( spaceName, space ) { + var cache = space.cache; + each( space.props, function( key, prop ) { - this.dragging = false; - if(this.cancelHelperRemoval) { - if(!noPropagation) { - this._trigger("beforeStop", event, this._uiHash()); - for (var i=0; i < delayedTriggers.length; i++) { delayedTriggers[i].call(this, event); }; //Trigger all delayed events - this._trigger("stop", event, this._uiHash()); + // if the cache doesn't exist, and we know how to convert + if ( !inst[ cache ] && space.to ) { + + // if the value was null, we don't need to copy it + // if the key was alpha, we don't need to copy it either + if ( key === "alpha" || red[ key ] == null ) { + return; + } + inst[ cache ] = space.to( inst._rgba ); + } + + // this is the only case where we allow nulls for ALL properties. + // call clamp with alwaysAllowEmpty + inst[ cache ][ prop.idx ] = clamp( red[ key ], prop, true ); + }); + + // everything defined but alpha? + if ( inst[ cache ] && $.inArray( null, inst[ cache ].slice( 0, 3 ) ) < 0 ) { + // use the default of 1 + inst[ cache ][ 3 ] = 1; + if ( space.from ) { + inst._rgba = space.from( inst[ cache ] ); + } + } + }); } - return false; + return this; } + }, + is: function( compare ) { + var is = color( compare ), + same = true, + inst = this; - if(!noPropagation) this._trigger("beforeStop", event, this._uiHash()); + each( spaces, function( _, space ) { + var localCache, + isCache = is[ space.cache ]; + if (isCache) { + localCache = inst[ space.cache ] || space.to && space.to( inst._rgba ) || []; + each( space.props, function( _, prop ) { + if ( isCache[ prop.idx ] != null ) { + same = ( isCache[ prop.idx ] === localCache[ prop.idx ] ); + return same; + } + }); + } + return same; + }); + return same; + }, + _space: function() { + var used = [], + inst = this; + each( spaces, function( spaceName, space ) { + if ( inst[ space.cache ] ) { + used.push( spaceName ); + } + }); + return used.pop(); + }, + transition: function( other, distance ) { + var end = color( other ), + spaceName = end._space(), + space = spaces[ spaceName ], + startColor = this.alpha() === 0 ? color( "transparent" ) : this, + start = startColor[ space.cache ] || space.to( startColor._rgba ), + result = start.slice(); + + end = end[ space.cache ]; + each( space.props, function( key, prop ) { + var index = prop.idx, + startValue = start[ index ], + endValue = end[ index ], + type = propTypes[ prop.type ] || {}; + + // if null, don't override start value + if ( endValue === null ) { + return; + } + // if null - use end + if ( startValue === null ) { + result[ index ] = endValue; + } else { + if ( type.mod ) { + if ( endValue - startValue > type.mod / 2 ) { + startValue += type.mod; + } else if ( startValue - endValue > type.mod / 2 ) { + startValue -= type.mod; + } + } + result[ index ] = clamp( ( endValue - startValue ) * distance + startValue, prop ); + } + }); + return this[ spaceName ]( result ); + }, + blend: function( opaque ) { + // if we are already opaque - return ourself + if ( this._rgba[ 3 ] === 1 ) { + return this; + } - //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node! - this.placeholder[0].parentNode.removeChild(this.placeholder[0]); + var rgb = this._rgba.slice(), + a = rgb.pop(), + blend = color( opaque )._rgba; - if(this.helper[0] != this.currentItem[0]) this.helper.remove(); this.helper = null; + return color( jQuery.map( rgb, function( v, i ) { + return ( 1 - a ) * blend[ i ] + a * v; + })); + }, + toRgbaString: function() { + var prefix = "rgba(", + rgba = jQuery.map( this._rgba, function( v, i ) { + return v == null ? ( i > 2 ? 1 : 0 ) : v; + }); - if(!noPropagation) { - for (var i=0; i < delayedTriggers.length; i++) { delayedTriggers[i].call(this, event); }; //Trigger all delayed events - this._trigger("stop", event, this._uiHash()); + if ( rgba[ 3 ] === 1 ) { + rgba.pop(); + prefix = "rgb("; } - this.fromOutside = false; - return true; - + return prefix + rgba.join() + ")"; }, + toHslaString: function() { + var prefix = "hsla(", + hsla = jQuery.map( this.hsla(), function( v, i ) { + if ( v == null ) { + v = i > 2 ? 1 : 0; + } - _trigger: function() { - if ($.Widget.prototype._trigger.apply(this, arguments) === false) { - this.cancel(); + // catch 1 and 2 + if ( i && i < 3 ) { + v = Math.round( v * 100 ) + "%"; + } + return v; + }); + + if ( hsla[ 3 ] === 1 ) { + hsla.pop(); + prefix = "hsl("; } + return prefix + hsla.join() + ")"; }, + toHexString: function( includeAlpha ) { + var rgba = this._rgba.slice(), + alpha = rgba.pop(); - _uiHash: function(inst) { - var self = inst || this; - return { - helper: self.helper, - placeholder: self.placeholder || $([]), - position: self.position, - originalPosition: self.originalPosition, - offset: self.positionAbs, - item: self.currentItem, - sender: inst ? inst.element : null - }; - } + if ( includeAlpha ) { + rgba.push( ~~( alpha * 255 ) ); + } -}); + return "#" + jQuery.map( rgba, function( v ) { -$.extend($.ui.sortable, { - version: "1.8.16" + // default to 0 when nulls exist + v = ( v || 0 ).toString( 16 ); + return v.length === 1 ? "0" + v : v; + }).join(""); + }, + toString: function() { + return this._rgba[ 3 ] === 0 ? "transparent" : this.toRgbaString(); + } }); +color.fn.parse.prototype = color.fn; -})(jQuery); -/* - * jQuery UI Effects 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Effects/ - */ -;jQuery.effects || (function($, undefined) { - -$.effects = {}; +// hsla conversions adapted from: +// https://code.google.com/p/maashaack/source/browse/packages/graphics/trunk/src/graphics/colors/HUE2RGB.as?r=5021 +function hue2rgb( p, q, h ) { + h = ( h + 1 ) % 1; + if ( h * 6 < 1 ) { + return p + (q - p) * h * 6; + } + if ( h * 2 < 1) { + return q; + } + if ( h * 3 < 2 ) { + return p + (q - p) * ((2/3) - h) * 6; + } + return p; +} +spaces.hsla.to = function ( rgba ) { + if ( rgba[ 0 ] == null || rgba[ 1 ] == null || rgba[ 2 ] == null ) { + return [ null, null, null, rgba[ 3 ] ]; + } + var r = rgba[ 0 ] / 255, + g = rgba[ 1 ] / 255, + b = rgba[ 2 ] / 255, + a = rgba[ 3 ], + max = Math.max( r, g, b ), + min = Math.min( r, g, b ), + diff = max - min, + add = max + min, + l = add * 0.5, + h, s; + + if ( min === max ) { + h = 0; + } else if ( r === max ) { + h = ( 60 * ( g - b ) / diff ) + 360; + } else if ( g === max ) { + h = ( 60 * ( b - r ) / diff ) + 120; + } else { + h = ( 60 * ( r - g ) / diff ) + 240; + } -/******************************************************************************/ -/****************************** COLOR ANIMATIONS ******************************/ -/******************************************************************************/ + if ( l === 0 || l === 1 ) { + s = l; + } else if ( l <= 0.5 ) { + s = diff / add; + } else { + s = diff / ( 2 - add ); + } + return [ Math.round(h) % 360, s, l, a == null ? 1 : a ]; +}; -// override the animation for color styles -$.each(['backgroundColor', 'borderBottomColor', 'borderLeftColor', - 'borderRightColor', 'borderTopColor', 'borderColor', 'color', 'outlineColor'], -function(i, attr) { - $.fx.step[attr] = function(fx) { - if (!fx.colorInit) { - fx.start = getColor(fx.elem, attr); - fx.end = getRGB(fx.end); - fx.colorInit = true; - } +spaces.hsla.from = function ( hsla ) { + if ( hsla[ 0 ] == null || hsla[ 1 ] == null || hsla[ 2 ] == null ) { + return [ null, null, null, hsla[ 3 ] ]; + } + var h = hsla[ 0 ] / 360, + s = hsla[ 1 ], + l = hsla[ 2 ], + a = hsla[ 3 ], + q = l <= 0.5 ? l * ( 1 + s ) : l + s - l * s, + p = 2 * l - q; + + return [ + Math.round( hue2rgb( p, q, h + ( 1 / 3 ) ) * 255 ), + Math.round( hue2rgb( p, q, h ) * 255 ), + Math.round( hue2rgb( p, q, h - ( 1 / 3 ) ) * 255 ), + a + ]; +}; - fx.elem.style[attr] = 'rgb(' + - Math.max(Math.min(parseInt((fx.pos * (fx.end[0] - fx.start[0])) + fx.start[0], 10), 255), 0) + ',' + - Math.max(Math.min(parseInt((fx.pos * (fx.end[1] - fx.start[1])) + fx.start[1], 10), 255), 0) + ',' + - Math.max(Math.min(parseInt((fx.pos * (fx.end[2] - fx.start[2])) + fx.start[2], 10), 255), 0) + ')'; - }; -}); -// Color Conversion functions from highlightFade -// By Blair Mitchelmore -// http://jquery.offput.ca/highlightFade/ +each( spaces, function( spaceName, space ) { + var props = space.props, + cache = space.cache, + to = space.to, + from = space.from; -// Parse strings looking for color tuples [255,255,255] -function getRGB(color) { - var result; + // makes rgba() and hsla() + color.fn[ spaceName ] = function( value ) { - // Check if we're already dealing with an array of colors - if ( color && color.constructor == Array && color.length == 3 ) - return color; + // generate a cache for this space if it doesn't exist + if ( to && !this[ cache ] ) { + this[ cache ] = to( this._rgba ); + } + if ( value === undefined ) { + return this[ cache ].slice(); + } - // Look for rgb(num,num,num) - if (result = /rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(color)) - return [parseInt(result[1],10), parseInt(result[2],10), parseInt(result[3],10)]; + var ret, + type = jQuery.type( value ), + arr = ( type === "array" || type === "object" ) ? value : arguments, + local = this[ cache ].slice(); - // Look for rgb(num%,num%,num%) - if (result = /rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(color)) - return [parseFloat(result[1])*2.55, parseFloat(result[2])*2.55, parseFloat(result[3])*2.55]; + each( props, function( key, prop ) { + var val = arr[ type === "object" ? key : prop.idx ]; + if ( val == null ) { + val = local[ prop.idx ]; + } + local[ prop.idx ] = clamp( val, prop ); + }); - // Look for #a0b1c2 - if (result = /#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(color)) - return [parseInt(result[1],16), parseInt(result[2],16), parseInt(result[3],16)]; + if ( from ) { + ret = color( from( local ) ); + ret[ cache ] = local; + return ret; + } else { + return color( local ); + } + }; - // Look for #fff - if (result = /#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(color)) - return [parseInt(result[1]+result[1],16), parseInt(result[2]+result[2],16), parseInt(result[3]+result[3],16)]; + // makes red() green() blue() alpha() hue() saturation() lightness() + each( props, function( key, prop ) { + // alpha is included in more than one space + if ( color.fn[ key ] ) { + return; + } + color.fn[ key ] = function( value ) { + var vtype = jQuery.type( value ), + fn = ( key === "alpha" ? ( this._hsla ? "hsla" : "rgba" ) : spaceName ), + local = this[ fn ](), + cur = local[ prop.idx ], + match; - // Look for rgba(0, 0, 0, 0) == transparent in Safari 3 - if (result = /rgba\(0, 0, 0, 0\)/.exec(color)) - return colors['transparent']; + if ( vtype === "undefined" ) { + return cur; + } - // Otherwise, we're most likely dealing with a named color - return colors[$.trim(color).toLowerCase()]; -} + if ( vtype === "function" ) { + value = value.call( this, cur ); + vtype = jQuery.type( value ); + } + if ( value == null && prop.empty ) { + return this; + } + if ( vtype === "string" ) { + match = rplusequals.exec( value ); + if ( match ) { + value = cur + parseFloat( match[ 2 ] ) * ( match[ 1 ] === "+" ? 1 : -1 ); + } + } + local[ prop.idx ] = value; + return this[ fn ]( local ); + }; + }); +}); -function getColor(elem, attr) { - var color; +// add .fx.step functions +each( stepHooks, function( i, hook ) { + jQuery.cssHooks[ hook ] = { + set: function( elem, value ) { + var parsed, curElem, + backgroundColor = ""; + + if ( jQuery.type( value ) !== "string" || ( parsed = stringParse( value ) ) ) { + value = color( parsed || value ); + if ( !support.rgba && value._rgba[ 3 ] !== 1 ) { + curElem = hook === "backgroundColor" ? elem.parentNode : elem; + while ( + (backgroundColor === "" || backgroundColor === "transparent") && + curElem && curElem.style + ) { + try { + backgroundColor = jQuery.css( curElem, "backgroundColor" ); + curElem = curElem.parentNode; + } catch ( e ) { + } + } - do { - color = $.curCSS(elem, attr); + value = value.blend( backgroundColor && backgroundColor !== "transparent" ? + backgroundColor : + "_default" ); + } - // Keep going until we find an element that has color, or we hit the body - if ( color != '' && color != 'transparent' || $.nodeName(elem, "body") ) - break; + value = value.toRgbaString(); + } + try { + elem.style[ hook ] = value; + } catch( error ) { + // wrapped to prevent IE from throwing errors on "invalid" values like 'auto' or 'inherit' + } + } + }; + jQuery.fx.step[ hook ] = function( fx ) { + if ( !fx.colorInit ) { + fx.start = color( fx.elem, hook ); + fx.end = color( fx.end ); + fx.colorInit = true; + } + jQuery.cssHooks[ hook ].set( fx.elem, fx.start.transition( fx.end, fx.pos ) ); + }; +}); - attr = "backgroundColor"; - } while ( elem = elem.parentNode ); +jQuery.cssHooks.borderColor = { + expand: function( value ) { + var expanded = {}; - return getRGB(color); + each( [ "Top", "Right", "Bottom", "Left" ], function( i, part ) { + expanded[ "border" + part + "Color" ] = value; + }); + return expanded; + } }; -// Some named colors to work with -// From Interface by Stefan Petre -// http://interface.eyecon.ro/ - -var colors = { - aqua:[0,255,255], - azure:[240,255,255], - beige:[245,245,220], - black:[0,0,0], - blue:[0,0,255], - brown:[165,42,42], - cyan:[0,255,255], - darkblue:[0,0,139], - darkcyan:[0,139,139], - darkgrey:[169,169,169], - darkgreen:[0,100,0], - darkkhaki:[189,183,107], - darkmagenta:[139,0,139], - darkolivegreen:[85,107,47], - darkorange:[255,140,0], - darkorchid:[153,50,204], - darkred:[139,0,0], - darksalmon:[233,150,122], - darkviolet:[148,0,211], - fuchsia:[255,0,255], - gold:[255,215,0], - green:[0,128,0], - indigo:[75,0,130], - khaki:[240,230,140], - lightblue:[173,216,230], - lightcyan:[224,255,255], - lightgreen:[144,238,144], - lightgrey:[211,211,211], - lightpink:[255,182,193], - lightyellow:[255,255,224], - lime:[0,255,0], - magenta:[255,0,255], - maroon:[128,0,0], - navy:[0,0,128], - olive:[128,128,0], - orange:[255,165,0], - pink:[255,192,203], - purple:[128,0,128], - violet:[128,0,128], - red:[255,0,0], - silver:[192,192,192], - white:[255,255,255], - yellow:[255,255,0], - transparent: [255,255,255] +// Basic color names only. +// Usage of any of the other color names requires adding yourself or including +// jquery.color.svg-names.js. +colors = jQuery.Color.names = { + // 4.1. Basic color keywords + aqua: "#00ffff", + black: "#000000", + blue: "#0000ff", + fuchsia: "#ff00ff", + gray: "#808080", + green: "#008000", + lime: "#00ff00", + maroon: "#800000", + navy: "#000080", + olive: "#808000", + purple: "#800080", + red: "#ff0000", + silver: "#c0c0c0", + teal: "#008080", + white: "#ffffff", + yellow: "#ffff00", + + // 4.2.3. "transparent" color keyword + transparent: [ null, null, null, 0 ], + + _default: "#ffffff" }; +})( jQuery ); + /******************************************************************************/ /****************************** CLASS ANIMATIONS ******************************/ /******************************************************************************/ +(function() { -var classAnimationActions = ['add', 'remove', 'toggle'], +var classAnimationActions = [ "add", "remove", "toggle" ], shorthandStyles = { border: 1, borderBottom: 1, @@ -4207,199 +7693,253 @@ var classAnimationActions = ['add', 'remove', 'toggle'], padding: 1 }; +$.each([ "borderLeftStyle", "borderRightStyle", "borderBottomStyle", "borderTopStyle" ], function( _, prop ) { + $.fx.step[ prop ] = function( fx ) { + if ( fx.end !== "none" && !fx.setAttr || fx.pos === 1 && !fx.setAttr ) { + jQuery.style( fx.elem, prop, fx.end ); + fx.setAttr = true; + } + }; +}); + function getElementStyles() { - var style = document.defaultView - ? document.defaultView.getComputedStyle(this, null) - : this.currentStyle, + var style = this.ownerDocument.defaultView ? + this.ownerDocument.defaultView.getComputedStyle( this, null ) : + this.currentStyle, newStyle = {}, key, - camelCase; + len; // webkit enumerates style porperties - if (style && style.length && style[0] && style[style[0]]) { - var len = style.length; - while (len--) { - key = style[len]; - if (typeof style[key] == 'string') { - camelCase = key.replace(/\-(\w)/g, function(all, letter){ - return letter.toUpperCase(); - }); - newStyle[camelCase] = style[key]; + if ( style && style.length && style[ 0 ] && style[ style[ 0 ] ] ) { + len = style.length; + while ( len-- ) { + key = style[ len ]; + if ( typeof style[ key ] === "string" ) { + newStyle[ $.camelCase( key ) ] = style[ key ]; } } } else { - for (key in style) { - if (typeof style[key] === 'string') { - newStyle[key] = style[key]; + for ( key in style ) { + if ( typeof style[ key ] === "string" ) { + newStyle[ key ] = style[ key ]; } } } - + return newStyle; } -function filterStyles(styles) { - var name, value; - for (name in styles) { - value = styles[name]; - if ( - // ignore null and undefined values - value == null || - // ignore functions (when does this occur?) - $.isFunction(value) || - // shorthand styles that need to be expanded - name in shorthandStyles || - // ignore scrollbars (break in IE) - (/scrollbar/).test(name) || - - // only colors or values that can be converted to numbers - (!(/color/i).test(name) && isNaN(parseFloat(value))) - ) { - delete styles[name]; - } - } - - return styles; -} -function styleDifference(oldStyle, newStyle) { - var diff = { _: 0 }, // http://dev.jquery.com/ticket/5459 - name; +function styleDifference( oldStyle, newStyle ) { + var diff = {}, + name, value; - for (name in newStyle) { - if (oldStyle[name] != newStyle[name]) { - diff[name] = newStyle[name]; + for ( name in newStyle ) { + value = newStyle[ name ]; + if ( oldStyle[ name ] !== value ) { + if ( !shorthandStyles[ name ] ) { + if ( $.fx.step[ name ] || !isNaN( parseFloat( value ) ) ) { + diff[ name ] = value; + } + } } } return diff; } -$.effects.animateClass = function(value, duration, easing, callback) { - if ($.isFunction(easing)) { - callback = easing; - easing = null; - } +$.effects.animateClass = function( value, duration, easing, callback ) { + var o = $.speed( duration, easing, callback ); - return this.queue(function() { - var that = $(this), - originalStyleAttr = that.attr('style') || ' ', - originalStyle = filterStyles(getElementStyles.call(this)), - newStyle, - className = that.attr('class'); + return this.queue( function() { + var animated = $( this ), + baseClass = animated.attr( "class" ) || "", + applyClassChange, + allAnimations = o.children ? animated.find( "*" ).andSelf() : animated; - $.each(classAnimationActions, function(i, action) { - if (value[action]) { - that[action + 'Class'](value[action]); - } + // map the animated objects to store the original styles. + allAnimations = allAnimations.map(function() { + var el = $( this ); + return { + el: el, + start: getElementStyles.call( this ) + }; }); - newStyle = filterStyles(getElementStyles.call(this)); - that.attr('class', className); - that.animate(styleDifference(originalStyle, newStyle), { - queue: false, - duration: duration, - easing: easing, - complete: function() { - $.each(classAnimationActions, function(i, action) { - if (value[action]) { that[action + 'Class'](value[action]); } - }); - // work around bug in IE by clearing the cssText before setting it - if (typeof that.attr('style') == 'object') { - that.attr('style').cssText = ''; - that.attr('style').cssText = originalStyleAttr; - } else { - that.attr('style', originalStyleAttr); + // apply class change + applyClassChange = function() { + $.each( classAnimationActions, function(i, action) { + if ( value[ action ] ) { + animated[ action + "Class" ]( value[ action ] ); } - if (callback) { callback.apply(this, arguments); } - $.dequeue( this ); - } + }); + }; + applyClassChange(); + + // map all animated objects again - calculate new styles and diff + allAnimations = allAnimations.map(function() { + this.end = getElementStyles.call( this.el[ 0 ] ); + this.diff = styleDifference( this.start, this.end ); + return this; + }); + + // apply original class + animated.attr( "class", baseClass ); + + // map all animated objects again - this time collecting a promise + allAnimations = allAnimations.map(function() { + var styleInfo = this, + dfd = $.Deferred(), + opts = jQuery.extend({}, o, { + queue: false, + complete: function() { + dfd.resolve( styleInfo ); + } + }); + + this.el.animate( this.diff, opts ); + return dfd.promise(); + }); + + // once all animations have completed: + $.when.apply( $, allAnimations.get() ).done(function() { + + // set the final class + applyClassChange(); + + // for each animated element, + // clear all css properties that were animated + $.each( arguments, function() { + var el = this.el; + $.each( this.diff, function(key) { + el.css( key, '' ); + }); + }); + + // this is guarnteed to be there if you use jQuery.speed() + // it also handles dequeuing the next anim... + o.complete.call( animated[ 0 ] ); }); }); }; $.fn.extend({ _addClass: $.fn.addClass, - addClass: function(classNames, speed, easing, callback) { - return speed ? $.effects.animateClass.apply(this, [{ add: classNames },speed,easing,callback]) : this._addClass(classNames); + addClass: function( classNames, speed, easing, callback ) { + return speed ? + $.effects.animateClass.call( this, + { add: classNames }, speed, easing, callback ) : + this._addClass( classNames ); }, _removeClass: $.fn.removeClass, - removeClass: function(classNames,speed,easing,callback) { - return speed ? $.effects.animateClass.apply(this, [{ remove: classNames },speed,easing,callback]) : this._removeClass(classNames); + removeClass: function( classNames, speed, easing, callback ) { + return speed ? + $.effects.animateClass.call( this, + { remove: classNames }, speed, easing, callback ) : + this._removeClass( classNames ); }, _toggleClass: $.fn.toggleClass, - toggleClass: function(classNames, force, speed, easing, callback) { - if ( typeof force == "boolean" || force === undefined ) { + toggleClass: function( classNames, force, speed, easing, callback ) { + if ( typeof force === "boolean" || force === undefined ) { if ( !speed ) { - // without speed parameter; - return this._toggleClass(classNames, force); + // without speed parameter + return this._toggleClass( classNames, force ); } else { - return $.effects.animateClass.apply(this, [(force?{add:classNames}:{remove:classNames}),speed,easing,callback]); + return $.effects.animateClass.call( this, + (force ? { add: classNames } : { remove: classNames }), + speed, easing, callback ); } } else { - // without switch parameter; - return $.effects.animateClass.apply(this, [{ toggle: classNames },force,speed,easing]); + // without force parameter + return $.effects.animateClass.call( this, + { toggle: classNames }, force, speed, easing ); } }, - switchClass: function(remove,add,speed,easing,callback) { - return $.effects.animateClass.apply(this, [{ add: add, remove: remove },speed,easing,callback]); + switchClass: function( remove, add, speed, easing, callback) { + return $.effects.animateClass.call( this, { + add: add, + remove: remove + }, speed, easing, callback ); } }); - +})(); /******************************************************************************/ /*********************************** EFFECTS **********************************/ /******************************************************************************/ -$.extend($.effects, { - version: "1.8.16", +(function() { + +$.extend( $.effects, { + version: "1.9.2", // Saves a set of properties in a data storage - save: function(element, set) { - for(var i=0; i < set.length; i++) { - if(set[i] !== null) element.data("ec.storage."+set[i], element[0].style[set[i]]); + save: function( element, set ) { + for( var i=0; i < set.length; i++ ) { + if ( set[ i ] !== null ) { + element.data( dataSpace + set[ i ], element[ 0 ].style[ set[ i ] ] ); + } } }, // Restores a set of previously saved properties from a data storage - restore: function(element, set) { - for(var i=0; i < set.length; i++) { - if(set[i] !== null) element.css(set[i], element.data("ec.storage."+set[i])); + restore: function( element, set ) { + var val, i; + for( i=0; i < set.length; i++ ) { + if ( set[ i ] !== null ) { + val = element.data( dataSpace + set[ i ] ); + // support: jQuery 1.6.2 + // http://bugs.jquery.com/ticket/9917 + // jQuery 1.6.2 incorrectly returns undefined for any falsy value. + // We can't differentiate between "" and 0 here, so we just assume + // empty string since it's likely to be a more common value... + if ( val === undefined ) { + val = ""; + } + element.css( set[ i ], val ); + } } }, - setMode: function(el, mode) { - if (mode == 'toggle') mode = el.is(':hidden') ? 'show' : 'hide'; // Set for toggle + setMode: function( el, mode ) { + if (mode === "toggle") { + mode = el.is( ":hidden" ) ? "show" : "hide"; + } return mode; }, - getBaseline: function(origin, original) { // Translates a [top,left] array into a baseline value - // this should be a little more flexible in the future to handle a string & hash + // Translates a [top,left] array into a baseline value + // this should be a little more flexible in the future to handle a string & hash + getBaseline: function( origin, original ) { var y, x; - switch (origin[0]) { - case 'top': y = 0; break; - case 'middle': y = 0.5; break; - case 'bottom': y = 1; break; - default: y = origin[0] / original.height; - }; - switch (origin[1]) { - case 'left': x = 0; break; - case 'center': x = 0.5; break; - case 'right': x = 1; break; - default: x = origin[1] / original.width; + switch ( origin[ 0 ] ) { + case "top": y = 0; break; + case "middle": y = 0.5; break; + case "bottom": y = 1; break; + default: y = origin[ 0 ] / original.height; + } + switch ( origin[ 1 ] ) { + case "left": x = 0; break; + case "center": x = 0.5; break; + case "right": x = 1; break; + default: x = origin[ 1 ] / original.width; + } + return { + x: x, + y: y }; - return {x: x, y: y}; }, // Wraps the element around a wrapper that copies position properties - createWrapper: function(element) { + createWrapper: function( element ) { // if the element is already wrapped, return it - if (element.parent().is('.ui-effects-wrapper')) { + if ( element.parent().is( ".ui-effects-wrapper" )) { return element.parent(); } @@ -4407,108 +7947,149 @@ $.extend($.effects, { var props = { width: element.outerWidth(true), height: element.outerHeight(true), - 'float': element.css('float') + "float": element.css( "float" ) }, - wrapper = $('

    ') - .addClass('ui-effects-wrapper') + wrapper = $( "
    " ) + .addClass( "ui-effects-wrapper" ) .css({ - fontSize: '100%', - background: 'transparent', - border: 'none', + fontSize: "100%", + background: "transparent", + border: "none", margin: 0, padding: 0 }), + // Store the size in case width/height are defined in % - Fixes #5245 + size = { + width: element.width(), + height: element.height() + }, active = document.activeElement; - element.wrap(wrapper); + // support: Firefox + // Firefox incorrectly exposes anonymous content + // https://bugzilla.mozilla.org/show_bug.cgi?id=561664 + try { + active.id; + } catch( e ) { + active = document.body; + } + + element.wrap( wrapper ); // Fixes #7595 - Elements lose focus when wrapped. if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) { $( active ).focus(); } - - wrapper = element.parent(); //Hotfix for jQuery 1.4 since some change in wrap() seems to actually loose the reference to the wrapped element + + wrapper = element.parent(); //Hotfix for jQuery 1.4 since some change in wrap() seems to actually lose the reference to the wrapped element // transfer positioning properties to the wrapper - if (element.css('position') == 'static') { - wrapper.css({ position: 'relative' }); - element.css({ position: 'relative' }); + if ( element.css( "position" ) === "static" ) { + wrapper.css({ position: "relative" }); + element.css({ position: "relative" }); } else { - $.extend(props, { - position: element.css('position'), - zIndex: element.css('z-index') + $.extend( props, { + position: element.css( "position" ), + zIndex: element.css( "z-index" ) }); - $.each(['top', 'left', 'bottom', 'right'], function(i, pos) { - props[pos] = element.css(pos); - if (isNaN(parseInt(props[pos], 10))) { - props[pos] = 'auto'; + $.each([ "top", "left", "bottom", "right" ], function(i, pos) { + props[ pos ] = element.css( pos ); + if ( isNaN( parseInt( props[ pos ], 10 ) ) ) { + props[ pos ] = "auto"; } }); - element.css({position: 'relative', top: 0, left: 0, right: 'auto', bottom: 'auto' }); + element.css({ + position: "relative", + top: 0, + left: 0, + right: "auto", + bottom: "auto" + }); } + element.css(size); - return wrapper.css(props).show(); + return wrapper.css( props ).show(); }, - removeWrapper: function(element) { - var parent, - active = document.activeElement; - - if (element.parent().is('.ui-effects-wrapper')) { - parent = element.parent().replaceWith(element); + removeWrapper: function( element ) { + var active = document.activeElement; + + if ( element.parent().is( ".ui-effects-wrapper" ) ) { + element.parent().replaceWith( element ); + // Fixes #7595 - Elements lose focus when wrapped. if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) { $( active ).focus(); } - return parent; } - + + return element; }, - setTransition: function(element, list, factor, value) { + setTransition: function( element, list, factor, value ) { value = value || {}; - $.each(list, function(i, x){ - unit = element.cssUnit(x); - if (unit[0] > 0) value[x] = unit[0] * factor + unit[1]; + $.each( list, function( i, x ) { + var unit = element.cssUnit( x ); + if ( unit[ 0 ] > 0 ) { + value[ x ] = unit[ 0 ] * factor + unit[ 1 ]; + } }); return value; } }); +// return an effect options object for the given parameters: +function _normalizeArguments( effect, options, speed, callback ) { -function _normalizeArguments(effect, options, speed, callback) { - // shift params for method overloading - if (typeof effect == 'object') { - callback = options; - speed = null; + // allow passing all options as the first parameter + if ( $.isPlainObject( effect ) ) { options = effect; - effect = options.effect; + effect = effect.effect; + } + + // convert to an object + effect = { effect: effect }; + + // catch (effect, null, ...) + if ( options == null ) { + options = {}; } - if ($.isFunction(options)) { + + // catch (effect, callback) + if ( $.isFunction( options ) ) { callback = options; speed = null; options = {}; } - if (typeof options == 'number' || $.fx.speeds[options]) { + + // catch (effect, speed, ?) + if ( typeof options === "number" || $.fx.speeds[ options ] ) { callback = speed; speed = options; options = {}; } - if ($.isFunction(speed)) { + + // catch (effect, options, callback) + if ( $.isFunction( speed ) ) { callback = speed; speed = null; } - options = options || {}; + // add options to effect + if ( options ) { + $.extend( effect, options ); + } speed = speed || options.duration; - speed = $.fx.off ? 0 : typeof speed == 'number' - ? speed : speed in $.fx.speeds ? $.fx.speeds[speed] : $.fx.speeds._default; + effect.duration = $.fx.off ? 0 : + typeof speed === "number" ? speed : + speed in $.fx.speeds ? $.fx.speeds[ speed ] : + $.fx.speeds._default; - callback = callback || options.complete; + effect.complete = callback || options.complete; - return [effect, options, speed, callback]; + return effect; } function standardSpeed( speed ) { @@ -4516,7252 +8097,6783 @@ function standardSpeed( speed ) { if ( !speed || typeof speed === "number" || $.fx.speeds[ speed ] ) { return true; } - + // invalid strings - treat as "normal" speed - if ( typeof speed === "string" && !$.effects[ speed ] ) { + if ( typeof speed === "string" && !$.effects.effect[ speed ] ) { + // TODO: remove in 2.0 (#7115) + if ( backCompat && $.effects[ speed ] ) { + return false; + } return true; } - + return false; } $.fn.extend({ - effect: function(effect, options, speed, callback) { - var args = _normalizeArguments.apply(this, arguments), - // TODO: make effects take actual parameters instead of a hash - args2 = { - options: args[1], - duration: args[2], - callback: args[3] - }, - mode = args2.options.mode, - effectMethod = $.effects[effect]; - - if ( $.fx.off || !effectMethod ) { + effect: function( /* effect, options, speed, callback */ ) { + var args = _normalizeArguments.apply( this, arguments ), + mode = args.mode, + queue = args.queue, + effectMethod = $.effects.effect[ args.effect ], + + // DEPRECATED: remove in 2.0 (#7115) + oldEffectMethod = !effectMethod && backCompat && $.effects[ args.effect ]; + + if ( $.fx.off || !( effectMethod || oldEffectMethod ) ) { // delegate to the original method (e.g., .show()) if possible if ( mode ) { - return this[ mode ]( args2.duration, args2.callback ); + return this[ mode ]( args.duration, args.complete ); } else { - return this.each(function() { - if ( args2.callback ) { - args2.callback.call( this ); + return this.each( function() { + if ( args.complete ) { + args.complete.call( this ); } }); } } - - return effectMethod.call(this, args2); + + function run( next ) { + var elem = $( this ), + complete = args.complete, + mode = args.mode; + + function done() { + if ( $.isFunction( complete ) ) { + complete.call( elem[0] ); + } + if ( $.isFunction( next ) ) { + next(); + } + } + + // if the element is hiddden and mode is hide, + // or element is visible and mode is show + if ( elem.is( ":hidden" ) ? mode === "hide" : mode === "show" ) { + done(); + } else { + effectMethod.call( elem[0], args, done ); + } + } + + // TODO: remove this check in 2.0, effectMethod will always be true + if ( effectMethod ) { + return queue === false ? this.each( run ) : this.queue( queue || "fx", run ); + } else { + // DEPRECATED: remove in 2.0 (#7115) + return oldEffectMethod.call(this, { + options: args, + duration: args.duration, + callback: args.complete, + mode: args.mode + }); + } }, _show: $.fn.show, - show: function(speed) { + show: function( speed ) { if ( standardSpeed( speed ) ) { - return this._show.apply(this, arguments); + return this._show.apply( this, arguments ); } else { - var args = _normalizeArguments.apply(this, arguments); - args[1].mode = 'show'; - return this.effect.apply(this, args); + var args = _normalizeArguments.apply( this, arguments ); + args.mode = "show"; + return this.effect.call( this, args ); } }, _hide: $.fn.hide, - hide: function(speed) { + hide: function( speed ) { if ( standardSpeed( speed ) ) { - return this._hide.apply(this, arguments); + return this._hide.apply( this, arguments ); } else { - var args = _normalizeArguments.apply(this, arguments); - args[1].mode = 'hide'; - return this.effect.apply(this, args); + var args = _normalizeArguments.apply( this, arguments ); + args.mode = "hide"; + return this.effect.call( this, args ); } }, // jQuery core overloads toggle and creates _toggle __toggle: $.fn.toggle, - toggle: function(speed) { + toggle: function( speed ) { if ( standardSpeed( speed ) || typeof speed === "boolean" || $.isFunction( speed ) ) { - return this.__toggle.apply(this, arguments); + return this.__toggle.apply( this, arguments ); } else { - var args = _normalizeArguments.apply(this, arguments); - args[1].mode = 'toggle'; - return this.effect.apply(this, args); + var args = _normalizeArguments.apply( this, arguments ); + args.mode = "toggle"; + return this.effect.call( this, args ); } }, // helper functions cssUnit: function(key) { - var style = this.css(key), val = []; - $.each( ['em','px','%','pt'], function(i, unit){ - if(style.indexOf(unit) > 0) - val = [parseFloat(style), unit]; + var style = this.css( key ), + val = []; + + $.each( [ "em", "px", "%", "pt" ], function( i, unit ) { + if ( style.indexOf( unit ) > 0 ) { + val = [ parseFloat( style ), unit ]; + } }); return val; } }); - +})(); /******************************************************************************/ /*********************************** EASING ***********************************/ /******************************************************************************/ -/* - * jQuery Easing v1.3 - http://gsgd.co.uk/sandbox/jquery/easing/ - * - * Uses the built in easing capabilities added In jQuery 1.1 - * to offer multiple easing options - * - * TERMS OF USE - jQuery Easing - * - * Open source under the BSD License. - * - * Copyright 2008 George McGinley Smith - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, this list - * of conditions and the following disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * Neither the name of the author nor the names of contributors may be used to endorse - * or promote products derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * -*/ +(function() { -// t: current time, b: begInnIng value, c: change In value, d: duration -$.easing.jswing = $.easing.swing; +// based on easing equations from Robert Penner (http://www.robertpenner.com/easing) -$.extend($.easing, -{ - def: 'easeOutQuad', - swing: function (x, t, b, c, d) { - //alert($.easing.default); - return $.easing[$.easing.def](x, t, b, c, d); - }, - easeInQuad: function (x, t, b, c, d) { - return c*(t/=d)*t + b; - }, - easeOutQuad: function (x, t, b, c, d) { - return -c *(t/=d)*(t-2) + b; - }, - easeInOutQuad: function (x, t, b, c, d) { - if ((t/=d/2) < 1) return c/2*t*t + b; - return -c/2 * ((--t)*(t-2) - 1) + b; - }, - easeInCubic: function (x, t, b, c, d) { - return c*(t/=d)*t*t + b; - }, - easeOutCubic: function (x, t, b, c, d) { - return c*((t=t/d-1)*t*t + 1) + b; - }, - easeInOutCubic: function (x, t, b, c, d) { - if ((t/=d/2) < 1) return c/2*t*t*t + b; - return c/2*((t-=2)*t*t + 2) + b; - }, - easeInQuart: function (x, t, b, c, d) { - return c*(t/=d)*t*t*t + b; - }, - easeOutQuart: function (x, t, b, c, d) { - return -c * ((t=t/d-1)*t*t*t - 1) + b; - }, - easeInOutQuart: function (x, t, b, c, d) { - if ((t/=d/2) < 1) return c/2*t*t*t*t + b; - return -c/2 * ((t-=2)*t*t*t - 2) + b; - }, - easeInQuint: function (x, t, b, c, d) { - return c*(t/=d)*t*t*t*t + b; - }, - easeOutQuint: function (x, t, b, c, d) { - return c*((t=t/d-1)*t*t*t*t + 1) + b; - }, - easeInOutQuint: function (x, t, b, c, d) { - if ((t/=d/2) < 1) return c/2*t*t*t*t*t + b; - return c/2*((t-=2)*t*t*t*t + 2) + b; - }, - easeInSine: function (x, t, b, c, d) { - return -c * Math.cos(t/d * (Math.PI/2)) + c + b; - }, - easeOutSine: function (x, t, b, c, d) { - return c * Math.sin(t/d * (Math.PI/2)) + b; - }, - easeInOutSine: function (x, t, b, c, d) { - return -c/2 * (Math.cos(Math.PI*t/d) - 1) + b; - }, - easeInExpo: function (x, t, b, c, d) { - return (t==0) ? b : c * Math.pow(2, 10 * (t/d - 1)) + b; - }, - easeOutExpo: function (x, t, b, c, d) { - return (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b; - }, - easeInOutExpo: function (x, t, b, c, d) { - if (t==0) return b; - if (t==d) return b+c; - if ((t/=d/2) < 1) return c/2 * Math.pow(2, 10 * (t - 1)) + b; - return c/2 * (-Math.pow(2, -10 * --t) + 2) + b; - }, - easeInCirc: function (x, t, b, c, d) { - return -c * (Math.sqrt(1 - (t/=d)*t) - 1) + b; - }, - easeOutCirc: function (x, t, b, c, d) { - return c * Math.sqrt(1 - (t=t/d-1)*t) + b; - }, - easeInOutCirc: function (x, t, b, c, d) { - if ((t/=d/2) < 1) return -c/2 * (Math.sqrt(1 - t*t) - 1) + b; - return c/2 * (Math.sqrt(1 - (t-=2)*t) + 1) + b; - }, - easeInElastic: function (x, t, b, c, d) { - var s=1.70158;var p=0;var a=c; - if (t==0) return b; if ((t/=d)==1) return b+c; if (!p) p=d*.3; - if (a < Math.abs(c)) { a=c; var s=p/4; } - else var s = p/(2*Math.PI) * Math.asin (c/a); - return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b; +var baseEasings = {}; + +$.each( [ "Quad", "Cubic", "Quart", "Quint", "Expo" ], function( i, name ) { + baseEasings[ name ] = function( p ) { + return Math.pow( p, i + 2 ); + }; +}); + +$.extend( baseEasings, { + Sine: function ( p ) { + return 1 - Math.cos( p * Math.PI / 2 ); }, - easeOutElastic: function (x, t, b, c, d) { - var s=1.70158;var p=0;var a=c; - if (t==0) return b; if ((t/=d)==1) return b+c; if (!p) p=d*.3; - if (a < Math.abs(c)) { a=c; var s=p/4; } - else var s = p/(2*Math.PI) * Math.asin (c/a); - return a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b; + Circ: function ( p ) { + return 1 - Math.sqrt( 1 - p * p ); }, - easeInOutElastic: function (x, t, b, c, d) { - var s=1.70158;var p=0;var a=c; - if (t==0) return b; if ((t/=d/2)==2) return b+c; if (!p) p=d*(.3*1.5); - if (a < Math.abs(c)) { a=c; var s=p/4; } - else var s = p/(2*Math.PI) * Math.asin (c/a); - if (t < 1) return -.5*(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b; - return a*Math.pow(2,-10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )*.5 + c + b; - }, - easeInBack: function (x, t, b, c, d, s) { - if (s == undefined) s = 1.70158; - return c*(t/=d)*t*((s+1)*t - s) + b; - }, - easeOutBack: function (x, t, b, c, d, s) { - if (s == undefined) s = 1.70158; - return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b; - }, - easeInOutBack: function (x, t, b, c, d, s) { - if (s == undefined) s = 1.70158; - if ((t/=d/2) < 1) return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b; - return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b; + Elastic: function( p ) { + return p === 0 || p === 1 ? p : + -Math.pow( 2, 8 * (p - 1) ) * Math.sin( ( (p - 1) * 80 - 7.5 ) * Math.PI / 15 ); }, - easeInBounce: function (x, t, b, c, d) { - return c - $.easing.easeOutBounce (x, d-t, 0, c, d) + b; - }, - easeOutBounce: function (x, t, b, c, d) { - if ((t/=d) < (1/2.75)) { - return c*(7.5625*t*t) + b; - } else if (t < (2/2.75)) { - return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b; - } else if (t < (2.5/2.75)) { - return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b; - } else { - return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b; - } + Back: function( p ) { + return p * p * ( 3 * p - 2 ); }, - easeInOutBounce: function (x, t, b, c, d) { - if (t < d/2) return $.easing.easeInBounce (x, t*2, 0, c, d) * .5 + b; - return $.easing.easeOutBounce (x, t*2-d, 0, c, d) * .5 + c*.5 + b; + Bounce: function ( p ) { + var pow2, + bounce = 4; + + while ( p < ( ( pow2 = Math.pow( 2, --bounce ) ) - 1 ) / 11 ) {} + return 1 / Math.pow( 4, 3 - bounce ) - 7.5625 * Math.pow( ( pow2 * 3 - 2 ) / 22 - p, 2 ); } }); -/* - * - * TERMS OF USE - EASING EQUATIONS - * - * Open source under the BSD License. - * - * Copyright 2001 Robert Penner - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, this list - * of conditions and the following disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * Neither the name of the author nor the names of contributors may be used to endorse - * or promote products derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ +$.each( baseEasings, function( name, easeIn ) { + $.easing[ "easeIn" + name ] = easeIn; + $.easing[ "easeOut" + name ] = function( p ) { + return 1 - easeIn( 1 - p ); + }; + $.easing[ "easeInOut" + name ] = function( p ) { + return p < 0.5 ? + easeIn( p * 2 ) / 2 : + 1 - easeIn( p * -2 + 2 ) / 2; + }; +}); + +})(); + +})(jQuery)); +(function( $, undefined ) { + +var rvertical = /up|down|vertical/, + rpositivemotion = /up|left|vertical|horizontal/; + +$.effects.effect.blind = function( o, done ) { + // Create element + var el = $( this ), + props = [ "position", "top", "bottom", "left", "right", "height", "width" ], + mode = $.effects.setMode( el, o.mode || "hide" ), + direction = o.direction || "up", + vertical = rvertical.test( direction ), + ref = vertical ? "height" : "width", + ref2 = vertical ? "top" : "left", + motion = rpositivemotion.test( direction ), + animation = {}, + show = mode === "show", + wrapper, distance, margin; + + // if already wrapped, the wrapper's properties are my property. #6245 + if ( el.parent().is( ".ui-effects-wrapper" ) ) { + $.effects.save( el.parent(), props ); + } else { + $.effects.save( el, props ); + } + el.show(); + wrapper = $.effects.createWrapper( el ).css({ + overflow: "hidden" + }); + + distance = wrapper[ ref ](); + margin = parseFloat( wrapper.css( ref2 ) ) || 0; + + animation[ ref ] = show ? distance : 0; + if ( !motion ) { + el + .css( vertical ? "bottom" : "right", 0 ) + .css( vertical ? "top" : "left", "auto" ) + .css({ position: "absolute" }); + + animation[ ref2 ] = show ? margin : distance + margin; + } + + // start at 0 if we are showing + if ( show ) { + wrapper.css( ref, 0 ); + if ( ! motion ) { + wrapper.css( ref2, margin + distance ); + } + } + + // Animate + wrapper.animate( animation, { + duration: o.duration, + easing: o.easing, + queue: false, + complete: function() { + if ( mode === "hide" ) { + el.hide(); + } + $.effects.restore( el, props ); + $.effects.removeWrapper( el ); + done(); + } + }); + +}; })(jQuery); -/* - * jQuery UI Effects Blind 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Effects/Blind - * - * Depends: - * jquery.effects.core.js - */ (function( $, undefined ) { -$.effects.blind = function(o) { +$.effects.effect.bounce = function( o, done ) { + var el = $( this ), + props = [ "position", "top", "bottom", "left", "right", "height", "width" ], + + // defaults: + mode = $.effects.setMode( el, o.mode || "effect" ), + hide = mode === "hide", + show = mode === "show", + direction = o.direction || "up", + distance = o.distance, + times = o.times || 5, + + // number of internal animations + anims = times * 2 + ( show || hide ? 1 : 0 ), + speed = o.duration / anims, + easing = o.easing, + + // utility: + ref = ( direction === "up" || direction === "down" ) ? "top" : "left", + motion = ( direction === "up" || direction === "left" ), + i, + upAnim, + downAnim, + + // we will need to re-assemble the queue to stack our animations in place + queue = el.queue(), + queuelen = queue.length; + + // Avoid touching opacity to prevent clearType and PNG issues in IE + if ( show || hide ) { + props.push( "opacity" ); + } + + $.effects.save( el, props ); + el.show(); + $.effects.createWrapper( el ); // Create Wrapper - return this.queue(function() { + // default distance for the BIGGEST bounce is the outer Distance / 3 + if ( !distance ) { + distance = el[ ref === "top" ? "outerHeight" : "outerWidth" ]() / 3; + } - // Create element - var el = $(this), props = ['position','top','bottom','left','right']; + if ( show ) { + downAnim = { opacity: 1 }; + downAnim[ ref ] = 0; - // Set options - var mode = $.effects.setMode(el, o.options.mode || 'hide'); // Set Mode - var direction = o.options.direction || 'vertical'; // Default direction - - // Adjust - $.effects.save(el, props); el.show(); // Save & Show - var wrapper = $.effects.createWrapper(el).css({overflow:'hidden'}); // Create Wrapper - var ref = (direction == 'vertical') ? 'height' : 'width'; - var distance = (direction == 'vertical') ? wrapper.height() : wrapper.width(); - if(mode == 'show') wrapper.css(ref, 0); // Shift - - // Animation - var animation = {}; - animation[ref] = mode == 'show' ? distance : 0; - - // Animate - wrapper.animate(animation, o.duration, o.options.easing, function() { - if(mode == 'hide') el.hide(); // Hide - $.effects.restore(el, props); $.effects.removeWrapper(el); // Restore - if(o.callback) o.callback.apply(el[0], arguments); // Callback - el.dequeue(); - }); + // if we are showing, force opacity 0 and set the initial position + // then do the "first" animation + el.css( "opacity", 0 ) + .css( ref, motion ? -distance * 2 : distance * 2 ) + .animate( downAnim, speed, easing ); + } + + // start at the smallest distance if we are hiding + if ( hide ) { + distance = distance / Math.pow( 2, times - 1 ); + } + + downAnim = {}; + downAnim[ ref ] = 0; + // Bounces up/down/left/right then back to 0 -- times * 2 animations happen here + for ( i = 0; i < times; i++ ) { + upAnim = {}; + upAnim[ ref ] = ( motion ? "-=" : "+=" ) + distance; + + el.animate( upAnim, speed, easing ) + .animate( downAnim, speed, easing ); + + distance = hide ? distance * 2 : distance / 2; + } + + // Last Bounce when Hiding + if ( hide ) { + upAnim = { opacity: 0 }; + upAnim[ ref ] = ( motion ? "-=" : "+=" ) + distance; + el.animate( upAnim, speed, easing ); + } + + el.queue(function() { + if ( hide ) { + el.hide(); + } + $.effects.restore( el, props ); + $.effects.removeWrapper( el ); + done(); }); + // inject all the animations we just queued to be first in line (after "inprogress") + if ( queuelen > 1) { + queue.splice.apply( queue, + [ 1, 0 ].concat( queue.splice( queuelen, anims + 1 ) ) ); + } + el.dequeue(); + }; })(jQuery); -/* - * jQuery UI Effects Bounce 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Effects/Bounce - * - * Depends: - * jquery.effects.core.js - */ (function( $, undefined ) { -$.effects.bounce = function(o) { +$.effects.effect.clip = function( o, done ) { + // Create element + var el = $( this ), + props = [ "position", "top", "bottom", "left", "right", "height", "width" ], + mode = $.effects.setMode( el, o.mode || "hide" ), + show = mode === "show", + direction = o.direction || "vertical", + vert = direction === "vertical", + size = vert ? "height" : "width", + position = vert ? "top" : "left", + animation = {}, + wrapper, animate, distance; + + // Save & Show + $.effects.save( el, props ); + el.show(); + + // Create Wrapper + wrapper = $.effects.createWrapper( el ).css({ + overflow: "hidden" + }); + animate = ( el[0].tagName === "IMG" ) ? wrapper : el; + distance = animate[ size ](); - return this.queue(function() { + // Shift + if ( show ) { + animate.css( size, 0 ); + animate.css( position, distance / 2 ); + } - // Create element - var el = $(this), props = ['position','top','bottom','left','right']; + // Create Animation Object: + animation[ size ] = show ? distance : 0; + animation[ position ] = show ? 0 : distance / 2; - // Set options - var mode = $.effects.setMode(el, o.options.mode || 'effect'); // Set Mode - var direction = o.options.direction || 'up'; // Default direction - var distance = o.options.distance || 20; // Default distance - var times = o.options.times || 5; // Default # of times - var speed = o.duration || 250; // Default speed per bounce - if (/show|hide/.test(mode)) props.push('opacity'); // Avoid touching opacity to prevent clearType and PNG issues in IE - - // Adjust - $.effects.save(el, props); el.show(); // Save & Show - $.effects.createWrapper(el); // Create Wrapper - var ref = (direction == 'up' || direction == 'down') ? 'top' : 'left'; - var motion = (direction == 'up' || direction == 'left') ? 'pos' : 'neg'; - var distance = o.options.distance || (ref == 'top' ? el.outerHeight({margin:true}) / 3 : el.outerWidth({margin:true}) / 3); - if (mode == 'show') el.css('opacity', 0).css(ref, motion == 'pos' ? -distance : distance); // Shift - if (mode == 'hide') distance = distance / (times * 2); - if (mode != 'hide') times--; - - // Animate - if (mode == 'show') { // Show Bounce - var animation = {opacity: 1}; - animation[ref] = (motion == 'pos' ? '+=' : '-=') + distance; - el.animate(animation, speed / 2, o.options.easing); - distance = distance / 2; - times--; - }; - for (var i = 0; i < times; i++) { // Bounces - var animation1 = {}, animation2 = {}; - animation1[ref] = (motion == 'pos' ? '-=' : '+=') + distance; - animation2[ref] = (motion == 'pos' ? '+=' : '-=') + distance; - el.animate(animation1, speed / 2, o.options.easing).animate(animation2, speed / 2, o.options.easing); - distance = (mode == 'hide') ? distance * 2 : distance / 2; - }; - if (mode == 'hide') { // Last Bounce - var animation = {opacity: 0}; - animation[ref] = (motion == 'pos' ? '-=' : '+=') + distance; - el.animate(animation, speed / 2, o.options.easing, function(){ - el.hide(); // Hide - $.effects.restore(el, props); $.effects.removeWrapper(el); // Restore - if(o.callback) o.callback.apply(this, arguments); // Callback - }); - } else { - var animation1 = {}, animation2 = {}; - animation1[ref] = (motion == 'pos' ? '-=' : '+=') + distance; - animation2[ref] = (motion == 'pos' ? '+=' : '-=') + distance; - el.animate(animation1, speed / 2, o.options.easing).animate(animation2, speed / 2, o.options.easing, function(){ - $.effects.restore(el, props); $.effects.removeWrapper(el); // Restore - if(o.callback) o.callback.apply(this, arguments); // Callback - }); - }; - el.queue('fx', function() { el.dequeue(); }); - el.dequeue(); + // Animate + animate.animate( animation, { + queue: false, + duration: o.duration, + easing: o.easing, + complete: function() { + if ( !show ) { + el.hide(); + } + $.effects.restore( el, props ); + $.effects.removeWrapper( el ); + done(); + } }); }; })(jQuery); -/* - * jQuery UI Effects Clip 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Effects/Clip - * - * Depends: - * jquery.effects.core.js - */ (function( $, undefined ) { -$.effects.clip = function(o) { +$.effects.effect.drop = function( o, done ) { + + var el = $( this ), + props = [ "position", "top", "bottom", "left", "right", "opacity", "height", "width" ], + mode = $.effects.setMode( el, o.mode || "hide" ), + show = mode === "show", + direction = o.direction || "left", + ref = ( direction === "up" || direction === "down" ) ? "top" : "left", + motion = ( direction === "up" || direction === "left" ) ? "pos" : "neg", + animation = { + opacity: show ? 1 : 0 + }, + distance; + + // Adjust + $.effects.save( el, props ); + el.show(); + $.effects.createWrapper( el ); + + distance = o.distance || el[ ref === "top" ? "outerHeight": "outerWidth" ]( true ) / 2; + + if ( show ) { + el + .css( "opacity", 0 ) + .css( ref, motion === "pos" ? -distance : distance ); + } + + // Animation + animation[ ref ] = ( show ? + ( motion === "pos" ? "+=" : "-=" ) : + ( motion === "pos" ? "-=" : "+=" ) ) + + distance; + + // Animate + el.animate( animation, { + queue: false, + duration: o.duration, + easing: o.easing, + complete: function() { + if ( mode === "hide" ) { + el.hide(); + } + $.effects.restore( el, props ); + $.effects.removeWrapper( el ); + done(); + } + }); +}; + +})(jQuery); +(function( $, undefined ) { + +$.effects.effect.explode = function( o, done ) { + + var rows = o.pieces ? Math.round( Math.sqrt( o.pieces ) ) : 3, + cells = rows, + el = $( this ), + mode = $.effects.setMode( el, o.mode || "hide" ), + show = mode === "show", + + // show and then visibility:hidden the element before calculating offset + offset = el.show().css( "visibility", "hidden" ).offset(), + + // width and height of a piece + width = Math.ceil( el.outerWidth() / cells ), + height = Math.ceil( el.outerHeight() / rows ), + pieces = [], + + // loop + i, j, left, top, mx, my; + + // children animate complete: + function childComplete() { + pieces.push( this ); + if ( pieces.length === rows * cells ) { + animComplete(); + } + } + + // clone the element for each row and cell. + for( i = 0; i < rows ; i++ ) { // ===> + top = offset.top + i * height; + my = i - ( rows - 1 ) / 2 ; + + for( j = 0; j < cells ; j++ ) { // ||| + left = offset.left + j * width; + mx = j - ( cells - 1 ) / 2 ; + + // Create a clone of the now hidden main element that will be absolute positioned + // within a wrapper div off the -left and -top equal to size of our pieces + el + .clone() + .appendTo( "body" ) + .wrap( "
    " ) + .css({ + position: "absolute", + visibility: "visible", + left: -j * width, + top: -i * height + }) + + // select the wrapper - make it overflow: hidden and absolute positioned based on + // where the original was located +left and +top equal to the size of pieces + .parent() + .addClass( "ui-effects-explode" ) + .css({ + position: "absolute", + overflow: "hidden", + width: width, + height: height, + left: left + ( show ? mx * width : 0 ), + top: top + ( show ? my * height : 0 ), + opacity: show ? 0 : 1 + }).animate({ + left: left + ( show ? 0 : mx * width ), + top: top + ( show ? 0 : my * height ), + opacity: show ? 1 : 0 + }, o.duration || 500, o.easing, childComplete ); + } + } + + function animComplete() { + el.css({ + visibility: "visible" + }); + $( pieces ).remove(); + if ( !show ) { + el.hide(); + } + done(); + } +}; + +})(jQuery); +(function( $, undefined ) { + +$.effects.effect.fade = function( o, done ) { + var el = $( this ), + mode = $.effects.setMode( el, o.mode || "toggle" ); + + el.animate({ + opacity: mode + }, { + queue: false, + duration: o.duration, + easing: o.easing, + complete: done + }); +}; + +})( jQuery ); +(function( $, undefined ) { + +$.effects.effect.fold = function( o, done ) { + + // Create element + var el = $( this ), + props = [ "position", "top", "bottom", "left", "right", "height", "width" ], + mode = $.effects.setMode( el, o.mode || "hide" ), + show = mode === "show", + hide = mode === "hide", + size = o.size || 15, + percent = /([0-9]+)%/.exec( size ), + horizFirst = !!o.horizFirst, + widthFirst = show !== horizFirst, + ref = widthFirst ? [ "width", "height" ] : [ "height", "width" ], + duration = o.duration / 2, + wrapper, distance, + animation1 = {}, + animation2 = {}; + + $.effects.save( el, props ); + el.show(); + + // Create Wrapper + wrapper = $.effects.createWrapper( el ).css({ + overflow: "hidden" + }); + distance = widthFirst ? + [ wrapper.width(), wrapper.height() ] : + [ wrapper.height(), wrapper.width() ]; + + if ( percent ) { + size = parseInt( percent[ 1 ], 10 ) / 100 * distance[ hide ? 0 : 1 ]; + } + if ( show ) { + wrapper.css( horizFirst ? { + height: 0, + width: size + } : { + height: size, + width: 0 + }); + } + + // Animation + animation1[ ref[ 0 ] ] = show ? distance[ 0 ] : size; + animation2[ ref[ 1 ] ] = show ? distance[ 1 ] : 0; + + // Animate + wrapper + .animate( animation1, duration, o.easing ) + .animate( animation2, duration, o.easing, function() { + if ( hide ) { + el.hide(); + } + $.effects.restore( el, props ); + $.effects.removeWrapper( el ); + done(); + }); + +}; + +})(jQuery); +(function( $, undefined ) { + +$.effects.effect.highlight = function( o, done ) { + var elem = $( this ), + props = [ "backgroundImage", "backgroundColor", "opacity" ], + mode = $.effects.setMode( elem, o.mode || "show" ), + animation = { + backgroundColor: elem.css( "backgroundColor" ) + }; + + if (mode === "hide") { + animation.opacity = 0; + } + + $.effects.save( elem, props ); + + elem + .show() + .css({ + backgroundImage: "none", + backgroundColor: o.color || "#ffff99" + }) + .animate( animation, { + queue: false, + duration: o.duration, + easing: o.easing, + complete: function() { + if ( mode === "hide" ) { + elem.hide(); + } + $.effects.restore( elem, props ); + done(); + } + }); +}; + +})(jQuery); +(function( $, undefined ) { + +$.effects.effect.pulsate = function( o, done ) { + var elem = $( this ), + mode = $.effects.setMode( elem, o.mode || "show" ), + show = mode === "show", + hide = mode === "hide", + showhide = ( show || mode === "hide" ), + + // showing or hiding leaves of the "last" animation + anims = ( ( o.times || 5 ) * 2 ) + ( showhide ? 1 : 0 ), + duration = o.duration / anims, + animateTo = 0, + queue = elem.queue(), + queuelen = queue.length, + i; + + if ( show || !elem.is(":visible")) { + elem.css( "opacity", 0 ).show(); + animateTo = 1; + } + + // anims - 1 opacity "toggles" + for ( i = 1; i < anims; i++ ) { + elem.animate({ + opacity: animateTo + }, duration, o.easing ); + animateTo = 1 - animateTo; + } + + elem.animate({ + opacity: animateTo + }, duration, o.easing); - return this.queue(function() { + elem.queue(function() { + if ( hide ) { + elem.hide(); + } + done(); + }); - // Create element - var el = $(this), props = ['position','top','bottom','left','right','height','width']; + // We just queued up "anims" animations, we need to put them next in the queue + if ( queuelen > 1 ) { + queue.splice.apply( queue, + [ 1, 0 ].concat( queue.splice( queuelen, anims + 1 ) ) ); + } + elem.dequeue(); +}; - // Set options - var mode = $.effects.setMode(el, o.options.mode || 'hide'); // Set Mode - var direction = o.options.direction || 'vertical'; // Default direction - - // Adjust - $.effects.save(el, props); el.show(); // Save & Show - var wrapper = $.effects.createWrapper(el).css({overflow:'hidden'}); // Create Wrapper - var animate = el[0].tagName == 'IMG' ? wrapper : el; - var ref = { - size: (direction == 'vertical') ? 'height' : 'width', - position: (direction == 'vertical') ? 'top' : 'left' +})(jQuery); +(function( $, undefined ) { + +$.effects.effect.puff = function( o, done ) { + var elem = $( this ), + mode = $.effects.setMode( elem, o.mode || "hide" ), + hide = mode === "hide", + percent = parseInt( o.percent, 10 ) || 150, + factor = percent / 100, + original = { + height: elem.height(), + width: elem.width(), + outerHeight: elem.outerHeight(), + outerWidth: elem.outerWidth() }; - var distance = (direction == 'vertical') ? animate.height() : animate.width(); - if(mode == 'show') { animate.css(ref.size, 0); animate.css(ref.position, distance / 2); } // Shift - - // Animation - var animation = {}; - animation[ref.size] = mode == 'show' ? distance : 0; - animation[ref.position] = mode == 'show' ? 0 : distance / 2; - - // Animate - animate.animate(animation, { queue: false, duration: o.duration, easing: o.options.easing, complete: function() { - if(mode == 'hide') el.hide(); // Hide - $.effects.restore(el, props); $.effects.removeWrapper(el); // Restore - if(o.callback) o.callback.apply(el[0], arguments); // Callback - el.dequeue(); - }}); + $.extend( o, { + effect: "scale", + queue: false, + fade: true, + mode: mode, + complete: done, + percent: hide ? percent : 100, + from: hide ? + original : + { + height: original.height * factor, + width: original.width * factor, + outerHeight: original.outerHeight * factor, + outerWidth: original.outerWidth * factor + } }); + elem.effect( o ); }; -})(jQuery); -/* - * jQuery UI Effects Drop 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Effects/Drop - * - * Depends: - * jquery.effects.core.js - */ -(function( $, undefined ) { +$.effects.effect.scale = function( o, done ) { + + // Create element + var el = $( this ), + options = $.extend( true, {}, o ), + mode = $.effects.setMode( el, o.mode || "effect" ), + percent = parseInt( o.percent, 10 ) || + ( parseInt( o.percent, 10 ) === 0 ? 0 : ( mode === "hide" ? 0 : 100 ) ), + direction = o.direction || "both", + origin = o.origin, + original = { + height: el.height(), + width: el.width(), + outerHeight: el.outerHeight(), + outerWidth: el.outerWidth() + }, + factor = { + y: direction !== "horizontal" ? (percent / 100) : 1, + x: direction !== "vertical" ? (percent / 100) : 1 + }; -$.effects.drop = function(o) { + // We are going to pass this effect to the size effect: + options.effect = "size"; + options.queue = false; + options.complete = done; - return this.queue(function() { + // Set default origin and restore for show/hide + if ( mode !== "effect" ) { + options.origin = origin || ["middle","center"]; + options.restore = true; + } - // Create element - var el = $(this), props = ['position','top','bottom','left','right','opacity']; + options.from = o.from || ( mode === "show" ? { + height: 0, + width: 0, + outerHeight: 0, + outerWidth: 0 + } : original ); + options.to = { + height: original.height * factor.y, + width: original.width * factor.x, + outerHeight: original.outerHeight * factor.y, + outerWidth: original.outerWidth * factor.x + }; - // Set options - var mode = $.effects.setMode(el, o.options.mode || 'hide'); // Set Mode - var direction = o.options.direction || 'left'; // Default Direction - - // Adjust - $.effects.save(el, props); el.show(); // Save & Show - $.effects.createWrapper(el); // Create Wrapper - var ref = (direction == 'up' || direction == 'down') ? 'top' : 'left'; - var motion = (direction == 'up' || direction == 'left') ? 'pos' : 'neg'; - var distance = o.options.distance || (ref == 'top' ? el.outerHeight({margin:true}) / 2 : el.outerWidth({margin:true}) / 2); - if (mode == 'show') el.css('opacity', 0).css(ref, motion == 'pos' ? -distance : distance); // Shift - - // Animation - var animation = {opacity: mode == 'show' ? 1 : 0}; - animation[ref] = (mode == 'show' ? (motion == 'pos' ? '+=' : '-=') : (motion == 'pos' ? '-=' : '+=')) + distance; - - // Animate - el.animate(animation, { queue: false, duration: o.duration, easing: o.options.easing, complete: function() { - if(mode == 'hide') el.hide(); // Hide - $.effects.restore(el, props); $.effects.removeWrapper(el); // Restore - if(o.callback) o.callback.apply(this, arguments); // Callback - el.dequeue(); - }}); + // Fade option to support puff + if ( options.fade ) { + if ( mode === "show" ) { + options.from.opacity = 0; + options.to.opacity = 1; + } + if ( mode === "hide" ) { + options.from.opacity = 1; + options.to.opacity = 0; + } + } - }); + // Animate + el.effect( options ); }; -})(jQuery); -/* - * jQuery UI Effects Explode 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Effects/Explode - * - * Depends: - * jquery.effects.core.js - */ -(function( $, undefined ) { +$.effects.effect.size = function( o, done ) { -$.effects.explode = function(o) { + // Create element + var original, baseline, factor, + el = $( this ), + props0 = [ "position", "top", "bottom", "left", "right", "width", "height", "overflow", "opacity" ], - return this.queue(function() { + // Always restore + props1 = [ "position", "top", "bottom", "left", "right", "overflow", "opacity" ], - var rows = o.options.pieces ? Math.round(Math.sqrt(o.options.pieces)) : 3; - var cells = o.options.pieces ? Math.round(Math.sqrt(o.options.pieces)) : 3; + // Copy for children + props2 = [ "width", "height", "overflow" ], + cProps = [ "fontSize" ], + vProps = [ "borderTopWidth", "borderBottomWidth", "paddingTop", "paddingBottom" ], + hProps = [ "borderLeftWidth", "borderRightWidth", "paddingLeft", "paddingRight" ], - o.options.mode = o.options.mode == 'toggle' ? ($(this).is(':visible') ? 'hide' : 'show') : o.options.mode; - var el = $(this).show().css('visibility', 'hidden'); - var offset = el.offset(); + // Set options + mode = $.effects.setMode( el, o.mode || "effect" ), + restore = o.restore || mode !== "effect", + scale = o.scale || "both", + origin = o.origin || [ "middle", "center" ], + position = el.css( "position" ), + props = restore ? props0 : props1, + zero = { + height: 0, + width: 0, + outerHeight: 0, + outerWidth: 0 + }; - //Substract the margins - not fixing the problem yet. - offset.top -= parseInt(el.css("marginTop"),10) || 0; - offset.left -= parseInt(el.css("marginLeft"),10) || 0; + if ( mode === "show" ) { + el.show(); + } + original = { + height: el.height(), + width: el.width(), + outerHeight: el.outerHeight(), + outerWidth: el.outerWidth() + }; - var width = el.outerWidth(true); - var height = el.outerHeight(true); + if ( o.mode === "toggle" && mode === "show" ) { + el.from = o.to || zero; + el.to = o.from || original; + } else { + el.from = o.from || ( mode === "show" ? zero : original ); + el.to = o.to || ( mode === "hide" ? zero : original ); + } - for(var i=0;i
    ') - .css({ - position: 'absolute', - visibility: 'visible', - left: -j*(width/cells), - top: -i*(height/rows) - }) - .parent() - .addClass('ui-effects-explode') - .css({ - position: 'absolute', - overflow: 'hidden', - width: width/cells, - height: height/rows, - left: offset.left + j*(width/cells) + (o.options.mode == 'show' ? (j-Math.floor(cells/2))*(width/cells) : 0), - top: offset.top + i*(height/rows) + (o.options.mode == 'show' ? (i-Math.floor(rows/2))*(height/rows) : 0), - opacity: o.options.mode == 'show' ? 0 : 1 - }).animate({ - left: offset.left + j*(width/cells) + (o.options.mode == 'show' ? 0 : (j-Math.floor(cells/2))*(width/cells)), - top: offset.top + i*(height/rows) + (o.options.mode == 'show' ? 0 : (i-Math.floor(rows/2))*(height/rows)), - opacity: o.options.mode == 'show' ? 1 : 0 - }, o.duration || 500); + // Set scaling factor + factor = { + from: { + y: el.from.height / original.height, + x: el.from.width / original.width + }, + to: { + y: el.to.height / original.height, + x: el.to.width / original.width + } + }; + + // Scale the css box + if ( scale === "box" || scale === "both" ) { + + // Vertical props scaling + if ( factor.from.y !== factor.to.y ) { + props = props.concat( vProps ); + el.from = $.effects.setTransition( el, vProps, factor.from.y, el.from ); + el.to = $.effects.setTransition( el, vProps, factor.to.y, el.to ); + } + + // Horizontal props scaling + if ( factor.from.x !== factor.to.x ) { + props = props.concat( hProps ); + el.from = $.effects.setTransition( el, hProps, factor.from.x, el.from ); + el.to = $.effects.setTransition( el, hProps, factor.to.x, el.to ); } } - // Set a timeout, to call the callback approx. when the other animations have finished - setTimeout(function() { + // Scale the content + if ( scale === "content" || scale === "both" ) { - o.options.mode == 'show' ? el.css({ visibility: 'visible' }) : el.css({ visibility: 'visible' }).hide(); - if(o.callback) o.callback.apply(el[0]); // Callback - el.dequeue(); + // Vertical props scaling + if ( factor.from.y !== factor.to.y ) { + props = props.concat( cProps ).concat( props2 ); + el.from = $.effects.setTransition( el, cProps, factor.from.y, el.from ); + el.to = $.effects.setTransition( el, cProps, factor.to.y, el.to ); + } + } - $('div.ui-effects-explode').remove(); + $.effects.save( el, props ); + el.show(); + $.effects.createWrapper( el ); + el.css( "overflow", "hidden" ).css( el.from ); + + // Adjust + if (origin) { // Calculate baseline shifts + baseline = $.effects.getBaseline( origin, original ); + el.from.top = ( original.outerHeight - el.outerHeight() ) * baseline.y; + el.from.left = ( original.outerWidth - el.outerWidth() ) * baseline.x; + el.to.top = ( original.outerHeight - el.to.outerHeight ) * baseline.y; + el.to.left = ( original.outerWidth - el.to.outerWidth ) * baseline.x; + } + el.css( el.from ); // set top & left + + // Animate + if ( scale === "content" || scale === "both" ) { // Scale the children + + // Add margins/font-size + vProps = vProps.concat([ "marginTop", "marginBottom" ]).concat(cProps); + hProps = hProps.concat([ "marginLeft", "marginRight" ]); + props2 = props0.concat(vProps).concat(hProps); + + el.find( "*[width]" ).each( function(){ + var child = $( this ), + c_original = { + height: child.height(), + width: child.width(), + outerHeight: child.outerHeight(), + outerWidth: child.outerWidth() + }; + if (restore) { + $.effects.save(child, props2); + } - }, o.duration || 500); + child.from = { + height: c_original.height * factor.from.y, + width: c_original.width * factor.from.x, + outerHeight: c_original.outerHeight * factor.from.y, + outerWidth: c_original.outerWidth * factor.from.x + }; + child.to = { + height: c_original.height * factor.to.y, + width: c_original.width * factor.to.x, + outerHeight: c_original.height * factor.to.y, + outerWidth: c_original.width * factor.to.x + }; + // Vertical props scaling + if ( factor.from.y !== factor.to.y ) { + child.from = $.effects.setTransition( child, vProps, factor.from.y, child.from ); + child.to = $.effects.setTransition( child, vProps, factor.to.y, child.to ); + } - }); + // Horizontal props scaling + if ( factor.from.x !== factor.to.x ) { + child.from = $.effects.setTransition( child, hProps, factor.from.x, child.from ); + child.to = $.effects.setTransition( child, hProps, factor.to.x, child.to ); + } -}; + // Animate children + child.css( child.from ); + child.animate( child.to, o.duration, o.easing, function() { -})(jQuery); -/* - * jQuery UI Effects Fade 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Effects/Fade - * - * Depends: - * jquery.effects.core.js - */ -(function( $, undefined ) { + // Restore children + if ( restore ) { + $.effects.restore( child, props2 ); + } + }); + }); + } -$.effects.fade = function(o) { - return this.queue(function() { - var elem = $(this), - mode = $.effects.setMode(elem, o.options.mode || 'hide'); + // Animate + el.animate( el.to, { + queue: false, + duration: o.duration, + easing: o.easing, + complete: function() { + if ( el.to.opacity === 0 ) { + el.css( "opacity", el.from.opacity ); + } + if( mode === "hide" ) { + el.hide(); + } + $.effects.restore( el, props ); + if ( !restore ) { + + // we need to calculate our new positioning based on the scaling + if ( position === "static" ) { + el.css({ + position: "relative", + top: el.to.top, + left: el.to.left + }); + } else { + $.each([ "top", "left" ], function( idx, pos ) { + el.css( pos, function( _, str ) { + var val = parseInt( str, 10 ), + toRef = idx ? el.to.left : el.to.top; + + // if original was "auto", recalculate the new value from wrapper + if ( str === "auto" ) { + return toRef + "px"; + } - elem.animate({ opacity: mode }, { - queue: false, - duration: o.duration, - easing: o.options.easing, - complete: function() { - (o.callback && o.callback.apply(this, arguments)); - elem.dequeue(); + return val + toRef + "px"; + }); + }); + } } - }); + + $.effects.removeWrapper( el ); + done(); + } }); + }; })(jQuery); -/* - * jQuery UI Effects Fold 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Effects/Fold - * - * Depends: - * jquery.effects.core.js - */ (function( $, undefined ) { -$.effects.fold = function(o) { - - return this.queue(function() { - - // Create element - var el = $(this), props = ['position','top','bottom','left','right']; - - // Set options - var mode = $.effects.setMode(el, o.options.mode || 'hide'); // Set Mode - var size = o.options.size || 15; // Default fold size - var horizFirst = !(!o.options.horizFirst); // Ensure a boolean value - var duration = o.duration ? o.duration / 2 : $.fx.speeds._default / 2; - - // Adjust - $.effects.save(el, props); el.show(); // Save & Show - var wrapper = $.effects.createWrapper(el).css({overflow:'hidden'}); // Create Wrapper - var widthFirst = ((mode == 'show') != horizFirst); - var ref = widthFirst ? ['width', 'height'] : ['height', 'width']; - var distance = widthFirst ? [wrapper.width(), wrapper.height()] : [wrapper.height(), wrapper.width()]; - var percent = /([0-9]+)%/.exec(size); - if(percent) size = parseInt(percent[1],10) / 100 * distance[mode == 'hide' ? 0 : 1]; - if(mode == 'show') wrapper.css(horizFirst ? {height: 0, width: size} : {height: size, width: 0}); // Shift - - // Animation - var animation1 = {}, animation2 = {}; - animation1[ref[0]] = mode == 'show' ? distance[0] : size; - animation2[ref[1]] = mode == 'show' ? distance[1] : 0; - - // Animate - wrapper.animate(animation1, duration, o.options.easing) - .animate(animation2, duration, o.options.easing, function() { - if(mode == 'hide') el.hide(); // Hide - $.effects.restore(el, props); $.effects.removeWrapper(el); // Restore - if(o.callback) o.callback.apply(el[0], arguments); // Callback - el.dequeue(); +$.effects.effect.shake = function( o, done ) { + + var el = $( this ), + props = [ "position", "top", "bottom", "left", "right", "height", "width" ], + mode = $.effects.setMode( el, o.mode || "effect" ), + direction = o.direction || "left", + distance = o.distance || 20, + times = o.times || 3, + anims = times * 2 + 1, + speed = Math.round(o.duration/anims), + ref = (direction === "up" || direction === "down") ? "top" : "left", + positiveMotion = (direction === "up" || direction === "left"), + animation = {}, + animation1 = {}, + animation2 = {}, + i, + + // we will need to re-assemble the queue to stack our animations in place + queue = el.queue(), + queuelen = queue.length; + + $.effects.save( el, props ); + el.show(); + $.effects.createWrapper( el ); + + // Animation + animation[ ref ] = ( positiveMotion ? "-=" : "+=" ) + distance; + animation1[ ref ] = ( positiveMotion ? "+=" : "-=" ) + distance * 2; + animation2[ ref ] = ( positiveMotion ? "-=" : "+=" ) + distance * 2; + + // Animate + el.animate( animation, speed, o.easing ); + + // Shakes + for ( i = 1; i < times; i++ ) { + el.animate( animation1, speed, o.easing ).animate( animation2, speed, o.easing ); + } + el + .animate( animation1, speed, o.easing ) + .animate( animation, speed / 2, o.easing ) + .queue(function() { + if ( mode === "hide" ) { + el.hide(); + } + $.effects.restore( el, props ); + $.effects.removeWrapper( el ); + done(); }); - }); + // inject all the animations we just queued to be first in line (after "inprogress") + if ( queuelen > 1) { + queue.splice.apply( queue, + [ 1, 0 ].concat( queue.splice( queuelen, anims + 1 ) ) ); + } + el.dequeue(); }; })(jQuery); -/* - * jQuery UI Effects Highlight 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Effects/Highlight - * - * Depends: - * jquery.effects.core.js - */ (function( $, undefined ) { -$.effects.highlight = function(o) { - return this.queue(function() { - var elem = $(this), - props = ['backgroundImage', 'backgroundColor', 'opacity'], - mode = $.effects.setMode(elem, o.options.mode || 'show'), - animation = { - backgroundColor: elem.css('backgroundColor') - }; +$.effects.effect.slide = function( o, done ) { + + // Create element + var el = $( this ), + props = [ "position", "top", "bottom", "left", "right", "width", "height" ], + mode = $.effects.setMode( el, o.mode || "show" ), + show = mode === "show", + direction = o.direction || "left", + ref = (direction === "up" || direction === "down") ? "top" : "left", + positiveMotion = (direction === "up" || direction === "left"), + distance, + animation = {}; + + // Adjust + $.effects.save( el, props ); + el.show(); + distance = o.distance || el[ ref === "top" ? "outerHeight" : "outerWidth" ]( true ); + + $.effects.createWrapper( el ).css({ + overflow: "hidden" + }); + + if ( show ) { + el.css( ref, positiveMotion ? (isNaN(distance) ? "-" + distance : -distance) : distance ); + } - if (mode == 'hide') { - animation.opacity = 0; + // Animation + animation[ ref ] = ( show ? + ( positiveMotion ? "+=" : "-=") : + ( positiveMotion ? "-=" : "+=")) + + distance; + + // Animate + el.animate( animation, { + queue: false, + duration: o.duration, + easing: o.easing, + complete: function() { + if ( mode === "hide" ) { + el.hide(); + } + $.effects.restore( el, props ); + $.effects.removeWrapper( el ); + done(); } + }); +}; - $.effects.save(elem, props); - elem - .show() +})(jQuery); +(function( $, undefined ) { + +$.effects.effect.transfer = function( o, done ) { + var elem = $( this ), + target = $( o.to ), + targetFixed = target.css( "position" ) === "fixed", + body = $("body"), + fixTop = targetFixed ? body.scrollTop() : 0, + fixLeft = targetFixed ? body.scrollLeft() : 0, + endPosition = target.offset(), + animation = { + top: endPosition.top - fixTop , + left: endPosition.left - fixLeft , + height: target.innerHeight(), + width: target.innerWidth() + }, + startPosition = elem.offset(), + transfer = $( '
    ' ) + .appendTo( document.body ) + .addClass( o.className ) .css({ - backgroundImage: 'none', - backgroundColor: o.options.color || '#ffff99' + top: startPosition.top - fixTop , + left: startPosition.left - fixLeft , + height: elem.innerHeight(), + width: elem.innerWidth(), + position: targetFixed ? "fixed" : "absolute" }) - .animate(animation, { - queue: false, - duration: o.duration, - easing: o.options.easing, - complete: function() { - (mode == 'hide' && elem.hide()); - $.effects.restore(elem, props); - (mode == 'show' && !$.support.opacity && this.style.removeAttribute('filter')); - (o.callback && o.callback.apply(this, arguments)); - elem.dequeue(); - } + .animate( animation, o.duration, o.easing, function() { + transfer.remove(); + done(); }); - }); }; })(jQuery); -/* - * jQuery UI Effects Pulsate 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Effects/Pulsate - * - * Depends: - * jquery.effects.core.js - */ (function( $, undefined ) { -$.effects.pulsate = function(o) { - return this.queue(function() { - var elem = $(this), - mode = $.effects.setMode(elem, o.options.mode || 'show'); - times = ((o.options.times || 5) * 2) - 1; - duration = o.duration ? o.duration / 2 : $.fx.speeds._default / 2, - isVisible = elem.is(':visible'), - animateTo = 0; - - if (!isVisible) { - elem.css('opacity', 0).show(); - animateTo = 1; - } - - if ((mode == 'hide' && isVisible) || (mode == 'show' && !isVisible)) { - times--; - } +var mouseHandled = false; - for (var i = 0; i < times; i++) { - elem.animate({ opacity: animateTo }, duration, o.options.easing); - animateTo = (animateTo + 1) % 2; - } +$.widget( "ui.menu", { + version: "1.9.2", + defaultElement: "
      ", + delay: 300, + options: { + icons: { + submenu: "ui-icon-carat-1-e" + }, + menus: "ul", + position: { + my: "left top", + at: "right top" + }, + role: "menu", - elem.animate({ opacity: animateTo }, duration, o.options.easing, function() { - if (animateTo == 0) { - elem.hide(); - } - (o.callback && o.callback.apply(this, arguments)); - }); + // callbacks + blur: null, + focus: null, + select: null + }, - elem - .queue('fx', function() { elem.dequeue(); }) - .dequeue(); - }); -}; + _create: function() { + this.activeMenu = this.element; + this.element + .uniqueId() + .addClass( "ui-menu ui-widget ui-widget-content ui-corner-all" ) + .toggleClass( "ui-menu-icons", !!this.element.find( ".ui-icon" ).length ) + .attr({ + role: this.options.role, + tabIndex: 0 + }) + // need to catch all clicks on disabled menu + // not possible through _on + .bind( "click" + this.eventNamespace, $.proxy(function( event ) { + if ( this.options.disabled ) { + event.preventDefault(); + } + }, this )); -})(jQuery); -/* - * jQuery UI Effects Scale 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Effects/Scale - * - * Depends: - * jquery.effects.core.js - */ -(function( $, undefined ) { + if ( this.options.disabled ) { + this.element + .addClass( "ui-state-disabled" ) + .attr( "aria-disabled", "true" ); + } -$.effects.puff = function(o) { - return this.queue(function() { - var elem = $(this), - mode = $.effects.setMode(elem, o.options.mode || 'hide'), - percent = parseInt(o.options.percent, 10) || 150, - factor = percent / 100, - original = { height: elem.height(), width: elem.width() }; - - $.extend(o.options, { - fade: true, - mode: mode, - percent: mode == 'hide' ? percent : 100, - from: mode == 'hide' - ? original - : { - height: original.height * factor, - width: original.width * factor + this._on({ + // Prevent focus from sticking to links inside menu after clicking + // them (focus should always stay on UL during navigation). + "mousedown .ui-menu-item > a": function( event ) { + event.preventDefault(); + }, + "click .ui-state-disabled > a": function( event ) { + event.preventDefault(); + }, + "click .ui-menu-item:has(a)": function( event ) { + var target = $( event.target ).closest( ".ui-menu-item" ); + if ( !mouseHandled && target.not( ".ui-state-disabled" ).length ) { + mouseHandled = true; + + this.select( event ); + // Open submenu on click + if ( target.has( ".ui-menu" ).length ) { + this.expand( event ); + } else if ( !this.element.is( ":focus" ) ) { + // Redirect focus to the menu + this.element.trigger( "focus", [ true ] ); + + // If the active item is on the top level, let it stay active. + // Otherwise, blur the active item since it is no longer visible. + if ( this.active && this.active.parents( ".ui-menu" ).length === 1 ) { + clearTimeout( this.timer ); + } + } + } + }, + "mouseenter .ui-menu-item": function( event ) { + var target = $( event.currentTarget ); + // Remove ui-state-active class from siblings of the newly focused menu item + // to avoid a jump caused by adjacent elements both having a class with a border + target.siblings().children( ".ui-state-active" ).removeClass( "ui-state-active" ); + this.focus( event, target ); + }, + mouseleave: "collapseAll", + "mouseleave .ui-menu": "collapseAll", + focus: function( event, keepActiveItem ) { + // If there's already an active item, keep it active + // If not, activate the first item + var item = this.active || this.element.children( ".ui-menu-item" ).eq( 0 ); + + if ( !keepActiveItem ) { + this.focus( event, item ); } + }, + blur: function( event ) { + this._delay(function() { + if ( !$.contains( this.element[0], this.document[0].activeElement ) ) { + this.collapseAll( event ); + } + }); + }, + keydown: "_keydown" }); - elem.effect('scale', o.options, o.duration, o.callback); - elem.dequeue(); - }); -}; - -$.effects.scale = function(o) { - - return this.queue(function() { + this.refresh(); - // Create element - var el = $(this); + // Clicks outside of a menu collapse any open menus + this._on( this.document, { + click: function( event ) { + if ( !$( event.target ).closest( ".ui-menu" ).length ) { + this.collapseAll( event ); + } - // Set options - var options = $.extend(true, {}, o.options); - var mode = $.effects.setMode(el, o.options.mode || 'effect'); // Set Mode - var percent = parseInt(o.options.percent,10) || (parseInt(o.options.percent,10) == 0 ? 0 : (mode == 'hide' ? 0 : 100)); // Set default scaling percent - var direction = o.options.direction || 'both'; // Set default axis - var origin = o.options.origin; // The origin of the scaling - if (mode != 'effect') { // Set default origin and restore for show/hide - options.origin = origin || ['middle','center']; - options.restore = true; - } - var original = {height: el.height(), width: el.width()}; // Save original - el.from = o.options.from || (mode == 'show' ? {height: 0, width: 0} : original); // Default from state - - // Adjust - var factor = { // Set scaling factor - y: direction != 'horizontal' ? (percent / 100) : 1, - x: direction != 'vertical' ? (percent / 100) : 1 - }; - el.to = {height: original.height * factor.y, width: original.width * factor.x}; // Set to state + // Reset the mouseHandled flag + mouseHandled = false; + } + }); + }, - if (o.options.fade) { // Fade option to support puff - if (mode == 'show') {el.from.opacity = 0; el.to.opacity = 1;}; - if (mode == 'hide') {el.from.opacity = 1; el.to.opacity = 0;}; - }; + _destroy: function() { + // Destroy (sub)menus + this.element + .removeAttr( "aria-activedescendant" ) + .find( ".ui-menu" ).andSelf() + .removeClass( "ui-menu ui-widget ui-widget-content ui-corner-all ui-menu-icons" ) + .removeAttr( "role" ) + .removeAttr( "tabIndex" ) + .removeAttr( "aria-labelledby" ) + .removeAttr( "aria-expanded" ) + .removeAttr( "aria-hidden" ) + .removeAttr( "aria-disabled" ) + .removeUniqueId() + .show(); + + // Destroy menu items + this.element.find( ".ui-menu-item" ) + .removeClass( "ui-menu-item" ) + .removeAttr( "role" ) + .removeAttr( "aria-disabled" ) + .children( "a" ) + .removeUniqueId() + .removeClass( "ui-corner-all ui-state-hover" ) + .removeAttr( "tabIndex" ) + .removeAttr( "role" ) + .removeAttr( "aria-haspopup" ) + .children().each( function() { + var elem = $( this ); + if ( elem.data( "ui-menu-submenu-carat" ) ) { + elem.remove(); + } + }); - // Animation - options.from = el.from; options.to = el.to; options.mode = mode; + // Destroy menu dividers + this.element.find( ".ui-menu-divider" ).removeClass( "ui-menu-divider ui-widget-content" ); + }, - // Animate - el.effect('size', options, o.duration, o.callback); - el.dequeue(); - }); + _keydown: function( event ) { + var match, prev, character, skip, regex, + preventDefault = true; -}; + function escape( value ) { + return value.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" ); + } -$.effects.size = function(o) { + switch ( event.keyCode ) { + case $.ui.keyCode.PAGE_UP: + this.previousPage( event ); + break; + case $.ui.keyCode.PAGE_DOWN: + this.nextPage( event ); + break; + case $.ui.keyCode.HOME: + this._move( "first", "first", event ); + break; + case $.ui.keyCode.END: + this._move( "last", "last", event ); + break; + case $.ui.keyCode.UP: + this.previous( event ); + break; + case $.ui.keyCode.DOWN: + this.next( event ); + break; + case $.ui.keyCode.LEFT: + this.collapse( event ); + break; + case $.ui.keyCode.RIGHT: + if ( this.active && !this.active.is( ".ui-state-disabled" ) ) { + this.expand( event ); + } + break; + case $.ui.keyCode.ENTER: + case $.ui.keyCode.SPACE: + this._activate( event ); + break; + case $.ui.keyCode.ESCAPE: + this.collapse( event ); + break; + default: + preventDefault = false; + prev = this.previousFilter || ""; + character = String.fromCharCode( event.keyCode ); + skip = false; - return this.queue(function() { + clearTimeout( this.filterTimer ); - // Create element - var el = $(this), props = ['position','top','bottom','left','right','width','height','overflow','opacity']; - var props1 = ['position','top','bottom','left','right','overflow','opacity']; // Always restore - var props2 = ['width','height','overflow']; // Copy for children - var cProps = ['fontSize']; - var vProps = ['borderTopWidth', 'borderBottomWidth', 'paddingTop', 'paddingBottom']; - var hProps = ['borderLeftWidth', 'borderRightWidth', 'paddingLeft', 'paddingRight']; + if ( character === prev ) { + skip = true; + } else { + character = prev + character; + } - // Set options - var mode = $.effects.setMode(el, o.options.mode || 'effect'); // Set Mode - var restore = o.options.restore || false; // Default restore - var scale = o.options.scale || 'both'; // Default scale mode - var origin = o.options.origin; // The origin of the sizing - var original = {height: el.height(), width: el.width()}; // Save original - el.from = o.options.from || original; // Default from state - el.to = o.options.to || original; // Default to state - // Adjust - if (origin) { // Calculate baseline shifts - var baseline = $.effects.getBaseline(origin, original); - el.from.top = (original.height - el.from.height) * baseline.y; - el.from.left = (original.width - el.from.width) * baseline.x; - el.to.top = (original.height - el.to.height) * baseline.y; - el.to.left = (original.width - el.to.width) * baseline.x; - }; - var factor = { // Set scaling factor - from: {y: el.from.height / original.height, x: el.from.width / original.width}, - to: {y: el.to.height / original.height, x: el.to.width / original.width} - }; - if (scale == 'box' || scale == 'both') { // Scale the css box - if (factor.from.y != factor.to.y) { // Vertical props scaling - props = props.concat(vProps); - el.from = $.effects.setTransition(el, vProps, factor.from.y, el.from); - el.to = $.effects.setTransition(el, vProps, factor.to.y, el.to); - }; - if (factor.from.x != factor.to.x) { // Horizontal props scaling - props = props.concat(hProps); - el.from = $.effects.setTransition(el, hProps, factor.from.x, el.from); - el.to = $.effects.setTransition(el, hProps, factor.to.x, el.to); - }; - }; - if (scale == 'content' || scale == 'both') { // Scale the content - if (factor.from.y != factor.to.y) { // Vertical props scaling - props = props.concat(cProps); - el.from = $.effects.setTransition(el, cProps, factor.from.y, el.from); - el.to = $.effects.setTransition(el, cProps, factor.to.y, el.to); - }; - }; - $.effects.save(el, restore ? props : props1); el.show(); // Save & Show - $.effects.createWrapper(el); // Create Wrapper - el.css('overflow','hidden').css(el.from); // Shift - - // Animate - if (scale == 'content' || scale == 'both') { // Scale the children - vProps = vProps.concat(['marginTop','marginBottom']).concat(cProps); // Add margins/font-size - hProps = hProps.concat(['marginLeft','marginRight']); // Add margins - props2 = props.concat(vProps).concat(hProps); // Concat - el.find("*[width]").each(function(){ - child = $(this); - if (restore) $.effects.save(child, props2); - var c_original = {height: child.height(), width: child.width()}; // Save original - child.from = {height: c_original.height * factor.from.y, width: c_original.width * factor.from.x}; - child.to = {height: c_original.height * factor.to.y, width: c_original.width * factor.to.x}; - if (factor.from.y != factor.to.y) { // Vertical props scaling - child.from = $.effects.setTransition(child, vProps, factor.from.y, child.from); - child.to = $.effects.setTransition(child, vProps, factor.to.y, child.to); - }; - if (factor.from.x != factor.to.x) { // Horizontal props scaling - child.from = $.effects.setTransition(child, hProps, factor.from.x, child.from); - child.to = $.effects.setTransition(child, hProps, factor.to.x, child.to); - }; - child.css(child.from); // Shift children - child.animate(child.to, o.duration, o.options.easing, function(){ - if (restore) $.effects.restore(child, props2); // Restore children - }); // Animate children + regex = new RegExp( "^" + escape( character ), "i" ); + match = this.activeMenu.children( ".ui-menu-item" ).filter(function() { + return regex.test( $( this ).children( "a" ).text() ); }); - }; + match = skip && match.index( this.active.next() ) !== -1 ? + this.active.nextAll( ".ui-menu-item" ) : + match; + + // If no matches on the current filter, reset to the last character pressed + // to move down the menu to the first item that starts with that character + if ( !match.length ) { + character = String.fromCharCode( event.keyCode ); + regex = new RegExp( "^" + escape( character ), "i" ); + match = this.activeMenu.children( ".ui-menu-item" ).filter(function() { + return regex.test( $( this ).children( "a" ).text() ); + }); + } - // Animate - el.animate(el.to, { queue: false, duration: o.duration, easing: o.options.easing, complete: function() { - if (el.to.opacity === 0) { - el.css('opacity', el.from.opacity); + if ( match.length ) { + this.focus( event, match ); + if ( match.length > 1 ) { + this.previousFilter = character; + this.filterTimer = this._delay(function() { + delete this.previousFilter; + }, 1000 ); + } else { + delete this.previousFilter; + } + } else { + delete this.previousFilter; } - if(mode == 'hide') el.hide(); // Hide - $.effects.restore(el, restore ? props : props1); $.effects.removeWrapper(el); // Restore - if(o.callback) o.callback.apply(this, arguments); // Callback - el.dequeue(); - }}); + } - }); + if ( preventDefault ) { + event.preventDefault(); + } + }, -}; + _activate: function( event ) { + if ( !this.active.is( ".ui-state-disabled" ) ) { + if ( this.active.children( "a[aria-haspopup='true']" ).length ) { + this.expand( event ); + } else { + this.select( event ); + } + } + }, -})(jQuery); -/* - * jQuery UI Effects Shake 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Effects/Shake - * - * Depends: - * jquery.effects.core.js - */ -(function( $, undefined ) { + refresh: function() { + var menus, + icon = this.options.icons.submenu, + submenus = this.element.find( this.options.menus ); -$.effects.shake = function(o) { + // Initialize nested menus + submenus.filter( ":not(.ui-menu)" ) + .addClass( "ui-menu ui-widget ui-widget-content ui-corner-all" ) + .hide() + .attr({ + role: this.options.role, + "aria-hidden": "true", + "aria-expanded": "false" + }) + .each(function() { + var menu = $( this ), + item = menu.prev( "a" ), + submenuCarat = $( "" ) + .addClass( "ui-menu-icon ui-icon " + icon ) + .data( "ui-menu-submenu-carat", true ); + + item + .attr( "aria-haspopup", "true" ) + .prepend( submenuCarat ); + menu.attr( "aria-labelledby", item.attr( "id" ) ); + }); - return this.queue(function() { + menus = submenus.add( this.element ); - // Create element - var el = $(this), props = ['position','top','bottom','left','right']; + // Don't refresh list items that are already adapted + menus.children( ":not(.ui-menu-item):has(a)" ) + .addClass( "ui-menu-item" ) + .attr( "role", "presentation" ) + .children( "a" ) + .uniqueId() + .addClass( "ui-corner-all" ) + .attr({ + tabIndex: -1, + role: this._itemRole() + }); - // Set options - var mode = $.effects.setMode(el, o.options.mode || 'effect'); // Set Mode - var direction = o.options.direction || 'left'; // Default direction - var distance = o.options.distance || 20; // Default distance - var times = o.options.times || 3; // Default # of times - var speed = o.duration || o.options.duration || 140; // Default speed per shake - - // Adjust - $.effects.save(el, props); el.show(); // Save & Show - $.effects.createWrapper(el); // Create Wrapper - var ref = (direction == 'up' || direction == 'down') ? 'top' : 'left'; - var motion = (direction == 'up' || direction == 'left') ? 'pos' : 'neg'; - - // Animation - var animation = {}, animation1 = {}, animation2 = {}; - animation[ref] = (motion == 'pos' ? '-=' : '+=') + distance; - animation1[ref] = (motion == 'pos' ? '+=' : '-=') + distance * 2; - animation2[ref] = (motion == 'pos' ? '-=' : '+=') + distance * 2; - - // Animate - el.animate(animation, speed, o.options.easing); - for (var i = 1; i < times; i++) { // Shakes - el.animate(animation1, speed, o.options.easing).animate(animation2, speed, o.options.easing); - }; - el.animate(animation1, speed, o.options.easing). - animate(animation, speed / 2, o.options.easing, function(){ // Last shake - $.effects.restore(el, props); $.effects.removeWrapper(el); // Restore - if(o.callback) o.callback.apply(this, arguments); // Callback + // Initialize unlinked menu-items containing spaces and/or dashes only as dividers + menus.children( ":not(.ui-menu-item)" ).each(function() { + var item = $( this ); + // hyphen, em dash, en dash + if ( !/[^\-—–\s]/.test( item.text() ) ) { + item.addClass( "ui-widget-content ui-menu-divider" ); + } }); - el.queue('fx', function() { el.dequeue(); }); - el.dequeue(); - }); -}; + // Add aria-disabled attribute to any disabled menu item + menus.children( ".ui-state-disabled" ).attr( "aria-disabled", "true" ); -})(jQuery); -/* - * jQuery UI Effects Slide 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Effects/Slide - * - * Depends: - * jquery.effects.core.js - */ -(function( $, undefined ) { + // If the active item has been removed, blur the menu + if ( this.active && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) { + this.blur(); + } + }, -$.effects.slide = function(o) { + _itemRole: function() { + return { + menu: "menuitem", + listbox: "option" + }[ this.options.role ]; + }, - return this.queue(function() { + focus: function( event, item ) { + var nested, focused; + this.blur( event, event && event.type === "focus" ); - // Create element - var el = $(this), props = ['position','top','bottom','left','right']; + this._scrollIntoView( item ); - // Set options - var mode = $.effects.setMode(el, o.options.mode || 'show'); // Set Mode - var direction = o.options.direction || 'left'; // Default Direction - - // Adjust - $.effects.save(el, props); el.show(); // Save & Show - $.effects.createWrapper(el).css({overflow:'hidden'}); // Create Wrapper - var ref = (direction == 'up' || direction == 'down') ? 'top' : 'left'; - var motion = (direction == 'up' || direction == 'left') ? 'pos' : 'neg'; - var distance = o.options.distance || (ref == 'top' ? el.outerHeight({margin:true}) : el.outerWidth({margin:true})); - if (mode == 'show') el.css(ref, motion == 'pos' ? (isNaN(distance) ? "-" + distance : -distance) : distance); // Shift - - // Animation - var animation = {}; - animation[ref] = (mode == 'show' ? (motion == 'pos' ? '+=' : '-=') : (motion == 'pos' ? '-=' : '+=')) + distance; - - // Animate - el.animate(animation, { queue: false, duration: o.duration, easing: o.options.easing, complete: function() { - if(mode == 'hide') el.hide(); // Hide - $.effects.restore(el, props); $.effects.removeWrapper(el); // Restore - if(o.callback) o.callback.apply(this, arguments); // Callback - el.dequeue(); - }}); + this.active = item.first(); + focused = this.active.children( "a" ).addClass( "ui-state-focus" ); + // Only update aria-activedescendant if there's a role + // otherwise we assume focus is managed elsewhere + if ( this.options.role ) { + this.element.attr( "aria-activedescendant", focused.attr( "id" ) ); + } - }); + // Highlight active parent menu item, if any + this.active + .parent() + .closest( ".ui-menu-item" ) + .children( "a:first" ) + .addClass( "ui-state-active" ); -}; + if ( event && event.type === "keydown" ) { + this._close(); + } else { + this.timer = this._delay(function() { + this._close(); + }, this.delay ); + } -})(jQuery); -/* - * jQuery UI Effects Transfer 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Effects/Transfer - * - * Depends: - * jquery.effects.core.js - */ -(function( $, undefined ) { + nested = item.children( ".ui-menu" ); + if ( nested.length && ( /^mouse/.test( event.type ) ) ) { + this._startOpening(nested); + } + this.activeMenu = item.parent(); -$.effects.transfer = function(o) { - return this.queue(function() { - var elem = $(this), - target = $(o.options.to), - endPosition = target.offset(), - animation = { - top: endPosition.top, - left: endPosition.left, - height: target.innerHeight(), - width: target.innerWidth() - }, - startPosition = elem.offset(), - transfer = $('
      ') - .appendTo(document.body) - .addClass(o.options.className) - .css({ - top: startPosition.top, - left: startPosition.left, - height: elem.innerHeight(), - width: elem.innerWidth(), - position: 'absolute' - }) - .animate(animation, o.duration, o.options.easing, function() { - transfer.remove(); - (o.callback && o.callback.apply(elem[0], arguments)); - elem.dequeue(); - }); - }); -}; + this._trigger( "focus", event, { item: item } ); + }, -})(jQuery); -/* - * jQuery UI Accordion 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Accordion - * - * Depends: - * jquery.ui.core.js - * jquery.ui.widget.js - */ -(function( $, undefined ) { + _scrollIntoView: function( item ) { + var borderTop, paddingTop, offset, scroll, elementHeight, itemHeight; + if ( this._hasScroll() ) { + borderTop = parseFloat( $.css( this.activeMenu[0], "borderTopWidth" ) ) || 0; + paddingTop = parseFloat( $.css( this.activeMenu[0], "paddingTop" ) ) || 0; + offset = item.offset().top - this.activeMenu.offset().top - borderTop - paddingTop; + scroll = this.activeMenu.scrollTop(); + elementHeight = this.activeMenu.height(); + itemHeight = item.height(); -$.widget( "ui.accordion", { - options: { - active: 0, - animated: "slide", - autoHeight: true, - clearStyle: false, - collapsible: false, - event: "click", - fillSpace: false, - header: "> li > :first-child,> :not(li):even", - icons: { - header: "ui-icon-triangle-1-e", - headerSelected: "ui-icon-triangle-1-s" - }, - navigation: false, - navigationFilter: function() { - return this.href.toLowerCase() === location.href.toLowerCase(); + if ( offset < 0 ) { + this.activeMenu.scrollTop( scroll + offset ); + } else if ( offset + itemHeight > elementHeight ) { + this.activeMenu.scrollTop( scroll + offset - elementHeight + itemHeight ); + } } }, - _create: function() { - var self = this, - options = self.options; + blur: function( event, fromFocus ) { + if ( !fromFocus ) { + clearTimeout( this.timer ); + } - self.running = 0; + if ( !this.active ) { + return; + } - self.element - .addClass( "ui-accordion ui-widget ui-helper-reset" ) - // in lack of child-selectors in CSS - // we need to mark top-LIs in a UL-accordion for some IE-fix - .children( "li" ) - .addClass( "ui-accordion-li-fix" ); + this.active.children( "a" ).removeClass( "ui-state-focus" ); + this.active = null; - self.headers = self.element.find( options.header ) - .addClass( "ui-accordion-header ui-helper-reset ui-state-default ui-corner-all" ) - .bind( "mouseenter.accordion", function() { - if ( options.disabled ) { - return; - } - $( this ).addClass( "ui-state-hover" ); - }) - .bind( "mouseleave.accordion", function() { - if ( options.disabled ) { - return; - } - $( this ).removeClass( "ui-state-hover" ); - }) - .bind( "focus.accordion", function() { - if ( options.disabled ) { - return; - } - $( this ).addClass( "ui-state-focus" ); - }) - .bind( "blur.accordion", function() { - if ( options.disabled ) { - return; - } - $( this ).removeClass( "ui-state-focus" ); - }); + this._trigger( "blur", event, { item: this.active } ); + }, - self.headers.next() - .addClass( "ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom" ); + _startOpening: function( submenu ) { + clearTimeout( this.timer ); - if ( options.navigation ) { - var current = self.element.find( "a" ).filter( options.navigationFilter ).eq( 0 ); - if ( current.length ) { - var header = current.closest( ".ui-accordion-header" ); - if ( header.length ) { - // anchor within header - self.active = header; - } else { - // anchor within content - self.active = current.closest( ".ui-accordion-content" ).prev(); - } - } + // Don't open if already open fixes a Firefox bug that caused a .5 pixel + // shift in the submenu position when mousing over the carat icon + if ( submenu.attr( "aria-hidden" ) !== "true" ) { + return; } - self.active = self._findActive( self.active || options.active ) - .addClass( "ui-state-default ui-state-active" ) - .toggleClass( "ui-corner-all" ) - .toggleClass( "ui-corner-top" ); - self.active.next().addClass( "ui-accordion-content-active" ); + this.timer = this._delay(function() { + this._close(); + this._open( submenu ); + }, this.delay ); + }, - self._createIcons(); - self.resize(); - - // ARIA - self.element.attr( "role", "tablist" ); + _open: function( submenu ) { + var position = $.extend({ + of: this.active + }, this.options.position ); - self.headers - .attr( "role", "tab" ) - .bind( "keydown.accordion", function( event ) { - return self._keydown( event ); - }) - .next() - .attr( "role", "tabpanel" ); + clearTimeout( this.timer ); + this.element.find( ".ui-menu" ).not( submenu.parents( ".ui-menu" ) ) + .hide() + .attr( "aria-hidden", "true" ); - self.headers - .not( self.active || "" ) - .attr({ - "aria-expanded": "false", - "aria-selected": "false", - tabIndex: -1 - }) - .next() - .hide(); + submenu + .show() + .removeAttr( "aria-hidden" ) + .attr( "aria-expanded", "true" ) + .position( position ); + }, - // make sure at least one header is in the tab order - if ( !self.active.length ) { - self.headers.eq( 0 ).attr( "tabIndex", 0 ); - } else { - self.active - .attr({ - "aria-expanded": "true", - "aria-selected": "true", - tabIndex: 0 - }); - } + collapseAll: function( event, all ) { + clearTimeout( this.timer ); + this.timer = this._delay(function() { + // If we were passed an event, look for the submenu that contains the event + var currentMenu = all ? this.element : + $( event && event.target ).closest( this.element.find( ".ui-menu" ) ); - // only need links in tab order for Safari - if ( !$.browser.safari ) { - self.headers.find( "a" ).attr( "tabIndex", -1 ); + // If we found no valid submenu ancestor, use the main menu to close all sub menus anyway + if ( !currentMenu.length ) { + currentMenu = this.element; + } + + this._close( currentMenu ); + + this.blur( event ); + this.activeMenu = currentMenu; + }, this.delay ); + }, + + // With no arguments, closes the currently active menu - if nothing is active + // it closes all menus. If passed an argument, it will search for menus BELOW + _close: function( startMenu ) { + if ( !startMenu ) { + startMenu = this.active ? this.active.parent() : this.element; } - if ( options.event ) { - self.headers.bind( options.event.split(" ").join(".accordion ") + ".accordion", function(event) { - self._clickHandler.call( self, event, this ); - event.preventDefault(); - }); + startMenu + .find( ".ui-menu" ) + .hide() + .attr( "aria-hidden", "true" ) + .attr( "aria-expanded", "false" ) + .end() + .find( "a.ui-state-active" ) + .removeClass( "ui-state-active" ); + }, + + collapse: function( event ) { + var newItem = this.active && + this.active.parent().closest( ".ui-menu-item", this.element ); + if ( newItem && newItem.length ) { + this._close(); + this.focus( event, newItem ); } }, - _createIcons: function() { - var options = this.options; - if ( options.icons ) { - $( "" ) - .addClass( "ui-icon " + options.icons.header ) - .prependTo( this.headers ); - this.active.children( ".ui-icon" ) - .toggleClass(options.icons.header) - .toggleClass(options.icons.headerSelected); - this.element.addClass( "ui-accordion-icons" ); + expand: function( event ) { + var newItem = this.active && + this.active + .children( ".ui-menu " ) + .children( ".ui-menu-item" ) + .first(); + + if ( newItem && newItem.length ) { + this._open( newItem.parent() ); + + // Delay so Firefox will not hide activedescendant change in expanding submenu from AT + this._delay(function() { + this.focus( event, newItem ); + }); } }, - _destroyIcons: function() { - this.headers.children( ".ui-icon" ).remove(); - this.element.removeClass( "ui-accordion-icons" ); + next: function( event ) { + this._move( "next", "first", event ); }, - destroy: function() { - var options = this.options; + previous: function( event ) { + this._move( "prev", "last", event ); + }, - this.element - .removeClass( "ui-accordion ui-widget ui-helper-reset" ) - .removeAttr( "role" ); + isFirstItem: function() { + return this.active && !this.active.prevAll( ".ui-menu-item" ).length; + }, - this.headers - .unbind( ".accordion" ) - .removeClass( "ui-accordion-header ui-accordion-disabled ui-helper-reset ui-state-default ui-corner-all ui-state-active ui-state-disabled ui-corner-top" ) - .removeAttr( "role" ) - .removeAttr( "aria-expanded" ) - .removeAttr( "aria-selected" ) - .removeAttr( "tabIndex" ); + isLastItem: function() { + return this.active && !this.active.nextAll( ".ui-menu-item" ).length; + }, - this.headers.find( "a" ).removeAttr( "tabIndex" ); - this._destroyIcons(); - var contents = this.headers.next() - .css( "display", "" ) - .removeAttr( "role" ) - .removeClass( "ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active ui-accordion-disabled ui-state-disabled" ); - if ( options.autoHeight || options.fillHeight ) { - contents.css( "height", "" ); + _move: function( direction, filter, event ) { + var next; + if ( this.active ) { + if ( direction === "first" || direction === "last" ) { + next = this.active + [ direction === "first" ? "prevAll" : "nextAll" ]( ".ui-menu-item" ) + .eq( -1 ); + } else { + next = this.active + [ direction + "All" ]( ".ui-menu-item" ) + .eq( 0 ); + } + } + if ( !next || !next.length || !this.active ) { + next = this.activeMenu.children( ".ui-menu-item" )[ filter ](); } - return $.Widget.prototype.destroy.call( this ); + this.focus( event, next ); }, - _setOption: function( key, value ) { - $.Widget.prototype._setOption.apply( this, arguments ); - - if ( key == "active" ) { - this.activate( value ); + nextPage: function( event ) { + var item, base, height; + + if ( !this.active ) { + this.next( event ); + return; } - if ( key == "icons" ) { - this._destroyIcons(); - if ( value ) { - this._createIcons(); - } + if ( this.isLastItem() ) { + return; } - // #5332 - opacity doesn't cascade to positioned elements in IE - // so we need to add the disabled class to the headers and panels - if ( key == "disabled" ) { - this.headers.add(this.headers.next()) - [ value ? "addClass" : "removeClass" ]( - "ui-accordion-disabled ui-state-disabled" ); + if ( this._hasScroll() ) { + base = this.active.offset().top; + height = this.element.height(); + this.active.nextAll( ".ui-menu-item" ).each(function() { + item = $( this ); + return item.offset().top - base - height < 0; + }); + + this.focus( event, item ); + } else { + this.focus( event, this.activeMenu.children( ".ui-menu-item" ) + [ !this.active ? "first" : "last" ]() ); } }, - _keydown: function( event ) { - if ( this.options.disabled || event.altKey || event.ctrlKey ) { + previousPage: function( event ) { + var item, base, height; + if ( !this.active ) { + this.next( event ); return; } - - var keyCode = $.ui.keyCode, - length = this.headers.length, - currentIndex = this.headers.index( event.target ), - toFocus = false; - - switch ( event.keyCode ) { - case keyCode.RIGHT: - case keyCode.DOWN: - toFocus = this.headers[ ( currentIndex + 1 ) % length ]; - break; - case keyCode.LEFT: - case keyCode.UP: - toFocus = this.headers[ ( currentIndex - 1 + length ) % length ]; - break; - case keyCode.SPACE: - case keyCode.ENTER: - this._clickHandler( { target: event.target }, event.target ); - event.preventDefault(); + if ( this.isFirstItem() ) { + return; } + if ( this._hasScroll() ) { + base = this.active.offset().top; + height = this.element.height(); + this.active.prevAll( ".ui-menu-item" ).each(function() { + item = $( this ); + return item.offset().top - base + height > 0; + }); - if ( toFocus ) { - $( event.target ).attr( "tabIndex", -1 ); - $( toFocus ).attr( "tabIndex", 0 ); - toFocus.focus(); - return false; + this.focus( event, item ); + } else { + this.focus( event, this.activeMenu.children( ".ui-menu-item" ).first() ); } + }, - return true; + _hasScroll: function() { + return this.element.outerHeight() < this.element.prop( "scrollHeight" ); }, - resize: function() { - var options = this.options, - maxHeight; + select: function( event ) { + // TODO: It should never be possible to not have an active item at this + // point, but the tests don't trigger mouseenter before click. + this.active = this.active || $( event.target ).closest( ".ui-menu-item" ); + var ui = { item: this.active }; + if ( !this.active.has( ".ui-menu" ).length ) { + this.collapseAll( event, true ); + } + this._trigger( "select", event, ui ); + } +}); - if ( options.fillSpace ) { - if ( $.browser.msie ) { - var defOverflow = this.element.parent().css( "overflow" ); - this.element.parent().css( "overflow", "hidden"); - } - maxHeight = this.element.parent().height(); - if ($.browser.msie) { - this.element.parent().css( "overflow", defOverflow ); - } +}( jQuery )); +(function( $, undefined ) { - this.headers.each(function() { - maxHeight -= $( this ).outerHeight( true ); - }); +$.widget( "ui.progressbar", { + version: "1.9.2", + options: { + value: 0, + max: 100 + }, - this.headers.next() - .each(function() { - $( this ).height( Math.max( 0, maxHeight - - $( this ).innerHeight() + $( this ).height() ) ); - }) - .css( "overflow", "auto" ); - } else if ( options.autoHeight ) { - maxHeight = 0; - this.headers.next() - .each(function() { - maxHeight = Math.max( maxHeight, $( this ).height( "" ).height() ); - }) - .height( maxHeight ); - } + min: 0, - return this; - }, + _create: function() { + this.element + .addClass( "ui-progressbar ui-widget ui-widget-content ui-corner-all" ) + .attr({ + role: "progressbar", + "aria-valuemin": this.min, + "aria-valuemax": this.options.max, + "aria-valuenow": this._value() + }); - activate: function( index ) { - // TODO this gets called on init, changing the option without an explicit call for that - this.options.active = index; - // call clickHandler with custom event - var active = this._findActive( index )[ 0 ]; - this._clickHandler( { target: active }, active ); + this.valueDiv = $( "
      " ) + .appendTo( this.element ); - return this; + this.oldValue = this._value(); + this._refreshValue(); }, - _findActive: function( selector ) { - return selector - ? typeof selector === "number" - ? this.headers.filter( ":eq(" + selector + ")" ) - : this.headers.not( this.headers.not( selector ) ) - : selector === false - ? $( [] ) - : this.headers.filter( ":eq(0)" ); + _destroy: function() { + this.element + .removeClass( "ui-progressbar ui-widget ui-widget-content ui-corner-all" ) + .removeAttr( "role" ) + .removeAttr( "aria-valuemin" ) + .removeAttr( "aria-valuemax" ) + .removeAttr( "aria-valuenow" ); + + this.valueDiv.remove(); }, - // TODO isn't event.target enough? why the separate target argument? - _clickHandler: function( event, target ) { - var options = this.options; - if ( options.disabled ) { - return; + value: function( newValue ) { + if ( newValue === undefined ) { + return this._value(); } - // called only when using activate(false) to close all parts programmatically - if ( !event.target ) { - if ( !options.collapsible ) { - return; + this._setOption( "value", newValue ); + return this; + }, + + _setOption: function( key, value ) { + if ( key === "value" ) { + this.options.value = value; + this._refreshValue(); + if ( this._value() === this.options.max ) { + this._trigger( "complete" ); } - this.active - .removeClass( "ui-state-active ui-corner-top" ) - .addClass( "ui-state-default ui-corner-all" ) - .children( ".ui-icon" ) - .removeClass( options.icons.headerSelected ) - .addClass( options.icons.header ); - this.active.next().addClass( "ui-accordion-content-active" ); - var toHide = this.active.next(), - data = { - options: options, - newHeader: $( [] ), - oldHeader: options.active, - newContent: $( [] ), - oldContent: toHide - }, - toShow = ( this.active = $( [] ) ); - this._toggle( toShow, toHide, data ); - return; } - // get the click target - var clicked = $( event.currentTarget || target ), - clickedIsActive = clicked[0] === this.active[0]; - - // TODO the option is changed, is that correct? - // TODO if it is correct, shouldn't that happen after determining that the click is valid? - options.active = options.collapsible && clickedIsActive ? - false : - this.headers.index( clicked ); + this._super( key, value ); + }, - // if animations are still active, or the active header is the target, ignore click - if ( this.running || ( !options.collapsible && clickedIsActive ) ) { - return; + _value: function() { + var val = this.options.value; + // normalize invalid value + if ( typeof val !== "number" ) { + val = 0; } + return Math.min( this.options.max, Math.max( this.min, val ) ); + }, - // find elements to show and hide - var active = this.active, - toShow = clicked.next(), - toHide = this.active.next(), - data = { - options: options, - newHeader: clickedIsActive && options.collapsible ? $([]) : clicked, - oldHeader: this.active, - newContent: clickedIsActive && options.collapsible ? $([]) : toShow, - oldContent: toHide - }, - down = this.headers.index( this.active[0] ) > this.headers.index( clicked[0] ); + _percentage: function() { + return 100 * this._value() / this.options.max; + }, - // when the call to ._toggle() comes after the class changes - // it causes a very odd bug in IE 8 (see #6720) - this.active = clickedIsActive ? $([]) : clicked; - this._toggle( toShow, toHide, data, clickedIsActive, down ); + _refreshValue: function() { + var value = this.value(), + percentage = this._percentage(); - // switch classes - active - .removeClass( "ui-state-active ui-corner-top" ) - .addClass( "ui-state-default ui-corner-all" ) - .children( ".ui-icon" ) - .removeClass( options.icons.headerSelected ) - .addClass( options.icons.header ); - if ( !clickedIsActive ) { - clicked - .removeClass( "ui-state-default ui-corner-all" ) - .addClass( "ui-state-active ui-corner-top" ) - .children( ".ui-icon" ) - .removeClass( options.icons.header ) - .addClass( options.icons.headerSelected ); - clicked - .next() - .addClass( "ui-accordion-content-active" ); + if ( this.oldValue !== value ) { + this.oldValue = value; + this._trigger( "change" ); } - return; - }, - - _toggle: function( toShow, toHide, data, clickedIsActive, down ) { - var self = this, - options = self.options; + this.valueDiv + .toggle( value > this.min ) + .toggleClass( "ui-corner-right", value === this.options.max ) + .width( percentage.toFixed(0) + "%" ); + this.element.attr( "aria-valuenow", value ); + } +}); - self.toShow = toShow; - self.toHide = toHide; - self.data = data; +})( jQuery ); +(function( $, undefined ) { - var complete = function() { - if ( !self ) { - return; - } - return self._completed.apply( self, arguments ); - }; +$.widget("ui.resizable", $.ui.mouse, { + version: "1.9.2", + widgetEventPrefix: "resize", + options: { + alsoResize: false, + animate: false, + animateDuration: "slow", + animateEasing: "swing", + aspectRatio: false, + autoHide: false, + containment: false, + ghost: false, + grid: false, + handles: "e,s,se", + helper: false, + maxHeight: null, + maxWidth: null, + minHeight: 10, + minWidth: 10, + zIndex: 1000 + }, + _create: function() { - // trigger changestart event - self._trigger( "changestart", null, self.data ); + var that = this, o = this.options; + this.element.addClass("ui-resizable"); - // count elements to animate - self.running = toHide.size() === 0 ? toShow.size() : toHide.size(); + $.extend(this, { + _aspectRatio: !!(o.aspectRatio), + aspectRatio: o.aspectRatio, + originalElement: this.element, + _proportionallyResizeElements: [], + _helper: o.helper || o.ghost || o.animate ? o.helper || 'ui-resizable-helper' : null + }); - if ( options.animated ) { - var animOptions = {}; + //Wrap the element if it cannot hold child nodes + if(this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)) { - if ( options.collapsible && clickedIsActive ) { - animOptions = { - toShow: $( [] ), - toHide: toHide, - complete: complete, - down: down, - autoHeight: options.autoHeight || options.fillSpace - }; - } else { - animOptions = { - toShow: toShow, - toHide: toHide, - complete: complete, - down: down, - autoHeight: options.autoHeight || options.fillSpace - }; - } + //Create a wrapper element and set the wrapper to the new current internal element + this.element.wrap( + $('
      ').css({ + position: this.element.css('position'), + width: this.element.outerWidth(), + height: this.element.outerHeight(), + top: this.element.css('top'), + left: this.element.css('left') + }) + ); - if ( !options.proxied ) { - options.proxied = options.animated; - } + //Overwrite the original this.element + this.element = this.element.parent().data( + "resizable", this.element.data('resizable') + ); - if ( !options.proxiedDuration ) { - options.proxiedDuration = options.duration; - } + this.elementIsWrapper = true; - options.animated = $.isFunction( options.proxied ) ? - options.proxied( animOptions ) : - options.proxied; + //Move margins to the wrapper + this.element.css({ marginLeft: this.originalElement.css("marginLeft"), marginTop: this.originalElement.css("marginTop"), marginRight: this.originalElement.css("marginRight"), marginBottom: this.originalElement.css("marginBottom") }); + this.originalElement.css({ marginLeft: 0, marginTop: 0, marginRight: 0, marginBottom: 0}); - options.duration = $.isFunction( options.proxiedDuration ) ? - options.proxiedDuration( animOptions ) : - options.proxiedDuration; + //Prevent Safari textarea resize + this.originalResizeStyle = this.originalElement.css('resize'); + this.originalElement.css('resize', 'none'); - var animations = $.ui.accordion.animations, - duration = options.duration, - easing = options.animated; + //Push the actual element to our proportionallyResize internal array + this._proportionallyResizeElements.push(this.originalElement.css({ position: 'static', zoom: 1, display: 'block' })); - if ( easing && !animations[ easing ] && !$.easing[ easing ] ) { - easing = "slide"; - } - if ( !animations[ easing ] ) { - animations[ easing ] = function( options ) { - this.slide( options, { - easing: easing, - duration: duration || 700 - }); - }; - } + // avoid IE jump (hard set the margin) + this.originalElement.css({ margin: this.originalElement.css('margin') }); - animations[ easing ]( animOptions ); - } else { - if ( options.collapsible && clickedIsActive ) { - toShow.toggle(); - } else { - toHide.hide(); - toShow.show(); - } + // fix handlers offset + this._proportionallyResize(); - complete( true ); } - // TODO assert that the blur and focus triggers are really necessary, remove otherwise - toHide.prev() - .attr({ - "aria-expanded": "false", - "aria-selected": "false", - tabIndex: -1 - }) - .blur(); - toShow.prev() - .attr({ - "aria-expanded": "true", - "aria-selected": "true", - tabIndex: 0 - }) - .focus(); - }, + this.handles = o.handles || (!$('.ui-resizable-handle', this.element).length ? "e,s,se" : { n: '.ui-resizable-n', e: '.ui-resizable-e', s: '.ui-resizable-s', w: '.ui-resizable-w', se: '.ui-resizable-se', sw: '.ui-resizable-sw', ne: '.ui-resizable-ne', nw: '.ui-resizable-nw' }); + if(this.handles.constructor == String) { - _completed: function( cancel ) { - this.running = cancel ? 0 : --this.running; - if ( this.running ) { - return; - } + if(this.handles == 'all') this.handles = 'n,e,s,w,se,sw,ne,nw'; + var n = this.handles.split(","); this.handles = {}; - if ( this.options.clearStyle ) { - this.toShow.add( this.toHide ).css({ - height: "", - overflow: "" - }); - } + for(var i = 0; i < n.length; i++) { - // other classes are removed before the animation; this one needs to stay until completed - this.toHide.removeClass( "ui-accordion-content-active" ); - // Work around for rendering bug in IE (#5421) - if ( this.toHide.length ) { - this.toHide.parent()[0].className = this.toHide.parent()[0].className; - } + var handle = $.trim(n[i]), hname = 'ui-resizable-'+handle; + var axis = $('
      '); - this._trigger( "change", null, this.data ); - } -}); + // Apply zIndex to all handles - see #7960 + axis.css({ zIndex: o.zIndex }); -$.extend( $.ui.accordion, { - version: "1.8.16", - animations: { - slide: function( options, additions ) { - options = $.extend({ - easing: "swing", - duration: 300 - }, options, additions ); - if ( !options.toHide.size() ) { - options.toShow.animate({ - height: "show", - paddingTop: "show", - paddingBottom: "show" - }, options ); - return; - } - if ( !options.toShow.size() ) { - options.toHide.animate({ - height: "hide", - paddingTop: "hide", - paddingBottom: "hide" - }, options ); - return; - } - var overflow = options.toShow.css( "overflow" ), - percentDone = 0, - showProps = {}, - hideProps = {}, - fxAttrs = [ "height", "paddingTop", "paddingBottom" ], - originalWidth; - // fix width before calculating height of hidden element - var s = options.toShow; - originalWidth = s[0].style.width; - s.width( parseInt( s.parent().width(), 10 ) - - parseInt( s.css( "paddingLeft" ), 10 ) - - parseInt( s.css( "paddingRight" ), 10 ) - - ( parseInt( s.css( "borderLeftWidth" ), 10 ) || 0 ) - - ( parseInt( s.css( "borderRightWidth" ), 10) || 0 ) ); - - $.each( fxAttrs, function( i, prop ) { - hideProps[ prop ] = "hide"; - - var parts = ( "" + $.css( options.toShow[0], prop ) ).match( /^([\d+-.]+)(.*)$/ ); - showProps[ prop ] = { - value: parts[ 1 ], - unit: parts[ 2 ] || "px" + //TODO : What's going on here? + if ('se' == handle) { + axis.addClass('ui-icon ui-icon-gripsmall-diagonal-se'); }; - }); - options.toShow.css({ height: 0, overflow: "hidden" }).show(); - options.toHide - .filter( ":hidden" ) - .each( options.complete ) - .end() - .filter( ":visible" ) - .animate( hideProps, { - step: function( now, settings ) { - // only calculate the percent when animating height - // IE gets very inconsistent results when animating elements - // with small values, which is common for padding - if ( settings.prop == "height" ) { - percentDone = ( settings.end - settings.start === 0 ) ? 0 : - ( settings.now - settings.start ) / ( settings.end - settings.start ); - } - - options.toShow[ 0 ].style[ settings.prop ] = - ( percentDone * showProps[ settings.prop ].value ) - + showProps[ settings.prop ].unit; - }, - duration: options.duration, - easing: options.easing, - complete: function() { - if ( !options.autoHeight ) { - options.toShow.css( "height", "" ); - } - options.toShow.css({ - width: originalWidth, - overflow: overflow - }); - options.complete(); - } - }); - }, - bounceslide: function( options ) { - this.slide( options, { - easing: options.down ? "easeOutBounce" : "swing", - duration: options.down ? 1000 : 200 - }); - } - } -}); -})( jQuery ); -/* - * jQuery UI Autocomplete 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Autocomplete - * - * Depends: - * jquery.ui.core.js - * jquery.ui.widget.js - * jquery.ui.position.js - */ -(function( $, undefined ) { + //Insert into internal handles object and append to element + this.handles[handle] = '.ui-resizable-'+handle; + this.element.append(axis); + } -// used to prevent race conditions with remote data sources -var requestIndex = 0; + } -$.widget( "ui.autocomplete", { - options: { - appendTo: "body", - autoFocus: false, - delay: 300, - minLength: 1, - position: { - my: "left top", - at: "left bottom", - collision: "none" - }, - source: null - }, + this._renderAxis = function(target) { - pending: 0, + target = target || this.element; - _create: function() { - var self = this, - doc = this.element[ 0 ].ownerDocument, - suppressKeyPress; + for(var i in this.handles) { - this.element - .addClass( "ui-autocomplete-input" ) - .attr( "autocomplete", "off" ) - // TODO verify these actually work as intended - .attr({ - role: "textbox", - "aria-autocomplete": "list", - "aria-haspopup": "true" - }) - .bind( "keydown.autocomplete", function( event ) { - if ( self.options.disabled || self.element.propAttr( "readOnly" ) ) { - return; - } + if(this.handles[i].constructor == String) + this.handles[i] = $(this.handles[i], this.element).show(); - suppressKeyPress = false; - var keyCode = $.ui.keyCode; - switch( event.keyCode ) { - case keyCode.PAGE_UP: - self._move( "previousPage", event ); - break; - case keyCode.PAGE_DOWN: - self._move( "nextPage", event ); - break; - case keyCode.UP: - self._move( "previous", event ); - // prevent moving cursor to beginning of text field in some browsers - event.preventDefault(); - break; - case keyCode.DOWN: - self._move( "next", event ); - // prevent moving cursor to end of text field in some browsers - event.preventDefault(); - break; - case keyCode.ENTER: - case keyCode.NUMPAD_ENTER: - // when menu is open and has focus - if ( self.menu.active ) { - // #6055 - Opera still allows the keypress to occur - // which causes forms to submit - suppressKeyPress = true; - event.preventDefault(); - } - //passthrough - ENTER and TAB both select the current element - case keyCode.TAB: - if ( !self.menu.active ) { - return; - } - self.menu.select( event ); - break; - case keyCode.ESCAPE: - self.element.val( self.term ); - self.close( event ); - break; - default: - // keypress is triggered before the input value is changed - clearTimeout( self.searching ); - self.searching = setTimeout(function() { - // only search if the value has changed - if ( self.term != self.element.val() ) { - self.selectedItem = null; - self.search( null, event ); - } - }, self.options.delay ); - break; - } - }) - .bind( "keypress.autocomplete", function( event ) { - if ( suppressKeyPress ) { - suppressKeyPress = false; - event.preventDefault(); - } - }) - .bind( "focus.autocomplete", function() { - if ( self.options.disabled ) { - return; - } + //Apply pad to wrapper element, needed to fix axis position (textarea, inputs, scrolls) + if (this.elementIsWrapper && this.originalElement[0].nodeName.match(/textarea|input|select|button/i)) { + + var axis = $(this.handles[i], this.element), padWrapper = 0; + + //Checking the correct pad and border + padWrapper = /sw|ne|nw|se|n|s/.test(i) ? axis.outerHeight() : axis.outerWidth(); + + //The padding type i have to apply... + var padPos = [ 'padding', + /ne|nw|n/.test(i) ? 'Top' : + /se|sw|s/.test(i) ? 'Bottom' : + /^e$/.test(i) ? 'Right' : 'Left' ].join(""); + + target.css(padPos, padWrapper); + + this._proportionallyResize(); - self.selectedItem = null; - self.previous = self.element.val(); - }) - .bind( "blur.autocomplete", function( event ) { - if ( self.options.disabled ) { - return; } - clearTimeout( self.searching ); - // clicks on the menu (or a button to trigger a search) will cause a blur event - self.closing = setTimeout(function() { - self.close( event ); - self._change( event ); - }, 150 ); - }); - this._initSource(); - this.response = function() { - return self._response.apply( self, arguments ); + //TODO: What's that good for? There's not anything to be executed left + if(!$(this.handles[i]).length) + continue; + + } }; - this.menu = $( "
        " ) - .addClass( "ui-autocomplete" ) - .appendTo( $( this.options.appendTo || "body", doc )[0] ) - // prevent the close-on-blur in case of a "slow" click on the menu (long mousedown) - .mousedown(function( event ) { - // clicking on the scrollbar causes focus to shift to the body - // but we can't detect a mouseup or a click immediately afterward - // so we have to track the next mousedown and close the menu if - // the user clicks somewhere outside of the autocomplete - var menuElement = self.menu.element[ 0 ]; - if ( !$( event.target ).closest( ".ui-menu-item" ).length ) { - setTimeout(function() { - $( document ).one( 'mousedown', function( event ) { - if ( event.target !== self.element[ 0 ] && - event.target !== menuElement && - !$.ui.contains( menuElement, event.target ) ) { - self.close(); - } - }); - }, 1 ); - } - // use another timeout to make sure the blur-event-handler on the input was already triggered - setTimeout(function() { - clearTimeout( self.closing ); - }, 13); - }) - .menu({ - focus: function( event, ui ) { - var item = ui.item.data( "item.autocomplete" ); - if ( false !== self._trigger( "focus", event, { item: item } ) ) { - // use value to match what will end up in the input, if it was a key event - if ( /^key/.test(event.originalEvent.type) ) { - self.element.val( item.value ); - } - } - }, - selected: function( event, ui ) { - var item = ui.item.data( "item.autocomplete" ), - previous = self.previous; - - // only trigger when focus was lost (click on menu) - if ( self.element[0] !== doc.activeElement ) { - self.element.focus(); - self.previous = previous; - // #6109 - IE triggers two focus events and the second - // is asynchronous, so we need to reset the previous - // term synchronously and asynchronously :-( - setTimeout(function() { - self.previous = previous; - self.selectedItem = item; - }, 1); - } + //TODO: make renderAxis a prototype function + this._renderAxis(this.element); - if ( false !== self._trigger( "select", event, { item: item } ) ) { - self.element.val( item.value ); - } - // reset the term after the select event - // this allows custom select handling to work properly - self.term = self.element.val(); + this._handles = $('.ui-resizable-handle', this.element) + .disableSelection(); - self.close( event ); - self.selectedItem = item; - }, - blur: function( event, ui ) { - // don't set the value of the text field if it's already correct - // this prevents moving the cursor unnecessarily - if ( self.menu.element.is(":visible") && - ( self.element.val() !== self.term ) ) { - self.element.val( self.term ); + //Matching axis name + this._handles.mouseover(function() { + if (!that.resizing) { + if (this.className) + var axis = this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i); + //Axis, default = se + that.axis = axis && axis[1] ? axis[1] : 'se'; + } + }); + + //If we want to auto hide the elements + if (o.autoHide) { + this._handles.hide(); + $(this.element) + .addClass("ui-resizable-autohide") + .mouseenter(function() { + if (o.disabled) return; + $(this).removeClass("ui-resizable-autohide"); + that._handles.show(); + }) + .mouseleave(function(){ + if (o.disabled) return; + if (!that.resizing) { + $(this).addClass("ui-resizable-autohide"); + that._handles.hide(); } - } - }) - .zIndex( this.element.zIndex() + 1 ) - // workaround for jQuery bug #5781 http://dev.jquery.com/ticket/5781 - .css({ top: 0, left: 0 }) - .hide() - .data( "menu" ); - if ( $.fn.bgiframe ) { - this.menu.element.bgiframe(); + }); } - }, - destroy: function() { - this.element - .removeClass( "ui-autocomplete-input" ) - .removeAttr( "autocomplete" ) - .removeAttr( "role" ) - .removeAttr( "aria-autocomplete" ) - .removeAttr( "aria-haspopup" ); - this.menu.element.remove(); - $.Widget.prototype.destroy.call( this ); + //Initialize the mouse interaction + this._mouseInit(); + }, - _setOption: function( key, value ) { - $.Widget.prototype._setOption.apply( this, arguments ); - if ( key === "source" ) { - this._initSource(); - } - if ( key === "appendTo" ) { - this.menu.element.appendTo( $( value || "body", this.element[0].ownerDocument )[0] ) - } - if ( key === "disabled" && value && this.xhr ) { - this.xhr.abort(); + _destroy: function() { + + this._mouseDestroy(); + + var _destroy = function(exp) { + $(exp).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing") + .removeData("resizable").removeData("ui-resizable").unbind(".resizable").find('.ui-resizable-handle').remove(); + }; + + //TODO: Unwrap at same DOM position + if (this.elementIsWrapper) { + _destroy(this.element); + var wrapper = this.element; + this.originalElement.css({ + position: wrapper.css('position'), + width: wrapper.outerWidth(), + height: wrapper.outerHeight(), + top: wrapper.css('top'), + left: wrapper.css('left') + }).insertAfter( wrapper ); + wrapper.remove(); } + + this.originalElement.css('resize', this.originalResizeStyle); + _destroy(this.originalElement); + + return this; }, - _initSource: function() { - var self = this, - array, - url; - if ( $.isArray(this.options.source) ) { - array = this.options.source; - this.source = function( request, response ) { - response( $.ui.autocomplete.filter(array, request.term) ); - }; - } else if ( typeof this.options.source === "string" ) { - url = this.options.source; - this.source = function( request, response ) { - if ( self.xhr ) { - self.xhr.abort(); - } - self.xhr = $.ajax({ - url: url, - data: request, - dataType: "json", - autocompleteRequest: ++requestIndex, - success: function( data, status ) { - if ( this.autocompleteRequest === requestIndex ) { - response( data ); - } - }, - error: function() { - if ( this.autocompleteRequest === requestIndex ) { - response( [] ); - } - } - }); - }; - } else { - this.source = this.options.source; + _mouseCapture: function(event) { + var handle = false; + for (var i in this.handles) { + if ($(this.handles[i])[0] == event.target) { + handle = true; + } } + + return !this.options.disabled && handle; }, - search: function( value, event ) { - value = value != null ? value : this.element.val(); + _mouseStart: function(event) { - // always save the actual value, not the one passed as an argument - this.term = this.element.val(); + var o = this.options, iniPos = this.element.position(), el = this.element; - if ( value.length < this.options.minLength ) { - return this.close( event ); + this.resizing = true; + this.documentScroll = { top: $(document).scrollTop(), left: $(document).scrollLeft() }; + + // bugfix for http://dev.jquery.com/ticket/1749 + if (el.is('.ui-draggable') || (/absolute/).test(el.css('position'))) { + el.css({ position: 'absolute', top: iniPos.top, left: iniPos.left }); } - clearTimeout( this.closing ); - if ( this._trigger( "search", event ) === false ) { - return; + this._renderProxy(); + + var curleft = num(this.helper.css('left')), curtop = num(this.helper.css('top')); + + if (o.containment) { + curleft += $(o.containment).scrollLeft() || 0; + curtop += $(o.containment).scrollTop() || 0; } - return this._search( value ); - }, + //Store needed variables + this.offset = this.helper.offset(); + this.position = { left: curleft, top: curtop }; + this.size = this._helper ? { width: el.outerWidth(), height: el.outerHeight() } : { width: el.width(), height: el.height() }; + this.originalSize = this._helper ? { width: el.outerWidth(), height: el.outerHeight() } : { width: el.width(), height: el.height() }; + this.originalPosition = { left: curleft, top: curtop }; + this.sizeDiff = { width: el.outerWidth() - el.width(), height: el.outerHeight() - el.height() }; + this.originalMousePosition = { left: event.pageX, top: event.pageY }; - _search: function( value ) { - this.pending++; - this.element.addClass( "ui-autocomplete-loading" ); + //Aspect Ratio + this.aspectRatio = (typeof o.aspectRatio == 'number') ? o.aspectRatio : ((this.originalSize.width / this.originalSize.height) || 1); - this.source( { term: value }, this.response ); - }, + var cursor = $('.ui-resizable-' + this.axis).css('cursor'); + $('body').css('cursor', cursor == 'auto' ? this.axis + '-resize' : cursor); - _response: function( content ) { - if ( !this.options.disabled && content && content.length ) { - content = this._normalize( content ); - this._suggest( content ); - this._trigger( "open" ); - } else { - this.close(); - } - this.pending--; - if ( !this.pending ) { - this.element.removeClass( "ui-autocomplete-loading" ); - } + el.addClass("ui-resizable-resizing"); + this._propagate("start", event); + return true; }, - close: function( event ) { - clearTimeout( this.closing ); - if ( this.menu.element.is(":visible") ) { - this.menu.element.hide(); - this.menu.deactivate(); - this._trigger( "close", event ); - } - }, - - _change: function( event ) { - if ( this.previous !== this.element.val() ) { - this._trigger( "change", event, { item: this.selectedItem } ); - } + _mouseDrag: function(event) { + + //Increase performance, avoid regex + var el = this.helper, o = this.options, props = {}, + that = this, smp = this.originalMousePosition, a = this.axis; + + var dx = (event.pageX-smp.left)||0, dy = (event.pageY-smp.top)||0; + var trigger = this._change[a]; + if (!trigger) return false; + + // Calculate the attrs that will be change + var data = trigger.apply(this, [event, dx, dy]); + + // Put this in the mouseDrag handler since the user can start pressing shift while resizing + this._updateVirtualBoundaries(event.shiftKey); + if (this._aspectRatio || event.shiftKey) + data = this._updateRatio(data, event); + + data = this._respectSize(data, event); + + // plugins callbacks need to be called first + this._propagate("resize", event); + + el.css({ + top: this.position.top + "px", left: this.position.left + "px", + width: this.size.width + "px", height: this.size.height + "px" + }); + + if (!this._helper && this._proportionallyResizeElements.length) + this._proportionallyResize(); + + this._updateCache(data); + + // calling the user callback at the end + this._trigger('resize', event, this.ui()); + + return false; }, - _normalize: function( items ) { - // assume all items have the right format when the first item is complete - if ( items.length && items[0].label && items[0].value ) { - return items; + _mouseStop: function(event) { + + this.resizing = false; + var o = this.options, that = this; + + if(this._helper) { + var pr = this._proportionallyResizeElements, ista = pr.length && (/textarea/i).test(pr[0].nodeName), + soffseth = ista && $.ui.hasScroll(pr[0], 'left') /* TODO - jump height */ ? 0 : that.sizeDiff.height, + soffsetw = ista ? 0 : that.sizeDiff.width; + + var s = { width: (that.helper.width() - soffsetw), height: (that.helper.height() - soffseth) }, + left = (parseInt(that.element.css('left'), 10) + (that.position.left - that.originalPosition.left)) || null, + top = (parseInt(that.element.css('top'), 10) + (that.position.top - that.originalPosition.top)) || null; + + if (!o.animate) + this.element.css($.extend(s, { top: top, left: left })); + + that.helper.height(that.size.height); + that.helper.width(that.size.width); + + if (this._helper && !o.animate) this._proportionallyResize(); } - return $.map( items, function(item) { - if ( typeof item === "string" ) { - return { - label: item, - value: item - }; - } - return $.extend({ - label: item.label || item.value, - value: item.value || item.label - }, item ); - }); + + $('body').css('cursor', 'auto'); + + this.element.removeClass("ui-resizable-resizing"); + + this._propagate("stop", event); + + if (this._helper) this.helper.remove(); + return false; + }, - _suggest: function( items ) { - var ul = this.menu.element - .empty() - .zIndex( this.element.zIndex() + 1 ); - this._renderMenu( ul, items ); - // TODO refresh should check if the active item is still in the dom, removing the need for a manual deactivate - this.menu.deactivate(); - this.menu.refresh(); + _updateVirtualBoundaries: function(forceAspectRatio) { + var o = this.options, pMinWidth, pMaxWidth, pMinHeight, pMaxHeight, b; - // size and position menu - ul.show(); - this._resizeMenu(); - ul.position( $.extend({ - of: this.element - }, this.options.position )); + b = { + minWidth: isNumber(o.minWidth) ? o.minWidth : 0, + maxWidth: isNumber(o.maxWidth) ? o.maxWidth : Infinity, + minHeight: isNumber(o.minHeight) ? o.minHeight : 0, + maxHeight: isNumber(o.maxHeight) ? o.maxHeight : Infinity + }; - if ( this.options.autoFocus ) { - this.menu.next( new $.Event("mouseover") ); + if(this._aspectRatio || forceAspectRatio) { + // We want to create an enclosing box whose aspect ration is the requested one + // First, compute the "projected" size for each dimension based on the aspect ratio and other dimension + pMinWidth = b.minHeight * this.aspectRatio; + pMinHeight = b.minWidth / this.aspectRatio; + pMaxWidth = b.maxHeight * this.aspectRatio; + pMaxHeight = b.maxWidth / this.aspectRatio; + + if(pMinWidth > b.minWidth) b.minWidth = pMinWidth; + if(pMinHeight > b.minHeight) b.minHeight = pMinHeight; + if(pMaxWidth < b.maxWidth) b.maxWidth = pMaxWidth; + if(pMaxHeight < b.maxHeight) b.maxHeight = pMaxHeight; } + this._vBoundaries = b; }, - _resizeMenu: function() { - var ul = this.menu.element; - ul.outerWidth( Math.max( - ul.width( "" ).outerWidth(), - this.element.outerWidth() - ) ); + _updateCache: function(data) { + var o = this.options; + this.offset = this.helper.offset(); + if (isNumber(data.left)) this.position.left = data.left; + if (isNumber(data.top)) this.position.top = data.top; + if (isNumber(data.height)) this.size.height = data.height; + if (isNumber(data.width)) this.size.width = data.width; }, - _renderMenu: function( ul, items ) { - var self = this; - $.each( items, function( index, item ) { - self._renderItem( ul, item ); - }); - }, + _updateRatio: function(data, event) { - _renderItem: function( ul, item) { - return $( "
      • " ) - .data( "item.autocomplete", item ) - .append( $( "" ).text( item.label ) ) - .appendTo( ul ); - }, + var o = this.options, cpos = this.position, csize = this.size, a = this.axis; - _move: function( direction, event ) { - if ( !this.menu.element.is(":visible") ) { - this.search( null, event ); - return; + if (isNumber(data.height)) data.width = (data.height * this.aspectRatio); + else if (isNumber(data.width)) data.height = (data.width / this.aspectRatio); + + if (a == 'sw') { + data.left = cpos.left + (csize.width - data.width); + data.top = null; } - if ( this.menu.first() && /^previous/.test(direction) || - this.menu.last() && /^next/.test(direction) ) { - this.element.val( this.term ); - this.menu.deactivate(); - return; + if (a == 'nw') { + data.top = cpos.top + (csize.height - data.height); + data.left = cpos.left + (csize.width - data.width); } - this.menu[ direction ]( event ); - }, - - widget: function() { - return this.menu.element; - } -}); -$.extend( $.ui.autocomplete, { - escapeRegex: function( value ) { - return value.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"); + return data; }, - filter: function(array, term) { - var matcher = new RegExp( $.ui.autocomplete.escapeRegex(term), "i" ); - return $.grep( array, function(value) { - return matcher.test( value.label || value.value || value ); - }); - } -}); -}( jQuery )); + _respectSize: function(data, event) { -/* - * jQuery UI Menu (not officially released) - * - * This widget isn't yet finished and the API is subject to change. We plan to finish - * it for the next release. You're welcome to give it a try anyway and give us feedback, - * as long as you're okay with migrating your code later on. We can help with that, too. - * - * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Menu - * - * Depends: - * jquery.ui.core.js - * jquery.ui.widget.js - */ -(function($) { + var el = this.helper, o = this._vBoundaries, pRatio = this._aspectRatio || event.shiftKey, a = this.axis, + ismaxw = isNumber(data.width) && o.maxWidth && (o.maxWidth < data.width), ismaxh = isNumber(data.height) && o.maxHeight && (o.maxHeight < data.height), + isminw = isNumber(data.width) && o.minWidth && (o.minWidth > data.width), isminh = isNumber(data.height) && o.minHeight && (o.minHeight > data.height); -$.widget("ui.menu", { - _create: function() { - var self = this; - this.element - .addClass("ui-menu ui-widget ui-widget-content ui-corner-all") - .attr({ - role: "listbox", - "aria-activedescendant": "ui-active-menuitem" - }) - .click(function( event ) { - if ( !$( event.target ).closest( ".ui-menu-item a" ).length ) { - return; - } - // temporary - event.preventDefault(); - self.select( event ); - }); - this.refresh(); - }, - - refresh: function() { - var self = this; - - // don't refresh list items that are already adapted - var items = this.element.children("li:not(.ui-menu-item):has(a)") - .addClass("ui-menu-item") - .attr("role", "menuitem"); - - items.children("a") - .addClass("ui-corner-all") - .attr("tabindex", -1) - // mouseenter doesn't work with event delegation - .mouseenter(function( event ) { - self.activate( event, $(this).parent() ); - }) - .mouseleave(function() { - self.deactivate(); - }); - }, + if (isminw) data.width = o.minWidth; + if (isminh) data.height = o.minHeight; + if (ismaxw) data.width = o.maxWidth; + if (ismaxh) data.height = o.maxHeight; - activate: function( event, item ) { - this.deactivate(); - if (this.hasScroll()) { - var offset = item.offset().top - this.element.offset().top, - scroll = this.element.scrollTop(), - elementHeight = this.element.height(); - if (offset < 0) { - this.element.scrollTop( scroll + offset); - } else if (offset >= elementHeight) { - this.element.scrollTop( scroll + offset - elementHeight + item.height()); - } - } - this.active = item.eq(0) - .children("a") - .addClass("ui-state-hover") - .attr("id", "ui-active-menuitem") - .end(); - this._trigger("focus", event, { item: item }); - }, + var dw = this.originalPosition.left + this.originalSize.width, dh = this.position.top + this.size.height; + var cw = /sw|nw|w/.test(a), ch = /nw|ne|n/.test(a); - deactivate: function() { - if (!this.active) { return; } + if (isminw && cw) data.left = dw - o.minWidth; + if (ismaxw && cw) data.left = dw - o.maxWidth; + if (isminh && ch) data.top = dh - o.minHeight; + if (ismaxh && ch) data.top = dh - o.maxHeight; - this.active.children("a") - .removeClass("ui-state-hover") - .removeAttr("id"); - this._trigger("blur"); - this.active = null; - }, + // fixing jump error on top/left - bug #2330 + var isNotwh = !data.width && !data.height; + if (isNotwh && !data.left && data.top) data.top = null; + else if (isNotwh && !data.top && data.left) data.left = null; - next: function(event) { - this.move("next", ".ui-menu-item:first", event); + return data; }, - previous: function(event) { - this.move("prev", ".ui-menu-item:last", event); - }, + _proportionallyResize: function() { - first: function() { - return this.active && !this.active.prevAll(".ui-menu-item").length; - }, + var o = this.options; + if (!this._proportionallyResizeElements.length) return; + var element = this.helper || this.element; - last: function() { - return this.active && !this.active.nextAll(".ui-menu-item").length; - }, + for (var i=0; i < this._proportionallyResizeElements.length; i++) { - move: function(direction, edge, event) { - if (!this.active) { - this.activate(event, this.element.children(edge)); - return; - } - var next = this.active[direction + "All"](".ui-menu-item").eq(0); - if (next.length) { - this.activate(event, next); - } else { - this.activate(event, this.element.children(edge)); - } - }, + var prel = this._proportionallyResizeElements[i]; - // TODO merge with previousPage - nextPage: function(event) { - if (this.hasScroll()) { - // TODO merge with no-scroll-else - if (!this.active || this.last()) { - this.activate(event, this.element.children(".ui-menu-item:first")); - return; - } - var base = this.active.offset().top, - height = this.element.height(), - result = this.element.children(".ui-menu-item").filter(function() { - var close = $(this).offset().top - base - height + $(this).height(); - // TODO improve approximation - return close < 10 && close > -10; - }); + if (!this.borderDif) { + var b = [prel.css('borderTopWidth'), prel.css('borderRightWidth'), prel.css('borderBottomWidth'), prel.css('borderLeftWidth')], + p = [prel.css('paddingTop'), prel.css('paddingRight'), prel.css('paddingBottom'), prel.css('paddingLeft')]; - // TODO try to catch this earlier when scrollTop indicates the last page anyway - if (!result.length) { - result = this.element.children(".ui-menu-item:last"); + this.borderDif = $.map(b, function(v, i) { + var border = parseInt(v,10)||0, padding = parseInt(p[i],10)||0; + return border + padding; + }); } - this.activate(event, result); - } else { - this.activate(event, this.element.children(".ui-menu-item") - .filter(!this.active || this.last() ? ":first" : ":last")); - } - }, - // TODO merge with nextPage - previousPage: function(event) { - if (this.hasScroll()) { - // TODO merge with no-scroll-else - if (!this.active || this.first()) { - this.activate(event, this.element.children(".ui-menu-item:last")); - return; - } + prel.css({ + height: (element.height() - this.borderDif[0] - this.borderDif[2]) || 0, + width: (element.width() - this.borderDif[1] - this.borderDif[3]) || 0 + }); - var base = this.active.offset().top, - height = this.element.height(); - result = this.element.children(".ui-menu-item").filter(function() { - var close = $(this).offset().top - base + height - $(this).height(); - // TODO improve approximation - return close < 10 && close > -10; - }); + }; - // TODO try to catch this earlier when scrollTop indicates the last page anyway - if (!result.length) { - result = this.element.children(".ui-menu-item:first"); - } - this.activate(event, result); - } else { - this.activate(event, this.element.children(".ui-menu-item") - .filter(!this.active || this.first() ? ":last" : ":first")); - } }, - hasScroll: function() { - return this.element.height() < this.element[ $.fn.prop ? "prop" : "attr" ]("scrollHeight"); - }, + _renderProxy: function() { - select: function( event ) { - this._trigger("selected", event, { item: this.active }); - } -}); + var el = this.element, o = this.options; + this.elementOffset = el.offset(); -}(jQuery)); -/* - * jQuery UI Button 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Button - * - * Depends: - * jquery.ui.core.js - * jquery.ui.widget.js - */ -(function( $, undefined ) { + if(this._helper) { -var lastActive, startXPos, startYPos, clickDragged, - baseClasses = "ui-button ui-widget ui-state-default ui-corner-all", - stateClasses = "ui-state-hover ui-state-active ", - typeClasses = "ui-button-icons-only ui-button-icon-only ui-button-text-icons ui-button-text-icon-primary ui-button-text-icon-secondary ui-button-text-only", - formResetHandler = function() { - var buttons = $( this ).find( ":ui-button" ); - setTimeout(function() { - buttons.button( "refresh" ); - }, 1 ); - }, - radioGroup = function( radio ) { - var name = radio.name, - form = radio.form, - radios = $( [] ); - if ( name ) { - if ( form ) { - radios = $( form ).find( "[name='" + name + "']" ); - } else { - radios = $( "[name='" + name + "']", radio.ownerDocument ) - .filter(function() { - return !this.form; - }); - } + this.helper = this.helper || $('
        '); + + // fix ie6 offset TODO: This seems broken + var ie6offset = ($.ui.ie6 ? 1 : 0), + pxyoffset = ( $.ui.ie6 ? 2 : -1 ); + + this.helper.addClass(this._helper).css({ + width: this.element.outerWidth() + pxyoffset, + height: this.element.outerHeight() + pxyoffset, + position: 'absolute', + left: this.elementOffset.left - ie6offset +'px', + top: this.elementOffset.top - ie6offset +'px', + zIndex: ++o.zIndex //TODO: Don't modify option + }); + + this.helper + .appendTo("body") + .disableSelection(); + + } else { + this.helper = this.element; } - return radios; - }; -$.widget( "ui.button", { - options: { - disabled: null, - text: true, - label: null, - icons: { - primary: null, - secondary: null + }, + + _change: { + e: function(event, dx, dy) { + return { width: this.originalSize.width + dx }; + }, + w: function(event, dx, dy) { + var o = this.options, cs = this.originalSize, sp = this.originalPosition; + return { left: sp.left + dx, width: cs.width - dx }; + }, + n: function(event, dx, dy) { + var o = this.options, cs = this.originalSize, sp = this.originalPosition; + return { top: sp.top + dy, height: cs.height - dy }; + }, + s: function(event, dx, dy) { + return { height: this.originalSize.height + dy }; + }, + se: function(event, dx, dy) { + return $.extend(this._change.s.apply(this, arguments), this._change.e.apply(this, [event, dx, dy])); + }, + sw: function(event, dx, dy) { + return $.extend(this._change.s.apply(this, arguments), this._change.w.apply(this, [event, dx, dy])); + }, + ne: function(event, dx, dy) { + return $.extend(this._change.n.apply(this, arguments), this._change.e.apply(this, [event, dx, dy])); + }, + nw: function(event, dx, dy) { + return $.extend(this._change.n.apply(this, arguments), this._change.w.apply(this, [event, dx, dy])); } }, - _create: function() { - this.element.closest( "form" ) - .unbind( "reset.button" ) - .bind( "reset.button", formResetHandler ); - if ( typeof this.options.disabled !== "boolean" ) { - this.options.disabled = this.element.propAttr( "disabled" ); - } + _propagate: function(n, event) { + $.ui.plugin.call(this, n, [event, this.ui()]); + (n != "resize" && this._trigger(n, event, this.ui())); + }, - this._determineButtonType(); - this.hasTitle = !!this.buttonElement.attr( "title" ); + plugins: {}, - var self = this, - options = this.options, - toggleButton = this.type === "checkbox" || this.type === "radio", - hoverClass = "ui-state-hover" + ( !toggleButton ? " ui-state-active" : "" ), - focusClass = "ui-state-focus"; + ui: function() { + return { + originalElement: this.originalElement, + element: this.element, + helper: this.helper, + position: this.position, + size: this.size, + originalSize: this.originalSize, + originalPosition: this.originalPosition + }; + } - if ( options.label === null ) { - options.label = this.buttonElement.html(); - } +}); - if ( this.element.is( ":disabled" ) ) { - options.disabled = true; - } +/* + * Resizable Extensions + */ - this.buttonElement - .addClass( baseClasses ) - .attr( "role", "button" ) - .bind( "mouseenter.button", function() { - if ( options.disabled ) { - return; - } - $( this ).addClass( "ui-state-hover" ); - if ( this === lastActive ) { - $( this ).addClass( "ui-state-active" ); - } - }) - .bind( "mouseleave.button", function() { - if ( options.disabled ) { - return; - } - $( this ).removeClass( hoverClass ); - }) - .bind( "click.button", function( event ) { - if ( options.disabled ) { - event.preventDefault(); - event.stopImmediatePropagation(); - } - }); +$.ui.plugin.add("resizable", "alsoResize", { - this.element - .bind( "focus.button", function() { - // no need to check disabled, focus won't be triggered anyway - self.buttonElement.addClass( focusClass ); - }) - .bind( "blur.button", function() { - self.buttonElement.removeClass( focusClass ); - }); + start: function (event, ui) { + var that = $(this).data("resizable"), o = that.options; - if ( toggleButton ) { - this.element.bind( "change.button", function() { - if ( clickDragged ) { - return; - } - self.refresh(); - }); - // if mouse moves between mousedown and mouseup (drag) set clickDragged flag - // prevents issue where button state changes but checkbox/radio checked state - // does not in Firefox (see ticket #6970) - this.buttonElement - .bind( "mousedown.button", function( event ) { - if ( options.disabled ) { - return; - } - clickDragged = false; - startXPos = event.pageX; - startYPos = event.pageY; - }) - .bind( "mouseup.button", function( event ) { - if ( options.disabled ) { - return; - } - if ( startXPos !== event.pageX || startYPos !== event.pageY ) { - clickDragged = true; - } + var _store = function (exp) { + $(exp).each(function() { + var el = $(this); + el.data("resizable-alsoresize", { + width: parseInt(el.width(), 10), height: parseInt(el.height(), 10), + left: parseInt(el.css('left'), 10), top: parseInt(el.css('top'), 10) + }); }); + }; + + if (typeof(o.alsoResize) == 'object' && !o.alsoResize.parentNode) { + if (o.alsoResize.length) { o.alsoResize = o.alsoResize[0]; _store(o.alsoResize); } + else { $.each(o.alsoResize, function (exp) { _store(exp); }); } + }else{ + _store(o.alsoResize); } + }, - if ( this.type === "checkbox" ) { - this.buttonElement.bind( "click.button", function() { - if ( options.disabled || clickDragged ) { - return false; - } - $( this ).toggleClass( "ui-state-active" ); - self.buttonElement.attr( "aria-pressed", self.element[0].checked ); - }); - } else if ( this.type === "radio" ) { - this.buttonElement.bind( "click.button", function() { - if ( options.disabled || clickDragged ) { - return false; - } - $( this ).addClass( "ui-state-active" ); - self.buttonElement.attr( "aria-pressed", "true" ); + resize: function (event, ui) { + var that = $(this).data("resizable"), o = that.options, os = that.originalSize, op = that.originalPosition; - var radio = self.element[ 0 ]; - radioGroup( radio ) - .not( radio ) - .map(function() { - return $( this ).button( "widget" )[ 0 ]; - }) - .removeClass( "ui-state-active" ) - .attr( "aria-pressed", "false" ); - }); - } else { - this.buttonElement - .bind( "mousedown.button", function() { - if ( options.disabled ) { - return false; - } - $( this ).addClass( "ui-state-active" ); - lastActive = this; - $( document ).one( "mouseup", function() { - lastActive = null; - }); - }) - .bind( "mouseup.button", function() { - if ( options.disabled ) { - return false; - } - $( this ).removeClass( "ui-state-active" ); - }) - .bind( "keydown.button", function(event) { - if ( options.disabled ) { - return false; - } - if ( event.keyCode == $.ui.keyCode.SPACE || event.keyCode == $.ui.keyCode.ENTER ) { - $( this ).addClass( "ui-state-active" ); - } - }) - .bind( "keyup.button", function() { - $( this ).removeClass( "ui-state-active" ); - }); + var delta = { + height: (that.size.height - os.height) || 0, width: (that.size.width - os.width) || 0, + top: (that.position.top - op.top) || 0, left: (that.position.left - op.left) || 0 + }, - if ( this.buttonElement.is("a") ) { - this.buttonElement.keyup(function(event) { - if ( event.keyCode === $.ui.keyCode.SPACE ) { - // TODO pass through original event correctly (just as 2nd argument doesn't work) - $( this ).click(); - } + _alsoResize = function (exp, c) { + $(exp).each(function() { + var el = $(this), start = $(this).data("resizable-alsoresize"), style = {}, + css = c && c.length ? c : el.parents(ui.originalElement[0]).length ? ['width', 'height'] : ['width', 'height', 'top', 'left']; + + $.each(css, function (i, prop) { + var sum = (start[prop]||0) + (delta[prop]||0); + if (sum && sum >= 0) + style[prop] = sum || null; }); - } - } - // TODO: pull out $.Widget's handling for the disabled option into - // $.Widget.prototype._setOptionDisabled so it's easy to proxy and can - // be overridden by individual plugins - this._setOption( "disabled", options.disabled ); - this._resetButton(); + el.css(style); + }); + }; + + if (typeof(o.alsoResize) == 'object' && !o.alsoResize.nodeType) { + $.each(o.alsoResize, function (exp, c) { _alsoResize(exp, c); }); + }else{ + _alsoResize(o.alsoResize); + } }, - _determineButtonType: function() { + stop: function (event, ui) { + $(this).removeData("resizable-alsoresize"); + } +}); - if ( this.element.is(":checkbox") ) { - this.type = "checkbox"; - } else if ( this.element.is(":radio") ) { - this.type = "radio"; - } else if ( this.element.is("input") ) { - this.type = "input"; - } else { - this.type = "button"; - } +$.ui.plugin.add("resizable", "animate", { + + stop: function(event, ui) { + var that = $(this).data("resizable"), o = that.options; + + var pr = that._proportionallyResizeElements, ista = pr.length && (/textarea/i).test(pr[0].nodeName), + soffseth = ista && $.ui.hasScroll(pr[0], 'left') /* TODO - jump height */ ? 0 : that.sizeDiff.height, + soffsetw = ista ? 0 : that.sizeDiff.width; + + var style = { width: (that.size.width - soffsetw), height: (that.size.height - soffseth) }, + left = (parseInt(that.element.css('left'), 10) + (that.position.left - that.originalPosition.left)) || null, + top = (parseInt(that.element.css('top'), 10) + (that.position.top - that.originalPosition.top)) || null; + + that.element.animate( + $.extend(style, top && left ? { top: top, left: left } : {}), { + duration: o.animateDuration, + easing: o.animateEasing, + step: function() { + + var data = { + width: parseInt(that.element.css('width'), 10), + height: parseInt(that.element.css('height'), 10), + top: parseInt(that.element.css('top'), 10), + left: parseInt(that.element.css('left'), 10) + }; + + if (pr && pr.length) $(pr[0]).css({ width: data.width, height: data.height }); + + // propagating resize, and updating values for each animation step + that._updateCache(data); + that._propagate("resize", event); - if ( this.type === "checkbox" || this.type === "radio" ) { - // we don't search against the document in case the element - // is disconnected from the DOM - var ancestor = this.element.parents().filter(":last"), - labelSelector = "label[for='" + this.element.attr("id") + "']"; - this.buttonElement = ancestor.find( labelSelector ); - if ( !this.buttonElement.length ) { - ancestor = ancestor.length ? ancestor.siblings() : this.element.siblings(); - this.buttonElement = ancestor.filter( labelSelector ); - if ( !this.buttonElement.length ) { - this.buttonElement = ancestor.find( labelSelector ); } } - this.element.addClass( "ui-helper-hidden-accessible" ); + ); + } - var checked = this.element.is( ":checked" ); - if ( checked ) { - this.buttonElement.addClass( "ui-state-active" ); - } - this.buttonElement.attr( "aria-pressed", checked ); - } else { - this.buttonElement = this.element; - } - }, +}); - widget: function() { - return this.buttonElement; - }, +$.ui.plugin.add("resizable", "containment", { - destroy: function() { - this.element - .removeClass( "ui-helper-hidden-accessible" ); - this.buttonElement - .removeClass( baseClasses + " " + stateClasses + " " + typeClasses ) - .removeAttr( "role" ) - .removeAttr( "aria-pressed" ) - .html( this.buttonElement.find(".ui-button-text").html() ); + start: function(event, ui) { + var that = $(this).data("resizable"), o = that.options, el = that.element; + var oc = o.containment, ce = (oc instanceof $) ? oc.get(0) : (/parent/.test(oc)) ? el.parent().get(0) : oc; + if (!ce) return; - if ( !this.hasTitle ) { - this.buttonElement.removeAttr( "title" ); + that.containerElement = $(ce); + + if (/document/.test(oc) || oc == document) { + that.containerOffset = { left: 0, top: 0 }; + that.containerPosition = { left: 0, top: 0 }; + + that.parentData = { + element: $(document), left: 0, top: 0, + width: $(document).width(), height: $(document).height() || document.body.parentNode.scrollHeight + }; } - $.Widget.prototype.destroy.call( this ); - }, + // i'm a node, so compute top, left, right, bottom + else { + var element = $(ce), p = []; + $([ "Top", "Right", "Left", "Bottom" ]).each(function(i, name) { p[i] = num(element.css("padding" + name)); }); - _setOption: function( key, value ) { - $.Widget.prototype._setOption.apply( this, arguments ); - if ( key === "disabled" ) { - if ( value ) { - this.element.propAttr( "disabled", true ); - } else { - this.element.propAttr( "disabled", false ); - } - return; + that.containerOffset = element.offset(); + that.containerPosition = element.position(); + that.containerSize = { height: (element.innerHeight() - p[3]), width: (element.innerWidth() - p[1]) }; + + var co = that.containerOffset, ch = that.containerSize.height, cw = that.containerSize.width, + width = ($.ui.hasScroll(ce, "left") ? ce.scrollWidth : cw ), height = ($.ui.hasScroll(ce) ? ce.scrollHeight : ch); + + that.parentData = { + element: ce, left: co.left, top: co.top, width: width, height: height + }; } - this._resetButton(); }, - refresh: function() { - var isDisabled = this.element.is( ":disabled" ); - if ( isDisabled !== this.options.disabled ) { - this._setOption( "disabled", isDisabled ); - } - if ( this.type === "radio" ) { - radioGroup( this.element[0] ).each(function() { - if ( $( this ).is( ":checked" ) ) { - $( this ).button( "widget" ) - .addClass( "ui-state-active" ) - .attr( "aria-pressed", "true" ); - } else { - $( this ).button( "widget" ) - .removeClass( "ui-state-active" ) - .attr( "aria-pressed", "false" ); - } - }); - } else if ( this.type === "checkbox" ) { - if ( this.element.is( ":checked" ) ) { - this.buttonElement - .addClass( "ui-state-active" ) - .attr( "aria-pressed", "true" ); - } else { - this.buttonElement - .removeClass( "ui-state-active" ) - .attr( "aria-pressed", "false" ); - } + resize: function(event, ui) { + var that = $(this).data("resizable"), o = that.options, + ps = that.containerSize, co = that.containerOffset, cs = that.size, cp = that.position, + pRatio = that._aspectRatio || event.shiftKey, cop = { top:0, left:0 }, ce = that.containerElement; + + if (ce[0] != document && (/static/).test(ce.css('position'))) cop = co; + + if (cp.left < (that._helper ? co.left : 0)) { + that.size.width = that.size.width + (that._helper ? (that.position.left - co.left) : (that.position.left - cop.left)); + if (pRatio) that.size.height = that.size.width / that.aspectRatio; + that.position.left = o.helper ? co.left : 0; } - }, - _resetButton: function() { - if ( this.type === "input" ) { - if ( this.options.label ) { - this.element.val( this.options.label ); - } - return; + if (cp.top < (that._helper ? co.top : 0)) { + that.size.height = that.size.height + (that._helper ? (that.position.top - co.top) : that.position.top); + if (pRatio) that.size.width = that.size.height * that.aspectRatio; + that.position.top = that._helper ? co.top : 0; } - var buttonElement = this.buttonElement.removeClass( typeClasses ), - buttonText = $( "" ) - .addClass( "ui-button-text" ) - .html( this.options.label ) - .appendTo( buttonElement.empty() ) - .text(), - icons = this.options.icons, - multipleIcons = icons.primary && icons.secondary, - buttonClasses = []; - if ( icons.primary || icons.secondary ) { - if ( this.options.text ) { - buttonClasses.push( "ui-button-text-icon" + ( multipleIcons ? "s" : ( icons.primary ? "-primary" : "-secondary" ) ) ); - } + that.offset.left = that.parentData.left+that.position.left; + that.offset.top = that.parentData.top+that.position.top; - if ( icons.primary ) { - buttonElement.prepend( "" ); - } + var woset = Math.abs( (that._helper ? that.offset.left - cop.left : (that.offset.left - cop.left)) + that.sizeDiff.width ), + hoset = Math.abs( (that._helper ? that.offset.top - cop.top : (that.offset.top - co.top)) + that.sizeDiff.height ); - if ( icons.secondary ) { - buttonElement.append( "" ); - } + var isParent = that.containerElement.get(0) == that.element.parent().get(0), + isOffsetRelative = /relative|absolute/.test(that.containerElement.css('position')); - if ( !this.options.text ) { - buttonClasses.push( multipleIcons ? "ui-button-icons-only" : "ui-button-icon-only" ); + if(isParent && isOffsetRelative) woset -= that.parentData.left; - if ( !this.hasTitle ) { - buttonElement.attr( "title", buttonText ); - } - } - } else { - buttonClasses.push( "ui-button-text-only" ); + if (woset + that.size.width >= that.parentData.width) { + that.size.width = that.parentData.width - woset; + if (pRatio) that.size.height = that.size.width / that.aspectRatio; } - buttonElement.addClass( buttonClasses.join( " " ) ); + + if (hoset + that.size.height >= that.parentData.height) { + that.size.height = that.parentData.height - hoset; + if (pRatio) that.size.width = that.size.height * that.aspectRatio; + } + }, + + stop: function(event, ui){ + var that = $(this).data("resizable"), o = that.options, cp = that.position, + co = that.containerOffset, cop = that.containerPosition, ce = that.containerElement; + + var helper = $(that.helper), ho = helper.offset(), w = helper.outerWidth() - that.sizeDiff.width, h = helper.outerHeight() - that.sizeDiff.height; + + if (that._helper && !o.animate && (/relative/).test(ce.css('position'))) + $(this).css({ left: ho.left - cop.left - co.left, width: w, height: h }); + + if (that._helper && !o.animate && (/static/).test(ce.css('position'))) + $(this).css({ left: ho.left - cop.left - co.left, width: w, height: h }); + } }); -$.widget( "ui.buttonset", { - options: { - items: ":button, :submit, :reset, :checkbox, :radio, a, :data(button)" - }, +$.ui.plugin.add("resizable", "ghost", { - _create: function() { - this.element.addClass( "ui-buttonset" ); - }, - - _init: function() { - this.refresh(); - }, + start: function(event, ui) { - _setOption: function( key, value ) { - if ( key === "disabled" ) { - this.buttons.button( "option", key, value ); - } + var that = $(this).data("resizable"), o = that.options, cs = that.size; + + that.ghost = that.originalElement.clone(); + that.ghost + .css({ opacity: .25, display: 'block', position: 'relative', height: cs.height, width: cs.width, margin: 0, left: 0, top: 0 }) + .addClass('ui-resizable-ghost') + .addClass(typeof o.ghost == 'string' ? o.ghost : ''); + + that.ghost.appendTo(that.helper); - $.Widget.prototype._setOption.apply( this, arguments ); - }, - - refresh: function() { - var ltr = this.element.css( "direction" ) === "ltr"; - - this.buttons = this.element.find( this.options.items ) - .filter( ":ui-button" ) - .button( "refresh" ) - .end() - .not( ":ui-button" ) - .button() - .end() - .map(function() { - return $( this ).button( "widget" )[ 0 ]; - }) - .removeClass( "ui-corner-all ui-corner-left ui-corner-right" ) - .filter( ":first" ) - .addClass( ltr ? "ui-corner-left" : "ui-corner-right" ) - .end() - .filter( ":last" ) - .addClass( ltr ? "ui-corner-right" : "ui-corner-left" ) - .end() - .end(); }, - destroy: function() { - this.element.removeClass( "ui-buttonset" ); - this.buttons - .map(function() { - return $( this ).button( "widget" )[ 0 ]; - }) - .removeClass( "ui-corner-left ui-corner-right" ) - .end() - .button( "destroy" ); + resize: function(event, ui){ + var that = $(this).data("resizable"), o = that.options; + if (that.ghost) that.ghost.css({ position: 'relative', height: that.size.height, width: that.size.width }); + }, - $.Widget.prototype.destroy.call( this ); + stop: function(event, ui){ + var that = $(this).data("resizable"), o = that.options; + if (that.ghost && that.helper) that.helper.get(0).removeChild(that.ghost.get(0)); } + }); -}( jQuery ) ); -/* - * jQuery UI Datepicker 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Datepicker - * - * Depends: - * jquery.ui.core.js - */ -(function( $, undefined ) { +$.ui.plugin.add("resizable", "grid", { -$.extend($.ui, { datepicker: { version: "1.8.16" } }); + resize: function(event, ui) { + var that = $(this).data("resizable"), o = that.options, cs = that.size, os = that.originalSize, op = that.originalPosition, a = that.axis, ratio = o._aspectRatio || event.shiftKey; + o.grid = typeof o.grid == "number" ? [o.grid, o.grid] : o.grid; + var ox = Math.round((cs.width - os.width) / (o.grid[0]||1)) * (o.grid[0]||1), oy = Math.round((cs.height - os.height) / (o.grid[1]||1)) * (o.grid[1]||1); -var PROP_NAME = 'datepicker'; -var dpuuid = new Date().getTime(); -var instActive; + if (/^(se|s|e)$/.test(a)) { + that.size.width = os.width + ox; + that.size.height = os.height + oy; + } + else if (/^(ne)$/.test(a)) { + that.size.width = os.width + ox; + that.size.height = os.height + oy; + that.position.top = op.top - oy; + } + else if (/^(sw)$/.test(a)) { + that.size.width = os.width + ox; + that.size.height = os.height + oy; + that.position.left = op.left - ox; + } + else { + that.size.width = os.width + ox; + that.size.height = os.height + oy; + that.position.top = op.top - oy; + that.position.left = op.left - ox; + } + } -/* Date picker manager. - Use the singleton instance of this class, $.datepicker, to interact with the date picker. - Settings for (groups of) date pickers are maintained in an instance object, - allowing multiple different settings on the same page. */ +}); -function Datepicker() { - this.debug = false; // Change this to true to start debugging - this._curInst = null; // The current instance in use - this._keyEvent = false; // If the last event was a key event - this._disabledInputs = []; // List of date picker inputs that have been disabled - this._datepickerShowing = false; // True if the popup picker is showing , false if not - this._inDialog = false; // True if showing within a "dialog", false if not - this._mainDivId = 'ui-datepicker-div'; // The ID of the main datepicker division - this._inlineClass = 'ui-datepicker-inline'; // The name of the inline marker class - this._appendClass = 'ui-datepicker-append'; // The name of the append marker class - this._triggerClass = 'ui-datepicker-trigger'; // The name of the trigger marker class - this._dialogClass = 'ui-datepicker-dialog'; // The name of the dialog marker class - this._disableClass = 'ui-datepicker-disabled'; // The name of the disabled covering marker class - this._unselectableClass = 'ui-datepicker-unselectable'; // The name of the unselectable cell marker class - this._currentClass = 'ui-datepicker-current-day'; // The name of the current day marker class - this._dayOverClass = 'ui-datepicker-days-cell-over'; // The name of the day hover marker class - this.regional = []; // Available regional settings, indexed by language code - this.regional[''] = { // Default regional settings - closeText: 'Done', // Display text for close link - prevText: 'Prev', // Display text for previous month link - nextText: 'Next', // Display text for next month link - currentText: 'Today', // Display text for current month link - monthNames: ['January','February','March','April','May','June', - 'July','August','September','October','November','December'], // Names of months for drop-down and formatting - monthNamesShort: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], // For formatting - dayNames: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], // For formatting - dayNamesShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], // For formatting - dayNamesMin: ['Su','Mo','Tu','We','Th','Fr','Sa'], // Column headings for days starting at Sunday - weekHeader: 'Wk', // Column header for week of the year - dateFormat: 'mm/dd/yy', // See format options on parseDate - firstDay: 0, // The first day of the week, Sun = 0, Mon = 1, ... - isRTL: false, // True if right-to-left language, false if left-to-right - showMonthAfterYear: false, // True if the year select precedes month, false for month then year - yearSuffix: '' // Additional text to append to the year in the month headers - }; - this._defaults = { // Global defaults for all the date picker instances - showOn: 'focus', // 'focus' for popup on focus, - // 'button' for trigger button, or 'both' for either - showAnim: 'fadeIn', // Name of jQuery animation for popup - showOptions: {}, // Options for enhanced animations - defaultDate: null, // Used when field is blank: actual date, - // +/-number for offset from today, null for today - appendText: '', // Display text following the input box, e.g. showing the format - buttonText: '...', // Text for trigger button - buttonImage: '', // URL for trigger button image - buttonImageOnly: false, // True if the image appears alone, false if it appears on a button - hideIfNoPrevNext: false, // True to hide next/previous month links - // if not applicable, false to just disable them - navigationAsDateFormat: false, // True if date formatting applied to prev/today/next links - gotoCurrent: false, // True if today link goes back to current selection instead - changeMonth: false, // True if month can be selected directly, false if only prev/next - changeYear: false, // True if year can be selected directly, false if only prev/next - yearRange: 'c-10:c+10', // Range of years to display in drop-down, - // either relative to today's year (-nn:+nn), relative to currently displayed year - // (c-nn:c+nn), absolute (nnnn:nnnn), or a combination of the above (nnnn:-n) - showOtherMonths: false, // True to show dates in other months, false to leave blank - selectOtherMonths: false, // True to allow selection of dates in other months, false for unselectable - showWeek: false, // True to show week of the year, false to not show it - calculateWeek: this.iso8601Week, // How to calculate the week of the year, - // takes a Date and returns the number of the week for it - shortYearCutoff: '+10', // Short year values < this are in the current century, - // > this are in the previous century, - // string value starting with '+' for current year + value - minDate: null, // The earliest selectable date, or null for no limit - maxDate: null, // The latest selectable date, or null for no limit - duration: 'fast', // Duration of display/closure - beforeShowDay: null, // Function that takes a date and returns an array with - // [0] = true if selectable, false if not, [1] = custom CSS class name(s) or '', - // [2] = cell title (optional), e.g. $.datepicker.noWeekends - beforeShow: null, // Function that takes an input field and - // returns a set of custom settings for the date picker - onSelect: null, // Define a callback function when a date is selected - onChangeMonthYear: null, // Define a callback function when the month or year is changed - onClose: null, // Define a callback function when the datepicker is closed - numberOfMonths: 1, // Number of months to show at a time - showCurrentAtPos: 0, // The position in multipe months at which to show the current month (starting at 0) - stepMonths: 1, // Number of months to step back/forward - stepBigMonths: 12, // Number of months to step back/forward for the big links - altField: '', // Selector for an alternate field to store selected dates into - altFormat: '', // The date format to use for the alternate field - constrainInput: true, // The input is constrained by the current date format - showButtonPanel: false, // True to show button panel, false to not show it - autoSize: false, // True to size the input for the date format, false to leave as is - disabled: false // The initial disabled state - }; - $.extend(this._defaults, this.regional['']); - this.dpDiv = bindHover($('
        ')); -} +var num = function(v) { + return parseInt(v, 10) || 0; +}; -$.extend(Datepicker.prototype, { - /* Class name added to elements to indicate already configured with a date picker. */ - markerClassName: 'hasDatepicker', - - //Keep track of the maximum number of rows displayed (see #7043) - maxRows: 4, +var isNumber = function(value) { + return !isNaN(parseInt(value, 10)); +}; - /* Debug logging (if enabled). */ - log: function () { - if (this.debug) - console.log.apply('', arguments); - }, - - // TODO rename to "widget" when switching to widget factory - _widgetDatepicker: function() { - return this.dpDiv; - }, +})(jQuery); +(function( $, undefined ) { - /* Override the default settings for all instances of the date picker. - @param settings object - the new settings to use as defaults (anonymous object) - @return the manager object */ - setDefaults: function(settings) { - extendRemove(this._defaults, settings || {}); - return this; +$.widget("ui.selectable", $.ui.mouse, { + version: "1.9.2", + options: { + appendTo: 'body', + autoRefresh: true, + distance: 0, + filter: '*', + tolerance: 'touch' }, + _create: function() { + var that = this; - /* Attach the date picker to a jQuery selection. - @param target element - the target input field or division or span - @param settings object - the new settings to use for this date picker instance (anonymous) */ - _attachDatepicker: function(target, settings) { - // check for settings on the control itself - in namespace 'date:' - var inlineSettings = null; - for (var attrName in this._defaults) { - var attrValue = target.getAttribute('date:' + attrName); - if (attrValue) { - inlineSettings = inlineSettings || {}; - try { - inlineSettings[attrName] = eval(attrValue); - } catch (err) { - inlineSettings[attrName] = attrValue; - } - } - } - var nodeName = target.nodeName.toLowerCase(); - var inline = (nodeName == 'div' || nodeName == 'span'); - if (!target.id) { - this.uuid += 1; - target.id = 'dp' + this.uuid; - } - var inst = this._newInst($(target), inline); - inst.settings = $.extend({}, settings || {}, inlineSettings || {}); - if (nodeName == 'input') { - this._connectDatepicker(target, inst); - } else if (inline) { - this._inlineDatepicker(target, inst); - } + this.element.addClass("ui-selectable"); + + this.dragged = false; + + // cache selectee children based on filter + var selectees; + this.refresh = function() { + selectees = $(that.options.filter, that.element[0]); + selectees.addClass("ui-selectee"); + selectees.each(function() { + var $this = $(this); + var pos = $this.offset(); + $.data(this, "selectable-item", { + element: this, + $element: $this, + left: pos.left, + top: pos.top, + right: pos.left + $this.outerWidth(), + bottom: pos.top + $this.outerHeight(), + startselected: false, + selected: $this.hasClass('ui-selected'), + selecting: $this.hasClass('ui-selecting'), + unselecting: $this.hasClass('ui-unselecting') + }); + }); + }; + this.refresh(); + + this.selectees = selectees.addClass("ui-selectee"); + + this._mouseInit(); + + this.helper = $("
        "); }, - /* Create a new instance object. */ - _newInst: function(target, inline) { - var id = target[0].id.replace(/([^A-Za-z0-9_-])/g, '\\\\$1'); // escape jQuery meta chars - return {id: id, input: target, // associated target - selectedDay: 0, selectedMonth: 0, selectedYear: 0, // current selection - drawMonth: 0, drawYear: 0, // month being drawn - inline: inline, // is datepicker inline or not - dpDiv: (!inline ? this.dpDiv : // presentation div - bindHover($('
        ')))}; + _destroy: function() { + this.selectees + .removeClass("ui-selectee") + .removeData("selectable-item"); + this.element + .removeClass("ui-selectable ui-selectable-disabled"); + this._mouseDestroy(); }, - /* Attach the date picker to an input field. */ - _connectDatepicker: function(target, inst) { - var input = $(target); - inst.append = $([]); - inst.trigger = $([]); - if (input.hasClass(this.markerClassName)) + _mouseStart: function(event) { + var that = this; + + this.opos = [event.pageX, event.pageY]; + + if (this.options.disabled) return; - this._attachments(input, inst); - input.addClass(this.markerClassName).keydown(this._doKeyDown). - keypress(this._doKeyPress).keyup(this._doKeyUp). - bind("setData.datepicker", function(event, key, value) { - inst.settings[key] = value; - }).bind("getData.datepicker", function(event, key) { - return this._get(inst, key); - }); - this._autoSize(inst); - $.data(target, PROP_NAME, inst); - //If disabled option is true, disable the datepicker once it has been attached to the input (see ticket #5665) - if( inst.settings.disabled ) { - this._disableDatepicker( target ); - } - }, - /* Make attachments based on settings. */ - _attachments: function(input, inst) { - var appendText = this._get(inst, 'appendText'); - var isRTL = this._get(inst, 'isRTL'); - if (inst.append) - inst.append.remove(); - if (appendText) { - inst.append = $('' + appendText + ''); - input[isRTL ? 'before' : 'after'](inst.append); + var options = this.options; + + this.selectees = $(options.filter, this.element[0]); + + this._trigger("start", event); + + $(options.appendTo).append(this.helper); + // position helper (lasso) + this.helper.css({ + "left": event.clientX, + "top": event.clientY, + "width": 0, + "height": 0 + }); + + if (options.autoRefresh) { + this.refresh(); } - input.unbind('focus', this._showDatepicker); - if (inst.trigger) - inst.trigger.remove(); - var showOn = this._get(inst, 'showOn'); - if (showOn == 'focus' || showOn == 'both') // pop-up date picker when in the marked field - input.focus(this._showDatepicker); - if (showOn == 'button' || showOn == 'both') { // pop-up date picker when button clicked - var buttonText = this._get(inst, 'buttonText'); - var buttonImage = this._get(inst, 'buttonImage'); - inst.trigger = $(this._get(inst, 'buttonImageOnly') ? - $('').addClass(this._triggerClass). - attr({ src: buttonImage, alt: buttonText, title: buttonText }) : - $('').addClass(this._triggerClass). - html(buttonImage == '' ? buttonText : $('').attr( - { src:buttonImage, alt:buttonText, title:buttonText }))); - input[isRTL ? 'before' : 'after'](inst.trigger); - inst.trigger.click(function() { - if ($.datepicker._datepickerShowing && $.datepicker._lastInput == input[0]) - $.datepicker._hideDatepicker(); - else - $.datepicker._showDatepicker(input[0]); + + this.selectees.filter('.ui-selected').each(function() { + var selectee = $.data(this, "selectable-item"); + selectee.startselected = true; + if (!event.metaKey && !event.ctrlKey) { + selectee.$element.removeClass('ui-selected'); + selectee.selected = false; + selectee.$element.addClass('ui-unselecting'); + selectee.unselecting = true; + // selectable UNSELECTING callback + that._trigger("unselecting", event, { + unselecting: selectee.element + }); + } + }); + + $(event.target).parents().andSelf().each(function() { + var selectee = $.data(this, "selectable-item"); + if (selectee) { + var doSelect = (!event.metaKey && !event.ctrlKey) || !selectee.$element.hasClass('ui-selected'); + selectee.$element + .removeClass(doSelect ? "ui-unselecting" : "ui-selected") + .addClass(doSelect ? "ui-selecting" : "ui-unselecting"); + selectee.unselecting = !doSelect; + selectee.selecting = doSelect; + selectee.selected = doSelect; + // selectable (UN)SELECTING callback + if (doSelect) { + that._trigger("selecting", event, { + selecting: selectee.element + }); + } else { + that._trigger("unselecting", event, { + unselecting: selectee.element + }); + } return false; - }); - } + } + }); + }, - /* Apply the maximum length for the date format. */ - _autoSize: function(inst) { - if (this._get(inst, 'autoSize') && !inst.inline) { - var date = new Date(2009, 12 - 1, 20); // Ensure double digits - var dateFormat = this._get(inst, 'dateFormat'); - if (dateFormat.match(/[DM]/)) { - var findMax = function(names) { - var max = 0; - var maxI = 0; - for (var i = 0; i < names.length; i++) { - if (names[i].length > max) { - max = names[i].length; - maxI = i; + _mouseDrag: function(event) { + var that = this; + this.dragged = true; + + if (this.options.disabled) + return; + + var options = this.options; + + var x1 = this.opos[0], y1 = this.opos[1], x2 = event.pageX, y2 = event.pageY; + if (x1 > x2) { var tmp = x2; x2 = x1; x1 = tmp; } + if (y1 > y2) { var tmp = y2; y2 = y1; y1 = tmp; } + this.helper.css({left: x1, top: y1, width: x2-x1, height: y2-y1}); + + this.selectees.each(function() { + var selectee = $.data(this, "selectable-item"); + //prevent helper from being selected if appendTo: selectable + if (!selectee || selectee.element == that.element[0]) + return; + var hit = false; + if (options.tolerance == 'touch') { + hit = ( !(selectee.left > x2 || selectee.right < x1 || selectee.top > y2 || selectee.bottom < y1) ); + } else if (options.tolerance == 'fit') { + hit = (selectee.left > x1 && selectee.right < x2 && selectee.top > y1 && selectee.bottom < y2); + } + + if (hit) { + // SELECT + if (selectee.selected) { + selectee.$element.removeClass('ui-selected'); + selectee.selected = false; + } + if (selectee.unselecting) { + selectee.$element.removeClass('ui-unselecting'); + selectee.unselecting = false; + } + if (!selectee.selecting) { + selectee.$element.addClass('ui-selecting'); + selectee.selecting = true; + // selectable SELECTING callback + that._trigger("selecting", event, { + selecting: selectee.element + }); + } + } else { + // UNSELECT + if (selectee.selecting) { + if ((event.metaKey || event.ctrlKey) && selectee.startselected) { + selectee.$element.removeClass('ui-selecting'); + selectee.selecting = false; + selectee.$element.addClass('ui-selected'); + selectee.selected = true; + } else { + selectee.$element.removeClass('ui-selecting'); + selectee.selecting = false; + if (selectee.startselected) { + selectee.$element.addClass('ui-unselecting'); + selectee.unselecting = true; } + // selectable UNSELECTING callback + that._trigger("unselecting", event, { + unselecting: selectee.element + }); } - return maxI; - }; - date.setMonth(findMax(this._get(inst, (dateFormat.match(/MM/) ? - 'monthNames' : 'monthNamesShort')))); - date.setDate(findMax(this._get(inst, (dateFormat.match(/DD/) ? - 'dayNames' : 'dayNamesShort'))) + 20 - date.getDay()); + } + if (selectee.selected) { + if (!event.metaKey && !event.ctrlKey && !selectee.startselected) { + selectee.$element.removeClass('ui-selected'); + selectee.selected = false; + + selectee.$element.addClass('ui-unselecting'); + selectee.unselecting = true; + // selectable UNSELECTING callback + that._trigger("unselecting", event, { + unselecting: selectee.element + }); + } + } } - inst.input.attr('size', this._formatDate(inst, date).length); - } + }); + + return false; }, - /* Attach an inline date picker to a div. */ - _inlineDatepicker: function(target, inst) { - var divSpan = $(target); - if (divSpan.hasClass(this.markerClassName)) - return; - divSpan.addClass(this.markerClassName).append(inst.dpDiv). - bind("setData.datepicker", function(event, key, value){ - inst.settings[key] = value; - }).bind("getData.datepicker", function(event, key){ - return this._get(inst, key); + _mouseStop: function(event) { + var that = this; + + this.dragged = false; + + var options = this.options; + + $('.ui-unselecting', this.element[0]).each(function() { + var selectee = $.data(this, "selectable-item"); + selectee.$element.removeClass('ui-unselecting'); + selectee.unselecting = false; + selectee.startselected = false; + that._trigger("unselected", event, { + unselected: selectee.element }); - $.data(target, PROP_NAME, inst); - this._setDate(inst, this._getDefaultDate(inst), true); - this._updateDatepicker(inst); - this._updateAlternate(inst); - //If disabled option is true, disable the datepicker before showing it (see ticket #5665) - if( inst.settings.disabled ) { - this._disableDatepicker( target ); - } - // Set display:block in place of inst.dpDiv.show() which won't work on disconnected elements - // http://bugs.jqueryui.com/ticket/7552 - A Datepicker created on a detached div has zero height - inst.dpDiv.css( "display", "block" ); - }, + }); + $('.ui-selecting', this.element[0]).each(function() { + var selectee = $.data(this, "selectable-item"); + selectee.$element.removeClass('ui-selecting').addClass('ui-selected'); + selectee.selecting = false; + selectee.selected = true; + selectee.startselected = true; + that._trigger("selected", event, { + selected: selectee.element + }); + }); + this._trigger("stop", event); - /* Pop-up the date picker in a "dialog" box. - @param input element - ignored - @param date string or Date - the initial date to display - @param onSelect function - the function to call when a date is selected - @param settings object - update the dialog date picker instance's settings (anonymous object) - @param pos int[2] - coordinates for the dialog's position within the screen or - event - with x/y coordinates or - leave empty for default (screen centre) - @return the manager object */ - _dialogDatepicker: function(input, date, onSelect, settings, pos) { - var inst = this._dialogInst; // internal instance - if (!inst) { - this.uuid += 1; - var id = 'dp' + this.uuid; - this._dialogInput = $(''); - this._dialogInput.keydown(this._doKeyDown); - $('body').append(this._dialogInput); - inst = this._dialogInst = this._newInst(this._dialogInput, false); - inst.settings = {}; - $.data(this._dialogInput[0], PROP_NAME, inst); - } - extendRemove(inst.settings, settings || {}); - date = (date && date.constructor == Date ? this._formatDate(inst, date) : date); - this._dialogInput.val(date); + this.helper.remove(); - this._pos = (pos ? (pos.length ? pos : [pos.pageX, pos.pageY]) : null); - if (!this._pos) { - var browserWidth = document.documentElement.clientWidth; - var browserHeight = document.documentElement.clientHeight; - var scrollX = document.documentElement.scrollLeft || document.body.scrollLeft; - var scrollY = document.documentElement.scrollTop || document.body.scrollTop; - this._pos = // should use actual width/height below - [(browserWidth / 2) - 100 + scrollX, (browserHeight / 2) - 150 + scrollY]; - } + return false; + } - // move input on screen for focus, but hidden behind dialog - this._dialogInput.css('left', (this._pos[0] + 20) + 'px').css('top', this._pos[1] + 'px'); - inst.settings.onSelect = onSelect; - this._inDialog = true; - this.dpDiv.addClass(this._dialogClass); - this._showDatepicker(this._dialogInput[0]); - if ($.blockUI) - $.blockUI(this.dpDiv); - $.data(this._dialogInput[0], PROP_NAME, inst); - return this; - }, +}); - /* Detach a datepicker from its control. - @param target element - the target input field or division or span */ - _destroyDatepicker: function(target) { - var $target = $(target); - var inst = $.data(target, PROP_NAME); - if (!$target.hasClass(this.markerClassName)) { - return; - } - var nodeName = target.nodeName.toLowerCase(); - $.removeData(target, PROP_NAME); - if (nodeName == 'input') { - inst.append.remove(); - inst.trigger.remove(); - $target.removeClass(this.markerClassName). - unbind('focus', this._showDatepicker). - unbind('keydown', this._doKeyDown). - unbind('keypress', this._doKeyPress). - unbind('keyup', this._doKeyUp); - } else if (nodeName == 'div' || nodeName == 'span') - $target.removeClass(this.markerClassName).empty(); - }, +})(jQuery); +(function( $, undefined ) { - /* Enable the date picker to a jQuery selection. - @param target element - the target input field or division or span */ - _enableDatepicker: function(target) { - var $target = $(target); - var inst = $.data(target, PROP_NAME); - if (!$target.hasClass(this.markerClassName)) { - return; - } - var nodeName = target.nodeName.toLowerCase(); - if (nodeName == 'input') { - target.disabled = false; - inst.trigger.filter('button'). - each(function() { this.disabled = false; }).end(). - filter('img').css({opacity: '1.0', cursor: ''}); - } - else if (nodeName == 'div' || nodeName == 'span') { - var inline = $target.children('.' + this._inlineClass); - inline.children().removeClass('ui-state-disabled'); - inline.find("select.ui-datepicker-month, select.ui-datepicker-year"). - removeAttr("disabled"); - } - this._disabledInputs = $.map(this._disabledInputs, - function(value) { return (value == target ? null : value); }); // delete entry - }, +// number of pages in a slider +// (how many times can you page up/down to go through the whole range) +var numPages = 5; - /* Disable the date picker to a jQuery selection. - @param target element - the target input field or division or span */ - _disableDatepicker: function(target) { - var $target = $(target); - var inst = $.data(target, PROP_NAME); - if (!$target.hasClass(this.markerClassName)) { - return; - } - var nodeName = target.nodeName.toLowerCase(); - if (nodeName == 'input') { - target.disabled = true; - inst.trigger.filter('button'). - each(function() { this.disabled = true; }).end(). - filter('img').css({opacity: '0.5', cursor: 'default'}); - } - else if (nodeName == 'div' || nodeName == 'span') { - var inline = $target.children('.' + this._inlineClass); - inline.children().addClass('ui-state-disabled'); - inline.find("select.ui-datepicker-month, select.ui-datepicker-year"). - attr("disabled", "disabled"); - } - this._disabledInputs = $.map(this._disabledInputs, - function(value) { return (value == target ? null : value); }); // delete entry - this._disabledInputs[this._disabledInputs.length] = target; - }, +$.widget( "ui.slider", $.ui.mouse, { + version: "1.9.2", + widgetEventPrefix: "slide", - /* Is the first field in a jQuery collection disabled as a datepicker? - @param target element - the target input field or division or span - @return boolean - true if disabled, false if enabled */ - _isDisabledDatepicker: function(target) { - if (!target) { - return false; - } - for (var i = 0; i < this._disabledInputs.length; i++) { - if (this._disabledInputs[i] == target) - return true; - } - return false; + options: { + animate: false, + distance: 0, + max: 100, + min: 0, + orientation: "horizontal", + range: false, + step: 1, + value: 0, + values: null }, - /* Retrieve the instance data for the target control. - @param target element - the target input field or division or span - @return object - the associated instance data - @throws error if a jQuery problem getting data */ - _getInst: function(target) { - try { - return $.data(target, PROP_NAME); - } - catch (err) { - throw 'Missing instance data for this datepicker'; - } - }, + _create: function() { + var i, handleCount, + o = this.options, + existingHandles = this.element.find( ".ui-slider-handle" ).addClass( "ui-state-default ui-corner-all" ), + handle = "", + handles = []; + + this._keySliding = false; + this._mouseSliding = false; + this._animateOff = true; + this._handleIndex = null; + this._detectOrientation(); + this._mouseInit(); + + this.element + .addClass( "ui-slider" + + " ui-slider-" + this.orientation + + " ui-widget" + + " ui-widget-content" + + " ui-corner-all" + + ( o.disabled ? " ui-slider-disabled ui-disabled" : "" ) ); + + this.range = $([]); - /* Update or retrieve the settings for a date picker attached to an input field or division. - @param target element - the target input field or division or span - @param name object - the new settings to update or - string - the name of the setting to change or retrieve, - when retrieving also 'all' for all instance settings or - 'defaults' for all global defaults - @param value any - the new value for the setting - (omit if above is an object or to retrieve a value) */ - _optionDatepicker: function(target, name, value) { - var inst = this._getInst(target); - if (arguments.length == 2 && typeof name == 'string') { - return (name == 'defaults' ? $.extend({}, $.datepicker._defaults) : - (inst ? (name == 'all' ? $.extend({}, inst.settings) : - this._get(inst, name)) : null)); - } - var settings = name || {}; - if (typeof name == 'string') { - settings = {}; - settings[name] = value; - } - if (inst) { - if (this._curInst == inst) { - this._hideDatepicker(); + if ( o.range ) { + if ( o.range === true ) { + if ( !o.values ) { + o.values = [ this._valueMin(), this._valueMin() ]; + } + if ( o.values.length && o.values.length !== 2 ) { + o.values = [ o.values[0], o.values[0] ]; + } } - var date = this._getDateDatepicker(target, true); - var minDate = this._getMinMaxDate(inst, 'min'); - var maxDate = this._getMinMaxDate(inst, 'max'); - extendRemove(inst.settings, settings); - // reformat the old minDate/maxDate values if dateFormat changes and a new minDate/maxDate isn't provided - if (minDate !== null && settings['dateFormat'] !== undefined && settings['minDate'] === undefined) - inst.settings.minDate = this._formatDate(inst, minDate); - if (maxDate !== null && settings['dateFormat'] !== undefined && settings['maxDate'] === undefined) - inst.settings.maxDate = this._formatDate(inst, maxDate); - this._attachments($(target), inst); - this._autoSize(inst); - this._setDate(inst, date); - this._updateAlternate(inst); - this._updateDatepicker(inst); + + this.range = $( "
        " ) + .appendTo( this.element ) + .addClass( "ui-slider-range" + + // note: this isn't the most fittingly semantic framework class for this element, + // but worked best visually with a variety of themes + " ui-widget-header" + + ( ( o.range === "min" || o.range === "max" ) ? " ui-slider-range-" + o.range : "" ) ); } - }, - // change method deprecated - _changeDatepicker: function(target, name, value) { - this._optionDatepicker(target, name, value); - }, + handleCount = ( o.values && o.values.length ) || 1; - /* Redraw the date picker attached to an input field or division. - @param target element - the target input field or division or span */ - _refreshDatepicker: function(target) { - var inst = this._getInst(target); - if (inst) { - this._updateDatepicker(inst); + for ( i = existingHandles.length; i < handleCount; i++ ) { + handles.push( handle ); } - }, - /* Set the dates for a jQuery selection. - @param target element - the target input field or division or span - @param date Date - the new date */ - _setDateDatepicker: function(target, date) { - var inst = this._getInst(target); - if (inst) { - this._setDate(inst, date); - this._updateDatepicker(inst); - this._updateAlternate(inst); - } - }, + this.handles = existingHandles.add( $( handles.join( "" ) ).appendTo( this.element ) ); - /* Get the date(s) for the first entry in a jQuery selection. - @param target element - the target input field or division or span - @param noDefault boolean - true if no default date is to be used - @return Date - the current date */ - _getDateDatepicker: function(target, noDefault) { - var inst = this._getInst(target); - if (inst && !inst.inline) - this._setDateFromField(inst, noDefault); - return (inst ? this._getDate(inst) : null); - }, + this.handle = this.handles.eq( 0 ); - /* Handle keystrokes. */ - _doKeyDown: function(event) { - var inst = $.datepicker._getInst(event.target); - var handled = true; - var isRTL = inst.dpDiv.is('.ui-datepicker-rtl'); - inst._keyEvent = true; - if ($.datepicker._datepickerShowing) - switch (event.keyCode) { - case 9: $.datepicker._hideDatepicker(); - handled = false; - break; // hide on tab out - case 13: var sel = $('td.' + $.datepicker._dayOverClass + ':not(.' + - $.datepicker._currentClass + ')', inst.dpDiv); - if (sel[0]) - $.datepicker._selectDay(event.target, inst.selectedMonth, inst.selectedYear, sel[0]); - var onSelect = $.datepicker._get(inst, 'onSelect'); - if (onSelect) { - var dateStr = $.datepicker._formatDate(inst); + this.handles.add( this.range ).filter( "a" ) + .click(function( event ) { + event.preventDefault(); + }) + .mouseenter(function() { + if ( !o.disabled ) { + $( this ).addClass( "ui-state-hover" ); + } + }) + .mouseleave(function() { + $( this ).removeClass( "ui-state-hover" ); + }) + .focus(function() { + if ( !o.disabled ) { + $( ".ui-slider .ui-state-focus" ).removeClass( "ui-state-focus" ); + $( this ).addClass( "ui-state-focus" ); + } else { + $( this ).blur(); + } + }) + .blur(function() { + $( this ).removeClass( "ui-state-focus" ); + }); - // trigger custom callback - onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]); + this.handles.each(function( i ) { + $( this ).data( "ui-slider-handle-index", i ); + }); + + this._on( this.handles, { + keydown: function( event ) { + var allowed, curVal, newVal, step, + index = $( event.target ).data( "ui-slider-handle-index" ); + + switch ( event.keyCode ) { + case $.ui.keyCode.HOME: + case $.ui.keyCode.END: + case $.ui.keyCode.PAGE_UP: + case $.ui.keyCode.PAGE_DOWN: + case $.ui.keyCode.UP: + case $.ui.keyCode.RIGHT: + case $.ui.keyCode.DOWN: + case $.ui.keyCode.LEFT: + event.preventDefault(); + if ( !this._keySliding ) { + this._keySliding = true; + $( event.target ).addClass( "ui-state-active" ); + allowed = this._start( event, index ); + if ( allowed === false ) { + return; } - else - $.datepicker._hideDatepicker(); - return false; // don't submit the form - break; // select the value on enter - case 27: $.datepicker._hideDatepicker(); - break; // hide on escape - case 33: $.datepicker._adjustDate(event.target, (event.ctrlKey ? - -$.datepicker._get(inst, 'stepBigMonths') : - -$.datepicker._get(inst, 'stepMonths')), 'M'); - break; // previous month/year on page up/+ ctrl - case 34: $.datepicker._adjustDate(event.target, (event.ctrlKey ? - +$.datepicker._get(inst, 'stepBigMonths') : - +$.datepicker._get(inst, 'stepMonths')), 'M'); - break; // next month/year on page down/+ ctrl - case 35: if (event.ctrlKey || event.metaKey) $.datepicker._clearDate(event.target); - handled = event.ctrlKey || event.metaKey; - break; // clear on ctrl or command +end - case 36: if (event.ctrlKey || event.metaKey) $.datepicker._gotoToday(event.target); - handled = event.ctrlKey || event.metaKey; - break; // current on ctrl or command +home - case 37: if (event.ctrlKey || event.metaKey) $.datepicker._adjustDate(event.target, (isRTL ? +1 : -1), 'D'); - handled = event.ctrlKey || event.metaKey; - // -1 day on ctrl or command +left - if (event.originalEvent.altKey) $.datepicker._adjustDate(event.target, (event.ctrlKey ? - -$.datepicker._get(inst, 'stepBigMonths') : - -$.datepicker._get(inst, 'stepMonths')), 'M'); - // next month/year on alt +left on Mac + } break; - case 38: if (event.ctrlKey || event.metaKey) $.datepicker._adjustDate(event.target, -7, 'D'); - handled = event.ctrlKey || event.metaKey; - break; // -1 week on ctrl or command +up - case 39: if (event.ctrlKey || event.metaKey) $.datepicker._adjustDate(event.target, (isRTL ? -1 : +1), 'D'); - handled = event.ctrlKey || event.metaKey; - // +1 day on ctrl or command +right - if (event.originalEvent.altKey) $.datepicker._adjustDate(event.target, (event.ctrlKey ? - +$.datepicker._get(inst, 'stepBigMonths') : - +$.datepicker._get(inst, 'stepMonths')), 'M'); - // next month/year on alt +right + } + + step = this.options.step; + if ( this.options.values && this.options.values.length ) { + curVal = newVal = this.values( index ); + } else { + curVal = newVal = this.value(); + } + + switch ( event.keyCode ) { + case $.ui.keyCode.HOME: + newVal = this._valueMin(); break; - case 40: if (event.ctrlKey || event.metaKey) $.datepicker._adjustDate(event.target, +7, 'D'); - handled = event.ctrlKey || event.metaKey; - break; // +1 week on ctrl or command +down - default: handled = false; + case $.ui.keyCode.END: + newVal = this._valueMax(); + break; + case $.ui.keyCode.PAGE_UP: + newVal = this._trimAlignValue( curVal + ( (this._valueMax() - this._valueMin()) / numPages ) ); + break; + case $.ui.keyCode.PAGE_DOWN: + newVal = this._trimAlignValue( curVal - ( (this._valueMax() - this._valueMin()) / numPages ) ); + break; + case $.ui.keyCode.UP: + case $.ui.keyCode.RIGHT: + if ( curVal === this._valueMax() ) { + return; + } + newVal = this._trimAlignValue( curVal + step ); + break; + case $.ui.keyCode.DOWN: + case $.ui.keyCode.LEFT: + if ( curVal === this._valueMin() ) { + return; + } + newVal = this._trimAlignValue( curVal - step ); + break; + } + + this._slide( event, index, newVal ); + }, + keyup: function( event ) { + var index = $( event.target ).data( "ui-slider-handle-index" ); + + if ( this._keySliding ) { + this._keySliding = false; + this._stop( event, index ); + this._change( event, index ); + $( event.target ).removeClass( "ui-state-active" ); + } + } + }); + + this._refreshValue(); + + this._animateOff = false; + }, + + _destroy: function() { + this.handles.remove(); + this.range.remove(); + + this.element + .removeClass( "ui-slider" + + " ui-slider-horizontal" + + " ui-slider-vertical" + + " ui-slider-disabled" + + " ui-widget" + + " ui-widget-content" + + " ui-corner-all" ); + + this._mouseDestroy(); + }, + + _mouseCapture: function( event ) { + var position, normValue, distance, closestHandle, index, allowed, offset, mouseOverHandle, + that = this, + o = this.options; + + if ( o.disabled ) { + return false; + } + + this.elementSize = { + width: this.element.outerWidth(), + height: this.element.outerHeight() + }; + this.elementOffset = this.element.offset(); + + position = { x: event.pageX, y: event.pageY }; + normValue = this._normValueFromMouse( position ); + distance = this._valueMax() - this._valueMin() + 1; + this.handles.each(function( i ) { + var thisDistance = Math.abs( normValue - that.values(i) ); + if ( distance > thisDistance ) { + distance = thisDistance; + closestHandle = $( this ); + index = i; } - else if (event.keyCode == 36 && event.ctrlKey) // display the date picker on ctrl+home - $.datepicker._showDatepicker(this); - else { - handled = false; + }); + + // workaround for bug #3736 (if both handles of a range are at 0, + // the first is always used as the one with least distance, + // and moving it is obviously prevented by preventing negative ranges) + if( o.range === true && this.values(1) === o.min ) { + index += 1; + closestHandle = $( this.handles[index] ); } - if (handled) { - event.preventDefault(); - event.stopPropagation(); + + allowed = this._start( event, index ); + if ( allowed === false ) { + return false; } - }, + this._mouseSliding = true; - /* Filter entered characters - based on date format. */ - _doKeyPress: function(event) { - var inst = $.datepicker._getInst(event.target); - if ($.datepicker._get(inst, 'constrainInput')) { - var chars = $.datepicker._possibleChars($.datepicker._get(inst, 'dateFormat')); - var chr = String.fromCharCode(event.charCode == undefined ? event.keyCode : event.charCode); - return event.ctrlKey || event.metaKey || (chr < ' ' || !chars || chars.indexOf(chr) > -1); + this._handleIndex = index; + + closestHandle + .addClass( "ui-state-active" ) + .focus(); + + offset = closestHandle.offset(); + mouseOverHandle = !$( event.target ).parents().andSelf().is( ".ui-slider-handle" ); + this._clickOffset = mouseOverHandle ? { left: 0, top: 0 } : { + left: event.pageX - offset.left - ( closestHandle.width() / 2 ), + top: event.pageY - offset.top - + ( closestHandle.height() / 2 ) - + ( parseInt( closestHandle.css("borderTopWidth"), 10 ) || 0 ) - + ( parseInt( closestHandle.css("borderBottomWidth"), 10 ) || 0) + + ( parseInt( closestHandle.css("marginTop"), 10 ) || 0) + }; + + if ( !this.handles.hasClass( "ui-state-hover" ) ) { + this._slide( event, index, normValue ); } + this._animateOff = true; + return true; }, - /* Synchronise manual entry and field/alternate field. */ - _doKeyUp: function(event) { - var inst = $.datepicker._getInst(event.target); - if (inst.input.val() != inst.lastVal) { - try { - var date = $.datepicker.parseDate($.datepicker._get(inst, 'dateFormat'), - (inst.input ? inst.input.val() : null), - $.datepicker._getFormatConfig(inst)); - if (date) { // only if valid - $.datepicker._setDateFromField(inst); - $.datepicker._updateAlternate(inst); - $.datepicker._updateDatepicker(inst); - } - } - catch (event) { - $.datepicker.log(event); - } - } + _mouseStart: function() { return true; }, - /* Pop-up the date picker for a given input field. - If false returned from beforeShow event handler do not show. - @param input element - the input field attached to the date picker or - event - if triggered by focus */ - _showDatepicker: function(input) { - input = input.target || input; - if (input.nodeName.toLowerCase() != 'input') // find from button/image trigger - input = $('input', input.parentNode)[0]; - if ($.datepicker._isDisabledDatepicker(input) || $.datepicker._lastInput == input) // already here - return; - var inst = $.datepicker._getInst(input); - if ($.datepicker._curInst && $.datepicker._curInst != inst) { - if ( $.datepicker._datepickerShowing ) { - $.datepicker._triggerOnClose($.datepicker._curInst); - } - $.datepicker._curInst.dpDiv.stop(true, true); - } - var beforeShow = $.datepicker._get(inst, 'beforeShow'); - var beforeShowSettings = beforeShow ? beforeShow.apply(input, [input, inst]) : {}; - if(beforeShowSettings === false){ - //false - return; + _mouseDrag: function( event ) { + var position = { x: event.pageX, y: event.pageY }, + normValue = this._normValueFromMouse( position ); + + this._slide( event, this._handleIndex, normValue ); + + return false; + }, + + _mouseStop: function( event ) { + this.handles.removeClass( "ui-state-active" ); + this._mouseSliding = false; + + this._stop( event, this._handleIndex ); + this._change( event, this._handleIndex ); + + this._handleIndex = null; + this._clickOffset = null; + this._animateOff = false; + + return false; + }, + + _detectOrientation: function() { + this.orientation = ( this.options.orientation === "vertical" ) ? "vertical" : "horizontal"; + }, + + _normValueFromMouse: function( position ) { + var pixelTotal, + pixelMouse, + percentMouse, + valueTotal, + valueMouse; + + if ( this.orientation === "horizontal" ) { + pixelTotal = this.elementSize.width; + pixelMouse = position.x - this.elementOffset.left - ( this._clickOffset ? this._clickOffset.left : 0 ); + } else { + pixelTotal = this.elementSize.height; + pixelMouse = position.y - this.elementOffset.top - ( this._clickOffset ? this._clickOffset.top : 0 ); } - extendRemove(inst.settings, beforeShowSettings); - inst.lastVal = null; - $.datepicker._lastInput = input; - $.datepicker._setDateFromField(inst); - if ($.datepicker._inDialog) // hide cursor - input.value = ''; - if (!$.datepicker._pos) { // position below input - $.datepicker._pos = $.datepicker._findPos(input); - $.datepicker._pos[1] += input.offsetHeight; // add the height + + percentMouse = ( pixelMouse / pixelTotal ); + if ( percentMouse > 1 ) { + percentMouse = 1; } - var isFixed = false; - $(input).parents().each(function() { - isFixed |= $(this).css('position') == 'fixed'; - return !isFixed; - }); - if (isFixed && $.browser.opera) { // correction for Opera when fixed and scrolled - $.datepicker._pos[0] -= document.documentElement.scrollLeft; - $.datepicker._pos[1] -= document.documentElement.scrollTop; + if ( percentMouse < 0 ) { + percentMouse = 0; } - var offset = {left: $.datepicker._pos[0], top: $.datepicker._pos[1]}; - $.datepicker._pos = null; - //to avoid flashes on Firefox - inst.dpDiv.empty(); - // determine sizing offscreen - inst.dpDiv.css({position: 'absolute', display: 'block', top: '-1000px'}); - $.datepicker._updateDatepicker(inst); - // fix width for dynamic number of date pickers - // and adjust position before showing - offset = $.datepicker._checkOffset(inst, offset, isFixed); - inst.dpDiv.css({position: ($.datepicker._inDialog && $.blockUI ? - 'static' : (isFixed ? 'fixed' : 'absolute')), display: 'none', - left: offset.left + 'px', top: offset.top + 'px'}); - if (!inst.inline) { - var showAnim = $.datepicker._get(inst, 'showAnim'); - var duration = $.datepicker._get(inst, 'duration'); - var postProcess = function() { - var cover = inst.dpDiv.find('iframe.ui-datepicker-cover'); // IE6- only - if( !! cover.length ){ - var borders = $.datepicker._getBorders(inst.dpDiv); - cover.css({left: -borders[0], top: -borders[1], - width: inst.dpDiv.outerWidth(), height: inst.dpDiv.outerHeight()}); - } - }; - inst.dpDiv.zIndex($(input).zIndex()+1); - $.datepicker._datepickerShowing = true; - if ($.effects && $.effects[showAnim]) - inst.dpDiv.show(showAnim, $.datepicker._get(inst, 'showOptions'), duration, postProcess); - else - inst.dpDiv[showAnim || 'show']((showAnim ? duration : null), postProcess); - if (!showAnim || !duration) - postProcess(); - if (inst.input.is(':visible') && !inst.input.is(':disabled')) - inst.input.focus(); - $.datepicker._curInst = inst; + if ( this.orientation === "vertical" ) { + percentMouse = 1 - percentMouse; } + + valueTotal = this._valueMax() - this._valueMin(); + valueMouse = this._valueMin() + percentMouse * valueTotal; + + return this._trimAlignValue( valueMouse ); }, - /* Generate the date picker content. */ - _updateDatepicker: function(inst) { - var self = this; - self.maxRows = 4; //Reset the max number of rows being displayed (see #7043) - var borders = $.datepicker._getBorders(inst.dpDiv); - instActive = inst; // for delegate hover events - inst.dpDiv.empty().append(this._generateHTML(inst)); - var cover = inst.dpDiv.find('iframe.ui-datepicker-cover'); // IE6- only - if( !!cover.length ){ //avoid call to outerXXXX() when not in IE6 - cover.css({left: -borders[0], top: -borders[1], width: inst.dpDiv.outerWidth(), height: inst.dpDiv.outerHeight()}) + _start: function( event, index ) { + var uiHash = { + handle: this.handles[ index ], + value: this.value() + }; + if ( this.options.values && this.options.values.length ) { + uiHash.value = this.values( index ); + uiHash.values = this.values(); } - inst.dpDiv.find('.' + this._dayOverClass + ' a').mouseover(); - var numMonths = this._getNumberOfMonths(inst); - var cols = numMonths[1]; - var width = 17; - inst.dpDiv.removeClass('ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4').width(''); - if (cols > 1) - inst.dpDiv.addClass('ui-datepicker-multi-' + cols).css('width', (width * cols) + 'em'); - inst.dpDiv[(numMonths[0] != 1 || numMonths[1] != 1 ? 'add' : 'remove') + - 'Class']('ui-datepicker-multi'); - inst.dpDiv[(this._get(inst, 'isRTL') ? 'add' : 'remove') + - 'Class']('ui-datepicker-rtl'); - if (inst == $.datepicker._curInst && $.datepicker._datepickerShowing && inst.input && - // #6694 - don't focus the input if it's already focused - // this breaks the change event in IE - inst.input.is(':visible') && !inst.input.is(':disabled') && inst.input[0] != document.activeElement) - inst.input.focus(); - // deffered render of the years select (to avoid flashes on Firefox) - if( inst.yearshtml ){ - var origyearshtml = inst.yearshtml; - setTimeout(function(){ - //assure that inst.yearshtml didn't change. - if( origyearshtml === inst.yearshtml && inst.yearshtml ){ - inst.dpDiv.find('select.ui-datepicker-year:first').replaceWith(inst.yearshtml); + return this._trigger( "start", event, uiHash ); + }, + + _slide: function( event, index, newVal ) { + var otherVal, + newValues, + allowed; + + if ( this.options.values && this.options.values.length ) { + otherVal = this.values( index ? 0 : 1 ); + + if ( ( this.options.values.length === 2 && this.options.range === true ) && + ( ( index === 0 && newVal > otherVal) || ( index === 1 && newVal < otherVal ) ) + ) { + newVal = otherVal; + } + + if ( newVal !== this.values( index ) ) { + newValues = this.values(); + newValues[ index ] = newVal; + // A slide can be canceled by returning false from the slide callback + allowed = this._trigger( "slide", event, { + handle: this.handles[ index ], + value: newVal, + values: newValues + } ); + otherVal = this.values( index ? 0 : 1 ); + if ( allowed !== false ) { + this.values( index, newVal, true ); } - origyearshtml = inst.yearshtml = null; - }, 0); + } + } else { + if ( newVal !== this.value() ) { + // A slide can be canceled by returning false from the slide callback + allowed = this._trigger( "slide", event, { + handle: this.handles[ index ], + value: newVal + } ); + if ( allowed !== false ) { + this.value( newVal ); + } + } } }, - /* Retrieve the size of left and top borders for an element. - @param elem (jQuery object) the element of interest - @return (number[2]) the left and top borders */ - _getBorders: function(elem) { - var convert = function(value) { - return {thin: 1, medium: 2, thick: 3}[value] || value; + _stop: function( event, index ) { + var uiHash = { + handle: this.handles[ index ], + value: this.value() }; - return [parseFloat(convert(elem.css('border-left-width'))), - parseFloat(convert(elem.css('border-top-width')))]; - }, - - /* Check positioning to remain on screen. */ - _checkOffset: function(inst, offset, isFixed) { - var dpWidth = inst.dpDiv.outerWidth(); - var dpHeight = inst.dpDiv.outerHeight(); - var inputWidth = inst.input ? inst.input.outerWidth() : 0; - var inputHeight = inst.input ? inst.input.outerHeight() : 0; - var viewWidth = document.documentElement.clientWidth + $(document).scrollLeft(); - var viewHeight = document.documentElement.clientHeight + $(document).scrollTop(); - - offset.left -= (this._get(inst, 'isRTL') ? (dpWidth - inputWidth) : 0); - offset.left -= (isFixed && offset.left == inst.input.offset().left) ? $(document).scrollLeft() : 0; - offset.top -= (isFixed && offset.top == (inst.input.offset().top + inputHeight)) ? $(document).scrollTop() : 0; - - // now check if datepicker is showing outside window viewport - move to a better place if so. - offset.left -= Math.min(offset.left, (offset.left + dpWidth > viewWidth && viewWidth > dpWidth) ? - Math.abs(offset.left + dpWidth - viewWidth) : 0); - offset.top -= Math.min(offset.top, (offset.top + dpHeight > viewHeight && viewHeight > dpHeight) ? - Math.abs(dpHeight + inputHeight) : 0); + if ( this.options.values && this.options.values.length ) { + uiHash.value = this.values( index ); + uiHash.values = this.values(); + } - return offset; + this._trigger( "stop", event, uiHash ); }, - /* Find an object's position on the screen. */ - _findPos: function(obj) { - var inst = this._getInst(obj); - var isRTL = this._get(inst, 'isRTL'); - while (obj && (obj.type == 'hidden' || obj.nodeType != 1 || $.expr.filters.hidden(obj))) { - obj = obj[isRTL ? 'previousSibling' : 'nextSibling']; - } - var position = $(obj).offset(); - return [position.left, position.top]; - }, + _change: function( event, index ) { + if ( !this._keySliding && !this._mouseSliding ) { + var uiHash = { + handle: this.handles[ index ], + value: this.value() + }; + if ( this.options.values && this.options.values.length ) { + uiHash.value = this.values( index ); + uiHash.values = this.values(); + } - /* Trigger custom callback of onClose. */ - _triggerOnClose: function(inst) { - var onClose = this._get(inst, 'onClose'); - if (onClose) - onClose.apply((inst.input ? inst.input[0] : null), - [(inst.input ? inst.input.val() : ''), inst]); + this._trigger( "change", event, uiHash ); + } }, - /* Hide the date picker from view. - @param input element - the input field attached to the date picker */ - _hideDatepicker: function(input) { - var inst = this._curInst; - if (!inst || (input && inst != $.data(input, PROP_NAME))) + value: function( newValue ) { + if ( arguments.length ) { + this.options.value = this._trimAlignValue( newValue ); + this._refreshValue(); + this._change( null, 0 ); return; - if (this._datepickerShowing) { - var showAnim = this._get(inst, 'showAnim'); - var duration = this._get(inst, 'duration'); - var postProcess = function() { - $.datepicker._tidyDialog(inst); - this._curInst = null; - }; - if ($.effects && $.effects[showAnim]) - inst.dpDiv.hide(showAnim, $.datepicker._get(inst, 'showOptions'), duration, postProcess); - else - inst.dpDiv[(showAnim == 'slideDown' ? 'slideUp' : - (showAnim == 'fadeIn' ? 'fadeOut' : 'hide'))]((showAnim ? duration : null), postProcess); - if (!showAnim) - postProcess(); - $.datepicker._triggerOnClose(inst); - this._datepickerShowing = false; - this._lastInput = null; - if (this._inDialog) { - this._dialogInput.css({ position: 'absolute', left: '0', top: '-100px' }); - if ($.blockUI) { - $.unblockUI(); - $('body').append(this.dpDiv); - } - } - this._inDialog = false; } - }, - /* Tidy up after a dialog display. */ - _tidyDialog: function(inst) { - inst.dpDiv.removeClass(this._dialogClass).unbind('.ui-datepicker-calendar'); + return this._value(); }, - /* Close date picker if clicked elsewhere. */ - _checkExternalClick: function(event) { - if (!$.datepicker._curInst) - return; - var $target = $(event.target); - if ($target[0].id != $.datepicker._mainDivId && - $target.parents('#' + $.datepicker._mainDivId).length == 0 && - !$target.hasClass($.datepicker.markerClassName) && - !$target.hasClass($.datepicker._triggerClass) && - $.datepicker._datepickerShowing && !($.datepicker._inDialog && $.blockUI)) - $.datepicker._hideDatepicker(); - }, + values: function( index, newValue ) { + var vals, + newValues, + i; - /* Adjust one of the date sub-fields. */ - _adjustDate: function(id, offset, period) { - var target = $(id); - var inst = this._getInst(target[0]); - if (this._isDisabledDatepicker(target[0])) { + if ( arguments.length > 1 ) { + this.options.values[ index ] = this._trimAlignValue( newValue ); + this._refreshValue(); + this._change( null, index ); return; } - this._adjustInstDate(inst, offset + - (period == 'M' ? this._get(inst, 'showCurrentAtPos') : 0), // undo positioning - period); - this._updateDatepicker(inst); + + if ( arguments.length ) { + if ( $.isArray( arguments[ 0 ] ) ) { + vals = this.options.values; + newValues = arguments[ 0 ]; + for ( i = 0; i < vals.length; i += 1 ) { + vals[ i ] = this._trimAlignValue( newValues[ i ] ); + this._change( null, i ); + } + this._refreshValue(); + } else { + if ( this.options.values && this.options.values.length ) { + return this._values( index ); + } else { + return this.value(); + } + } + } else { + return this._values(); + } }, - /* Action for current link. */ - _gotoToday: function(id) { - var target = $(id); - var inst = this._getInst(target[0]); - if (this._get(inst, 'gotoCurrent') && inst.currentDay) { - inst.selectedDay = inst.currentDay; - inst.drawMonth = inst.selectedMonth = inst.currentMonth; - inst.drawYear = inst.selectedYear = inst.currentYear; + _setOption: function( key, value ) { + var i, + valsLength = 0; + + if ( $.isArray( this.options.values ) ) { + valsLength = this.options.values.length; } - else { - var date = new Date(); - inst.selectedDay = date.getDate(); - inst.drawMonth = inst.selectedMonth = date.getMonth(); - inst.drawYear = inst.selectedYear = date.getFullYear(); + + $.Widget.prototype._setOption.apply( this, arguments ); + + switch ( key ) { + case "disabled": + if ( value ) { + this.handles.filter( ".ui-state-focus" ).blur(); + this.handles.removeClass( "ui-state-hover" ); + this.handles.prop( "disabled", true ); + this.element.addClass( "ui-disabled" ); + } else { + this.handles.prop( "disabled", false ); + this.element.removeClass( "ui-disabled" ); + } + break; + case "orientation": + this._detectOrientation(); + this.element + .removeClass( "ui-slider-horizontal ui-slider-vertical" ) + .addClass( "ui-slider-" + this.orientation ); + this._refreshValue(); + break; + case "value": + this._animateOff = true; + this._refreshValue(); + this._change( null, 0 ); + this._animateOff = false; + break; + case "values": + this._animateOff = true; + this._refreshValue(); + for ( i = 0; i < valsLength; i += 1 ) { + this._change( null, i ); + } + this._animateOff = false; + break; + case "min": + case "max": + this._animateOff = true; + this._refreshValue(); + this._animateOff = false; + break; } - this._notifyChange(inst); - this._adjustDate(target); }, - /* Action for selecting a new month/year. */ - _selectMonthYear: function(id, select, period) { - var target = $(id); - var inst = this._getInst(target[0]); - inst['selected' + (period == 'M' ? 'Month' : 'Year')] = - inst['draw' + (period == 'M' ? 'Month' : 'Year')] = - parseInt(select.options[select.selectedIndex].value,10); - this._notifyChange(inst); - this._adjustDate(target); - }, + //internal value getter + // _value() returns value trimmed by min and max, aligned by step + _value: function() { + var val = this.options.value; + val = this._trimAlignValue( val ); - /* Action for selecting a day. */ - _selectDay: function(id, month, year, td) { - var target = $(id); - if ($(td).hasClass(this._unselectableClass) || this._isDisabledDatepicker(target[0])) { - return; - } - var inst = this._getInst(target[0]); - inst.selectedDay = inst.currentDay = $('a', td).html(); - inst.selectedMonth = inst.currentMonth = month; - inst.selectedYear = inst.currentYear = year; - this._selectDate(id, this._formatDate(inst, - inst.currentDay, inst.currentMonth, inst.currentYear)); + return val; }, - /* Erase the input field and hide the date picker. */ - _clearDate: function(id) { - var target = $(id); - var inst = this._getInst(target[0]); - this._selectDate(target, ''); - }, + //internal values getter + // _values() returns array of values trimmed by min and max, aligned by step + // _values( index ) returns single value trimmed by min and max, aligned by step + _values: function( index ) { + var val, + vals, + i; + + if ( arguments.length ) { + val = this.options.values[ index ]; + val = this._trimAlignValue( val ); + + return val; + } else { + // .slice() creates a copy of the array + // this copy gets trimmed by min and max and then returned + vals = this.options.values.slice(); + for ( i = 0; i < vals.length; i+= 1) { + vals[ i ] = this._trimAlignValue( vals[ i ] ); + } - /* Update the input field with the selected date. */ - _selectDate: function(id, dateStr) { - var target = $(id); - var inst = this._getInst(target[0]); - dateStr = (dateStr != null ? dateStr : this._formatDate(inst)); - if (inst.input) - inst.input.val(dateStr); - this._updateAlternate(inst); - var onSelect = this._get(inst, 'onSelect'); - if (onSelect) - onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]); // trigger custom callback - else if (inst.input) - inst.input.trigger('change'); // fire the change event - if (inst.inline) - this._updateDatepicker(inst); - else { - this._hideDatepicker(); - this._lastInput = inst.input[0]; - if (typeof(inst.input[0]) != 'object') - inst.input.focus(); // restore focus - this._lastInput = null; + return vals; } }, - /* Update any alternate field to synchronise with the main field. */ - _updateAlternate: function(inst) { - var altField = this._get(inst, 'altField'); - if (altField) { // update alternate field too - var altFormat = this._get(inst, 'altFormat') || this._get(inst, 'dateFormat'); - var date = this._getDate(inst); - var dateStr = this.formatDate(altFormat, date, this._getFormatConfig(inst)); - $(altField).each(function() { $(this).val(dateStr); }); + // returns the step-aligned value that val is closest to, between (inclusive) min and max + _trimAlignValue: function( val ) { + if ( val <= this._valueMin() ) { + return this._valueMin(); } + if ( val >= this._valueMax() ) { + return this._valueMax(); + } + var step = ( this.options.step > 0 ) ? this.options.step : 1, + valModStep = (val - this._valueMin()) % step, + alignValue = val - valModStep; + + if ( Math.abs(valModStep) * 2 >= step ) { + alignValue += ( valModStep > 0 ) ? step : ( -step ); + } + + // Since JavaScript has problems with large floats, round + // the final value to 5 digits after the decimal point (see #4124) + return parseFloat( alignValue.toFixed(5) ); }, - /* Set as beforeShowDay function to prevent selection of weekends. - @param date Date - the date to customise - @return [boolean, string] - is this date selectable?, what is its CSS class? */ - noWeekends: function(date) { - var day = date.getDay(); - return [(day > 0 && day < 6), '']; + _valueMin: function() { + return this.options.min; }, - /* Set as calculateWeek to determine the week of the year based on the ISO 8601 definition. - @param date Date - the date to get the week for - @return number - the number of the week within the year that contains this date */ - iso8601Week: function(date) { - var checkDate = new Date(date.getTime()); - // Find Thursday of this week starting on Monday - checkDate.setDate(checkDate.getDate() + 4 - (checkDate.getDay() || 7)); - var time = checkDate.getTime(); - checkDate.setMonth(0); // Compare with Jan 1 - checkDate.setDate(1); - return Math.floor(Math.round((time - checkDate) / 86400000) / 7) + 1; + _valueMax: function() { + return this.options.max; }, - /* Parse a string value into a date object. - See formatDate below for the possible formats. + _refreshValue: function() { + var lastValPercent, valPercent, value, valueMin, valueMax, + oRange = this.options.range, + o = this.options, + that = this, + animate = ( !this._animateOff ) ? o.animate : false, + _set = {}; - @param format string - the expected format of the date - @param value string - the date in the above format - @param settings Object - attributes include: - shortYearCutoff number - the cutoff year for determining the century (optional) - dayNamesShort string[7] - abbreviated names of the days from Sunday (optional) - dayNames string[7] - names of the days from Sunday (optional) - monthNamesShort string[12] - abbreviated names of the months (optional) - monthNames string[12] - names of the months (optional) - @return Date - the extracted date value or null if value is blank */ - parseDate: function (format, value, settings) { - if (format == null || value == null) - throw 'Invalid arguments'; - value = (typeof value == 'object' ? value.toString() : value + ''); - if (value == '') - return null; - var shortYearCutoff = (settings ? settings.shortYearCutoff : null) || this._defaults.shortYearCutoff; - shortYearCutoff = (typeof shortYearCutoff != 'string' ? shortYearCutoff : - new Date().getFullYear() % 100 + parseInt(shortYearCutoff, 10)); - var dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort; - var dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames; - var monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort; - var monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames; - var year = -1; - var month = -1; - var day = -1; - var doy = -1; - var literal = false; - // Check whether a format character is doubled - var lookAhead = function(match) { - var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) == match); - if (matches) - iFormat++; - return matches; - }; - // Extract a number from the string value - var getNumber = function(match) { - var isDoubled = lookAhead(match); - var size = (match == '@' ? 14 : (match == '!' ? 20 : - (match == 'y' && isDoubled ? 4 : (match == 'o' ? 3 : 2)))); - var digits = new RegExp('^\\d{1,' + size + '}'); - var num = value.substring(iValue).match(digits); - if (!num) - throw 'Missing number at position ' + iValue; - iValue += num[0].length; - return parseInt(num[0], 10); - }; - // Extract a name from the string value and convert to an index - var getName = function(match, shortNames, longNames) { - var names = $.map(lookAhead(match) ? longNames : shortNames, function (v, k) { - return [ [k, v] ]; - }).sort(function (a, b) { - return -(a[1].length - b[1].length); - }); - var index = -1; - $.each(names, function (i, pair) { - var name = pair[1]; - if (value.substr(iValue, name.length).toLowerCase() == name.toLowerCase()) { - index = pair[0]; - iValue += name.length; - return false; + if ( this.options.values && this.options.values.length ) { + this.handles.each(function( i ) { + valPercent = ( that.values(i) - that._valueMin() ) / ( that._valueMax() - that._valueMin() ) * 100; + _set[ that.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%"; + $( this ).stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate ); + if ( that.options.range === true ) { + if ( that.orientation === "horizontal" ) { + if ( i === 0 ) { + that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { left: valPercent + "%" }, o.animate ); + } + if ( i === 1 ) { + that.range[ animate ? "animate" : "css" ]( { width: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: o.animate } ); + } + } else { + if ( i === 0 ) { + that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { bottom: ( valPercent ) + "%" }, o.animate ); + } + if ( i === 1 ) { + that.range[ animate ? "animate" : "css" ]( { height: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: o.animate } ); + } + } } + lastValPercent = valPercent; }); - if (index != -1) - return index + 1; - else - throw 'Unknown name at position ' + iValue; - }; - // Confirm that a literal character matches the string value - var checkLiteral = function() { - if (value.charAt(iValue) != format.charAt(iFormat)) - throw 'Unexpected literal at position ' + iValue; - iValue++; - }; - var iValue = 0; - for (var iFormat = 0; iFormat < format.length; iFormat++) { - if (literal) - if (format.charAt(iFormat) == "'" && !lookAhead("'")) - literal = false; - else - checkLiteral(); - else - switch (format.charAt(iFormat)) { - case 'd': - day = getNumber('d'); - break; - case 'D': - getName('D', dayNamesShort, dayNames); - break; - case 'o': - doy = getNumber('o'); - break; - case 'm': - month = getNumber('m'); - break; - case 'M': - month = getName('M', monthNamesShort, monthNames); - break; - case 'y': - year = getNumber('y'); - break; - case '@': - var date = new Date(getNumber('@')); - year = date.getFullYear(); - month = date.getMonth() + 1; - day = date.getDate(); - break; - case '!': - var date = new Date((getNumber('!') - this._ticksTo1970) / 10000); - year = date.getFullYear(); - month = date.getMonth() + 1; - day = date.getDate(); - break; - case "'": - if (lookAhead("'")) - checkLiteral(); - else - literal = true; - break; - default: - checkLiteral(); - } - } - if (iValue < value.length){ - throw "Extra/unparsed characters found in date: " + value.substring(iValue); - } - if (year == -1) - year = new Date().getFullYear(); - else if (year < 100) - year += new Date().getFullYear() - new Date().getFullYear() % 100 + - (year <= shortYearCutoff ? 0 : -100); - if (doy > -1) { - month = 1; - day = doy; - do { - var dim = this._getDaysInMonth(year, month - 1); - if (day <= dim) - break; - month++; - day -= dim; - } while (true); + } else { + value = this.value(); + valueMin = this._valueMin(); + valueMax = this._valueMax(); + valPercent = ( valueMax !== valueMin ) ? + ( value - valueMin ) / ( valueMax - valueMin ) * 100 : + 0; + _set[ this.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%"; + this.handle.stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate ); + + if ( oRange === "min" && this.orientation === "horizontal" ) { + this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { width: valPercent + "%" }, o.animate ); + } + if ( oRange === "max" && this.orientation === "horizontal" ) { + this.range[ animate ? "animate" : "css" ]( { width: ( 100 - valPercent ) + "%" }, { queue: false, duration: o.animate } ); + } + if ( oRange === "min" && this.orientation === "vertical" ) { + this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { height: valPercent + "%" }, o.animate ); + } + if ( oRange === "max" && this.orientation === "vertical" ) { + this.range[ animate ? "animate" : "css" ]( { height: ( 100 - valPercent ) + "%" }, { queue: false, duration: o.animate } ); + } } - var date = this._daylightSavingAdjust(new Date(year, month - 1, day)); - if (date.getFullYear() != year || date.getMonth() + 1 != month || date.getDate() != day) - throw 'Invalid date'; // E.g. 31/02/00 - return date; + } + +}); + +}(jQuery)); +(function( $, undefined ) { + +$.widget("ui.sortable", $.ui.mouse, { + version: "1.9.2", + widgetEventPrefix: "sort", + ready: false, + options: { + appendTo: "parent", + axis: false, + connectWith: false, + containment: false, + cursor: 'auto', + cursorAt: false, + dropOnEmpty: true, + forcePlaceholderSize: false, + forceHelperSize: false, + grid: false, + handle: false, + helper: "original", + items: '> *', + opacity: false, + placeholder: false, + revert: false, + scroll: true, + scrollSensitivity: 20, + scrollSpeed: 20, + scope: "default", + tolerance: "intersect", + zIndex: 1000 }, + _create: function() { - /* Standard date formats. */ - ATOM: 'yy-mm-dd', // RFC 3339 (ISO 8601) - COOKIE: 'D, dd M yy', - ISO_8601: 'yy-mm-dd', - RFC_822: 'D, d M y', - RFC_850: 'DD, dd-M-y', - RFC_1036: 'D, d M y', - RFC_1123: 'D, d M yy', - RFC_2822: 'D, d M yy', - RSS: 'D, d M y', // RFC 822 - TICKS: '!', - TIMESTAMP: '@', - W3C: 'yy-mm-dd', // ISO 8601 + var o = this.options; + this.containerCache = {}; + this.element.addClass("ui-sortable"); - _ticksTo1970: (((1970 - 1) * 365 + Math.floor(1970 / 4) - Math.floor(1970 / 100) + - Math.floor(1970 / 400)) * 24 * 60 * 60 * 10000000), + //Get the items + this.refresh(); - /* Format a date object into a string value. - The format can be combinations of the following: - d - day of month (no leading zero) - dd - day of month (two digit) - o - day of year (no leading zeros) - oo - day of year (three digit) - D - day name short - DD - day name long - m - month of year (no leading zero) - mm - month of year (two digit) - M - month name short - MM - month name long - y - year (two digit) - yy - year (four digit) - @ - Unix timestamp (ms since 01/01/1970) - ! - Windows ticks (100ns since 01/01/0001) - '...' - literal text - '' - single quote + //Let's determine if the items are being displayed horizontally + this.floating = this.items.length ? o.axis === 'x' || (/left|right/).test(this.items[0].item.css('float')) || (/inline|table-cell/).test(this.items[0].item.css('display')) : false; - @param format string - the desired format of the date - @param date Date - the date value to format - @param settings Object - attributes include: - dayNamesShort string[7] - abbreviated names of the days from Sunday (optional) - dayNames string[7] - names of the days from Sunday (optional) - monthNamesShort string[12] - abbreviated names of the months (optional) - monthNames string[12] - names of the months (optional) - @return string - the date in the above format */ - formatDate: function (format, date, settings) { - if (!date) - return ''; - var dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort; - var dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames; - var monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort; - var monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames; - // Check whether a format character is doubled - var lookAhead = function(match) { - var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) == match); - if (matches) - iFormat++; - return matches; - }; - // Format a number, with leading zero if necessary - var formatNumber = function(match, value, len) { - var num = '' + value; - if (lookAhead(match)) - while (num.length < len) - num = '0' + num; - return num; - }; - // Format a name, short or long as requested - var formatName = function(match, value, shortNames, longNames) { - return (lookAhead(match) ? longNames[value] : shortNames[value]); - }; - var output = ''; - var literal = false; - if (date) - for (var iFormat = 0; iFormat < format.length; iFormat++) { - if (literal) - if (format.charAt(iFormat) == "'" && !lookAhead("'")) - literal = false; - else - output += format.charAt(iFormat); - else - switch (format.charAt(iFormat)) { - case 'd': - output += formatNumber('d', date.getDate(), 2); - break; - case 'D': - output += formatName('D', date.getDay(), dayNamesShort, dayNames); - break; - case 'o': - output += formatNumber('o', - Math.round((new Date(date.getFullYear(), date.getMonth(), date.getDate()).getTime() - new Date(date.getFullYear(), 0, 0).getTime()) / 86400000), 3); - break; - case 'm': - output += formatNumber('m', date.getMonth() + 1, 2); - break; - case 'M': - output += formatName('M', date.getMonth(), monthNamesShort, monthNames); - break; - case 'y': - output += (lookAhead('y') ? date.getFullYear() : - (date.getYear() % 100 < 10 ? '0' : '') + date.getYear() % 100); - break; - case '@': - output += date.getTime(); - break; - case '!': - output += date.getTime() * 10000 + this._ticksTo1970; - break; - case "'": - if (lookAhead("'")) - output += "'"; - else - literal = true; - break; - default: - output += format.charAt(iFormat); - } + //Let's determine the parent's offset + this.offset = this.element.offset(); + + //Initialize mouse events for interaction + this._mouseInit(); + + //We're ready to go + this.ready = true + + }, + + _destroy: function() { + this.element + .removeClass("ui-sortable ui-sortable-disabled"); + this._mouseDestroy(); + + for ( var i = this.items.length - 1; i >= 0; i-- ) + this.items[i].item.removeData(this.widgetName + "-item"); + + return this; + }, + + _setOption: function(key, value){ + if ( key === "disabled" ) { + this.options[ key ] = value; + + this.widget().toggleClass( "ui-sortable-disabled", !!value ); + } else { + // Don't call widget base _setOption for disable as it adds ui-state-disabled class + $.Widget.prototype._setOption.apply(this, arguments); + } + }, + + _mouseCapture: function(event, overrideHandle) { + var that = this; + + if (this.reverting) { + return false; + } + + if(this.options.disabled || this.options.type == 'static') return false; + + //We have to refresh the items data once first + this._refreshItems(event); + + //Find out if the clicked node (or one of its parents) is a actual item in this.items + var currentItem = null, nodes = $(event.target).parents().each(function() { + if($.data(this, that.widgetName + '-item') == that) { + currentItem = $(this); + return false; } - return output; + }); + if($.data(event.target, that.widgetName + '-item') == that) currentItem = $(event.target); + + if(!currentItem) return false; + if(this.options.handle && !overrideHandle) { + var validHandle = false; + + $(this.options.handle, currentItem).find("*").andSelf().each(function() { if(this == event.target) validHandle = true; }); + if(!validHandle) return false; + } + + this.currentItem = currentItem; + this._removeCurrentsFromItems(); + return true; + }, - /* Extract all possible characters from the date format. */ - _possibleChars: function (format) { - var chars = ''; - var literal = false; - // Check whether a format character is doubled - var lookAhead = function(match) { - var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) == match); - if (matches) - iFormat++; - return matches; + _mouseStart: function(event, overrideHandle, noActivation) { + + var o = this.options; + this.currentContainer = this; + + //We only need to call refreshPositions, because the refreshItems call has been moved to mouseCapture + this.refreshPositions(); + + //Create and append the visible helper + this.helper = this._createHelper(event); + + //Cache the helper size + this._cacheHelperProportions(); + + /* + * - Position generation - + * This block generates everything position related - it's the core of draggables. + */ + + //Cache the margins of the original element + this._cacheMargins(); + + //Get the next scrolling parent + this.scrollParent = this.helper.scrollParent(); + + //The element's absolute position on the page minus margins + this.offset = this.currentItem.offset(); + this.offset = { + top: this.offset.top - this.margins.top, + left: this.offset.left - this.margins.left }; - for (var iFormat = 0; iFormat < format.length; iFormat++) - if (literal) - if (format.charAt(iFormat) == "'" && !lookAhead("'")) - literal = false; - else - chars += format.charAt(iFormat); - else - switch (format.charAt(iFormat)) { - case 'd': case 'm': case 'y': case '@': - chars += '0123456789'; - break; - case 'D': case 'M': - return null; // Accept anything - case "'": - if (lookAhead("'")) - chars += "'"; - else - literal = true; - break; - default: - chars += format.charAt(iFormat); - } - return chars; - }, - /* Get a setting value, defaulting if necessary. */ - _get: function(inst, name) { - return inst.settings[name] !== undefined ? - inst.settings[name] : this._defaults[name]; - }, + $.extend(this.offset, { + click: { //Where the click happened, relative to the element + left: event.pageX - this.offset.left, + top: event.pageY - this.offset.top + }, + parent: this._getParentOffset(), + relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper + }); - /* Parse existing date and initialise date picker. */ - _setDateFromField: function(inst, noDefault) { - if (inst.input.val() == inst.lastVal) { - return; + // Only after we got the offset, we can change the helper's position to absolute + // TODO: Still need to figure out a way to make relative sorting possible + this.helper.css("position", "absolute"); + this.cssPosition = this.helper.css("position"); + + //Generate the original position + this.originalPosition = this._generatePosition(event); + this.originalPageX = event.pageX; + this.originalPageY = event.pageY; + + //Adjust the mouse offset relative to the helper if 'cursorAt' is supplied + (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt)); + + //Cache the former DOM position + this.domPosition = { prev: this.currentItem.prev()[0], parent: this.currentItem.parent()[0] }; + + //If the helper is not the original, hide the original so it's not playing any role during the drag, won't cause anything bad this way + if(this.helper[0] != this.currentItem[0]) { + this.currentItem.hide(); } - var dateFormat = this._get(inst, 'dateFormat'); - var dates = inst.lastVal = inst.input ? inst.input.val() : null; - var date, defaultDate; - date = defaultDate = this._getDefaultDate(inst); - var settings = this._getFormatConfig(inst); - try { - date = this.parseDate(dateFormat, dates, settings) || defaultDate; - } catch (event) { - this.log(event); - dates = (noDefault ? '' : dates); + + //Create the placeholder + this._createPlaceholder(); + + //Set a containment if given in the options + if(o.containment) + this._setContainment(); + + if(o.cursor) { // cursor option + if ($('body').css("cursor")) this._storedCursor = $('body').css("cursor"); + $('body').css("cursor", o.cursor); } - inst.selectedDay = date.getDate(); - inst.drawMonth = inst.selectedMonth = date.getMonth(); - inst.drawYear = inst.selectedYear = date.getFullYear(); - inst.currentDay = (dates ? date.getDate() : 0); - inst.currentMonth = (dates ? date.getMonth() : 0); - inst.currentYear = (dates ? date.getFullYear() : 0); - this._adjustInstDate(inst); - }, - /* Retrieve the default date shown on opening. */ - _getDefaultDate: function(inst) { - return this._restrictMinMax(inst, - this._determineDate(inst, this._get(inst, 'defaultDate'), new Date())); - }, + if(o.opacity) { // opacity option + if (this.helper.css("opacity")) this._storedOpacity = this.helper.css("opacity"); + this.helper.css("opacity", o.opacity); + } - /* A date may be specified as an exact value or a relative one. */ - _determineDate: function(inst, date, defaultDate) { - var offsetNumeric = function(offset) { - var date = new Date(); - date.setDate(date.getDate() + offset); - return date; - }; - var offsetString = function(offset) { - try { - return $.datepicker.parseDate($.datepicker._get(inst, 'dateFormat'), - offset, $.datepicker._getFormatConfig(inst)); - } - catch (e) { - // Ignore - } - var date = (offset.toLowerCase().match(/^c/) ? - $.datepicker._getDate(inst) : null) || new Date(); - var year = date.getFullYear(); - var month = date.getMonth(); - var day = date.getDate(); - var pattern = /([+-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g; - var matches = pattern.exec(offset); - while (matches) { - switch (matches[2] || 'd') { - case 'd' : case 'D' : - day += parseInt(matches[1],10); break; - case 'w' : case 'W' : - day += parseInt(matches[1],10) * 7; break; - case 'm' : case 'M' : - month += parseInt(matches[1],10); - day = Math.min(day, $.datepicker._getDaysInMonth(year, month)); - break; - case 'y': case 'Y' : - year += parseInt(matches[1],10); - day = Math.min(day, $.datepicker._getDaysInMonth(year, month)); - break; - } - matches = pattern.exec(offset); - } - return new Date(year, month, day); - }; - var newDate = (date == null || date === '' ? defaultDate : (typeof date == 'string' ? offsetString(date) : - (typeof date == 'number' ? (isNaN(date) ? defaultDate : offsetNumeric(date)) : new Date(date.getTime())))); - newDate = (newDate && newDate.toString() == 'Invalid Date' ? defaultDate : newDate); - if (newDate) { - newDate.setHours(0); - newDate.setMinutes(0); - newDate.setSeconds(0); - newDate.setMilliseconds(0); + if(o.zIndex) { // zIndex option + if (this.helper.css("zIndex")) this._storedZIndex = this.helper.css("zIndex"); + this.helper.css("zIndex", o.zIndex); } - return this._daylightSavingAdjust(newDate); - }, - /* Handle switch to/from daylight saving. - Hours may be non-zero on daylight saving cut-over: - > 12 when midnight changeover, but then cannot generate - midnight datetime, so jump to 1AM, otherwise reset. - @param date (Date) the date to check - @return (Date) the corrected date */ - _daylightSavingAdjust: function(date) { - if (!date) return null; - date.setHours(date.getHours() > 12 ? date.getHours() + 2 : 0); - return date; - }, + //Prepare scrolling + if(this.scrollParent[0] != document && this.scrollParent[0].tagName != 'HTML') + this.overflowOffset = this.scrollParent.offset(); - /* Set the date(s) directly. */ - _setDate: function(inst, date, noChange) { - var clear = !date; - var origMonth = inst.selectedMonth; - var origYear = inst.selectedYear; - var newDate = this._restrictMinMax(inst, this._determineDate(inst, date, new Date())); - inst.selectedDay = inst.currentDay = newDate.getDate(); - inst.drawMonth = inst.selectedMonth = inst.currentMonth = newDate.getMonth(); - inst.drawYear = inst.selectedYear = inst.currentYear = newDate.getFullYear(); - if ((origMonth != inst.selectedMonth || origYear != inst.selectedYear) && !noChange) - this._notifyChange(inst); - this._adjustInstDate(inst); - if (inst.input) { - inst.input.val(clear ? '' : this._formatDate(inst)); + //Call callbacks + this._trigger("start", event, this._uiHash()); + + //Recache the helper size + if(!this._preserveHelperProportions) + this._cacheHelperProportions(); + + + //Post 'activate' events to possible containers + if(!noActivation) { + for (var i = this.containers.length - 1; i >= 0; i--) { this.containers[i]._trigger("activate", event, this._uiHash(this)); } } - }, - /* Retrieve the date(s) directly. */ - _getDate: function(inst) { - var startDate = (!inst.currentYear || (inst.input && inst.input.val() == '') ? null : - this._daylightSavingAdjust(new Date( - inst.currentYear, inst.currentMonth, inst.currentDay))); - return startDate; + //Prepare possible droppables + if($.ui.ddmanager) + $.ui.ddmanager.current = this; + + if ($.ui.ddmanager && !o.dropBehaviour) + $.ui.ddmanager.prepareOffsets(this, event); + + this.dragging = true; + + this.helper.addClass("ui-sortable-helper"); + this._mouseDrag(event); //Execute the drag once - this causes the helper not to be visible before getting its correct position + return true; + }, - /* Generate the HTML for the current state of the date picker. */ - _generateHTML: function(inst) { - var today = new Date(); - today = this._daylightSavingAdjust( - new Date(today.getFullYear(), today.getMonth(), today.getDate())); // clear time - var isRTL = this._get(inst, 'isRTL'); - var showButtonPanel = this._get(inst, 'showButtonPanel'); - var hideIfNoPrevNext = this._get(inst, 'hideIfNoPrevNext'); - var navigationAsDateFormat = this._get(inst, 'navigationAsDateFormat'); - var numMonths = this._getNumberOfMonths(inst); - var showCurrentAtPos = this._get(inst, 'showCurrentAtPos'); - var stepMonths = this._get(inst, 'stepMonths'); - var isMultiMonth = (numMonths[0] != 1 || numMonths[1] != 1); - var currentDate = this._daylightSavingAdjust((!inst.currentDay ? new Date(9999, 9, 9) : - new Date(inst.currentYear, inst.currentMonth, inst.currentDay))); - var minDate = this._getMinMaxDate(inst, 'min'); - var maxDate = this._getMinMaxDate(inst, 'max'); - var drawMonth = inst.drawMonth - showCurrentAtPos; - var drawYear = inst.drawYear; - if (drawMonth < 0) { - drawMonth += 12; - drawYear--; + _mouseDrag: function(event) { + + //Compute the helpers position + this.position = this._generatePosition(event); + this.positionAbs = this._convertPositionTo("absolute"); + + if (!this.lastPositionAbs) { + this.lastPositionAbs = this.positionAbs; } - if (maxDate) { - var maxDraw = this._daylightSavingAdjust(new Date(maxDate.getFullYear(), - maxDate.getMonth() - (numMonths[0] * numMonths[1]) + 1, maxDate.getDate())); - maxDraw = (minDate && maxDraw < minDate ? minDate : maxDraw); - while (this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1)) > maxDraw) { - drawMonth--; - if (drawMonth < 0) { - drawMonth = 11; - drawYear--; - } + + //Do scrolling + if(this.options.scroll) { + var o = this.options, scrolled = false; + if(this.scrollParent[0] != document && this.scrollParent[0].tagName != 'HTML') { + + if((this.overflowOffset.top + this.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity) + this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop + o.scrollSpeed; + else if(event.pageY - this.overflowOffset.top < o.scrollSensitivity) + this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop - o.scrollSpeed; + + if((this.overflowOffset.left + this.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity) + this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft + o.scrollSpeed; + else if(event.pageX - this.overflowOffset.left < o.scrollSensitivity) + this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft - o.scrollSpeed; + + } else { + + if(event.pageY - $(document).scrollTop() < o.scrollSensitivity) + scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed); + else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity) + scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed); + + if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity) + scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed); + else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity) + scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed); + } + + if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) + $.ui.ddmanager.prepareOffsets(this, event); } - inst.drawMonth = drawMonth; - inst.drawYear = drawYear; - var prevText = this._get(inst, 'prevText'); - prevText = (!navigationAsDateFormat ? prevText : this.formatDate(prevText, - this._daylightSavingAdjust(new Date(drawYear, drawMonth - stepMonths, 1)), - this._getFormatConfig(inst))); - var prev = (this._canAdjustMonth(inst, -1, drawYear, drawMonth) ? - '' + prevText + '' : - (hideIfNoPrevNext ? '' : '' + prevText + '')); - var nextText = this._get(inst, 'nextText'); - nextText = (!navigationAsDateFormat ? nextText : this.formatDate(nextText, - this._daylightSavingAdjust(new Date(drawYear, drawMonth + stepMonths, 1)), - this._getFormatConfig(inst))); - var next = (this._canAdjustMonth(inst, +1, drawYear, drawMonth) ? - '' + nextText + '' : - (hideIfNoPrevNext ? '' : '' + nextText + '')); - var currentText = this._get(inst, 'currentText'); - var gotoDate = (this._get(inst, 'gotoCurrent') && inst.currentDay ? currentDate : today); - currentText = (!navigationAsDateFormat ? currentText : - this.formatDate(currentText, gotoDate, this._getFormatConfig(inst))); - var controls = (!inst.inline ? '' : ''); - var buttonPanel = (showButtonPanel) ? '
        ' + (isRTL ? controls : '') + - (this._isInRange(inst, gotoDate) ? '' : '') + (isRTL ? '' : controls) + '
        ' : ''; - var firstDay = parseInt(this._get(inst, 'firstDay'),10); - firstDay = (isNaN(firstDay) ? 0 : firstDay); - var showWeek = this._get(inst, 'showWeek'); - var dayNames = this._get(inst, 'dayNames'); - var dayNamesShort = this._get(inst, 'dayNamesShort'); - var dayNamesMin = this._get(inst, 'dayNamesMin'); - var monthNames = this._get(inst, 'monthNames'); - var monthNamesShort = this._get(inst, 'monthNamesShort'); - var beforeShowDay = this._get(inst, 'beforeShowDay'); - var showOtherMonths = this._get(inst, 'showOtherMonths'); - var selectOtherMonths = this._get(inst, 'selectOtherMonths'); - var calculateWeek = this._get(inst, 'calculateWeek') || this.iso8601Week; - var defaultDate = this._getDefaultDate(inst); - var html = ''; - for (var row = 0; row < numMonths[0]; row++) { - var group = ''; - this.maxRows = 4; - for (var col = 0; col < numMonths[1]; col++) { - var selectedDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, inst.selectedDay)); - var cornerClass = ' ui-corner-all'; - var calender = ''; - if (isMultiMonth) { - calender += '
        '; - } - calender += '
        ' + - (/all|left/.test(cornerClass) && row == 0 ? (isRTL ? next : prev) : '') + - (/all|right/.test(cornerClass) && row == 0 ? (isRTL ? prev : next) : '') + - this._generateMonthYearHeader(inst, drawMonth, drawYear, minDate, maxDate, - row > 0 || col > 0, monthNames, monthNamesShort) + // draw month headers - '
        ' + - ''; - var thead = (showWeek ? '' : ''); - for (var dow = 0; dow < 7; dow++) { // days of the week - var day = (dow + firstDay) % 7; - thead += '= 5 ? ' class="ui-datepicker-week-end"' : '') + '>' + - '' + dayNamesMin[day] + ''; - } - calender += thead + ''; - var daysInMonth = this._getDaysInMonth(drawYear, drawMonth); - if (drawYear == inst.selectedYear && drawMonth == inst.selectedMonth) - inst.selectedDay = Math.min(inst.selectedDay, daysInMonth); - var leadDays = (this._getFirstDayOfMonth(drawYear, drawMonth) - firstDay + 7) % 7; - var curRows = Math.ceil((leadDays + daysInMonth) / 7); // calculate the number of rows to generate - var numRows = (isMultiMonth ? this.maxRows > curRows ? this.maxRows : curRows : curRows); //If multiple months, use the higher number of rows (see #7043) - this.maxRows = numRows; - var printDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1 - leadDays)); - for (var dRow = 0; dRow < numRows; dRow++) { // create date picker rows - calender += ''; - var tbody = (!showWeek ? '' : ''); - for (var dow = 0; dow < 7; dow++) { // create date picker days - var daySettings = (beforeShowDay ? - beforeShowDay.apply((inst.input ? inst.input[0] : null), [printDate]) : [true, '']); - var otherMonth = (printDate.getMonth() != drawMonth); - var unselectable = (otherMonth && !selectOtherMonths) || !daySettings[0] || - (minDate && printDate < minDate) || (maxDate && printDate > maxDate); - tbody += ''; // display selectable date - printDate.setDate(printDate.getDate() + 1); - printDate = this._daylightSavingAdjust(printDate); - } - calender += tbody + ''; - } - drawMonth++; - if (drawMonth > 11) { - drawMonth = 0; - drawYear++; + + //Regenerate the absolute position used for position checks + this.positionAbs = this._convertPositionTo("absolute"); + + //Set the helper position + if(!this.options.axis || this.options.axis != "y") this.helper[0].style.left = this.position.left+'px'; + if(!this.options.axis || this.options.axis != "x") this.helper[0].style.top = this.position.top+'px'; + + //Rearrange + for (var i = this.items.length - 1; i >= 0; i--) { + + //Cache variables and intersection, continue if no intersection + var item = this.items[i], itemElement = item.item[0], intersection = this._intersectsWithPointer(item); + if (!intersection) continue; + + // Only put the placeholder inside the current Container, skip all + // items form other containers. This works because when moving + // an item from one container to another the + // currentContainer is switched before the placeholder is moved. + // + // Without this moving items in "sub-sortables" can cause the placeholder to jitter + // beetween the outer and inner container. + if (item.instance !== this.currentContainer) continue; + + if (itemElement != this.currentItem[0] //cannot intersect with itself + && this.placeholder[intersection == 1 ? "next" : "prev"]()[0] != itemElement //no useless actions that have been done before + && !$.contains(this.placeholder[0], itemElement) //no action if the item moved is the parent of the item checked + && (this.options.type == 'semi-dynamic' ? !$.contains(this.element[0], itemElement) : true) + //&& itemElement.parentNode == this.placeholder[0].parentNode // only rearrange items within the same container + ) { + + this.direction = intersection == 1 ? "down" : "up"; + + if (this.options.tolerance == "pointer" || this._intersectsWithSides(item)) { + this._rearrange(event, item); + } else { + break; } - calender += '
        ' + this._get(inst, 'weekHeader') + '
        ' + - this._get(inst, 'calculateWeek')(printDate) + '' + // actions - (otherMonth && !showOtherMonths ? ' ' : // display for other months - (unselectable ? '' + printDate.getDate() + '' : '' + printDate.getDate() + '')) + '
        ' + (isMultiMonth ? '
        ' + - ((numMonths[0] > 0 && col == numMonths[1]-1) ? '
        ' : '') : ''); - group += calender; + + this._trigger("change", event, this._uiHash()); + break; } - html += group; } - html += buttonPanel + ($.browser.msie && parseInt($.browser.version,10) < 7 && !inst.inline ? - '' : ''); - inst._keyEvent = false; - return html; + + //Post events to containers + this._contactContainers(event); + + //Interconnect with droppables + if($.ui.ddmanager) $.ui.ddmanager.drag(this, event); + + //Call callbacks + this._trigger('sort', event, this._uiHash()); + + this.lastPositionAbs = this.positionAbs; + return false; + }, - /* Generate the month and year header. */ - _generateMonthYearHeader: function(inst, drawMonth, drawYear, minDate, maxDate, - secondary, monthNames, monthNamesShort) { - var changeMonth = this._get(inst, 'changeMonth'); - var changeYear = this._get(inst, 'changeYear'); - var showMonthAfterYear = this._get(inst, 'showMonthAfterYear'); - var html = '
        '; - var monthHtml = ''; - // month selection - if (secondary || !changeMonth) - monthHtml += '' + monthNames[drawMonth] + ''; - else { - var inMinYear = (minDate && minDate.getFullYear() == drawYear); - var inMaxYear = (maxDate && maxDate.getFullYear() == drawYear); - monthHtml += ''; + _mouseStop: function(event, noPropagation) { + + if(!event) return; + + //If we are using droppables, inform the manager about the drop + if ($.ui.ddmanager && !this.options.dropBehaviour) + $.ui.ddmanager.drop(this, event); + + if(this.options.revert) { + var that = this; + var cur = this.placeholder.offset(); + + this.reverting = true; + + $(this.helper).animate({ + left: cur.left - this.offset.parent.left - this.margins.left + (this.offsetParent[0] == document.body ? 0 : this.offsetParent[0].scrollLeft), + top: cur.top - this.offset.parent.top - this.margins.top + (this.offsetParent[0] == document.body ? 0 : this.offsetParent[0].scrollTop) + }, parseInt(this.options.revert, 10) || 500, function() { + that._clear(event); + }); + } else { + this._clear(event, noPropagation); } - if (!showMonthAfterYear) - html += monthHtml + (secondary || !(changeMonth && changeYear) ? ' ' : ''); - // year selection - if ( !inst.yearshtml ) { - inst.yearshtml = ''; - if (secondary || !changeYear) - html += '' + drawYear + ''; - else { - // determine range of years to display - var years = this._get(inst, 'yearRange').split(':'); - var thisYear = new Date().getFullYear(); - var determineYear = function(value) { - var year = (value.match(/c[+-].*/) ? drawYear + parseInt(value.substring(1), 10) : - (value.match(/[+-].*/) ? thisYear + parseInt(value, 10) : - parseInt(value, 10))); - return (isNaN(year) ? thisYear : year); - }; - var year = determineYear(years[0]); - var endYear = Math.max(year, determineYear(years[1] || '')); - year = (minDate ? Math.max(year, minDate.getFullYear()) : year); - endYear = (maxDate ? Math.min(endYear, maxDate.getFullYear()) : endYear); - inst.yearshtml += ''; - - html += inst.yearshtml; - inst.yearshtml = null; } + } - html += this._get(inst, 'yearSuffix'); - if (showMonthAfterYear) - html += (secondary || !(changeMonth && changeYear) ? ' ' : '') + monthHtml; - html += '
        '; // Close datepicker_header - return html; - }, - /* Adjust one of the date sub-fields. */ - _adjustInstDate: function(inst, offset, period) { - var year = inst.drawYear + (period == 'Y' ? offset : 0); - var month = inst.drawMonth + (period == 'M' ? offset : 0); - var day = Math.min(inst.selectedDay, this._getDaysInMonth(year, month)) + - (period == 'D' ? offset : 0); - var date = this._restrictMinMax(inst, - this._daylightSavingAdjust(new Date(year, month, day))); - inst.selectedDay = date.getDate(); - inst.drawMonth = inst.selectedMonth = date.getMonth(); - inst.drawYear = inst.selectedYear = date.getFullYear(); - if (period == 'M' || period == 'Y') - this._notifyChange(inst); + if (this.placeholder) { + //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node! + if(this.placeholder[0].parentNode) this.placeholder[0].parentNode.removeChild(this.placeholder[0]); + if(this.options.helper != "original" && this.helper && this.helper[0].parentNode) this.helper.remove(); + + $.extend(this, { + helper: null, + dragging: false, + reverting: false, + _noFinalSort: null + }); + + if(this.domPosition.prev) { + $(this.domPosition.prev).after(this.currentItem); + } else { + $(this.domPosition.parent).prepend(this.currentItem); + } + } + + return this; + }, - /* Ensure a date is within any min/max bounds. */ - _restrictMinMax: function(inst, date) { - var minDate = this._getMinMaxDate(inst, 'min'); - var maxDate = this._getMinMaxDate(inst, 'max'); - var newDate = (minDate && date < minDate ? minDate : date); - newDate = (maxDate && newDate > maxDate ? maxDate : newDate); - return newDate; + serialize: function(o) { + + var items = this._getItemsAsjQuery(o && o.connected); + var str = []; o = o || {}; + + $(items).each(function() { + var res = ($(o.item || this).attr(o.attribute || 'id') || '').match(o.expression || (/(.+)[-=_](.+)/)); + if(res) str.push((o.key || res[1]+'[]')+'='+(o.key && o.expression ? res[1] : res[2])); + }); + + if(!str.length && o.key) { + str.push(o.key + '='); + } + + return str.join('&'); + }, - /* Notify change of month/year. */ - _notifyChange: function(inst) { - var onChange = this._get(inst, 'onChangeMonthYear'); - if (onChange) - onChange.apply((inst.input ? inst.input[0] : null), - [inst.selectedYear, inst.selectedMonth + 1, inst]); + toArray: function(o) { + + var items = this._getItemsAsjQuery(o && o.connected); + var ret = []; o = o || {}; + + items.each(function() { ret.push($(o.item || this).attr(o.attribute || 'id') || ''); }); + return ret; + }, - /* Determine the number of months to show. */ - _getNumberOfMonths: function(inst) { - var numMonths = this._get(inst, 'numberOfMonths'); - return (numMonths == null ? [1, 1] : (typeof numMonths == 'number' ? [1, numMonths] : numMonths)); + /* Be careful with the following core functions */ + _intersectsWith: function(item) { + + var x1 = this.positionAbs.left, + x2 = x1 + this.helperProportions.width, + y1 = this.positionAbs.top, + y2 = y1 + this.helperProportions.height; + + var l = item.left, + r = l + item.width, + t = item.top, + b = t + item.height; + + var dyClick = this.offset.click.top, + dxClick = this.offset.click.left; + + var isOverElement = (y1 + dyClick) > t && (y1 + dyClick) < b && (x1 + dxClick) > l && (x1 + dxClick) < r; + + if( this.options.tolerance == "pointer" + || this.options.forcePointerForContainers + || (this.options.tolerance != "pointer" && this.helperProportions[this.floating ? 'width' : 'height'] > item[this.floating ? 'width' : 'height']) + ) { + return isOverElement; + } else { + + return (l < x1 + (this.helperProportions.width / 2) // Right Half + && x2 - (this.helperProportions.width / 2) < r // Left Half + && t < y1 + (this.helperProportions.height / 2) // Bottom Half + && y2 - (this.helperProportions.height / 2) < b ); // Top Half + + } }, - /* Determine the current maximum date - ensure no time components are set. */ - _getMinMaxDate: function(inst, minMax) { - return this._determineDate(inst, this._get(inst, minMax + 'Date'), null); + _intersectsWithPointer: function(item) { + + var isOverElementHeight = (this.options.axis === 'x') || $.ui.isOverAxis(this.positionAbs.top + this.offset.click.top, item.top, item.height), + isOverElementWidth = (this.options.axis === 'y') || $.ui.isOverAxis(this.positionAbs.left + this.offset.click.left, item.left, item.width), + isOverElement = isOverElementHeight && isOverElementWidth, + verticalDirection = this._getDragVerticalDirection(), + horizontalDirection = this._getDragHorizontalDirection(); + + if (!isOverElement) + return false; + + return this.floating ? + ( ((horizontalDirection && horizontalDirection == "right") || verticalDirection == "down") ? 2 : 1 ) + : ( verticalDirection && (verticalDirection == "down" ? 2 : 1) ); + }, - /* Find the number of days in a given month. */ - _getDaysInMonth: function(year, month) { - return 32 - this._daylightSavingAdjust(new Date(year, month, 32)).getDate(); + _intersectsWithSides: function(item) { + + var isOverBottomHalf = $.ui.isOverAxis(this.positionAbs.top + this.offset.click.top, item.top + (item.height/2), item.height), + isOverRightHalf = $.ui.isOverAxis(this.positionAbs.left + this.offset.click.left, item.left + (item.width/2), item.width), + verticalDirection = this._getDragVerticalDirection(), + horizontalDirection = this._getDragHorizontalDirection(); + + if (this.floating && horizontalDirection) { + return ((horizontalDirection == "right" && isOverRightHalf) || (horizontalDirection == "left" && !isOverRightHalf)); + } else { + return verticalDirection && ((verticalDirection == "down" && isOverBottomHalf) || (verticalDirection == "up" && !isOverBottomHalf)); + } + }, - /* Find the day of the week of the first of a month. */ - _getFirstDayOfMonth: function(year, month) { - return new Date(year, month, 1).getDay(); + _getDragVerticalDirection: function() { + var delta = this.positionAbs.top - this.lastPositionAbs.top; + return delta != 0 && (delta > 0 ? "down" : "up"); }, - /* Determines if we should allow a "next/prev" month display change. */ - _canAdjustMonth: function(inst, offset, curYear, curMonth) { - var numMonths = this._getNumberOfMonths(inst); - var date = this._daylightSavingAdjust(new Date(curYear, - curMonth + (offset < 0 ? offset : numMonths[0] * numMonths[1]), 1)); - if (offset < 0) - date.setDate(this._getDaysInMonth(date.getFullYear(), date.getMonth())); - return this._isInRange(inst, date); + _getDragHorizontalDirection: function() { + var delta = this.positionAbs.left - this.lastPositionAbs.left; + return delta != 0 && (delta > 0 ? "right" : "left"); }, - /* Is the given date in the accepted range? */ - _isInRange: function(inst, date) { - var minDate = this._getMinMaxDate(inst, 'min'); - var maxDate = this._getMinMaxDate(inst, 'max'); - return ((!minDate || date.getTime() >= minDate.getTime()) && - (!maxDate || date.getTime() <= maxDate.getTime())); + refresh: function(event) { + this._refreshItems(event); + this.refreshPositions(); + return this; }, - /* Provide the configuration settings for formatting/parsing. */ - _getFormatConfig: function(inst) { - var shortYearCutoff = this._get(inst, 'shortYearCutoff'); - shortYearCutoff = (typeof shortYearCutoff != 'string' ? shortYearCutoff : - new Date().getFullYear() % 100 + parseInt(shortYearCutoff, 10)); - return {shortYearCutoff: shortYearCutoff, - dayNamesShort: this._get(inst, 'dayNamesShort'), dayNames: this._get(inst, 'dayNames'), - monthNamesShort: this._get(inst, 'monthNamesShort'), monthNames: this._get(inst, 'monthNames')}; + _connectWith: function() { + var options = this.options; + return options.connectWith.constructor == String + ? [options.connectWith] + : options.connectWith; }, - /* Format the given date for display. */ - _formatDate: function(inst, day, month, year) { - if (!day) { - inst.currentDay = inst.selectedDay; - inst.currentMonth = inst.selectedMonth; - inst.currentYear = inst.selectedYear; - } - var date = (day ? (typeof day == 'object' ? day : - this._daylightSavingAdjust(new Date(year, month, day))) : - this._daylightSavingAdjust(new Date(inst.currentYear, inst.currentMonth, inst.currentDay))); - return this.formatDate(this._get(inst, 'dateFormat'), date, this._getFormatConfig(inst)); - } -}); + _getItemsAsjQuery: function(connected) { -/* - * Bind hover events for datepicker elements. - * Done via delegate so the binding only occurs once in the lifetime of the parent div. - * Global instActive, set by _updateDatepicker allows the handlers to find their way back to the active picker. - */ -function bindHover(dpDiv) { - var selector = 'button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a'; - return dpDiv.bind('mouseout', function(event) { - var elem = $( event.target ).closest( selector ); - if ( !elem.length ) { - return; - } - elem.removeClass( "ui-state-hover ui-datepicker-prev-hover ui-datepicker-next-hover" ); - }) - .bind('mouseover', function(event) { - var elem = $( event.target ).closest( selector ); - if ($.datepicker._isDisabledDatepicker( instActive.inline ? dpDiv.parent()[0] : instActive.input[0]) || - !elem.length ) { - return; - } - elem.parents('.ui-datepicker-calendar').find('a').removeClass('ui-state-hover'); - elem.addClass('ui-state-hover'); - if (elem.hasClass('ui-datepicker-prev')) elem.addClass('ui-datepicker-prev-hover'); - if (elem.hasClass('ui-datepicker-next')) elem.addClass('ui-datepicker-next-hover'); - }); -} + var items = []; + var queries = []; + var connectWith = this._connectWith(); -/* jQuery extend now ignores nulls! */ -function extendRemove(target, props) { - $.extend(target, props); - for (var name in props) - if (props[name] == null || props[name] == undefined) - target[name] = props[name]; - return target; -}; + if(connectWith && connected) { + for (var i = connectWith.length - 1; i >= 0; i--){ + var cur = $(connectWith[i]); + for (var j = cur.length - 1; j >= 0; j--){ + var inst = $.data(cur[j], this.widgetName); + if(inst && inst != this && !inst.options.disabled) { + queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element) : $(inst.options.items, inst.element).not(".ui-sortable-helper").not('.ui-sortable-placeholder'), inst]); + } + }; + }; + } -/* Determine whether an object is an array. */ -function isArray(a) { - return (a && (($.browser.safari && typeof a == 'object' && a.length) || - (a.constructor && a.constructor.toString().match(/\Array\(\)/)))); -}; + queries.push([$.isFunction(this.options.items) ? this.options.items.call(this.element, null, { options: this.options, item: this.currentItem }) : $(this.options.items, this.element).not(".ui-sortable-helper").not('.ui-sortable-placeholder'), this]); + + for (var i = queries.length - 1; i >= 0; i--){ + queries[i][0].each(function() { + items.push(this); + }); + }; -/* Invoke the datepicker functionality. - @param options string - a command, optionally followed by additional parameters or - Object - settings for attaching new datepicker functionality - @return jQuery object */ -$.fn.datepicker = function(options){ - - /* Verify an empty collection wasn't passed - Fixes #6976 */ - if ( !this.length ) { - return this; - } - - /* Initialise the date picker. */ - if (!$.datepicker.initialized) { - $(document).mousedown($.datepicker._checkExternalClick). - find('body').append($.datepicker.dpDiv); - $.datepicker.initialized = true; - } + return $(items); - var otherArgs = Array.prototype.slice.call(arguments, 1); - if (typeof options == 'string' && (options == 'isDisabled' || options == 'getDate' || options == 'widget')) - return $.datepicker['_' + options + 'Datepicker']. - apply($.datepicker, [this[0]].concat(otherArgs)); - if (options == 'option' && arguments.length == 2 && typeof arguments[1] == 'string') - return $.datepicker['_' + options + 'Datepicker']. - apply($.datepicker, [this[0]].concat(otherArgs)); - return this.each(function() { - typeof options == 'string' ? - $.datepicker['_' + options + 'Datepicker']. - apply($.datepicker, [this].concat(otherArgs)) : - $.datepicker._attachDatepicker(this, options); - }); -}; + }, -$.datepicker = new Datepicker(); // singleton instance -$.datepicker.initialized = false; -$.datepicker.uuid = new Date().getTime(); -$.datepicker.version = "1.8.16"; + _removeCurrentsFromItems: function() { -// Workaround for #4055 -// Add another global to avoid noConflict issues with inline event handlers -window['DP_jQuery_' + dpuuid] = $; + var list = this.currentItem.find(":data(" + this.widgetName + "-item)"); -})(jQuery); -/* - * jQuery UI Dialog 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Dialog - * - * Depends: - * jquery.ui.core.js - * jquery.ui.widget.js - * jquery.ui.button.js - * jquery.ui.draggable.js - * jquery.ui.mouse.js - * jquery.ui.position.js - * jquery.ui.resizable.js - */ -(function( $, undefined ) { + this.items = $.grep(this.items, function (item) { + for (var j=0; j < list.length; j++) { + if(list[j] == item.item[0]) + return false; + }; + return true; + }); -var uiDialogClasses = - 'ui-dialog ' + - 'ui-widget ' + - 'ui-widget-content ' + - 'ui-corner-all ', - sizeRelatedOptions = { - buttons: true, - height: true, - maxHeight: true, - maxWidth: true, - minHeight: true, - minWidth: true, - width: true - }, - resizableRelatedOptions = { - maxHeight: true, - maxWidth: true, - minHeight: true, - minWidth: true }, - // support for jQuery 1.3.2 - handle common attrFn methods for dialog - attrFn = $.attrFn || { - val: true, - css: true, - html: true, - text: true, - data: true, - width: true, - height: true, - offset: true, - click: true - }; -$.widget("ui.dialog", { - options: { - autoOpen: true, - buttons: {}, - closeOnEscape: true, - closeText: 'close', - dialogClass: '', - draggable: true, - hide: null, - height: 'auto', - maxHeight: false, - maxWidth: false, - minHeight: 150, - minWidth: 150, - modal: false, - position: { - my: 'center', - at: 'center', - collision: 'fit', - // ensure that the titlebar is never outside the document - using: function(pos) { - var topOffset = $(this).css(pos).offset().top; - if (topOffset < 0) { - $(this).css('top', pos.top - topOffset); - } - } - }, - resizable: true, - show: null, - stack: true, - title: '', - width: 300, - zIndex: 1000 - }, + _refreshItems: function(event) { - _create: function() { - this.originalTitle = this.element.attr('title'); - // #5742 - .attr() might return a DOMElement - if ( typeof this.originalTitle !== "string" ) { - this.originalTitle = ""; + this.items = []; + this.containers = [this]; + var items = this.items; + var queries = [[$.isFunction(this.options.items) ? this.options.items.call(this.element[0], event, { item: this.currentItem }) : $(this.options.items, this.element), this]]; + var connectWith = this._connectWith(); + + if(connectWith && this.ready) { //Shouldn't be run the first time through due to massive slow-down + for (var i = connectWith.length - 1; i >= 0; i--){ + var cur = $(connectWith[i]); + for (var j = cur.length - 1; j >= 0; j--){ + var inst = $.data(cur[j], this.widgetName); + if(inst && inst != this && !inst.options.disabled) { + queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element[0], event, { item: this.currentItem }) : $(inst.options.items, inst.element), inst]); + this.containers.push(inst); + } + }; + }; } - this.options.title = this.options.title || this.originalTitle; - var self = this, - options = self.options, + for (var i = queries.length - 1; i >= 0; i--) { + var targetData = queries[i][1]; + var _queries = queries[i][0]; - title = options.title || ' ', - titleId = $.ui.dialog.getTitleId(self.element), + for (var j=0, queriesLength = _queries.length; j < queriesLength; j++) { + var item = $(_queries[j]); - uiDialog = (self.uiDialog = $('
        ')) - .appendTo(document.body) - .hide() - .addClass(uiDialogClasses + options.dialogClass) - .css({ - zIndex: options.zIndex - }) - // setting tabIndex makes the div focusable - // setting outline to 0 prevents a border on focus in Mozilla - .attr('tabIndex', -1).css('outline', 0).keydown(function(event) { - if (options.closeOnEscape && !event.isDefaultPrevented() && event.keyCode && - event.keyCode === $.ui.keyCode.ESCAPE) { - - self.close(event); - event.preventDefault(); - } - }) - .attr({ - role: 'dialog', - 'aria-labelledby': titleId - }) - .mousedown(function(event) { - self.moveToTop(false, event); - }), + item.data(this.widgetName + '-item', targetData); // Data for target checking (mouse manager) - uiDialogContent = self.element - .show() - .removeAttr('title') - .addClass( - 'ui-dialog-content ' + - 'ui-widget-content') - .appendTo(uiDialog), - - uiDialogTitlebar = (self.uiDialogTitlebar = $('
        ')) - .addClass( - 'ui-dialog-titlebar ' + - 'ui-widget-header ' + - 'ui-corner-all ' + - 'ui-helper-clearfix' - ) - .prependTo(uiDialog), - - uiDialogTitlebarClose = $('') - .addClass( - 'ui-dialog-titlebar-close ' + - 'ui-corner-all' - ) - .attr('role', 'button') - .hover( - function() { - uiDialogTitlebarClose.addClass('ui-state-hover'); - }, - function() { - uiDialogTitlebarClose.removeClass('ui-state-hover'); - } - ) - .focus(function() { - uiDialogTitlebarClose.addClass('ui-state-focus'); - }) - .blur(function() { - uiDialogTitlebarClose.removeClass('ui-state-focus'); - }) - .click(function(event) { - self.close(event); - return false; - }) - .appendTo(uiDialogTitlebar), + items.push({ + item: item, + instance: targetData, + width: 0, height: 0, + left: 0, top: 0 + }); + }; + }; - uiDialogTitlebarCloseText = (self.uiDialogTitlebarCloseText = $('')) - .addClass( - 'ui-icon ' + - 'ui-icon-closethick' - ) - .text(options.closeText) - .appendTo(uiDialogTitlebarClose), + }, - uiDialogTitle = $('') - .addClass('ui-dialog-title') - .attr('id', titleId) - .html(title) - .prependTo(uiDialogTitlebar); + refreshPositions: function(fast) { - //handling of deprecated beforeclose (vs beforeClose) option - //Ticket #4669 http://dev.jqueryui.com/ticket/4669 - //TODO: remove in 1.9pre - if ($.isFunction(options.beforeclose) && !$.isFunction(options.beforeClose)) { - options.beforeClose = options.beforeclose; + //This has to be redone because due to the item being moved out/into the offsetParent, the offsetParent's position will change + if(this.offsetParent && this.helper) { + this.offset.parent = this._getParentOffset(); } - uiDialogTitlebar.find("*").add(uiDialogTitlebar).disableSelection(); + for (var i = this.items.length - 1; i >= 0; i--){ + var item = this.items[i]; - if (options.draggable && $.fn.draggable) { - self._makeDraggable(); - } - if (options.resizable && $.fn.resizable) { - self._makeResizable(); - } + //We ignore calculating positions of all connected containers when we're not over them + if(item.instance != this.currentContainer && this.currentContainer && item.item[0] != this.currentItem[0]) + continue; - self._createButtons(options.buttons); - self._isOpen = false; + var t = this.options.toleranceElement ? $(this.options.toleranceElement, item.item) : item.item; - if ($.fn.bgiframe) { - uiDialog.bgiframe(); - } - }, + if (!fast) { + item.width = t.outerWidth(); + item.height = t.outerHeight(); + } - _init: function() { - if ( this.options.autoOpen ) { - this.open(); + var p = t.offset(); + item.left = p.left; + item.top = p.top; + }; + + if(this.options.custom && this.options.custom.refreshContainers) { + this.options.custom.refreshContainers.call(this); + } else { + for (var i = this.containers.length - 1; i >= 0; i--){ + var p = this.containers[i].element.offset(); + this.containers[i].containerCache.left = p.left; + this.containers[i].containerCache.top = p.top; + this.containers[i].containerCache.width = this.containers[i].element.outerWidth(); + this.containers[i].containerCache.height = this.containers[i].element.outerHeight(); + }; } + + return this; }, - destroy: function() { - var self = this; - - if (self.overlay) { - self.overlay.destroy(); - } - self.uiDialog.hide(); - self.element - .unbind('.dialog') - .removeData('dialog') - .removeClass('ui-dialog-content ui-widget-content') - .hide().appendTo('body'); - self.uiDialog.remove(); + _createPlaceholder: function(that) { + that = that || this; + var o = that.options; + + if(!o.placeholder || o.placeholder.constructor == String) { + var className = o.placeholder; + o.placeholder = { + element: function() { + + var el = $(document.createElement(that.currentItem[0].nodeName)) + .addClass(className || that.currentItem[0].className+" ui-sortable-placeholder") + .removeClass("ui-sortable-helper")[0]; + + if(!className) + el.style.visibility = "hidden"; + + return el; + }, + update: function(container, p) { - if (self.originalTitle) { - self.element.attr('title', self.originalTitle); + // 1. If a className is set as 'placeholder option, we don't force sizes - the class is responsible for that + // 2. The option 'forcePlaceholderSize can be enabled to force it even if a class name is specified + if(className && !o.forcePlaceholderSize) return; + + //If the element doesn't have a actual height by itself (without styles coming from a stylesheet), it receives the inline height from the dragged item + if(!p.height()) { p.height(that.currentItem.innerHeight() - parseInt(that.currentItem.css('paddingTop')||0, 10) - parseInt(that.currentItem.css('paddingBottom')||0, 10)); }; + if(!p.width()) { p.width(that.currentItem.innerWidth() - parseInt(that.currentItem.css('paddingLeft')||0, 10) - parseInt(that.currentItem.css('paddingRight')||0, 10)); }; + } + }; } - return self; - }, + //Create the placeholder + that.placeholder = $(o.placeholder.element.call(that.element, that.currentItem)); + + //Append it after the actual current item + that.currentItem.after(that.placeholder); + + //Update the size of the placeholder (TODO: Logic to fuzzy, see line 316/317) + o.placeholder.update(that, that.placeholder); - widget: function() { - return this.uiDialog; }, - close: function(event) { - var self = this, - maxZ, thisZ; - - if (false === self._trigger('beforeClose', event)) { - return; - } + _contactContainers: function(event) { - if (self.overlay) { - self.overlay.destroy(); - } - self.uiDialog.unbind('keypress.ui-dialog'); + // get innermost container that intersects with item + var innermostContainer = null, innermostIndex = null; - self._isOpen = false; - if (self.options.hide) { - self.uiDialog.hide(self.options.hide, function() { - self._trigger('close', event); - }); - } else { - self.uiDialog.hide(); - self._trigger('close', event); - } + for (var i = this.containers.length - 1; i >= 0; i--){ - $.ui.dialog.overlay.resize(); + // never consider a container that's located within the item itself + if($.contains(this.currentItem[0], this.containers[i].element[0])) + continue; - // adjust the maxZ to allow other modal dialogs to continue to work (see #4309) - if (self.options.modal) { - maxZ = 0; - $('.ui-dialog').each(function() { - if (this !== self.uiDialog[0]) { - thisZ = $(this).css('z-index'); - if(!isNaN(thisZ)) { - maxZ = Math.max(maxZ, thisZ); - } + if(this._intersectsWith(this.containers[i].containerCache)) { + + // if we've already found a container and it's more "inner" than this, then continue + if(innermostContainer && $.contains(this.containers[i].element[0], innermostContainer.element[0])) + continue; + + innermostContainer = this.containers[i]; + innermostIndex = i; + + } else { + // container doesn't intersect. trigger "out" event if necessary + if(this.containers[i].containerCache.over) { + this.containers[i]._trigger("out", event, this._uiHash(this)); + this.containers[i].containerCache.over = 0; } - }); - $.ui.dialog.maxZ = maxZ; + } + } - return self; - }, + // if no intersecting containers found, return + if(!innermostContainer) return; - isOpen: function() { - return this._isOpen; - }, + // move the item into the container if it's not there already + if(this.containers.length === 1) { + this.containers[innermostIndex]._trigger("over", event, this._uiHash(this)); + this.containers[innermostIndex].containerCache.over = 1; + } else { + + //When entering a new container, we will find the item with the least distance and append our item near it + var dist = 10000; var itemWithLeastDistance = null; + var posProperty = this.containers[innermostIndex].floating ? 'left' : 'top'; + var sizeProperty = this.containers[innermostIndex].floating ? 'width' : 'height'; + var base = this.positionAbs[posProperty] + this.offset.click[posProperty]; + for (var j = this.items.length - 1; j >= 0; j--) { + if(!$.contains(this.containers[innermostIndex].element[0], this.items[j].item[0])) continue; + if(this.items[j].item[0] == this.currentItem[0]) continue; + var cur = this.items[j].item.offset()[posProperty]; + var nearBottom = false; + if(Math.abs(cur - base) > Math.abs(cur + this.items[j][sizeProperty] - base)){ + nearBottom = true; + cur += this.items[j][sizeProperty]; + } + + if(Math.abs(cur - base) < dist) { + dist = Math.abs(cur - base); itemWithLeastDistance = this.items[j]; + this.direction = nearBottom ? "up": "down"; + } + } - // the force parameter allows us to move modal dialogs to their correct - // position on open - moveToTop: function(force, event) { - var self = this, - options = self.options, - saveScroll; + if(!itemWithLeastDistance && !this.options.dropOnEmpty) //Check if dropOnEmpty is enabled + return; - if ((options.modal && !force) || - (!options.stack && !options.modal)) { - return self._trigger('focus', event); - } + this.currentContainer = this.containers[innermostIndex]; + itemWithLeastDistance ? this._rearrange(event, itemWithLeastDistance, null, true) : this._rearrange(event, null, this.containers[innermostIndex].element, true); + this._trigger("change", event, this._uiHash()); + this.containers[innermostIndex]._trigger("change", event, this._uiHash(this)); - if (options.zIndex > $.ui.dialog.maxZ) { - $.ui.dialog.maxZ = options.zIndex; - } - if (self.overlay) { - $.ui.dialog.maxZ += 1; - self.overlay.$el.css('z-index', $.ui.dialog.overlay.maxZ = $.ui.dialog.maxZ); + //Update the placeholder + this.options.placeholder.update(this.currentContainer, this.placeholder); + + this.containers[innermostIndex]._trigger("over", event, this._uiHash(this)); + this.containers[innermostIndex].containerCache.over = 1; } - //Save and then restore scroll since Opera 9.5+ resets when parent z-Index is changed. - // http://ui.jquery.com/bugs/ticket/3193 - saveScroll = { scrollTop: self.element.scrollTop(), scrollLeft: self.element.scrollLeft() }; - $.ui.dialog.maxZ += 1; - self.uiDialog.css('z-index', $.ui.dialog.maxZ); - self.element.attr(saveScroll); - self._trigger('focus', event); - return self; }, - open: function() { - if (this._isOpen) { return; } - - var self = this, - options = self.options, - uiDialog = self.uiDialog; + _createHelper: function(event) { - self.overlay = options.modal ? new $.ui.dialog.overlay(self) : null; - self._size(); - self._position(options.position); - uiDialog.show(options.show); - self.moveToTop(true); + var o = this.options; + var helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event, this.currentItem])) : (o.helper == 'clone' ? this.currentItem.clone() : this.currentItem); - // prevent tabbing out of modal dialogs - if (options.modal) { - uiDialog.bind('keypress.ui-dialog', function(event) { - if (event.keyCode !== $.ui.keyCode.TAB) { - return; - } + if(!helper.parents('body').length) //Add the helper to the DOM if that didn't happen already + $(o.appendTo != 'parent' ? o.appendTo : this.currentItem[0].parentNode)[0].appendChild(helper[0]); - var tabbables = $(':tabbable', this), - first = tabbables.filter(':first'), - last = tabbables.filter(':last'); + if(helper[0] == this.currentItem[0]) + this._storedCSS = { width: this.currentItem[0].style.width, height: this.currentItem[0].style.height, position: this.currentItem.css("position"), top: this.currentItem.css("top"), left: this.currentItem.css("left") }; - if (event.target === last[0] && !event.shiftKey) { - first.focus(1); - return false; - } else if (event.target === first[0] && event.shiftKey) { - last.focus(1); - return false; - } - }); - } + if(helper[0].style.width == '' || o.forceHelperSize) helper.width(this.currentItem.width()); + if(helper[0].style.height == '' || o.forceHelperSize) helper.height(this.currentItem.height()); - // set focus to the first tabbable element in the content area or the first button - // if there are no tabbable elements, set focus on the dialog itself - $(self.element.find(':tabbable').get().concat( - uiDialog.find('.ui-dialog-buttonpane :tabbable').get().concat( - uiDialog.get()))).eq(0).focus(); - - self._isOpen = true; - self._trigger('open'); - - return self; - }, - - _createButtons: function(buttons) { - var self = this, - hasButtons = false, - uiDialogButtonPane = $('
        ') - .addClass( - 'ui-dialog-buttonpane ' + - 'ui-widget-content ' + - 'ui-helper-clearfix' - ), - uiButtonSet = $( "
        " ) - .addClass( "ui-dialog-buttonset" ) - .appendTo( uiDialogButtonPane ); + return helper; - // if we already have a button pane, remove it - self.uiDialog.find('.ui-dialog-buttonpane').remove(); + }, - if (typeof buttons === 'object' && buttons !== null) { - $.each(buttons, function() { - return !(hasButtons = true); - }); + _adjustOffsetFromHelper: function(obj) { + if (typeof obj == 'string') { + obj = obj.split(' '); } - if (hasButtons) { - $.each(buttons, function(name, props) { - props = $.isFunction( props ) ? - { click: props, text: name } : - props; - var button = $('') - .click(function() { - props.click.apply(self.element[0], arguments); - }) - .appendTo(uiButtonSet); - // can't use .attr( props, true ) with jQuery 1.3.2. - $.each( props, function( key, value ) { - if ( key === "click" ) { - return; - } - if ( key in attrFn ) { - button[ key ]( value ); - } else { - button.attr( key, value ); - } - }); - if ($.fn.button) { - button.button(); - } - }); - uiDialogButtonPane.appendTo(self.uiDialog); + if ($.isArray(obj)) { + obj = {left: +obj[0], top: +obj[1] || 0}; + } + if ('left' in obj) { + this.offset.click.left = obj.left + this.margins.left; + } + if ('right' in obj) { + this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left; + } + if ('top' in obj) { + this.offset.click.top = obj.top + this.margins.top; + } + if ('bottom' in obj) { + this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top; } }, - _makeDraggable: function() { - var self = this, - options = self.options, - doc = $(document), - heightBeforeDrag; + _getParentOffset: function() { - function filteredUi(ui) { - return { - position: ui.position, - offset: ui.offset - }; + + //Get the offsetParent and cache its position + this.offsetParent = this.helper.offsetParent(); + var po = this.offsetParent.offset(); + + // This is a special case where we need to modify a offset calculated on start, since the following happened: + // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent + // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that + // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag + if(this.cssPosition == 'absolute' && this.scrollParent[0] != document && $.contains(this.scrollParent[0], this.offsetParent[0])) { + po.left += this.scrollParent.scrollLeft(); + po.top += this.scrollParent.scrollTop(); } - self.uiDialog.draggable({ - cancel: '.ui-dialog-content, .ui-dialog-titlebar-close', - handle: '.ui-dialog-titlebar', - containment: 'document', - start: function(event, ui) { - heightBeforeDrag = options.height === "auto" ? "auto" : $(this).height(); - $(this).height($(this).height()).addClass("ui-dialog-dragging"); - self._trigger('dragStart', event, filteredUi(ui)); - }, - drag: function(event, ui) { - self._trigger('drag', event, filteredUi(ui)); - }, - stop: function(event, ui) { - options.position = [ui.position.left - doc.scrollLeft(), - ui.position.top - doc.scrollTop()]; - $(this).removeClass("ui-dialog-dragging").height(heightBeforeDrag); - self._trigger('dragStop', event, filteredUi(ui)); - $.ui.dialog.overlay.resize(); - } - }); + if((this.offsetParent[0] == document.body) //This needs to be actually done for all browsers, since pageX/pageY includes this information + || (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() == 'html' && $.ui.ie)) //Ugly IE fix + po = { top: 0, left: 0 }; + + return { + top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0), + left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0) + }; + }, - _makeResizable: function(handles) { - handles = (handles === undefined ? this.options.resizable : handles); - var self = this, - options = self.options, - // .ui-resizable has position: relative defined in the stylesheet - // but dialogs have to use absolute or fixed positioning - position = self.uiDialog.css('position'), - resizeHandles = (typeof handles === 'string' ? - handles : - 'n,e,s,w,se,sw,ne,nw' - ); + _getRelativeOffset: function() { - function filteredUi(ui) { + if(this.cssPosition == "relative") { + var p = this.currentItem.position(); return { - originalPosition: ui.originalPosition, - originalSize: ui.originalSize, - position: ui.position, - size: ui.size + top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(), + left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft() }; + } else { + return { top: 0, left: 0 }; } - self.uiDialog.resizable({ - cancel: '.ui-dialog-content', - containment: 'document', - alsoResize: self.element, - maxWidth: options.maxWidth, - maxHeight: options.maxHeight, - minWidth: options.minWidth, - minHeight: self._minHeight(), - handles: resizeHandles, - start: function(event, ui) { - $(this).addClass("ui-dialog-resizing"); - self._trigger('resizeStart', event, filteredUi(ui)); - }, - resize: function(event, ui) { - self._trigger('resize', event, filteredUi(ui)); - }, - stop: function(event, ui) { - $(this).removeClass("ui-dialog-resizing"); - options.height = $(this).height(); - options.width = $(this).width(); - self._trigger('resizeStop', event, filteredUi(ui)); - $.ui.dialog.overlay.resize(); - } - }) - .css('position', position) - .find('.ui-resizable-se').addClass('ui-icon ui-icon-grip-diagonal-se'); }, - _minHeight: function() { - var options = this.options; + _cacheMargins: function() { + this.margins = { + left: (parseInt(this.currentItem.css("marginLeft"),10) || 0), + top: (parseInt(this.currentItem.css("marginTop"),10) || 0) + }; + }, - if (options.height === 'auto') { - return options.minHeight; - } else { - return Math.min(options.minHeight, options.height); - } + _cacheHelperProportions: function() { + this.helperProportions = { + width: this.helper.outerWidth(), + height: this.helper.outerHeight() + }; }, - _position: function(position) { - var myAt = [], - offset = [0, 0], - isVisible; + _setContainment: function() { - if (position) { - // deep extending converts arrays to objects in jQuery <= 1.3.2 :-( - // if (typeof position == 'string' || $.isArray(position)) { - // myAt = $.isArray(position) ? position : position.split(' '); + var o = this.options; + if(o.containment == 'parent') o.containment = this.helper[0].parentNode; + if(o.containment == 'document' || o.containment == 'window') this.containment = [ + 0 - this.offset.relative.left - this.offset.parent.left, + 0 - this.offset.relative.top - this.offset.parent.top, + $(o.containment == 'document' ? document : window).width() - this.helperProportions.width - this.margins.left, + ($(o.containment == 'document' ? document : window).height() || document.body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top + ]; - if (typeof position === 'string' || (typeof position === 'object' && '0' in position)) { - myAt = position.split ? position.split(' ') : [position[0], position[1]]; - if (myAt.length === 1) { - myAt[1] = myAt[0]; - } + if(!(/^(document|window|parent)$/).test(o.containment)) { + var ce = $(o.containment)[0]; + var co = $(o.containment).offset(); + var over = ($(ce).css("overflow") != 'hidden'); - $.each(['left', 'top'], function(i, offsetPosition) { - if (+myAt[i] === myAt[i]) { - offset[i] = myAt[i]; - myAt[i] = offsetPosition; - } - }); + this.containment = [ + co.left + (parseInt($(ce).css("borderLeftWidth"),10) || 0) + (parseInt($(ce).css("paddingLeft"),10) || 0) - this.margins.left, + co.top + (parseInt($(ce).css("borderTopWidth"),10) || 0) + (parseInt($(ce).css("paddingTop"),10) || 0) - this.margins.top, + co.left+(over ? Math.max(ce.scrollWidth,ce.offsetWidth) : ce.offsetWidth) - (parseInt($(ce).css("borderLeftWidth"),10) || 0) - (parseInt($(ce).css("paddingRight"),10) || 0) - this.helperProportions.width - this.margins.left, + co.top+(over ? Math.max(ce.scrollHeight,ce.offsetHeight) : ce.offsetHeight) - (parseInt($(ce).css("borderTopWidth"),10) || 0) - (parseInt($(ce).css("paddingBottom"),10) || 0) - this.helperProportions.height - this.margins.top + ]; + } - position = { - my: myAt.join(" "), - at: myAt.join(" "), - offset: offset.join(" ") - }; - } + }, - position = $.extend({}, $.ui.dialog.prototype.options.position, position); - } else { - position = $.ui.dialog.prototype.options.position; - } + _convertPositionTo: function(d, pos) { + + if(!pos) pos = this.position; + var mod = d == "absolute" ? 1 : -1; + var o = this.options, scroll = this.cssPosition == 'absolute' && !(this.scrollParent[0] != document && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName); + + return { + top: ( + pos.top // The absolute mouse position + + this.offset.relative.top * mod // Only for relative positioned nodes: Relative offset from element to offset parent + + this.offset.parent.top * mod // The offsetParent's offset without borders (offset + border) + - ( ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod) + ), + left: ( + pos.left // The absolute mouse position + + this.offset.relative.left * mod // Only for relative positioned nodes: Relative offset from element to offset parent + + this.offset.parent.left * mod // The offsetParent's offset without borders (offset + border) + - ( ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) * mod) + ) + }; - // need to show the dialog to get the actual offset in the position plugin - isVisible = this.uiDialog.is(':visible'); - if (!isVisible) { - this.uiDialog.show(); - } - this.uiDialog - // workaround for jQuery bug #5781 http://dev.jquery.com/ticket/5781 - .css({ top: 0, left: 0 }) - .position($.extend({ of: window }, position)); - if (!isVisible) { - this.uiDialog.hide(); - } }, - _setOptions: function( options ) { - var self = this, - resizableOptions = {}, - resize = false; + _generatePosition: function(event) { - $.each( options, function( key, value ) { - self._setOption( key, value ); - - if ( key in sizeRelatedOptions ) { - resize = true; - } - if ( key in resizableRelatedOptions ) { - resizableOptions[ key ] = value; - } - }); + var o = this.options, scroll = this.cssPosition == 'absolute' && !(this.scrollParent[0] != document && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName); - if ( resize ) { - this._size(); - } - if ( this.uiDialog.is( ":data(resizable)" ) ) { - this.uiDialog.resizable( "option", resizableOptions ); + // This is another very weird special case that only happens for relative elements: + // 1. If the css position is relative + // 2. and the scroll parent is the document or similar to the offset parent + // we have to refresh the relative offset during the scroll so there are no jumps + if(this.cssPosition == 'relative' && !(this.scrollParent[0] != document && this.scrollParent[0] != this.offsetParent[0])) { + this.offset.relative = this._getRelativeOffset(); } - }, - _setOption: function(key, value){ - var self = this, - uiDialog = self.uiDialog; - - switch (key) { - //handling of deprecated beforeclose (vs beforeClose) option - //Ticket #4669 http://dev.jqueryui.com/ticket/4669 - //TODO: remove in 1.9pre - case "beforeclose": - key = "beforeClose"; - break; - case "buttons": - self._createButtons(value); - break; - case "closeText": - // ensure that we always pass a string - self.uiDialogTitlebarCloseText.text("" + value); - break; - case "dialogClass": - uiDialog - .removeClass(self.options.dialogClass) - .addClass(uiDialogClasses + value); - break; - case "disabled": - if (value) { - uiDialog.addClass('ui-dialog-disabled'); - } else { - uiDialog.removeClass('ui-dialog-disabled'); - } - break; - case "draggable": - var isDraggable = uiDialog.is( ":data(draggable)" ); - if ( isDraggable && !value ) { - uiDialog.draggable( "destroy" ); - } - - if ( !isDraggable && value ) { - self._makeDraggable(); - } - break; - case "position": - self._position(value); - break; - case "resizable": - // currently resizable, becoming non-resizable - var isResizable = uiDialog.is( ":data(resizable)" ); - if (isResizable && !value) { - uiDialog.resizable('destroy'); - } + var pageX = event.pageX; + var pageY = event.pageY; + + /* + * - Position constraining - + * Constrain the position to a mix of grid, containment. + */ + + if(this.originalPosition) { //If we are not dragging yet, we won't check for options - // currently resizable, changing handles - if (isResizable && typeof value === 'string') { - uiDialog.resizable('option', 'handles', value); - } + if(this.containment) { + if(event.pageX - this.offset.click.left < this.containment[0]) pageX = this.containment[0] + this.offset.click.left; + if(event.pageY - this.offset.click.top < this.containment[1]) pageY = this.containment[1] + this.offset.click.top; + if(event.pageX - this.offset.click.left > this.containment[2]) pageX = this.containment[2] + this.offset.click.left; + if(event.pageY - this.offset.click.top > this.containment[3]) pageY = this.containment[3] + this.offset.click.top; + } + + if(o.grid) { + var top = this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1]; + pageY = this.containment ? (!(top - this.offset.click.top < this.containment[1] || top - this.offset.click.top > this.containment[3]) ? top : (!(top - this.offset.click.top < this.containment[1]) ? top - o.grid[1] : top + o.grid[1])) : top; + + var left = this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0]; + pageX = this.containment ? (!(left - this.offset.click.left < this.containment[0] || left - this.offset.click.left > this.containment[2]) ? left : (!(left - this.offset.click.left < this.containment[0]) ? left - o.grid[0] : left + o.grid[0])) : left; + } - // currently non-resizable, becoming resizable - if (!isResizable && value !== false) { - self._makeResizable(value); - } - break; - case "title": - // convert whatever was passed in o a string, for html() to not throw up - $(".ui-dialog-title", self.uiDialogTitlebar).html("" + (value || ' ')); - break; } - $.Widget.prototype._setOption.apply(self, arguments); + return { + top: ( + pageY // The absolute mouse position + - this.offset.click.top // Click offset (relative to the element) + - this.offset.relative.top // Only for relative positioned nodes: Relative offset from element to offset parent + - this.offset.parent.top // The offsetParent's offset without borders (offset + border) + + ( ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) )) + ), + left: ( + pageX // The absolute mouse position + - this.offset.click.left // Click offset (relative to the element) + - this.offset.relative.left // Only for relative positioned nodes: Relative offset from element to offset parent + - this.offset.parent.left // The offsetParent's offset without borders (offset + border) + + ( ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() )) + ) + }; + }, - _size: function() { - /* If the user has resized the dialog, the .ui-dialog and .ui-dialog-content - * divs will both have width and height set, so we need to reset them - */ - var options = this.options, - nonContentHeight, - minContentHeight, - isVisible = this.uiDialog.is( ":visible" ); + _rearrange: function(event, i, a, hardRefresh) { - // reset content sizing - this.element.show().css({ - width: 'auto', - minHeight: 0, - height: 0 + a ? a[0].appendChild(this.placeholder[0]) : i.item[0].parentNode.insertBefore(this.placeholder[0], (this.direction == 'down' ? i.item[0] : i.item[0].nextSibling)); + + //Various things done here to improve the performance: + // 1. we create a setTimeout, that calls refreshPositions + // 2. on the instance, we have a counter variable, that get's higher after every append + // 3. on the local scope, we copy the counter variable, and check in the timeout, if it's still the same + // 4. this lets only the last addition to the timeout stack through + this.counter = this.counter ? ++this.counter : 1; + var counter = this.counter; + + this._delay(function() { + if(counter == this.counter) this.refreshPositions(!hardRefresh); //Precompute after each DOM insertion, NOT on mousemove }); - if (options.minWidth > options.width) { - options.width = options.minWidth; - } + }, - // reset wrapper sizing - // determine the height of all the non-content elements - nonContentHeight = this.uiDialog.css({ - height: 'auto', - width: options.width - }) - .height(); - minContentHeight = Math.max( 0, options.minHeight - nonContentHeight ); - - if ( options.height === "auto" ) { - // only needed for IE6 support - if ( $.support.minHeight ) { - this.element.css({ - minHeight: minContentHeight, - height: "auto" - }); - } else { - this.uiDialog.show(); - var autoHeight = this.element.css( "height", "auto" ).height(); - if ( !isVisible ) { - this.uiDialog.hide(); - } - this.element.height( Math.max( autoHeight, minContentHeight ) ); + _clear: function(event, noPropagation) { + + this.reverting = false; + // We delay all events that have to be triggered to after the point where the placeholder has been removed and + // everything else normalized again + var delayedTriggers = []; + + // We first have to update the dom position of the actual currentItem + // Note: don't do it if the current item is already removed (by a user), or it gets reappended (see #4088) + if(!this._noFinalSort && this.currentItem.parent().length) this.placeholder.before(this.currentItem); + this._noFinalSort = null; + + if(this.helper[0] == this.currentItem[0]) { + for(var i in this._storedCSS) { + if(this._storedCSS[i] == 'auto' || this._storedCSS[i] == 'static') this._storedCSS[i] = ''; } + this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"); } else { - this.element.height( Math.max( options.height - nonContentHeight, 0 ) ); + this.currentItem.show(); } - if (this.uiDialog.is(':data(resizable)')) { - this.uiDialog.resizable('option', 'minHeight', this._minHeight()); - } - } -}); + if(this.fromOutside && !noPropagation) delayedTriggers.push(function(event) { this._trigger("receive", event, this._uiHash(this.fromOutside)); }); + if((this.fromOutside || this.domPosition.prev != this.currentItem.prev().not(".ui-sortable-helper")[0] || this.domPosition.parent != this.currentItem.parent()[0]) && !noPropagation) delayedTriggers.push(function(event) { this._trigger("update", event, this._uiHash()); }); //Trigger update callback if the DOM position has changed -$.extend($.ui.dialog, { - version: "1.8.16", + // Check if the items Container has Changed and trigger appropriate + // events. + if (this !== this.currentContainer) { + if(!noPropagation) { + delayedTriggers.push(function(event) { this._trigger("remove", event, this._uiHash()); }); + delayedTriggers.push((function(c) { return function(event) { c._trigger("receive", event, this._uiHash(this)); }; }).call(this, this.currentContainer)); + delayedTriggers.push((function(c) { return function(event) { c._trigger("update", event, this._uiHash(this)); }; }).call(this, this.currentContainer)); + } + } - uuid: 0, - maxZ: 0, - getTitleId: function($el) { - var id = $el.attr('id'); - if (!id) { - this.uuid += 1; - id = this.uuid; + //Post events to containers + for (var i = this.containers.length - 1; i >= 0; i--){ + if(!noPropagation) delayedTriggers.push((function(c) { return function(event) { c._trigger("deactivate", event, this._uiHash(this)); }; }).call(this, this.containers[i])); + if(this.containers[i].containerCache.over) { + delayedTriggers.push((function(c) { return function(event) { c._trigger("out", event, this._uiHash(this)); }; }).call(this, this.containers[i])); + this.containers[i].containerCache.over = 0; + } } - return 'ui-dialog-title-' + id; - }, - - overlay: function(dialog) { - this.$el = $.ui.dialog.overlay.create(dialog); - } -}); -$.extend($.ui.dialog.overlay, { - instances: [], - // reuse old instances due to IE memory leak with alpha transparency (see #5185) - oldInstances: [], - maxZ: 0, - events: $.map('focus,mousedown,mouseup,keydown,keypress,click'.split(','), - function(event) { return event + '.dialog-overlay'; }).join(' '), - create: function(dialog) { - if (this.instances.length === 0) { - // prevent use of anchors and inputs - // we use a setTimeout in case the overlay is created from an - // event that we're going to be cancelling (see #2804) - setTimeout(function() { - // handle $(el).dialog().dialog('close') (see #4065) - if ($.ui.dialog.overlay.instances.length) { - $(document).bind($.ui.dialog.overlay.events, function(event) { - // stop events if the z-index of the target is < the z-index of the overlay - // we cannot return true when we don't want to cancel the event (#3523) - if ($(event.target).zIndex() < $.ui.dialog.overlay.maxZ) { - return false; - } - }); - } - }, 1); + //Do what was originally in plugins + if(this._storedCursor) $('body').css("cursor", this._storedCursor); //Reset cursor + if(this._storedOpacity) this.helper.css("opacity", this._storedOpacity); //Reset opacity + if(this._storedZIndex) this.helper.css("zIndex", this._storedZIndex == 'auto' ? '' : this._storedZIndex); //Reset z-index - // allow closing by pressing the escape key - $(document).bind('keydown.dialog-overlay', function(event) { - if (dialog.options.closeOnEscape && !event.isDefaultPrevented() && event.keyCode && - event.keyCode === $.ui.keyCode.ESCAPE) { - - dialog.close(event); - event.preventDefault(); - } - }); + this.dragging = false; + if(this.cancelHelperRemoval) { + if(!noPropagation) { + this._trigger("beforeStop", event, this._uiHash()); + for (var i=0; i < delayedTriggers.length; i++) { delayedTriggers[i].call(this, event); }; //Trigger all delayed events + this._trigger("stop", event, this._uiHash()); + } - // handle window resize - $(window).bind('resize.dialog-overlay', $.ui.dialog.overlay.resize); + this.fromOutside = false; + return false; } - var $el = (this.oldInstances.pop() || $('
        ').addClass('ui-widget-overlay')) - .appendTo(document.body) - .css({ - width: this.width(), - height: this.height() - }); + if(!noPropagation) this._trigger("beforeStop", event, this._uiHash()); - if ($.fn.bgiframe) { - $el.bgiframe(); + //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node! + this.placeholder[0].parentNode.removeChild(this.placeholder[0]); + + if(this.helper[0] != this.currentItem[0]) this.helper.remove(); this.helper = null; + + if(!noPropagation) { + for (var i=0; i < delayedTriggers.length; i++) { delayedTriggers[i].call(this, event); }; //Trigger all delayed events + this._trigger("stop", event, this._uiHash()); } - this.instances.push($el); - return $el; + this.fromOutside = false; + return true; + }, - destroy: function($el) { - var indexOf = $.inArray($el, this.instances); - if (indexOf != -1){ - this.oldInstances.push(this.instances.splice(indexOf, 1)[0]); + _trigger: function() { + if ($.Widget.prototype._trigger.apply(this, arguments) === false) { + this.cancel(); } + }, + + _uiHash: function(_inst) { + var inst = _inst || this; + return { + helper: inst.helper, + placeholder: inst.placeholder || $([]), + position: inst.position, + originalPosition: inst.originalPosition, + offset: inst.positionAbs, + item: inst.currentItem, + sender: _inst ? _inst.element : null + }; + } - if (this.instances.length === 0) { - $([document, window]).unbind('.dialog-overlay'); +}); + +})(jQuery); +(function( $ ) { + +function modifier( fn ) { + return function() { + var previous = this.element.val(); + fn.apply( this, arguments ); + this._refresh(); + if ( previous !== this.element.val() ) { + this._trigger( "change" ); } + }; +} - $el.remove(); - - // adjust the maxZ to allow other modal dialogs to continue to work (see #4309) - var maxZ = 0; - $.each(this.instances, function() { - maxZ = Math.max(maxZ, this.css('z-index')); - }); - this.maxZ = maxZ; +$.widget( "ui.spinner", { + version: "1.9.2", + defaultElement: "", + widgetEventPrefix: "spin", + options: { + culture: null, + icons: { + down: "ui-icon-triangle-1-s", + up: "ui-icon-triangle-1-n" + }, + incremental: true, + max: null, + min: null, + numberFormat: null, + page: 10, + step: 1, + + change: null, + spin: null, + start: null, + stop: null }, - height: function() { - var scrollHeight, - offsetHeight; - // handle IE 6 - if ($.browser.msie && $.browser.version < 7) { - scrollHeight = Math.max( - document.documentElement.scrollHeight, - document.body.scrollHeight - ); - offsetHeight = Math.max( - document.documentElement.offsetHeight, - document.body.offsetHeight - ); + _create: function() { + // handle string values that need to be parsed + this._setOption( "max", this.options.max ); + this._setOption( "min", this.options.min ); + this._setOption( "step", this.options.step ); - if (scrollHeight < offsetHeight) { - return $(window).height() + 'px'; - } else { - return scrollHeight + 'px'; + // format the value, but don't constrain + this._value( this.element.val(), true ); + + this._draw(); + this._on( this._events ); + this._refresh(); + + // turning off autocomplete prevents the browser from remembering the + // value when navigating through history, so we re-enable autocomplete + // if the page is unloaded before the widget is destroyed. #7790 + this._on( this.window, { + beforeunload: function() { + this.element.removeAttr( "autocomplete" ); } - // handle "good" browsers - } else { - return $(document).height() + 'px'; - } + }); }, - width: function() { - var scrollWidth, - offsetWidth; - // handle IE - if ( $.browser.msie ) { - scrollWidth = Math.max( - document.documentElement.scrollWidth, - document.body.scrollWidth - ); - offsetWidth = Math.max( - document.documentElement.offsetWidth, - document.body.offsetWidth - ); + _getCreateOptions: function() { + var options = {}, + element = this.element; - if (scrollWidth < offsetWidth) { - return $(window).width() + 'px'; - } else { - return scrollWidth + 'px'; + $.each( [ "min", "max", "step" ], function( i, option ) { + var value = element.attr( option ); + if ( value !== undefined && value.length ) { + options[ option ] = value; } - // handle "good" browsers - } else { - return $(document).width() + 'px'; - } + }); + + return options; }, - resize: function() { - /* If the dialog is draggable and the user drags it past the - * right edge of the window, the document becomes wider so we - * need to stretch the overlay. If the user then drags the - * dialog back to the left, the document will become narrower, - * so we need to shrink the overlay to the appropriate size. - * This is handled by shrinking the overlay before setting it - * to the full document size. - */ - var $overlays = $([]); - $.each($.ui.dialog.overlay.instances, function() { - $overlays = $overlays.add(this); - }); + _events: { + keydown: function( event ) { + if ( this._start( event ) && this._keydown( event ) ) { + event.preventDefault(); + } + }, + keyup: "_stop", + focus: function() { + this.previous = this.element.val(); + }, + blur: function( event ) { + if ( this.cancelBlur ) { + delete this.cancelBlur; + return; + } - $overlays.css({ - width: 0, - height: 0 - }).css({ - width: $.ui.dialog.overlay.width(), - height: $.ui.dialog.overlay.height() - }); - } -}); + this._refresh(); + if ( this.previous !== this.element.val() ) { + this._trigger( "change", event ); + } + }, + mousewheel: function( event, delta ) { + if ( !delta ) { + return; + } + if ( !this.spinning && !this._start( event ) ) { + return false; + } -$.extend($.ui.dialog.overlay.prototype, { - destroy: function() { - $.ui.dialog.overlay.destroy(this.$el); - } -}); + this._spin( (delta > 0 ? 1 : -1) * this.options.step, event ); + clearTimeout( this.mousewheelTimer ); + this.mousewheelTimer = this._delay(function() { + if ( this.spinning ) { + this._stop( event ); + } + }, 100 ); + event.preventDefault(); + }, + "mousedown .ui-spinner-button": function( event ) { + var previous; + + // We never want the buttons to have focus; whenever the user is + // interacting with the spinner, the focus should be on the input. + // If the input is focused then this.previous is properly set from + // when the input first received focus. If the input is not focused + // then we need to set this.previous based on the value before spinning. + previous = this.element[0] === this.document[0].activeElement ? + this.previous : this.element.val(); + function checkFocus() { + var isActive = this.element[0] === this.document[0].activeElement; + if ( !isActive ) { + this.element.focus(); + this.previous = previous; + // support: IE + // IE sets focus asynchronously, so we need to check if focus + // moved off of the input because the user clicked on the button. + this._delay(function() { + this.previous = previous; + }); + } + } -}(jQuery)); -/* - * jQuery UI Position 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Position - */ -(function( $, undefined ) { + // ensure focus is on (or stays on) the text field + event.preventDefault(); + checkFocus.call( this ); + + // support: IE + // IE doesn't prevent moving focus even with event.preventDefault() + // so we set a flag to know when we should ignore the blur event + // and check (again) if focus moved off of the input. + this.cancelBlur = true; + this._delay(function() { + delete this.cancelBlur; + checkFocus.call( this ); + }); -$.ui = $.ui || {}; + if ( this._start( event ) === false ) { + return; + } -var horizontalPositions = /left|center|right/, - verticalPositions = /top|center|bottom/, - center = "center", - _position = $.fn.position, - _offset = $.fn.offset; + this._repeat( null, $( event.currentTarget ).hasClass( "ui-spinner-up" ) ? 1 : -1, event ); + }, + "mouseup .ui-spinner-button": "_stop", + "mouseenter .ui-spinner-button": function( event ) { + // button will add ui-state-active if mouse was down while mouseleave and kept down + if ( !$( event.currentTarget ).hasClass( "ui-state-active" ) ) { + return; + } -$.fn.position = function( options ) { - if ( !options || !options.of ) { - return _position.apply( this, arguments ); - } + if ( this._start( event ) === false ) { + return false; + } + this._repeat( null, $( event.currentTarget ).hasClass( "ui-spinner-up" ) ? 1 : -1, event ); + }, + // TODO: do we really want to consider this a stop? + // shouldn't we just stop the repeater and wait until mouseup before + // we trigger the stop event? + "mouseleave .ui-spinner-button": "_stop" + }, - // make a copy, we don't want to modify arguments - options = $.extend( {}, options ); + _draw: function() { + var uiSpinner = this.uiSpinner = this.element + .addClass( "ui-spinner-input" ) + .attr( "autocomplete", "off" ) + .wrap( this._uiSpinnerHtml() ) + .parent() + // add buttons + .append( this._buttonHtml() ); - var target = $( options.of ), - targetElem = target[0], - collision = ( options.collision || "flip" ).split( " " ), - offset = options.offset ? options.offset.split( " " ) : [ 0, 0 ], - targetWidth, - targetHeight, - basePosition; + this.element.attr( "role", "spinbutton" ); - if ( targetElem.nodeType === 9 ) { - targetWidth = target.width(); - targetHeight = target.height(); - basePosition = { top: 0, left: 0 }; - // TODO: use $.isWindow() in 1.9 - } else if ( targetElem.setTimeout ) { - targetWidth = target.width(); - targetHeight = target.height(); - basePosition = { top: target.scrollTop(), left: target.scrollLeft() }; - } else if ( targetElem.preventDefault ) { - // force left top to allow flipping - options.at = "left top"; - targetWidth = targetHeight = 0; - basePosition = { top: options.of.pageY, left: options.of.pageX }; - } else { - targetWidth = target.outerWidth(); - targetHeight = target.outerHeight(); - basePosition = target.offset(); - } + // button bindings + this.buttons = uiSpinner.find( ".ui-spinner-button" ) + .attr( "tabIndex", -1 ) + .button() + .removeClass( "ui-corner-all" ); - // force my and at to have valid horizontal and veritcal positions - // if a value is missing or invalid, it will be converted to center - $.each( [ "my", "at" ], function() { - var pos = ( options[this] || "" ).split( " " ); - if ( pos.length === 1) { - pos = horizontalPositions.test( pos[0] ) ? - pos.concat( [center] ) : - verticalPositions.test( pos[0] ) ? - [ center ].concat( pos ) : - [ center, center ]; - } - pos[ 0 ] = horizontalPositions.test( pos[0] ) ? pos[ 0 ] : center; - pos[ 1 ] = verticalPositions.test( pos[1] ) ? pos[ 1 ] : center; - options[ this ] = pos; - }); + // IE 6 doesn't understand height: 50% for the buttons + // unless the wrapper has an explicit height + if ( this.buttons.height() > Math.ceil( uiSpinner.height() * 0.5 ) && + uiSpinner.height() > 0 ) { + uiSpinner.height( uiSpinner.height() ); + } - // normalize collision option - if ( collision.length === 1 ) { - collision[ 1 ] = collision[ 0 ]; - } + // disable spinner if element was already disabled + if ( this.options.disabled ) { + this.disable(); + } + }, - // normalize offset option - offset[ 0 ] = parseInt( offset[0], 10 ) || 0; - if ( offset.length === 1 ) { - offset[ 1 ] = offset[ 0 ]; - } - offset[ 1 ] = parseInt( offset[1], 10 ) || 0; + _keydown: function( event ) { + var options = this.options, + keyCode = $.ui.keyCode; - if ( options.at[0] === "right" ) { - basePosition.left += targetWidth; - } else if ( options.at[0] === center ) { - basePosition.left += targetWidth / 2; - } + switch ( event.keyCode ) { + case keyCode.UP: + this._repeat( null, 1, event ); + return true; + case keyCode.DOWN: + this._repeat( null, -1, event ); + return true; + case keyCode.PAGE_UP: + this._repeat( null, options.page, event ); + return true; + case keyCode.PAGE_DOWN: + this._repeat( null, -options.page, event ); + return true; + } - if ( options.at[1] === "bottom" ) { - basePosition.top += targetHeight; - } else if ( options.at[1] === center ) { - basePosition.top += targetHeight / 2; - } + return false; + }, - basePosition.left += offset[ 0 ]; - basePosition.top += offset[ 1 ]; + _uiSpinnerHtml: function() { + return ""; + }, - return this.each(function() { - var elem = $( this ), - elemWidth = elem.outerWidth(), - elemHeight = elem.outerHeight(), - marginLeft = parseInt( $.curCSS( this, "marginLeft", true ) ) || 0, - marginTop = parseInt( $.curCSS( this, "marginTop", true ) ) || 0, - collisionWidth = elemWidth + marginLeft + - ( parseInt( $.curCSS( this, "marginRight", true ) ) || 0 ), - collisionHeight = elemHeight + marginTop + - ( parseInt( $.curCSS( this, "marginBottom", true ) ) || 0 ), - position = $.extend( {}, basePosition ), - collisionPosition; + _buttonHtml: function() { + return "" + + "" + + "" + + "" + + "" + + "" + + ""; + }, - if ( options.my[0] === "right" ) { - position.left -= elemWidth; - } else if ( options.my[0] === center ) { - position.left -= elemWidth / 2; + _start: function( event ) { + if ( !this.spinning && this._trigger( "start", event ) === false ) { + return false; } - if ( options.my[1] === "bottom" ) { - position.top -= elemHeight; - } else if ( options.my[1] === center ) { - position.top -= elemHeight / 2; + if ( !this.counter ) { + this.counter = 1; } + this.spinning = true; + return true; + }, - // prevent fractions (see #5280) - position.left = Math.round( position.left ); - position.top = Math.round( position.top ); + _repeat: function( i, steps, event ) { + i = i || 500; - collisionPosition = { - left: position.left - marginLeft, - top: position.top - marginTop - }; + clearTimeout( this.timer ); + this.timer = this._delay(function() { + this._repeat( 40, steps, event ); + }, i ); - $.each( [ "left", "top" ], function( i, dir ) { - if ( $.ui.position[ collision[i] ] ) { - $.ui.position[ collision[i] ][ dir ]( position, { - targetWidth: targetWidth, - targetHeight: targetHeight, - elemWidth: elemWidth, - elemHeight: elemHeight, - collisionPosition: collisionPosition, - collisionWidth: collisionWidth, - collisionHeight: collisionHeight, - offset: offset, - my: options.my, - at: options.at - }); - } - }); + this._spin( steps * this.options.step, event ); + }, - if ( $.fn.bgiframe ) { - elem.bgiframe(); + _spin: function( step, event ) { + var value = this.value() || 0; + + if ( !this.counter ) { + this.counter = 1; } - elem.offset( $.extend( position, { using: options.using } ) ); - }); -}; -$.ui.position = { - fit: { - left: function( position, data ) { - var win = $( window ), - over = data.collisionPosition.left + data.collisionWidth - win.width() - win.scrollLeft(); - position.left = over > 0 ? position.left - over : Math.max( position.left - data.collisionPosition.left, position.left ); - }, - top: function( position, data ) { - var win = $( window ), - over = data.collisionPosition.top + data.collisionHeight - win.height() - win.scrollTop(); - position.top = over > 0 ? position.top - over : Math.max( position.top - data.collisionPosition.top, position.top ); + value = this._adjustValue( value + step * this._increment( this.counter ) ); + + if ( !this.spinning || this._trigger( "spin", event, { value: value } ) !== false) { + this._value( value ); + this.counter++; } }, - flip: { - left: function( position, data ) { - if ( data.at[0] === center ) { - return; - } - var win = $( window ), - over = data.collisionPosition.left + data.collisionWidth - win.width() - win.scrollLeft(), - myOffset = data.my[ 0 ] === "left" ? - -data.elemWidth : - data.my[ 0 ] === "right" ? - data.elemWidth : - 0, - atOffset = data.at[ 0 ] === "left" ? - data.targetWidth : - -data.targetWidth, - offset = -2 * data.offset[ 0 ]; - position.left += data.collisionPosition.left < 0 ? - myOffset + atOffset + offset : - over > 0 ? - myOffset + atOffset + offset : - 0; - }, - top: function( position, data ) { - if ( data.at[1] === center ) { - return; - } - var win = $( window ), - over = data.collisionPosition.top + data.collisionHeight - win.height() - win.scrollTop(), - myOffset = data.my[ 1 ] === "top" ? - -data.elemHeight : - data.my[ 1 ] === "bottom" ? - data.elemHeight : - 0, - atOffset = data.at[ 1 ] === "top" ? - data.targetHeight : - -data.targetHeight, - offset = -2 * data.offset[ 1 ]; - position.top += data.collisionPosition.top < 0 ? - myOffset + atOffset + offset : - over > 0 ? - myOffset + atOffset + offset : - 0; + _increment: function( i ) { + var incremental = this.options.incremental; + + if ( incremental ) { + return $.isFunction( incremental ) ? + incremental( i ) : + Math.floor( i*i*i/50000 - i*i/500 + 17*i/200 + 1 ); } - } -}; -// offset setter from jQuery 1.4 -if ( !$.offset.setOffset ) { - $.offset.setOffset = function( elem, options ) { - // set position first, in-case top/left are set even on static elem - if ( /static/.test( $.curCSS( elem, "position" ) ) ) { - elem.style.position = "relative"; - } - var curElem = $( elem ), - curOffset = curElem.offset(), - curTop = parseInt( $.curCSS( elem, "top", true ), 10 ) || 0, - curLeft = parseInt( $.curCSS( elem, "left", true ), 10) || 0, - props = { - top: (options.top - curOffset.top) + curTop, - left: (options.left - curOffset.left) + curLeft - }; - - if ( 'using' in options ) { - options.using.call( elem, props ); - } else { - curElem.css( props ); + return 1; + }, + + _precision: function() { + var precision = this._precisionOf( this.options.step ); + if ( this.options.min !== null ) { + precision = Math.max( precision, this._precisionOf( this.options.min ) ); } - }; + return precision; + }, - $.fn.offset = function( options ) { - var elem = this[ 0 ]; - if ( !elem || !elem.ownerDocument ) { return null; } - if ( options ) { - return this.each(function() { - $.offset.setOffset( this, options ); - }); + _precisionOf: function( num ) { + var str = num.toString(), + decimal = str.indexOf( "." ); + return decimal === -1 ? 0 : str.length - decimal - 1; + }, + + _adjustValue: function( value ) { + var base, aboveMin, + options = this.options; + + // make sure we're at a valid step + // - find out where we are relative to the base (min or 0) + base = options.min !== null ? options.min : 0; + aboveMin = value - base; + // - round to the nearest step + aboveMin = Math.round(aboveMin / options.step) * options.step; + // - rounding is based on 0, so adjust back to our base + value = base + aboveMin; + + // fix precision from bad JS floating point math + value = parseFloat( value.toFixed( this._precision() ) ); + + // clamp the value + if ( options.max !== null && value > options.max) { + return options.max; + } + if ( options.min !== null && value < options.min ) { + return options.min; } - return _offset.call( this ); - }; -} -}( jQuery )); -/* - * jQuery UI Progressbar 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Progressbar - * - * Depends: - * jquery.ui.core.js - * jquery.ui.widget.js - */ -(function( $, undefined ) { + return value; + }, -$.widget( "ui.progressbar", { - options: { - value: 0, - max: 100 + _stop: function( event ) { + if ( !this.spinning ) { + return; + } + + clearTimeout( this.timer ); + clearTimeout( this.mousewheelTimer ); + this.counter = 0; + this.spinning = false; + this._trigger( "stop", event ); }, - min: 0, + _setOption: function( key, value ) { + if ( key === "culture" || key === "numberFormat" ) { + var prevValue = this._parse( this.element.val() ); + this.options[ key ] = value; + this.element.val( this._format( prevValue ) ); + return; + } - _create: function() { - this.element - .addClass( "ui-progressbar ui-widget ui-widget-content ui-corner-all" ) - .attr({ - role: "progressbar", - "aria-valuemin": this.min, - "aria-valuemax": this.options.max, - "aria-valuenow": this._value() - }); + if ( key === "max" || key === "min" || key === "step" ) { + if ( typeof value === "string" ) { + value = this._parse( value ); + } + } - this.valueDiv = $( "
        " ) - .appendTo( this.element ); + this._super( key, value ); - this.oldValue = this._value(); - this._refreshValue(); + if ( key === "disabled" ) { + if ( value ) { + this.element.prop( "disabled", true ); + this.buttons.button( "disable" ); + } else { + this.element.prop( "disabled", false ); + this.buttons.button( "enable" ); + } + } }, - destroy: function() { - this.element - .removeClass( "ui-progressbar ui-widget ui-widget-content ui-corner-all" ) - .removeAttr( "role" ) - .removeAttr( "aria-valuemin" ) - .removeAttr( "aria-valuemax" ) - .removeAttr( "aria-valuenow" ); - - this.valueDiv.remove(); + _setOptions: modifier(function( options ) { + this._super( options ); + this._value( this.element.val() ); + }), - $.Widget.prototype.destroy.apply( this, arguments ); + _parse: function( val ) { + if ( typeof val === "string" && val !== "" ) { + val = window.Globalize && this.options.numberFormat ? + Globalize.parseFloat( val, 10, this.options.culture ) : +val; + } + return val === "" || isNaN( val ) ? null : val; }, - value: function( newValue ) { - if ( newValue === undefined ) { - return this._value(); + _format: function( value ) { + if ( value === "" ) { + return ""; } + return window.Globalize && this.options.numberFormat ? + Globalize.format( value, this.options.numberFormat, this.options.culture ) : + value; + }, - this._setOption( "value", newValue ); - return this; + _refresh: function() { + this.element.attr({ + "aria-valuemin": this.options.min, + "aria-valuemax": this.options.max, + // TODO: what should we do with values that can't be parsed? + "aria-valuenow": this._parse( this.element.val() ) + }); }, - _setOption: function( key, value ) { - if ( key === "value" ) { - this.options.value = value; - this._refreshValue(); - if ( this._value() === this.options.max ) { - this._trigger( "complete" ); + // update the value without triggering change + _value: function( value, allowAny ) { + var parsed; + if ( value !== "" ) { + parsed = this._parse( value ); + if ( parsed !== null ) { + if ( !allowAny ) { + parsed = this._adjustValue( parsed ); + } + value = this._format( parsed ); } } + this.element.val( value ); + this._refresh(); + }, - $.Widget.prototype._setOption.apply( this, arguments ); + _destroy: function() { + this.element + .removeClass( "ui-spinner-input" ) + .prop( "disabled", false ) + .removeAttr( "autocomplete" ) + .removeAttr( "role" ) + .removeAttr( "aria-valuemin" ) + .removeAttr( "aria-valuemax" ) + .removeAttr( "aria-valuenow" ); + this.uiSpinner.replaceWith( this.element ); }, - _value: function() { - var val = this.options.value; - // normalize invalid value - if ( typeof val !== "number" ) { - val = 0; - } - return Math.min( this.options.max, Math.max( this.min, val ) ); + stepUp: modifier(function( steps ) { + this._stepUp( steps ); + }), + _stepUp: function( steps ) { + this._spin( (steps || 1) * this.options.step ); }, - _percentage: function() { - return 100 * this._value() / this.options.max; + stepDown: modifier(function( steps ) { + this._stepDown( steps ); + }), + _stepDown: function( steps ) { + this._spin( (steps || 1) * -this.options.step ); }, - _refreshValue: function() { - var value = this.value(); - var percentage = this._percentage(); + pageUp: modifier(function( pages ) { + this._stepUp( (pages || 1) * this.options.page ); + }), - if ( this.oldValue !== value ) { - this.oldValue = value; - this._trigger( "change" ); - } + pageDown: modifier(function( pages ) { + this._stepDown( (pages || 1) * this.options.page ); + }), - this.valueDiv - .toggle( value > this.min ) - .toggleClass( "ui-corner-right", value === this.options.max ) - .width( percentage.toFixed(0) + "%" ); - this.element.attr( "aria-valuenow", value ); - } -}); + value: function( newVal ) { + if ( !arguments.length ) { + return this._parse( this.element.val() ); + } + modifier( this._value ).call( this, newVal ); + }, -$.extend( $.ui.progressbar, { - version: "1.8.16" + widget: function() { + return this.uiSpinner; + } }); -})( jQuery ); -/* - * jQuery UI Slider 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Slider - * - * Depends: - * jquery.ui.core.js - * jquery.ui.mouse.js - * jquery.ui.widget.js - */ +}( jQuery ) ); (function( $, undefined ) { -// number of pages in a slider -// (how many times can you page up/down to go through the whole range) -var numPages = 5; +var tabId = 0, + rhash = /#.*$/; -$.widget( "ui.slider", $.ui.mouse, { +function getNextTabId() { + return ++tabId; +} - widgetEventPrefix: "slide", +function isLocal( anchor ) { + return anchor.hash.length > 1 && + anchor.href.replace( rhash, "" ) === + location.href.replace( rhash, "" ) + // support: Safari 5.1 + // Safari 5.1 doesn't encode spaces in window.location + // but it does encode spaces from anchors (#8777) + .replace( /\s/g, "%20" ); +} +$.widget( "ui.tabs", { + version: "1.9.2", + delay: 300, options: { - animate: false, - distance: 0, - max: 100, - min: 0, - orientation: "horizontal", - range: false, - step: 1, - value: 0, - values: null + active: null, + collapsible: false, + event: "click", + heightStyle: "content", + hide: null, + show: null, + + // callbacks + activate: null, + beforeActivate: null, + beforeLoad: null, + load: null }, _create: function() { - var self = this, - o = this.options, - existingHandles = this.element.find( ".ui-slider-handle" ).addClass( "ui-state-default ui-corner-all" ), - handle = "", - handleCount = ( o.values && o.values.length ) || 1, - handles = []; + var that = this, + options = this.options, + active = options.active, + locationHash = location.hash.substring( 1 ); - this._keySliding = false; - this._mouseSliding = false; - this._animateOff = true; - this._handleIndex = null; - this._detectOrientation(); - this._mouseInit(); + this.running = false; this.element - .addClass( "ui-slider" + - " ui-slider-" + this.orientation + - " ui-widget" + - " ui-widget-content" + - " ui-corner-all" + - ( o.disabled ? " ui-slider-disabled ui-disabled" : "" ) ); - - this.range = $([]); - - if ( o.range ) { - if ( o.range === true ) { - if ( !o.values ) { - o.values = [ this._valueMin(), this._valueMin() ]; + .addClass( "ui-tabs ui-widget ui-widget-content ui-corner-all" ) + .toggleClass( "ui-tabs-collapsible", options.collapsible ) + // Prevent users from focusing disabled tabs via click + .delegate( ".ui-tabs-nav > li", "mousedown" + this.eventNamespace, function( event ) { + if ( $( this ).is( ".ui-state-disabled" ) ) { + event.preventDefault(); } - if ( o.values.length && o.values.length !== 2 ) { - o.values = [ o.values[0], o.values[0] ]; + }) + // support: IE <9 + // Preventing the default action in mousedown doesn't prevent IE + // from focusing the element, so if the anchor gets focused, blur. + // We don't have to worry about focusing the previously focused + // element since clicking on a non-focusable element should focus + // the body anyway. + .delegate( ".ui-tabs-anchor", "focus" + this.eventNamespace, function() { + if ( $( this ).closest( "li" ).is( ".ui-state-disabled" ) ) { + this.blur(); } + }); + + this._processTabs(); + + if ( active === null ) { + // check the fragment identifier in the URL + if ( locationHash ) { + this.tabs.each(function( i, tab ) { + if ( $( tab ).attr( "aria-controls" ) === locationHash ) { + active = i; + return false; + } + }); } - this.range = $( "
        " ) - .appendTo( this.element ) - .addClass( "ui-slider-range" + - // note: this isn't the most fittingly semantic framework class for this element, - // but worked best visually with a variety of themes - " ui-widget-header" + - ( ( o.range === "min" || o.range === "max" ) ? " ui-slider-range-" + o.range : "" ) ); - } + // check for a tab marked active via a class + if ( active === null ) { + active = this.tabs.index( this.tabs.filter( ".ui-tabs-active" ) ); + } - for ( var i = existingHandles.length; i < handleCount; i += 1 ) { - handles.push( handle ); + // no active tab, set to false + if ( active === null || active === -1 ) { + active = this.tabs.length ? 0 : false; + } } - this.handles = existingHandles.add( $( handles.join( "" ) ).appendTo( self.element ) ); + // handle numbers: negative, out of range + if ( active !== false ) { + active = this.tabs.index( this.tabs.eq( active ) ); + if ( active === -1 ) { + active = options.collapsible ? false : 0; + } + } + options.active = active; - this.handle = this.handles.eq( 0 ); + // don't allow collapsible: false and active: false + if ( !options.collapsible && options.active === false && this.anchors.length ) { + options.active = 0; + } - this.handles.add( this.range ).filter( "a" ) - .click(function( event ) { - event.preventDefault(); - }) - .hover(function() { - if ( !o.disabled ) { - $( this ).addClass( "ui-state-hover" ); - } - }, function() { - $( this ).removeClass( "ui-state-hover" ); - }) - .focus(function() { - if ( !o.disabled ) { - $( ".ui-slider .ui-state-focus" ).removeClass( "ui-state-focus" ); - $( this ).addClass( "ui-state-focus" ); - } else { - $( this ).blur(); - } - }) - .blur(function() { - $( this ).removeClass( "ui-state-focus" ); - }); + // Take disabling tabs via class attribute from HTML + // into account and update option properly. + if ( $.isArray( options.disabled ) ) { + options.disabled = $.unique( options.disabled.concat( + $.map( this.tabs.filter( ".ui-state-disabled" ), function( li ) { + return that.tabs.index( li ); + }) + ) ).sort(); + } - this.handles.each(function( i ) { - $( this ).data( "index.ui-slider-handle", i ); - }); + // check for length avoids error when initializing empty list + if ( this.options.active !== false && this.anchors.length ) { + this.active = this._findActive( this.options.active ); + } else { + this.active = $(); + } - this.handles - .keydown(function( event ) { - var ret = true, - index = $( this ).data( "index.ui-slider-handle" ), - allowed, - curVal, - newVal, - step; - - if ( self.options.disabled ) { - return; - } - - switch ( event.keyCode ) { - case $.ui.keyCode.HOME: - case $.ui.keyCode.END: - case $.ui.keyCode.PAGE_UP: - case $.ui.keyCode.PAGE_DOWN: - case $.ui.keyCode.UP: - case $.ui.keyCode.RIGHT: - case $.ui.keyCode.DOWN: - case $.ui.keyCode.LEFT: - ret = false; - if ( !self._keySliding ) { - self._keySliding = true; - $( this ).addClass( "ui-state-active" ); - allowed = self._start( event, index ); - if ( allowed === false ) { - return; - } - } - break; - } - - step = self.options.step; - if ( self.options.values && self.options.values.length ) { - curVal = newVal = self.values( index ); - } else { - curVal = newVal = self.value(); - } - - switch ( event.keyCode ) { - case $.ui.keyCode.HOME: - newVal = self._valueMin(); - break; - case $.ui.keyCode.END: - newVal = self._valueMax(); - break; - case $.ui.keyCode.PAGE_UP: - newVal = self._trimAlignValue( curVal + ( (self._valueMax() - self._valueMin()) / numPages ) ); - break; - case $.ui.keyCode.PAGE_DOWN: - newVal = self._trimAlignValue( curVal - ( (self._valueMax() - self._valueMin()) / numPages ) ); - break; - case $.ui.keyCode.UP: - case $.ui.keyCode.RIGHT: - if ( curVal === self._valueMax() ) { - return; - } - newVal = self._trimAlignValue( curVal + step ); - break; - case $.ui.keyCode.DOWN: - case $.ui.keyCode.LEFT: - if ( curVal === self._valueMin() ) { - return; - } - newVal = self._trimAlignValue( curVal - step ); - break; - } - - self._slide( event, index, newVal ); - - return ret; - - }) - .keyup(function( event ) { - var index = $( this ).data( "index.ui-slider-handle" ); - - if ( self._keySliding ) { - self._keySliding = false; - self._stop( event, index ); - self._change( event, index ); - $( this ).removeClass( "ui-state-active" ); - } - - }); + this._refresh(); - this._refreshValue(); + if ( this.active.length ) { + this.load( options.active ); + } + }, - this._animateOff = false; + _getCreateEventData: function() { + return { + tab: this.active, + panel: !this.active.length ? $() : this._getPanelForTab( this.active ) + }; }, - destroy: function() { - this.handles.remove(); - this.range.remove(); + _tabKeydown: function( event ) { + var focusedTab = $( this.document[0].activeElement ).closest( "li" ), + selectedIndex = this.tabs.index( focusedTab ), + goingForward = true; - this.element - .removeClass( "ui-slider" + - " ui-slider-horizontal" + - " ui-slider-vertical" + - " ui-slider-disabled" + - " ui-widget" + - " ui-widget-content" + - " ui-corner-all" ) - .removeData( "slider" ) - .unbind( ".slider" ); + if ( this._handlePageNav( event ) ) { + return; + } - this._mouseDestroy(); + switch ( event.keyCode ) { + case $.ui.keyCode.RIGHT: + case $.ui.keyCode.DOWN: + selectedIndex++; + break; + case $.ui.keyCode.UP: + case $.ui.keyCode.LEFT: + goingForward = false; + selectedIndex--; + break; + case $.ui.keyCode.END: + selectedIndex = this.anchors.length - 1; + break; + case $.ui.keyCode.HOME: + selectedIndex = 0; + break; + case $.ui.keyCode.SPACE: + // Activate only, no collapsing + event.preventDefault(); + clearTimeout( this.activating ); + this._activate( selectedIndex ); + return; + case $.ui.keyCode.ENTER: + // Toggle (cancel delayed activation, allow collapsing) + event.preventDefault(); + clearTimeout( this.activating ); + // Determine if we should collapse or activate + this._activate( selectedIndex === this.options.active ? false : selectedIndex ); + return; + default: + return; + } - return this; + // Focus the appropriate tab, based on which key was pressed + event.preventDefault(); + clearTimeout( this.activating ); + selectedIndex = this._focusNextTab( selectedIndex, goingForward ); + + // Navigating with control key will prevent automatic activation + if ( !event.ctrlKey ) { + // Update aria-selected immediately so that AT think the tab is already selected. + // Otherwise AT may confuse the user by stating that they need to activate the tab, + // but the tab will already be activated by the time the announcement finishes. + focusedTab.attr( "aria-selected", "false" ); + this.tabs.eq( selectedIndex ).attr( "aria-selected", "true" ); + + this.activating = this._delay(function() { + this.option( "active", selectedIndex ); + }, this.delay ); + } }, - _mouseCapture: function( event ) { - var o = this.options, - position, - normValue, - distance, - closestHandle, - self, - index, - allowed, - offset, - mouseOverHandle; + _panelKeydown: function( event ) { + if ( this._handlePageNav( event ) ) { + return; + } - if ( o.disabled ) { - return false; + // Ctrl+up moves focus to the current tab + if ( event.ctrlKey && event.keyCode === $.ui.keyCode.UP ) { + event.preventDefault(); + this.active.focus(); } + }, - this.elementSize = { - width: this.element.outerWidth(), - height: this.element.outerHeight() - }; - this.elementOffset = this.element.offset(); + // Alt+page up/down moves focus to the previous/next tab (and activates) + _handlePageNav: function( event ) { + if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_UP ) { + this._activate( this._focusNextTab( this.options.active - 1, false ) ); + return true; + } + if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_DOWN ) { + this._activate( this._focusNextTab( this.options.active + 1, true ) ); + return true; + } + }, - position = { x: event.pageX, y: event.pageY }; - normValue = this._normValueFromMouse( position ); - distance = this._valueMax() - this._valueMin() + 1; - self = this; - this.handles.each(function( i ) { - var thisDistance = Math.abs( normValue - self.values(i) ); - if ( distance > thisDistance ) { - distance = thisDistance; - closestHandle = $( this ); - index = i; + _findNextTab: function( index, goingForward ) { + var lastTabIndex = this.tabs.length - 1; + + function constrain() { + if ( index > lastTabIndex ) { + index = 0; } - }); + if ( index < 0 ) { + index = lastTabIndex; + } + return index; + } - // workaround for bug #3736 (if both handles of a range are at 0, - // the first is always used as the one with least distance, - // and moving it is obviously prevented by preventing negative ranges) - if( o.range === true && this.values(1) === o.min ) { - index += 1; - closestHandle = $( this.handles[index] ); + while ( $.inArray( constrain(), this.options.disabled ) !== -1 ) { + index = goingForward ? index + 1 : index - 1; } - allowed = this._start( event, index ); - if ( allowed === false ) { - return false; + return index; + }, + + _focusNextTab: function( index, goingForward ) { + index = this._findNextTab( index, goingForward ); + this.tabs.eq( index ).focus(); + return index; + }, + + _setOption: function( key, value ) { + if ( key === "active" ) { + // _activate() will handle invalid values and update this.options + this._activate( value ); + return; + } + + if ( key === "disabled" ) { + // don't use the widget factory's disabled handling + this._setupDisabled( value ); + return; } - this._mouseSliding = true; - self._handleIndex = index; + this._super( key, value); - closestHandle - .addClass( "ui-state-active" ) - .focus(); - - offset = closestHandle.offset(); - mouseOverHandle = !$( event.target ).parents().andSelf().is( ".ui-slider-handle" ); - this._clickOffset = mouseOverHandle ? { left: 0, top: 0 } : { - left: event.pageX - offset.left - ( closestHandle.width() / 2 ), - top: event.pageY - offset.top - - ( closestHandle.height() / 2 ) - - ( parseInt( closestHandle.css("borderTopWidth"), 10 ) || 0 ) - - ( parseInt( closestHandle.css("borderBottomWidth"), 10 ) || 0) + - ( parseInt( closestHandle.css("marginTop"), 10 ) || 0) - }; + if ( key === "collapsible" ) { + this.element.toggleClass( "ui-tabs-collapsible", value ); + // Setting collapsible: false while collapsed; open first panel + if ( !value && this.options.active === false ) { + this._activate( 0 ); + } + } - if ( !this.handles.hasClass( "ui-state-hover" ) ) { - this._slide( event, index, normValue ); + if ( key === "event" ) { + this._setupEvents( value ); } - this._animateOff = true; - return true; - }, - _mouseStart: function( event ) { - return true; + if ( key === "heightStyle" ) { + this._setupHeightStyle( value ); + } }, - _mouseDrag: function( event ) { - var position = { x: event.pageX, y: event.pageY }, - normValue = this._normValueFromMouse( position ); - - this._slide( event, this._handleIndex, normValue ); + _tabId: function( tab ) { + return tab.attr( "aria-controls" ) || "ui-tabs-" + getNextTabId(); + }, - return false; + _sanitizeSelector: function( hash ) { + return hash ? hash.replace( /[!"$%&'()*+,.\/:;<=>?@\[\]\^`{|}~]/g, "\\$&" ) : ""; }, - _mouseStop: function( event ) { - this.handles.removeClass( "ui-state-active" ); - this._mouseSliding = false; + refresh: function() { + var options = this.options, + lis = this.tablist.children( ":has(a[href])" ); - this._stop( event, this._handleIndex ); - this._change( event, this._handleIndex ); + // get disabled tabs from class attribute from HTML + // this will get converted to a boolean if needed in _refresh() + options.disabled = $.map( lis.filter( ".ui-state-disabled" ), function( tab ) { + return lis.index( tab ); + }); - this._handleIndex = null; - this._clickOffset = null; - this._animateOff = false; + this._processTabs(); + + // was collapsed or no tabs + if ( options.active === false || !this.anchors.length ) { + options.active = false; + this.active = $(); + // was active, but active tab is gone + } else if ( this.active.length && !$.contains( this.tablist[ 0 ], this.active[ 0 ] ) ) { + // all remaining tabs are disabled + if ( this.tabs.length === options.disabled.length ) { + options.active = false; + this.active = $(); + // activate previous tab + } else { + this._activate( this._findNextTab( Math.max( 0, options.active - 1 ), false ) ); + } + // was active, active tab still exists + } else { + // make sure active index is correct + options.active = this.tabs.index( this.active ); + } - return false; - }, - - _detectOrientation: function() { - this.orientation = ( this.options.orientation === "vertical" ) ? "vertical" : "horizontal"; + this._refresh(); }, - _normValueFromMouse: function( position ) { - var pixelTotal, - pixelMouse, - percentMouse, - valueTotal, - valueMouse; + _refresh: function() { + this._setupDisabled( this.options.disabled ); + this._setupEvents( this.options.event ); + this._setupHeightStyle( this.options.heightStyle ); - if ( this.orientation === "horizontal" ) { - pixelTotal = this.elementSize.width; - pixelMouse = position.x - this.elementOffset.left - ( this._clickOffset ? this._clickOffset.left : 0 ); + this.tabs.not( this.active ).attr({ + "aria-selected": "false", + tabIndex: -1 + }); + this.panels.not( this._getPanelForTab( this.active ) ) + .hide() + .attr({ + "aria-expanded": "false", + "aria-hidden": "true" + }); + + // Make sure one tab is in the tab order + if ( !this.active.length ) { + this.tabs.eq( 0 ).attr( "tabIndex", 0 ); } else { - pixelTotal = this.elementSize.height; - pixelMouse = position.y - this.elementOffset.top - ( this._clickOffset ? this._clickOffset.top : 0 ); + this.active + .addClass( "ui-tabs-active ui-state-active" ) + .attr({ + "aria-selected": "true", + tabIndex: 0 + }); + this._getPanelForTab( this.active ) + .show() + .attr({ + "aria-expanded": "true", + "aria-hidden": "false" + }); } + }, - percentMouse = ( pixelMouse / pixelTotal ); - if ( percentMouse > 1 ) { - percentMouse = 1; - } - if ( percentMouse < 0 ) { - percentMouse = 0; - } - if ( this.orientation === "vertical" ) { - percentMouse = 1 - percentMouse; - } + _processTabs: function() { + var that = this; - valueTotal = this._valueMax() - this._valueMin(); - valueMouse = this._valueMin() + percentMouse * valueTotal; + this.tablist = this._getList() + .addClass( "ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all" ) + .attr( "role", "tablist" ); - return this._trimAlignValue( valueMouse ); - }, + this.tabs = this.tablist.find( "> li:has(a[href])" ) + .addClass( "ui-state-default ui-corner-top" ) + .attr({ + role: "tab", + tabIndex: -1 + }); - _start: function( event, index ) { - var uiHash = { - handle: this.handles[ index ], - value: this.value() - }; - if ( this.options.values && this.options.values.length ) { - uiHash.value = this.values( index ); - uiHash.values = this.values(); - } - return this._trigger( "start", event, uiHash ); - }, + this.anchors = this.tabs.map(function() { + return $( "a", this )[ 0 ]; + }) + .addClass( "ui-tabs-anchor" ) + .attr({ + role: "presentation", + tabIndex: -1 + }); - _slide: function( event, index, newVal ) { - var otherVal, - newValues, - allowed; + this.panels = $(); - if ( this.options.values && this.options.values.length ) { - otherVal = this.values( index ? 0 : 1 ); + this.anchors.each(function( i, anchor ) { + var selector, panel, panelId, + anchorId = $( anchor ).uniqueId().attr( "id" ), + tab = $( anchor ).closest( "li" ), + originalAriaControls = tab.attr( "aria-controls" ); - if ( ( this.options.values.length === 2 && this.options.range === true ) && - ( ( index === 0 && newVal > otherVal) || ( index === 1 && newVal < otherVal ) ) - ) { - newVal = otherVal; + // inline tab + if ( isLocal( anchor ) ) { + selector = anchor.hash; + panel = that.element.find( that._sanitizeSelector( selector ) ); + // remote tab + } else { + panelId = that._tabId( tab ); + selector = "#" + panelId; + panel = that.element.find( selector ); + if ( !panel.length ) { + panel = that._createPanel( panelId ); + panel.insertAfter( that.panels[ i - 1 ] || that.tablist ); + } + panel.attr( "aria-live", "polite" ); } - if ( newVal !== this.values( index ) ) { - newValues = this.values(); - newValues[ index ] = newVal; - // A slide can be canceled by returning false from the slide callback - allowed = this._trigger( "slide", event, { - handle: this.handles[ index ], - value: newVal, - values: newValues - } ); - otherVal = this.values( index ? 0 : 1 ); - if ( allowed !== false ) { - this.values( index, newVal, true ); - } + if ( panel.length) { + that.panels = that.panels.add( panel ); } - } else { - if ( newVal !== this.value() ) { - // A slide can be canceled by returning false from the slide callback - allowed = this._trigger( "slide", event, { - handle: this.handles[ index ], - value: newVal - } ); - if ( allowed !== false ) { - this.value( newVal ); - } + if ( originalAriaControls ) { + tab.data( "ui-tabs-aria-controls", originalAriaControls ); } - } + tab.attr({ + "aria-controls": selector.substring( 1 ), + "aria-labelledby": anchorId + }); + panel.attr( "aria-labelledby", anchorId ); + }); + + this.panels + .addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" ) + .attr( "role", "tabpanel" ); }, - _stop: function( event, index ) { - var uiHash = { - handle: this.handles[ index ], - value: this.value() - }; - if ( this.options.values && this.options.values.length ) { - uiHash.value = this.values( index ); - uiHash.values = this.values(); - } + // allow overriding how to find the list for rare usage scenarios (#7715) + _getList: function() { + return this.element.find( "ol,ul" ).eq( 0 ); + }, - this._trigger( "stop", event, uiHash ); + _createPanel: function( id ) { + return $( "
        " ) + .attr( "id", id ) + .addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" ) + .data( "ui-tabs-destroy", true ); }, - _change: function( event, index ) { - if ( !this._keySliding && !this._mouseSliding ) { - var uiHash = { - handle: this.handles[ index ], - value: this.value() - }; - if ( this.options.values && this.options.values.length ) { - uiHash.value = this.values( index ); - uiHash.values = this.values(); + _setupDisabled: function( disabled ) { + if ( $.isArray( disabled ) ) { + if ( !disabled.length ) { + disabled = false; + } else if ( disabled.length === this.anchors.length ) { + disabled = true; } + } - this._trigger( "change", event, uiHash ); + // disable tabs + for ( var i = 0, li; ( li = this.tabs[ i ] ); i++ ) { + if ( disabled === true || $.inArray( i, disabled ) !== -1 ) { + $( li ) + .addClass( "ui-state-disabled" ) + .attr( "aria-disabled", "true" ); + } else { + $( li ) + .removeClass( "ui-state-disabled" ) + .removeAttr( "aria-disabled" ); + } } + + this.options.disabled = disabled; }, - value: function( newValue ) { - if ( arguments.length ) { - this.options.value = this._trimAlignValue( newValue ); - this._refreshValue(); - this._change( null, 0 ); - return; + _setupEvents: function( event ) { + var events = { + click: function( event ) { + event.preventDefault(); + } + }; + if ( event ) { + $.each( event.split(" "), function( index, eventName ) { + events[ eventName ] = "_eventHandler"; + }); } - return this._value(); + this._off( this.anchors.add( this.tabs ).add( this.panels ) ); + this._on( this.anchors, events ); + this._on( this.tabs, { keydown: "_tabKeydown" } ); + this._on( this.panels, { keydown: "_panelKeydown" } ); + + this._focusable( this.tabs ); + this._hoverable( this.tabs ); }, - values: function( index, newValue ) { - var vals, - newValues, - i; + _setupHeightStyle: function( heightStyle ) { + var maxHeight, overflow, + parent = this.element.parent(); - if ( arguments.length > 1 ) { - this.options.values[ index ] = this._trimAlignValue( newValue ); - this._refreshValue(); - this._change( null, index ); - return; - } + if ( heightStyle === "fill" ) { + // IE 6 treats height like minHeight, so we need to turn off overflow + // in order to get a reliable height + // we use the minHeight support test because we assume that only + // browsers that don't support minHeight will treat height as minHeight + if ( !$.support.minHeight ) { + overflow = parent.css( "overflow" ); + parent.css( "overflow", "hidden"); + } + maxHeight = parent.height(); + this.element.siblings( ":visible" ).each(function() { + var elem = $( this ), + position = elem.css( "position" ); - if ( arguments.length ) { - if ( $.isArray( arguments[ 0 ] ) ) { - vals = this.options.values; - newValues = arguments[ 0 ]; - for ( i = 0; i < vals.length; i += 1 ) { - vals[ i ] = this._trimAlignValue( newValues[ i ] ); - this._change( null, i ); - } - this._refreshValue(); - } else { - if ( this.options.values && this.options.values.length ) { - return this._values( index ); - } else { - return this.value(); + if ( position === "absolute" || position === "fixed" ) { + return; } + maxHeight -= elem.outerHeight( true ); + }); + if ( overflow ) { + parent.css( "overflow", overflow ); } - } else { - return this._values(); + + this.element.children().not( this.panels ).each(function() { + maxHeight -= $( this ).outerHeight( true ); + }); + + this.panels.each(function() { + $( this ).height( Math.max( 0, maxHeight - + $( this ).innerHeight() + $( this ).height() ) ); + }) + .css( "overflow", "auto" ); + } else if ( heightStyle === "auto" ) { + maxHeight = 0; + this.panels.each(function() { + maxHeight = Math.max( maxHeight, $( this ).height( "" ).height() ); + }).height( maxHeight ); } }, - _setOption: function( key, value ) { - var i, - valsLength = 0; + _eventHandler: function( event ) { + var options = this.options, + active = this.active, + anchor = $( event.currentTarget ), + tab = anchor.closest( "li" ), + clickedIsActive = tab[ 0 ] === active[ 0 ], + collapsing = clickedIsActive && options.collapsible, + toShow = collapsing ? $() : this._getPanelForTab( tab ), + toHide = !active.length ? $() : this._getPanelForTab( active ), + eventData = { + oldTab: active, + oldPanel: toHide, + newTab: collapsing ? $() : tab, + newPanel: toShow + }; - if ( $.isArray( this.options.values ) ) { - valsLength = this.options.values.length; + event.preventDefault(); + + if ( tab.hasClass( "ui-state-disabled" ) || + // tab is already loading + tab.hasClass( "ui-tabs-loading" ) || + // can't switch durning an animation + this.running || + // click on active header, but not collapsible + ( clickedIsActive && !options.collapsible ) || + // allow canceling activation + ( this._trigger( "beforeActivate", event, eventData ) === false ) ) { + return; } - $.Widget.prototype._setOption.apply( this, arguments ); + options.active = collapsing ? false : this.tabs.index( tab ); - switch ( key ) { - case "disabled": - if ( value ) { - this.handles.filter( ".ui-state-focus" ).blur(); - this.handles.removeClass( "ui-state-hover" ); - this.handles.propAttr( "disabled", true ); - this.element.addClass( "ui-disabled" ); - } else { - this.handles.propAttr( "disabled", false ); - this.element.removeClass( "ui-disabled" ); - } - break; - case "orientation": - this._detectOrientation(); - this.element - .removeClass( "ui-slider-horizontal ui-slider-vertical" ) - .addClass( "ui-slider-" + this.orientation ); - this._refreshValue(); - break; - case "value": - this._animateOff = true; - this._refreshValue(); - this._change( null, 0 ); - this._animateOff = false; - break; - case "values": - this._animateOff = true; - this._refreshValue(); - for ( i = 0; i < valsLength; i += 1 ) { - this._change( null, i ); - } - this._animateOff = false; - break; + this.active = clickedIsActive ? $() : tab; + if ( this.xhr ) { + this.xhr.abort(); } - }, - //internal value getter - // _value() returns value trimmed by min and max, aligned by step - _value: function() { - var val = this.options.value; - val = this._trimAlignValue( val ); + if ( !toHide.length && !toShow.length ) { + $.error( "jQuery UI Tabs: Mismatching fragment identifier." ); + } - return val; + if ( toShow.length ) { + this.load( this.tabs.index( tab ), event ); + } + this._toggle( event, eventData ); }, - //internal values getter - // _values() returns array of values trimmed by min and max, aligned by step - // _values( index ) returns single value trimmed by min and max, aligned by step - _values: function( index ) { - var val, - vals, - i; + // handles show/hide for selecting tabs + _toggle: function( event, eventData ) { + var that = this, + toShow = eventData.newPanel, + toHide = eventData.oldPanel; - if ( arguments.length ) { - val = this.options.values[ index ]; - val = this._trimAlignValue( val ); + this.running = true; - return val; - } else { - // .slice() creates a copy of the array - // this copy gets trimmed by min and max and then returned - vals = this.options.values.slice(); - for ( i = 0; i < vals.length; i+= 1) { - vals[ i ] = this._trimAlignValue( vals[ i ] ); + function complete() { + that.running = false; + that._trigger( "activate", event, eventData ); + } + + function show() { + eventData.newTab.closest( "li" ).addClass( "ui-tabs-active ui-state-active" ); + + if ( toShow.length && that.options.show ) { + that._show( toShow, that.options.show, complete ); + } else { + toShow.show(); + complete(); } + } - return vals; + // start out by hiding, then showing, then completing + if ( toHide.length && this.options.hide ) { + this._hide( toHide, this.options.hide, function() { + eventData.oldTab.closest( "li" ).removeClass( "ui-tabs-active ui-state-active" ); + show(); + }); + } else { + eventData.oldTab.closest( "li" ).removeClass( "ui-tabs-active ui-state-active" ); + toHide.hide(); + show(); } - }, - - // returns the step-aligned value that val is closest to, between (inclusive) min and max - _trimAlignValue: function( val ) { - if ( val <= this._valueMin() ) { - return this._valueMin(); + + toHide.attr({ + "aria-expanded": "false", + "aria-hidden": "true" + }); + eventData.oldTab.attr( "aria-selected", "false" ); + // If we're switching tabs, remove the old tab from the tab order. + // If we're opening from collapsed state, remove the previous tab from the tab order. + // If we're collapsing, then keep the collapsing tab in the tab order. + if ( toShow.length && toHide.length ) { + eventData.oldTab.attr( "tabIndex", -1 ); + } else if ( toShow.length ) { + this.tabs.filter(function() { + return $( this ).attr( "tabIndex" ) === 0; + }) + .attr( "tabIndex", -1 ); } - if ( val >= this._valueMax() ) { - return this._valueMax(); + + toShow.attr({ + "aria-expanded": "true", + "aria-hidden": "false" + }); + eventData.newTab.attr({ + "aria-selected": "true", + tabIndex: 0 + }); + }, + + _activate: function( index ) { + var anchor, + active = this._findActive( index ); + + // trying to activate the already active panel + if ( active[ 0 ] === this.active[ 0 ] ) { + return; } - var step = ( this.options.step > 0 ) ? this.options.step : 1, - valModStep = (val - this._valueMin()) % step, - alignValue = val - valModStep; - if ( Math.abs(valModStep) * 2 >= step ) { - alignValue += ( valModStep > 0 ) ? step : ( -step ); + // trying to collapse, simulate a click on the current active header + if ( !active.length ) { + active = this.active; } - // Since JavaScript has problems with large floats, round - // the final value to 5 digits after the decimal point (see #4124) - return parseFloat( alignValue.toFixed(5) ); + anchor = active.find( ".ui-tabs-anchor" )[ 0 ]; + this._eventHandler({ + target: anchor, + currentTarget: anchor, + preventDefault: $.noop + }); }, - _valueMin: function() { - return this.options.min; + _findActive: function( index ) { + return index === false ? $() : this.tabs.eq( index ); }, - _valueMax: function() { - return this.options.max; - }, - - _refreshValue: function() { - var oRange = this.options.range, - o = this.options, - self = this, - animate = ( !this._animateOff ) ? o.animate : false, - valPercent, - _set = {}, - lastValPercent, - value, - valueMin, - valueMax; + _getIndex: function( index ) { + // meta-function to give users option to provide a href string instead of a numerical index. + if ( typeof index === "string" ) { + index = this.anchors.index( this.anchors.filter( "[href$='" + index + "']" ) ); + } - if ( this.options.values && this.options.values.length ) { - this.handles.each(function( i, j ) { - valPercent = ( self.values(i) - self._valueMin() ) / ( self._valueMax() - self._valueMin() ) * 100; - _set[ self.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%"; - $( this ).stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate ); - if ( self.options.range === true ) { - if ( self.orientation === "horizontal" ) { - if ( i === 0 ) { - self.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { left: valPercent + "%" }, o.animate ); - } - if ( i === 1 ) { - self.range[ animate ? "animate" : "css" ]( { width: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: o.animate } ); - } - } else { - if ( i === 0 ) { - self.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { bottom: ( valPercent ) + "%" }, o.animate ); - } - if ( i === 1 ) { - self.range[ animate ? "animate" : "css" ]( { height: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: o.animate } ); - } - } - } - lastValPercent = valPercent; - }); - } else { - value = this.value(); - valueMin = this._valueMin(); - valueMax = this._valueMax(); - valPercent = ( valueMax !== valueMin ) ? - ( value - valueMin ) / ( valueMax - valueMin ) * 100 : - 0; - _set[ self.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%"; - this.handle.stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate ); + return index; + }, - if ( oRange === "min" && this.orientation === "horizontal" ) { - this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { width: valPercent + "%" }, o.animate ); - } - if ( oRange === "max" && this.orientation === "horizontal" ) { - this.range[ animate ? "animate" : "css" ]( { width: ( 100 - valPercent ) + "%" }, { queue: false, duration: o.animate } ); - } - if ( oRange === "min" && this.orientation === "vertical" ) { - this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { height: valPercent + "%" }, o.animate ); - } - if ( oRange === "max" && this.orientation === "vertical" ) { - this.range[ animate ? "animate" : "css" ]( { height: ( 100 - valPercent ) + "%" }, { queue: false, duration: o.animate } ); - } + _destroy: function() { + if ( this.xhr ) { + this.xhr.abort(); } - } -}); + this.element.removeClass( "ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible" ); -$.extend( $.ui.slider, { - version: "1.8.16" -}); + this.tablist + .removeClass( "ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all" ) + .removeAttr( "role" ); -}(jQuery)); -/* - * jQuery UI Tabs 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Tabs - * - * Depends: - * jquery.ui.core.js - * jquery.ui.widget.js - */ -(function( $, undefined ) { + this.anchors + .removeClass( "ui-tabs-anchor" ) + .removeAttr( "role" ) + .removeAttr( "tabIndex" ) + .removeData( "href.tabs" ) + .removeData( "load.tabs" ) + .removeUniqueId(); -var tabId = 0, - listId = 0; + this.tabs.add( this.panels ).each(function() { + if ( $.data( this, "ui-tabs-destroy" ) ) { + $( this ).remove(); + } else { + $( this ) + .removeClass( "ui-state-default ui-state-active ui-state-disabled " + + "ui-corner-top ui-corner-bottom ui-widget-content ui-tabs-active ui-tabs-panel" ) + .removeAttr( "tabIndex" ) + .removeAttr( "aria-live" ) + .removeAttr( "aria-busy" ) + .removeAttr( "aria-selected" ) + .removeAttr( "aria-labelledby" ) + .removeAttr( "aria-hidden" ) + .removeAttr( "aria-expanded" ) + .removeAttr( "role" ); + } + }); -function getNextTabId() { - return ++tabId; -} + this.tabs.each(function() { + var li = $( this ), + prev = li.data( "ui-tabs-aria-controls" ); + if ( prev ) { + li.attr( "aria-controls", prev ); + } else { + li.removeAttr( "aria-controls" ); + } + }); -function getNextListId() { - return ++listId; -} + this.panels.show(); -$.widget( "ui.tabs", { - options: { - add: null, - ajaxOptions: null, - cache: false, - cookie: null, // e.g. { expires: 7, path: '/', domain: 'jquery.com', secure: true } - collapsible: false, - disable: null, - disabled: [], - enable: null, - event: "click", - fx: null, // e.g. { height: 'toggle', opacity: 'toggle', duration: 200 } - idPrefix: "ui-tabs-", - load: null, - panelTemplate: "
        ", - remove: null, - select: null, - show: null, - spinner: "Loading…", - tabTemplate: "
      • #{label}
      • " + if ( this.options.heightStyle !== "content" ) { + this.panels.css( "height", "" ); + } }, - _create: function() { - this._tabify( true ); + enable: function( index ) { + var disabled = this.options.disabled; + if ( disabled === false ) { + return; + } + + if ( index === undefined ) { + disabled = false; + } else { + index = this._getIndex( index ); + if ( $.isArray( disabled ) ) { + disabled = $.map( disabled, function( num ) { + return num !== index ? num : null; + }); + } else { + disabled = $.map( this.tabs, function( li, num ) { + return num !== index ? num : null; + }); + } + } + this._setupDisabled( disabled ); }, - _setOption: function( key, value ) { - if ( key == "selected" ) { - if (this.options.collapsible && value == this.options.selected ) { + disable: function( index ) { + var disabled = this.options.disabled; + if ( disabled === true ) { + return; + } + + if ( index === undefined ) { + disabled = true; + } else { + index = this._getIndex( index ); + if ( $.inArray( index, disabled ) !== -1 ) { return; } - this.select( value ); - } else { - this.options[ key ] = value; - this._tabify(); + if ( $.isArray( disabled ) ) { + disabled = $.merge( [ index ], disabled ).sort(); + } else { + disabled = [ index ]; + } } + this._setupDisabled( disabled ); }, - _tabId: function( a ) { - return a.title && a.title.replace( /\s/g, "_" ).replace( /[^\w\u00c0-\uFFFF-]/g, "" ) || - this.options.idPrefix + getNextTabId(); - }, + load: function( index, event ) { + index = this._getIndex( index ); + var that = this, + tab = this.tabs.eq( index ), + anchor = tab.find( ".ui-tabs-anchor" ), + panel = this._getPanelForTab( tab ), + eventData = { + tab: tab, + panel: panel + }; - _sanitizeSelector: function( hash ) { - // we need this because an id may contain a ":" - return hash.replace( /:/g, "\\:" ); + // not remote + if ( isLocal( anchor[ 0 ] ) ) { + return; + } + + this.xhr = $.ajax( this._ajaxSettings( anchor, event, eventData ) ); + + // support: jQuery <1.8 + // jQuery <1.8 returns false if the request is canceled in beforeSend, + // but as of 1.8, $.ajax() always returns a jqXHR object. + if ( this.xhr && this.xhr.statusText !== "canceled" ) { + tab.addClass( "ui-tabs-loading" ); + panel.attr( "aria-busy", "true" ); + + this.xhr + .success(function( response ) { + // support: jQuery <1.8 + // http://bugs.jquery.com/ticket/11778 + setTimeout(function() { + panel.html( response ); + that._trigger( "load", event, eventData ); + }, 1 ); + }) + .complete(function( jqXHR, status ) { + // support: jQuery <1.8 + // http://bugs.jquery.com/ticket/11778 + setTimeout(function() { + if ( status === "abort" ) { + that.panels.stop( false, true ); + } + + tab.removeClass( "ui-tabs-loading" ); + panel.removeAttr( "aria-busy" ); + + if ( jqXHR === that.xhr ) { + delete that.xhr; + } + }, 1 ); + }); + } }, - _cookie: function() { - var cookie = this.cookie || - ( this.cookie = this.options.cookie.name || "ui-tabs-" + getNextListId() ); - return $.cookie.apply( null, [ cookie ].concat( $.makeArray( arguments ) ) ); + // TODO: Remove this function in 1.10 when ajaxOptions is removed + _ajaxSettings: function( anchor, event, eventData ) { + var that = this; + return { + url: anchor.attr( "href" ), + beforeSend: function( jqXHR, settings ) { + return that._trigger( "beforeLoad", event, + $.extend( { jqXHR : jqXHR, ajaxSettings: settings }, eventData ) ); + } + }; }, - _ui: function( tab, panel ) { + _getPanelForTab: function( tab ) { + var id = $( tab ).attr( "aria-controls" ); + return this.element.find( this._sanitizeSelector( "#" + id ) ); + } +}); + +// DEPRECATED +if ( $.uiBackCompat !== false ) { + + // helper method for a lot of the back compat extensions + $.ui.tabs.prototype._ui = function( tab, panel ) { return { tab: tab, panel: panel, index: this.anchors.index( tab ) }; - }, + }; - _cleanup: function() { - // restore all former loading tabs labels - this.lis.filter( ".ui-state-processing" ) - .removeClass( "ui-state-processing" ) - .find( "span:data(label.tabs)" ) - .each(function() { - var el = $( this ); - el.html( el.data( "label.tabs" ) ).removeData( "label.tabs" ); + // url method + $.widget( "ui.tabs", $.ui.tabs, { + url: function( index, url ) { + this.anchors.eq( index ).attr( "href", url ); + } + }); + + // TODO: Remove _ajaxSettings() method when removing this extension + // ajaxOptions and cache options + $.widget( "ui.tabs", $.ui.tabs, { + options: { + ajaxOptions: null, + cache: false + }, + + _create: function() { + this._super(); + + var that = this; + + this._on({ tabsbeforeload: function( event, ui ) { + // tab is already cached + if ( $.data( ui.tab[ 0 ], "cache.tabs" ) ) { + event.preventDefault(); + return; + } + + ui.jqXHR.success(function() { + if ( that.options.cache ) { + $.data( ui.tab[ 0 ], "cache.tabs", true ); + } }); - }, + }}); + }, - _tabify: function( init ) { - var self = this, - o = this.options, - fragmentId = /^#.+/; // Safari 2 reports '#' for an empty hash + _ajaxSettings: function( anchor, event, ui ) { + var ajaxOptions = this.options.ajaxOptions; + return $.extend( {}, ajaxOptions, { + error: function( xhr, status ) { + try { + // Passing index avoid a race condition when this method is + // called after the user has selected another tab. + // Pass the anchor that initiated this request allows + // loadError to manipulate the tab content panel via $(a.hash) + ajaxOptions.error( + xhr, status, ui.tab.closest( "li" ).index(), ui.tab[ 0 ] ); + } + catch ( error ) {} + } + }, this._superApply( arguments ) ); + }, - this.list = this.element.find( "ol,ul" ).eq( 0 ); - this.lis = $( " > li:has(a[href])", this.list ); - this.anchors = this.lis.map(function() { - return $( "a", this )[ 0 ]; - }); - this.panels = $( [] ); - - this.anchors.each(function( i, a ) { - var href = $( a ).attr( "href" ); - // For dynamically created HTML that contains a hash as href IE < 8 expands - // such href to the full page url with hash and then misinterprets tab as ajax. - // Same consideration applies for an added tab with a fragment identifier - // since a[href=#fragment-identifier] does unexpectedly not match. - // Thus normalize href attribute... - var hrefBase = href.split( "#" )[ 0 ], - baseEl; - if ( hrefBase && ( hrefBase === location.toString().split( "#" )[ 0 ] || - ( baseEl = $( "base" )[ 0 ]) && hrefBase === baseEl.href ) ) { - href = a.hash; - a.href = href; + _setOption: function( key, value ) { + // reset cache if switching from cached to not cached + if ( key === "cache" && value === false ) { + this.anchors.removeData( "cache.tabs" ); } + this._super( key, value ); + }, - // inline tab - if ( fragmentId.test( href ) ) { - self.panels = self.panels.add( self.element.find( self._sanitizeSelector( href ) ) ); - // remote tab - // prevent loading the page itself if href is just "#" - } else if ( href && href !== "#" ) { - // required for restore on destroy - $.data( a, "href.tabs", href ); - - // TODO until #3808 is fixed strip fragment identifier from url - // (IE fails to load from such url) - $.data( a, "load.tabs", href.replace( /#.*$/, "" ) ); - - var id = self._tabId( a ); - a.href = "#" + id; - var $panel = self.element.find( "#" + id ); - if ( !$panel.length ) { - $panel = $( o.panelTemplate ) - .attr( "id", id ) - .addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" ) - .insertAfter( self.panels[ i - 1 ] || self.list ); - $panel.data( "destroy.tabs", true ); - } - self.panels = self.panels.add( $panel ); - // invalid tab href - } else { - o.disabled.push( i ); + _destroy: function() { + this.anchors.removeData( "cache.tabs" ); + this._super(); + }, + + url: function( index ){ + this.anchors.eq( index ).removeData( "cache.tabs" ); + this._superApply( arguments ); + } + }); + + // abort method + $.widget( "ui.tabs", $.ui.tabs, { + abort: function() { + if ( this.xhr ) { + this.xhr.abort(); } - }); + } + }); - // initialization from scratch - if ( init ) { - // attach necessary classes for styling - this.element.addClass( "ui-tabs ui-widget ui-widget-content ui-corner-all" ); - this.list.addClass( "ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all" ); - this.lis.addClass( "ui-state-default ui-corner-top" ); - this.panels.addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" ); - - // Selected tab - // use "selected" option or try to retrieve: - // 1. from fragment identifier in url - // 2. from cookie - // 3. from selected class attribute on
      • - if ( o.selected === undefined ) { - if ( location.hash ) { - this.anchors.each(function( i, a ) { - if ( a.hash == location.hash ) { - o.selected = i; - return false; - } + // spinner + $.widget( "ui.tabs", $.ui.tabs, { + options: { + spinner: "Loading…" + }, + _create: function() { + this._super(); + this._on({ + tabsbeforeload: function( event, ui ) { + // Don't react to nested tabs or tabs that don't use a spinner + if ( event.target !== this.element[ 0 ] || + !this.options.spinner ) { + return; + } + + var span = ui.tab.find( "span" ), + html = span.html(); + span.html( this.options.spinner ); + ui.jqXHR.complete(function() { + span.html( html ); }); } - if ( typeof o.selected !== "number" && o.cookie ) { - o.selected = parseInt( self._cookie(), 10 ); - } - if ( typeof o.selected !== "number" && this.lis.filter( ".ui-tabs-selected" ).length ) { - o.selected = this.lis.index( this.lis.filter( ".ui-tabs-selected" ) ); + }); + } + }); + + // enable/disable events + $.widget( "ui.tabs", $.ui.tabs, { + options: { + enable: null, + disable: null + }, + + enable: function( index ) { + var options = this.options, + trigger; + + if ( index && options.disabled === true || + ( $.isArray( options.disabled ) && $.inArray( index, options.disabled ) !== -1 ) ) { + trigger = true; + } + + this._superApply( arguments ); + + if ( trigger ) { + this._trigger( "enable", null, this._ui( this.anchors[ index ], this.panels[ index ] ) ); + } + }, + + disable: function( index ) { + var options = this.options, + trigger; + + if ( index && options.disabled === false || + ( $.isArray( options.disabled ) && $.inArray( index, options.disabled ) === -1 ) ) { + trigger = true; + } + + this._superApply( arguments ); + + if ( trigger ) { + this._trigger( "disable", null, this._ui( this.anchors[ index ], this.panels[ index ] ) ); + } + } + }); + + // add/remove methods and events + $.widget( "ui.tabs", $.ui.tabs, { + options: { + add: null, + remove: null, + tabTemplate: "
      • #{label}
      • " + }, + + add: function( url, label, index ) { + if ( index === undefined ) { + index = this.anchors.length; + } + + var doInsertAfter, panel, + options = this.options, + li = $( options.tabTemplate + .replace( /#\{href\}/g, url ) + .replace( /#\{label\}/g, label ) ), + id = !url.indexOf( "#" ) ? + url.replace( "#", "" ) : + this._tabId( li ); + + li.addClass( "ui-state-default ui-corner-top" ).data( "ui-tabs-destroy", true ); + li.attr( "aria-controls", id ); + + doInsertAfter = index >= this.tabs.length; + + // try to find an existing element before creating a new one + panel = this.element.find( "#" + id ); + if ( !panel.length ) { + panel = this._createPanel( id ); + if ( doInsertAfter ) { + if ( index > 0 ) { + panel.insertAfter( this.panels.eq( -1 ) ); + } else { + panel.appendTo( this.element ); + } + } else { + panel.insertBefore( this.panels[ index ] ); } - o.selected = o.selected || ( this.lis.length ? 0 : -1 ); - } else if ( o.selected === null ) { // usage of null is deprecated, TODO remove in next release - o.selected = -1; } + panel.addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" ).hide(); - // sanity check - default to first tab... - o.selected = ( ( o.selected >= 0 && this.anchors[ o.selected ] ) || o.selected < 0 ) - ? o.selected - : 0; + if ( doInsertAfter ) { + li.appendTo( this.tablist ); + } else { + li.insertBefore( this.tabs[ index ] ); + } - // Take disabling tabs via class attribute from HTML - // into account and update option properly. - // A selected tab cannot become disabled. - o.disabled = $.unique( o.disabled.concat( - $.map( this.lis.filter( ".ui-state-disabled" ), function( n, i ) { - return self.lis.index( n ); - }) - ) ).sort(); + options.disabled = $.map( options.disabled, function( n ) { + return n >= index ? ++n : n; + }); - if ( $.inArray( o.selected, o.disabled ) != -1 ) { - o.disabled.splice( $.inArray( o.selected, o.disabled ), 1 ); + this.refresh(); + if ( this.tabs.length === 1 && options.active === false ) { + this.option( "active", 0 ); } - // highlight selected tab - this.panels.addClass( "ui-tabs-hide" ); - this.lis.removeClass( "ui-tabs-selected ui-state-active" ); - // check for length avoids error when initializing empty list - if ( o.selected >= 0 && this.anchors.length ) { - self.element.find( self._sanitizeSelector( self.anchors[ o.selected ].hash ) ).removeClass( "ui-tabs-hide" ); - this.lis.eq( o.selected ).addClass( "ui-tabs-selected ui-state-active" ); + this._trigger( "add", null, this._ui( this.anchors[ index ], this.panels[ index ] ) ); + return this; + }, - // seems to be expected behavior that the show callback is fired - self.element.queue( "tabs", function() { - self._trigger( "show", null, - self._ui( self.anchors[ o.selected ], self.element.find( self._sanitizeSelector( self.anchors[ o.selected ].hash ) )[ 0 ] ) ); - }); + remove: function( index ) { + index = this._getIndex( index ); + var options = this.options, + tab = this.tabs.eq( index ).remove(), + panel = this._getPanelForTab( tab ).remove(); - this.load( o.selected ); + // If selected tab was removed focus tab to the right or + // in case the last tab was removed the tab to the left. + // We check for more than 2 tabs, because if there are only 2, + // then when we remove this tab, there will only be one tab left + // so we don't need to detect which tab to activate. + if ( tab.hasClass( "ui-tabs-active" ) && this.anchors.length > 2 ) { + this._activate( index + ( index + 1 < this.anchors.length ? 1 : -1 ) ); } - // clean up to avoid memory leaks in certain versions of IE 6 - // TODO: namespace this event - $( window ).bind( "unload", function() { - self.lis.add( self.anchors ).unbind( ".tabs" ); - self.lis = self.anchors = self.panels = null; - }); - // update selected after add/remove - } else { - o.selected = this.lis.index( this.lis.filter( ".ui-tabs-selected" ) ); - } + options.disabled = $.map( + $.grep( options.disabled, function( n ) { + return n !== index; + }), + function( n ) { + return n >= index ? --n : n; + }); - // update collapsible - // TODO: use .toggleClass() - this.element[ o.collapsible ? "addClass" : "removeClass" ]( "ui-tabs-collapsible" ); + this.refresh(); - // set or update cookie after init and add/remove respectively - if ( o.cookie ) { - this._cookie( o.selected, o.cookie ); + this._trigger( "remove", null, this._ui( tab.find( "a" )[ 0 ], panel[ 0 ] ) ); + return this; } + }); - // disable tabs - for ( var i = 0, li; ( li = this.lis[ i ] ); i++ ) { - $( li )[ $.inArray( i, o.disabled ) != -1 && - // TODO: use .toggleClass() - !$( li ).hasClass( "ui-tabs-selected" ) ? "addClass" : "removeClass" ]( "ui-state-disabled" ); + // length method + $.widget( "ui.tabs", $.ui.tabs, { + length: function() { + return this.anchors.length; } + }); - // reset cache if switching from cached to not cached - if ( o.cache === false ) { - this.anchors.removeData( "cache.tabs" ); + // panel ids (idPrefix option + title attribute) + $.widget( "ui.tabs", $.ui.tabs, { + options: { + idPrefix: "ui-tabs-" + }, + + _tabId: function( tab ) { + var a = tab.is( "li" ) ? tab.find( "a[href]" ) : tab; + a = a[0]; + return $( a ).closest( "li" ).attr( "aria-controls" ) || + a.title && a.title.replace( /\s/g, "_" ).replace( /[^\w\u00c0-\uFFFF\-]/g, "" ) || + this.options.idPrefix + getNextTabId(); } + }); - // remove all handlers before, tabify may run on existing tabs after add or option change - this.lis.add( this.anchors ).unbind( ".tabs" ); + // _createPanel method + $.widget( "ui.tabs", $.ui.tabs, { + options: { + panelTemplate: "
        " + }, - if ( o.event !== "mouseover" ) { - var addState = function( state, el ) { - if ( el.is( ":not(.ui-state-disabled)" ) ) { - el.addClass( "ui-state-" + state ); - } - }; - var removeState = function( state, el ) { - el.removeClass( "ui-state-" + state ); - }; - this.lis.bind( "mouseover.tabs" , function() { - addState( "hover", $( this ) ); - }); - this.lis.bind( "mouseout.tabs", function() { - removeState( "hover", $( this ) ); - }); - this.anchors.bind( "focus.tabs", function() { - addState( "focus", $( this ).closest( "li" ) ); - }); - this.anchors.bind( "blur.tabs", function() { - removeState( "focus", $( this ).closest( "li" ) ); - }); + _createPanel: function( id ) { + return $( this.options.panelTemplate ) + .attr( "id", id ) + .addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" ) + .data( "ui-tabs-destroy", true ); } + }); - // set up animations - var hideFx, showFx; - if ( o.fx ) { - if ( $.isArray( o.fx ) ) { - hideFx = o.fx[ 0 ]; - showFx = o.fx[ 1 ]; - } else { - hideFx = showFx = o.fx; + // selected option + $.widget( "ui.tabs", $.ui.tabs, { + _create: function() { + var options = this.options; + if ( options.active === null && options.selected !== undefined ) { + options.active = options.selected === -1 ? false : options.selected; } - } - - // Reset certain styles left over from animation - // and prevent IE's ClearType bug... - function resetStyle( $el, fx ) { - $el.css( "display", "" ); - if ( !$.support.opacity && fx.opacity ) { - $el[ 0 ].style.removeAttribute( "filter" ); + this._super(); + options.selected = options.active; + if ( options.selected === false ) { + options.selected = -1; } - } + }, - // Show a tab... - var showTab = showFx - ? function( clicked, $show ) { - $( clicked ).closest( "li" ).addClass( "ui-tabs-selected ui-state-active" ); - $show.hide().removeClass( "ui-tabs-hide" ) // avoid flicker that way - .animate( showFx, showFx.duration || "normal", function() { - resetStyle( $show, showFx ); - self._trigger( "show", null, self._ui( clicked, $show[ 0 ] ) ); - }); + _setOption: function( key, value ) { + if ( key !== "selected" ) { + return this._super( key, value ); } - : function( clicked, $show ) { - $( clicked ).closest( "li" ).addClass( "ui-tabs-selected ui-state-active" ); - $show.removeClass( "ui-tabs-hide" ); - self._trigger( "show", null, self._ui( clicked, $show[ 0 ] ) ); - }; - // Hide a tab, $show is optional... - var hideTab = hideFx - ? function( clicked, $hide ) { - $hide.animate( hideFx, hideFx.duration || "normal", function() { - self.lis.removeClass( "ui-tabs-selected ui-state-active" ); - $hide.addClass( "ui-tabs-hide" ); - resetStyle( $hide, hideFx ); - self.element.dequeue( "tabs" ); - }); + var options = this.options; + this._super( "active", value === -1 ? false : value ); + options.selected = options.active; + if ( options.selected === false ) { + options.selected = -1; } - : function( clicked, $hide, $show ) { - self.lis.removeClass( "ui-tabs-selected ui-state-active" ); - $hide.addClass( "ui-tabs-hide" ); - self.element.dequeue( "tabs" ); - }; + }, - // attach tab event handler, unbind to avoid duplicates from former tabifying... - this.anchors.bind( o.event + ".tabs", function() { - var el = this, - $li = $(el).closest( "li" ), - $hide = self.panels.filter( ":not(.ui-tabs-hide)" ), - $show = self.element.find( self._sanitizeSelector( el.hash ) ); - - // If tab is already selected and not collapsible or tab disabled or - // or is already loading or click callback returns false stop here. - // Check if click handler returns false last so that it is not executed - // for a disabled or loading tab! - if ( ( $li.hasClass( "ui-tabs-selected" ) && !o.collapsible) || - $li.hasClass( "ui-state-disabled" ) || - $li.hasClass( "ui-state-processing" ) || - self.panels.filter( ":animated" ).length || - self._trigger( "select", null, self._ui( this, $show[ 0 ] ) ) === false ) { - this.blur(); - return false; + _eventHandler: function() { + this._superApply( arguments ); + this.options.selected = this.options.active; + if ( this.options.selected === false ) { + this.options.selected = -1; } + } + }); - o.selected = self.anchors.index( this ); - - self.abort(); - - // if tab may be closed - if ( o.collapsible ) { - if ( $li.hasClass( "ui-tabs-selected" ) ) { - o.selected = -1; + // show and select event + $.widget( "ui.tabs", $.ui.tabs, { + options: { + show: null, + select: null + }, + _create: function() { + this._super(); + if ( this.options.active !== false ) { + this._trigger( "show", null, this._ui( + this.active.find( ".ui-tabs-anchor" )[ 0 ], + this._getPanelForTab( this.active )[ 0 ] ) ); + } + }, + _trigger: function( type, event, data ) { + var tab, panel, + ret = this._superApply( arguments ); - if ( o.cookie ) { - self._cookie( o.selected, o.cookie ); - } + if ( !ret ) { + return false; + } - self.element.queue( "tabs", function() { - hideTab( el, $hide ); - }).dequeue( "tabs" ); + if ( type === "beforeActivate" ) { + tab = data.newTab.length ? data.newTab : data.oldTab; + panel = data.newPanel.length ? data.newPanel : data.oldPanel; + ret = this._super( "select", event, { + tab: tab.find( ".ui-tabs-anchor" )[ 0], + panel: panel[ 0 ], + index: tab.closest( "li" ).index() + }); + } else if ( type === "activate" && data.newTab.length ) { + ret = this._super( "show", event, { + tab: data.newTab.find( ".ui-tabs-anchor" )[ 0 ], + panel: data.newPanel[ 0 ], + index: data.newTab.closest( "li" ).index() + }); + } + return ret; + } + }); - this.blur(); - return false; - } else if ( !$hide.length ) { - if ( o.cookie ) { - self._cookie( o.selected, o.cookie ); - } + // select method + $.widget( "ui.tabs", $.ui.tabs, { + select: function( index ) { + index = this._getIndex( index ); + if ( index === -1 ) { + if ( this.options.collapsible && this.options.selected !== -1 ) { + index = this.options.selected; + } else { + return; + } + } + this.anchors.eq( index ).trigger( this.options.event + this.eventNamespace ); + } + }); - self.element.queue( "tabs", function() { - showTab( el, $show ); - }); + // cookie option + (function() { - // TODO make passing in node possible, see also http://dev.jqueryui.com/ticket/3171 - self.load( self.anchors.index( this ) ); + var listId = 0; - this.blur(); - return false; + $.widget( "ui.tabs", $.ui.tabs, { + options: { + cookie: null // e.g. { expires: 7, path: '/', domain: 'jquery.com', secure: true } + }, + _create: function() { + var options = this.options, + active; + if ( options.active == null && options.cookie ) { + active = parseInt( this._cookie(), 10 ); + if ( active === -1 ) { + active = false; } + options.active = active; } - - if ( o.cookie ) { - self._cookie( o.selected, o.cookie ); + this._super(); + }, + _cookie: function( active ) { + var cookie = [ this.cookie || + ( this.cookie = this.options.cookie.name || "ui-tabs-" + (++listId) ) ]; + if ( arguments.length ) { + cookie.push( active === false ? -1 : active ); + cookie.push( this.options.cookie ); + } + return $.cookie.apply( null, cookie ); + }, + _refresh: function() { + this._super(); + if ( this.options.cookie ) { + this._cookie( this.options.active, this.options.cookie ); + } + }, + _eventHandler: function() { + this._superApply( arguments ); + if ( this.options.cookie ) { + this._cookie( this.options.active, this.options.cookie ); + } + }, + _destroy: function() { + this._super(); + if ( this.options.cookie ) { + this._cookie( null, this.options.cookie ); } + } + }); - // show new tab - if ( $show.length ) { - if ( $hide.length ) { - self.element.queue( "tabs", function() { - hideTab( el, $hide ); - }); - } - self.element.queue( "tabs", function() { - showTab( el, $show ); - }); + })(); - self.load( self.anchors.index( this ) ); - } else { - throw "jQuery UI Tabs: Mismatching fragment identifier."; + // load event + $.widget( "ui.tabs", $.ui.tabs, { + _trigger: function( type, event, data ) { + var _data = $.extend( {}, data ); + if ( type === "load" ) { + _data.panel = _data.panel[ 0 ]; + _data.tab = _data.tab.find( ".ui-tabs-anchor" )[ 0 ]; } + return this._super( type, event, _data ); + } + }); - // Prevent IE from keeping other link focussed when using the back button - // and remove dotted border from clicked link. This is controlled via CSS - // in modern browsers; blur() removes focus from address bar in Firefox - // which can become a usability and annoying problem with tabs('rotate'). - if ( $.browser.msie ) { - this.blur(); - } - }); + // fx option + // The new animation options (show, hide) conflict with the old show callback. + // The old fx option wins over show/hide anyway (always favor back-compat). + // If a user wants to use the new animation API, they must give up the old API. + $.widget( "ui.tabs", $.ui.tabs, { + options: { + fx: null // e.g. { height: "toggle", opacity: "toggle", duration: 200 } + }, - // disable click in any case - this.anchors.bind( "click.tabs", function(){ - return false; - }); - }, + _getFx: function() { + var hide, show, + fx = this.options.fx; - _getIndex: function( index ) { - // meta-function to give users option to provide a href string instead of a numerical index. - // also sanitizes numerical indexes to valid values. - if ( typeof index == "string" ) { - index = this.anchors.index( this.anchors.filter( "[href$=" + index + "]" ) ); - } + if ( fx ) { + if ( $.isArray( fx ) ) { + hide = fx[ 0 ]; + show = fx[ 1 ]; + } else { + hide = show = fx; + } + } - return index; - }, + return fx ? { show: show, hide: hide } : null; + }, - destroy: function() { - var o = this.options; + _toggle: function( event, eventData ) { + var that = this, + toShow = eventData.newPanel, + toHide = eventData.oldPanel, + fx = this._getFx(); + + if ( !fx ) { + return this._super( event, eventData ); + } - this.abort(); + that.running = true; - this.element - .unbind( ".tabs" ) - .removeClass( "ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible" ) - .removeData( "tabs" ); + function complete() { + that.running = false; + that._trigger( "activate", event, eventData ); + } - this.list.removeClass( "ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all" ); + function show() { + eventData.newTab.closest( "li" ).addClass( "ui-tabs-active ui-state-active" ); - this.anchors.each(function() { - var href = $.data( this, "href.tabs" ); - if ( href ) { - this.href = href; + if ( toShow.length && fx.show ) { + toShow + .animate( fx.show, fx.show.duration, function() { + complete(); + }); + } else { + toShow.show(); + complete(); + } } - var $this = $( this ).unbind( ".tabs" ); - $.each( [ "href", "load", "cache" ], function( i, prefix ) { - $this.removeData( prefix + ".tabs" ); - }); - }); - this.lis.unbind( ".tabs" ).add( this.panels ).each(function() { - if ( $.data( this, "destroy.tabs" ) ) { - $( this ).remove(); + // start out by hiding, then showing, then completing + if ( toHide.length && fx.hide ) { + toHide.animate( fx.hide, fx.hide.duration, function() { + eventData.oldTab.closest( "li" ).removeClass( "ui-tabs-active ui-state-active" ); + show(); + }); } else { - $( this ).removeClass([ - "ui-state-default", - "ui-corner-top", - "ui-tabs-selected", - "ui-state-active", - "ui-state-hover", - "ui-state-focus", - "ui-state-disabled", - "ui-tabs-panel", - "ui-widget-content", - "ui-corner-bottom", - "ui-tabs-hide" - ].join( " " ) ); + eventData.oldTab.closest( "li" ).removeClass( "ui-tabs-active ui-state-active" ); + toHide.hide(); + show(); } - }); - - if ( o.cookie ) { - this._cookie( null, o.cookie ); } + }); +} - return this; - }, +})( jQuery ); +(function( $ ) { - add: function( url, label, index ) { - if ( index === undefined ) { - index = this.anchors.length; - } +var increments = 0; - var self = this, - o = this.options, - $li = $( o.tabTemplate.replace( /#\{href\}/g, url ).replace( /#\{label\}/g, label ) ), - id = !url.indexOf( "#" ) ? url.replace( "#", "" ) : this._tabId( $( "a", $li )[ 0 ] ); +function addDescribedBy( elem, id ) { + var describedby = (elem.attr( "aria-describedby" ) || "").split( /\s+/ ); + describedby.push( id ); + elem + .data( "ui-tooltip-id", id ) + .attr( "aria-describedby", $.trim( describedby.join( " " ) ) ); +} - $li.addClass( "ui-state-default ui-corner-top" ).data( "destroy.tabs", true ); +function removeDescribedBy( elem ) { + var id = elem.data( "ui-tooltip-id" ), + describedby = (elem.attr( "aria-describedby" ) || "").split( /\s+/ ), + index = $.inArray( id, describedby ); + if ( index !== -1 ) { + describedby.splice( index, 1 ); + } - // try to find an existing element before creating a new one - var $panel = self.element.find( "#" + id ); - if ( !$panel.length ) { - $panel = $( o.panelTemplate ) - .attr( "id", id ) - .data( "destroy.tabs", true ); - } - $panel.addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide" ); + elem.removeData( "ui-tooltip-id" ); + describedby = $.trim( describedby.join( " " ) ); + if ( describedby ) { + elem.attr( "aria-describedby", describedby ); + } else { + elem.removeAttr( "aria-describedby" ); + } +} - if ( index >= this.lis.length ) { - $li.appendTo( this.list ); - $panel.appendTo( this.list[ 0 ].parentNode ); - } else { - $li.insertBefore( this.lis[ index ] ); - $panel.insertBefore( this.panels[ index ] ); - } +$.widget( "ui.tooltip", { + version: "1.9.2", + options: { + content: function() { + return $( this ).attr( "title" ); + }, + hide: true, + // Disabled elements have inconsistent behavior across browsers (#8661) + items: "[title]:not([disabled])", + position: { + my: "left top+15", + at: "left bottom", + collision: "flipfit flip" + }, + show: true, + tooltipClass: null, + track: false, - o.disabled = $.map( o.disabled, function( n, i ) { - return n >= index ? ++n : n; - }); + // callbacks + close: null, + open: null + }, - this._tabify(); + _create: function() { + this._on({ + mouseover: "open", + focusin: "open" + }); - if ( this.anchors.length == 1 ) { - o.selected = 0; - $li.addClass( "ui-tabs-selected ui-state-active" ); - $panel.removeClass( "ui-tabs-hide" ); - this.element.queue( "tabs", function() { - self._trigger( "show", null, self._ui( self.anchors[ 0 ], self.panels[ 0 ] ) ); - }); + // IDs of generated tooltips, needed for destroy + this.tooltips = {}; + // IDs of parent tooltips where we removed the title attribute + this.parents = {}; - this.load( 0 ); + if ( this.options.disabled ) { + this._disable(); } - - this._trigger( "add", null, this._ui( this.anchors[ index ], this.panels[ index ] ) ); - return this; }, - remove: function( index ) { - index = this._getIndex( index ); - var o = this.options, - $li = this.lis.eq( index ).remove(), - $panel = this.panels.eq( index ).remove(); - - // If selected tab was removed focus tab to the right or - // in case the last tab was removed the tab to the left. - if ( $li.hasClass( "ui-tabs-selected" ) && this.anchors.length > 1) { - this.select( index + ( index + 1 < this.anchors.length ? 1 : -1 ) ); - } - - o.disabled = $.map( - $.grep( o.disabled, function(n, i) { - return n != index; - }), - function( n, i ) { - return n >= index ? --n : n; - }); + _setOption: function( key, value ) { + var that = this; - this._tabify(); + if ( key === "disabled" ) { + this[ value ? "_disable" : "_enable" ](); + this.options[ key ] = value; + // disable element style changes + return; + } - this._trigger( "remove", null, this._ui( $li.find( "a" )[ 0 ], $panel[ 0 ] ) ); - return this; - }, + this._super( key, value ); - enable: function( index ) { - index = this._getIndex( index ); - var o = this.options; - if ( $.inArray( index, o.disabled ) == -1 ) { - return; + if ( key === "content" ) { + $.each( this.tooltips, function( id, element ) { + that._updateContent( element ); + }); } + }, + + _disable: function() { + var that = this; - this.lis.eq( index ).removeClass( "ui-state-disabled" ); - o.disabled = $.grep( o.disabled, function( n, i ) { - return n != index; + // close open tooltips + $.each( this.tooltips, function( id, element ) { + var event = $.Event( "blur" ); + event.target = event.currentTarget = element[0]; + that.close( event, true ); }); - this._trigger( "enable", null, this._ui( this.anchors[ index ], this.panels[ index ] ) ); - return this; + // remove title attributes to prevent native tooltips + this.element.find( this.options.items ).andSelf().each(function() { + var element = $( this ); + if ( element.is( "[title]" ) ) { + element + .data( "ui-tooltip-title", element.attr( "title" ) ) + .attr( "title", "" ); + } + }); }, - disable: function( index ) { - index = this._getIndex( index ); - var self = this, o = this.options; - // cannot disable already selected tab - if ( index != o.selected ) { - this.lis.eq( index ).addClass( "ui-state-disabled" ); + _enable: function() { + // restore title attributes + this.element.find( this.options.items ).andSelf().each(function() { + var element = $( this ); + if ( element.data( "ui-tooltip-title" ) ) { + element.attr( "title", element.data( "ui-tooltip-title" ) ); + } + }); + }, - o.disabled.push( index ); - o.disabled.sort(); + open: function( event ) { + var that = this, + target = $( event ? event.target : this.element ) + // we need closest here due to mouseover bubbling, + // but always pointing at the same event target + .closest( this.options.items ); - this._trigger( "disable", null, this._ui( this.anchors[ index ], this.panels[ index ] ) ); + // No element to show a tooltip for or the tooltip is already open + if ( !target.length || target.data( "ui-tooltip-id" ) ) { + return; } - return this; + if ( target.attr( "title" ) ) { + target.data( "ui-tooltip-title", target.attr( "title" ) ); + } + + target.data( "ui-tooltip-open", true ); + + // kill parent tooltips, custom or native, for hover + if ( event && event.type === "mouseover" ) { + target.parents().each(function() { + var parent = $( this ), + blurEvent; + if ( parent.data( "ui-tooltip-open" ) ) { + blurEvent = $.Event( "blur" ); + blurEvent.target = blurEvent.currentTarget = this; + that.close( blurEvent, true ); + } + if ( parent.attr( "title" ) ) { + parent.uniqueId(); + that.parents[ this.id ] = { + element: this, + title: parent.attr( "title" ) + }; + parent.attr( "title", "" ); + } + }); + } + + this._updateContent( target, event ); }, - select: function( index ) { - index = this._getIndex( index ); - if ( index == -1 ) { - if ( this.options.collapsible && this.options.selected != -1 ) { - index = this.options.selected; - } else { - return this; + _updateContent: function( target, event ) { + var content, + contentOption = this.options.content, + that = this, + eventType = event ? event.type : null; + + if ( typeof contentOption === "string" ) { + return this._open( event, target, contentOption ); + } + + content = contentOption.call( target[0], function( response ) { + // ignore async response if tooltip was closed already + if ( !target.data( "ui-tooltip-open" ) ) { + return; } + // IE may instantly serve a cached response for ajax requests + // delay this call to _open so the other call to _open runs first + that._delay(function() { + // jQuery creates a special event for focusin when it doesn't + // exist natively. To improve performance, the native event + // object is reused and the type is changed. Therefore, we can't + // rely on the type being correct after the event finished + // bubbling, so we set it back to the previous value. (#8740) + if ( event ) { + event.type = eventType; + } + this._open( event, target, response ); + }); + }); + if ( content ) { + this._open( event, target, content ); } - this.anchors.eq( index ).trigger( this.options.event + ".tabs" ); - return this; }, - load: function( index ) { - index = this._getIndex( index ); - var self = this, - o = this.options, - a = this.anchors.eq( index )[ 0 ], - url = $.data( a, "load.tabs" ); + _open: function( event, target, content ) { + var tooltip, events, delayedShow, + positionOption = $.extend( {}, this.options.position ); - this.abort(); - - // not remote or from cache - if ( !url || this.element.queue( "tabs" ).length !== 0 && $.data( a, "cache.tabs" ) ) { - this.element.dequeue( "tabs" ); + if ( !content ) { return; } - // load remote from here on - this.lis.eq( index ).addClass( "ui-state-processing" ); - - if ( o.spinner ) { - var span = $( "span", a ); - span.data( "label.tabs", span.html() ).html( o.spinner ); + // Content can be updated multiple times. If the tooltip already + // exists, then just update the content and bail. + tooltip = this._find( target ); + if ( tooltip.length ) { + tooltip.find( ".ui-tooltip-content" ).html( content ); + return; } - this.xhr = $.ajax( $.extend( {}, o.ajaxOptions, { - url: url, - success: function( r, s ) { - self.element.find( self._sanitizeSelector( a.hash ) ).html( r ); + // if we have a title, clear it to prevent the native tooltip + // we have to check first to avoid defining a title if none exists + // (we don't want to cause an element to start matching [title]) + // + // We use removeAttr only for key events, to allow IE to export the correct + // accessible attributes. For mouse events, set to empty string to avoid + // native tooltip showing up (happens only when removing inside mouseover). + if ( target.is( "[title]" ) ) { + if ( event && event.type === "mouseover" ) { + target.attr( "title", "" ); + } else { + target.removeAttr( "title" ); + } + } - // take care of tab labels - self._cleanup(); + tooltip = this._tooltip( target ); + addDescribedBy( target, tooltip.attr( "id" ) ); + tooltip.find( ".ui-tooltip-content" ).html( content ); - if ( o.cache ) { - $.data( a, "cache.tabs", true ); + function position( event ) { + positionOption.of = event; + if ( tooltip.is( ":hidden" ) ) { + return; + } + tooltip.position( positionOption ); + } + if ( this.options.track && event && /^mouse/.test( event.type ) ) { + this._on( this.document, { + mousemove: position + }); + // trigger once to override element-relative positioning + position( event ); + } else { + tooltip.position( $.extend({ + of: target + }, this.options.position ) ); + } + + tooltip.hide(); + + this._show( tooltip, this.options.show ); + // Handle tracking tooltips that are shown with a delay (#8644). As soon + // as the tooltip is visible, position the tooltip using the most recent + // event. + if ( this.options.show && this.options.show.delay ) { + delayedShow = setInterval(function() { + if ( tooltip.is( ":visible" ) ) { + position( positionOption.of ); + clearInterval( delayedShow ); } + }, $.fx.interval ); + } - self._trigger( "load", null, self._ui( self.anchors[ index ], self.panels[ index ] ) ); - try { - o.ajaxOptions.success( r, s ); - } - catch ( e ) {} - }, - error: function( xhr, s, e ) { - // take care of tab labels - self._cleanup(); + this._trigger( "open", event, { tooltip: tooltip } ); - self._trigger( "load", null, self._ui( self.anchors[ index ], self.panels[ index ] ) ); - try { - // Passing index avoid a race condition when this method is - // called after the user has selected another tab. - // Pass the anchor that initiated this request allows - // loadError to manipulate the tab content panel via $(a.hash) - o.ajaxOptions.error( xhr, s, index, a ); + events = { + keyup: function( event ) { + if ( event.keyCode === $.ui.keyCode.ESCAPE ) { + var fakeEvent = $.Event(event); + fakeEvent.currentTarget = target[0]; + this.close( fakeEvent, true ); } - catch ( e ) {} + }, + remove: function() { + this._removeTooltip( tooltip ); } - } ) ); + }; + if ( !event || event.type === "mouseover" ) { + events.mouseleave = "close"; + } + if ( !event || event.type === "focusin" ) { + events.focusout = "close"; + } + this._on( true, target, events ); + }, - // last, so that load event is fired before show... - self.element.dequeue( "tabs" ); + close: function( event ) { + var that = this, + target = $( event ? event.currentTarget : this.element ), + tooltip = this._find( target ); - return this; - }, + // disabling closes the tooltip, so we need to track when we're closing + // to avoid an infinite loop in case the tooltip becomes disabled on close + if ( this.closing ) { + return; + } - abort: function() { - // stop possibly running animations - this.element.queue( [] ); - this.panels.stop( false, true ); + // only set title if we had one before (see comment in _open()) + if ( target.data( "ui-tooltip-title" ) ) { + target.attr( "title", target.data( "ui-tooltip-title" ) ); + } - // "tabs" queue must not contain more than two elements, - // which are the callbacks for the latest clicked tab... - this.element.queue( "tabs", this.element.queue( "tabs" ).splice( -2, 2 ) ); + removeDescribedBy( target ); - // terminate pending requests from other tabs - if ( this.xhr ) { - this.xhr.abort(); - delete this.xhr; + tooltip.stop( true ); + this._hide( tooltip, this.options.hide, function() { + that._removeTooltip( $( this ) ); + }); + + target.removeData( "ui-tooltip-open" ); + this._off( target, "mouseleave focusout keyup" ); + // Remove 'remove' binding only on delegated targets + if ( target[0] !== this.element[0] ) { + this._off( target, "remove" ); } + this._off( this.document, "mousemove" ); - // take care of tab labels - this._cleanup(); - return this; + if ( event && event.type === "mouseleave" ) { + $.each( this.parents, function( id, parent ) { + $( parent.element ).attr( "title", parent.title ); + delete that.parents[ id ]; + }); + } + + this.closing = true; + this._trigger( "close", event, { tooltip: tooltip } ); + this.closing = false; }, - url: function( index, url ) { - this.anchors.eq( index ).removeData( "cache.tabs" ).data( "load.tabs", url ); - return this; + _tooltip: function( element ) { + var id = "ui-tooltip-" + increments++, + tooltip = $( "
        " ) + .attr({ + id: id, + role: "tooltip" + }) + .addClass( "ui-tooltip ui-widget ui-corner-all ui-widget-content " + + ( this.options.tooltipClass || "" ) ); + $( "
        " ) + .addClass( "ui-tooltip-content" ) + .appendTo( tooltip ); + tooltip.appendTo( this.document[0].body ); + if ( $.fn.bgiframe ) { + tooltip.bgiframe(); + } + this.tooltips[ id ] = element; + return tooltip; }, - length: function() { - return this.anchors.length; - } -}); + _find: function( target ) { + var id = target.data( "ui-tooltip-id" ); + return id ? $( "#" + id ) : $(); + }, -$.extend( $.ui.tabs, { - version: "1.8.16" -}); + _removeTooltip: function( tooltip ) { + tooltip.remove(); + delete this.tooltips[ tooltip.attr( "id" ) ]; + }, -/* - * Tabs Extensions - */ + _destroy: function() { + var that = this; -/* - * Rotate - */ -$.extend( $.ui.tabs.prototype, { - rotation: null, - rotate: function( ms, continuing ) { - var self = this, - o = this.options; + // close open tooltips + $.each( this.tooltips, function( id, element ) { + // Delegate to close method to handle common cleanup + var event = $.Event( "blur" ); + event.target = event.currentTarget = element[0]; + that.close( event, true ); - var rotate = self._rotate || ( self._rotate = function( e ) { - clearTimeout( self.rotation ); - self.rotation = setTimeout(function() { - var t = o.selected; - self.select( ++t < self.anchors.length ? t : 0 ); - }, ms ); - - if ( e ) { - e.stopPropagation(); - } - }); + // Remove immediately; destroying an open tooltip doesn't use the + // hide animation + $( "#" + id ).remove(); - var stop = self._unrotate || ( self._unrotate = !continuing - ? function(e) { - if (e.clientX) { // in case of a true click - self.rotate(null); - } + // Restore the title + if ( element.data( "ui-tooltip-title" ) ) { + element.attr( "title", element.data( "ui-tooltip-title" ) ); + element.removeData( "ui-tooltip-title" ); } - : function( e ) { - t = o.selected; - rotate(); - }); - - // start rotation - if ( ms ) { - this.element.bind( "tabsshow", rotate ); - this.anchors.bind( o.event + ".tabs", stop ); - rotate(); - // stop rotation - } else { - clearTimeout( self.rotation ); - this.element.unbind( "tabsshow", rotate ); - this.anchors.unbind( o.event + ".tabs", stop ); - delete this._rotate; - delete this._unrotate; - } - - return this; + }); } }); -})( jQuery ); +}( jQuery ) ); diff --git a/lib/scripts/jquery/jquery-ui.min.js b/lib/scripts/jquery/jquery-ui.min.js old mode 100644 new mode 100755 index 0202506b5..9b3b84deb --- a/lib/scripts/jquery/jquery-ui.min.js +++ b/lib/scripts/jquery/jquery-ui.min.js @@ -1,414 +1,6 @@ -/*! - * jQuery UI 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI - */ -(function(a,d){function c(h,g){var i=h.nodeName.toLowerCase();if("area"===i){g=h.parentNode;i=g.name;if(!h.href||!i||g.nodeName.toLowerCase()!=="map")return false;h=a("img[usemap=#"+i+"]")[0];return!!h&&e(h)}return(/input|select|textarea|button|object/.test(i)?!h.disabled:"a"==i?h.href||g:g)&&e(h)}function e(h){return!a(h).parents().andSelf().filter(function(){return a.curCSS(this,"visibility")==="hidden"||a.expr.filters.hidden(this)}).length}a.ui=a.ui||{};if(!a.ui.version){a.extend(a.ui,{version:"1.8.16", -keyCode:{ALT:18,BACKSPACE:8,CAPS_LOCK:20,COMMA:188,COMMAND:91,COMMAND_LEFT:91,COMMAND_RIGHT:93,CONTROL:17,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,INSERT:45,LEFT:37,MENU:93,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SHIFT:16,SPACE:32,TAB:9,UP:38,WINDOWS:91}});a.fn.extend({propAttr:a.fn.prop||a.fn.attr,_focus:a.fn.focus,focus:function(h,g){return typeof h==="number"?this.each(function(){var i= -this;setTimeout(function(){a(i).focus();g&&g.call(i)},h)}):this._focus.apply(this,arguments)},scrollParent:function(){var h;h=a.browser.msie&&/(static|relative)/.test(this.css("position"))||/absolute/.test(this.css("position"))?this.parents().filter(function(){return/(relative|absolute|fixed)/.test(a.curCSS(this,"position",1))&&/(auto|scroll)/.test(a.curCSS(this,"overflow",1)+a.curCSS(this,"overflow-y",1)+a.curCSS(this,"overflow-x",1))}).eq(0):this.parents().filter(function(){return/(auto|scroll)/.test(a.curCSS(this, -"overflow",1)+a.curCSS(this,"overflow-y",1)+a.curCSS(this,"overflow-x",1))}).eq(0);return/fixed/.test(this.css("position"))||!h.length?a(document):h},zIndex:function(h){if(h!==d)return this.css("zIndex",h);if(this.length){h=a(this[0]);for(var g;h.length&&h[0]!==document;){g=h.css("position");if(g==="absolute"||g==="relative"||g==="fixed"){g=parseInt(h.css("zIndex"),10);if(!isNaN(g)&&g!==0)return g}h=h.parent()}}return 0},disableSelection:function(){return this.bind((a.support.selectstart?"selectstart": -"mousedown")+".ui-disableSelection",function(h){h.preventDefault()})},enableSelection:function(){return this.unbind(".ui-disableSelection")}});a.each(["Width","Height"],function(h,g){function i(l,o,n,k){a.each(b,function(){o-=parseFloat(a.curCSS(l,"padding"+this,true))||0;if(n)o-=parseFloat(a.curCSS(l,"border"+this+"Width",true))||0;if(k)o-=parseFloat(a.curCSS(l,"margin"+this,true))||0});return o}var b=g==="Width"?["Left","Right"]:["Top","Bottom"],f=g.toLowerCase(),j={innerWidth:a.fn.innerWidth,innerHeight:a.fn.innerHeight, -outerWidth:a.fn.outerWidth,outerHeight:a.fn.outerHeight};a.fn["inner"+g]=function(l){if(l===d)return j["inner"+g].call(this);return this.each(function(){a(this).css(f,i(this,l)+"px")})};a.fn["outer"+g]=function(l,o){if(typeof l!=="number")return j["outer"+g].call(this,l);return this.each(function(){a(this).css(f,i(this,l,true,o)+"px")})}});a.extend(a.expr[":"],{data:function(h,g,i){return!!a.data(h,i[3])},focusable:function(h){return c(h,!isNaN(a.attr(h,"tabindex")))},tabbable:function(h){var g=a.attr(h, -"tabindex"),i=isNaN(g);return(i||g>=0)&&c(h,!i)}});a(function(){var h=document.body,g=h.appendChild(g=document.createElement("div"));a.extend(g.style,{minHeight:"100px",height:"auto",padding:0,borderWidth:0});a.support.minHeight=g.offsetHeight===100;a.support.selectstart="onselectstart"in g;h.removeChild(g).style.display="none"});a.extend(a.ui,{plugin:{add:function(h,g,i){h=a.ui[h].prototype;for(var b in i){h.plugins[b]=h.plugins[b]||[];h.plugins[b].push([g,i[b]])}},call:function(h,g,i){if((g=h.plugins[g])&& -h.element[0].parentNode)for(var b=0;b0)return true;h[g]=1;i=h[g]>0;h[g]=0;return i},isOverAxis:function(h,g,i){return h>g&&h=9)&&!c.button)return this._mouseUp(c);if(this._mouseStarted){this._mouseDrag(c);return c.preventDefault()}if(this._mouseDistanceMet(c)&&this._mouseDelayMet(c))(this._mouseStarted=this._mouseStart(this._mouseDownEvent,c)!==false)?this._mouseDrag(c):this._mouseUp(c);return!this._mouseStarted},_mouseUp:function(c){a(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate);if(this._mouseStarted){this._mouseStarted= -false;c.target==this._mouseDownEvent.target&&a.data(c.target,this.widgetName+".preventClickEvent",true);this._mouseStop(c)}return false},_mouseDistanceMet:function(c){return Math.max(Math.abs(this._mouseDownEvent.pageX-c.pageX),Math.abs(this._mouseDownEvent.pageY-c.pageY))>=this.options.distance},_mouseDelayMet:function(){return this.mouseDelayMet},_mouseStart:function(){},_mouseDrag:function(){},_mouseStop:function(){},_mouseCapture:function(){return true}})})(jQuery); -(function(a){a.widget("ui.draggable",a.ui.mouse,{widgetEventPrefix:"drag",options:{addClasses:true,appendTo:"parent",axis:false,connectToSortable:false,containment:false,cursor:"auto",cursorAt:false,grid:false,handle:false,helper:"original",iframeFix:false,opacity:false,refreshPositions:false,revert:false,revertDuration:500,scope:"default",scroll:true,scrollSensitivity:20,scrollSpeed:20,snap:false,snapMode:"both",snapTolerance:20,stack:false,zIndex:false},_create:function(){if(this.options.helper== -"original"&&!/^(?:r|a|f)/.test(this.element.css("position")))this.element[0].style.position="relative";this.options.addClasses&&this.element.addClass("ui-draggable");this.options.disabled&&this.element.addClass("ui-draggable-disabled");this._mouseInit()},destroy:function(){if(this.element.data("draggable")){this.element.removeData("draggable").unbind(".draggable").removeClass("ui-draggable ui-draggable-dragging ui-draggable-disabled");this._mouseDestroy();return this}},_mouseCapture:function(d){var c= -this.options;if(this.helper||c.disabled||a(d.target).is(".ui-resizable-handle"))return false;this.handle=this._getHandle(d);if(!this.handle)return false;if(c.iframeFix)a(c.iframeFix===true?"iframe":c.iframeFix).each(function(){a('
        ').css({width:this.offsetWidth+"px",height:this.offsetHeight+"px",position:"absolute",opacity:"0.001",zIndex:1E3}).css(a(this).offset()).appendTo("body")});return true},_mouseStart:function(d){var c=this.options; -this.helper=this._createHelper(d);this._cacheHelperProportions();if(a.ui.ddmanager)a.ui.ddmanager.current=this;this._cacheMargins();this.cssPosition=this.helper.css("position");this.scrollParent=this.helper.scrollParent();this.offset=this.positionAbs=this.element.offset();this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left};a.extend(this.offset,{click:{left:d.pageX-this.offset.left,top:d.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()}); -this.originalPosition=this.position=this._generatePosition(d);this.originalPageX=d.pageX;this.originalPageY=d.pageY;c.cursorAt&&this._adjustOffsetFromHelper(c.cursorAt);c.containment&&this._setContainment();if(this._trigger("start",d)===false){this._clear();return false}this._cacheHelperProportions();a.ui.ddmanager&&!c.dropBehaviour&&a.ui.ddmanager.prepareOffsets(this,d);this.helper.addClass("ui-draggable-dragging");this._mouseDrag(d,true);a.ui.ddmanager&&a.ui.ddmanager.dragStart(this,d);return true}, -_mouseDrag:function(d,c){this.position=this._generatePosition(d);this.positionAbs=this._convertPositionTo("absolute");if(!c){c=this._uiHash();if(this._trigger("drag",d,c)===false){this._mouseUp({});return false}this.position=c.position}if(!this.options.axis||this.options.axis!="y")this.helper[0].style.left=this.position.left+"px";if(!this.options.axis||this.options.axis!="x")this.helper[0].style.top=this.position.top+"px";a.ui.ddmanager&&a.ui.ddmanager.drag(this,d);return false},_mouseStop:function(d){var c= -false;if(a.ui.ddmanager&&!this.options.dropBehaviour)c=a.ui.ddmanager.drop(this,d);if(this.dropped){c=this.dropped;this.dropped=false}if((!this.element[0]||!this.element[0].parentNode)&&this.options.helper=="original")return false;if(this.options.revert=="invalid"&&!c||this.options.revert=="valid"&&c||this.options.revert===true||a.isFunction(this.options.revert)&&this.options.revert.call(this.element,c)){var e=this;a(this.helper).animate(this.originalPosition,parseInt(this.options.revertDuration, -10),function(){e._trigger("stop",d)!==false&&e._clear()})}else this._trigger("stop",d)!==false&&this._clear();return false},_mouseUp:function(d){this.options.iframeFix===true&&a("div.ui-draggable-iframeFix").each(function(){this.parentNode.removeChild(this)});a.ui.ddmanager&&a.ui.ddmanager.dragStop(this,d);return a.ui.mouse.prototype._mouseUp.call(this,d)},cancel:function(){this.helper.is(".ui-draggable-dragging")?this._mouseUp({}):this._clear();return this},_getHandle:function(d){var c=!this.options.handle|| -!a(this.options.handle,this.element).length?true:false;a(this.options.handle,this.element).find("*").andSelf().each(function(){if(this==d.target)c=true});return c},_createHelper:function(d){var c=this.options;d=a.isFunction(c.helper)?a(c.helper.apply(this.element[0],[d])):c.helper=="clone"?this.element.clone().removeAttr("id"):this.element;d.parents("body").length||d.appendTo(c.appendTo=="parent"?this.element[0].parentNode:c.appendTo);d[0]!=this.element[0]&&!/(fixed|absolute)/.test(d.css("position"))&& -d.css("position","absolute");return d},_adjustOffsetFromHelper:function(d){if(typeof d=="string")d=d.split(" ");if(a.isArray(d))d={left:+d[0],top:+d[1]||0};if("left"in d)this.offset.click.left=d.left+this.margins.left;if("right"in d)this.offset.click.left=this.helperProportions.width-d.right+this.margins.left;if("top"in d)this.offset.click.top=d.top+this.margins.top;if("bottom"in d)this.offset.click.top=this.helperProportions.height-d.bottom+this.margins.top},_getParentOffset:function(){this.offsetParent= -this.helper.offsetParent();var d=this.offsetParent.offset();if(this.cssPosition=="absolute"&&this.scrollParent[0]!=document&&a.ui.contains(this.scrollParent[0],this.offsetParent[0])){d.left+=this.scrollParent.scrollLeft();d.top+=this.scrollParent.scrollTop()}if(this.offsetParent[0]==document.body||this.offsetParent[0].tagName&&this.offsetParent[0].tagName.toLowerCase()=="html"&&a.browser.msie)d={top:0,left:0};return{top:d.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:d.left+(parseInt(this.offsetParent.css("borderLeftWidth"), -10)||0)}},_getRelativeOffset:function(){if(this.cssPosition=="relative"){var d=this.element.position();return{top:d.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:d.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}else return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.element.css("marginLeft"),10)||0,top:parseInt(this.element.css("marginTop"),10)||0,right:parseInt(this.element.css("marginRight"),10)||0,bottom:parseInt(this.element.css("marginBottom"), -10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var d=this.options;if(d.containment=="parent")d.containment=this.helper[0].parentNode;if(d.containment=="document"||d.containment=="window")this.containment=[d.containment=="document"?0:a(window).scrollLeft()-this.offset.relative.left-this.offset.parent.left,d.containment=="document"?0:a(window).scrollTop()-this.offset.relative.top-this.offset.parent.top, -(d.containment=="document"?0:a(window).scrollLeft())+a(d.containment=="document"?document:window).width()-this.helperProportions.width-this.margins.left,(d.containment=="document"?0:a(window).scrollTop())+(a(d.containment=="document"?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top];if(!/^(document|window|parent)$/.test(d.containment)&&d.containment.constructor!=Array){d=a(d.containment);var c=d[0];if(c){d.offset();var e=a(c).css("overflow")!= -"hidden";this.containment=[(parseInt(a(c).css("borderLeftWidth"),10)||0)+(parseInt(a(c).css("paddingLeft"),10)||0),(parseInt(a(c).css("borderTopWidth"),10)||0)+(parseInt(a(c).css("paddingTop"),10)||0),(e?Math.max(c.scrollWidth,c.offsetWidth):c.offsetWidth)-(parseInt(a(c).css("borderLeftWidth"),10)||0)-(parseInt(a(c).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left-this.margins.right,(e?Math.max(c.scrollHeight,c.offsetHeight):c.offsetHeight)-(parseInt(a(c).css("borderTopWidth"), -10)||0)-(parseInt(a(c).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top-this.margins.bottom];this.relative_container=d}}else if(d.containment.constructor==Array)this.containment=d.containment},_convertPositionTo:function(d,c){if(!c)c=this.position;d=d=="absolute"?1:-1;var e=this.cssPosition=="absolute"&&!(this.scrollParent[0]!=document&&a.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,h=/(html|body)/i.test(e[0].tagName);return{top:c.top+ -this.offset.relative.top*d+this.offset.parent.top*d-(a.browser.safari&&a.browser.version<526&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollTop():h?0:e.scrollTop())*d),left:c.left+this.offset.relative.left*d+this.offset.parent.left*d-(a.browser.safari&&a.browser.version<526&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():h?0:e.scrollLeft())*d)}},_generatePosition:function(d){var c=this.options,e=this.cssPosition=="absolute"&& -!(this.scrollParent[0]!=document&&a.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,h=/(html|body)/i.test(e[0].tagName),g=d.pageX,i=d.pageY;if(this.originalPosition){var b;if(this.containment){if(this.relative_container){b=this.relative_container.offset();b=[this.containment[0]+b.left,this.containment[1]+b.top,this.containment[2]+b.left,this.containment[3]+b.top]}else b=this.containment;if(d.pageX-this.offset.click.leftb[2])g=b[2]+this.offset.click.left;if(d.pageY-this.offset.click.top>b[3])i=b[3]+this.offset.click.top}if(c.grid){i=c.grid[1]?this.originalPageY+Math.round((i-this.originalPageY)/c.grid[1])*c.grid[1]:this.originalPageY;i=b?!(i-this.offset.click.topb[3])?i:!(i-this.offset.click.topb[2])?g:!(g-this.offset.click.left=0;l--){var o=e.snapElements[l].left,n=o+e.snapElements[l].width,k=e.snapElements[l].top,m=k+e.snapElements[l].height;if(o-g=l&&i<=o||b>=l&&b<=o||io)&&(h>= -f&&h<=j||g>=f&&g<=j||hj);default:return false}};a.ui.ddmanager={current:null,droppables:{"default":[]},prepareOffsets:function(d,c){var e=a.ui.ddmanager.droppables[d.options.scope]||[],h=c?c.type:null,g=(d.currentItem||d.element).find(":data(droppable)").andSelf(),i=0;a:for(;i
        ').css({position:this.element.css("position"),width:this.element.outerWidth(),height:this.element.outerHeight(), -top:this.element.css("top"),left:this.element.css("left")}));this.element=this.element.parent().data("resizable",this.element.data("resizable"));this.elementIsWrapper=true;this.element.css({marginLeft:this.originalElement.css("marginLeft"),marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom")});this.originalElement.css({marginLeft:0,marginTop:0,marginRight:0,marginBottom:0});this.originalResizeStyle= -this.originalElement.css("resize");this.originalElement.css("resize","none");this._proportionallyResizeElements.push(this.originalElement.css({position:"static",zoom:1,display:"block"}));this.originalElement.css({margin:this.originalElement.css("margin")});this._proportionallyResize()}this.handles=h.handles||(!a(".ui-resizable-handle",this.element).length?"e,s,se":{n:".ui-resizable-n",e:".ui-resizable-e",s:".ui-resizable-s",w:".ui-resizable-w",se:".ui-resizable-se",sw:".ui-resizable-sw",ne:".ui-resizable-ne", -nw:".ui-resizable-nw"});if(this.handles.constructor==String){if(this.handles=="all")this.handles="n,e,s,w,se,sw,ne,nw";var g=this.handles.split(",");this.handles={};for(var i=0;i
        ');/sw|se|ne|nw/.test(b)&&f.css({zIndex:++h.zIndex});"se"==b&&f.addClass("ui-icon ui-icon-gripsmall-diagonal-se");this.handles[b]=".ui-resizable-"+b;this.element.append(f)}}this._renderAxis=function(j){j=j||this.element;for(var l in this.handles){if(this.handles[l].constructor== -String)this.handles[l]=a(this.handles[l],this.element).show();if(this.elementIsWrapper&&this.originalElement[0].nodeName.match(/textarea|input|select|button/i)){var o=a(this.handles[l],this.element),n=0;n=/sw|ne|nw|se|n|s/.test(l)?o.outerHeight():o.outerWidth();o=["padding",/ne|nw|n/.test(l)?"Top":/se|sw|s/.test(l)?"Bottom":/^e$/.test(l)?"Right":"Left"].join("");j.css(o,n);this._proportionallyResize()}a(this.handles[l])}};this._renderAxis(this.element);this._handles=a(".ui-resizable-handle",this.element).disableSelection(); -this._handles.mouseover(function(){if(!e.resizing){if(this.className)var j=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i);e.axis=j&&j[1]?j[1]:"se"}});if(h.autoHide){this._handles.hide();a(this.element).addClass("ui-resizable-autohide").hover(function(){if(!h.disabled){a(this).removeClass("ui-resizable-autohide");e._handles.show()}},function(){if(!h.disabled)if(!e.resizing){a(this).addClass("ui-resizable-autohide");e._handles.hide()}})}this._mouseInit()},destroy:function(){this._mouseDestroy(); -var e=function(g){a(g).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing").removeData("resizable").unbind(".resizable").find(".ui-resizable-handle").remove()};if(this.elementIsWrapper){e(this.element);var h=this.element;h.after(this.originalElement.css({position:h.css("position"),width:h.outerWidth(),height:h.outerHeight(),top:h.css("top"),left:h.css("left")})).remove()}this.originalElement.css("resize",this.originalResizeStyle);e(this.originalElement);return this},_mouseCapture:function(e){var h= -false;for(var g in this.handles)if(a(this.handles[g])[0]==e.target)h=true;return!this.options.disabled&&h},_mouseStart:function(e){var h=this.options,g=this.element.position(),i=this.element;this.resizing=true;this.documentScroll={top:a(document).scrollTop(),left:a(document).scrollLeft()};if(i.is(".ui-draggable")||/absolute/.test(i.css("position")))i.css({position:"absolute",top:g.top,left:g.left});a.browser.opera&&/relative/.test(i.css("position"))&&i.css({position:"relative",top:"auto",left:"auto"}); -this._renderProxy();g=d(this.helper.css("left"));var b=d(this.helper.css("top"));if(h.containment){g+=a(h.containment).scrollLeft()||0;b+=a(h.containment).scrollTop()||0}this.offset=this.helper.offset();this.position={left:g,top:b};this.size=this._helper?{width:i.outerWidth(),height:i.outerHeight()}:{width:i.width(),height:i.height()};this.originalSize=this._helper?{width:i.outerWidth(),height:i.outerHeight()}:{width:i.width(),height:i.height()};this.originalPosition={left:g,top:b};this.sizeDiff= -{width:i.outerWidth()-i.width(),height:i.outerHeight()-i.height()};this.originalMousePosition={left:e.pageX,top:e.pageY};this.aspectRatio=typeof h.aspectRatio=="number"?h.aspectRatio:this.originalSize.width/this.originalSize.height||1;h=a(".ui-resizable-"+this.axis).css("cursor");a("body").css("cursor",h=="auto"?this.axis+"-resize":h);i.addClass("ui-resizable-resizing");this._propagate("start",e);return true},_mouseDrag:function(e){var h=this.helper,g=this.originalMousePosition,i=this._change[this.axis]; -if(!i)return false;g=i.apply(this,[e,e.pageX-g.left||0,e.pageY-g.top||0]);this._updateVirtualBoundaries(e.shiftKey);if(this._aspectRatio||e.shiftKey)g=this._updateRatio(g,e);g=this._respectSize(g,e);this._propagate("resize",e);h.css({top:this.position.top+"px",left:this.position.left+"px",width:this.size.width+"px",height:this.size.height+"px"});!this._helper&&this._proportionallyResizeElements.length&&this._proportionallyResize();this._updateCache(g);this._trigger("resize",e,this.ui());return false}, -_mouseStop:function(e){this.resizing=false;var h=this.options,g=this;if(this._helper){var i=this._proportionallyResizeElements,b=i.length&&/textarea/i.test(i[0].nodeName);i=b&&a.ui.hasScroll(i[0],"left")?0:g.sizeDiff.height;b=b?0:g.sizeDiff.width;b={width:g.helper.width()-b,height:g.helper.height()-i};i=parseInt(g.element.css("left"),10)+(g.position.left-g.originalPosition.left)||null;var f=parseInt(g.element.css("top"),10)+(g.position.top-g.originalPosition.top)||null;h.animate||this.element.css(a.extend(b, -{top:f,left:i}));g.helper.height(g.size.height);g.helper.width(g.size.width);this._helper&&!h.animate&&this._proportionallyResize()}a("body").css("cursor","auto");this.element.removeClass("ui-resizable-resizing");this._propagate("stop",e);this._helper&&this.helper.remove();return false},_updateVirtualBoundaries:function(e){var h=this.options,g,i,b;h={minWidth:c(h.minWidth)?h.minWidth:0,maxWidth:c(h.maxWidth)?h.maxWidth:Infinity,minHeight:c(h.minHeight)?h.minHeight:0,maxHeight:c(h.maxHeight)?h.maxHeight: -Infinity};if(this._aspectRatio||e){e=h.minHeight*this.aspectRatio;i=h.minWidth/this.aspectRatio;g=h.maxHeight*this.aspectRatio;b=h.maxWidth/this.aspectRatio;if(e>h.minWidth)h.minWidth=e;if(i>h.minHeight)h.minHeight=i;if(ge.width,j=c(e.height)&&h.minHeight&&h.minHeight>e.height;if(f)e.width=h.minWidth;if(j)e.height=h.minHeight;if(i)e.width=h.maxWidth;if(b)e.height=h.maxHeight;var l=this.originalPosition.left+this.originalSize.width,o=this.position.top+this.size.height,n=/sw|nw|w/.test(g);g=/nw|ne|n/.test(g);if(f&&n)e.left=l-h.minWidth;if(i&&n)e.left=l-h.maxWidth;if(j&&g)e.top=o-h.minHeight;if(b&&g)e.top=o-h.maxHeight;if((h=!e.width&&!e.height)&&!e.left&&e.top)e.top=null;else if(h&&!e.top&&e.left)e.left= -null;return e},_proportionallyResize:function(){if(this._proportionallyResizeElements.length)for(var e=this.helper||this.element,h=0;h
        ');var h=a.browser.msie&&a.browser.version<7,g=h?1:0;h=h?2:-1;this.helper.addClass(this._helper).css({width:this.element.outerWidth()+ -h,height:this.element.outerHeight()+h,position:"absolute",left:this.elementOffset.left-g+"px",top:this.elementOffset.top-g+"px",zIndex:++e.zIndex});this.helper.appendTo("body").disableSelection()}else this.helper=this.element},_change:{e:function(e,h){return{width:this.originalSize.width+h}},w:function(e,h){return{left:this.originalPosition.left+h,width:this.originalSize.width-h}},n:function(e,h,g){return{top:this.originalPosition.top+g,height:this.originalSize.height-g}},s:function(e,h,g){return{height:this.originalSize.height+ -g}},se:function(e,h,g){return a.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[e,h,g]))},sw:function(e,h,g){return a.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[e,h,g]))},ne:function(e,h,g){return a.extend(this._change.n.apply(this,arguments),this._change.e.apply(this,[e,h,g]))},nw:function(e,h,g){return a.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[e,h,g]))}},_propagate:function(e,h){a.ui.plugin.call(this,e,[h,this.ui()]); -e!="resize"&&this._trigger(e,h,this.ui())},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize,originalPosition:this.originalPosition}}});a.extend(a.ui.resizable,{version:"1.8.16"});a.ui.plugin.add("resizable","alsoResize",{start:function(){var e=a(this).data("resizable").options,h=function(g){a(g).each(function(){var i=a(this);i.data("resizable-alsoresize",{width:parseInt(i.width(), -10),height:parseInt(i.height(),10),left:parseInt(i.css("left"),10),top:parseInt(i.css("top"),10),position:i.css("position")})})};if(typeof e.alsoResize=="object"&&!e.alsoResize.parentNode)if(e.alsoResize.length){e.alsoResize=e.alsoResize[0];h(e.alsoResize)}else a.each(e.alsoResize,function(g){h(g)});else h(e.alsoResize)},resize:function(e,h){var g=a(this).data("resizable");e=g.options;var i=g.originalSize,b=g.originalPosition,f={height:g.size.height-i.height||0,width:g.size.width-i.width||0,top:g.position.top- -b.top||0,left:g.position.left-b.left||0},j=function(l,o){a(l).each(function(){var n=a(this),k=a(this).data("resizable-alsoresize"),m={},p=o&&o.length?o:n.parents(h.originalElement[0]).length?["width","height"]:["width","height","top","left"];a.each(p,function(q,s){if((q=(k[s]||0)+(f[s]||0))&&q>=0)m[s]=q||null});if(a.browser.opera&&/relative/.test(n.css("position"))){g._revertToRelativePosition=true;n.css({position:"absolute",top:"auto",left:"auto"})}n.css(m)})};typeof e.alsoResize=="object"&&!e.alsoResize.nodeType? -a.each(e.alsoResize,function(l,o){j(l,o)}):j(e.alsoResize)},stop:function(){var e=a(this).data("resizable"),h=e.options,g=function(i){a(i).each(function(){var b=a(this);b.css({position:b.data("resizable-alsoresize").position})})};if(e._revertToRelativePosition){e._revertToRelativePosition=false;typeof h.alsoResize=="object"&&!h.alsoResize.nodeType?a.each(h.alsoResize,function(i){g(i)}):g(h.alsoResize)}a(this).removeData("resizable-alsoresize")}});a.ui.plugin.add("resizable","animate",{stop:function(e){var h= -a(this).data("resizable"),g=h.options,i=h._proportionallyResizeElements,b=i.length&&/textarea/i.test(i[0].nodeName),f=b&&a.ui.hasScroll(i[0],"left")?0:h.sizeDiff.height;b={width:h.size.width-(b?0:h.sizeDiff.width),height:h.size.height-f};f=parseInt(h.element.css("left"),10)+(h.position.left-h.originalPosition.left)||null;var j=parseInt(h.element.css("top"),10)+(h.position.top-h.originalPosition.top)||null;h.element.animate(a.extend(b,j&&f?{top:j,left:f}:{}),{duration:g.animateDuration,easing:g.animateEasing, -step:function(){var l={width:parseInt(h.element.css("width"),10),height:parseInt(h.element.css("height"),10),top:parseInt(h.element.css("top"),10),left:parseInt(h.element.css("left"),10)};i&&i.length&&a(i[0]).css({width:l.width,height:l.height});h._updateCache(l);h._propagate("resize",e)}})}});a.ui.plugin.add("resizable","containment",{start:function(){var e=a(this).data("resizable"),h=e.element,g=e.options.containment;if(h=g instanceof a?g.get(0):/parent/.test(g)?h.parent().get(0):g){e.containerElement= -a(h);if(/document/.test(g)||g==document){e.containerOffset={left:0,top:0};e.containerPosition={left:0,top:0};e.parentData={element:a(document),left:0,top:0,width:a(document).width(),height:a(document).height()||document.body.parentNode.scrollHeight}}else{var i=a(h),b=[];a(["Top","Right","Left","Bottom"]).each(function(l,o){b[l]=d(i.css("padding"+o))});e.containerOffset=i.offset();e.containerPosition=i.position();e.containerSize={height:i.innerHeight()-b[3],width:i.innerWidth()-b[1]};g=e.containerOffset; -var f=e.containerSize.height,j=e.containerSize.width;j=a.ui.hasScroll(h,"left")?h.scrollWidth:j;f=a.ui.hasScroll(h)?h.scrollHeight:f;e.parentData={element:h,left:g.left,top:g.top,width:j,height:f}}}},resize:function(e){var h=a(this).data("resizable"),g=h.options,i=h.containerOffset,b=h.position;e=h._aspectRatio||e.shiftKey;var f={top:0,left:0},j=h.containerElement;if(j[0]!=document&&/static/.test(j.css("position")))f=i;if(b.left<(h._helper?i.left:0)){h.size.width+=h._helper?h.position.left-i.left: -h.position.left-f.left;if(e)h.size.height=h.size.width/g.aspectRatio;h.position.left=g.helper?i.left:0}if(b.top<(h._helper?i.top:0)){h.size.height+=h._helper?h.position.top-i.top:h.position.top;if(e)h.size.width=h.size.height*g.aspectRatio;h.position.top=h._helper?i.top:0}h.offset.left=h.parentData.left+h.position.left;h.offset.top=h.parentData.top+h.position.top;g=Math.abs((h._helper?h.offset.left-f.left:h.offset.left-f.left)+h.sizeDiff.width);i=Math.abs((h._helper?h.offset.top-f.top:h.offset.top- -i.top)+h.sizeDiff.height);b=h.containerElement.get(0)==h.element.parent().get(0);f=/relative|absolute/.test(h.containerElement.css("position"));if(b&&f)g-=h.parentData.left;if(g+h.size.width>=h.parentData.width){h.size.width=h.parentData.width-g;if(e)h.size.height=h.size.width/h.aspectRatio}if(i+h.size.height>=h.parentData.height){h.size.height=h.parentData.height-i;if(e)h.size.width=h.size.height*h.aspectRatio}},stop:function(){var e=a(this).data("resizable"),h=e.options,g=e.containerOffset,i=e.containerPosition, -b=e.containerElement,f=a(e.helper),j=f.offset(),l=f.outerWidth()-e.sizeDiff.width;f=f.outerHeight()-e.sizeDiff.height;e._helper&&!h.animate&&/relative/.test(b.css("position"))&&a(this).css({left:j.left-i.left-g.left,width:l,height:f});e._helper&&!h.animate&&/static/.test(b.css("position"))&&a(this).css({left:j.left-i.left-g.left,width:l,height:f})}});a.ui.plugin.add("resizable","ghost",{start:function(){var e=a(this).data("resizable"),h=e.options,g=e.size;e.ghost=e.originalElement.clone();e.ghost.css({opacity:0.25, -display:"block",position:"relative",height:g.height,width:g.width,margin:0,left:0,top:0}).addClass("ui-resizable-ghost").addClass(typeof h.ghost=="string"?h.ghost:"");e.ghost.appendTo(e.helper)},resize:function(){var e=a(this).data("resizable");e.ghost&&e.ghost.css({position:"relative",height:e.size.height,width:e.size.width})},stop:function(){var e=a(this).data("resizable");e.ghost&&e.helper&&e.helper.get(0).removeChild(e.ghost.get(0))}});a.ui.plugin.add("resizable","grid",{resize:function(){var e= -a(this).data("resizable"),h=e.options,g=e.size,i=e.originalSize,b=e.originalPosition,f=e.axis;h.grid=typeof h.grid=="number"?[h.grid,h.grid]:h.grid;var j=Math.round((g.width-i.width)/(h.grid[0]||1))*(h.grid[0]||1);h=Math.round((g.height-i.height)/(h.grid[1]||1))*(h.grid[1]||1);if(/^(se|s|e)$/.test(f)){e.size.width=i.width+j;e.size.height=i.height+h}else if(/^(ne)$/.test(f)){e.size.width=i.width+j;e.size.height=i.height+h;e.position.top=b.top-h}else{if(/^(sw)$/.test(f)){e.size.width=i.width+j;e.size.height= -i.height+h}else{e.size.width=i.width+j;e.size.height=i.height+h;e.position.top=b.top-h}e.position.left=b.left-j}}});var d=function(e){return parseInt(e,10)||0},c=function(e){return!isNaN(parseInt(e,10))}})(jQuery); -(function(a){a.widget("ui.selectable",a.ui.mouse,{options:{appendTo:"body",autoRefresh:true,distance:0,filter:"*",tolerance:"touch"},_create:function(){var d=this;this.element.addClass("ui-selectable");this.dragged=false;var c;this.refresh=function(){c=a(d.options.filter,d.element[0]);c.each(function(){var e=a(this),h=e.offset();a.data(this,"selectable-item",{element:this,$element:e,left:h.left,top:h.top,right:h.left+e.outerWidth(),bottom:h.top+e.outerHeight(),startselected:false,selected:e.hasClass("ui-selected"), -selecting:e.hasClass("ui-selecting"),unselecting:e.hasClass("ui-unselecting")})})};this.refresh();this.selectees=c.addClass("ui-selectee");this._mouseInit();this.helper=a("
        ")},destroy:function(){this.selectees.removeClass("ui-selectee").removeData("selectable-item");this.element.removeClass("ui-selectable ui-selectable-disabled").removeData("selectable").unbind(".selectable");this._mouseDestroy();return this},_mouseStart:function(d){var c=this;this.opos=[d.pageX, -d.pageY];if(!this.options.disabled){var e=this.options;this.selectees=a(e.filter,this.element[0]);this._trigger("start",d);a(e.appendTo).append(this.helper);this.helper.css({left:d.clientX,top:d.clientY,width:0,height:0});e.autoRefresh&&this.refresh();this.selectees.filter(".ui-selected").each(function(){var h=a.data(this,"selectable-item");h.startselected=true;if(!d.metaKey){h.$element.removeClass("ui-selected");h.selected=false;h.$element.addClass("ui-unselecting");h.unselecting=true;c._trigger("unselecting", -d,{unselecting:h.element})}});a(d.target).parents().andSelf().each(function(){var h=a.data(this,"selectable-item");if(h){var g=!d.metaKey||!h.$element.hasClass("ui-selected");h.$element.removeClass(g?"ui-unselecting":"ui-selected").addClass(g?"ui-selecting":"ui-unselecting");h.unselecting=!g;h.selecting=g;(h.selected=g)?c._trigger("selecting",d,{selecting:h.element}):c._trigger("unselecting",d,{unselecting:h.element});return false}})}},_mouseDrag:function(d){var c=this;this.dragged=true;if(!this.options.disabled){var e= -this.options,h=this.opos[0],g=this.opos[1],i=d.pageX,b=d.pageY;if(h>i){var f=i;i=h;h=f}if(g>b){f=b;b=g;g=f}this.helper.css({left:h,top:g,width:i-h,height:b-g});this.selectees.each(function(){var j=a.data(this,"selectable-item");if(!(!j||j.element==c.element[0])){var l=false;if(e.tolerance=="touch")l=!(j.left>i||j.rightb||j.bottomh&&j.rightg&&j.bottom *",opacity:false,placeholder:false,revert:false,scroll:true,scrollSensitivity:20,scrollSpeed:20,scope:"default",tolerance:"intersect",zIndex:1E3},_create:function(){var d=this.options;this.containerCache={};this.element.addClass("ui-sortable"); -this.refresh();this.floating=this.items.length?d.axis==="x"||/left|right/.test(this.items[0].item.css("float"))||/inline|table-cell/.test(this.items[0].item.css("display")):false;this.offset=this.element.offset();this._mouseInit()},destroy:function(){this.element.removeClass("ui-sortable ui-sortable-disabled").removeData("sortable").unbind(".sortable");this._mouseDestroy();for(var d=this.items.length-1;d>=0;d--)this.items[d].item.removeData("sortable-item");return this},_setOption:function(d,c){if(d=== -"disabled"){this.options[d]=c;this.widget()[c?"addClass":"removeClass"]("ui-sortable-disabled")}else a.Widget.prototype._setOption.apply(this,arguments)},_mouseCapture:function(d,c){if(this.reverting)return false;if(this.options.disabled||this.options.type=="static")return false;this._refreshItems(d);var e=null,h=this;a(d.target).parents().each(function(){if(a.data(this,"sortable-item")==h){e=a(this);return false}});if(a.data(d.target,"sortable-item")==h)e=a(d.target);if(!e)return false;if(this.options.handle&& -!c){var g=false;a(this.options.handle,e).find("*").andSelf().each(function(){if(this==d.target)g=true});if(!g)return false}this.currentItem=e;this._removeCurrentsFromItems();return true},_mouseStart:function(d,c,e){c=this.options;var h=this;this.currentContainer=this;this.refreshPositions();this.helper=this._createHelper(d);this._cacheHelperProportions();this._cacheMargins();this.scrollParent=this.helper.scrollParent();this.offset=this.currentItem.offset();this.offset={top:this.offset.top-this.margins.top, -left:this.offset.left-this.margins.left};this.helper.css("position","absolute");this.cssPosition=this.helper.css("position");a.extend(this.offset,{click:{left:d.pageX-this.offset.left,top:d.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()});this.originalPosition=this._generatePosition(d);this.originalPageX=d.pageX;this.originalPageY=d.pageY;c.cursorAt&&this._adjustOffsetFromHelper(c.cursorAt);this.domPosition={prev:this.currentItem.prev()[0],parent:this.currentItem.parent()[0]}; -this.helper[0]!=this.currentItem[0]&&this.currentItem.hide();this._createPlaceholder();c.containment&&this._setContainment();if(c.cursor){if(a("body").css("cursor"))this._storedCursor=a("body").css("cursor");a("body").css("cursor",c.cursor)}if(c.opacity){if(this.helper.css("opacity"))this._storedOpacity=this.helper.css("opacity");this.helper.css("opacity",c.opacity)}if(c.zIndex){if(this.helper.css("zIndex"))this._storedZIndex=this.helper.css("zIndex");this.helper.css("zIndex",c.zIndex)}if(this.scrollParent[0]!= -document&&this.scrollParent[0].tagName!="HTML")this.overflowOffset=this.scrollParent.offset();this._trigger("start",d,this._uiHash());this._preserveHelperProportions||this._cacheHelperProportions();if(!e)for(e=this.containers.length-1;e>=0;e--)this.containers[e]._trigger("activate",d,h._uiHash(this));if(a.ui.ddmanager)a.ui.ddmanager.current=this;a.ui.ddmanager&&!c.dropBehaviour&&a.ui.ddmanager.prepareOffsets(this,d);this.dragging=true;this.helper.addClass("ui-sortable-helper");this._mouseDrag(d); -return true},_mouseDrag:function(d){this.position=this._generatePosition(d);this.positionAbs=this._convertPositionTo("absolute");if(!this.lastPositionAbs)this.lastPositionAbs=this.positionAbs;if(this.options.scroll){var c=this.options,e=false;if(this.scrollParent[0]!=document&&this.scrollParent[0].tagName!="HTML"){if(this.overflowOffset.top+this.scrollParent[0].offsetHeight-d.pageY=0;c--){e=this.items[c];var h=e.item[0],g=this._intersectsWithPointer(e);if(g)if(h!=this.currentItem[0]&&this.placeholder[g==1?"next":"prev"]()[0]!=h&&!a.ui.contains(this.placeholder[0],h)&&(this.options.type=="semi-dynamic"?!a.ui.contains(this.element[0], -h):true)){this.direction=g==1?"down":"up";if(this.options.tolerance=="pointer"||this._intersectsWithSides(e))this._rearrange(d,e);else break;this._trigger("change",d,this._uiHash());break}}this._contactContainers(d);a.ui.ddmanager&&a.ui.ddmanager.drag(this,d);this._trigger("sort",d,this._uiHash());this.lastPositionAbs=this.positionAbs;return false},_mouseStop:function(d,c){if(d){a.ui.ddmanager&&!this.options.dropBehaviour&&a.ui.ddmanager.drop(this,d);if(this.options.revert){var e=this;c=e.placeholder.offset(); -e.reverting=true;a(this.helper).animate({left:c.left-this.offset.parent.left-e.margins.left+(this.offsetParent[0]==document.body?0:this.offsetParent[0].scrollLeft),top:c.top-this.offset.parent.top-e.margins.top+(this.offsetParent[0]==document.body?0:this.offsetParent[0].scrollTop)},parseInt(this.options.revert,10)||500,function(){e._clear(d)})}else this._clear(d,c);return false}},cancel:function(){var d=this;if(this.dragging){this._mouseUp({target:null});this.options.helper=="original"?this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"): -this.currentItem.show();for(var c=this.containers.length-1;c>=0;c--){this.containers[c]._trigger("deactivate",null,d._uiHash(this));if(this.containers[c].containerCache.over){this.containers[c]._trigger("out",null,d._uiHash(this));this.containers[c].containerCache.over=0}}}if(this.placeholder){this.placeholder[0].parentNode&&this.placeholder[0].parentNode.removeChild(this.placeholder[0]);this.options.helper!="original"&&this.helper&&this.helper[0].parentNode&&this.helper.remove();a.extend(this,{helper:null, -dragging:false,reverting:false,_noFinalSort:null});this.domPosition.prev?a(this.domPosition.prev).after(this.currentItem):a(this.domPosition.parent).prepend(this.currentItem)}return this},serialize:function(d){var c=this._getItemsAsjQuery(d&&d.connected),e=[];d=d||{};a(c).each(function(){var h=(a(d.item||this).attr(d.attribute||"id")||"").match(d.expression||/(.+)[-=_](.+)/);if(h)e.push((d.key||h[1]+"[]")+"="+(d.key&&d.expression?h[1]:h[2]))});!e.length&&d.key&&e.push(d.key+"=");return e.join("&")}, -toArray:function(d){var c=this._getItemsAsjQuery(d&&d.connected),e=[];d=d||{};c.each(function(){e.push(a(d.item||this).attr(d.attribute||"id")||"")});return e},_intersectsWith:function(d){var c=this.positionAbs.left,e=c+this.helperProportions.width,h=this.positionAbs.top,g=h+this.helperProportions.height,i=d.left,b=i+d.width,f=d.top,j=f+d.height,l=this.offset.click.top,o=this.offset.click.left;l=h+l>f&&h+li&&c+od[this.floating?"width":"height"]?l:i0?"down":"up")},_getDragHorizontalDirection:function(){var d=this.positionAbs.left-this.lastPositionAbs.left;return d!=0&&(d>0?"right":"left")},refresh:function(d){this._refreshItems(d);this.refreshPositions();return this},_connectWith:function(){var d=this.options;return d.connectWith.constructor==String?[d.connectWith]:d.connectWith},_getItemsAsjQuery:function(d){var c=[],e=[],h=this._connectWith(); -if(h&&d)for(d=h.length-1;d>=0;d--)for(var g=a(h[d]),i=g.length-1;i>=0;i--){var b=a.data(g[i],"sortable");if(b&&b!=this&&!b.options.disabled)e.push([a.isFunction(b.options.items)?b.options.items.call(b.element):a(b.options.items,b.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),b])}e.push([a.isFunction(this.options.items)?this.options.items.call(this.element,null,{options:this.options,item:this.currentItem}):a(this.options.items,this.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"), -this]);for(d=e.length-1;d>=0;d--)e[d][0].each(function(){c.push(this)});return a(c)},_removeCurrentsFromItems:function(){for(var d=this.currentItem.find(":data(sortable-item)"),c=0;c=0;g--)for(var i=a(h[g]),b=i.length-1;b>=0;b--){var f=a.data(i[b],"sortable");if(f&&f!=this&&!f.options.disabled){e.push([a.isFunction(f.options.items)?f.options.items.call(f.element[0],d,{item:this.currentItem}):a(f.options.items,f.element),f]);this.containers.push(f)}}for(g=e.length-1;g>=0;g--){d=e[g][1];h=e[g][0];b=0;for(i=h.length;b=0;c--){var e=this.items[c];if(!(e.instance!=this.currentContainer&&this.currentContainer&&e.item[0]!=this.currentItem[0])){var h=this.options.toleranceElement?a(this.options.toleranceElement,e.item):e.item;if(!d){e.width=h.outerWidth();e.height=h.outerHeight()}h=h.offset();e.left=h.left;e.top=h.top}}if(this.options.custom&&this.options.custom.refreshContainers)this.options.custom.refreshContainers.call(this);else for(c= -this.containers.length-1;c>=0;c--){h=this.containers[c].element.offset();this.containers[c].containerCache.left=h.left;this.containers[c].containerCache.top=h.top;this.containers[c].containerCache.width=this.containers[c].element.outerWidth();this.containers[c].containerCache.height=this.containers[c].element.outerHeight()}return this},_createPlaceholder:function(d){var c=d||this,e=c.options;if(!e.placeholder||e.placeholder.constructor==String){var h=e.placeholder;e.placeholder={element:function(){var g= -a(document.createElement(c.currentItem[0].nodeName)).addClass(h||c.currentItem[0].className+" ui-sortable-placeholder").removeClass("ui-sortable-helper")[0];if(!h)g.style.visibility="hidden";return g},update:function(g,i){if(!(h&&!e.forcePlaceholderSize)){i.height()||i.height(c.currentItem.innerHeight()-parseInt(c.currentItem.css("paddingTop")||0,10)-parseInt(c.currentItem.css("paddingBottom")||0,10));i.width()||i.width(c.currentItem.innerWidth()-parseInt(c.currentItem.css("paddingLeft")||0,10)-parseInt(c.currentItem.css("paddingRight")|| -0,10))}}}}c.placeholder=a(e.placeholder.element.call(c.element,c.currentItem));c.currentItem.after(c.placeholder);e.placeholder.update(c,c.placeholder)},_contactContainers:function(d){for(var c=null,e=null,h=this.containers.length-1;h>=0;h--)if(!a.ui.contains(this.currentItem[0],this.containers[h].element[0]))if(this._intersectsWith(this.containers[h].containerCache)){if(!(c&&a.ui.contains(this.containers[h].element[0],c.element[0]))){c=this.containers[h];e=h}}else if(this.containers[h].containerCache.over){this.containers[h]._trigger("out", -d,this._uiHash(this));this.containers[h].containerCache.over=0}if(c)if(this.containers.length===1){this.containers[e]._trigger("over",d,this._uiHash(this));this.containers[e].containerCache.over=1}else if(this.currentContainer!=this.containers[e]){c=1E4;h=null;for(var g=this.positionAbs[this.containers[e].floating?"left":"top"],i=this.items.length-1;i>=0;i--)if(a.ui.contains(this.containers[e].element[0],this.items[i].item[0])){var b=this.items[i][this.containers[e].floating?"left":"top"];if(Math.abs(b- -g)this.containment[2])g=this.containment[2]+this.offset.click.left;if(d.pageY-this.offset.click.top>this.containment[3])i=this.containment[3]+this.offset.click.top}if(c.grid){i=this.originalPageY+Math.round((i- -this.originalPageY)/c.grid[1])*c.grid[1];i=this.containment?!(i-this.offset.click.topthis.containment[3])?i:!(i-this.offset.click.topthis.containment[2])?g:!(g-this.offset.click.left=0;h--)if(a.ui.contains(this.containers[h].element[0],this.currentItem[0])&&!c){e.push(function(g){return function(i){g._trigger("receive",i,this._uiHash(this))}}.call(this,this.containers[h]));e.push(function(g){return function(i){g._trigger("update",i,this._uiHash(this))}}.call(this,this.containers[h]))}}for(h=this.containers.length-1;h>=0;h--){c||e.push(function(g){return function(i){g._trigger("deactivate",i,this._uiHash(this))}}.call(this, -this.containers[h]));if(this.containers[h].containerCache.over){e.push(function(g){return function(i){g._trigger("out",i,this._uiHash(this))}}.call(this,this.containers[h]));this.containers[h].containerCache.over=0}}this._storedCursor&&a("body").css("cursor",this._storedCursor);this._storedOpacity&&this.helper.css("opacity",this._storedOpacity);if(this._storedZIndex)this.helper.css("zIndex",this._storedZIndex=="auto"?"":this._storedZIndex);this.dragging=false;if(this.cancelHelperRemoval){if(!c){this._trigger("beforeStop", -d,this._uiHash());for(h=0;h
      ").addClass("ui-effects-wrapper").css({fontSize:"100%",background:"transparent",border:"none",margin:0,padding:0}), -p=document.activeElement;n.wrap(m);if(n[0]===p||a.contains(n[0],p))a(p).focus();m=n.parent();if(n.css("position")=="static"){m.css({position:"relative"});n.css({position:"relative"})}else{a.extend(k,{position:n.css("position"),zIndex:n.css("z-index")});a.each(["top","left","bottom","right"],function(q,s){k[s]=n.css(s);if(isNaN(parseInt(k[s],10)))k[s]="auto"});n.css({position:"relative",top:0,left:0,right:"auto",bottom:"auto"})}return m.css(k).show()},removeWrapper:function(n){var k,m=document.activeElement; -if(n.parent().is(".ui-effects-wrapper")){k=n.parent().replaceWith(n);if(n[0]===m||a.contains(n[0],m))a(m).focus();return k}return n},setTransition:function(n,k,m,p){p=p||{};a.each(k,function(q,s){unit=n.cssUnit(s);if(unit[0]>0)p[s]=unit[0]*m+unit[1]});return p}});a.fn.extend({effect:function(n){var k=b.apply(this,arguments),m={options:k[1],duration:k[2],callback:k[3]};k=m.options.mode;var p=a.effects[n];if(a.fx.off||!p)return k?this[k](m.duration,m.callback):this.each(function(){m.callback&&m.callback.call(this)}); -return p.call(this,m)},_show:a.fn.show,show:function(n){if(f(n))return this._show.apply(this,arguments);else{var k=b.apply(this,arguments);k[1].mode="show";return this.effect.apply(this,k)}},_hide:a.fn.hide,hide:function(n){if(f(n))return this._hide.apply(this,arguments);else{var k=b.apply(this,arguments);k[1].mode="hide";return this.effect.apply(this,k)}},__toggle:a.fn.toggle,toggle:function(n){if(f(n)||typeof n==="boolean"||a.isFunction(n))return this.__toggle.apply(this,arguments);else{var k=b.apply(this, -arguments);k[1].mode="toggle";return this.effect.apply(this,k)}},cssUnit:function(n){var k=this.css(n),m=[];a.each(["em","px","%","pt"],function(p,q){if(k.indexOf(q)>0)m=[parseFloat(k),q]});return m}});a.easing.jswing=a.easing.swing;a.extend(a.easing,{def:"easeOutQuad",swing:function(n,k,m,p,q){return a.easing[a.easing.def](n,k,m,p,q)},easeInQuad:function(n,k,m,p,q){return p*(k/=q)*k+m},easeOutQuad:function(n,k,m,p,q){return-p*(k/=q)*(k-2)+m},easeInOutQuad:function(n,k,m,p,q){if((k/=q/2)<1)return p/ -2*k*k+m;return-p/2*(--k*(k-2)-1)+m},easeInCubic:function(n,k,m,p,q){return p*(k/=q)*k*k+m},easeOutCubic:function(n,k,m,p,q){return p*((k=k/q-1)*k*k+1)+m},easeInOutCubic:function(n,k,m,p,q){if((k/=q/2)<1)return p/2*k*k*k+m;return p/2*((k-=2)*k*k+2)+m},easeInQuart:function(n,k,m,p,q){return p*(k/=q)*k*k*k+m},easeOutQuart:function(n,k,m,p,q){return-p*((k=k/q-1)*k*k*k-1)+m},easeInOutQuart:function(n,k,m,p,q){if((k/=q/2)<1)return p/2*k*k*k*k+m;return-p/2*((k-=2)*k*k*k-2)+m},easeInQuint:function(n,k,m, -p,q){return p*(k/=q)*k*k*k*k+m},easeOutQuint:function(n,k,m,p,q){return p*((k=k/q-1)*k*k*k*k+1)+m},easeInOutQuint:function(n,k,m,p,q){if((k/=q/2)<1)return p/2*k*k*k*k*k+m;return p/2*((k-=2)*k*k*k*k+2)+m},easeInSine:function(n,k,m,p,q){return-p*Math.cos(k/q*(Math.PI/2))+p+m},easeOutSine:function(n,k,m,p,q){return p*Math.sin(k/q*(Math.PI/2))+m},easeInOutSine:function(n,k,m,p,q){return-p/2*(Math.cos(Math.PI*k/q)-1)+m},easeInExpo:function(n,k,m,p,q){return k==0?m:p*Math.pow(2,10*(k/q-1))+m},easeOutExpo:function(n, -k,m,p,q){return k==q?m+p:p*(-Math.pow(2,-10*k/q)+1)+m},easeInOutExpo:function(n,k,m,p,q){if(k==0)return m;if(k==q)return m+p;if((k/=q/2)<1)return p/2*Math.pow(2,10*(k-1))+m;return p/2*(-Math.pow(2,-10*--k)+2)+m},easeInCirc:function(n,k,m,p,q){return-p*(Math.sqrt(1-(k/=q)*k)-1)+m},easeOutCirc:function(n,k,m,p,q){return p*Math.sqrt(1-(k=k/q-1)*k)+m},easeInOutCirc:function(n,k,m,p,q){if((k/=q/2)<1)return-p/2*(Math.sqrt(1-k*k)-1)+m;return p/2*(Math.sqrt(1-(k-=2)*k)+1)+m},easeInElastic:function(n,k,m, -p,q){n=1.70158;var s=0,r=p;if(k==0)return m;if((k/=q)==1)return m+p;s||(s=q*0.3);if(r
      ").css({position:"absolute",visibility:"visible",left:-j*(i/e),top:-f*(b/c)}).parent().addClass("ui-effects-explode").css({position:"absolute",overflow:"hidden",width:i/e,height:b/c,left:g.left+j*(i/e)+(d.options.mode=="show"?(j-Math.floor(e/2))*(i/e):0),top:g.top+f*(b/c)+(d.options.mode=="show"?(f-Math.floor(c/2))*(b/c):0),opacity:d.options.mode=="show"?0:1}).animate({left:g.left+j*(i/e)+(d.options.mode=="show"?0:(j-Math.floor(e/2))*(i/e)),top:g.top+ -f*(b/c)+(d.options.mode=="show"?0:(f-Math.floor(c/2))*(b/c)),opacity:d.options.mode=="show"?1:0},d.duration||500);setTimeout(function(){d.options.mode=="show"?h.css({visibility:"visible"}):h.css({visibility:"visible"}).hide();d.callback&&d.callback.apply(h[0]);h.dequeue();a("div.ui-effects-explode").remove()},d.duration||500)})}})(jQuery); -(function(a){a.effects.fade=function(d){return this.queue(function(){var c=a(this),e=a.effects.setMode(c,d.options.mode||"hide");c.animate({opacity:e},{queue:false,duration:d.duration,easing:d.options.easing,complete:function(){d.callback&&d.callback.apply(this,arguments);c.dequeue()}})})}})(jQuery); -(function(a){a.effects.fold=function(d){return this.queue(function(){var c=a(this),e=["position","top","bottom","left","right"],h=a.effects.setMode(c,d.options.mode||"hide"),g=d.options.size||15,i=!!d.options.horizFirst,b=d.duration?d.duration/2:a.fx.speeds._default/2;a.effects.save(c,e);c.show();var f=a.effects.createWrapper(c).css({overflow:"hidden"}),j=h=="show"!=i,l=j?["width","height"]:["height","width"];j=j?[f.width(),f.height()]:[f.height(),f.width()];var o=/([0-9]+)%/.exec(g);if(o)g=parseInt(o[1], -10)/100*j[h=="hide"?0:1];if(h=="show")f.css(i?{height:0,width:g}:{height:g,width:0});i={};o={};i[l[0]]=h=="show"?j[0]:g;o[l[1]]=h=="show"?j[1]:0;f.animate(i,b,d.options.easing).animate(o,b,d.options.easing,function(){h=="hide"&&c.hide();a.effects.restore(c,e);a.effects.removeWrapper(c);d.callback&&d.callback.apply(c[0],arguments);c.dequeue()})})}})(jQuery); -(function(a){a.effects.highlight=function(d){return this.queue(function(){var c=a(this),e=["backgroundImage","backgroundColor","opacity"],h=a.effects.setMode(c,d.options.mode||"show"),g={backgroundColor:c.css("backgroundColor")};if(h=="hide")g.opacity=0;a.effects.save(c,e);c.show().css({backgroundImage:"none",backgroundColor:d.options.color||"#ffff99"}).animate(g,{queue:false,duration:d.duration,easing:d.options.easing,complete:function(){h=="hide"&&c.hide();a.effects.restore(c,e);h=="show"&&!a.support.opacity&& -this.style.removeAttribute("filter");d.callback&&d.callback.apply(this,arguments);c.dequeue()}})})}})(jQuery); -(function(a){a.effects.pulsate=function(d){return this.queue(function(){var c=a(this),e=a.effects.setMode(c,d.options.mode||"show");times=(d.options.times||5)*2-1;duration=d.duration?d.duration/2:a.fx.speeds._default/2;isVisible=c.is(":visible");animateTo=0;if(!isVisible){c.css("opacity",0).show();animateTo=1}if(e=="hide"&&isVisible||e=="show"&&!isVisible)times--;for(e=0;e
      ').appendTo(document.body).addClass(d.options.className).css({top:h.top,left:h.left,height:c.innerHeight(),width:c.innerWidth(),position:"absolute"}).animate(e,d.duration,d.options.easing,function(){g.remove();d.callback&&d.callback.apply(c[0],arguments); -c.dequeue()})})}})(jQuery); -(function(a){a.widget("ui.accordion",{options:{active:0,animated:"slide",autoHeight:true,clearStyle:false,collapsible:false,event:"click",fillSpace:false,header:"> li > :first-child,> :not(li):even",icons:{header:"ui-icon-triangle-1-e",headerSelected:"ui-icon-triangle-1-s"},navigation:false,navigationFilter:function(){return this.href.toLowerCase()===location.href.toLowerCase()}},_create:function(){var d=this,c=d.options;d.running=0;d.element.addClass("ui-accordion ui-widget ui-helper-reset").children("li").addClass("ui-accordion-li-fix");d.headers= -d.element.find(c.header).addClass("ui-accordion-header ui-helper-reset ui-state-default ui-corner-all").bind("mouseenter.accordion",function(){c.disabled||a(this).addClass("ui-state-hover")}).bind("mouseleave.accordion",function(){c.disabled||a(this).removeClass("ui-state-hover")}).bind("focus.accordion",function(){c.disabled||a(this).addClass("ui-state-focus")}).bind("blur.accordion",function(){c.disabled||a(this).removeClass("ui-state-focus")});d.headers.next().addClass("ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom"); -if(c.navigation){var e=d.element.find("a").filter(c.navigationFilter).eq(0);if(e.length){var h=e.closest(".ui-accordion-header");d.active=h.length?h:e.closest(".ui-accordion-content").prev()}}d.active=d._findActive(d.active||c.active).addClass("ui-state-default ui-state-active").toggleClass("ui-corner-all").toggleClass("ui-corner-top");d.active.next().addClass("ui-accordion-content-active");d._createIcons();d.resize();d.element.attr("role","tablist");d.headers.attr("role","tab").bind("keydown.accordion", -function(g){return d._keydown(g)}).next().attr("role","tabpanel");d.headers.not(d.active||"").attr({"aria-expanded":"false","aria-selected":"false",tabIndex:-1}).next().hide();d.active.length?d.active.attr({"aria-expanded":"true","aria-selected":"true",tabIndex:0}):d.headers.eq(0).attr("tabIndex",0);a.browser.safari||d.headers.find("a").attr("tabIndex",-1);c.event&&d.headers.bind(c.event.split(" ").join(".accordion ")+".accordion",function(g){d._clickHandler.call(d,g,this);g.preventDefault()})},_createIcons:function(){var d= -this.options;if(d.icons){a("").addClass("ui-icon "+d.icons.header).prependTo(this.headers);this.active.children(".ui-icon").toggleClass(d.icons.header).toggleClass(d.icons.headerSelected);this.element.addClass("ui-accordion-icons")}},_destroyIcons:function(){this.headers.children(".ui-icon").remove();this.element.removeClass("ui-accordion-icons")},destroy:function(){var d=this.options;this.element.removeClass("ui-accordion ui-widget ui-helper-reset").removeAttr("role");this.headers.unbind(".accordion").removeClass("ui-accordion-header ui-accordion-disabled ui-helper-reset ui-state-default ui-corner-all ui-state-active ui-state-disabled ui-corner-top").removeAttr("role").removeAttr("aria-expanded").removeAttr("aria-selected").removeAttr("tabIndex"); -this.headers.find("a").removeAttr("tabIndex");this._destroyIcons();var c=this.headers.next().css("display","").removeAttr("role").removeClass("ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active ui-accordion-disabled ui-state-disabled");if(d.autoHeight||d.fillHeight)c.css("height","");return a.Widget.prototype.destroy.call(this)},_setOption:function(d,c){a.Widget.prototype._setOption.apply(this,arguments);d=="active"&&this.activate(c);if(d=="icons"){this._destroyIcons(); -c&&this._createIcons()}if(d=="disabled")this.headers.add(this.headers.next())[c?"addClass":"removeClass"]("ui-accordion-disabled ui-state-disabled")},_keydown:function(d){if(!(this.options.disabled||d.altKey||d.ctrlKey)){var c=a.ui.keyCode,e=this.headers.length,h=this.headers.index(d.target),g=false;switch(d.keyCode){case c.RIGHT:case c.DOWN:g=this.headers[(h+1)%e];break;case c.LEFT:case c.UP:g=this.headers[(h-1+e)%e];break;case c.SPACE:case c.ENTER:this._clickHandler({target:d.target},d.target); -d.preventDefault()}if(g){a(d.target).attr("tabIndex",-1);a(g).attr("tabIndex",0);g.focus();return false}return true}},resize:function(){var d=this.options,c;if(d.fillSpace){if(a.browser.msie){var e=this.element.parent().css("overflow");this.element.parent().css("overflow","hidden")}c=this.element.parent().height();a.browser.msie&&this.element.parent().css("overflow",e);this.headers.each(function(){c-=a(this).outerHeight(true)});this.headers.next().each(function(){a(this).height(Math.max(0,c-a(this).innerHeight()+ -a(this).height()))}).css("overflow","auto")}else if(d.autoHeight){c=0;this.headers.next().each(function(){c=Math.max(c,a(this).height("").height())}).height(c)}return this},activate:function(d){this.options.active=d;d=this._findActive(d)[0];this._clickHandler({target:d},d);return this},_findActive:function(d){return d?typeof d==="number"?this.headers.filter(":eq("+d+")"):this.headers.not(this.headers.not(d)):d===false?a([]):this.headers.filter(":eq(0)")},_clickHandler:function(d,c){var e=this.options; -if(!e.disabled)if(d.target){d=a(d.currentTarget||c);c=d[0]===this.active[0];e.active=e.collapsible&&c?false:this.headers.index(d);if(!(this.running||!e.collapsible&&c)){var h=this.active;f=d.next();i=this.active.next();b={options:e,newHeader:c&&e.collapsible?a([]):d,oldHeader:this.active,newContent:c&&e.collapsible?a([]):f,oldContent:i};var g=this.headers.index(this.active[0])>this.headers.index(d[0]);this.active=c?a([]):d;this._toggle(f,i,b,c,g);h.removeClass("ui-state-active ui-corner-top").addClass("ui-state-default ui-corner-all").children(".ui-icon").removeClass(e.icons.headerSelected).addClass(e.icons.header); -if(!c){d.removeClass("ui-state-default ui-corner-all").addClass("ui-state-active ui-corner-top").children(".ui-icon").removeClass(e.icons.header).addClass(e.icons.headerSelected);d.next().addClass("ui-accordion-content-active")}}}else if(e.collapsible){this.active.removeClass("ui-state-active ui-corner-top").addClass("ui-state-default ui-corner-all").children(".ui-icon").removeClass(e.icons.headerSelected).addClass(e.icons.header);this.active.next().addClass("ui-accordion-content-active");var i=this.active.next(), -b={options:e,newHeader:a([]),oldHeader:e.active,newContent:a([]),oldContent:i},f=this.active=a([]);this._toggle(f,i,b)}},_toggle:function(d,c,e,h,g){var i=this,b=i.options;i.toShow=d;i.toHide=c;i.data=e;var f=function(){if(i)return i._completed.apply(i,arguments)};i._trigger("changestart",null,i.data);i.running=c.size()===0?d.size():c.size();if(b.animated){e={};e=b.collapsible&&h?{toShow:a([]),toHide:c,complete:f,down:g,autoHeight:b.autoHeight||b.fillSpace}:{toShow:d,toHide:c,complete:f,down:g,autoHeight:b.autoHeight|| -b.fillSpace};if(!b.proxied)b.proxied=b.animated;if(!b.proxiedDuration)b.proxiedDuration=b.duration;b.animated=a.isFunction(b.proxied)?b.proxied(e):b.proxied;b.duration=a.isFunction(b.proxiedDuration)?b.proxiedDuration(e):b.proxiedDuration;h=a.ui.accordion.animations;var j=b.duration,l=b.animated;if(l&&!h[l]&&!a.easing[l])l="slide";h[l]||(h[l]=function(o){this.slide(o,{easing:l,duration:j||700})});h[l](e)}else{if(b.collapsible&&h)d.toggle();else{c.hide();d.show()}f(true)}c.prev().attr({"aria-expanded":"false", -"aria-selected":"false",tabIndex:-1}).blur();d.prev().attr({"aria-expanded":"true","aria-selected":"true",tabIndex:0}).focus()},_completed:function(d){this.running=d?0:--this.running;if(!this.running){this.options.clearStyle&&this.toShow.add(this.toHide).css({height:"",overflow:""});this.toHide.removeClass("ui-accordion-content-active");if(this.toHide.length)this.toHide.parent()[0].className=this.toHide.parent()[0].className;this._trigger("change",null,this.data)}}});a.extend(a.ui.accordion,{version:"1.8.16", -animations:{slide:function(d,c){d=a.extend({easing:"swing",duration:300},d,c);if(d.toHide.size())if(d.toShow.size()){var e=d.toShow.css("overflow"),h=0,g={},i={},b;c=d.toShow;b=c[0].style.width;c.width(parseInt(c.parent().width(),10)-parseInt(c.css("paddingLeft"),10)-parseInt(c.css("paddingRight"),10)-(parseInt(c.css("borderLeftWidth"),10)||0)-(parseInt(c.css("borderRightWidth"),10)||0));a.each(["height","paddingTop","paddingBottom"],function(f,j){i[j]="hide";f=(""+a.css(d.toShow[0],j)).match(/^([\d+-.]+)(.*)$/); -g[j]={value:f[1],unit:f[2]||"px"}});d.toShow.css({height:0,overflow:"hidden"}).show();d.toHide.filter(":hidden").each(d.complete).end().filter(":visible").animate(i,{step:function(f,j){if(j.prop=="height")h=j.end-j.start===0?0:(j.now-j.start)/(j.end-j.start);d.toShow[0].style[j.prop]=h*g[j.prop].value+g[j.prop].unit},duration:d.duration,easing:d.easing,complete:function(){d.autoHeight||d.toShow.css("height","");d.toShow.css({width:b,overflow:e});d.complete()}})}else d.toHide.animate({height:"hide", -paddingTop:"hide",paddingBottom:"hide"},d);else d.toShow.animate({height:"show",paddingTop:"show",paddingBottom:"show"},d)},bounceslide:function(d){this.slide(d,{easing:d.down?"easeOutBounce":"swing",duration:d.down?1E3:200})}}})})(jQuery); -(function(a){var d=0;a.widget("ui.autocomplete",{options:{appendTo:"body",autoFocus:false,delay:300,minLength:1,position:{my:"left top",at:"left bottom",collision:"none"},source:null},pending:0,_create:function(){var c=this,e=this.element[0].ownerDocument,h;this.element.addClass("ui-autocomplete-input").attr("autocomplete","off").attr({role:"textbox","aria-autocomplete":"list","aria-haspopup":"true"}).bind("keydown.autocomplete",function(g){if(!(c.options.disabled||c.element.propAttr("readOnly"))){h= -false;var i=a.ui.keyCode;switch(g.keyCode){case i.PAGE_UP:c._move("previousPage",g);break;case i.PAGE_DOWN:c._move("nextPage",g);break;case i.UP:c._move("previous",g);g.preventDefault();break;case i.DOWN:c._move("next",g);g.preventDefault();break;case i.ENTER:case i.NUMPAD_ENTER:if(c.menu.active){h=true;g.preventDefault()}case i.TAB:if(!c.menu.active)return;c.menu.select(g);break;case i.ESCAPE:c.element.val(c.term);c.close(g);break;default:clearTimeout(c.searching);c.searching=setTimeout(function(){if(c.term!= -c.element.val()){c.selectedItem=null;c.search(null,g)}},c.options.delay);break}}}).bind("keypress.autocomplete",function(g){if(h){h=false;g.preventDefault()}}).bind("focus.autocomplete",function(){if(!c.options.disabled){c.selectedItem=null;c.previous=c.element.val()}}).bind("blur.autocomplete",function(g){if(!c.options.disabled){clearTimeout(c.searching);c.closing=setTimeout(function(){c.close(g);c._change(g)},150)}});this._initSource();this.response=function(){return c._response.apply(c,arguments)}; -this.menu=a("
        ").addClass("ui-autocomplete").appendTo(a(this.options.appendTo||"body",e)[0]).mousedown(function(g){var i=c.menu.element[0];a(g.target).closest(".ui-menu-item").length||setTimeout(function(){a(document).one("mousedown",function(b){b.target!==c.element[0]&&b.target!==i&&!a.ui.contains(i,b.target)&&c.close()})},1);setTimeout(function(){clearTimeout(c.closing)},13)}).menu({focus:function(g,i){i=i.item.data("item.autocomplete");false!==c._trigger("focus",g,{item:i})&&/^key/.test(g.originalEvent.type)&& -c.element.val(i.value)},selected:function(g,i){var b=i.item.data("item.autocomplete"),f=c.previous;if(c.element[0]!==e.activeElement){c.element.focus();c.previous=f;setTimeout(function(){c.previous=f;c.selectedItem=b},1)}false!==c._trigger("select",g,{item:b})&&c.element.val(b.value);c.term=c.element.val();c.close(g);c.selectedItem=b},blur:function(){c.menu.element.is(":visible")&&c.element.val()!==c.term&&c.element.val(c.term)}}).zIndex(this.element.zIndex()+1).css({top:0,left:0}).hide().data("menu"); -a.fn.bgiframe&&this.menu.element.bgiframe()},destroy:function(){this.element.removeClass("ui-autocomplete-input").removeAttr("autocomplete").removeAttr("role").removeAttr("aria-autocomplete").removeAttr("aria-haspopup");this.menu.element.remove();a.Widget.prototype.destroy.call(this)},_setOption:function(c,e){a.Widget.prototype._setOption.apply(this,arguments);c==="source"&&this._initSource();if(c==="appendTo")this.menu.element.appendTo(a(e||"body",this.element[0].ownerDocument)[0]);c==="disabled"&& -e&&this.xhr&&this.xhr.abort()},_initSource:function(){var c=this,e,h;if(a.isArray(this.options.source)){e=this.options.source;this.source=function(g,i){i(a.ui.autocomplete.filter(e,g.term))}}else if(typeof this.options.source==="string"){h=this.options.source;this.source=function(g,i){c.xhr&&c.xhr.abort();c.xhr=a.ajax({url:h,data:g,dataType:"json",autocompleteRequest:++d,success:function(b){this.autocompleteRequest===d&&i(b)},error:function(){this.autocompleteRequest===d&&i([])}})}}else this.source= -this.options.source},search:function(c,e){c=c!=null?c:this.element.val();this.term=this.element.val();if(c.length
      • ").data("item.autocomplete",e).append(a("").text(e.label)).appendTo(c)},_move:function(c,e){if(this.menu.element.is(":visible"))if(this.menu.first()&&/^previous/.test(c)||this.menu.last()&&/^next/.test(c)){this.element.val(this.term);this.menu.deactivate()}else this.menu[c](e);else this.search(null,e)},widget:function(){return this.menu.element}});a.extend(a.ui.autocomplete,{escapeRegex:function(c){return c.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, -"\\$&")},filter:function(c,e){var h=new RegExp(a.ui.autocomplete.escapeRegex(e),"i");return a.grep(c,function(g){return h.test(g.label||g.value||g)})}})})(jQuery); -(function(a){a.widget("ui.menu",{_create:function(){var d=this;this.element.addClass("ui-menu ui-widget ui-widget-content ui-corner-all").attr({role:"listbox","aria-activedescendant":"ui-active-menuitem"}).click(function(c){if(a(c.target).closest(".ui-menu-item a").length){c.preventDefault();d.select(c)}});this.refresh()},refresh:function(){var d=this;this.element.children("li:not(.ui-menu-item):has(a)").addClass("ui-menu-item").attr("role","menuitem").children("a").addClass("ui-corner-all").attr("tabindex", --1).mouseenter(function(c){d.activate(c,a(this).parent())}).mouseleave(function(){d.deactivate()})},activate:function(d,c){this.deactivate();if(this.hasScroll()){var e=c.offset().top-this.element.offset().top,h=this.element.scrollTop(),g=this.element.height();if(e<0)this.element.scrollTop(h+e);else e>=g&&this.element.scrollTop(h+e-g+c.height())}this.active=c.eq(0).children("a").addClass("ui-state-hover").attr("id","ui-active-menuitem").end();this._trigger("focus",d,{item:c})},deactivate:function(){if(this.active){this.active.children("a").removeClass("ui-state-hover").removeAttr("id"); -this._trigger("blur");this.active=null}},next:function(d){this.move("next",".ui-menu-item:first",d)},previous:function(d){this.move("prev",".ui-menu-item:last",d)},first:function(){return this.active&&!this.active.prevAll(".ui-menu-item").length},last:function(){return this.active&&!this.active.nextAll(".ui-menu-item").length},move:function(d,c,e){if(this.active){d=this.active[d+"All"](".ui-menu-item").eq(0);d.length?this.activate(e,d):this.activate(e,this.element.children(c))}else this.activate(e, -this.element.children(c))},nextPage:function(d){if(this.hasScroll())if(!this.active||this.last())this.activate(d,this.element.children(".ui-menu-item:first"));else{var c=this.active.offset().top,e=this.element.height(),h=this.element.children(".ui-menu-item").filter(function(){var g=a(this).offset().top-c-e+a(this).height();return g<10&&g>-10});h.length||(h=this.element.children(".ui-menu-item:last"));this.activate(d,h)}else this.activate(d,this.element.children(".ui-menu-item").filter(!this.active|| -this.last()?":first":":last"))},previousPage:function(d){if(this.hasScroll())if(!this.active||this.first())this.activate(d,this.element.children(".ui-menu-item:last"));else{var c=this.active.offset().top,e=this.element.height();result=this.element.children(".ui-menu-item").filter(function(){var h=a(this).offset().top-c+e-a(this).height();return h<10&&h>-10});result.length||(result=this.element.children(".ui-menu-item:first"));this.activate(d,result)}else this.activate(d,this.element.children(".ui-menu-item").filter(!this.active|| -this.first()?":last":":first"))},hasScroll:function(){return this.element.height()").addClass("ui-button-text").html(this.options.label).appendTo(b.empty()).text(),j=this.options.icons,l=j.primary&&j.secondary,o=[];if(j.primary||j.secondary){if(this.options.text)o.push("ui-button-text-icon"+(l?"s":j.primary?"-primary":"-secondary"));j.primary&&b.prepend("");j.secondary&&b.append("");if(!this.options.text){o.push(l?"ui-button-icons-only": -"ui-button-icon-only");this.hasTitle||b.attr("title",f)}}else o.push("ui-button-text-only");b.addClass(o.join(" "))}}});a.widget("ui.buttonset",{options:{items:":button, :submit, :reset, :checkbox, :radio, a, :data(button)"},_create:function(){this.element.addClass("ui-buttonset")},_init:function(){this.refresh()},_setOption:function(b,f){b==="disabled"&&this.buttons.button("option",b,f);a.Widget.prototype._setOption.apply(this,arguments)},refresh:function(){var b=this.element.css("direction")=== -"ltr";this.buttons=this.element.find(this.options.items).filter(":ui-button").button("refresh").end().not(":ui-button").button().end().map(function(){return a(this).button("widget")[0]}).removeClass("ui-corner-all ui-corner-left ui-corner-right").filter(":first").addClass(b?"ui-corner-left":"ui-corner-right").end().filter(":last").addClass(b?"ui-corner-right":"ui-corner-left").end().end()},destroy:function(){this.element.removeClass("ui-buttonset");this.buttons.map(function(){return a(this).button("widget")[0]}).removeClass("ui-corner-left ui-corner-right").end().button("destroy"); -a.Widget.prototype.destroy.call(this)}})})(jQuery); -(function(a,d){function c(){this.debug=false;this._curInst=null;this._keyEvent=false;this._disabledInputs=[];this._inDialog=this._datepickerShowing=false;this._mainDivId="ui-datepicker-div";this._inlineClass="ui-datepicker-inline";this._appendClass="ui-datepicker-append";this._triggerClass="ui-datepicker-trigger";this._dialogClass="ui-datepicker-dialog";this._disableClass="ui-datepicker-disabled";this._unselectableClass="ui-datepicker-unselectable";this._currentClass="ui-datepicker-current-day";this._dayOverClass= -"ui-datepicker-days-cell-over";this.regional=[];this.regional[""]={closeText:"Done",prevText:"Prev",nextText:"Next",currentText:"Today",monthNames:["January","February","March","April","May","June","July","August","September","October","November","December"],monthNamesShort:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],dayNames:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],dayNamesShort:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],dayNamesMin:["Su", -"Mo","Tu","We","Th","Fr","Sa"],weekHeader:"Wk",dateFormat:"mm/dd/yy",firstDay:0,isRTL:false,showMonthAfterYear:false,yearSuffix:""};this._defaults={showOn:"focus",showAnim:"fadeIn",showOptions:{},defaultDate:null,appendText:"",buttonText:"...",buttonImage:"",buttonImageOnly:false,hideIfNoPrevNext:false,navigationAsDateFormat:false,gotoCurrent:false,changeMonth:false,changeYear:false,yearRange:"c-10:c+10",showOtherMonths:false,selectOtherMonths:false,showWeek:false,calculateWeek:this.iso8601Week,shortYearCutoff:"+10", -minDate:null,maxDate:null,duration:"fast",beforeShowDay:null,beforeShow:null,onSelect:null,onChangeMonthYear:null,onClose:null,numberOfMonths:1,showCurrentAtPos:0,stepMonths:1,stepBigMonths:12,altField:"",altFormat:"",constrainInput:true,showButtonPanel:false,autoSize:false,disabled:false};a.extend(this._defaults,this.regional[""]);this.dpDiv=e(a('
        '))}function e(b){return b.bind("mouseout", -function(f){f=a(f.target).closest("button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a");f.length&&f.removeClass("ui-state-hover ui-datepicker-prev-hover ui-datepicker-next-hover")}).bind("mouseover",function(f){f=a(f.target).closest("button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a");if(!(a.datepicker._isDisabledDatepicker(i.inline?b.parent()[0]:i.input[0])||!f.length)){f.parents(".ui-datepicker-calendar").find("a").removeClass("ui-state-hover"); -f.addClass("ui-state-hover");f.hasClass("ui-datepicker-prev")&&f.addClass("ui-datepicker-prev-hover");f.hasClass("ui-datepicker-next")&&f.addClass("ui-datepicker-next-hover")}})}function h(b,f){a.extend(b,f);for(var j in f)if(f[j]==null||f[j]==d)b[j]=f[j];return b}a.extend(a.ui,{datepicker:{version:"1.8.16"}});var g=(new Date).getTime(),i;a.extend(c.prototype,{markerClassName:"hasDatepicker",maxRows:4,log:function(){this.debug&&console.log.apply("",arguments)},_widgetDatepicker:function(){return this.dpDiv}, -setDefaults:function(b){h(this._defaults,b||{});return this},_attachDatepicker:function(b,f){var j=null;for(var l in this._defaults){var o=b.getAttribute("date:"+l);if(o){j=j||{};try{j[l]=eval(o)}catch(n){j[l]=o}}}l=b.nodeName.toLowerCase();o=l=="div"||l=="span";if(!b.id){this.uuid+=1;b.id="dp"+this.uuid}var k=this._newInst(a(b),o);k.settings=a.extend({},f||{},j||{});if(l=="input")this._connectDatepicker(b,k);else o&&this._inlineDatepicker(b,k)},_newInst:function(b,f){return{id:b[0].id.replace(/([^A-Za-z0-9_-])/g, -"\\\\$1"),input:b,selectedDay:0,selectedMonth:0,selectedYear:0,drawMonth:0,drawYear:0,inline:f,dpDiv:!f?this.dpDiv:e(a('
        '))}},_connectDatepicker:function(b,f){var j=a(b);f.append=a([]);f.trigger=a([]);if(!j.hasClass(this.markerClassName)){this._attachments(j,f);j.addClass(this.markerClassName).keydown(this._doKeyDown).keypress(this._doKeyPress).keyup(this._doKeyUp).bind("setData.datepicker", -function(l,o,n){f.settings[o]=n}).bind("getData.datepicker",function(l,o){return this._get(f,o)});this._autoSize(f);a.data(b,"datepicker",f);f.settings.disabled&&this._disableDatepicker(b)}},_attachments:function(b,f){var j=this._get(f,"appendText"),l=this._get(f,"isRTL");f.append&&f.append.remove();if(j){f.append=a(''+j+"");b[l?"before":"after"](f.append)}b.unbind("focus",this._showDatepicker);f.trigger&&f.trigger.remove();j=this._get(f,"showOn");if(j== -"focus"||j=="both")b.focus(this._showDatepicker);if(j=="button"||j=="both"){j=this._get(f,"buttonText");var o=this._get(f,"buttonImage");f.trigger=a(this._get(f,"buttonImageOnly")?a("").addClass(this._triggerClass).attr({src:o,alt:j,title:j}):a('').addClass(this._triggerClass).html(o==""?j:a("").attr({src:o,alt:j,title:j})));b[l?"before":"after"](f.trigger);f.trigger.click(function(){a.datepicker._datepickerShowing&&a.datepicker._lastInput==b[0]?a.datepicker._hideDatepicker(): -a.datepicker._showDatepicker(b[0]);return false})}},_autoSize:function(b){if(this._get(b,"autoSize")&&!b.inline){var f=new Date(2009,11,20),j=this._get(b,"dateFormat");if(j.match(/[DM]/)){var l=function(o){for(var n=0,k=0,m=0;mn){n=o[m].length;k=m}return k};f.setMonth(l(this._get(b,j.match(/MM/)?"monthNames":"monthNamesShort")));f.setDate(l(this._get(b,j.match(/DD/)?"dayNames":"dayNamesShort"))+20-f.getDay())}b.input.attr("size",this._formatDate(b,f).length)}},_inlineDatepicker:function(b, -f){var j=a(b);if(!j.hasClass(this.markerClassName)){j.addClass(this.markerClassName).append(f.dpDiv).bind("setData.datepicker",function(l,o,n){f.settings[o]=n}).bind("getData.datepicker",function(l,o){return this._get(f,o)});a.data(b,"datepicker",f);this._setDate(f,this._getDefaultDate(f),true);this._updateDatepicker(f);this._updateAlternate(f);f.settings.disabled&&this._disableDatepicker(b);f.dpDiv.css("display","block")}},_dialogDatepicker:function(b,f,j,l,o){b=this._dialogInst;if(!b){this.uuid+= -1;this._dialogInput=a('');this._dialogInput.keydown(this._doKeyDown);a("body").append(this._dialogInput);b=this._dialogInst=this._newInst(this._dialogInput,false);b.settings={};a.data(this._dialogInput[0],"datepicker",b)}h(b.settings,l||{});f=f&&f.constructor==Date?this._formatDate(b,f):f;this._dialogInput.val(f);this._pos=o?o.length?o:[o.pageX,o.pageY]:null;if(!this._pos)this._pos=[document.documentElement.clientWidth/ -2-100+(document.documentElement.scrollLeft||document.body.scrollLeft),document.documentElement.clientHeight/2-150+(document.documentElement.scrollTop||document.body.scrollTop)];this._dialogInput.css("left",this._pos[0]+20+"px").css("top",this._pos[1]+"px");b.settings.onSelect=j;this._inDialog=true;this.dpDiv.addClass(this._dialogClass);this._showDatepicker(this._dialogInput[0]);a.blockUI&&a.blockUI(this.dpDiv);a.data(this._dialogInput[0],"datepicker",b);return this},_destroyDatepicker:function(b){var f= -a(b),j=a.data(b,"datepicker");if(f.hasClass(this.markerClassName)){var l=b.nodeName.toLowerCase();a.removeData(b,"datepicker");if(l=="input"){j.append.remove();j.trigger.remove();f.removeClass(this.markerClassName).unbind("focus",this._showDatepicker).unbind("keydown",this._doKeyDown).unbind("keypress",this._doKeyPress).unbind("keyup",this._doKeyUp)}else if(l=="div"||l=="span")f.removeClass(this.markerClassName).empty()}},_enableDatepicker:function(b){var f=a(b),j=a.data(b,"datepicker");if(f.hasClass(this.markerClassName)){var l= -b.nodeName.toLowerCase();if(l=="input"){b.disabled=false;j.trigger.filter("button").each(function(){this.disabled=false}).end().filter("img").css({opacity:"1.0",cursor:""})}else if(l=="div"||l=="span"){f=f.children("."+this._inlineClass);f.children().removeClass("ui-state-disabled");f.find("select.ui-datepicker-month, select.ui-datepicker-year").removeAttr("disabled")}this._disabledInputs=a.map(this._disabledInputs,function(o){return o==b?null:o})}},_disableDatepicker:function(b){var f=a(b),j=a.data(b, -"datepicker");if(f.hasClass(this.markerClassName)){var l=b.nodeName.toLowerCase();if(l=="input"){b.disabled=true;j.trigger.filter("button").each(function(){this.disabled=true}).end().filter("img").css({opacity:"0.5",cursor:"default"})}else if(l=="div"||l=="span"){f=f.children("."+this._inlineClass);f.children().addClass("ui-state-disabled");f.find("select.ui-datepicker-month, select.ui-datepicker-year").attr("disabled","disabled")}this._disabledInputs=a.map(this._disabledInputs,function(o){return o== -b?null:o});this._disabledInputs[this._disabledInputs.length]=b}},_isDisabledDatepicker:function(b){if(!b)return false;for(var f=0;f-1}},_doKeyUp:function(b){b=a.datepicker._getInst(b.target);if(b.input.val()!=b.lastVal)try{if(a.datepicker.parseDate(a.datepicker._get(b,"dateFormat"),b.input?b.input.val():null,a.datepicker._getFormatConfig(b))){a.datepicker._setDateFromField(b);a.datepicker._updateAlternate(b);a.datepicker._updateDatepicker(b)}}catch(f){a.datepicker.log(f)}return true},_showDatepicker:function(b){b=b.target||b;if(b.nodeName.toLowerCase()!="input")b=a("input", -b.parentNode)[0];if(!(a.datepicker._isDisabledDatepicker(b)||a.datepicker._lastInput==b)){var f=a.datepicker._getInst(b);if(a.datepicker._curInst&&a.datepicker._curInst!=f){a.datepicker._datepickerShowing&&a.datepicker._triggerOnClose(a.datepicker._curInst);a.datepicker._curInst.dpDiv.stop(true,true)}var j=a.datepicker._get(f,"beforeShow");j=j?j.apply(b,[b,f]):{};if(j!==false){h(f.settings,j);f.lastVal=null;a.datepicker._lastInput=b;a.datepicker._setDateFromField(f);if(a.datepicker._inDialog)b.value= -"";if(!a.datepicker._pos){a.datepicker._pos=a.datepicker._findPos(b);a.datepicker._pos[1]+=b.offsetHeight}var l=false;a(b).parents().each(function(){l|=a(this).css("position")=="fixed";return!l});if(l&&a.browser.opera){a.datepicker._pos[0]-=document.documentElement.scrollLeft;a.datepicker._pos[1]-=document.documentElement.scrollTop}j={left:a.datepicker._pos[0],top:a.datepicker._pos[1]};a.datepicker._pos=null;f.dpDiv.empty();f.dpDiv.css({position:"absolute",display:"block",top:"-1000px"});a.datepicker._updateDatepicker(f); -j=a.datepicker._checkOffset(f,j,l);f.dpDiv.css({position:a.datepicker._inDialog&&a.blockUI?"static":l?"fixed":"absolute",display:"none",left:j.left+"px",top:j.top+"px"});if(!f.inline){j=a.datepicker._get(f,"showAnim");var o=a.datepicker._get(f,"duration"),n=function(){var k=f.dpDiv.find("iframe.ui-datepicker-cover");if(k.length){var m=a.datepicker._getBorders(f.dpDiv);k.css({left:-m[0],top:-m[1],width:f.dpDiv.outerWidth(),height:f.dpDiv.outerHeight()})}};f.dpDiv.zIndex(a(b).zIndex()+1);a.datepicker._datepickerShowing= -true;a.effects&&a.effects[j]?f.dpDiv.show(j,a.datepicker._get(f,"showOptions"),o,n):f.dpDiv[j||"show"](j?o:null,n);if(!j||!o)n();f.input.is(":visible")&&!f.input.is(":disabled")&&f.input.focus();a.datepicker._curInst=f}}}},_updateDatepicker:function(b){this.maxRows=4;var f=a.datepicker._getBorders(b.dpDiv);i=b;b.dpDiv.empty().append(this._generateHTML(b));var j=b.dpDiv.find("iframe.ui-datepicker-cover");j.length&&j.css({left:-f[0],top:-f[1],width:b.dpDiv.outerWidth(),height:b.dpDiv.outerHeight()}); -b.dpDiv.find("."+this._dayOverClass+" a").mouseover();f=this._getNumberOfMonths(b);j=f[1];b.dpDiv.removeClass("ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4").width("");j>1&&b.dpDiv.addClass("ui-datepicker-multi-"+j).css("width",17*j+"em");b.dpDiv[(f[0]!=1||f[1]!=1?"add":"remove")+"Class"]("ui-datepicker-multi");b.dpDiv[(this._get(b,"isRTL")?"add":"remove")+"Class"]("ui-datepicker-rtl");b==a.datepicker._curInst&&a.datepicker._datepickerShowing&&b.input&&b.input.is(":visible")&& -!b.input.is(":disabled")&&b.input[0]!=document.activeElement&&b.input.focus();if(b.yearshtml){var l=b.yearshtml;setTimeout(function(){l===b.yearshtml&&b.yearshtml&&b.dpDiv.find("select.ui-datepicker-year:first").replaceWith(b.yearshtml);l=b.yearshtml=null},0)}},_getBorders:function(b){var f=function(j){return{thin:1,medium:2,thick:3}[j]||j};return[parseFloat(f(b.css("border-left-width"))),parseFloat(f(b.css("border-top-width")))]},_checkOffset:function(b,f,j){var l=b.dpDiv.outerWidth(),o=b.dpDiv.outerHeight(), -n=b.input?b.input.outerWidth():0,k=b.input?b.input.outerHeight():0,m=document.documentElement.clientWidth+a(document).scrollLeft(),p=document.documentElement.clientHeight+a(document).scrollTop();f.left-=this._get(b,"isRTL")?l-n:0;f.left-=j&&f.left==b.input.offset().left?a(document).scrollLeft():0;f.top-=j&&f.top==b.input.offset().top+k?a(document).scrollTop():0;f.left-=Math.min(f.left,f.left+l>m&&m>l?Math.abs(f.left+l-m):0);f.top-=Math.min(f.top,f.top+o>p&&p>o?Math.abs(o+k):0);return f},_findPos:function(b){for(var f= -this._get(this._getInst(b),"isRTL");b&&(b.type=="hidden"||b.nodeType!=1||a.expr.filters.hidden(b));)b=b[f?"previousSibling":"nextSibling"];b=a(b).offset();return[b.left,b.top]},_triggerOnClose:function(b){var f=this._get(b,"onClose");if(f)f.apply(b.input?b.input[0]:null,[b.input?b.input.val():"",b])},_hideDatepicker:function(b){var f=this._curInst;if(!(!f||b&&f!=a.data(b,"datepicker")))if(this._datepickerShowing){b=this._get(f,"showAnim");var j=this._get(f,"duration"),l=function(){a.datepicker._tidyDialog(f); -this._curInst=null};a.effects&&a.effects[b]?f.dpDiv.hide(b,a.datepicker._get(f,"showOptions"),j,l):f.dpDiv[b=="slideDown"?"slideUp":b=="fadeIn"?"fadeOut":"hide"](b?j:null,l);b||l();a.datepicker._triggerOnClose(f);this._datepickerShowing=false;this._lastInput=null;if(this._inDialog){this._dialogInput.css({position:"absolute",left:"0",top:"-100px"});if(a.blockUI){a.unblockUI();a("body").append(this.dpDiv)}}this._inDialog=false}},_tidyDialog:function(b){b.dpDiv.removeClass(this._dialogClass).unbind(".ui-datepicker-calendar")}, -_checkExternalClick:function(b){if(a.datepicker._curInst){b=a(b.target);b[0].id!=a.datepicker._mainDivId&&b.parents("#"+a.datepicker._mainDivId).length==0&&!b.hasClass(a.datepicker.markerClassName)&&!b.hasClass(a.datepicker._triggerClass)&&a.datepicker._datepickerShowing&&!(a.datepicker._inDialog&&a.blockUI)&&a.datepicker._hideDatepicker()}},_adjustDate:function(b,f,j){b=a(b);var l=this._getInst(b[0]);if(!this._isDisabledDatepicker(b[0])){this._adjustInstDate(l,f+(j=="M"?this._get(l,"showCurrentAtPos"): -0),j);this._updateDatepicker(l)}},_gotoToday:function(b){b=a(b);var f=this._getInst(b[0]);if(this._get(f,"gotoCurrent")&&f.currentDay){f.selectedDay=f.currentDay;f.drawMonth=f.selectedMonth=f.currentMonth;f.drawYear=f.selectedYear=f.currentYear}else{var j=new Date;f.selectedDay=j.getDate();f.drawMonth=f.selectedMonth=j.getMonth();f.drawYear=f.selectedYear=j.getFullYear()}this._notifyChange(f);this._adjustDate(b)},_selectMonthYear:function(b,f,j){b=a(b);var l=this._getInst(b[0]);l["selected"+(j=="M"? -"Month":"Year")]=l["draw"+(j=="M"?"Month":"Year")]=parseInt(f.options[f.selectedIndex].value,10);this._notifyChange(l);this._adjustDate(b)},_selectDay:function(b,f,j,l){var o=a(b);if(!(a(l).hasClass(this._unselectableClass)||this._isDisabledDatepicker(o[0]))){o=this._getInst(o[0]);o.selectedDay=o.currentDay=a("a",l).html();o.selectedMonth=o.currentMonth=f;o.selectedYear=o.currentYear=j;this._selectDate(b,this._formatDate(o,o.currentDay,o.currentMonth,o.currentYear))}},_clearDate:function(b){b=a(b); -this._getInst(b[0]);this._selectDate(b,"")},_selectDate:function(b,f){b=this._getInst(a(b)[0]);f=f!=null?f:this._formatDate(b);b.input&&b.input.val(f);this._updateAlternate(b);var j=this._get(b,"onSelect");if(j)j.apply(b.input?b.input[0]:null,[f,b]);else b.input&&b.input.trigger("change");if(b.inline)this._updateDatepicker(b);else{this._hideDatepicker();this._lastInput=b.input[0];typeof b.input[0]!="object"&&b.input.focus();this._lastInput=null}},_updateAlternate:function(b){var f=this._get(b,"altField"); -if(f){var j=this._get(b,"altFormat")||this._get(b,"dateFormat"),l=this._getDate(b),o=this.formatDate(j,l,this._getFormatConfig(b));a(f).each(function(){a(this).val(o)})}},noWeekends:function(b){b=b.getDay();return[b>0&&b<6,""]},iso8601Week:function(b){b=new Date(b.getTime());b.setDate(b.getDate()+4-(b.getDay()||7));var f=b.getTime();b.setMonth(0);b.setDate(1);return Math.floor(Math.round((f-b)/864E5)/7)+1},parseDate:function(b,f,j){if(b==null||f==null)throw"Invalid arguments";f=typeof f=="object"? -f.toString():f+"";if(f=="")return null;var l=(j?j.shortYearCutoff:null)||this._defaults.shortYearCutoff;l=typeof l!="string"?l:(new Date).getFullYear()%100+parseInt(l,10);for(var o=(j?j.dayNamesShort:null)||this._defaults.dayNamesShort,n=(j?j.dayNames:null)||this._defaults.dayNames,k=(j?j.monthNamesShort:null)||this._defaults.monthNamesShort,m=(j?j.monthNames:null)||this._defaults.monthNames,p=j=-1,q=-1,s=-1,r=false,u=function(z){(z=H+1-1){p=1;q=s;do{l=this._getDaysInMonth(j,p-1);if(q<=l)break;p++;q-=l}while(1)}C=this._daylightSavingAdjust(new Date(j,p-1,q));if(C.getFullYear()!=j||C.getMonth()+1!=p||C.getDate()!=q)throw"Invalid date";return C},ATOM:"yy-mm-dd", -COOKIE:"D, dd M yy",ISO_8601:"yy-mm-dd",RFC_822:"D, d M y",RFC_850:"DD, dd-M-y",RFC_1036:"D, d M y",RFC_1123:"D, d M yy",RFC_2822:"D, d M yy",RSS:"D, d M y",TICKS:"!",TIMESTAMP:"@",W3C:"yy-mm-dd",_ticksTo1970:(718685+Math.floor(492.5)-Math.floor(19.7)+Math.floor(4.925))*24*60*60*1E7,formatDate:function(b,f,j){if(!f)return"";var l=(j?j.dayNamesShort:null)||this._defaults.dayNamesShort,o=(j?j.dayNames:null)||this._defaults.dayNames,n=(j?j.monthNamesShort:null)||this._defaults.monthNamesShort;j=(j?j.monthNames: -null)||this._defaults.monthNames;var k=function(u){(u=r+1 -12?b.getHours()+2:0);return b},_setDate:function(b,f,j){var l=!f,o=b.selectedMonth,n=b.selectedYear;f=this._restrictMinMax(b,this._determineDate(b,f,new Date));b.selectedDay=b.currentDay=f.getDate();b.drawMonth=b.selectedMonth=b.currentMonth=f.getMonth();b.drawYear=b.selectedYear=b.currentYear=f.getFullYear();if((o!=b.selectedMonth||n!=b.selectedYear)&&!j)this._notifyChange(b);this._adjustInstDate(b);if(b.input)b.input.val(l?"":this._formatDate(b))},_getDate:function(b){return!b.currentYear||b.input&& -b.input.val()==""?null:this._daylightSavingAdjust(new Date(b.currentYear,b.currentMonth,b.currentDay))},_generateHTML:function(b){var f=new Date;f=this._daylightSavingAdjust(new Date(f.getFullYear(),f.getMonth(),f.getDate()));var j=this._get(b,"isRTL"),l=this._get(b,"showButtonPanel"),o=this._get(b,"hideIfNoPrevNext"),n=this._get(b,"navigationAsDateFormat"),k=this._getNumberOfMonths(b),m=this._get(b,"showCurrentAtPos"),p=this._get(b,"stepMonths"),q=k[0]!=1||k[1]!=1,s=this._daylightSavingAdjust(!b.currentDay? -new Date(9999,9,9):new Date(b.currentYear,b.currentMonth,b.currentDay)),r=this._getMinMaxDate(b,"min"),u=this._getMinMaxDate(b,"max");m=b.drawMonth-m;var v=b.drawYear;if(m<0){m+=12;v--}if(u){var w=this._daylightSavingAdjust(new Date(u.getFullYear(),u.getMonth()-k[0]*k[1]+1,u.getDate()));for(w=r&&ww;){m--;if(m<0){m=11;v--}}}b.drawMonth=m;b.drawYear=v;w=this._get(b,"prevText");w=!n?w:this.formatDate(w,this._daylightSavingAdjust(new Date(v,m-p,1)),this._getFormatConfig(b)); -w=this._canAdjustMonth(b,-1,v,m)?''+w+"":o?"":''+w+"";var x=this._get(b,"nextText");x=!n?x:this.formatDate(x,this._daylightSavingAdjust(new Date(v, -m+p,1)),this._getFormatConfig(b));o=this._canAdjustMonth(b,+1,v,m)?''+x+"":o?"":''+x+"";p=this._get(b,"currentText");x=this._get(b,"gotoCurrent")&& -b.currentDay?s:f;p=!n?p:this.formatDate(p,x,this._getFormatConfig(b));n=!b.inline?'":"";l=l?'
        '+(j?n:"")+(this._isInRange(b,x)?'":"")+(j?"":n)+"
        ":"";n=parseInt(this._get(b,"firstDay"),10);n=isNaN(n)?0:n;p=this._get(b,"showWeek");x=this._get(b,"dayNames");this._get(b,"dayNamesShort");var y=this._get(b,"dayNamesMin"),H=this._get(b,"monthNames"),C=this._get(b,"monthNamesShort"),z=this._get(b,"beforeShowDay"),I=this._get(b,"showOtherMonths"),N=this._get(b,"selectOtherMonths");this._get(b,"calculateWeek");for(var J=this._getDefaultDate(b),D="",E=0;E1)switch(L){case 0:F+=" ui-datepicker-group-first";B=" ui-corner-"+(j?"right":"left");break;case k[1]-1:F+=" ui-datepicker-group-last";B=" ui-corner-"+(j?"left":"right");break;default:F+=" ui-datepicker-group-middle";B="";break}F+='">'}F+='
        '+(/all|left/.test(B)&& -E==0?j?o:w:"")+(/all|right/.test(B)&&E==0?j?w:o:"")+this._generateMonthYearHeader(b,m,v,r,u,E>0||L>0,H,C)+'
        ';var G=p?'":"";for(B=0;B<7;B++){var A=(B+n)%7;G+="=5?' class="ui-datepicker-week-end"':"")+'>'+y[A]+""}F+=G+"";G=this._getDaysInMonth(v,m);if(v==b.selectedYear&&m==b.selectedMonth)b.selectedDay=Math.min(b.selectedDay, -G);B=(this._getFirstDayOfMonth(v,m)-n+7)%7;G=Math.ceil((B+G)/7);this.maxRows=G=q?this.maxRows>G?this.maxRows:G:G;A=this._daylightSavingAdjust(new Date(v,m,1-B));for(var R=0;R";var S=!p?"":'";for(B=0;B<7;B++){var M=z?z.apply(b.input?b.input[0]:null,[A]):[true,""],K=A.getMonth()!=m,O=K&&!N||!M[0]||r&&Au;S+='";A.setDate(A.getDate()+1);A=this._daylightSavingAdjust(A)}F+=S+""}m++;if(m>11){m=0;v++}F+="
        '+this._get(b,"weekHeader")+"
        '+this._get(b,"calculateWeek")(A)+""+(K&&!I?" ":O?''+ -A.getDate()+"":''+A.getDate()+"")+"
        "+(q?"
      "+(k[0]>0&&L==k[1]-1?'
      ':""):"");P+=F}D+=P}D+=l+(a.browser.msie&&parseInt(a.browser.version,10)<7&&!b.inline?'': -"");b._keyEvent=false;return D},_generateMonthYearHeader:function(b,f,j,l,o,n,k,m){var p=this._get(b,"changeMonth"),q=this._get(b,"changeYear"),s=this._get(b,"showMonthAfterYear"),r='
      ',u="";if(n||!p)u+=''+k[f]+"";else{k=l&&l.getFullYear()==j;var v=o&&o.getFullYear()==j;u+='"}s||(r+=u+(n||!(p&&q)?" ":""));if(!b.yearshtml){b.yearshtml="";if(n||!q)r+=''+j+"";else{m=this._get(b,"yearRange").split(":");var x=(new Date).getFullYear();k=function(y){y=y.match(/c[+-].*/)?j+parseInt(y.substring(1),10):y.match(/[+-].*/)?x+parseInt(y,10):parseInt(y,10);return isNaN(y)?x:y};f=k(m[0]);m=Math.max(f,k(m[1]||""));f=l?Math.max(f, -l.getFullYear()):f;m=o?Math.min(m,o.getFullYear()):m;for(b.yearshtml+='";r+=b.yearshtml;b.yearshtml=null}}r+=this._get(b,"yearSuffix");if(s)r+=(n||!(p&&q)?" ":"")+u;r+="
      ";return r},_adjustInstDate:function(b,f,j){var l=b.drawYear+(j=="Y"?f:0),o=b.drawMonth+ -(j=="M"?f:0);f=Math.min(b.selectedDay,this._getDaysInMonth(l,o))+(j=="D"?f:0);l=this._restrictMinMax(b,this._daylightSavingAdjust(new Date(l,o,f)));b.selectedDay=l.getDate();b.drawMonth=b.selectedMonth=l.getMonth();b.drawYear=b.selectedYear=l.getFullYear();if(j=="M"||j=="Y")this._notifyChange(b)},_restrictMinMax:function(b,f){var j=this._getMinMaxDate(b,"min");b=this._getMinMaxDate(b,"max");f=j&&fb?b:f},_notifyChange:function(b){var f=this._get(b,"onChangeMonthYear");if(f)f.apply(b.input? -b.input[0]:null,[b.selectedYear,b.selectedMonth+1,b])},_getNumberOfMonths:function(b){b=this._get(b,"numberOfMonths");return b==null?[1,1]:typeof b=="number"?[1,b]:b},_getMinMaxDate:function(b,f){return this._determineDate(b,this._get(b,f+"Date"),null)},_getDaysInMonth:function(b,f){return 32-this._daylightSavingAdjust(new Date(b,f,32)).getDate()},_getFirstDayOfMonth:function(b,f){return(new Date(b,f,1)).getDay()},_canAdjustMonth:function(b,f,j,l){var o=this._getNumberOfMonths(b);j=this._daylightSavingAdjust(new Date(j, -l+(f<0?f:o[0]*o[1]),1));f<0&&j.setDate(this._getDaysInMonth(j.getFullYear(),j.getMonth()));return this._isInRange(b,j)},_isInRange:function(b,f){var j=this._getMinMaxDate(b,"min");b=this._getMinMaxDate(b,"max");return(!j||f.getTime()>=j.getTime())&&(!b||f.getTime()<=b.getTime())},_getFormatConfig:function(b){var f=this._get(b,"shortYearCutoff");f=typeof f!="string"?f:(new Date).getFullYear()%100+parseInt(f,10);return{shortYearCutoff:f,dayNamesShort:this._get(b,"dayNamesShort"),dayNames:this._get(b, -"dayNames"),monthNamesShort:this._get(b,"monthNamesShort"),monthNames:this._get(b,"monthNames")}},_formatDate:function(b,f,j,l){if(!f){b.currentDay=b.selectedDay;b.currentMonth=b.selectedMonth;b.currentYear=b.selectedYear}f=f?typeof f=="object"?f:this._daylightSavingAdjust(new Date(l,j,f)):this._daylightSavingAdjust(new Date(b.currentYear,b.currentMonth,b.currentDay));return this.formatDate(this._get(b,"dateFormat"),f,this._getFormatConfig(b))}});a.fn.datepicker=function(b){if(!this.length)return this; -if(!a.datepicker.initialized){a(document).mousedown(a.datepicker._checkExternalClick).find("body").append(a.datepicker.dpDiv);a.datepicker.initialized=true}var f=Array.prototype.slice.call(arguments,1);if(typeof b=="string"&&(b=="isDisabled"||b=="getDate"||b=="widget"))return a.datepicker["_"+b+"Datepicker"].apply(a.datepicker,[this[0]].concat(f));if(b=="option"&&arguments.length==2&&typeof arguments[1]=="string")return a.datepicker["_"+b+"Datepicker"].apply(a.datepicker,[this[0]].concat(f));return this.each(function(){typeof b== -"string"?a.datepicker["_"+b+"Datepicker"].apply(a.datepicker,[this].concat(f)):a.datepicker._attachDatepicker(this,b)})};a.datepicker=new c;a.datepicker.initialized=false;a.datepicker.uuid=(new Date).getTime();a.datepicker.version="1.8.16";window["DP_jQuery_"+g]=a})(jQuery); -(function(a,d){var c={buttons:true,height:true,maxHeight:true,maxWidth:true,minHeight:true,minWidth:true,width:true},e={maxHeight:true,maxWidth:true,minHeight:true,minWidth:true},h=a.attrFn||{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true,click:true};a.widget("ui.dialog",{options:{autoOpen:true,buttons:{},closeOnEscape:true,closeText:"close",dialogClass:"",draggable:true,hide:null,height:"auto",maxHeight:false,maxWidth:false,minHeight:150,minWidth:150,modal:false, -position:{my:"center",at:"center",collision:"fit",using:function(g){var i=a(this).css(g).offset().top;i<0&&a(this).css("top",g.top-i)}},resizable:true,show:null,stack:true,title:"",width:300,zIndex:1E3},_create:function(){this.originalTitle=this.element.attr("title");if(typeof this.originalTitle!=="string")this.originalTitle="";this.options.title=this.options.title||this.originalTitle;var g=this,i=g.options,b=i.title||" ",f=a.ui.dialog.getTitleId(g.element),j=(g.uiDialog=a("
      ")).appendTo(document.body).hide().addClass("ui-dialog ui-widget ui-widget-content ui-corner-all "+ -i.dialogClass).css({zIndex:i.zIndex}).attr("tabIndex",-1).css("outline",0).keydown(function(n){if(i.closeOnEscape&&!n.isDefaultPrevented()&&n.keyCode&&n.keyCode===a.ui.keyCode.ESCAPE){g.close(n);n.preventDefault()}}).attr({role:"dialog","aria-labelledby":f}).mousedown(function(n){g.moveToTop(false,n)});g.element.show().removeAttr("title").addClass("ui-dialog-content ui-widget-content").appendTo(j);var l=(g.uiDialogTitlebar=a("
      ")).addClass("ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix").prependTo(j), -o=a('').addClass("ui-dialog-titlebar-close ui-corner-all").attr("role","button").hover(function(){o.addClass("ui-state-hover")},function(){o.removeClass("ui-state-hover")}).focus(function(){o.addClass("ui-state-focus")}).blur(function(){o.removeClass("ui-state-focus")}).click(function(n){g.close(n);return false}).appendTo(l);(g.uiDialogTitlebarCloseText=a("")).addClass("ui-icon ui-icon-closethick").text(i.closeText).appendTo(o);a("").addClass("ui-dialog-title").attr("id", -f).html(b).prependTo(l);if(a.isFunction(i.beforeclose)&&!a.isFunction(i.beforeClose))i.beforeClose=i.beforeclose;l.find("*").add(l).disableSelection();i.draggable&&a.fn.draggable&&g._makeDraggable();i.resizable&&a.fn.resizable&&g._makeResizable();g._createButtons(i.buttons);g._isOpen=false;a.fn.bgiframe&&j.bgiframe()},_init:function(){this.options.autoOpen&&this.open()},destroy:function(){var g=this;g.overlay&&g.overlay.destroy();g.uiDialog.hide();g.element.unbind(".dialog").removeData("dialog").removeClass("ui-dialog-content ui-widget-content").hide().appendTo("body"); -g.uiDialog.remove();g.originalTitle&&g.element.attr("title",g.originalTitle);return g},widget:function(){return this.uiDialog},close:function(g){var i=this,b,f;if(false!==i._trigger("beforeClose",g)){i.overlay&&i.overlay.destroy();i.uiDialog.unbind("keypress.ui-dialog");i._isOpen=false;if(i.options.hide)i.uiDialog.hide(i.options.hide,function(){i._trigger("close",g)});else{i.uiDialog.hide();i._trigger("close",g)}a.ui.dialog.overlay.resize();if(i.options.modal){b=0;a(".ui-dialog").each(function(){if(this!== -i.uiDialog[0]){f=a(this).css("z-index");isNaN(f)||(b=Math.max(b,f))}});a.ui.dialog.maxZ=b}return i}},isOpen:function(){return this._isOpen},moveToTop:function(g,i){var b=this,f=b.options;if(f.modal&&!g||!f.stack&&!f.modal)return b._trigger("focus",i);if(f.zIndex>a.ui.dialog.maxZ)a.ui.dialog.maxZ=f.zIndex;if(b.overlay){a.ui.dialog.maxZ+=1;b.overlay.$el.css("z-index",a.ui.dialog.overlay.maxZ=a.ui.dialog.maxZ)}g={scrollTop:b.element.scrollTop(),scrollLeft:b.element.scrollLeft()};a.ui.dialog.maxZ+=1; -b.uiDialog.css("z-index",a.ui.dialog.maxZ);b.element.attr(g);b._trigger("focus",i);return b},open:function(){if(!this._isOpen){var g=this,i=g.options,b=g.uiDialog;g.overlay=i.modal?new a.ui.dialog.overlay(g):null;g._size();g._position(i.position);b.show(i.show);g.moveToTop(true);i.modal&&b.bind("keypress.ui-dialog",function(f){if(f.keyCode===a.ui.keyCode.TAB){var j=a(":tabbable",this),l=j.filter(":first");j=j.filter(":last");if(f.target===j[0]&&!f.shiftKey){l.focus(1);return false}else if(f.target=== -l[0]&&f.shiftKey){j.focus(1);return false}}});a(g.element.find(":tabbable").get().concat(b.find(".ui-dialog-buttonpane :tabbable").get().concat(b.get()))).eq(0).focus();g._isOpen=true;g._trigger("open");return g}},_createButtons:function(g){var i=this,b=false,f=a("
      ").addClass("ui-dialog-buttonpane ui-widget-content ui-helper-clearfix"),j=a("
      ").addClass("ui-dialog-buttonset").appendTo(f);i.uiDialog.find(".ui-dialog-buttonpane").remove();typeof g==="object"&&g!==null&&a.each(g, -function(){return!(b=true)});if(b){a.each(g,function(l,o){o=a.isFunction(o)?{click:o,text:l}:o;var n=a('').click(function(){o.click.apply(i.element[0],arguments)}).appendTo(j);a.each(o,function(k,m){if(k!=="click")k in h?n[k](m):n.attr(k,m)});a.fn.button&&n.button()});f.appendTo(i.uiDialog)}},_makeDraggable:function(){function g(l){return{position:l.position,offset:l.offset}}var i=this,b=i.options,f=a(document),j;i.uiDialog.draggable({cancel:".ui-dialog-content, .ui-dialog-titlebar-close", -handle:".ui-dialog-titlebar",containment:"document",start:function(l,o){j=b.height==="auto"?"auto":a(this).height();a(this).height(a(this).height()).addClass("ui-dialog-dragging");i._trigger("dragStart",l,g(o))},drag:function(l,o){i._trigger("drag",l,g(o))},stop:function(l,o){b.position=[o.position.left-f.scrollLeft(),o.position.top-f.scrollTop()];a(this).removeClass("ui-dialog-dragging").height(j);i._trigger("dragStop",l,g(o));a.ui.dialog.overlay.resize()}})},_makeResizable:function(g){function i(l){return{originalPosition:l.originalPosition, -originalSize:l.originalSize,position:l.position,size:l.size}}g=g===d?this.options.resizable:g;var b=this,f=b.options,j=b.uiDialog.css("position");g=typeof g==="string"?g:"n,e,s,w,se,sw,ne,nw";b.uiDialog.resizable({cancel:".ui-dialog-content",containment:"document",alsoResize:b.element,maxWidth:f.maxWidth,maxHeight:f.maxHeight,minWidth:f.minWidth,minHeight:b._minHeight(),handles:g,start:function(l,o){a(this).addClass("ui-dialog-resizing");b._trigger("resizeStart",l,i(o))},resize:function(l,o){b._trigger("resize", -l,i(o))},stop:function(l,o){a(this).removeClass("ui-dialog-resizing");f.height=a(this).height();f.width=a(this).width();b._trigger("resizeStop",l,i(o));a.ui.dialog.overlay.resize()}}).css("position",j).find(".ui-resizable-se").addClass("ui-icon ui-icon-grip-diagonal-se")},_minHeight:function(){var g=this.options;return g.height==="auto"?g.minHeight:Math.min(g.minHeight,g.height)},_position:function(g){var i=[],b=[0,0],f;if(g){if(typeof g==="string"||typeof g==="object"&&"0"in g){i=g.split?g.split(" "): -[g[0],g[1]];if(i.length===1)i[1]=i[0];a.each(["left","top"],function(j,l){if(+i[j]===i[j]){b[j]=i[j];i[j]=l}});g={my:i.join(" "),at:i.join(" "),offset:b.join(" ")}}g=a.extend({},a.ui.dialog.prototype.options.position,g)}else g=a.ui.dialog.prototype.options.position;(f=this.uiDialog.is(":visible"))||this.uiDialog.show();this.uiDialog.css({top:0,left:0}).position(a.extend({of:window},g));f||this.uiDialog.hide()},_setOptions:function(g){var i=this,b={},f=false;a.each(g,function(j,l){i._setOption(j,l); -if(j in c)f=true;if(j in e)b[j]=l});f&&this._size();this.uiDialog.is(":data(resizable)")&&this.uiDialog.resizable("option",b)},_setOption:function(g,i){var b=this,f=b.uiDialog;switch(g){case "beforeclose":g="beforeClose";break;case "buttons":b._createButtons(i);break;case "closeText":b.uiDialogTitlebarCloseText.text(""+i);break;case "dialogClass":f.removeClass(b.options.dialogClass).addClass("ui-dialog ui-widget ui-widget-content ui-corner-all "+i);break;case "disabled":i?f.addClass("ui-dialog-disabled"): -f.removeClass("ui-dialog-disabled");break;case "draggable":var j=f.is(":data(draggable)");j&&!i&&f.draggable("destroy");!j&&i&&b._makeDraggable();break;case "position":b._position(i);break;case "resizable":(j=f.is(":data(resizable)"))&&!i&&f.resizable("destroy");j&&typeof i==="string"&&f.resizable("option","handles",i);!j&&i!==false&&b._makeResizable(i);break;case "title":a(".ui-dialog-title",b.uiDialogTitlebar).html(""+(i||" "));break}a.Widget.prototype._setOption.apply(b,arguments)},_size:function(){var g= -this.options,i,b,f=this.uiDialog.is(":visible");this.element.show().css({width:"auto",minHeight:0,height:0});if(g.minWidth>g.width)g.width=g.minWidth;i=this.uiDialog.css({height:"auto",width:g.width}).height();b=Math.max(0,g.minHeight-i);if(g.height==="auto")if(a.support.minHeight)this.element.css({minHeight:b,height:"auto"});else{this.uiDialog.show();g=this.element.css("height","auto").height();f||this.uiDialog.hide();this.element.height(Math.max(g,b))}else this.element.height(Math.max(g.height- -i,0));this.uiDialog.is(":data(resizable)")&&this.uiDialog.resizable("option","minHeight",this._minHeight())}});a.extend(a.ui.dialog,{version:"1.8.16",uuid:0,maxZ:0,getTitleId:function(g){g=g.attr("id");if(!g){this.uuid+=1;g=this.uuid}return"ui-dialog-title-"+g},overlay:function(g){this.$el=a.ui.dialog.overlay.create(g)}});a.extend(a.ui.dialog.overlay,{instances:[],oldInstances:[],maxZ:0,events:a.map("focus,mousedown,mouseup,keydown,keypress,click".split(","),function(g){return g+".dialog-overlay"}).join(" "), -create:function(g){if(this.instances.length===0){setTimeout(function(){a.ui.dialog.overlay.instances.length&&a(document).bind(a.ui.dialog.overlay.events,function(b){if(a(b.target).zIndex()").addClass("ui-widget-overlay")).appendTo(document.body).css({width:this.width(),height:this.height()});a.fn.bgiframe&&i.bgiframe();this.instances.push(i);return i},destroy:function(g){var i=a.inArray(g,this.instances);i!=-1&&this.oldInstances.push(this.instances.splice(i,1)[0]);this.instances.length===0&&a([document,window]).unbind(".dialog-overlay");g.remove();var b=0;a.each(this.instances,function(){b=Math.max(b,this.css("z-index"))});this.maxZ=b},height:function(){var g,i;if(a.browser.msie&& -a.browser.version<7){g=Math.max(document.documentElement.scrollHeight,document.body.scrollHeight);i=Math.max(document.documentElement.offsetHeight,document.body.offsetHeight);return g0?g.left-b:Math.max(g.left-i.collisionPosition.left,g.left)},top:function(g,i){var b=a(window);b=i.collisionPosition.top+i.collisionHeight-b.height()-b.scrollTop();g.top=b>0?g.top-b:Math.max(g.top-i.collisionPosition.top,g.top)}},flip:{left:function(g,i){if(i.at[0]!=="center"){var b=a(window);b=i.collisionPosition.left+i.collisionWidth-b.width()-b.scrollLeft();var f=i.my[0]==="left"?-i.elemWidth:i.my[0]==="right"?i.elemWidth:0,j=i.at[0]==="left"?i.targetWidth:-i.targetWidth,l=-2*i.offset[0];g.left+= -i.collisionPosition.left<0?f+j+l:b>0?f+j+l:0}},top:function(g,i){if(i.at[1]!=="center"){var b=a(window);b=i.collisionPosition.top+i.collisionHeight-b.height()-b.scrollTop();var f=i.my[1]==="top"?-i.elemHeight:i.my[1]==="bottom"?i.elemHeight:0,j=i.at[1]==="top"?i.targetHeight:-i.targetHeight,l=-2*i.offset[1];g.top+=i.collisionPosition.top<0?f+j+l:b>0?f+j+l:0}}}};if(!a.offset.setOffset){a.offset.setOffset=function(g,i){if(/static/.test(a.curCSS(g,"position")))g.style.position="relative";var b=a(g), -f=b.offset(),j=parseInt(a.curCSS(g,"top",true),10)||0,l=parseInt(a.curCSS(g,"left",true),10)||0;f={top:i.top-f.top+j,left:i.left-f.left+l};"using"in i?i.using.call(g,f):b.css(f)};a.fn.offset=function(g){var i=this[0];if(!i||!i.ownerDocument)return null;if(g)return this.each(function(){a.offset.setOffset(this,g)});return h.call(this)}}})(jQuery); -(function(a,d){a.widget("ui.progressbar",{options:{value:0,max:100},min:0,_create:function(){this.element.addClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").attr({role:"progressbar","aria-valuemin":this.min,"aria-valuemax":this.options.max,"aria-valuenow":this._value()});this.valueDiv=a("
      ").appendTo(this.element);this.oldValue=this._value();this._refreshValue()},destroy:function(){this.element.removeClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").removeAttr("role").removeAttr("aria-valuemin").removeAttr("aria-valuemax").removeAttr("aria-valuenow"); -this.valueDiv.remove();a.Widget.prototype.destroy.apply(this,arguments)},value:function(c){if(c===d)return this._value();this._setOption("value",c);return this},_setOption:function(c,e){if(c==="value"){this.options.value=e;this._refreshValue();this._value()===this.options.max&&this._trigger("complete")}a.Widget.prototype._setOption.apply(this,arguments)},_value:function(){var c=this.options.value;if(typeof c!=="number")c=0;return Math.min(this.options.max,Math.max(this.min,c))},_percentage:function(){return 100* -this._value()/this.options.max},_refreshValue:function(){var c=this.value(),e=this._percentage();if(this.oldValue!==c){this.oldValue=c;this._trigger("change")}this.valueDiv.toggle(c>this.min).toggleClass("ui-corner-right",c===this.options.max).width(e.toFixed(0)+"%");this.element.attr("aria-valuenow",c)}});a.extend(a.ui.progressbar,{version:"1.8.16"})})(jQuery); -(function(a){a.widget("ui.slider",a.ui.mouse,{widgetEventPrefix:"slide",options:{animate:false,distance:0,max:100,min:0,orientation:"horizontal",range:false,step:1,value:0,values:null},_create:function(){var d=this,c=this.options,e=this.element.find(".ui-slider-handle").addClass("ui-state-default ui-corner-all"),h=c.values&&c.values.length||1,g=[];this._mouseSliding=this._keySliding=false;this._animateOff=true;this._handleIndex=null;this._detectOrientation();this._mouseInit();this.element.addClass("ui-slider ui-slider-"+ -this.orientation+" ui-widget ui-widget-content ui-corner-all"+(c.disabled?" ui-slider-disabled ui-disabled":""));this.range=a([]);if(c.range){if(c.range===true){if(!c.values)c.values=[this._valueMin(),this._valueMin()];if(c.values.length&&c.values.length!==2)c.values=[c.values[0],c.values[0]]}this.range=a("
      ").appendTo(this.element).addClass("ui-slider-range ui-widget-header"+(c.range==="min"||c.range==="max"?" ui-slider-range-"+c.range:""))}for(var i=e.length;i"); -this.handles=e.add(a(g.join("")).appendTo(d.element));this.handle=this.handles.eq(0);this.handles.add(this.range).filter("a").click(function(b){b.preventDefault()}).hover(function(){c.disabled||a(this).addClass("ui-state-hover")},function(){a(this).removeClass("ui-state-hover")}).focus(function(){if(c.disabled)a(this).blur();else{a(".ui-slider .ui-state-focus").removeClass("ui-state-focus");a(this).addClass("ui-state-focus")}}).blur(function(){a(this).removeClass("ui-state-focus")});this.handles.each(function(b){a(this).data("index.ui-slider-handle", -b)});this.handles.keydown(function(b){var f=true,j=a(this).data("index.ui-slider-handle"),l,o,n;if(!d.options.disabled){switch(b.keyCode){case a.ui.keyCode.HOME:case a.ui.keyCode.END:case a.ui.keyCode.PAGE_UP:case a.ui.keyCode.PAGE_DOWN:case a.ui.keyCode.UP:case a.ui.keyCode.RIGHT:case a.ui.keyCode.DOWN:case a.ui.keyCode.LEFT:f=false;if(!d._keySliding){d._keySliding=true;a(this).addClass("ui-state-active");l=d._start(b,j);if(l===false)return}break}n=d.options.step;l=d.options.values&&d.options.values.length? -(o=d.values(j)):(o=d.value());switch(b.keyCode){case a.ui.keyCode.HOME:o=d._valueMin();break;case a.ui.keyCode.END:o=d._valueMax();break;case a.ui.keyCode.PAGE_UP:o=d._trimAlignValue(l+(d._valueMax()-d._valueMin())/5);break;case a.ui.keyCode.PAGE_DOWN:o=d._trimAlignValue(l-(d._valueMax()-d._valueMin())/5);break;case a.ui.keyCode.UP:case a.ui.keyCode.RIGHT:if(l===d._valueMax())return;o=d._trimAlignValue(l+n);break;case a.ui.keyCode.DOWN:case a.ui.keyCode.LEFT:if(l===d._valueMin())return;o=d._trimAlignValue(l- -n);break}d._slide(b,j,o);return f}}).keyup(function(b){var f=a(this).data("index.ui-slider-handle");if(d._keySliding){d._keySliding=false;d._stop(b,f);d._change(b,f);a(this).removeClass("ui-state-active")}});this._refreshValue();this._animateOff=false},destroy:function(){this.handles.remove();this.range.remove();this.element.removeClass("ui-slider ui-slider-horizontal ui-slider-vertical ui-slider-disabled ui-widget ui-widget-content ui-corner-all").removeData("slider").unbind(".slider");this._mouseDestroy(); -return this},_mouseCapture:function(d){var c=this.options,e,h,g,i,b;if(c.disabled)return false;this.elementSize={width:this.element.outerWidth(),height:this.element.outerHeight()};this.elementOffset=this.element.offset();e=this._normValueFromMouse({x:d.pageX,y:d.pageY});h=this._valueMax()-this._valueMin()+1;i=this;this.handles.each(function(f){var j=Math.abs(e-i.values(f));if(h>j){h=j;g=a(this);b=f}});if(c.range===true&&this.values(1)===c.min){b+=1;g=a(this.handles[b])}if(this._start(d,b)===false)return false; -this._mouseSliding=true;i._handleIndex=b;g.addClass("ui-state-active").focus();c=g.offset();this._clickOffset=!a(d.target).parents().andSelf().is(".ui-slider-handle")?{left:0,top:0}:{left:d.pageX-c.left-g.width()/2,top:d.pageY-c.top-g.height()/2-(parseInt(g.css("borderTopWidth"),10)||0)-(parseInt(g.css("borderBottomWidth"),10)||0)+(parseInt(g.css("marginTop"),10)||0)};this.handles.hasClass("ui-state-hover")||this._slide(d,b,e);return this._animateOff=true},_mouseStart:function(){return true},_mouseDrag:function(d){var c= -this._normValueFromMouse({x:d.pageX,y:d.pageY});this._slide(d,this._handleIndex,c);return false},_mouseStop:function(d){this.handles.removeClass("ui-state-active");this._mouseSliding=false;this._stop(d,this._handleIndex);this._change(d,this._handleIndex);this._clickOffset=this._handleIndex=null;return this._animateOff=false},_detectOrientation:function(){this.orientation=this.options.orientation==="vertical"?"vertical":"horizontal"},_normValueFromMouse:function(d){var c;if(this.orientation==="horizontal"){c= -this.elementSize.width;d=d.x-this.elementOffset.left-(this._clickOffset?this._clickOffset.left:0)}else{c=this.elementSize.height;d=d.y-this.elementOffset.top-(this._clickOffset?this._clickOffset.top:0)}c=d/c;if(c>1)c=1;if(c<0)c=0;if(this.orientation==="vertical")c=1-c;d=this._valueMax()-this._valueMin();return this._trimAlignValue(this._valueMin()+c*d)},_start:function(d,c){var e={handle:this.handles[c],value:this.value()};if(this.options.values&&this.options.values.length){e.value=this.values(c); -e.values=this.values()}return this._trigger("start",d,e)},_slide:function(d,c,e){var h;if(this.options.values&&this.options.values.length){h=this.values(c?0:1);if(this.options.values.length===2&&this.options.range===true&&(c===0&&e>h||c===1&&e1){this.options.values[d]=this._trimAlignValue(c);this._refreshValue();this._change(null,d)}else if(arguments.length)if(a.isArray(arguments[0])){e=this.options.values;h=arguments[0];for(g=0;g=this._valueMax())return this._valueMax();var c=this.options.step>0?this.options.step:1,e=(d-this._valueMin())%c;d=d-e;if(Math.abs(e)*2>=c)d+=e>0?c:-c;return parseFloat(d.toFixed(5))},_valueMin:function(){return this.options.min},_valueMax:function(){return this.options.max},_refreshValue:function(){var d= -this.options.range,c=this.options,e=this,h=!this._animateOff?c.animate:false,g,i={},b,f,j,l;if(this.options.values&&this.options.values.length)this.handles.each(function(o){g=(e.values(o)-e._valueMin())/(e._valueMax()-e._valueMin())*100;i[e.orientation==="horizontal"?"left":"bottom"]=g+"%";a(this).stop(1,1)[h?"animate":"css"](i,c.animate);if(e.options.range===true)if(e.orientation==="horizontal"){if(o===0)e.range.stop(1,1)[h?"animate":"css"]({left:g+"%"},c.animate);if(o===1)e.range[h?"animate":"css"]({width:g- -b+"%"},{queue:false,duration:c.animate})}else{if(o===0)e.range.stop(1,1)[h?"animate":"css"]({bottom:g+"%"},c.animate);if(o===1)e.range[h?"animate":"css"]({height:g-b+"%"},{queue:false,duration:c.animate})}b=g});else{f=this.value();j=this._valueMin();l=this._valueMax();g=l!==j?(f-j)/(l-j)*100:0;i[e.orientation==="horizontal"?"left":"bottom"]=g+"%";this.handle.stop(1,1)[h?"animate":"css"](i,c.animate);if(d==="min"&&this.orientation==="horizontal")this.range.stop(1,1)[h?"animate":"css"]({width:g+"%"}, -c.animate);if(d==="max"&&this.orientation==="horizontal")this.range[h?"animate":"css"]({width:100-g+"%"},{queue:false,duration:c.animate});if(d==="min"&&this.orientation==="vertical")this.range.stop(1,1)[h?"animate":"css"]({height:g+"%"},c.animate);if(d==="max"&&this.orientation==="vertical")this.range[h?"animate":"css"]({height:100-g+"%"},{queue:false,duration:c.animate})}}});a.extend(a.ui.slider,{version:"1.8.16"})})(jQuery); -(function(a,d){function c(){return++h}function e(){return++g}var h=0,g=0;a.widget("ui.tabs",{options:{add:null,ajaxOptions:null,cache:false,cookie:null,collapsible:false,disable:null,disabled:[],enable:null,event:"click",fx:null,idPrefix:"ui-tabs-",load:null,panelTemplate:"
      ",remove:null,select:null,show:null,spinner:"Loading…",tabTemplate:"
    • #{label}
    • "},_create:function(){this._tabify(true)},_setOption:function(i,b){if(i=="selected")this.options.collapsible&& -b==this.options.selected||this.select(b);else{this.options[i]=b;this._tabify()}},_tabId:function(i){return i.title&&i.title.replace(/\s/g,"_").replace(/[^\w\u00c0-\uFFFF-]/g,"")||this.options.idPrefix+c()},_sanitizeSelector:function(i){return i.replace(/:/g,"\\:")},_cookie:function(){var i=this.cookie||(this.cookie=this.options.cookie.name||"ui-tabs-"+e());return a.cookie.apply(null,[i].concat(a.makeArray(arguments)))},_ui:function(i,b){return{tab:i,panel:b,index:this.anchors.index(i)}},_cleanup:function(){this.lis.filter(".ui-state-processing").removeClass("ui-state-processing").find("span:data(label.tabs)").each(function(){var i= -a(this);i.html(i.data("label.tabs")).removeData("label.tabs")})},_tabify:function(i){function b(r,u){r.css("display","");!a.support.opacity&&u.opacity&&r[0].style.removeAttribute("filter")}var f=this,j=this.options,l=/^#.+/;this.list=this.element.find("ol,ul").eq(0);this.lis=a(" > li:has(a[href])",this.list);this.anchors=this.lis.map(function(){return a("a",this)[0]});this.panels=a([]);this.anchors.each(function(r,u){var v=a(u).attr("href"),w=v.split("#")[0],x;if(w&&(w===location.toString().split("#")[0]|| -(x=a("base")[0])&&w===x.href)){v=u.hash;u.href=v}if(l.test(v))f.panels=f.panels.add(f.element.find(f._sanitizeSelector(v)));else if(v&&v!=="#"){a.data(u,"href.tabs",v);a.data(u,"load.tabs",v.replace(/#.*$/,""));v=f._tabId(u);u.href="#"+v;u=f.element.find("#"+v);if(!u.length){u=a(j.panelTemplate).attr("id",v).addClass("ui-tabs-panel ui-widget-content ui-corner-bottom").insertAfter(f.panels[r-1]||f.list);u.data("destroy.tabs",true)}f.panels=f.panels.add(u)}else j.disabled.push(r)});if(i){this.element.addClass("ui-tabs ui-widget ui-widget-content ui-corner-all"); -this.list.addClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all");this.lis.addClass("ui-state-default ui-corner-top");this.panels.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom");if(j.selected===d){location.hash&&this.anchors.each(function(r,u){if(u.hash==location.hash){j.selected=r;return false}});if(typeof j.selected!=="number"&&j.cookie)j.selected=parseInt(f._cookie(),10);if(typeof j.selected!=="number"&&this.lis.filter(".ui-tabs-selected").length)j.selected= -this.lis.index(this.lis.filter(".ui-tabs-selected"));j.selected=j.selected||(this.lis.length?0:-1)}else if(j.selected===null)j.selected=-1;j.selected=j.selected>=0&&this.anchors[j.selected]||j.selected<0?j.selected:0;j.disabled=a.unique(j.disabled.concat(a.map(this.lis.filter(".ui-state-disabled"),function(r){return f.lis.index(r)}))).sort();a.inArray(j.selected,j.disabled)!=-1&&j.disabled.splice(a.inArray(j.selected,j.disabled),1);this.panels.addClass("ui-tabs-hide");this.lis.removeClass("ui-tabs-selected ui-state-active"); -if(j.selected>=0&&this.anchors.length){f.element.find(f._sanitizeSelector(f.anchors[j.selected].hash)).removeClass("ui-tabs-hide");this.lis.eq(j.selected).addClass("ui-tabs-selected ui-state-active");f.element.queue("tabs",function(){f._trigger("show",null,f._ui(f.anchors[j.selected],f.element.find(f._sanitizeSelector(f.anchors[j.selected].hash))[0]))});this.load(j.selected)}a(window).bind("unload",function(){f.lis.add(f.anchors).unbind(".tabs");f.lis=f.anchors=f.panels=null})}else j.selected=this.lis.index(this.lis.filter(".ui-tabs-selected")); -this.element[j.collapsible?"addClass":"removeClass"]("ui-tabs-collapsible");j.cookie&&this._cookie(j.selected,j.cookie);i=0;for(var o;o=this.lis[i];i++)a(o)[a.inArray(i,j.disabled)!=-1&&!a(o).hasClass("ui-tabs-selected")?"addClass":"removeClass"]("ui-state-disabled");j.cache===false&&this.anchors.removeData("cache.tabs");this.lis.add(this.anchors).unbind(".tabs");if(j.event!=="mouseover"){var n=function(r,u){u.is(":not(.ui-state-disabled)")&&u.addClass("ui-state-"+r)},k=function(r,u){u.removeClass("ui-state-"+ -r)};this.lis.bind("mouseover.tabs",function(){n("hover",a(this))});this.lis.bind("mouseout.tabs",function(){k("hover",a(this))});this.anchors.bind("focus.tabs",function(){n("focus",a(this).closest("li"))});this.anchors.bind("blur.tabs",function(){k("focus",a(this).closest("li"))})}var m,p;if(j.fx)if(a.isArray(j.fx)){m=j.fx[0];p=j.fx[1]}else m=p=j.fx;var q=p?function(r,u){a(r).closest("li").addClass("ui-tabs-selected ui-state-active");u.hide().removeClass("ui-tabs-hide").animate(p,p.duration||"normal", -function(){b(u,p);f._trigger("show",null,f._ui(r,u[0]))})}:function(r,u){a(r).closest("li").addClass("ui-tabs-selected ui-state-active");u.removeClass("ui-tabs-hide");f._trigger("show",null,f._ui(r,u[0]))},s=m?function(r,u){u.animate(m,m.duration||"normal",function(){f.lis.removeClass("ui-tabs-selected ui-state-active");u.addClass("ui-tabs-hide");b(u,m);f.element.dequeue("tabs")})}:function(r,u){f.lis.removeClass("ui-tabs-selected ui-state-active");u.addClass("ui-tabs-hide");f.element.dequeue("tabs")}; -this.anchors.bind(j.event+".tabs",function(){var r=this,u=a(r).closest("li"),v=f.panels.filter(":not(.ui-tabs-hide)"),w=f.element.find(f._sanitizeSelector(r.hash));if(u.hasClass("ui-tabs-selected")&&!j.collapsible||u.hasClass("ui-state-disabled")||u.hasClass("ui-state-processing")||f.panels.filter(":animated").length||f._trigger("select",null,f._ui(this,w[0]))===false){this.blur();return false}j.selected=f.anchors.index(this);f.abort();if(j.collapsible)if(u.hasClass("ui-tabs-selected")){j.selected= --1;j.cookie&&f._cookie(j.selected,j.cookie);f.element.queue("tabs",function(){s(r,v)}).dequeue("tabs");this.blur();return false}else if(!v.length){j.cookie&&f._cookie(j.selected,j.cookie);f.element.queue("tabs",function(){q(r,w)});f.load(f.anchors.index(this));this.blur();return false}j.cookie&&f._cookie(j.selected,j.cookie);if(w.length){v.length&&f.element.queue("tabs",function(){s(r,v)});f.element.queue("tabs",function(){q(r,w)});f.load(f.anchors.index(this))}else throw"jQuery UI Tabs: Mismatching fragment identifier."; -a.browser.msie&&this.blur()});this.anchors.bind("click.tabs",function(){return false})},_getIndex:function(i){if(typeof i=="string")i=this.anchors.index(this.anchors.filter("[href$="+i+"]"));return i},destroy:function(){var i=this.options;this.abort();this.element.unbind(".tabs").removeClass("ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible").removeData("tabs");this.list.removeClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all");this.anchors.each(function(){var b= -a.data(this,"href.tabs");if(b)this.href=b;var f=a(this).unbind(".tabs");a.each(["href","load","cache"],function(j,l){f.removeData(l+".tabs")})});this.lis.unbind(".tabs").add(this.panels).each(function(){a.data(this,"destroy.tabs")?a(this).remove():a(this).removeClass("ui-state-default ui-corner-top ui-tabs-selected ui-state-active ui-state-hover ui-state-focus ui-state-disabled ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide")});i.cookie&&this._cookie(null,i.cookie);return this},add:function(i, -b,f){if(f===d)f=this.anchors.length;var j=this,l=this.options;b=a(l.tabTemplate.replace(/#\{href\}/g,i).replace(/#\{label\}/g,b));i=!i.indexOf("#")?i.replace("#",""):this._tabId(a("a",b)[0]);b.addClass("ui-state-default ui-corner-top").data("destroy.tabs",true);var o=j.element.find("#"+i);o.length||(o=a(l.panelTemplate).attr("id",i).data("destroy.tabs",true));o.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide");if(f>=this.lis.length){b.appendTo(this.list);o.appendTo(this.list[0].parentNode)}else{b.insertBefore(this.lis[f]); -o.insertBefore(this.panels[f])}l.disabled=a.map(l.disabled,function(n){return n>=f?++n:n});this._tabify();if(this.anchors.length==1){l.selected=0;b.addClass("ui-tabs-selected ui-state-active");o.removeClass("ui-tabs-hide");this.element.queue("tabs",function(){j._trigger("show",null,j._ui(j.anchors[0],j.panels[0]))});this.load(0)}this._trigger("add",null,this._ui(this.anchors[f],this.panels[f]));return this},remove:function(i){i=this._getIndex(i);var b=this.options,f=this.lis.eq(i).remove(),j=this.panels.eq(i).remove(); -if(f.hasClass("ui-tabs-selected")&&this.anchors.length>1)this.select(i+(i+1=i?--l:l});this._tabify();this._trigger("remove",null,this._ui(f.find("a")[0],j[0]));return this},enable:function(i){i=this._getIndex(i);var b=this.options;if(a.inArray(i,b.disabled)!=-1){this.lis.eq(i).removeClass("ui-state-disabled");b.disabled=a.grep(b.disabled,function(f){return f!=i});this._trigger("enable",null, -this._ui(this.anchors[i],this.panels[i]));return this}},disable:function(i){i=this._getIndex(i);var b=this.options;if(i!=b.selected){this.lis.eq(i).addClass("ui-state-disabled");b.disabled.push(i);b.disabled.sort();this._trigger("disable",null,this._ui(this.anchors[i],this.panels[i]))}return this},select:function(i){i=this._getIndex(i);if(i==-1)if(this.options.collapsible&&this.options.selected!=-1)i=this.options.selected;else return this;this.anchors.eq(i).trigger(this.options.event+".tabs");return this}, -load:function(i){i=this._getIndex(i);var b=this,f=this.options,j=this.anchors.eq(i)[0],l=a.data(j,"load.tabs");this.abort();if(!l||this.element.queue("tabs").length!==0&&a.data(j,"cache.tabs"))this.element.dequeue("tabs");else{this.lis.eq(i).addClass("ui-state-processing");if(f.spinner){var o=a("span",j);o.data("label.tabs",o.html()).html(f.spinner)}this.xhr=a.ajax(a.extend({},f.ajaxOptions,{url:l,success:function(n,k){b.element.find(b._sanitizeSelector(j.hash)).html(n);b._cleanup();f.cache&&a.data(j, -"cache.tabs",true);b._trigger("load",null,b._ui(b.anchors[i],b.panels[i]));try{f.ajaxOptions.success(n,k)}catch(m){}},error:function(n,k){b._cleanup();b._trigger("load",null,b._ui(b.anchors[i],b.panels[i]));try{f.ajaxOptions.error(n,k,i,j)}catch(m){}}}));b.element.dequeue("tabs");return this}},abort:function(){this.element.queue([]);this.panels.stop(false,true);this.element.queue("tabs",this.element.queue("tabs").splice(-2,2));if(this.xhr){this.xhr.abort();delete this.xhr}this._cleanup();return this}, -url:function(i,b){this.anchors.eq(i).removeData("cache.tabs").data("load.tabs",b);return this},length:function(){return this.anchors.length}});a.extend(a.ui.tabs,{version:"1.8.16"});a.extend(a.ui.tabs.prototype,{rotation:null,rotate:function(i,b){var f=this,j=this.options,l=f._rotate||(f._rotate=function(o){clearTimeout(f.rotation);f.rotation=setTimeout(function(){var n=j.selected;f.select(++n=0)&&i(t,!r)}}),e(function(){var t=document.body,n=t.appendChild(n=document.createElement("div"));n.offsetHeight,e.extend(n.style,{minHeight:"100px",height:"auto",padding:0,borderWidth:0}),e.support.minHeight=n.offsetHeight===100,e.support.selectstart="onselectstart"in n,t.removeChild(n).style.display="none"}),e("").outerWidth(1).jquery||e.each(["Width","Height"],function(n,r){function u(t,n,r,s){return e.each(i,function(){n-=parseFloat(e.css(t,"padding"+this))||0,r&&(n-=parseFloat(e.css(t,"border"+this+"Width"))||0),s&&(n-=parseFloat(e.css(t,"margin"+this))||0)}),n}var i=r==="Width"?["Left","Right"]:["Top","Bottom"],s=r.toLowerCase(),o={innerWidth:e.fn.innerWidth,innerHeight:e.fn.innerHeight,outerWidth:e.fn.outerWidth,outerHeight:e.fn.outerHeight};e.fn["inner"+r]=function(n){return n===t?o["inner"+r].call(this):this.each(function(){e(this).css(s,u(this,n)+"px")})},e.fn["outer"+r]=function(t,n){return typeof t!="number"?o["outer"+r].call(this,t):this.each(function(){e(this).css(s,u(this,t,!0,n)+"px")})}}),e("").data("a-b","a").removeData("a-b").data("a-b")&&(e.fn.removeData=function(t){return function(n){return arguments.length?t.call(this,e.camelCase(n)):t.call(this)}}(e.fn.removeData)),function(){var t=/msie ([\w.]+)/.exec(navigator.userAgent.toLowerCase())||[];e.ui.ie=t.length?!0:!1,e.ui.ie6=parseFloat(t[1],10)===6}(),e.fn.extend({disableSelection:function(){return this.bind((e.support.selectstart?"selectstart":"mousedown")+".ui-disableSelection",function(e){e.preventDefault()})},enableSelection:function(){return this.unbind(".ui-disableSelection")}}),e.extend(e.ui,{plugin:{add:function(t,n,r){var i,s=e.ui[t].prototype;for(i in r)s.plugins[i]=s.plugins[i]||[],s.plugins[i].push([n,r[i]])},call:function(e,t,n){var r,i=e.plugins[t];if(!i||!e.element[0].parentNode||e.element[0].parentNode.nodeType===11)return;for(r=0;r0?!0:(t[r]=1,i=t[r]>0,t[r]=0,i)},isOverAxis:function(e,t,n){return e>t&&e",options:{disabled:!1,create:null},_createWidget:function(t,r){r=e(r||this.defaultElement||this)[0],this.element=e(r),this.uuid=n++,this.eventNamespace="."+this.widgetName+this.uuid,this.options=e.widget.extend({},this.options,this._getCreateOptions(),t),this.bindings=e(),this.hoverable=e(),this.focusable=e(),r!==this&&(e.data(r,this.widgetName,this),e.data(r,this.widgetFullName,this),this._on(!0,this.element,{remove:function(e){e.target===r&&this.destroy()}}),this.document=e(r.style?r.ownerDocument:r.document||r),this.window=e(this.document[0].defaultView||this.document[0].parentWindow)),this._create(),this._trigger("create",null,this._getCreateEventData()),this._init()},_getCreateOptions:e.noop,_getCreateEventData:e.noop,_create:e.noop,_init:e.noop,destroy:function(){this._destroy(),this.element.unbind(this.eventNamespace).removeData(this.widgetName).removeData(this.widgetFullName).removeData(e.camelCase(this.widgetFullName)),this.widget().unbind(this.eventNamespace).removeAttr("aria-disabled").removeClass(this.widgetFullName+"-disabled "+"ui-state-disabled"),this.bindings.unbind(this.eventNamespace),this.hoverable.removeClass("ui-state-hover"),this.focusable.removeClass("ui-state-focus")},_destroy:e.noop,widget:function(){return this.element},option:function(n,r){var i=n,s,o,u;if(arguments.length===0)return e.widget.extend({},this.options);if(typeof n=="string"){i={},s=n.split("."),n=s.shift();if(s.length){o=i[n]=e.widget.extend({},this.options[n]);for(u=0;u=9||!!t.button?this._mouseStarted?(this._mouseDrag(t),t.preventDefault()):(this._mouseDistanceMet(t)&&this._mouseDelayMet(t)&&(this._mouseStarted=this._mouseStart(this._mouseDownEvent,t)!==!1,this._mouseStarted?this._mouseDrag(t):this._mouseUp(t)),!this._mouseStarted):this._mouseUp(t)},_mouseUp:function(t){return e(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate),this._mouseStarted&&(this._mouseStarted=!1,t.target===this._mouseDownEvent.target&&e.data(t.target,this.widgetName+".preventClickEvent",!0),this._mouseStop(t)),!1},_mouseDistanceMet:function(e){return Math.max(Math.abs(this._mouseDownEvent.pageX-e.pageX),Math.abs(this._mouseDownEvent.pageY-e.pageY))>=this.options.distance},_mouseDelayMet:function(e){return this.mouseDelayMet},_mouseStart:function(e){},_mouseDrag:function(e){},_mouseStop:function(e){},_mouseCapture:function(e){return!0}})})(jQuery);(function(e,t){function h(e,t,n){return[parseInt(e[0],10)*(l.test(e[0])?t/100:1),parseInt(e[1],10)*(l.test(e[1])?n/100:1)]}function p(t,n){return parseInt(e.css(t,n),10)||0}e.ui=e.ui||{};var n,r=Math.max,i=Math.abs,s=Math.round,o=/left|center|right/,u=/top|center|bottom/,a=/[\+\-]\d+%?/,f=/^\w+/,l=/%$/,c=e.fn.position;e.position={scrollbarWidth:function(){if(n!==t)return n;var r,i,s=e("
      "),o=s.children()[0];return e("body").append(s),r=o.offsetWidth,s.css("overflow","scroll"),i=o.offsetWidth,r===i&&(i=s[0].clientWidth),s.remove(),n=r-i},getScrollInfo:function(t){var n=t.isWindow?"":t.element.css("overflow-x"),r=t.isWindow?"":t.element.css("overflow-y"),i=n==="scroll"||n==="auto"&&t.width0?"right":"center",vertical:u<0?"top":o>0?"bottom":"middle"};lr(i(o),i(u))?h.important="horizontal":h.important="vertical",t.using.call(this,e,h)}),a.offset(e.extend(C,{using:u}))})},e.ui.position={fit:{left:function(e,t){var n=t.within,i=n.isWindow?n.scrollLeft:n.offset.left,s=n.width,o=e.left-t.collisionPosition.marginLeft,u=i-o,a=o+t.collisionWidth-s-i,f;t.collisionWidth>s?u>0&&a<=0?(f=e.left+u+t.collisionWidth-s-i,e.left+=u-f):a>0&&u<=0?e.left=i:u>a?e.left=i+s-t.collisionWidth:e.left=i:u>0?e.left+=u:a>0?e.left-=a:e.left=r(e.left-o,e.left)},top:function(e,t){var n=t.within,i=n.isWindow?n.scrollTop:n.offset.top,s=t.within.height,o=e.top-t.collisionPosition.marginTop,u=i-o,a=o+t.collisionHeight-s-i,f;t.collisionHeight>s?u>0&&a<=0?(f=e.top+u+t.collisionHeight-s-i,e.top+=u-f):a>0&&u<=0?e.top=i:u>a?e.top=i+s-t.collisionHeight:e.top=i:u>0?e.top+=u:a>0?e.top-=a:e.top=r(e.top-o,e.top)}},flip:{left:function(e,t){var n=t.within,r=n.offset.left+n.scrollLeft,s=n.width,o=n.isWindow?n.scrollLeft:n.offset.left,u=e.left-t.collisionPosition.marginLeft,a=u-o,f=u+t.collisionWidth-s-o,l=t.my[0]==="left"?-t.elemWidth:t.my[0]==="right"?t.elemWidth:0,c=t.at[0]==="left"?t.targetWidth:t.at[0]==="right"?-t.targetWidth:0,h=-2*t.offset[0],p,d;if(a<0){p=e.left+l+c+h+t.collisionWidth-s-r;if(p<0||p0){d=e.left-t.collisionPosition.marginLeft+l+c+h-o;if(d>0||i(d)a&&(v<0||v0&&(d=e.top-t.collisionPosition.marginTop+c+h+p-o,e.top+c+h+p>f&&(d>0||i(d)10&&i<11,t.innerHTML="",n.removeChild(t)}(),e.uiBackCompat!==!1&&function(e){var n=e.fn.position;e.fn.position=function(r){if(!r||!r.offset)return n.call(this,r);var i=r.offset.split(" "),s=r.at.split(" ");return i.length===1&&(i[1]=i[0]),/^\d/.test(i[0])&&(i[0]="+"+i[0]),/^\d/.test(i[1])&&(i[1]="+"+i[1]),s.length===1&&(/left|center|right/.test(s[0])?s[1]="center":(s[1]=s[0],s[0]="center")),n.call(this,e.extend(r,{at:s[0]+i[0]+" "+s[1]+i[1],offset:t}))}}(jQuery)})(jQuery);(function(e,t){var n=0,r={},i={};r.height=r.paddingTop=r.paddingBottom=r.borderTopWidth=r.borderBottomWidth="hide",i.height=i.paddingTop=i.paddingBottom=i.borderTopWidth=i.borderBottomWidth="show",e.widget("ui.accordion",{version:"1.9.2",options:{active:0,animate:{},collapsible:!1,event:"click",header:"> li > :first-child,> :not(li):even",heightStyle:"auto",icons:{activeHeader:"ui-icon-triangle-1-s",header:"ui-icon-triangle-1-e"},activate:null,beforeActivate:null},_create:function(){var t=this.accordionId="ui-accordion-"+(this.element.attr("id")||++n),r=this.options;this.prevShow=this.prevHide=e(),this.element.addClass("ui-accordion ui-widget ui-helper-reset"),this.headers=this.element.find(r.header).addClass("ui-accordion-header ui-helper-reset ui-state-default ui-corner-all"),this._hoverable(this.headers),this._focusable(this.headers),this.headers.next().addClass("ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom").hide(),!r.collapsible&&(r.active===!1||r.active==null)&&(r.active=0),r.active<0&&(r.active+=this.headers.length),this.active=this._findActive(r.active).addClass("ui-accordion-header-active ui-state-active").toggleClass("ui-corner-all ui-corner-top"),this.active.next().addClass("ui-accordion-content-active").show(),this._createIcons(),this.refresh(),this.element.attr("role","tablist"),this.headers.attr("role","tab").each(function(n){var r=e(this),i=r.attr("id"),s=r.next(),o=s.attr("id");i||(i=t+"-header-"+n,r.attr("id",i)),o||(o=t+"-panel-"+n,s.attr("id",o)),r.attr("aria-controls",o),s.attr("aria-labelledby",i)}).next().attr("role","tabpanel"),this.headers.not(this.active).attr({"aria-selected":"false",tabIndex:-1}).next().attr({"aria-expanded":"false","aria-hidden":"true"}).hide(),this.active.length?this.active.attr({"aria-selected":"true",tabIndex:0}).next().attr({"aria-expanded":"true","aria-hidden":"false"}):this.headers.eq(0).attr("tabIndex",0),this._on(this.headers,{keydown:"_keydown"}),this._on(this.headers.next(),{keydown:"_panelKeyDown"}),this._setupEvents(r.event)},_getCreateEventData:function(){return{header:this.active,content:this.active.length?this.active.next():e()}},_createIcons:function(){var t=this.options.icons;t&&(e("").addClass("ui-accordion-header-icon ui-icon "+t.header).prependTo(this.headers),this.active.children(".ui-accordion-header-icon").removeClass(t.header).addClass(t.activeHeader),this.headers.addClass("ui-accordion-icons"))},_destroyIcons:function(){this.headers.removeClass("ui-accordion-icons").children(".ui-accordion-header-icon").remove()},_destroy:function(){var e;this.element.removeClass("ui-accordion ui-widget ui-helper-reset").removeAttr("role"),this.headers.removeClass("ui-accordion-header ui-accordion-header-active ui-helper-reset ui-state-default ui-corner-all ui-state-active ui-state-disabled ui-corner-top").removeAttr("role").removeAttr("aria-selected").removeAttr("aria-controls").removeAttr("tabIndex").each(function(){/^ui-accordion/.test(this.id)&&this.removeAttribute("id")}),this._destroyIcons(),e=this.headers.next().css("display","").removeAttr("role").removeAttr("aria-expanded").removeAttr("aria-hidden").removeAttr("aria-labelledby").removeClass("ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active ui-state-disabled").each(function(){/^ui-accordion/.test(this.id)&&this.removeAttribute("id")}),this.options.heightStyle!=="content"&&e.css("height","")},_setOption:function(e,t){if(e==="active"){this._activate(t);return}e==="event"&&(this.options.event&&this._off(this.headers,this.options.event),this._setupEvents(t)),this._super(e,t),e==="collapsible"&&!t&&this.options.active===!1&&this._activate(0),e==="icons"&&(this._destroyIcons(),t&&this._createIcons()),e==="disabled"&&this.headers.add(this.headers.next()).toggleClass("ui-state-disabled",!!t)},_keydown:function(t){if(t.altKey||t.ctrlKey)return;var n=e.ui.keyCode,r=this.headers.length,i=this.headers.index(t.target),s=!1;switch(t.keyCode){case n.RIGHT:case n.DOWN:s=this.headers[(i+1)%r];break;case n.LEFT:case n.UP:s=this.headers[(i-1+r)%r];break;case n.SPACE:case n.ENTER:this._eventHandler(t);break;case n.HOME:s=this.headers[0];break;case n.END:s=this.headers[r-1]}s&&(e(t.target).attr("tabIndex",-1),e(s).attr("tabIndex",0),s.focus(),t.preventDefault())},_panelKeyDown:function(t){t.keyCode===e.ui.keyCode.UP&&t.ctrlKey&&e(t.currentTarget).prev().focus()},refresh:function(){var t,n,r=this.options.heightStyle,i=this.element.parent();r==="fill"?(e.support.minHeight||(n=i.css("overflow"),i.css("overflow","hidden")),t=i.height(),this.element.siblings(":visible").each(function(){var n=e(this),r=n.css("position");if(r==="absolute"||r==="fixed")return;t-=n.outerHeight(!0)}),n&&i.css("overflow",n),this.headers.each(function(){t-=e(this).outerHeight(!0)}),this.headers.next().each(function(){e(this).height(Math.max(0,t-e(this).innerHeight()+e(this).height()))}).css("overflow","auto")):r==="auto"&&(t=0,this.headers.next().each(function(){t=Math.max(t,e(this).css("height","").height())}).height(t))},_activate:function(t){var n=this._findActive(t)[0];if(n===this.active[0])return;n=n||this.active[0],this._eventHandler({target:n,currentTarget:n,preventDefault:e.noop})},_findActive:function(t){return typeof t=="number"?this.headers.eq(t):e()},_setupEvents:function(t){var n={};if(!t)return;e.each(t.split(" "),function(e,t){n[t]="_eventHandler"}),this._on(this.headers,n)},_eventHandler:function(t){var n=this.options,r=this.active,i=e(t.currentTarget),s=i[0]===r[0],o=s&&n.collapsible,u=o?e():i.next(),a=r.next(),f={oldHeader:r,oldPanel:a,newHeader:o?e():i,newPanel:u};t.preventDefault();if(s&&!n.collapsible||this._trigger("beforeActivate",t,f)===!1)return;n.active=o?!1:this.headers.index(i),this.active=s?e():i,this._toggle(f),r.removeClass("ui-accordion-header-active ui-state-active"),n.icons&&r.children(".ui-accordion-header-icon").removeClass(n.icons.activeHeader).addClass(n.icons.header),s||(i.removeClass("ui-corner-all").addClass("ui-accordion-header-active ui-state-active ui-corner-top"),n.icons&&i.children(".ui-accordion-header-icon").removeClass(n.icons.header).addClass(n.icons.activeHeader),i.next().addClass("ui-accordion-content-active"))},_toggle:function(t){var n=t.newPanel,r=this.prevShow.length?this.prevShow:t.oldPanel;this.prevShow.add(this.prevHide).stop(!0,!0),this.prevShow=n,this.prevHide=r,this.options.animate?this._animate(n,r,t):(r.hide(),n.show(),this._toggleComplete(t)),r.attr({"aria-expanded":"false","aria-hidden":"true"}),r.prev().attr("aria-selected","false"),n.length&&r.length?r.prev().attr("tabIndex",-1):n.length&&this.headers.filter(function(){return e(this).attr("tabIndex")===0}).attr("tabIndex",-1),n.attr({"aria-expanded":"true","aria-hidden":"false"}).prev().attr({"aria-selected":"true",tabIndex:0})},_animate:function(e,t,n){var s,o,u,a=this,f=0,l=e.length&&(!t.length||e.index()",options:{appendTo:"body",autoFocus:!1,delay:300,minLength:1,position:{my:"left top",at:"left bottom",collision:"none"},source:null,change:null,close:null,focus:null,open:null,response:null,search:null,select:null},pending:0,_create:function(){var t,n,r;this.isMultiLine=this._isMultiLine(),this.valueMethod=this.element[this.element.is("input,textarea")?"val":"text"],this.isNewMenu=!0,this.element.addClass("ui-autocomplete-input").attr("autocomplete","off"),this._on(this.element,{keydown:function(i){if(this.element.prop("readOnly")){t=!0,r=!0,n=!0;return}t=!1,r=!1,n=!1;var s=e.ui.keyCode;switch(i.keyCode){case s.PAGE_UP:t=!0,this._move("previousPage",i);break;case s.PAGE_DOWN:t=!0,this._move("nextPage",i);break;case s.UP:t=!0,this._keyEvent("previous",i);break;case s.DOWN:t=!0,this._keyEvent("next",i);break;case s.ENTER:case s.NUMPAD_ENTER:this.menu.active&&(t=!0,i.preventDefault(),this.menu.select(i));break;case s.TAB:this.menu.active&&this.menu.select(i);break;case s.ESCAPE:this.menu.element.is(":visible")&&(this._value(this.term),this.close(i),i.preventDefault());break;default:n=!0,this._searchTimeout(i)}},keypress:function(r){if(t){t=!1,r.preventDefault();return}if(n)return;var i=e.ui.keyCode;switch(r.keyCode){case i.PAGE_UP:this._move("previousPage",r);break;case i.PAGE_DOWN:this._move("nextPage",r);break;case i.UP:this._keyEvent("previous",r);break;case i.DOWN:this._keyEvent("next",r)}},input:function(e){if(r){r=!1,e.preventDefault();return}this._searchTimeout(e)},focus:function(){this.selectedItem=null,this.previous=this._value()},blur:function(e){if(this.cancelBlur){delete this.cancelBlur;return}clearTimeout(this.searching),this.close(e),this._change(e)}}),this._initSource(),this.menu=e("
        ").addClass("ui-autocomplete").appendTo(this.document.find(this.options.appendTo||"body")[0]).menu({input:e(),role:null}).zIndex(this.element.zIndex()+1).hide().data("menu"),this._on(this.menu.element,{mousedown:function(t){t.preventDefault(),this.cancelBlur=!0,this._delay(function(){delete this.cancelBlur});var n=this.menu.element[0];e(t.target).closest(".ui-menu-item").length||this._delay(function(){var t=this;this.document.one("mousedown",function(r){r.target!==t.element[0]&&r.target!==n&&!e.contains(n,r.target)&&t.close()})})},menufocus:function(t,n){if(this.isNewMenu){this.isNewMenu=!1;if(t.originalEvent&&/^mouse/.test(t.originalEvent.type)){this.menu.blur(),this.document.one("mousemove",function(){e(t.target).trigger(t.originalEvent)});return}}var r=n.item.data("ui-autocomplete-item")||n.item.data("item.autocomplete");!1!==this._trigger("focus",t,{item:r})?t.originalEvent&&/^key/.test(t.originalEvent.type)&&this._value(r.value):this.liveRegion.text(r.value)},menuselect:function(e,t){var n=t.item.data("ui-autocomplete-item")||t.item.data("item.autocomplete"),r=this.previous;this.element[0]!==this.document[0].activeElement&&(this.element.focus(),this.previous=r,this._delay(function(){this.previous=r,this.selectedItem=n})),!1!==this._trigger("select",e,{item:n})&&this._value(n.value),this.term=this._value(),this.close(e),this.selectedItem=n}}),this.liveRegion=e("",{role:"status","aria-live":"polite"}).addClass("ui-helper-hidden-accessible").insertAfter(this.element),e.fn.bgiframe&&this.menu.element.bgiframe(),this._on(this.window,{beforeunload:function(){this.element.removeAttr("autocomplete")}})},_destroy:function(){clearTimeout(this.searching),this.element.removeClass("ui-autocomplete-input").removeAttr("autocomplete"),this.menu.element.remove(),this.liveRegion.remove()},_setOption:function(e,t){this._super(e,t),e==="source"&&this._initSource(),e==="appendTo"&&this.menu.element.appendTo(this.document.find(t||"body")[0]),e==="disabled"&&t&&this.xhr&&this.xhr.abort()},_isMultiLine:function(){return this.element.is("textarea")?!0:this.element.is("input")?!1:this.element.prop("isContentEditable")},_initSource:function(){var t,n,r=this;e.isArray(this.options.source)?(t=this.options.source,this.source=function(n,r){r(e.ui.autocomplete.filter(t,n.term))}):typeof this.options.source=="string"?(n=this.options.source,this.source=function(t,i){r.xhr&&r.xhr.abort(),r.xhr=e.ajax({url:n,data:t,dataType:"json",success:function(e){i(e)},error:function(){i([])}})}):this.source=this.options.source},_searchTimeout:function(e){clearTimeout(this.searching),this.searching=this._delay(function(){this.term!==this._value()&&(this.selectedItem=null,this.search(null,e))},this.options.delay)},search:function(e,t){e=e!=null?e:this._value(),this.term=this._value();if(e.length").append(e("").text(n.label)).appendTo(t)},_move:function(e,t){if(!this.menu.element.is(":visible")){this.search(null,t);return}if(this.menu.isFirstItem()&&/^previous/.test(e)||this.menu.isLastItem()&&/^next/.test(e)){this._value(this.term),this.menu.blur();return}this.menu[e](t)},widget:function(){return this.menu.element},_value:function(){return this.valueMethod.apply(this.element,arguments)},_keyEvent:function(e,t){if(!this.isMultiLine||this.menu.element.is(":visible"))this._move(e,t),t.preventDefault()}}),e.extend(e.ui.autocomplete,{escapeRegex:function(e){return e.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g,"\\$&")},filter:function(t,n){var r=new RegExp(e.ui.autocomplete.escapeRegex(n),"i");return e.grep(t,function(e){return r.test(e.label||e.value||e)})}}),e.widget("ui.autocomplete",e.ui.autocomplete,{options:{messages:{noResults:"No search results.",results:function(e){return e+(e>1?" results are":" result is")+" available, use up and down arrow keys to navigate."}}},__response:function(e){var t;this._superApply(arguments);if(this.options.disabled||this.cancelSearch)return;e&&e.length?t=this.options.messages.results(e.length):t=this.options.messages.noResults,this.liveRegion.text(t)}})})(jQuery);(function(e,t){var n,r,i,s,o="ui-button ui-widget ui-state-default ui-corner-all",u="ui-state-hover ui-state-active ",a="ui-button-icons-only ui-button-icon-only ui-button-text-icons ui-button-text-icon-primary ui-button-text-icon-secondary ui-button-text-only",f=function(){var t=e(this).find(":ui-button");setTimeout(function(){t.button("refresh")},1)},l=function(t){var n=t.name,r=t.form,i=e([]);return n&&(r?i=e(r).find("[name='"+n+"']"):i=e("[name='"+n+"']",t.ownerDocument).filter(function(){return!this.form})),i};e.widget("ui.button",{version:"1.9.2",defaultElement:"').addClass(this._triggerClass).html(o==""?s:$("").attr({src:o,alt:s,title:s}))),e[r?"before":"after"](t.trigger),t.trigger.click(function(){return $.datepicker._datepickerShowing&&$.datepicker._lastInput==e[0]?$.datepicker._hideDatepicker():$.datepicker._datepickerShowing&&$.datepicker._lastInput!=e[0]?($.datepicker._hideDatepicker(),$.datepicker._showDatepicker(e[0])):$.datepicker._showDatepicker(e[0]),!1})}},_autoSize:function(e){if(this._get(e,"autoSize")&&!e.inline){var t=new Date(2009,11,20),n=this._get(e,"dateFormat");if(n.match(/[DM]/)){var r=function(e){var t=0,n=0;for(var r=0;rt&&(t=e[r].length,n=r);return n};t.setMonth(r(this._get(e,n.match(/MM/)?"monthNames":"monthNamesShort"))),t.setDate(r(this._get(e,n.match(/DD/)?"dayNames":"dayNamesShort"))+20-t.getDay())}e.input.attr("size",this._formatDate(e,t).length)}},_inlineDatepicker:function(e,t){var n=$(e);if(n.hasClass(this.markerClassName))return;n.addClass(this.markerClassName).append(t.dpDiv).bind("setData.datepicker",function(e,n,r){t.settings[n]=r}).bind("getData.datepicker",function(e,n){return this._get(t,n)}),$.data(e,PROP_NAME,t),this._setDate(t,this._getDefaultDate(t),!0),this._updateDatepicker(t),this._updateAlternate(t),t.settings.disabled&&this._disableDatepicker(e),t.dpDiv.css("display","block")},_dialogDatepicker:function(e,t,n,r,i){var s=this._dialogInst;if(!s){this.uuid+=1;var o="dp"+this.uuid;this._dialogInput=$(''),this._dialogInput.keydown(this._doKeyDown),$("body").append(this._dialogInput),s=this._dialogInst=this._newInst(this._dialogInput,!1),s.settings={},$.data(this._dialogInput[0],PROP_NAME,s)}extendRemove(s.settings,r||{}),t=t&&t.constructor==Date?this._formatDate(s,t):t,this._dialogInput.val(t),this._pos=i?i.length?i:[i.pageX,i.pageY]:null;if(!this._pos){var u=document.documentElement.clientWidth,a=document.documentElement.clientHeight,f=document.documentElement.scrollLeft||document.body.scrollLeft,l=document.documentElement.scrollTop||document.body.scrollTop;this._pos=[u/2-100+f,a/2-150+l]}return this._dialogInput.css("left",this._pos[0]+20+"px").css("top",this._pos[1]+"px"),s.settings.onSelect=n,this._inDialog=!0,this.dpDiv.addClass(this._dialogClass),this._showDatepicker(this._dialogInput[0]),$.blockUI&&$.blockUI(this.dpDiv),$.data(this._dialogInput[0],PROP_NAME,s),this},_destroyDatepicker:function(e){var t=$(e),n=$.data(e,PROP_NAME);if(!t.hasClass(this.markerClassName))return;var r=e.nodeName.toLowerCase();$.removeData(e,PROP_NAME),r=="input"?(n.append.remove(),n.trigger.remove(),t.removeClass(this.markerClassName).unbind("focus",this._showDatepicker).unbind("keydown",this._doKeyDown).unbind("keypress",this._doKeyPress).unbind("keyup",this._doKeyUp)):(r=="div"||r=="span")&&t.removeClass(this.markerClassName).empty()},_enableDatepicker:function(e){var t=$(e),n=$.data(e,PROP_NAME);if(!t.hasClass(this.markerClassName))return;var r=e.nodeName.toLowerCase();if(r=="input")e.disabled=!1,n.trigger.filter("button").each(function(){this.disabled=!1}).end().filter("img").css({opacity:"1.0",cursor:""});else if(r=="div"||r=="span"){var i=t.children("."+this._inlineClass);i.children().removeClass("ui-state-disabled"),i.find("select.ui-datepicker-month, select.ui-datepicker-year").prop("disabled",!1)}this._disabledInputs=$.map(this._disabledInputs,function(t){return t==e?null:t})},_disableDatepicker:function(e){var t=$(e),n=$.data(e,PROP_NAME);if(!t.hasClass(this.markerClassName))return;var r=e.nodeName.toLowerCase();if(r=="input")e.disabled=!0,n.trigger.filter("button").each(function(){this.disabled=!0}).end().filter("img").css({opacity:"0.5",cursor:"default"});else if(r=="div"||r=="span"){var i=t.children("."+this._inlineClass);i.children().addClass("ui-state-disabled"),i.find("select.ui-datepicker-month, select.ui-datepicker-year").prop("disabled",!0)}this._disabledInputs=$.map(this._disabledInputs,function(t){return t==e?null:t}),this._disabledInputs[this._disabledInputs.length]=e},_isDisabledDatepicker:function(e){if(!e)return!1;for(var t=0;t-1}},_doKeyUp:function(e){var t=$.datepicker._getInst(e.target);if(t.input.val()!=t.lastVal)try{var n=$.datepicker.parseDate($.datepicker._get(t,"dateFormat"),t.input?t.input.val():null,$.datepicker._getFormatConfig(t));n&&($.datepicker._setDateFromField(t),$.datepicker._updateAlternate(t),$.datepicker._updateDatepicker(t))}catch(r){$.datepicker.log(r)}return!0},_showDatepicker:function(e){e=e.target||e,e.nodeName.toLowerCase()!="input"&&(e=$("input",e.parentNode)[0]);if($.datepicker._isDisabledDatepicker(e)||$.datepicker._lastInput==e)return;var t=$.datepicker._getInst(e);$.datepicker._curInst&&$.datepicker._curInst!=t&&($.datepicker._curInst.dpDiv.stop(!0,!0),t&&$.datepicker._datepickerShowing&&$.datepicker._hideDatepicker($.datepicker._curInst.input[0]));var n=$.datepicker._get(t,"beforeShow"),r=n?n.apply(e,[e,t]):{};if(r===!1)return;extendRemove(t.settings,r),t.lastVal=null,$.datepicker._lastInput=e,$.datepicker._setDateFromField(t),$.datepicker._inDialog&&(e.value=""),$.datepicker._pos||($.datepicker._pos=$.datepicker._findPos(e),$.datepicker._pos[1]+=e.offsetHeight);var i=!1;$(e).parents().each(function(){return i|=$(this).css("position")=="fixed",!i});var s={left:$.datepicker._pos[0],top:$.datepicker._pos[1]};$.datepicker._pos=null,t.dpDiv.empty(),t.dpDiv.css({position:"absolute",display:"block",top:"-1000px"}),$.datepicker._updateDatepicker(t),s=$.datepicker._checkOffset(t,s,i),t.dpDiv.css({position:$.datepicker._inDialog&&$.blockUI?"static":i?"fixed":"absolute",display:"none",left:s.left+"px",top:s.top+"px"});if(!t.inline){var o=$.datepicker._get(t,"showAnim"),u=$.datepicker._get(t,"duration"),a=function(){var e=t.dpDiv.find("iframe.ui-datepicker-cover");if(!!e.length){var n=$.datepicker._getBorders(t.dpDiv);e.css({left:-n[0],top:-n[1],width:t.dpDiv.outerWidth(),height:t.dpDiv.outerHeight()})}};t.dpDiv.zIndex($(e).zIndex()+1),$.datepicker._datepickerShowing=!0,$.effects&&($.effects.effect[o]||$.effects[o])?t.dpDiv.show(o,$.datepicker._get(t,"showOptions"),u,a):t.dpDiv[o||"show"](o?u:null,a),(!o||!u)&&a(),t.input.is(":visible")&&!t.input.is(":disabled")&&t.input.focus(),$.datepicker._curInst=t}},_updateDatepicker:function(e){this.maxRows=4;var t=$.datepicker._getBorders(e.dpDiv);instActive=e,e.dpDiv.empty().append(this._generateHTML(e)),this._attachHandlers(e);var n=e.dpDiv.find("iframe.ui-datepicker-cover");!n.length||n.css({left:-t[0],top:-t[1],width:e.dpDiv.outerWidth(),height:e.dpDiv.outerHeight()}),e.dpDiv.find("."+this._dayOverClass+" a").mouseover();var r=this._getNumberOfMonths(e),i=r[1],s=17;e.dpDiv.removeClass("ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4").width(""),i>1&&e.dpDiv.addClass("ui-datepicker-multi-"+i).css("width",s*i+"em"),e.dpDiv[(r[0]!=1||r[1]!=1?"add":"remove")+"Class"]("ui-datepicker-multi"),e.dpDiv[(this._get(e,"isRTL")?"add":"remove")+"Class"]("ui-datepicker-rtl"),e==$.datepicker._curInst&&$.datepicker._datepickerShowing&&e.input&&e.input.is(":visible")&&!e.input.is(":disabled")&&e.input[0]!=document.activeElement&&e.input.focus();if(e.yearshtml){var o=e.yearshtml;setTimeout(function(){o===e.yearshtml&&e.yearshtml&&e.dpDiv.find("select.ui-datepicker-year:first").replaceWith(e.yearshtml),o=e.yearshtml=null},0)}},_getBorders:function(e){var t=function(e){return{thin:1,medium:2,thick:3}[e]||e};return[parseFloat(t(e.css("border-left-width"))),parseFloat(t(e.css("border-top-width")))]},_checkOffset:function(e,t,n){var r=e.dpDiv.outerWidth(),i=e.dpDiv.outerHeight(),s=e.input?e.input.outerWidth():0,o=e.input?e.input.outerHeight():0,u=document.documentElement.clientWidth+(n?0:$(document).scrollLeft()),a=document.documentElement.clientHeight+(n?0:$(document).scrollTop());return t.left-=this._get(e,"isRTL")?r-s:0,t.left-=n&&t.left==e.input.offset().left?$(document).scrollLeft():0,t.top-=n&&t.top==e.input.offset().top+o?$(document).scrollTop():0,t.left-=Math.min(t.left,t.left+r>u&&u>r?Math.abs(t.left+r-u):0),t.top-=Math.min(t.top,t.top+i>a&&a>i?Math.abs(i+o):0),t},_findPos:function(e){var t=this._getInst(e),n=this._get(t,"isRTL");while(e&&(e.type=="hidden"||e.nodeType!=1||$.expr.filters.hidden(e)))e=e[n?"previousSibling":"nextSibling"];var r=$(e).offset();return[r.left,r.top]},_hideDatepicker:function(e){var t=this._curInst;if(!t||e&&t!=$.data(e,PROP_NAME))return;if(this._datepickerShowing){var n=this._get(t,"showAnim"),r=this._get(t,"duration"),i=function(){$.datepicker._tidyDialog(t)};$.effects&&($.effects.effect[n]||$.effects[n])?t.dpDiv.hide(n,$.datepicker._get(t,"showOptions"),r,i):t.dpDiv[n=="slideDown"?"slideUp":n=="fadeIn"?"fadeOut":"hide"](n?r:null,i),n||i(),this._datepickerShowing=!1;var s=this._get(t,"onClose");s&&s.apply(t.input?t.input[0]:null,[t.input?t.input.val():"",t]),this._lastInput=null,this._inDialog&&(this._dialogInput.css({position:"absolute",left:"0",top:"-100px"}),$.blockUI&&($.unblockUI(),$("body").append(this.dpDiv))),this._inDialog=!1}},_tidyDialog:function(e){e.dpDiv.removeClass(this._dialogClass).unbind(".ui-datepicker-calendar")},_checkExternalClick:function(e){if(!$.datepicker._curInst)return;var t=$(e.target),n=$.datepicker._getInst(t[0]);(t[0].id!=$.datepicker._mainDivId&&t.parents("#"+$.datepicker._mainDivId).length==0&&!t.hasClass($.datepicker.markerClassName)&&!t.closest("."+$.datepicker._triggerClass).length&&$.datepicker._datepickerShowing&&(!$.datepicker._inDialog||!$.blockUI)||t.hasClass($.datepicker.markerClassName)&&$.datepicker._curInst!=n)&&$.datepicker._hideDatepicker()},_adjustDate:function(e,t,n){var r=$(e),i=this._getInst(r[0]);if(this._isDisabledDatepicker(r[0]))return;this._adjustInstDate(i,t+(n=="M"?this._get(i,"showCurrentAtPos"):0),n),this._updateDatepicker(i)},_gotoToday:function(e){var t=$(e),n=this._getInst(t[0]);if(this._get(n,"gotoCurrent")&&n.currentDay)n.selectedDay=n.currentDay,n.drawMonth=n.selectedMonth=n.currentMonth,n.drawYear=n.selectedYear=n.currentYear;else{var r=new Date;n.selectedDay=r.getDate(),n.drawMonth=n.selectedMonth=r.getMonth(),n.drawYear=n.selectedYear=r.getFullYear()}this._notifyChange(n),this._adjustDate(t)},_selectMonthYear:function(e,t,n){var r=$(e),i=this._getInst(r[0]);i["selected"+(n=="M"?"Month":"Year")]=i["draw"+(n=="M"?"Month":"Year")]=parseInt(t.options[t.selectedIndex].value,10),this._notifyChange(i),this._adjustDate(r)},_selectDay:function(e,t,n,r){var i=$(e);if($(r).hasClass(this._unselectableClass)||this._isDisabledDatepicker(i[0]))return;var s=this._getInst(i[0]);s.selectedDay=s.currentDay=$("a",r).html(),s.selectedMonth=s.currentMonth=t,s.selectedYear=s.currentYear=n,this._selectDate(e,this._formatDate(s,s.currentDay,s.currentMonth,s.currentYear))},_clearDate:function(e){var t=$(e),n=this._getInst(t[0]);this._selectDate(t,"")},_selectDate:function(e,t){var n=$(e),r=this._getInst(n[0]);t=t!=null?t:this._formatDate(r),r.input&&r.input.val(t),this._updateAlternate(r);var i=this._get(r,"onSelect");i?i.apply(r.input?r.input[0]:null,[t,r]):r.input&&r.input.trigger("change"),r.inline?this._updateDatepicker(r):(this._hideDatepicker(),this._lastInput=r.input[0],typeof r.input[0]!="object"&&r.input.focus(),this._lastInput=null)},_updateAlternate:function(e){var t=this._get(e,"altField");if(t){var n=this._get(e,"altFormat")||this._get(e,"dateFormat"),r=this._getDate(e),i=this.formatDate(n,r,this._getFormatConfig(e));$(t).each(function(){$(this).val(i)})}},noWeekends:function(e){var t=e.getDay();return[t>0&&t<6,""]},iso8601Week:function(e){var t=new Date(e.getTime());t.setDate(t.getDate()+4-(t.getDay()||7));var n=t.getTime();return t.setMonth(0),t.setDate(1),Math.floor(Math.round((n-t)/864e5)/7)+1},parseDate:function(e,t,n){if(e==null||t==null)throw"Invalid arguments";t=typeof t=="object"?t.toString():t+"";if(t=="")return null;var r=(n?n.shortYearCutoff:null)||this._defaults.shortYearCutoff;r=typeof r!="string"?r:(new Date).getFullYear()%100+parseInt(r,10);var i=(n?n.dayNamesShort:null)||this._defaults.dayNamesShort,s=(n?n.dayNames:null)||this._defaults.dayNames,o=(n?n.monthNamesShort:null)||this._defaults.monthNamesShort,u=(n?n.monthNames:null)||this._defaults.monthNames,a=-1,f=-1,l=-1,c=-1,h=!1,p=function(t){var n=y+1-1){f=1,l=c;do{var E=this._getDaysInMonth(a,f-1);if(l<=E)break;f++,l-=E}while(!0)}var b=this._daylightSavingAdjust(new Date(a,f-1,l));if(b.getFullYear()!=a||b.getMonth()+1!=f||b.getDate()!=l)throw"Invalid date";return b},ATOM:"yy-mm-dd",COOKIE:"D, dd M yy",ISO_8601:"yy-mm-dd",RFC_822:"D, d M y",RFC_850:"DD, dd-M-y",RFC_1036:"D, d M y",RFC_1123:"D, d M yy",RFC_2822:"D, d M yy",RSS:"D, d M y",TICKS:"!",TIMESTAMP:"@",W3C:"yy-mm-dd",_ticksTo1970:(718685+Math.floor(492.5)-Math.floor(19.7)+Math.floor(4.925))*24*60*60*1e7,formatDate:function(e,t,n){if(!t)return"";var r=(n?n.dayNamesShort:null)||this._defaults.dayNamesShort,i=(n?n.dayNames:null)||this._defaults.dayNames,s=(n?n.monthNamesShort:null)||this._defaults.monthNamesShort,o=(n?n.monthNames:null)||this._defaults.monthNames,u=function(t){var n=h+112?e.getHours()+2:0),e):null},_setDate:function(e,t,n){var r=!t,i=e.selectedMonth,s=e.selectedYear,o=this._restrictMinMax(e,this._determineDate(e,t,new Date));e.selectedDay=e.currentDay=o.getDate(),e.drawMonth=e.selectedMonth=e.currentMonth=o.getMonth(),e.drawYear=e.selectedYear=e.currentYear=o.getFullYear(),(i!=e.selectedMonth||s!=e.selectedYear)&&!n&&this._notifyChange(e),this._adjustInstDate(e),e.input&&e.input.val(r?"":this._formatDate(e))},_getDate:function(e){var t=!e.currentYear||e.input&&e.input.val()==""?null:this._daylightSavingAdjust(new Date(e.currentYear,e.currentMonth,e.currentDay));return t},_attachHandlers:function(e){var t=this._get(e,"stepMonths"),n="#"+e.id.replace(/\\\\/g,"\\");e.dpDiv.find("[data-handler]").map(function(){var e={prev:function(){window["DP_jQuery_"+dpuuid].datepicker._adjustDate(n,-t,"M")},next:function(){window["DP_jQuery_"+dpuuid].datepicker._adjustDate(n,+t,"M")},hide:function(){window["DP_jQuery_"+dpuuid].datepicker._hideDatepicker()},today:function(){window["DP_jQuery_"+dpuuid].datepicker._gotoToday(n)},selectDay:function(){return window["DP_jQuery_"+dpuuid].datepicker._selectDay(n,+this.getAttribute("data-month"),+this.getAttribute("data-year"),this),!1},selectMonth:function(){return window["DP_jQuery_"+dpuuid].datepicker._selectMonthYear(n,this,"M"),!1},selectYear:function(){return window["DP_jQuery_"+dpuuid].datepicker._selectMonthYear(n,this,"Y"),!1}};$(this).bind(this.getAttribute("data-event"),e[this.getAttribute("data-handler")])})},_generateHTML:function(e){var t=new Date;t=this._daylightSavingAdjust(new Date(t.getFullYear(),t.getMonth(),t.getDate()));var n=this._get(e,"isRTL"),r=this._get(e,"showButtonPanel"),i=this._get(e,"hideIfNoPrevNext"),s=this._get(e,"navigationAsDateFormat"),o=this._getNumberOfMonths(e),u=this._get(e,"showCurrentAtPos"),a=this._get(e,"stepMonths"),f=o[0]!=1||o[1]!=1,l=this._daylightSavingAdjust(e.currentDay?new Date(e.currentYear,e.currentMonth,e.currentDay):new Date(9999,9,9)),c=this._getMinMaxDate(e,"min"),h=this._getMinMaxDate(e,"max"),p=e.drawMonth-u,d=e.drawYear;p<0&&(p+=12,d--);if(h){var v=this._daylightSavingAdjust(new Date(h.getFullYear(),h.getMonth()-o[0]*o[1]+1,h.getDate()));v=c&&vv)p--,p<0&&(p=11,d--)}e.drawMonth=p,e.drawYear=d;var m=this._get(e,"prevText");m=s?this.formatDate(m,this._daylightSavingAdjust(new Date(d,p-a,1)),this._getFormatConfig(e)):m;var g=this._canAdjustMonth(e,-1,d,p)?''+m+"":i?"":''+m+"",y=this._get(e,"nextText");y=s?this.formatDate(y,this._daylightSavingAdjust(new Date(d,p+a,1)),this._getFormatConfig(e)):y;var b=this._canAdjustMonth(e,1,d,p)?''+y+"":i?"":''+y+"",w=this._get(e,"currentText"),E=this._get(e,"gotoCurrent")&&e.currentDay?l:t;w=s?this.formatDate(w,E,this._getFormatConfig(e)):w;var S=e.inline?"":'",x=r?'
        '+(n?S:"")+(this._isInRange(e,E)?'":"")+(n?"":S)+"
        ":"",T=parseInt(this._get(e,"firstDay"),10);T=isNaN(T)?0:T;var N=this._get(e,"showWeek"),C=this._get(e,"dayNames"),k=this._get(e,"dayNamesShort"),L=this._get(e,"dayNamesMin"),A=this._get(e,"monthNames"),O=this._get(e,"monthNamesShort"),M=this._get(e,"beforeShowDay"),_=this._get(e,"showOtherMonths"),D=this._get(e,"selectOtherMonths"),P=this._get(e,"calculateWeek")||this.iso8601Week,H=this._getDefaultDate(e),B="";for(var j=0;j1)switch(I){case 0:U+=" ui-datepicker-group-first",R=" ui-corner-"+(n?"right":"left");break;case o[1]-1:U+=" ui-datepicker-group-last",R=" ui-corner-"+(n?"left":"right");break;default:U+=" ui-datepicker-group-middle",R=""}U+='">'}U+='
        '+(/all|left/.test(R)&&j==0?n?b:g:"")+(/all|right/.test(R)&&j==0?n?g:b:"")+this._generateMonthYearHeader(e,p,d,c,h,j>0||I>0,A,O)+'
        '+"";var z=N?'":"";for(var W=0;W<7;W++){var X=(W+T)%7;z+="=5?' class="ui-datepicker-week-end"':"")+">"+''+L[X]+""}U+=z+"";var V=this._getDaysInMonth(d,p);d==e.selectedYear&&p==e.selectedMonth&&(e.selectedDay=Math.min(e.selectedDay,V));var J=(this._getFirstDayOfMonth(d,p)-T+7)%7,K=Math.ceil((J+V)/7),Q=f?this.maxRows>K?this.maxRows:K:K;this.maxRows=Q;var G=this._daylightSavingAdjust(new Date(d,p,1-J));for(var Y=0;Y";var Z=N?'":"";for(var W=0;W<7;W++){var et=M?M.apply(e.input?e.input[0]:null,[G]):[!0,""],tt=G.getMonth()!=p,nt=tt&&!D||!et[0]||c&&Gh;Z+='",G.setDate(G.getDate()+1),G=this._daylightSavingAdjust(G)}U+=Z+""}p++,p>11&&(p=0,d++),U+="
        '+this._get(e,"weekHeader")+"
        '+this._get(e,"calculateWeek")(G)+""+(tt&&!_?" ":nt?''+G.getDate()+"":''+G.getDate()+"")+"
        "+(f?""+(o[0]>0&&I==o[1]-1?'
        ':""):""),F+=U}B+=F}return B+=x+($.ui.ie6&&!e.inline?'':""),e._keyEvent=!1,B},_generateMonthYearHeader:function(e,t,n,r,i,s,o,u){var a=this._get(e,"changeMonth"),f=this._get(e,"changeYear"),l=this._get(e,"showMonthAfterYear"),c='
        ',h="";if(s||!a)h+=''+o[t]+"";else{var p=r&&r.getFullYear()==n,d=i&&i.getFullYear()==n;h+='"}l||(c+=h+(s||!a||!f?" ":""));if(!e.yearshtml){e.yearshtml="";if(s||!f)c+=''+n+"";else{var m=this._get(e,"yearRange").split(":"),g=(new Date).getFullYear(),y=function(e){var t=e.match(/c[+-].*/)?n+parseInt(e.substring(1),10):e.match(/[+-].*/)?g+parseInt(e,10):parseInt(e,10);return isNaN(t)?g:t},b=y(m[0]),w=Math.max(b,y(m[1]||""));b=r?Math.max(b,r.getFullYear()):b,w=i?Math.min(w,i.getFullYear()):w,e.yearshtml+='",c+=e.yearshtml,e.yearshtml=null}}return c+=this._get(e,"yearSuffix"),l&&(c+=(s||!a||!f?" ":"")+h),c+="
        ",c},_adjustInstDate:function(e,t,n){var r=e.drawYear+(n=="Y"?t:0),i=e.drawMonth+(n=="M"?t:0),s=Math.min(e.selectedDay,this._getDaysInMonth(r,i))+(n=="D"?t:0),o=this._restrictMinMax(e,this._daylightSavingAdjust(new Date(r,i,s)));e.selectedDay=o.getDate(),e.drawMonth=e.selectedMonth=o.getMonth(),e.drawYear=e.selectedYear=o.getFullYear(),(n=="M"||n=="Y")&&this._notifyChange(e)},_restrictMinMax:function(e,t){var n=this._getMinMaxDate(e,"min"),r=this._getMinMaxDate(e,"max"),i=n&&tr?r:i,i},_notifyChange:function(e){var t=this._get(e,"onChangeMonthYear");t&&t.apply(e.input?e.input[0]:null,[e.selectedYear,e.selectedMonth+1,e])},_getNumberOfMonths:function(e){var t=this._get(e,"numberOfMonths");return t==null?[1,1]:typeof t=="number"?[1,t]:t},_getMinMaxDate:function(e,t){return this._determineDate(e,this._get(e,t+"Date"),null)},_getDaysInMonth:function(e,t){return 32-this._daylightSavingAdjust(new Date(e,t,32)).getDate()},_getFirstDayOfMonth:function(e,t){return(new Date(e,t,1)).getDay()},_canAdjustMonth:function(e,t,n,r){var i=this._getNumberOfMonths(e),s=this._daylightSavingAdjust(new Date(n,r+(t<0?t:i[0]*i[1]),1));return t<0&&s.setDate(this._getDaysInMonth(s.getFullYear(),s.getMonth())),this._isInRange(e,s)},_isInRange:function(e,t){var n=this._getMinMaxDate(e,"min"),r=this._getMinMaxDate(e,"max");return(!n||t.getTime()>=n.getTime())&&(!r||t.getTime()<=r.getTime())},_getFormatConfig:function(e){var t=this._get(e,"shortYearCutoff");return t=typeof t!="string"?t:(new Date).getFullYear()%100+parseInt(t,10),{shortYearCutoff:t,dayNamesShort:this._get(e,"dayNamesShort"),dayNames:this._get(e,"dayNames"),monthNamesShort:this._get(e,"monthNamesShort"),monthNames:this._get(e,"monthNames")}},_formatDate:function(e,t,n,r){t||(e.currentDay=e.selectedDay,e.currentMonth=e.selectedMonth,e.currentYear=e.selectedYear);var i=t?typeof t=="object"?t:this._daylightSavingAdjust(new Date(r,n,t)):this._daylightSavingAdjust(new Date(e.currentYear,e.currentMonth,e.currentDay));return this.formatDate(this._get(e,"dateFormat"),i,this._getFormatConfig(e))}}),$.fn.datepicker=function(e){if(!this.length)return this;$.datepicker.initialized||($(document).mousedown($.datepicker._checkExternalClick).find(document.body).append($.datepicker.dpDiv),$.datepicker.initialized=!0);var t=Array.prototype.slice.call(arguments,1);return typeof e!="string"||e!="isDisabled"&&e!="getDate"&&e!="widget"?e=="option"&&arguments.length==2&&typeof arguments[1]=="string"?$.datepicker["_"+e+"Datepicker"].apply($.datepicker,[this[0]].concat(t)):this.each(function(){typeof e=="string"?$.datepicker["_"+e+"Datepicker"].apply($.datepicker,[this].concat(t)):$.datepicker._attachDatepicker(this,e)}):$.datepicker["_"+e+"Datepicker"].apply($.datepicker,[this[0]].concat(t))},$.datepicker=new Datepicker,$.datepicker.initialized=!1,$.datepicker.uuid=(new Date).getTime(),$.datepicker.version="1.9.2",window["DP_jQuery_"+dpuuid]=$})(jQuery);(function(e,t){var n="ui-dialog ui-widget ui-widget-content ui-corner-all ",r={buttons:!0,height:!0,maxHeight:!0,maxWidth:!0,minHeight:!0,minWidth:!0,width:!0},i={maxHeight:!0,maxWidth:!0,minHeight:!0,minWidth:!0};e.widget("ui.dialog",{version:"1.9.2",options:{autoOpen:!0,buttons:{},closeOnEscape:!0,closeText:"close",dialogClass:"",draggable:!0,hide:null,height:"auto",maxHeight:!1,maxWidth:!1,minHeight:150,minWidth:150,modal:!1,position:{my:"center",at:"center",of:window,collision:"fit",using:function(t){var n=e(this).css(t).offset().top;n<0&&e(this).css("top",t.top-n)}},resizable:!0,show:null,stack:!0,title:"",width:300,zIndex:1e3},_create:function(){this.originalTitle=this.element.attr("title"),typeof this.originalTitle!="string"&&(this.originalTitle=""),this.oldPosition={parent:this.element.parent(),index:this.element.parent().children().index(this.element)},this.options.title=this.options.title||this.originalTitle;var t=this,r=this.options,i=r.title||" ",s,o,u,a,f;s=(this.uiDialog=e("
        ")).addClass(n+r.dialogClass).css({display:"none",outline:0,zIndex:r.zIndex}).attr("tabIndex",-1).keydown(function(n){r.closeOnEscape&&!n.isDefaultPrevented()&&n.keyCode&&n.keyCode===e.ui.keyCode.ESCAPE&&(t.close(n),n.preventDefault())}).mousedown(function(e){t.moveToTop(!1,e)}).appendTo("body"),this.element.show().removeAttr("title").addClass("ui-dialog-content ui-widget-content").appendTo(s),o=(this.uiDialogTitlebar=e("
        ")).addClass("ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix").bind("mousedown",function(){s.focus()}).prependTo(s),u=e("").addClass("ui-dialog-titlebar-close ui-corner-all").attr("role","button").click(function(e){e.preventDefault(),t.close(e)}).appendTo(o),(this.uiDialogTitlebarCloseText=e("")).addClass("ui-icon ui-icon-closethick").text(r.closeText).appendTo(u),a=e("").uniqueId().addClass("ui-dialog-title").html(i).prependTo(o),f=(this.uiDialogButtonPane=e("
        ")).addClass("ui-dialog-buttonpane ui-widget-content ui-helper-clearfix"),(this.uiButtonSet=e("
        ")).addClass("ui-dialog-buttonset").appendTo(f),s.attr({role:"dialog","aria-labelledby":a.attr("id")}),o.find("*").add(o).disableSelection(),this._hoverable(u),this._focusable(u),r.draggable&&e.fn.draggable&&this._makeDraggable(),r.resizable&&e.fn.resizable&&this._makeResizable(),this._createButtons(r.buttons),this._isOpen=!1,e.fn.bgiframe&&s.bgiframe(),this._on(s,{keydown:function(t){if(!r.modal||t.keyCode!==e.ui.keyCode.TAB)return;var n=e(":tabbable",s),i=n.filter(":first"),o=n.filter(":last");if(t.target===o[0]&&!t.shiftKey)return i.focus(1),!1;if(t.target===i[0]&&t.shiftKey)return o.focus(1),!1}})},_init:function(){this.options.autoOpen&&this.open()},_destroy:function(){var e,t=this.oldPosition;this.overlay&&this.overlay.destroy(),this.uiDialog.hide(),this.element.removeClass("ui-dialog-content ui-widget-content").hide().appendTo("body"),this.uiDialog.remove(),this.originalTitle&&this.element.attr("title",this.originalTitle),e=t.parent.children().eq(t.index),e.length&&e[0]!==this.element[0]?e.before(this.element):t.parent.append(this.element)},widget:function(){return this.uiDialog},close:function(t){var n=this,r,i;if(!this._isOpen)return;if(!1===this._trigger("beforeClose",t))return;return this._isOpen=!1,this.overlay&&this.overlay.destroy(),this.options.hide?this._hide(this.uiDialog,this.options.hide,function(){n._trigger("close",t)}):(this.uiDialog.hide(),this._trigger("close",t)),e.ui.dialog.overlay.resize(),this.options.modal&&(r=0,e(".ui-dialog").each(function(){this!==n.uiDialog[0]&&(i=e(this).css("z-index"),isNaN(i)||(r=Math.max(r,i)))}),e.ui.dialog.maxZ=r),this},isOpen:function(){return this._isOpen},moveToTop:function(t,n){var r=this.options,i;return r.modal&&!t||!r.stack&&!r.modal?this._trigger("focus",n):(r.zIndex>e.ui.dialog.maxZ&&(e.ui.dialog.maxZ=r.zIndex),this.overlay&&(e.ui.dialog.maxZ+=1,e.ui.dialog.overlay.maxZ=e.ui.dialog.maxZ,this.overlay.$el.css("z-index",e.ui.dialog.overlay.maxZ)),i={scrollTop:this.element.scrollTop(),scrollLeft:this.element.scrollLeft()},e.ui.dialog.maxZ+=1,this.uiDialog.css("z-index",e.ui.dialog.maxZ),this.element.attr(i),this._trigger("focus",n),this)},open:function(){if(this._isOpen)return;var t,n=this.options,r=this.uiDialog;return this._size(),this._position(n.position),r.show(n.show),this.overlay=n.modal?new e.ui.dialog.overlay(this):null,this.moveToTop(!0),t=this.element.find(":tabbable"),t.length||(t=this.uiDialogButtonPane.find(":tabbable"),t.length||(t=r)),t.eq(0).focus(),this._isOpen=!0,this._trigger("open"),this},_createButtons:function(t){var n=this,r=!1;this.uiDialogButtonPane.remove(),this.uiButtonSet.empty(),typeof t=="object"&&t!==null&&e.each(t,function(){return!(r=!0)}),r?(e.each(t,function(t,r){var i,s;r=e.isFunction(r)?{click:r,text:t}:r,r=e.extend({type:"button"},r),s=r.click,r.click=function(){s.apply(n.element[0],arguments)},i=e("",r).appendTo(n.uiButtonSet),e.fn.button&&i.button()}),this.uiDialog.addClass("ui-dialog-buttons"),this.uiDialogButtonPane.appendTo(this.uiDialog)):this.uiDialog.removeClass("ui-dialog-buttons")},_makeDraggable:function(){function r(e){return{position:e.position,offset:e.offset}}var t=this,n=this.options;this.uiDialog.draggable({cancel:".ui-dialog-content, .ui-dialog-titlebar-close",handle:".ui-dialog-titlebar",containment:"document",start:function(n,i){e(this).addClass("ui-dialog-dragging"),t._trigger("dragStart",n,r(i))},drag:function(e,n){t._trigger("drag",e,r(n))},stop:function(i,s){n.position=[s.position.left-t.document.scrollLeft(),s.position.top-t.document.scrollTop()],e(this).removeClass("ui-dialog-dragging"),t._trigger("dragStop",i,r(s)),e.ui.dialog.overlay.resize()}})},_makeResizable:function(n){function u(e){return{originalPosition:e.originalPosition,originalSize:e.originalSize,position:e.position,size:e.size}}n=n===t?this.options.resizable:n;var r=this,i=this.options,s=this.uiDialog.css("position"),o=typeof n=="string"?n:"n,e,s,w,se,sw,ne,nw";this.uiDialog.resizable({cancel:".ui-dialog-content",containment:"document",alsoResize:this.element,maxWidth:i.maxWidth,maxHeight:i.maxHeight,minWidth:i.minWidth,minHeight:this._minHeight(),handles:o,start:function(t,n){e(this).addClass("ui-dialog-resizing"),r._trigger("resizeStart",t,u(n))},resize:function(e,t){r._trigger("resize",e,u(t))},stop:function(t,n){e(this).removeClass("ui-dialog-resizing"),i.height=e(this).height(),i.width=e(this).width(),r._trigger("resizeStop",t,u(n)),e.ui.dialog.overlay.resize()}}).css("position",s).find(".ui-resizable-se").addClass("ui-icon ui-icon-grip-diagonal-se")},_minHeight:function(){var e=this.options;return e.height==="auto"?e.minHeight:Math.min(e.minHeight,e.height)},_position:function(t){var n=[],r=[0,0],i;if(t){if(typeof t=="string"||typeof t=="object"&&"0"in t)n=t.split?t.split(" "):[t[0],t[1]],n.length===1&&(n[1]=n[0]),e.each(["left","top"],function(e,t){+n[e]===n[e]&&(r[e]=n[e],n[e]=t)}),t={my:n[0]+(r[0]<0?r[0]:"+"+r[0])+" "+n[1]+(r[1]<0?r[1]:"+"+r[1]),at:n.join(" ")};t=e.extend({},e.ui.dialog.prototype.options.position,t)}else t=e.ui.dialog.prototype.options.position;i=this.uiDialog.is(":visible"),i||this.uiDialog.show(),this.uiDialog.position(t),i||this.uiDialog.hide()},_setOptions:function(t){var n=this,s={},o=!1;e.each(t,function(e,t){n._setOption(e,t),e in r&&(o=!0),e in i&&(s[e]=t)}),o&&this._size(),this.uiDialog.is(":data(resizable)")&&this.uiDialog.resizable("option",s)},_setOption:function(t,r){var i,s,o=this.uiDialog;switch(t){case"buttons":this._createButtons(r);break;case"closeText":this.uiDialogTitlebarCloseText.text(""+r);break;case"dialogClass":o.removeClass(this.options.dialogClass).addClass(n+r);break;case"disabled":r?o.addClass("ui-dialog-disabled"):o.removeClass("ui-dialog-disabled");break;case"draggable":i=o.is(":data(draggable)"),i&&!r&&o.draggable("destroy"),!i&&r&&this._makeDraggable();break;case"position":this._position(r);break;case"resizable":s=o.is(":data(resizable)"),s&&!r&&o.resizable("destroy"),s&&typeof r=="string"&&o.resizable("option","handles",r),!s&&r!==!1&&this._makeResizable(r);break;case"title":e(".ui-dialog-title",this.uiDialogTitlebar).html(""+(r||" "))}this._super(t,r)},_size:function(){var t,n,r,i=this.options,s=this.uiDialog.is(":visible");this.element.show().css({width:"auto",minHeight:0,height:0}),i.minWidth>i.width&&(i.width=i.minWidth),t=this.uiDialog.css({height:"auto",width:i.width}).outerHeight(),n=Math.max(0,i.minHeight-t),i.height==="auto"?e.support.minHeight?this.element.css({minHeight:n,height:"auto"}):(this.uiDialog.show(),r=this.element.css("height","auto").height(),s||this.uiDialog.hide(),this.element.height(Math.max(r,n))):this.element.height(Math.max(i.height-t,0)),this.uiDialog.is(":data(resizable)")&&this.uiDialog.resizable("option","minHeight",this._minHeight())}}),e.extend(e.ui.dialog,{uuid:0,maxZ:0,getTitleId:function(e){var t=e.attr("id");return t||(this.uuid+=1,t=this.uuid),"ui-dialog-title-"+t},overlay:function(t){this.$el=e.ui.dialog.overlay.create(t)}}),e.extend(e.ui.dialog.overlay,{instances:[],oldInstances:[],maxZ:0,events:e.map("focus,mousedown,mouseup,keydown,keypress,click".split(","),function(e){return e+".dialog-overlay"}).join(" "),create:function(t){this.instances.length===0&&(setTimeout(function(){e.ui.dialog.overlay.instances.length&&e(document).bind(e.ui.dialog.overlay.events,function(t){if(e(t.target).zIndex()").addClass("ui-widget-overlay");return e(document).bind("keydown.dialog-overlay",function(r){var i=e.ui.dialog.overlay.instances;i.length!==0&&i[i.length-1]===n&&t.options.closeOnEscape&&!r.isDefaultPrevented()&&r.keyCode&&r.keyCode===e.ui.keyCode.ESCAPE&&(t.close(r),r.preventDefault())}),n.appendTo(document.body).css({width:this.width(),height:this.height()}),e.fn.bgiframe&&n.bgiframe(),this.instances.push(n),n},destroy:function(t){var n=e.inArray(t,this.instances),r=0;n!==-1&&this.oldInstances.push(this.instances.splice(n,1)[0]),this.instances.length===0&&e([document,window]).unbind(".dialog-overlay"),t.height(0).width(0).remove(),e.each(this.instances,function(){r=Math.max(r,this.css("z-index"))}),this.maxZ=r},height:function(){var t,n;return e.ui.ie?(t=Math.max(document.documentElement.scrollHeight,document.body.scrollHeight),n=Math.max(document.documentElement.offsetHeight,document.body.offsetHeight),t
        ').css({width:this.offsetWidth+"px",height:this.offsetHeight+"px",position:"absolute",opacity:"0.001",zIndex:1e3}).css(e(this).offset()).appendTo("body")}),!0):!1)},_mouseStart:function(t){var n=this.options;return this.helper=this._createHelper(t),this.helper.addClass("ui-draggable-dragging"),this._cacheHelperProportions(),e.ui.ddmanager&&(e.ui.ddmanager.current=this),this._cacheMargins(),this.cssPosition=this.helper.css("position"),this.scrollParent=this.helper.scrollParent(),this.offset=this.positionAbs=this.element.offset(),this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left},e.extend(this.offset,{click:{left:t.pageX-this.offset.left,top:t.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()}),this.originalPosition=this.position=this._generatePosition(t),this.originalPageX=t.pageX,this.originalPageY=t.pageY,n.cursorAt&&this._adjustOffsetFromHelper(n.cursorAt),n.containment&&this._setContainment(),this._trigger("start",t)===!1?(this._clear(),!1):(this._cacheHelperProportions(),e.ui.ddmanager&&!n.dropBehaviour&&e.ui.ddmanager.prepareOffsets(this,t),this._mouseDrag(t,!0),e.ui.ddmanager&&e.ui.ddmanager.dragStart(this,t),!0)},_mouseDrag:function(t,n){this.position=this._generatePosition(t),this.positionAbs=this._convertPositionTo("absolute");if(!n){var r=this._uiHash();if(this._trigger("drag",t,r)===!1)return this._mouseUp({}),!1;this.position=r.position}if(!this.options.axis||this.options.axis!="y")this.helper[0].style.left=this.position.left+"px";if(!this.options.axis||this.options.axis!="x")this.helper[0].style.top=this.position.top+"px";return e.ui.ddmanager&&e.ui.ddmanager.drag(this,t),!1},_mouseStop:function(t){var n=!1;e.ui.ddmanager&&!this.options.dropBehaviour&&(n=e.ui.ddmanager.drop(this,t)),this.dropped&&(n=this.dropped,this.dropped=!1);var r=this.element[0],i=!1;while(r&&(r=r.parentNode))r==document&&(i=!0);if(!i&&this.options.helper==="original")return!1;if(this.options.revert=="invalid"&&!n||this.options.revert=="valid"&&n||this.options.revert===!0||e.isFunction(this.options.revert)&&this.options.revert.call(this.element,n)){var s=this;e(this.helper).animate(this.originalPosition,parseInt(this.options.revertDuration,10),function(){s._trigger("stop",t)!==!1&&s._clear()})}else this._trigger("stop",t)!==!1&&this._clear();return!1},_mouseUp:function(t){return e("div.ui-draggable-iframeFix").each(function(){this.parentNode.removeChild(this)}),e.ui.ddmanager&&e.ui.ddmanager.dragStop(this,t),e.ui.mouse.prototype._mouseUp.call(this,t)},cancel:function(){return this.helper.is(".ui-draggable-dragging")?this._mouseUp({}):this._clear(),this},_getHandle:function(t){var n=!this.options.handle||!e(this.options.handle,this.element).length?!0:!1;return e(this.options.handle,this.element).find("*").andSelf().each(function(){this==t.target&&(n=!0)}),n},_createHelper:function(t){var n=this.options,r=e.isFunction(n.helper)?e(n.helper.apply(this.element[0],[t])):n.helper=="clone"?this.element.clone().removeAttr("id"):this.element;return r.parents("body").length||r.appendTo(n.appendTo=="parent"?this.element[0].parentNode:n.appendTo),r[0]!=this.element[0]&&!/(fixed|absolute)/.test(r.css("position"))&&r.css("position","absolute"),r},_adjustOffsetFromHelper:function(t){typeof t=="string"&&(t=t.split(" ")),e.isArray(t)&&(t={left:+t[0],top:+t[1]||0}),"left"in t&&(this.offset.click.left=t.left+this.margins.left),"right"in t&&(this.offset.click.left=this.helperProportions.width-t.right+this.margins.left),"top"in t&&(this.offset.click.top=t.top+this.margins.top),"bottom"in t&&(this.offset.click.top=this.helperProportions.height-t.bottom+this.margins.top)},_getParentOffset:function(){this.offsetParent=this.helper.offsetParent();var t=this.offsetParent.offset();this.cssPosition=="absolute"&&this.scrollParent[0]!=document&&e.contains(this.scrollParent[0],this.offsetParent[0])&&(t.left+=this.scrollParent.scrollLeft(),t.top+=this.scrollParent.scrollTop());if(this.offsetParent[0]==document.body||this.offsetParent[0].tagName&&this.offsetParent[0].tagName.toLowerCase()=="html"&&e.ui.ie)t={top:0,left:0};return{top:t.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:t.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if(this.cssPosition=="relative"){var e=this.element.position();return{top:e.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:e.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.element.css("marginLeft"),10)||0,top:parseInt(this.element.css("marginTop"),10)||0,right:parseInt(this.element.css("marginRight"),10)||0,bottom:parseInt(this.element.css("marginBottom"),10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var t=this.options;t.containment=="parent"&&(t.containment=this.helper[0].parentNode);if(t.containment=="document"||t.containment=="window")this.containment=[t.containment=="document"?0:e(window).scrollLeft()-this.offset.relative.left-this.offset.parent.left,t.containment=="document"?0:e(window).scrollTop()-this.offset.relative.top-this.offset.parent.top,(t.containment=="document"?0:e(window).scrollLeft())+e(t.containment=="document"?document:window).width()-this.helperProportions.width-this.margins.left,(t.containment=="document"?0:e(window).scrollTop())+(e(t.containment=="document"?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top];if(!/^(document|window|parent)$/.test(t.containment)&&t.containment.constructor!=Array){var n=e(t.containment),r=n[0];if(!r)return;var i=n.offset(),s=e(r).css("overflow")!="hidden";this.containment=[(parseInt(e(r).css("borderLeftWidth"),10)||0)+(parseInt(e(r).css("paddingLeft"),10)||0),(parseInt(e(r).css("borderTopWidth"),10)||0)+(parseInt(e(r).css("paddingTop"),10)||0),(s?Math.max(r.scrollWidth,r.offsetWidth):r.offsetWidth)-(parseInt(e(r).css("borderLeftWidth"),10)||0)-(parseInt(e(r).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left-this.margins.right,(s?Math.max(r.scrollHeight,r.offsetHeight):r.offsetHeight)-(parseInt(e(r).css("borderTopWidth"),10)||0)-(parseInt(e(r).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top-this.margins.bottom],this.relative_container=n}else t.containment.constructor==Array&&(this.containment=t.containment)},_convertPositionTo:function(t,n){n||(n=this.position);var r=t=="absolute"?1:-1,i=this.options,s=this.cssPosition!="absolute"||this.scrollParent[0]!=document&&!!e.contains(this.scrollParent[0],this.offsetParent[0])?this.scrollParent:this.offsetParent,o=/(html|body)/i.test(s[0].tagName);return{top:n.top+this.offset.relative.top*r+this.offset.parent.top*r-(this.cssPosition=="fixed"?-this.scrollParent.scrollTop():o?0:s.scrollTop())*r,left:n.left+this.offset.relative.left*r+this.offset.parent.left*r-(this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():o?0:s.scrollLeft())*r}},_generatePosition:function(t){var n=this.options,r=this.cssPosition!="absolute"||this.scrollParent[0]!=document&&!!e.contains(this.scrollParent[0],this.offsetParent[0])?this.scrollParent:this.offsetParent,i=/(html|body)/i.test(r[0].tagName),s=t.pageX,o=t.pageY;if(this.originalPosition){var u;if(this.containment){if(this.relative_container){var a=this.relative_container.offset();u=[this.containment[0]+a.left,this.containment[1]+a.top,this.containment[2]+a.left,this.containment[3]+a.top]}else u=this.containment;t.pageX-this.offset.click.leftu[2]&&(s=u[2]+this.offset.click.left),t.pageY-this.offset.click.top>u[3]&&(o=u[3]+this.offset.click.top)}if(n.grid){var f=n.grid[1]?this.originalPageY+Math.round((o-this.originalPageY)/n.grid[1])*n.grid[1]:this.originalPageY;o=u?f-this.offset.click.topu[3]?f-this.offset.click.topu[2]?l-this.offset.click.left=0;l--){var c=r.snapElements[l].left,h=c+r.snapElements[l].width,p=r.snapElements[l].top,d=p+r.snapElements[l].height;if(!(c-s=l&&o<=c||u>=l&&u<=c||oc)&&(i>=a&&i<=f||s>=a&&s<=f||if);default:return!1}},e.ui.ddmanager={current:null,droppables:{"default":[]},prepareOffsets:function(t,n){var r=e.ui.ddmanager.droppables[t.options.scope]||[],i=n?n.type:null,s=(t.currentItem||t.element).find(":data(droppable)").andSelf();e:for(var o=0;oe?0:r.max")[0],c,h=t.each;l.style.cssText="background-color:rgba(1,1,1,.5)",f.rgba=l.style.backgroundColor.indexOf("rgba")>-1,h(u,function(e,t){t.cache="_"+e,t.props.alpha={idx:3,type:"percent",def:1}}),o.fn=t.extend(o.prototype,{parse:function(r,i,s,a){if(r===n)return this._rgba=[null,null,null,null],this;if(r.jquery||r.nodeType)r=t(r).css(i),i=n;var f=this,l=t.type(r),v=this._rgba=[];i!==n&&(r=[r,i,s,a],l="array");if(l==="string")return this.parse(d(r)||c._default);if(l==="array")return h(u.rgba.props,function(e,t){v[t.idx]=p(r[t.idx],t)}),this;if(l==="object")return r instanceof o?h(u,function(e,t){r[t.cache]&&(f[t.cache]=r[t.cache].slice())}):h(u,function(t,n){var i=n.cache;h(n.props,function(e,t){if(!f[i]&&n.to){if(e==="alpha"||r[e]==null)return;f[i]=n.to(f._rgba)}f[i][t.idx]=p(r[e],t,!0)}),f[i]&&e.inArray(null,f[i].slice(0,3))<0&&(f[i][3]=1,n.from&&(f._rgba=n.from(f[i])))}),this},is:function(e){var t=o(e),n=!0,r=this;return h(u,function(e,i){var s,o=t[i.cache];return o&&(s=r[i.cache]||i.to&&i.to(r._rgba)||[],h(i.props,function(e,t){if(o[t.idx]!=null)return n=o[t.idx]===s[t.idx],n})),n}),n},_space:function(){var e=[],t=this;return h(u,function(n,r){t[r.cache]&&e.push(n)}),e.pop()},transition:function(e,t){var n=o(e),r=n._space(),i=u[r],s=this.alpha()===0?o("transparent"):this,f=s[i.cache]||i.to(s._rgba),l=f.slice();return n=n[i.cache],h(i.props,function(e,r){var i=r.idx,s=f[i],o=n[i],u=a[r.type]||{};if(o===null)return;s===null?l[i]=o:(u.mod&&(o-s>u.mod/2?s+=u.mod:s-o>u.mod/2&&(s-=u.mod)),l[i]=p((o-s)*t+s,r))}),this[r](l)},blend:function(e){if(this._rgba[3]===1)return this;var n=this._rgba.slice(),r=n.pop(),i=o(e)._rgba;return o(t.map(n,function(e,t){return(1-r)*i[t]+r*e}))},toRgbaString:function(){var e="rgba(",n=t.map(this._rgba,function(e,t){return e==null?t>2?1:0:e});return n[3]===1&&(n.pop(),e="rgb("),e+n.join()+")"},toHslaString:function(){var e="hsla(",n=t.map(this.hsla(),function(e,t){return e==null&&(e=t>2?1:0),t&&t<3&&(e=Math.round(e*100)+"%"),e});return n[3]===1&&(n.pop(),e="hsl("),e+n.join()+")"},toHexString:function(e){var n=this._rgba.slice(),r=n.pop();return e&&n.push(~~(r*255)),"#"+t.map(n,function(e){return e=(e||0).toString(16),e.length===1?"0"+e:e}).join("")},toString:function(){return this._rgba[3]===0?"transparent":this.toRgbaString()}}),o.fn.parse.prototype=o.fn,u.hsla.to=function(e){if(e[0]==null||e[1]==null||e[2]==null)return[null,null,null,e[3]];var t=e[0]/255,n=e[1]/255,r=e[2]/255,i=e[3],s=Math.max(t,n,r),o=Math.min(t,n,r),u=s-o,a=s+o,f=a*.5,l,c;return o===s?l=0:t===s?l=60*(n-r)/u+360:n===s?l=60*(r-t)/u+120:l=60*(t-n)/u+240,f===0||f===1?c=f:f<=.5?c=u/a:c=u/(2-a),[Math.round(l)%360,c,f,i==null?1:i]},u.hsla.from=function(e){if(e[0]==null||e[1]==null||e[2]==null)return[null,null,null,e[3]];var t=e[0]/360,n=e[1],r=e[2],i=e[3],s=r<=.5?r*(1+n):r+n-r*n,o=2*r-s;return[Math.round(v(o,s,t+1/3)*255),Math.round(v(o,s,t)*255),Math.round(v(o,s,t-1/3)*255),i]},h(u,function(e,r){var s=r.props,u=r.cache,a=r.to,f=r.from;o.fn[e]=function(e){a&&!this[u]&&(this[u]=a(this._rgba));if(e===n)return this[u].slice();var r,i=t.type(e),l=i==="array"||i==="object"?e:arguments,c=this[u].slice();return h(s,function(e,t){var n=l[i==="object"?e:t.idx];n==null&&(n=c[t.idx]),c[t.idx]=p(n,t)}),f?(r=o(f(c)),r[u]=c,r):o(c)},h(s,function(n,r){if(o.fn[n])return;o.fn[n]=function(s){var o=t.type(s),u=n==="alpha"?this._hsla?"hsla":"rgba":e,a=this[u](),f=a[r.idx],l;return o==="undefined"?f:(o==="function"&&(s=s.call(this,f),o=t.type(s)),s==null&&r.empty?this:(o==="string"&&(l=i.exec(s),l&&(s=f+parseFloat(l[2])*(l[1]==="+"?1:-1))),a[r.idx]=s,this[u](a)))}})}),h(r,function(e,n){t.cssHooks[n]={set:function(e,r){var i,s,u="";if(t.type(r)!=="string"||(i=d(r))){r=o(i||r);if(!f.rgba&&r._rgba[3]!==1){s=n==="backgroundColor"?e.parentNode:e;while((u===""||u==="transparent")&&s&&s.style)try{u=t.css(s,"backgroundColor"),s=s.parentNode}catch(a){}r=r.blend(u&&u!=="transparent"?u:"_default")}r=r.toRgbaString()}try{e.style[n]=r}catch(l){}}},t.fx.step[n]=function(e){e.colorInit||(e.start=o(e.elem,n),e.end=o(e.end),e.colorInit=!0),t.cssHooks[n].set(e.elem,e.start.transition(e.end,e.pos))}}),t.cssHooks.borderColor={expand:function(e){var t={};return h(["Top","Right","Bottom","Left"],function(n,r){t["border"+r+"Color"]=e}),t}},c=t.Color.names={aqua:"#00ffff",black:"#000000",blue:"#0000ff",fuchsia:"#ff00ff",gray:"#808080",green:"#008000",lime:"#00ff00",maroon:"#800000",navy:"#000080",olive:"#808000",purple:"#800080",red:"#ff0000",silver:"#c0c0c0",teal:"#008080",white:"#ffffff",yellow:"#ffff00",transparent:[null,null,null,0],_default:"#ffffff"}}(jQuery),function(){function i(){var t=this.ownerDocument.defaultView?this.ownerDocument.defaultView.getComputedStyle(this,null):this.currentStyle,n={},r,i;if(t&&t.length&&t[0]&&t[t[0]]){i=t.length;while(i--)r=t[i],typeof t[r]=="string"&&(n[e.camelCase(r)]=t[r])}else for(r in t)typeof t[r]=="string"&&(n[r]=t[r]);return n}function s(t,n){var i={},s,o;for(s in n)o=n[s],t[s]!==o&&!r[s]&&(e.fx.step[s]||!isNaN(parseFloat(o)))&&(i[s]=o);return i}var n=["add","remove","toggle"],r={border:1,borderBottom:1,borderColor:1,borderLeft:1,borderRight:1,borderTop:1,borderWidth:1,margin:1,padding:1};e.each(["borderLeftStyle","borderRightStyle","borderBottomStyle","borderTopStyle"],function(t,n){e.fx.step[n]=function(e){if(e.end!=="none"&&!e.setAttr||e.pos===1&&!e.setAttr)jQuery.style(e.elem,n,e.end),e.setAttr=!0}}),e.effects.animateClass=function(t,r,o,u){var a=e.speed(r,o,u);return this.queue(function(){var r=e(this),o=r.attr("class")||"",u,f=a.children?r.find("*").andSelf():r;f=f.map(function(){var t=e(this);return{el:t,start:i.call(this)}}),u=function(){e.each(n,function(e,n){t[n]&&r[n+"Class"](t[n])})},u(),f=f.map(function(){return this.end=i.call(this.el[0]),this.diff=s(this.start,this.end),this}),r.attr("class",o),f=f.map(function(){var t=this,n=e.Deferred(),r=jQuery.extend({},a,{queue:!1,complete:function(){n.resolve(t)}});return this.el.animate(this.diff,r),n.promise()}),e.when.apply(e,f.get()).done(function(){u(),e.each(arguments,function(){var t=this.el;e.each(this.diff,function(e){t.css(e,"")})}),a.complete.call(r[0])})})},e.fn.extend({_addClass:e.fn.addClass,addClass:function(t,n,r,i){return n?e.effects.animateClass.call(this,{add:t},n,r,i):this._addClass(t)},_removeClass:e.fn.removeClass,removeClass:function(t,n,r,i){return n?e.effects.animateClass.call(this,{remove:t},n,r,i):this._removeClass(t)},_toggleClass:e.fn.toggleClass,toggleClass:function(n,r,i,s,o){return typeof r=="boolean"||r===t?i?e.effects.animateClass.call(this,r?{add:n}:{remove:n},i,s,o):this._toggleClass(n,r):e.effects.animateClass.call(this,{toggle:n},r,i,s)},switchClass:function(t,n,r,i,s){return e.effects.animateClass.call(this,{add:n,remove:t},r,i,s)}})}(),function(){function i(t,n,r,i){e.isPlainObject(t)&&(n=t,t=t.effect),t={effect:t},n==null&&(n={}),e.isFunction(n)&&(i=n,r=null,n={});if(typeof n=="number"||e.fx.speeds[n])i=r,r=n,n={};return e.isFunction(r)&&(i=r,r=null),n&&e.extend(t,n),r=r||n.duration,t.duration=e.fx.off?0:typeof r=="number"?r:r in e.fx.speeds?e.fx.speeds[r]:e.fx.speeds._default,t.complete=i||n.complete,t}function s(t){return!t||typeof t=="number"||e.fx.speeds[t]?!0:typeof t=="string"&&!e.effects.effect[t]?n&&e.effects[t]?!1:!0:!1}e.extend(e.effects,{version:"1.9.2",save:function(e,t){for(var n=0;n
        ").addClass("ui-effects-wrapper").css({fontSize:"100%",background:"transparent",border:"none",margin:0,padding:0}),i={width:t.width(),height:t.height()},s=document.activeElement;try{s.id}catch(o){s=document.body}return t.wrap(r),(t[0]===s||e.contains(t[0],s))&&e(s).focus(),r=t.parent(),t.css("position")==="static"?(r.css({position:"relative"}),t.css({position:"relative"})):(e.extend(n,{position:t.css("position"),zIndex:t.css("z-index")}),e.each(["top","left","bottom","right"],function(e,r){n[r]=t.css(r),isNaN(parseInt(n[r],10))&&(n[r]="auto")}),t.css({position:"relative",top:0,left:0,right:"auto",bottom:"auto"})),t.css(i),r.css(n).show()},removeWrapper:function(t){var n=document.activeElement;return t.parent().is(".ui-effects-wrapper")&&(t.parent().replaceWith(t),(t[0]===n||e.contains(t[0],n))&&e(n).focus()),t},setTransition:function(t,n,r,i){return i=i||{},e.each(n,function(e,n){var s=t.cssUnit(n);s[0]>0&&(i[n]=s[0]*r+s[1])}),i}}),e.fn.extend({effect:function(){function a(n){function u(){e.isFunction(i)&&i.call(r[0]),e.isFunction(n)&&n()}var r=e(this),i=t.complete,s=t.mode;(r.is(":hidden")?s==="hide":s==="show")?u():o.call(r[0],t,u)}var t=i.apply(this,arguments),r=t.mode,s=t.queue,o=e.effects.effect[t.effect],u=!o&&n&&e.effects[t.effect];return e.fx.off||!o&&!u?r?this[r](t.duration,t.complete):this.each(function(){t.complete&&t.complete.call(this)}):o?s===!1?this.each(a):this.queue(s||"fx",a):u.call(this,{options:t,duration:t.duration,callback:t.complete,mode:t.mode})},_show:e.fn.show,show:function(e){if(s(e))return this._show.apply(this,arguments);var t=i.apply(this,arguments);return t.mode="show",this.effect.call(this,t)},_hide:e.fn.hide,hide:function(e){if(s(e))return this._hide.apply(this,arguments);var t=i.apply(this,arguments);return t.mode="hide",this.effect.call(this,t)},__toggle:e.fn.toggle,toggle:function(t){if(s(t)||typeof t=="boolean"||e.isFunction(t))return this.__toggle.apply(this,arguments);var n=i.apply(this,arguments);return n.mode="toggle",this.effect.call(this,n)},cssUnit:function(t){var n=this.css(t),r=[];return e.each(["em","px","%","pt"],function(e,t){n.indexOf(t)>0&&(r=[parseFloat(n),t])}),r}})}(),function(){var t={};e.each(["Quad","Cubic","Quart","Quint","Expo"],function(e,n){t[n]=function(t){return Math.pow(t,e+2)}}),e.extend(t,{Sine:function(e){return 1-Math.cos(e*Math.PI/2)},Circ:function(e){return 1-Math.sqrt(1-e*e)},Elastic:function(e){return e===0||e===1?e:-Math.pow(2,8*(e-1))*Math.sin(((e-1)*80-7.5)*Math.PI/15)},Back:function(e){return e*e*(3*e-2)},Bounce:function(e){var t,n=4;while(e<((t=Math.pow(2,--n))-1)/11);return 1/Math.pow(4,3-n)-7.5625*Math.pow((t*3-2)/22-e,2)}}),e.each(t,function(t,n){e.easing["easeIn"+t]=n,e.easing["easeOut"+t]=function(e){return 1-n(1-e)},e.easing["easeInOut"+t]=function(e){return e<.5?n(e*2)/2:1-n(e*-2+2)/2}})}()}(jQuery);(function(e,t){var n=/up|down|vertical/,r=/up|left|vertical|horizontal/;e.effects.effect.blind=function(t,i){var s=e(this),o=["position","top","bottom","left","right","height","width"],u=e.effects.setMode(s,t.mode||"hide"),a=t.direction||"up",f=n.test(a),l=f?"height":"width",c=f?"top":"left",h=r.test(a),p={},d=u==="show",v,m,g;s.parent().is(".ui-effects-wrapper")?e.effects.save(s.parent(),o):e.effects.save(s,o),s.show(),v=e.effects.createWrapper(s).css({overflow:"hidden"}),m=v[l](),g=parseFloat(v.css(c))||0,p[l]=d?m:0,h||(s.css(f?"bottom":"right",0).css(f?"top":"left","auto").css({position:"absolute"}),p[c]=d?g:m+g),d&&(v.css(l,0),h||v.css(c,g+m)),v.animate(p,{duration:t.duration,easing:t.easing,queue:!1,complete:function(){u==="hide"&&s.hide(),e.effects.restore(s,o),e.effects.removeWrapper(s),i()}})}})(jQuery);(function(e,t){e.effects.effect.bounce=function(t,n){var r=e(this),i=["position","top","bottom","left","right","height","width"],s=e.effects.setMode(r,t.mode||"effect"),o=s==="hide",u=s==="show",a=t.direction||"up",f=t.distance,l=t.times||5,c=l*2+(u||o?1:0),h=t.duration/c,p=t.easing,d=a==="up"||a==="down"?"top":"left",v=a==="up"||a==="left",m,g,y,b=r.queue(),w=b.length;(u||o)&&i.push("opacity"),e.effects.save(r,i),r.show(),e.effects.createWrapper(r),f||(f=r[d==="top"?"outerHeight":"outerWidth"]()/3),u&&(y={opacity:1},y[d]=0,r.css("opacity",0).css(d,v?-f*2:f*2).animate(y,h,p)),o&&(f/=Math.pow(2,l-1)),y={},y[d]=0;for(m=0;m1&&b.splice.apply(b,[1,0].concat(b.splice(w,c+1))),r.dequeue()}})(jQuery);(function(e,t){e.effects.effect.clip=function(t,n){var r=e(this),i=["position","top","bottom","left","right","height","width"],s=e.effects.setMode(r,t.mode||"hide"),o=s==="show",u=t.direction||"vertical",a=u==="vertical",f=a?"height":"width",l=a?"top":"left",c={},h,p,d;e.effects.save(r,i),r.show(),h=e.effects.createWrapper(r).css({overflow:"hidden"}),p=r[0].tagName==="IMG"?h:r,d=p[f](),o&&(p.css(f,0),p.css(l,d/2)),c[f]=o?d:0,c[l]=o?0:d/2,p.animate(c,{queue:!1,duration:t.duration,easing:t.easing,complete:function(){o||r.hide(),e.effects.restore(r,i),e.effects.removeWrapper(r),n()}})}})(jQuery);(function(e,t){e.effects.effect.drop=function(t,n){var r=e(this),i=["position","top","bottom","left","right","opacity","height","width"],s=e.effects.setMode(r,t.mode||"hide"),o=s==="show",u=t.direction||"left",a=u==="up"||u==="down"?"top":"left",f=u==="up"||u==="left"?"pos":"neg",l={opacity:o?1:0},c;e.effects.save(r,i),r.show(),e.effects.createWrapper(r),c=t.distance||r[a==="top"?"outerHeight":"outerWidth"](!0)/2,o&&r.css("opacity",0).css(a,f==="pos"?-c:c),l[a]=(o?f==="pos"?"+=":"-=":f==="pos"?"-=":"+=")+c,r.animate(l,{queue:!1,duration:t.duration,easing:t.easing,complete:function(){s==="hide"&&r.hide(),e.effects.restore(r,i),e.effects.removeWrapper(r),n()}})}})(jQuery);(function(e,t){e.effects.effect.explode=function(t,n){function y(){c.push(this),c.length===r*i&&b()}function b(){s.css({visibility:"visible"}),e(c).remove(),u||s.hide(),n()}var r=t.pieces?Math.round(Math.sqrt(t.pieces)):3,i=r,s=e(this),o=e.effects.setMode(s,t.mode||"hide"),u=o==="show",a=s.show().css("visibility","hidden").offset(),f=Math.ceil(s.outerWidth()/i),l=Math.ceil(s.outerHeight()/r),c=[],h,p,d,v,m,g;for(h=0;h
        ").css({position:"absolute",visibility:"visible",left:-p*f,top:-h*l}).parent().addClass("ui-effects-explode").css({position:"absolute",overflow:"hidden",width:f,height:l,left:d+(u?m*f:0),top:v+(u?g*l:0),opacity:u?0:1}).animate({left:d+(u?0:m*f),top:v+(u?0:g*l),opacity:u?1:0},t.duration||500,t.easing,y)}}})(jQuery);(function(e,t){e.effects.effect.fade=function(t,n){var r=e(this),i=e.effects.setMode(r,t.mode||"toggle");r.animate({opacity:i},{queue:!1,duration:t.duration,easing:t.easing,complete:n})}})(jQuery);(function(e,t){e.effects.effect.fold=function(t,n){var r=e(this),i=["position","top","bottom","left","right","height","width"],s=e.effects.setMode(r,t.mode||"hide"),o=s==="show",u=s==="hide",a=t.size||15,f=/([0-9]+)%/.exec(a),l=!!t.horizFirst,c=o!==l,h=c?["width","height"]:["height","width"],p=t.duration/2,d,v,m={},g={};e.effects.save(r,i),r.show(),d=e.effects.createWrapper(r).css({overflow:"hidden"}),v=c?[d.width(),d.height()]:[d.height(),d.width()],f&&(a=parseInt(f[1],10)/100*v[u?0:1]),o&&d.css(l?{height:0,width:a}:{height:a,width:0}),m[h[0]]=o?v[0]:a,g[h[1]]=o?v[1]:0,d.animate(m,p,t.easing).animate(g,p,t.easing,function(){u&&r.hide(),e.effects.restore(r,i),e.effects.removeWrapper(r),n()})}})(jQuery);(function(e,t){e.effects.effect.highlight=function(t,n){var r=e(this),i=["backgroundImage","backgroundColor","opacity"],s=e.effects.setMode(r,t.mode||"show"),o={backgroundColor:r.css("backgroundColor")};s==="hide"&&(o.opacity=0),e.effects.save(r,i),r.show().css({backgroundImage:"none",backgroundColor:t.color||"#ffff99"}).animate(o,{queue:!1,duration:t.duration,easing:t.easing,complete:function(){s==="hide"&&r.hide(),e.effects.restore(r,i),n()}})}})(jQuery);(function(e,t){e.effects.effect.pulsate=function(t,n){var r=e(this),i=e.effects.setMode(r,t.mode||"show"),s=i==="show",o=i==="hide",u=s||i==="hide",a=(t.times||5)*2+(u?1:0),f=t.duration/a,l=0,c=r.queue(),h=c.length,p;if(s||!r.is(":visible"))r.css("opacity",0).show(),l=1;for(p=1;p1&&c.splice.apply(c,[1,0].concat(c.splice(h,a+1))),r.dequeue()}})(jQuery);(function(e,t){e.effects.effect.puff=function(t,n){var r=e(this),i=e.effects.setMode(r,t.mode||"hide"),s=i==="hide",o=parseInt(t.percent,10)||150,u=o/100,a={height:r.height(),width:r.width(),outerHeight:r.outerHeight(),outerWidth:r.outerWidth()};e.extend(t,{effect:"scale",queue:!1,fade:!0,mode:i,complete:n,percent:s?o:100,from:s?a:{height:a.height*u,width:a.width*u,outerHeight:a.outerHeight*u,outerWidth:a.outerWidth*u}}),r.effect(t)},e.effects.effect.scale=function(t,n){var r=e(this),i=e.extend(!0,{},t),s=e.effects.setMode(r,t.mode||"effect"),o=parseInt(t.percent,10)||(parseInt(t.percent,10)===0?0:s==="hide"?0:100),u=t.direction||"both",a=t.origin,f={height:r.height(),width:r.width(),outerHeight:r.outerHeight(),outerWidth:r.outerWidth()},l={y:u!=="horizontal"?o/100:1,x:u!=="vertical"?o/100:1};i.effect="size",i.queue=!1,i.complete=n,s!=="effect"&&(i.origin=a||["middle","center"],i.restore=!0),i.from=t.from||(s==="show"?{height:0,width:0,outerHeight:0,outerWidth:0}:f),i.to={height:f.height*l.y,width:f.width*l.x,outerHeight:f.outerHeight*l.y,outerWidth:f.outerWidth*l.x},i.fade&&(s==="show"&&(i.from.opacity=0,i.to.opacity=1),s==="hide"&&(i.from.opacity=1,i.to.opacity=0)),r.effect(i)},e.effects.effect.size=function(t,n){var r,i,s,o=e(this),u=["position","top","bottom","left","right","width","height","overflow","opacity"],a=["position","top","bottom","left","right","overflow","opacity"],f=["width","height","overflow"],l=["fontSize"],c=["borderTopWidth","borderBottomWidth","paddingTop","paddingBottom"],h=["borderLeftWidth","borderRightWidth","paddingLeft","paddingRight"],p=e.effects.setMode(o,t.mode||"effect"),d=t.restore||p!=="effect",v=t.scale||"both",m=t.origin||["middle","center"],g=o.css("position"),y=d?u:a,b={height:0,width:0,outerHeight:0,outerWidth:0};p==="show"&&o.show(),r={height:o.height(),width:o.width(),outerHeight:o.outerHeight(),outerWidth:o.outerWidth()},t.mode==="toggle"&&p==="show"?(o.from=t.to||b,o.to=t.from||r):(o.from=t.from||(p==="show"?b:r),o.to=t.to||(p==="hide"?b:r)),s={from:{y:o.from.height/r.height,x:o.from.width/r.width},to:{y:o.to.height/r.height,x:o.to.width/r.width}};if(v==="box"||v==="both")s.from.y!==s.to.y&&(y=y.concat(c),o.from=e.effects.setTransition(o,c,s.from.y,o.from),o.to=e.effects.setTransition(o,c,s.to.y,o.to)),s.from.x!==s.to.x&&(y=y.concat(h),o.from=e.effects.setTransition(o,h,s.from.x,o.from),o.to=e.effects.setTransition(o,h,s.to.x,o.to));(v==="content"||v==="both")&&s.from.y!==s.to.y&&(y=y.concat(l).concat(f),o.from=e.effects.setTransition(o,l,s.from.y,o.from),o.to=e.effects.setTransition(o,l,s.to.y,o.to)),e.effects.save(o,y),o.show(),e.effects.createWrapper(o),o.css("overflow","hidden").css(o.from),m&&(i=e.effects.getBaseline(m,r),o.from.top=(r.outerHeight-o.outerHeight())*i.y,o.from.left=(r.outerWidth-o.outerWidth())*i.x,o.to.top=(r.outerHeight-o.to.outerHeight)*i.y,o.to.left=(r.outerWidth-o.to.outerWidth)*i.x),o.css(o.from);if(v==="content"||v==="both")c=c.concat(["marginTop","marginBottom"]).concat(l),h=h.concat(["marginLeft","marginRight"]),f=u.concat(c).concat(h),o.find("*[width]").each(function(){var n=e(this),r={height:n.height(),width:n.width(),outerHeight:n.outerHeight(),outerWidth:n.outerWidth()};d&&e.effects.save(n,f),n.from={height:r.height*s.from.y,width:r.width*s.from.x,outerHeight:r.outerHeight*s.from.y,outerWidth:r.outerWidth*s.from.x},n.to={height:r.height*s.to.y,width:r.width*s.to.x,outerHeight:r.height*s.to.y,outerWidth:r.width*s.to.x},s.from.y!==s.to.y&&(n.from=e.effects.setTransition(n,c,s.from.y,n.from),n.to=e.effects.setTransition(n,c,s.to.y,n.to)),s.from.x!==s.to.x&&(n.from=e.effects.setTransition(n,h,s.from.x,n.from),n.to=e.effects.setTransition(n,h,s.to.x,n.to)),n.css(n.from),n.animate(n.to,t.duration,t.easing,function(){d&&e.effects.restore(n,f)})});o.animate(o.to,{queue:!1,duration:t.duration,easing:t.easing,complete:function(){o.to.opacity===0&&o.css("opacity",o.from.opacity),p==="hide"&&o.hide(),e.effects.restore(o,y),d||(g==="static"?o.css({position:"relative",top:o.to.top,left:o.to.left}):e.each(["top","left"],function(e,t){o.css(t,function(t,n){var r=parseInt(n,10),i=e?o.to.left:o.to.top;return n==="auto"?i+"px":r+i+"px"})})),e.effects.removeWrapper(o),n()}})}})(jQuery);(function(e,t){e.effects.effect.shake=function(t,n){var r=e(this),i=["position","top","bottom","left","right","height","width"],s=e.effects.setMode(r,t.mode||"effect"),o=t.direction||"left",u=t.distance||20,a=t.times||3,f=a*2+1,l=Math.round(t.duration/f),c=o==="up"||o==="down"?"top":"left",h=o==="up"||o==="left",p={},d={},v={},m,g=r.queue(),y=g.length;e.effects.save(r,i),r.show(),e.effects.createWrapper(r),p[c]=(h?"-=":"+=")+u,d[c]=(h?"+=":"-=")+u*2,v[c]=(h?"-=":"+=")+u*2,r.animate(p,l,t.easing);for(m=1;m1&&g.splice.apply(g,[1,0].concat(g.splice(y,f+1))),r.dequeue()}})(jQuery);(function(e,t){e.effects.effect.slide=function(t,n){var r=e(this),i=["position","top","bottom","left","right","width","height"],s=e.effects.setMode(r,t.mode||"show"),o=s==="show",u=t.direction||"left",a=u==="up"||u==="down"?"top":"left",f=u==="up"||u==="left",l,c={};e.effects.save(r,i),r.show(),l=t.distance||r[a==="top"?"outerHeight":"outerWidth"](!0),e.effects.createWrapper(r).css({overflow:"hidden"}),o&&r.css(a,f?isNaN(l)?"-"+l:-l:l),c[a]=(o?f?"+=":"-=":f?"-=":"+=")+l,r.animate(c,{queue:!1,duration:t.duration,easing:t.easing,complete:function(){s==="hide"&&r.hide(),e.effects.restore(r,i),e.effects.removeWrapper(r),n()}})}})(jQuery);(function(e,t){e.effects.effect.transfer=function(t,n){var r=e(this),i=e(t.to),s=i.css("position")==="fixed",o=e("body"),u=s?o.scrollTop():0,a=s?o.scrollLeft():0,f=i.offset(),l={top:f.top-u,left:f.left-a,height:i.innerHeight(),width:i.innerWidth()},c=r.offset(),h=e('
        ').appendTo(document.body).addClass(t.className).css({top:c.top-u,left:c.left-a,height:r.innerHeight(),width:r.innerWidth(),position:s?"fixed":"absolute"}).animate(l,t.duration,t.easing,function(){h.remove(),n()})}})(jQuery);(function(e,t){var n=!1;e.widget("ui.menu",{version:"1.9.2",defaultElement:"
          ",delay:300,options:{icons:{submenu:"ui-icon-carat-1-e"},menus:"ul",position:{my:"left top",at:"right top"},role:"menu",blur:null,focus:null,select:null},_create:function(){this.activeMenu=this.element,this.element.uniqueId().addClass("ui-menu ui-widget ui-widget-content ui-corner-all").toggleClass("ui-menu-icons",!!this.element.find(".ui-icon").length).attr({role:this.options.role,tabIndex:0}).bind("click"+this.eventNamespace,e.proxy(function(e){this.options.disabled&&e.preventDefault()},this)),this.options.disabled&&this.element.addClass("ui-state-disabled").attr("aria-disabled","true"),this._on({"mousedown .ui-menu-item > a":function(e){e.preventDefault()},"click .ui-state-disabled > a":function(e){e.preventDefault()},"click .ui-menu-item:has(a)":function(t){var r=e(t.target).closest(".ui-menu-item");!n&&r.not(".ui-state-disabled").length&&(n=!0,this.select(t),r.has(".ui-menu").length?this.expand(t):this.element.is(":focus")||(this.element.trigger("focus",[!0]),this.active&&this.active.parents(".ui-menu").length===1&&clearTimeout(this.timer)))},"mouseenter .ui-menu-item":function(t){var n=e(t.currentTarget);n.siblings().children(".ui-state-active").removeClass("ui-state-active"),this.focus(t,n)},mouseleave:"collapseAll","mouseleave .ui-menu":"collapseAll",focus:function(e,t){var n=this.active||this.element.children(".ui-menu-item").eq(0);t||this.focus(e,n)},blur:function(t){this._delay(function(){e.contains(this.element[0],this.document[0].activeElement)||this.collapseAll(t)})},keydown:"_keydown"}),this.refresh(),this._on(this.document,{click:function(t){e(t.target).closest(".ui-menu").length||this.collapseAll(t),n=!1}})},_destroy:function(){this.element.removeAttr("aria-activedescendant").find(".ui-menu").andSelf().removeClass("ui-menu ui-widget ui-widget-content ui-corner-all ui-menu-icons").removeAttr("role").removeAttr("tabIndex").removeAttr("aria-labelledby").removeAttr("aria-expanded").removeAttr("aria-hidden").removeAttr("aria-disabled").removeUniqueId().show(),this.element.find(".ui-menu-item").removeClass("ui-menu-item").removeAttr("role").removeAttr("aria-disabled").children("a").removeUniqueId().removeClass("ui-corner-all ui-state-hover").removeAttr("tabIndex").removeAttr("role").removeAttr("aria-haspopup").children().each(function(){var t=e(this);t.data("ui-menu-submenu-carat")&&t.remove()}),this.element.find(".ui-menu-divider").removeClass("ui-menu-divider ui-widget-content")},_keydown:function(t){function a(e){return e.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g,"\\$&")}var n,r,i,s,o,u=!0;switch(t.keyCode){case e.ui.keyCode.PAGE_UP:this.previousPage(t);break;case e.ui.keyCode.PAGE_DOWN:this.nextPage(t);break;case e.ui.keyCode.HOME:this._move("first","first",t);break;case e.ui.keyCode.END:this._move("last","last",t);break;case e.ui.keyCode.UP:this.previous(t);break;case e.ui.keyCode.DOWN:this.next(t);break;case e.ui.keyCode.LEFT:this.collapse(t);break;case e.ui.keyCode.RIGHT:this.active&&!this.active.is(".ui-state-disabled")&&this.expand(t);break;case e.ui.keyCode.ENTER:case e.ui.keyCode.SPACE:this._activate(t);break;case e.ui.keyCode.ESCAPE:this.collapse(t);break;default:u=!1,r=this.previousFilter||"",i=String.fromCharCode(t.keyCode),s=!1,clearTimeout(this.filterTimer),i===r?s=!0:i=r+i,o=new RegExp("^"+a(i),"i"),n=this.activeMenu.children(".ui-menu-item").filter(function(){return o.test(e(this).children("a").text())}),n=s&&n.index(this.active.next())!==-1?this.active.nextAll(".ui-menu-item"):n,n.length||(i=String.fromCharCode(t.keyCode),o=new RegExp("^"+a(i),"i"),n=this.activeMenu.children(".ui-menu-item").filter(function(){return o.test(e(this).children("a").text())})),n.length?(this.focus(t,n),n.length>1?(this.previousFilter=i,this.filterTimer=this._delay(function(){delete this.previousFilter},1e3)):delete this.previousFilter):delete this.previousFilter}u&&t.preventDefault()},_activate:function(e){this.active.is(".ui-state-disabled")||(this.active.children("a[aria-haspopup='true']").length?this.expand(e):this.select(e))},refresh:function(){var t,n=this.options.icons.submenu,r=this.element.find(this.options.menus);r.filter(":not(.ui-menu)").addClass("ui-menu ui-widget ui-widget-content ui-corner-all").hide().attr({role:this.options.role,"aria-hidden":"true","aria-expanded":"false"}).each(function(){var t=e(this),r=t.prev("a"),i=e("").addClass("ui-menu-icon ui-icon "+n).data("ui-menu-submenu-carat",!0);r.attr("aria-haspopup","true").prepend(i),t.attr("aria-labelledby",r.attr("id"))}),t=r.add(this.element),t.children(":not(.ui-menu-item):has(a)").addClass("ui-menu-item").attr("role","presentation").children("a").uniqueId().addClass("ui-corner-all").attr({tabIndex:-1,role:this._itemRole()}),t.children(":not(.ui-menu-item)").each(function(){var t=e(this);/[^\-—–\s]/.test(t.text())||t.addClass("ui-widget-content ui-menu-divider")}),t.children(".ui-state-disabled").attr("aria-disabled","true"),this.active&&!e.contains(this.element[0],this.active[0])&&this.blur()},_itemRole:function(){return{menu:"menuitem",listbox:"option"}[this.options.role]},focus:function(e,t){var n,r;this.blur(e,e&&e.type==="focus"),this._scrollIntoView(t),this.active=t.first(),r=this.active.children("a").addClass("ui-state-focus"),this.options.role&&this.element.attr("aria-activedescendant",r.attr("id")),this.active.parent().closest(".ui-menu-item").children("a:first").addClass("ui-state-active"),e&&e.type==="keydown"?this._close():this.timer=this._delay(function(){this._close()},this.delay),n=t.children(".ui-menu"),n.length&&/^mouse/.test(e.type)&&this._startOpening(n),this.activeMenu=t.parent(),this._trigger("focus",e,{item:t})},_scrollIntoView:function(t){var n,r,i,s,o,u;this._hasScroll()&&(n=parseFloat(e.css(this.activeMenu[0],"borderTopWidth"))||0,r=parseFloat(e.css(this.activeMenu[0],"paddingTop"))||0,i=t.offset().top-this.activeMenu.offset().top-n-r,s=this.activeMenu.scrollTop(),o=this.activeMenu.height(),u=t.height(),i<0?this.activeMenu.scrollTop(s+i):i+u>o&&this.activeMenu.scrollTop(s+i-o+u))},blur:function(e,t){t||clearTimeout(this.timer);if(!this.active)return;this.active.children("a").removeClass("ui-state-focus"),this.active=null,this._trigger("blur",e,{item:this.active})},_startOpening:function(e){clearTimeout(this.timer);if(e.attr("aria-hidden")!=="true")return;this.timer=this._delay(function(){this._close(),this._open(e)},this.delay)},_open:function(t){var n=e.extend({of:this.active},this.options.position);clearTimeout(this.timer),this.element.find(".ui-menu").not(t.parents(".ui-menu")).hide().attr("aria-hidden","true"),t.show().removeAttr("aria-hidden").attr("aria-expanded","true").position(n)},collapseAll:function(t,n){clearTimeout(this.timer),this.timer=this._delay(function(){var r=n?this.element:e(t&&t.target).closest(this.element.find(".ui-menu"));r.length||(r=this.element),this._close(r),this.blur(t),this.activeMenu=r},this.delay)},_close:function(e){e||(e=this.active?this.active.parent():this.element),e.find(".ui-menu").hide().attr("aria-hidden","true").attr("aria-expanded","false").end().find("a.ui-state-active").removeClass("ui-state-active")},collapse:function(e){var t=this.active&&this.active.parent().closest(".ui-menu-item",this.element);t&&t.length&&(this._close(),this.focus(e,t))},expand:function(e){var t=this.active&&this.active.children(".ui-menu ").children(".ui-menu-item").first();t&&t.length&&(this._open(t.parent()),this._delay(function(){this.focus(e,t)}))},next:function(e){this._move("next","first",e)},previous:function(e){this._move("prev","last",e)},isFirstItem:function(){return this.active&&!this.active.prevAll(".ui-menu-item").length},isLastItem:function(){return this.active&&!this.active.nextAll(".ui-menu-item").length},_move:function(e,t,n){var r;this.active&&(e==="first"||e==="last"?r=this.active[e==="first"?"prevAll":"nextAll"](".ui-menu-item").eq(-1):r=this.active[e+"All"](".ui-menu-item").eq(0));if(!r||!r.length||!this.active)r=this.activeMenu.children(".ui-menu-item")[t]();this.focus(n,r)},nextPage:function(t){var n,r,i;if(!this.active){this.next(t);return}if(this.isLastItem())return;this._hasScroll()?(r=this.active.offset().top,i=this.element.height(),this.active.nextAll(".ui-menu-item").each(function(){return n=e(this),n.offset().top-r-i<0}),this.focus(t,n)):this.focus(t,this.activeMenu.children(".ui-menu-item")[this.active?"last":"first"]())},previousPage:function(t){var n,r,i;if(!this.active){this.next(t);return}if(this.isFirstItem())return;this._hasScroll()?(r=this.active.offset().top,i=this.element.height(),this.active.prevAll(".ui-menu-item").each(function(){return n=e(this),n.offset().top-r+i>0}),this.focus(t,n)):this.focus(t,this.activeMenu.children(".ui-menu-item").first())},_hasScroll:function(){return this.element.outerHeight()
        ").appendTo(this.element),this.oldValue=this._value(),this._refreshValue()},_destroy:function(){this.element.removeClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").removeAttr("role").removeAttr("aria-valuemin").removeAttr("aria-valuemax").removeAttr("aria-valuenow"),this.valueDiv.remove()},value:function(e){return e===t?this._value():(this._setOption("value",e),this)},_setOption:function(e,t){e==="value"&&(this.options.value=t,this._refreshValue(),this._value()===this.options.max&&this._trigger("complete")),this._super(e,t)},_value:function(){var e=this.options.value;return typeof e!="number"&&(e=0),Math.min(this.options.max,Math.max(this.min,e))},_percentage:function(){return 100*this._value()/this.options.max},_refreshValue:function(){var e=this.value(),t=this._percentage();this.oldValue!==e&&(this.oldValue=e,this._trigger("change")),this.valueDiv.toggle(e>this.min).toggleClass("ui-corner-right",e===this.options.max).width(t.toFixed(0)+"%"),this.element.attr("aria-valuenow",e)}})})(jQuery);(function(e,t){e.widget("ui.resizable",e.ui.mouse,{version:"1.9.2",widgetEventPrefix:"resize",options:{alsoResize:!1,animate:!1,animateDuration:"slow",animateEasing:"swing",aspectRatio:!1,autoHide:!1,containment:!1,ghost:!1,grid:!1,handles:"e,s,se",helper:!1,maxHeight:null,maxWidth:null,minHeight:10,minWidth:10,zIndex:1e3},_create:function(){var t=this,n=this.options;this.element.addClass("ui-resizable"),e.extend(this,{_aspectRatio:!!n.aspectRatio,aspectRatio:n.aspectRatio,originalElement:this.element,_proportionallyResizeElements:[],_helper:n.helper||n.ghost||n.animate?n.helper||"ui-resizable-helper":null}),this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)&&(this.element.wrap(e('
        ').css({position:this.element.css("position"),width:this.element.outerWidth(),height:this.element.outerHeight(),top:this.element.css("top"),left:this.element.css("left")})),this.element=this.element.parent().data("resizable",this.element.data("resizable")),this.elementIsWrapper=!0,this.element.css({marginLeft:this.originalElement.css("marginLeft"),marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom")}),this.originalElement.css({marginLeft:0,marginTop:0,marginRight:0,marginBottom:0}),this.originalResizeStyle=this.originalElement.css("resize"),this.originalElement.css("resize","none"),this._proportionallyResizeElements.push(this.originalElement.css({position:"static",zoom:1,display:"block"})),this.originalElement.css({margin:this.originalElement.css("margin")}),this._proportionallyResize()),this.handles=n.handles||(e(".ui-resizable-handle",this.element).length?{n:".ui-resizable-n",e:".ui-resizable-e",s:".ui-resizable-s",w:".ui-resizable-w",se:".ui-resizable-se",sw:".ui-resizable-sw",ne:".ui-resizable-ne",nw:".ui-resizable-nw"}:"e,s,se");if(this.handles.constructor==String){this.handles=="all"&&(this.handles="n,e,s,w,se,sw,ne,nw");var r=this.handles.split(",");this.handles={};for(var i=0;i');u.css({zIndex:n.zIndex}),"se"==s&&u.addClass("ui-icon ui-icon-gripsmall-diagonal-se"),this.handles[s]=".ui-resizable-"+s,this.element.append(u)}}this._renderAxis=function(t){t=t||this.element;for(var n in this.handles){this.handles[n].constructor==String&&(this.handles[n]=e(this.handles[n],this.element).show());if(this.elementIsWrapper&&this.originalElement[0].nodeName.match(/textarea|input|select|button/i)){var r=e(this.handles[n],this.element),i=0;i=/sw|ne|nw|se|n|s/.test(n)?r.outerHeight():r.outerWidth();var s=["padding",/ne|nw|n/.test(n)?"Top":/se|sw|s/.test(n)?"Bottom":/^e$/.test(n)?"Right":"Left"].join("");t.css(s,i),this._proportionallyResize()}if(!e(this.handles[n]).length)continue}},this._renderAxis(this.element),this._handles=e(".ui-resizable-handle",this.element).disableSelection(),this._handles.mouseover(function(){if(!t.resizing){if(this.className)var e=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i);t.axis=e&&e[1]?e[1]:"se"}}),n.autoHide&&(this._handles.hide(),e(this.element).addClass("ui-resizable-autohide").mouseenter(function(){if(n.disabled)return;e(this).removeClass("ui-resizable-autohide"),t._handles.show()}).mouseleave(function(){if(n.disabled)return;t.resizing||(e(this).addClass("ui-resizable-autohide"),t._handles.hide())})),this._mouseInit()},_destroy:function(){this._mouseDestroy();var t=function(t){e(t).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing").removeData("resizable").removeData("ui-resizable").unbind(".resizable").find(".ui-resizable-handle").remove()};if(this.elementIsWrapper){t(this.element);var n=this.element;this.originalElement.css({position:n.css("position"),width:n.outerWidth(),height:n.outerHeight(),top:n.css("top"),left:n.css("left")}).insertAfter(n),n.remove()}return this.originalElement.css("resize",this.originalResizeStyle),t(this.originalElement),this},_mouseCapture:function(t){var n=!1;for(var r in this.handles)e(this.handles[r])[0]==t.target&&(n=!0);return!this.options.disabled&&n},_mouseStart:function(t){var r=this.options,i=this.element.position(),s=this.element;this.resizing=!0,this.documentScroll={top:e(document).scrollTop(),left:e(document).scrollLeft()},(s.is(".ui-draggable")||/absolute/.test(s.css("position")))&&s.css({position:"absolute",top:i.top,left:i.left}),this._renderProxy();var o=n(this.helper.css("left")),u=n(this.helper.css("top"));r.containment&&(o+=e(r.containment).scrollLeft()||0,u+=e(r.containment).scrollTop()||0),this.offset=this.helper.offset(),this.position={left:o,top:u},this.size=this._helper?{width:s.outerWidth(),height:s.outerHeight()}:{width:s.width(),height:s.height()},this.originalSize=this._helper?{width:s.outerWidth(),height:s.outerHeight()}:{width:s.width(),height:s.height()},this.originalPosition={left:o,top:u},this.sizeDiff={width:s.outerWidth()-s.width(),height:s.outerHeight()-s.height()},this.originalMousePosition={left:t.pageX,top:t.pageY},this.aspectRatio=typeof r.aspectRatio=="number"?r.aspectRatio:this.originalSize.width/this.originalSize.height||1;var a=e(".ui-resizable-"+this.axis).css("cursor");return e("body").css("cursor",a=="auto"?this.axis+"-resize":a),s.addClass("ui-resizable-resizing"),this._propagate("start",t),!0},_mouseDrag:function(e){var t=this.helper,n=this.options,r={},i=this,s=this.originalMousePosition,o=this.axis,u=e.pageX-s.left||0,a=e.pageY-s.top||0,f=this._change[o];if(!f)return!1;var l=f.apply(this,[e,u,a]);this._updateVirtualBoundaries(e.shiftKey);if(this._aspectRatio||e.shiftKey)l=this._updateRatio(l,e);return l=this._respectSize(l,e),this._propagate("resize",e),t.css({top:this.position.top+"px",left:this.position.left+"px",width:this.size.width+"px",height:this.size.height+"px"}),!this._helper&&this._proportionallyResizeElements.length&&this._proportionallyResize(),this._updateCache(l),this._trigger("resize",e,this.ui()),!1},_mouseStop:function(t){this.resizing=!1;var n=this.options,r=this;if(this._helper){var i=this._proportionallyResizeElements,s=i.length&&/textarea/i.test(i[0].nodeName),o=s&&e.ui.hasScroll(i[0],"left")?0:r.sizeDiff.height,u=s?0:r.sizeDiff.width,a={width:r.helper.width()-u,height:r.helper.height()-o},f=parseInt(r.element.css("left"),10)+(r.position.left-r.originalPosition.left)||null,l=parseInt(r.element.css("top"),10)+(r.position.top-r.originalPosition.top)||null;n.animate||this.element.css(e.extend(a,{top:l,left:f})),r.helper.height(r.size.height),r.helper.width(r.size.width),this._helper&&!n.animate&&this._proportionallyResize()}return e("body").css("cursor","auto"),this.element.removeClass("ui-resizable-resizing"),this._propagate("stop",t),this._helper&&this.helper.remove(),!1},_updateVirtualBoundaries:function(e){var t=this.options,n,i,s,o,u;u={minWidth:r(t.minWidth)?t.minWidth:0,maxWidth:r(t.maxWidth)?t.maxWidth:Infinity,minHeight:r(t.minHeight)?t.minHeight:0,maxHeight:r(t.maxHeight)?t.maxHeight:Infinity};if(this._aspectRatio||e)n=u.minHeight*this.aspectRatio,s=u.minWidth/this.aspectRatio,i=u.maxHeight*this.aspectRatio,o=u.maxWidth/this.aspectRatio,n>u.minWidth&&(u.minWidth=n),s>u.minHeight&&(u.minHeight=s),ie.width,l=r(e.height)&&i.minHeight&&i.minHeight>e.height;f&&(e.width=i.minWidth),l&&(e.height=i.minHeight),u&&(e.width=i.maxWidth),a&&(e.height=i.maxHeight);var c=this.originalPosition.left+this.originalSize.width,h=this.position.top+this.size.height,p=/sw|nw|w/.test(o),d=/nw|ne|n/.test(o);f&&p&&(e.left=c-i.minWidth),u&&p&&(e.left=c-i.maxWidth),l&&d&&(e.top=h-i.minHeight),a&&d&&(e.top=h-i.maxHeight);var v=!e.width&&!e.height;return v&&!e.left&&e.top?e.top=null:v&&!e.top&&e.left&&(e.left=null),e},_proportionallyResize:function(){var t=this.options;if(!this._proportionallyResizeElements.length)return;var n=this.helper||this.element;for(var r=0;r');var r=e.ui.ie6?1:0,i=e.ui.ie6?2:-1;this.helper.addClass(this._helper).css({width:this.element.outerWidth()+i,height:this.element.outerHeight()+i,position:"absolute",left:this.elementOffset.left-r+"px",top:this.elementOffset.top-r+"px",zIndex:++n.zIndex}),this.helper.appendTo("body").disableSelection()}else this.helper=this.element},_change:{e:function(e,t,n){return{width:this.originalSize.width+t}},w:function(e,t,n){var r=this.options,i=this.originalSize,s=this.originalPosition;return{left:s.left+t,width:i.width-t}},n:function(e,t,n){var r=this.options,i=this.originalSize,s=this.originalPosition;return{top:s.top+n,height:i.height-n}},s:function(e,t,n){return{height:this.originalSize.height+n}},se:function(t,n,r){return e.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[t,n,r]))},sw:function(t,n,r){return e.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[t,n,r]))},ne:function(t,n,r){return e.extend(this._change.n.apply(this,arguments),this._change.e.apply(this,[t,n,r]))},nw:function(t,n,r){return e.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[t,n,r]))}},_propagate:function(t,n){e.ui.plugin.call(this,t,[n,this.ui()]),t!="resize"&&this._trigger(t,n,this.ui())},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize,originalPosition:this.originalPosition}}}),e.ui.plugin.add("resizable","alsoResize",{start:function(t,n){var r=e(this).data("resizable"),i=r.options,s=function(t){e(t).each(function(){var t=e(this);t.data("resizable-alsoresize",{width:parseInt(t.width(),10),height:parseInt(t.height(),10),left:parseInt(t.css("left"),10),top:parseInt(t.css("top"),10)})})};typeof i.alsoResize=="object"&&!i.alsoResize.parentNode?i.alsoResize.length?(i.alsoResize=i.alsoResize[0],s(i.alsoResize)):e.each(i.alsoResize,function(e){s(e)}):s(i.alsoResize)},resize:function(t,n){var r=e(this).data("resizable"),i=r.options,s=r.originalSize,o=r.originalPosition,u={height:r.size.height-s.height||0,width:r.size.width-s.width||0,top:r.position.top-o.top||0,left:r.position.left-o.left||0},a=function(t,r){e(t).each(function(){var t=e(this),i=e(this).data("resizable-alsoresize"),s={},o=r&&r.length?r:t.parents(n.originalElement[0]).length?["width","height"]:["width","height","top","left"];e.each(o,function(e,t){var n=(i[t]||0)+(u[t]||0);n&&n>=0&&(s[t]=n||null)}),t.css(s)})};typeof i.alsoResize=="object"&&!i.alsoResize.nodeType?e.each(i.alsoResize,function(e,t){a(e,t)}):a(i.alsoResize)},stop:function(t,n){e(this).removeData("resizable-alsoresize")}}),e.ui.plugin.add("resizable","animate",{stop:function(t,n){var r=e(this).data("resizable"),i=r.options,s=r._proportionallyResizeElements,o=s.length&&/textarea/i.test(s[0].nodeName),u=o&&e.ui.hasScroll(s[0],"left")?0:r.sizeDiff.height,a=o?0:r.sizeDiff.width,f={width:r.size.width-a,height:r.size.height-u},l=parseInt(r.element.css("left"),10)+(r.position.left-r.originalPosition.left)||null,c=parseInt(r.element.css("top"),10)+(r.position.top-r.originalPosition.top)||null;r.element.animate(e.extend(f,c&&l?{top:c,left:l}:{}),{duration:i.animateDuration,easing:i.animateEasing,step:function(){var n={width:parseInt(r.element.css("width"),10),height:parseInt(r.element.css("height"),10),top:parseInt(r.element.css("top"),10),left:parseInt(r.element.css("left"),10)};s&&s.length&&e(s[0]).css({width:n.width,height:n.height}),r._updateCache(n),r._propagate("resize",t)}})}}),e.ui.plugin.add("resizable","containment",{start:function(t,r){var i=e(this).data("resizable"),s=i.options,o=i.element,u=s.containment,a=u instanceof e?u.get(0):/parent/.test(u)?o.parent().get(0):u;if(!a)return;i.containerElement=e(a);if(/document/.test(u)||u==document)i.containerOffset={left:0,top:0},i.containerPosition={left:0,top:0},i.parentData={element:e(document),left:0,top:0,width:e(document).width(),height:e(document).height()||document.body.parentNode.scrollHeight};else{var f=e(a),l=[];e(["Top","Right","Left","Bottom"]).each(function(e,t){l[e]=n(f.css("padding"+t))}),i.containerOffset=f.offset(),i.containerPosition=f.position(),i.containerSize={height:f.innerHeight()-l[3],width:f.innerWidth()-l[1]};var c=i.containerOffset,h=i.containerSize.height,p=i.containerSize.width,d=e.ui.hasScroll(a,"left")?a.scrollWidth:p,v=e.ui.hasScroll(a)?a.scrollHeight:h;i.parentData={element:a,left:c.left,top:c.top,width:d,height:v}}},resize:function(t,n){var r=e(this).data("resizable"),i=r.options,s=r.containerSize,o=r.containerOffset,u=r.size,a=r.position,f=r._aspectRatio||t.shiftKey,l={top:0,left:0},c=r.containerElement;c[0]!=document&&/static/.test(c.css("position"))&&(l=o),a.left<(r._helper?o.left:0)&&(r.size.width=r.size.width+(r._helper?r.position.left-o.left:r.position.left-l.left),f&&(r.size.height=r.size.width/r.aspectRatio),r.position.left=i.helper?o.left:0),a.top<(r._helper?o.top:0)&&(r.size.height=r.size.height+(r._helper?r.position.top-o.top:r.position.top),f&&(r.size.width=r.size.height*r.aspectRatio),r.position.top=r._helper?o.top:0),r.offset.left=r.parentData.left+r.position.left,r.offset.top=r.parentData.top+r.position.top;var h=Math.abs((r._helper?r.offset.left-l.left:r.offset.left-l.left)+r.sizeDiff.width),p=Math.abs((r._helper?r.offset.top-l.top:r.offset.top-o.top)+r.sizeDiff.height),d=r.containerElement.get(0)==r.element.parent().get(0),v=/relative|absolute/.test(r.containerElement.css("position"));d&&v&&(h-=r.parentData.left),h+r.size.width>=r.parentData.width&&(r.size.width=r.parentData.width-h,f&&(r.size.height=r.size.width/r.aspectRatio)),p+r.size.height>=r.parentData.height&&(r.size.height=r.parentData.height-p,f&&(r.size.width=r.size.height*r.aspectRatio))},stop:function(t,n){var r=e(this).data("resizable"),i=r.options,s=r.position,o=r.containerOffset,u=r.containerPosition,a=r.containerElement,f=e(r.helper),l=f.offset(),c=f.outerWidth()-r.sizeDiff.width,h=f.outerHeight()-r.sizeDiff.height;r._helper&&!i.animate&&/relative/.test(a.css("position"))&&e(this).css({left:l.left-u.left-o.left,width:c,height:h}),r._helper&&!i.animate&&/static/.test(a.css("position"))&&e(this).css({left:l.left-u.left-o.left,width:c,height:h})}}),e.ui.plugin.add("resizable","ghost",{start:function(t,n){var r=e(this).data("resizable"),i=r.options,s=r.size;r.ghost=r.originalElement.clone(),r.ghost.css({opacity:.25,display:"block",position:"relative",height:s.height,width:s.width,margin:0,left:0,top:0}).addClass("ui-resizable-ghost").addClass(typeof i.ghost=="string"?i.ghost:""),r.ghost.appendTo(r.helper)},resize:function(t,n){var r=e(this).data("resizable"),i=r.options;r.ghost&&r.ghost.css({position:"relative",height:r.size.height,width:r.size.width})},stop:function(t,n){var r=e(this).data("resizable"),i=r.options;r.ghost&&r.helper&&r.helper.get(0).removeChild(r.ghost.get(0))}}),e.ui.plugin.add("resizable","grid",{resize:function(t,n){var r=e(this).data("resizable"),i=r.options,s=r.size,o=r.originalSize,u=r.originalPosition,a=r.axis,f=i._aspectRatio||t.shiftKey;i.grid=typeof i.grid=="number"?[i.grid,i.grid]:i.grid;var l=Math.round((s.width-o.width)/(i.grid[0]||1))*(i.grid[0]||1),c=Math.round((s.height-o.height)/(i.grid[1]||1))*(i.grid[1]||1);/^(se|s|e)$/.test(a)?(r.size.width=o.width+l,r.size.height=o.height+c):/^(ne)$/.test(a)?(r.size.width=o.width+l,r.size.height=o.height+c,r.position.top=u.top-c):/^(sw)$/.test(a)?(r.size.width=o.width+l,r.size.height=o.height+c,r.position.left=u.left-l):(r.size.width=o.width+l,r.size.height=o.height+c,r.position.top=u.top-c,r.position.left=u.left-l)}});var n=function(e){return parseInt(e,10)||0},r=function(e){return!isNaN(parseInt(e,10))}})(jQuery);(function(e,t){e.widget("ui.selectable",e.ui.mouse,{version:"1.9.2",options:{appendTo:"body",autoRefresh:!0,distance:0,filter:"*",tolerance:"touch"},_create:function(){var t=this;this.element.addClass("ui-selectable"),this.dragged=!1;var n;this.refresh=function(){n=e(t.options.filter,t.element[0]),n.addClass("ui-selectee"),n.each(function(){var t=e(this),n=t.offset();e.data(this,"selectable-item",{element:this,$element:t,left:n.left,top:n.top,right:n.left+t.outerWidth(),bottom:n.top+t.outerHeight(),startselected:!1,selected:t.hasClass("ui-selected"),selecting:t.hasClass("ui-selecting"),unselecting:t.hasClass("ui-unselecting")})})},this.refresh(),this.selectees=n.addClass("ui-selectee"),this._mouseInit(),this.helper=e("
        ")},_destroy:function(){this.selectees.removeClass("ui-selectee").removeData("selectable-item"),this.element.removeClass("ui-selectable ui-selectable-disabled"),this._mouseDestroy()},_mouseStart:function(t){var n=this;this.opos=[t.pageX,t.pageY];if(this.options.disabled)return;var r=this.options;this.selectees=e(r.filter,this.element[0]),this._trigger("start",t),e(r.appendTo).append(this.helper),this.helper.css({left:t.clientX,top:t.clientY,width:0,height:0}),r.autoRefresh&&this.refresh(),this.selectees.filter(".ui-selected").each(function(){var r=e.data(this,"selectable-item");r.startselected=!0,!t.metaKey&&!t.ctrlKey&&(r.$element.removeClass("ui-selected"),r.selected=!1,r.$element.addClass("ui-unselecting"),r.unselecting=!0,n._trigger("unselecting",t,{unselecting:r.element}))}),e(t.target).parents().andSelf().each(function(){var r=e.data(this,"selectable-item");if(r){var i=!t.metaKey&&!t.ctrlKey||!r.$element.hasClass("ui-selected");return r.$element.removeClass(i?"ui-unselecting":"ui-selected").addClass(i?"ui-selecting":"ui-unselecting"),r.unselecting=!i,r.selecting=i,r.selected=i,i?n._trigger("selecting",t,{selecting:r.element}):n._trigger("unselecting",t,{unselecting:r.element}),!1}})},_mouseDrag:function(t){var n=this;this.dragged=!0;if(this.options.disabled)return;var r=this.options,i=this.opos[0],s=this.opos[1],o=t.pageX,u=t.pageY;if(i>o){var a=o;o=i,i=a}if(s>u){var a=u;u=s,s=a}return this.helper.css({left:i,top:s,width:o-i,height:u-s}),this.selectees.each(function(){var a=e.data(this,"selectable-item");if(!a||a.element==n.element[0])return;var f=!1;r.tolerance=="touch"?f=!(a.left>o||a.rightu||a.bottomi&&a.rights&&a.bottom").appendTo(this.element).addClass("ui-slider-range ui-widget-header"+(i.range==="min"||i.range==="max"?" ui-slider-range-"+i.range:""))),r=i.values&&i.values.length||1;for(t=s.length;tn&&(i=n,s=e(this),o=t)}),c.range===!0&&this.values(1)===c.min&&(o+=1,s=e(this.handles[o])),u=this._start(t,o),u===!1?!1:(this._mouseSliding=!0,this._handleIndex=o,s.addClass("ui-state-active").focus(),a=s.offset(),f=!e(t.target).parents().andSelf().is(".ui-slider-handle"),this._clickOffset=f?{left:0,top:0}:{left:t.pageX-a.left-s.width()/2,top:t.pageY-a.top-s.height()/2-(parseInt(s.css("borderTopWidth"),10)||0)-(parseInt(s.css("borderBottomWidth"),10)||0)+(parseInt(s.css("marginTop"),10)||0)},this.handles.hasClass("ui-state-hover")||this._slide(t,o,r),this._animateOff=!0,!0))},_mouseStart:function(){return!0},_mouseDrag:function(e){var t={x:e.pageX,y:e.pageY},n=this._normValueFromMouse(t);return this._slide(e,this._handleIndex,n),!1},_mouseStop:function(e){return this.handles.removeClass("ui-state-active"),this._mouseSliding=!1,this._stop(e,this._handleIndex),this._change(e,this._handleIndex),this._handleIndex=null,this._clickOffset=null,this._animateOff=!1,!1},_detectOrientation:function(){this.orientation=this.options.orientation==="vertical"?"vertical":"horizontal"},_normValueFromMouse:function(e){var t,n,r,i,s;return this.orientation==="horizontal"?(t=this.elementSize.width,n=e.x-this.elementOffset.left-(this._clickOffset?this._clickOffset.left:0)):(t=this.elementSize.height,n=e.y-this.elementOffset.top-(this._clickOffset?this._clickOffset.top:0)),r=n/t,r>1&&(r=1),r<0&&(r=0),this.orientation==="vertical"&&(r=1-r),i=this._valueMax()-this._valueMin(),s=this._valueMin()+r*i,this._trimAlignValue(s)},_start:function(e,t){var n={handle:this.handles[t],value:this.value()};return this.options.values&&this.options.values.length&&(n.value=this.values(t),n.values=this.values()),this._trigger("start",e,n)},_slide:function(e,t,n){var r,i,s;this.options.values&&this.options.values.length?(r=this.values(t?0:1),this.options.values.length===2&&this.options.range===!0&&(t===0&&n>r||t===1&&n1){this.options.values[t]=this._trimAlignValue(n),this._refreshValue(),this._change(null,t);return}if(!arguments.length)return this._values();if(!e.isArray(arguments[0]))return this.options.values&&this.options.values.length?this._values(t):this.value();r=this.options.values,i=arguments[0];for(s=0;s=this._valueMax())return this._valueMax();var t=this.options.step>0?this.options.step:1,n=(e-this._valueMin())%t,r=e-n;return Math.abs(n)*2>=t&&(r+=n>0?t:-t),parseFloat(r.toFixed(5))},_valueMin:function(){return this.options.min},_valueMax:function(){return this.options.max},_refreshValue:function(){var t,n,r,i,s,o=this.options.range,u=this.options,a=this,f=this._animateOff?!1:u.animate,l={};this.options.values&&this.options.values.length?this.handles.each(function(r){n=(a.values(r)-a._valueMin())/(a._valueMax()-a._valueMin())*100,l[a.orientation==="horizontal"?"left":"bottom"]=n+"%",e(this).stop(1,1)[f?"animate":"css"](l,u.animate),a.options.range===!0&&(a.orientation==="horizontal"?(r===0&&a.range.stop(1,1)[f?"animate":"css"]({left:n+"%"},u.animate),r===1&&a.range[f?"animate":"css"]({width:n-t+"%"},{queue:!1,duration:u.animate})):(r===0&&a.range.stop(1,1)[f?"animate":"css"]({bottom:n+"%"},u.animate),r===1&&a.range[f?"animate":"css"]({height:n-t+"%"},{queue:!1,duration:u.animate}))),t=n}):(r=this.value(),i=this._valueMin(),s=this._valueMax(),n=s!==i?(r-i)/(s-i)*100:0,l[this.orientation==="horizontal"?"left":"bottom"]=n+"%",this.handle.stop(1,1)[f?"animate":"css"](l,u.animate),o==="min"&&this.orientation==="horizontal"&&this.range.stop(1,1)[f?"animate":"css"]({width:n+"%"},u.animate),o==="max"&&this.orientation==="horizontal"&&this.range[f?"animate":"css"]({width:100-n+"%"},{queue:!1,duration:u.animate}),o==="min"&&this.orientation==="vertical"&&this.range.stop(1,1)[f?"animate":"css"]({height:n+"%"},u.animate),o==="max"&&this.orientation==="vertical"&&this.range[f?"animate":"css"]({height:100-n+"%"},{queue:!1,duration:u.animate}))}})})(jQuery);(function(e,t){e.widget("ui.sortable",e.ui.mouse,{version:"1.9.2",widgetEventPrefix:"sort",ready:!1,options:{appendTo:"parent",axis:!1,connectWith:!1,containment:!1,cursor:"auto",cursorAt:!1,dropOnEmpty:!0,forcePlaceholderSize:!1,forceHelperSize:!1,grid:!1,handle:!1,helper:"original",items:"> *",opacity:!1,placeholder:!1,revert:!1,scroll:!0,scrollSensitivity:20,scrollSpeed:20,scope:"default",tolerance:"intersect",zIndex:1e3},_create:function(){var e=this.options;this.containerCache={},this.element.addClass("ui-sortable"),this.refresh(),this.floating=this.items.length?e.axis==="x"||/left|right/.test(this.items[0].item.css("float"))||/inline|table-cell/.test(this.items[0].item.css("display")):!1,this.offset=this.element.offset(),this._mouseInit(),this.ready=!0},_destroy:function(){this.element.removeClass("ui-sortable ui-sortable-disabled"),this._mouseDestroy();for(var e=this.items.length-1;e>=0;e--)this.items[e].item.removeData(this.widgetName+"-item");return this},_setOption:function(t,n){t==="disabled"?(this.options[t]=n,this.widget().toggleClass("ui-sortable-disabled",!!n)):e.Widget.prototype._setOption.apply(this,arguments)},_mouseCapture:function(t,n){var r=this;if(this.reverting)return!1;if(this.options.disabled||this.options.type=="static")return!1;this._refreshItems(t);var i=null,s=e(t.target).parents().each(function(){if(e.data(this,r.widgetName+"-item")==r)return i=e(this),!1});e.data(t.target,r.widgetName+"-item")==r&&(i=e(t.target));if(!i)return!1;if(this.options.handle&&!n){var o=!1;e(this.options.handle,i).find("*").andSelf().each(function(){this==t.target&&(o=!0)});if(!o)return!1}return this.currentItem=i,this._removeCurrentsFromItems(),!0},_mouseStart:function(t,n,r){var i=this.options;this.currentContainer=this,this.refreshPositions(),this.helper=this._createHelper(t),this._cacheHelperProportions(),this._cacheMargins(),this.scrollParent=this.helper.scrollParent(),this.offset=this.currentItem.offset(),this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left},e.extend(this.offset,{click:{left:t.pageX-this.offset.left,top:t.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()}),this.helper.css("position","absolute"),this.cssPosition=this.helper.css("position"),this.originalPosition=this._generatePosition(t),this.originalPageX=t.pageX,this.originalPageY=t.pageY,i.cursorAt&&this._adjustOffsetFromHelper(i.cursorAt),this.domPosition={prev:this.currentItem.prev()[0],parent:this.currentItem.parent()[0]},this.helper[0]!=this.currentItem[0]&&this.currentItem.hide(),this._createPlaceholder(),i.containment&&this._setContainment(),i.cursor&&(e("body").css("cursor")&&(this._storedCursor=e("body").css("cursor")),e("body").css("cursor",i.cursor)),i.opacity&&(this.helper.css("opacity")&&(this._storedOpacity=this.helper.css("opacity")),this.helper.css("opacity",i.opacity)),i.zIndex&&(this.helper.css("zIndex")&&(this._storedZIndex=this.helper.css("zIndex")),this.helper.css("zIndex",i.zIndex)),this.scrollParent[0]!=document&&this.scrollParent[0].tagName!="HTML"&&(this.overflowOffset=this.scrollParent.offset()),this._trigger("start",t,this._uiHash()),this._preserveHelperProportions||this._cacheHelperProportions();if(!r)for(var s=this.containers.length-1;s>=0;s--)this.containers[s]._trigger("activate",t,this._uiHash(this));return e.ui.ddmanager&&(e.ui.ddmanager.current=this),e.ui.ddmanager&&!i.dropBehaviour&&e.ui.ddmanager.prepareOffsets(this,t),this.dragging=!0,this.helper.addClass("ui-sortable-helper"),this._mouseDrag(t),!0},_mouseDrag:function(t){this.position=this._generatePosition(t),this.positionAbs=this._convertPositionTo("absolute"),this.lastPositionAbs||(this.lastPositionAbs=this.positionAbs);if(this.options.scroll){var n=this.options,r=!1;this.scrollParent[0]!=document&&this.scrollParent[0].tagName!="HTML"?(this.overflowOffset.top+this.scrollParent[0].offsetHeight-t.pageY=0;i--){var s=this.items[i],o=s.item[0],u=this._intersectsWithPointer(s);if(!u)continue;if(s.instance!==this.currentContainer)continue;if(o!=this.currentItem[0]&&this.placeholder[u==1?"next":"prev"]()[0]!=o&&!e.contains(this.placeholder[0],o)&&(this.options.type=="semi-dynamic"?!e.contains(this.element[0],o):!0)){this.direction=u==1?"down":"up";if(this.options.tolerance!="pointer"&&!this._intersectsWithSides(s))break;this._rearrange(t,s),this._trigger("change",t,this._uiHash());break}}return this._contactContainers(t),e.ui.ddmanager&&e.ui.ddmanager.drag(this,t),this._trigger("sort",t,this._uiHash()),this.lastPositionAbs=this.positionAbs,!1},_mouseStop:function(t,n){if(!t)return;e.ui.ddmanager&&!this.options.dropBehaviour&&e.ui.ddmanager.drop(this,t);if(this.options.revert){var r=this,i=this.placeholder.offset();this.reverting=!0,e(this.helper).animate({left:i.left-this.offset.parent.left-this.margins.left+(this.offsetParent[0]==document.body?0:this.offsetParent[0].scrollLeft),top:i.top-this.offset.parent.top-this.margins.top+(this.offsetParent[0]==document.body?0:this.offsetParent[0].scrollTop)},parseInt(this.options.revert,10)||500,function(){r._clear(t)})}else this._clear(t,n);return!1},cancel:function(){if(this.dragging){this._mouseUp({target:null}),this.options.helper=="original"?this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"):this.currentItem.show();for(var t=this.containers.length-1;t>=0;t--)this.containers[t]._trigger("deactivate",null,this._uiHash(this)),this.containers[t].containerCache.over&&(this.containers[t]._trigger("out",null,this._uiHash(this)),this.containers[t].containerCache.over=0)}return this.placeholder&&(this.placeholder[0].parentNode&&this.placeholder[0].parentNode.removeChild(this.placeholder[0]),this.options.helper!="original"&&this.helper&&this.helper[0].parentNode&&this.helper.remove(),e.extend(this,{helper:null,dragging:!1,reverting:!1,_noFinalSort:null}),this.domPosition.prev?e(this.domPosition.prev).after(this.currentItem):e(this.domPosition.parent).prepend(this.currentItem)),this},serialize:function(t){var n=this._getItemsAsjQuery(t&&t.connected),r=[];return t=t||{},e(n).each(function(){var n=(e(t.item||this).attr(t.attribute||"id")||"").match(t.expression||/(.+)[-=_](.+)/);n&&r.push((t.key||n[1]+"[]")+"="+(t.key&&t.expression?n[1]:n[2]))}),!r.length&&t.key&&r.push(t.key+"="),r.join("&")},toArray:function(t){var n=this._getItemsAsjQuery(t&&t.connected),r=[];return t=t||{},n.each(function(){r.push(e(t.item||this).attr(t.attribute||"id")||"")}),r},_intersectsWith:function(e){var t=this.positionAbs.left,n=t+this.helperProportions.width,r=this.positionAbs.top,i=r+this.helperProportions.height,s=e.left,o=s+e.width,u=e.top,a=u+e.height,f=this.offset.click.top,l=this.offset.click.left,c=r+f>u&&r+fs&&t+le[this.floating?"width":"height"]?c:s0?"down":"up")},_getDragHorizontalDirection:function(){var e=this.positionAbs.left-this.lastPositionAbs.left;return e!=0&&(e>0?"right":"left")},refresh:function(e){return this._refreshItems(e),this.refreshPositions(),this},_connectWith:function(){var e=this.options;return e.connectWith.constructor==String?[e.connectWith]:e.connectWith},_getItemsAsjQuery:function(t){var n=[],r=[],i=this._connectWith();if(i&&t)for(var s=i.length-1;s>=0;s--){var o=e(i[s]);for(var u=o.length-1;u>=0;u--){var a=e.data(o[u],this.widgetName);a&&a!=this&&!a.options.disabled&&r.push([e.isFunction(a.options.items)?a.options.items.call(a.element):e(a.options.items,a.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),a])}}r.push([e.isFunction(this.options.items)?this.options.items.call(this.element,null,{options:this.options,item:this.currentItem}):e(this.options.items,this.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),this]);for(var s=r.length-1;s>=0;s--)r[s][0].each(function(){n.push(this)});return e(n)},_removeCurrentsFromItems:function(){var t=this.currentItem.find(":data("+this.widgetName+"-item)");this.items=e.grep(this.items,function(e){for(var n=0;n=0;s--){var o=e(i[s]);for(var u=o.length-1;u>=0;u--){var a=e.data(o[u],this.widgetName);a&&a!=this&&!a.options.disabled&&(r.push([e.isFunction(a.options.items)?a.options.items.call(a.element[0],t,{item:this.currentItem}):e(a.options.items,a.element),a]),this.containers.push(a))}}for(var s=r.length-1;s>=0;s--){var f=r[s][1],l=r[s][0];for(var u=0,c=l.length;u=0;n--){var r=this.items[n];if(r.instance!=this.currentContainer&&this.currentContainer&&r.item[0]!=this.currentItem[0])continue;var i=this.options.toleranceElement?e(this.options.toleranceElement,r.item):r.item;t||(r.width=i.outerWidth(),r.height=i.outerHeight());var s=i.offset();r.left=s.left,r.top=s.top}if(this.options.custom&&this.options.custom.refreshContainers)this.options.custom.refreshContainers.call(this);else for(var n=this.containers.length-1;n>=0;n--){var s=this.containers[n].element.offset();this.containers[n].containerCache.left=s.left,this.containers[n].containerCache.top=s.top,this.containers[n].containerCache.width=this.containers[n].element.outerWidth(),this.containers[n].containerCache.height=this.containers[n].element.outerHeight()}return this},_createPlaceholder:function(t){t=t||this;var n=t.options;if(!n.placeholder||n.placeholder.constructor==String){var r=n.placeholder;n.placeholder={element:function(){var n=e(document.createElement(t.currentItem[0].nodeName)).addClass(r||t.currentItem[0].className+" ui-sortable-placeholder").removeClass("ui-sortable-helper")[0];return r||(n.style.visibility="hidden"),n},update:function(e,i){if(r&&!n.forcePlaceholderSize)return;i.height()||i.height(t.currentItem.innerHeight()-parseInt(t.currentItem.css("paddingTop")||0,10)-parseInt(t.currentItem.css("paddingBottom")||0,10)),i.width()||i.width(t.currentItem.innerWidth()-parseInt(t.currentItem.css("paddingLeft")||0,10)-parseInt(t.currentItem.css("paddingRight")||0,10))}}}t.placeholder=e(n.placeholder.element.call(t.element,t.currentItem)),t.currentItem.after(t.placeholder),n.placeholder.update(t,t.placeholder)},_contactContainers:function(t){var n=null,r=null;for(var i=this.containers.length-1;i>=0;i--){if(e.contains(this.currentItem[0],this.containers[i].element[0]))continue;if(this._intersectsWith(this.containers[i].containerCache)){if(n&&e.contains(this.containers[i].element[0],n.element[0]))continue;n=this.containers[i],r=i}else this.containers[i].containerCache.over&&(this.containers[i]._trigger("out",t,this._uiHash(this)),this.containers[i].containerCache.over=0)}if(!n)return;if(this.containers.length===1)this.containers[r]._trigger("over",t,this._uiHash(this)),this.containers[r].containerCache.over=1;else{var s=1e4,o=null,u=this.containers[r].floating?"left":"top",a=this.containers[r].floating?"width":"height",f=this.positionAbs[u]+this.offset.click[u];for(var l=this.items.length-1;l>=0;l--){if(!e.contains(this.containers[r].element[0],this.items[l].item[0]))continue;if(this.items[l].item[0]==this.currentItem[0])continue;var c=this.items[l].item.offset()[u],h=!1;Math.abs(c-f)>Math.abs(c+this.items[l][a]-f)&&(h=!0,c+=this.items[l][a]),Math.abs(c-f)this.containment[2]&&(s=this.containment[2]+this.offset.click.left),t.pageY-this.offset.click.top>this.containment[3]&&(o=this.containment[3]+this.offset.click.top));if(n.grid){var u=this.originalPageY+Math.round((o-this.originalPageY)/n.grid[1])*n.grid[1];o=this.containment?u-this.offset.click.topthis.containment[3]?u-this.offset.click.topthis.containment[2]?a-this.offset.click.left=0;i--)n||r.push(function(e){return function(t){e._trigger("deactivate",t,this._uiHash(this))}}.call(this,this.containers[i])),this.containers[i].containerCache.over&&(r.push(function(e){return function(t){e._trigger("out",t,this._uiHash(this))}}.call(this,this.containers[i])),this.containers[i].containerCache.over=0);this._storedCursor&&e("body").css("cursor",this._storedCursor),this._storedOpacity&&this.helper.css("opacity",this._storedOpacity),this._storedZIndex&&this.helper.css("zIndex",this._storedZIndex=="auto"?"":this._storedZIndex),this.dragging=!1;if(this.cancelHelperRemoval){if(!n){this._trigger("beforeStop",t,this._uiHash());for(var i=0;i",widgetEventPrefix:"spin",options:{culture:null,icons:{down:"ui-icon-triangle-1-s",up:"ui-icon-triangle-1-n"},incremental:!0,max:null,min:null,numberFormat:null,page:10,step:1,change:null,spin:null,start:null,stop:null},_create:function(){this._setOption("max",this.options.max),this._setOption("min",this.options.min),this._setOption("step",this.options.step),this._value(this.element.val(),!0),this._draw(),this._on(this._events),this._refresh(),this._on(this.window,{beforeunload:function(){this.element.removeAttr("autocomplete")}})},_getCreateOptions:function(){var t={},n=this.element;return e.each(["min","max","step"],function(e,r){var i=n.attr(r);i!==undefined&&i.length&&(t[r]=i)}),t},_events:{keydown:function(e){this._start(e)&&this._keydown(e)&&e.preventDefault()},keyup:"_stop",focus:function(){this.previous=this.element.val()},blur:function(e){if(this.cancelBlur){delete this.cancelBlur;return}this._refresh(),this.previous!==this.element.val()&&this._trigger("change",e)},mousewheel:function(e,t){if(!t)return;if(!this.spinning&&!this._start(e))return!1;this._spin((t>0?1:-1)*this.options.step,e),clearTimeout(this.mousewheelTimer),this.mousewheelTimer=this._delay(function(){this.spinning&&this._stop(e)},100),e.preventDefault()},"mousedown .ui-spinner-button":function(t){function r(){var e=this.element[0]===this.document[0].activeElement;e||(this.element.focus(),this.previous=n,this._delay(function(){this.previous=n}))}var n;n=this.element[0]===this.document[0].activeElement?this.previous:this.element.val(),t.preventDefault(),r.call(this),this.cancelBlur=!0,this._delay(function(){delete this.cancelBlur,r.call(this)});if(this._start(t)===!1)return;this._repeat(null,e(t.currentTarget).hasClass("ui-spinner-up")?1:-1,t)},"mouseup .ui-spinner-button":"_stop","mouseenter .ui-spinner-button":function(t){if(!e(t.currentTarget).hasClass("ui-state-active"))return;if(this._start(t)===!1)return!1;this._repeat(null,e(t.currentTarget).hasClass("ui-spinner-up")?1:-1,t)},"mouseleave .ui-spinner-button":"_stop"},_draw:function(){var e=this.uiSpinner=this.element.addClass("ui-spinner-input").attr("autocomplete","off").wrap(this._uiSpinnerHtml()).parent().append(this._buttonHtml());this.element.attr("role","spinbutton"),this.buttons=e.find(".ui-spinner-button").attr("tabIndex",-1).button().removeClass("ui-corner-all"),this.buttons.height()>Math.ceil(e.height()*.5)&&e.height()>0&&e.height(e.height()),this.options.disabled&&this.disable()},_keydown:function(t){var n=this.options,r=e.ui.keyCode;switch(t.keyCode){case r.UP:return this._repeat(null,1,t),!0;case r.DOWN:return this._repeat(null,-1,t),!0;case r.PAGE_UP:return this._repeat(null,n.page,t),!0;case r.PAGE_DOWN:return this._repeat(null,-n.page,t),!0}return!1},_uiSpinnerHtml:function(){return""},_buttonHtml:function(){return""+""+""+""+""},_start:function(e){return!this.spinning&&this._trigger("start",e)===!1?!1:(this.counter||(this.counter=1),this.spinning=!0,!0)},_repeat:function(e,t,n){e=e||500,clearTimeout(this.timer),this.timer=this._delay(function(){this._repeat(40,t,n)},e),this._spin(t*this.options.step,n)},_spin:function(e,t){var n=this.value()||0;this.counter||(this.counter=1),n=this._adjustValue(n+e*this._increment(this.counter));if(!this.spinning||this._trigger("spin",t,{value:n})!==!1)this._value(n),this.counter++},_increment:function(t){var n=this.options.incremental;return n?e.isFunction(n)?n(t):Math.floor(t*t*t/5e4-t*t/500+17*t/200+1):1},_precision:function(){var e=this._precisionOf(this.options.step);return this.options.min!==null&&(e=Math.max(e,this._precisionOf(this.options.min))),e},_precisionOf:function(e){var t=e.toString(),n=t.indexOf(".");return n===-1?0:t.length-n-1},_adjustValue:function(e){var t,n,r=this.options;return t=r.min!==null?r.min:0,n=e-t,n=Math.round(n/r.step)*r.step,e=t+n,e=parseFloat(e.toFixed(this._precision())),r.max!==null&&e>r.max?r.max:r.min!==null&&e1&&e.href.replace(r,"")===location.href.replace(r,"").replace(/\s/g,"%20")}var n=0,r=/#.*$/;e.widget("ui.tabs",{version:"1.9.2",delay:300,options:{active:null,collapsible:!1,event:"click",heightStyle:"content",hide:null,show:null,activate:null,beforeActivate:null,beforeLoad:null,load:null},_create:function(){var t=this,n=this.options,r=n.active,i=location.hash.substring(1);this.running=!1,this.element.addClass("ui-tabs ui-widget ui-widget-content ui-corner-all").toggleClass("ui-tabs-collapsible",n.collapsible).delegate(".ui-tabs-nav > li","mousedown"+this.eventNamespace,function(t){e(this).is(".ui-state-disabled")&&t.preventDefault()}).delegate(".ui-tabs-anchor","focus"+this.eventNamespace,function(){e(this).closest("li").is(".ui-state-disabled")&&this.blur()}),this._processTabs();if(r===null){i&&this.tabs.each(function(t,n){if(e(n).attr("aria-controls")===i)return r=t,!1}),r===null&&(r=this.tabs.index(this.tabs.filter(".ui-tabs-active")));if(r===null||r===-1)r=this.tabs.length?0:!1}r!==!1&&(r=this.tabs.index(this.tabs.eq(r)),r===-1&&(r=n.collapsible?!1:0)),n.active=r,!n.collapsible&&n.active===!1&&this.anchors.length&&(n.active=0),e.isArray(n.disabled)&&(n.disabled=e.unique(n.disabled.concat(e.map(this.tabs.filter(".ui-state-disabled"),function(e){return t.tabs.index(e)}))).sort()),this.options.active!==!1&&this.anchors.length?this.active=this._findActive(this.options.active):this.active=e(),this._refresh(),this.active.length&&this.load(n.active)},_getCreateEventData:function(){return{tab:this.active,panel:this.active.length?this._getPanelForTab(this.active):e()}},_tabKeydown:function(t){var n=e(this.document[0].activeElement).closest("li"),r=this.tabs.index(n),i=!0;if(this._handlePageNav(t))return;switch(t.keyCode){case e.ui.keyCode.RIGHT:case e.ui.keyCode.DOWN:r++;break;case e.ui.keyCode.UP:case e.ui.keyCode.LEFT:i=!1,r--;break;case e.ui.keyCode.END:r=this.anchors.length-1;break;case e.ui.keyCode.HOME:r=0;break;case e.ui.keyCode.SPACE:t.preventDefault(),clearTimeout(this.activating),this._activate(r);return;case e.ui.keyCode.ENTER:t.preventDefault(),clearTimeout(this.activating),this._activate(r===this.options.active?!1:r);return;default:return}t.preventDefault(),clearTimeout(this.activating),r=this._focusNextTab(r,i),t.ctrlKey||(n.attr("aria-selected","false"),this.tabs.eq(r).attr("aria-selected","true"),this.activating=this._delay(function(){this.option("active",r)},this.delay))},_panelKeydown:function(t){if(this._handlePageNav(t))return;t.ctrlKey&&t.keyCode===e.ui.keyCode.UP&&(t.preventDefault(),this.active.focus())},_handlePageNav:function(t){if(t.altKey&&t.keyCode===e.ui.keyCode.PAGE_UP)return this._activate(this._focusNextTab(this.options.active-1,!1)),!0;if(t.altKey&&t.keyCode===e.ui.keyCode.PAGE_DOWN)return this._activate(this._focusNextTab(this.options.active+1,!0)),!0},_findNextTab:function(t,n){function i(){return t>r&&(t=0),t<0&&(t=r),t}var r=this.tabs.length-1;while(e.inArray(i(),this.options.disabled)!==-1)t=n?t+1:t-1;return t},_focusNextTab:function(e,t){return e=this._findNextTab(e,t),this.tabs.eq(e).focus(),e},_setOption:function(e,t){if(e==="active"){this._activate(t);return}if(e==="disabled"){this._setupDisabled(t);return}this._super(e,t),e==="collapsible"&&(this.element.toggleClass("ui-tabs-collapsible",t),!t&&this.options.active===!1&&this._activate(0)),e==="event"&&this._setupEvents(t),e==="heightStyle"&&this._setupHeightStyle(t)},_tabId:function(e){return e.attr("aria-controls")||"ui-tabs-"+i()},_sanitizeSelector:function(e){return e?e.replace(/[!"$%&'()*+,.\/:;<=>?@\[\]\^`{|}~]/g,"\\$&"):""},refresh:function(){var t=this.options,n=this.tablist.children(":has(a[href])");t.disabled=e.map(n.filter(".ui-state-disabled"),function(e){return n.index(e)}),this._processTabs(),t.active===!1||!this.anchors.length?(t.active=!1,this.active=e()):this.active.length&&!e.contains(this.tablist[0],this.active[0])?this.tabs.length===t.disabled.length?(t.active=!1,this.active=e()):this._activate(this._findNextTab(Math.max(0,t.active-1),!1)):t.active=this.tabs.index(this.active),this._refresh()},_refresh:function(){this._setupDisabled(this.options.disabled),this._setupEvents(this.options.event),this._setupHeightStyle(this.options.heightStyle),this.tabs.not(this.active).attr({"aria-selected":"false",tabIndex:-1}),this.panels.not(this._getPanelForTab(this.active)).hide().attr({"aria-expanded":"false","aria-hidden":"true"}),this.active.length?(this.active.addClass("ui-tabs-active ui-state-active").attr({"aria-selected":"true",tabIndex:0}),this._getPanelForTab(this.active).show().attr({"aria-expanded":"true","aria-hidden":"false"})):this.tabs.eq(0).attr("tabIndex",0)},_processTabs:function(){var t=this;this.tablist=this._getList().addClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all").attr("role","tablist"),this.tabs=this.tablist.find("> li:has(a[href])").addClass("ui-state-default ui-corner-top").attr({role:"tab",tabIndex:-1}),this.anchors=this.tabs.map(function(){return e("a",this)[0]}).addClass("ui-tabs-anchor").attr({role:"presentation",tabIndex:-1}),this.panels=e(),this.anchors.each(function(n,r){var i,o,u,a=e(r).uniqueId().attr("id"),f=e(r).closest("li"),l=f.attr("aria-controls");s(r)?(i=r.hash,o=t.element.find(t._sanitizeSelector(i))):(u=t._tabId(f),i="#"+u,o=t.element.find(i),o.length||(o=t._createPanel(u),o.insertAfter(t.panels[n-1]||t.tablist)),o.attr("aria-live","polite")),o.length&&(t.panels=t.panels.add(o)),l&&f.data("ui-tabs-aria-controls",l),f.attr({"aria-controls":i.substring(1),"aria-labelledby":a}),o.attr("aria-labelledby",a)}),this.panels.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom").attr("role","tabpanel")},_getList:function(){return this.element.find("ol,ul").eq(0)},_createPanel:function(t){return e("
        ").attr("id",t).addClass("ui-tabs-panel ui-widget-content ui-corner-bottom").data("ui-tabs-destroy",!0)},_setupDisabled:function(t){e.isArray(t)&&(t.length?t.length===this.anchors.length&&(t=!0):t=!1);for(var n=0,r;r=this.tabs[n];n++)t===!0||e.inArray(n,t)!==-1?e(r).addClass("ui-state-disabled").attr("aria-disabled","true"):e(r).removeClass("ui-state-disabled").removeAttr("aria-disabled");this.options.disabled=t},_setupEvents:function(t){var n={click:function(e){e.preventDefault()}};t&&e.each(t.split(" "),function(e,t){n[t]="_eventHandler"}),this._off(this.anchors.add(this.tabs).add(this.panels)),this._on(this.anchors,n),this._on(this.tabs,{keydown:"_tabKeydown"}),this._on(this.panels,{keydown:"_panelKeydown"}),this._focusable(this.tabs),this._hoverable(this.tabs)},_setupHeightStyle:function(t){var n,r,i=this.element.parent();t==="fill"?(e.support.minHeight||(r=i.css("overflow"),i.css("overflow","hidden")),n=i.height(),this.element.siblings(":visible").each(function(){var t=e(this),r=t.css("position");if(r==="absolute"||r==="fixed")return;n-=t.outerHeight(!0)}),r&&i.css("overflow",r),this.element.children().not(this.panels).each(function(){n-=e(this).outerHeight(!0)}),this.panels.each(function(){e(this).height(Math.max(0,n-e(this).innerHeight()+e(this).height()))}).css("overflow","auto")):t==="auto"&&(n=0,this.panels.each(function(){n=Math.max(n,e(this).height("").height())}).height(n))},_eventHandler:function(t){var n=this.options,r=this.active,i=e(t.currentTarget),s=i.closest("li"),o=s[0]===r[0],u=o&&n.collapsible,a=u?e():this._getPanelForTab(s),f=r.length?this._getPanelForTab(r):e(),l={oldTab:r,oldPanel:f,newTab:u?e():s,newPanel:a};t.preventDefault();if(s.hasClass("ui-state-disabled")||s.hasClass("ui-tabs-loading")||this.running||o&&!n.collapsible||this._trigger("beforeActivate",t,l)===!1)return;n.active=u?!1:this.tabs.index(s),this.active=o?e():s,this.xhr&&this.xhr.abort(),!f.length&&!a.length&&e.error("jQuery UI Tabs: Mismatching fragment identifier."),a.length&&this.load(this.tabs.index(s),t),this._toggle(t,l)},_toggle:function(t,n){function o(){r.running=!1,r._trigger("activate",t,n)}function u(){n.newTab.closest("li").addClass("ui-tabs-active ui-state-active"),i.length&&r.options.show?r._show(i,r.options.show,o):(i.show(),o())}var r=this,i=n.newPanel,s=n.oldPanel;this.running=!0,s.length&&this.options.hide?this._hide(s,this.options.hide,function(){n.oldTab.closest("li").removeClass("ui-tabs-active ui-state-active"),u()}):(n.oldTab.closest("li").removeClass("ui-tabs-active ui-state-active"),s.hide(),u()),s.attr({"aria-expanded":"false","aria-hidden":"true"}),n.oldTab.attr("aria-selected","false"),i.length&&s.length?n.oldTab.attr("tabIndex",-1):i.length&&this.tabs.filter(function(){return e(this).attr("tabIndex")===0}).attr("tabIndex",-1),i.attr({"aria-expanded":"true","aria-hidden":"false"}),n.newTab.attr({"aria-selected":"true",tabIndex:0})},_activate:function(t){var n,r=this._findActive(t);if(r[0]===this.active[0])return;r.length||(r=this.active),n=r.find(".ui-tabs-anchor")[0],this._eventHandler({target:n,currentTarget:n,preventDefault:e.noop})},_findActive:function(t){return t===!1?e():this.tabs.eq(t)},_getIndex:function(e){return typeof e=="string"&&(e=this.anchors.index(this.anchors.filter("[href$='"+e+"']"))),e},_destroy:function(){this.xhr&&this.xhr.abort(),this.element.removeClass("ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible"),this.tablist.removeClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all").removeAttr("role"),this.anchors.removeClass("ui-tabs-anchor").removeAttr("role").removeAttr("tabIndex").removeData("href.tabs").removeData("load.tabs").removeUniqueId(),this.tabs.add(this.panels).each(function(){e.data(this,"ui-tabs-destroy")?e(this).remove():e(this).removeClass("ui-state-default ui-state-active ui-state-disabled ui-corner-top ui-corner-bottom ui-widget-content ui-tabs-active ui-tabs-panel").removeAttr("tabIndex").removeAttr("aria-live").removeAttr("aria-busy").removeAttr("aria-selected").removeAttr("aria-labelledby").removeAttr("aria-hidden").removeAttr("aria-expanded").removeAttr("role")}),this.tabs.each(function(){var t=e(this),n=t.data("ui-tabs-aria-controls");n?t.attr("aria-controls",n):t.removeAttr("aria-controls")}),this.panels.show(),this.options.heightStyle!=="content"&&this.panels.css("height","")},enable:function(n){var r=this.options.disabled;if(r===!1)return;n===t?r=!1:(n=this._getIndex(n),e.isArray(r)?r=e.map(r,function(e){return e!==n?e:null}):r=e.map(this.tabs,function(e,t){return t!==n?t:null})),this._setupDisabled(r)},disable:function(n){var r=this.options.disabled;if(r===!0)return;if(n===t)r=!0;else{n=this._getIndex(n);if(e.inArray(n,r)!==-1)return;e.isArray(r)?r=e.merge([n],r).sort():r=[n]}this._setupDisabled(r)},load:function(t,n){t=this._getIndex(t);var r=this,i=this.tabs.eq(t),o=i.find(".ui-tabs-anchor"),u=this._getPanelForTab(i),a={tab:i,panel:u};if(s(o[0]))return;this.xhr=e.ajax(this._ajaxSettings(o,n,a)),this.xhr&&this.xhr.statusText!=="canceled"&&(i.addClass("ui-tabs-loading"),u.attr("aria-busy","true"),this.xhr.success(function(e){setTimeout(function(){u.html(e),r._trigger("load",n,a)},1)}).complete(function(e,t){setTimeout(function(){t==="abort"&&r.panels.stop(!1,!0),i.removeClass("ui-tabs-loading"),u.removeAttr("aria-busy"),e===r.xhr&&delete r.xhr},1)}))},_ajaxSettings:function(t,n,r){var i=this;return{url:t.attr("href"),beforeSend:function(t,s){return i._trigger("beforeLoad",n,e.extend({jqXHR:t,ajaxSettings:s},r))}}},_getPanelForTab:function(t){var n=e(t).attr("aria-controls");return this.element.find(this._sanitizeSelector("#"+n))}}),e.uiBackCompat!==!1&&(e.ui.tabs.prototype._ui=function(e,t){return{tab:e,panel:t,index:this.anchors.index(e)}},e.widget("ui.tabs",e.ui.tabs,{url:function(e,t){this.anchors.eq(e).attr("href",t)}}),e.widget("ui.tabs",e.ui.tabs,{options:{ajaxOptions:null,cache:!1},_create:function(){this._super();var t=this;this._on({tabsbeforeload:function(n,r){if(e.data(r.tab[0],"cache.tabs")){n.preventDefault();return}r.jqXHR.success(function(){t.options.cache&&e.data(r.tab[0],"cache.tabs",!0)})}})},_ajaxSettings:function(t,n,r){var i=this.options.ajaxOptions;return e.extend({},i,{error:function(e,t){try{i.error(e,t,r.tab.closest("li").index(),r.tab[0])}catch(n){}}},this._superApply(arguments))},_setOption:function(e,t){e==="cache"&&t===!1&&this.anchors.removeData("cache.tabs"),this._super(e,t)},_destroy:function(){this.anchors.removeData("cache.tabs"),this._super()},url:function(e){this.anchors.eq(e).removeData("cache.tabs"),this._superApply(arguments)}}),e.widget("ui.tabs",e.ui.tabs,{abort:function(){this.xhr&&this.xhr.abort()}}),e.widget("ui.tabs",e.ui.tabs,{options:{spinner:"Loading…"},_create:function(){this._super(),this._on({tabsbeforeload:function(e,t){if(e.target!==this.element[0]||!this.options.spinner)return;var n=t.tab.find("span"),r=n.html();n.html(this.options.spinner),t.jqXHR.complete(function(){n.html(r)})}})}}),e.widget("ui.tabs",e.ui.tabs,{options:{enable:null,disable:null},enable:function(t){var n=this.options,r;if(t&&n.disabled===!0||e.isArray(n.disabled)&&e.inArray(t,n.disabled)!==-1)r=!0;this._superApply(arguments),r&&this._trigger("enable",null,this._ui(this.anchors[t],this.panels[t]))},disable:function(t){var n=this.options,r;if(t&&n.disabled===!1||e.isArray(n.disabled)&&e.inArray(t,n.disabled)===-1)r=!0;this._superApply(arguments),r&&this._trigger("disable",null,this._ui(this.anchors[t],this.panels[t]))}}),e.widget("ui.tabs",e.ui.tabs,{options:{add:null,remove:null,tabTemplate:"
      • #{label}
      • "},add:function(n,r,i){i===t&&(i=this.anchors.length);var s,o,u=this.options,a=e(u.tabTemplate.replace(/#\{href\}/g,n).replace(/#\{label\}/g,r)),f=n.indexOf("#")?this._tabId(a):n.replace("#","");return a.addClass("ui-state-default ui-corner-top").data("ui-tabs-destroy",!0),a.attr("aria-controls",f),s=i>=this.tabs.length,o=this.element.find("#"+f),o.length||(o=this._createPanel(f),s?i>0?o.insertAfter(this.panels.eq(-1)):o.appendTo(this.element):o.insertBefore(this.panels[i])),o.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom").hide(),s?a.appendTo(this.tablist):a.insertBefore(this.tabs[i]),u.disabled=e.map(u.disabled,function(e){return e>=i?++e:e}),this.refresh(),this.tabs.length===1&&u.active===!1&&this.option("active",0),this._trigger("add",null,this._ui(this.anchors[i],this.panels[i])),this},remove:function(t){t=this._getIndex(t);var n=this.options,r=this.tabs.eq(t).remove(),i=this._getPanelForTab(r).remove();return r.hasClass("ui-tabs-active")&&this.anchors.length>2&&this._activate(t+(t+1=t?--e:e}),this.refresh(),this._trigger("remove",null,this._ui(r.find("a")[0],i[0])),this}}),e.widget("ui.tabs",e.ui.tabs,{length:function(){return this.anchors.length}}),e.widget("ui.tabs",e.ui.tabs,{options:{idPrefix:"ui-tabs-"},_tabId:function(t){var n=t.is("li")?t.find("a[href]"):t;return n=n[0],e(n).closest("li").attr("aria-controls")||n.title&&n.title.replace(/\s/g,"_").replace(/[^\w\u00c0-\uFFFF\-]/g,"")||this.options.idPrefix+i()}}),e.widget("ui.tabs",e.ui.tabs,{options:{panelTemplate:"
        "},_createPanel:function(t){return e(this.options.panelTemplate).attr("id",t).addClass("ui-tabs-panel ui-widget-content ui-corner-bottom").data("ui-tabs-destroy",!0)}}),e.widget("ui.tabs",e.ui.tabs,{_create:function(){var e=this.options;e.active===null&&e.selected!==t&&(e.active=e.selected===-1?!1:e.selected),this._super(),e.selected=e.active,e.selected===!1&&(e.selected=-1)},_setOption:function(e,t){if(e!=="selected")return this._super(e,t);var n=this.options;this._super("active",t===-1?!1:t),n.selected=n.active,n.selected===!1&&(n.selected=-1)},_eventHandler:function(){this._superApply(arguments),this.options.selected=this.options.active,this.options.selected===!1&&(this.options.selected=-1)}}),e.widget("ui.tabs",e.ui.tabs,{options:{show:null,select:null},_create:function(){this._super(),this.options.active!==!1&&this._trigger("show",null,this._ui(this.active.find(".ui-tabs-anchor")[0],this._getPanelForTab(this.active)[0]))},_trigger:function(e,t,n){var r,i,s=this._superApply(arguments);return s?(e==="beforeActivate"?(r=n.newTab.length?n.newTab:n.oldTab,i=n.newPanel.length?n.newPanel:n.oldPanel,s=this._super("select",t,{tab:r.find(".ui-tabs-anchor")[0],panel:i[0],index:r.closest("li").index()})):e==="activate"&&n.newTab.length&&(s=this._super("show",t,{tab:n.newTab.find(".ui-tabs-anchor")[0],panel:n.newPanel[0],index:n.newTab.closest("li").index()})),s):!1}}),e.widget("ui.tabs",e.ui.tabs,{select:function(e){e=this._getIndex(e);if(e===-1){if(!this.options.collapsible||this.options.selected===-1)return;e=this.options.selected}this.anchors.eq(e).trigger(this.options.event+this.eventNamespace)}}),function(){var t=0;e.widget("ui.tabs",e.ui.tabs,{options:{cookie:null},_create:function(){var e=this.options,t;e.active==null&&e.cookie&&(t=parseInt(this._cookie(),10),t===-1&&(t=!1),e.active=t),this._super()},_cookie:function(n){var r=[this.cookie||(this.cookie=this.options.cookie.name||"ui-tabs-"+ ++t)];return arguments.length&&(r.push(n===!1?-1:n),r.push(this.options.cookie)),e.cookie.apply(null,r)},_refresh:function(){this._super(),this.options.cookie&&this._cookie(this.options.active,this.options.cookie)},_eventHandler:function(){this._superApply(arguments),this.options.cookie&&this._cookie(this.options.active,this.options.cookie)},_destroy:function(){this._super(),this.options.cookie&&this._cookie(null,this.options.cookie)}})}(),e.widget("ui.tabs",e.ui.tabs,{_trigger:function(t,n,r){var i=e.extend({},r);return t==="load"&&(i.panel=i.panel[0],i.tab=i.tab.find(".ui-tabs-anchor")[0]),this._super(t,n,i)}}),e.widget("ui.tabs",e.ui.tabs,{options:{fx:null},_getFx:function(){var t,n,r=this.options.fx;return r&&(e.isArray(r)?(t=r[0],n=r[1]):t=n=r),r?{show:n,hide:t}:null},_toggle:function(e,t){function o(){n.running=!1,n._trigger("activate",e,t)}function u(){t.newTab.closest("li").addClass("ui-tabs-active ui-state-active"),r.length&&s.show?r.animate(s.show,s.show.duration,function(){o()}):(r.show(),o())}var n=this,r=t.newPanel,i=t.oldPanel,s=this._getFx();if(!s)return this._super(e,t);n.running=!0,i.length&&s.hide?i.animate(s.hide,s.hide.duration,function(){t.oldTab.closest("li").removeClass("ui-tabs-active ui-state-active"),u()}):(t.oldTab.closest("li").removeClass("ui-tabs-active ui-state-active"),i.hide(),u())}}))})(jQuery);(function(e){function n(t,n){var r=(t.attr("aria-describedby")||"").split(/\s+/);r.push(n),t.data("ui-tooltip-id",n).attr("aria-describedby",e.trim(r.join(" ")))}function r(t){var n=t.data("ui-tooltip-id"),r=(t.attr("aria-describedby")||"").split(/\s+/),i=e.inArray(n,r);i!==-1&&r.splice(i,1),t.removeData("ui-tooltip-id"),r=e.trim(r.join(" ")),r?t.attr("aria-describedby",r):t.removeAttr("aria-describedby")}var t=0;e.widget("ui.tooltip",{version:"1.9.2",options:{content:function(){return e(this).attr("title")},hide:!0,items:"[title]:not([disabled])",position:{my:"left top+15",at:"left bottom",collision:"flipfit flip"},show:!0,tooltipClass:null,track:!1,close:null,open:null},_create:function(){this._on({mouseover:"open",focusin:"open"}),this.tooltips={},this.parents={},this.options.disabled&&this._disable()},_setOption:function(t,n){var r=this;if(t==="disabled"){this[n?"_disable":"_enable"](),this.options[t]=n;return}this._super(t,n),t==="content"&&e.each(this.tooltips,function(e,t){r._updateContent(t)})},_disable:function(){var t=this;e.each(this.tooltips,function(n,r){var i=e.Event("blur");i.target=i.currentTarget=r[0],t.close(i,!0)}),this.element.find(this.options.items).andSelf().each(function(){var t=e(this);t.is("[title]")&&t.data("ui-tooltip-title",t.attr("title")).attr("title","")})},_enable:function(){this.element.find(this.options.items).andSelf().each(function(){var t=e(this);t.data("ui-tooltip-title")&&t.attr("title",t.data("ui-tooltip-title"))})},open:function(t){var n=this,r=e(t?t.target:this.element).closest(this.options.items);if(!r.length||r.data("ui-tooltip-id"))return;r.attr("title")&&r.data("ui-tooltip-title",r.attr("title")),r.data("ui-tooltip-open",!0),t&&t.type==="mouseover"&&r.parents().each(function(){var t=e(this),r;t.data("ui-tooltip-open")&&(r=e.Event("blur"),r.target=r.currentTarget=this,n.close(r,!0)),t.attr("title")&&(t.uniqueId(),n.parents[this.id]={element:this,title:t.attr("title")},t.attr("title",""))}),this._updateContent(r,t)},_updateContent:function(e,t){var n,r=this.options.content,i=this,s=t?t.type:null;if(typeof r=="string")return this._open(t,e,r);n=r.call(e[0],function(n){if(!e.data("ui-tooltip-open"))return;i._delay(function(){t&&(t.type=s),this._open(t,e,n)})}),n&&this._open(t,e,n)},_open:function(t,r,i){function f(e){a.of=e;if(s.is(":hidden"))return;s.position(a)}var s,o,u,a=e.extend({},this.options.position);if(!i)return;s=this._find(r);if(s.length){s.find(".ui-tooltip-content").html(i);return}r.is("[title]")&&(t&&t.type==="mouseover"?r.attr("title",""):r.removeAttr("title")),s=this._tooltip(r),n(r,s.attr("id")),s.find(".ui-tooltip-content").html(i),this.options.track&&t&&/^mouse/.test(t.type)?(this._on(this.document,{mousemove:f}),f(t)):s.position(e.extend({of:r},this.options.position)),s.hide(),this._show(s,this.options.show),this.options.show&&this.options.show.delay&&(u=setInterval(function(){s.is(":visible")&&(f(a.of),clearInterval(u))},e.fx.interval)),this._trigger("open",t,{tooltip:s}),o={keyup:function(t){if(t.keyCode===e.ui.keyCode.ESCAPE){var n=e.Event(t);n.currentTarget=r[0],this.close(n,!0)}},remove:function(){this._removeTooltip(s)}};if(!t||t.type==="mouseover")o.mouseleave="close";if(!t||t.type==="focusin")o.focusout="close";this._on(!0,r,o)},close:function(t){var n=this,i=e(t?t.currentTarget:this.element),s=this._find(i);if(this.closing)return;i.data("ui-tooltip-title")&&i.attr("title",i.data("ui-tooltip-title")),r(i),s.stop(!0),this._hide(s,this.options.hide,function(){n._removeTooltip(e(this))}),i.removeData("ui-tooltip-open"),this._off(i,"mouseleave focusout keyup"),i[0]!==this.element[0]&&this._off(i,"remove"),this._off(this.document,"mousemove"),t&&t.type==="mouseleave"&&e.each(this.parents,function(t,r){e(r.element).attr("title",r.title),delete n.parents[t]}),this.closing=!0,this._trigger("close",t,{tooltip:s}),this.closing=!1},_tooltip:function(n){var r="ui-tooltip-"+t++,i=e("
        ").attr({id:r,role:"tooltip"}).addClass("ui-tooltip ui-widget ui-corner-all ui-widget-content "+(this.options.tooltipClass||""));return e("
        ").addClass("ui-tooltip-content").appendTo(i),i.appendTo(this.document[0].body),e.fn.bgiframe&&i.bgiframe(),this.tooltips[r]=n,i},_find:function(t){var n=t.data("ui-tooltip-id");return n?e("#"+n):e()},_removeTooltip:function(e){e.remove(),delete this.tooltips[e.attr("id")]},_destroy:function(){var t=this;e.each(this.tooltips,function(n,r){var i=e.Event("blur");i.target=i.currentTarget=r[0],t.close(i,!0),e("#"+n).remove(),r.data("ui-tooltip-title")&&(r.attr("title",r.data("ui-tooltip-title")),r.removeData("ui-tooltip-title"))})}})})(jQuery); \ No newline at end of file diff --git a/lib/scripts/jquery/jquery.cookie.js b/lib/scripts/jquery/jquery.cookie.js index 6a3e394b4..2d4c05a84 100644 --- a/lib/scripts/jquery/jquery.cookie.js +++ b/lib/scripts/jquery/jquery.cookie.js @@ -1,41 +1,72 @@ -/** - * jQuery Cookie plugin +/*! + * jQuery Cookie Plugin v1.3 + * https://github.com/carhartl/jquery-cookie * - * Copyright (c) 2010 Klaus Hartl (stilbuero.de) - * Dual licensed under the MIT and GPL licenses: + * Copyright 2011, Klaus Hartl + * Dual licensed under the MIT or GPL Version 2 licenses. * http://www.opensource.org/licenses/mit-license.php - * http://www.gnu.org/licenses/gpl.html - * + * http://www.opensource.org/licenses/GPL-2.0 */ -jQuery.cookie = function (key, value, options) { - - // key and at least value given, set cookie... - if (arguments.length > 1 && String(value) !== "[object Object]") { - options = jQuery.extend({}, options); - - if (value === null || value === undefined) { - options.expires = -1; - } - - if (typeof options.expires === 'number') { - var days = options.expires, t = options.expires = new Date(); - t.setDate(t.getDate() + days); - } - - value = String(value); - - return (document.cookie = [ - encodeURIComponent(key), '=', - options.raw ? value : encodeURIComponent(value), - options.expires ? '; expires=' + options.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE - options.path ? '; path=' + options.path : '', - options.domain ? '; domain=' + options.domain : '', - options.secure ? '; secure' : '' - ].join('')); - } - - // key and possibly options given, get cookie... - options = value || {}; - var result, decode = options.raw ? function (s) { return s; } : decodeURIComponent; - return (result = new RegExp('(?:^|; )' + encodeURIComponent(key) + '=([^;]*)').exec(document.cookie)) ? decode(result[1]) : null; -}; +(function ($, document, undefined) { + + var pluses = /\+/g; + + function raw(s) { + return s; + } + + function decoded(s) { + return decodeURIComponent(s.replace(pluses, ' ')); + } + + var config = $.cookie = function (key, value, options) { + + // write + if (value !== undefined) { + options = $.extend({}, config.defaults, options); + + if (value === null) { + options.expires = -1; + } + + if (typeof options.expires === 'number') { + var days = options.expires, t = options.expires = new Date(); + t.setDate(t.getDate() + days); + } + + value = config.json ? JSON.stringify(value) : String(value); + + return (document.cookie = [ + encodeURIComponent(key), '=', config.raw ? value : encodeURIComponent(value), + options.expires ? '; expires=' + options.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE + options.path ? '; path=' + options.path : '', + options.domain ? '; domain=' + options.domain : '', + options.secure ? '; secure' : '' + ].join('')); + } + + // read + var decode = config.raw ? raw : decoded; + var cookies = document.cookie.split('; '); + for (var i = 0, l = cookies.length; i < l; i++) { + var parts = cookies[i].split('='); + if (decode(parts.shift()) === key) { + var cookie = decode(parts.join('=')); + return config.json ? JSON.parse(cookie) : cookie; + } + } + + return null; + }; + + config.defaults = {}; + + $.removeCookie = function (key, options) { + if ($.cookie(key) !== null) { + $.cookie(key, null, options); + return true; + } + return false; + }; + +})(jQuery, document); diff --git a/lib/scripts/jquery/jquery.js b/lib/scripts/jquery/jquery.js deleted file mode 100644 index 719e1d4ec..000000000 --- a/lib/scripts/jquery/jquery.js +++ /dev/null @@ -1,9046 +0,0 @@ -/*! - * jQuery JavaScript Library v1.6.4 - * http://jquery.com/ - * - * Copyright 2011, John Resig - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * Includes Sizzle.js - * http://sizzlejs.com/ - * Copyright 2011, The Dojo Foundation - * Released under the MIT, BSD, and GPL Licenses. - * - * Date: Mon Sep 12 18:54:48 2011 -0400 - */ -(function( window, undefined ) { - -// Use the correct document accordingly with window argument (sandbox) -var document = window.document, - navigator = window.navigator, - location = window.location; -var jQuery = (function() { - -// Define a local copy of jQuery -var jQuery = function( selector, context ) { - // The jQuery object is actually just the init constructor 'enhanced' - return new jQuery.fn.init( selector, context, rootjQuery ); - }, - - // Map over jQuery in case of overwrite - _jQuery = window.jQuery, - - // Map over the $ in case of overwrite - _$ = window.$, - - // A central reference to the root jQuery(document) - rootjQuery, - - // A simple way to check for HTML strings or ID strings - // Prioritize #id over to avoid XSS via location.hash (#9521) - quickExpr = /^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/, - - // Check if a string has a non-whitespace character in it - rnotwhite = /\S/, - - // Used for trimming whitespace - trimLeft = /^\s+/, - trimRight = /\s+$/, - - // Check for digits - rdigit = /\d/, - - // Match a standalone tag - rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>)?$/, - - // JSON RegExp - rvalidchars = /^[\],:{}\s]*$/, - rvalidescape = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, - rvalidtokens = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, - rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g, - - // Useragent RegExp - rwebkit = /(webkit)[ \/]([\w.]+)/, - ropera = /(opera)(?:.*version)?[ \/]([\w.]+)/, - rmsie = /(msie) ([\w.]+)/, - rmozilla = /(mozilla)(?:.*? rv:([\w.]+))?/, - - // Matches dashed string for camelizing - rdashAlpha = /-([a-z]|[0-9])/ig, - rmsPrefix = /^-ms-/, - - // Used by jQuery.camelCase as callback to replace() - fcamelCase = function( all, letter ) { - return ( letter + "" ).toUpperCase(); - }, - - // Keep a UserAgent string for use with jQuery.browser - userAgent = navigator.userAgent, - - // For matching the engine and version of the browser - browserMatch, - - // The deferred used on DOM ready - readyList, - - // The ready event handler - DOMContentLoaded, - - // Save a reference to some core methods - toString = Object.prototype.toString, - hasOwn = Object.prototype.hasOwnProperty, - push = Array.prototype.push, - slice = Array.prototype.slice, - trim = String.prototype.trim, - indexOf = Array.prototype.indexOf, - - // [[Class]] -> type pairs - class2type = {}; - -jQuery.fn = jQuery.prototype = { - constructor: jQuery, - init: function( selector, context, rootjQuery ) { - var match, elem, ret, doc; - - // Handle $(""), $(null), or $(undefined) - if ( !selector ) { - return this; - } - - // Handle $(DOMElement) - if ( selector.nodeType ) { - this.context = this[0] = selector; - this.length = 1; - return this; - } - - // The body element only exists once, optimize finding it - if ( selector === "body" && !context && document.body ) { - this.context = document; - this[0] = document.body; - this.selector = selector; - this.length = 1; - return this; - } - - // Handle HTML strings - if ( typeof selector === "string" ) { - // Are we dealing with HTML string or an ID? - if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) { - // Assume that strings that start and end with <> are HTML and skip the regex check - match = [ null, selector, null ]; - - } else { - match = quickExpr.exec( selector ); - } - - // Verify a match, and that no context was specified for #id - if ( match && (match[1] || !context) ) { - - // HANDLE: $(html) -> $(array) - if ( match[1] ) { - context = context instanceof jQuery ? context[0] : context; - doc = (context ? context.ownerDocument || context : document); - - // If a single string is passed in and it's a single tag - // just do a createElement and skip the rest - ret = rsingleTag.exec( selector ); - - if ( ret ) { - if ( jQuery.isPlainObject( context ) ) { - selector = [ document.createElement( ret[1] ) ]; - jQuery.fn.attr.call( selector, context, true ); - - } else { - selector = [ doc.createElement( ret[1] ) ]; - } - - } else { - ret = jQuery.buildFragment( [ match[1] ], [ doc ] ); - selector = (ret.cacheable ? jQuery.clone(ret.fragment) : ret.fragment).childNodes; - } - - return jQuery.merge( this, selector ); - - // HANDLE: $("#id") - } else { - elem = document.getElementById( match[2] ); - - // Check parentNode to catch when Blackberry 4.6 returns - // nodes that are no longer in the document #6963 - if ( elem && elem.parentNode ) { - // Handle the case where IE and Opera return items - // by name instead of ID - if ( elem.id !== match[2] ) { - return rootjQuery.find( selector ); - } - - // Otherwise, we inject the element directly into the jQuery object - this.length = 1; - this[0] = elem; - } - - this.context = document; - this.selector = selector; - return this; - } - - // HANDLE: $(expr, $(...)) - } else if ( !context || context.jquery ) { - return (context || rootjQuery).find( selector ); - - // HANDLE: $(expr, context) - // (which is just equivalent to: $(context).find(expr) - } else { - return this.constructor( context ).find( selector ); - } - - // HANDLE: $(function) - // Shortcut for document ready - } else if ( jQuery.isFunction( selector ) ) { - return rootjQuery.ready( selector ); - } - - if (selector.selector !== undefined) { - this.selector = selector.selector; - this.context = selector.context; - } - - return jQuery.makeArray( selector, this ); - }, - - // Start with an empty selector - selector: "", - - // The current version of jQuery being used - jquery: "1.6.4", - - // The default length of a jQuery object is 0 - length: 0, - - // The number of elements contained in the matched element set - size: function() { - return this.length; - }, - - toArray: function() { - return slice.call( this, 0 ); - }, - - // Get the Nth element in the matched element set OR - // Get the whole matched element set as a clean array - get: function( num ) { - return num == null ? - - // Return a 'clean' array - this.toArray() : - - // Return just the object - ( num < 0 ? this[ this.length + num ] : this[ num ] ); - }, - - // Take an array of elements and push it onto the stack - // (returning the new matched element set) - pushStack: function( elems, name, selector ) { - // Build a new jQuery matched element set - var ret = this.constructor(); - - if ( jQuery.isArray( elems ) ) { - push.apply( ret, elems ); - - } else { - jQuery.merge( ret, elems ); - } - - // Add the old object onto the stack (as a reference) - ret.prevObject = this; - - ret.context = this.context; - - if ( name === "find" ) { - ret.selector = this.selector + (this.selector ? " " : "") + selector; - } else if ( name ) { - ret.selector = this.selector + "." + name + "(" + selector + ")"; - } - - // Return the newly-formed element set - return ret; - }, - - // Execute a callback for every element in the matched set. - // (You can seed the arguments with an array of args, but this is - // only used internally.) - each: function( callback, args ) { - return jQuery.each( this, callback, args ); - }, - - ready: function( fn ) { - // Attach the listeners - jQuery.bindReady(); - - // Add the callback - readyList.done( fn ); - - return this; - }, - - eq: function( i ) { - return i === -1 ? - this.slice( i ) : - this.slice( i, +i + 1 ); - }, - - first: function() { - return this.eq( 0 ); - }, - - last: function() { - return this.eq( -1 ); - }, - - slice: function() { - return this.pushStack( slice.apply( this, arguments ), - "slice", slice.call(arguments).join(",") ); - }, - - map: function( callback ) { - return this.pushStack( jQuery.map(this, function( elem, i ) { - return callback.call( elem, i, elem ); - })); - }, - - end: function() { - return this.prevObject || this.constructor(null); - }, - - // For internal use only. - // Behaves like an Array's method, not like a jQuery method. - push: push, - sort: [].sort, - splice: [].splice -}; - -// Give the init function the jQuery prototype for later instantiation -jQuery.fn.init.prototype = jQuery.fn; - -jQuery.extend = jQuery.fn.extend = function() { - var options, name, src, copy, copyIsArray, clone, - target = arguments[0] || {}, - i = 1, - length = arguments.length, - deep = false; - - // Handle a deep copy situation - if ( typeof target === "boolean" ) { - deep = target; - target = arguments[1] || {}; - // skip the boolean and the target - i = 2; - } - - // Handle case when target is a string or something (possible in deep copy) - if ( typeof target !== "object" && !jQuery.isFunction(target) ) { - target = {}; - } - - // extend jQuery itself if only one argument is passed - if ( length === i ) { - target = this; - --i; - } - - for ( ; i < length; i++ ) { - // Only deal with non-null/undefined values - if ( (options = arguments[ i ]) != null ) { - // Extend the base object - for ( name in options ) { - src = target[ name ]; - copy = options[ name ]; - - // Prevent never-ending loop - if ( target === copy ) { - continue; - } - - // Recurse if we're merging plain objects or arrays - if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) { - if ( copyIsArray ) { - copyIsArray = false; - clone = src && jQuery.isArray(src) ? src : []; - - } else { - clone = src && jQuery.isPlainObject(src) ? src : {}; - } - - // Never move original objects, clone them - target[ name ] = jQuery.extend( deep, clone, copy ); - - // Don't bring in undefined values - } else if ( copy !== undefined ) { - target[ name ] = copy; - } - } - } - } - - // Return the modified object - return target; -}; - -jQuery.extend({ - noConflict: function( deep ) { - if ( window.$ === jQuery ) { - window.$ = _$; - } - - if ( deep && window.jQuery === jQuery ) { - window.jQuery = _jQuery; - } - - return jQuery; - }, - - // Is the DOM ready to be used? Set to true once it occurs. - isReady: false, - - // A counter to track how many items to wait for before - // the ready event fires. See #6781 - readyWait: 1, - - // Hold (or release) the ready event - holdReady: function( hold ) { - if ( hold ) { - jQuery.readyWait++; - } else { - jQuery.ready( true ); - } - }, - - // Handle when the DOM is ready - ready: function( wait ) { - // Either a released hold or an DOMready/load event and not yet ready - if ( (wait === true && !--jQuery.readyWait) || (wait !== true && !jQuery.isReady) ) { - // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). - if ( !document.body ) { - return setTimeout( jQuery.ready, 1 ); - } - - // Remember that the DOM is ready - jQuery.isReady = true; - - // If a normal DOM Ready event fired, decrement, and wait if need be - if ( wait !== true && --jQuery.readyWait > 0 ) { - return; - } - - // If there are functions bound, to execute - readyList.resolveWith( document, [ jQuery ] ); - - // Trigger any bound ready events - if ( jQuery.fn.trigger ) { - jQuery( document ).trigger( "ready" ).unbind( "ready" ); - } - } - }, - - bindReady: function() { - if ( readyList ) { - return; - } - - readyList = jQuery._Deferred(); - - // Catch cases where $(document).ready() is called after the - // browser event has already occurred. - if ( document.readyState === "complete" ) { - // Handle it asynchronously to allow scripts the opportunity to delay ready - return setTimeout( jQuery.ready, 1 ); - } - - // Mozilla, Opera and webkit nightlies currently support this event - if ( document.addEventListener ) { - // Use the handy event callback - document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false ); - - // A fallback to window.onload, that will always work - window.addEventListener( "load", jQuery.ready, false ); - - // If IE event model is used - } else if ( document.attachEvent ) { - // ensure firing before onload, - // maybe late but safe also for iframes - document.attachEvent( "onreadystatechange", DOMContentLoaded ); - - // A fallback to window.onload, that will always work - window.attachEvent( "onload", jQuery.ready ); - - // If IE and not a frame - // continually check to see if the document is ready - var toplevel = false; - - try { - toplevel = window.frameElement == null; - } catch(e) {} - - if ( document.documentElement.doScroll && toplevel ) { - doScrollCheck(); - } - } - }, - - // See test/unit/core.js for details concerning isFunction. - // Since version 1.3, DOM methods and functions like alert - // aren't supported. They return false on IE (#2968). - isFunction: function( obj ) { - return jQuery.type(obj) === "function"; - }, - - isArray: Array.isArray || function( obj ) { - return jQuery.type(obj) === "array"; - }, - - // A crude way of determining if an object is a window - isWindow: function( obj ) { - return obj && typeof obj === "object" && "setInterval" in obj; - }, - - isNaN: function( obj ) { - return obj == null || !rdigit.test( obj ) || isNaN( obj ); - }, - - type: function( obj ) { - return obj == null ? - String( obj ) : - class2type[ toString.call(obj) ] || "object"; - }, - - isPlainObject: function( obj ) { - // Must be an Object. - // Because of IE, we also have to check the presence of the constructor property. - // Make sure that DOM nodes and window objects don't pass through, as well - if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) { - return false; - } - - try { - // Not own constructor property must be Object - if ( obj.constructor && - !hasOwn.call(obj, "constructor") && - !hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) { - return false; - } - } catch ( e ) { - // IE8,9 Will throw exceptions on certain host objects #9897 - return false; - } - - // Own properties are enumerated firstly, so to speed up, - // if last one is own, then all properties are own. - - var key; - for ( key in obj ) {} - - return key === undefined || hasOwn.call( obj, key ); - }, - - isEmptyObject: function( obj ) { - for ( var name in obj ) { - return false; - } - return true; - }, - - error: function( msg ) { - throw msg; - }, - - parseJSON: function( data ) { - if ( typeof data !== "string" || !data ) { - return null; - } - - // Make sure leading/trailing whitespace is removed (IE can't handle it) - data = jQuery.trim( data ); - - // Attempt to parse using the native JSON parser first - if ( window.JSON && window.JSON.parse ) { - return window.JSON.parse( data ); - } - - // Make sure the incoming data is actual JSON - // Logic borrowed from http://json.org/json2.js - if ( rvalidchars.test( data.replace( rvalidescape, "@" ) - .replace( rvalidtokens, "]" ) - .replace( rvalidbraces, "")) ) { - - return (new Function( "return " + data ))(); - - } - jQuery.error( "Invalid JSON: " + data ); - }, - - // Cross-browser xml parsing - parseXML: function( data ) { - var xml, tmp; - try { - if ( window.DOMParser ) { // Standard - tmp = new DOMParser(); - xml = tmp.parseFromString( data , "text/xml" ); - } else { // IE - xml = new ActiveXObject( "Microsoft.XMLDOM" ); - xml.async = "false"; - xml.loadXML( data ); - } - } catch( e ) { - xml = undefined; - } - if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) { - jQuery.error( "Invalid XML: " + data ); - } - return xml; - }, - - noop: function() {}, - - // Evaluates a script in a global context - // Workarounds based on findings by Jim Driscoll - // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context - globalEval: function( data ) { - if ( data && rnotwhite.test( data ) ) { - // We use execScript on Internet Explorer - // We use an anonymous function so that context is window - // rather than jQuery in Firefox - ( window.execScript || function( data ) { - window[ "eval" ].call( window, data ); - } )( data ); - } - }, - - // Convert dashed to camelCase; used by the css and data modules - // Microsoft forgot to hump their vendor prefix (#9572) - camelCase: function( string ) { - return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); - }, - - nodeName: function( elem, name ) { - return elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase(); - }, - - // args is for internal usage only - each: function( object, callback, args ) { - var name, i = 0, - length = object.length, - isObj = length === undefined || jQuery.isFunction( object ); - - if ( args ) { - if ( isObj ) { - for ( name in object ) { - if ( callback.apply( object[ name ], args ) === false ) { - break; - } - } - } else { - for ( ; i < length; ) { - if ( callback.apply( object[ i++ ], args ) === false ) { - break; - } - } - } - - // A special, fast, case for the most common use of each - } else { - if ( isObj ) { - for ( name in object ) { - if ( callback.call( object[ name ], name, object[ name ] ) === false ) { - break; - } - } - } else { - for ( ; i < length; ) { - if ( callback.call( object[ i ], i, object[ i++ ] ) === false ) { - break; - } - } - } - } - - return object; - }, - - // Use native String.trim function wherever possible - trim: trim ? - function( text ) { - return text == null ? - "" : - trim.call( text ); - } : - - // Otherwise use our own trimming functionality - function( text ) { - return text == null ? - "" : - text.toString().replace( trimLeft, "" ).replace( trimRight, "" ); - }, - - // results is for internal usage only - makeArray: function( array, results ) { - var ret = results || []; - - if ( array != null ) { - // The window, strings (and functions) also have 'length' - // The extra typeof function check is to prevent crashes - // in Safari 2 (See: #3039) - // Tweaked logic slightly to handle Blackberry 4.7 RegExp issues #6930 - var type = jQuery.type( array ); - - if ( array.length == null || type === "string" || type === "function" || type === "regexp" || jQuery.isWindow( array ) ) { - push.call( ret, array ); - } else { - jQuery.merge( ret, array ); - } - } - - return ret; - }, - - inArray: function( elem, array ) { - if ( !array ) { - return -1; - } - - if ( indexOf ) { - return indexOf.call( array, elem ); - } - - for ( var i = 0, length = array.length; i < length; i++ ) { - if ( array[ i ] === elem ) { - return i; - } - } - - return -1; - }, - - merge: function( first, second ) { - var i = first.length, - j = 0; - - if ( typeof second.length === "number" ) { - for ( var l = second.length; j < l; j++ ) { - first[ i++ ] = second[ j ]; - } - - } else { - while ( second[j] !== undefined ) { - first[ i++ ] = second[ j++ ]; - } - } - - first.length = i; - - return first; - }, - - grep: function( elems, callback, inv ) { - var ret = [], retVal; - inv = !!inv; - - // Go through the array, only saving the items - // that pass the validator function - for ( var i = 0, length = elems.length; i < length; i++ ) { - retVal = !!callback( elems[ i ], i ); - if ( inv !== retVal ) { - ret.push( elems[ i ] ); - } - } - - return ret; - }, - - // arg is for internal usage only - map: function( elems, callback, arg ) { - var value, key, ret = [], - i = 0, - length = elems.length, - // jquery objects are treated as arrays - isArray = elems instanceof jQuery || length !== undefined && typeof length === "number" && ( ( length > 0 && elems[ 0 ] && elems[ length -1 ] ) || length === 0 || jQuery.isArray( elems ) ) ; - - // Go through the array, translating each of the items to their - if ( isArray ) { - for ( ; i < length; i++ ) { - value = callback( elems[ i ], i, arg ); - - if ( value != null ) { - ret[ ret.length ] = value; - } - } - - // Go through every key on the object, - } else { - for ( key in elems ) { - value = callback( elems[ key ], key, arg ); - - if ( value != null ) { - ret[ ret.length ] = value; - } - } - } - - // Flatten any nested arrays - return ret.concat.apply( [], ret ); - }, - - // A global GUID counter for objects - guid: 1, - - // Bind a function to a context, optionally partially applying any - // arguments. - proxy: function( fn, context ) { - if ( typeof context === "string" ) { - var tmp = fn[ context ]; - context = fn; - fn = tmp; - } - - // Quick check to determine if target is callable, in the spec - // this throws a TypeError, but we will just return undefined. - if ( !jQuery.isFunction( fn ) ) { - return undefined; - } - - // Simulated bind - var args = slice.call( arguments, 2 ), - proxy = function() { - return fn.apply( context, args.concat( slice.call( arguments ) ) ); - }; - - // Set the guid of unique handler to the same of original handler, so it can be removed - proxy.guid = fn.guid = fn.guid || proxy.guid || jQuery.guid++; - - return proxy; - }, - - // Mutifunctional method to get and set values to a collection - // The value/s can optionally be executed if it's a function - access: function( elems, key, value, exec, fn, pass ) { - var length = elems.length; - - // Setting many attributes - if ( typeof key === "object" ) { - for ( var k in key ) { - jQuery.access( elems, k, key[k], exec, fn, value ); - } - return elems; - } - - // Setting one attribute - if ( value !== undefined ) { - // Optionally, function values get executed if exec is true - exec = !pass && exec && jQuery.isFunction(value); - - for ( var i = 0; i < length; i++ ) { - fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass ); - } - - return elems; - } - - // Getting an attribute - return length ? fn( elems[0], key ) : undefined; - }, - - now: function() { - return (new Date()).getTime(); - }, - - // Use of jQuery.browser is frowned upon. - // More details: http://docs.jquery.com/Utilities/jQuery.browser - uaMatch: function( ua ) { - ua = ua.toLowerCase(); - - var match = rwebkit.exec( ua ) || - ropera.exec( ua ) || - rmsie.exec( ua ) || - ua.indexOf("compatible") < 0 && rmozilla.exec( ua ) || - []; - - return { browser: match[1] || "", version: match[2] || "0" }; - }, - - sub: function() { - function jQuerySub( selector, context ) { - return new jQuerySub.fn.init( selector, context ); - } - jQuery.extend( true, jQuerySub, this ); - jQuerySub.superclass = this; - jQuerySub.fn = jQuerySub.prototype = this(); - jQuerySub.fn.constructor = jQuerySub; - jQuerySub.sub = this.sub; - jQuerySub.fn.init = function init( selector, context ) { - if ( context && context instanceof jQuery && !(context instanceof jQuerySub) ) { - context = jQuerySub( context ); - } - - return jQuery.fn.init.call( this, selector, context, rootjQuerySub ); - }; - jQuerySub.fn.init.prototype = jQuerySub.fn; - var rootjQuerySub = jQuerySub(document); - return jQuerySub; - }, - - browser: {} -}); - -// Populate the class2type map -jQuery.each("Boolean Number String Function Array Date RegExp Object".split(" "), function(i, name) { - class2type[ "[object " + name + "]" ] = name.toLowerCase(); -}); - -browserMatch = jQuery.uaMatch( userAgent ); -if ( browserMatch.browser ) { - jQuery.browser[ browserMatch.browser ] = true; - jQuery.browser.version = browserMatch.version; -} - -// Deprecated, use jQuery.browser.webkit instead -if ( jQuery.browser.webkit ) { - jQuery.browser.safari = true; -} - -// IE doesn't match non-breaking spaces with \s -if ( rnotwhite.test( "\xA0" ) ) { - trimLeft = /^[\s\xA0]+/; - trimRight = /[\s\xA0]+$/; -} - -// All jQuery objects should point back to these -rootjQuery = jQuery(document); - -// Cleanup functions for the document ready method -if ( document.addEventListener ) { - DOMContentLoaded = function() { - document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false ); - jQuery.ready(); - }; - -} else if ( document.attachEvent ) { - DOMContentLoaded = function() { - // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). - if ( document.readyState === "complete" ) { - document.detachEvent( "onreadystatechange", DOMContentLoaded ); - jQuery.ready(); - } - }; -} - -// The DOM ready check for Internet Explorer -function doScrollCheck() { - if ( jQuery.isReady ) { - return; - } - - try { - // If IE is used, use the trick by Diego Perini - // http://javascript.nwbox.com/IEContentLoaded/ - document.documentElement.doScroll("left"); - } catch(e) { - setTimeout( doScrollCheck, 1 ); - return; - } - - // and execute any waiting functions - jQuery.ready(); -} - -return jQuery; - -})(); - - -var // Promise methods - promiseMethods = "done fail isResolved isRejected promise then always pipe".split( " " ), - // Static reference to slice - sliceDeferred = [].slice; - -jQuery.extend({ - // Create a simple deferred (one callbacks list) - _Deferred: function() { - var // callbacks list - callbacks = [], - // stored [ context , args ] - fired, - // to avoid firing when already doing so - firing, - // flag to know if the deferred has been cancelled - cancelled, - // the deferred itself - deferred = { - - // done( f1, f2, ...) - done: function() { - if ( !cancelled ) { - var args = arguments, - i, - length, - elem, - type, - _fired; - if ( fired ) { - _fired = fired; - fired = 0; - } - for ( i = 0, length = args.length; i < length; i++ ) { - elem = args[ i ]; - type = jQuery.type( elem ); - if ( type === "array" ) { - deferred.done.apply( deferred, elem ); - } else if ( type === "function" ) { - callbacks.push( elem ); - } - } - if ( _fired ) { - deferred.resolveWith( _fired[ 0 ], _fired[ 1 ] ); - } - } - return this; - }, - - // resolve with given context and args - resolveWith: function( context, args ) { - if ( !cancelled && !fired && !firing ) { - // make sure args are available (#8421) - args = args || []; - firing = 1; - try { - while( callbacks[ 0 ] ) { - callbacks.shift().apply( context, args ); - } - } - finally { - fired = [ context, args ]; - firing = 0; - } - } - return this; - }, - - // resolve with this as context and given arguments - resolve: function() { - deferred.resolveWith( this, arguments ); - return this; - }, - - // Has this deferred been resolved? - isResolved: function() { - return !!( firing || fired ); - }, - - // Cancel - cancel: function() { - cancelled = 1; - callbacks = []; - return this; - } - }; - - return deferred; - }, - - // Full fledged deferred (two callbacks list) - Deferred: function( func ) { - var deferred = jQuery._Deferred(), - failDeferred = jQuery._Deferred(), - promise; - // Add errorDeferred methods, then and promise - jQuery.extend( deferred, { - then: function( doneCallbacks, failCallbacks ) { - deferred.done( doneCallbacks ).fail( failCallbacks ); - return this; - }, - always: function() { - return deferred.done.apply( deferred, arguments ).fail.apply( this, arguments ); - }, - fail: failDeferred.done, - rejectWith: failDeferred.resolveWith, - reject: failDeferred.resolve, - isRejected: failDeferred.isResolved, - pipe: function( fnDone, fnFail ) { - return jQuery.Deferred(function( newDefer ) { - jQuery.each( { - done: [ fnDone, "resolve" ], - fail: [ fnFail, "reject" ] - }, function( handler, data ) { - var fn = data[ 0 ], - action = data[ 1 ], - returned; - if ( jQuery.isFunction( fn ) ) { - deferred[ handler ](function() { - returned = fn.apply( this, arguments ); - if ( returned && jQuery.isFunction( returned.promise ) ) { - returned.promise().then( newDefer.resolve, newDefer.reject ); - } else { - newDefer[ action + "With" ]( this === deferred ? newDefer : this, [ returned ] ); - } - }); - } else { - deferred[ handler ]( newDefer[ action ] ); - } - }); - }).promise(); - }, - // Get a promise for this deferred - // If obj is provided, the promise aspect is added to the object - promise: function( obj ) { - if ( obj == null ) { - if ( promise ) { - return promise; - } - promise = obj = {}; - } - var i = promiseMethods.length; - while( i-- ) { - obj[ promiseMethods[i] ] = deferred[ promiseMethods[i] ]; - } - return obj; - } - }); - // Make sure only one callback list will be used - deferred.done( failDeferred.cancel ).fail( deferred.cancel ); - // Unexpose cancel - delete deferred.cancel; - // Call given func if any - if ( func ) { - func.call( deferred, deferred ); - } - return deferred; - }, - - // Deferred helper - when: function( firstParam ) { - var args = arguments, - i = 0, - length = args.length, - count = length, - deferred = length <= 1 && firstParam && jQuery.isFunction( firstParam.promise ) ? - firstParam : - jQuery.Deferred(); - function resolveFunc( i ) { - return function( value ) { - args[ i ] = arguments.length > 1 ? sliceDeferred.call( arguments, 0 ) : value; - if ( !( --count ) ) { - // Strange bug in FF4: - // Values changed onto the arguments object sometimes end up as undefined values - // outside the $.when method. Cloning the object into a fresh array solves the issue - deferred.resolveWith( deferred, sliceDeferred.call( args, 0 ) ); - } - }; - } - if ( length > 1 ) { - for( ; i < length; i++ ) { - if ( args[ i ] && jQuery.isFunction( args[ i ].promise ) ) { - args[ i ].promise().then( resolveFunc(i), deferred.reject ); - } else { - --count; - } - } - if ( !count ) { - deferred.resolveWith( deferred, args ); - } - } else if ( deferred !== firstParam ) { - deferred.resolveWith( deferred, length ? [ firstParam ] : [] ); - } - return deferred.promise(); - } -}); - - - -jQuery.support = (function() { - - var div = document.createElement( "div" ), - documentElement = document.documentElement, - all, - a, - select, - opt, - input, - marginDiv, - support, - fragment, - body, - testElementParent, - testElement, - testElementStyle, - tds, - events, - eventName, - i, - isSupported; - - // Preliminary tests - div.setAttribute("className", "t"); - div.innerHTML = "
        a"; - - - all = div.getElementsByTagName( "*" ); - a = div.getElementsByTagName( "a" )[ 0 ]; - - // Can't get basic test support - if ( !all || !all.length || !a ) { - return {}; - } - - // First batch of supports tests - select = document.createElement( "select" ); - opt = select.appendChild( document.createElement("option") ); - input = div.getElementsByTagName( "input" )[ 0 ]; - - support = { - // IE strips leading whitespace when .innerHTML is used - leadingWhitespace: ( div.firstChild.nodeType === 3 ), - - // Make sure that tbody elements aren't automatically inserted - // IE will insert them into empty tables - tbody: !div.getElementsByTagName( "tbody" ).length, - - // Make sure that link elements get serialized correctly by innerHTML - // This requires a wrapper element in IE - htmlSerialize: !!div.getElementsByTagName( "link" ).length, - - // Get the style information from getAttribute - // (IE uses .cssText instead) - style: /top/.test( a.getAttribute("style") ), - - // Make sure that URLs aren't manipulated - // (IE normalizes it by default) - hrefNormalized: ( a.getAttribute( "href" ) === "/a" ), - - // Make sure that element opacity exists - // (IE uses filter instead) - // Use a regex to work around a WebKit issue. See #5145 - opacity: /^0.55$/.test( a.style.opacity ), - - // Verify style float existence - // (IE uses styleFloat instead of cssFloat) - cssFloat: !!a.style.cssFloat, - - // Make sure that if no value is specified for a checkbox - // that it defaults to "on". - // (WebKit defaults to "" instead) - checkOn: ( input.value === "on" ), - - // Make sure that a selected-by-default option has a working selected property. - // (WebKit defaults to false instead of true, IE too, if it's in an optgroup) - optSelected: opt.selected, - - // Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7) - getSetAttribute: div.className !== "t", - - // Will be defined later - submitBubbles: true, - changeBubbles: true, - focusinBubbles: false, - deleteExpando: true, - noCloneEvent: true, - inlineBlockNeedsLayout: false, - shrinkWrapBlocks: false, - reliableMarginRight: true - }; - - // Make sure checked status is properly cloned - input.checked = true; - support.noCloneChecked = input.cloneNode( true ).checked; - - // Make sure that the options inside disabled selects aren't marked as disabled - // (WebKit marks them as disabled) - select.disabled = true; - support.optDisabled = !opt.disabled; - - // Test to see if it's possible to delete an expando from an element - // Fails in Internet Explorer - try { - delete div.test; - } catch( e ) { - support.deleteExpando = false; - } - - if ( !div.addEventListener && div.attachEvent && div.fireEvent ) { - div.attachEvent( "onclick", function() { - // Cloning a node shouldn't copy over any - // bound event handlers (IE does this) - support.noCloneEvent = false; - }); - div.cloneNode( true ).fireEvent( "onclick" ); - } - - // Check if a radio maintains it's value - // after being appended to the DOM - input = document.createElement("input"); - input.value = "t"; - input.setAttribute("type", "radio"); - support.radioValue = input.value === "t"; - - input.setAttribute("checked", "checked"); - div.appendChild( input ); - fragment = document.createDocumentFragment(); - fragment.appendChild( div.firstChild ); - - // WebKit doesn't clone checked state correctly in fragments - support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked; - - div.innerHTML = ""; - - // Figure out if the W3C box model works as expected - div.style.width = div.style.paddingLeft = "1px"; - - body = document.getElementsByTagName( "body" )[ 0 ]; - // We use our own, invisible, body unless the body is already present - // in which case we use a div (#9239) - testElement = document.createElement( body ? "div" : "body" ); - testElementStyle = { - visibility: "hidden", - width: 0, - height: 0, - border: 0, - margin: 0, - background: "none" - }; - if ( body ) { - jQuery.extend( testElementStyle, { - position: "absolute", - left: "-1000px", - top: "-1000px" - }); - } - for ( i in testElementStyle ) { - testElement.style[ i ] = testElementStyle[ i ]; - } - testElement.appendChild( div ); - testElementParent = body || documentElement; - testElementParent.insertBefore( testElement, testElementParent.firstChild ); - - // Check if a disconnected checkbox will retain its checked - // value of true after appended to the DOM (IE6/7) - support.appendChecked = input.checked; - - support.boxModel = div.offsetWidth === 2; - - if ( "zoom" in div.style ) { - // Check if natively block-level elements act like inline-block - // elements when setting their display to 'inline' and giving - // them layout - // (IE < 8 does this) - div.style.display = "inline"; - div.style.zoom = 1; - support.inlineBlockNeedsLayout = ( div.offsetWidth === 2 ); - - // Check if elements with layout shrink-wrap their children - // (IE 6 does this) - div.style.display = ""; - div.innerHTML = "
        "; - support.shrinkWrapBlocks = ( div.offsetWidth !== 2 ); - } - - div.innerHTML = "
        t
        "; - tds = div.getElementsByTagName( "td" ); - - // Check if table cells still have offsetWidth/Height when they are set - // to display:none and there are still other visible table cells in a - // table row; if so, offsetWidth/Height are not reliable for use when - // determining if an element has been hidden directly using - // display:none (it is still safe to use offsets if a parent element is - // hidden; don safety goggles and see bug #4512 for more information). - // (only IE 8 fails this test) - isSupported = ( tds[ 0 ].offsetHeight === 0 ); - - tds[ 0 ].style.display = ""; - tds[ 1 ].style.display = "none"; - - // Check if empty table cells still have offsetWidth/Height - // (IE < 8 fail this test) - support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 ); - div.innerHTML = ""; - - // Check if div with explicit width and no margin-right incorrectly - // gets computed margin-right based on width of container. For more - // info see bug #3333 - // Fails in WebKit before Feb 2011 nightlies - // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right - if ( document.defaultView && document.defaultView.getComputedStyle ) { - marginDiv = document.createElement( "div" ); - marginDiv.style.width = "0"; - marginDiv.style.marginRight = "0"; - div.appendChild( marginDiv ); - support.reliableMarginRight = - ( parseInt( ( document.defaultView.getComputedStyle( marginDiv, null ) || { marginRight: 0 } ).marginRight, 10 ) || 0 ) === 0; - } - - // Remove the body element we added - testElement.innerHTML = ""; - testElementParent.removeChild( testElement ); - - // Technique from Juriy Zaytsev - // http://thinkweb2.com/projects/prototype/detecting-event-support-without-browser-sniffing/ - // We only care about the case where non-standard event systems - // are used, namely in IE. Short-circuiting here helps us to - // avoid an eval call (in setAttribute) which can cause CSP - // to go haywire. See: https://developer.mozilla.org/en/Security/CSP - if ( div.attachEvent ) { - for( i in { - submit: 1, - change: 1, - focusin: 1 - } ) { - eventName = "on" + i; - isSupported = ( eventName in div ); - if ( !isSupported ) { - div.setAttribute( eventName, "return;" ); - isSupported = ( typeof div[ eventName ] === "function" ); - } - support[ i + "Bubbles" ] = isSupported; - } - } - - // Null connected elements to avoid leaks in IE - testElement = fragment = select = opt = body = marginDiv = div = input = null; - - return support; -})(); - -// Keep track of boxModel -jQuery.boxModel = jQuery.support.boxModel; - - - - -var rbrace = /^(?:\{.*\}|\[.*\])$/, - rmultiDash = /([A-Z])/g; - -jQuery.extend({ - cache: {}, - - // Please use with caution - uuid: 0, - - // Unique for each copy of jQuery on the page - // Non-digits removed to match rinlinejQuery - expando: "jQuery" + ( jQuery.fn.jquery + Math.random() ).replace( /\D/g, "" ), - - // The following elements throw uncatchable exceptions if you - // attempt to add expando properties to them. - noData: { - "embed": true, - // Ban all objects except for Flash (which handle expandos) - "object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000", - "applet": true - }, - - hasData: function( elem ) { - elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ]; - - return !!elem && !isEmptyDataObject( elem ); - }, - - data: function( elem, name, data, pvt /* Internal Use Only */ ) { - if ( !jQuery.acceptData( elem ) ) { - return; - } - - var thisCache, ret, - internalKey = jQuery.expando, - getByName = typeof name === "string", - - // We have to handle DOM nodes and JS objects differently because IE6-7 - // can't GC object references properly across the DOM-JS boundary - isNode = elem.nodeType, - - // Only DOM nodes need the global jQuery cache; JS object data is - // attached directly to the object so GC can occur automatically - cache = isNode ? jQuery.cache : elem, - - // Only defining an ID for JS objects if its cache already exists allows - // the code to shortcut on the same path as a DOM node with no cache - id = isNode ? elem[ jQuery.expando ] : elem[ jQuery.expando ] && jQuery.expando; - - // Avoid doing any more work than we need to when trying to get data on an - // object that has no data at all - if ( (!id || (pvt && id && (cache[ id ] && !cache[ id ][ internalKey ]))) && getByName && data === undefined ) { - return; - } - - if ( !id ) { - // Only DOM nodes need a new unique ID for each element since their data - // ends up in the global cache - if ( isNode ) { - elem[ jQuery.expando ] = id = ++jQuery.uuid; - } else { - id = jQuery.expando; - } - } - - if ( !cache[ id ] ) { - cache[ id ] = {}; - - // TODO: This is a hack for 1.5 ONLY. Avoids exposing jQuery - // metadata on plain JS objects when the object is serialized using - // JSON.stringify - if ( !isNode ) { - cache[ id ].toJSON = jQuery.noop; - } - } - - // An object can be passed to jQuery.data instead of a key/value pair; this gets - // shallow copied over onto the existing cache - if ( typeof name === "object" || typeof name === "function" ) { - if ( pvt ) { - cache[ id ][ internalKey ] = jQuery.extend(cache[ id ][ internalKey ], name); - } else { - cache[ id ] = jQuery.extend(cache[ id ], name); - } - } - - thisCache = cache[ id ]; - - // Internal jQuery data is stored in a separate object inside the object's data - // cache in order to avoid key collisions between internal data and user-defined - // data - if ( pvt ) { - if ( !thisCache[ internalKey ] ) { - thisCache[ internalKey ] = {}; - } - - thisCache = thisCache[ internalKey ]; - } - - if ( data !== undefined ) { - thisCache[ jQuery.camelCase( name ) ] = data; - } - - // TODO: This is a hack for 1.5 ONLY. It will be removed in 1.6. Users should - // not attempt to inspect the internal events object using jQuery.data, as this - // internal data object is undocumented and subject to change. - if ( name === "events" && !thisCache[name] ) { - return thisCache[ internalKey ] && thisCache[ internalKey ].events; - } - - // Check for both converted-to-camel and non-converted data property names - // If a data property was specified - if ( getByName ) { - - // First Try to find as-is property data - ret = thisCache[ name ]; - - // Test for null|undefined property data - if ( ret == null ) { - - // Try to find the camelCased property - ret = thisCache[ jQuery.camelCase( name ) ]; - } - } else { - ret = thisCache; - } - - return ret; - }, - - removeData: function( elem, name, pvt /* Internal Use Only */ ) { - if ( !jQuery.acceptData( elem ) ) { - return; - } - - var thisCache, - - // Reference to internal data cache key - internalKey = jQuery.expando, - - isNode = elem.nodeType, - - // See jQuery.data for more information - cache = isNode ? jQuery.cache : elem, - - // See jQuery.data for more information - id = isNode ? elem[ jQuery.expando ] : jQuery.expando; - - // If there is already no cache entry for this object, there is no - // purpose in continuing - if ( !cache[ id ] ) { - return; - } - - if ( name ) { - - thisCache = pvt ? cache[ id ][ internalKey ] : cache[ id ]; - - if ( thisCache ) { - - // Support interoperable removal of hyphenated or camelcased keys - if ( !thisCache[ name ] ) { - name = jQuery.camelCase( name ); - } - - delete thisCache[ name ]; - - // If there is no data left in the cache, we want to continue - // and let the cache object itself get destroyed - if ( !isEmptyDataObject(thisCache) ) { - return; - } - } - } - - // See jQuery.data for more information - if ( pvt ) { - delete cache[ id ][ internalKey ]; - - // Don't destroy the parent cache unless the internal data object - // had been the only thing left in it - if ( !isEmptyDataObject(cache[ id ]) ) { - return; - } - } - - var internalCache = cache[ id ][ internalKey ]; - - // Browsers that fail expando deletion also refuse to delete expandos on - // the window, but it will allow it on all other JS objects; other browsers - // don't care - // Ensure that `cache` is not a window object #10080 - if ( jQuery.support.deleteExpando || !cache.setInterval ) { - delete cache[ id ]; - } else { - cache[ id ] = null; - } - - // We destroyed the entire user cache at once because it's faster than - // iterating through each key, but we need to continue to persist internal - // data if it existed - if ( internalCache ) { - cache[ id ] = {}; - // TODO: This is a hack for 1.5 ONLY. Avoids exposing jQuery - // metadata on plain JS objects when the object is serialized using - // JSON.stringify - if ( !isNode ) { - cache[ id ].toJSON = jQuery.noop; - } - - cache[ id ][ internalKey ] = internalCache; - - // Otherwise, we need to eliminate the expando on the node to avoid - // false lookups in the cache for entries that no longer exist - } else if ( isNode ) { - // IE does not allow us to delete expando properties from nodes, - // nor does it have a removeAttribute function on Document nodes; - // we must handle all of these cases - if ( jQuery.support.deleteExpando ) { - delete elem[ jQuery.expando ]; - } else if ( elem.removeAttribute ) { - elem.removeAttribute( jQuery.expando ); - } else { - elem[ jQuery.expando ] = null; - } - } - }, - - // For internal use only. - _data: function( elem, name, data ) { - return jQuery.data( elem, name, data, true ); - }, - - // A method for determining if a DOM node can handle the data expando - acceptData: function( elem ) { - if ( elem.nodeName ) { - var match = jQuery.noData[ elem.nodeName.toLowerCase() ]; - - if ( match ) { - return !(match === true || elem.getAttribute("classid") !== match); - } - } - - return true; - } -}); - -jQuery.fn.extend({ - data: function( key, value ) { - var data = null; - - if ( typeof key === "undefined" ) { - if ( this.length ) { - data = jQuery.data( this[0] ); - - if ( this[0].nodeType === 1 ) { - var attr = this[0].attributes, name; - for ( var i = 0, l = attr.length; i < l; i++ ) { - name = attr[i].name; - - if ( name.indexOf( "data-" ) === 0 ) { - name = jQuery.camelCase( name.substring(5) ); - - dataAttr( this[0], name, data[ name ] ); - } - } - } - } - - return data; - - } else if ( typeof key === "object" ) { - return this.each(function() { - jQuery.data( this, key ); - }); - } - - var parts = key.split("."); - parts[1] = parts[1] ? "." + parts[1] : ""; - - if ( value === undefined ) { - data = this.triggerHandler("getData" + parts[1] + "!", [parts[0]]); - - // Try to fetch any internally stored data first - if ( data === undefined && this.length ) { - data = jQuery.data( this[0], key ); - data = dataAttr( this[0], key, data ); - } - - return data === undefined && parts[1] ? - this.data( parts[0] ) : - data; - - } else { - return this.each(function() { - var $this = jQuery( this ), - args = [ parts[0], value ]; - - $this.triggerHandler( "setData" + parts[1] + "!", args ); - jQuery.data( this, key, value ); - $this.triggerHandler( "changeData" + parts[1] + "!", args ); - }); - } - }, - - removeData: function( key ) { - return this.each(function() { - jQuery.removeData( this, key ); - }); - } -}); - -function dataAttr( elem, key, data ) { - // If nothing was found internally, try to fetch any - // data from the HTML5 data-* attribute - if ( data === undefined && elem.nodeType === 1 ) { - - var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase(); - - data = elem.getAttribute( name ); - - if ( typeof data === "string" ) { - try { - data = data === "true" ? true : - data === "false" ? false : - data === "null" ? null : - !jQuery.isNaN( data ) ? parseFloat( data ) : - rbrace.test( data ) ? jQuery.parseJSON( data ) : - data; - } catch( e ) {} - - // Make sure we set the data so it isn't changed later - jQuery.data( elem, key, data ); - - } else { - data = undefined; - } - } - - return data; -} - -// TODO: This is a hack for 1.5 ONLY to allow objects with a single toJSON -// property to be considered empty objects; this property always exists in -// order to make sure JSON.stringify does not expose internal metadata -function isEmptyDataObject( obj ) { - for ( var name in obj ) { - if ( name !== "toJSON" ) { - return false; - } - } - - return true; -} - - - - -function handleQueueMarkDefer( elem, type, src ) { - var deferDataKey = type + "defer", - queueDataKey = type + "queue", - markDataKey = type + "mark", - defer = jQuery.data( elem, deferDataKey, undefined, true ); - if ( defer && - ( src === "queue" || !jQuery.data( elem, queueDataKey, undefined, true ) ) && - ( src === "mark" || !jQuery.data( elem, markDataKey, undefined, true ) ) ) { - // Give room for hard-coded callbacks to fire first - // and eventually mark/queue something else on the element - setTimeout( function() { - if ( !jQuery.data( elem, queueDataKey, undefined, true ) && - !jQuery.data( elem, markDataKey, undefined, true ) ) { - jQuery.removeData( elem, deferDataKey, true ); - defer.resolve(); - } - }, 0 ); - } -} - -jQuery.extend({ - - _mark: function( elem, type ) { - if ( elem ) { - type = (type || "fx") + "mark"; - jQuery.data( elem, type, (jQuery.data(elem,type,undefined,true) || 0) + 1, true ); - } - }, - - _unmark: function( force, elem, type ) { - if ( force !== true ) { - type = elem; - elem = force; - force = false; - } - if ( elem ) { - type = type || "fx"; - var key = type + "mark", - count = force ? 0 : ( (jQuery.data( elem, key, undefined, true) || 1 ) - 1 ); - if ( count ) { - jQuery.data( elem, key, count, true ); - } else { - jQuery.removeData( elem, key, true ); - handleQueueMarkDefer( elem, type, "mark" ); - } - } - }, - - queue: function( elem, type, data ) { - if ( elem ) { - type = (type || "fx") + "queue"; - var q = jQuery.data( elem, type, undefined, true ); - // Speed up dequeue by getting out quickly if this is just a lookup - if ( data ) { - if ( !q || jQuery.isArray(data) ) { - q = jQuery.data( elem, type, jQuery.makeArray(data), true ); - } else { - q.push( data ); - } - } - return q || []; - } - }, - - dequeue: function( elem, type ) { - type = type || "fx"; - - var queue = jQuery.queue( elem, type ), - fn = queue.shift(), - defer; - - // If the fx queue is dequeued, always remove the progress sentinel - if ( fn === "inprogress" ) { - fn = queue.shift(); - } - - if ( fn ) { - // Add a progress sentinel to prevent the fx queue from being - // automatically dequeued - if ( type === "fx" ) { - queue.unshift("inprogress"); - } - - fn.call(elem, function() { - jQuery.dequeue(elem, type); - }); - } - - if ( !queue.length ) { - jQuery.removeData( elem, type + "queue", true ); - handleQueueMarkDefer( elem, type, "queue" ); - } - } -}); - -jQuery.fn.extend({ - queue: function( type, data ) { - if ( typeof type !== "string" ) { - data = type; - type = "fx"; - } - - if ( data === undefined ) { - return jQuery.queue( this[0], type ); - } - return this.each(function() { - var queue = jQuery.queue( this, type, data ); - - if ( type === "fx" && queue[0] !== "inprogress" ) { - jQuery.dequeue( this, type ); - } - }); - }, - dequeue: function( type ) { - return this.each(function() { - jQuery.dequeue( this, type ); - }); - }, - // Based off of the plugin by Clint Helfers, with permission. - // http://blindsignals.com/index.php/2009/07/jquery-delay/ - delay: function( time, type ) { - time = jQuery.fx ? jQuery.fx.speeds[time] || time : time; - type = type || "fx"; - - return this.queue( type, function() { - var elem = this; - setTimeout(function() { - jQuery.dequeue( elem, type ); - }, time ); - }); - }, - clearQueue: function( type ) { - return this.queue( type || "fx", [] ); - }, - // Get a promise resolved when queues of a certain type - // are emptied (fx is the type by default) - promise: function( type, object ) { - if ( typeof type !== "string" ) { - object = type; - type = undefined; - } - type = type || "fx"; - var defer = jQuery.Deferred(), - elements = this, - i = elements.length, - count = 1, - deferDataKey = type + "defer", - queueDataKey = type + "queue", - markDataKey = type + "mark", - tmp; - function resolve() { - if ( !( --count ) ) { - defer.resolveWith( elements, [ elements ] ); - } - } - while( i-- ) { - if (( tmp = jQuery.data( elements[ i ], deferDataKey, undefined, true ) || - ( jQuery.data( elements[ i ], queueDataKey, undefined, true ) || - jQuery.data( elements[ i ], markDataKey, undefined, true ) ) && - jQuery.data( elements[ i ], deferDataKey, jQuery._Deferred(), true ) )) { - count++; - tmp.done( resolve ); - } - } - resolve(); - return defer.promise(); - } -}); - - - - -var rclass = /[\n\t\r]/g, - rspace = /\s+/, - rreturn = /\r/g, - rtype = /^(?:button|input)$/i, - rfocusable = /^(?:button|input|object|select|textarea)$/i, - rclickable = /^a(?:rea)?$/i, - rboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i, - nodeHook, boolHook; - -jQuery.fn.extend({ - attr: function( name, value ) { - return jQuery.access( this, name, value, true, jQuery.attr ); - }, - - removeAttr: function( name ) { - return this.each(function() { - jQuery.removeAttr( this, name ); - }); - }, - - prop: function( name, value ) { - return jQuery.access( this, name, value, true, jQuery.prop ); - }, - - removeProp: function( name ) { - name = jQuery.propFix[ name ] || name; - return this.each(function() { - // try/catch handles cases where IE balks (such as removing a property on window) - try { - this[ name ] = undefined; - delete this[ name ]; - } catch( e ) {} - }); - }, - - addClass: function( value ) { - var classNames, i, l, elem, - setClass, c, cl; - - if ( jQuery.isFunction( value ) ) { - return this.each(function( j ) { - jQuery( this ).addClass( value.call(this, j, this.className) ); - }); - } - - if ( value && typeof value === "string" ) { - classNames = value.split( rspace ); - - for ( i = 0, l = this.length; i < l; i++ ) { - elem = this[ i ]; - - if ( elem.nodeType === 1 ) { - if ( !elem.className && classNames.length === 1 ) { - elem.className = value; - - } else { - setClass = " " + elem.className + " "; - - for ( c = 0, cl = classNames.length; c < cl; c++ ) { - if ( !~setClass.indexOf( " " + classNames[ c ] + " " ) ) { - setClass += classNames[ c ] + " "; - } - } - elem.className = jQuery.trim( setClass ); - } - } - } - } - - return this; - }, - - removeClass: function( value ) { - var classNames, i, l, elem, className, c, cl; - - if ( jQuery.isFunction( value ) ) { - return this.each(function( j ) { - jQuery( this ).removeClass( value.call(this, j, this.className) ); - }); - } - - if ( (value && typeof value === "string") || value === undefined ) { - classNames = (value || "").split( rspace ); - - for ( i = 0, l = this.length; i < l; i++ ) { - elem = this[ i ]; - - if ( elem.nodeType === 1 && elem.className ) { - if ( value ) { - className = (" " + elem.className + " ").replace( rclass, " " ); - for ( c = 0, cl = classNames.length; c < cl; c++ ) { - className = className.replace(" " + classNames[ c ] + " ", " "); - } - elem.className = jQuery.trim( className ); - - } else { - elem.className = ""; - } - } - } - } - - return this; - }, - - toggleClass: function( value, stateVal ) { - var type = typeof value, - isBool = typeof stateVal === "boolean"; - - if ( jQuery.isFunction( value ) ) { - return this.each(function( i ) { - jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal ); - }); - } - - return this.each(function() { - if ( type === "string" ) { - // toggle individual class names - var className, - i = 0, - self = jQuery( this ), - state = stateVal, - classNames = value.split( rspace ); - - while ( (className = classNames[ i++ ]) ) { - // check each className given, space seperated list - state = isBool ? state : !self.hasClass( className ); - self[ state ? "addClass" : "removeClass" ]( className ); - } - - } else if ( type === "undefined" || type === "boolean" ) { - if ( this.className ) { - // store className if set - jQuery._data( this, "__className__", this.className ); - } - - // toggle whole className - this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || ""; - } - }); - }, - - hasClass: function( selector ) { - var className = " " + selector + " "; - for ( var i = 0, l = this.length; i < l; i++ ) { - if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) > -1 ) { - return true; - } - } - - return false; - }, - - val: function( value ) { - var hooks, ret, - elem = this[0]; - - if ( !arguments.length ) { - if ( elem ) { - hooks = jQuery.valHooks[ elem.nodeName.toLowerCase() ] || jQuery.valHooks[ elem.type ]; - - if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) { - return ret; - } - - ret = elem.value; - - return typeof ret === "string" ? - // handle most common string cases - ret.replace(rreturn, "") : - // handle cases where value is null/undef or number - ret == null ? "" : ret; - } - - return undefined; - } - - var isFunction = jQuery.isFunction( value ); - - return this.each(function( i ) { - var self = jQuery(this), val; - - if ( this.nodeType !== 1 ) { - return; - } - - if ( isFunction ) { - val = value.call( this, i, self.val() ); - } else { - val = value; - } - - // Treat null/undefined as ""; convert numbers to string - if ( val == null ) { - val = ""; - } else if ( typeof val === "number" ) { - val += ""; - } else if ( jQuery.isArray( val ) ) { - val = jQuery.map(val, function ( value ) { - return value == null ? "" : value + ""; - }); - } - - hooks = jQuery.valHooks[ this.nodeName.toLowerCase() ] || jQuery.valHooks[ this.type ]; - - // If set returns undefined, fall back to normal setting - if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) { - this.value = val; - } - }); - } -}); - -jQuery.extend({ - valHooks: { - option: { - get: function( elem ) { - // attributes.value is undefined in Blackberry 4.7 but - // uses .value. See #6932 - var val = elem.attributes.value; - return !val || val.specified ? elem.value : elem.text; - } - }, - select: { - get: function( elem ) { - var value, - index = elem.selectedIndex, - values = [], - options = elem.options, - one = elem.type === "select-one"; - - // Nothing was selected - if ( index < 0 ) { - return null; - } - - // Loop through all the selected options - for ( var i = one ? index : 0, max = one ? index + 1 : options.length; i < max; i++ ) { - var option = options[ i ]; - - // Don't return options that are disabled or in a disabled optgroup - if ( option.selected && (jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null) && - (!option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" )) ) { - - // Get the specific value for the option - value = jQuery( option ).val(); - - // We don't need an array for one selects - if ( one ) { - return value; - } - - // Multi-Selects return an array - values.push( value ); - } - } - - // Fixes Bug #2551 -- select.val() broken in IE after form.reset() - if ( one && !values.length && options.length ) { - return jQuery( options[ index ] ).val(); - } - - return values; - }, - - set: function( elem, value ) { - var values = jQuery.makeArray( value ); - - jQuery(elem).find("option").each(function() { - this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0; - }); - - if ( !values.length ) { - elem.selectedIndex = -1; - } - return values; - } - } - }, - - attrFn: { - val: true, - css: true, - html: true, - text: true, - data: true, - width: true, - height: true, - offset: true - }, - - attrFix: { - // Always normalize to ensure hook usage - tabindex: "tabIndex" - }, - - attr: function( elem, name, value, pass ) { - var nType = elem.nodeType; - - // don't get/set attributes on text, comment and attribute nodes - if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { - return undefined; - } - - if ( pass && name in jQuery.attrFn ) { - return jQuery( elem )[ name ]( value ); - } - - // Fallback to prop when attributes are not supported - if ( !("getAttribute" in elem) ) { - return jQuery.prop( elem, name, value ); - } - - var ret, hooks, - notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); - - // Normalize the name if needed - if ( notxml ) { - name = jQuery.attrFix[ name ] || name; - - hooks = jQuery.attrHooks[ name ]; - - if ( !hooks ) { - // Use boolHook for boolean attributes - if ( rboolean.test( name ) ) { - hooks = boolHook; - - // Use nodeHook if available( IE6/7 ) - } else if ( nodeHook ) { - hooks = nodeHook; - } - } - } - - if ( value !== undefined ) { - - if ( value === null ) { - jQuery.removeAttr( elem, name ); - return undefined; - - } else if ( hooks && "set" in hooks && notxml && (ret = hooks.set( elem, value, name )) !== undefined ) { - return ret; - - } else { - elem.setAttribute( name, "" + value ); - return value; - } - - } else if ( hooks && "get" in hooks && notxml && (ret = hooks.get( elem, name )) !== null ) { - return ret; - - } else { - - ret = elem.getAttribute( name ); - - // Non-existent attributes return null, we normalize to undefined - return ret === null ? - undefined : - ret; - } - }, - - removeAttr: function( elem, name ) { - var propName; - if ( elem.nodeType === 1 ) { - name = jQuery.attrFix[ name ] || name; - - jQuery.attr( elem, name, "" ); - elem.removeAttribute( name ); - - // Set corresponding property to false for boolean attributes - if ( rboolean.test( name ) && (propName = jQuery.propFix[ name ] || name) in elem ) { - elem[ propName ] = false; - } - } - }, - - attrHooks: { - type: { - set: function( elem, value ) { - // We can't allow the type property to be changed (since it causes problems in IE) - if ( rtype.test( elem.nodeName ) && elem.parentNode ) { - jQuery.error( "type property can't be changed" ); - } else if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) { - // Setting the type on a radio button after the value resets the value in IE6-9 - // Reset value to it's default in case type is set after value - // This is for element creation - var val = elem.value; - elem.setAttribute( "type", value ); - if ( val ) { - elem.value = val; - } - return value; - } - } - }, - // Use the value property for back compat - // Use the nodeHook for button elements in IE6/7 (#1954) - value: { - get: function( elem, name ) { - if ( nodeHook && jQuery.nodeName( elem, "button" ) ) { - return nodeHook.get( elem, name ); - } - return name in elem ? - elem.value : - null; - }, - set: function( elem, value, name ) { - if ( nodeHook && jQuery.nodeName( elem, "button" ) ) { - return nodeHook.set( elem, value, name ); - } - // Does not return so that setAttribute is also used - elem.value = value; - } - } - }, - - propFix: { - tabindex: "tabIndex", - readonly: "readOnly", - "for": "htmlFor", - "class": "className", - maxlength: "maxLength", - cellspacing: "cellSpacing", - cellpadding: "cellPadding", - rowspan: "rowSpan", - colspan: "colSpan", - usemap: "useMap", - frameborder: "frameBorder", - contenteditable: "contentEditable" - }, - - prop: function( elem, name, value ) { - var nType = elem.nodeType; - - // don't get/set properties on text, comment and attribute nodes - if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { - return undefined; - } - - var ret, hooks, - notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); - - if ( notxml ) { - // Fix name and attach hooks - name = jQuery.propFix[ name ] || name; - hooks = jQuery.propHooks[ name ]; - } - - if ( value !== undefined ) { - if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) { - return ret; - - } else { - return (elem[ name ] = value); - } - - } else { - if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) { - return ret; - - } else { - return elem[ name ]; - } - } - }, - - propHooks: { - tabIndex: { - get: function( elem ) { - // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set - // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ - var attributeNode = elem.getAttributeNode("tabindex"); - - return attributeNode && attributeNode.specified ? - parseInt( attributeNode.value, 10 ) : - rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ? - 0 : - undefined; - } - } - } -}); - -// Add the tabindex propHook to attrHooks for back-compat -jQuery.attrHooks.tabIndex = jQuery.propHooks.tabIndex; - -// Hook for boolean attributes -boolHook = { - get: function( elem, name ) { - // Align boolean attributes with corresponding properties - // Fall back to attribute presence where some booleans are not supported - var attrNode; - return jQuery.prop( elem, name ) === true || ( attrNode = elem.getAttributeNode( name ) ) && attrNode.nodeValue !== false ? - name.toLowerCase() : - undefined; - }, - set: function( elem, value, name ) { - var propName; - if ( value === false ) { - // Remove boolean attributes when set to false - jQuery.removeAttr( elem, name ); - } else { - // value is true since we know at this point it's type boolean and not false - // Set boolean attributes to the same name and set the DOM property - propName = jQuery.propFix[ name ] || name; - if ( propName in elem ) { - // Only set the IDL specifically if it already exists on the element - elem[ propName ] = true; - } - - elem.setAttribute( name, name.toLowerCase() ); - } - return name; - } -}; - -// IE6/7 do not support getting/setting some attributes with get/setAttribute -if ( !jQuery.support.getSetAttribute ) { - - // Use this for any attribute in IE6/7 - // This fixes almost every IE6/7 issue - nodeHook = jQuery.valHooks.button = { - get: function( elem, name ) { - var ret; - ret = elem.getAttributeNode( name ); - // Return undefined if nodeValue is empty string - return ret && ret.nodeValue !== "" ? - ret.nodeValue : - undefined; - }, - set: function( elem, value, name ) { - // Set the existing or create a new attribute node - var ret = elem.getAttributeNode( name ); - if ( !ret ) { - ret = document.createAttribute( name ); - elem.setAttributeNode( ret ); - } - return (ret.nodeValue = value + ""); - } - }; - - // Set width and height to auto instead of 0 on empty string( Bug #8150 ) - // This is for removals - jQuery.each([ "width", "height" ], function( i, name ) { - jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { - set: function( elem, value ) { - if ( value === "" ) { - elem.setAttribute( name, "auto" ); - return value; - } - } - }); - }); -} - - -// Some attributes require a special call on IE -if ( !jQuery.support.hrefNormalized ) { - jQuery.each([ "href", "src", "width", "height" ], function( i, name ) { - jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { - get: function( elem ) { - var ret = elem.getAttribute( name, 2 ); - return ret === null ? undefined : ret; - } - }); - }); -} - -if ( !jQuery.support.style ) { - jQuery.attrHooks.style = { - get: function( elem ) { - // Return undefined in the case of empty string - // Normalize to lowercase since IE uppercases css property names - return elem.style.cssText.toLowerCase() || undefined; - }, - set: function( elem, value ) { - return (elem.style.cssText = "" + value); - } - }; -} - -// Safari mis-reports the default selected property of an option -// Accessing the parent's selectedIndex property fixes it -if ( !jQuery.support.optSelected ) { - jQuery.propHooks.selected = jQuery.extend( jQuery.propHooks.selected, { - get: function( elem ) { - var parent = elem.parentNode; - - if ( parent ) { - parent.selectedIndex; - - // Make sure that it also works with optgroups, see #5701 - if ( parent.parentNode ) { - parent.parentNode.selectedIndex; - } - } - return null; - } - }); -} - -// Radios and checkboxes getter/setter -if ( !jQuery.support.checkOn ) { - jQuery.each([ "radio", "checkbox" ], function() { - jQuery.valHooks[ this ] = { - get: function( elem ) { - // Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified - return elem.getAttribute("value") === null ? "on" : elem.value; - } - }; - }); -} -jQuery.each([ "radio", "checkbox" ], function() { - jQuery.valHooks[ this ] = jQuery.extend( jQuery.valHooks[ this ], { - set: function( elem, value ) { - if ( jQuery.isArray( value ) ) { - return (elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0); - } - } - }); -}); - - - - -var rnamespaces = /\.(.*)$/, - rformElems = /^(?:textarea|input|select)$/i, - rperiod = /\./g, - rspaces = / /g, - rescape = /[^\w\s.|`]/g, - fcleanup = function( nm ) { - return nm.replace(rescape, "\\$&"); - }; - -/* - * A number of helper functions used for managing events. - * Many of the ideas behind this code originated from - * Dean Edwards' addEvent library. - */ -jQuery.event = { - - // Bind an event to an element - // Original by Dean Edwards - add: function( elem, types, handler, data ) { - if ( elem.nodeType === 3 || elem.nodeType === 8 ) { - return; - } - - if ( handler === false ) { - handler = returnFalse; - } else if ( !handler ) { - // Fixes bug #7229. Fix recommended by jdalton - return; - } - - var handleObjIn, handleObj; - - if ( handler.handler ) { - handleObjIn = handler; - handler = handleObjIn.handler; - } - - // Make sure that the function being executed has a unique ID - if ( !handler.guid ) { - handler.guid = jQuery.guid++; - } - - // Init the element's event structure - var elemData = jQuery._data( elem ); - - // If no elemData is found then we must be trying to bind to one of the - // banned noData elements - if ( !elemData ) { - return; - } - - var events = elemData.events, - eventHandle = elemData.handle; - - if ( !events ) { - elemData.events = events = {}; - } - - if ( !eventHandle ) { - elemData.handle = eventHandle = function( e ) { - // Discard the second event of a jQuery.event.trigger() and - // when an event is called after a page has unloaded - return typeof jQuery !== "undefined" && (!e || jQuery.event.triggered !== e.type) ? - jQuery.event.handle.apply( eventHandle.elem, arguments ) : - undefined; - }; - } - - // Add elem as a property of the handle function - // This is to prevent a memory leak with non-native events in IE. - eventHandle.elem = elem; - - // Handle multiple events separated by a space - // jQuery(...).bind("mouseover mouseout", fn); - types = types.split(" "); - - var type, i = 0, namespaces; - - while ( (type = types[ i++ ]) ) { - handleObj = handleObjIn ? - jQuery.extend({}, handleObjIn) : - { handler: handler, data: data }; - - // Namespaced event handlers - if ( type.indexOf(".") > -1 ) { - namespaces = type.split("."); - type = namespaces.shift(); - handleObj.namespace = namespaces.slice(0).sort().join("."); - - } else { - namespaces = []; - handleObj.namespace = ""; - } - - handleObj.type = type; - if ( !handleObj.guid ) { - handleObj.guid = handler.guid; - } - - // Get the current list of functions bound to this event - var handlers = events[ type ], - special = jQuery.event.special[ type ] || {}; - - // Init the event handler queue - if ( !handlers ) { - handlers = events[ type ] = []; - - // Check for a special event handler - // Only use addEventListener/attachEvent if the special - // events handler returns false - if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) { - // Bind the global event handler to the element - if ( elem.addEventListener ) { - elem.addEventListener( type, eventHandle, false ); - - } else if ( elem.attachEvent ) { - elem.attachEvent( "on" + type, eventHandle ); - } - } - } - - if ( special.add ) { - special.add.call( elem, handleObj ); - - if ( !handleObj.handler.guid ) { - handleObj.handler.guid = handler.guid; - } - } - - // Add the function to the element's handler list - handlers.push( handleObj ); - - // Keep track of which events have been used, for event optimization - jQuery.event.global[ type ] = true; - } - - // Nullify elem to prevent memory leaks in IE - elem = null; - }, - - global: {}, - - // Detach an event or set of events from an element - remove: function( elem, types, handler, pos ) { - // don't do events on text and comment nodes - if ( elem.nodeType === 3 || elem.nodeType === 8 ) { - return; - } - - if ( handler === false ) { - handler = returnFalse; - } - - var ret, type, fn, j, i = 0, all, namespaces, namespace, special, eventType, handleObj, origType, - elemData = jQuery.hasData( elem ) && jQuery._data( elem ), - events = elemData && elemData.events; - - if ( !elemData || !events ) { - return; - } - - // types is actually an event object here - if ( types && types.type ) { - handler = types.handler; - types = types.type; - } - - // Unbind all events for the element - if ( !types || typeof types === "string" && types.charAt(0) === "." ) { - types = types || ""; - - for ( type in events ) { - jQuery.event.remove( elem, type + types ); - } - - return; - } - - // Handle multiple events separated by a space - // jQuery(...).unbind("mouseover mouseout", fn); - types = types.split(" "); - - while ( (type = types[ i++ ]) ) { - origType = type; - handleObj = null; - all = type.indexOf(".") < 0; - namespaces = []; - - if ( !all ) { - // Namespaced event handlers - namespaces = type.split("."); - type = namespaces.shift(); - - namespace = new RegExp("(^|\\.)" + - jQuery.map( namespaces.slice(0).sort(), fcleanup ).join("\\.(?:.*\\.)?") + "(\\.|$)"); - } - - eventType = events[ type ]; - - if ( !eventType ) { - continue; - } - - if ( !handler ) { - for ( j = 0; j < eventType.length; j++ ) { - handleObj = eventType[ j ]; - - if ( all || namespace.test( handleObj.namespace ) ) { - jQuery.event.remove( elem, origType, handleObj.handler, j ); - eventType.splice( j--, 1 ); - } - } - - continue; - } - - special = jQuery.event.special[ type ] || {}; - - for ( j = pos || 0; j < eventType.length; j++ ) { - handleObj = eventType[ j ]; - - if ( handler.guid === handleObj.guid ) { - // remove the given handler for the given type - if ( all || namespace.test( handleObj.namespace ) ) { - if ( pos == null ) { - eventType.splice( j--, 1 ); - } - - if ( special.remove ) { - special.remove.call( elem, handleObj ); - } - } - - if ( pos != null ) { - break; - } - } - } - - // remove generic event handler if no more handlers exist - if ( eventType.length === 0 || pos != null && eventType.length === 1 ) { - if ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) { - jQuery.removeEvent( elem, type, elemData.handle ); - } - - ret = null; - delete events[ type ]; - } - } - - // Remove the expando if it's no longer used - if ( jQuery.isEmptyObject( events ) ) { - var handle = elemData.handle; - if ( handle ) { - handle.elem = null; - } - - delete elemData.events; - delete elemData.handle; - - if ( jQuery.isEmptyObject( elemData ) ) { - jQuery.removeData( elem, undefined, true ); - } - } - }, - - // Events that are safe to short-circuit if no handlers are attached. - // Native DOM events should not be added, they may have inline handlers. - customEvent: { - "getData": true, - "setData": true, - "changeData": true - }, - - trigger: function( event, data, elem, onlyHandlers ) { - // Event object or event type - var type = event.type || event, - namespaces = [], - exclusive; - - if ( type.indexOf("!") >= 0 ) { - // Exclusive events trigger only for the exact event (no namespaces) - type = type.slice(0, -1); - exclusive = true; - } - - if ( type.indexOf(".") >= 0 ) { - // Namespaced trigger; create a regexp to match event type in handle() - namespaces = type.split("."); - type = namespaces.shift(); - namespaces.sort(); - } - - if ( (!elem || jQuery.event.customEvent[ type ]) && !jQuery.event.global[ type ] ) { - // No jQuery handlers for this event type, and it can't have inline handlers - return; - } - - // Caller can pass in an Event, Object, or just an event type string - event = typeof event === "object" ? - // jQuery.Event object - event[ jQuery.expando ] ? event : - // Object literal - new jQuery.Event( type, event ) : - // Just the event type (string) - new jQuery.Event( type ); - - event.type = type; - event.exclusive = exclusive; - event.namespace = namespaces.join("."); - event.namespace_re = new RegExp("(^|\\.)" + namespaces.join("\\.(?:.*\\.)?") + "(\\.|$)"); - - // triggerHandler() and global events don't bubble or run the default action - if ( onlyHandlers || !elem ) { - event.preventDefault(); - event.stopPropagation(); - } - - // Handle a global trigger - if ( !elem ) { - // TODO: Stop taunting the data cache; remove global events and always attach to document - jQuery.each( jQuery.cache, function() { - // internalKey variable is just used to make it easier to find - // and potentially change this stuff later; currently it just - // points to jQuery.expando - var internalKey = jQuery.expando, - internalCache = this[ internalKey ]; - if ( internalCache && internalCache.events && internalCache.events[ type ] ) { - jQuery.event.trigger( event, data, internalCache.handle.elem ); - } - }); - return; - } - - // Don't do events on text and comment nodes - if ( elem.nodeType === 3 || elem.nodeType === 8 ) { - return; - } - - // Clean up the event in case it is being reused - event.result = undefined; - event.target = elem; - - // Clone any incoming data and prepend the event, creating the handler arg list - data = data != null ? jQuery.makeArray( data ) : []; - data.unshift( event ); - - var cur = elem, - // IE doesn't like method names with a colon (#3533, #8272) - ontype = type.indexOf(":") < 0 ? "on" + type : ""; - - // Fire event on the current element, then bubble up the DOM tree - do { - var handle = jQuery._data( cur, "handle" ); - - event.currentTarget = cur; - if ( handle ) { - handle.apply( cur, data ); - } - - // Trigger an inline bound script - if ( ontype && jQuery.acceptData( cur ) && cur[ ontype ] && cur[ ontype ].apply( cur, data ) === false ) { - event.result = false; - event.preventDefault(); - } - - // Bubble up to document, then to window - cur = cur.parentNode || cur.ownerDocument || cur === event.target.ownerDocument && window; - } while ( cur && !event.isPropagationStopped() ); - - // If nobody prevented the default action, do it now - if ( !event.isDefaultPrevented() ) { - var old, - special = jQuery.event.special[ type ] || {}; - - if ( (!special._default || special._default.call( elem.ownerDocument, event ) === false) && - !(type === "click" && jQuery.nodeName( elem, "a" )) && jQuery.acceptData( elem ) ) { - - // Call a native DOM method on the target with the same name name as the event. - // Can't use an .isFunction)() check here because IE6/7 fails that test. - // IE<9 dies on focus to hidden element (#1486), may want to revisit a try/catch. - try { - if ( ontype && elem[ type ] ) { - // Don't re-trigger an onFOO event when we call its FOO() method - old = elem[ ontype ]; - - if ( old ) { - elem[ ontype ] = null; - } - - jQuery.event.triggered = type; - elem[ type ](); - } - } catch ( ieError ) {} - - if ( old ) { - elem[ ontype ] = old; - } - - jQuery.event.triggered = undefined; - } - } - - return event.result; - }, - - handle: function( event ) { - event = jQuery.event.fix( event || window.event ); - // Snapshot the handlers list since a called handler may add/remove events. - var handlers = ((jQuery._data( this, "events" ) || {})[ event.type ] || []).slice(0), - run_all = !event.exclusive && !event.namespace, - args = Array.prototype.slice.call( arguments, 0 ); - - // Use the fix-ed Event rather than the (read-only) native event - args[0] = event; - event.currentTarget = this; - - for ( var j = 0, l = handlers.length; j < l; j++ ) { - var handleObj = handlers[ j ]; - - // Triggered event must 1) be non-exclusive and have no namespace, or - // 2) have namespace(s) a subset or equal to those in the bound event. - if ( run_all || event.namespace_re.test( handleObj.namespace ) ) { - // Pass in a reference to the handler function itself - // So that we can later remove it - event.handler = handleObj.handler; - event.data = handleObj.data; - event.handleObj = handleObj; - - var ret = handleObj.handler.apply( this, args ); - - if ( ret !== undefined ) { - event.result = ret; - if ( ret === false ) { - event.preventDefault(); - event.stopPropagation(); - } - } - - if ( event.isImmediatePropagationStopped() ) { - break; - } - } - } - return event.result; - }, - - props: "altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "), - - fix: function( event ) { - if ( event[ jQuery.expando ] ) { - return event; - } - - // store a copy of the original event object - // and "clone" to set read-only properties - var originalEvent = event; - event = jQuery.Event( originalEvent ); - - for ( var i = this.props.length, prop; i; ) { - prop = this.props[ --i ]; - event[ prop ] = originalEvent[ prop ]; - } - - // Fix target property, if necessary - if ( !event.target ) { - // Fixes #1925 where srcElement might not be defined either - event.target = event.srcElement || document; - } - - // check if target is a textnode (safari) - if ( event.target.nodeType === 3 ) { - event.target = event.target.parentNode; - } - - // Add relatedTarget, if necessary - if ( !event.relatedTarget && event.fromElement ) { - event.relatedTarget = event.fromElement === event.target ? event.toElement : event.fromElement; - } - - // Calculate pageX/Y if missing and clientX/Y available - if ( event.pageX == null && event.clientX != null ) { - var eventDocument = event.target.ownerDocument || document, - doc = eventDocument.documentElement, - body = eventDocument.body; - - event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0); - event.pageY = event.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc && doc.clientTop || body && body.clientTop || 0); - } - - // Add which for key events - if ( event.which == null && (event.charCode != null || event.keyCode != null) ) { - event.which = event.charCode != null ? event.charCode : event.keyCode; - } - - // Add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs) - if ( !event.metaKey && event.ctrlKey ) { - event.metaKey = event.ctrlKey; - } - - // Add which for click: 1 === left; 2 === middle; 3 === right - // Note: button is not normalized, so don't use it - if ( !event.which && event.button !== undefined ) { - event.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) )); - } - - return event; - }, - - // Deprecated, use jQuery.guid instead - guid: 1E8, - - // Deprecated, use jQuery.proxy instead - proxy: jQuery.proxy, - - special: { - ready: { - // Make sure the ready event is setup - setup: jQuery.bindReady, - teardown: jQuery.noop - }, - - live: { - add: function( handleObj ) { - jQuery.event.add( this, - liveConvert( handleObj.origType, handleObj.selector ), - jQuery.extend({}, handleObj, {handler: liveHandler, guid: handleObj.handler.guid}) ); - }, - - remove: function( handleObj ) { - jQuery.event.remove( this, liveConvert( handleObj.origType, handleObj.selector ), handleObj ); - } - }, - - beforeunload: { - setup: function( data, namespaces, eventHandle ) { - // We only want to do this special case on windows - if ( jQuery.isWindow( this ) ) { - this.onbeforeunload = eventHandle; - } - }, - - teardown: function( namespaces, eventHandle ) { - if ( this.onbeforeunload === eventHandle ) { - this.onbeforeunload = null; - } - } - } - } -}; - -jQuery.removeEvent = document.removeEventListener ? - function( elem, type, handle ) { - if ( elem.removeEventListener ) { - elem.removeEventListener( type, handle, false ); - } - } : - function( elem, type, handle ) { - if ( elem.detachEvent ) { - elem.detachEvent( "on" + type, handle ); - } - }; - -jQuery.Event = function( src, props ) { - // Allow instantiation without the 'new' keyword - if ( !this.preventDefault ) { - return new jQuery.Event( src, props ); - } - - // Event object - if ( src && src.type ) { - this.originalEvent = src; - this.type = src.type; - - // Events bubbling up the document may have been marked as prevented - // by a handler lower down the tree; reflect the correct value. - this.isDefaultPrevented = (src.defaultPrevented || src.returnValue === false || - src.getPreventDefault && src.getPreventDefault()) ? returnTrue : returnFalse; - - // Event type - } else { - this.type = src; - } - - // Put explicitly provided properties onto the event object - if ( props ) { - jQuery.extend( this, props ); - } - - // timeStamp is buggy for some events on Firefox(#3843) - // So we won't rely on the native value - this.timeStamp = jQuery.now(); - - // Mark it as fixed - this[ jQuery.expando ] = true; -}; - -function returnFalse() { - return false; -} -function returnTrue() { - return true; -} - -// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding -// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html -jQuery.Event.prototype = { - preventDefault: function() { - this.isDefaultPrevented = returnTrue; - - var e = this.originalEvent; - if ( !e ) { - return; - } - - // if preventDefault exists run it on the original event - if ( e.preventDefault ) { - e.preventDefault(); - - // otherwise set the returnValue property of the original event to false (IE) - } else { - e.returnValue = false; - } - }, - stopPropagation: function() { - this.isPropagationStopped = returnTrue; - - var e = this.originalEvent; - if ( !e ) { - return; - } - // if stopPropagation exists run it on the original event - if ( e.stopPropagation ) { - e.stopPropagation(); - } - // otherwise set the cancelBubble property of the original event to true (IE) - e.cancelBubble = true; - }, - stopImmediatePropagation: function() { - this.isImmediatePropagationStopped = returnTrue; - this.stopPropagation(); - }, - isDefaultPrevented: returnFalse, - isPropagationStopped: returnFalse, - isImmediatePropagationStopped: returnFalse -}; - -// Checks if an event happened on an element within another element -// Used in jQuery.event.special.mouseenter and mouseleave handlers -var withinElement = function( event ) { - - // Check if mouse(over|out) are still within the same parent element - var related = event.relatedTarget, - inside = false, - eventType = event.type; - - event.type = event.data; - - if ( related !== this ) { - - if ( related ) { - inside = jQuery.contains( this, related ); - } - - if ( !inside ) { - - jQuery.event.handle.apply( this, arguments ); - - event.type = eventType; - } - } -}, - -// In case of event delegation, we only need to rename the event.type, -// liveHandler will take care of the rest. -delegate = function( event ) { - event.type = event.data; - jQuery.event.handle.apply( this, arguments ); -}; - -// Create mouseenter and mouseleave events -jQuery.each({ - mouseenter: "mouseover", - mouseleave: "mouseout" -}, function( orig, fix ) { - jQuery.event.special[ orig ] = { - setup: function( data ) { - jQuery.event.add( this, fix, data && data.selector ? delegate : withinElement, orig ); - }, - teardown: function( data ) { - jQuery.event.remove( this, fix, data && data.selector ? delegate : withinElement ); - } - }; -}); - -// submit delegation -if ( !jQuery.support.submitBubbles ) { - - jQuery.event.special.submit = { - setup: function( data, namespaces ) { - if ( !jQuery.nodeName( this, "form" ) ) { - jQuery.event.add(this, "click.specialSubmit", function( e ) { - // Avoid triggering error on non-existent type attribute in IE VML (#7071) - var elem = e.target, - type = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.type : ""; - - if ( (type === "submit" || type === "image") && jQuery( elem ).closest("form").length ) { - trigger( "submit", this, arguments ); - } - }); - - jQuery.event.add(this, "keypress.specialSubmit", function( e ) { - var elem = e.target, - type = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.type : ""; - - if ( (type === "text" || type === "password") && jQuery( elem ).closest("form").length && e.keyCode === 13 ) { - trigger( "submit", this, arguments ); - } - }); - - } else { - return false; - } - }, - - teardown: function( namespaces ) { - jQuery.event.remove( this, ".specialSubmit" ); - } - }; - -} - -// change delegation, happens here so we have bind. -if ( !jQuery.support.changeBubbles ) { - - var changeFilters, - - getVal = function( elem ) { - var type = jQuery.nodeName( elem, "input" ) ? elem.type : "", - val = elem.value; - - if ( type === "radio" || type === "checkbox" ) { - val = elem.checked; - - } else if ( type === "select-multiple" ) { - val = elem.selectedIndex > -1 ? - jQuery.map( elem.options, function( elem ) { - return elem.selected; - }).join("-") : - ""; - - } else if ( jQuery.nodeName( elem, "select" ) ) { - val = elem.selectedIndex; - } - - return val; - }, - - testChange = function testChange( e ) { - var elem = e.target, data, val; - - if ( !rformElems.test( elem.nodeName ) || elem.readOnly ) { - return; - } - - data = jQuery._data( elem, "_change_data" ); - val = getVal(elem); - - // the current data will be also retrieved by beforeactivate - if ( e.type !== "focusout" || elem.type !== "radio" ) { - jQuery._data( elem, "_change_data", val ); - } - - if ( data === undefined || val === data ) { - return; - } - - if ( data != null || val ) { - e.type = "change"; - e.liveFired = undefined; - jQuery.event.trigger( e, arguments[1], elem ); - } - }; - - jQuery.event.special.change = { - filters: { - focusout: testChange, - - beforedeactivate: testChange, - - click: function( e ) { - var elem = e.target, type = jQuery.nodeName( elem, "input" ) ? elem.type : ""; - - if ( type === "radio" || type === "checkbox" || jQuery.nodeName( elem, "select" ) ) { - testChange.call( this, e ); - } - }, - - // Change has to be called before submit - // Keydown will be called before keypress, which is used in submit-event delegation - keydown: function( e ) { - var elem = e.target, type = jQuery.nodeName( elem, "input" ) ? elem.type : ""; - - if ( (e.keyCode === 13 && !jQuery.nodeName( elem, "textarea" ) ) || - (e.keyCode === 32 && (type === "checkbox" || type === "radio")) || - type === "select-multiple" ) { - testChange.call( this, e ); - } - }, - - // Beforeactivate happens also before the previous element is blurred - // with this event you can't trigger a change event, but you can store - // information - beforeactivate: function( e ) { - var elem = e.target; - jQuery._data( elem, "_change_data", getVal(elem) ); - } - }, - - setup: function( data, namespaces ) { - if ( this.type === "file" ) { - return false; - } - - for ( var type in changeFilters ) { - jQuery.event.add( this, type + ".specialChange", changeFilters[type] ); - } - - return rformElems.test( this.nodeName ); - }, - - teardown: function( namespaces ) { - jQuery.event.remove( this, ".specialChange" ); - - return rformElems.test( this.nodeName ); - } - }; - - changeFilters = jQuery.event.special.change.filters; - - // Handle when the input is .focus()'d - changeFilters.focus = changeFilters.beforeactivate; -} - -function trigger( type, elem, args ) { - // Piggyback on a donor event to simulate a different one. - // Fake originalEvent to avoid donor's stopPropagation, but if the - // simulated event prevents default then we do the same on the donor. - // Don't pass args or remember liveFired; they apply to the donor event. - var event = jQuery.extend( {}, args[ 0 ] ); - event.type = type; - event.originalEvent = {}; - event.liveFired = undefined; - jQuery.event.handle.call( elem, event ); - if ( event.isDefaultPrevented() ) { - args[ 0 ].preventDefault(); - } -} - -// Create "bubbling" focus and blur events -if ( !jQuery.support.focusinBubbles ) { - jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) { - - // Attach a single capturing handler while someone wants focusin/focusout - var attaches = 0; - - jQuery.event.special[ fix ] = { - setup: function() { - if ( attaches++ === 0 ) { - document.addEventListener( orig, handler, true ); - } - }, - teardown: function() { - if ( --attaches === 0 ) { - document.removeEventListener( orig, handler, true ); - } - } - }; - - function handler( donor ) { - // Donor event is always a native one; fix it and switch its type. - // Let focusin/out handler cancel the donor focus/blur event. - var e = jQuery.event.fix( donor ); - e.type = fix; - e.originalEvent = {}; - jQuery.event.trigger( e, null, e.target ); - if ( e.isDefaultPrevented() ) { - donor.preventDefault(); - } - } - }); -} - -jQuery.each(["bind", "one"], function( i, name ) { - jQuery.fn[ name ] = function( type, data, fn ) { - var handler; - - // Handle object literals - if ( typeof type === "object" ) { - for ( var key in type ) { - this[ name ](key, data, type[key], fn); - } - return this; - } - - if ( arguments.length === 2 || data === false ) { - fn = data; - data = undefined; - } - - if ( name === "one" ) { - handler = function( event ) { - jQuery( this ).unbind( event, handler ); - return fn.apply( this, arguments ); - }; - handler.guid = fn.guid || jQuery.guid++; - } else { - handler = fn; - } - - if ( type === "unload" && name !== "one" ) { - this.one( type, data, fn ); - - } else { - for ( var i = 0, l = this.length; i < l; i++ ) { - jQuery.event.add( this[i], type, handler, data ); - } - } - - return this; - }; -}); - -jQuery.fn.extend({ - unbind: function( type, fn ) { - // Handle object literals - if ( typeof type === "object" && !type.preventDefault ) { - for ( var key in type ) { - this.unbind(key, type[key]); - } - - } else { - for ( var i = 0, l = this.length; i < l; i++ ) { - jQuery.event.remove( this[i], type, fn ); - } - } - - return this; - }, - - delegate: function( selector, types, data, fn ) { - return this.live( types, data, fn, selector ); - }, - - undelegate: function( selector, types, fn ) { - if ( arguments.length === 0 ) { - return this.unbind( "live" ); - - } else { - return this.die( types, null, fn, selector ); - } - }, - - trigger: function( type, data ) { - return this.each(function() { - jQuery.event.trigger( type, data, this ); - }); - }, - - triggerHandler: function( type, data ) { - if ( this[0] ) { - return jQuery.event.trigger( type, data, this[0], true ); - } - }, - - toggle: function( fn ) { - // Save reference to arguments for access in closure - var args = arguments, - guid = fn.guid || jQuery.guid++, - i = 0, - toggler = function( event ) { - // Figure out which function to execute - var lastToggle = ( jQuery.data( this, "lastToggle" + fn.guid ) || 0 ) % i; - jQuery.data( this, "lastToggle" + fn.guid, lastToggle + 1 ); - - // Make sure that clicks stop - event.preventDefault(); - - // and execute the function - return args[ lastToggle ].apply( this, arguments ) || false; - }; - - // link all the functions, so any of them can unbind this click handler - toggler.guid = guid; - while ( i < args.length ) { - args[ i++ ].guid = guid; - } - - return this.click( toggler ); - }, - - hover: function( fnOver, fnOut ) { - return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver ); - } -}); - -var liveMap = { - focus: "focusin", - blur: "focusout", - mouseenter: "mouseover", - mouseleave: "mouseout" -}; - -jQuery.each(["live", "die"], function( i, name ) { - jQuery.fn[ name ] = function( types, data, fn, origSelector /* Internal Use Only */ ) { - var type, i = 0, match, namespaces, preType, - selector = origSelector || this.selector, - context = origSelector ? this : jQuery( this.context ); - - if ( typeof types === "object" && !types.preventDefault ) { - for ( var key in types ) { - context[ name ]( key, data, types[key], selector ); - } - - return this; - } - - if ( name === "die" && !types && - origSelector && origSelector.charAt(0) === "." ) { - - context.unbind( origSelector ); - - return this; - } - - if ( data === false || jQuery.isFunction( data ) ) { - fn = data || returnFalse; - data = undefined; - } - - types = (types || "").split(" "); - - while ( (type = types[ i++ ]) != null ) { - match = rnamespaces.exec( type ); - namespaces = ""; - - if ( match ) { - namespaces = match[0]; - type = type.replace( rnamespaces, "" ); - } - - if ( type === "hover" ) { - types.push( "mouseenter" + namespaces, "mouseleave" + namespaces ); - continue; - } - - preType = type; - - if ( liveMap[ type ] ) { - types.push( liveMap[ type ] + namespaces ); - type = type + namespaces; - - } else { - type = (liveMap[ type ] || type) + namespaces; - } - - if ( name === "live" ) { - // bind live handler - for ( var j = 0, l = context.length; j < l; j++ ) { - jQuery.event.add( context[j], "live." + liveConvert( type, selector ), - { data: data, selector: selector, handler: fn, origType: type, origHandler: fn, preType: preType } ); - } - - } else { - // unbind live handler - context.unbind( "live." + liveConvert( type, selector ), fn ); - } - } - - return this; - }; -}); - -function liveHandler( event ) { - var stop, maxLevel, related, match, handleObj, elem, j, i, l, data, close, namespace, ret, - elems = [], - selectors = [], - events = jQuery._data( this, "events" ); - - // Make sure we avoid non-left-click bubbling in Firefox (#3861) and disabled elements in IE (#6911) - if ( event.liveFired === this || !events || !events.live || event.target.disabled || event.button && event.type === "click" ) { - return; - } - - if ( event.namespace ) { - namespace = new RegExp("(^|\\.)" + event.namespace.split(".").join("\\.(?:.*\\.)?") + "(\\.|$)"); - } - - event.liveFired = this; - - var live = events.live.slice(0); - - for ( j = 0; j < live.length; j++ ) { - handleObj = live[j]; - - if ( handleObj.origType.replace( rnamespaces, "" ) === event.type ) { - selectors.push( handleObj.selector ); - - } else { - live.splice( j--, 1 ); - } - } - - match = jQuery( event.target ).closest( selectors, event.currentTarget ); - - for ( i = 0, l = match.length; i < l; i++ ) { - close = match[i]; - - for ( j = 0; j < live.length; j++ ) { - handleObj = live[j]; - - if ( close.selector === handleObj.selector && (!namespace || namespace.test( handleObj.namespace )) && !close.elem.disabled ) { - elem = close.elem; - related = null; - - // Those two events require additional checking - if ( handleObj.preType === "mouseenter" || handleObj.preType === "mouseleave" ) { - event.type = handleObj.preType; - related = jQuery( event.relatedTarget ).closest( handleObj.selector )[0]; - - // Make sure not to accidentally match a child element with the same selector - if ( related && jQuery.contains( elem, related ) ) { - related = elem; - } - } - - if ( !related || related !== elem ) { - elems.push({ elem: elem, handleObj: handleObj, level: close.level }); - } - } - } - } - - for ( i = 0, l = elems.length; i < l; i++ ) { - match = elems[i]; - - if ( maxLevel && match.level > maxLevel ) { - break; - } - - event.currentTarget = match.elem; - event.data = match.handleObj.data; - event.handleObj = match.handleObj; - - ret = match.handleObj.origHandler.apply( match.elem, arguments ); - - if ( ret === false || event.isPropagationStopped() ) { - maxLevel = match.level; - - if ( ret === false ) { - stop = false; - } - if ( event.isImmediatePropagationStopped() ) { - break; - } - } - } - - return stop; -} - -function liveConvert( type, selector ) { - return (type && type !== "*" ? type + "." : "") + selector.replace(rperiod, "`").replace(rspaces, "&"); -} - -jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " + - "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " + - "change select submit keydown keypress keyup error").split(" "), function( i, name ) { - - // Handle event binding - jQuery.fn[ name ] = function( data, fn ) { - if ( fn == null ) { - fn = data; - data = null; - } - - return arguments.length > 0 ? - this.bind( name, data, fn ) : - this.trigger( name ); - }; - - if ( jQuery.attrFn ) { - jQuery.attrFn[ name ] = true; - } -}); - - - -/*! - * Sizzle CSS Selector Engine - * Copyright 2011, The Dojo Foundation - * Released under the MIT, BSD, and GPL Licenses. - * More information: http://sizzlejs.com/ - */ -(function(){ - -var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g, - done = 0, - toString = Object.prototype.toString, - hasDuplicate = false, - baseHasDuplicate = true, - rBackslash = /\\/g, - rNonWord = /\W/; - -// Here we check if the JavaScript engine is using some sort of -// optimization where it does not always call our comparision -// function. If that is the case, discard the hasDuplicate value. -// Thus far that includes Google Chrome. -[0, 0].sort(function() { - baseHasDuplicate = false; - return 0; -}); - -var Sizzle = function( selector, context, results, seed ) { - results = results || []; - context = context || document; - - var origContext = context; - - if ( context.nodeType !== 1 && context.nodeType !== 9 ) { - return []; - } - - if ( !selector || typeof selector !== "string" ) { - return results; - } - - var m, set, checkSet, extra, ret, cur, pop, i, - prune = true, - contextXML = Sizzle.isXML( context ), - parts = [], - soFar = selector; - - // Reset the position of the chunker regexp (start from head) - do { - chunker.exec( "" ); - m = chunker.exec( soFar ); - - if ( m ) { - soFar = m[3]; - - parts.push( m[1] ); - - if ( m[2] ) { - extra = m[3]; - break; - } - } - } while ( m ); - - if ( parts.length > 1 && origPOS.exec( selector ) ) { - - if ( parts.length === 2 && Expr.relative[ parts[0] ] ) { - set = posProcess( parts[0] + parts[1], context ); - - } else { - set = Expr.relative[ parts[0] ] ? - [ context ] : - Sizzle( parts.shift(), context ); - - while ( parts.length ) { - selector = parts.shift(); - - if ( Expr.relative[ selector ] ) { - selector += parts.shift(); - } - - set = posProcess( selector, set ); - } - } - - } else { - // Take a shortcut and set the context if the root selector is an ID - // (but not if it'll be faster if the inner selector is an ID) - if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML && - Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) { - - ret = Sizzle.find( parts.shift(), context, contextXML ); - context = ret.expr ? - Sizzle.filter( ret.expr, ret.set )[0] : - ret.set[0]; - } - - if ( context ) { - ret = seed ? - { expr: parts.pop(), set: makeArray(seed) } : - Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML ); - - set = ret.expr ? - Sizzle.filter( ret.expr, ret.set ) : - ret.set; - - if ( parts.length > 0 ) { - checkSet = makeArray( set ); - - } else { - prune = false; - } - - while ( parts.length ) { - cur = parts.pop(); - pop = cur; - - if ( !Expr.relative[ cur ] ) { - cur = ""; - } else { - pop = parts.pop(); - } - - if ( pop == null ) { - pop = context; - } - - Expr.relative[ cur ]( checkSet, pop, contextXML ); - } - - } else { - checkSet = parts = []; - } - } - - if ( !checkSet ) { - checkSet = set; - } - - if ( !checkSet ) { - Sizzle.error( cur || selector ); - } - - if ( toString.call(checkSet) === "[object Array]" ) { - if ( !prune ) { - results.push.apply( results, checkSet ); - - } else if ( context && context.nodeType === 1 ) { - for ( i = 0; checkSet[i] != null; i++ ) { - if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && Sizzle.contains(context, checkSet[i])) ) { - results.push( set[i] ); - } - } - - } else { - for ( i = 0; checkSet[i] != null; i++ ) { - if ( checkSet[i] && checkSet[i].nodeType === 1 ) { - results.push( set[i] ); - } - } - } - - } else { - makeArray( checkSet, results ); - } - - if ( extra ) { - Sizzle( extra, origContext, results, seed ); - Sizzle.uniqueSort( results ); - } - - return results; -}; - -Sizzle.uniqueSort = function( results ) { - if ( sortOrder ) { - hasDuplicate = baseHasDuplicate; - results.sort( sortOrder ); - - if ( hasDuplicate ) { - for ( var i = 1; i < results.length; i++ ) { - if ( results[i] === results[ i - 1 ] ) { - results.splice( i--, 1 ); - } - } - } - } - - return results; -}; - -Sizzle.matches = function( expr, set ) { - return Sizzle( expr, null, null, set ); -}; - -Sizzle.matchesSelector = function( node, expr ) { - return Sizzle( expr, null, null, [node] ).length > 0; -}; - -Sizzle.find = function( expr, context, isXML ) { - var set; - - if ( !expr ) { - return []; - } - - for ( var i = 0, l = Expr.order.length; i < l; i++ ) { - var match, - type = Expr.order[i]; - - if ( (match = Expr.leftMatch[ type ].exec( expr )) ) { - var left = match[1]; - match.splice( 1, 1 ); - - if ( left.substr( left.length - 1 ) !== "\\" ) { - match[1] = (match[1] || "").replace( rBackslash, "" ); - set = Expr.find[ type ]( match, context, isXML ); - - if ( set != null ) { - expr = expr.replace( Expr.match[ type ], "" ); - break; - } - } - } - } - - if ( !set ) { - set = typeof context.getElementsByTagName !== "undefined" ? - context.getElementsByTagName( "*" ) : - []; - } - - return { set: set, expr: expr }; -}; - -Sizzle.filter = function( expr, set, inplace, not ) { - var match, anyFound, - old = expr, - result = [], - curLoop = set, - isXMLFilter = set && set[0] && Sizzle.isXML( set[0] ); - - while ( expr && set.length ) { - for ( var type in Expr.filter ) { - if ( (match = Expr.leftMatch[ type ].exec( expr )) != null && match[2] ) { - var found, item, - filter = Expr.filter[ type ], - left = match[1]; - - anyFound = false; - - match.splice(1,1); - - if ( left.substr( left.length - 1 ) === "\\" ) { - continue; - } - - if ( curLoop === result ) { - result = []; - } - - if ( Expr.preFilter[ type ] ) { - match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter ); - - if ( !match ) { - anyFound = found = true; - - } else if ( match === true ) { - continue; - } - } - - if ( match ) { - for ( var i = 0; (item = curLoop[i]) != null; i++ ) { - if ( item ) { - found = filter( item, match, i, curLoop ); - var pass = not ^ !!found; - - if ( inplace && found != null ) { - if ( pass ) { - anyFound = true; - - } else { - curLoop[i] = false; - } - - } else if ( pass ) { - result.push( item ); - anyFound = true; - } - } - } - } - - if ( found !== undefined ) { - if ( !inplace ) { - curLoop = result; - } - - expr = expr.replace( Expr.match[ type ], "" ); - - if ( !anyFound ) { - return []; - } - - break; - } - } - } - - // Improper expression - if ( expr === old ) { - if ( anyFound == null ) { - Sizzle.error( expr ); - - } else { - break; - } - } - - old = expr; - } - - return curLoop; -}; - -Sizzle.error = function( msg ) { - throw "Syntax error, unrecognized expression: " + msg; -}; - -var Expr = Sizzle.selectors = { - order: [ "ID", "NAME", "TAG" ], - - match: { - ID: /#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/, - CLASS: /\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/, - NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/, - ATTR: /\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(?:(['"])(.*?)\3|(#?(?:[\w\u00c0-\uFFFF\-]|\\.)*)|)|)\s*\]/, - TAG: /^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/, - CHILD: /:(only|nth|last|first)-child(?:\(\s*(even|odd|(?:[+\-]?\d+|(?:[+\-]?\d*)?n\s*(?:[+\-]\s*\d+)?))\s*\))?/, - POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/, - PSEUDO: /:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/ - }, - - leftMatch: {}, - - attrMap: { - "class": "className", - "for": "htmlFor" - }, - - attrHandle: { - href: function( elem ) { - return elem.getAttribute( "href" ); - }, - type: function( elem ) { - return elem.getAttribute( "type" ); - } - }, - - relative: { - "+": function(checkSet, part){ - var isPartStr = typeof part === "string", - isTag = isPartStr && !rNonWord.test( part ), - isPartStrNotTag = isPartStr && !isTag; - - if ( isTag ) { - part = part.toLowerCase(); - } - - for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) { - if ( (elem = checkSet[i]) ) { - while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {} - - checkSet[i] = isPartStrNotTag || elem && elem.nodeName.toLowerCase() === part ? - elem || false : - elem === part; - } - } - - if ( isPartStrNotTag ) { - Sizzle.filter( part, checkSet, true ); - } - }, - - ">": function( checkSet, part ) { - var elem, - isPartStr = typeof part === "string", - i = 0, - l = checkSet.length; - - if ( isPartStr && !rNonWord.test( part ) ) { - part = part.toLowerCase(); - - for ( ; i < l; i++ ) { - elem = checkSet[i]; - - if ( elem ) { - var parent = elem.parentNode; - checkSet[i] = parent.nodeName.toLowerCase() === part ? parent : false; - } - } - - } else { - for ( ; i < l; i++ ) { - elem = checkSet[i]; - - if ( elem ) { - checkSet[i] = isPartStr ? - elem.parentNode : - elem.parentNode === part; - } - } - - if ( isPartStr ) { - Sizzle.filter( part, checkSet, true ); - } - } - }, - - "": function(checkSet, part, isXML){ - var nodeCheck, - doneName = done++, - checkFn = dirCheck; - - if ( typeof part === "string" && !rNonWord.test( part ) ) { - part = part.toLowerCase(); - nodeCheck = part; - checkFn = dirNodeCheck; - } - - checkFn( "parentNode", part, doneName, checkSet, nodeCheck, isXML ); - }, - - "~": function( checkSet, part, isXML ) { - var nodeCheck, - doneName = done++, - checkFn = dirCheck; - - if ( typeof part === "string" && !rNonWord.test( part ) ) { - part = part.toLowerCase(); - nodeCheck = part; - checkFn = dirNodeCheck; - } - - checkFn( "previousSibling", part, doneName, checkSet, nodeCheck, isXML ); - } - }, - - find: { - ID: function( match, context, isXML ) { - if ( typeof context.getElementById !== "undefined" && !isXML ) { - var m = context.getElementById(match[1]); - // Check parentNode to catch when Blackberry 4.6 returns - // nodes that are no longer in the document #6963 - return m && m.parentNode ? [m] : []; - } - }, - - NAME: function( match, context ) { - if ( typeof context.getElementsByName !== "undefined" ) { - var ret = [], - results = context.getElementsByName( match[1] ); - - for ( var i = 0, l = results.length; i < l; i++ ) { - if ( results[i].getAttribute("name") === match[1] ) { - ret.push( results[i] ); - } - } - - return ret.length === 0 ? null : ret; - } - }, - - TAG: function( match, context ) { - if ( typeof context.getElementsByTagName !== "undefined" ) { - return context.getElementsByTagName( match[1] ); - } - } - }, - preFilter: { - CLASS: function( match, curLoop, inplace, result, not, isXML ) { - match = " " + match[1].replace( rBackslash, "" ) + " "; - - if ( isXML ) { - return match; - } - - for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) { - if ( elem ) { - if ( not ^ (elem.className && (" " + elem.className + " ").replace(/[\t\n\r]/g, " ").indexOf(match) >= 0) ) { - if ( !inplace ) { - result.push( elem ); - } - - } else if ( inplace ) { - curLoop[i] = false; - } - } - } - - return false; - }, - - ID: function( match ) { - return match[1].replace( rBackslash, "" ); - }, - - TAG: function( match, curLoop ) { - return match[1].replace( rBackslash, "" ).toLowerCase(); - }, - - CHILD: function( match ) { - if ( match[1] === "nth" ) { - if ( !match[2] ) { - Sizzle.error( match[0] ); - } - - match[2] = match[2].replace(/^\+|\s*/g, ''); - - // parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6' - var test = /(-?)(\d*)(?:n([+\-]?\d*))?/.exec( - match[2] === "even" && "2n" || match[2] === "odd" && "2n+1" || - !/\D/.test( match[2] ) && "0n+" + match[2] || match[2]); - - // calculate the numbers (first)n+(last) including if they are negative - match[2] = (test[1] + (test[2] || 1)) - 0; - match[3] = test[3] - 0; - } - else if ( match[2] ) { - Sizzle.error( match[0] ); - } - - // TODO: Move to normal caching system - match[0] = done++; - - return match; - }, - - ATTR: function( match, curLoop, inplace, result, not, isXML ) { - var name = match[1] = match[1].replace( rBackslash, "" ); - - if ( !isXML && Expr.attrMap[name] ) { - match[1] = Expr.attrMap[name]; - } - - // Handle if an un-quoted value was used - match[4] = ( match[4] || match[5] || "" ).replace( rBackslash, "" ); - - if ( match[2] === "~=" ) { - match[4] = " " + match[4] + " "; - } - - return match; - }, - - PSEUDO: function( match, curLoop, inplace, result, not ) { - if ( match[1] === "not" ) { - // If we're dealing with a complex expression, or a simple one - if ( ( chunker.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) { - match[3] = Sizzle(match[3], null, null, curLoop); - - } else { - var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not); - - if ( !inplace ) { - result.push.apply( result, ret ); - } - - return false; - } - - } else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) { - return true; - } - - return match; - }, - - POS: function( match ) { - match.unshift( true ); - - return match; - } - }, - - filters: { - enabled: function( elem ) { - return elem.disabled === false && elem.type !== "hidden"; - }, - - disabled: function( elem ) { - return elem.disabled === true; - }, - - checked: function( elem ) { - return elem.checked === true; - }, - - selected: function( elem ) { - // Accessing this property makes selected-by-default - // options in Safari work properly - if ( elem.parentNode ) { - elem.parentNode.selectedIndex; - } - - return elem.selected === true; - }, - - parent: function( elem ) { - return !!elem.firstChild; - }, - - empty: function( elem ) { - return !elem.firstChild; - }, - - has: function( elem, i, match ) { - return !!Sizzle( match[3], elem ).length; - }, - - header: function( elem ) { - return (/h\d/i).test( elem.nodeName ); - }, - - text: function( elem ) { - var attr = elem.getAttribute( "type" ), type = elem.type; - // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc) - // use getAttribute instead to test this case - return elem.nodeName.toLowerCase() === "input" && "text" === type && ( attr === type || attr === null ); - }, - - radio: function( elem ) { - return elem.nodeName.toLowerCase() === "input" && "radio" === elem.type; - }, - - checkbox: function( elem ) { - return elem.nodeName.toLowerCase() === "input" && "checkbox" === elem.type; - }, - - file: function( elem ) { - return elem.nodeName.toLowerCase() === "input" && "file" === elem.type; - }, - - password: function( elem ) { - return elem.nodeName.toLowerCase() === "input" && "password" === elem.type; - }, - - submit: function( elem ) { - var name = elem.nodeName.toLowerCase(); - return (name === "input" || name === "button") && "submit" === elem.type; - }, - - image: function( elem ) { - return elem.nodeName.toLowerCase() === "input" && "image" === elem.type; - }, - - reset: function( elem ) { - var name = elem.nodeName.toLowerCase(); - return (name === "input" || name === "button") && "reset" === elem.type; - }, - - button: function( elem ) { - var name = elem.nodeName.toLowerCase(); - return name === "input" && "button" === elem.type || name === "button"; - }, - - input: function( elem ) { - return (/input|select|textarea|button/i).test( elem.nodeName ); - }, - - focus: function( elem ) { - return elem === elem.ownerDocument.activeElement; - } - }, - setFilters: { - first: function( elem, i ) { - return i === 0; - }, - - last: function( elem, i, match, array ) { - return i === array.length - 1; - }, - - even: function( elem, i ) { - return i % 2 === 0; - }, - - odd: function( elem, i ) { - return i % 2 === 1; - }, - - lt: function( elem, i, match ) { - return i < match[3] - 0; - }, - - gt: function( elem, i, match ) { - return i > match[3] - 0; - }, - - nth: function( elem, i, match ) { - return match[3] - 0 === i; - }, - - eq: function( elem, i, match ) { - return match[3] - 0 === i; - } - }, - filter: { - PSEUDO: function( elem, match, i, array ) { - var name = match[1], - filter = Expr.filters[ name ]; - - if ( filter ) { - return filter( elem, i, match, array ); - - } else if ( name === "contains" ) { - return (elem.textContent || elem.innerText || Sizzle.getText([ elem ]) || "").indexOf(match[3]) >= 0; - - } else if ( name === "not" ) { - var not = match[3]; - - for ( var j = 0, l = not.length; j < l; j++ ) { - if ( not[j] === elem ) { - return false; - } - } - - return true; - - } else { - Sizzle.error( name ); - } - }, - - CHILD: function( elem, match ) { - var type = match[1], - node = elem; - - switch ( type ) { - case "only": - case "first": - while ( (node = node.previousSibling) ) { - if ( node.nodeType === 1 ) { - return false; - } - } - - if ( type === "first" ) { - return true; - } - - node = elem; - - case "last": - while ( (node = node.nextSibling) ) { - if ( node.nodeType === 1 ) { - return false; - } - } - - return true; - - case "nth": - var first = match[2], - last = match[3]; - - if ( first === 1 && last === 0 ) { - return true; - } - - var doneName = match[0], - parent = elem.parentNode; - - if ( parent && (parent.sizcache !== doneName || !elem.nodeIndex) ) { - var count = 0; - - for ( node = parent.firstChild; node; node = node.nextSibling ) { - if ( node.nodeType === 1 ) { - node.nodeIndex = ++count; - } - } - - parent.sizcache = doneName; - } - - var diff = elem.nodeIndex - last; - - if ( first === 0 ) { - return diff === 0; - - } else { - return ( diff % first === 0 && diff / first >= 0 ); - } - } - }, - - ID: function( elem, match ) { - return elem.nodeType === 1 && elem.getAttribute("id") === match; - }, - - TAG: function( elem, match ) { - return (match === "*" && elem.nodeType === 1) || elem.nodeName.toLowerCase() === match; - }, - - CLASS: function( elem, match ) { - return (" " + (elem.className || elem.getAttribute("class")) + " ") - .indexOf( match ) > -1; - }, - - ATTR: function( elem, match ) { - var name = match[1], - result = Expr.attrHandle[ name ] ? - Expr.attrHandle[ name ]( elem ) : - elem[ name ] != null ? - elem[ name ] : - elem.getAttribute( name ), - value = result + "", - type = match[2], - check = match[4]; - - return result == null ? - type === "!=" : - type === "=" ? - value === check : - type === "*=" ? - value.indexOf(check) >= 0 : - type === "~=" ? - (" " + value + " ").indexOf(check) >= 0 : - !check ? - value && result !== false : - type === "!=" ? - value !== check : - type === "^=" ? - value.indexOf(check) === 0 : - type === "$=" ? - value.substr(value.length - check.length) === check : - type === "|=" ? - value === check || value.substr(0, check.length + 1) === check + "-" : - false; - }, - - POS: function( elem, match, i, array ) { - var name = match[2], - filter = Expr.setFilters[ name ]; - - if ( filter ) { - return filter( elem, i, match, array ); - } - } - } -}; - -var origPOS = Expr.match.POS, - fescape = function(all, num){ - return "\\" + (num - 0 + 1); - }; - -for ( var type in Expr.match ) { - Expr.match[ type ] = new RegExp( Expr.match[ type ].source + (/(?![^\[]*\])(?![^\(]*\))/.source) ); - Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source.replace(/\\(\d+)/g, fescape) ); -} - -var makeArray = function( array, results ) { - array = Array.prototype.slice.call( array, 0 ); - - if ( results ) { - results.push.apply( results, array ); - return results; - } - - return array; -}; - -// Perform a simple check to determine if the browser is capable of -// converting a NodeList to an array using builtin methods. -// Also verifies that the returned array holds DOM nodes -// (which is not the case in the Blackberry browser) -try { - Array.prototype.slice.call( document.documentElement.childNodes, 0 )[0].nodeType; - -// Provide a fallback method if it does not work -} catch( e ) { - makeArray = function( array, results ) { - var i = 0, - ret = results || []; - - if ( toString.call(array) === "[object Array]" ) { - Array.prototype.push.apply( ret, array ); - - } else { - if ( typeof array.length === "number" ) { - for ( var l = array.length; i < l; i++ ) { - ret.push( array[i] ); - } - - } else { - for ( ; array[i]; i++ ) { - ret.push( array[i] ); - } - } - } - - return ret; - }; -} - -var sortOrder, siblingCheck; - -if ( document.documentElement.compareDocumentPosition ) { - sortOrder = function( a, b ) { - if ( a === b ) { - hasDuplicate = true; - return 0; - } - - if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) { - return a.compareDocumentPosition ? -1 : 1; - } - - return a.compareDocumentPosition(b) & 4 ? -1 : 1; - }; - -} else { - sortOrder = function( a, b ) { - // The nodes are identical, we can exit early - if ( a === b ) { - hasDuplicate = true; - return 0; - - // Fallback to using sourceIndex (in IE) if it's available on both nodes - } else if ( a.sourceIndex && b.sourceIndex ) { - return a.sourceIndex - b.sourceIndex; - } - - var al, bl, - ap = [], - bp = [], - aup = a.parentNode, - bup = b.parentNode, - cur = aup; - - // If the nodes are siblings (or identical) we can do a quick check - if ( aup === bup ) { - return siblingCheck( a, b ); - - // If no parents were found then the nodes are disconnected - } else if ( !aup ) { - return -1; - - } else if ( !bup ) { - return 1; - } - - // Otherwise they're somewhere else in the tree so we need - // to build up a full list of the parentNodes for comparison - while ( cur ) { - ap.unshift( cur ); - cur = cur.parentNode; - } - - cur = bup; - - while ( cur ) { - bp.unshift( cur ); - cur = cur.parentNode; - } - - al = ap.length; - bl = bp.length; - - // Start walking down the tree looking for a discrepancy - for ( var i = 0; i < al && i < bl; i++ ) { - if ( ap[i] !== bp[i] ) { - return siblingCheck( ap[i], bp[i] ); - } - } - - // We ended someplace up the tree so do a sibling check - return i === al ? - siblingCheck( a, bp[i], -1 ) : - siblingCheck( ap[i], b, 1 ); - }; - - siblingCheck = function( a, b, ret ) { - if ( a === b ) { - return ret; - } - - var cur = a.nextSibling; - - while ( cur ) { - if ( cur === b ) { - return -1; - } - - cur = cur.nextSibling; - } - - return 1; - }; -} - -// Utility function for retreiving the text value of an array of DOM nodes -Sizzle.getText = function( elems ) { - var ret = "", elem; - - for ( var i = 0; elems[i]; i++ ) { - elem = elems[i]; - - // Get the text from text nodes and CDATA nodes - if ( elem.nodeType === 3 || elem.nodeType === 4 ) { - ret += elem.nodeValue; - - // Traverse everything else, except comment nodes - } else if ( elem.nodeType !== 8 ) { - ret += Sizzle.getText( elem.childNodes ); - } - } - - return ret; -}; - -// Check to see if the browser returns elements by name when -// querying by getElementById (and provide a workaround) -(function(){ - // We're going to inject a fake input element with a specified name - var form = document.createElement("div"), - id = "script" + (new Date()).getTime(), - root = document.documentElement; - - form.innerHTML = ""; - - // Inject it into the root element, check its status, and remove it quickly - root.insertBefore( form, root.firstChild ); - - // The workaround has to do additional checks after a getElementById - // Which slows things down for other browsers (hence the branching) - if ( document.getElementById( id ) ) { - Expr.find.ID = function( match, context, isXML ) { - if ( typeof context.getElementById !== "undefined" && !isXML ) { - var m = context.getElementById(match[1]); - - return m ? - m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ? - [m] : - undefined : - []; - } - }; - - Expr.filter.ID = function( elem, match ) { - var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id"); - - return elem.nodeType === 1 && node && node.nodeValue === match; - }; - } - - root.removeChild( form ); - - // release memory in IE - root = form = null; -})(); - -(function(){ - // Check to see if the browser returns only elements - // when doing getElementsByTagName("*") - - // Create a fake element - var div = document.createElement("div"); - div.appendChild( document.createComment("") ); - - // Make sure no comments are found - if ( div.getElementsByTagName("*").length > 0 ) { - Expr.find.TAG = function( match, context ) { - var results = context.getElementsByTagName( match[1] ); - - // Filter out possible comments - if ( match[1] === "*" ) { - var tmp = []; - - for ( var i = 0; results[i]; i++ ) { - if ( results[i].nodeType === 1 ) { - tmp.push( results[i] ); - } - } - - results = tmp; - } - - return results; - }; - } - - // Check to see if an attribute returns normalized href attributes - div.innerHTML = ""; - - if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" && - div.firstChild.getAttribute("href") !== "#" ) { - - Expr.attrHandle.href = function( elem ) { - return elem.getAttribute( "href", 2 ); - }; - } - - // release memory in IE - div = null; -})(); - -if ( document.querySelectorAll ) { - (function(){ - var oldSizzle = Sizzle, - div = document.createElement("div"), - id = "__sizzle__"; - - div.innerHTML = "

        "; - - // Safari can't handle uppercase or unicode characters when - // in quirks mode. - if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) { - return; - } - - Sizzle = function( query, context, extra, seed ) { - context = context || document; - - // Only use querySelectorAll on non-XML documents - // (ID selectors don't work in non-HTML documents) - if ( !seed && !Sizzle.isXML(context) ) { - // See if we find a selector to speed up - var match = /^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec( query ); - - if ( match && (context.nodeType === 1 || context.nodeType === 9) ) { - // Speed-up: Sizzle("TAG") - if ( match[1] ) { - return makeArray( context.getElementsByTagName( query ), extra ); - - // Speed-up: Sizzle(".CLASS") - } else if ( match[2] && Expr.find.CLASS && context.getElementsByClassName ) { - return makeArray( context.getElementsByClassName( match[2] ), extra ); - } - } - - if ( context.nodeType === 9 ) { - // Speed-up: Sizzle("body") - // The body element only exists once, optimize finding it - if ( query === "body" && context.body ) { - return makeArray( [ context.body ], extra ); - - // Speed-up: Sizzle("#ID") - } else if ( match && match[3] ) { - var elem = context.getElementById( match[3] ); - - // Check parentNode to catch when Blackberry 4.6 returns - // nodes that are no longer in the document #6963 - if ( elem && elem.parentNode ) { - // Handle the case where IE and Opera return items - // by name instead of ID - if ( elem.id === match[3] ) { - return makeArray( [ elem ], extra ); - } - - } else { - return makeArray( [], extra ); - } - } - - try { - return makeArray( context.querySelectorAll(query), extra ); - } catch(qsaError) {} - - // qSA works strangely on Element-rooted queries - // We can work around this by specifying an extra ID on the root - // and working up from there (Thanks to Andrew Dupont for the technique) - // IE 8 doesn't work on object elements - } else if ( context.nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) { - var oldContext = context, - old = context.getAttribute( "id" ), - nid = old || id, - hasParent = context.parentNode, - relativeHierarchySelector = /^\s*[+~]/.test( query ); - - if ( !old ) { - context.setAttribute( "id", nid ); - } else { - nid = nid.replace( /'/g, "\\$&" ); - } - if ( relativeHierarchySelector && hasParent ) { - context = context.parentNode; - } - - try { - if ( !relativeHierarchySelector || hasParent ) { - return makeArray( context.querySelectorAll( "[id='" + nid + "'] " + query ), extra ); - } - - } catch(pseudoError) { - } finally { - if ( !old ) { - oldContext.removeAttribute( "id" ); - } - } - } - } - - return oldSizzle(query, context, extra, seed); - }; - - for ( var prop in oldSizzle ) { - Sizzle[ prop ] = oldSizzle[ prop ]; - } - - // release memory in IE - div = null; - })(); -} - -(function(){ - var html = document.documentElement, - matches = html.matchesSelector || html.mozMatchesSelector || html.webkitMatchesSelector || html.msMatchesSelector; - - if ( matches ) { - // Check to see if it's possible to do matchesSelector - // on a disconnected node (IE 9 fails this) - var disconnectedMatch = !matches.call( document.createElement( "div" ), "div" ), - pseudoWorks = false; - - try { - // This should fail with an exception - // Gecko does not error, returns false instead - matches.call( document.documentElement, "[test!='']:sizzle" ); - - } catch( pseudoError ) { - pseudoWorks = true; - } - - Sizzle.matchesSelector = function( node, expr ) { - // Make sure that attribute selectors are quoted - expr = expr.replace(/\=\s*([^'"\]]*)\s*\]/g, "='$1']"); - - if ( !Sizzle.isXML( node ) ) { - try { - if ( pseudoWorks || !Expr.match.PSEUDO.test( expr ) && !/!=/.test( expr ) ) { - var ret = matches.call( node, expr ); - - // IE 9's matchesSelector returns false on disconnected nodes - if ( ret || !disconnectedMatch || - // As well, disconnected nodes are said to be in a document - // fragment in IE 9, so check for that - node.document && node.document.nodeType !== 11 ) { - return ret; - } - } - } catch(e) {} - } - - return Sizzle(expr, null, null, [node]).length > 0; - }; - } -})(); - -(function(){ - var div = document.createElement("div"); - - div.innerHTML = "
        "; - - // Opera can't find a second classname (in 9.6) - // Also, make sure that getElementsByClassName actually exists - if ( !div.getElementsByClassName || div.getElementsByClassName("e").length === 0 ) { - return; - } - - // Safari caches class attributes, doesn't catch changes (in 3.2) - div.lastChild.className = "e"; - - if ( div.getElementsByClassName("e").length === 1 ) { - return; - } - - Expr.order.splice(1, 0, "CLASS"); - Expr.find.CLASS = function( match, context, isXML ) { - if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) { - return context.getElementsByClassName(match[1]); - } - }; - - // release memory in IE - div = null; -})(); - -function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { - for ( var i = 0, l = checkSet.length; i < l; i++ ) { - var elem = checkSet[i]; - - if ( elem ) { - var match = false; - - elem = elem[dir]; - - while ( elem ) { - if ( elem.sizcache === doneName ) { - match = checkSet[elem.sizset]; - break; - } - - if ( elem.nodeType === 1 && !isXML ){ - elem.sizcache = doneName; - elem.sizset = i; - } - - if ( elem.nodeName.toLowerCase() === cur ) { - match = elem; - break; - } - - elem = elem[dir]; - } - - checkSet[i] = match; - } - } -} - -function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { - for ( var i = 0, l = checkSet.length; i < l; i++ ) { - var elem = checkSet[i]; - - if ( elem ) { - var match = false; - - elem = elem[dir]; - - while ( elem ) { - if ( elem.sizcache === doneName ) { - match = checkSet[elem.sizset]; - break; - } - - if ( elem.nodeType === 1 ) { - if ( !isXML ) { - elem.sizcache = doneName; - elem.sizset = i; - } - - if ( typeof cur !== "string" ) { - if ( elem === cur ) { - match = true; - break; - } - - } else if ( Sizzle.filter( cur, [elem] ).length > 0 ) { - match = elem; - break; - } - } - - elem = elem[dir]; - } - - checkSet[i] = match; - } - } -} - -if ( document.documentElement.contains ) { - Sizzle.contains = function( a, b ) { - return a !== b && (a.contains ? a.contains(b) : true); - }; - -} else if ( document.documentElement.compareDocumentPosition ) { - Sizzle.contains = function( a, b ) { - return !!(a.compareDocumentPosition(b) & 16); - }; - -} else { - Sizzle.contains = function() { - return false; - }; -} - -Sizzle.isXML = function( elem ) { - // documentElement is verified for cases where it doesn't yet exist - // (such as loading iframes in IE - #4833) - var documentElement = (elem ? elem.ownerDocument || elem : 0).documentElement; - - return documentElement ? documentElement.nodeName !== "HTML" : false; -}; - -var posProcess = function( selector, context ) { - var match, - tmpSet = [], - later = "", - root = context.nodeType ? [context] : context; - - // Position selectors must be done after the filter - // And so must :not(positional) so we move all PSEUDOs to the end - while ( (match = Expr.match.PSEUDO.exec( selector )) ) { - later += match[0]; - selector = selector.replace( Expr.match.PSEUDO, "" ); - } - - selector = Expr.relative[selector] ? selector + "*" : selector; - - for ( var i = 0, l = root.length; i < l; i++ ) { - Sizzle( selector, root[i], tmpSet ); - } - - return Sizzle.filter( later, tmpSet ); -}; - -// EXPOSE -jQuery.find = Sizzle; -jQuery.expr = Sizzle.selectors; -jQuery.expr[":"] = jQuery.expr.filters; -jQuery.unique = Sizzle.uniqueSort; -jQuery.text = Sizzle.getText; -jQuery.isXMLDoc = Sizzle.isXML; -jQuery.contains = Sizzle.contains; - - -})(); - - -var runtil = /Until$/, - rparentsprev = /^(?:parents|prevUntil|prevAll)/, - // Note: This RegExp should be improved, or likely pulled from Sizzle - rmultiselector = /,/, - isSimple = /^.[^:#\[\.,]*$/, - slice = Array.prototype.slice, - POS = jQuery.expr.match.POS, - // methods guaranteed to produce a unique set when starting from a unique set - guaranteedUnique = { - children: true, - contents: true, - next: true, - prev: true - }; - -jQuery.fn.extend({ - find: function( selector ) { - var self = this, - i, l; - - if ( typeof selector !== "string" ) { - return jQuery( selector ).filter(function() { - for ( i = 0, l = self.length; i < l; i++ ) { - if ( jQuery.contains( self[ i ], this ) ) { - return true; - } - } - }); - } - - var ret = this.pushStack( "", "find", selector ), - length, n, r; - - for ( i = 0, l = this.length; i < l; i++ ) { - length = ret.length; - jQuery.find( selector, this[i], ret ); - - if ( i > 0 ) { - // Make sure that the results are unique - for ( n = length; n < ret.length; n++ ) { - for ( r = 0; r < length; r++ ) { - if ( ret[r] === ret[n] ) { - ret.splice(n--, 1); - break; - } - } - } - } - } - - return ret; - }, - - has: function( target ) { - var targets = jQuery( target ); - return this.filter(function() { - for ( var i = 0, l = targets.length; i < l; i++ ) { - if ( jQuery.contains( this, targets[i] ) ) { - return true; - } - } - }); - }, - - not: function( selector ) { - return this.pushStack( winnow(this, selector, false), "not", selector); - }, - - filter: function( selector ) { - return this.pushStack( winnow(this, selector, true), "filter", selector ); - }, - - is: function( selector ) { - return !!selector && ( typeof selector === "string" ? - jQuery.filter( selector, this ).length > 0 : - this.filter( selector ).length > 0 ); - }, - - closest: function( selectors, context ) { - var ret = [], i, l, cur = this[0]; - - // Array - if ( jQuery.isArray( selectors ) ) { - var match, selector, - matches = {}, - level = 1; - - if ( cur && selectors.length ) { - for ( i = 0, l = selectors.length; i < l; i++ ) { - selector = selectors[i]; - - if ( !matches[ selector ] ) { - matches[ selector ] = POS.test( selector ) ? - jQuery( selector, context || this.context ) : - selector; - } - } - - while ( cur && cur.ownerDocument && cur !== context ) { - for ( selector in matches ) { - match = matches[ selector ]; - - if ( match.jquery ? match.index( cur ) > -1 : jQuery( cur ).is( match ) ) { - ret.push({ selector: selector, elem: cur, level: level }); - } - } - - cur = cur.parentNode; - level++; - } - } - - return ret; - } - - // String - var pos = POS.test( selectors ) || typeof selectors !== "string" ? - jQuery( selectors, context || this.context ) : - 0; - - for ( i = 0, l = this.length; i < l; i++ ) { - cur = this[i]; - - while ( cur ) { - if ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) { - ret.push( cur ); - break; - - } else { - cur = cur.parentNode; - if ( !cur || !cur.ownerDocument || cur === context || cur.nodeType === 11 ) { - break; - } - } - } - } - - ret = ret.length > 1 ? jQuery.unique( ret ) : ret; - - return this.pushStack( ret, "closest", selectors ); - }, - - // Determine the position of an element within - // the matched set of elements - index: function( elem ) { - - // No argument, return index in parent - if ( !elem ) { - return ( this[0] && this[0].parentNode ) ? this.prevAll().length : -1; - } - - // index in selector - if ( typeof elem === "string" ) { - return jQuery.inArray( this[0], jQuery( elem ) ); - } - - // Locate the position of the desired element - return jQuery.inArray( - // If it receives a jQuery object, the first element is used - elem.jquery ? elem[0] : elem, this ); - }, - - add: function( selector, context ) { - var set = typeof selector === "string" ? - jQuery( selector, context ) : - jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ), - all = jQuery.merge( this.get(), set ); - - return this.pushStack( isDisconnected( set[0] ) || isDisconnected( all[0] ) ? - all : - jQuery.unique( all ) ); - }, - - andSelf: function() { - return this.add( this.prevObject ); - } -}); - -// A painfully simple check to see if an element is disconnected -// from a document (should be improved, where feasible). -function isDisconnected( node ) { - return !node || !node.parentNode || node.parentNode.nodeType === 11; -} - -jQuery.each({ - parent: function( elem ) { - var parent = elem.parentNode; - return parent && parent.nodeType !== 11 ? parent : null; - }, - parents: function( elem ) { - return jQuery.dir( elem, "parentNode" ); - }, - parentsUntil: function( elem, i, until ) { - return jQuery.dir( elem, "parentNode", until ); - }, - next: function( elem ) { - return jQuery.nth( elem, 2, "nextSibling" ); - }, - prev: function( elem ) { - return jQuery.nth( elem, 2, "previousSibling" ); - }, - nextAll: function( elem ) { - return jQuery.dir( elem, "nextSibling" ); - }, - prevAll: function( elem ) { - return jQuery.dir( elem, "previousSibling" ); - }, - nextUntil: function( elem, i, until ) { - return jQuery.dir( elem, "nextSibling", until ); - }, - prevUntil: function( elem, i, until ) { - return jQuery.dir( elem, "previousSibling", until ); - }, - siblings: function( elem ) { - return jQuery.sibling( elem.parentNode.firstChild, elem ); - }, - children: function( elem ) { - return jQuery.sibling( elem.firstChild ); - }, - contents: function( elem ) { - return jQuery.nodeName( elem, "iframe" ) ? - elem.contentDocument || elem.contentWindow.document : - jQuery.makeArray( elem.childNodes ); - } -}, function( name, fn ) { - jQuery.fn[ name ] = function( until, selector ) { - var ret = jQuery.map( this, fn, until ), - // The variable 'args' was introduced in - // https://github.com/jquery/jquery/commit/52a0238 - // to work around a bug in Chrome 10 (Dev) and should be removed when the bug is fixed. - // http://code.google.com/p/v8/issues/detail?id=1050 - args = slice.call(arguments); - - if ( !runtil.test( name ) ) { - selector = until; - } - - if ( selector && typeof selector === "string" ) { - ret = jQuery.filter( selector, ret ); - } - - ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret; - - if ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( name ) ) { - ret = ret.reverse(); - } - - return this.pushStack( ret, name, args.join(",") ); - }; -}); - -jQuery.extend({ - filter: function( expr, elems, not ) { - if ( not ) { - expr = ":not(" + expr + ")"; - } - - return elems.length === 1 ? - jQuery.find.matchesSelector(elems[0], expr) ? [ elems[0] ] : [] : - jQuery.find.matches(expr, elems); - }, - - dir: function( elem, dir, until ) { - var matched = [], - cur = elem[ dir ]; - - while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) { - if ( cur.nodeType === 1 ) { - matched.push( cur ); - } - cur = cur[dir]; - } - return matched; - }, - - nth: function( cur, result, dir, elem ) { - result = result || 1; - var num = 0; - - for ( ; cur; cur = cur[dir] ) { - if ( cur.nodeType === 1 && ++num === result ) { - break; - } - } - - return cur; - }, - - sibling: function( n, elem ) { - var r = []; - - for ( ; n; n = n.nextSibling ) { - if ( n.nodeType === 1 && n !== elem ) { - r.push( n ); - } - } - - return r; - } -}); - -// Implement the identical functionality for filter and not -function winnow( elements, qualifier, keep ) { - - // Can't pass null or undefined to indexOf in Firefox 4 - // Set to 0 to skip string check - qualifier = qualifier || 0; - - if ( jQuery.isFunction( qualifier ) ) { - return jQuery.grep(elements, function( elem, i ) { - var retVal = !!qualifier.call( elem, i, elem ); - return retVal === keep; - }); - - } else if ( qualifier.nodeType ) { - return jQuery.grep(elements, function( elem, i ) { - return (elem === qualifier) === keep; - }); - - } else if ( typeof qualifier === "string" ) { - var filtered = jQuery.grep(elements, function( elem ) { - return elem.nodeType === 1; - }); - - if ( isSimple.test( qualifier ) ) { - return jQuery.filter(qualifier, filtered, !keep); - } else { - qualifier = jQuery.filter( qualifier, filtered ); - } - } - - return jQuery.grep(elements, function( elem, i ) { - return (jQuery.inArray( elem, qualifier ) >= 0) === keep; - }); -} - - - - -var rinlinejQuery = / jQuery\d+="(?:\d+|null)"/g, - rleadingWhitespace = /^\s+/, - rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig, - rtagName = /<([\w:]+)/, - rtbody = /", "" ], - legend: [ 1, "
        ", "
        " ], - thead: [ 1, "", "
        " ], - tr: [ 2, "", "
        " ], - td: [ 3, "", "
        " ], - col: [ 2, "", "
        " ], - area: [ 1, "", "" ], - _default: [ 0, "", "" ] - }; - -wrapMap.optgroup = wrapMap.option; -wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; -wrapMap.th = wrapMap.td; - -// IE can't serialize and "; + } } - } - function get_latitude() - { - if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lat')) - { - return (float) $return[0]['data']; - } - elseif (($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_GEORSS, 'point')) && preg_match('/^((?:-)?[0-9]+(?:\.[0-9]+)) ((?:-)?[0-9]+(?:\.[0-9]+))$/', trim($return[0]['data']), $match)) - { - return (float) $match[1]; - } - else + // Flash Media Player file types. + // Preferred handler for MP3 file types. + elseif ($handler === 'fmedia' || ($handler === 'mp3' && $mediaplayer !== '')) { - return null; + $height += 20; + if ($native) + { + $embed .= "get_link().'?file_extension=.'.$this->get_extension()) . "&autostart=false&repeat=$loop&showdigits=true&showfsbutton=false\">"; + } + else + { + $embed .= ""; + } } - } - function get_longitude() - { - if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'long')) - { - return (float) $return[0]['data']; - } - elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lon')) - { - return (float) $return[0]['data']; - } - elseif (($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_GEORSS, 'point')) && preg_match('/^((?:-)?[0-9]+(?:\.[0-9]+)) ((?:-)?[0-9]+(?:\.[0-9]+))$/', trim($return[0]['data']), $match)) - { - return (float) $match[2]; - } - else + // QuickTime 7 file types. Need to test with QuickTime 6. + // Only handle MP3's if the Flash Media Player is not present. + elseif ($handler === 'quicktime' || ($handler === 'mp3' && $mediaplayer === '')) { - return null; + $height += 16; + if ($native) + { + if ($placeholder !== '') + { + $embed .= "get_link() . "\" src=\"$placeholder\" width=\"$width\" height=\"$height\" autoplay=\"false\" target=\"myself\" controller=\"false\" loop=\"$loop\" scale=\"aspect\" bgcolor=\"$bgcolor\" pluginspage=\"http://apple.com/quicktime/download/\">"; + } + else + { + $embed .= "get_link() . "\" width=\"$width\" height=\"$height\" autoplay=\"false\" target=\"myself\" controller=\"true\" loop=\"$loop\" scale=\"aspect\" bgcolor=\"$bgcolor\" pluginspage=\"http://apple.com/quicktime/download/\">"; + } + } + else + { + $embed .= ""; + } } - } - function get_image_url() - { - if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'image')) - { - return $this->sanitize($return[0]['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI); - } - elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'logo')) - { - return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0])); - } - elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'icon')) - { - return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0])); - } - else + // Windows Media + elseif ($handler === 'wmedia') { - return null; + $height += 45; + if ($native) + { + $embed .= "get_link() . "\" autosize=\"1\" width=\"$width\" height=\"$height\" showcontrols=\"1\" showstatusbar=\"0\" showdisplay=\"0\" autostart=\"0\">"; + } + else + { + $embed .= ""; + } } - } -} -class SimplePie_Author -{ - var $name; - var $link; - var $email; + // Everything else + else $embed .= '' . $alt . ''; - // Constructor, used to input the data - function SimplePie_Author($name = null, $link = null, $email = null) - { - $this->name = $name; - $this->link = $link; - $this->email = $email; + return $embed; } - function __toString() + /** + * Get the real media type + * + * Often, feeds lie to us, necessitating a bit of deeper inspection. This + * converts types to their canonical representations based on the file + * extension + * + * @see get_type() + * @param bool $find_handler Internal use only, use {@see get_handler()} instead + * @return string MIME type + */ + public function get_real_type($find_handler = false) { - // There is no $this->data here - return md5(serialize($this)); - } + // Mime-types by handler. + $types_flash = array('application/x-shockwave-flash', 'application/futuresplash'); // Flash + $types_fmedia = array('video/flv', 'video/x-flv','flv-application/octet-stream'); // Flash Media Player + $types_quicktime = array('audio/3gpp', 'audio/3gpp2', 'audio/aac', 'audio/x-aac', 'audio/aiff', 'audio/x-aiff', 'audio/mid', 'audio/midi', 'audio/x-midi', 'audio/mp4', 'audio/m4a', 'audio/x-m4a', 'audio/wav', 'audio/x-wav', 'video/3gpp', 'video/3gpp2', 'video/m4v', 'video/x-m4v', 'video/mp4', 'video/mpeg', 'video/x-mpeg', 'video/quicktime', 'video/sd-video'); // QuickTime + $types_wmedia = array('application/asx', 'application/x-mplayer2', 'audio/x-ms-wma', 'audio/x-ms-wax', 'video/x-ms-asf-plugin', 'video/x-ms-asf', 'video/x-ms-wm', 'video/x-ms-wmv', 'video/x-ms-wvx'); // Windows Media + $types_mp3 = array('audio/mp3', 'audio/x-mp3', 'audio/mpeg', 'audio/x-mpeg'); // MP3 - function get_name() - { - if ($this->name !== null) + if ($this->get_type() !== null) { - return $this->name; + $type = strtolower($this->type); } else { - return null; + $type = null; } - } - function get_link() - { - if ($this->link !== null) - { - return $this->link; - } - else + // If we encounter an unsupported mime-type, check the file extension and guess intelligently. + if (!in_array($type, array_merge($types_flash, $types_fmedia, $types_quicktime, $types_wmedia, $types_mp3))) { - return null; - } - } + switch (strtolower($this->get_extension())) + { + // Audio mime-types + case 'aac': + case 'adts': + $type = 'audio/acc'; + break; - function get_email() - { - if ($this->email !== null) - { - return $this->email; - } - else - { - return null; - } - } -} + case 'aif': + case 'aifc': + case 'aiff': + case 'cdda': + $type = 'audio/aiff'; + break; -class SimplePie_Category -{ - var $term; - var $scheme; - var $label; + case 'bwf': + $type = 'audio/wav'; + break; - // Constructor, used to input the data - function SimplePie_Category($term = null, $scheme = null, $label = null) - { - $this->term = $term; - $this->scheme = $scheme; - $this->label = $label; - } + case 'kar': + case 'mid': + case 'midi': + case 'smf': + $type = 'audio/midi'; + break; - function __toString() - { - // There is no $this->data here - return md5(serialize($this)); - } + case 'm4a': + $type = 'audio/x-m4a'; + break; - function get_term() - { - if ($this->term !== null) - { - return $this->term; - } - else - { - return null; - } - } + case 'mp3': + case 'swa': + $type = 'audio/mp3'; + break; - function get_scheme() - { - if ($this->scheme !== null) - { - return $this->scheme; - } - else - { - return null; + case 'wav': + $type = 'audio/wav'; + break; + + case 'wax': + $type = 'audio/x-ms-wax'; + break; + + case 'wma': + $type = 'audio/x-ms-wma'; + break; + + // Video mime-types + case '3gp': + case '3gpp': + $type = 'video/3gpp'; + break; + + case '3g2': + case '3gp2': + $type = 'video/3gpp2'; + break; + + case 'asf': + $type = 'video/x-ms-asf'; + break; + + case 'flv': + $type = 'video/x-flv'; + break; + + case 'm1a': + case 'm1s': + case 'm1v': + case 'm15': + case 'm75': + case 'mp2': + case 'mpa': + case 'mpeg': + case 'mpg': + case 'mpm': + case 'mpv': + $type = 'video/mpeg'; + break; + + case 'm4v': + $type = 'video/x-m4v'; + break; + + case 'mov': + case 'qt': + $type = 'video/quicktime'; + break; + + case 'mp4': + case 'mpg4': + $type = 'video/mp4'; + break; + + case 'sdv': + $type = 'video/sd-video'; + break; + + case 'wm': + $type = 'video/x-ms-wm'; + break; + + case 'wmv': + $type = 'video/x-ms-wmv'; + break; + + case 'wvx': + $type = 'video/x-ms-wvx'; + break; + + // Flash mime-types + case 'spl': + $type = 'application/futuresplash'; + break; + + case 'swf': + $type = 'application/x-shockwave-flash'; + break; + } } - } - function get_label() - { - if ($this->label !== null) + if ($find_handler) { - return $this->label; + if (in_array($type, $types_flash)) + { + return 'flash'; + } + elseif (in_array($type, $types_fmedia)) + { + return 'fmedia'; + } + elseif (in_array($type, $types_quicktime)) + { + return 'quicktime'; + } + elseif (in_array($type, $types_wmedia)) + { + return 'wmedia'; + } + elseif (in_array($type, $types_mp3)) + { + return 'mp3'; + } + else + { + return null; + } } else { - return $this->get_term(); + return $type; } } } -class SimplePie_Enclosure +/** + * General SimplePie exception class + * + * @package SimplePie + */ +class SimplePie_Exception extends Exception { - var $bitrate; - var $captions; - var $categories; - var $channels; - var $copyright; - var $credits; - var $description; - var $duration; - var $expression; - var $framerate; - var $handler; - var $hashes; - var $height; - var $javascript; - var $keywords; - var $lang; - var $length; - var $link; - var $medium; - var $player; - var $ratings; - var $restrictions; - var $samplingrate; - var $thumbnails; - var $title; - var $type; - var $width; +} + +/** + * Used for fetching remote files and reading local files + * + * Supports HTTP 1.0 via cURL or fsockopen, with spotty HTTP 1.1 support + * + * This class can be overloaded with {@see SimplePie::set_file_class()} + * + * @package SimplePie + * @subpackage HTTP + * @todo Move to properly supporting RFC2616 (HTTP/1.1) + */ +class SimplePie_File +{ + var $url; + var $useragent; + var $success = true; + var $headers = array(); + var $body; + var $status_code; + var $redirects = 0; + var $error; + var $method = SIMPLEPIE_FILE_SOURCE_NONE; - // Constructor, used to input the data - function SimplePie_Enclosure($link = null, $type = null, $length = null, $javascript = null, $bitrate = null, $captions = null, $categories = null, $channels = null, $copyright = null, $credits = null, $description = null, $duration = null, $expression = null, $framerate = null, $hashes = null, $height = null, $keywords = null, $lang = null, $medium = null, $player = null, $ratings = null, $restrictions = null, $samplingrate = null, $thumbnails = null, $title = null, $width = null) + public function __construct($url, $timeout = 10, $redirects = 5, $headers = null, $useragent = null, $force_fsockopen = false) { - $this->bitrate = $bitrate; - $this->captions = $captions; - $this->categories = $categories; - $this->channels = $channels; - $this->copyright = $copyright; - $this->credits = $credits; - $this->description = $description; - $this->duration = $duration; - $this->expression = $expression; - $this->framerate = $framerate; - $this->hashes = $hashes; - $this->height = $height; - $this->javascript = $javascript; - $this->keywords = $keywords; - $this->lang = $lang; - $this->length = $length; - $this->link = $link; - $this->medium = $medium; - $this->player = $player; - $this->ratings = $ratings; - $this->restrictions = $restrictions; - $this->samplingrate = $samplingrate; - $this->thumbnails = $thumbnails; - $this->title = $title; - $this->type = $type; - $this->width = $width; if (class_exists('idna_convert')) { - $idn = new idna_convert; - $parsed = SimplePie_Misc::parse_url($link); - $this->link = SimplePie_Misc::compress_parse_url($parsed['scheme'], $idn->encode($parsed['authority']), $parsed['path'], $parsed['query'], $parsed['fragment']); + $idn = new idna_convert(); + $parsed = SimplePie_Misc::parse_url($url); + $url = SimplePie_Misc::compress_parse_url($parsed['scheme'], $idn->encode($parsed['authority']), $parsed['path'], $parsed['query'], $parsed['fragment']); } - $this->handler = $this->get_handler(); // Needs to load last - } + $this->url = $url; + $this->useragent = $useragent; + if (preg_match('/^http(s)?:\/\//i', $url)) + { + if ($useragent === null) + { + $useragent = ini_get('user_agent'); + $this->useragent = $useragent; + } + if (!is_array($headers)) + { + $headers = array(); + } + if (!$force_fsockopen && function_exists('curl_exec')) + { + $this->method = SIMPLEPIE_FILE_SOURCE_REMOTE | SIMPLEPIE_FILE_SOURCE_CURL; + $fp = curl_init(); + $headers2 = array(); + foreach ($headers as $key => $value) + { + $headers2[] = "$key: $value"; + } + if (version_compare(SimplePie_Misc::get_curl_version(), '7.10.5', '>=')) + { + curl_setopt($fp, CURLOPT_ENCODING, ''); + } + curl_setopt($fp, CURLOPT_URL, $url); + curl_setopt($fp, CURLOPT_HEADER, 1); + curl_setopt($fp, CURLOPT_RETURNTRANSFER, 1); + curl_setopt($fp, CURLOPT_TIMEOUT, $timeout); + curl_setopt($fp, CURLOPT_CONNECTTIMEOUT, $timeout); + curl_setopt($fp, CURLOPT_REFERER, $url); + curl_setopt($fp, CURLOPT_USERAGENT, $useragent); + curl_setopt($fp, CURLOPT_HTTPHEADER, $headers2); + if (!ini_get('open_basedir') && !ini_get('safe_mode') && version_compare(SimplePie_Misc::get_curl_version(), '7.15.2', '>=')) + { + curl_setopt($fp, CURLOPT_FOLLOWLOCATION, 1); + curl_setopt($fp, CURLOPT_MAXREDIRS, $redirects); + } - function __toString() - { - // There is no $this->data here - return md5(serialize($this)); - } + $this->headers = curl_exec($fp); + if (curl_errno($fp) === 23 || curl_errno($fp) === 61) + { + curl_setopt($fp, CURLOPT_ENCODING, 'none'); + $this->headers = curl_exec($fp); + } + if (curl_errno($fp)) + { + $this->error = 'cURL error ' . curl_errno($fp) . ': ' . curl_error($fp); + $this->success = false; + } + else + { + $info = curl_getinfo($fp); + curl_close($fp); + $this->headers = explode("\r\n\r\n", $this->headers, $info['redirect_count'] + 1); + $this->headers = array_pop($this->headers); + $parser = new SimplePie_HTTP_Parser($this->headers); + if ($parser->parse()) + { + $this->headers = $parser->headers; + $this->body = $parser->body; + $this->status_code = $parser->status_code; + if ((in_array($this->status_code, array(300, 301, 302, 303, 307)) || $this->status_code > 307 && $this->status_code < 400) && isset($this->headers['location']) && $this->redirects < $redirects) + { + $this->redirects++; + $location = SimplePie_Misc::absolutize_url($this->headers['location'], $url); + return $this->__construct($location, $timeout, $redirects, $headers, $useragent, $force_fsockopen); + } + } + } + } + else + { + $this->method = SIMPLEPIE_FILE_SOURCE_REMOTE | SIMPLEPIE_FILE_SOURCE_FSOCKOPEN; + $url_parts = parse_url($url); + $socket_host = $url_parts['host']; + if (isset($url_parts['scheme']) && strtolower($url_parts['scheme']) === 'https') + { + $socket_host = "ssl://$url_parts[host]"; + $url_parts['port'] = 443; + } + if (!isset($url_parts['port'])) + { + $url_parts['port'] = 80; + } + $fp = @fsockopen($socket_host, $url_parts['port'], $errno, $errstr, $timeout); + if (!$fp) + { + $this->error = 'fsockopen error: ' . $errstr; + $this->success = false; + } + else + { + stream_set_timeout($fp, $timeout); + if (isset($url_parts['path'])) + { + if (isset($url_parts['query'])) + { + $get = "$url_parts[path]?$url_parts[query]"; + } + else + { + $get = $url_parts['path']; + } + } + else + { + $get = '/'; + } + $out = "GET $get HTTP/1.1\r\n"; + $out .= "Host: $url_parts[host]\r\n"; + $out .= "User-Agent: $useragent\r\n"; + if (extension_loaded('zlib')) + { + $out .= "Accept-Encoding: x-gzip,gzip,deflate\r\n"; + } - function get_bitrate() - { - if ($this->bitrate !== null) - { - return $this->bitrate; - } - else - { - return null; - } - } + if (isset($url_parts['user']) && isset($url_parts['pass'])) + { + $out .= "Authorization: Basic " . base64_encode("$url_parts[user]:$url_parts[pass]") . "\r\n"; + } + foreach ($headers as $key => $value) + { + $out .= "$key: $value\r\n"; + } + $out .= "Connection: Close\r\n\r\n"; + fwrite($fp, $out); - function get_caption($key = 0) - { - $captions = $this->get_captions(); - if (isset($captions[$key])) - { - return $captions[$key]; - } - else - { - return null; - } - } + $info = stream_get_meta_data($fp); - function get_captions() - { - if ($this->captions !== null) - { - return $this->captions; + $this->headers = ''; + while (!$info['eof'] && !$info['timed_out']) + { + $this->headers .= fread($fp, 1160); + $info = stream_get_meta_data($fp); + } + if (!$info['timed_out']) + { + $parser = new SimplePie_HTTP_Parser($this->headers); + if ($parser->parse()) + { + $this->headers = $parser->headers; + $this->body = $parser->body; + $this->status_code = $parser->status_code; + if ((in_array($this->status_code, array(300, 301, 302, 303, 307)) || $this->status_code > 307 && $this->status_code < 400) && isset($this->headers['location']) && $this->redirects < $redirects) + { + $this->redirects++; + $location = SimplePie_Misc::absolutize_url($this->headers['location'], $url); + return $this->__construct($location, $timeout, $redirects, $headers, $useragent, $force_fsockopen); + } + if (isset($this->headers['content-encoding'])) + { + // Hey, we act dumb elsewhere, so let's do that here too + switch (strtolower(trim($this->headers['content-encoding'], "\x09\x0A\x0D\x20"))) + { + case 'gzip': + case 'x-gzip': + $decoder = new SimplePie_gzdecode($this->body); + if (!$decoder->parse()) + { + $this->error = 'Unable to decode HTTP "gzip" stream'; + $this->success = false; + } + else + { + $this->body = $decoder->data; + } + break; + + case 'deflate': + if (($decompressed = gzinflate($this->body)) !== false) + { + $this->body = $decompressed; + } + else if (($decompressed = gzuncompress($this->body)) !== false) + { + $this->body = $decompressed; + } + else if (function_exists('gzdecode') && ($decompressed = gzdecode($this->body)) !== false) + { + $this->body = $decompressed; + } + else + { + $this->error = 'Unable to decode HTTP "deflate" stream'; + $this->success = false; + } + break; + + default: + $this->error = 'Unknown content coding'; + $this->success = false; + } + } + } + } + else + { + $this->error = 'fsocket timed out'; + $this->success = false; + } + fclose($fp); + } + } } else { - return null; + $this->method = SIMPLEPIE_FILE_SOURCE_LOCAL | SIMPLEPIE_FILE_SOURCE_FILE_GET_CONTENTS; + if (!$this->body = file_get_contents($url)) + { + $this->error = 'file_get_contents could not read the file'; + $this->success = false; + } } } +} - function get_category($key = 0) - { - $categories = $this->get_categories(); - if (isset($categories[$key])) - { - return $categories[$key]; - } - else - { - return null; - } - } +/** + * Decode 'gzip' encoded HTTP data + * + * @package SimplePie + * @subpackage HTTP + * @link http://www.gzip.org/format.txt + */ +class SimplePie_gzdecode +{ + /** + * Compressed data + * + * @access private + * @var string + * @see gzdecode::$data + */ + var $compressed_data; - function get_categories() - { - if ($this->categories !== null) - { - return $this->categories; - } - else - { - return null; - } - } + /** + * Size of compressed data + * + * @access private + * @var int + */ + var $compressed_size; - function get_channels() - { - if ($this->channels !== null) - { - return $this->channels; - } - else - { - return null; - } - } + /** + * Minimum size of a valid gzip string + * + * @access private + * @var int + */ + var $min_compressed_size = 18; - function get_copyright() - { - if ($this->copyright !== null) - { - return $this->copyright; - } - else - { - return null; - } - } + /** + * Current position of pointer + * + * @access private + * @var int + */ + var $position = 0; - function get_credit($key = 0) - { - $credits = $this->get_credits(); - if (isset($credits[$key])) - { - return $credits[$key]; - } - else - { - return null; - } - } + /** + * Flags (FLG) + * + * @access private + * @var int + */ + var $flags; + + /** + * Uncompressed data + * + * @access public + * @see gzdecode::$compressed_data + * @var string + */ + var $data; + + /** + * Modified time + * + * @access public + * @var int + */ + var $MTIME; + + /** + * Extra Flags + * + * @access public + * @var int + */ + var $XFL; + + /** + * Operating System + * + * @access public + * @var int + */ + var $OS; + + /** + * Subfield ID 1 + * + * @access public + * @see gzdecode::$extra_field + * @see gzdecode::$SI2 + * @var string + */ + var $SI1; + + /** + * Subfield ID 2 + * + * @access public + * @see gzdecode::$extra_field + * @see gzdecode::$SI1 + * @var string + */ + var $SI2; + + /** + * Extra field content + * + * @access public + * @see gzdecode::$SI1 + * @see gzdecode::$SI2 + * @var string + */ + var $extra_field; + + /** + * Original filename + * + * @access public + * @var string + */ + var $filename; + + /** + * Human readable comment + * + * @access public + * @var string + */ + var $comment; - function get_credits() + /** + * Don't allow anything to be set + * + * @param string $name + * @param mixed $value + */ + public function __set($name, $value) { - if ($this->credits !== null) - { - return $this->credits; - } - else - { - return null; - } + trigger_error("Cannot write property $name", E_USER_ERROR); } - function get_description() + /** + * Set the compressed string and related properties + * + * @param string $data + */ + public function __construct($data) { - if ($this->description !== null) - { - return $this->description; - } - else - { - return null; - } + $this->compressed_data = $data; + $this->compressed_size = strlen($data); } - function get_duration($convert = false) + /** + * Decode the GZIP stream + * + * @return bool Successfulness + */ + public function parse() { - if ($this->duration !== null) + if ($this->compressed_size >= $this->min_compressed_size) { - if ($convert) + // Check ID1, ID2, and CM + if (substr($this->compressed_data, 0, 3) !== "\x1F\x8B\x08") { - $time = SimplePie_Misc::time_hms($this->duration); - return $time; + return false; } - else + + // Get the FLG (FLaGs) + $this->flags = ord($this->compressed_data[3]); + + // FLG bits above (1 << 4) are reserved + if ($this->flags > 0x1F) { - return $this->duration; + return false; } - } - else - { - return null; - } - } - function get_expression() - { - if ($this->expression !== null) - { - return $this->expression; - } - else - { - return 'full'; - } - } + // Advance the pointer after the above + $this->position += 4; - function get_extension() - { - if ($this->link !== null) - { - $url = SimplePie_Misc::parse_url($this->link); - if ($url['path'] !== '') + // MTIME + $mtime = substr($this->compressed_data, $this->position, 4); + // Reverse the string if we're on a big-endian arch because l is the only signed long and is machine endianness + if (current(unpack('S', "\x00\x01")) === 1) { - return pathinfo($url['path'], PATHINFO_EXTENSION); + $mtime = strrev($mtime); } - } - return null; - } + $this->MTIME = current(unpack('l', $mtime)); + $this->position += 4; - function get_framerate() - { - if ($this->framerate !== null) - { - return $this->framerate; + // Get the XFL (eXtra FLags) + $this->XFL = ord($this->compressed_data[$this->position++]); + + // Get the OS (Operating System) + $this->OS = ord($this->compressed_data[$this->position++]); + + // Parse the FEXTRA + if ($this->flags & 4) + { + // Read subfield IDs + $this->SI1 = $this->compressed_data[$this->position++]; + $this->SI2 = $this->compressed_data[$this->position++]; + + // SI2 set to zero is reserved for future use + if ($this->SI2 === "\x00") + { + return false; + } + + // Get the length of the extra field + $len = current(unpack('v', substr($this->compressed_data, $this->position, 2))); + $this->position += 2; + + // Check the length of the string is still valid + $this->min_compressed_size += $len + 4; + if ($this->compressed_size >= $this->min_compressed_size) + { + // Set the extra field to the given data + $this->extra_field = substr($this->compressed_data, $this->position, $len); + $this->position += $len; + } + else + { + return false; + } + } + + // Parse the FNAME + if ($this->flags & 8) + { + // Get the length of the filename + $len = strcspn($this->compressed_data, "\x00", $this->position); + + // Check the length of the string is still valid + $this->min_compressed_size += $len + 1; + if ($this->compressed_size >= $this->min_compressed_size) + { + // Set the original filename to the given string + $this->filename = substr($this->compressed_data, $this->position, $len); + $this->position += $len + 1; + } + else + { + return false; + } + } + + // Parse the FCOMMENT + if ($this->flags & 16) + { + // Get the length of the comment + $len = strcspn($this->compressed_data, "\x00", $this->position); + + // Check the length of the string is still valid + $this->min_compressed_size += $len + 1; + if ($this->compressed_size >= $this->min_compressed_size) + { + // Set the original comment to the given string + $this->comment = substr($this->compressed_data, $this->position, $len); + $this->position += $len + 1; + } + else + { + return false; + } + } + + // Parse the FHCRC + if ($this->flags & 2) + { + // Check the length of the string is still valid + $this->min_compressed_size += $len + 2; + if ($this->compressed_size >= $this->min_compressed_size) + { + // Read the CRC + $crc = current(unpack('v', substr($this->compressed_data, $this->position, 2))); + + // Check the CRC matches + if ((crc32(substr($this->compressed_data, 0, $this->position)) & 0xFFFF) === $crc) + { + $this->position += 2; + } + else + { + return false; + } + } + else + { + return false; + } + } + + // Decompress the actual data + if (($this->data = gzinflate(substr($this->compressed_data, $this->position, -8))) === false) + { + return false; + } + else + { + $this->position = $this->compressed_size - 8; + } + + // Check CRC of data + $crc = current(unpack('V', substr($this->compressed_data, $this->position, 4))); + $this->position += 4; + /*if (extension_loaded('hash') && sprintf('%u', current(unpack('V', hash('crc32b', $this->data)))) !== sprintf('%u', $crc)) + { + return false; + }*/ + + // Check ISIZE of data + $isize = current(unpack('V', substr($this->compressed_data, $this->position, 4))); + $this->position += 4; + if (sprintf('%u', strlen($this->data) & 0xFFFFFFFF) !== sprintf('%u', $isize)) + { + return false; + } + + // Wow, against all odds, we've actually got a valid gzip string + return true; } else { - return null; + return false; } } +} - function get_handler() - { - return $this->get_real_type(true); - } +/** + * HTTP Response Parser + * + * @package SimplePie + * @subpackage HTTP + */ +class SimplePie_HTTP_Parser +{ + /** + * HTTP Version + * + * @var float + */ + public $http_version = 0.0; + + /** + * Status code + * + * @var int + */ + public $status_code = 0; + + /** + * Reason phrase + * + * @var string + */ + public $reason = ''; + + /** + * Key/value pairs of the headers + * + * @var array + */ + public $headers = array(); + + /** + * Body of the response + * + * @var string + */ + public $body = ''; + + /** + * Current state of the state machine + * + * @var string + */ + protected $state = 'http_version'; + + /** + * Input data + * + * @var string + */ + protected $data = ''; + + /** + * Input data length (to avoid calling strlen() everytime this is needed) + * + * @var int + */ + protected $data_length = 0; + + /** + * Current position of the pointer + * + * @var int + */ + protected $position = 0; + + /** + * Name of the hedaer currently being parsed + * + * @var string + */ + protected $name = ''; + + /** + * Value of the hedaer currently being parsed + * + * @var string + */ + protected $value = ''; - function get_hash($key = 0) + /** + * Create an instance of the class with the input data + * + * @param string $data Input data + */ + public function __construct($data) { - $hashes = $this->get_hashes(); - if (isset($hashes[$key])) - { - return $hashes[$key]; - } - else - { - return null; - } + $this->data = $data; + $this->data_length = strlen($this->data); } - function get_hashes() + /** + * Parse the input data + * + * @return bool true on success, false on failure + */ + public function parse() { - if ($this->hashes !== null) - { - return $this->hashes; - } - else + while ($this->state && $this->state !== 'emit' && $this->has_data()) { - return null; + $state = $this->state; + $this->$state(); } - } - - function get_height() - { - if ($this->height !== null) + $this->data = ''; + if ($this->state === 'emit' || $this->state === 'body') { - return $this->height; + return true; } else { - return null; + $this->http_version = ''; + $this->status_code = ''; + $this->reason = ''; + $this->headers = array(); + $this->body = ''; + return false; } } - function get_language() - { - if ($this->lang !== null) - { - return $this->lang; - } - else - { - return null; - } + /** + * Check whether there is data beyond the pointer + * + * @return bool true if there is further data, false if not + */ + protected function has_data() + { + return (bool) ($this->position < $this->data_length); } - function get_keyword($key = 0) + /** + * See if the next character is LWS + * + * @return bool true if the next character is LWS, false if not + */ + protected function is_linear_whitespace() { - $keywords = $this->get_keywords(); - if (isset($keywords[$key])) - { - return $keywords[$key]; - } - else - { - return null; - } + return (bool) ($this->data[$this->position] === "\x09" + || $this->data[$this->position] === "\x20" + || ($this->data[$this->position] === "\x0A" + && isset($this->data[$this->position + 1]) + && ($this->data[$this->position + 1] === "\x09" || $this->data[$this->position + 1] === "\x20"))); } - function get_keywords() + /** + * Parse the HTTP version + */ + protected function http_version() { - if ($this->keywords !== null) + if (strpos($this->data, "\x0A") !== false && strtoupper(substr($this->data, 0, 5)) === 'HTTP/') { - return $this->keywords; + $len = strspn($this->data, '0123456789.', 5); + $this->http_version = substr($this->data, 5, $len); + $this->position += 5 + $len; + if (substr_count($this->http_version, '.') <= 1) + { + $this->http_version = (float) $this->http_version; + $this->position += strspn($this->data, "\x09\x20", $this->position); + $this->state = 'status'; + } + else + { + $this->state = false; + } } else { - return null; + $this->state = false; } } - function get_length() + /** + * Parse the status code + */ + protected function status() { - if ($this->length !== null) + if ($len = strspn($this->data, '0123456789', $this->position)) { - return $this->length; + $this->status_code = (int) substr($this->data, $this->position, $len); + $this->position += $len; + $this->state = 'reason'; } else { - return null; + $this->state = false; } } - function get_link() + /** + * Parse the reason phrase + */ + protected function reason() { - if ($this->link !== null) - { - return urldecode($this->link); - } - else - { - return null; - } + $len = strcspn($this->data, "\x0A", $this->position); + $this->reason = trim(substr($this->data, $this->position, $len), "\x09\x0D\x20"); + $this->position += $len + 1; + $this->state = 'new_line'; } - function get_medium() + /** + * Deal with a new line, shifting data around as needed + */ + protected function new_line() { - if ($this->medium !== null) + $this->value = trim($this->value, "\x0D\x20"); + if ($this->name !== '' && $this->value !== '') { - return $this->medium; + $this->name = strtolower($this->name); + // We should only use the last Content-Type header. c.f. issue #1 + if (isset($this->headers[$this->name]) && $this->name !== 'content-type') + { + $this->headers[$this->name] .= ', ' . $this->value; + } + else + { + $this->headers[$this->name] = $this->value; + } } - else + $this->name = ''; + $this->value = ''; + if (substr($this->data[$this->position], 0, 2) === "\x0D\x0A") { - return null; + $this->position += 2; + $this->state = 'body'; } - } - - function get_player() - { - if ($this->player !== null) + elseif ($this->data[$this->position] === "\x0A") { - return $this->player; + $this->position++; + $this->state = 'body'; } else { - return null; + $this->state = 'name'; } } - function get_rating($key = 0) + /** + * Parse a header name + */ + protected function name() { - $ratings = $this->get_ratings(); - if (isset($ratings[$key])) + $len = strcspn($this->data, "\x0A:", $this->position); + if (isset($this->data[$this->position + $len])) { - return $ratings[$key]; + if ($this->data[$this->position + $len] === "\x0A") + { + $this->position += $len; + $this->state = 'new_line'; + } + else + { + $this->name = substr($this->data, $this->position, $len); + $this->position += $len + 1; + $this->state = 'value'; + } } else { - return null; + $this->state = false; } } - function get_ratings() + /** + * Parse LWS, replacing consecutive LWS characters with a single space + */ + protected function linear_whitespace() { - if ($this->ratings !== null) - { - return $this->ratings; - } - else + do { - return null; - } + if (substr($this->data, $this->position, 2) === "\x0D\x0A") + { + $this->position += 2; + } + elseif ($this->data[$this->position] === "\x0A") + { + $this->position++; + } + $this->position += strspn($this->data, "\x09\x20", $this->position); + } while ($this->has_data() && $this->is_linear_whitespace()); + $this->value .= "\x20"; } - function get_restriction($key = 0) + /** + * See what state to move to while within non-quoted header values + */ + protected function value() { - $restrictions = $this->get_restrictions(); - if (isset($restrictions[$key])) + if ($this->is_linear_whitespace()) { - return $restrictions[$key]; + $this->linear_whitespace(); } else { - return null; + switch ($this->data[$this->position]) + { + case '"': + // Workaround for ETags: we have to include the quotes as + // part of the tag. + if (strtolower($this->name) === 'etag') + { + $this->value .= '"'; + $this->position++; + $this->state = 'value_char'; + break; + } + $this->position++; + $this->state = 'quote'; + break; + + case "\x0A": + $this->position++; + $this->state = 'new_line'; + break; + + default: + $this->state = 'value_char'; + break; + } } } - function get_restrictions() + /** + * Parse a header value while outside quotes + */ + protected function value_char() { - if ($this->restrictions !== null) - { - return $this->restrictions; - } - else - { - return null; - } + $len = strcspn($this->data, "\x09\x20\x0A\"", $this->position); + $this->value .= substr($this->data, $this->position, $len); + $this->position += $len; + $this->state = 'value'; } - function get_sampling_rate() + /** + * See what state to move to while within quoted header values + */ + protected function quote() { - if ($this->samplingrate !== null) + if ($this->is_linear_whitespace()) { - return $this->samplingrate; + $this->linear_whitespace(); } else { - return null; + switch ($this->data[$this->position]) + { + case '"': + $this->position++; + $this->state = 'value'; + break; + + case "\x0A": + $this->position++; + $this->state = 'new_line'; + break; + + case '\\': + $this->position++; + $this->state = 'quote_escaped'; + break; + + default: + $this->state = 'quote_char'; + break; + } } } - function get_size() + /** + * Parse a header value while within quotes + */ + protected function quote_char() { - $length = $this->get_length(); - if ($length !== null) + $len = strcspn($this->data, "\x09\x20\x0A\"\\", $this->position); + $this->value .= substr($this->data, $this->position, $len); + $this->position += $len; + $this->state = 'value'; + } + + /** + * Parse an escaped character within quotes + */ + protected function quote_escaped() + { + $this->value .= $this->data[$this->position]; + $this->position++; + $this->state = 'quote'; + } + + /** + * Parse the body + */ + protected function body() + { + $this->body = substr($this->data, $this->position); + if (!empty($this->headers['transfer-encoding'])) { - return round($length/1048576, 2); + unset($this->headers['transfer-encoding']); + $this->state = 'chunked'; } else { - return null; + $this->state = 'emit'; } } - function get_thumbnail($key = 0) + /** + * Parsed a "Transfer-Encoding: chunked" body + */ + protected function chunked() { - $thumbnails = $this->get_thumbnails(); - if (isset($thumbnails[$key])) + if (!preg_match('/^([0-9a-f]+)[^\r\n]*\r\n/i', trim($this->body))) { - return $thumbnails[$key]; + $this->state = 'emit'; + return; } - else + + $decoded = ''; + $encoded = $this->body; + + while (true) { - return null; + $is_chunked = (bool) preg_match( '/^([0-9a-f]+)[^\r\n]*\r\n/i', $encoded, $matches ); + if (!$is_chunked) + { + // Looks like it's not chunked after all + $this->state = 'emit'; + return; + } + + $length = hexdec(trim($matches[1])); + if ($length === 0) + { + // Ignore trailer headers + $this->state = 'emit'; + $this->body = $decoded; + return; + } + + $chunk_length = strlen($matches[0]); + $decoded .= $part = substr($encoded, $chunk_length, $length); + $encoded = substr($encoded, $chunk_length + $length + 2); + + if (trim($encoded) === '0' || empty($encoded)) + { + $this->state = 'emit'; + $this->body = $decoded; + return; + } } } +} + +/** + * IRI parser/serialiser/normaliser + * + * @package SimplePie + * @subpackage HTTP + * @author Geoffrey Sneddon + * @author Steve Minutillo + * @author Ryan McCue + * @copyright 2007-2012 Geoffrey Sneddon, Steve Minutillo, Ryan McCue + * @license http://www.opensource.org/licenses/bsd-license.php + */ +class SimplePie_IRI +{ + /** + * Scheme + * + * @var string + */ + protected $scheme = null; + + /** + * User Information + * + * @var string + */ + protected $iuserinfo = null; + + /** + * ihost + * + * @var string + */ + protected $ihost = null; + + /** + * Port + * + * @var string + */ + protected $port = null; + + /** + * ipath + * + * @var string + */ + protected $ipath = ''; + + /** + * iquery + * + * @var string + */ + protected $iquery = null; + + /** + * ifragment + * + * @var string + */ + protected $ifragment = null; + + /** + * Normalization database + * + * Each key is the scheme, each value is an array with each key as the IRI + * part and value as the default value for that part. + */ + protected $normalization = array( + 'acap' => array( + 'port' => 674 + ), + 'dict' => array( + 'port' => 2628 + ), + 'file' => array( + 'ihost' => 'localhost' + ), + 'http' => array( + 'port' => 80, + 'ipath' => '/' + ), + 'https' => array( + 'port' => 443, + 'ipath' => '/' + ), + ); + + /** + * Return the entire IRI when you try and read the object as a string + * + * @return string + */ + public function __toString() + { + return $this->get_iri(); + } - function get_thumbnails() + /** + * Overload __set() to provide access via properties + * + * @param string $name Property name + * @param mixed $value Property value + */ + public function __set($name, $value) { - if ($this->thumbnails !== null) + if (method_exists($this, 'set_' . $name)) { - return $this->thumbnails; + call_user_func(array($this, 'set_' . $name), $value); } - else + elseif ( + $name === 'iauthority' + || $name === 'iuserinfo' + || $name === 'ihost' + || $name === 'ipath' + || $name === 'iquery' + || $name === 'ifragment' + ) { - return null; + call_user_func(array($this, 'set_' . substr($name, 1)), $value); } } - function get_title() + /** + * Overload __get() to provide access via properties + * + * @param string $name Property name + * @return mixed + */ + public function __get($name) { - if ($this->title !== null) + // isset() returns false for null, we don't want to do that + // Also why we use array_key_exists below instead of isset() + $props = get_object_vars($this); + + if ( + $name === 'iri' || + $name === 'uri' || + $name === 'iauthority' || + $name === 'authority' + ) { - return $this->title; + $return = $this->{"get_$name"}(); + } + elseif (array_key_exists($name, $props)) + { + $return = $this->$name; + } + // host -> ihost + elseif (($prop = 'i' . $name) && array_key_exists($prop, $props)) + { + $name = $prop; + $return = $this->$prop; + } + // ischeme -> scheme + elseif (($prop = substr($name, 1)) && array_key_exists($prop, $props)) + { + $name = $prop; + $return = $this->$prop; } else { - return null; + trigger_error('Undefined property: ' . get_class($this) . '::' . $name, E_USER_NOTICE); + $return = null; } - } - function get_type() - { - if ($this->type !== null) + if ($return === null && isset($this->normalization[$this->scheme][$name])) { - return $this->type; + return $this->normalization[$this->scheme][$name]; } else { - return null; + return $return; } } - function get_width() + /** + * Overload __isset() to provide access via properties + * + * @param string $name Property name + * @return bool + */ + public function __isset($name) { - if ($this->width !== null) + if (method_exists($this, 'get_' . $name) || isset($this->$name)) { - return $this->width; + return true; } else { - return null; + return false; } } - function native_embed($options='') + /** + * Overload __unset() to provide access via properties + * + * @param string $name Property name + */ + public function __unset($name) { - return $this->embed($options, true); + if (method_exists($this, 'set_' . $name)) + { + call_user_func(array($this, 'set_' . $name), ''); + } } /** - * @todo If the dimensions for media:content are defined, use them when width/height are set to 'auto'. + * Create a new IRI object, from a specified string + * + * @param string $iri */ - function embed($options = '', $native = false) + public function __construct($iri = null) { - // Set up defaults - $audio = ''; - $video = ''; - $alt = ''; - $altclass = ''; - $loop = 'false'; - $width = 'auto'; - $height = 'auto'; - $bgcolor = '#ffffff'; - $mediaplayer = ''; - $widescreen = false; - $handler = $this->get_handler(); - $type = $this->get_real_type(); + $this->set_iri($iri); + } - // Process options and reassign values as necessary - if (is_array($options)) + /** + * Create a new IRI object by resolving a relative IRI + * + * Returns false if $base is not absolute, otherwise an IRI. + * + * @param IRI|string $base (Absolute) Base IRI + * @param IRI|string $relative Relative IRI + * @return IRI|false + */ + public static function absolutize($base, $relative) + { + if (!($relative instanceof SimplePie_IRI)) { - extract($options); + $relative = new SimplePie_IRI($relative); + } + if (!$relative->is_valid()) + { + return false; + } + elseif ($relative->scheme !== null) + { + return clone $relative; } else { - $options = explode(',', $options); - foreach($options as $option) + if (!($base instanceof SimplePie_IRI)) { - $opt = explode(':', $option, 2); - if (isset($opt[0], $opt[1])) - { - $opt[0] = trim($opt[0]); - $opt[1] = trim($opt[1]); - switch ($opt[0]) - { - case 'audio': - $audio = $opt[1]; - break; - - case 'video': - $video = $opt[1]; - break; - - case 'alt': - $alt = $opt[1]; - break; - - case 'altclass': - $altclass = $opt[1]; - break; - - case 'loop': - $loop = $opt[1]; - break; - - case 'width': - $width = $opt[1]; - break; - - case 'height': - $height = $opt[1]; - break; - - case 'bgcolor': - $bgcolor = $opt[1]; - break; - - case 'mediaplayer': - $mediaplayer = $opt[1]; - break; - - case 'widescreen': - $widescreen = $opt[1]; - break; - } - } + $base = new SimplePie_IRI($base); } - } - - $mime = explode('/', $type, 2); - $mime = $mime[0]; - - // Process values for 'auto' - if ($width === 'auto') - { - if ($mime === 'video') + if ($base->scheme !== null && $base->is_valid()) { - if ($height === 'auto') - { - $width = 480; - } - elseif ($widescreen) + if ($relative->get_iri() !== '') { - $width = round((intval($height)/9)*16); + if ($relative->iuserinfo !== null || $relative->ihost !== null || $relative->port !== null) + { + $target = clone $relative; + $target->scheme = $base->scheme; + } + else + { + $target = new SimplePie_IRI; + $target->scheme = $base->scheme; + $target->iuserinfo = $base->iuserinfo; + $target->ihost = $base->ihost; + $target->port = $base->port; + if ($relative->ipath !== '') + { + if ($relative->ipath[0] === '/') + { + $target->ipath = $relative->ipath; + } + elseif (($base->iuserinfo !== null || $base->ihost !== null || $base->port !== null) && $base->ipath === '') + { + $target->ipath = '/' . $relative->ipath; + } + elseif (($last_segment = strrpos($base->ipath, '/')) !== false) + { + $target->ipath = substr($base->ipath, 0, $last_segment + 1) . $relative->ipath; + } + else + { + $target->ipath = $relative->ipath; + } + $target->ipath = $target->remove_dot_segments($target->ipath); + $target->iquery = $relative->iquery; + } + else + { + $target->ipath = $base->ipath; + if ($relative->iquery !== null) + { + $target->iquery = $relative->iquery; + } + elseif ($base->iquery !== null) + { + $target->iquery = $base->iquery; + } + } + $target->ifragment = $relative->ifragment; + } } else { - $width = round((intval($height)/3)*4); + $target = clone $base; + $target->ifragment = null; } + $target->scheme_normalization(); + return $target; } else { - $width = '100%'; + return false; } } + } - if ($height === 'auto') + /** + * Parse an IRI into scheme/authority/path/query/fragment segments + * + * @param string $iri + * @return array + */ + protected function parse_iri($iri) + { + $iri = trim($iri, "\x20\x09\x0A\x0C\x0D"); + if (preg_match('/^((?P[^:\/?#]+):)?(\/\/(?P[^\/?#]*))?(?P[^?#]*)(\?(?P[^#]*))?(#(?P.*))?$/', $iri, $match)) { - if ($mime === 'audio') + if ($match[1] === '') { - $height = 0; + $match['scheme'] = null; } - elseif ($mime === 'video') + if (!isset($match[3]) || $match[3] === '') { - if ($width === 'auto') - { - if ($widescreen) - { - $height = 270; - } - else - { - $height = 360; - } - } - elseif ($widescreen) - { - $height = round((intval($width)/16)*9); - } - else - { - $height = round((intval($width)/4)*3); - } + $match['authority'] = null; } - else + if (!isset($match[5])) { - $height = 376; + $match['path'] = ''; } + if (!isset($match[6]) || $match[6] === '') + { + $match['query'] = null; + } + if (!isset($match[8]) || $match[8] === '') + { + $match['fragment'] = null; + } + return $match; } - elseif ($mime === 'audio') - { - $height = 0; - } - - // Set proper placeholder value - if ($mime === 'audio') - { - $placeholder = $audio; - } - elseif ($mime === 'video') + else { - $placeholder = $video; + // This can occur when a paragraph is accidentally parsed as a URI + return false; } + } - $embed = ''; - - // Make sure the JS library is included - if (!$native) + /** + * Remove dot segments from a path + * + * @param string $input + * @return string + */ + protected function remove_dot_segments($input) + { + $output = ''; + while (strpos($input, './') !== false || strpos($input, '/.') !== false || $input === '.' || $input === '..') { - static $javascript_outputted = null; - if (!$javascript_outputted && $this->javascript) + // A: If the input buffer begins with a prefix of "../" or "./", then remove that prefix from the input buffer; otherwise, + if (strpos($input, '../') === 0) { - $embed .= ''; - $javascript_outputted = true; + $input = substr($input, 3); } - } - - // Odeo Feed MP3's - if ($handler === 'odeo') - { - if ($native) + elseif (strpos($input, './') === 0) { - $embed .= ''; + $input = substr($input, 2); } - else + // B: if the input buffer begins with a prefix of "/./" or "/.", where "." is a complete path segment, then replace that prefix with "/" in the input buffer; otherwise, + elseif (strpos($input, '/./') === 0) { - $embed .= ''; + $input = substr($input, 2); } - } - - // Flash - elseif ($handler === 'flash') - { - if ($native) + elseif ($input === '/.') { - $embed .= "get_link() . "\" pluginspage=\"http://adobe.com/go/getflashplayer\" type=\"$type\" quality=\"high\" width=\"$width\" height=\"$height\" bgcolor=\"$bgcolor\" loop=\"$loop\">"; + $input = '/'; + } + // C: if the input buffer begins with a prefix of "/../" or "/..", where ".." is a complete path segment, then replace that prefix with "/" in the input buffer and remove the last segment and its preceding "/" (if any) from the output buffer; otherwise, + elseif (strpos($input, '/../') === 0) + { + $input = substr($input, 3); + $output = substr_replace($output, '', strrpos($output, '/')); + } + elseif ($input === '/..') + { + $input = '/'; + $output = substr_replace($output, '', strrpos($output, '/')); + } + // D: if the input buffer consists only of "." or "..", then remove that from the input buffer; otherwise, + elseif ($input === '.' || $input === '..') + { + $input = ''; + } + // E: move the first path segment in the input buffer to the end of the output buffer, including the initial "/" character (if any) and any subsequent characters up to, but not including, the next "/" character or the end of the input buffer + elseif (($pos = strpos($input, '/', 1)) !== false) + { + $output .= substr($input, 0, $pos); + $input = substr_replace($input, '', 0, $pos); } else { - $embed .= ""; + $output .= $input; + $input = ''; } } + return $output . $input; + } - // Flash Media Player file types. - // Preferred handler for MP3 file types. - elseif ($handler === 'fmedia' || ($handler === 'mp3' && $mediaplayer !== '')) + /** + * Replace invalid character with percent encoding + * + * @param string $string Input string + * @param string $extra_chars Valid characters not in iunreserved or + * iprivate (this is ASCII-only) + * @param bool $iprivate Allow iprivate + * @return string + */ + protected function replace_invalid_with_pct_encoding($string, $extra_chars, $iprivate = false) + { + // Normalize as many pct-encoded sections as possible + $string = preg_replace_callback('/(?:%[A-Fa-f0-9]{2})+/', array($this, 'remove_iunreserved_percent_encoded'), $string); + + // Replace invalid percent characters + $string = preg_replace('/%(?![A-Fa-f0-9]{2})/', '%25', $string); + + // Add unreserved and % to $extra_chars (the latter is safe because all + // pct-encoded sections are now valid). + $extra_chars .= 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~%'; + + // Now replace any bytes that aren't allowed with their pct-encoded versions + $position = 0; + $strlen = strlen($string); + while (($position += strspn($string, $extra_chars, $position)) < $strlen) { - $height += 20; - if ($native) + $value = ord($string[$position]); + + // Start position + $start = $position; + + // By default we are valid + $valid = true; + + // No one byte sequences are valid due to the while. + // Two byte sequence: + if (($value & 0xE0) === 0xC0) { - $embed .= "get_link().'?file_extension=.'.$this->get_extension()) . "&autostart=false&repeat=$loop&showdigits=true&showfsbutton=false\">"; + $character = ($value & 0x1F) << 6; + $length = 2; + $remaining = 1; + } + // Three byte sequence: + elseif (($value & 0xF0) === 0xE0) + { + $character = ($value & 0x0F) << 12; + $length = 3; + $remaining = 2; + } + // Four byte sequence: + elseif (($value & 0xF8) === 0xF0) + { + $character = ($value & 0x07) << 18; + $length = 4; + $remaining = 3; } + // Invalid byte: else { - $embed .= ""; + $valid = false; + $length = 1; + $remaining = 0; } - } - // QuickTime 7 file types. Need to test with QuickTime 6. - // Only handle MP3's if the Flash Media Player is not present. - elseif ($handler === 'quicktime' || ($handler === 'mp3' && $mediaplayer === '')) - { - $height += 16; - if ($native) + if ($remaining) { - if ($placeholder !== '') + if ($position + $length <= $strlen) { - $embed .= "get_link() . "\" src=\"$placeholder\" width=\"$width\" height=\"$height\" autoplay=\"false\" target=\"myself\" controller=\"false\" loop=\"$loop\" scale=\"aspect\" bgcolor=\"$bgcolor\" pluginspage=\"http://apple.com/quicktime/download/\">"; + for ($position++; $remaining; $position++) + { + $value = ord($string[$position]); + + // Check that the byte is valid, then add it to the character: + if (($value & 0xC0) === 0x80) + { + $character |= ($value & 0x3F) << (--$remaining * 6); + } + // If it is invalid, count the sequence as invalid and reprocess the current byte: + else + { + $valid = false; + $position--; + break; + } + } } else { - $embed .= "get_link() . "\" width=\"$width\" height=\"$height\" autoplay=\"false\" target=\"myself\" controller=\"true\" loop=\"$loop\" scale=\"aspect\" bgcolor=\"$bgcolor\" pluginspage=\"http://apple.com/quicktime/download/\">"; + $position = $strlen - 1; + $valid = false; } } - else - { - $embed .= ""; - } - } - // Windows Media - elseif ($handler === 'wmedia') - { - $height += 45; - if ($native) - { - $embed .= "get_link() . "\" autosize=\"1\" width=\"$width\" height=\"$height\" showcontrols=\"1\" showstatusbar=\"0\" showdisplay=\"0\" autostart=\"0\">"; - } - else + // Percent encode anything invalid or not in ucschar + if ( + // Invalid sequences + !$valid + // Non-shortest form sequences are invalid + || $length > 1 && $character <= 0x7F + || $length > 2 && $character <= 0x7FF + || $length > 3 && $character <= 0xFFFF + // Outside of range of ucschar codepoints + // Noncharacters + || ($character & 0xFFFE) === 0xFFFE + || $character >= 0xFDD0 && $character <= 0xFDEF + || ( + // Everything else not in ucschar + $character > 0xD7FF && $character < 0xF900 + || $character < 0xA0 + || $character > 0xEFFFD + ) + && ( + // Everything not in iprivate, if it applies + !$iprivate + || $character < 0xE000 + || $character > 0x10FFFD + ) + ) { - $embed .= ""; + // If we were a character, pretend we weren't, but rather an error. + if ($valid) + $position--; + + for ($j = $start; $j <= $position; $j++) + { + $string = substr_replace($string, sprintf('%%%02X', ord($string[$j])), $j, 1); + $j += 2; + $position += 2; + $strlen += 2; + } } } - // Everything else - else $embed .= '' . $alt . ''; - - return $embed; + return $string; } - function get_real_type($find_handler = false) + /** + * Callback function for preg_replace_callback. + * + * Removes sequences of percent encoded bytes that represent UTF-8 + * encoded characters in iunreserved + * + * @param array $match PCRE match + * @return string Replacement + */ + protected function remove_iunreserved_percent_encoded($match) { - // If it's Odeo, let's get it out of the way. - if (substr(strtolower($this->get_link()), 0, 15) === 'http://odeo.com') - { - return 'odeo'; - } - - // Mime-types by handler. - $types_flash = array('application/x-shockwave-flash', 'application/futuresplash'); // Flash - $types_fmedia = array('video/flv', 'video/x-flv','flv-application/octet-stream'); // Flash Media Player - $types_quicktime = array('audio/3gpp', 'audio/3gpp2', 'audio/aac', 'audio/x-aac', 'audio/aiff', 'audio/x-aiff', 'audio/mid', 'audio/midi', 'audio/x-midi', 'audio/mp4', 'audio/m4a', 'audio/x-m4a', 'audio/wav', 'audio/x-wav', 'video/3gpp', 'video/3gpp2', 'video/m4v', 'video/x-m4v', 'video/mp4', 'video/mpeg', 'video/x-mpeg', 'video/quicktime', 'video/sd-video'); // QuickTime - $types_wmedia = array('application/asx', 'application/x-mplayer2', 'audio/x-ms-wma', 'audio/x-ms-wax', 'video/x-ms-asf-plugin', 'video/x-ms-asf', 'video/x-ms-wm', 'video/x-ms-wmv', 'video/x-ms-wvx'); // Windows Media - $types_mp3 = array('audio/mp3', 'audio/x-mp3', 'audio/mpeg', 'audio/x-mpeg'); // MP3 + // As we just have valid percent encoded sequences we can just explode + // and ignore the first member of the returned array (an empty string). + $bytes = explode('%', $match[0]); - if ($this->get_type() !== null) - { - $type = strtolower($this->type); - } - else - { - $type = null; - } + // Initialize the new string (this is what will be returned) and that + // there are no bytes remaining in the current sequence (unsurprising + // at the first byte!). + $string = ''; + $remaining = 0; - // If we encounter an unsupported mime-type, check the file extension and guess intelligently. - if (!in_array($type, array_merge($types_flash, $types_fmedia, $types_quicktime, $types_wmedia, $types_mp3))) + // Loop over each and every byte, and set $value to its value + for ($i = 1, $len = count($bytes); $i < $len; $i++) { - switch (strtolower($this->get_extension())) - { - // Audio mime-types - case 'aac': - case 'adts': - $type = 'audio/acc'; - break; - - case 'aif': - case 'aifc': - case 'aiff': - case 'cdda': - $type = 'audio/aiff'; - break; - - case 'bwf': - $type = 'audio/wav'; - break; + $value = hexdec($bytes[$i]); - case 'kar': - case 'mid': - case 'midi': - case 'smf': - $type = 'audio/midi'; - break; + // If we're the first byte of sequence: + if (!$remaining) + { + // Start position + $start = $i; - case 'm4a': - $type = 'audio/x-m4a'; - break; + // By default we are valid + $valid = true; - case 'mp3': - case 'swa': - $type = 'audio/mp3'; - break; + // One byte sequence: + if ($value <= 0x7F) + { + $character = $value; + $length = 1; + } + // Two byte sequence: + elseif (($value & 0xE0) === 0xC0) + { + $character = ($value & 0x1F) << 6; + $length = 2; + $remaining = 1; + } + // Three byte sequence: + elseif (($value & 0xF0) === 0xE0) + { + $character = ($value & 0x0F) << 12; + $length = 3; + $remaining = 2; + } + // Four byte sequence: + elseif (($value & 0xF8) === 0xF0) + { + $character = ($value & 0x07) << 18; + $length = 4; + $remaining = 3; + } + // Invalid byte: + else + { + $valid = false; + $remaining = 0; + } + } + // Continuation byte: + else + { + // Check that the byte is valid, then add it to the character: + if (($value & 0xC0) === 0x80) + { + $remaining--; + $character |= ($value & 0x3F) << ($remaining * 6); + } + // If it is invalid, count the sequence as invalid and reprocess the current byte as the start of a sequence: + else + { + $valid = false; + $remaining = 0; + $i--; + } + } - case 'wav': - $type = 'audio/wav'; - break; + // If we've reached the end of the current byte sequence, append it to Unicode::$data + if (!$remaining) + { + // Percent encode anything invalid or not in iunreserved + if ( + // Invalid sequences + !$valid + // Non-shortest form sequences are invalid + || $length > 1 && $character <= 0x7F + || $length > 2 && $character <= 0x7FF + || $length > 3 && $character <= 0xFFFF + // Outside of range of iunreserved codepoints + || $character < 0x2D + || $character > 0xEFFFD + // Noncharacters + || ($character & 0xFFFE) === 0xFFFE + || $character >= 0xFDD0 && $character <= 0xFDEF + // Everything else not in iunreserved (this is all BMP) + || $character === 0x2F + || $character > 0x39 && $character < 0x41 + || $character > 0x5A && $character < 0x61 + || $character > 0x7A && $character < 0x7E + || $character > 0x7E && $character < 0xA0 + || $character > 0xD7FF && $character < 0xF900 + ) + { + for ($j = $start; $j <= $i; $j++) + { + $string .= '%' . strtoupper($bytes[$j]); + } + } + else + { + for ($j = $start; $j <= $i; $j++) + { + $string .= chr(hexdec($bytes[$j])); + } + } + } + } - case 'wax': - $type = 'audio/x-ms-wax'; - break; + // If we have any bytes left over they are invalid (i.e., we are + // mid-way through a multi-byte sequence) + if ($remaining) + { + for ($j = $start; $j < $len; $j++) + { + $string .= '%' . strtoupper($bytes[$j]); + } + } - case 'wma': - $type = 'audio/x-ms-wma'; - break; + return $string; + } - // Video mime-types - case '3gp': - case '3gpp': - $type = 'video/3gpp'; - break; + protected function scheme_normalization() + { + if (isset($this->normalization[$this->scheme]['iuserinfo']) && $this->iuserinfo === $this->normalization[$this->scheme]['iuserinfo']) + { + $this->iuserinfo = null; + } + if (isset($this->normalization[$this->scheme]['ihost']) && $this->ihost === $this->normalization[$this->scheme]['ihost']) + { + $this->ihost = null; + } + if (isset($this->normalization[$this->scheme]['port']) && $this->port === $this->normalization[$this->scheme]['port']) + { + $this->port = null; + } + if (isset($this->normalization[$this->scheme]['ipath']) && $this->ipath === $this->normalization[$this->scheme]['ipath']) + { + $this->ipath = ''; + } + if (isset($this->normalization[$this->scheme]['iquery']) && $this->iquery === $this->normalization[$this->scheme]['iquery']) + { + $this->iquery = null; + } + if (isset($this->normalization[$this->scheme]['ifragment']) && $this->ifragment === $this->normalization[$this->scheme]['ifragment']) + { + $this->ifragment = null; + } + } - case '3g2': - case '3gp2': - $type = 'video/3gpp2'; - break; + /** + * Check if the object represents a valid IRI. This needs to be done on each + * call as some things change depending on another part of the IRI. + * + * @return bool + */ + public function is_valid() + { + $isauthority = $this->iuserinfo !== null || $this->ihost !== null || $this->port !== null; + if ($this->ipath !== '' && + ( + $isauthority && ( + $this->ipath[0] !== '/' || + substr($this->ipath, 0, 2) === '//' + ) || + ( + $this->scheme === null && + !$isauthority && + strpos($this->ipath, ':') !== false && + (strpos($this->ipath, '/') === false ? true : strpos($this->ipath, ':') < strpos($this->ipath, '/')) + ) + ) + ) + { + return false; + } - case 'asf': - $type = 'video/x-ms-asf'; - break; + return true; + } - case 'flv': - $type = 'video/x-flv'; - break; + /** + * Set the entire IRI. Returns true on success, false on failure (if there + * are any invalid characters). + * + * @param string $iri + * @return bool + */ + public function set_iri($iri) + { + static $cache; + if (!$cache) + { + $cache = array(); + } - case 'm1a': - case 'm1s': - case 'm1v': - case 'm15': - case 'm75': - case 'mp2': - case 'mpa': - case 'mpeg': - case 'mpg': - case 'mpm': - case 'mpv': - $type = 'video/mpeg'; - break; + if ($iri === null) + { + return true; + } + elseif (isset($cache[$iri])) + { + list($this->scheme, + $this->iuserinfo, + $this->ihost, + $this->port, + $this->ipath, + $this->iquery, + $this->ifragment, + $return) = $cache[$iri]; + return $return; + } + else + { + $parsed = $this->parse_iri((string) $iri); + if (!$parsed) + { + return false; + } - case 'm4v': - $type = 'video/x-m4v'; - break; + $return = $this->set_scheme($parsed['scheme']) + && $this->set_authority($parsed['authority']) + && $this->set_path($parsed['path']) + && $this->set_query($parsed['query']) + && $this->set_fragment($parsed['fragment']); + + $cache[$iri] = array($this->scheme, + $this->iuserinfo, + $this->ihost, + $this->port, + $this->ipath, + $this->iquery, + $this->ifragment, + $return); + return $return; + } + } - case 'mov': - case 'qt': - $type = 'video/quicktime'; - break; - - case 'mp4': - case 'mpg4': - $type = 'video/mp4'; - break; - - case 'sdv': - $type = 'video/sd-video'; - break; - - case 'wm': - $type = 'video/x-ms-wm'; - break; - - case 'wmv': - $type = 'video/x-ms-wmv'; - break; - - case 'wvx': - $type = 'video/x-ms-wvx'; - break; + /** + * Set the scheme. Returns true on success, false on failure (if there are + * any invalid characters). + * + * @param string $scheme + * @return bool + */ + public function set_scheme($scheme) + { + if ($scheme === null) + { + $this->scheme = null; + } + elseif (!preg_match('/^[A-Za-z][0-9A-Za-z+\-.]*$/', $scheme)) + { + $this->scheme = null; + return false; + } + else + { + $this->scheme = strtolower($scheme); + } + return true; + } - // Flash mime-types - case 'spl': - $type = 'application/futuresplash'; - break; + /** + * Set the authority. Returns true on success, false on failure (if there are + * any invalid characters). + * + * @param string $authority + * @return bool + */ + public function set_authority($authority) + { + static $cache; + if (!$cache) + $cache = array(); - case 'swf': - $type = 'application/x-shockwave-flash'; - break; - } + if ($authority === null) + { + $this->iuserinfo = null; + $this->ihost = null; + $this->port = null; + return true; } + elseif (isset($cache[$authority])) + { + list($this->iuserinfo, + $this->ihost, + $this->port, + $return) = $cache[$authority]; - if ($find_handler) + return $return; + } + else { - if (in_array($type, $types_flash)) - { - return 'flash'; - } - elseif (in_array($type, $types_fmedia)) - { - return 'fmedia'; - } - elseif (in_array($type, $types_quicktime)) + $remaining = $authority; + if (($iuserinfo_end = strrpos($remaining, '@')) !== false) { - return 'quicktime'; + $iuserinfo = substr($remaining, 0, $iuserinfo_end); + $remaining = substr($remaining, $iuserinfo_end + 1); } - elseif (in_array($type, $types_wmedia)) + else { - return 'wmedia'; + $iuserinfo = null; } - elseif (in_array($type, $types_mp3)) + if (($port_start = strpos($remaining, ':', strpos($remaining, ']'))) !== false) { - return 'mp3'; + if (($port = substr($remaining, $port_start + 1)) === false) + { + $port = null; + } + $remaining = substr($remaining, 0, $port_start); } else { - return null; + $port = null; } - } - else - { - return $type; - } - } -} -class SimplePie_Caption -{ - var $type; - var $lang; - var $startTime; - var $endTime; - var $text; + $return = $this->set_userinfo($iuserinfo) && + $this->set_host($remaining) && + $this->set_port($port); - // Constructor, used to input the data - function SimplePie_Caption($type = null, $lang = null, $startTime = null, $endTime = null, $text = null) - { - $this->type = $type; - $this->lang = $lang; - $this->startTime = $startTime; - $this->endTime = $endTime; - $this->text = $text; - } + $cache[$authority] = array($this->iuserinfo, + $this->ihost, + $this->port, + $return); - function __toString() - { - // There is no $this->data here - return md5(serialize($this)); + return $return; + } } - function get_endtime() + /** + * Set the iuserinfo. + * + * @param string $iuserinfo + * @return bool + */ + public function set_userinfo($iuserinfo) { - if ($this->endTime !== null) + if ($iuserinfo === null) { - return $this->endTime; + $this->iuserinfo = null; } else { - return null; + $this->iuserinfo = $this->replace_invalid_with_pct_encoding($iuserinfo, '!$&\'()*+,;=:'); + $this->scheme_normalization(); } + + return true; } - function get_language() + /** + * Set the ihost. Returns true on success, false on failure (if there are + * any invalid characters). + * + * @param string $ihost + * @return bool + */ + public function set_host($ihost) { - if ($this->lang !== null) + if ($ihost === null) { - return $this->lang; + $this->ihost = null; + return true; + } + elseif (substr($ihost, 0, 1) === '[' && substr($ihost, -1) === ']') + { + if (SimplePie_Net_IPv6::check_ipv6(substr($ihost, 1, -1))) + { + $this->ihost = '[' . SimplePie_Net_IPv6::compress(substr($ihost, 1, -1)) . ']'; + } + else + { + $this->ihost = null; + return false; + } } else { - return null; + $ihost = $this->replace_invalid_with_pct_encoding($ihost, '!$&\'()*+,;='); + + // Lowercase, but ignore pct-encoded sections (as they should + // remain uppercase). This must be done after the previous step + // as that can add unescaped characters. + $position = 0; + $strlen = strlen($ihost); + while (($position += strcspn($ihost, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ%', $position)) < $strlen) + { + if ($ihost[$position] === '%') + { + $position += 3; + } + else + { + $ihost[$position] = strtolower($ihost[$position]); + $position++; + } + } + + $this->ihost = $ihost; } + + $this->scheme_normalization(); + + return true; } - function get_starttime() + /** + * Set the port. Returns true on success, false on failure (if there are + * any invalid characters). + * + * @param string $port + * @return bool + */ + public function set_port($port) { - if ($this->startTime !== null) + if ($port === null) { - return $this->startTime; + $this->port = null; + return true; + } + elseif (strspn($port, '0123456789') === strlen($port)) + { + $this->port = (int) $port; + $this->scheme_normalization(); + return true; } else { - return null; + $this->port = null; + return false; } } - function get_text() + /** + * Set the ipath. + * + * @param string $ipath + * @return bool + */ + public function set_path($ipath) { - if ($this->text !== null) - { - return $this->text; - } - else + static $cache; + if (!$cache) { - return null; + $cache = array(); } - } - function get_type() - { - if ($this->type !== null) + $ipath = (string) $ipath; + + if (isset($cache[$ipath])) { - return $this->type; + $this->ipath = $cache[$ipath][(int) ($this->scheme !== null)]; } else { - return null; - } - } -} + $valid = $this->replace_invalid_with_pct_encoding($ipath, '!$&\'()*+,;=@:/'); + $removed = $this->remove_dot_segments($valid); -class SimplePie_Credit -{ - var $role; - var $scheme; - var $name; - - // Constructor, used to input the data - function SimplePie_Credit($role = null, $scheme = null, $name = null) - { - $this->role = $role; - $this->scheme = $scheme; - $this->name = $name; - } + $cache[$ipath] = array($valid, $removed); + $this->ipath = ($this->scheme !== null) ? $removed : $valid; + } - function __toString() - { - // There is no $this->data here - return md5(serialize($this)); + $this->scheme_normalization(); + return true; } - function get_role() + /** + * Set the iquery. + * + * @param string $iquery + * @return bool + */ + public function set_query($iquery) { - if ($this->role !== null) + if ($iquery === null) { - return $this->role; + $this->iquery = null; } else { - return null; + $this->iquery = $this->replace_invalid_with_pct_encoding($iquery, '!$&\'()*+,;=:@/?', true); + $this->scheme_normalization(); } + return true; } - function get_scheme() + /** + * Set the ifragment. + * + * @param string $ifragment + * @return bool + */ + public function set_fragment($ifragment) { - if ($this->scheme !== null) + if ($ifragment === null) { - return $this->scheme; + $this->ifragment = null; } else { - return null; + $this->ifragment = $this->replace_invalid_with_pct_encoding($ifragment, '!$&\'()*+,;=:@/?'); + $this->scheme_normalization(); } + return true; } - function get_name() + /** + * Convert an IRI to a URI (or parts thereof) + * + * @return string + */ + public function to_uri($string) { - if ($this->name !== null) + static $non_ascii; + if (!$non_ascii) { - return $this->name; + $non_ascii = implode('', range("\x80", "\xFF")); } - else + + $position = 0; + $strlen = strlen($string); + while (($position += strcspn($string, $non_ascii, $position)) < $strlen) { - return null; + $string = substr_replace($string, sprintf('%%%02X', ord($string[$position])), $position, 1); + $position += 3; + $strlen += 2; } - } -} - -class SimplePie_Copyright -{ - var $url; - var $label; - - // Constructor, used to input the data - function SimplePie_Copyright($url = null, $label = null) - { - $this->url = $url; - $this->label = $label; - } - function __toString() - { - // There is no $this->data here - return md5(serialize($this)); + return $string; } - function get_url() + /** + * Get the complete IRI + * + * @return string + */ + public function get_iri() { - if ($this->url !== null) + if (!$this->is_valid()) { - return $this->url; + return false; } - else + + $iri = ''; + if ($this->scheme !== null) { - return null; + $iri .= $this->scheme . ':'; } - } - - function get_attribution() - { - if ($this->label !== null) + if (($iauthority = $this->get_iauthority()) !== null) { - return $this->label; + $iri .= '//' . $iauthority; } - else + if ($this->ipath !== '') { - return null; + $iri .= $this->ipath; + } + elseif (!empty($this->normalization[$this->scheme]['ipath']) && $iauthority !== null && $iauthority !== '') + { + $iri .= $this->normalization[$this->scheme]['ipath']; + } + if ($this->iquery !== null) + { + $iri .= '?' . $this->iquery; + } + if ($this->ifragment !== null) + { + $iri .= '#' . $this->ifragment; } - } -} - -class SimplePie_Rating -{ - var $scheme; - var $value; - // Constructor, used to input the data - function SimplePie_Rating($scheme = null, $value = null) - { - $this->scheme = $scheme; - $this->value = $value; + return $iri; } - function __toString() + /** + * Get the complete URI + * + * @return string + */ + public function get_uri() { - // There is no $this->data here - return md5(serialize($this)); + return $this->to_uri($this->get_iri()); } - function get_scheme() + /** + * Get the complete iauthority + * + * @return string + */ + protected function get_iauthority() { - if ($this->scheme !== null) + if ($this->iuserinfo !== null || $this->ihost !== null || $this->port !== null) { - return $this->scheme; + $iauthority = ''; + if ($this->iuserinfo !== null) + { + $iauthority .= $this->iuserinfo . '@'; + } + if ($this->ihost !== null) + { + $iauthority .= $this->ihost; + } + if ($this->port !== null) + { + $iauthority .= ':' . $this->port; + } + return $iauthority; } else { @@ -7569,56 +8996,125 @@ class SimplePie_Rating } } - function get_value() + /** + * Get the complete authority + * + * @return string + */ + protected function get_authority() { - if ($this->value !== null) - { - return $this->value; - } + $iauthority = $this->get_iauthority(); + if (is_string($iauthority)) + return $this->to_uri($iauthority); else - { - return null; - } + return $iauthority; } } -class SimplePie_Restriction +/** + * Manages all item-related data + * + * Used by {@see SimplePie::get_item()} and {@see SimplePie::get_items()} + * + * This class can be overloaded with {@see SimplePie::set_item_class()} + * + * @package SimplePie + * @subpackage API + */ +class SimplePie_Item { - var $relationship; - var $type; - var $value; + /** + * Parent feed + * + * @access private + * @var SimplePie + */ + var $feed; + + /** + * Raw data + * + * @access private + * @var array + */ + var $data = array(); + + /** + * Registry object + * + * @see set_registry + * @var SimplePie_Registry + */ + protected $registry; - // Constructor, used to input the data - function SimplePie_Restriction($relationship = null, $type = null, $value = null) + /** + * Create a new item object + * + * This is usually used by {@see SimplePie::get_items} and + * {@see SimplePie::get_item}. Avoid creating this manually. + * + * @param SimplePie $feed Parent feed + * @param array $data Raw data + */ + public function __construct($feed, $data) { - $this->relationship = $relationship; - $this->type = $type; - $this->value = $value; + $this->feed = $feed; + $this->data = $data; } - function __toString() + /** + * Set the registry handler + * + * This is usually used by {@see SimplePie_Registry::create} + * + * @since 1.3 + * @param SimplePie_Registry $registry + */ + public function set_registry(SimplePie_Registry $registry) { - // There is no $this->data here - return md5(serialize($this)); + $this->registry = $registry; } - function get_relationship() + /** + * Get a string representation of the item + * + * @return string + */ + public function __toString() { - if ($this->relationship !== null) - { - return $this->relationship; - } - else + return md5(serialize($this->data)); + } + + /** + * Remove items that link back to this before destroying this object + */ + public function __destruct() + { + if ((version_compare(PHP_VERSION, '5.3', '<') || !gc_enabled()) && !ini_get('zend.ze1_compatibility_mode')) { - return null; + unset($this->feed); } } - function get_type() + /** + * Get data for an item-level element + * + * This method allows you to get access to ANY element/attribute that is a + * sub-element of the item/entry tag. + * + * See {@see SimplePie::get_feed_tags()} for a description of the return value + * + * @since 1.0 + * @see http://simplepie.org/wiki/faq/supported_xml_namespaces + * @param string $namespace The URL of the XML namespace of the elements you're trying to access + * @param string $tag Tag name + * @return array + */ + public function get_item_tags($namespace, $tag) { - if ($this->type !== null) + if (isset($this->data['child'][$namespace][$tag])) { - return $this->type; + return $this->data['child'][$namespace][$tag]; } else { @@ -7626,7674 +9122,8647 @@ class SimplePie_Restriction } } - function get_value() + /** + * Get the base URL value from the parent feed + * + * Uses `` + * + * @param array $element + * @return string + */ + public function get_base($element = array()) { - if ($this->value !== null) + return $this->feed->get_base($element); + } + + /** + * Sanitize feed data + * + * @access private + * @see SimplePie::sanitize() + * @param string $data Data to sanitize + * @param int $type One of the SIMPLEPIE_CONSTRUCT_* constants + * @param string $base Base URL to resolve URLs against + * @return string Sanitized data + */ + public function sanitize($data, $type, $base = '') + { + return $this->feed->sanitize($data, $type, $base); + } + + /** + * Get the parent feed + * + * Note: this may not work as you think for multifeeds! + * + * @link http://simplepie.org/faq/typical_multifeed_gotchas#missing_data_from_feed + * @since 1.0 + * @return SimplePie + */ + public function get_feed() + { + return $this->feed; + } + + /** + * Get the unique identifier for the item + * + * This is usually used when writing code to check for new items in a feed. + * + * Uses ``, ``, `` or the `about` attribute + * for RDF. If none of these are supplied (or `$hash` is true), creates an + * MD5 hash based on the permalink and title. If either of those are not + * supplied, creates a hash based on the full feed data. + * + * @since Beta 2 + * @param boolean $hash Should we force using a hash instead of the supplied ID? + * @return string + */ + public function get_id($hash = false) + { + if (!$hash) { - return $this->value; + if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'id')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'id')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'guid')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'identifier')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'identifier')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + elseif (isset($this->data['attribs'][SIMPLEPIE_NAMESPACE_RDF]['about'])) + { + return $this->sanitize($this->data['attribs'][SIMPLEPIE_NAMESPACE_RDF]['about'], SIMPLEPIE_CONSTRUCT_TEXT); + } + elseif (($return = $this->get_permalink()) !== null) + { + return $return; + } + elseif (($return = $this->get_title()) !== null) + { + return $return; + } + } + if ($this->get_permalink() !== null || $this->get_title() !== null) + { + return md5($this->get_permalink() . $this->get_title()); } else { - return null; + return md5(serialize($this->data)); } } -} - -/** - * @todo Move to properly supporting RFC2616 (HTTP/1.1) - */ -class SimplePie_File -{ - var $url; - var $useragent; - var $success = true; - var $headers = array(); - var $body; - var $status_code; - var $redirects = 0; - var $error; - var $method = SIMPLEPIE_FILE_SOURCE_NONE; - function SimplePie_File($url, $timeout = 10, $redirects = 5, $headers = null, $useragent = null, $force_fsockopen = false) + /** + * Get the title of the item + * + * Uses ``, `` or `<dc:title>` + * + * @since Beta 2 (previously called `get_item_title` since 0.8) + * @return string|null + */ + public function get_title() { - if (class_exists('idna_convert')) - { - $idn = new idna_convert; - $parsed = SimplePie_Misc::parse_url($url); - $url = SimplePie_Misc::compress_parse_url($parsed['scheme'], $idn->encode($parsed['authority']), $parsed['path'], $parsed['query'], $parsed['fragment']); - } - $this->url = $url; - $this->useragent = $useragent; - if (preg_match('/^http(s)?:\/\//i', $url)) + if (!isset($this->data['title'])) { - if ($useragent === null) + if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'title')) { - $useragent = ini_get('user_agent'); - $this->useragent = $useragent; + $this->data['title'] = $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0])); } - if (!is_array($headers)) + elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'title')) { - $headers = array(); + $this->data['title'] = $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0])); } - if (!$force_fsockopen && function_exists('curl_exec')) + elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'title')) { - $this->method = SIMPLEPIE_FILE_SOURCE_REMOTE | SIMPLEPIE_FILE_SOURCE_CURL; - $fp = curl_init(); - $headers2 = array(); - foreach ($headers as $key => $value) - { - $headers2[] = "$key: $value"; - } - if (version_compare(SimplePie_Misc::get_curl_version(), '7.10.5', '>=')) - { - curl_setopt($fp, CURLOPT_ENCODING, ''); - } - curl_setopt($fp, CURLOPT_URL, $url); - curl_setopt($fp, CURLOPT_HEADER, 1); - curl_setopt($fp, CURLOPT_RETURNTRANSFER, 1); - curl_setopt($fp, CURLOPT_TIMEOUT, $timeout); - curl_setopt($fp, CURLOPT_CONNECTTIMEOUT, $timeout); - curl_setopt($fp, CURLOPT_REFERER, $url); - curl_setopt($fp, CURLOPT_USERAGENT, $useragent); - curl_setopt($fp, CURLOPT_HTTPHEADER, $headers2); - if (!ini_get('open_basedir') && !ini_get('safe_mode') && version_compare(SimplePie_Misc::get_curl_version(), '7.15.2', '>=')) - { - curl_setopt($fp, CURLOPT_FOLLOWLOCATION, 1); - curl_setopt($fp, CURLOPT_MAXREDIRS, $redirects); - } - - $this->headers = curl_exec($fp); - if (curl_errno($fp) === 23 || curl_errno($fp) === 61) - { - curl_setopt($fp, CURLOPT_ENCODING, 'none'); - $this->headers = curl_exec($fp); - } - if (curl_errno($fp)) - { - $this->error = 'cURL error ' . curl_errno($fp) . ': ' . curl_error($fp); - $this->success = false; - } - else - { - $info = curl_getinfo($fp); - curl_close($fp); - $this->headers = explode("\r\n\r\n", $this->headers, $info['redirect_count'] + 1); - $this->headers = array_pop($this->headers); - $parser = new SimplePie_HTTP_Parser($this->headers); - if ($parser->parse()) - { - $this->headers = $parser->headers; - $this->body = $parser->body; - $this->status_code = $parser->status_code; - if ((in_array($this->status_code, array(300, 301, 302, 303, 307)) || $this->status_code > 307 && $this->status_code < 400) && isset($this->headers['location']) && $this->redirects < $redirects) - { - $this->redirects++; - $location = SimplePie_Misc::absolutize_url($this->headers['location'], $url); - return $this->SimplePie_File($location, $timeout, $redirects, $headers, $useragent, $force_fsockopen); - } - } - } + $this->data['title'] = $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0])); } - else + elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'title')) { - $this->method = SIMPLEPIE_FILE_SOURCE_REMOTE | SIMPLEPIE_FILE_SOURCE_FSOCKOPEN; - $url_parts = parse_url($url); - $socket_host = $url_parts['host']; - if (isset($url_parts['scheme']) && strtolower($url_parts['scheme']) === 'https') - { - $socket_host = "ssl://$url_parts[host]"; - $url_parts['port'] = 443; - } - if (!isset($url_parts['port'])) - { - $url_parts['port'] = 80; - } - $fp = @fsockopen($socket_host, $url_parts['port'], $errno, $errstr, $timeout); - if (!$fp) - { - $this->error = 'fsockopen error: ' . $errstr; - $this->success = false; - } - else - { - stream_set_timeout($fp, $timeout); - if (isset($url_parts['path'])) - { - if (isset($url_parts['query'])) - { - $get = "$url_parts[path]?$url_parts[query]"; - } - else - { - $get = $url_parts['path']; - } - } - else - { - $get = '/'; - } - $out = "GET $get HTTP/1.0\r\n"; - $out .= "Host: $url_parts[host]\r\n"; - $out .= "User-Agent: $useragent\r\n"; - if (extension_loaded('zlib')) - { - $out .= "Accept-Encoding: x-gzip,gzip,deflate\r\n"; - } - - if (isset($url_parts['user']) && isset($url_parts['pass'])) - { - $out .= "Authorization: Basic " . base64_encode("$url_parts[user]:$url_parts[pass]") . "\r\n"; - } - foreach ($headers as $key => $value) - { - $out .= "$key: $value\r\n"; - } - $out .= "Connection: Close\r\n\r\n"; - fwrite($fp, $out); - - $info = stream_get_meta_data($fp); - - $this->headers = ''; - while (!$info['eof'] && !$info['timed_out']) - { - $this->headers .= fread($fp, 1160); - $info = stream_get_meta_data($fp); - } - if (!$info['timed_out']) - { - $parser = new SimplePie_HTTP_Parser($this->headers); - if ($parser->parse()) - { - $this->headers = $parser->headers; - $this->body = $parser->body; - $this->status_code = $parser->status_code; - if ((in_array($this->status_code, array(300, 301, 302, 303, 307)) || $this->status_code > 307 && $this->status_code < 400) && isset($this->headers['location']) && $this->redirects < $redirects) - { - $this->redirects++; - $location = SimplePie_Misc::absolutize_url($this->headers['location'], $url); - return $this->SimplePie_File($location, $timeout, $redirects, $headers, $useragent, $force_fsockopen); - } - if (isset($this->headers['content-encoding'])) - { - // Hey, we act dumb elsewhere, so let's do that here too - switch (strtolower(trim($this->headers['content-encoding'], "\x09\x0A\x0D\x20"))) - { - case 'gzip': - case 'x-gzip': - $decoder = new SimplePie_gzdecode($this->body); - if (!$decoder->parse()) - { - $this->error = 'Unable to decode HTTP "gzip" stream'; - $this->success = false; - } - else - { - $this->body = $decoder->data; - } - break; - - case 'deflate': - if (($body = gzuncompress($this->body)) === false) - { - if (($body = gzinflate($this->body)) === false) - { - $this->error = 'Unable to decode HTTP "deflate" stream'; - $this->success = false; - } - } - $this->body = $body; - break; - - default: - $this->error = 'Unknown content coding'; - $this->success = false; - } - } - } - } - else - { - $this->error = 'fsocket timed out'; - $this->success = false; - } - fclose($fp); - } + $this->data['title'] = $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0])); } - } - else - { - $this->method = SIMPLEPIE_FILE_SOURCE_LOCAL | SIMPLEPIE_FILE_SOURCE_FILE_GET_CONTENTS; - if (!$this->body = file_get_contents($url)) + elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'title')) { - $this->error = 'file_get_contents could not read the file'; - $this->success = false; + $this->data['title'] = $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0])); + } + elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'title')) + { + $this->data['title'] = $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'title')) + { + $this->data['title'] = $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + else + { + $this->data['title'] = null; } } + return $this->data['title']; } -} -/** - * HTTP Response Parser - * - * @package SimplePie - */ -class SimplePie_HTTP_Parser -{ /** - * HTTP Version + * Get the content for the item * - * @access public - * @var float - */ - var $http_version = 0.0; - - /** - * Status code + * Prefers summaries over full content , but will return full content if a + * summary does not exist. * - * @access public - * @var int - */ - var $status_code = 0; - - /** - * Reason phrase + * To prefer full content instead, use {@see get_content} * - * @access public - * @var string - */ - var $reason = ''; - - /** - * Key/value pairs of the headers + * Uses `<atom:summary>`, `<description>`, `<dc:description>` or + * `<itunes:subtitle>` * - * @access public - * @var array + * @since 0.8 + * @param boolean $description_only Should we avoid falling back to the content? + * @return string|null */ - var $headers = array(); + public function get_description($description_only = false) + { + if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'summary')) + { + return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0])); + } + elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'summary')) + { + return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0])); + } + elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'description')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0])); + } + elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'description')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0])); + } + elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'description')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'description')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'summary')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0])); + } + elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'subtitle')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'description')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML); + } + + elseif (!$description_only) + { + return $this->get_content(true); + } + else + { + return null; + } + } /** - * Body of the response - * - * @access public - * @var string - */ - var $body = ''; - - /** - * Current state of the state machine - * - * @access private - * @var string - */ - var $state = 'http_version'; - - /** - * Input data - * - * @access private - * @var string - */ - var $data = ''; - - /** - * Input data length (to avoid calling strlen() everytime this is needed) - * - * @access private - * @var int - */ - var $data_length = 0; - - /** - * Current position of the pointer - * - * @var int - * @access private - */ - var $position = 0; - - /** - * Name of the hedaer currently being parsed + * Get the content for the item * - * @access private - * @var string - */ - var $name = ''; - - /** - * Value of the hedaer currently being parsed + * Prefers full content over summaries, but will return a summary if full + * content does not exist. * - * @access private - * @var string - */ - var $value = ''; - - /** - * Create an instance of the class with the input data + * To prefer summaries instead, use {@see get_description} * - * @access public - * @param string $data Input data - */ - function SimplePie_HTTP_Parser($data) - { - $this->data = $data; - $this->data_length = strlen($this->data); - } - - /** - * Parse the input data + * Uses `<atom:content>` or `<content:encoded>` (RSS 1.0 Content Module) * - * @access public - * @return bool true on success, false on failure + * @since 1.0 + * @param boolean $content_only Should we avoid falling back to the description? + * @return string|null */ - function parse() + public function get_content($content_only = false) { - while ($this->state && $this->state !== 'emit' && $this->has_data()) + if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'content')) { - $state = $this->state; - $this->$state(); + return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_content_construct_type', array($return[0]['attribs'])), $this->get_base($return[0])); } - $this->data = ''; - if ($this->state === 'emit' || $this->state === 'body') + elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'content')) { - return true; + return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0])); + } + elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_10_MODULES_CONTENT, 'encoded')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0])); + } + elseif (!$content_only) + { + return $this->get_description(true); } else { - $this->http_version = ''; - $this->status_code = ''; - $this->reason = ''; - $this->headers = array(); - $this->body = ''; - return false; + return null; } } /** - * Check whether there is data beyond the pointer + * Get a category for the item * - * @access private - * @return bool true if there is further data, false if not + * @since Beta 3 (previously called `get_categories()` since Beta 2) + * @param int $key The category that you want to return. Remember that arrays begin with 0, not 1 + * @return SimplePie_Category|null */ - function has_data() + public function get_category($key = 0) { - return (bool) ($this->position < $this->data_length); + $categories = $this->get_categories(); + if (isset($categories[$key])) + { + return $categories[$key]; + } + else + { + return null; + } } /** - * See if the next character is LWS + * Get all categories for the item * - * @access private - * @return bool true if the next character is LWS, false if not - */ - function is_linear_whitespace() - { - return (bool) ($this->data[$this->position] === "\x09" - || $this->data[$this->position] === "\x20" - || ($this->data[$this->position] === "\x0A" - && isset($this->data[$this->position + 1]) - && ($this->data[$this->position + 1] === "\x09" || $this->data[$this->position + 1] === "\x20"))); - } - - /** - * Parse the HTTP version + * Uses `<atom:category>`, `<category>` or `<dc:subject>` * - * @access private + * @since Beta 3 + * @return array|null List of {@see SimplePie_Category} objects */ - function http_version() + public function get_categories() { - if (strpos($this->data, "\x0A") !== false && strtoupper(substr($this->data, 0, 5)) === 'HTTP/') + $categories = array(); + + foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'category') as $category) { - $len = strspn($this->data, '0123456789.', 5); - $this->http_version = substr($this->data, 5, $len); - $this->position += 5 + $len; - if (substr_count($this->http_version, '.') <= 1) + $term = null; + $scheme = null; + $label = null; + if (isset($category['attribs']['']['term'])) { - $this->http_version = (float) $this->http_version; - $this->position += strspn($this->data, "\x09\x20", $this->position); - $this->state = 'status'; + $term = $this->sanitize($category['attribs']['']['term'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($category['attribs']['']['scheme'])) + { + $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($category['attribs']['']['label'])) + { + $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT); + } + $categories[] = $this->registry->create('Category', array($term, $scheme, $label)); + } + foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'category') as $category) + { + // This is really the label, but keep this as the term also for BC. + // Label will also work on retrieving because that falls back to term. + $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT); + if (isset($category['attribs']['']['domain'])) + { + $scheme = $this->sanitize($category['attribs']['']['domain'], SIMPLEPIE_CONSTRUCT_TEXT); } else { - $this->state = false; + $scheme = null; } + $categories[] = $this->registry->create('Category', array($term, $scheme, null)); + } + foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'subject') as $category) + { + $categories[] = $this->registry->create('Category', array($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null)); + } + foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'subject') as $category) + { + $categories[] = $this->registry->create('Category', array($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null)); + } + + if (!empty($categories)) + { + return array_unique($categories); } else { - $this->state = false; + return null; } } /** - * Parse the status code + * Get an author for the item * - * @access private + * @since Beta 2 + * @param int $key The author that you want to return. Remember that arrays begin with 0, not 1 + * @return SimplePie_Author|null */ - function status() + public function get_author($key = 0) { - if ($len = strspn($this->data, '0123456789', $this->position)) + $authors = $this->get_authors(); + if (isset($authors[$key])) { - $this->status_code = (int) substr($this->data, $this->position, $len); - $this->position += $len; - $this->state = 'reason'; + return $authors[$key]; } else { - $this->state = false; + return null; } } /** - * Parse the reason phrase + * Get a contributor for the item * - * @access private + * @since 1.1 + * @param int $key The contrbutor that you want to return. Remember that arrays begin with 0, not 1 + * @return SimplePie_Author|null */ - function reason() + public function get_contributor($key = 0) { - $len = strcspn($this->data, "\x0A", $this->position); - $this->reason = trim(substr($this->data, $this->position, $len), "\x09\x0D\x20"); - $this->position += $len + 1; - $this->state = 'new_line'; + $contributors = $this->get_contributors(); + if (isset($contributors[$key])) + { + return $contributors[$key]; + } + else + { + return null; + } } /** - * Deal with a new line, shifting data around as needed + * Get all contributors for the item * - * @access private + * Uses `<atom:contributor>` + * + * @since 1.1 + * @return array|null List of {@see SimplePie_Author} objects */ - function new_line() + public function get_contributors() { - $this->value = trim($this->value, "\x0D\x20"); - if ($this->name !== '' && $this->value !== '') + $contributors = array(); + foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'contributor') as $contributor) { - $this->name = strtolower($this->name); - if (isset($this->headers[$this->name])) + $name = null; + $uri = null; + $email = null; + if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'])) { - $this->headers[$this->name] .= ', ' . $this->value; + $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); } - else + if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data'])) { - $this->headers[$this->name] = $this->value; + $uri = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0])); + } + if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'])) + { + $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if ($name !== null || $email !== null || $uri !== null) + { + $contributors[] = $this->registry->create('Author', array($name, $uri, $email)); } } - $this->name = ''; - $this->value = ''; - if (substr($this->data[$this->position], 0, 2) === "\x0D\x0A") + foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'contributor') as $contributor) { - $this->position += 2; - $this->state = 'body'; + $name = null; + $url = null; + $email = null; + if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'])) + { + $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data'])) + { + $url = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0])); + } + if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'])) + { + $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if ($name !== null || $email !== null || $url !== null) + { + $contributors[] = $this->registry->create('Author', array($name, $url, $email)); + } } - elseif ($this->data[$this->position] === "\x0A") + + if (!empty($contributors)) { - $this->position++; - $this->state = 'body'; + return array_unique($contributors); } else { - $this->state = 'name'; + return null; } } /** - * Parse a header name + * Get all authors for the item * - * @access private + * Uses `<atom:author>`, `<author>`, `<dc:creator>` or `<itunes:author>` + * + * @since Beta 2 + * @return array|null List of {@see SimplePie_Author} objects */ - function name() + public function get_authors() { - $len = strcspn($this->data, "\x0A:", $this->position); - if (isset($this->data[$this->position + $len])) + $authors = array(); + foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'author') as $author) { - if ($this->data[$this->position + $len] === "\x0A") - { - $this->position += $len; - $this->state = 'new_line'; + $name = null; + $uri = null; + $email = null; + if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'])) + { + $name = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); } - else + if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data'])) { - $this->name = substr($this->data, $this->position, $len); - $this->position += $len + 1; - $this->state = 'value'; + $uri = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0])); + } + if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'])) + { + $email = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if ($name !== null || $email !== null || $uri !== null) + { + $authors[] = $this->registry->create('Author', array($name, $uri, $email)); + } + } + if ($author = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'author')) + { + $name = null; + $url = null; + $email = null; + if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'])) + { + $name = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data'])) + { + $url = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0])); + } + if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'])) + { + $email = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if ($name !== null || $email !== null || $url !== null) + { + $authors[] = $this->registry->create('Author', array($name, $url, $email)); } } + if ($author = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'author')) + { + $authors[] = $this->registry->create('Author', array(null, null, $this->sanitize($author[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT))); + } + foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'creator') as $author) + { + $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null)); + } + foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'creator') as $author) + { + $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null)); + } + foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'author') as $author) + { + $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null)); + } + + if (!empty($authors)) + { + return array_unique($authors); + } + elseif (($source = $this->get_source()) && ($authors = $source->get_authors())) + { + return $authors; + } + elseif ($authors = $this->feed->get_authors()) + { + return $authors; + } else { - $this->state = false; + return null; } } /** - * Parse LWS, replacing consecutive LWS characters with a single space + * Get the copyright info for the item * - * @access private + * Uses `<atom:rights>` or `<dc:rights>` + * + * @since 1.1 + * @return string */ - function linear_whitespace() + public function get_copyright() { - do + if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'rights')) { - if (substr($this->data, $this->position, 2) === "\x0D\x0A") - { - $this->position += 2; - } - elseif ($this->data[$this->position] === "\x0A") - { - $this->position++; - } - $this->position += strspn($this->data, "\x09\x20", $this->position); - } while ($this->has_data() && $this->is_linear_whitespace()); - $this->value .= "\x20"; + return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0])); + } + elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'rights')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'rights')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + else + { + return null; + } } /** - * See what state to move to while within non-quoted header values + * Get the posting date/time for the item * - * @access private + * Uses `<atom:published>`, `<atom:updated>`, `<atom:issued>`, + * `<atom:modified>`, `<pubDate>` or `<dc:date>` + * + * Note: obeys PHP's timezone setting. To get a UTC date/time, use + * {@see get_gmdate} + * + * @since Beta 2 (previously called `get_item_date` since 0.8) + * + * @param string $date_format Supports any PHP date format from {@see http://php.net/date} (empty for the raw data) + * @return int|string|null */ - function value() + public function get_date($date_format = 'j F Y, g:i a') { - if ($this->is_linear_whitespace()) + if (!isset($this->data['date'])) { - $this->linear_whitespace(); + if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'published')) + { + $this->data['date']['raw'] = $return[0]['data']; + } + elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'updated')) + { + $this->data['date']['raw'] = $return[0]['data']; + } + elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'issued')) + { + $this->data['date']['raw'] = $return[0]['data']; + } + elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'created')) + { + $this->data['date']['raw'] = $return[0]['data']; + } + elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'modified')) + { + $this->data['date']['raw'] = $return[0]['data']; + } + elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'pubDate')) + { + $this->data['date']['raw'] = $return[0]['data']; + } + elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'date')) + { + $this->data['date']['raw'] = $return[0]['data']; + } + elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'date')) + { + $this->data['date']['raw'] = $return[0]['data']; + } + + if (!empty($this->data['date']['raw'])) + { + $parser = $this->registry->call('Parse_Date', 'get'); + $this->data['date']['parsed'] = $parser->parse($this->data['date']['raw']); + } + else + { + $this->data['date'] = null; + } } - else + if ($this->data['date']) { - switch ($this->data[$this->position]) + $date_format = (string) $date_format; + switch ($date_format) { - case '"': - $this->position++; - $this->state = 'quote'; - break; + case '': + return $this->sanitize($this->data['date']['raw'], SIMPLEPIE_CONSTRUCT_TEXT); - case "\x0A": - $this->position++; - $this->state = 'new_line'; - break; + case 'U': + return $this->data['date']['parsed']; default: - $this->state = 'value_char'; - break; + return date($date_format, $this->data['date']['parsed']); } } + else + { + return null; + } } /** - * Parse a header value while outside quotes + * Get the update date/time for the item * - * @access private - */ - function value_char() - { - $len = strcspn($this->data, "\x09\x20\x0A\"", $this->position); - $this->value .= substr($this->data, $this->position, $len); - $this->position += $len; - $this->state = 'value'; - } - - /** - * See what state to move to while within quoted header values + * Uses `<atom:updated>` * - * @access private + * Note: obeys PHP's timezone setting. To get a UTC date/time, use + * {@see get_gmdate} + * + * @param string $date_format Supports any PHP date format from {@see http://php.net/date} (empty for the raw data) + * @return int|string|null */ - function quote() + public function get_updated_date($date_format = 'j F Y, g:i a') { - if ($this->is_linear_whitespace()) + if (!isset($this->data['updated'])) { - $this->linear_whitespace(); + if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'updated')) + { + $this->data['updated']['raw'] = $return[0]['data']; + } + + if (!empty($this->data['updated']['raw'])) + { + $parser = $this->registry->call('Parse_Date', 'get'); + $this->data['updated']['parsed'] = $parser->parse($this->data['date']['raw']); + } + else + { + $this->data['updated'] = null; + } } - else + if ($this->data['updated']) { - switch ($this->data[$this->position]) + $date_format = (string) $date_format; + switch ($date_format) { - case '"': - $this->position++; - $this->state = 'value'; - break; - - case "\x0A": - $this->position++; - $this->state = 'new_line'; - break; + case '': + return $this->sanitize($this->data['updated']['raw'], SIMPLEPIE_CONSTRUCT_TEXT); - case '\\': - $this->position++; - $this->state = 'quote_escaped'; - break; + case 'U': + return $this->data['updated']['parsed']; default: - $this->state = 'quote_char'; - break; + return date($date_format, $this->data['updated']['parsed']); } } + else + { + return null; + } } /** - * Parse a header value while within quotes + * Get the localized posting date/time for the item * - * @access private + * Returns the date formatted in the localized language. To display in + * languages other than the server's default, you need to change the locale + * with {@link http://php.net/setlocale setlocale()}. The available + * localizations depend on which ones are installed on your web server. + * + * @since 1.0 + * + * @param string $date_format Supports any PHP date format from {@see http://php.net/strftime} (empty for the raw data) + * @return int|string|null */ - function quote_char() + public function get_local_date($date_format = '%c') { - $len = strcspn($this->data, "\x09\x20\x0A\"\\", $this->position); - $this->value .= substr($this->data, $this->position, $len); - $this->position += $len; - $this->state = 'value'; + if (!$date_format) + { + return $this->sanitize($this->get_date(''), SIMPLEPIE_CONSTRUCT_TEXT); + } + elseif (($date = $this->get_date('U')) !== null && $date !== false) + { + return strftime($date_format, $date); + } + else + { + return null; + } } /** - * Parse an escaped character within quotes + * Get the posting date/time for the item (UTC time) * - * @access private + * @see get_date + * @param string $date_format Supports any PHP date format from {@see http://php.net/date} + * @return int|string|null */ - function quote_escaped() + public function get_gmdate($date_format = 'j F Y, g:i a') { - $this->value .= $this->data[$this->position]; - $this->position++; - $this->state = 'quote'; + $date = $this->get_date('U'); + if ($date === null) + { + return null; + } + + return gmdate($date_format, $date); } /** - * Parse the body + * Get the update date/time for the item (UTC time) * - * @access private + * @see get_updated_date + * @param string $date_format Supports any PHP date format from {@see http://php.net/date} + * @return int|string|null */ - function body() + public function get_updated_gmdate($date_format = 'j F Y, g:i a') { - $this->body = substr($this->data, $this->position); - $this->state = 'emit'; - } -} - -/** - * gzdecode - * - * @package SimplePie - */ -class SimplePie_gzdecode -{ - /** - * Compressed data - * - * @access private - * @see gzdecode::$data - */ - var $compressed_data; - - /** - * Size of compressed data - * - * @access private - */ - var $compressed_size; - - /** - * Minimum size of a valid gzip string - * - * @access private - */ - var $min_compressed_size = 18; - - /** - * Current position of pointer - * - * @access private - */ - var $position = 0; - - /** - * Flags (FLG) - * - * @access private - */ - var $flags; - - /** - * Uncompressed data - * - * @access public - * @see gzdecode::$compressed_data - */ - var $data; - - /** - * Modified time - * - * @access public - */ - var $MTIME; - - /** - * Extra Flags - * - * @access public - */ - var $XFL; - - /** - * Operating System - * - * @access public - */ - var $OS; - - /** - * Subfield ID 1 - * - * @access public - * @see gzdecode::$extra_field - * @see gzdecode::$SI2 - */ - var $SI1; - - /** - * Subfield ID 2 - * - * @access public - * @see gzdecode::$extra_field - * @see gzdecode::$SI1 - */ - var $SI2; - - /** - * Extra field content - * - * @access public - * @see gzdecode::$SI1 - * @see gzdecode::$SI2 - */ - var $extra_field; + $date = $this->get_updated_date('U'); + if ($date === null) + { + return null; + } - /** - * Original filename - * - * @access public - */ - var $filename; + return gmdate($date_format, $date); + } /** - * Human readable comment + * Get the permalink for the item * - * @access public - */ - var $comment; - - /** - * Don't allow anything to be set + * Returns the first link available with a relationship of "alternate". + * Identical to {@see get_link()} with key 0 * - * @access public + * @see get_link + * @since 0.8 + * @return string|null Permalink URL */ - function __set($name, $value) + public function get_permalink() { - trigger_error("Cannot write property $name", E_USER_ERROR); + $link = $this->get_link(); + $enclosure = $this->get_enclosure(0); + if ($link !== null) + { + return $link; + } + elseif ($enclosure !== null) + { + return $enclosure->get_link(); + } + else + { + return null; + } } /** - * Set the compressed string and related properties + * Get a single link for the item * - * @access public + * @since Beta 3 + * @param int $key The link that you want to return. Remember that arrays begin with 0, not 1 + * @param string $rel The relationship of the link to return + * @return string|null Link URL */ - function SimplePie_gzdecode($data) + public function get_link($key = 0, $rel = 'alternate') { - $this->compressed_data = $data; - $this->compressed_size = strlen($data); + $links = $this->get_links($rel); + if ($links[$key] !== null) + { + return $links[$key]; + } + else + { + return null; + } } /** - * Decode the GZIP stream + * Get all links for the item * - * @access public + * Uses `<atom:link>`, `<link>` or `<guid>` + * + * @since Beta 2 + * @param string $rel The relationship of links to return + * @return array|null Links found for the item (strings) */ - function parse() + public function get_links($rel = 'alternate') { - if ($this->compressed_size >= $this->min_compressed_size) + if (!isset($this->data['links'])) { - // Check ID1, ID2, and CM - if (substr($this->compressed_data, 0, 3) !== "\x1F\x8B\x08") + $this->data['links'] = array(); + foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'link') as $link) { - return false; - } - - // Get the FLG (FLaGs) - $this->flags = ord($this->compressed_data[3]); + if (isset($link['attribs']['']['href'])) + { + $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate'; + $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link)); - // FLG bits above (1 << 4) are reserved - if ($this->flags > 0x1F) + } + } + foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'link') as $link) { - return false; + if (isset($link['attribs']['']['href'])) + { + $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate'; + $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link)); + } } - - // Advance the pointer after the above - $this->position += 4; - - // MTIME - $mtime = substr($this->compressed_data, $this->position, 4); - // Reverse the string if we're on a big-endian arch because l is the only signed long and is machine endianness - if (current(unpack('S', "\x00\x01")) === 1) + if ($links = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'link')) { - $mtime = strrev($mtime); + $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0])); } - $this->MTIME = current(unpack('l', $mtime)); - $this->position += 4; - - // Get the XFL (eXtra FLags) - $this->XFL = ord($this->compressed_data[$this->position++]); - - // Get the OS (Operating System) - $this->OS = ord($this->compressed_data[$this->position++]); - - // Parse the FEXTRA - if ($this->flags & 4) + if ($links = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'link')) { - // Read subfield IDs - $this->SI1 = $this->compressed_data[$this->position++]; - $this->SI2 = $this->compressed_data[$this->position++]; - - // SI2 set to zero is reserved for future use - if ($this->SI2 === "\x00") - { - return false; - } - - // Get the length of the extra field - $len = current(unpack('v', substr($this->compressed_data, $this->position, 2))); - $this->position += 2; - - // Check the length of the string is still valid - $this->min_compressed_size += $len + 4; - if ($this->compressed_size >= $this->min_compressed_size) - { - // Set the extra field to the given data - $this->extra_field = substr($this->compressed_data, $this->position, $len); - $this->position += $len; - } - else + $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0])); + } + if ($links = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'link')) + { + $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0])); + } + if ($links = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'guid')) + { + if (!isset($links[0]['attribs']['']['isPermaLink']) || strtolower(trim($links[0]['attribs']['']['isPermaLink'])) === 'true') { - return false; + $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0])); } } - // Parse the FNAME - if ($this->flags & 8) + $keys = array_keys($this->data['links']); + foreach ($keys as $key) { - // Get the length of the filename - $len = strcspn($this->compressed_data, "\x00", $this->position); - - // Check the length of the string is still valid - $this->min_compressed_size += $len + 1; - if ($this->compressed_size >= $this->min_compressed_size) + if ($this->registry->call('Misc', 'is_isegment_nz_nc', array($key))) { - // Set the original filename to the given string - $this->filename = substr($this->compressed_data, $this->position, $len); - $this->position += $len + 1; + if (isset($this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key])) + { + $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] = array_merge($this->data['links'][$key], $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]); + $this->data['links'][$key] =& $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]; + } + else + { + $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] =& $this->data['links'][$key]; + } } - else + elseif (substr($key, 0, 41) === SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY) { - return false; + $this->data['links'][substr($key, 41)] =& $this->data['links'][$key]; } + $this->data['links'][$key] = array_unique($this->data['links'][$key]); } - - // Parse the FCOMMENT - if ($this->flags & 16) - { - // Get the length of the comment - $len = strcspn($this->compressed_data, "\x00", $this->position); - - // Check the length of the string is still valid - $this->min_compressed_size += $len + 1; - if ($this->compressed_size >= $this->min_compressed_size) - { - // Set the original comment to the given string - $this->comment = substr($this->compressed_data, $this->position, $len); - $this->position += $len + 1; - } - else - { - return false; - } - } - - // Parse the FHCRC - if ($this->flags & 2) - { - // Check the length of the string is still valid - $this->min_compressed_size += $len + 2; - if ($this->compressed_size >= $this->min_compressed_size) - { - // Read the CRC - $crc = current(unpack('v', substr($this->compressed_data, $this->position, 2))); - - // Check the CRC matches - if ((crc32(substr($this->compressed_data, 0, $this->position)) & 0xFFFF) === $crc) - { - $this->position += 2; - } - else - { - return false; - } - } - else - { - return false; - } - } - - // Decompress the actual data - if (($this->data = gzinflate(substr($this->compressed_data, $this->position, -8))) === false) - { - return false; - } - else - { - $this->position = $this->compressed_size - 8; - } - - // Check CRC of data - $crc = current(unpack('V', substr($this->compressed_data, $this->position, 4))); - $this->position += 4; - /*if (extension_loaded('hash') && sprintf('%u', current(unpack('V', hash('crc32b', $this->data)))) !== sprintf('%u', $crc)) - { - return false; - }*/ - - // Check ISIZE of data - $isize = current(unpack('V', substr($this->compressed_data, $this->position, 4))); - $this->position += 4; - if (sprintf('%u', strlen($this->data) & 0xFFFFFFFF) !== sprintf('%u', $isize)) - { - return false; - } - - // Wow, against all odds, we've actually got a valid gzip string - return true; + } + if (isset($this->data['links'][$rel])) + { + return $this->data['links'][$rel]; } else { - return false; + return null; } } -} -class SimplePie_Cache -{ /** - * Don't call the constructor. Please. + * Get an enclosure from the item * - * @access private + * Supports the <enclosure> RSS tag, as well as Media RSS and iTunes RSS. + * + * @since Beta 2 + * @todo Add ability to prefer one type of content over another (in a media group). + * @param int $key The enclosure that you want to return. Remember that arrays begin with 0, not 1 + * @return SimplePie_Enclosure|null */ - function SimplePie_Cache() + public function get_enclosure($key = 0, $prefer = null) { - trigger_error('Please call SimplePie_Cache::create() instead of the constructor', E_USER_ERROR); + $enclosures = $this->get_enclosures(); + if (isset($enclosures[$key])) + { + return $enclosures[$key]; + } + else + { + return null; + } } /** - * Create a new SimplePie_Cache object + * Get all available enclosures (podcasts, etc.) * - * @static - * @access public + * Supports the <enclosure> RSS tag, as well as Media RSS and iTunes RSS. + * + * At this point, we're pretty much assuming that all enclosures for an item + * are the same content. Anything else is too complicated to + * properly support. + * + * @since Beta 2 + * @todo Add support for end-user defined sorting of enclosures by type/handler (so we can prefer the faster-loading FLV over MP4). + * @todo If an element exists at a level, but it's value is empty, we should fall back to the value from the parent (if it exists). + * @return array|null List of SimplePie_Enclosure items */ - function create($location, $filename, $extension) + public function get_enclosures() { - $location_iri = new SimplePie_IRI($location); - switch ($location_iri->get_scheme()) + if (!isset($this->data['enclosures'])) { - case 'mysql': - if (extension_loaded('mysql')) - { - return new SimplePie_Cache_MySQL($location_iri, $filename, $extension); - } - break; - - default: - return new SimplePie_Cache_File($location, $filename, $extension); - } - } -} - -class SimplePie_Cache_File -{ - var $location; - var $filename; - var $extension; - var $name; - - function SimplePie_Cache_File($location, $filename, $extension) - { - $this->location = $location; - $this->filename = $filename; - $this->extension = $extension; - $this->name = "$this->location/$this->filename.$this->extension"; - } + $this->data['enclosures'] = array(); - function save($data) - { - if (file_exists($this->name) && is_writeable($this->name) || file_exists($this->location) && is_writeable($this->location)) - { - if (is_a($data, 'SimplePie')) - { - $data = $data->data; - } + // Elements + $captions_parent = null; + $categories_parent = null; + $copyrights_parent = null; + $credits_parent = null; + $description_parent = null; + $duration_parent = null; + $hashes_parent = null; + $keywords_parent = null; + $player_parent = null; + $ratings_parent = null; + $restrictions_parent = null; + $thumbnails_parent = null; + $title_parent = null; - $data = serialize($data); + // Let's do the channel and item-level ones first, and just re-use them if we need to. + $parent = $this->get_feed(); - if (function_exists('file_put_contents')) + // CAPTIONS + if ($captions = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'text')) { - return (bool) file_put_contents($this->name, $data); + foreach ($captions as $caption) + { + $caption_type = null; + $caption_lang = null; + $caption_startTime = null; + $caption_endTime = null; + $caption_text = null; + if (isset($caption['attribs']['']['type'])) + { + $caption_type = $this->sanitize($caption['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($caption['attribs']['']['lang'])) + { + $caption_lang = $this->sanitize($caption['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($caption['attribs']['']['start'])) + { + $caption_startTime = $this->sanitize($caption['attribs']['']['start'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($caption['attribs']['']['end'])) + { + $caption_endTime = $this->sanitize($caption['attribs']['']['end'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($caption['data'])) + { + $caption_text = $this->sanitize($caption['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + $captions_parent[] = $this->registry->create('Caption', array($caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text)); + } } - else + elseif ($captions = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'text')) { - $fp = fopen($this->name, 'wb'); - if ($fp) + foreach ($captions as $caption) { - fwrite($fp, $data); - fclose($fp); - return true; + $caption_type = null; + $caption_lang = null; + $caption_startTime = null; + $caption_endTime = null; + $caption_text = null; + if (isset($caption['attribs']['']['type'])) + { + $caption_type = $this->sanitize($caption['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($caption['attribs']['']['lang'])) + { + $caption_lang = $this->sanitize($caption['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($caption['attribs']['']['start'])) + { + $caption_startTime = $this->sanitize($caption['attribs']['']['start'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($caption['attribs']['']['end'])) + { + $caption_endTime = $this->sanitize($caption['attribs']['']['end'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($caption['data'])) + { + $caption_text = $this->sanitize($caption['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + $captions_parent[] = $this->registry->create('Caption', array($caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text)); } } - } - return false; - } - - function load() - { - if (file_exists($this->name) && is_readable($this->name)) - { - return unserialize(file_get_contents($this->name)); - } - return false; - } - - function mtime() - { - if (file_exists($this->name)) - { - return filemtime($this->name); - } - return false; - } - - function touch() - { - if (file_exists($this->name)) - { - return touch($this->name); - } - return false; - } - - function unlink() - { - if (file_exists($this->name)) - { - return unlink($this->name); - } - return false; - } -} - -class SimplePie_Cache_DB -{ - function prepare_simplepie_object_for_cache($data) - { - $items = $data->get_items(); - $items_by_id = array(); - - if (!empty($items)) - { - foreach ($items as $item) + if (is_array($captions_parent)) { - $items_by_id[$item->get_id()] = $item; + $captions_parent = array_values(array_unique($captions_parent)); } - if (count($items_by_id) !== count($items)) + // CATEGORIES + foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'category') as $category) { - $items_by_id = array(); - foreach ($items as $item) + $term = null; + $scheme = null; + $label = null; + if (isset($category['data'])) { - $items_by_id[$item->get_id(true)] = $item; + $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT); } - } - - if (isset($data->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0])) - { - $channel =& $data->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]; - } - elseif (isset($data->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0])) - { - $channel =& $data->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]; - } - elseif (isset($data->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0])) - { - $channel =& $data->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]; - } - elseif (isset($data->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_20]['channel'][0])) - { - $channel =& $data->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_20]['channel'][0]; - } - else - { - $channel = null; - } - - if ($channel !== null) - { - if (isset($channel['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['entry'])) + if (isset($category['attribs']['']['scheme'])) { - unset($channel['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['entry']); + $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT); } - if (isset($channel['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['entry'])) + else { - unset($channel['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['entry']); + $scheme = 'http://search.yahoo.com/mrss/category_schema'; } - if (isset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_10]['item'])) + if (isset($category['attribs']['']['label'])) { - unset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_10]['item']); + $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT); } - if (isset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_090]['item'])) + $categories_parent[] = $this->registry->create('Category', array($term, $scheme, $label)); + } + foreach ((array) $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'category') as $category) + { + $term = null; + $scheme = null; + $label = null; + if (isset($category['data'])) { - unset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_090]['item']); + $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT); } - if (isset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_20]['item'])) + if (isset($category['attribs']['']['scheme'])) { - unset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_20]['item']); + $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT); } - } - if (isset($data->data['items'])) - { - unset($data->data['items']); - } - if (isset($data->data['ordered_items'])) - { - unset($data->data['ordered_items']); - } - } - return array(serialize($data->data), $items_by_id); - } -} - -class SimplePie_Cache_MySQL extends SimplePie_Cache_DB -{ - var $mysql; - var $options; - var $id; - - function SimplePie_Cache_MySQL($mysql_location, $name, $extension) - { - $host = $mysql_location->get_host(); - if (SimplePie_Misc::stripos($host, 'unix(') === 0 && substr($host, -1) === ')') - { - $server = ':' . substr($host, 5, -1); - } - else - { - $server = $host; - if ($mysql_location->get_port() !== null) - { - $server .= ':' . $mysql_location->get_port(); - } - } - - if (strpos($mysql_location->get_userinfo(), ':') !== false) - { - list($username, $password) = explode(':', $mysql_location->get_userinfo(), 2); - } - else - { - $username = $mysql_location->get_userinfo(); - $password = null; - } - - if ($this->mysql = mysql_connect($server, $username, $password)) - { - $this->id = $name . $extension; - $this->options = SimplePie_Misc::parse_str($mysql_location->get_query()); - if (!isset($this->options['prefix'][0])) - { - $this->options['prefix'][0] = ''; - } - - if (mysql_select_db(ltrim($mysql_location->get_path(), '/')) - && mysql_query('SET NAMES utf8') - && ($query = mysql_unbuffered_query('SHOW TABLES'))) - { - $db = array(); - while ($row = mysql_fetch_row($query)) + else { - $db[] = $row[0]; + $scheme = 'http://search.yahoo.com/mrss/category_schema'; } - - if (!in_array($this->options['prefix'][0] . 'cache_data', $db)) + if (isset($category['attribs']['']['label'])) { - if (!mysql_query('CREATE TABLE `' . $this->options['prefix'][0] . 'cache_data` (`id` TEXT CHARACTER SET utf8 NOT NULL, `items` SMALLINT NOT NULL DEFAULT 0, `data` BLOB NOT NULL, `mtime` INT UNSIGNED NOT NULL, UNIQUE (`id`(125)))')) - { - $this->mysql = null; - } + $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT); + } + $categories_parent[] = $this->registry->create('Category', array($term, $scheme, $label)); + } + foreach ((array) $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'category') as $category) + { + $term = null; + $scheme = 'http://www.itunes.com/dtds/podcast-1.0.dtd'; + $label = null; + if (isset($category['attribs']['']['text'])) + { + $label = $this->sanitize($category['attribs']['']['text'], SIMPLEPIE_CONSTRUCT_TEXT); } + $categories_parent[] = $this->registry->create('Category', array($term, $scheme, $label)); - if (!in_array($this->options['prefix'][0] . 'items', $db)) + if (isset($category['child'][SIMPLEPIE_NAMESPACE_ITUNES]['category'])) { - if (!mysql_query('CREATE TABLE `' . $this->options['prefix'][0] . 'items` (`feed_id` TEXT CHARACTER SET utf8 NOT NULL, `id` TEXT CHARACTER SET utf8 NOT NULL, `data` TEXT CHARACTER SET utf8 NOT NULL, `posted` INT UNSIGNED NOT NULL, INDEX `feed_id` (`feed_id`(125)))')) + foreach ((array) $category['child'][SIMPLEPIE_NAMESPACE_ITUNES]['category'] as $subcategory) { - $this->mysql = null; + if (isset($subcategory['attribs']['']['text'])) + { + $label = $this->sanitize($subcategory['attribs']['']['text'], SIMPLEPIE_CONSTRUCT_TEXT); + } + $categories_parent[] = $this->registry->create('Category', array($term, $scheme, $label)); } } } - else + if (is_array($categories_parent)) { - $this->mysql = null; + $categories_parent = array_values(array_unique($categories_parent)); } - } - } - - function save($data) - { - if ($this->mysql) - { - $feed_id = "'" . mysql_real_escape_string($this->id) . "'"; - if (is_a($data, 'SimplePie')) + // COPYRIGHT + if ($copyright = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'copyright')) { - if (SIMPLEPIE_PHP5) + $copyright_url = null; + $copyright_label = null; + if (isset($copyright[0]['attribs']['']['url'])) + { + $copyright_url = $this->sanitize($copyright[0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($copyright[0]['data'])) { - // This keyword needs to defy coding standards for PHP4 compatibility - $data = clone($data); + $copyright_label = $this->sanitize($copyright[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); } + $copyrights_parent = $this->registry->create('Copyright', array($copyright_url, $copyright_label)); + } + elseif ($copyright = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'copyright')) + { + $copyright_url = null; + $copyright_label = null; + if (isset($copyright[0]['attribs']['']['url'])) + { + $copyright_url = $this->sanitize($copyright[0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($copyright[0]['data'])) + { + $copyright_label = $this->sanitize($copyright[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + $copyrights_parent = $this->registry->create('Copyright', array($copyright_url, $copyright_label)); + } - $prepared = $this->prepare_simplepie_object_for_cache($data); - - if ($query = mysql_query('SELECT `id` FROM `' . $this->options['prefix'][0] . 'cache_data` WHERE `id` = ' . $feed_id, $this->mysql)) + // CREDITS + if ($credits = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'credit')) + { + foreach ($credits as $credit) { - if (mysql_num_rows($query)) + $credit_role = null; + $credit_scheme = null; + $credit_name = null; + if (isset($credit['attribs']['']['role'])) { - $items = count($prepared[1]); - if ($items) - { - $sql = 'UPDATE `' . $this->options['prefix'][0] . 'cache_data` SET `items` = ' . $items . ', `data` = \'' . mysql_real_escape_string($prepared[0]) . '\', `mtime` = ' . time() . ' WHERE `id` = ' . $feed_id; - } - else - { - $sql = 'UPDATE `' . $this->options['prefix'][0] . 'cache_data` SET `data` = \'' . mysql_real_escape_string($prepared[0]) . '\', `mtime` = ' . time() . ' WHERE `id` = ' . $feed_id; - } - - if (!mysql_query($sql, $this->mysql)) - { - return false; - } + $credit_role = $this->sanitize($credit['attribs']['']['role'], SIMPLEPIE_CONSTRUCT_TEXT); } - elseif (!mysql_query('INSERT INTO `' . $this->options['prefix'][0] . 'cache_data` (`id`, `items`, `data`, `mtime`) VALUES(' . $feed_id . ', ' . count($prepared[1]) . ', \'' . mysql_real_escape_string($prepared[0]) . '\', ' . time() . ')', $this->mysql)) + if (isset($credit['attribs']['']['scheme'])) { - return false; + $credit_scheme = $this->sanitize($credit['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT); } - - $ids = array_keys($prepared[1]); - if (!empty($ids)) + else { - foreach ($ids as $id) - { - $database_ids[] = mysql_real_escape_string($id); - } - - if ($query = mysql_unbuffered_query('SELECT `id` FROM `' . $this->options['prefix'][0] . 'items` WHERE `id` = \'' . implode('\' OR `id` = \'', $database_ids) . '\' AND `feed_id` = ' . $feed_id, $this->mysql)) - { - $existing_ids = array(); - while ($row = mysql_fetch_row($query)) - { - $existing_ids[] = $row[0]; - } - - $new_ids = array_diff($ids, $existing_ids); - - foreach ($new_ids as $new_id) - { - if (!($date = $prepared[1][$new_id]->get_date('U'))) - { - $date = time(); - } - - if (!mysql_query('INSERT INTO `' . $this->options['prefix'][0] . 'items` (`feed_id`, `id`, `data`, `posted`) VALUES(' . $feed_id . ', \'' . mysql_real_escape_string($new_id) . '\', \'' . mysql_real_escape_string(serialize($prepared[1][$new_id]->data)) . '\', ' . $date . ')', $this->mysql)) - { - return false; - } - } - return true; - } + $credit_scheme = 'urn:ebu'; } - else + if (isset($credit['data'])) { - return true; + $credit_name = $this->sanitize($credit['data'], SIMPLEPIE_CONSTRUCT_TEXT); } + $credits_parent[] = $this->registry->create('Credit', array($credit_role, $credit_scheme, $credit_name)); } } - elseif ($query = mysql_query('SELECT `id` FROM `' . $this->options['prefix'][0] . 'cache_data` WHERE `id` = ' . $feed_id, $this->mysql)) + elseif ($credits = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'credit')) { - if (mysql_num_rows($query)) + foreach ($credits as $credit) { - if (mysql_query('UPDATE `' . $this->options['prefix'][0] . 'cache_data` SET `items` = 0, `data` = \'' . mysql_real_escape_string(serialize($data)) . '\', `mtime` = ' . time() . ' WHERE `id` = ' . $feed_id, $this->mysql)) + $credit_role = null; + $credit_scheme = null; + $credit_name = null; + if (isset($credit['attribs']['']['role'])) { - return true; + $credit_role = $this->sanitize($credit['attribs']['']['role'], SIMPLEPIE_CONSTRUCT_TEXT); } + if (isset($credit['attribs']['']['scheme'])) + { + $credit_scheme = $this->sanitize($credit['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT); + } + else + { + $credit_scheme = 'urn:ebu'; + } + if (isset($credit['data'])) + { + $credit_name = $this->sanitize($credit['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + $credits_parent[] = $this->registry->create('Credit', array($credit_role, $credit_scheme, $credit_name)); } - elseif (mysql_query('INSERT INTO `' . $this->options['prefix'][0] . 'cache_data` (`id`, `items`, `data`, `mtime`) VALUES(\'' . mysql_real_escape_string($this->id) . '\', 0, \'' . mysql_real_escape_string(serialize($data)) . '\', ' . time() . ')', $this->mysql)) - { - return true; - } - } - } - return false; - } - - function load() - { - if ($this->mysql && ($query = mysql_query('SELECT `items`, `data` FROM `' . $this->options['prefix'][0] . 'cache_data` WHERE `id` = \'' . mysql_real_escape_string($this->id) . "'", $this->mysql)) && ($row = mysql_fetch_row($query))) - { - $data = unserialize($row[1]); - - if (isset($this->options['items'][0])) - { - $items = (int) $this->options['items'][0]; } - else + if (is_array($credits_parent)) { - $items = (int) $row[0]; + $credits_parent = array_values(array_unique($credits_parent)); } - if ($items !== 0) + // DESCRIPTION + if ($description_parent = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'description')) { - if (isset($data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0])) - { - $feed =& $data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]; - } - elseif (isset($data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0])) + if (isset($description_parent[0]['data'])) { - $feed =& $data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]; + $description_parent = $this->sanitize($description_parent[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); } - elseif (isset($data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0])) + } + elseif ($description_parent = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'description')) + { + if (isset($description_parent[0]['data'])) { - $feed =& $data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]; - } - elseif (isset($data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0])) - { - $feed =& $data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]; - } - else - { - $feed = null; + $description_parent = $this->sanitize($description_parent[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); } + } - if ($feed !== null) + // DURATION + if ($duration_parent = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'duration')) + { + $seconds = null; + $minutes = null; + $hours = null; + if (isset($duration_parent[0]['data'])) { - $sql = 'SELECT `data` FROM `' . $this->options['prefix'][0] . 'items` WHERE `feed_id` = \'' . mysql_real_escape_string($this->id) . '\' ORDER BY `posted` DESC'; - if ($items > 0) + $temp = explode(':', $this->sanitize($duration_parent[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT)); + if (sizeof($temp) > 0) { - $sql .= ' LIMIT ' . $items; + $seconds = (int) array_pop($temp); } - - if ($query = mysql_unbuffered_query($sql, $this->mysql)) + if (sizeof($temp) > 0) { - while ($row = mysql_fetch_row($query)) - { - $feed['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['entry'][] = unserialize($row[0]); - } + $minutes = (int) array_pop($temp); + $seconds += $minutes * 60; } - else + if (sizeof($temp) > 0) { - return false; + $hours = (int) array_pop($temp); + $seconds += $hours * 3600; } + unset($temp); + $duration_parent = $seconds; } } - return $data; - } - return false; - } - - function mtime() - { - if ($this->mysql && ($query = mysql_query('SELECT `mtime` FROM `' . $this->options['prefix'][0] . 'cache_data` WHERE `id` = \'' . mysql_real_escape_string($this->id) . "'", $this->mysql)) && ($row = mysql_fetch_row($query))) - { - return $row[0]; - } - else - { - return false; - } - } - - function touch() - { - if ($this->mysql && ($query = mysql_query('UPDATE `' . $this->options['prefix'][0] . 'cache_data` SET `mtime` = ' . time() . ' WHERE `id` = \'' . mysql_real_escape_string($this->id) . "'", $this->mysql)) && mysql_affected_rows($this->mysql)) - { - return true; - } - else - { - return false; - } - } - - function unlink() - { - if ($this->mysql && ($query = mysql_query('DELETE FROM `' . $this->options['prefix'][0] . 'cache_data` WHERE `id` = \'' . mysql_real_escape_string($this->id) . "'", $this->mysql)) && ($query2 = mysql_query('DELETE FROM `' . $this->options['prefix'][0] . 'items` WHERE `feed_id` = \'' . mysql_real_escape_string($this->id) . "'", $this->mysql))) - { - return true; - } - else - { - return false; - } - } -} - -class SimplePie_Misc -{ - function time_hms($seconds) - { - $time = ''; - - $hours = floor($seconds / 3600); - $remainder = $seconds % 3600; - if ($hours > 0) - { - $time .= $hours.':'; - } - - $minutes = floor($remainder / 60); - $seconds = $remainder % 60; - if ($minutes < 10 && $hours > 0) - { - $minutes = '0' . $minutes; - } - if ($seconds < 10) - { - $seconds = '0' . $seconds; - } - - $time .= $minutes.':'; - $time .= $seconds; - - return $time; - } - function absolutize_url($relative, $base) - { - $iri = SimplePie_IRI::absolutize(new SimplePie_IRI($base), $relative); - return $iri->get_iri(); - } - - function remove_dot_segments($input) - { - $output = ''; - while (strpos($input, './') !== false || strpos($input, '/.') !== false || $input === '.' || $input === '..') - { - // A: If the input buffer begins with a prefix of "../" or "./", then remove that prefix from the input buffer; otherwise, - if (strpos($input, '../') === 0) - { - $input = substr($input, 3); - } - elseif (strpos($input, './') === 0) + // HASHES + if ($hashes_iterator = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'hash')) { - $input = substr($input, 2); + foreach ($hashes_iterator as $hash) + { + $value = null; + $algo = null; + if (isset($hash['data'])) + { + $value = $this->sanitize($hash['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($hash['attribs']['']['algo'])) + { + $algo = $this->sanitize($hash['attribs']['']['algo'], SIMPLEPIE_CONSTRUCT_TEXT); + } + else + { + $algo = 'md5'; + } + $hashes_parent[] = $algo.':'.$value; + } } - // B: if the input buffer begins with a prefix of "/./" or "/.", where "." is a complete path segment, then replace that prefix with "/" in the input buffer; otherwise, - elseif (strpos($input, '/./') === 0) + elseif ($hashes_iterator = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'hash')) { - $input = substr_replace($input, '/', 0, 3); + foreach ($hashes_iterator as $hash) + { + $value = null; + $algo = null; + if (isset($hash['data'])) + { + $value = $this->sanitize($hash['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($hash['attribs']['']['algo'])) + { + $algo = $this->sanitize($hash['attribs']['']['algo'], SIMPLEPIE_CONSTRUCT_TEXT); + } + else + { + $algo = 'md5'; + } + $hashes_parent[] = $algo.':'.$value; + } } - elseif ($input === '/.') + if (is_array($hashes_parent)) { - $input = '/'; + $hashes_parent = array_values(array_unique($hashes_parent)); } - // C: if the input buffer begins with a prefix of "/../" or "/..", where ".." is a complete path segment, then replace that prefix with "/" in the input buffer and remove the last segment and its preceding "/" (if any) from the output buffer; otherwise, - elseif (strpos($input, '/../') === 0) + + // KEYWORDS + if ($keywords = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'keywords')) { - $input = substr_replace($input, '/', 0, 4); - $output = substr_replace($output, '', strrpos($output, '/')); + if (isset($keywords[0]['data'])) + { + $temp = explode(',', $this->sanitize($keywords[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT)); + foreach ($temp as $word) + { + $keywords_parent[] = trim($word); + } + } + unset($temp); } - elseif ($input === '/..') + elseif ($keywords = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'keywords')) { - $input = '/'; - $output = substr_replace($output, '', strrpos($output, '/')); + if (isset($keywords[0]['data'])) + { + $temp = explode(',', $this->sanitize($keywords[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT)); + foreach ($temp as $word) + { + $keywords_parent[] = trim($word); + } + } + unset($temp); } - // D: if the input buffer consists only of "." or "..", then remove that from the input buffer; otherwise, - elseif ($input === '.' || $input === '..') + elseif ($keywords = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'keywords')) { - $input = ''; + if (isset($keywords[0]['data'])) + { + $temp = explode(',', $this->sanitize($keywords[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT)); + foreach ($temp as $word) + { + $keywords_parent[] = trim($word); + } + } + unset($temp); } - // E: move the first path segment in the input buffer to the end of the output buffer, including the initial "/" character (if any) and any subsequent characters up to, but not including, the next "/" character or the end of the input buffer - elseif (($pos = strpos($input, '/', 1)) !== false) + elseif ($keywords = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'keywords')) { - $output .= substr($input, 0, $pos); - $input = substr_replace($input, '', 0, $pos); + if (isset($keywords[0]['data'])) + { + $temp = explode(',', $this->sanitize($keywords[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT)); + foreach ($temp as $word) + { + $keywords_parent[] = trim($word); + } + } + unset($temp); } - else + if (is_array($keywords_parent)) { - $output .= $input; - $input = ''; + $keywords_parent = array_values(array_unique($keywords_parent)); } - } - return $output . $input; - } - function get_element($realname, $string) - { - $return = array(); - $name = preg_quote($realname, '/'); - if (preg_match_all("/<($name)" . SIMPLEPIE_PCRE_HTML_ATTRIBUTE . "(>(.*)<\/$name>|(\/)?>)/siU", $string, $matches, PREG_SET_ORDER | PREG_OFFSET_CAPTURE)) - { - for ($i = 0, $total_matches = count($matches); $i < $total_matches; $i++) + // PLAYER + if ($player_parent = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'player')) { - $return[$i]['tag'] = $realname; - $return[$i]['full'] = $matches[$i][0][0]; - $return[$i]['offset'] = $matches[$i][0][1]; - if (strlen($matches[$i][3][0]) <= 2) - { - $return[$i]['self_closing'] = true; - } - else + if (isset($player_parent[0]['attribs']['']['url'])) { - $return[$i]['self_closing'] = false; - $return[$i]['content'] = $matches[$i][4][0]; + $player_parent = $this->sanitize($player_parent[0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI); } - $return[$i]['attribs'] = array(); - if (isset($matches[$i][2][0]) && preg_match_all('/[\x09\x0A\x0B\x0C\x0D\x20]+([^\x09\x0A\x0B\x0C\x0D\x20\x2F\x3E][^\x09\x0A\x0B\x0C\x0D\x20\x2F\x3D\x3E]*)(?:[\x09\x0A\x0B\x0C\x0D\x20]*=[\x09\x0A\x0B\x0C\x0D\x20]*(?:"([^"]*)"|\'([^\']*)\'|([^\x09\x0A\x0B\x0C\x0D\x20\x22\x27\x3E][^\x09\x0A\x0B\x0C\x0D\x20\x3E]*)?))?/', ' ' . $matches[$i][2][0] . ' ', $attribs, PREG_SET_ORDER)) + } + elseif ($player_parent = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'player')) + { + if (isset($player_parent[0]['attribs']['']['url'])) { - for ($j = 0, $total_attribs = count($attribs); $j < $total_attribs; $j++) - { - if (count($attribs[$j]) === 2) - { - $attribs[$j][2] = $attribs[$j][1]; - } - $return[$i]['attribs'][strtolower($attribs[$j][1])]['data'] = SimplePie_Misc::entities_decode(end($attribs[$j]), 'UTF-8'); - } + $player_parent = $this->sanitize($player_parent[0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI); } } - } - return $return; - } - function element_implode($element) - { - $full = "<$element[tag]"; - foreach ($element['attribs'] as $key => $value) - { - $key = strtolower($key); - $full .= " $key=\"" . htmlspecialchars($value['data']) . '"'; - } - if ($element['self_closing']) - { - $full .= ' />'; - } - else - { - $full .= ">$element[content]</$element[tag]>"; - } - return $full; - } - - function error($message, $level, $file, $line) - { - if ((ini_get('error_reporting') & $level) > 0) - { - switch ($level) + // RATINGS + if ($ratings = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'rating')) { - case E_USER_ERROR: - $note = 'PHP Error'; - break; - case E_USER_WARNING: - $note = 'PHP Warning'; - break; - case E_USER_NOTICE: - $note = 'PHP Notice'; - break; - default: - $note = 'Unknown Error'; - break; + foreach ($ratings as $rating) + { + $rating_scheme = null; + $rating_value = null; + if (isset($rating['attribs']['']['scheme'])) + { + $rating_scheme = $this->sanitize($rating['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT); + } + else + { + $rating_scheme = 'urn:simple'; + } + if (isset($rating['data'])) + { + $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + $ratings_parent[] = $this->registry->create('Rating', array($rating_scheme, $rating_value)); + } } - - $log_error = true; - if (!function_exists('error_log')) + elseif ($ratings = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'explicit')) { - $log_error = false; + foreach ($ratings as $rating) + { + $rating_scheme = 'urn:itunes'; + $rating_value = null; + if (isset($rating['data'])) + { + $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + $ratings_parent[] = $this->registry->create('Rating', array($rating_scheme, $rating_value)); + } } - - $log_file = @ini_get('error_log'); - if (!empty($log_file) && ('syslog' != $log_file) && !@is_writable($log_file)) + elseif ($ratings = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'rating')) { - $log_error = false; + foreach ($ratings as $rating) + { + $rating_scheme = null; + $rating_value = null; + if (isset($rating['attribs']['']['scheme'])) + { + $rating_scheme = $this->sanitize($rating['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT); + } + else + { + $rating_scheme = 'urn:simple'; + } + if (isset($rating['data'])) + { + $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + $ratings_parent[] = $this->registry->create('Rating', array($rating_scheme, $rating_value)); + } } - - if ($log_error) + elseif ($ratings = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'explicit')) { - @error_log("$note: $message in $file on line $line", 0); + foreach ($ratings as $rating) + { + $rating_scheme = 'urn:itunes'; + $rating_value = null; + if (isset($rating['data'])) + { + $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + $ratings_parent[] = $this->registry->create('Rating', array($rating_scheme, $rating_value)); + } + } + if (is_array($ratings_parent)) + { + $ratings_parent = array_values(array_unique($ratings_parent)); } - } - - return $message; - } - - /** - * If a file has been cached, retrieve and display it. - * - * This is most useful for caching images (get_favicon(), etc.), - * however it works for all cached files. This WILL NOT display ANY - * file/image/page/whatever, but rather only display what has already - * been cached by SimplePie. - * - * @access public - * @see SimplePie::get_favicon() - * @param str $identifier_url URL that is used to identify the content. - * This may or may not be the actual URL of the live content. - * @param str $cache_location Location of SimplePie's cache. Defaults - * to './cache'. - * @param str $cache_extension The file extension that the file was - * cached with. Defaults to 'spc'. - * @param str $cache_class Name of the cache-handling class being used - * in SimplePie. Defaults to 'SimplePie_Cache', and should be left - * as-is unless you've overloaded the class. - * @param str $cache_name_function Obsolete. Exists for backwards - * compatibility reasons only. - */ - function display_cached_file($identifier_url, $cache_location = './cache', $cache_extension = 'spc', $cache_class = 'SimplePie_Cache', $cache_name_function = 'md5') - { - $cache = call_user_func(array($cache_class, 'create'), $cache_location, $identifier_url, $cache_extension); - if ($file = $cache->load()) - { - if (isset($file['headers']['content-type'])) + // RESTRICTIONS + if ($restrictions = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'restriction')) + { + foreach ($restrictions as $restriction) + { + $restriction_relationship = null; + $restriction_type = null; + $restriction_value = null; + if (isset($restriction['attribs']['']['relationship'])) + { + $restriction_relationship = $this->sanitize($restriction['attribs']['']['relationship'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($restriction['attribs']['']['type'])) + { + $restriction_type = $this->sanitize($restriction['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($restriction['data'])) + { + $restriction_value = $this->sanitize($restriction['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + $restrictions_parent[] = $this->registry->create('Restriction', array($restriction_relationship, $restriction_type, $restriction_value)); + } + } + elseif ($restrictions = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'block')) + { + foreach ($restrictions as $restriction) + { + $restriction_relationship = 'allow'; + $restriction_type = null; + $restriction_value = 'itunes'; + if (isset($restriction['data']) && strtolower($restriction['data']) === 'yes') + { + $restriction_relationship = 'deny'; + } + $restrictions_parent[] = $this->registry->create('Restriction', array($restriction_relationship, $restriction_type, $restriction_value)); + } + } + elseif ($restrictions = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'restriction')) + { + foreach ($restrictions as $restriction) + { + $restriction_relationship = null; + $restriction_type = null; + $restriction_value = null; + if (isset($restriction['attribs']['']['relationship'])) + { + $restriction_relationship = $this->sanitize($restriction['attribs']['']['relationship'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($restriction['attribs']['']['type'])) + { + $restriction_type = $this->sanitize($restriction['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($restriction['data'])) + { + $restriction_value = $this->sanitize($restriction['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + $restrictions_parent[] = $this->registry->create('Restriction', array($restriction_relationship, $restriction_type, $restriction_value)); + } + } + elseif ($restrictions = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'block')) + { + foreach ($restrictions as $restriction) + { + $restriction_relationship = 'allow'; + $restriction_type = null; + $restriction_value = 'itunes'; + if (isset($restriction['data']) && strtolower($restriction['data']) === 'yes') + { + $restriction_relationship = 'deny'; + } + $restrictions_parent[] = $this->registry->create('Restriction', array($restriction_relationship, $restriction_type, $restriction_value)); + } + } + if (is_array($restrictions_parent)) { - header('Content-type:' . $file['headers']['content-type']); + $restrictions_parent = array_values(array_unique($restrictions_parent)); } else { - header('Content-type: application/octet-stream'); + $restrictions_parent = array(new SimplePie_Restriction('allow', null, 'default')); } - header('Expires: ' . gmdate('D, d M Y H:i:s', time() + 604800) . ' GMT'); // 7 days - echo $file['body']; - exit; - } - - die('Cached file for ' . $identifier_url . ' cannot be found.'); - } - function fix_protocol($url, $http = 1) - { - $url = SimplePie_Misc::normalize_url($url); - $parsed = SimplePie_Misc::parse_url($url); - if ($parsed['scheme'] !== '' && $parsed['scheme'] !== 'http' && $parsed['scheme'] !== 'https') - { - return SimplePie_Misc::fix_protocol(SimplePie_Misc::compress_parse_url('http', $parsed['authority'], $parsed['path'], $parsed['query'], $parsed['fragment']), $http); - } + // THUMBNAILS + if ($thumbnails = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'thumbnail')) + { + foreach ($thumbnails as $thumbnail) + { + if (isset($thumbnail['attribs']['']['url'])) + { + $thumbnails_parent[] = $this->sanitize($thumbnail['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI); + } + } + } + elseif ($thumbnails = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'thumbnail')) + { + foreach ($thumbnails as $thumbnail) + { + if (isset($thumbnail['attribs']['']['url'])) + { + $thumbnails_parent[] = $this->sanitize($thumbnail['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI); + } + } + } - if ($parsed['scheme'] === '' && $parsed['authority'] === '' && !file_exists($url)) - { - return SimplePie_Misc::fix_protocol(SimplePie_Misc::compress_parse_url('http', $parsed['path'], '', $parsed['query'], $parsed['fragment']), $http); - } + // TITLES + if ($title_parent = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'title')) + { + if (isset($title_parent[0]['data'])) + { + $title_parent = $this->sanitize($title_parent[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + } + elseif ($title_parent = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'title')) + { + if (isset($title_parent[0]['data'])) + { + $title_parent = $this->sanitize($title_parent[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + } - if ($http === 2 && $parsed['scheme'] !== '') - { - return "feed:$url"; - } - elseif ($http === 3 && strtolower($parsed['scheme']) === 'http') - { - return substr_replace($url, 'podcast', 0, 4); - } - elseif ($http === 4 && strtolower($parsed['scheme']) === 'http') - { - return substr_replace($url, 'itpc', 0, 4); - } - else - { - return $url; - } - } + // Clear the memory + unset($parent); - function parse_url($url) - { - $iri = new SimplePie_IRI($url); - return array( - 'scheme' => (string) $iri->get_scheme(), - 'authority' => (string) $iri->get_authority(), - 'path' => (string) $iri->get_path(), - 'query' => (string) $iri->get_query(), - 'fragment' => (string) $iri->get_fragment() - ); - } - - function compress_parse_url($scheme = '', $authority = '', $path = '', $query = '', $fragment = '') - { - $iri = new SimplePie_IRI(''); - $iri->set_scheme($scheme); - $iri->set_authority($authority); - $iri->set_path($path); - $iri->set_query($query); - $iri->set_fragment($fragment); - return $iri->get_iri(); - } - - function normalize_url($url) - { - $iri = new SimplePie_IRI($url); - return $iri->get_iri(); - } - - function percent_encoding_normalization($match) - { - $integer = hexdec($match[1]); - if ($integer >= 0x41 && $integer <= 0x5A || $integer >= 0x61 && $integer <= 0x7A || $integer >= 0x30 && $integer <= 0x39 || $integer === 0x2D || $integer === 0x2E || $integer === 0x5F || $integer === 0x7E) - { - return chr($integer); - } - else - { - return strtoupper($match[0]); - } - } - - /** - * Remove bad UTF-8 bytes - * - * PCRE Pattern to locate bad bytes in a UTF-8 string comes from W3C - * FAQ: Multilingual Forms (modified to include full ASCII range) - * - * @author Geoffrey Sneddon - * @see http://www.w3.org/International/questions/qa-forms-utf-8 - * @param string $str String to remove bad UTF-8 bytes from - * @return string UTF-8 string - */ - function utf8_bad_replace($str) - { - if (function_exists('iconv') && ($return = @iconv('UTF-8', 'UTF-8//IGNORE', $str))) - { - return $return; - } - elseif (function_exists('mb_convert_encoding') && ($return = @mb_convert_encoding($str, 'UTF-8', 'UTF-8'))) - { - return $return; - } - elseif (preg_match_all('/(?:[\x00-\x7F]|[\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})+/', $str, $matches)) - { - return implode("\xEF\xBF\xBD", $matches[0]); - } - elseif ($str !== '') - { - return "\xEF\xBF\xBD"; - } - else - { - return ''; - } - } - - /** - * Converts a Windows-1252 encoded string to a UTF-8 encoded string - * - * @static - * @access public - * @param string $string Windows-1252 encoded string - * @return string UTF-8 encoded string - */ - function windows_1252_to_utf8($string) - { - static $convert_table = array("\x80" => "\xE2\x82\xAC", "\x81" => "\xEF\xBF\xBD", "\x82" => "\xE2\x80\x9A", "\x83" => "\xC6\x92", "\x84" => "\xE2\x80\x9E", "\x85" => "\xE2\x80\xA6", "\x86" => "\xE2\x80\xA0", "\x87" => "\xE2\x80\xA1", "\x88" => "\xCB\x86", "\x89" => "\xE2\x80\xB0", "\x8A" => "\xC5\xA0", "\x8B" => "\xE2\x80\xB9", "\x8C" => "\xC5\x92", "\x8D" => "\xEF\xBF\xBD", "\x8E" => "\xC5\xBD", "\x8F" => "\xEF\xBF\xBD", "\x90" => "\xEF\xBF\xBD", "\x91" => "\xE2\x80\x98", "\x92" => "\xE2\x80\x99", "\x93" => "\xE2\x80\x9C", "\x94" => "\xE2\x80\x9D", "\x95" => "\xE2\x80\xA2", "\x96" => "\xE2\x80\x93", "\x97" => "\xE2\x80\x94", "\x98" => "\xCB\x9C", "\x99" => "\xE2\x84\xA2", "\x9A" => "\xC5\xA1", "\x9B" => "\xE2\x80\xBA", "\x9C" => "\xC5\x93", "\x9D" => "\xEF\xBF\xBD", "\x9E" => "\xC5\xBE", "\x9F" => "\xC5\xB8", "\xA0" => "\xC2\xA0", "\xA1" => "\xC2\xA1", "\xA2" => "\xC2\xA2", "\xA3" => "\xC2\xA3", "\xA4" => "\xC2\xA4", "\xA5" => "\xC2\xA5", "\xA6" => "\xC2\xA6", "\xA7" => "\xC2\xA7", "\xA8" => "\xC2\xA8", "\xA9" => "\xC2\xA9", "\xAA" => "\xC2\xAA", "\xAB" => "\xC2\xAB", "\xAC" => "\xC2\xAC", "\xAD" => "\xC2\xAD", "\xAE" => "\xC2\xAE", "\xAF" => "\xC2\xAF", "\xB0" => "\xC2\xB0", "\xB1" => "\xC2\xB1", "\xB2" => "\xC2\xB2", "\xB3" => "\xC2\xB3", "\xB4" => "\xC2\xB4", "\xB5" => "\xC2\xB5", "\xB6" => "\xC2\xB6", "\xB7" => "\xC2\xB7", "\xB8" => "\xC2\xB8", "\xB9" => "\xC2\xB9", "\xBA" => "\xC2\xBA", "\xBB" => "\xC2\xBB", "\xBC" => "\xC2\xBC", "\xBD" => "\xC2\xBD", "\xBE" => "\xC2\xBE", "\xBF" => "\xC2\xBF", "\xC0" => "\xC3\x80", "\xC1" => "\xC3\x81", "\xC2" => "\xC3\x82", "\xC3" => "\xC3\x83", "\xC4" => "\xC3\x84", "\xC5" => "\xC3\x85", "\xC6" => "\xC3\x86", "\xC7" => "\xC3\x87", "\xC8" => "\xC3\x88", "\xC9" => "\xC3\x89", "\xCA" => "\xC3\x8A", "\xCB" => "\xC3\x8B", "\xCC" => "\xC3\x8C", "\xCD" => "\xC3\x8D", "\xCE" => "\xC3\x8E", "\xCF" => "\xC3\x8F", "\xD0" => "\xC3\x90", "\xD1" => "\xC3\x91", "\xD2" => "\xC3\x92", "\xD3" => "\xC3\x93", "\xD4" => "\xC3\x94", "\xD5" => "\xC3\x95", "\xD6" => "\xC3\x96", "\xD7" => "\xC3\x97", "\xD8" => "\xC3\x98", "\xD9" => "\xC3\x99", "\xDA" => "\xC3\x9A", "\xDB" => "\xC3\x9B", "\xDC" => "\xC3\x9C", "\xDD" => "\xC3\x9D", "\xDE" => "\xC3\x9E", "\xDF" => "\xC3\x9F", "\xE0" => "\xC3\xA0", "\xE1" => "\xC3\xA1", "\xE2" => "\xC3\xA2", "\xE3" => "\xC3\xA3", "\xE4" => "\xC3\xA4", "\xE5" => "\xC3\xA5", "\xE6" => "\xC3\xA6", "\xE7" => "\xC3\xA7", "\xE8" => "\xC3\xA8", "\xE9" => "\xC3\xA9", "\xEA" => "\xC3\xAA", "\xEB" => "\xC3\xAB", "\xEC" => "\xC3\xAC", "\xED" => "\xC3\xAD", "\xEE" => "\xC3\xAE", "\xEF" => "\xC3\xAF", "\xF0" => "\xC3\xB0", "\xF1" => "\xC3\xB1", "\xF2" => "\xC3\xB2", "\xF3" => "\xC3\xB3", "\xF4" => "\xC3\xB4", "\xF5" => "\xC3\xB5", "\xF6" => "\xC3\xB6", "\xF7" => "\xC3\xB7", "\xF8" => "\xC3\xB8", "\xF9" => "\xC3\xB9", "\xFA" => "\xC3\xBA", "\xFB" => "\xC3\xBB", "\xFC" => "\xC3\xBC", "\xFD" => "\xC3\xBD", "\xFE" => "\xC3\xBE", "\xFF" => "\xC3\xBF"); - - return strtr($string, $convert_table); - } + // Attributes + $bitrate = null; + $channels = null; + $duration = null; + $expression = null; + $framerate = null; + $height = null; + $javascript = null; + $lang = null; + $length = null; + $medium = null; + $samplingrate = null; + $type = null; + $url = null; + $width = null; - function change_encoding($data, $input, $output) - { - $input = SimplePie_Misc::encoding($input); - $output = SimplePie_Misc::encoding($output); + // Elements + $captions = null; + $categories = null; + $copyrights = null; + $credits = null; + $description = null; + $hashes = null; + $keywords = null; + $player = null; + $ratings = null; + $restrictions = null; + $thumbnails = null; + $title = null; - // We fail to fail on non US-ASCII bytes - if ($input === 'US-ASCII') - { - static $non_ascii_octects = ''; - if (!$non_ascii_octects) + // If we have media:group tags, loop through them. + foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'group') as $group) { - for ($i = 0x80; $i <= 0xFF; $i++) + if(isset($group['child']) && isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['content'])) { - $non_ascii_octects .= chr($i); - } - } - $data = substr($data, 0, strcspn($data, $non_ascii_octects)); - } - - // This is first, as behaviour of this is completely predictable - if ($input === 'windows-1252' && $output === 'UTF-8') - { - return SimplePie_Misc::windows_1252_to_utf8($data); - } - // This is second, as behaviour of this varies only with PHP version (the middle part of this expression checks the encoding is supported). - elseif (function_exists('mb_convert_encoding') && @mb_convert_encoding("\x80", 'UTF-16BE', $input) !== "\x00\x80" && in_array($input, mb_list_encodings()) && ($return = @mb_convert_encoding($data, $output, $input))) - { - return $return; - } - // This is last, as behaviour of this varies with OS userland and PHP version - elseif (function_exists('iconv') && ($return = @iconv($input, $output, $data))) - { - return $return; - } - // If we can't do anything, just fail - else - { - return false; - } - } - - /** - * Normalize an encoding name - * - * This is automatically generated by create.php - * - * To generate it, run `php create.php` on the command line, and copy the - * output to replace this function. - * - * @param string $charset Character set to standardise - * @return string Standardised name - */ - function encoding($charset) - { - // Normalization from UTS #22 - switch (strtolower(preg_replace('/(?:[^a-zA-Z0-9]+|([^0-9])0+)/', '\1', $charset))) - { - case 'adobestandardencoding': - case 'csadobestandardencoding': - return 'Adobe-Standard-Encoding'; - - case 'adobesymbolencoding': - case 'cshppsmath': - return 'Adobe-Symbol-Encoding'; - - case 'ami1251': - case 'amiga1251': - return 'Amiga-1251'; + // If we have media:content tags, loop through them. + foreach ((array) $group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['content'] as $content) + { + if (isset($content['attribs']['']['url'])) + { + // Attributes + $bitrate = null; + $channels = null; + $duration = null; + $expression = null; + $framerate = null; + $height = null; + $javascript = null; + $lang = null; + $length = null; + $medium = null; + $samplingrate = null; + $type = null; + $url = null; + $width = null; - case 'ansix31101983': - case 'csat5001983': - case 'csiso99naplps': - case 'isoir99': - case 'naplps': - return 'ANSI_X3.110-1983'; + // Elements + $captions = null; + $categories = null; + $copyrights = null; + $credits = null; + $description = null; + $hashes = null; + $keywords = null; + $player = null; + $ratings = null; + $restrictions = null; + $thumbnails = null; + $title = null; - case 'arabic7': - case 'asmo449': - case 'csiso89asmo449': - case 'iso9036': - case 'isoir89': - return 'ASMO_449'; + // Start checking the attributes of media:content + if (isset($content['attribs']['']['bitrate'])) + { + $bitrate = $this->sanitize($content['attribs']['']['bitrate'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($content['attribs']['']['channels'])) + { + $channels = $this->sanitize($content['attribs']['']['channels'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($content['attribs']['']['duration'])) + { + $duration = $this->sanitize($content['attribs']['']['duration'], SIMPLEPIE_CONSTRUCT_TEXT); + } + else + { + $duration = $duration_parent; + } + if (isset($content['attribs']['']['expression'])) + { + $expression = $this->sanitize($content['attribs']['']['expression'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($content['attribs']['']['framerate'])) + { + $framerate = $this->sanitize($content['attribs']['']['framerate'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($content['attribs']['']['height'])) + { + $height = $this->sanitize($content['attribs']['']['height'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($content['attribs']['']['lang'])) + { + $lang = $this->sanitize($content['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($content['attribs']['']['fileSize'])) + { + $length = ceil($content['attribs']['']['fileSize']); + } + if (isset($content['attribs']['']['medium'])) + { + $medium = $this->sanitize($content['attribs']['']['medium'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($content['attribs']['']['samplingrate'])) + { + $samplingrate = $this->sanitize($content['attribs']['']['samplingrate'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($content['attribs']['']['type'])) + { + $type = $this->sanitize($content['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($content['attribs']['']['width'])) + { + $width = $this->sanitize($content['attribs']['']['width'], SIMPLEPIE_CONSTRUCT_TEXT); + } + $url = $this->sanitize($content['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI); - case 'big5': - case 'csbig5': - return 'Big5'; + // Checking the other optional media: elements. Priority: media:content, media:group, item, channel - case 'big5hkscs': - return 'Big5-HKSCS'; + // CAPTIONS + if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text'])) + { + foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text'] as $caption) + { + $caption_type = null; + $caption_lang = null; + $caption_startTime = null; + $caption_endTime = null; + $caption_text = null; + if (isset($caption['attribs']['']['type'])) + { + $caption_type = $this->sanitize($caption['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($caption['attribs']['']['lang'])) + { + $caption_lang = $this->sanitize($caption['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($caption['attribs']['']['start'])) + { + $caption_startTime = $this->sanitize($caption['attribs']['']['start'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($caption['attribs']['']['end'])) + { + $caption_endTime = $this->sanitize($caption['attribs']['']['end'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($caption['data'])) + { + $caption_text = $this->sanitize($caption['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + $captions[] = $this->registry->create('Caption', array($caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text)); + } + if (is_array($captions)) + { + $captions = array_values(array_unique($captions)); + } + } + elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text'])) + { + foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text'] as $caption) + { + $caption_type = null; + $caption_lang = null; + $caption_startTime = null; + $caption_endTime = null; + $caption_text = null; + if (isset($caption['attribs']['']['type'])) + { + $caption_type = $this->sanitize($caption['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($caption['attribs']['']['lang'])) + { + $caption_lang = $this->sanitize($caption['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($caption['attribs']['']['start'])) + { + $caption_startTime = $this->sanitize($caption['attribs']['']['start'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($caption['attribs']['']['end'])) + { + $caption_endTime = $this->sanitize($caption['attribs']['']['end'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($caption['data'])) + { + $caption_text = $this->sanitize($caption['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + $captions[] = $this->registry->create('Caption', array($caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text)); + } + if (is_array($captions)) + { + $captions = array_values(array_unique($captions)); + } + } + else + { + $captions = $captions_parent; + } - case 'bocu1': - case 'csbocu1': - return 'BOCU-1'; + // CATEGORIES + if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category'])) + { + foreach ((array) $content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category'] as $category) + { + $term = null; + $scheme = null; + $label = null; + if (isset($category['data'])) + { + $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($category['attribs']['']['scheme'])) + { + $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT); + } + else + { + $scheme = 'http://search.yahoo.com/mrss/category_schema'; + } + if (isset($category['attribs']['']['label'])) + { + $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT); + } + $categories[] = $this->registry->create('Category', array($term, $scheme, $label)); + } + } + if (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category'])) + { + foreach ((array) $group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category'] as $category) + { + $term = null; + $scheme = null; + $label = null; + if (isset($category['data'])) + { + $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($category['attribs']['']['scheme'])) + { + $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT); + } + else + { + $scheme = 'http://search.yahoo.com/mrss/category_schema'; + } + if (isset($category['attribs']['']['label'])) + { + $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT); + } + $categories[] = $this->registry->create('Category', array($term, $scheme, $label)); + } + } + if (is_array($categories) && is_array($categories_parent)) + { + $categories = array_values(array_unique(array_merge($categories, $categories_parent))); + } + elseif (is_array($categories)) + { + $categories = array_values(array_unique($categories)); + } + elseif (is_array($categories_parent)) + { + $categories = array_values(array_unique($categories_parent)); + } - case 'brf': - case 'csbrf': - return 'BRF'; + // COPYRIGHTS + if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'])) + { + $copyright_url = null; + $copyright_label = null; + if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url'])) + { + $copyright_url = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data'])) + { + $copyright_label = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + $copyrights = $this->registry->create('Copyright', array($copyright_url, $copyright_label)); + } + elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'])) + { + $copyright_url = null; + $copyright_label = null; + if (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url'])) + { + $copyright_url = $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data'])) + { + $copyright_label = $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + $copyrights = $this->registry->create('Copyright', array($copyright_url, $copyright_label)); + } + else + { + $copyrights = $copyrights_parent; + } - case 'bs4730': - case 'csiso4unitedkingdom': - case 'gb': - case 'iso646gb': - case 'isoir4': - case 'uk': - return 'BS_4730'; + // CREDITS + if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit'])) + { + foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit'] as $credit) + { + $credit_role = null; + $credit_scheme = null; + $credit_name = null; + if (isset($credit['attribs']['']['role'])) + { + $credit_role = $this->sanitize($credit['attribs']['']['role'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($credit['attribs']['']['scheme'])) + { + $credit_scheme = $this->sanitize($credit['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT); + } + else + { + $credit_scheme = 'urn:ebu'; + } + if (isset($credit['data'])) + { + $credit_name = $this->sanitize($credit['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + $credits[] = $this->registry->create('Credit', array($credit_role, $credit_scheme, $credit_name)); + } + if (is_array($credits)) + { + $credits = array_values(array_unique($credits)); + } + } + elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit'])) + { + foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit'] as $credit) + { + $credit_role = null; + $credit_scheme = null; + $credit_name = null; + if (isset($credit['attribs']['']['role'])) + { + $credit_role = $this->sanitize($credit['attribs']['']['role'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($credit['attribs']['']['scheme'])) + { + $credit_scheme = $this->sanitize($credit['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT); + } + else + { + $credit_scheme = 'urn:ebu'; + } + if (isset($credit['data'])) + { + $credit_name = $this->sanitize($credit['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + $credits[] = $this->registry->create('Credit', array($credit_role, $credit_scheme, $credit_name)); + } + if (is_array($credits)) + { + $credits = array_values(array_unique($credits)); + } + } + else + { + $credits = $credits_parent; + } - case 'bsviewdata': - case 'csiso47bsviewdata': - case 'isoir47': - return 'BS_viewdata'; + // DESCRIPTION + if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description'])) + { + $description = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description'])) + { + $description = $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + else + { + $description = $description_parent; + } - case 'cesu8': - case 'cscesu8': - return 'CESU-8'; - - case 'ca': - case 'csa71': - case 'csaz243419851': - case 'csiso121canadian1': - case 'iso646ca': - case 'isoir121': - return 'CSA_Z243.4-1985-1'; - - case 'csa72': - case 'csaz243419852': - case 'csiso122canadian2': - case 'iso646ca2': - case 'isoir122': - return 'CSA_Z243.4-1985-2'; - - case 'csaz24341985gr': - case 'csiso123csaz24341985gr': - case 'isoir123': - return 'CSA_Z243.4-1985-gr'; - - case 'csiso139csn369103': - case 'csn369103': - case 'isoir139': - return 'CSN_369103'; - - case 'csdecmcs': - case 'dec': - case 'decmcs': - return 'DEC-MCS'; + // HASHES + if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash'])) + { + foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash'] as $hash) + { + $value = null; + $algo = null; + if (isset($hash['data'])) + { + $value = $this->sanitize($hash['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($hash['attribs']['']['algo'])) + { + $algo = $this->sanitize($hash['attribs']['']['algo'], SIMPLEPIE_CONSTRUCT_TEXT); + } + else + { + $algo = 'md5'; + } + $hashes[] = $algo.':'.$value; + } + if (is_array($hashes)) + { + $hashes = array_values(array_unique($hashes)); + } + } + elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash'])) + { + foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash'] as $hash) + { + $value = null; + $algo = null; + if (isset($hash['data'])) + { + $value = $this->sanitize($hash['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($hash['attribs']['']['algo'])) + { + $algo = $this->sanitize($hash['attribs']['']['algo'], SIMPLEPIE_CONSTRUCT_TEXT); + } + else + { + $algo = 'md5'; + } + $hashes[] = $algo.':'.$value; + } + if (is_array($hashes)) + { + $hashes = array_values(array_unique($hashes)); + } + } + else + { + $hashes = $hashes_parent; + } - case 'csiso21german': - case 'de': - case 'din66003': - case 'iso646de': - case 'isoir21': - return 'DIN_66003'; + // KEYWORDS + if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'])) + { + if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data'])) + { + $temp = explode(',', $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT)); + foreach ($temp as $word) + { + $keywords[] = trim($word); + } + unset($temp); + } + if (is_array($keywords)) + { + $keywords = array_values(array_unique($keywords)); + } + } + elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'])) + { + if (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data'])) + { + $temp = explode(',', $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT)); + foreach ($temp as $word) + { + $keywords[] = trim($word); + } + unset($temp); + } + if (is_array($keywords)) + { + $keywords = array_values(array_unique($keywords)); + } + } + else + { + $keywords = $keywords_parent; + } - case 'csdkus': - case 'dkus': - return 'dk-us'; + // PLAYER + if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player'])) + { + $player = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI); + } + elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player'])) + { + $player = $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI); + } + else + { + $player = $player_parent; + } - case 'csiso646danish': - case 'dk': - case 'ds2089': - case 'iso646dk': - return 'DS_2089'; + // RATINGS + if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating'])) + { + foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating'] as $rating) + { + $rating_scheme = null; + $rating_value = null; + if (isset($rating['attribs']['']['scheme'])) + { + $rating_scheme = $this->sanitize($rating['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT); + } + else + { + $rating_scheme = 'urn:simple'; + } + if (isset($rating['data'])) + { + $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + $ratings[] = $this->registry->create('Rating', array($rating_scheme, $rating_value)); + } + if (is_array($ratings)) + { + $ratings = array_values(array_unique($ratings)); + } + } + elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating'])) + { + foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating'] as $rating) + { + $rating_scheme = null; + $rating_value = null; + if (isset($rating['attribs']['']['scheme'])) + { + $rating_scheme = $this->sanitize($rating['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT); + } + else + { + $rating_scheme = 'urn:simple'; + } + if (isset($rating['data'])) + { + $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + $ratings[] = $this->registry->create('Rating', array($rating_scheme, $rating_value)); + } + if (is_array($ratings)) + { + $ratings = array_values(array_unique($ratings)); + } + } + else + { + $ratings = $ratings_parent; + } - case 'csibmebcdicatde': - case 'ebcdicatde': - return 'EBCDIC-AT-DE'; + // RESTRICTIONS + if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction'])) + { + foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction'] as $restriction) + { + $restriction_relationship = null; + $restriction_type = null; + $restriction_value = null; + if (isset($restriction['attribs']['']['relationship'])) + { + $restriction_relationship = $this->sanitize($restriction['attribs']['']['relationship'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($restriction['attribs']['']['type'])) + { + $restriction_type = $this->sanitize($restriction['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($restriction['data'])) + { + $restriction_value = $this->sanitize($restriction['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + $restrictions[] = $this->registry->create('Restriction', array($restriction_relationship, $restriction_type, $restriction_value)); + } + if (is_array($restrictions)) + { + $restrictions = array_values(array_unique($restrictions)); + } + } + elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction'])) + { + foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction'] as $restriction) + { + $restriction_relationship = null; + $restriction_type = null; + $restriction_value = null; + if (isset($restriction['attribs']['']['relationship'])) + { + $restriction_relationship = $this->sanitize($restriction['attribs']['']['relationship'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($restriction['attribs']['']['type'])) + { + $restriction_type = $this->sanitize($restriction['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($restriction['data'])) + { + $restriction_value = $this->sanitize($restriction['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + $restrictions[] = $this->registry->create('Restriction', array($restriction_relationship, $restriction_type, $restriction_value)); + } + if (is_array($restrictions)) + { + $restrictions = array_values(array_unique($restrictions)); + } + } + else + { + $restrictions = $restrictions_parent; + } - case 'csebcdicatdea': - case 'ebcdicatdea': - return 'EBCDIC-AT-DE-A'; + // THUMBNAILS + if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail'])) + { + foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail'] as $thumbnail) + { + $thumbnails[] = $this->sanitize($thumbnail['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI); + } + if (is_array($thumbnails)) + { + $thumbnails = array_values(array_unique($thumbnails)); + } + } + elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail'])) + { + foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail'] as $thumbnail) + { + $thumbnails[] = $this->sanitize($thumbnail['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI); + } + if (is_array($thumbnails)) + { + $thumbnails = array_values(array_unique($thumbnails)); + } + } + else + { + $thumbnails = $thumbnails_parent; + } - case 'csebcdiccafr': - case 'ebcdiccafr': - return 'EBCDIC-CA-FR'; + // TITLES + if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title'])) + { + $title = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title'])) + { + $title = $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + else + { + $title = $title_parent; + } - case 'csebcdicdkno': - case 'ebcdicdkno': - return 'EBCDIC-DK-NO'; + $this->data['enclosures'][] = $this->registry->create('Enclosure', array($url, $type, $length, null, $bitrate, $captions, $categories, $channels, $copyrights, $credits, $description, $duration, $expression, $framerate, $hashes, $height, $keywords, $lang, $medium, $player, $ratings, $restrictions, $samplingrate, $thumbnails, $title, $width)); + } + } + } + } - case 'csebcdicdknoa': - case 'ebcdicdknoa': - return 'EBCDIC-DK-NO-A'; + // If we have standalone media:content tags, loop through them. + if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['content'])) + { + foreach ((array) $this->data['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['content'] as $content) + { + if (isset($content['attribs']['']['url']) || isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player'])) + { + // Attributes + $bitrate = null; + $channels = null; + $duration = null; + $expression = null; + $framerate = null; + $height = null; + $javascript = null; + $lang = null; + $length = null; + $medium = null; + $samplingrate = null; + $type = null; + $url = null; + $width = null; - case 'csebcdices': - case 'ebcdices': - return 'EBCDIC-ES'; + // Elements + $captions = null; + $categories = null; + $copyrights = null; + $credits = null; + $description = null; + $hashes = null; + $keywords = null; + $player = null; + $ratings = null; + $restrictions = null; + $thumbnails = null; + $title = null; - case 'csebcdicesa': - case 'ebcdicesa': - return 'EBCDIC-ES-A'; + // Start checking the attributes of media:content + if (isset($content['attribs']['']['bitrate'])) + { + $bitrate = $this->sanitize($content['attribs']['']['bitrate'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($content['attribs']['']['channels'])) + { + $channels = $this->sanitize($content['attribs']['']['channels'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($content['attribs']['']['duration'])) + { + $duration = $this->sanitize($content['attribs']['']['duration'], SIMPLEPIE_CONSTRUCT_TEXT); + } + else + { + $duration = $duration_parent; + } + if (isset($content['attribs']['']['expression'])) + { + $expression = $this->sanitize($content['attribs']['']['expression'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($content['attribs']['']['framerate'])) + { + $framerate = $this->sanitize($content['attribs']['']['framerate'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($content['attribs']['']['height'])) + { + $height = $this->sanitize($content['attribs']['']['height'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($content['attribs']['']['lang'])) + { + $lang = $this->sanitize($content['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($content['attribs']['']['fileSize'])) + { + $length = ceil($content['attribs']['']['fileSize']); + } + if (isset($content['attribs']['']['medium'])) + { + $medium = $this->sanitize($content['attribs']['']['medium'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($content['attribs']['']['samplingrate'])) + { + $samplingrate = $this->sanitize($content['attribs']['']['samplingrate'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($content['attribs']['']['type'])) + { + $type = $this->sanitize($content['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($content['attribs']['']['width'])) + { + $width = $this->sanitize($content['attribs']['']['width'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($content['attribs']['']['url'])) + { + $url = $this->sanitize($content['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI); + } + // Checking the other optional media: elements. Priority: media:content, media:group, item, channel - case 'csebcdicess': - case 'ebcdicess': - return 'EBCDIC-ES-S'; + // CAPTIONS + if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text'])) + { + foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text'] as $caption) + { + $caption_type = null; + $caption_lang = null; + $caption_startTime = null; + $caption_endTime = null; + $caption_text = null; + if (isset($caption['attribs']['']['type'])) + { + $caption_type = $this->sanitize($caption['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($caption['attribs']['']['lang'])) + { + $caption_lang = $this->sanitize($caption['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($caption['attribs']['']['start'])) + { + $caption_startTime = $this->sanitize($caption['attribs']['']['start'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($caption['attribs']['']['end'])) + { + $caption_endTime = $this->sanitize($caption['attribs']['']['end'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($caption['data'])) + { + $caption_text = $this->sanitize($caption['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + $captions[] = $this->registry->create('Caption', array($caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text)); + } + if (is_array($captions)) + { + $captions = array_values(array_unique($captions)); + } + } + else + { + $captions = $captions_parent; + } - case 'csebcdicfise': - case 'ebcdicfise': - return 'EBCDIC-FI-SE'; + // CATEGORIES + if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category'])) + { + foreach ((array) $content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category'] as $category) + { + $term = null; + $scheme = null; + $label = null; + if (isset($category['data'])) + { + $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($category['attribs']['']['scheme'])) + { + $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT); + } + else + { + $scheme = 'http://search.yahoo.com/mrss/category_schema'; + } + if (isset($category['attribs']['']['label'])) + { + $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT); + } + $categories[] = $this->registry->create('Category', array($term, $scheme, $label)); + } + } + if (is_array($categories) && is_array($categories_parent)) + { + $categories = array_values(array_unique(array_merge($categories, $categories_parent))); + } + elseif (is_array($categories)) + { + $categories = array_values(array_unique($categories)); + } + elseif (is_array($categories_parent)) + { + $categories = array_values(array_unique($categories_parent)); + } + else + { + $categories = null; + } - case 'csebcdicfisea': - case 'ebcdicfisea': - return 'EBCDIC-FI-SE-A'; + // COPYRIGHTS + if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'])) + { + $copyright_url = null; + $copyright_label = null; + if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url'])) + { + $copyright_url = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data'])) + { + $copyright_label = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + $copyrights = $this->registry->create('Copyright', array($copyright_url, $copyright_label)); + } + else + { + $copyrights = $copyrights_parent; + } - case 'csebcdicfr': - case 'ebcdicfr': - return 'EBCDIC-FR'; - - case 'csebcdicit': - case 'ebcdicit': - return 'EBCDIC-IT'; + // CREDITS + if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit'])) + { + foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit'] as $credit) + { + $credit_role = null; + $credit_scheme = null; + $credit_name = null; + if (isset($credit['attribs']['']['role'])) + { + $credit_role = $this->sanitize($credit['attribs']['']['role'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($credit['attribs']['']['scheme'])) + { + $credit_scheme = $this->sanitize($credit['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT); + } + else + { + $credit_scheme = 'urn:ebu'; + } + if (isset($credit['data'])) + { + $credit_name = $this->sanitize($credit['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + $credits[] = $this->registry->create('Credit', array($credit_role, $credit_scheme, $credit_name)); + } + if (is_array($credits)) + { + $credits = array_values(array_unique($credits)); + } + } + else + { + $credits = $credits_parent; + } - case 'csebcdicpt': - case 'ebcdicpt': - return 'EBCDIC-PT'; + // DESCRIPTION + if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description'])) + { + $description = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + else + { + $description = $description_parent; + } - case 'csebcdicuk': - case 'ebcdicuk': - return 'EBCDIC-UK'; + // HASHES + if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash'])) + { + foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash'] as $hash) + { + $value = null; + $algo = null; + if (isset($hash['data'])) + { + $value = $this->sanitize($hash['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($hash['attribs']['']['algo'])) + { + $algo = $this->sanitize($hash['attribs']['']['algo'], SIMPLEPIE_CONSTRUCT_TEXT); + } + else + { + $algo = 'md5'; + } + $hashes[] = $algo.':'.$value; + } + if (is_array($hashes)) + { + $hashes = array_values(array_unique($hashes)); + } + } + else + { + $hashes = $hashes_parent; + } - case 'csebcdicus': - case 'ebcdicus': - return 'EBCDIC-US'; + // KEYWORDS + if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'])) + { + if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data'])) + { + $temp = explode(',', $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT)); + foreach ($temp as $word) + { + $keywords[] = trim($word); + } + unset($temp); + } + if (is_array($keywords)) + { + $keywords = array_values(array_unique($keywords)); + } + } + else + { + $keywords = $keywords_parent; + } - case 'csiso111ecmacyrillic': - case 'ecmacyrillic': - case 'isoir111': - case 'koi8e': - return 'ECMA-cyrillic'; + // PLAYER + if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player'])) + { + $player = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI); + } + else + { + $player = $player_parent; + } - case 'csiso17spanish': - case 'es': - case 'iso646es': - case 'isoir17': - return 'ES'; + // RATINGS + if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating'])) + { + foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating'] as $rating) + { + $rating_scheme = null; + $rating_value = null; + if (isset($rating['attribs']['']['scheme'])) + { + $rating_scheme = $this->sanitize($rating['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT); + } + else + { + $rating_scheme = 'urn:simple'; + } + if (isset($rating['data'])) + { + $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + $ratings[] = $this->registry->create('Rating', array($rating_scheme, $rating_value)); + } + if (is_array($ratings)) + { + $ratings = array_values(array_unique($ratings)); + } + } + else + { + $ratings = $ratings_parent; + } - case 'csiso85spanish2': - case 'es2': - case 'iso646es2': - case 'isoir85': - return 'ES2'; + // RESTRICTIONS + if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction'])) + { + foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction'] as $restriction) + { + $restriction_relationship = null; + $restriction_type = null; + $restriction_value = null; + if (isset($restriction['attribs']['']['relationship'])) + { + $restriction_relationship = $this->sanitize($restriction['attribs']['']['relationship'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($restriction['attribs']['']['type'])) + { + $restriction_type = $this->sanitize($restriction['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($restriction['data'])) + { + $restriction_value = $this->sanitize($restriction['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + $restrictions[] = $this->registry->create('Restriction', array($restriction_relationship, $restriction_type, $restriction_value)); + } + if (is_array($restrictions)) + { + $restrictions = array_values(array_unique($restrictions)); + } + } + else + { + $restrictions = $restrictions_parent; + } - case 'cseucpkdfmtjapanese': - case 'eucjp': - case 'extendedunixcodepackedformatforjapanese': - return 'EUC-JP'; + // THUMBNAILS + if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail'])) + { + foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail'] as $thumbnail) + { + $thumbnails[] = $this->sanitize($thumbnail['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI); + } + if (is_array($thumbnails)) + { + $thumbnails = array_values(array_unique($thumbnails)); + } + } + else + { + $thumbnails = $thumbnails_parent; + } - case 'cseucfixwidjapanese': - case 'extendedunixcodefixedwidthforjapanese': - return 'Extended_UNIX_Code_Fixed_Width_for_Japanese'; + // TITLES + if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title'])) + { + $title = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + else + { + $title = $title_parent; + } - case 'gb18030': - return 'GB18030'; + $this->data['enclosures'][] = $this->registry->create('Enclosure', array($url, $type, $length, null, $bitrate, $captions, $categories, $channels, $copyrights, $credits, $description, $duration, $expression, $framerate, $hashes, $height, $keywords, $lang, $medium, $player, $ratings, $restrictions, $samplingrate, $thumbnails, $title, $width)); + } + } + } - case 'chinese': - case 'cp936': - case 'csgb2312': - case 'csiso58gb231280': - case 'gb2312': - case 'gb231280': - case 'gbk': - case 'isoir58': - case 'ms936': - case 'windows936': - return 'GBK'; + foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'link') as $link) + { + if (isset($link['attribs']['']['href']) && !empty($link['attribs']['']['rel']) && $link['attribs']['']['rel'] === 'enclosure') + { + // Attributes + $bitrate = null; + $channels = null; + $duration = null; + $expression = null; + $framerate = null; + $height = null; + $javascript = null; + $lang = null; + $length = null; + $medium = null; + $samplingrate = null; + $type = null; + $url = null; + $width = null; - case 'cn': - case 'csiso57gb1988': - case 'gb198880': - case 'iso646cn': - case 'isoir57': - return 'GB_1988-80'; + $url = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link)); + if (isset($link['attribs']['']['type'])) + { + $type = $this->sanitize($link['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($link['attribs']['']['length'])) + { + $length = ceil($link['attribs']['']['length']); + } - case 'csiso153gost1976874': - case 'gost1976874': - case 'isoir153': - case 'stsev35888': - return 'GOST_19768-74'; + // Since we don't have group or content for these, we'll just pass the '*_parent' variables directly to the constructor + $this->data['enclosures'][] = $this->registry->create('Enclosure', array($url, $type, $length, null, $bitrate, $captions_parent, $categories_parent, $channels, $copyrights_parent, $credits_parent, $description_parent, $duration_parent, $expression, $framerate, $hashes_parent, $height, $keywords_parent, $lang, $medium, $player_parent, $ratings_parent, $restrictions_parent, $samplingrate, $thumbnails_parent, $title_parent, $width)); + } + } - case 'csiso150': - case 'csiso150greekccitt': - case 'greekccitt': - case 'isoir150': - return 'greek-ccitt'; + foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'link') as $link) + { + if (isset($link['attribs']['']['href']) && !empty($link['attribs']['']['rel']) && $link['attribs']['']['rel'] === 'enclosure') + { + // Attributes + $bitrate = null; + $channels = null; + $duration = null; + $expression = null; + $framerate = null; + $height = null; + $javascript = null; + $lang = null; + $length = null; + $medium = null; + $samplingrate = null; + $type = null; + $url = null; + $width = null; - case 'csiso88greek7': - case 'greek7': - case 'isoir88': - return 'greek7'; + $url = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link)); + if (isset($link['attribs']['']['type'])) + { + $type = $this->sanitize($link['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($link['attribs']['']['length'])) + { + $length = ceil($link['attribs']['']['length']); + } - case 'csiso18greek7old': - case 'greek7old': - case 'isoir18': - return 'greek7-old'; + // Since we don't have group or content for these, we'll just pass the '*_parent' variables directly to the constructor + $this->data['enclosures'][] = $this->registry->create('Enclosure', array($url, $type, $length, null, $bitrate, $captions_parent, $categories_parent, $channels, $copyrights_parent, $credits_parent, $description_parent, $duration_parent, $expression, $framerate, $hashes_parent, $height, $keywords_parent, $lang, $medium, $player_parent, $ratings_parent, $restrictions_parent, $samplingrate, $thumbnails_parent, $title_parent, $width)); + } + } - case 'cshpdesktop': - case 'hpdesktop': - return 'HP-DeskTop'; + if ($enclosure = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'enclosure')) + { + if (isset($enclosure[0]['attribs']['']['url'])) + { + // Attributes + $bitrate = null; + $channels = null; + $duration = null; + $expression = null; + $framerate = null; + $height = null; + $javascript = null; + $lang = null; + $length = null; + $medium = null; + $samplingrate = null; + $type = null; + $url = null; + $width = null; - case 'cshplegal': - case 'hplegal': - return 'HP-Legal'; + $url = $this->sanitize($enclosure[0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($enclosure[0])); + if (isset($enclosure[0]['attribs']['']['type'])) + { + $type = $this->sanitize($enclosure[0]['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($enclosure[0]['attribs']['']['length'])) + { + $length = ceil($enclosure[0]['attribs']['']['length']); + } - case 'cshpmath8': - case 'hpmath8': - return 'HP-Math8'; + // Since we don't have group or content for these, we'll just pass the '*_parent' variables directly to the constructor + $this->data['enclosures'][] = $this->registry->create('Enclosure', array($url, $type, $length, null, $bitrate, $captions_parent, $categories_parent, $channels, $copyrights_parent, $credits_parent, $description_parent, $duration_parent, $expression, $framerate, $hashes_parent, $height, $keywords_parent, $lang, $medium, $player_parent, $ratings_parent, $restrictions_parent, $samplingrate, $thumbnails_parent, $title_parent, $width)); + } + } - case 'cshppifont': - case 'hppifont': - return 'HP-Pi-font'; + if (sizeof($this->data['enclosures']) === 0 && ($url || $type || $length || $bitrate || $captions_parent || $categories_parent || $channels || $copyrights_parent || $credits_parent || $description_parent || $duration_parent || $expression || $framerate || $hashes_parent || $height || $keywords_parent || $lang || $medium || $player_parent || $ratings_parent || $restrictions_parent || $samplingrate || $thumbnails_parent || $title_parent || $width)) + { + // Since we don't have group or content for these, we'll just pass the '*_parent' variables directly to the constructor + $this->data['enclosures'][] = $this->registry->create('Enclosure', array($url, $type, $length, null, $bitrate, $captions_parent, $categories_parent, $channels, $copyrights_parent, $credits_parent, $description_parent, $duration_parent, $expression, $framerate, $hashes_parent, $height, $keywords_parent, $lang, $medium, $player_parent, $ratings_parent, $restrictions_parent, $samplingrate, $thumbnails_parent, $title_parent, $width)); + } - case 'cshproman8': - case 'hproman8': - case 'r8': - case 'roman8': - return 'hp-roman8'; + $this->data['enclosures'] = array_values(array_unique($this->data['enclosures'])); + } + if (!empty($this->data['enclosures'])) + { + return $this->data['enclosures']; + } + else + { + return null; + } + } - case 'hzgb2312': - return 'HZ-GB-2312'; + /** + * Get the latitude coordinates for the item + * + * Compatible with the W3C WGS84 Basic Geo and GeoRSS specifications + * + * Uses `<geo:lat>` or `<georss:point>` + * + * @since 1.0 + * @link http://www.w3.org/2003/01/geo/ W3C WGS84 Basic Geo + * @link http://www.georss.org/ GeoRSS + * @return string|null + */ + public function get_latitude() + { + if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lat')) + { + return (float) $return[0]['data']; + } + elseif (($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_GEORSS, 'point')) && preg_match('/^((?:-)?[0-9]+(?:\.[0-9]+)) ((?:-)?[0-9]+(?:\.[0-9]+))$/', trim($return[0]['data']), $match)) + { + return (float) $match[1]; + } + else + { + return null; + } + } - case 'csibmsymbols': - case 'ibmsymbols': - return 'IBM-Symbols'; + /** + * Get the longitude coordinates for the item + * + * Compatible with the W3C WGS84 Basic Geo and GeoRSS specifications + * + * Uses `<geo:long>`, `<geo:lon>` or `<georss:point>` + * + * @since 1.0 + * @link http://www.w3.org/2003/01/geo/ W3C WGS84 Basic Geo + * @link http://www.georss.org/ GeoRSS + * @return string|null + */ + public function get_longitude() + { + if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'long')) + { + return (float) $return[0]['data']; + } + elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lon')) + { + return (float) $return[0]['data']; + } + elseif (($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_GEORSS, 'point')) && preg_match('/^((?:-)?[0-9]+(?:\.[0-9]+)) ((?:-)?[0-9]+(?:\.[0-9]+))$/', trim($return[0]['data']), $match)) + { + return (float) $match[2]; + } + else + { + return null; + } + } - case 'csibmthai': - case 'ibmthai': - return 'IBM-Thai'; + /** + * Get the `<atom:source>` for the item + * + * @since 1.1 + * @return SimplePie_Source|null + */ + public function get_source() + { + if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'source')) + { + return $this->registry->create('Source', array($this, $return[0])); + } + else + { + return null; + } + } +} - case 'cp37': - case 'csibm37': - case 'ebcdiccpca': - case 'ebcdiccpnl': - case 'ebcdiccpus': - case 'ebcdiccpwt': - case 'ibm37': - return 'IBM037'; +/** + * Used for feed auto-discovery + * + * + * This class can be overloaded with {@see SimplePie::set_locator_class()} + * + * @package SimplePie + */ +class SimplePie_Locator +{ + var $useragent; + var $timeout; + var $file; + var $local = array(); + var $elsewhere = array(); + var $cached_entities = array(); + var $http_base; + var $base; + var $base_location = 0; + var $checked_feeds = 0; + var $max_checked_feeds = 10; + protected $registry; - case 'cp38': - case 'csibm38': - case 'ebcdicint': - case 'ibm38': - return 'IBM038'; + public function __construct(SimplePie_File $file, $timeout = 10, $useragent = null, $max_checked_feeds = 10) + { + $this->file = $file; + $this->useragent = $useragent; + $this->timeout = $timeout; + $this->max_checked_feeds = $max_checked_feeds; - case 'cp273': - case 'csibm273': - case 'ibm273': - return 'IBM273'; + if (class_exists('DOMDocument')) + { + $this->dom = new DOMDocument(); - case 'cp274': - case 'csibm274': - case 'ebcdicbe': - case 'ibm274': - return 'IBM274'; + set_error_handler(array('SimplePie_Misc', 'silence_errors')); + $this->dom->loadHTML($this->file->body); + restore_error_handler(); + } + else + { + $this->dom = null; + } + } - case 'cp275': - case 'csibm275': - case 'ebcdicbr': - case 'ibm275': - return 'IBM275'; + public function set_registry(SimplePie_Registry $registry) + { + $this->registry = $registry; + } - case 'csibm277': - case 'ebcdiccpdk': - case 'ebcdiccpno': - case 'ibm277': - return 'IBM277'; + public function find($type = SIMPLEPIE_LOCATOR_ALL, &$working) + { + if ($this->is_feed($this->file)) + { + return $this->file; + } - case 'cp278': - case 'csibm278': - case 'ebcdiccpfi': - case 'ebcdiccpse': - case 'ibm278': - return 'IBM278'; + if ($this->file->method & SIMPLEPIE_FILE_SOURCE_REMOTE) + { + $sniffer = $this->registry->create('Content_Type_Sniffer', array($this->file)); + if ($sniffer->get_type() !== 'text/html') + { + return null; + } + } - case 'cp280': - case 'csibm280': - case 'ebcdiccpit': - case 'ibm280': - return 'IBM280'; + if ($type & ~SIMPLEPIE_LOCATOR_NONE) + { + $this->get_base(); + } - case 'cp281': - case 'csibm281': - case 'ebcdicjpe': - case 'ibm281': - return 'IBM281'; + if ($type & SIMPLEPIE_LOCATOR_AUTODISCOVERY && $working = $this->autodiscovery()) + { + return $working[0]; + } - case 'cp284': - case 'csibm284': - case 'ebcdiccpes': - case 'ibm284': - return 'IBM284'; + if ($type & (SIMPLEPIE_LOCATOR_LOCAL_EXTENSION | SIMPLEPIE_LOCATOR_LOCAL_BODY | SIMPLEPIE_LOCATOR_REMOTE_EXTENSION | SIMPLEPIE_LOCATOR_REMOTE_BODY) && $this->get_links()) + { + if ($type & SIMPLEPIE_LOCATOR_LOCAL_EXTENSION && $working = $this->extension($this->local)) + { + return $working; + } - case 'cp285': - case 'csibm285': - case 'ebcdiccpgb': - case 'ibm285': - return 'IBM285'; + if ($type & SIMPLEPIE_LOCATOR_LOCAL_BODY && $working = $this->body($this->local)) + { + return $working; + } - case 'cp290': - case 'csibm290': - case 'ebcdicjpkana': - case 'ibm290': - return 'IBM290'; + if ($type & SIMPLEPIE_LOCATOR_REMOTE_EXTENSION && $working = $this->extension($this->elsewhere)) + { + return $working; + } - case 'cp297': - case 'csibm297': - case 'ebcdiccpfr': - case 'ibm297': - return 'IBM297'; + if ($type & SIMPLEPIE_LOCATOR_REMOTE_BODY && $working = $this->body($this->elsewhere)) + { + return $working; + } + } + return null; + } - case 'cp420': - case 'csibm420': - case 'ebcdiccpar1': - case 'ibm420': - return 'IBM420'; + public function is_feed($file) + { + if ($file->method & SIMPLEPIE_FILE_SOURCE_REMOTE) + { + $sniffer = $this->registry->create('Content_Type_Sniffer', array($file)); + $sniffed = $sniffer->get_type(); + if (in_array($sniffed, array('application/rss+xml', 'application/rdf+xml', 'text/rdf', 'application/atom+xml', 'text/xml', 'application/xml'))) + { + return true; + } + else + { + return false; + } + } + elseif ($file->method & SIMPLEPIE_FILE_SOURCE_LOCAL) + { + return true; + } + else + { + return false; + } + } - case 'cp423': - case 'csibm423': - case 'ebcdiccpgr': - case 'ibm423': - return 'IBM423'; + public function get_base() + { + if ($this->dom === null) + { + throw new SimplePie_Exception('DOMDocument not found, unable to use locator'); + } + $this->http_base = $this->file->url; + $this->base = $this->http_base; + $elements = $this->dom->getElementsByTagName('base'); + foreach ($elements as $element) + { + if ($element->hasAttribute('href')) + { + $base = $this->registry->call('Misc', 'absolutize_url', array(trim($element->getAttribute('href')), $this->http_base)); + if ($base === false) + { + continue; + } + $this->base = $base; + $this->base_location = method_exists($element, 'getLineNo') ? $element->getLineNo() : 0; + break; + } + } + } - case 'cp424': - case 'csibm424': - case 'ebcdiccphe': - case 'ibm424': - return 'IBM424'; + public function autodiscovery() + { + $done = array(); + $feeds = array(); + $feeds = array_merge($feeds, $this->search_elements_by_tag('link', $done, $feeds)); + $feeds = array_merge($feeds, $this->search_elements_by_tag('a', $done, $feeds)); + $feeds = array_merge($feeds, $this->search_elements_by_tag('area', $done, $feeds)); - case '437': - case 'cp437': - case 'cspc8codepage437': - case 'ibm437': - return 'IBM437'; + if (!empty($feeds)) + { + return array_values($feeds); + } + else + { + return null; + } + } - case 'cp500': - case 'csibm500': - case 'ebcdiccpbe': - case 'ebcdiccpch': - case 'ibm500': - return 'IBM500'; + protected function search_elements_by_tag($name, &$done, $feeds) + { + if ($this->dom === null) + { + throw new SimplePie_Exception('DOMDocument not found, unable to use locator'); + } - case 'cp775': - case 'cspc775baltic': - case 'ibm775': - return 'IBM775'; + $links = $this->dom->getElementsByTagName($name); + foreach ($links as $link) + { + if ($this->checked_feeds === $this->max_checked_feeds) + { + break; + } + if ($link->hasAttribute('href') && $link->hasAttribute('rel')) + { + $rel = array_unique($this->registry->call('Misc', 'space_seperated_tokens', array(strtolower($link->getAttribute('rel'))))); + $line = method_exists($link, 'getLineNo') ? $link->getLineNo() : 1; - case '850': - case 'cp850': - case 'cspc850multilingual': - case 'ibm850': - return 'IBM850'; + if ($this->base_location < $line) + { + $href = $this->registry->call('Misc', 'absolutize_url', array(trim($link->getAttribute('href')), $this->base)); + } + else + { + $href = $this->registry->call('Misc', 'absolutize_url', array(trim($link->getAttribute('href')), $this->http_base)); + } + if ($href === false) + { + continue; + } - case '851': - case 'cp851': - case 'csibm851': - case 'ibm851': - return 'IBM851'; + if (!in_array($href, $done) && in_array('feed', $rel) || (in_array('alternate', $rel) && !in_array('stylesheet', $rel) && $link->hasAttribute('type') && in_array(strtolower($this->registry->call('Misc', 'parse_mime', array($link->getAttribute('type')))), array('application/rss+xml', 'application/atom+xml'))) && !isset($feeds[$href])) + { + $this->checked_feeds++; + $headers = array( + 'Accept' => 'application/atom+xml, application/rss+xml, application/rdf+xml;q=0.9, application/xml;q=0.8, text/xml;q=0.8, text/html;q=0.7, unknown/unknown;q=0.1, application/unknown;q=0.1, */*;q=0.1', + ); + $feed = $this->registry->create('File', array($href, $this->timeout, 5, $headers, $this->useragent)); + if ($feed->success && ($feed->method & SIMPLEPIE_FILE_SOURCE_REMOTE === 0 || ($feed->status_code === 200 || $feed->status_code > 206 && $feed->status_code < 300)) && $this->is_feed($feed)) + { + $feeds[$href] = $feed; + } + } + $done[] = $href; + } + } - case '852': - case 'cp852': - case 'cspcp852': - case 'ibm852': - return 'IBM852'; + return $feeds; + } - case '855': - case 'cp855': - case 'csibm855': - case 'ibm855': - return 'IBM855'; + public function get_links() + { + if ($this->dom === null) + { + throw new SimplePie_Exception('DOMDocument not found, unable to use locator'); + } - case '857': - case 'cp857': - case 'csibm857': - case 'ibm857': - return 'IBM857'; + $links = $this->dom->getElementsByTagName('a'); + foreach ($links as $link) + { + if ($link->hasAttribute('href')) + { + $href = trim($link->getAttribute('href')); + $parsed = $this->registry->call('Misc', 'parse_url', array($href)); + if ($parsed['scheme'] === '' || preg_match('/^(http(s)|feed)?$/i', $parsed['scheme'])) + { + if ($this->base_location < $link->getLineNo()) + { + $href = $this->registry->call('Misc', 'absolutize_url', array(trim($link->getAttribute('href')), $this->base)); + } + else + { + $href = $this->registry->call('Misc', 'absolutize_url', array(trim($link->getAttribute('href')), $this->http_base)); + } + if ($href === false) + { + continue; + } - case 'ccsid858': - case 'cp858': - case 'ibm858': - case 'pcmultilingual850euro': - return 'IBM00858'; + $current = $this->registry->call('Misc', 'parse_url', array($this->file->url)); - case '860': - case 'cp860': - case 'csibm860': - case 'ibm860': - return 'IBM860'; + if ($parsed['authority'] === '' || $parsed['authority'] === $current['authority']) + { + $this->local[] = $href; + } + else + { + $this->elsewhere[] = $href; + } + } + } + } + $this->local = array_unique($this->local); + $this->elsewhere = array_unique($this->elsewhere); + if (!empty($this->local) || !empty($this->elsewhere)) + { + return true; + } + return null; + } - case '861': - case 'cp861': - case 'cpis': - case 'csibm861': - case 'ibm861': - return 'IBM861'; - - case '862': - case 'cp862': - case 'cspc862latinhebrew': - case 'ibm862': - return 'IBM862'; + public function extension(&$array) + { + foreach ($array as $key => $value) + { + if ($this->checked_feeds === $this->max_checked_feeds) + { + break; + } + if (in_array(strtolower(strrchr($value, '.')), array('.rss', '.rdf', '.atom', '.xml'))) + { + $this->checked_feeds++; - case '863': - case 'cp863': - case 'csibm863': - case 'ibm863': - return 'IBM863'; + $headers = array( + 'Accept' => 'application/atom+xml, application/rss+xml, application/rdf+xml;q=0.9, application/xml;q=0.8, text/xml;q=0.8, text/html;q=0.7, unknown/unknown;q=0.1, application/unknown;q=0.1, */*;q=0.1', + ); + $feed = $this->registry->create('File', array($value, $this->timeout, 5, $headers, $this->useragent)); + if ($feed->success && ($feed->method & SIMPLEPIE_FILE_SOURCE_REMOTE === 0 || ($feed->status_code === 200 || $feed->status_code > 206 && $feed->status_code < 300)) && $this->is_feed($feed)) + { + return $feed; + } + else + { + unset($array[$key]); + } + } + } + return null; + } - case 'cp864': - case 'csibm864': - case 'ibm864': - return 'IBM864'; + public function body(&$array) + { + foreach ($array as $key => $value) + { + if ($this->checked_feeds === $this->max_checked_feeds) + { + break; + } + if (preg_match('/(rss|rdf|atom|xml)/i', $value)) + { + $this->checked_feeds++; + $headers = array( + 'Accept' => 'application/atom+xml, application/rss+xml, application/rdf+xml;q=0.9, application/xml;q=0.8, text/xml;q=0.8, text/html;q=0.7, unknown/unknown;q=0.1, application/unknown;q=0.1, */*;q=0.1', + ); + $feed = $this->registry->create('File', array($value, $this->timeout, 5, null, $this->useragent)); + if ($feed->success && ($feed->method & SIMPLEPIE_FILE_SOURCE_REMOTE === 0 || ($feed->status_code === 200 || $feed->status_code > 206 && $feed->status_code < 300)) && $this->is_feed($feed)) + { + return $feed; + } + else + { + unset($array[$key]); + } + } + } + return null; + } +} - case '865': - case 'cp865': - case 'csibm865': - case 'ibm865': - return 'IBM865'; +/** + * Miscellanous utilities + * + * @package SimplePie + */ +class SimplePie_Misc +{ + public static function time_hms($seconds) + { + $time = ''; - case '866': - case 'cp866': - case 'csibm866': - case 'ibm866': - return 'IBM866'; + $hours = floor($seconds / 3600); + $remainder = $seconds % 3600; + if ($hours > 0) + { + $time .= $hours.':'; + } - case 'cp868': - case 'cpar': - case 'csibm868': - case 'ibm868': - return 'IBM868'; + $minutes = floor($remainder / 60); + $seconds = $remainder % 60; + if ($minutes < 10 && $hours > 0) + { + $minutes = '0' . $minutes; + } + if ($seconds < 10) + { + $seconds = '0' . $seconds; + } - case '869': - case 'cp869': - case 'cpgr': - case 'csibm869': - case 'ibm869': - return 'IBM869'; + $time .= $minutes.':'; + $time .= $seconds; - case 'cp870': - case 'csibm870': - case 'ebcdiccproece': - case 'ebcdiccpyu': - case 'ibm870': - return 'IBM870'; + return $time; + } - case 'cp871': - case 'csibm871': - case 'ebcdiccpis': - case 'ibm871': - return 'IBM871'; + public static function absolutize_url($relative, $base) + { + $iri = SimplePie_IRI::absolutize(new SimplePie_IRI($base), $relative); + if ($iri === false) + { + return false; + } + return $iri->get_uri(); + } - case 'cp880': - case 'csibm880': - case 'ebcdiccyrillic': - case 'ibm880': - return 'IBM880'; + /** + * Get a HTML/XML element from a HTML string + * + * @deprecated Use DOMDocument instead (parsing HTML with regex is bad!) + * @param string $realname Element name (including namespace prefix if applicable) + * @param string $string HTML document + * @return array + */ + public static function get_element($realname, $string) + { + $return = array(); + $name = preg_quote($realname, '/'); + if (preg_match_all("/<($name)" . SIMPLEPIE_PCRE_HTML_ATTRIBUTE . "(>(.*)<\/$name>|(\/)?>)/siU", $string, $matches, PREG_SET_ORDER | PREG_OFFSET_CAPTURE)) + { + for ($i = 0, $total_matches = count($matches); $i < $total_matches; $i++) + { + $return[$i]['tag'] = $realname; + $return[$i]['full'] = $matches[$i][0][0]; + $return[$i]['offset'] = $matches[$i][0][1]; + if (strlen($matches[$i][3][0]) <= 2) + { + $return[$i]['self_closing'] = true; + } + else + { + $return[$i]['self_closing'] = false; + $return[$i]['content'] = $matches[$i][4][0]; + } + $return[$i]['attribs'] = array(); + if (isset($matches[$i][2][0]) && preg_match_all('/[\x09\x0A\x0B\x0C\x0D\x20]+([^\x09\x0A\x0B\x0C\x0D\x20\x2F\x3E][^\x09\x0A\x0B\x0C\x0D\x20\x2F\x3D\x3E]*)(?:[\x09\x0A\x0B\x0C\x0D\x20]*=[\x09\x0A\x0B\x0C\x0D\x20]*(?:"([^"]*)"|\'([^\']*)\'|([^\x09\x0A\x0B\x0C\x0D\x20\x22\x27\x3E][^\x09\x0A\x0B\x0C\x0D\x20\x3E]*)?))?/', ' ' . $matches[$i][2][0] . ' ', $attribs, PREG_SET_ORDER)) + { + for ($j = 0, $total_attribs = count($attribs); $j < $total_attribs; $j++) + { + if (count($attribs[$j]) === 2) + { + $attribs[$j][2] = $attribs[$j][1]; + } + $return[$i]['attribs'][strtolower($attribs[$j][1])]['data'] = SimplePie_Misc::entities_decode(end($attribs[$j]), 'UTF-8'); + } + } + } + } + return $return; + } - case 'cp891': - case 'csibm891': - case 'ibm891': - return 'IBM891'; + public static function element_implode($element) + { + $full = "<$element[tag]"; + foreach ($element['attribs'] as $key => $value) + { + $key = strtolower($key); + $full .= " $key=\"" . htmlspecialchars($value['data']) . '"'; + } + if ($element['self_closing']) + { + $full .= ' />'; + } + else + { + $full .= ">$element[content]</$element[tag]>"; + } + return $full; + } - case 'cp903': - case 'csibm903': - case 'ibm903': - return 'IBM903'; + public static function error($message, $level, $file, $line) + { + if ((ini_get('error_reporting') & $level) > 0) + { + switch ($level) + { + case E_USER_ERROR: + $note = 'PHP Error'; + break; + case E_USER_WARNING: + $note = 'PHP Warning'; + break; + case E_USER_NOTICE: + $note = 'PHP Notice'; + break; + default: + $note = 'Unknown Error'; + break; + } - case '904': - case 'cp904': - case 'csibbm904': - case 'ibm904': - return 'IBM904'; + $log_error = true; + if (!function_exists('error_log')) + { + $log_error = false; + } - case 'cp905': - case 'csibm905': - case 'ebcdiccptr': - case 'ibm905': - return 'IBM905'; + $log_file = @ini_get('error_log'); + if (!empty($log_file) && ('syslog' !== $log_file) && !@is_writable($log_file)) + { + $log_error = false; + } - case 'cp918': - case 'csibm918': - case 'ebcdiccpar2': - case 'ibm918': - return 'IBM918'; + if ($log_error) + { + @error_log("$note: $message in $file on line $line", 0); + } + } - case 'ccsid924': - case 'cp924': - case 'ebcdiclatin9euro': - case 'ibm924': - return 'IBM00924'; + return $message; + } - case 'cp1026': - case 'csibm1026': - case 'ibm1026': - return 'IBM1026'; + public static function fix_protocol($url, $http = 1) + { + $url = SimplePie_Misc::normalize_url($url); + $parsed = SimplePie_Misc::parse_url($url); + if ($parsed['scheme'] !== '' && $parsed['scheme'] !== 'http' && $parsed['scheme'] !== 'https') + { + return SimplePie_Misc::fix_protocol(SimplePie_Misc::compress_parse_url('http', $parsed['authority'], $parsed['path'], $parsed['query'], $parsed['fragment']), $http); + } - case 'ibm1047': - return 'IBM1047'; + if ($parsed['scheme'] === '' && $parsed['authority'] === '' && !file_exists($url)) + { + return SimplePie_Misc::fix_protocol(SimplePie_Misc::compress_parse_url('http', $parsed['path'], '', $parsed['query'], $parsed['fragment']), $http); + } - case 'ccsid1140': - case 'cp1140': - case 'ebcdicus37euro': - case 'ibm1140': - return 'IBM01140'; + if ($http === 2 && $parsed['scheme'] !== '') + { + return "feed:$url"; + } + elseif ($http === 3 && strtolower($parsed['scheme']) === 'http') + { + return substr_replace($url, 'podcast', 0, 4); + } + elseif ($http === 4 && strtolower($parsed['scheme']) === 'http') + { + return substr_replace($url, 'itpc', 0, 4); + } + else + { + return $url; + } + } - case 'ccsid1141': - case 'cp1141': - case 'ebcdicde273euro': - case 'ibm1141': - return 'IBM01141'; + public static function parse_url($url) + { + $iri = new SimplePie_IRI($url); + return array( + 'scheme' => (string) $iri->scheme, + 'authority' => (string) $iri->authority, + 'path' => (string) $iri->path, + 'query' => (string) $iri->query, + 'fragment' => (string) $iri->fragment + ); + } - case 'ccsid1142': - case 'cp1142': - case 'ebcdicdk277euro': - case 'ebcdicno277euro': - case 'ibm1142': - return 'IBM01142'; + public static function compress_parse_url($scheme = '', $authority = '', $path = '', $query = '', $fragment = '') + { + $iri = new SimplePie_IRI(''); + $iri->scheme = $scheme; + $iri->authority = $authority; + $iri->path = $path; + $iri->query = $query; + $iri->fragment = $fragment; + return $iri->get_uri(); + } - case 'ccsid1143': - case 'cp1143': - case 'ebcdicfi278euro': - case 'ebcdicse278euro': - case 'ibm1143': - return 'IBM01143'; + public static function normalize_url($url) + { + $iri = new SimplePie_IRI($url); + return $iri->get_uri(); + } - case 'ccsid1144': - case 'cp1144': - case 'ebcdicit280euro': - case 'ibm1144': - return 'IBM01144'; + public static function percent_encoding_normalization($match) + { + $integer = hexdec($match[1]); + if ($integer >= 0x41 && $integer <= 0x5A || $integer >= 0x61 && $integer <= 0x7A || $integer >= 0x30 && $integer <= 0x39 || $integer === 0x2D || $integer === 0x2E || $integer === 0x5F || $integer === 0x7E) + { + return chr($integer); + } + else + { + return strtoupper($match[0]); + } + } - case 'ccsid1145': - case 'cp1145': - case 'ebcdices284euro': - case 'ibm1145': - return 'IBM01145'; + /** + * Converts a Windows-1252 encoded string to a UTF-8 encoded string + * + * @static + * @param string $string Windows-1252 encoded string + * @return string UTF-8 encoded string + */ + public static function windows_1252_to_utf8($string) + { + static $convert_table = array("\x80" => "\xE2\x82\xAC", "\x81" => "\xEF\xBF\xBD", "\x82" => "\xE2\x80\x9A", "\x83" => "\xC6\x92", "\x84" => "\xE2\x80\x9E", "\x85" => "\xE2\x80\xA6", "\x86" => "\xE2\x80\xA0", "\x87" => "\xE2\x80\xA1", "\x88" => "\xCB\x86", "\x89" => "\xE2\x80\xB0", "\x8A" => "\xC5\xA0", "\x8B" => "\xE2\x80\xB9", "\x8C" => "\xC5\x92", "\x8D" => "\xEF\xBF\xBD", "\x8E" => "\xC5\xBD", "\x8F" => "\xEF\xBF\xBD", "\x90" => "\xEF\xBF\xBD", "\x91" => "\xE2\x80\x98", "\x92" => "\xE2\x80\x99", "\x93" => "\xE2\x80\x9C", "\x94" => "\xE2\x80\x9D", "\x95" => "\xE2\x80\xA2", "\x96" => "\xE2\x80\x93", "\x97" => "\xE2\x80\x94", "\x98" => "\xCB\x9C", "\x99" => "\xE2\x84\xA2", "\x9A" => "\xC5\xA1", "\x9B" => "\xE2\x80\xBA", "\x9C" => "\xC5\x93", "\x9D" => "\xEF\xBF\xBD", "\x9E" => "\xC5\xBE", "\x9F" => "\xC5\xB8", "\xA0" => "\xC2\xA0", "\xA1" => "\xC2\xA1", "\xA2" => "\xC2\xA2", "\xA3" => "\xC2\xA3", "\xA4" => "\xC2\xA4", "\xA5" => "\xC2\xA5", "\xA6" => "\xC2\xA6", "\xA7" => "\xC2\xA7", "\xA8" => "\xC2\xA8", "\xA9" => "\xC2\xA9", "\xAA" => "\xC2\xAA", "\xAB" => "\xC2\xAB", "\xAC" => "\xC2\xAC", "\xAD" => "\xC2\xAD", "\xAE" => "\xC2\xAE", "\xAF" => "\xC2\xAF", "\xB0" => "\xC2\xB0", "\xB1" => "\xC2\xB1", "\xB2" => "\xC2\xB2", "\xB3" => "\xC2\xB3", "\xB4" => "\xC2\xB4", "\xB5" => "\xC2\xB5", "\xB6" => "\xC2\xB6", "\xB7" => "\xC2\xB7", "\xB8" => "\xC2\xB8", "\xB9" => "\xC2\xB9", "\xBA" => "\xC2\xBA", "\xBB" => "\xC2\xBB", "\xBC" => "\xC2\xBC", "\xBD" => "\xC2\xBD", "\xBE" => "\xC2\xBE", "\xBF" => "\xC2\xBF", "\xC0" => "\xC3\x80", "\xC1" => "\xC3\x81", "\xC2" => "\xC3\x82", "\xC3" => "\xC3\x83", "\xC4" => "\xC3\x84", "\xC5" => "\xC3\x85", "\xC6" => "\xC3\x86", "\xC7" => "\xC3\x87", "\xC8" => "\xC3\x88", "\xC9" => "\xC3\x89", "\xCA" => "\xC3\x8A", "\xCB" => "\xC3\x8B", "\xCC" => "\xC3\x8C", "\xCD" => "\xC3\x8D", "\xCE" => "\xC3\x8E", "\xCF" => "\xC3\x8F", "\xD0" => "\xC3\x90", "\xD1" => "\xC3\x91", "\xD2" => "\xC3\x92", "\xD3" => "\xC3\x93", "\xD4" => "\xC3\x94", "\xD5" => "\xC3\x95", "\xD6" => "\xC3\x96", "\xD7" => "\xC3\x97", "\xD8" => "\xC3\x98", "\xD9" => "\xC3\x99", "\xDA" => "\xC3\x9A", "\xDB" => "\xC3\x9B", "\xDC" => "\xC3\x9C", "\xDD" => "\xC3\x9D", "\xDE" => "\xC3\x9E", "\xDF" => "\xC3\x9F", "\xE0" => "\xC3\xA0", "\xE1" => "\xC3\xA1", "\xE2" => "\xC3\xA2", "\xE3" => "\xC3\xA3", "\xE4" => "\xC3\xA4", "\xE5" => "\xC3\xA5", "\xE6" => "\xC3\xA6", "\xE7" => "\xC3\xA7", "\xE8" => "\xC3\xA8", "\xE9" => "\xC3\xA9", "\xEA" => "\xC3\xAA", "\xEB" => "\xC3\xAB", "\xEC" => "\xC3\xAC", "\xED" => "\xC3\xAD", "\xEE" => "\xC3\xAE", "\xEF" => "\xC3\xAF", "\xF0" => "\xC3\xB0", "\xF1" => "\xC3\xB1", "\xF2" => "\xC3\xB2", "\xF3" => "\xC3\xB3", "\xF4" => "\xC3\xB4", "\xF5" => "\xC3\xB5", "\xF6" => "\xC3\xB6", "\xF7" => "\xC3\xB7", "\xF8" => "\xC3\xB8", "\xF9" => "\xC3\xB9", "\xFA" => "\xC3\xBA", "\xFB" => "\xC3\xBB", "\xFC" => "\xC3\xBC", "\xFD" => "\xC3\xBD", "\xFE" => "\xC3\xBE", "\xFF" => "\xC3\xBF"); - case 'ccsid1146': - case 'cp1146': - case 'ebcdicgb285euro': - case 'ibm1146': - return 'IBM01146'; + return strtr($string, $convert_table); + } - case 'ccsid1147': - case 'cp1147': - case 'ebcdicfr297euro': - case 'ibm1147': - return 'IBM01147'; + /** + * Change a string from one encoding to another + * + * @param string $data Raw data in $input encoding + * @param string $input Encoding of $data + * @param string $output Encoding you want + * @return string|boolean False if we can't convert it + */ + public static function change_encoding($data, $input, $output) + { + $input = SimplePie_Misc::encoding($input); + $output = SimplePie_Misc::encoding($output); - case 'ccsid1148': - case 'cp1148': - case 'ebcdicinternational500euro': - case 'ibm1148': - return 'IBM01148'; + // We fail to fail on non US-ASCII bytes + if ($input === 'US-ASCII') + { + static $non_ascii_octects = ''; + if (!$non_ascii_octects) + { + for ($i = 0x80; $i <= 0xFF; $i++) + { + $non_ascii_octects .= chr($i); + } + } + $data = substr($data, 0, strcspn($data, $non_ascii_octects)); + } - case 'ccsid1149': - case 'cp1149': - case 'ebcdicis871euro': - case 'ibm1149': - return 'IBM01149'; + // This is first, as behaviour of this is completely predictable + if ($input === 'windows-1252' && $output === 'UTF-8') + { + return SimplePie_Misc::windows_1252_to_utf8($data); + } + // This is second, as behaviour of this varies only with PHP version (the middle part of this expression checks the encoding is supported). + elseif (function_exists('mb_convert_encoding') && ($return = SimplePie_Misc::change_encoding_mbstring($data, $input, $output))) + { + return $return; + } + // This is last, as behaviour of this varies with OS userland and PHP version + elseif (function_exists('iconv') && ($return = SimplePie_Misc::change_encoding_iconv($data, $input, $output))) + { + return $return; + } + // If we can't do anything, just fail + else + { + return false; + } + } - case 'csiso143iecp271': - case 'iecp271': - case 'isoir143': - return 'IEC_P27-1'; + protected static function change_encoding_mbstring($data, $input, $output) + { + if ($input === 'windows-949') + { + $input = 'EUC-KR'; + } + if ($output === 'windows-949') + { + $output = 'EUC-KR'; + } + if ($input === 'Windows-31J') + { + $input = 'SJIS'; + } + if ($output === 'Windows-31J') + { + $output = 'SJIS'; + } - case 'csiso49inis': - case 'inis': - case 'isoir49': - return 'INIS'; + // Check that the encoding is supported + if (@mb_convert_encoding("\x80", 'UTF-16BE', $input) === "\x00\x80") + { + return false; + } + if (!in_array($input, mb_list_encodings())) + { + return false; + } - case 'csiso50inis8': - case 'inis8': - case 'isoir50': - return 'INIS-8'; + // Let's do some conversion + if ($return = @mb_convert_encoding($data, $output, $input)) + { + return $return; + } - case 'csiso51iniscyrillic': - case 'iniscyrillic': - case 'isoir51': - return 'INIS-cyrillic'; + return false; + } - case 'csinvariant': - case 'invariant': - return 'INVARIANT'; + protected static function change_encoding_iconv($data, $input, $output) + { + return @iconv($input, $output, $data); + } - case 'iso2022cn': - return 'ISO-2022-CN'; + /** + * Normalize an encoding name + * + * This is automatically generated by create.php + * + * To generate it, run `php create.php` on the command line, and copy the + * output to replace this function. + * + * @param string $charset Character set to standardise + * @return string Standardised name + */ + public static function encoding($charset) + { + // Normalization from UTS #22 + switch (strtolower(preg_replace('/(?:[^a-zA-Z0-9]+|([^0-9])0+)/', '\1', $charset))) + { + case 'adobestandardencoding': + case 'csadobestandardencoding': + return 'Adobe-Standard-Encoding'; - case 'iso2022cnext': - return 'ISO-2022-CN-EXT'; + case 'adobesymbolencoding': + case 'cshppsmath': + return 'Adobe-Symbol-Encoding'; - case 'csiso2022jp': - case 'iso2022jp': - return 'ISO-2022-JP'; + case 'ami1251': + case 'amiga1251': + return 'Amiga-1251'; - case 'csiso2022jp2': - case 'iso2022jp2': - return 'ISO-2022-JP-2'; + case 'ansix31101983': + case 'csat5001983': + case 'csiso99naplps': + case 'isoir99': + case 'naplps': + return 'ANSI_X3.110-1983'; - case 'csiso2022kr': - case 'iso2022kr': - return 'ISO-2022-KR'; + case 'arabic7': + case 'asmo449': + case 'csiso89asmo449': + case 'iso9036': + case 'isoir89': + return 'ASMO_449'; - case 'cswindows30latin1': - case 'iso88591windows30latin1': - return 'ISO-8859-1-Windows-3.0-Latin-1'; + case 'big5': + case 'csbig5': + return 'Big5'; - case 'cswindows31latin1': - case 'iso88591windows31latin1': - return 'ISO-8859-1-Windows-3.1-Latin-1'; + case 'big5hkscs': + return 'Big5-HKSCS'; - case 'csisolatin2': - case 'iso88592': - case 'iso885921987': - case 'isoir101': - case 'l2': - case 'latin2': - return 'ISO-8859-2'; - - case 'cswindows31latin2': - case 'iso88592windowslatin2': - return 'ISO-8859-2-Windows-Latin-2'; + case 'bocu1': + case 'csbocu1': + return 'BOCU-1'; - case 'csisolatin3': - case 'iso88593': - case 'iso885931988': - case 'isoir109': - case 'l3': - case 'latin3': - return 'ISO-8859-3'; + case 'brf': + case 'csbrf': + return 'BRF'; - case 'csisolatin4': - case 'iso88594': - case 'iso885941988': - case 'isoir110': - case 'l4': - case 'latin4': - return 'ISO-8859-4'; + case 'bs4730': + case 'csiso4unitedkingdom': + case 'gb': + case 'iso646gb': + case 'isoir4': + case 'uk': + return 'BS_4730'; - case 'csisolatincyrillic': - case 'cyrillic': - case 'iso88595': - case 'iso885951988': - case 'isoir144': - return 'ISO-8859-5'; + case 'bsviewdata': + case 'csiso47bsviewdata': + case 'isoir47': + return 'BS_viewdata'; - case 'arabic': - case 'asmo708': - case 'csisolatinarabic': - case 'ecma114': - case 'iso88596': - case 'iso885961987': - case 'isoir127': - return 'ISO-8859-6'; + case 'cesu8': + case 'cscesu8': + return 'CESU-8'; - case 'csiso88596e': - case 'iso88596e': - return 'ISO-8859-6-E'; + case 'ca': + case 'csa71': + case 'csaz243419851': + case 'csiso121canadian1': + case 'iso646ca': + case 'isoir121': + return 'CSA_Z243.4-1985-1'; - case 'csiso88596i': - case 'iso88596i': - return 'ISO-8859-6-I'; + case 'csa72': + case 'csaz243419852': + case 'csiso122canadian2': + case 'iso646ca2': + case 'isoir122': + return 'CSA_Z243.4-1985-2'; - case 'csisolatingreek': - case 'ecma118': - case 'elot928': - case 'greek': - case 'greek8': - case 'iso88597': - case 'iso885971987': - case 'isoir126': - return 'ISO-8859-7'; + case 'csaz24341985gr': + case 'csiso123csaz24341985gr': + case 'isoir123': + return 'CSA_Z243.4-1985-gr'; - case 'csisolatinhebrew': - case 'hebrew': - case 'iso88598': - case 'iso885981988': - case 'isoir138': - return 'ISO-8859-8'; + case 'csiso139csn369103': + case 'csn369103': + case 'isoir139': + return 'CSN_369103'; - case 'csiso88598e': - case 'iso88598e': - return 'ISO-8859-8-E'; + case 'csdecmcs': + case 'dec': + case 'decmcs': + return 'DEC-MCS'; - case 'csiso88598i': - case 'iso88598i': - return 'ISO-8859-8-I'; + case 'csiso21german': + case 'de': + case 'din66003': + case 'iso646de': + case 'isoir21': + return 'DIN_66003'; - case 'cswindows31latin5': - case 'iso88599windowslatin5': - return 'ISO-8859-9-Windows-Latin-5'; + case 'csdkus': + case 'dkus': + return 'dk-us'; - case 'csisolatin6': - case 'iso885910': - case 'iso8859101992': - case 'isoir157': - case 'l6': - case 'latin6': - return 'ISO-8859-10'; + case 'csiso646danish': + case 'dk': + case 'ds2089': + case 'iso646dk': + return 'DS_2089'; - case 'iso885913': - return 'ISO-8859-13'; + case 'csibmebcdicatde': + case 'ebcdicatde': + return 'EBCDIC-AT-DE'; - case 'iso885914': - case 'iso8859141998': - case 'isoceltic': - case 'isoir199': - case 'l8': - case 'latin8': - return 'ISO-8859-14'; + case 'csebcdicatdea': + case 'ebcdicatdea': + return 'EBCDIC-AT-DE-A'; - case 'iso885915': - case 'latin9': - return 'ISO-8859-15'; + case 'csebcdiccafr': + case 'ebcdiccafr': + return 'EBCDIC-CA-FR'; - case 'iso885916': - case 'iso8859162001': - case 'isoir226': - case 'l10': - case 'latin10': - return 'ISO-8859-16'; + case 'csebcdicdkno': + case 'ebcdicdkno': + return 'EBCDIC-DK-NO'; - case 'iso10646j1': - return 'ISO-10646-J-1'; + case 'csebcdicdknoa': + case 'ebcdicdknoa': + return 'EBCDIC-DK-NO-A'; - case 'csunicode': - case 'iso10646ucs2': - return 'ISO-10646-UCS-2'; + case 'csebcdices': + case 'ebcdices': + return 'EBCDIC-ES'; - case 'csucs4': - case 'iso10646ucs4': - return 'ISO-10646-UCS-4'; + case 'csebcdicesa': + case 'ebcdicesa': + return 'EBCDIC-ES-A'; - case 'csunicodeascii': - case 'iso10646ucsbasic': - return 'ISO-10646-UCS-Basic'; + case 'csebcdicess': + case 'ebcdicess': + return 'EBCDIC-ES-S'; - case 'csunicodelatin1': - case 'iso10646': - case 'iso10646unicodelatin1': - return 'ISO-10646-Unicode-Latin1'; + case 'csebcdicfise': + case 'ebcdicfise': + return 'EBCDIC-FI-SE'; - case 'csiso10646utf1': - case 'iso10646utf1': - return 'ISO-10646-UTF-1'; + case 'csebcdicfisea': + case 'ebcdicfisea': + return 'EBCDIC-FI-SE-A'; - case 'csiso115481': - case 'iso115481': - case 'isotr115481': - return 'ISO-11548-1'; + case 'csebcdicfr': + case 'ebcdicfr': + return 'EBCDIC-FR'; - case 'csiso90': - case 'isoir90': - return 'iso-ir-90'; + case 'csebcdicit': + case 'ebcdicit': + return 'EBCDIC-IT'; - case 'csunicodeibm1261': - case 'isounicodeibm1261': - return 'ISO-Unicode-IBM-1261'; + case 'csebcdicpt': + case 'ebcdicpt': + return 'EBCDIC-PT'; - case 'csunicodeibm1264': - case 'isounicodeibm1264': - return 'ISO-Unicode-IBM-1264'; + case 'csebcdicuk': + case 'ebcdicuk': + return 'EBCDIC-UK'; - case 'csunicodeibm1265': - case 'isounicodeibm1265': - return 'ISO-Unicode-IBM-1265'; + case 'csebcdicus': + case 'ebcdicus': + return 'EBCDIC-US'; - case 'csunicodeibm1268': - case 'isounicodeibm1268': - return 'ISO-Unicode-IBM-1268'; + case 'csiso111ecmacyrillic': + case 'ecmacyrillic': + case 'isoir111': + case 'koi8e': + return 'ECMA-cyrillic'; - case 'csunicodeibm1276': - case 'isounicodeibm1276': - return 'ISO-Unicode-IBM-1276'; + case 'csiso17spanish': + case 'es': + case 'iso646es': + case 'isoir17': + return 'ES'; - case 'csiso646basic1983': - case 'iso646basic1983': - case 'ref': - return 'ISO_646.basic:1983'; + case 'csiso85spanish2': + case 'es2': + case 'iso646es2': + case 'isoir85': + return 'ES2'; - case 'csiso2intlrefversion': - case 'irv': - case 'iso646irv1983': - case 'isoir2': - return 'ISO_646.irv:1983'; - - case 'csiso2033': - case 'e13b': - case 'iso20331983': - case 'isoir98': - return 'ISO_2033-1983'; + case 'cseucpkdfmtjapanese': + case 'eucjp': + case 'extendedunixcodepackedformatforjapanese': + return 'EUC-JP'; - case 'csiso5427cyrillic': - case 'iso5427': - case 'isoir37': - return 'ISO_5427'; + case 'cseucfixwidjapanese': + case 'extendedunixcodefixedwidthforjapanese': + return 'Extended_UNIX_Code_Fixed_Width_for_Japanese'; - case 'iso5427cyrillic1981': - case 'iso54271981': - case 'isoir54': - return 'ISO_5427:1981'; + case 'gb18030': + return 'GB18030'; - case 'csiso5428greek': - case 'iso54281980': - case 'isoir55': - return 'ISO_5428:1980'; + case 'chinese': + case 'cp936': + case 'csgb2312': + case 'csiso58gb231280': + case 'gb2312': + case 'gb231280': + case 'gbk': + case 'isoir58': + case 'ms936': + case 'windows936': + return 'GBK'; - case 'csiso6937add': - case 'iso6937225': - case 'isoir152': - return 'ISO_6937-2-25'; + case 'cn': + case 'csiso57gb1988': + case 'gb198880': + case 'iso646cn': + case 'isoir57': + return 'GB_1988-80'; - case 'csisotextcomm': - case 'iso69372add': - case 'isoir142': - return 'ISO_6937-2-add'; + case 'csiso153gost1976874': + case 'gost1976874': + case 'isoir153': + case 'stsev35888': + return 'GOST_19768-74'; - case 'csiso8859supp': - case 'iso8859supp': - case 'isoir154': - case 'latin125': - return 'ISO_8859-supp'; + case 'csiso150': + case 'csiso150greekccitt': + case 'greekccitt': + case 'isoir150': + return 'greek-ccitt'; - case 'csiso10367box': - case 'iso10367box': - case 'isoir155': - return 'ISO_10367-box'; + case 'csiso88greek7': + case 'greek7': + case 'isoir88': + return 'greek7'; - case 'csiso15italian': - case 'iso646it': - case 'isoir15': - case 'it': - return 'IT'; + case 'csiso18greek7old': + case 'greek7old': + case 'isoir18': + return 'greek7-old'; - case 'csiso13jisc6220jp': - case 'isoir13': - case 'jisc62201969': - case 'jisc62201969jp': - case 'katakana': - case 'x2017': - return 'JIS_C6220-1969-jp'; + case 'cshpdesktop': + case 'hpdesktop': + return 'HP-DeskTop'; - case 'csiso14jisc6220ro': - case 'iso646jp': - case 'isoir14': - case 'jisc62201969ro': - case 'jp': - return 'JIS_C6220-1969-ro'; + case 'cshplegal': + case 'hplegal': + return 'HP-Legal'; - case 'csiso42jisc62261978': - case 'isoir42': - case 'jisc62261978': - return 'JIS_C6226-1978'; + case 'cshpmath8': + case 'hpmath8': + return 'HP-Math8'; - case 'csiso87jisx208': - case 'isoir87': - case 'jisc62261983': - case 'jisx2081983': - case 'x208': - return 'JIS_C6226-1983'; + case 'cshppifont': + case 'hppifont': + return 'HP-Pi-font'; - case 'csiso91jisc62291984a': - case 'isoir91': - case 'jisc62291984a': - case 'jpocra': - return 'JIS_C6229-1984-a'; + case 'cshproman8': + case 'hproman8': + case 'r8': + case 'roman8': + return 'hp-roman8'; - case 'csiso92jisc62991984b': - case 'iso646jpocrb': - case 'isoir92': - case 'jisc62291984b': - case 'jpocrb': - return 'JIS_C6229-1984-b'; + case 'hzgb2312': + return 'HZ-GB-2312'; - case 'csiso93jis62291984badd': - case 'isoir93': - case 'jisc62291984badd': - case 'jpocrbadd': - return 'JIS_C6229-1984-b-add'; + case 'csibmsymbols': + case 'ibmsymbols': + return 'IBM-Symbols'; - case 'csiso94jis62291984hand': - case 'isoir94': - case 'jisc62291984hand': - case 'jpocrhand': - return 'JIS_C6229-1984-hand'; + case 'csibmthai': + case 'ibmthai': + return 'IBM-Thai'; - case 'csiso95jis62291984handadd': - case 'isoir95': - case 'jisc62291984handadd': - case 'jpocrhandadd': - return 'JIS_C6229-1984-hand-add'; + case 'cp37': + case 'csibm37': + case 'ebcdiccpca': + case 'ebcdiccpnl': + case 'ebcdiccpus': + case 'ebcdiccpwt': + case 'ibm37': + return 'IBM037'; - case 'csiso96jisc62291984kana': - case 'isoir96': - case 'jisc62291984kana': - return 'JIS_C6229-1984-kana'; + case 'cp38': + case 'csibm38': + case 'ebcdicint': + case 'ibm38': + return 'IBM038'; - case 'csjisencoding': - case 'jisencoding': - return 'JIS_Encoding'; + case 'cp273': + case 'csibm273': + case 'ibm273': + return 'IBM273'; - case 'cshalfwidthkatakana': - case 'jisx201': - case 'x201': - return 'JIS_X0201'; + case 'cp274': + case 'csibm274': + case 'ebcdicbe': + case 'ibm274': + return 'IBM274'; - case 'csiso159jisx2121990': - case 'isoir159': - case 'jisx2121990': - case 'x212': - return 'JIS_X0212-1990'; + case 'cp275': + case 'csibm275': + case 'ebcdicbr': + case 'ibm275': + return 'IBM275'; - case 'csiso141jusib1002': - case 'iso646yu': - case 'isoir141': - case 'js': - case 'jusib1002': - case 'yu': - return 'JUS_I.B1.002'; + case 'csibm277': + case 'ebcdiccpdk': + case 'ebcdiccpno': + case 'ibm277': + return 'IBM277'; - case 'csiso147macedonian': - case 'isoir147': - case 'jusib1003mac': - case 'macedonian': - return 'JUS_I.B1.003-mac'; + case 'cp278': + case 'csibm278': + case 'ebcdiccpfi': + case 'ebcdiccpse': + case 'ibm278': + return 'IBM278'; - case 'csiso146serbian': - case 'isoir146': - case 'jusib1003serb': - case 'serbian': - return 'JUS_I.B1.003-serb'; + case 'cp280': + case 'csibm280': + case 'ebcdiccpit': + case 'ibm280': + return 'IBM280'; - case 'koi7switched': - return 'KOI7-switched'; + case 'cp281': + case 'csibm281': + case 'ebcdicjpe': + case 'ibm281': + return 'IBM281'; - case 'cskoi8r': - case 'koi8r': - return 'KOI8-R'; + case 'cp284': + case 'csibm284': + case 'ebcdiccpes': + case 'ibm284': + return 'IBM284'; - case 'koi8u': - return 'KOI8-U'; + case 'cp285': + case 'csibm285': + case 'ebcdiccpgb': + case 'ibm285': + return 'IBM285'; - case 'csksc5636': - case 'iso646kr': - case 'ksc5636': - return 'KSC5636'; + case 'cp290': + case 'csibm290': + case 'ebcdicjpkana': + case 'ibm290': + return 'IBM290'; - case 'cskz1048': - case 'kz1048': - case 'rk1048': - case 'strk10482002': - return 'KZ-1048'; + case 'cp297': + case 'csibm297': + case 'ebcdiccpfr': + case 'ibm297': + return 'IBM297'; - case 'csiso19latingreek': - case 'isoir19': - case 'latingreek': - return 'latin-greek'; + case 'cp420': + case 'csibm420': + case 'ebcdiccpar1': + case 'ibm420': + return 'IBM420'; - case 'csiso27latingreek1': - case 'isoir27': - case 'latingreek1': - return 'Latin-greek-1'; + case 'cp423': + case 'csibm423': + case 'ebcdiccpgr': + case 'ibm423': + return 'IBM423'; - case 'csiso158lap': - case 'isoir158': - case 'lap': - case 'latinlap': - return 'latin-lap'; + case 'cp424': + case 'csibm424': + case 'ebcdiccphe': + case 'ibm424': + return 'IBM424'; - case 'csmacintosh': - case 'mac': - case 'macintosh': - return 'macintosh'; + case '437': + case 'cp437': + case 'cspc8codepage437': + case 'ibm437': + return 'IBM437'; - case 'csmicrosoftpublishing': - case 'microsoftpublishing': - return 'Microsoft-Publishing'; + case 'cp500': + case 'csibm500': + case 'ebcdiccpbe': + case 'ebcdiccpch': + case 'ibm500': + return 'IBM500'; - case 'csmnem': - case 'mnem': - return 'MNEM'; + case 'cp775': + case 'cspc775baltic': + case 'ibm775': + return 'IBM775'; - case 'csmnemonic': - case 'mnemonic': - return 'MNEMONIC'; + case '850': + case 'cp850': + case 'cspc850multilingual': + case 'ibm850': + return 'IBM850'; - case 'csiso86hungarian': - case 'hu': - case 'iso646hu': - case 'isoir86': - case 'msz77953': - return 'MSZ_7795.3'; + case '851': + case 'cp851': + case 'csibm851': + case 'ibm851': + return 'IBM851'; - case 'csnatsdano': - case 'isoir91': - case 'natsdano': - return 'NATS-DANO'; + case '852': + case 'cp852': + case 'cspcp852': + case 'ibm852': + return 'IBM852'; - case 'csnatsdanoadd': - case 'isoir92': - case 'natsdanoadd': - return 'NATS-DANO-ADD'; + case '855': + case 'cp855': + case 'csibm855': + case 'ibm855': + return 'IBM855'; - case 'csnatssefi': - case 'isoir81': - case 'natssefi': - return 'NATS-SEFI'; + case '857': + case 'cp857': + case 'csibm857': + case 'ibm857': + return 'IBM857'; - case 'csnatssefiadd': - case 'isoir82': - case 'natssefiadd': - return 'NATS-SEFI-ADD'; + case 'ccsid858': + case 'cp858': + case 'ibm858': + case 'pcmultilingual850euro': + return 'IBM00858'; - case 'csiso151cuba': - case 'cuba': - case 'iso646cu': - case 'isoir151': - case 'ncnc1081': - return 'NC_NC00-10:81'; + case '860': + case 'cp860': + case 'csibm860': + case 'ibm860': + return 'IBM860'; - case 'csiso69french': - case 'fr': - case 'iso646fr': - case 'isoir69': - case 'nfz62010': - return 'NF_Z_62-010'; + case '861': + case 'cp861': + case 'cpis': + case 'csibm861': + case 'ibm861': + return 'IBM861'; - case 'csiso25french': - case 'iso646fr1': - case 'isoir25': - case 'nfz620101973': - return 'NF_Z_62-010_(1973)'; + case '862': + case 'cp862': + case 'cspc862latinhebrew': + case 'ibm862': + return 'IBM862'; - case 'csiso60danishnorwegian': - case 'csiso60norwegian1': - case 'iso646no': - case 'isoir60': - case 'no': - case 'ns45511': - return 'NS_4551-1'; + case '863': + case 'cp863': + case 'csibm863': + case 'ibm863': + return 'IBM863'; - case 'csiso61norwegian2': - case 'iso646no2': - case 'isoir61': - case 'no2': - case 'ns45512': - return 'NS_4551-2'; + case 'cp864': + case 'csibm864': + case 'ibm864': + return 'IBM864'; - case 'osdebcdicdf3irv': - return 'OSD_EBCDIC_DF03_IRV'; + case '865': + case 'cp865': + case 'csibm865': + case 'ibm865': + return 'IBM865'; - case 'osdebcdicdf41': - return 'OSD_EBCDIC_DF04_1'; + case '866': + case 'cp866': + case 'csibm866': + case 'ibm866': + return 'IBM866'; - case 'osdebcdicdf415': - return 'OSD_EBCDIC_DF04_15'; + case 'cp868': + case 'cpar': + case 'csibm868': + case 'ibm868': + return 'IBM868'; - case 'cspc8danishnorwegian': - case 'pc8danishnorwegian': - return 'PC8-Danish-Norwegian'; + case '869': + case 'cp869': + case 'cpgr': + case 'csibm869': + case 'ibm869': + return 'IBM869'; - case 'cspc8turkish': - case 'pc8turkish': - return 'PC8-Turkish'; + case 'cp870': + case 'csibm870': + case 'ebcdiccproece': + case 'ebcdiccpyu': + case 'ibm870': + return 'IBM870'; - case 'csiso16portuguese': - case 'iso646pt': - case 'isoir16': - case 'pt': - return 'PT'; + case 'cp871': + case 'csibm871': + case 'ebcdiccpis': + case 'ibm871': + return 'IBM871'; - case 'csiso84portuguese2': - case 'iso646pt2': - case 'isoir84': - case 'pt2': - return 'PT2'; + case 'cp880': + case 'csibm880': + case 'ebcdiccyrillic': + case 'ibm880': + return 'IBM880'; - case 'cp154': - case 'csptcp154': - case 'cyrillicasian': - case 'pt154': - case 'ptcp154': - return 'PTCP154'; + case 'cp891': + case 'csibm891': + case 'ibm891': + return 'IBM891'; - case 'scsu': - return 'SCSU'; - - case 'csiso10swedish': - case 'fi': - case 'iso646fi': - case 'iso646se': - case 'isoir10': - case 'se': - case 'sen850200b': - return 'SEN_850200_B'; + case 'cp903': + case 'csibm903': + case 'ibm903': + return 'IBM903'; - case 'csiso11swedishfornames': - case 'iso646se2': - case 'isoir11': - case 'se2': - case 'sen850200c': - return 'SEN_850200_C'; + case '904': + case 'cp904': + case 'csibbm904': + case 'ibm904': + return 'IBM904'; - case 'csiso102t617bit': - case 'isoir102': - case 't617bit': - return 'T.61-7bit'; + case 'cp905': + case 'csibm905': + case 'ebcdiccptr': + case 'ibm905': + return 'IBM905'; - case 'csiso103t618bit': - case 'isoir103': - case 't61': - case 't618bit': - return 'T.61-8bit'; + case 'cp918': + case 'csibm918': + case 'ebcdiccpar2': + case 'ibm918': + return 'IBM918'; - case 'csiso128t101g2': - case 'isoir128': - case 't101g2': - return 'T.101-G2'; + case 'ccsid924': + case 'cp924': + case 'ebcdiclatin9euro': + case 'ibm924': + return 'IBM00924'; - case 'cstscii': - case 'tscii': - return 'TSCII'; + case 'cp1026': + case 'csibm1026': + case 'ibm1026': + return 'IBM1026'; - case 'csunicode11': - case 'unicode11': - return 'UNICODE-1-1'; + case 'ibm1047': + return 'IBM1047'; - case 'csunicode11utf7': - case 'unicode11utf7': - return 'UNICODE-1-1-UTF-7'; + case 'ccsid1140': + case 'cp1140': + case 'ebcdicus37euro': + case 'ibm1140': + return 'IBM01140'; - case 'csunknown8bit': - case 'unknown8bit': - return 'UNKNOWN-8BIT'; + case 'ccsid1141': + case 'cp1141': + case 'ebcdicde273euro': + case 'ibm1141': + return 'IBM01141'; - case 'ansix341968': - case 'ansix341986': - case 'ascii': - case 'cp367': - case 'csascii': - case 'ibm367': - case 'iso646irv1991': - case 'iso646us': - case 'isoir6': - case 'us': - case 'usascii': - return 'US-ASCII'; + case 'ccsid1142': + case 'cp1142': + case 'ebcdicdk277euro': + case 'ebcdicno277euro': + case 'ibm1142': + return 'IBM01142'; - case 'csusdk': - case 'usdk': - return 'us-dk'; + case 'ccsid1143': + case 'cp1143': + case 'ebcdicfi278euro': + case 'ebcdicse278euro': + case 'ibm1143': + return 'IBM01143'; - case 'utf7': - return 'UTF-7'; + case 'ccsid1144': + case 'cp1144': + case 'ebcdicit280euro': + case 'ibm1144': + return 'IBM01144'; - case 'utf8': - return 'UTF-8'; + case 'ccsid1145': + case 'cp1145': + case 'ebcdices284euro': + case 'ibm1145': + return 'IBM01145'; - case 'utf16': - return 'UTF-16'; + case 'ccsid1146': + case 'cp1146': + case 'ebcdicgb285euro': + case 'ibm1146': + return 'IBM01146'; - case 'utf16be': - return 'UTF-16BE'; + case 'ccsid1147': + case 'cp1147': + case 'ebcdicfr297euro': + case 'ibm1147': + return 'IBM01147'; - case 'utf16le': - return 'UTF-16LE'; + case 'ccsid1148': + case 'cp1148': + case 'ebcdicinternational500euro': + case 'ibm1148': + return 'IBM01148'; - case 'utf32': - return 'UTF-32'; + case 'ccsid1149': + case 'cp1149': + case 'ebcdicis871euro': + case 'ibm1149': + return 'IBM01149'; - case 'utf32be': - return 'UTF-32BE'; + case 'csiso143iecp271': + case 'iecp271': + case 'isoir143': + return 'IEC_P27-1'; - case 'utf32le': - return 'UTF-32LE'; + case 'csiso49inis': + case 'inis': + case 'isoir49': + return 'INIS'; - case 'csventurainternational': - case 'venturainternational': - return 'Ventura-International'; + case 'csiso50inis8': + case 'inis8': + case 'isoir50': + return 'INIS-8'; - case 'csventuramath': - case 'venturamath': - return 'Ventura-Math'; + case 'csiso51iniscyrillic': + case 'iniscyrillic': + case 'isoir51': + return 'INIS-cyrillic'; - case 'csventuraus': - case 'venturaus': - return 'Ventura-US'; + case 'csinvariant': + case 'invariant': + return 'INVARIANT'; - case 'csiso70videotexsupp1': - case 'isoir70': - case 'videotexsuppl': - return 'videotex-suppl'; + case 'iso2022cn': + return 'ISO-2022-CN'; - case 'csviqr': - case 'viqr': - return 'VIQR'; + case 'iso2022cnext': + return 'ISO-2022-CN-EXT'; - case 'csviscii': - case 'viscii': - return 'VISCII'; + case 'csiso2022jp': + case 'iso2022jp': + return 'ISO-2022-JP'; - case 'csshiftjis': - case 'cswindows31j': - case 'mskanji': - case 'shiftjis': - case 'windows31j': - return 'Windows-31J'; + case 'csiso2022jp2': + case 'iso2022jp2': + return 'ISO-2022-JP-2'; - case 'iso885911': - case 'tis620': - return 'windows-874'; + case 'csiso2022kr': + case 'iso2022kr': + return 'ISO-2022-KR'; - case 'cseuckr': - case 'csksc56011987': - case 'euckr': - case 'isoir149': - case 'korean': - case 'ksc5601': - case 'ksc56011987': - case 'ksc56011989': - case 'windows949': - return 'windows-949'; + case 'cswindows30latin1': + case 'iso88591windows30latin1': + return 'ISO-8859-1-Windows-3.0-Latin-1'; - case 'windows1250': - return 'windows-1250'; + case 'cswindows31latin1': + case 'iso88591windows31latin1': + return 'ISO-8859-1-Windows-3.1-Latin-1'; - case 'windows1251': - return 'windows-1251'; + case 'csisolatin2': + case 'iso88592': + case 'iso885921987': + case 'isoir101': + case 'l2': + case 'latin2': + return 'ISO-8859-2'; - case 'cp819': - case 'csisolatin1': - case 'ibm819': - case 'iso88591': - case 'iso885911987': - case 'isoir100': - case 'l1': - case 'latin1': - case 'windows1252': - return 'windows-1252'; + case 'cswindows31latin2': + case 'iso88592windowslatin2': + return 'ISO-8859-2-Windows-Latin-2'; - case 'windows1253': - return 'windows-1253'; + case 'csisolatin3': + case 'iso88593': + case 'iso885931988': + case 'isoir109': + case 'l3': + case 'latin3': + return 'ISO-8859-3'; - case 'csisolatin5': - case 'iso88599': - case 'iso885991989': - case 'isoir148': - case 'l5': - case 'latin5': - case 'windows1254': - return 'windows-1254'; + case 'csisolatin4': + case 'iso88594': + case 'iso885941988': + case 'isoir110': + case 'l4': + case 'latin4': + return 'ISO-8859-4'; - case 'windows1255': - return 'windows-1255'; + case 'csisolatincyrillic': + case 'cyrillic': + case 'iso88595': + case 'iso885951988': + case 'isoir144': + return 'ISO-8859-5'; - case 'windows1256': - return 'windows-1256'; + case 'arabic': + case 'asmo708': + case 'csisolatinarabic': + case 'ecma114': + case 'iso88596': + case 'iso885961987': + case 'isoir127': + return 'ISO-8859-6'; - case 'windows1257': - return 'windows-1257'; + case 'csiso88596e': + case 'iso88596e': + return 'ISO-8859-6-E'; - case 'windows1258': - return 'windows-1258'; + case 'csiso88596i': + case 'iso88596i': + return 'ISO-8859-6-I'; - default: - return $charset; - } - } + case 'csisolatingreek': + case 'ecma118': + case 'elot928': + case 'greek': + case 'greek8': + case 'iso88597': + case 'iso885971987': + case 'isoir126': + return 'ISO-8859-7'; - function get_curl_version() - { - if (is_array($curl = curl_version())) - { - $curl = $curl['version']; - } - elseif (substr($curl, 0, 5) === 'curl/') - { - $curl = substr($curl, 5, strcspn($curl, "\x09\x0A\x0B\x0C\x0D", 5)); - } - elseif (substr($curl, 0, 8) === 'libcurl/') - { - $curl = substr($curl, 8, strcspn($curl, "\x09\x0A\x0B\x0C\x0D", 8)); - } - else - { - $curl = 0; - } - return $curl; - } + case 'csisolatinhebrew': + case 'hebrew': + case 'iso88598': + case 'iso885981988': + case 'isoir138': + return 'ISO-8859-8'; - function is_subclass_of($class1, $class2) - { - if (func_num_args() !== 2) - { - trigger_error('Wrong parameter count for SimplePie_Misc::is_subclass_of()', E_USER_WARNING); - } - elseif (version_compare(PHP_VERSION, '5.0.3', '>=') || is_object($class1)) - { - return is_subclass_of($class1, $class2); - } - elseif (is_string($class1) && is_string($class2)) - { - if (class_exists($class1)) - { - if (class_exists($class2)) - { - $class2 = strtolower($class2); - while ($class1 = strtolower(get_parent_class($class1))) - { - if ($class1 === $class2) - { - return true; - } - } - } - } - else - { - trigger_error('Unknown class passed as parameter', E_USER_WARNNG); - } - } - return false; - } + case 'csiso88598e': + case 'iso88598e': + return 'ISO-8859-8-E'; - /** - * Strip HTML comments - * - * @access public - * @param string $data Data to strip comments from - * @return string Comment stripped string - */ - function strip_comments($data) - { - $output = ''; - while (($start = strpos($data, '<!--')) !== false) - { - $output .= substr($data, 0, $start); - if (($end = strpos($data, '-->', $start)) !== false) - { - $data = substr_replace($data, '', 0, $end + 3); - } - else - { - $data = ''; - } - } - return $output . $data; - } + case 'csiso88598i': + case 'iso88598i': + return 'ISO-8859-8-I'; - function parse_date($dt) - { - $parser = SimplePie_Parse_Date::get(); - return $parser->parse($dt); - } + case 'cswindows31latin5': + case 'iso88599windowslatin5': + return 'ISO-8859-9-Windows-Latin-5'; - /** - * Decode HTML entities - * - * @static - * @access public - * @param string $data Input data - * @return string Output data - */ - function entities_decode($data) - { - $decoder = new SimplePie_Decode_HTML_Entities($data); - return $decoder->parse(); - } + case 'csisolatin6': + case 'iso885910': + case 'iso8859101992': + case 'isoir157': + case 'l6': + case 'latin6': + return 'ISO-8859-10'; - /** - * Remove RFC822 comments - * - * @access public - * @param string $data Data to strip comments from - * @return string Comment stripped string - */ - function uncomment_rfc822($string) - { - $string = (string) $string; - $position = 0; - $length = strlen($string); - $depth = 0; + case 'iso885913': + return 'ISO-8859-13'; - $output = ''; + case 'iso885914': + case 'iso8859141998': + case 'isoceltic': + case 'isoir199': + case 'l8': + case 'latin8': + return 'ISO-8859-14'; - while ($position < $length && ($pos = strpos($string, '(', $position)) !== false) - { - $output .= substr($string, $position, $pos - $position); - $position = $pos + 1; - if ($string[$pos - 1] !== '\\') - { - $depth++; - while ($depth && $position < $length) - { - $position += strcspn($string, '()', $position); - if ($string[$position - 1] === '\\') - { - $position++; - continue; - } - elseif (isset($string[$position])) - { - switch ($string[$position]) - { - case '(': - $depth++; - break; + case 'iso885915': + case 'latin9': + return 'ISO-8859-15'; - case ')': - $depth--; - break; - } - $position++; - } - else - { - break; - } - } - } - else - { - $output .= '('; - } - } - $output .= substr($string, $position); + case 'iso885916': + case 'iso8859162001': + case 'isoir226': + case 'l10': + case 'latin10': + return 'ISO-8859-16'; - return $output; - } + case 'iso10646j1': + return 'ISO-10646-J-1'; - function parse_mime($mime) - { - if (($pos = strpos($mime, ';')) === false) - { - return trim($mime); - } - else - { - return trim(substr($mime, 0, $pos)); - } - } + case 'csunicode': + case 'iso10646ucs2': + return 'ISO-10646-UCS-2'; - function htmlspecialchars_decode($string, $quote_style) - { - if (function_exists('htmlspecialchars_decode')) - { - return htmlspecialchars_decode($string, $quote_style); - } - else - { - return strtr($string, array_flip(get_html_translation_table(HTML_SPECIALCHARS, $quote_style))); - } - } + case 'csucs4': + case 'iso10646ucs4': + return 'ISO-10646-UCS-4'; - function atom_03_construct_type($attribs) - { - if (isset($attribs['']['mode']) && strtolower(trim($attribs['']['mode']) === 'base64')) - { - $mode = SIMPLEPIE_CONSTRUCT_BASE64; - } - else - { - $mode = SIMPLEPIE_CONSTRUCT_NONE; - } - if (isset($attribs['']['type'])) - { - switch (strtolower(trim($attribs['']['type']))) - { - case 'text': - case 'text/plain': - return SIMPLEPIE_CONSTRUCT_TEXT | $mode; + case 'csunicodeascii': + case 'iso10646ucsbasic': + return 'ISO-10646-UCS-Basic'; - case 'html': - case 'text/html': - return SIMPLEPIE_CONSTRUCT_HTML | $mode; + case 'csunicodelatin1': + case 'iso10646': + case 'iso10646unicodelatin1': + return 'ISO-10646-Unicode-Latin1'; - case 'xhtml': - case 'application/xhtml+xml': - return SIMPLEPIE_CONSTRUCT_XHTML | $mode; + case 'csiso10646utf1': + case 'iso10646utf1': + return 'ISO-10646-UTF-1'; - default: - return SIMPLEPIE_CONSTRUCT_NONE | $mode; - } - } - else - { - return SIMPLEPIE_CONSTRUCT_TEXT | $mode; - } - } + case 'csiso115481': + case 'iso115481': + case 'isotr115481': + return 'ISO-11548-1'; - function atom_10_construct_type($attribs) - { - if (isset($attribs['']['type'])) - { - switch (strtolower(trim($attribs['']['type']))) - { - case 'text': - return SIMPLEPIE_CONSTRUCT_TEXT; + case 'csiso90': + case 'isoir90': + return 'iso-ir-90'; - case 'html': - return SIMPLEPIE_CONSTRUCT_HTML; + case 'csunicodeibm1261': + case 'isounicodeibm1261': + return 'ISO-Unicode-IBM-1261'; - case 'xhtml': - return SIMPLEPIE_CONSTRUCT_XHTML; + case 'csunicodeibm1264': + case 'isounicodeibm1264': + return 'ISO-Unicode-IBM-1264'; - default: - return SIMPLEPIE_CONSTRUCT_NONE; - } - } - return SIMPLEPIE_CONSTRUCT_TEXT; - } + case 'csunicodeibm1265': + case 'isounicodeibm1265': + return 'ISO-Unicode-IBM-1265'; - function atom_10_content_construct_type($attribs) - { - if (isset($attribs['']['type'])) - { - $type = strtolower(trim($attribs['']['type'])); - switch ($type) - { - case 'text': - return SIMPLEPIE_CONSTRUCT_TEXT; + case 'csunicodeibm1268': + case 'isounicodeibm1268': + return 'ISO-Unicode-IBM-1268'; - case 'html': - return SIMPLEPIE_CONSTRUCT_HTML; + case 'csunicodeibm1276': + case 'isounicodeibm1276': + return 'ISO-Unicode-IBM-1276'; - case 'xhtml': - return SIMPLEPIE_CONSTRUCT_XHTML; - } - if (in_array(substr($type, -4), array('+xml', '/xml')) || substr($type, 0, 5) === 'text/') - { - return SIMPLEPIE_CONSTRUCT_NONE; - } - else - { - return SIMPLEPIE_CONSTRUCT_BASE64; - } - } - else - { - return SIMPLEPIE_CONSTRUCT_TEXT; - } - } + case 'csiso646basic1983': + case 'iso646basic1983': + case 'ref': + return 'ISO_646.basic:1983'; - function is_isegment_nz_nc($string) - { - return (bool) preg_match('/^([A-Za-z0-9\-._~\x{A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}\x{10000}-\x{1FFFD}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}\x{40000}-\x{4FFFD}\x{50000}-\x{5FFFD}\x{60000}-\x{6FFFD}\x{70000}-\x{7FFFD}\x{80000}-\x{8FFFD}\x{90000}-\x{9FFFD}\x{A0000}-\x{AFFFD}\x{B0000}-\x{BFFFD}\x{C0000}-\x{CFFFD}\x{D0000}-\x{DFFFD}\x{E1000}-\x{EFFFD}!$&\'()*+,;=@]|(%[0-9ABCDEF]{2}))+$/u', $string); - } + case 'csiso2intlrefversion': + case 'irv': + case 'iso646irv1983': + case 'isoir2': + return 'ISO_646.irv:1983'; - function space_seperated_tokens($string) - { - $space_characters = "\x20\x09\x0A\x0B\x0C\x0D"; - $string_length = strlen($string); + case 'csiso2033': + case 'e13b': + case 'iso20331983': + case 'isoir98': + return 'ISO_2033-1983'; - $position = strspn($string, $space_characters); - $tokens = array(); + case 'csiso5427cyrillic': + case 'iso5427': + case 'isoir37': + return 'ISO_5427'; - while ($position < $string_length) - { - $len = strcspn($string, $space_characters, $position); - $tokens[] = substr($string, $position, $len); - $position += $len; - $position += strspn($string, $space_characters, $position); - } + case 'iso5427cyrillic1981': + case 'iso54271981': + case 'isoir54': + return 'ISO_5427:1981'; - return $tokens; - } + case 'csiso5428greek': + case 'iso54281980': + case 'isoir55': + return 'ISO_5428:1980'; - function array_unique($array) - { - if (version_compare(PHP_VERSION, '5.2', '>=')) - { - return array_unique($array); - } - else - { - $array = (array) $array; - $new_array = array(); - $new_array_strings = array(); - foreach ($array as $key => $value) - { - if (is_object($value)) - { - if (method_exists($value, '__toString')) - { - $cmp = $value->__toString(); - } - else - { - trigger_error('Object of class ' . get_class($value) . ' could not be converted to string', E_USER_ERROR); - } - } - elseif (is_array($value)) - { - $cmp = (string) reset($value); - } - else - { - $cmp = (string) $value; - } - if (!in_array($cmp, $new_array_strings)) - { - $new_array[$key] = $value; - $new_array_strings[] = $cmp; - } - } - return $new_array; - } - } + case 'csiso6937add': + case 'iso6937225': + case 'isoir152': + return 'ISO_6937-2-25'; - /** - * Converts a unicode codepoint to a UTF-8 character - * - * @static - * @access public - * @param int $codepoint Unicode codepoint - * @return string UTF-8 character - */ - function codepoint_to_utf8($codepoint) - { - $codepoint = (int) $codepoint; - if ($codepoint < 0) - { - return false; - } - else if ($codepoint <= 0x7f) - { - return chr($codepoint); - } - else if ($codepoint <= 0x7ff) - { - return chr(0xc0 | ($codepoint >> 6)) . chr(0x80 | ($codepoint & 0x3f)); - } - else if ($codepoint <= 0xffff) - { - return chr(0xe0 | ($codepoint >> 12)) . chr(0x80 | (($codepoint >> 6) & 0x3f)) . chr(0x80 | ($codepoint & 0x3f)); - } - else if ($codepoint <= 0x10ffff) - { - return chr(0xf0 | ($codepoint >> 18)) . chr(0x80 | (($codepoint >> 12) & 0x3f)) . chr(0x80 | (($codepoint >> 6) & 0x3f)) . chr(0x80 | ($codepoint & 0x3f)); - } - else - { - // U+FFFD REPLACEMENT CHARACTER - return "\xEF\xBF\xBD"; - } - } + case 'csisotextcomm': + case 'iso69372add': + case 'isoir142': + return 'ISO_6937-2-add'; - /** - * Re-implementation of PHP 5's stripos() - * - * Returns the numeric position of the first occurrence of needle in the - * haystack string. - * - * @static - * @access string - * @param object $haystack - * @param string $needle Note that the needle may be a string of one or more - * characters. If needle is not a string, it is converted to an integer - * and applied as the ordinal value of a character. - * @param int $offset The optional offset parameter allows you to specify which - * character in haystack to start searching. The position returned is still - * relative to the beginning of haystack. - * @return bool If needle is not found, stripos() will return boolean false. - */ - function stripos($haystack, $needle, $offset = 0) - { - if (function_exists('stripos')) - { - return stripos($haystack, $needle, $offset); - } - else - { - if (is_string($needle)) - { - $needle = strtolower($needle); - } - elseif (is_int($needle) || is_bool($needle) || is_double($needle)) - { - $needle = strtolower(chr($needle)); - } - else - { - trigger_error('needle is not a string or an integer', E_USER_WARNING); - return false; - } + case 'csiso8859supp': + case 'iso8859supp': + case 'isoir154': + case 'latin125': + return 'ISO_8859-supp'; - return strpos(strtolower($haystack), $needle, $offset); - } - } + case 'csiso10367box': + case 'iso10367box': + case 'isoir155': + return 'ISO_10367-box'; - /** - * Similar to parse_str() - * - * Returns an associative array of name/value pairs, where the value is an - * array of values that have used the same name - * - * @static - * @access string - * @param string $str The input string. - * @return array - */ - function parse_str($str) - { - $return = array(); - $str = explode('&', $str); + case 'csiso15italian': + case 'iso646it': + case 'isoir15': + case 'it': + return 'IT'; - foreach ($str as $section) - { - if (strpos($section, '=') !== false) - { - list($name, $value) = explode('=', $section, 2); - $return[urldecode($name)][] = urldecode($value); - } - else - { - $return[urldecode($section)][] = null; - } - } + case 'csiso13jisc6220jp': + case 'isoir13': + case 'jisc62201969': + case 'jisc62201969jp': + case 'katakana': + case 'x2017': + return 'JIS_C6220-1969-jp'; - return $return; - } + case 'csiso14jisc6220ro': + case 'iso646jp': + case 'isoir14': + case 'jisc62201969ro': + case 'jp': + return 'JIS_C6220-1969-ro'; - /** - * Detect XML encoding, as per XML 1.0 Appendix F.1 - * - * @todo Add support for EBCDIC - * @param string $data XML data - * @return array Possible encodings - */ - function xml_encoding($data) - { - // UTF-32 Big Endian BOM - if (substr($data, 0, 4) === "\x00\x00\xFE\xFF") - { - $encoding[] = 'UTF-32BE'; - } - // UTF-32 Little Endian BOM - elseif (substr($data, 0, 4) === "\xFF\xFE\x00\x00") - { - $encoding[] = 'UTF-32LE'; - } - // UTF-16 Big Endian BOM - elseif (substr($data, 0, 2) === "\xFE\xFF") - { - $encoding[] = 'UTF-16BE'; - } - // UTF-16 Little Endian BOM - elseif (substr($data, 0, 2) === "\xFF\xFE") - { - $encoding[] = 'UTF-16LE'; - } - // UTF-8 BOM - elseif (substr($data, 0, 3) === "\xEF\xBB\xBF") - { - $encoding[] = 'UTF-8'; - } - // UTF-32 Big Endian Without BOM - elseif (substr($data, 0, 20) === "\x00\x00\x00\x3C\x00\x00\x00\x3F\x00\x00\x00\x78\x00\x00\x00\x6D\x00\x00\x00\x6C") - { - if ($pos = strpos($data, "\x00\x00\x00\x3F\x00\x00\x00\x3E")) - { - $parser = new SimplePie_XML_Declaration_Parser(SimplePie_Misc::change_encoding(substr($data, 20, $pos - 20), 'UTF-32BE', 'UTF-8')); - if ($parser->parse()) - { - $encoding[] = $parser->encoding; - } - } - $encoding[] = 'UTF-32BE'; - } - // UTF-32 Little Endian Without BOM - elseif (substr($data, 0, 20) === "\x3C\x00\x00\x00\x3F\x00\x00\x00\x78\x00\x00\x00\x6D\x00\x00\x00\x6C\x00\x00\x00") - { - if ($pos = strpos($data, "\x3F\x00\x00\x00\x3E\x00\x00\x00")) - { - $parser = new SimplePie_XML_Declaration_Parser(SimplePie_Misc::change_encoding(substr($data, 20, $pos - 20), 'UTF-32LE', 'UTF-8')); - if ($parser->parse()) - { - $encoding[] = $parser->encoding; - } - } - $encoding[] = 'UTF-32LE'; - } - // UTF-16 Big Endian Without BOM - elseif (substr($data, 0, 10) === "\x00\x3C\x00\x3F\x00\x78\x00\x6D\x00\x6C") - { - if ($pos = strpos($data, "\x00\x3F\x00\x3E")) - { - $parser = new SimplePie_XML_Declaration_Parser(SimplePie_Misc::change_encoding(substr($data, 20, $pos - 10), 'UTF-16BE', 'UTF-8')); - if ($parser->parse()) - { - $encoding[] = $parser->encoding; - } - } - $encoding[] = 'UTF-16BE'; - } - // UTF-16 Little Endian Without BOM - elseif (substr($data, 0, 10) === "\x3C\x00\x3F\x00\x78\x00\x6D\x00\x6C\x00") - { - if ($pos = strpos($data, "\x3F\x00\x3E\x00")) - { - $parser = new SimplePie_XML_Declaration_Parser(SimplePie_Misc::change_encoding(substr($data, 20, $pos - 10), 'UTF-16LE', 'UTF-8')); - if ($parser->parse()) - { - $encoding[] = $parser->encoding; - } - } - $encoding[] = 'UTF-16LE'; - } - // US-ASCII (or superset) - elseif (substr($data, 0, 5) === "\x3C\x3F\x78\x6D\x6C") - { - if ($pos = strpos($data, "\x3F\x3E")) - { - $parser = new SimplePie_XML_Declaration_Parser(substr($data, 5, $pos - 5)); - if ($parser->parse()) - { - $encoding[] = $parser->encoding; - } - } - $encoding[] = 'UTF-8'; - } - // Fallback to UTF-8 - else - { - $encoding[] = 'UTF-8'; - } - return $encoding; - } + case 'csiso42jisc62261978': + case 'isoir42': + case 'jisc62261978': + return 'JIS_C6226-1978'; - function output_javascript() - { - if (function_exists('ob_gzhandler')) - { - ob_start('ob_gzhandler'); - } - header('Content-type: text/javascript; charset: UTF-8'); - header('Cache-Control: must-revalidate'); - header('Expires: ' . gmdate('D, d M Y H:i:s', time() + 604800) . ' GMT'); // 7 days - ?> -function embed_odeo(link) { - document.writeln('<embed src="http://odeo.com/flash/audio_player_fullsize.swf" pluginspage="http://www.macromedia.com/go/getflashplayer" type="application/x-shockwave-flash" quality="high" width="440" height="80" wmode="transparent" allowScriptAccess="any" flashvars="valid_sample_rate=true&external_url='+link+'"></embed>'); -} + case 'csiso87jisx208': + case 'isoir87': + case 'jisc62261983': + case 'jisx2081983': + case 'x208': + return 'JIS_C6226-1983'; -function embed_quicktime(type, bgcolor, width, height, link, placeholder, loop) { - if (placeholder != '') { - document.writeln('<embed type="'+type+'" style="cursor:hand; cursor:pointer;" href="'+link+'" src="'+placeholder+'" width="'+width+'" height="'+height+'" autoplay="false" target="myself" controller="false" loop="'+loop+'" scale="aspect" bgcolor="'+bgcolor+'" pluginspage="http://www.apple.com/quicktime/download/"></embed>'); - } - else { - document.writeln('<embed type="'+type+'" style="cursor:hand; cursor:pointer;" src="'+link+'" width="'+width+'" height="'+height+'" autoplay="false" target="myself" controller="true" loop="'+loop+'" scale="aspect" bgcolor="'+bgcolor+'" pluginspage="http://www.apple.com/quicktime/download/"></embed>'); - } -} + case 'csiso91jisc62291984a': + case 'isoir91': + case 'jisc62291984a': + case 'jpocra': + return 'JIS_C6229-1984-a'; -function embed_flash(bgcolor, width, height, link, loop, type) { - document.writeln('<embed src="'+link+'" pluginspage="http://www.macromedia.com/go/getflashplayer" type="'+type+'" quality="high" width="'+width+'" height="'+height+'" bgcolor="'+bgcolor+'" loop="'+loop+'"></embed>'); -} + case 'csiso92jisc62991984b': + case 'iso646jpocrb': + case 'isoir92': + case 'jisc62291984b': + case 'jpocrb': + return 'JIS_C6229-1984-b'; -function embed_flv(width, height, link, placeholder, loop, player) { - document.writeln('<embed src="'+player+'" pluginspage="http://www.macromedia.com/go/getflashplayer" type="application/x-shockwave-flash" quality="high" width="'+width+'" height="'+height+'" wmode="transparent" flashvars="file='+link+'&autostart=false&repeat='+loop+'&showdigits=true&showfsbutton=false"></embed>'); -} + case 'csiso93jis62291984badd': + case 'isoir93': + case 'jisc62291984badd': + case 'jpocrbadd': + return 'JIS_C6229-1984-b-add'; -function embed_wmedia(width, height, link) { - document.writeln('<embed type="application/x-mplayer2" src="'+link+'" autosize="1" width="'+width+'" height="'+height+'" showcontrols="1" showstatusbar="0" showdisplay="0" autostart="0"></embed>'); -} - <?php - } + case 'csiso94jis62291984hand': + case 'isoir94': + case 'jisc62291984hand': + case 'jpocrhand': + return 'JIS_C6229-1984-hand'; + case 'csiso95jis62291984handadd': + case 'isoir95': + case 'jisc62291984handadd': + case 'jpocrhandadd': + return 'JIS_C6229-1984-hand-add'; + case 'csiso96jisc62291984kana': + case 'isoir96': + case 'jisc62291984kana': + return 'JIS_C6229-1984-kana'; - /** - * Format debugging information - */ - function debug($sp) - { - $info = 'SimplePie ' . SIMPLEPIE_VERSION . ' Build ' . SIMPLEPIE_BUILD . "\n"; - $info .= 'PHP ' . PHP_VERSION . "\n"; - if ($sp->error() !== null) - { - $info .= 'Error occurred: ' . $sp->error() . "\n"; - } - else - { - $info .= "No error found.\n"; - } - $info .= "Extensions:\n"; - $extensions = array('pcre', 'curl', 'zlib', 'mbstring', 'iconv', 'xmlreader', 'xml'); - foreach ($extensions as $ext) - { - if (extension_loaded($ext)) - { - $info .= " $ext loaded\n"; - switch ($ext) - { - case 'pcre': - $info .= ' Version ' . PCRE_VERSION . "\n"; - break; - case 'curl': - $version = curl_version(); - $info .= ' Version ' . $version['version'] . "\n"; - break; - case 'mbstring': - $info .= ' Overloading: ' . mb_get_info('func_overload') . "\n"; - break; - case 'iconv': - $info .= ' Version ' . ICONV_VERSION . "\n"; - break; - case 'xml': - $info .= ' Version ' . LIBXML_DOTTED_VERSION . "\n"; - break; - } - } - else - { - $info .= " $ext not loaded\n"; - } - } - return $info; - } -} + case 'csjisencoding': + case 'jisencoding': + return 'JIS_Encoding'; -/** - * Decode HTML Entities - * - * This implements HTML5 as of revision 967 (2007-06-28) - * - * @package SimplePie - */ -class SimplePie_Decode_HTML_Entities -{ - /** - * Data to be parsed - * - * @access private - * @var string - */ - var $data = ''; + case 'cshalfwidthkatakana': + case 'jisx201': + case 'x201': + return 'JIS_X0201'; - /** - * Currently consumed bytes - * - * @access private - * @var string - */ - var $consumed = ''; + case 'csiso159jisx2121990': + case 'isoir159': + case 'jisx2121990': + case 'x212': + return 'JIS_X0212-1990'; - /** - * Position of the current byte being parsed - * - * @access private - * @var int - */ - var $position = 0; + case 'csiso141jusib1002': + case 'iso646yu': + case 'isoir141': + case 'js': + case 'jusib1002': + case 'yu': + return 'JUS_I.B1.002'; - /** - * Create an instance of the class with the input data - * - * @access public - * @param string $data Input data - */ - function SimplePie_Decode_HTML_Entities($data) - { - $this->data = $data; - } + case 'csiso147macedonian': + case 'isoir147': + case 'jusib1003mac': + case 'macedonian': + return 'JUS_I.B1.003-mac'; - /** - * Parse the input data - * - * @access public - * @return string Output data - */ - function parse() - { - while (($this->position = strpos($this->data, '&', $this->position)) !== false) - { - $this->consume(); - $this->entity(); - $this->consumed = ''; - } - return $this->data; - } + case 'csiso146serbian': + case 'isoir146': + case 'jusib1003serb': + case 'serbian': + return 'JUS_I.B1.003-serb'; - /** - * Consume the next byte - * - * @access private - * @return mixed The next byte, or false, if there is no more data - */ - function consume() - { - if (isset($this->data[$this->position])) - { - $this->consumed .= $this->data[$this->position]; - return $this->data[$this->position++]; - } - else - { - return false; - } - } + case 'koi7switched': + return 'KOI7-switched'; - /** - * Consume a range of characters - * - * @access private - * @param string $chars Characters to consume - * @return mixed A series of characters that match the range, or false - */ - function consume_range($chars) - { - if ($len = strspn($this->data, $chars, $this->position)) - { - $data = substr($this->data, $this->position, $len); - $this->consumed .= $data; - $this->position += $len; - return $data; - } - else - { - return false; - } - } + case 'cskoi8r': + case 'koi8r': + return 'KOI8-R'; - /** - * Unconsume one byte - * - * @access private - */ - function unconsume() - { - $this->consumed = substr($this->consumed, 0, -1); - $this->position--; - } + case 'koi8u': + return 'KOI8-U'; - /** - * Decode an entity - * - * @access private - */ - function entity() - { - switch ($this->consume()) - { - case "\x09": - case "\x0A": - case "\x0B": - case "\x0B": - case "\x0C": - case "\x20": - case "\x3C": - case "\x26": - case false: - break; + case 'csksc5636': + case 'iso646kr': + case 'ksc5636': + return 'KSC5636'; - case "\x23": - switch ($this->consume()) - { - case "\x78": - case "\x58": - $range = '0123456789ABCDEFabcdef'; - $hex = true; - break; + case 'cskz1048': + case 'kz1048': + case 'rk1048': + case 'strk10482002': + return 'KZ-1048'; - default: - $range = '0123456789'; - $hex = false; - $this->unconsume(); - break; - } + case 'csiso19latingreek': + case 'isoir19': + case 'latingreek': + return 'latin-greek'; - if ($codepoint = $this->consume_range($range)) - { - static $windows_1252_specials = array(0x0D => "\x0A", 0x80 => "\xE2\x82\xAC", 0x81 => "\xEF\xBF\xBD", 0x82 => "\xE2\x80\x9A", 0x83 => "\xC6\x92", 0x84 => "\xE2\x80\x9E", 0x85 => "\xE2\x80\xA6", 0x86 => "\xE2\x80\xA0", 0x87 => "\xE2\x80\xA1", 0x88 => "\xCB\x86", 0x89 => "\xE2\x80\xB0", 0x8A => "\xC5\xA0", 0x8B => "\xE2\x80\xB9", 0x8C => "\xC5\x92", 0x8D => "\xEF\xBF\xBD", 0x8E => "\xC5\xBD", 0x8F => "\xEF\xBF\xBD", 0x90 => "\xEF\xBF\xBD", 0x91 => "\xE2\x80\x98", 0x92 => "\xE2\x80\x99", 0x93 => "\xE2\x80\x9C", 0x94 => "\xE2\x80\x9D", 0x95 => "\xE2\x80\xA2", 0x96 => "\xE2\x80\x93", 0x97 => "\xE2\x80\x94", 0x98 => "\xCB\x9C", 0x99 => "\xE2\x84\xA2", 0x9A => "\xC5\xA1", 0x9B => "\xE2\x80\xBA", 0x9C => "\xC5\x93", 0x9D => "\xEF\xBF\xBD", 0x9E => "\xC5\xBE", 0x9F => "\xC5\xB8"); + case 'csiso27latingreek1': + case 'isoir27': + case 'latingreek1': + return 'Latin-greek-1'; - if ($hex) - { - $codepoint = hexdec($codepoint); - } - else - { - $codepoint = intval($codepoint); - } + case 'csiso158lap': + case 'isoir158': + case 'lap': + case 'latinlap': + return 'latin-lap'; - if (isset($windows_1252_specials[$codepoint])) - { - $replacement = $windows_1252_specials[$codepoint]; - } - else - { - $replacement = SimplePie_Misc::codepoint_to_utf8($codepoint); - } + case 'csmacintosh': + case 'mac': + case 'macintosh': + return 'macintosh'; - if (!in_array($this->consume(), array(';', false), true)) - { - $this->unconsume(); - } + case 'csmicrosoftpublishing': + case 'microsoftpublishing': + return 'Microsoft-Publishing'; - $consumed_length = strlen($this->consumed); - $this->data = substr_replace($this->data, $replacement, $this->position - $consumed_length, $consumed_length); - $this->position += strlen($replacement) - $consumed_length; - } - break; + case 'csmnem': + case 'mnem': + return 'MNEM'; - default: - static $entities = array('Aacute' => "\xC3\x81", 'aacute' => "\xC3\xA1", 'Aacute;' => "\xC3\x81", 'aacute;' => "\xC3\xA1", 'Acirc' => "\xC3\x82", 'acirc' => "\xC3\xA2", 'Acirc;' => "\xC3\x82", 'acirc;' => "\xC3\xA2", 'acute' => "\xC2\xB4", 'acute;' => "\xC2\xB4", 'AElig' => "\xC3\x86", 'aelig' => "\xC3\xA6", 'AElig;' => "\xC3\x86", 'aelig;' => "\xC3\xA6", 'Agrave' => "\xC3\x80", 'agrave' => "\xC3\xA0", 'Agrave;' => "\xC3\x80", 'agrave;' => "\xC3\xA0", 'alefsym;' => "\xE2\x84\xB5", 'Alpha;' => "\xCE\x91", 'alpha;' => "\xCE\xB1", 'AMP' => "\x26", 'amp' => "\x26", 'AMP;' => "\x26", 'amp;' => "\x26", 'and;' => "\xE2\x88\xA7", 'ang;' => "\xE2\x88\xA0", 'apos;' => "\x27", 'Aring' => "\xC3\x85", 'aring' => "\xC3\xA5", 'Aring;' => "\xC3\x85", 'aring;' => "\xC3\xA5", 'asymp;' => "\xE2\x89\x88", 'Atilde' => "\xC3\x83", 'atilde' => "\xC3\xA3", 'Atilde;' => "\xC3\x83", 'atilde;' => "\xC3\xA3", 'Auml' => "\xC3\x84", 'auml' => "\xC3\xA4", 'Auml;' => "\xC3\x84", 'auml;' => "\xC3\xA4", 'bdquo;' => "\xE2\x80\x9E", 'Beta;' => "\xCE\x92", 'beta;' => "\xCE\xB2", 'brvbar' => "\xC2\xA6", 'brvbar;' => "\xC2\xA6", 'bull;' => "\xE2\x80\xA2", 'cap;' => "\xE2\x88\xA9", 'Ccedil' => "\xC3\x87", 'ccedil' => "\xC3\xA7", 'Ccedil;' => "\xC3\x87", 'ccedil;' => "\xC3\xA7", 'cedil' => "\xC2\xB8", 'cedil;' => "\xC2\xB8", 'cent' => "\xC2\xA2", 'cent;' => "\xC2\xA2", 'Chi;' => "\xCE\xA7", 'chi;' => "\xCF\x87", 'circ;' => "\xCB\x86", 'clubs;' => "\xE2\x99\xA3", 'cong;' => "\xE2\x89\x85", 'COPY' => "\xC2\xA9", 'copy' => "\xC2\xA9", 'COPY;' => "\xC2\xA9", 'copy;' => "\xC2\xA9", 'crarr;' => "\xE2\x86\xB5", 'cup;' => "\xE2\x88\xAA", 'curren' => "\xC2\xA4", 'curren;' => "\xC2\xA4", 'Dagger;' => "\xE2\x80\xA1", 'dagger;' => "\xE2\x80\xA0", 'dArr;' => "\xE2\x87\x93", 'darr;' => "\xE2\x86\x93", 'deg' => "\xC2\xB0", 'deg;' => "\xC2\xB0", 'Delta;' => "\xCE\x94", 'delta;' => "\xCE\xB4", 'diams;' => "\xE2\x99\xA6", 'divide' => "\xC3\xB7", 'divide;' => "\xC3\xB7", 'Eacute' => "\xC3\x89", 'eacute' => "\xC3\xA9", 'Eacute;' => "\xC3\x89", 'eacute;' => "\xC3\xA9", 'Ecirc' => "\xC3\x8A", 'ecirc' => "\xC3\xAA", 'Ecirc;' => "\xC3\x8A", 'ecirc;' => "\xC3\xAA", 'Egrave' => "\xC3\x88", 'egrave' => "\xC3\xA8", 'Egrave;' => "\xC3\x88", 'egrave;' => "\xC3\xA8", 'empty;' => "\xE2\x88\x85", 'emsp;' => "\xE2\x80\x83", 'ensp;' => "\xE2\x80\x82", 'Epsilon;' => "\xCE\x95", 'epsilon;' => "\xCE\xB5", 'equiv;' => "\xE2\x89\xA1", 'Eta;' => "\xCE\x97", 'eta;' => "\xCE\xB7", 'ETH' => "\xC3\x90", 'eth' => "\xC3\xB0", 'ETH;' => "\xC3\x90", 'eth;' => "\xC3\xB0", 'Euml' => "\xC3\x8B", 'euml' => "\xC3\xAB", 'Euml;' => "\xC3\x8B", 'euml;' => "\xC3\xAB", 'euro;' => "\xE2\x82\xAC", 'exist;' => "\xE2\x88\x83", 'fnof;' => "\xC6\x92", 'forall;' => "\xE2\x88\x80", 'frac12' => "\xC2\xBD", 'frac12;' => "\xC2\xBD", 'frac14' => "\xC2\xBC", 'frac14;' => "\xC2\xBC", 'frac34' => "\xC2\xBE", 'frac34;' => "\xC2\xBE", 'frasl;' => "\xE2\x81\x84", 'Gamma;' => "\xCE\x93", 'gamma;' => "\xCE\xB3", 'ge;' => "\xE2\x89\xA5", 'GT' => "\x3E", 'gt' => "\x3E", 'GT;' => "\x3E", 'gt;' => "\x3E", 'hArr;' => "\xE2\x87\x94", 'harr;' => "\xE2\x86\x94", 'hearts;' => "\xE2\x99\xA5", 'hellip;' => "\xE2\x80\xA6", 'Iacute' => "\xC3\x8D", 'iacute' => "\xC3\xAD", 'Iacute;' => "\xC3\x8D", 'iacute;' => "\xC3\xAD", 'Icirc' => "\xC3\x8E", 'icirc' => "\xC3\xAE", 'Icirc;' => "\xC3\x8E", 'icirc;' => "\xC3\xAE", 'iexcl' => "\xC2\xA1", 'iexcl;' => "\xC2\xA1", 'Igrave' => "\xC3\x8C", 'igrave' => "\xC3\xAC", 'Igrave;' => "\xC3\x8C", 'igrave;' => "\xC3\xAC", 'image;' => "\xE2\x84\x91", 'infin;' => "\xE2\x88\x9E", 'int;' => "\xE2\x88\xAB", 'Iota;' => "\xCE\x99", 'iota;' => "\xCE\xB9", 'iquest' => "\xC2\xBF", 'iquest;' => "\xC2\xBF", 'isin;' => "\xE2\x88\x88", 'Iuml' => "\xC3\x8F", 'iuml' => "\xC3\xAF", 'Iuml;' => "\xC3\x8F", 'iuml;' => "\xC3\xAF", 'Kappa;' => "\xCE\x9A", 'kappa;' => "\xCE\xBA", 'Lambda;' => "\xCE\x9B", 'lambda;' => "\xCE\xBB", 'lang;' => "\xE3\x80\x88", 'laquo' => "\xC2\xAB", 'laquo;' => "\xC2\xAB", 'lArr;' => "\xE2\x87\x90", 'larr;' => "\xE2\x86\x90", 'lceil;' => "\xE2\x8C\x88", 'ldquo;' => "\xE2\x80\x9C", 'le;' => "\xE2\x89\xA4", 'lfloor;' => "\xE2\x8C\x8A", 'lowast;' => "\xE2\x88\x97", 'loz;' => "\xE2\x97\x8A", 'lrm;' => "\xE2\x80\x8E", 'lsaquo;' => "\xE2\x80\xB9", 'lsquo;' => "\xE2\x80\x98", 'LT' => "\x3C", 'lt' => "\x3C", 'LT;' => "\x3C", 'lt;' => "\x3C", 'macr' => "\xC2\xAF", 'macr;' => "\xC2\xAF", 'mdash;' => "\xE2\x80\x94", 'micro' => "\xC2\xB5", 'micro;' => "\xC2\xB5", 'middot' => "\xC2\xB7", 'middot;' => "\xC2\xB7", 'minus;' => "\xE2\x88\x92", 'Mu;' => "\xCE\x9C", 'mu;' => "\xCE\xBC", 'nabla;' => "\xE2\x88\x87", 'nbsp' => "\xC2\xA0", 'nbsp;' => "\xC2\xA0", 'ndash;' => "\xE2\x80\x93", 'ne;' => "\xE2\x89\xA0", 'ni;' => "\xE2\x88\x8B", 'not' => "\xC2\xAC", 'not;' => "\xC2\xAC", 'notin;' => "\xE2\x88\x89", 'nsub;' => "\xE2\x8A\x84", 'Ntilde' => "\xC3\x91", 'ntilde' => "\xC3\xB1", 'Ntilde;' => "\xC3\x91", 'ntilde;' => "\xC3\xB1", 'Nu;' => "\xCE\x9D", 'nu;' => "\xCE\xBD", 'Oacute' => "\xC3\x93", 'oacute' => "\xC3\xB3", 'Oacute;' => "\xC3\x93", 'oacute;' => "\xC3\xB3", 'Ocirc' => "\xC3\x94", 'ocirc' => "\xC3\xB4", 'Ocirc;' => "\xC3\x94", 'ocirc;' => "\xC3\xB4", 'OElig;' => "\xC5\x92", 'oelig;' => "\xC5\x93", 'Ograve' => "\xC3\x92", 'ograve' => "\xC3\xB2", 'Ograve;' => "\xC3\x92", 'ograve;' => "\xC3\xB2", 'oline;' => "\xE2\x80\xBE", 'Omega;' => "\xCE\xA9", 'omega;' => "\xCF\x89", 'Omicron;' => "\xCE\x9F", 'omicron;' => "\xCE\xBF", 'oplus;' => "\xE2\x8A\x95", 'or;' => "\xE2\x88\xA8", 'ordf' => "\xC2\xAA", 'ordf;' => "\xC2\xAA", 'ordm' => "\xC2\xBA", 'ordm;' => "\xC2\xBA", 'Oslash' => "\xC3\x98", 'oslash' => "\xC3\xB8", 'Oslash;' => "\xC3\x98", 'oslash;' => "\xC3\xB8", 'Otilde' => "\xC3\x95", 'otilde' => "\xC3\xB5", 'Otilde;' => "\xC3\x95", 'otilde;' => "\xC3\xB5", 'otimes;' => "\xE2\x8A\x97", 'Ouml' => "\xC3\x96", 'ouml' => "\xC3\xB6", 'Ouml;' => "\xC3\x96", 'ouml;' => "\xC3\xB6", 'para' => "\xC2\xB6", 'para;' => "\xC2\xB6", 'part;' => "\xE2\x88\x82", 'permil;' => "\xE2\x80\xB0", 'perp;' => "\xE2\x8A\xA5", 'Phi;' => "\xCE\xA6", 'phi;' => "\xCF\x86", 'Pi;' => "\xCE\xA0", 'pi;' => "\xCF\x80", 'piv;' => "\xCF\x96", 'plusmn' => "\xC2\xB1", 'plusmn;' => "\xC2\xB1", 'pound' => "\xC2\xA3", 'pound;' => "\xC2\xA3", 'Prime;' => "\xE2\x80\xB3", 'prime;' => "\xE2\x80\xB2", 'prod;' => "\xE2\x88\x8F", 'prop;' => "\xE2\x88\x9D", 'Psi;' => "\xCE\xA8", 'psi;' => "\xCF\x88", 'QUOT' => "\x22", 'quot' => "\x22", 'QUOT;' => "\x22", 'quot;' => "\x22", 'radic;' => "\xE2\x88\x9A", 'rang;' => "\xE3\x80\x89", 'raquo' => "\xC2\xBB", 'raquo;' => "\xC2\xBB", 'rArr;' => "\xE2\x87\x92", 'rarr;' => "\xE2\x86\x92", 'rceil;' => "\xE2\x8C\x89", 'rdquo;' => "\xE2\x80\x9D", 'real;' => "\xE2\x84\x9C", 'REG' => "\xC2\xAE", 'reg' => "\xC2\xAE", 'REG;' => "\xC2\xAE", 'reg;' => "\xC2\xAE", 'rfloor;' => "\xE2\x8C\x8B", 'Rho;' => "\xCE\xA1", 'rho;' => "\xCF\x81", 'rlm;' => "\xE2\x80\x8F", 'rsaquo;' => "\xE2\x80\xBA", 'rsquo;' => "\xE2\x80\x99", 'sbquo;' => "\xE2\x80\x9A", 'Scaron;' => "\xC5\xA0", 'scaron;' => "\xC5\xA1", 'sdot;' => "\xE2\x8B\x85", 'sect' => "\xC2\xA7", 'sect;' => "\xC2\xA7", 'shy' => "\xC2\xAD", 'shy;' => "\xC2\xAD", 'Sigma;' => "\xCE\xA3", 'sigma;' => "\xCF\x83", 'sigmaf;' => "\xCF\x82", 'sim;' => "\xE2\x88\xBC", 'spades;' => "\xE2\x99\xA0", 'sub;' => "\xE2\x8A\x82", 'sube;' => "\xE2\x8A\x86", 'sum;' => "\xE2\x88\x91", 'sup;' => "\xE2\x8A\x83", 'sup1' => "\xC2\xB9", 'sup1;' => "\xC2\xB9", 'sup2' => "\xC2\xB2", 'sup2;' => "\xC2\xB2", 'sup3' => "\xC2\xB3", 'sup3;' => "\xC2\xB3", 'supe;' => "\xE2\x8A\x87", 'szlig' => "\xC3\x9F", 'szlig;' => "\xC3\x9F", 'Tau;' => "\xCE\xA4", 'tau;' => "\xCF\x84", 'there4;' => "\xE2\x88\xB4", 'Theta;' => "\xCE\x98", 'theta;' => "\xCE\xB8", 'thetasym;' => "\xCF\x91", 'thinsp;' => "\xE2\x80\x89", 'THORN' => "\xC3\x9E", 'thorn' => "\xC3\xBE", 'THORN;' => "\xC3\x9E", 'thorn;' => "\xC3\xBE", 'tilde;' => "\xCB\x9C", 'times' => "\xC3\x97", 'times;' => "\xC3\x97", 'TRADE;' => "\xE2\x84\xA2", 'trade;' => "\xE2\x84\xA2", 'Uacute' => "\xC3\x9A", 'uacute' => "\xC3\xBA", 'Uacute;' => "\xC3\x9A", 'uacute;' => "\xC3\xBA", 'uArr;' => "\xE2\x87\x91", 'uarr;' => "\xE2\x86\x91", 'Ucirc' => "\xC3\x9B", 'ucirc' => "\xC3\xBB", 'Ucirc;' => "\xC3\x9B", 'ucirc;' => "\xC3\xBB", 'Ugrave' => "\xC3\x99", 'ugrave' => "\xC3\xB9", 'Ugrave;' => "\xC3\x99", 'ugrave;' => "\xC3\xB9", 'uml' => "\xC2\xA8", 'uml;' => "\xC2\xA8", 'upsih;' => "\xCF\x92", 'Upsilon;' => "\xCE\xA5", 'upsilon;' => "\xCF\x85", 'Uuml' => "\xC3\x9C", 'uuml' => "\xC3\xBC", 'Uuml;' => "\xC3\x9C", 'uuml;' => "\xC3\xBC", 'weierp;' => "\xE2\x84\x98", 'Xi;' => "\xCE\x9E", 'xi;' => "\xCE\xBE", 'Yacute' => "\xC3\x9D", 'yacute' => "\xC3\xBD", 'Yacute;' => "\xC3\x9D", 'yacute;' => "\xC3\xBD", 'yen' => "\xC2\xA5", 'yen;' => "\xC2\xA5", 'yuml' => "\xC3\xBF", 'Yuml;' => "\xC5\xB8", 'yuml;' => "\xC3\xBF", 'Zeta;' => "\xCE\x96", 'zeta;' => "\xCE\xB6", 'zwj;' => "\xE2\x80\x8D", 'zwnj;' => "\xE2\x80\x8C"); + case 'csmnemonic': + case 'mnemonic': + return 'MNEMONIC'; - for ($i = 0, $match = null; $i < 9 && $this->consume() !== false; $i++) - { - $consumed = substr($this->consumed, 1); - if (isset($entities[$consumed])) - { - $match = $consumed; - } - } + case 'csiso86hungarian': + case 'hu': + case 'iso646hu': + case 'isoir86': + case 'msz77953': + return 'MSZ_7795.3'; - if ($match !== null) - { - $this->data = substr_replace($this->data, $entities[$match], $this->position - strlen($consumed) - 1, strlen($match) + 1); - $this->position += strlen($entities[$match]) - strlen($consumed) - 1; - } - break; - } - } -} + case 'csnatsdano': + case 'isoir91': + case 'natsdano': + return 'NATS-DANO'; -/** - * IRI parser/serialiser - * - * @package SimplePie - */ -class SimplePie_IRI -{ - /** - * Scheme - * - * @access private - * @var string - */ - var $scheme; + case 'csnatsdanoadd': + case 'isoir92': + case 'natsdanoadd': + return 'NATS-DANO-ADD'; - /** - * User Information - * - * @access private - * @var string - */ - var $userinfo; + case 'csnatssefi': + case 'isoir81': + case 'natssefi': + return 'NATS-SEFI'; - /** - * Host - * - * @access private - * @var string - */ - var $host; + case 'csnatssefiadd': + case 'isoir82': + case 'natssefiadd': + return 'NATS-SEFI-ADD'; - /** - * Port - * - * @access private - * @var string - */ - var $port; + case 'csiso151cuba': + case 'cuba': + case 'iso646cu': + case 'isoir151': + case 'ncnc1081': + return 'NC_NC00-10:81'; - /** - * Path - * - * @access private - * @var string - */ - var $path; + case 'csiso69french': + case 'fr': + case 'iso646fr': + case 'isoir69': + case 'nfz62010': + return 'NF_Z_62-010'; - /** - * Query - * - * @access private - * @var string - */ - var $query; + case 'csiso25french': + case 'iso646fr1': + case 'isoir25': + case 'nfz620101973': + return 'NF_Z_62-010_(1973)'; - /** - * Fragment - * - * @access private - * @var string - */ - var $fragment; + case 'csiso60danishnorwegian': + case 'csiso60norwegian1': + case 'iso646no': + case 'isoir60': + case 'no': + case 'ns45511': + return 'NS_4551-1'; - /** - * Whether the object represents a valid IRI - * - * @access private - * @var array - */ - var $valid = array(); + case 'csiso61norwegian2': + case 'iso646no2': + case 'isoir61': + case 'no2': + case 'ns45512': + return 'NS_4551-2'; - /** - * Return the entire IRI when you try and read the object as a string - * - * @access public - * @return string - */ - function __toString() - { - return $this->get_iri(); - } + case 'osdebcdicdf3irv': + return 'OSD_EBCDIC_DF03_IRV'; - /** - * Create a new IRI object, from a specified string - * - * @access public - * @param string $iri - * @return SimplePie_IRI - */ - function SimplePie_IRI($iri) - { - $iri = (string) $iri; - if ($iri !== '') - { - $parsed = $this->parse_iri($iri); - $this->set_scheme($parsed['scheme']); - $this->set_authority($parsed['authority']); - $this->set_path($parsed['path']); - $this->set_query($parsed['query']); - $this->set_fragment($parsed['fragment']); - } - } + case 'osdebcdicdf41': + return 'OSD_EBCDIC_DF04_1'; - /** - * Create a new IRI object by resolving a relative IRI - * - * @static - * @access public - * @param SimplePie_IRI $base Base IRI - * @param string $relative Relative IRI - * @return SimplePie_IRI - */ - function absolutize($base, $relative) - { - $relative = (string) $relative; - if ($relative !== '') - { - $relative = new SimplePie_IRI($relative); - if ($relative->get_scheme() !== null) - { - $target = $relative; - } - elseif ($base->get_iri() !== null) - { - if ($relative->get_authority() !== null) - { - $target = $relative; - $target->set_scheme($base->get_scheme()); - } - else - { - $target = new SimplePie_IRI(''); - $target->set_scheme($base->get_scheme()); - $target->set_userinfo($base->get_userinfo()); - $target->set_host($base->get_host()); - $target->set_port($base->get_port()); - if ($relative->get_path() !== null) - { - if (strpos($relative->get_path(), '/') === 0) - { - $target->set_path($relative->get_path()); - } - elseif (($base->get_userinfo() !== null || $base->get_host() !== null || $base->get_port() !== null) && $base->get_path() === null) - { - $target->set_path('/' . $relative->get_path()); - } - elseif (($last_segment = strrpos($base->get_path(), '/')) !== false) - { - $target->set_path(substr($base->get_path(), 0, $last_segment + 1) . $relative->get_path()); - } - else - { - $target->set_path($relative->get_path()); - } - $target->set_query($relative->get_query()); - } - else - { - $target->set_path($base->get_path()); - if ($relative->get_query() !== null) - { - $target->set_query($relative->get_query()); - } - elseif ($base->get_query() !== null) - { - $target->set_query($base->get_query()); - } - } - } - $target->set_fragment($relative->get_fragment()); - } - else - { - // No base URL, just return the relative URL - $target = $relative; - } - } - else - { - $target = $base; - } - return $target; - } + case 'osdebcdicdf415': + return 'OSD_EBCDIC_DF04_15'; - /** - * Parse an IRI into scheme/authority/path/query/fragment segments - * - * @access private - * @param string $iri - * @return array - */ - function parse_iri($iri) - { - preg_match('/^(([^:\/?#]+):)?(\/\/([^\/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?$/', $iri, $match); - for ($i = count($match); $i <= 9; $i++) - { - $match[$i] = ''; - } - return array('scheme' => $match[2], 'authority' => $match[4], 'path' => $match[5], 'query' => $match[7], 'fragment' => $match[9]); - } + case 'cspc8danishnorwegian': + case 'pc8danishnorwegian': + return 'PC8-Danish-Norwegian'; - /** - * Remove dot segments from a path - * - * @access private - * @param string $input - * @return string - */ - function remove_dot_segments($input) - { - $output = ''; - while (strpos($input, './') !== false || strpos($input, '/.') !== false || $input === '.' || $input === '..') - { - // A: If the input buffer begins with a prefix of "../" or "./", then remove that prefix from the input buffer; otherwise, - if (strpos($input, '../') === 0) - { - $input = substr($input, 3); - } - elseif (strpos($input, './') === 0) - { - $input = substr($input, 2); - } - // B: if the input buffer begins with a prefix of "/./" or "/.", where "." is a complete path segment, then replace that prefix with "/" in the input buffer; otherwise, - elseif (strpos($input, '/./') === 0) - { - $input = substr_replace($input, '/', 0, 3); - } - elseif ($input === '/.') - { - $input = '/'; - } - // C: if the input buffer begins with a prefix of "/../" or "/..", where ".." is a complete path segment, then replace that prefix with "/" in the input buffer and remove the last segment and its preceding "/" (if any) from the output buffer; otherwise, - elseif (strpos($input, '/../') === 0) - { - $input = substr_replace($input, '/', 0, 4); - $output = substr_replace($output, '', strrpos($output, '/')); - } - elseif ($input === '/..') - { - $input = '/'; - $output = substr_replace($output, '', strrpos($output, '/')); - } - // D: if the input buffer consists only of "." or "..", then remove that from the input buffer; otherwise, - elseif ($input === '.' || $input === '..') - { - $input = ''; - } - // E: move the first path segment in the input buffer to the end of the output buffer, including the initial "/" character (if any) and any subsequent characters up to, but not including, the next "/" character or the end of the input buffer - elseif (($pos = strpos($input, '/', 1)) !== false) - { - $output .= substr($input, 0, $pos); - $input = substr_replace($input, '', 0, $pos); - } - else - { - $output .= $input; - $input = ''; - } - } - return $output . $input; - } + case 'cspc8turkish': + case 'pc8turkish': + return 'PC8-Turkish'; - /** - * Replace invalid character with percent encoding - * - * @param string $string Input string - * @param string $valid_chars Valid characters - * @param int $case Normalise case - * @return string - */ - function replace_invalid_with_pct_encoding($string, $valid_chars, $case = SIMPLEPIE_SAME_CASE, $iprivate = false) - { - // Normalize as many pct-encoded sections as possible - $string = preg_replace_callback('/(?:%[A-Fa-f0-9]{2})+/', array(&$this, 'remove_iunreserved_percent_encoded'), $string); + case 'csiso16portuguese': + case 'iso646pt': + case 'isoir16': + case 'pt': + return 'PT'; - // Replace invalid percent characters - $string = preg_replace('/%(?![A-Fa-f0-9]{2})/', '%25', $string); + case 'csiso84portuguese2': + case 'iso646pt2': + case 'isoir84': + case 'pt2': + return 'PT2'; - // Add unreserved and % to $valid_chars (the latter is safe because all - // pct-encoded sections are now valid). - $valid_chars .= 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~%'; + case 'cp154': + case 'csptcp154': + case 'cyrillicasian': + case 'pt154': + case 'ptcp154': + return 'PTCP154'; - // Now replace any bytes that aren't allowed with their pct-encoded versions - $position = 0; - $strlen = strlen($string); - while (($position += strspn($string, $valid_chars, $position)) < $strlen) - { - $value = ord($string[$position]); + case 'scsu': + return 'SCSU'; - // Start position - $start = $position; + case 'csiso10swedish': + case 'fi': + case 'iso646fi': + case 'iso646se': + case 'isoir10': + case 'se': + case 'sen850200b': + return 'SEN_850200_B'; - // By default we are valid - $valid = true; + case 'csiso11swedishfornames': + case 'iso646se2': + case 'isoir11': + case 'se2': + case 'sen850200c': + return 'SEN_850200_C'; - // No one byte sequences are valid due to the while. - // Two byte sequence: - if (($value & 0xE0) === 0xC0) - { - $character = ($value & 0x1F) << 6; - $length = 2; - $remaining = 1; - } - // Three byte sequence: - elseif (($value & 0xF0) === 0xE0) - { - $character = ($value & 0x0F) << 12; - $length = 3; - $remaining = 2; - } - // Four byte sequence: - elseif (($value & 0xF8) === 0xF0) - { - $character = ($value & 0x07) << 18; - $length = 4; - $remaining = 3; - } - // Invalid byte: - else - { - $valid = false; - $length = 1; - $remaining = 0; - } + case 'csiso102t617bit': + case 'isoir102': + case 't617bit': + return 'T.61-7bit'; - if ($remaining) - { - if ($position + $length <= $strlen) - { - for ($position++; $remaining; $position++) - { - $value = ord($string[$position]); + case 'csiso103t618bit': + case 'isoir103': + case 't61': + case 't618bit': + return 'T.61-8bit'; - // Check that the byte is valid, then add it to the character: - if (($value & 0xC0) === 0x80) - { - $character |= ($value & 0x3F) << (--$remaining * 6); - } - // If it is invalid, count the sequence as invalid and reprocess the current byte: - else - { - $valid = false; - $position--; - break; - } - } - } - else - { - $position = $strlen - 1; - $valid = false; - } - } + case 'csiso128t101g2': + case 'isoir128': + case 't101g2': + return 'T.101-G2'; - // Percent encode anything invalid or not in ucschar - if ( - // Invalid sequences - !$valid - // Non-shortest form sequences are invalid - || $length > 1 && $character <= 0x7F - || $length > 2 && $character <= 0x7FF - || $length > 3 && $character <= 0xFFFF - // Outside of range of ucschar codepoints - // Noncharacters - || ($character & 0xFFFE) === 0xFFFE - || $character >= 0xFDD0 && $character <= 0xFDEF - || ( - // Everything else not in ucschar - $character > 0xD7FF && $character < 0xF900 - || $character < 0xA0 - || $character > 0xEFFFD - ) - && ( - // Everything not in iprivate, if it applies - !$iprivate - || $character < 0xE000 - || $character > 0x10FFFD - ) - ) - { - // If we were a character, pretend we weren't, but rather an error. - if ($valid) - $position--; + case 'cstscii': + case 'tscii': + return 'TSCII'; - for ($j = $start; $j <= $position; $j++) - { - $string = substr_replace($string, sprintf('%%%02X', ord($string[$j])), $j, 1); - $j += 2; - $position += 2; - $strlen += 2; - } - } - } + case 'csunicode11': + case 'unicode11': + return 'UNICODE-1-1'; - // Normalise case - if ($case & SIMPLEPIE_LOWERCASE) - { - $string = strtolower($string); - } - elseif ($case & SIMPLEPIE_UPPERCASE) - { - $string = strtoupper($string); - } + case 'csunicode11utf7': + case 'unicode11utf7': + return 'UNICODE-1-1-UTF-7'; - return $string; - } + case 'csunknown8bit': + case 'unknown8bit': + return 'UNKNOWN-8BIT'; - /** - * Callback function for preg_replace_callback. - * - * Removes sequences of percent encoded bytes that represent UTF-8 - * encoded characters in iunreserved - * - * @access private - * @param array $match PCRE match - * @return string Replacement - */ - function remove_iunreserved_percent_encoded($match) - { - // As we just have valid percent encoded sequences we can just explode - // and ignore the first member of the returned array (an empty string). - $bytes = explode('%', $match[0]); + case 'ansix341968': + case 'ansix341986': + case 'ascii': + case 'cp367': + case 'csascii': + case 'ibm367': + case 'iso646irv1991': + case 'iso646us': + case 'isoir6': + case 'us': + case 'usascii': + return 'US-ASCII'; - // Initialize the new string (this is what will be returned) and that - // there are no bytes remaining in the current sequence (unsurprising - // at the first byte!). - $string = ''; - $remaining = 0; + case 'csusdk': + case 'usdk': + return 'us-dk'; - // Loop over each and every byte, and set $value to its value - for ($i = 1, $len = count($bytes); $i < $len; $i++) - { - $value = hexdec($bytes[$i]); + case 'utf7': + return 'UTF-7'; - // If we're the first byte of sequence: - if (!$remaining) - { - // Start position - $start = $i; + case 'utf8': + return 'UTF-8'; - // By default we are valid - $valid = true; + case 'utf16': + return 'UTF-16'; - // One byte sequence: - if ($value <= 0x7F) - { - $character = $value; - $length = 1; - } - // Two byte sequence: - elseif (($value & 0xE0) === 0xC0) - { - $character = ($value & 0x1F) << 6; - $length = 2; - $remaining = 1; - } - // Three byte sequence: - elseif (($value & 0xF0) === 0xE0) - { - $character = ($value & 0x0F) << 12; - $length = 3; - $remaining = 2; - } - // Four byte sequence: - elseif (($value & 0xF8) === 0xF0) - { - $character = ($value & 0x07) << 18; - $length = 4; - $remaining = 3; - } - // Invalid byte: - else - { - $valid = false; - $remaining = 0; - } - } - // Continuation byte: - else - { - // Check that the byte is valid, then add it to the character: - if (($value & 0xC0) === 0x80) - { - $remaining--; - $character |= ($value & 0x3F) << ($remaining * 6); - } - // If it is invalid, count the sequence as invalid and reprocess the current byte as the start of a sequence: - else - { - $valid = false; - $remaining = 0; - $i--; - } - } + case 'utf16be': + return 'UTF-16BE'; - // If we've reached the end of the current byte sequence, append it to Unicode::$data - if (!$remaining) - { - // Percent encode anything invalid or not in iunreserved - if ( - // Invalid sequences - !$valid - // Non-shortest form sequences are invalid - || $length > 1 && $character <= 0x7F - || $length > 2 && $character <= 0x7FF - || $length > 3 && $character <= 0xFFFF - // Outside of range of iunreserved codepoints - || $character < 0x2D - || $character > 0xEFFFD - // Noncharacters - || ($character & 0xFFFE) === 0xFFFE - || $character >= 0xFDD0 && $character <= 0xFDEF - // Everything else not in iunreserved (this is all BMP) - || $character === 0x2F - || $character > 0x39 && $character < 0x41 - || $character > 0x5A && $character < 0x61 - || $character > 0x7A && $character < 0x7E - || $character > 0x7E && $character < 0xA0 - || $character > 0xD7FF && $character < 0xF900 - ) - { - for ($j = $start; $j <= $i; $j++) - { - $string .= '%' . strtoupper($bytes[$j]); - } - } - else - { - for ($j = $start; $j <= $i; $j++) - { - $string .= chr(hexdec($bytes[$j])); - } - } - } - } + case 'utf16le': + return 'UTF-16LE'; - // If we have any bytes left over they are invalid (i.e., we are - // mid-way through a multi-byte sequence) - if ($remaining) - { - for ($j = $start; $j < $len; $j++) - { - $string .= '%' . strtoupper($bytes[$j]); - } - } + case 'utf32': + return 'UTF-32'; - return $string; - } + case 'utf32be': + return 'UTF-32BE'; - /** - * Check if the object represents a valid IRI - * - * @access public - * @return bool - */ - function is_valid() - { - return array_sum($this->valid) === count($this->valid); - } + case 'utf32le': + return 'UTF-32LE'; - /** - * Set the scheme. Returns true on success, false on failure (if there are - * any invalid characters). - * - * @access public - * @param string $scheme - * @return bool - */ - function set_scheme($scheme) - { - if ($scheme === null || $scheme === '') - { - $this->scheme = null; - } - else - { - $len = strlen($scheme); - switch (true) - { - case $len > 1: - if (!strspn($scheme, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-.', 1)) - { - $this->scheme = null; - $this->valid[__FUNCTION__] = false; - return false; - } + case 'csventurainternational': + case 'venturainternational': + return 'Ventura-International'; - case $len > 0: - if (!strspn($scheme, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz', 0, 1)) - { - $this->scheme = null; - $this->valid[__FUNCTION__] = false; - return false; - } - } - $this->scheme = strtolower($scheme); + case 'csventuramath': + case 'venturamath': + return 'Ventura-Math'; + + case 'csventuraus': + case 'venturaus': + return 'Ventura-US'; + + case 'csiso70videotexsupp1': + case 'isoir70': + case 'videotexsuppl': + return 'videotex-suppl'; + + case 'csviqr': + case 'viqr': + return 'VIQR'; + + case 'csviscii': + case 'viscii': + return 'VISCII'; + + case 'csshiftjis': + case 'cswindows31j': + case 'mskanji': + case 'shiftjis': + case 'windows31j': + return 'Windows-31J'; + + case 'iso885911': + case 'tis620': + return 'windows-874'; + + case 'cseuckr': + case 'csksc56011987': + case 'euckr': + case 'isoir149': + case 'korean': + case 'ksc5601': + case 'ksc56011987': + case 'ksc56011989': + case 'windows949': + return 'windows-949'; + + case 'windows1250': + return 'windows-1250'; + + case 'windows1251': + return 'windows-1251'; + + case 'cp819': + case 'csisolatin1': + case 'ibm819': + case 'iso88591': + case 'iso885911987': + case 'isoir100': + case 'l1': + case 'latin1': + case 'windows1252': + return 'windows-1252'; + + case 'windows1253': + return 'windows-1253'; + + case 'csisolatin5': + case 'iso88599': + case 'iso885991989': + case 'isoir148': + case 'l5': + case 'latin5': + case 'windows1254': + return 'windows-1254'; + + case 'windows1255': + return 'windows-1255'; + + case 'windows1256': + return 'windows-1256'; + + case 'windows1257': + return 'windows-1257'; + + case 'windows1258': + return 'windows-1258'; + + default: + return $charset; } - $this->valid[__FUNCTION__] = true; - return true; } - /** - * Set the authority. Returns true on success, false on failure (if there are - * any invalid characters). - * - * @access public - * @param string $authority - * @return bool - */ - function set_authority($authority) + public static function get_curl_version() { - if (($userinfo_end = strrpos($authority, '@')) !== false) - { - $userinfo = substr($authority, 0, $userinfo_end); - $authority = substr($authority, $userinfo_end + 1); - } - else - { - $userinfo = null; - } - - if (($port_start = strpos($authority, ':')) !== false) + if (is_array($curl = curl_version())) { - $port = substr($authority, $port_start + 1); - $authority = substr($authority, 0, $port_start); + $curl = $curl['version']; } - else + elseif (substr($curl, 0, 5) === 'curl/') { - $port = null; + $curl = substr($curl, 5, strcspn($curl, "\x09\x0A\x0B\x0C\x0D", 5)); } - - return $this->set_userinfo($userinfo) && $this->set_host($authority) && $this->set_port($port); - } - - /** - * Set the userinfo. - * - * @access public - * @param string $userinfo - * @return bool - */ - function set_userinfo($userinfo) - { - if ($userinfo === null || $userinfo === '') + elseif (substr($curl, 0, 8) === 'libcurl/') { - $this->userinfo = null; + $curl = substr($curl, 8, strcspn($curl, "\x09\x0A\x0B\x0C\x0D", 8)); } else { - $this->userinfo = $this->replace_invalid_with_pct_encoding($userinfo, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~!$&\'()*+,;=:'); + $curl = 0; } - $this->valid[__FUNCTION__] = true; - return true; + return $curl; } /** - * Set the host. Returns true on success, false on failure (if there are - * any invalid characters). + * Strip HTML comments * - * @access public - * @param string $host - * @return bool + * @param string $data Data to strip comments from + * @return string Comment stripped string */ - function set_host($host) + public static function strip_comments($data) { - if ($host === null || $host === '') - { - $this->host = null; - $this->valid[__FUNCTION__] = true; - return true; - } - elseif ($host[0] === '[' && substr($host, -1) === ']') + $output = ''; + while (($start = strpos($data, '<!--')) !== false) { - if (Net_IPv6::checkIPv6(substr($host, 1, -1))) + $output .= substr($data, 0, $start); + if (($end = strpos($data, '-->', $start)) !== false) { - $this->host = $host; - $this->valid[__FUNCTION__] = true; - return true; + $data = substr_replace($data, '', 0, $end + 3); } else { - $this->host = null; - $this->valid[__FUNCTION__] = false; - return false; + $data = ''; } } - else - { - $this->host = $this->replace_invalid_with_pct_encoding($host, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~!$&\'()*+,;=', SIMPLEPIE_LOWERCASE); - $this->valid[__FUNCTION__] = true; - return true; - } + return $output . $data; + } + + public static function parse_date($dt) + { + $parser = SimplePie_Parse_Date::get(); + return $parser->parse($dt); } /** - * Set the port. Returns true on success, false on failure (if there are - * any invalid characters). + * Decode HTML entities * - * @access public - * @param string $port - * @return bool - */ - function set_port($port) + * @deprecated Use DOMDocument instead + * @param string $data Input data + * @return string Output data + */ + public static function entities_decode($data) + { + $decoder = new SimplePie_Decode_HTML_Entities($data); + return $decoder->parse(); + } + + /** + * Remove RFC822 comments + * + * @param string $data Data to strip comments from + * @return string Comment stripped string + */ + public static function uncomment_rfc822($string) { - if ($port === null || $port === '') + $string = (string) $string; + $position = 0; + $length = strlen($string); + $depth = 0; + + $output = ''; + + while ($position < $length && ($pos = strpos($string, '(', $position)) !== false) { - $this->port = null; - $this->valid[__FUNCTION__] = true; - return true; + $output .= substr($string, $position, $pos - $position); + $position = $pos + 1; + if ($string[$pos - 1] !== '\\') + { + $depth++; + while ($depth && $position < $length) + { + $position += strcspn($string, '()', $position); + if ($string[$position - 1] === '\\') + { + $position++; + continue; + } + elseif (isset($string[$position])) + { + switch ($string[$position]) + { + case '(': + $depth++; + break; + + case ')': + $depth--; + break; + } + $position++; + } + else + { + break; + } + } + } + else + { + $output .= '('; + } } - elseif (strspn($port, '0123456789') === strlen($port)) + $output .= substr($string, $position); + + return $output; + } + + public static function parse_mime($mime) + { + if (($pos = strpos($mime, ';')) === false) { - $this->port = (int) $port; - $this->valid[__FUNCTION__] = true; - return true; + return trim($mime); } else { - $this->port = null; - $this->valid[__FUNCTION__] = false; + return trim(substr($mime, 0, $pos)); + } + } + + public static function atom_03_construct_type($attribs) + { + if (isset($attribs['']['mode']) && strtolower(trim($attribs['']['mode']) === 'base64')) + { + $mode = SIMPLEPIE_CONSTRUCT_BASE64; + } + else + { + $mode = SIMPLEPIE_CONSTRUCT_NONE; + } + if (isset($attribs['']['type'])) + { + switch (strtolower(trim($attribs['']['type']))) + { + case 'text': + case 'text/plain': + return SIMPLEPIE_CONSTRUCT_TEXT | $mode; + + case 'html': + case 'text/html': + return SIMPLEPIE_CONSTRUCT_HTML | $mode; + + case 'xhtml': + case 'application/xhtml+xml': + return SIMPLEPIE_CONSTRUCT_XHTML | $mode; + + default: + return SIMPLEPIE_CONSTRUCT_NONE | $mode; + } + } + else + { + return SIMPLEPIE_CONSTRUCT_TEXT | $mode; + } + } + + public static function atom_10_construct_type($attribs) + { + if (isset($attribs['']['type'])) + { + switch (strtolower(trim($attribs['']['type']))) + { + case 'text': + return SIMPLEPIE_CONSTRUCT_TEXT; + + case 'html': + return SIMPLEPIE_CONSTRUCT_HTML; + + case 'xhtml': + return SIMPLEPIE_CONSTRUCT_XHTML; + + default: + return SIMPLEPIE_CONSTRUCT_NONE; + } + } + return SIMPLEPIE_CONSTRUCT_TEXT; + } + + public static function atom_10_content_construct_type($attribs) + { + if (isset($attribs['']['type'])) + { + $type = strtolower(trim($attribs['']['type'])); + switch ($type) + { + case 'text': + return SIMPLEPIE_CONSTRUCT_TEXT; + + case 'html': + return SIMPLEPIE_CONSTRUCT_HTML; + + case 'xhtml': + return SIMPLEPIE_CONSTRUCT_XHTML; + } + if (in_array(substr($type, -4), array('+xml', '/xml')) || substr($type, 0, 5) === 'text/') + { + return SIMPLEPIE_CONSTRUCT_NONE; + } + else + { + return SIMPLEPIE_CONSTRUCT_BASE64; + } + } + else + { + return SIMPLEPIE_CONSTRUCT_TEXT; + } + } + + public static function is_isegment_nz_nc($string) + { + return (bool) preg_match('/^([A-Za-z0-9\-._~\x{A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}\x{10000}-\x{1FFFD}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}\x{40000}-\x{4FFFD}\x{50000}-\x{5FFFD}\x{60000}-\x{6FFFD}\x{70000}-\x{7FFFD}\x{80000}-\x{8FFFD}\x{90000}-\x{9FFFD}\x{A0000}-\x{AFFFD}\x{B0000}-\x{BFFFD}\x{C0000}-\x{CFFFD}\x{D0000}-\x{DFFFD}\x{E1000}-\x{EFFFD}!$&\'()*+,;=@]|(%[0-9ABCDEF]{2}))+$/u', $string); + } + + public static function space_seperated_tokens($string) + { + $space_characters = "\x20\x09\x0A\x0B\x0C\x0D"; + $string_length = strlen($string); + + $position = strspn($string, $space_characters); + $tokens = array(); + + while ($position < $string_length) + { + $len = strcspn($string, $space_characters, $position); + $tokens[] = substr($string, $position, $len); + $position += $len; + $position += strspn($string, $space_characters, $position); + } + + return $tokens; + } + + /** + * Converts a unicode codepoint to a UTF-8 character + * + * @static + * @param int $codepoint Unicode codepoint + * @return string UTF-8 character + */ + public static function codepoint_to_utf8($codepoint) + { + $codepoint = (int) $codepoint; + if ($codepoint < 0) + { return false; } + else if ($codepoint <= 0x7f) + { + return chr($codepoint); + } + else if ($codepoint <= 0x7ff) + { + return chr(0xc0 | ($codepoint >> 6)) . chr(0x80 | ($codepoint & 0x3f)); + } + else if ($codepoint <= 0xffff) + { + return chr(0xe0 | ($codepoint >> 12)) . chr(0x80 | (($codepoint >> 6) & 0x3f)) . chr(0x80 | ($codepoint & 0x3f)); + } + else if ($codepoint <= 0x10ffff) + { + return chr(0xf0 | ($codepoint >> 18)) . chr(0x80 | (($codepoint >> 12) & 0x3f)) . chr(0x80 | (($codepoint >> 6) & 0x3f)) . chr(0x80 | ($codepoint & 0x3f)); + } + else + { + // U+FFFD REPLACEMENT CHARACTER + return "\xEF\xBF\xBD"; + } + } + + /** + * Similar to parse_str() + * + * Returns an associative array of name/value pairs, where the value is an + * array of values that have used the same name + * + * @static + * @param string $str The input string. + * @return array + */ + public static function parse_str($str) + { + $return = array(); + $str = explode('&', $str); + + foreach ($str as $section) + { + if (strpos($section, '=') !== false) + { + list($name, $value) = explode('=', $section, 2); + $return[urldecode($name)][] = urldecode($value); + } + else + { + $return[urldecode($section)][] = null; + } + } + + return $return; } /** - * Set the path. + * Detect XML encoding, as per XML 1.0 Appendix F.1 + * + * @todo Add support for EBCDIC + * @param string $data XML data + * @param SimplePie_Registry $registry Class registry + * @return array Possible encodings + */ + public static function xml_encoding($data, $registry) + { + // UTF-32 Big Endian BOM + if (substr($data, 0, 4) === "\x00\x00\xFE\xFF") + { + $encoding[] = 'UTF-32BE'; + } + // UTF-32 Little Endian BOM + elseif (substr($data, 0, 4) === "\xFF\xFE\x00\x00") + { + $encoding[] = 'UTF-32LE'; + } + // UTF-16 Big Endian BOM + elseif (substr($data, 0, 2) === "\xFE\xFF") + { + $encoding[] = 'UTF-16BE'; + } + // UTF-16 Little Endian BOM + elseif (substr($data, 0, 2) === "\xFF\xFE") + { + $encoding[] = 'UTF-16LE'; + } + // UTF-8 BOM + elseif (substr($data, 0, 3) === "\xEF\xBB\xBF") + { + $encoding[] = 'UTF-8'; + } + // UTF-32 Big Endian Without BOM + elseif (substr($data, 0, 20) === "\x00\x00\x00\x3C\x00\x00\x00\x3F\x00\x00\x00\x78\x00\x00\x00\x6D\x00\x00\x00\x6C") + { + if ($pos = strpos($data, "\x00\x00\x00\x3F\x00\x00\x00\x3E")) + { + $parser = $registry->create('XML_Declaration_Parser', array(SimplePie_Misc::change_encoding(substr($data, 20, $pos - 20), 'UTF-32BE', 'UTF-8'))); + if ($parser->parse()) + { + $encoding[] = $parser->encoding; + } + } + $encoding[] = 'UTF-32BE'; + } + // UTF-32 Little Endian Without BOM + elseif (substr($data, 0, 20) === "\x3C\x00\x00\x00\x3F\x00\x00\x00\x78\x00\x00\x00\x6D\x00\x00\x00\x6C\x00\x00\x00") + { + if ($pos = strpos($data, "\x3F\x00\x00\x00\x3E\x00\x00\x00")) + { + $parser = $registry->create('XML_Declaration_Parser', array(SimplePie_Misc::change_encoding(substr($data, 20, $pos - 20), 'UTF-32LE', 'UTF-8'))); + if ($parser->parse()) + { + $encoding[] = $parser->encoding; + } + } + $encoding[] = 'UTF-32LE'; + } + // UTF-16 Big Endian Without BOM + elseif (substr($data, 0, 10) === "\x00\x3C\x00\x3F\x00\x78\x00\x6D\x00\x6C") + { + if ($pos = strpos($data, "\x00\x3F\x00\x3E")) + { + $parser = $registry->create('XML_Declaration_Parser', array(SimplePie_Misc::change_encoding(substr($data, 20, $pos - 10), 'UTF-16BE', 'UTF-8'))); + if ($parser->parse()) + { + $encoding[] = $parser->encoding; + } + } + $encoding[] = 'UTF-16BE'; + } + // UTF-16 Little Endian Without BOM + elseif (substr($data, 0, 10) === "\x3C\x00\x3F\x00\x78\x00\x6D\x00\x6C\x00") + { + if ($pos = strpos($data, "\x3F\x00\x3E\x00")) + { + $parser = $registry->create('XML_Declaration_Parser', array(SimplePie_Misc::change_encoding(substr($data, 20, $pos - 10), 'UTF-16LE', 'UTF-8'))); + if ($parser->parse()) + { + $encoding[] = $parser->encoding; + } + } + $encoding[] = 'UTF-16LE'; + } + // US-ASCII (or superset) + elseif (substr($data, 0, 5) === "\x3C\x3F\x78\x6D\x6C") + { + if ($pos = strpos($data, "\x3F\x3E")) + { + $parser = $registry->create('XML_Declaration_Parser', array(substr($data, 5, $pos - 5))); + if ($parser->parse()) + { + $encoding[] = $parser->encoding; + } + } + $encoding[] = 'UTF-8'; + } + // Fallback to UTF-8 + else + { + $encoding[] = 'UTF-8'; + } + return $encoding; + } + + public static function output_javascript() + { + if (function_exists('ob_gzhandler')) + { + ob_start('ob_gzhandler'); + } + header('Content-type: text/javascript; charset: UTF-8'); + header('Cache-Control: must-revalidate'); + header('Expires: ' . gmdate('D, d M Y H:i:s', time() + 604800) . ' GMT'); // 7 days + ?> +function embed_quicktime(type, bgcolor, width, height, link, placeholder, loop) { + if (placeholder != '') { + document.writeln('<embed type="'+type+'" style="cursor:hand; cursor:pointer;" href="'+link+'" src="'+placeholder+'" width="'+width+'" height="'+height+'" autoplay="false" target="myself" controller="false" loop="'+loop+'" scale="aspect" bgcolor="'+bgcolor+'" pluginspage="http://www.apple.com/quicktime/download/"></embed>'); + } + else { + document.writeln('<embed type="'+type+'" style="cursor:hand; cursor:pointer;" src="'+link+'" width="'+width+'" height="'+height+'" autoplay="false" target="myself" controller="true" loop="'+loop+'" scale="aspect" bgcolor="'+bgcolor+'" pluginspage="http://www.apple.com/quicktime/download/"></embed>'); + } +} + +function embed_flash(bgcolor, width, height, link, loop, type) { + document.writeln('<embed src="'+link+'" pluginspage="http://www.macromedia.com/go/getflashplayer" type="'+type+'" quality="high" width="'+width+'" height="'+height+'" bgcolor="'+bgcolor+'" loop="'+loop+'"></embed>'); +} + +function embed_flv(width, height, link, placeholder, loop, player) { + document.writeln('<embed src="'+player+'" pluginspage="http://www.macromedia.com/go/getflashplayer" type="application/x-shockwave-flash" quality="high" width="'+width+'" height="'+height+'" wmode="transparent" flashvars="file='+link+'&autostart=false&repeat='+loop+'&showdigits=true&showfsbutton=false"></embed>'); +} + +function embed_wmedia(width, height, link) { + document.writeln('<embed type="application/x-mplayer2" src="'+link+'" autosize="1" width="'+width+'" height="'+height+'" showcontrols="1" showstatusbar="0" showdisplay="0" autostart="0"></embed>'); +} + <?php + } + + /** + * Get the SimplePie build timestamp + * + * Uses the git index if it exists, otherwise uses the modification time + * of the newest file. + */ + public static function get_build() + { + $root = dirname(dirname(__FILE__)); + if (file_exists($root . '/.git/index')) + { + return filemtime($root . '/.git/index'); + } + elseif (file_exists($root . '/SimplePie')) + { + $time = 0; + foreach (glob($root . '/SimplePie/*.php') as $file) + { + if (($mtime = filemtime($file)) > $time) + { + $time = $mtime; + } + } + return $time; + } + elseif (file_exists(dirname(__FILE__) . '/Core.php')) + { + return filemtime(dirname(__FILE__) . '/Core.php'); + } + else + { + return filemtime(__FILE__); + } + } + + /** + * Format debugging information + */ + public static function debug(&$sp) + { + $info = 'SimplePie ' . SIMPLEPIE_VERSION . ' Build ' . SIMPLEPIE_BUILD . "\n"; + $info .= 'PHP ' . PHP_VERSION . "\n"; + if ($sp->error() !== null) + { + $info .= 'Error occurred: ' . $sp->error() . "\n"; + } + else + { + $info .= "No error found.\n"; + } + $info .= "Extensions:\n"; + $extensions = array('pcre', 'curl', 'zlib', 'mbstring', 'iconv', 'xmlreader', 'xml'); + foreach ($extensions as $ext) + { + if (extension_loaded($ext)) + { + $info .= " $ext loaded\n"; + switch ($ext) + { + case 'pcre': + $info .= ' Version ' . PCRE_VERSION . "\n"; + break; + case 'curl': + $version = curl_version(); + $info .= ' Version ' . $version['version'] . "\n"; + break; + case 'mbstring': + $info .= ' Overloading: ' . mb_get_info('func_overload') . "\n"; + break; + case 'iconv': + $info .= ' Version ' . ICONV_VERSION . "\n"; + break; + case 'xml': + $info .= ' Version ' . LIBXML_DOTTED_VERSION . "\n"; + break; + } + } + else + { + $info .= " $ext not loaded\n"; + } + } + return $info; + } + + public static function silence_errors($num, $str) + { + // No-op + } +} + +/** + * Class to validate and to work with IPv6 addresses. + * + * @package SimplePie + * @subpackage HTTP + * @copyright 2003-2005 The PHP Group + * @license http://www.opensource.org/licenses/bsd-license.php + * @link http://pear.php.net/package/Net_IPv6 + * @author Alexander Merz <alexander.merz@web.de> + * @author elfrink at introweb dot nl + * @author Josh Peck <jmp at joshpeck dot org> + * @author Geoffrey Sneddon <geoffers@gmail.com> + */ +class SimplePie_Net_IPv6 +{ + /** + * Uncompresses an IPv6 address + * + * RFC 4291 allows you to compress concecutive zero pieces in an address to + * '::'. This method expects a valid IPv6 address and expands the '::' to + * the required number of zero pieces. + * + * Example: FF01::101 -> FF01:0:0:0:0:0:0:101 + * ::1 -> 0:0:0:0:0:0:0:1 + * + * @author Alexander Merz <alexander.merz@web.de> + * @author elfrink at introweb dot nl + * @author Josh Peck <jmp at joshpeck dot org> + * @copyright 2003-2005 The PHP Group + * @license http://www.opensource.org/licenses/bsd-license.php + * @param string $ip An IPv6 address + * @return string The uncompressed IPv6 address + */ + public static function uncompress($ip) + { + $c1 = -1; + $c2 = -1; + if (substr_count($ip, '::') === 1) + { + list($ip1, $ip2) = explode('::', $ip); + if ($ip1 === '') + { + $c1 = -1; + } + else + { + $c1 = substr_count($ip1, ':'); + } + if ($ip2 === '') + { + $c2 = -1; + } + else + { + $c2 = substr_count($ip2, ':'); + } + if (strpos($ip2, '.') !== false) + { + $c2++; + } + // :: + if ($c1 === -1 && $c2 === -1) + { + $ip = '0:0:0:0:0:0:0:0'; + } + // ::xxx + else if ($c1 === -1) + { + $fill = str_repeat('0:', 7 - $c2); + $ip = str_replace('::', $fill, $ip); + } + // xxx:: + else if ($c2 === -1) + { + $fill = str_repeat(':0', 7 - $c1); + $ip = str_replace('::', $fill, $ip); + } + // xxx::xxx + else + { + $fill = ':' . str_repeat('0:', 6 - $c2 - $c1); + $ip = str_replace('::', $fill, $ip); + } + } + return $ip; + } + + /** + * Compresses an IPv6 address + * + * RFC 4291 allows you to compress concecutive zero pieces in an address to + * '::'. This method expects a valid IPv6 address and compresses consecutive + * zero pieces to '::'. + * + * Example: FF01:0:0:0:0:0:0:101 -> FF01::101 + * 0:0:0:0:0:0:0:1 -> ::1 + * + * @see uncompress() + * @param string $ip An IPv6 address + * @return string The compressed IPv6 address + */ + public static function compress($ip) + { + // Prepare the IP to be compressed + $ip = self::uncompress($ip); + $ip_parts = self::split_v6_v4($ip); + + // Replace all leading zeros + $ip_parts[0] = preg_replace('/(^|:)0+([0-9])/', '\1\2', $ip_parts[0]); + + // Find bunches of zeros + if (preg_match_all('/(?:^|:)(?:0(?::|$))+/', $ip_parts[0], $matches, PREG_OFFSET_CAPTURE)) + { + $max = 0; + $pos = null; + foreach ($matches[0] as $match) + { + if (strlen($match[0]) > $max) + { + $max = strlen($match[0]); + $pos = $match[1]; + } + } + + $ip_parts[0] = substr_replace($ip_parts[0], '::', $pos, $max); + } + + if ($ip_parts[1] !== '') + { + return implode(':', $ip_parts); + } + else + { + return $ip_parts[0]; + } + } + + /** + * Splits an IPv6 address into the IPv6 and IPv4 representation parts + * + * RFC 4291 allows you to represent the last two parts of an IPv6 address + * using the standard IPv4 representation + * + * Example: 0:0:0:0:0:0:13.1.68.3 + * 0:0:0:0:0:FFFF:129.144.52.38 + * + * @param string $ip An IPv6 address + * @return array [0] contains the IPv6 represented part, and [1] the IPv4 represented part + */ + private static function split_v6_v4($ip) + { + if (strpos($ip, '.') !== false) + { + $pos = strrpos($ip, ':'); + $ipv6_part = substr($ip, 0, $pos); + $ipv4_part = substr($ip, $pos + 1); + return array($ipv6_part, $ipv4_part); + } + else + { + return array($ip, ''); + } + } + + /** + * Checks an IPv6 address + * + * Checks if the given IP is a valid IPv6 address + * + * @param string $ip An IPv6 address + * @return bool true if $ip is a valid IPv6 address + */ + public static function check_ipv6($ip) + { + $ip = self::uncompress($ip); + list($ipv6, $ipv4) = self::split_v6_v4($ip); + $ipv6 = explode(':', $ipv6); + $ipv4 = explode('.', $ipv4); + if (count($ipv6) === 8 && count($ipv4) === 1 || count($ipv6) === 6 && count($ipv4) === 4) + { + foreach ($ipv6 as $ipv6_part) + { + // The section can't be empty + if ($ipv6_part === '') + return false; + + // Nor can it be over four characters + if (strlen($ipv6_part) > 4) + return false; + + // Remove leading zeros (this is safe because of the above) + $ipv6_part = ltrim($ipv6_part, '0'); + if ($ipv6_part === '') + $ipv6_part = '0'; + + // Check the value is valid + $value = hexdec($ipv6_part); + if (dechex($value) !== strtolower($ipv6_part) || $value < 0 || $value > 0xFFFF) + return false; + } + if (count($ipv4) === 4) + { + foreach ($ipv4 as $ipv4_part) + { + $value = (int) $ipv4_part; + if ((string) $value !== $ipv4_part || $value < 0 || $value > 0xFF) + return false; + } + } + return true; + } + else + { + return false; + } + } + + /** + * Checks if the given IP is a valid IPv6 address + * + * @codeCoverageIgnore + * @deprecated Use {@see SimplePie_Net_IPv6::check_ipv6()} instead + * @see check_ipv6 + * @param string $ip An IPv6 address + * @return bool true if $ip is a valid IPv6 address + */ + public static function checkIPv6($ip) + { + return self::check_ipv6($ip); + } +} + +/** + * Date Parser + * + * @package SimplePie + * @subpackage Parsing + */ +class SimplePie_Parse_Date +{ + /** + * Input data + * + * @access protected + * @var string + */ + var $date; + + /** + * List of days, calendar day name => ordinal day number in the week + * + * @access protected + * @var array + */ + var $day = array( + // English + 'mon' => 1, + 'monday' => 1, + 'tue' => 2, + 'tuesday' => 2, + 'wed' => 3, + 'wednesday' => 3, + 'thu' => 4, + 'thursday' => 4, + 'fri' => 5, + 'friday' => 5, + 'sat' => 6, + 'saturday' => 6, + 'sun' => 7, + 'sunday' => 7, + // Dutch + 'maandag' => 1, + 'dinsdag' => 2, + 'woensdag' => 3, + 'donderdag' => 4, + 'vrijdag' => 5, + 'zaterdag' => 6, + 'zondag' => 7, + // French + 'lundi' => 1, + 'mardi' => 2, + 'mercredi' => 3, + 'jeudi' => 4, + 'vendredi' => 5, + 'samedi' => 6, + 'dimanche' => 7, + // German + 'montag' => 1, + 'dienstag' => 2, + 'mittwoch' => 3, + 'donnerstag' => 4, + 'freitag' => 5, + 'samstag' => 6, + 'sonnabend' => 6, + 'sonntag' => 7, + // Italian + 'lunedì' => 1, + 'martedì' => 2, + 'mercoledì' => 3, + 'giovedì' => 4, + 'venerdì' => 5, + 'sabato' => 6, + 'domenica' => 7, + // Spanish + 'lunes' => 1, + 'martes' => 2, + 'miércoles' => 3, + 'jueves' => 4, + 'viernes' => 5, + 'sábado' => 6, + 'domingo' => 7, + // Finnish + 'maanantai' => 1, + 'tiistai' => 2, + 'keskiviikko' => 3, + 'torstai' => 4, + 'perjantai' => 5, + 'lauantai' => 6, + 'sunnuntai' => 7, + // Hungarian + 'hétfő' => 1, + 'kedd' => 2, + 'szerda' => 3, + 'csütörtok' => 4, + 'péntek' => 5, + 'szombat' => 6, + 'vasárnap' => 7, + // Greek + 'Δευ' => 1, + 'Τρι' => 2, + 'Τετ' => 3, + 'Πεμ' => 4, + 'Παρ' => 5, + 'Σαβ' => 6, + 'Κυρ' => 7, + ); + + /** + * List of months, calendar month name => calendar month number + * + * @access protected + * @var array + */ + var $month = array( + // English + 'jan' => 1, + 'january' => 1, + 'feb' => 2, + 'february' => 2, + 'mar' => 3, + 'march' => 3, + 'apr' => 4, + 'april' => 4, + 'may' => 5, + // No long form of May + 'jun' => 6, + 'june' => 6, + 'jul' => 7, + 'july' => 7, + 'aug' => 8, + 'august' => 8, + 'sep' => 9, + 'september' => 8, + 'oct' => 10, + 'october' => 10, + 'nov' => 11, + 'november' => 11, + 'dec' => 12, + 'december' => 12, + // Dutch + 'januari' => 1, + 'februari' => 2, + 'maart' => 3, + 'april' => 4, + 'mei' => 5, + 'juni' => 6, + 'juli' => 7, + 'augustus' => 8, + 'september' => 9, + 'oktober' => 10, + 'november' => 11, + 'december' => 12, + // French + 'janvier' => 1, + 'février' => 2, + 'mars' => 3, + 'avril' => 4, + 'mai' => 5, + 'juin' => 6, + 'juillet' => 7, + 'août' => 8, + 'septembre' => 9, + 'octobre' => 10, + 'novembre' => 11, + 'décembre' => 12, + // German + 'januar' => 1, + 'februar' => 2, + 'märz' => 3, + 'april' => 4, + 'mai' => 5, + 'juni' => 6, + 'juli' => 7, + 'august' => 8, + 'september' => 9, + 'oktober' => 10, + 'november' => 11, + 'dezember' => 12, + // Italian + 'gennaio' => 1, + 'febbraio' => 2, + 'marzo' => 3, + 'aprile' => 4, + 'maggio' => 5, + 'giugno' => 6, + 'luglio' => 7, + 'agosto' => 8, + 'settembre' => 9, + 'ottobre' => 10, + 'novembre' => 11, + 'dicembre' => 12, + // Spanish + 'enero' => 1, + 'febrero' => 2, + 'marzo' => 3, + 'abril' => 4, + 'mayo' => 5, + 'junio' => 6, + 'julio' => 7, + 'agosto' => 8, + 'septiembre' => 9, + 'setiembre' => 9, + 'octubre' => 10, + 'noviembre' => 11, + 'diciembre' => 12, + // Finnish + 'tammikuu' => 1, + 'helmikuu' => 2, + 'maaliskuu' => 3, + 'huhtikuu' => 4, + 'toukokuu' => 5, + 'kesäkuu' => 6, + 'heinäkuu' => 7, + 'elokuu' => 8, + 'suuskuu' => 9, + 'lokakuu' => 10, + 'marras' => 11, + 'joulukuu' => 12, + // Hungarian + 'január' => 1, + 'február' => 2, + 'március' => 3, + 'április' => 4, + 'május' => 5, + 'június' => 6, + 'július' => 7, + 'augusztus' => 8, + 'szeptember' => 9, + 'október' => 10, + 'november' => 11, + 'december' => 12, + // Greek + 'Ιαν' => 1, + 'Φεβ' => 2, + 'Μάώ' => 3, + 'Μαώ' => 3, + 'Απρ' => 4, + 'Μάι' => 5, + 'Μαϊ' => 5, + 'Μαι' => 5, + 'Ιούν' => 6, + 'Ιον' => 6, + 'Ιούλ' => 7, + 'Ιολ' => 7, + 'Αύγ' => 8, + 'Αυγ' => 8, + 'Σεπ' => 9, + 'Οκτ' => 10, + 'Νοέ' => 11, + 'Δεκ' => 12, + ); + + /** + * List of timezones, abbreviation => offset from UTC + * + * @access protected + * @var array + */ + var $timezone = array( + 'ACDT' => 37800, + 'ACIT' => 28800, + 'ACST' => 34200, + 'ACT' => -18000, + 'ACWDT' => 35100, + 'ACWST' => 31500, + 'AEDT' => 39600, + 'AEST' => 36000, + 'AFT' => 16200, + 'AKDT' => -28800, + 'AKST' => -32400, + 'AMDT' => 18000, + 'AMT' => -14400, + 'ANAST' => 46800, + 'ANAT' => 43200, + 'ART' => -10800, + 'AZOST' => -3600, + 'AZST' => 18000, + 'AZT' => 14400, + 'BIOT' => 21600, + 'BIT' => -43200, + 'BOT' => -14400, + 'BRST' => -7200, + 'BRT' => -10800, + 'BST' => 3600, + 'BTT' => 21600, + 'CAST' => 18000, + 'CAT' => 7200, + 'CCT' => 23400, + 'CDT' => -18000, + 'CEDT' => 7200, + 'CET' => 3600, + 'CGST' => -7200, + 'CGT' => -10800, + 'CHADT' => 49500, + 'CHAST' => 45900, + 'CIST' => -28800, + 'CKT' => -36000, + 'CLDT' => -10800, + 'CLST' => -14400, + 'COT' => -18000, + 'CST' => -21600, + 'CVT' => -3600, + 'CXT' => 25200, + 'DAVT' => 25200, + 'DTAT' => 36000, + 'EADT' => -18000, + 'EAST' => -21600, + 'EAT' => 10800, + 'ECT' => -18000, + 'EDT' => -14400, + 'EEST' => 10800, + 'EET' => 7200, + 'EGT' => -3600, + 'EKST' => 21600, + 'EST' => -18000, + 'FJT' => 43200, + 'FKDT' => -10800, + 'FKST' => -14400, + 'FNT' => -7200, + 'GALT' => -21600, + 'GEDT' => 14400, + 'GEST' => 10800, + 'GFT' => -10800, + 'GILT' => 43200, + 'GIT' => -32400, + 'GST' => 14400, + 'GST' => -7200, + 'GYT' => -14400, + 'HAA' => -10800, + 'HAC' => -18000, + 'HADT' => -32400, + 'HAE' => -14400, + 'HAP' => -25200, + 'HAR' => -21600, + 'HAST' => -36000, + 'HAT' => -9000, + 'HAY' => -28800, + 'HKST' => 28800, + 'HMT' => 18000, + 'HNA' => -14400, + 'HNC' => -21600, + 'HNE' => -18000, + 'HNP' => -28800, + 'HNR' => -25200, + 'HNT' => -12600, + 'HNY' => -32400, + 'IRDT' => 16200, + 'IRKST' => 32400, + 'IRKT' => 28800, + 'IRST' => 12600, + 'JFDT' => -10800, + 'JFST' => -14400, + 'JST' => 32400, + 'KGST' => 21600, + 'KGT' => 18000, + 'KOST' => 39600, + 'KOVST' => 28800, + 'KOVT' => 25200, + 'KRAST' => 28800, + 'KRAT' => 25200, + 'KST' => 32400, + 'LHDT' => 39600, + 'LHST' => 37800, + 'LINT' => 50400, + 'LKT' => 21600, + 'MAGST' => 43200, + 'MAGT' => 39600, + 'MAWT' => 21600, + 'MDT' => -21600, + 'MESZ' => 7200, + 'MEZ' => 3600, + 'MHT' => 43200, + 'MIT' => -34200, + 'MNST' => 32400, + 'MSDT' => 14400, + 'MSST' => 10800, + 'MST' => -25200, + 'MUT' => 14400, + 'MVT' => 18000, + 'MYT' => 28800, + 'NCT' => 39600, + 'NDT' => -9000, + 'NFT' => 41400, + 'NMIT' => 36000, + 'NOVST' => 25200, + 'NOVT' => 21600, + 'NPT' => 20700, + 'NRT' => 43200, + 'NST' => -12600, + 'NUT' => -39600, + 'NZDT' => 46800, + 'NZST' => 43200, + 'OMSST' => 25200, + 'OMST' => 21600, + 'PDT' => -25200, + 'PET' => -18000, + 'PETST' => 46800, + 'PETT' => 43200, + 'PGT' => 36000, + 'PHOT' => 46800, + 'PHT' => 28800, + 'PKT' => 18000, + 'PMDT' => -7200, + 'PMST' => -10800, + 'PONT' => 39600, + 'PST' => -28800, + 'PWT' => 32400, + 'PYST' => -10800, + 'PYT' => -14400, + 'RET' => 14400, + 'ROTT' => -10800, + 'SAMST' => 18000, + 'SAMT' => 14400, + 'SAST' => 7200, + 'SBT' => 39600, + 'SCDT' => 46800, + 'SCST' => 43200, + 'SCT' => 14400, + 'SEST' => 3600, + 'SGT' => 28800, + 'SIT' => 28800, + 'SRT' => -10800, + 'SST' => -39600, + 'SYST' => 10800, + 'SYT' => 7200, + 'TFT' => 18000, + 'THAT' => -36000, + 'TJT' => 18000, + 'TKT' => -36000, + 'TMT' => 18000, + 'TOT' => 46800, + 'TPT' => 32400, + 'TRUT' => 36000, + 'TVT' => 43200, + 'TWT' => 28800, + 'UYST' => -7200, + 'UYT' => -10800, + 'UZT' => 18000, + 'VET' => -14400, + 'VLAST' => 39600, + 'VLAT' => 36000, + 'VOST' => 21600, + 'VUT' => 39600, + 'WAST' => 7200, + 'WAT' => 3600, + 'WDT' => 32400, + 'WEST' => 3600, + 'WFT' => 43200, + 'WIB' => 25200, + 'WIT' => 32400, + 'WITA' => 28800, + 'WKST' => 18000, + 'WST' => 28800, + 'YAKST' => 36000, + 'YAKT' => 32400, + 'YAPT' => 36000, + 'YEKST' => 21600, + 'YEKT' => 18000, + ); + + /** + * Cached PCRE for SimplePie_Parse_Date::$day * - * @access public - * @param string $path - * @return bool + * @access protected + * @var string */ - function set_path($path) - { - if ($path === null || $path === '') - { - $this->path = null; - $this->valid[__FUNCTION__] = true; - return true; - } - elseif (substr($path, 0, 2) === '//' && $this->userinfo === null && $this->host === null && $this->port === null) - { - $this->path = null; - $this->valid[__FUNCTION__] = false; - return false; - } - else - { - $this->path = $this->replace_invalid_with_pct_encoding($path, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~!$&\'()*+,;=@/'); - if ($this->scheme !== null) - { - $this->path = $this->remove_dot_segments($this->path); - } - $this->valid[__FUNCTION__] = true; - return true; - } - } + var $day_pcre; /** - * Set the query. + * Cached PCRE for SimplePie_Parse_Date::$month * - * @access public - * @param string $query - * @return bool + * @access protected + * @var string */ - function set_query($query) - { - if ($query === null || $query === '') - { - $this->query = null; - } - else - { - $this->query = $this->replace_invalid_with_pct_encoding($query, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~!$\'()*+,;:@/?&='); - } - $this->valid[__FUNCTION__] = true; - return true; - } + var $month_pcre; /** - * Set the fragment. + * Array of user-added callback methods * - * @access public - * @param string $fragment - * @return bool + * @access private + * @var array */ - function set_fragment($fragment) - { - if ($fragment === null || $fragment === '') - { - $this->fragment = null; - } - else - { - $this->fragment = $this->replace_invalid_with_pct_encoding($fragment, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~!$&\'()*+,;=:@/?'); - } - $this->valid[__FUNCTION__] = true; - return true; - } + var $built_in = array(); /** - * Get the complete IRI + * Array of user-added callback methods * - * @access public - * @return string + * @access private + * @var array */ - function get_iri() - { - $iri = ''; - if ($this->scheme !== null) - { - $iri .= $this->scheme . ':'; - } - if (($authority = $this->get_authority()) !== null) - { - $iri .= '//' . $authority; - } - if ($this->path !== null) - { - $iri .= $this->path; - } - if ($this->query !== null) - { - $iri .= '?' . $this->query; - } - if ($this->fragment !== null) - { - $iri .= '#' . $this->fragment; - } - - if ($iri !== '') - { - return $iri; - } - else - { - return null; - } - } + var $user = array(); /** - * Get the scheme + * Create new SimplePie_Parse_Date object, and set self::day_pcre, + * self::month_pcre, and self::built_in * - * @access public - * @return string + * @access private */ - function get_scheme() + public function __construct() { - return $this->scheme; - } + $this->day_pcre = '(' . implode(array_keys($this->day), '|') . ')'; + $this->month_pcre = '(' . implode(array_keys($this->month), '|') . ')'; - /** - * Get the complete authority - * - * @access public - * @return string - */ - function get_authority() - { - $authority = ''; - if ($this->userinfo !== null) - { - $authority .= $this->userinfo . '@'; - } - if ($this->host !== null) - { - $authority .= $this->host; - } - if ($this->port !== null) + static $cache; + if (!isset($cache[get_class($this)])) { - $authority .= ':' . $this->port; - } + $all_methods = get_class_methods($this); - if ($authority !== '') - { - return $authority; + foreach ($all_methods as $method) + { + if (strtolower(substr($method, 0, 5)) === 'date_') + { + $cache[get_class($this)][] = $method; + } + } } - else + + foreach ($cache[get_class($this)] as $method) { - return null; + $this->built_in[] = $method; } } /** - * Get the user information - * - * @access public - * @return string - */ - function get_userinfo() - { - return $this->userinfo; - } - - /** - * Get the host - * - * @access public - * @return string - */ - function get_host() - { - return $this->host; - } - - /** - * Get the port - * - * @access public - * @return string - */ - function get_port() - { - return $this->port; - } - - /** - * Get the path - * - * @access public - * @return string - */ - function get_path() - { - return $this->path; - } - - /** - * Get the query - * - * @access public - * @return string - */ - function get_query() - { - return $this->query; - } - - /** - * Get the fragment - * - * @access public - * @return string - */ - function get_fragment() - { - return $this->fragment; - } -} - -/** - * Class to validate and to work with IPv6 addresses. - * - * @package SimplePie - * @copyright 2003-2005 The PHP Group - * @license http://www.opensource.org/licenses/bsd-license.php - * @link http://pear.php.net/package/Net_IPv6 - * @author Alexander Merz <alexander.merz@web.de> - * @author elfrink at introweb dot nl - * @author Josh Peck <jmp at joshpeck dot org> - * @author Geoffrey Sneddon <geoffers@gmail.com> - */ -class SimplePie_Net_IPv6 -{ - /** - * Removes a possible existing netmask specification of an IP address. + * Get the object * - * @param string $ip the (compressed) IP as Hex representation - * @return string the IP the without netmask - * @since 1.1.0 * @access public - * @static */ - function removeNetmaskSpec($ip) + public static function get() { - if (strpos($ip, '/') !== false) - { - list($addr, $nm) = explode('/', $ip); - } - else + static $object; + if (!$object) { - $addr = $ip; + $object = new SimplePie_Parse_Date; } - return $addr; + return $object; } /** - * Uncompresses an IPv6 address - * - * RFC 2373 allows you to compress zeros in an address to '::'. This - * function expects an valid IPv6 address and expands the '::' to - * the required zeros. - * - * Example: FF01::101 -> FF01:0:0:0:0:0:0:101 - * ::1 -> 0:0:0:0:0:0:0:1 - * - * @access public - * @static - * @param string $ip a valid IPv6-address (hex format) - * @return string the uncompressed IPv6-address (hex format) - */ - function Uncompress($ip) - { - $uip = SimplePie_Net_IPv6::removeNetmaskSpec($ip); - $c1 = -1; - $c2 = -1; - if (strpos($ip, '::') !== false) - { - list($ip1, $ip2) = explode('::', $ip); - if ($ip1 === '') - { - $c1 = -1; - } - else - { - $pos = 0; - if (($pos = substr_count($ip1, ':')) > 0) - { - $c1 = $pos; - } - else - { - $c1 = 0; - } - } - if ($ip2 === '') - { - $c2 = -1; - } - else - { - $pos = 0; - if (($pos = substr_count($ip2, ':')) > 0) - { - $c2 = $pos; - } - else - { - $c2 = 0; - } - } - if (strstr($ip2, '.')) - { - $c2++; - } - // :: - if ($c1 === -1 && $c2 === -1) - { - $uip = '0:0:0:0:0:0:0:0'; - } - // ::xxx - else if ($c1 === -1) - { - $fill = str_repeat('0:', 7 - $c2); - $uip = str_replace('::', $fill, $uip); - } - // xxx:: - else if ($c2 === -1) + * Parse a date + * + * @final + * @access public + * @param string $date Date to parse + * @return int Timestamp corresponding to date string, or false on failure + */ + public function parse($date) + { + foreach ($this->user as $method) + { + if (($returned = call_user_func($method, $date)) !== false) { - $fill = str_repeat(':0', 7 - $c1); - $uip = str_replace('::', $fill, $uip); + return $returned; } - // xxx::xxx - else + } + + foreach ($this->built_in as $method) + { + if (($returned = call_user_func(array($this, $method), $date)) !== false) { - $fill = str_repeat(':0:', 6 - $c2 - $c1); - $uip = str_replace('::', $fill, $uip); - $uip = str_replace('::', ':', $uip); + return $returned; } } - return $uip; + + return false; } /** - * Splits an IPv6 address into the IPv6 and a possible IPv4 part - * - * RFC 2373 allows you to note the last two parts of an IPv6 address as - * an IPv4 compatible address - * - * Example: 0:0:0:0:0:0:13.1.68.3 - * 0:0:0:0:0:FFFF:129.144.52.38 + * Add a callback method to parse a date * + * @final * @access public - * @static - * @param string $ip a valid IPv6-address (hex format) - * @return array [0] contains the IPv6 part, [1] the IPv4 part (hex format) + * @param callback $callback */ - function SplitV64($ip) + public function add_callback($callback) { - $ip = SimplePie_Net_IPv6::Uncompress($ip); - if (strstr($ip, '.')) + if (is_callable($callback)) { - $pos = strrpos($ip, ':'); - $ip[$pos] = '_'; - $ipPart = explode('_', $ip); - return $ipPart; + $this->user[] = $callback; } else { - return array($ip, ''); + trigger_error('User-supplied function must be a valid callback', E_USER_WARNING); } } /** - * Checks an IPv6 address - * - * Checks if the given IP is IPv6-compatible + * Parse a superset of W3C-DTF (allows hyphens and colons to be omitted, as + * well as allowing any of upper or lower case "T", horizontal tabs, or + * spaces to be used as the time seperator (including more than one)) * - * @access public - * @static - * @param string $ip a valid IPv6-address - * @return bool true if $ip is an IPv6 address + * @access protected + * @return int Timestamp */ - function checkIPv6($ip) + public function date_w3cdtf($date) { - $ipPart = SimplePie_Net_IPv6::SplitV64($ip); - $count = 0; - if (!empty($ipPart[0])) + static $pcre; + if (!$pcre) + { + $year = '([0-9]{4})'; + $month = $day = $hour = $minute = $second = '([0-9]{2})'; + $decimal = '([0-9]*)'; + $zone = '(?:(Z)|([+\-])([0-9]{1,2}):?([0-9]{1,2}))'; + $pcre = '/^' . $year . '(?:-?' . $month . '(?:-?' . $day . '(?:[Tt\x09\x20]+' . $hour . '(?::?' . $minute . '(?::?' . $second . '(?:.' . $decimal . ')?)?)?' . $zone . ')?)?)?$/'; + } + if (preg_match($pcre, $date, $match)) { - $ipv6 = explode(':', $ipPart[0]); - for ($i = 0; $i < count($ipv6); $i++) + /* + Capturing subpatterns: + 1: Year + 2: Month + 3: Day + 4: Hour + 5: Minute + 6: Second + 7: Decimal fraction of a second + 8: Zulu + 9: Timezone ± + 10: Timezone hours + 11: Timezone minutes + */ + + // Fill in empty matches + for ($i = count($match); $i <= 3; $i++) { - $dec = hexdec($ipv6[$i]); - $hex = strtoupper(preg_replace('/^[0]{1,3}(.*[0-9a-fA-F])$/', '\\1', $ipv6[$i])); - if ($ipv6[$i] >= 0 && $dec <= 65535 && $hex === strtoupper(dechex($dec))) - { - $count++; - } + $match[$i] = '1'; } - if ($count === 8) + + for ($i = count($match); $i <= 7; $i++) { - return true; + $match[$i] = '0'; } - elseif ($count === 6 && !empty($ipPart[1])) + + // Numeric timezone + if (isset($match[9]) && $match[9] !== '') { - $ipv4 = explode('.', $ipPart[1]); - $count = 0; - foreach ($ipv4 as $ipv4_part) - { - if ($ipv4_part >= 0 && $ipv4_part <= 255 && preg_match('/^\d{1,3}$/', $ipv4_part)) - { - $count++; - } - } - if ($count === 4) + $timezone = $match[10] * 3600; + $timezone += $match[11] * 60; + if ($match[9] === '-') { - return true; + $timezone = 0 - $timezone; } } else { - return false; + $timezone = 0; } + // Convert the number of seconds to an integer, taking decimals into account + $second = round($match[6] + $match[7] / pow(10, strlen($match[7]))); + + return gmmktime($match[4], $match[5], $second, $match[2], $match[3], $match[1]) - $timezone; } else { return false; } } -} -/** - * Date Parser - * - * @package SimplePie - */ -class SimplePie_Parse_Date -{ /** - * Input data + * Remove RFC822 comments * * @access protected - * @var string + * @param string $data Data to strip comments from + * @return string Comment stripped string */ - var $date; + public function remove_rfc2822_comments($string) + { + $string = (string) $string; + $position = 0; + $length = strlen($string); + $depth = 0; + + $output = ''; + + while ($position < $length && ($pos = strpos($string, '(', $position)) !== false) + { + $output .= substr($string, $position, $pos - $position); + $position = $pos + 1; + if ($string[$pos - 1] !== '\\') + { + $depth++; + while ($depth && $position < $length) + { + $position += strcspn($string, '()', $position); + if ($string[$position - 1] === '\\') + { + $position++; + continue; + } + elseif (isset($string[$position])) + { + switch ($string[$position]) + { + case '(': + $depth++; + break; + + case ')': + $depth--; + break; + } + $position++; + } + else + { + break; + } + } + } + else + { + $output .= '('; + } + } + $output .= substr($string, $position); + + return $output; + } /** - * List of days, calendar day name => ordinal day number in the week + * Parse RFC2822's date format * * @access protected - * @var array + * @return int Timestamp */ - var $day = array( - // English - 'mon' => 1, - 'monday' => 1, - 'tue' => 2, - 'tuesday' => 2, - 'wed' => 3, - 'wednesday' => 3, - 'thu' => 4, - 'thursday' => 4, - 'fri' => 5, - 'friday' => 5, - 'sat' => 6, - 'saturday' => 6, - 'sun' => 7, - 'sunday' => 7, - // Dutch - 'maandag' => 1, - 'dinsdag' => 2, - 'woensdag' => 3, - 'donderdag' => 4, - 'vrijdag' => 5, - 'zaterdag' => 6, - 'zondag' => 7, - // French - 'lundi' => 1, - 'mardi' => 2, - 'mercredi' => 3, - 'jeudi' => 4, - 'vendredi' => 5, - 'samedi' => 6, - 'dimanche' => 7, - // German - 'montag' => 1, - 'dienstag' => 2, - 'mittwoch' => 3, - 'donnerstag' => 4, - 'freitag' => 5, - 'samstag' => 6, - 'sonnabend' => 6, - 'sonntag' => 7, - // Italian - 'lunedì' => 1, - 'martedì' => 2, - 'mercoledì' => 3, - 'giovedì' => 4, - 'venerdì' => 5, - 'sabato' => 6, - 'domenica' => 7, - // Spanish - 'lunes' => 1, - 'martes' => 2, - 'miércoles' => 3, - 'jueves' => 4, - 'viernes' => 5, - 'sábado' => 6, - 'domingo' => 7, - // Finnish - 'maanantai' => 1, - 'tiistai' => 2, - 'keskiviikko' => 3, - 'torstai' => 4, - 'perjantai' => 5, - 'lauantai' => 6, - 'sunnuntai' => 7, - // Hungarian - 'hétfő' => 1, - 'kedd' => 2, - 'szerda' => 3, - 'csütörtok' => 4, - 'péntek' => 5, - 'szombat' => 6, - 'vasárnap' => 7, - // Greek - 'Δευ' => 1, - 'Τρι' => 2, - 'Τετ' => 3, - 'Πεμ' => 4, - 'Παρ' => 5, - 'Σαβ' => 6, - 'Κυρ' => 7, - ); + public function date_rfc2822($date) + { + static $pcre; + if (!$pcre) + { + $wsp = '[\x09\x20]'; + $fws = '(?:' . $wsp . '+|' . $wsp . '*(?:\x0D\x0A' . $wsp . '+)+)'; + $optional_fws = $fws . '?'; + $day_name = $this->day_pcre; + $month = $this->month_pcre; + $day = '([0-9]{1,2})'; + $hour = $minute = $second = '([0-9]{2})'; + $year = '([0-9]{2,4})'; + $num_zone = '([+\-])([0-9]{2})([0-9]{2})'; + $character_zone = '([A-Z]{1,5})'; + $zone = '(?:' . $num_zone . '|' . $character_zone . ')'; + $pcre = '/(?:' . $optional_fws . $day_name . $optional_fws . ',)?' . $optional_fws . $day . $fws . $month . $fws . $year . $fws . $hour . $optional_fws . ':' . $optional_fws . $minute . '(?:' . $optional_fws . ':' . $optional_fws . $second . ')?' . $fws . $zone . '/i'; + } + if (preg_match($pcre, $this->remove_rfc2822_comments($date), $match)) + { + /* + Capturing subpatterns: + 1: Day name + 2: Day + 3: Month + 4: Year + 5: Hour + 6: Minute + 7: Second + 8: Timezone ± + 9: Timezone hours + 10: Timezone minutes + 11: Alphabetic timezone + */ + + // Find the month number + $month = $this->month[strtolower($match[3])]; + + // Numeric timezone + if ($match[8] !== '') + { + $timezone = $match[9] * 3600; + $timezone += $match[10] * 60; + if ($match[8] === '-') + { + $timezone = 0 - $timezone; + } + } + // Character timezone + elseif (isset($this->timezone[strtoupper($match[11])])) + { + $timezone = $this->timezone[strtoupper($match[11])]; + } + // Assume everything else to be -0000 + else + { + $timezone = 0; + } + + // Deal with 2/3 digit years + if ($match[4] < 50) + { + $match[4] += 2000; + } + elseif ($match[4] < 1000) + { + $match[4] += 1900; + } + + // Second is optional, if it is empty set it to zero + if ($match[7] !== '') + { + $second = $match[7]; + } + else + { + $second = 0; + } + + return gmmktime($match[5], $match[6], $second, $month, $match[2], $match[4]) - $timezone; + } + else + { + return false; + } + } /** - * List of months, calendar month name => calendar month number + * Parse RFC850's date format * * @access protected - * @var array + * @return int Timestamp */ - var $month = array( - // English - 'jan' => 1, - 'january' => 1, - 'feb' => 2, - 'february' => 2, - 'mar' => 3, - 'march' => 3, - 'apr' => 4, - 'april' => 4, - 'may' => 5, - // No long form of May - 'jun' => 6, - 'june' => 6, - 'jul' => 7, - 'july' => 7, - 'aug' => 8, - 'august' => 8, - 'sep' => 9, - 'september' => 8, - 'oct' => 10, - 'october' => 10, - 'nov' => 11, - 'november' => 11, - 'dec' => 12, - 'december' => 12, - // Dutch - 'januari' => 1, - 'februari' => 2, - 'maart' => 3, - 'april' => 4, - 'mei' => 5, - 'juni' => 6, - 'juli' => 7, - 'augustus' => 8, - 'september' => 9, - 'oktober' => 10, - 'november' => 11, - 'december' => 12, - // French - 'janvier' => 1, - 'février' => 2, - 'mars' => 3, - 'avril' => 4, - 'mai' => 5, - 'juin' => 6, - 'juillet' => 7, - 'août' => 8, - 'septembre' => 9, - 'octobre' => 10, - 'novembre' => 11, - 'décembre' => 12, - // German - 'januar' => 1, - 'februar' => 2, - 'märz' => 3, - 'april' => 4, - 'mai' => 5, - 'juni' => 6, - 'juli' => 7, - 'august' => 8, - 'september' => 9, - 'oktober' => 10, - 'november' => 11, - 'dezember' => 12, - // Italian - 'gennaio' => 1, - 'febbraio' => 2, - 'marzo' => 3, - 'aprile' => 4, - 'maggio' => 5, - 'giugno' => 6, - 'luglio' => 7, - 'agosto' => 8, - 'settembre' => 9, - 'ottobre' => 10, - 'novembre' => 11, - 'dicembre' => 12, - // Spanish - 'enero' => 1, - 'febrero' => 2, - 'marzo' => 3, - 'abril' => 4, - 'mayo' => 5, - 'junio' => 6, - 'julio' => 7, - 'agosto' => 8, - 'septiembre' => 9, - 'setiembre' => 9, - 'octubre' => 10, - 'noviembre' => 11, - 'diciembre' => 12, - // Finnish - 'tammikuu' => 1, - 'helmikuu' => 2, - 'maaliskuu' => 3, - 'huhtikuu' => 4, - 'toukokuu' => 5, - 'kesäkuu' => 6, - 'heinäkuu' => 7, - 'elokuu' => 8, - 'suuskuu' => 9, - 'lokakuu' => 10, - 'marras' => 11, - 'joulukuu' => 12, - // Hungarian - 'január' => 1, - 'február' => 2, - 'március' => 3, - 'április' => 4, - 'május' => 5, - 'június' => 6, - 'július' => 7, - 'augusztus' => 8, - 'szeptember' => 9, - 'október' => 10, - 'november' => 11, - 'december' => 12, - // Greek - 'Ιαν' => 1, - 'Φεβ' => 2, - 'Μάώ' => 3, - 'Μαώ' => 3, - 'Απρ' => 4, - 'Μάι' => 5, - 'Μαϊ' => 5, - 'Μαι' => 5, - 'Ιούν' => 6, - 'Ιον' => 6, - 'Ιούλ' => 7, - 'Ιολ' => 7, - 'Αύγ' => 8, - 'Αυγ' => 8, - 'Σεπ' => 9, - 'Οκτ' => 10, - 'Νοέ' => 11, - 'Δεκ' => 12, - ); + public function date_rfc850($date) + { + static $pcre; + if (!$pcre) + { + $space = '[\x09\x20]+'; + $day_name = $this->day_pcre; + $month = $this->month_pcre; + $day = '([0-9]{1,2})'; + $year = $hour = $minute = $second = '([0-9]{2})'; + $zone = '([A-Z]{1,5})'; + $pcre = '/^' . $day_name . ',' . $space . $day . '-' . $month . '-' . $year . $space . $hour . ':' . $minute . ':' . $second . $space . $zone . '$/i'; + } + if (preg_match($pcre, $date, $match)) + { + /* + Capturing subpatterns: + 1: Day name + 2: Day + 3: Month + 4: Year + 5: Hour + 6: Minute + 7: Second + 8: Timezone + */ + + // Month + $month = $this->month[strtolower($match[3])]; + + // Character timezone + if (isset($this->timezone[strtoupper($match[8])])) + { + $timezone = $this->timezone[strtoupper($match[8])]; + } + // Assume everything else to be -0000 + else + { + $timezone = 0; + } - /** - * List of timezones, abbreviation => offset from UTC - * - * @access protected - * @var array - */ - var $timezone = array( - 'ACDT' => 37800, - 'ACIT' => 28800, - 'ACST' => 34200, - 'ACT' => -18000, - 'ACWDT' => 35100, - 'ACWST' => 31500, - 'AEDT' => 39600, - 'AEST' => 36000, - 'AFT' => 16200, - 'AKDT' => -28800, - 'AKST' => -32400, - 'AMDT' => 18000, - 'AMT' => -14400, - 'ANAST' => 46800, - 'ANAT' => 43200, - 'ART' => -10800, - 'AZOST' => -3600, - 'AZST' => 18000, - 'AZT' => 14400, - 'BIOT' => 21600, - 'BIT' => -43200, - 'BOT' => -14400, - 'BRST' => -7200, - 'BRT' => -10800, - 'BST' => 3600, - 'BTT' => 21600, - 'CAST' => 18000, - 'CAT' => 7200, - 'CCT' => 23400, - 'CDT' => -18000, - 'CEDT' => 7200, - 'CET' => 3600, - 'CGST' => -7200, - 'CGT' => -10800, - 'CHADT' => 49500, - 'CHAST' => 45900, - 'CIST' => -28800, - 'CKT' => -36000, - 'CLDT' => -10800, - 'CLST' => -14400, - 'COT' => -18000, - 'CST' => -21600, - 'CVT' => -3600, - 'CXT' => 25200, - 'DAVT' => 25200, - 'DTAT' => 36000, - 'EADT' => -18000, - 'EAST' => -21600, - 'EAT' => 10800, - 'ECT' => -18000, - 'EDT' => -14400, - 'EEST' => 10800, - 'EET' => 7200, - 'EGT' => -3600, - 'EKST' => 21600, - 'EST' => -18000, - 'FJT' => 43200, - 'FKDT' => -10800, - 'FKST' => -14400, - 'FNT' => -7200, - 'GALT' => -21600, - 'GEDT' => 14400, - 'GEST' => 10800, - 'GFT' => -10800, - 'GILT' => 43200, - 'GIT' => -32400, - 'GST' => 14400, - 'GST' => -7200, - 'GYT' => -14400, - 'HAA' => -10800, - 'HAC' => -18000, - 'HADT' => -32400, - 'HAE' => -14400, - 'HAP' => -25200, - 'HAR' => -21600, - 'HAST' => -36000, - 'HAT' => -9000, - 'HAY' => -28800, - 'HKST' => 28800, - 'HMT' => 18000, - 'HNA' => -14400, - 'HNC' => -21600, - 'HNE' => -18000, - 'HNP' => -28800, - 'HNR' => -25200, - 'HNT' => -12600, - 'HNY' => -32400, - 'IRDT' => 16200, - 'IRKST' => 32400, - 'IRKT' => 28800, - 'IRST' => 12600, - 'JFDT' => -10800, - 'JFST' => -14400, - 'JST' => 32400, - 'KGST' => 21600, - 'KGT' => 18000, - 'KOST' => 39600, - 'KOVST' => 28800, - 'KOVT' => 25200, - 'KRAST' => 28800, - 'KRAT' => 25200, - 'KST' => 32400, - 'LHDT' => 39600, - 'LHST' => 37800, - 'LINT' => 50400, - 'LKT' => 21600, - 'MAGST' => 43200, - 'MAGT' => 39600, - 'MAWT' => 21600, - 'MDT' => -21600, - 'MESZ' => 7200, - 'MEZ' => 3600, - 'MHT' => 43200, - 'MIT' => -34200, - 'MNST' => 32400, - 'MSDT' => 14400, - 'MSST' => 10800, - 'MST' => -25200, - 'MUT' => 14400, - 'MVT' => 18000, - 'MYT' => 28800, - 'NCT' => 39600, - 'NDT' => -9000, - 'NFT' => 41400, - 'NMIT' => 36000, - 'NOVST' => 25200, - 'NOVT' => 21600, - 'NPT' => 20700, - 'NRT' => 43200, - 'NST' => -12600, - 'NUT' => -39600, - 'NZDT' => 46800, - 'NZST' => 43200, - 'OMSST' => 25200, - 'OMST' => 21600, - 'PDT' => -25200, - 'PET' => -18000, - 'PETST' => 46800, - 'PETT' => 43200, - 'PGT' => 36000, - 'PHOT' => 46800, - 'PHT' => 28800, - 'PKT' => 18000, - 'PMDT' => -7200, - 'PMST' => -10800, - 'PONT' => 39600, - 'PST' => -28800, - 'PWT' => 32400, - 'PYST' => -10800, - 'PYT' => -14400, - 'RET' => 14400, - 'ROTT' => -10800, - 'SAMST' => 18000, - 'SAMT' => 14400, - 'SAST' => 7200, - 'SBT' => 39600, - 'SCDT' => 46800, - 'SCST' => 43200, - 'SCT' => 14400, - 'SEST' => 3600, - 'SGT' => 28800, - 'SIT' => 28800, - 'SRT' => -10800, - 'SST' => -39600, - 'SYST' => 10800, - 'SYT' => 7200, - 'TFT' => 18000, - 'THAT' => -36000, - 'TJT' => 18000, - 'TKT' => -36000, - 'TMT' => 18000, - 'TOT' => 46800, - 'TPT' => 32400, - 'TRUT' => 36000, - 'TVT' => 43200, - 'TWT' => 28800, - 'UYST' => -7200, - 'UYT' => -10800, - 'UZT' => 18000, - 'VET' => -14400, - 'VLAST' => 39600, - 'VLAT' => 36000, - 'VOST' => 21600, - 'VUT' => 39600, - 'WAST' => 7200, - 'WAT' => 3600, - 'WDT' => 32400, - 'WEST' => 3600, - 'WFT' => 43200, - 'WIB' => 25200, - 'WIT' => 32400, - 'WITA' => 28800, - 'WKST' => 18000, - 'WST' => 28800, - 'YAKST' => 36000, - 'YAKT' => 32400, - 'YAPT' => 36000, - 'YEKST' => 21600, - 'YEKT' => 18000, - ); + // Deal with 2 digit year + if ($match[4] < 50) + { + $match[4] += 2000; + } + else + { + $match[4] += 1900; + } + + return gmmktime($match[5], $match[6], $match[7], $month, $match[2], $match[4]) - $timezone; + } + else + { + return false; + } + } /** - * Cached PCRE for SimplePie_Parse_Date::$day + * Parse C99's asctime()'s date format * * @access protected - * @var string + * @return int Timestamp */ - var $day_pcre; + public function date_asctime($date) + { + static $pcre; + if (!$pcre) + { + $space = '[\x09\x20]+'; + $wday_name = $this->day_pcre; + $mon_name = $this->month_pcre; + $day = '([0-9]{1,2})'; + $hour = $sec = $min = '([0-9]{2})'; + $year = '([0-9]{4})'; + $terminator = '\x0A?\x00?'; + $pcre = '/^' . $wday_name . $space . $mon_name . $space . $day . $space . $hour . ':' . $min . ':' . $sec . $space . $year . $terminator . '$/i'; + } + if (preg_match($pcre, $date, $match)) + { + /* + Capturing subpatterns: + 1: Day name + 2: Month + 3: Day + 4: Hour + 5: Minute + 6: Second + 7: Year + */ + + $month = $this->month[strtolower($match[2])]; + return gmmktime($match[4], $match[5], $match[6], $month, $match[3], $match[7]); + } + else + { + return false; + } + } /** - * Cached PCRE for SimplePie_Parse_Date::$month + * Parse dates using strtotime() * * @access protected - * @var string + * @return int Timestamp */ - var $month_pcre; + public function date_strtotime($date) + { + $strtotime = strtotime($date); + if ($strtotime === -1 || $strtotime === false) + { + return false; + } + else + { + return $strtotime; + } + } +} - /** - * Array of user-added callback methods - * - * @access private - * @var array - */ - var $built_in = array(); +/** + * Parses XML into something sane + * + * + * This class can be overloaded with {@see SimplePie::set_parser_class()} + * + * @package SimplePie + * @subpackage Parsing + */ +class SimplePie_Parser +{ + var $error_code; + var $error_string; + var $current_line; + var $current_column; + var $current_byte; + var $separator = ' '; + var $namespace = array(''); + var $element = array(''); + var $xml_base = array(''); + var $xml_base_explicit = array(false); + var $xml_lang = array(''); + var $data = array(); + var $datas = array(array()); + var $current_xhtml_construct = -1; + var $encoding; + protected $registry; - /** - * Array of user-added callback methods - * - * @access private - * @var array - */ - var $user = array(); + public function set_registry(SimplePie_Registry $registry) + { + $this->registry = $registry; + } - /** - * Create new SimplePie_Parse_Date object, and set self::day_pcre, - * self::month_pcre, and self::built_in - * - * @access private - */ - function SimplePie_Parse_Date() + public function parse(&$data, $encoding) { - $this->day_pcre = '(' . implode(array_keys($this->day), '|') . ')'; - $this->month_pcre = '(' . implode(array_keys($this->month), '|') . ')'; + // Use UTF-8 if we get passed US-ASCII, as every US-ASCII character is a UTF-8 character + if (strtoupper($encoding) === 'US-ASCII') + { + $this->encoding = 'UTF-8'; + } + else + { + $this->encoding = $encoding; + } - static $cache; - if (!isset($cache[get_class($this)])) + // Strip BOM: + // UTF-32 Big Endian BOM + if (substr($data, 0, 4) === "\x00\x00\xFE\xFF") { - $all_methods = get_class_methods($this); + $data = substr($data, 4); + } + // UTF-32 Little Endian BOM + elseif (substr($data, 0, 4) === "\xFF\xFE\x00\x00") + { + $data = substr($data, 4); + } + // UTF-16 Big Endian BOM + elseif (substr($data, 0, 2) === "\xFE\xFF") + { + $data = substr($data, 2); + } + // UTF-16 Little Endian BOM + elseif (substr($data, 0, 2) === "\xFF\xFE") + { + $data = substr($data, 2); + } + // UTF-8 BOM + elseif (substr($data, 0, 3) === "\xEF\xBB\xBF") + { + $data = substr($data, 3); + } - foreach ($all_methods as $method) + if (substr($data, 0, 5) === '<?xml' && strspn(substr($data, 5, 1), "\x09\x0A\x0D\x20") && ($pos = strpos($data, '?>')) !== false) + { + $declaration = $this->registry->create('XML_Declaration_Parser', array(substr($data, 5, $pos - 5))); + if ($declaration->parse()) { - if (strtolower(substr($method, 0, 5)) === 'date_') - { - $cache[get_class($this)][] = $method; - } + $data = substr($data, $pos + 2); + $data = '<?xml version="' . $declaration->version . '" encoding="' . $encoding . '" standalone="' . (($declaration->standalone) ? 'yes' : 'no') . '"?>' . $data; + } + else + { + $this->error_string = 'SimplePie bug! Please report this!'; + return false; } } - foreach ($cache[get_class($this)] as $method) + $return = true; + + static $xml_is_sane = null; + if ($xml_is_sane === null) { - $this->built_in[] = $method; + $parser_check = xml_parser_create(); + xml_parse_into_struct($parser_check, '<foo>&</foo>', $values); + xml_parser_free($parser_check); + $xml_is_sane = isset($values[0]['value']); } - } - /** - * Get the object - * - * @access public - */ - function get() - { - static $object; - if (!$object) + // Create the parser + if ($xml_is_sane) { - $object = new SimplePie_Parse_Date; - } - return $object; - } + $xml = xml_parser_create_ns($this->encoding, $this->separator); + xml_parser_set_option($xml, XML_OPTION_SKIP_WHITE, 1); + xml_parser_set_option($xml, XML_OPTION_CASE_FOLDING, 0); + xml_set_object($xml, $this); + xml_set_character_data_handler($xml, 'cdata'); + xml_set_element_handler($xml, 'tag_open', 'tag_close'); - /** - * Parse a date - * - * @final - * @access public - * @param string $date Date to parse - * @return int Timestamp corresponding to date string, or false on failure - */ - function parse($date) - { - foreach ($this->user as $method) + // Parse! + if (!xml_parse($xml, $data, true)) + { + $this->error_code = xml_get_error_code($xml); + $this->error_string = xml_error_string($this->error_code); + $return = false; + } + $this->current_line = xml_get_current_line_number($xml); + $this->current_column = xml_get_current_column_number($xml); + $this->current_byte = xml_get_current_byte_index($xml); + xml_parser_free($xml); + return $return; + } + else { - if (($returned = call_user_func($method, $date)) !== false) + libxml_clear_errors(); + $xml = new XMLReader(); + $xml->xml($data); + while (@$xml->read()) { - return $returned; + switch ($xml->nodeType) + { + + case constant('XMLReader::END_ELEMENT'): + if ($xml->namespaceURI !== '') + { + $tagName = $xml->namespaceURI . $this->separator . $xml->localName; + } + else + { + $tagName = $xml->localName; + } + $this->tag_close(null, $tagName); + break; + case constant('XMLReader::ELEMENT'): + $empty = $xml->isEmptyElement; + if ($xml->namespaceURI !== '') + { + $tagName = $xml->namespaceURI . $this->separator . $xml->localName; + } + else + { + $tagName = $xml->localName; + } + $attributes = array(); + while ($xml->moveToNextAttribute()) + { + if ($xml->namespaceURI !== '') + { + $attrName = $xml->namespaceURI . $this->separator . $xml->localName; + } + else + { + $attrName = $xml->localName; + } + $attributes[$attrName] = $xml->value; + } + $this->tag_open(null, $tagName, $attributes); + if ($empty) + { + $this->tag_close(null, $tagName); + } + break; + case constant('XMLReader::TEXT'): + + case constant('XMLReader::CDATA'): + $this->cdata(null, $xml->value); + break; + } + } + if ($error = libxml_get_last_error()) + { + $this->error_code = $error->code; + $this->error_string = $error->message; + $this->current_line = $error->line; + $this->current_column = $error->column; + return false; + } + else + { + return true; } } + } + + public function get_error_code() + { + return $this->error_code; + } + + public function get_error_string() + { + return $this->error_string; + } + + public function get_current_line() + { + return $this->current_line; + } - foreach ($this->built_in as $method) - { - if (($returned = call_user_func(array(&$this, $method), $date)) !== false) - { - return $returned; - } - } + public function get_current_column() + { + return $this->current_column; + } - return false; + public function get_current_byte() + { + return $this->current_byte; } - /** - * Add a callback method to parse a date - * - * @final - * @access public - * @param callback $callback - */ - function add_callback($callback) + public function get_data() { - if (is_callable($callback)) - { - $this->user[] = $callback; - } - else - { - trigger_error('User-supplied function must be a valid callback', E_USER_WARNING); - } + return $this->data; } - /** - * Parse a superset of W3C-DTF (allows hyphens and colons to be omitted, as - * well as allowing any of upper or lower case "T", horizontal tabs, or - * spaces to be used as the time seperator (including more than one)) - * - * @access protected - * @return int Timestamp - */ - function date_w3cdtf($date) + public function tag_open($parser, $tag, $attributes) { - static $pcre; - if (!$pcre) + list($this->namespace[], $this->element[]) = $this->split_ns($tag); + + $attribs = array(); + foreach ($attributes as $name => $value) { - $year = '([0-9]{4})'; - $month = $day = $hour = $minute = $second = '([0-9]{2})'; - $decimal = '([0-9]*)'; - $zone = '(?:(Z)|([+\-])([0-9]{1,2}):?([0-9]{1,2}))'; - $pcre = '/^' . $year . '(?:-?' . $month . '(?:-?' . $day . '(?:[Tt\x09\x20]+' . $hour . '(?::?' . $minute . '(?::?' . $second . '(?:.' . $decimal . ')?)?)?' . $zone . ')?)?)?$/'; + list($attrib_namespace, $attribute) = $this->split_ns($name); + $attribs[$attrib_namespace][$attribute] = $value; } - if (preg_match($pcre, $date, $match)) - { - /* - Capturing subpatterns: - 1: Year - 2: Month - 3: Day - 4: Hour - 5: Minute - 6: Second - 7: Decimal fraction of a second - 8: Zulu - 9: Timezone ± - 10: Timezone hours - 11: Timezone minutes - */ - - // Fill in empty matches - for ($i = count($match); $i <= 3; $i++) - { - $match[$i] = '1'; - } - - for ($i = count($match); $i <= 7; $i++) - { - $match[$i] = '0'; - } - // Numeric timezone - if (isset($match[9]) && $match[9] !== '') - { - $timezone = $match[10] * 3600; - $timezone += $match[11] * 60; - if ($match[9] === '-') - { - $timezone = 0 - $timezone; - } - } - else + if (isset($attribs[SIMPLEPIE_NAMESPACE_XML]['base'])) + { + $base = $this->registry->call('Misc', 'absolutize_url', array($attribs[SIMPLEPIE_NAMESPACE_XML]['base'], end($this->xml_base))); + if ($base !== false) { - $timezone = 0; + $this->xml_base[] = $base; + $this->xml_base_explicit[] = true; } - - // Convert the number of seconds to an integer, taking decimals into account - $second = round($match[6] + $match[7] / pow(10, strlen($match[7]))); - - return gmmktime($match[4], $match[5], $second, $match[2], $match[3], $match[1]) - $timezone; } else { - return false; + $this->xml_base[] = end($this->xml_base); + $this->xml_base_explicit[] = end($this->xml_base_explicit); } - } - - /** - * Remove RFC822 comments - * - * @access protected - * @param string $data Data to strip comments from - * @return string Comment stripped string - */ - function remove_rfc2822_comments($string) - { - $string = (string) $string; - $position = 0; - $length = strlen($string); - $depth = 0; - $output = ''; + if (isset($attribs[SIMPLEPIE_NAMESPACE_XML]['lang'])) + { + $this->xml_lang[] = $attribs[SIMPLEPIE_NAMESPACE_XML]['lang']; + } + else + { + $this->xml_lang[] = end($this->xml_lang); + } - while ($position < $length && ($pos = strpos($string, '(', $position)) !== false) + if ($this->current_xhtml_construct >= 0) { - $output .= substr($string, $position, $pos - $position); - $position = $pos + 1; - if ($string[$pos - 1] !== '\\') + $this->current_xhtml_construct++; + if (end($this->namespace) === SIMPLEPIE_NAMESPACE_XHTML) { - $depth++; - while ($depth && $position < $length) + $this->data['data'] .= '<' . end($this->element); + if (isset($attribs[''])) { - $position += strcspn($string, '()', $position); - if ($string[$position - 1] === '\\') - { - $position++; - continue; - } - elseif (isset($string[$position])) - { - switch ($string[$position]) - { - case '(': - $depth++; - break; - - case ')': - $depth--; - break; - } - $position++; - } - else + foreach ($attribs[''] as $name => $value) { - break; + $this->data['data'] .= ' ' . $name . '="' . htmlspecialchars($value, ENT_COMPAT, $this->encoding) . '"'; } } + $this->data['data'] .= '>'; } - else + } + else + { + $this->datas[] =& $this->data; + $this->data =& $this->data['child'][end($this->namespace)][end($this->element)][]; + $this->data = array('data' => '', 'attribs' => $attribs, 'xml_base' => end($this->xml_base), 'xml_base_explicit' => end($this->xml_base_explicit), 'xml_lang' => end($this->xml_lang)); + if ((end($this->namespace) === SIMPLEPIE_NAMESPACE_ATOM_03 && in_array(end($this->element), array('title', 'tagline', 'copyright', 'info', 'summary', 'content')) && isset($attribs['']['mode']) && $attribs['']['mode'] === 'xml') + || (end($this->namespace) === SIMPLEPIE_NAMESPACE_ATOM_10 && in_array(end($this->element), array('rights', 'subtitle', 'summary', 'info', 'title', 'content')) && isset($attribs['']['type']) && $attribs['']['type'] === 'xhtml') + || (end($this->namespace) === SIMPLEPIE_NAMESPACE_RSS_20 && in_array(end($this->element), array('title'))) + || (end($this->namespace) === SIMPLEPIE_NAMESPACE_RSS_090 && in_array(end($this->element), array('title'))) + || (end($this->namespace) === SIMPLEPIE_NAMESPACE_RSS_10 && in_array(end($this->element), array('title')))) { - $output .= '('; + $this->current_xhtml_construct = 0; } } - $output .= substr($string, $position); - - return $output; } - /** - * Parse RFC2822's date format - * - * @access protected - * @return int Timestamp - */ - function date_rfc2822($date) + public function cdata($parser, $cdata) { - static $pcre; - if (!$pcre) - { - $wsp = '[\x09\x20]'; - $fws = '(?:' . $wsp . '+|' . $wsp . '*(?:\x0D\x0A' . $wsp . '+)+)'; - $optional_fws = $fws . '?'; - $day_name = $this->day_pcre; - $month = $this->month_pcre; - $day = '([0-9]{1,2})'; - $hour = $minute = $second = '([0-9]{2})'; - $year = '([0-9]{2,4})'; - $num_zone = '([+\-])([0-9]{2})([0-9]{2})'; - $character_zone = '([A-Z]{1,5})'; - $zone = '(?:' . $num_zone . '|' . $character_zone . ')'; - $pcre = '/(?:' . $optional_fws . $day_name . $optional_fws . ',)?' . $optional_fws . $day . $fws . $month . $fws . $year . $fws . $hour . $optional_fws . ':' . $optional_fws . $minute . '(?:' . $optional_fws . ':' . $optional_fws . $second . ')?' . $fws . $zone . '/i'; - } - if (preg_match($pcre, $this->remove_rfc2822_comments($date), $match)) - { - /* - Capturing subpatterns: - 1: Day name - 2: Day - 3: Month - 4: Year - 5: Hour - 6: Minute - 7: Second - 8: Timezone ± - 9: Timezone hours - 10: Timezone minutes - 11: Alphabetic timezone - */ - - // Find the month number - $month = $this->month[strtolower($match[3])]; - - // Numeric timezone - if ($match[8] !== '') - { - $timezone = $match[9] * 3600; - $timezone += $match[10] * 60; - if ($match[8] === '-') - { - $timezone = 0 - $timezone; - } - } - // Character timezone - elseif (isset($this->timezone[strtoupper($match[11])])) - { - $timezone = $this->timezone[strtoupper($match[11])]; - } - // Assume everything else to be -0000 - else - { - $timezone = 0; - } - - // Deal with 2/3 digit years - if ($match[4] < 50) - { - $match[4] += 2000; - } - elseif ($match[4] < 1000) - { - $match[4] += 1900; - } - - // Second is optional, if it is empty set it to zero - if ($match[7] !== '') - { - $second = $match[7]; - } - else - { - $second = 0; - } - - return gmmktime($match[5], $match[6], $second, $month, $match[2], $match[4]) - $timezone; + if ($this->current_xhtml_construct >= 0) + { + $this->data['data'] .= htmlspecialchars($cdata, ENT_QUOTES, $this->encoding); } else { - return false; + $this->data['data'] .= $cdata; } } - /** - * Parse RFC850's date format - * - * @access protected - * @return int Timestamp - */ - function date_rfc850($date) + public function tag_close($parser, $tag) { - static $pcre; - if (!$pcre) + if ($this->current_xhtml_construct >= 0) { - $space = '[\x09\x20]+'; - $day_name = $this->day_pcre; - $month = $this->month_pcre; - $day = '([0-9]{1,2})'; - $year = $hour = $minute = $second = '([0-9]{2})'; - $zone = '([A-Z]{1,5})'; - $pcre = '/^' . $day_name . ',' . $space . $day . '-' . $month . '-' . $year . $space . $hour . ':' . $minute . ':' . $second . $space . $zone . '$/i'; + $this->current_xhtml_construct--; + if (end($this->namespace) === SIMPLEPIE_NAMESPACE_XHTML && !in_array(end($this->element), array('area', 'base', 'basefont', 'br', 'col', 'frame', 'hr', 'img', 'input', 'isindex', 'link', 'meta', 'param'))) + { + $this->data['data'] .= '</' . end($this->element) . '>'; + } } - if (preg_match($pcre, $date, $match)) + if ($this->current_xhtml_construct === -1) { - /* - Capturing subpatterns: - 1: Day name - 2: Day - 3: Month - 4: Year - 5: Hour - 6: Minute - 7: Second - 8: Timezone - */ + $this->data =& $this->datas[count($this->datas) - 1]; + array_pop($this->datas); + } - // Month - $month = $this->month[strtolower($match[3])]; + array_pop($this->element); + array_pop($this->namespace); + array_pop($this->xml_base); + array_pop($this->xml_base_explicit); + array_pop($this->xml_lang); + } - // Character timezone - if (isset($this->timezone[strtoupper($match[8])])) - { - $timezone = $this->timezone[strtoupper($match[8])]; - } - // Assume everything else to be -0000 - else + public function split_ns($string) + { + static $cache = array(); + if (!isset($cache[$string])) + { + if ($pos = strpos($string, $this->separator)) { - $timezone = 0; - } + static $separator_length; + if (!$separator_length) + { + $separator_length = strlen($this->separator); + } + $namespace = substr($string, 0, $pos); + $local_name = substr($string, $pos + $separator_length); + if (strtolower($namespace) === SIMPLEPIE_NAMESPACE_ITUNES) + { + $namespace = SIMPLEPIE_NAMESPACE_ITUNES; + } - // Deal with 2 digit year - if ($match[4] < 50) - { - $match[4] += 2000; + // Normalize the Media RSS namespaces + if ($namespace === SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG || + $namespace === SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG2 || + $namespace === SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG3 || + $namespace === SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG4 || + $namespace === SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG5 ) + { + $namespace = SIMPLEPIE_NAMESPACE_MEDIARSS; + } + $cache[$string] = array($namespace, $local_name); } else { - $match[4] += 1900; + $cache[$string] = array('', $string); } - - return gmmktime($match[5], $match[6], $match[7], $month, $match[2], $match[4]) - $timezone; - } - else - { - return false; } + return $cache[$string]; } +} + +/** + * Handles `<media:rating>` or `<itunes:explicit>` tags as defined in Media RSS and iTunes RSS respectively + * + * Used by {@see SimplePie_Enclosure::get_rating()} and {@see SimplePie_Enclosure::get_ratings()} + * + * This class can be overloaded with {@see SimplePie::set_rating_class()} + * + * @package SimplePie + * @subpackage API + */ +class SimplePie_Rating +{ + /** + * Rating scheme + * + * @var string + * @see get_scheme() + */ + var $scheme; /** - * Parse C99's asctime()'s date format + * Rating value * - * @access protected - * @return int Timestamp + * @var string + * @see get_value() */ - function date_asctime($date) + var $value; + + /** + * Constructor, used to input the data + * + * For documentation on all the parameters, see the corresponding + * properties and their accessors + */ + public function __construct($scheme = null, $value = null) { - static $pcre; - if (!$pcre) - { - $space = '[\x09\x20]+'; - $wday_name = $this->day_pcre; - $mon_name = $this->month_pcre; - $day = '([0-9]{1,2})'; - $hour = $sec = $min = '([0-9]{2})'; - $year = '([0-9]{4})'; - $terminator = '\x0A?\x00?'; - $pcre = '/^' . $wday_name . $space . $mon_name . $space . $day . $space . $hour . ':' . $min . ':' . $sec . $space . $year . $terminator . '$/i'; - } - if (preg_match($pcre, $date, $match)) - { - /* - Capturing subpatterns: - 1: Day name - 2: Month - 3: Day - 4: Hour - 5: Minute - 6: Second - 7: Year - */ + $this->scheme = $scheme; + $this->value = $value; + } - $month = $this->month[strtolower($match[2])]; - return gmmktime($match[4], $match[5], $match[6], $month, $match[3], $match[7]); + /** + * String-ified version + * + * @return string + */ + public function __toString() + { + // There is no $this->data here + return md5(serialize($this)); + } + + /** + * Get the organizational scheme for the rating + * + * @return string|null + */ + public function get_scheme() + { + if ($this->scheme !== null) + { + return $this->scheme; } else { - return false; + return null; } } /** - * Parse dates using strtotime() + * Get the value of the rating * - * @access protected - * @return int Timestamp + * @return string|null */ - function date_strtotime($date) + public function get_value() { - $strtotime = strtotime($date); - if ($strtotime === -1 || $strtotime === false) + if ($this->value !== null) { - return false; + return $this->value; } else { - return $strtotime; + return null; } } } /** - * Content-type sniffing + * Handles creating objects and calling methods + * + * Access this via {@see SimplePie::get_registry()} * * @package SimplePie */ -class SimplePie_Content_Type_Sniffer +class SimplePie_Registry { /** - * File object + * Default class mapping * - * @var SimplePie_File - * @access private + * Overriding classes *must* subclass these. + * + * @var array */ - var $file; + protected $default = array( + 'Cache' => 'SimplePie_Cache', + 'Locator' => 'SimplePie_Locator', + 'Parser' => 'SimplePie_Parser', + 'File' => 'SimplePie_File', + 'Sanitize' => 'SimplePie_Sanitize', + 'Item' => 'SimplePie_Item', + 'Author' => 'SimplePie_Author', + 'Category' => 'SimplePie_Category', + 'Enclosure' => 'SimplePie_Enclosure', + 'Caption' => 'SimplePie_Caption', + 'Copyright' => 'SimplePie_Copyright', + 'Credit' => 'SimplePie_Credit', + 'Rating' => 'SimplePie_Rating', + 'Restriction' => 'SimplePie_Restriction', + 'Content_Type_Sniffer' => 'SimplePie_Content_Type_Sniffer', + 'Source' => 'SimplePie_Source', + 'Misc' => 'SimplePie_Misc', + 'XML_Declaration_Parser' => 'SimplePie_XML_Declaration_Parser', + 'Parse_Date' => 'SimplePie_Parse_Date', + ); /** - * Create an instance of the class with the input file + * Class mapping * - * @access public - * @param SimplePie_Content_Type_Sniffer $file Input file + * @see register() + * @var array */ - function SimplePie_Content_Type_Sniffer($file) - { - $this->file = $file; - } + protected $classes = array(); /** - * Get the Content-Type of the specified file + * Legacy classes * - * @access public - * @return string Actual Content-Type + * @see register() + * @var array */ - function get_type() - { - if (isset($this->file->headers['content-type'])) - { - if (!isset($this->file->headers['content-encoding']) - && ($this->file->headers['content-type'] === 'text/plain' - || $this->file->headers['content-type'] === 'text/plain; charset=ISO-8859-1' - || $this->file->headers['content-type'] === 'text/plain; charset=iso-8859-1')) - { - return $this->text_or_binary(); - } - - if (($pos = strpos($this->file->headers['content-type'], ';')) !== false) - { - $official = substr($this->file->headers['content-type'], 0, $pos); - } - else - { - $official = $this->file->headers['content-type']; - } - $official = strtolower($official); - - if ($official === 'unknown/unknown' - || $official === 'application/unknown') - { - return $this->unknown(); - } - elseif (substr($official, -4) === '+xml' - || $official === 'text/xml' - || $official === 'application/xml') - { - return $official; - } - elseif (substr($official, 0, 6) === 'image/') - { - if ($return = $this->image()) - { - return $return; - } - else - { - return $official; - } - } - elseif ($official === 'text/html') - { - return $this->feed_or_html(); - } - else - { - return $official; - } - } - else - { - return $this->unknown(); - } - } + protected $legacy = array(); /** - * Sniff text or binary + * Constructor * - * @access private - * @return string Actual Content-Type + * No-op + */ + public function __construct() { } + + /** + * Register a class + * + * @param string $type See {@see $default} for names + * @param string $class Class name, must subclass the corresponding default + * @param bool $legacy Whether to enable legacy support for this class + * @return bool Successfulness */ - function text_or_binary() + public function register($type, $class, $legacy = false) { - if (substr($this->file->body, 0, 2) === "\xFE\xFF" - || substr($this->file->body, 0, 2) === "\xFF\xFE" - || substr($this->file->body, 0, 4) === "\x00\x00\xFE\xFF" - || substr($this->file->body, 0, 3) === "\xEF\xBB\xBF") - { - return 'text/plain'; - } - elseif (preg_match('/[\x00-\x08\x0E-\x1A\x1C-\x1F]/', $this->file->body)) + if (!is_subclass_of($class, $this->default[$type])) { - return 'application/octect-stream'; + return false; } - else + + $this->classes[$type] = $class; + + if ($legacy) { - return 'text/plain'; + $this->legacy[] = $class; } + + return true; } /** - * Sniff unknown + * Get the class registered for a type * - * @access private - * @return string Actual Content-Type + * Where possible, use {@see create()} or {@see call()} instead + * + * @param string $type + * @return string|null */ - function unknown() + public function get_class($type) { - $ws = strspn($this->file->body, "\x09\x0A\x0B\x0C\x0D\x20"); - if (strtolower(substr($this->file->body, $ws, 14)) === '<!doctype html' - || strtolower(substr($this->file->body, $ws, 5)) === '<html' - || strtolower(substr($this->file->body, $ws, 7)) === '<script') - { - return 'text/html'; - } - elseif (substr($this->file->body, 0, 5) === '%PDF-') - { - return 'application/pdf'; - } - elseif (substr($this->file->body, 0, 11) === '%!PS-Adobe-') - { - return 'application/postscript'; - } - elseif (substr($this->file->body, 0, 6) === 'GIF87a' - || substr($this->file->body, 0, 6) === 'GIF89a') - { - return 'image/gif'; - } - elseif (substr($this->file->body, 0, 8) === "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A") - { - return 'image/png'; - } - elseif (substr($this->file->body, 0, 3) === "\xFF\xD8\xFF") - { - return 'image/jpeg'; - } - elseif (substr($this->file->body, 0, 2) === "\x42\x4D") + if (!empty($this->classes[$type])) { - return 'image/bmp'; + return $this->classes[$type]; } - else + if (!empty($this->default[$type])) { - return $this->text_or_binary(); + return $this->default[$type]; } + + return null; } /** - * Sniff images + * Create a new instance of a given type * - * @access private - * @return string Actual Content-Type + * @param string $type + * @param array $parameters Parameters to pass to the constructor + * @return object Instance of class */ - function image() + public function &create($type, $parameters = array()) { - if (substr($this->file->body, 0, 6) === 'GIF87a' - || substr($this->file->body, 0, 6) === 'GIF89a') - { - return 'image/gif'; - } - elseif (substr($this->file->body, 0, 8) === "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A") + $class = $this->get_class($type); + + if (in_array($class, $this->legacy)) { - return 'image/png'; + switch ($type) + { + case 'locator': + // Legacy: file, timeout, useragent, file_class, max_checked_feeds, content_type_sniffer_class + // Specified: file, timeout, useragent, max_checked_feeds + $replacement = array($this->get_class('file'), $parameters[3], $this->get_class('content_type_sniffer')); + array_splice($parameters, 3, 1, $replacement); + break; + } } - elseif (substr($this->file->body, 0, 3) === "\xFF\xD8\xFF") + + if (!method_exists($class, '__construct')) { - return 'image/jpeg'; + $instance = new $class; } - elseif (substr($this->file->body, 0, 2) === "\x42\x4D") + else { - return 'image/bmp'; + $reflector = new ReflectionClass($class); + $instance = $reflector->newInstanceArgs($parameters); } - else + + if (method_exists($instance, 'set_registry')) { - return false; + $instance->set_registry($this); } + return $instance; } /** - * Sniff HTML + * Call a static method for a type * - * @access private - * @return string Actual Content-Type + * @param string $type + * @param string $method + * @param array $parameters + * @return mixed */ - function feed_or_html() + public function &call($type, $method, $parameters = array()) { - $len = strlen($this->file->body); - $pos = strspn($this->file->body, "\x09\x0A\x0D\x20"); + $class = $this->get_class($type); - while ($pos < $len) + if (in_array($class, $this->legacy)) { - switch ($this->file->body[$pos]) + switch ($type) { - case "\x09": - case "\x0A": - case "\x0D": - case "\x20": - $pos += strspn($this->file->body, "\x09\x0A\x0D\x20", $pos); - continue 2; - - case '<': - $pos++; + case 'Cache': + // For backwards compatibility with old non-static + // Cache::create() methods + if ($method === 'get_handler') + { + $result = @call_user_func_array(array($class, 'create'), $parameters); + return $result; + } break; - - default: - return 'text/html'; - } - - if (substr($this->file->body, $pos, 3) === '!--') - { - $pos += 3; - if ($pos < $len && ($pos = strpos($this->file->body, '-->', $pos)) !== false) - { - $pos += 3; - } - else - { - return 'text/html'; - } - } - elseif (substr($this->file->body, $pos, 1) === '!') - { - if ($pos < $len && ($pos = strpos($this->file->body, '>', $pos)) !== false) - { - $pos++; - } - else - { - return 'text/html'; - } - } - elseif (substr($this->file->body, $pos, 1) === '?') - { - if ($pos < $len && ($pos = strpos($this->file->body, '?>', $pos)) !== false) - { - $pos += 2; - } - else - { - return 'text/html'; - } - } - elseif (substr($this->file->body, $pos, 3) === 'rss' - || substr($this->file->body, $pos, 7) === 'rdf:RDF') - { - return 'application/rss+xml'; - } - elseif (substr($this->file->body, $pos, 4) === 'feed') - { - return 'application/atom+xml'; - } - else - { - return 'text/html'; } } - return 'text/html'; + $result = call_user_func_array(array($class, $method), $parameters); + return $result; } } /** - * Parses the XML Declaration + * Handles `<media:restriction>` as defined in Media RSS + * + * Used by {@see SimplePie_Enclosure::get_restriction()} and {@see SimplePie_Enclosure::get_restrictions()} + * + * This class can be overloaded with {@see SimplePie::set_restriction_class()} * * @package SimplePie + * @subpackage API */ -class SimplePie_XML_Declaration_Parser +class SimplePie_Restriction { /** - * XML Version + * Relationship ('allow'/'deny') * - * @access public * @var string + * @see get_relationship() */ - var $version = '1.0'; + var $relationship; /** - * Encoding + * Type of restriction * - * @access public * @var string + * @see get_type() */ - var $encoding = 'UTF-8'; + var $type; /** - * Standalone + * Restricted values * - * @access public - * @var bool + * @var string + * @see get_value() */ - var $standalone = false; + var $value; /** - * Current state of the state machine + * Constructor, used to input the data * - * @access private - * @var string + * For documentation on all the parameters, see the corresponding + * properties and their accessors */ - var $state = 'before_version_name'; + public function __construct($relationship = null, $type = null, $value = null) + { + $this->relationship = $relationship; + $this->type = $type; + $this->value = $value; + } /** - * Input data + * String-ified version * - * @access private - * @var string + * @return string */ - var $data = ''; + public function __toString() + { + // There is no $this->data here + return md5(serialize($this)); + } /** - * Input data length (to avoid calling strlen() everytime this is needed) + * Get the relationship * - * @access private - * @var int + * @return string|null Either 'allow' or 'deny' */ - var $data_length = 0; + public function get_relationship() + { + if ($this->relationship !== null) + { + return $this->relationship; + } + else + { + return null; + } + } /** - * Current position of the pointer + * Get the type * - * @var int - * @access private + * @return string|null */ - var $position = 0; + public function get_type() + { + if ($this->type !== null) + { + return $this->type; + } + else + { + return null; + } + } + + /** + * Get the list of restricted things + * + * @return string|null + */ + public function get_value() + { + if ($this->value !== null) + { + return $this->value; + } + else + { + return null; + } + } +} + +/** + * Used for data cleanup and post-processing + * + * + * This class can be overloaded with {@see SimplePie::set_sanitize_class()} + * + * @package SimplePie + * @todo Move to using an actual HTML parser (this will allow tags to be properly stripped, and to switch between HTML and XHTML), this will also make it easier to shorten a string while preserving HTML tags + */ +class SimplePie_Sanitize +{ + // Private vars + var $base; + + // Options + var $remove_div = true; + var $image_handler = ''; + var $strip_htmltags = array('base', 'blink', 'body', 'doctype', 'embed', 'font', 'form', 'frame', 'frameset', 'html', 'iframe', 'input', 'marquee', 'meta', 'noscript', 'object', 'param', 'script', 'style'); + var $encode_instead_of_strip = false; + var $strip_attributes = array('bgsound', 'class', 'expr', 'id', 'style', 'onclick', 'onerror', 'onfinish', 'onmouseover', 'onmouseout', 'onfocus', 'onblur', 'lowsrc', 'dynsrc'); + var $strip_comments = false; + var $output_encoding = 'UTF-8'; + var $enable_cache = true; + var $cache_location = './cache'; + var $cache_name_function = 'md5'; + var $timeout = 10; + var $useragent = ''; + var $force_fsockopen = false; + var $replace_url_attributes = null; - /** - * Create an instance of the class with the input data - * - * @access public - * @param string $data Input data - */ - function SimplePie_XML_Declaration_Parser($data) + public function __construct() { - $this->data = $data; - $this->data_length = strlen($this->data); + // Set defaults + $this->set_url_replacements(null); } - /** - * Parse the input data - * - * @access public - * @return bool true on success, false on failure - */ - function parse() + public function remove_div($enable = true) { - while ($this->state && $this->state !== 'emit' && $this->has_data()) - { - $state = $this->state; - $this->$state(); - } - $this->data = ''; - if ($this->state === 'emit') + $this->remove_div = (bool) $enable; + } + + public function set_image_handler($page = false) + { + if ($page) { - return true; + $this->image_handler = (string) $page; } else { - $this->version = ''; - $this->encoding = ''; - $this->standalone = ''; - return false; + $this->image_handler = false; } } - /** - * Check whether there is data beyond the pointer - * - * @access private - * @return bool true if there is further data, false if not - */ - function has_data() + public function set_registry(SimplePie_Registry $registry) { - return (bool) ($this->position < $this->data_length); + $this->registry = $registry; } - /** - * Advance past any whitespace - * - * @return int Number of whitespace characters passed - */ - function skip_whitespace() + public function pass_cache_data($enable_cache = true, $cache_location = './cache', $cache_name_function = 'md5', $cache_class = 'SimplePie_Cache') { - $whitespace = strspn($this->data, "\x09\x0A\x0D\x20", $this->position); - $this->position += $whitespace; - return $whitespace; + if (isset($enable_cache)) + { + $this->enable_cache = (bool) $enable_cache; + } + + if ($cache_location) + { + $this->cache_location = (string) $cache_location; + } + + if ($cache_name_function) + { + $this->cache_name_function = (string) $cache_name_function; + } } - /** - * Read value - */ - function get_value() + public function pass_file_data($file_class = 'SimplePie_File', $timeout = 10, $useragent = '', $force_fsockopen = false) { - $quote = substr($this->data, $this->position, 1); - if ($quote === '"' || $quote === "'") + if ($timeout) { - $this->position++; - $len = strcspn($this->data, $quote, $this->position); - if ($this->has_data()) + $this->timeout = (string) $timeout; + } + + if ($useragent) + { + $this->useragent = (string) $useragent; + } + + if ($force_fsockopen) + { + $this->force_fsockopen = (string) $force_fsockopen; + } + } + + public function strip_htmltags($tags = array('base', 'blink', 'body', 'doctype', 'embed', 'font', 'form', 'frame', 'frameset', 'html', 'iframe', 'input', 'marquee', 'meta', 'noscript', 'object', 'param', 'script', 'style')) + { + if ($tags) + { + if (is_array($tags)) { - $value = substr($this->data, $this->position, $len); - $this->position += $len + 1; - return $value; + $this->strip_htmltags = $tags; + } + else + { + $this->strip_htmltags = explode(',', $tags); } } - return false; + else + { + $this->strip_htmltags = false; + } } - function before_version_name() + public function encode_instead_of_strip($encode = false) { - if ($this->skip_whitespace()) + $this->encode_instead_of_strip = (bool) $encode; + } + + public function strip_attributes($attribs = array('bgsound', 'class', 'expr', 'id', 'style', 'onclick', 'onerror', 'onfinish', 'onmouseover', 'onmouseout', 'onfocus', 'onblur', 'lowsrc', 'dynsrc')) + { + if ($attribs) { - $this->state = 'version_name'; + if (is_array($attribs)) + { + $this->strip_attributes = $attribs; + } + else + { + $this->strip_attributes = explode(',', $attribs); + } } else { - $this->state = false; + $this->strip_attributes = false; + } + } + + public function strip_comments($strip = false) + { + $this->strip_comments = (bool) $strip; + } + + public function set_output_encoding($encoding = 'UTF-8') + { + $this->output_encoding = (string) $encoding; + } + + /** + * Set element/attribute key/value pairs of HTML attributes + * containing URLs that need to be resolved relative to the feed + * + * Defaults to |a|@href, |area|@href, |blockquote|@cite, |del|@cite, + * |form|@action, |img|@longdesc, |img|@src, |input|@src, |ins|@cite, + * |q|@cite + * + * @since 1.0 + * @param array|null $element_attribute Element/attribute key/value pairs, null for default + */ + public function set_url_replacements($element_attribute = null) + { + if ($element_attribute === null) + { + $element_attribute = array( + 'a' => 'href', + 'area' => 'href', + 'blockquote' => 'cite', + 'del' => 'cite', + 'form' => 'action', + 'img' => array( + 'longdesc', + 'src' + ), + 'input' => 'src', + 'ins' => 'cite', + 'q' => 'cite' + ); + } + $this->replace_url_attributes = (array) $element_attribute; + } + + public function sanitize($data, $type, $base = '') + { + $data = trim($data); + if ($data !== '' || $type & SIMPLEPIE_CONSTRUCT_IRI) + { + if ($type & SIMPLEPIE_CONSTRUCT_MAYBE_HTML) + { + if (preg_match('/(&(#(x[0-9a-fA-F]+|[0-9]+)|[a-zA-Z0-9]+)|<\/[A-Za-z][^\x09\x0A\x0B\x0C\x0D\x20\x2F\x3E]*' . SIMPLEPIE_PCRE_HTML_ATTRIBUTE . '>)/', $data)) + { + $type |= SIMPLEPIE_CONSTRUCT_HTML; + } + else + { + $type |= SIMPLEPIE_CONSTRUCT_TEXT; + } + } + + if ($type & SIMPLEPIE_CONSTRUCT_BASE64) + { + $data = base64_decode($data); + } + + if ($type & (SIMPLEPIE_CONSTRUCT_HTML | SIMPLEPIE_CONSTRUCT_XHTML)) + { + + $document = new DOMDocument(); + $document->encoding = 'UTF-8'; + $data = $this->preprocess($data, $type); + + set_error_handler(array('SimplePie_Misc', 'silence_errors')); + $document->loadHTML($data); + restore_error_handler(); + + // Strip comments + if ($this->strip_comments) + { + $xpath = new DOMXPath($document); + $comments = $xpath->query('//comment()'); + + foreach ($comments as $comment) + { + $comment->parentNode->removeChild($comment); + } + } + + // Strip out HTML tags and attributes that might cause various security problems. + // Based on recommendations by Mark Pilgrim at: + // http://diveintomark.org/archives/2003/06/12/how_to_consume_rss_safely + if ($this->strip_htmltags) + { + foreach ($this->strip_htmltags as $tag) + { + $this->strip_tag($tag, $document, $type); + } + } + + if ($this->strip_attributes) + { + foreach ($this->strip_attributes as $attrib) + { + $this->strip_attr($attrib, $document); + } + } + + // Replace relative URLs + $this->base = $base; + foreach ($this->replace_url_attributes as $element => $attributes) + { + $this->replace_urls($document, $element, $attributes); + } + + // If image handling (caching, etc.) is enabled, cache and rewrite all the image tags. + if (isset($this->image_handler) && ((string) $this->image_handler) !== '' && $this->enable_cache) + { + $images = $document->getElementsByTagName('img'); + foreach ($images as $img) + { + if ($img->hasAttribute('src')) + { + $image_url = call_user_func($this->cache_name_function, $img->getAttribute('src')); + $cache = $this->registry->call('Cache', 'get_handler', array($this->cache_location, $image_url, 'spi')); + + if ($cache->load()) + { + $img->setAttribute('src', $this->image_handler . $image_url); + } + else + { + $file = $this->registry->create('File', array($img['attribs']['src']['data'], $this->timeout, 5, array('X-FORWARDED-FOR' => $_SERVER['REMOTE_ADDR']), $this->useragent, $this->force_fsockopen)); + $headers = $file->headers; + + if ($file->success && ($file->method & SIMPLEPIE_FILE_SOURCE_REMOTE === 0 || ($file->status_code === 200 || $file->status_code > 206 && $file->status_code < 300))) + { + if ($cache->save(array('headers' => $file->headers, 'body' => $file->body))) + { + $img->setAttribute('src', $this->image_handler . $image_url); + } + else + { + trigger_error("$this->cache_location is not writeable. Make sure you've set the correct relative or absolute path, and that the location is server-writable.", E_USER_WARNING); + } + } + } + } + } + } + + // Remove the DOCTYPE + // Seems to cause segfaulting if we don't do this + if ($document->firstChild instanceof DOMDocumentType) + { + $document->removeChild($document->firstChild); + } + + // Move everything from the body to the root + $real_body = $document->getElementsByTagName('body')->item(0)->childNodes->item(0); + $document->replaceChild($real_body, $document->firstChild); + + // Finally, convert to a HTML string + $data = trim($document->saveHTML()); + + if ($this->remove_div) + { + $data = preg_replace('/^<div' . SIMPLEPIE_PCRE_XML_ATTRIBUTE . '>/', '', $data); + $data = preg_replace('/<\/div>$/', '', $data); + } + else + { + $data = preg_replace('/^<div' . SIMPLEPIE_PCRE_XML_ATTRIBUTE . '>/', '<div>', $data); + } + } + + if ($type & SIMPLEPIE_CONSTRUCT_IRI) + { + $absolute = $this->registry->call('Misc', 'absolutize_url', array($data, $base)); + if ($absolute !== false) + { + $data = $absolute; + } + } + + if ($type & (SIMPLEPIE_CONSTRUCT_TEXT | SIMPLEPIE_CONSTRUCT_IRI)) + { + $data = htmlspecialchars($data, ENT_COMPAT, 'UTF-8'); + } + + if ($this->output_encoding !== 'UTF-8') + { + $data = $this->registry->call('Misc', 'change_encoding', array($data, 'UTF-8', $this->output_encoding)); + } } + return $data; } - function version_name() + protected function preprocess($html, $type) { - if (substr($this->data, $this->position, 7) === 'version') + $ret = ''; + if ($type & ~SIMPLEPIE_CONSTRUCT_XHTML) { - $this->position += 7; - $this->skip_whitespace(); - $this->state = 'version_equals'; + // Atom XHTML constructs are wrapped with a div by default + // Note: No protection if $html contains a stray </div>! + $html = '<div>' . $html . '</div>'; + $ret .= '<!DOCTYPE html>'; + $content_type = 'text/html'; } else { - $this->state = false; + $ret .= '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">'; + $content_type = 'application/xhtml+xml'; } + + $ret .= '<html><head>'; + $ret .= '<meta http-equiv="Content-Type" content="' . $content_type . '; charset=utf-8" />'; + $ret .= '</head><body>' . $html . '</body></html>'; + return $ret; } - function version_equals() + public function replace_urls($document, $tag, $attributes) { - if (substr($this->data, $this->position, 1) === '=') + if (!is_array($attributes)) { - $this->position++; - $this->skip_whitespace(); - $this->state = 'version_value'; + $attributes = array($attributes); } - else + + if (!is_array($this->strip_htmltags) || !in_array($tag, $this->strip_htmltags)) { - $this->state = false; + $elements = $document->getElementsByTagName($tag); + foreach ($elements as $element) + { + foreach ($attributes as $attribute) + { + if ($element->hasAttribute($attribute)) + { + $value = $this->registry->call('Misc', 'absolutize_url', array($element->getAttribute($attribute), $this->base)); + if ($value !== false) + { + $element->setAttribute($attribute, $value); + } + } + } + } } } - function version_value() + public function do_strip_htmltags($match) { - if ($this->version = $this->get_value()) + if ($this->encode_instead_of_strip) { - $this->skip_whitespace(); - if ($this->has_data()) + if (isset($match[4]) && !in_array(strtolower($match[1]), array('script', 'style'))) { - $this->state = 'encoding_name'; + $match[1] = htmlspecialchars($match[1], ENT_COMPAT, 'UTF-8'); + $match[2] = htmlspecialchars($match[2], ENT_COMPAT, 'UTF-8'); + return "<$match[1]$match[2]>$match[3]</$match[1]>"; } else { - $this->state = 'emit'; + return htmlspecialchars($match[0], ENT_COMPAT, 'UTF-8'); } } + elseif (isset($match[4]) && !in_array(strtolower($match[1]), array('script', 'style'))) + { + return $match[4]; + } else { - $this->state = false; + return ''; } } - function encoding_name() + protected function strip_tag($tag, $document, $type) { - if (substr($this->data, $this->position, 8) === 'encoding') + $xpath = new DOMXPath($document); + $elements = $xpath->query('body//' . $tag); + if ($this->encode_instead_of_strip) { - $this->position += 8; - $this->skip_whitespace(); - $this->state = 'encoding_equals'; + foreach ($elements as $element) + { + $fragment = $document->createDocumentFragment(); + + // For elements which aren't script or style, include the tag itself + if (!in_array($tag, array('script', 'style'))) + { + $text = '<' . $tag; + if ($element->hasAttributes()) + { + $attrs = array(); + foreach ($element->attributes as $name => $attr) + { + $value = $attr->value; + + // In XHTML, empty values should never exist, so we repeat the value + if (empty($value) && ($type & SIMPLEPIE_CONSTRUCT_XHTML)) + { + $value = $name; + } + // For HTML, empty is fine + elseif (empty($value) && ($type & SIMPLEPIE_CONSTRUCT_HTML)) + { + $attrs[] = $name; + continue; + } + + // Standard attribute text + $attrs[] = $name . '="' . $attr->value . '"'; + } + $text .= ' ' . implode(' ', $attrs); + } + $text .= '>'; + $fragment->appendChild(new DOMText($text)); + } + + $number = $element->childNodes->length; + for ($i = $number; $i > 0; $i--) + { + $child = $element->childNodes->item(0); + $fragment->appendChild($child); + } + + if (!in_array($tag, array('script', 'style'))) + { + $fragment->appendChild(new DOMText('</' . $tag . '>')); + } + + $element->parentNode->replaceChild($fragment, $element); + } + + return; + } + elseif (in_array($tag, array('script', 'style'))) + { + foreach ($elements as $element) + { + $element->parentNode->removeChild($element); + } + + return; } else { - $this->state = 'standalone_name'; + foreach ($elements as $element) + { + $fragment = $document->createDocumentFragment(); + $number = $element->childNodes->length; + for ($i = $number; $i > 0; $i--) + { + $child = $element->childNodes->item(0); + $fragment->appendChild($child); + } + + $element->parentNode->replaceChild($fragment, $element); + } } } - function encoding_equals() + protected function strip_attr($attrib, $document) { - if (substr($this->data, $this->position, 1) === '=') - { - $this->position++; - $this->skip_whitespace(); - $this->state = 'encoding_value'; - } - else + $xpath = new DOMXPath($document); + $elements = $xpath->query('//*[@' . $attrib . ']'); + + foreach ($elements as $element) { - $this->state = false; + $element->removeAttribute($attrib); } } +} + +/** + * Handles `<atom:source>` + * + * Used by {@see SimplePie_Item::get_source()} + * + * This class can be overloaded with {@see SimplePie::set_source_class()} + * + * @package SimplePie + * @subpackage API + */ +class SimplePie_Source +{ + var $item; + var $data = array(); + protected $registry; + + public function __construct($item, $data) + { + $this->item = $item; + $this->data = $data; + } - function encoding_value() + public function set_registry(SimplePie_Registry $registry) { - if ($this->encoding = $this->get_value()) + $this->registry = $registry; + } + + public function __toString() + { + return md5(serialize($this->data)); + } + + public function get_source_tags($namespace, $tag) + { + if (isset($this->data['child'][$namespace][$tag])) { - $this->skip_whitespace(); - if ($this->has_data()) - { - $this->state = 'standalone_name'; - } - else - { - $this->state = 'emit'; - } + return $this->data['child'][$namespace][$tag]; } else { - $this->state = false; + return null; } } - function standalone_name() + public function get_base($element = array()) { - if (substr($this->data, $this->position, 10) === 'standalone') + return $this->item->get_base($element); + } + + public function sanitize($data, $type, $base = '') + { + return $this->item->sanitize($data, $type, $base); + } + + public function get_item() + { + return $this->item; + } + + public function get_title() + { + if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'title')) { - $this->position += 10; - $this->skip_whitespace(); - $this->state = 'standalone_equals'; + return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0])); + } + elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'title')) + { + return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0])); + } + elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'title')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0])); + } + elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'title')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0])); + } + elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'title')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0])); + } + elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'title')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'title')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); } else { - $this->state = false; + return null; } } - function standalone_equals() + public function get_category($key = 0) { - if (substr($this->data, $this->position, 1) === '=') + $categories = $this->get_categories(); + if (isset($categories[$key])) { - $this->position++; - $this->skip_whitespace(); - $this->state = 'standalone_value'; + return $categories[$key]; } else { - $this->state = false; + return null; } } - function standalone_value() + public function get_categories() { - if ($standalone = $this->get_value()) + $categories = array(); + + foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'category') as $category) { - switch ($standalone) + $term = null; + $scheme = null; + $label = null; + if (isset($category['attribs']['']['term'])) { - case 'yes': - $this->standalone = true; - break; - - case 'no': - $this->standalone = false; - break; - - default: - $this->state = false; - return; + $term = $this->sanitize($category['attribs']['']['term'], SIMPLEPIE_CONSTRUCT_TEXT); } - - $this->skip_whitespace(); - if ($this->has_data()) + if (isset($category['attribs']['']['scheme'])) { - $this->state = false; + $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT); } - else + if (isset($category['attribs']['']['label'])) { - $this->state = 'emit'; + $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT); } + $categories[] = $this->registry->create('Category', array($term, $scheme, $label)); } - else + foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'category') as $category) { - $this->state = false; + // This is really the label, but keep this as the term also for BC. + // Label will also work on retrieving because that falls back to term. + $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT); + if (isset($category['attribs']['']['domain'])) + { + $scheme = $this->sanitize($category['attribs']['']['domain'], SIMPLEPIE_CONSTRUCT_TEXT); + } + else + { + $scheme = null; + } + $categories[] = $this->registry->create('Category', array($term, $scheme, null)); } - } -} - -class SimplePie_Locator -{ - var $useragent; - var $timeout; - var $file; - var $local = array(); - var $elsewhere = array(); - var $file_class = 'SimplePie_File'; - var $cached_entities = array(); - var $http_base; - var $base; - var $base_location = 0; - var $checked_feeds = 0; - var $max_checked_feeds = 10; - var $content_type_sniffer_class = 'SimplePie_Content_Type_Sniffer'; - - function SimplePie_Locator(&$file, $timeout = 10, $useragent = null, $file_class = 'SimplePie_File', $max_checked_feeds = 10, $content_type_sniffer_class = 'SimplePie_Content_Type_Sniffer') - { - $this->file =& $file; - $this->file_class = $file_class; - $this->useragent = $useragent; - $this->timeout = $timeout; - $this->max_checked_feeds = $max_checked_feeds; - $this->content_type_sniffer_class = $content_type_sniffer_class; - } - - function find($type = SIMPLEPIE_LOCATOR_ALL, &$working) - { - if ($this->is_feed($this->file)) + foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'subject') as $category) + { + $categories[] = $this->registry->create('Category', array($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null)); + } + foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'subject') as $category) { - return $this->file; + $categories[] = $this->registry->create('Category', array($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null)); } - if ($this->file->method & SIMPLEPIE_FILE_SOURCE_REMOTE) + if (!empty($categories)) { - $sniffer = new $this->content_type_sniffer_class($this->file); - if ($sniffer->get_type() !== 'text/html') - { - return null; - } + return array_unique($categories); } - - if ($type & ~SIMPLEPIE_LOCATOR_NONE) + else { - $this->get_base(); + return null; } + } - if ($type & SIMPLEPIE_LOCATOR_AUTODISCOVERY && $working = $this->autodiscovery()) + public function get_author($key = 0) + { + $authors = $this->get_authors(); + if (isset($authors[$key])) { - return $working[0]; + return $authors[$key]; + } + else + { + return null; } + } - if ($type & (SIMPLEPIE_LOCATOR_LOCAL_EXTENSION | SIMPLEPIE_LOCATOR_LOCAL_BODY | SIMPLEPIE_LOCATOR_REMOTE_EXTENSION | SIMPLEPIE_LOCATOR_REMOTE_BODY) && $this->get_links()) + public function get_authors() + { + $authors = array(); + foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'author') as $author) { - if ($type & SIMPLEPIE_LOCATOR_LOCAL_EXTENSION && $working = $this->extension($this->local)) + $name = null; + $uri = null; + $email = null; + if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'])) { - return $working; + $name = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); } - - if ($type & SIMPLEPIE_LOCATOR_LOCAL_BODY && $working = $this->body($this->local)) + if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data'])) { - return $working; + $uri = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0])); } - - if ($type & SIMPLEPIE_LOCATOR_REMOTE_EXTENSION && $working = $this->extension($this->elsewhere)) + if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'])) { - return $working; + $email = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); } - - if ($type & SIMPLEPIE_LOCATOR_REMOTE_BODY && $working = $this->body($this->elsewhere)) + if ($name !== null || $email !== null || $uri !== null) { - return $working; + $authors[] = $this->registry->create('Author', array($name, $uri, $email)); } } - return null; - } - - function is_feed(&$file) - { - if ($file->method & SIMPLEPIE_FILE_SOURCE_REMOTE) + if ($author = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'author')) { - $sniffer = new $this->content_type_sniffer_class($file); - $sniffed = $sniffer->get_type(); - if (in_array($sniffed, array('application/rss+xml', 'application/rdf+xml', 'text/rdf', 'application/atom+xml', 'text/xml', 'application/xml'))) + $name = null; + $url = null; + $email = null; + if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'])) { - return true; + $name = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); } - else + if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data'])) { - return false; + $url = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0])); + } + if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'])) + { + $email = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if ($name !== null || $email !== null || $url !== null) + { + $authors[] = $this->registry->create('Author', array($name, $url, $email)); } } - elseif ($file->method & SIMPLEPIE_FILE_SOURCE_LOCAL) + foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'creator') as $author) { - return true; + $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null)); + } + foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'creator') as $author) + { + $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null)); + } + foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'author') as $author) + { + $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null)); + } + + if (!empty($authors)) + { + return array_unique($authors); } else { - return false; + return null; } } - function get_base() + public function get_contributor($key = 0) { - $this->http_base = $this->file->url; - $this->base = $this->http_base; - $elements = SimplePie_Misc::get_element('base', $this->file->body); - foreach ($elements as $element) + $contributors = $this->get_contributors(); + if (isset($contributors[$key])) { - if ($element['attribs']['href']['data'] !== '') - { - $this->base = SimplePie_Misc::absolutize_url(trim($element['attribs']['href']['data']), $this->http_base); - $this->base_location = $element['offset']; - break; - } + return $contributors[$key]; + } + else + { + return null; } } - function autodiscovery() + public function get_contributors() { - $links = array_merge(SimplePie_Misc::get_element('link', $this->file->body), SimplePie_Misc::get_element('a', $this->file->body), SimplePie_Misc::get_element('area', $this->file->body)); - $done = array(); - $feeds = array(); - foreach ($links as $link) + $contributors = array(); + foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'contributor') as $contributor) { - if ($this->checked_feeds === $this->max_checked_feeds) + $name = null; + $uri = null; + $email = null; + if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'])) { - break; + $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); } - if (isset($link['attribs']['href']['data']) && isset($link['attribs']['rel']['data'])) + if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data'])) { - $rel = array_unique(SimplePie_Misc::space_seperated_tokens(strtolower($link['attribs']['rel']['data']))); - - if ($this->base_location < $link['offset']) - { - $href = SimplePie_Misc::absolutize_url(trim($link['attribs']['href']['data']), $this->base); - } - else - { - $href = SimplePie_Misc::absolutize_url(trim($link['attribs']['href']['data']), $this->http_base); - } - - if (!in_array($href, $done) && in_array('feed', $rel) || (in_array('alternate', $rel) && !empty($link['attribs']['type']['data']) && in_array(strtolower(SimplePie_Misc::parse_mime($link['attribs']['type']['data'])), array('application/rss+xml', 'application/atom+xml'))) && !isset($feeds[$href])) - { - $this->checked_feeds++; - $feed = new $this->file_class($href, $this->timeout, 5, null, $this->useragent); - if ($feed->success && ($feed->method & SIMPLEPIE_FILE_SOURCE_REMOTE === 0 || ($feed->status_code === 200 || $feed->status_code > 206 && $feed->status_code < 300)) && $this->is_feed($feed)) - { - $feeds[$href] = $feed; - } - } - $done[] = $href; + $uri = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0])); + } + if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'])) + { + $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if ($name !== null || $email !== null || $uri !== null) + { + $contributors[] = $this->registry->create('Author', array($name, $uri, $email)); + } + } + foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'contributor') as $contributor) + { + $name = null; + $url = null; + $email = null; + if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'])) + { + $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data'])) + { + $url = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0])); + } + if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'])) + { + $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if ($name !== null || $email !== null || $url !== null) + { + $contributors[] = $this->registry->create('Author', array($name, $url, $email)); } } - if (!empty($feeds)) + if (!empty($contributors)) { - return array_values($feeds); + return array_unique($contributors); } - else { + else + { return null; } } - function get_links() + public function get_link($key = 0, $rel = 'alternate') { - $links = SimplePie_Misc::get_element('a', $this->file->body); - foreach ($links as $link) + $links = $this->get_links($rel); + if (isset($links[$key])) { - if (isset($link['attribs']['href']['data'])) - { - $href = trim($link['attribs']['href']['data']); - $parsed = SimplePie_Misc::parse_url($href); - if ($parsed['scheme'] === '' || preg_match('/^(http(s)|feed)?$/i', $parsed['scheme'])) - { - if ($this->base_location < $link['offset']) - { - $href = SimplePie_Misc::absolutize_url(trim($link['attribs']['href']['data']), $this->base); - } - else - { - $href = SimplePie_Misc::absolutize_url(trim($link['attribs']['href']['data']), $this->http_base); - } - - $current = SimplePie_Misc::parse_url($this->file->url); - - if ($parsed['authority'] === '' || $parsed['authority'] === $current['authority']) - { - $this->local[] = $href; - } - else - { - $this->elsewhere[] = $href; - } - } - } + return $links[$key]; } - $this->local = array_unique($this->local); - $this->elsewhere = array_unique($this->elsewhere); - if (!empty($this->local) || !empty($this->elsewhere)) + else { - return true; + return null; } - return null; } - function extension(&$array) + /** + * Added for parity between the parent-level and the item/entry-level. + */ + public function get_permalink() + { + return $this->get_link(0); + } + + public function get_links($rel = 'alternate') { - foreach ($array as $key => $value) + if (!isset($this->data['links'])) { - if ($this->checked_feeds === $this->max_checked_feeds) - { - break; - } - if (in_array(strtolower(strrchr($value, '.')), array('.rss', '.rdf', '.atom', '.xml'))) + $this->data['links'] = array(); + if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'link')) { - $this->checked_feeds++; - $feed = new $this->file_class($value, $this->timeout, 5, null, $this->useragent); - if ($feed->success && ($feed->method & SIMPLEPIE_FILE_SOURCE_REMOTE === 0 || ($feed->status_code === 200 || $feed->status_code > 206 && $feed->status_code < 300)) && $this->is_feed($feed)) + foreach ($links as $link) { - return $feed; + if (isset($link['attribs']['']['href'])) + { + $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate'; + $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link)); + } } - else + } + if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'link')) + { + foreach ($links as $link) { - unset($array[$key]); + if (isset($link['attribs']['']['href'])) + { + $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate'; + $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link)); + + } } } - } - return null; - } - - function body(&$array) - { - foreach ($array as $key => $value) - { - if ($this->checked_feeds === $this->max_checked_feeds) + if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'link')) { - break; + $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0])); } - if (preg_match('/(rss|rdf|atom|xml)/i', $value)) + if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'link')) + { + $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0])); + } + if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'link')) + { + $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0])); + } + + $keys = array_keys($this->data['links']); + foreach ($keys as $key) { - $this->checked_feeds++; - $feed = new $this->file_class($value, $this->timeout, 5, null, $this->useragent); - if ($feed->success && ($feed->method & SIMPLEPIE_FILE_SOURCE_REMOTE === 0 || ($feed->status_code === 200 || $feed->status_code > 206 && $feed->status_code < 300)) && $this->is_feed($feed)) + if ($this->registry->call('Misc', 'is_isegment_nz_nc', array($key))) { - return $feed; + if (isset($this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key])) + { + $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] = array_merge($this->data['links'][$key], $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]); + $this->data['links'][$key] =& $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]; + } + else + { + $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] =& $this->data['links'][$key]; + } } - else + elseif (substr($key, 0, 41) === SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY) { - unset($array[$key]); + $this->data['links'][substr($key, 41)] =& $this->data['links'][$key]; } + $this->data['links'][$key] = array_unique($this->data['links'][$key]); } } - return null; - } -} - -class SimplePie_Parser -{ - var $error_code; - var $error_string; - var $current_line; - var $current_column; - var $current_byte; - var $separator = ' '; - var $namespace = array(''); - var $element = array(''); - var $xml_base = array(''); - var $xml_base_explicit = array(false); - var $xml_lang = array(''); - var $data = array(); - var $datas = array(array()); - var $current_xhtml_construct = -1; - var $encoding; - function parse(&$data, $encoding) - { - // Use UTF-8 if we get passed US-ASCII, as every US-ASCII character is a UTF-8 character - if (strtoupper($encoding) === 'US-ASCII') + if (isset($this->data['links'][$rel])) { - $this->encoding = 'UTF-8'; + return $this->data['links'][$rel]; } else { - $this->encoding = $encoding; + return null; } + } - // Strip BOM: - // UTF-32 Big Endian BOM - if (substr($data, 0, 4) === "\x00\x00\xFE\xFF") + public function get_description() + { + if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'subtitle')) { - $data = substr($data, 4); + return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0])); } - // UTF-32 Little Endian BOM - elseif (substr($data, 0, 4) === "\xFF\xFE\x00\x00") + elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'tagline')) { - $data = substr($data, 4); + return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0])); } - // UTF-16 Big Endian BOM - elseif (substr($data, 0, 2) === "\xFE\xFF") + elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'description')) { - $data = substr($data, 2); + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0])); } - // UTF-16 Little Endian BOM - elseif (substr($data, 0, 2) === "\xFF\xFE") + elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'description')) { - $data = substr($data, 2); + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0])); } - // UTF-8 BOM - elseif (substr($data, 0, 3) === "\xEF\xBB\xBF") + elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'description')) { - $data = substr($data, 3); + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0])); } - - if (substr($data, 0, 5) === '<?xml' && strspn(substr($data, 5, 1), "\x09\x0A\x0D\x20") && ($pos = strpos($data, '?>')) !== false) + elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'description')) { - $declaration = new SimplePie_XML_Declaration_Parser(substr($data, 5, $pos - 5)); - if ($declaration->parse()) - { - $data = substr($data, $pos + 2); - $data = '<?xml version="' . $declaration->version . '" encoding="' . $encoding . '" standalone="' . (($declaration->standalone) ? 'yes' : 'no') . '"?>' . $data; - } - else - { - $this->error_string = 'SimplePie bug! Please report this!'; - return false; - } + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); } - - $return = true; - - static $xml_is_sane = null; - if ($xml_is_sane === null) + elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'description')) { - $parser_check = xml_parser_create(); - xml_parse_into_struct($parser_check, '<foo>&</foo>', $values); - xml_parser_free($parser_check); - $xml_is_sane = isset($values[0]['value']); + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); } - - // Create the parser - if ($xml_is_sane) + elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'summary')) { - $xml = xml_parser_create_ns($this->encoding, $this->separator); - xml_parser_set_option($xml, XML_OPTION_SKIP_WHITE, 1); - xml_parser_set_option($xml, XML_OPTION_CASE_FOLDING, 0); - xml_set_object($xml, $this); - xml_set_character_data_handler($xml, 'cdata'); - xml_set_element_handler($xml, 'tag_open', 'tag_close'); - - // Parse! - if (!xml_parse($xml, $data, true)) - { - $this->error_code = xml_get_error_code($xml); - $this->error_string = xml_error_string($this->error_code); - $return = false; - } - $this->current_line = xml_get_current_line_number($xml); - $this->current_column = xml_get_current_column_number($xml); - $this->current_byte = xml_get_current_byte_index($xml); - xml_parser_free($xml); - return $return; + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0])); + } + elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'subtitle')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0])); } else { - libxml_clear_errors(); - $xml = new XMLReader(); - $xml->xml($data); - while (@$xml->read()) - { - switch ($xml->nodeType) - { - - case constant('XMLReader::END_ELEMENT'): - if ($xml->namespaceURI !== '') - { - $tagName = $xml->namespaceURI . $this->separator . $xml->localName; - } - else - { - $tagName = $xml->localName; - } - $this->tag_close(null, $tagName); - break; - case constant('XMLReader::ELEMENT'): - $empty = $xml->isEmptyElement; - if ($xml->namespaceURI !== '') - { - $tagName = $xml->namespaceURI . $this->separator . $xml->localName; - } - else - { - $tagName = $xml->localName; - } - $attributes = array(); - while ($xml->moveToNextAttribute()) - { - if ($xml->namespaceURI !== '') - { - $attrName = $xml->namespaceURI . $this->separator . $xml->localName; - } - else - { - $attrName = $xml->localName; - } - $attributes[$attrName] = $xml->value; - } - $this->tag_open(null, $tagName, $attributes); - if ($empty) - { - $this->tag_close(null, $tagName); - } - break; - case constant('XMLReader::TEXT'): - - case constant('XMLReader::CDATA'): - $this->cdata(null, $xml->value); - break; - } - } - if ($error = libxml_get_last_error()) - { - $this->error_code = $error->code; - $this->error_string = $error->message; - $this->current_line = $error->line; - $this->current_column = $error->column; - return false; - } - else - { - return true; - } + return null; } } - function get_error_code() - { - return $this->error_code; - } - - function get_error_string() - { - return $this->error_string; - } - - function get_current_line() - { - return $this->current_line; - } - - function get_current_column() - { - return $this->current_column; - } - - function get_current_byte() - { - return $this->current_byte; - } - - function get_data() + public function get_copyright() { - return $this->data; + if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'rights')) + { + return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0])); + } + elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'copyright')) + { + return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0])); + } + elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'copyright')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'rights')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'rights')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + else + { + return null; + } } - function tag_open($parser, $tag, $attributes) + public function get_language() { - list($this->namespace[], $this->element[]) = $this->split_ns($tag); - - $attribs = array(); - foreach ($attributes as $name => $value) + if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'language')) { - list($attrib_namespace, $attribute) = $this->split_ns($name); - $attribs[$attrib_namespace][$attribute] = $value; + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); } - - if (isset($attribs[SIMPLEPIE_NAMESPACE_XML]['base'])) + elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'language')) { - $this->xml_base[] = SimplePie_Misc::absolutize_url($attribs[SIMPLEPIE_NAMESPACE_XML]['base'], end($this->xml_base)); - $this->xml_base_explicit[] = true; + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); } - else + elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'language')) { - $this->xml_base[] = end($this->xml_base); - $this->xml_base_explicit[] = end($this->xml_base_explicit); + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); } - - if (isset($attribs[SIMPLEPIE_NAMESPACE_XML]['lang'])) + elseif (isset($this->data['xml_lang'])) { - $this->xml_lang[] = $attribs[SIMPLEPIE_NAMESPACE_XML]['lang']; + return $this->sanitize($this->data['xml_lang'], SIMPLEPIE_CONSTRUCT_TEXT); } else { - $this->xml_lang[] = end($this->xml_lang); + return null; } + } - if ($this->current_xhtml_construct >= 0) + public function get_latitude() + { + if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lat')) { - $this->current_xhtml_construct++; - if (end($this->namespace) === SIMPLEPIE_NAMESPACE_XHTML) - { - $this->data['data'] .= '<' . end($this->element); - if (isset($attribs[''])) - { - foreach ($attribs[''] as $name => $value) - { - $this->data['data'] .= ' ' . $name . '="' . htmlspecialchars($value, ENT_COMPAT, $this->encoding) . '"'; - } - } - $this->data['data'] .= '>'; - } + return (float) $return[0]['data']; + } + elseif (($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_GEORSS, 'point')) && preg_match('/^((?:-)?[0-9]+(?:\.[0-9]+)) ((?:-)?[0-9]+(?:\.[0-9]+))$/', trim($return[0]['data']), $match)) + { + return (float) $match[1]; } else { - $this->datas[] =& $this->data; - $this->data =& $this->data['child'][end($this->namespace)][end($this->element)][]; - $this->data = array('data' => '', 'attribs' => $attribs, 'xml_base' => end($this->xml_base), 'xml_base_explicit' => end($this->xml_base_explicit), 'xml_lang' => end($this->xml_lang)); - if ((end($this->namespace) === SIMPLEPIE_NAMESPACE_ATOM_03 && in_array(end($this->element), array('title', 'tagline', 'copyright', 'info', 'summary', 'content')) && isset($attribs['']['mode']) && $attribs['']['mode'] === 'xml') - || (end($this->namespace) === SIMPLEPIE_NAMESPACE_ATOM_10 && in_array(end($this->element), array('rights', 'subtitle', 'summary', 'info', 'title', 'content')) && isset($attribs['']['type']) && $attribs['']['type'] === 'xhtml')) - { - $this->current_xhtml_construct = 0; - } + return null; } } - function cdata($parser, $cdata) + public function get_longitude() { - if ($this->current_xhtml_construct >= 0) + if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'long')) { - $this->data['data'] .= htmlspecialchars($cdata, ENT_QUOTES, $this->encoding); + return (float) $return[0]['data']; + } + elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lon')) + { + return (float) $return[0]['data']; + } + elseif (($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_GEORSS, 'point')) && preg_match('/^((?:-)?[0-9]+(?:\.[0-9]+)) ((?:-)?[0-9]+(?:\.[0-9]+))$/', trim($return[0]['data']), $match)) + { + return (float) $match[2]; } else { - $this->data['data'] .= $cdata; + return null; } } - function tag_close($parser, $tag) + public function get_image_url() { - if ($this->current_xhtml_construct >= 0) + if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'image')) { - $this->current_xhtml_construct--; - if (end($this->namespace) === SIMPLEPIE_NAMESPACE_XHTML && !in_array(end($this->element), array('area', 'base', 'basefont', 'br', 'col', 'frame', 'hr', 'img', 'input', 'isindex', 'link', 'meta', 'param'))) - { - $this->data['data'] .= '</' . end($this->element) . '>'; - } + return $this->sanitize($return[0]['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI); } - if ($this->current_xhtml_construct === -1) + elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'logo')) { - $this->data =& $this->datas[count($this->datas) - 1]; - array_pop($this->datas); + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0])); } - - array_pop($this->element); - array_pop($this->namespace); - array_pop($this->xml_base); - array_pop($this->xml_base_explicit); - array_pop($this->xml_lang); - } - - function split_ns($string) - { - static $cache = array(); - if (!isset($cache[$string])) + elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'icon')) { - if ($pos = strpos($string, $this->separator)) - { - static $separator_length; - if (!$separator_length) - { - $separator_length = strlen($this->separator); - } - $namespace = substr($string, 0, $pos); - $local_name = substr($string, $pos + $separator_length); - if (strtolower($namespace) === SIMPLEPIE_NAMESPACE_ITUNES) - { - $namespace = SIMPLEPIE_NAMESPACE_ITUNES; - } - - // Normalize the Media RSS namespaces - if ($namespace === SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG) - { - $namespace = SIMPLEPIE_NAMESPACE_MEDIARSS; - } - $cache[$string] = array($namespace, $local_name); - } - else - { - $cache[$string] = array('', $string); - } + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0])); + } + else + { + return null; } - return $cache[$string]; } } /** - * @todo Move to using an actual HTML parser (this will allow tags to be properly stripped, and to switch between HTML and XHTML), this will also make it easier to shorten a string while preserving HTML tags + * Parses the XML Declaration + * + * @package SimplePie + * @subpackage Parsing */ -class SimplePie_Sanitize +class SimplePie_XML_Declaration_Parser { - // Private vars - var $base; + /** + * XML Version + * + * @access public + * @var string + */ + var $version = '1.0'; - // Options - var $remove_div = true; - var $image_handler = ''; - var $strip_htmltags = array('base', 'blink', 'body', 'doctype', 'embed', 'font', 'form', 'frame', 'frameset', 'html', 'iframe', 'input', 'marquee', 'meta', 'noscript', 'object', 'param', 'script', 'style'); - var $encode_instead_of_strip = false; - var $strip_attributes = array('bgsound', 'class', 'expr', 'id', 'style', 'onclick', 'onerror', 'onfinish', 'onmouseover', 'onmouseout', 'onfocus', 'onblur', 'lowsrc', 'dynsrc'); - var $strip_comments = false; - var $output_encoding = 'UTF-8'; - var $enable_cache = true; - var $cache_location = './cache'; - var $cache_name_function = 'md5'; - var $cache_class = 'SimplePie_Cache'; - var $file_class = 'SimplePie_File'; - var $timeout = 10; - var $useragent = ''; - var $force_fsockopen = false; + /** + * Encoding + * + * @access public + * @var string + */ + var $encoding = 'UTF-8'; - var $replace_url_attributes = array( - 'a' => 'href', - 'area' => 'href', - 'blockquote' => 'cite', - 'del' => 'cite', - 'form' => 'action', - 'img' => array('longdesc', 'src'), - 'input' => 'src', - 'ins' => 'cite', - 'q' => 'cite' - ); + /** + * Standalone + * + * @access public + * @var bool + */ + var $standalone = false; + + /** + * Current state of the state machine + * + * @access private + * @var string + */ + var $state = 'before_version_name'; + + /** + * Input data + * + * @access private + * @var string + */ + var $data = ''; + + /** + * Input data length (to avoid calling strlen() everytime this is needed) + * + * @access private + * @var int + */ + var $data_length = 0; + + /** + * Current position of the pointer + * + * @var int + * @access private + */ + var $position = 0; - function remove_div($enable = true) + /** + * Create an instance of the class with the input data + * + * @access public + * @param string $data Input data + */ + public function __construct($data) { - $this->remove_div = (bool) $enable; + $this->data = $data; + $this->data_length = strlen($this->data); } - function set_image_handler($page = false) + /** + * Parse the input data + * + * @access public + * @return bool true on success, false on failure + */ + public function parse() { - if ($page) + while ($this->state && $this->state !== 'emit' && $this->has_data()) { - $this->image_handler = (string) $page; + $state = $this->state; + $this->$state(); + } + $this->data = ''; + if ($this->state === 'emit') + { + return true; } else { - $this->image_handler = false; + $this->version = ''; + $this->encoding = ''; + $this->standalone = ''; + return false; } } - function pass_cache_data($enable_cache = true, $cache_location = './cache', $cache_name_function = 'md5', $cache_class = 'SimplePie_Cache') + /** + * Check whether there is data beyond the pointer + * + * @access private + * @return bool true if there is further data, false if not + */ + public function has_data() { - if (isset($enable_cache)) - { - $this->enable_cache = (bool) $enable_cache; - } + return (bool) ($this->position < $this->data_length); + } - if ($cache_location) + /** + * Advance past any whitespace + * + * @return int Number of whitespace characters passed + */ + public function skip_whitespace() + { + $whitespace = strspn($this->data, "\x09\x0A\x0D\x20", $this->position); + $this->position += $whitespace; + return $whitespace; + } + + /** + * Read value + */ + public function get_value() + { + $quote = substr($this->data, $this->position, 1); + if ($quote === '"' || $quote === "'") { - $this->cache_location = (string) $cache_location; + $this->position++; + $len = strcspn($this->data, $quote, $this->position); + if ($this->has_data()) + { + $value = substr($this->data, $this->position, $len); + $this->position += $len + 1; + return $value; + } } + return false; + } - if ($cache_name_function) + public function before_version_name() + { + if ($this->skip_whitespace()) { - $this->cache_name_function = (string) $cache_name_function; + $this->state = 'version_name'; } - - if ($cache_class) + else { - $this->cache_class = (string) $cache_class; + $this->state = false; } } - function pass_file_data($file_class = 'SimplePie_File', $timeout = 10, $useragent = '', $force_fsockopen = false) + public function version_name() { - if ($file_class) + if (substr($this->data, $this->position, 7) === 'version') { - $this->file_class = (string) $file_class; + $this->position += 7; + $this->skip_whitespace(); + $this->state = 'version_equals'; } - - if ($timeout) + else { - $this->timeout = (string) $timeout; + $this->state = false; } + } - if ($useragent) + public function version_equals() + { + if (substr($this->data, $this->position, 1) === '=') { - $this->useragent = (string) $useragent; + $this->position++; + $this->skip_whitespace(); + $this->state = 'version_value'; } - - if ($force_fsockopen) + else { - $this->force_fsockopen = (string) $force_fsockopen; + $this->state = false; } } - function strip_htmltags($tags = array('base', 'blink', 'body', 'doctype', 'embed', 'font', 'form', 'frame', 'frameset', 'html', 'iframe', 'input', 'marquee', 'meta', 'noscript', 'object', 'param', 'script', 'style')) + public function version_value() { - if ($tags) + if ($this->version = $this->get_value()) { - if (is_array($tags)) + $this->skip_whitespace(); + if ($this->has_data()) { - $this->strip_htmltags = $tags; + $this->state = 'encoding_name'; } else { - $this->strip_htmltags = explode(',', $tags); + $this->state = 'emit'; } } else { - $this->strip_htmltags = false; + $this->state = false; } } - function encode_instead_of_strip($encode = false) + public function encoding_name() { - $this->encode_instead_of_strip = (bool) $encode; + if (substr($this->data, $this->position, 8) === 'encoding') + { + $this->position += 8; + $this->skip_whitespace(); + $this->state = 'encoding_equals'; + } + else + { + $this->state = 'standalone_name'; + } } - function strip_attributes($attribs = array('bgsound', 'class', 'expr', 'id', 'style', 'onclick', 'onerror', 'onfinish', 'onmouseover', 'onmouseout', 'onfocus', 'onblur', 'lowsrc', 'dynsrc')) + public function encoding_equals() { - if ($attribs) + if (substr($this->data, $this->position, 1) === '=') { - if (is_array($attribs)) + $this->position++; + $this->skip_whitespace(); + $this->state = 'encoding_value'; + } + else + { + $this->state = false; + } + } + + public function encoding_value() + { + if ($this->encoding = $this->get_value()) + { + $this->skip_whitespace(); + if ($this->has_data()) { - $this->strip_attributes = $attribs; + $this->state = 'standalone_name'; } else { - $this->strip_attributes = explode(',', $attribs); + $this->state = 'emit'; } } else { - $this->strip_attributes = false; + $this->state = false; } } - function strip_comments($strip = false) - { - $this->strip_comments = (bool) $strip; - } - - function set_output_encoding($encoding = 'UTF-8') - { - $this->output_encoding = (string) $encoding; - } - - /** - * Set element/attribute key/value pairs of HTML attributes - * containing URLs that need to be resolved relative to the feed - * - * @access public - * @since 1.0 - * @param array $element_attribute Element/attribute key/value pairs - */ - function set_url_replacements($element_attribute = array('a' => 'href', 'area' => 'href', 'blockquote' => 'cite', 'del' => 'cite', 'form' => 'action', 'img' => array('longdesc', 'src'), 'input' => 'src', 'ins' => 'cite', 'q' => 'cite')) + public function standalone_name() { - $this->replace_url_attributes = (array) $element_attribute; + if (substr($this->data, $this->position, 10) === 'standalone') + { + $this->position += 10; + $this->skip_whitespace(); + $this->state = 'standalone_equals'; + } + else + { + $this->state = false; + } } - function sanitize($data, $type, $base = '') + public function standalone_equals() { - $data = trim($data); - if ($data !== '' || $type & SIMPLEPIE_CONSTRUCT_IRI) + if (substr($this->data, $this->position, 1) === '=') { - if ($type & SIMPLEPIE_CONSTRUCT_MAYBE_HTML) - { - if (preg_match('/(&(#(x[0-9a-fA-F]+|[0-9]+)|[a-zA-Z0-9]+)|<\/[A-Za-z][^\x09\x0A\x0B\x0C\x0D\x20\x2F\x3E]*' . SIMPLEPIE_PCRE_HTML_ATTRIBUTE . '>)/', $data)) - { - $type |= SIMPLEPIE_CONSTRUCT_HTML; - } - else - { - $type |= SIMPLEPIE_CONSTRUCT_TEXT; - } - } - - if ($type & SIMPLEPIE_CONSTRUCT_BASE64) - { - $data = base64_decode($data); - } - - if ($type & SIMPLEPIE_CONSTRUCT_XHTML) - { - if ($this->remove_div) - { - $data = preg_replace('/^<div' . SIMPLEPIE_PCRE_XML_ATTRIBUTE . '>/', '', $data); - $data = preg_replace('/<\/div>$/', '', $data); - } - else - { - $data = preg_replace('/^<div' . SIMPLEPIE_PCRE_XML_ATTRIBUTE . '>/', '<div>', $data); - } - } - - if ($type & (SIMPLEPIE_CONSTRUCT_HTML | SIMPLEPIE_CONSTRUCT_XHTML)) - { - // Strip comments - if ($this->strip_comments) - { - $data = SimplePie_Misc::strip_comments($data); - } - - // Strip out HTML tags and attributes that might cause various security problems. - // Based on recommendations by Mark Pilgrim at: - // http://diveintomark.org/archives/2003/06/12/how_to_consume_rss_safely - if ($this->strip_htmltags) - { - foreach ($this->strip_htmltags as $tag) - { - $pcre = "/<($tag)" . SIMPLEPIE_PCRE_HTML_ATTRIBUTE . "(>(.*)<\/$tag" . SIMPLEPIE_PCRE_HTML_ATTRIBUTE . '>|(\/)?>)/siU'; - while (preg_match($pcre, $data)) - { - $data = preg_replace_callback($pcre, array(&$this, 'do_strip_htmltags'), $data); - } - } - } - - if ($this->strip_attributes) - { - foreach ($this->strip_attributes as $attrib) - { - $data = preg_replace('/(<[A-Za-z][^\x09\x0A\x0B\x0C\x0D\x20\x2F\x3E]*)' . SIMPLEPIE_PCRE_HTML_ATTRIBUTE . trim($attrib) . '(?:\s*=\s*(?:"(?:[^"]*)"|\'(?:[^\']*)\'|(?:[^\x09\x0A\x0B\x0C\x0D\x20\x22\x27\x3E][^\x09\x0A\x0B\x0C\x0D\x20\x3E]*)?))?' . SIMPLEPIE_PCRE_HTML_ATTRIBUTE . '>/', '\1\2\3>', $data); - } - } - - // Replace relative URLs - $this->base = $base; - foreach ($this->replace_url_attributes as $element => $attributes) - { - $data = $this->replace_urls($data, $element, $attributes); - } - - // If image handling (caching, etc.) is enabled, cache and rewrite all the image tags. - if (isset($this->image_handler) && ((string) $this->image_handler) !== '' && $this->enable_cache) - { - $images = SimplePie_Misc::get_element('img', $data); - foreach ($images as $img) - { - if (isset($img['attribs']['src']['data'])) - { - $image_url = call_user_func($this->cache_name_function, $img['attribs']['src']['data']); - $cache = call_user_func(array($this->cache_class, 'create'), $this->cache_location, $image_url, 'spi'); - - if ($cache->load()) - { - $img['attribs']['src']['data'] = $this->image_handler . $image_url; - $data = str_replace($img['full'], SimplePie_Misc::element_implode($img), $data); - } - else - { - $file = new $this->file_class($img['attribs']['src']['data'], $this->timeout, 5, array('X-FORWARDED-FOR' => $_SERVER['REMOTE_ADDR']), $this->useragent, $this->force_fsockopen); - $headers = $file->headers; - - if ($file->success && ($file->method & SIMPLEPIE_FILE_SOURCE_REMOTE === 0 || ($file->status_code === 200 || $file->status_code > 206 && $file->status_code < 300))) - { - if ($cache->save(array('headers' => $file->headers, 'body' => $file->body))) - { - $img['attribs']['src']['data'] = $this->image_handler . $image_url; - $data = str_replace($img['full'], SimplePie_Misc::element_implode($img), $data); - } - else - { - trigger_error("$this->cache_location is not writeable. Make sure you've set the correct relative or absolute path, and that the location is server-writable.", E_USER_WARNING); - } - } - } - } - } - } - - // Having (possibly) taken stuff out, there may now be whitespace at the beginning/end of the data - $data = trim($data); - } - - if ($type & SIMPLEPIE_CONSTRUCT_IRI) - { - $data = SimplePie_Misc::absolutize_url($data, $base); - } - - if ($type & (SIMPLEPIE_CONSTRUCT_TEXT | SIMPLEPIE_CONSTRUCT_IRI)) - { - $data = htmlspecialchars($data, ENT_COMPAT, 'UTF-8'); - } - - if ($this->output_encoding !== 'UTF-8') - { - $data = SimplePie_Misc::change_encoding($data, 'UTF-8', $this->output_encoding); - } + $this->position++; + $this->skip_whitespace(); + $this->state = 'standalone_value'; + } + else + { + $this->state = false; } - return $data; } - function replace_urls($data, $tag, $attributes) + public function standalone_value() { - if (!is_array($this->strip_htmltags) || !in_array($tag, $this->strip_htmltags)) + if ($standalone = $this->get_value()) { - $elements = SimplePie_Misc::get_element($tag, $data); - foreach ($elements as $element) + switch ($standalone) { - if (is_array($attributes)) - { - foreach ($attributes as $attribute) - { - if (isset($element['attribs'][$attribute]['data'])) - { - $element['attribs'][$attribute]['data'] = SimplePie_Misc::absolutize_url($element['attribs'][$attribute]['data'], $this->base); - $new_element = SimplePie_Misc::element_implode($element); - $data = str_replace($element['full'], $new_element, $data); - $element['full'] = $new_element; - } - } - } - elseif (isset($element['attribs'][$attributes]['data'])) - { - $element['attribs'][$attributes]['data'] = SimplePie_Misc::absolutize_url($element['attribs'][$attributes]['data'], $this->base); - $data = str_replace($element['full'], SimplePie_Misc::element_implode($element), $data); - } + case 'yes': + $this->standalone = true; + break; + + case 'no': + $this->standalone = false; + break; + + default: + $this->state = false; + return; } - } - return $data; - } - function do_strip_htmltags($match) - { - if ($this->encode_instead_of_strip) - { - if (isset($match[4]) && !in_array(strtolower($match[1]), array('script', 'style'))) + $this->skip_whitespace(); + if ($this->has_data()) { - $match[1] = htmlspecialchars($match[1], ENT_COMPAT, 'UTF-8'); - $match[2] = htmlspecialchars($match[2], ENT_COMPAT, 'UTF-8'); - return "<$match[1]$match[2]>$match[3]</$match[1]>"; + $this->state = false; } else { - return htmlspecialchars($match[0], ENT_COMPAT, 'UTF-8'); + $this->state = 'emit'; } } - elseif (isset($match[4]) && !in_array(strtolower($match[1]), array('script', 'style'))) - { - return $match[4]; - } else { - return ''; + $this->state = false; } } } -?> -- cgit v1.2.3 From 192151b74b6b77cce79e36afd94200c50437085e Mon Sep 17 00:00:00 2001 From: Andreas Gohr <andi@splitbrain.org> Date: Sun, 3 Feb 2013 22:45:40 +0100 Subject: fixed revision JS for images --- lib/scripts/behaviour.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/scripts/behaviour.js b/lib/scripts/behaviour.js index 6878b0b96..f1c46bf4c 100644 --- a/lib/scripts/behaviour.js +++ b/lib/scripts/behaviour.js @@ -51,7 +51,7 @@ var dw_behaviour = { dw_behaviour.subscription(); dw_behaviour.revisionBoxHandler(); - jQuery('#page__revisions input[type=checkbox]').on('click', + jQuery(document).on('click','#page__revisions input[type=checkbox]', dw_behaviour.revisionBoxHandler ); }, -- cgit v1.2.3 From 36ec377e95e1b932a063729ea6582386dbafdb91 Mon Sep 17 00:00:00 2001 From: Christopher Smith <chris@jalakai.co.uk> Date: Sun, 3 Feb 2013 21:06:25 +0000 Subject: update for encoded cookie value & using rawurlencode --- inc/common.php | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/inc/common.php b/inc/common.php index 2626c0d92..730f4dc80 100644 --- a/inc/common.php +++ b/inc/common.php @@ -1548,12 +1548,14 @@ function valid_input_set($param, $valid_values, $array, $exc = '') { * Read a preference from the DokuWiki cookie */ function get_doku_pref($pref, $default) { - if(strpos($_COOKIE['DOKU_PREFS'], $pref) !== false) { - $parts = explode('#', $_COOKIE['DOKU_PREFS']); + // first, urldecode the cookie value + $doku_prefs = urldecode($_COOKIE['DOKU_PREFS']); + if(strpos($doku_prefs, $pref) !== false) { + $parts = explode('#', $doku_prefs); $cnt = count($parts); for($i = 0; $i < $cnt; $i += 2) { - if(urldecode($parts[$i]) == $pref) { - return urldecode($parts[$i + 1]); + if($parts[$i] == $pref) { + return $parts[$i + 1]; } } } @@ -1562,6 +1564,7 @@ function get_doku_pref($pref, $default) { /** * Add a preference to the DokuWiki cookie + * (remembering $_COOKIE['DOKU_PREFS'] is urlencoded) */ function set_doku_pref($pref, $val) { global $conf; @@ -1571,15 +1574,17 @@ function set_doku_pref($pref, $val) { if($orig && ($orig != $val)) { $parts = explode('#', $_COOKIE['DOKU_PREFS']); $cnt = count($parts); + // urlencode $pref for the comparison + $enc_pref = rawurlencode($pref); for($i = 0; $i < $cnt; $i += 2) { - if(urldecode($parts[$i]) == $pref) { - $parts[$i + 1] = urlencode($val); + if($parts[$i] == $enc_pref) { + $parts[$i + 1] = rawurlencode($val); break; } } $cookieVal = implode('#', $parts); } else if (!$orig) { - $cookieVal = ($_COOKIE['DOKU_PREFS'] ? $_COOKIE['DOKU_PREFS'].'#' : '').urlencode($pref).'#'.urlencode($val); + $cookieVal = ($_COOKIE['DOKU_PREFS'] ? $_COOKIE['DOKU_PREFS'].'#' : '').rawurlencode($pref).'#'.rawurlencode($val); } if (!empty($cookieVal)) { -- cgit v1.2.3 From 646a531a33fe5c5e32a932e2a889c43702505c48 Mon Sep 17 00:00:00 2001 From: Christopher Smith <chris@jalakai.co.uk> Date: Sun, 3 Feb 2013 21:20:42 +0000 Subject: ensure getter works with keys & values containing '#' --- inc/common.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/inc/common.php b/inc/common.php index 730f4dc80..be369d28a 100644 --- a/inc/common.php +++ b/inc/common.php @@ -1546,16 +1546,16 @@ function valid_input_set($param, $valid_values, $array, $exc = '') { /** * Read a preference from the DokuWiki cookie + * (remembering both keys & values are urlencoded) */ function get_doku_pref($pref, $default) { - // first, urldecode the cookie value - $doku_prefs = urldecode($_COOKIE['DOKU_PREFS']); - if(strpos($doku_prefs, $pref) !== false) { - $parts = explode('#', $doku_prefs); + $enc_pref = urlencode($pref); + if(strpos($_COOKIE['DOKU_PREFS'], $enc_pref) !== false) { + $parts = explode('#', $_COOKIE['DOKU_PREFS']); $cnt = count($parts); for($i = 0; $i < $cnt; $i += 2) { - if($parts[$i] == $pref) { - return $parts[$i + 1]; + if($parts[$i] == $enc_pref) { + return urldecode($parts[$i + 1]); } } } -- cgit v1.2.3 From 6ecd102555022984aa926a4d423a98c775a06ca4 Mon Sep 17 00:00:00 2001 From: Andreas Gohr <andi@splitbrain.org> Date: Sun, 3 Feb 2013 23:02:34 +0100 Subject: fixed acl tests failed because of the rename of auth_basic --- _test/tests/inc/auth_aclcheck_caseinsensitive.test.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_test/tests/inc/auth_aclcheck_caseinsensitive.test.php b/_test/tests/inc/auth_aclcheck_caseinsensitive.test.php index 2f4821c2d..21b2cfdb0 100644 --- a/_test/tests/inc/auth_aclcheck_caseinsensitive.test.php +++ b/_test/tests/inc/auth_aclcheck_caseinsensitive.test.php @@ -1,6 +1,6 @@ <?php -class auth_acl_caseinsensitive_auth extends auth_basic { +class auth_acl_caseinsensitive_auth extends DokuWiki_Auth_Plugin { function isCaseSensitive() { return false; } -- cgit v1.2.3 From 138c83cad0431b3efcc1edfc6b3f0ccfa2e5c6e5 Mon Sep 17 00:00:00 2001 From: Andreas Gohr <andi@splitbrain.org> Date: Sun, 3 Feb 2013 23:42:57 +0100 Subject: fixed jquery-ui FS permissions --- lib/scripts/jquery/jquery-ui.js | 0 lib/scripts/jquery/jquery-ui.min.js | 0 2 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 lib/scripts/jquery/jquery-ui.js mode change 100755 => 100644 lib/scripts/jquery/jquery-ui.min.js diff --git a/lib/scripts/jquery/jquery-ui.js b/lib/scripts/jquery/jquery-ui.js old mode 100755 new mode 100644 diff --git a/lib/scripts/jquery/jquery-ui.min.js b/lib/scripts/jquery/jquery-ui.min.js old mode 100755 new mode 100644 -- cgit v1.2.3 From fe3fe1c75cac4bc306f10601b6e18313e9090821 Mon Sep 17 00:00:00 2001 From: Andreas Gohr <andi@splitbrain.org> Date: Tue, 5 Feb 2013 13:55:30 +0100 Subject: fixed authpg plugin info --- lib/plugins/authpgsql/plugin.info.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/plugins/authpgsql/plugin.info.txt b/lib/plugins/authpgsql/plugin.info.txt index 598eb848b..9699d3365 100644 --- a/lib/plugins/authpgsql/plugin.info.txt +++ b/lib/plugins/authpgsql/plugin.info.txt @@ -1,7 +1,7 @@ -base authad +base authpg author Andreas Gohr email andi@splitbrain.org date 2012-10-06 -name active directory auth plugin -desc Provides authentication against a Microsoft Active Directory -url http://www.dokuwiki.org/plugin:authad +name PostgreSQL auth plugin +desc Provides authentication against a PostgreSQL database +url http://www.dokuwiki.org/plugin:authpg -- cgit v1.2.3 From ed2c6a71b7c05ed9ffb9031519900a6bd9e64d0a Mon Sep 17 00:00:00 2001 From: Klap-in <klapinklapin@gmail.com> Date: Tue, 5 Feb 2013 20:15:04 +0100 Subject: use consistent name for authpgsql --- lib/plugins/authpgsql/plugin.info.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/plugins/authpgsql/plugin.info.txt b/lib/plugins/authpgsql/plugin.info.txt index 9699d3365..ad71771b4 100644 --- a/lib/plugins/authpgsql/plugin.info.txt +++ b/lib/plugins/authpgsql/plugin.info.txt @@ -1,7 +1,7 @@ -base authpg +base authpgsql author Andreas Gohr email andi@splitbrain.org date 2012-10-06 name PostgreSQL auth plugin desc Provides authentication against a PostgreSQL database -url http://www.dokuwiki.org/plugin:authpg +url http://www.dokuwiki.org/plugin:authpgsql -- cgit v1.2.3 From a701b283f573ba104a34ba98717e3855c6b20621 Mon Sep 17 00:00:00 2001 From: Andreas Gohr <andi@splitbrain.org> Date: Fri, 8 Feb 2013 13:20:59 +0100 Subject: fixed config loading for auth plugins --- lib/plugins/auth.php | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/plugins/auth.php b/lib/plugins/auth.php index 42dbf1859..c14a04dfb 100644 --- a/lib/plugins/auth.php +++ b/lib/plugins/auth.php @@ -434,6 +434,7 @@ class DokuWiki_Auth_Plugin extends DokuWiki_Plugin { if(isset($conf['auth'][$plugin])) $oldconf = (array) $conf['auth'][$plugin]; $conf['plugin'][$plugin] = array_merge($default, $oldconf, $conf['plugin'][$plugin]); + $this->conf =& $conf['plugin'][$plugin]; $this->configloaded = true; } } -- cgit v1.2.3 From 3b399a1bd4eba22429d676bddd759ed762c9e80e Mon Sep 17 00:00:00 2001 From: Andreas Gohr <andi@splitbrain.org> Date: Sat, 16 Feb 2013 11:07:36 +0100 Subject: reformatted lib/exe/fetch.php --- lib/exe/fetch.php | 295 +++++++++++++++++++++++++++--------------------------- 1 file changed, 147 insertions(+), 148 deletions(-) diff --git a/lib/exe/fetch.php b/lib/exe/fetch.php index 52e7ebe1e..f86809320 100644 --- a/lib/exe/fetch.php +++ b/lib/exe/fetch.php @@ -6,84 +6,84 @@ * @author Andreas Gohr <andi@splitbrain.org> */ - if(!defined('DOKU_INC')) define('DOKU_INC',dirname(__FILE__).'/../../'); - define('DOKU_DISABLE_GZIP_OUTPUT', 1); - require_once(DOKU_INC.'inc/init.php'); - - //close session - session_write_close(); - - $mimetypes = getMimeTypes(); - - //get input - $MEDIA = stripctl(getID('media',false)); // no cleaning except control chars - maybe external - $CACHE = calc_cache($INPUT->str('cache')); - $WIDTH = $INPUT->int('w'); - $HEIGHT = $INPUT->int('h'); - $REV = &$INPUT->ref('rev'); - //sanitize revision - $REV = preg_replace('/[^0-9]/','',$REV); - - list($EXT,$MIME,$DL) = mimetype($MEDIA,false); - if($EXT === false){ +if(!defined('DOKU_INC')) define('DOKU_INC', dirname(__FILE__).'/../../'); +define('DOKU_DISABLE_GZIP_OUTPUT', 1); +require_once(DOKU_INC.'inc/init.php'); +//close session +session_write_close(); + +$mimetypes = getMimeTypes(); + +//get input +$MEDIA = stripctl(getID('media', false)); // no cleaning except control chars - maybe external +$CACHE = calc_cache($INPUT->str('cache')); +$WIDTH = $INPUT->int('w'); +$HEIGHT = $INPUT->int('h'); +$REV = & $INPUT->ref('rev'); +//sanitize revision +$REV = preg_replace('/[^0-9]/', '', $REV); + +list($EXT, $MIME, $DL) = mimetype($MEDIA, false); +if($EXT === false) { $EXT = 'unknown'; $MIME = 'application/octet-stream'; $DL = true; - } - - // check for permissions, preconditions and cache external files - list($STATUS, $STATUSMESSAGE) = checkFileStatus($MEDIA, $FILE, $REV); - - // prepare data for plugin events - $data = array('media' => $MEDIA, - 'file' => $FILE, - 'orig' => $FILE, - 'mime' => $MIME, - 'download' => $DL, - 'cache' => $CACHE, - 'ext' => $EXT, - 'width' => $WIDTH, - 'height' => $HEIGHT, - 'status' => $STATUS, - 'statusmessage' => $STATUSMESSAGE, - ); - - // handle the file status - $evt = new Doku_Event('FETCH_MEDIA_STATUS', $data); - if ( $evt->advise_before() ) { +} + +// check for permissions, preconditions and cache external files +list($STATUS, $STATUSMESSAGE) = checkFileStatus($MEDIA, $FILE, $REV); + +// prepare data for plugin events +$data = array( + 'media' => $MEDIA, + 'file' => $FILE, + 'orig' => $FILE, + 'mime' => $MIME, + 'download' => $DL, + 'cache' => $CACHE, + 'ext' => $EXT, + 'width' => $WIDTH, + 'height' => $HEIGHT, + 'status' => $STATUS, + 'statusmessage' => $STATUSMESSAGE, +); + +// handle the file status +$evt = new Doku_Event('FETCH_MEDIA_STATUS', $data); +if($evt->advise_before()) { // redirects - if($data['status'] > 300 && $data['status'] <= 304){ - send_redirect($data['statusmessage']); + if($data['status'] > 300 && $data['status'] <= 304) { + send_redirect($data['statusmessage']); } // send any non 200 status - if($data['status'] != 200){ - header('HTTP/1.0 ' . $data['status'] . ' ' . $data['statusmessage']); + if($data['status'] != 200) { + header('HTTP/1.0 '.$data['status'].' '.$data['statusmessage']); } // die on errors - if($data['status'] > 203){ - print $data['statusmessage']; - exit; + if($data['status'] > 203) { + print $data['statusmessage']; + exit; } - } - $evt->advise_after(); - unset($evt); - - //handle image resizing/cropping - if((substr($MIME,0,5) == 'image') && $WIDTH){ - if($HEIGHT){ - $data['file'] = $FILE = media_crop_image($data['file'],$EXT,$WIDTH,$HEIGHT); - }else{ - $data['file'] = $FILE = media_resize_image($data['file'],$EXT,$WIDTH,$HEIGHT); +} +$evt->advise_after(); +unset($evt); + +//handle image resizing/cropping +if((substr($MIME, 0, 5) == 'image') && $WIDTH) { + if($HEIGHT) { + $data['file'] = $FILE = media_crop_image($data['file'], $EXT, $WIDTH, $HEIGHT); + } else { + $data['file'] = $FILE = media_resize_image($data['file'], $EXT, $WIDTH, $HEIGHT); } - } +} - // finally send the file to the client - $evt = new Doku_Event('MEDIA_SENDFILE', $data); - if ($evt->advise_before()) { - sendFile($data['file'],$data['mime'],$data['download'],$data['cache']); - } - // Do something after the download finished. - $evt->advise_after(); +// finally send the file to the client +$evt = new Doku_Event('MEDIA_SENDFILE', $data); +if($evt->advise_before()) { + sendFile($data['file'], $data['mime'], $data['download'], $data['cache']); +} +// Do something after the download finished. +$evt->advise_after(); /* ------------------------------------------------------------------------ */ @@ -93,51 +93,50 @@ * @author Andreas Gohr <andi@splitbrain.org> * @author Ben Coburn <btcoburn@silicodon.net> */ -function sendFile($file,$mime,$dl,$cache){ - global $conf; - $fmtime = @filemtime($file); - // send headers - header("Content-Type: $mime"); - // smart http caching headers - if ($cache==-1) { - // cache - // cachetime or one hour - header('Expires: '.gmdate("D, d M Y H:i:s", time()+max($conf['cachetime'], 3600)).' GMT'); - header('Cache-Control: public, proxy-revalidate, no-transform, max-age='.max($conf['cachetime'], 3600)); - header('Pragma: public'); - } else if ($cache>0) { - // recache - // remaining cachetime + 10 seconds so the newly recached media is used - header('Expires: '.gmdate("D, d M Y H:i:s", $fmtime+$conf['cachetime']+10).' GMT'); - header('Cache-Control: public, proxy-revalidate, no-transform, max-age='.max($fmtime-time()+$conf['cachetime']+10, 0)); - header('Pragma: public'); - } else if ($cache==0) { - // nocache - header('Cache-Control: must-revalidate, no-transform, post-check=0, pre-check=0'); - header('Pragma: public'); - } - //send important headers first, script stops here if '304 Not Modified' response - http_conditionalRequest($fmtime); - - - //download or display? - if($dl){ - header('Content-Disposition: attachment; filename="'.utf8_basename($file).'";'); - }else{ - header('Content-Disposition: inline; filename="'.utf8_basename($file).'";'); - } - - //use x-sendfile header to pass the delivery to compatible webservers - if (http_sendfile($file)) exit; - - // send file contents - $fp = @fopen($file,"rb"); - if($fp){ - http_rangeRequest($fp,filesize($file),$mime); - }else{ - header("HTTP/1.0 500 Internal Server Error"); - print "Could not read $file - bad permissions?"; - } +function sendFile($file, $mime, $dl, $cache) { + global $conf; + $fmtime = @filemtime($file); + // send headers + header("Content-Type: $mime"); + // smart http caching headers + if($cache == -1) { + // cache + // cachetime or one hour + header('Expires: '.gmdate("D, d M Y H:i:s", time() + max($conf['cachetime'], 3600)).' GMT'); + header('Cache-Control: public, proxy-revalidate, no-transform, max-age='.max($conf['cachetime'], 3600)); + header('Pragma: public'); + } else if($cache > 0) { + // recache + // remaining cachetime + 10 seconds so the newly recached media is used + header('Expires: '.gmdate("D, d M Y H:i:s", $fmtime + $conf['cachetime'] + 10).' GMT'); + header('Cache-Control: public, proxy-revalidate, no-transform, max-age='.max($fmtime - time() + $conf['cachetime'] + 10, 0)); + header('Pragma: public'); + } else if($cache == 0) { + // nocache + header('Cache-Control: must-revalidate, no-transform, post-check=0, pre-check=0'); + header('Pragma: public'); + } + //send important headers first, script stops here if '304 Not Modified' response + http_conditionalRequest($fmtime); + + //download or display? + if($dl) { + header('Content-Disposition: attachment; filename="'.utf8_basename($file).'";'); + } else { + header('Content-Disposition: inline; filename="'.utf8_basename($file).'";'); + } + + //use x-sendfile header to pass the delivery to compatible webservers + if(http_sendfile($file)) exit; + + // send file contents + $fp = @fopen($file, "rb"); + if($fp) { + http_rangeRequest($fp, filesize($file), $mime); + } else { + header("HTTP/1.0 500 Internal Server Error"); + print "Could not read $file - bad permissions?"; + } } /** @@ -148,43 +147,43 @@ function sendFile($file,$mime,$dl,$cache){ * * @author Gerry Weissbach <gerry.w@gammaproduction.de> * @param $media reference to the media id - * @param $file reference to the file variable + * @param $file reference to the file variable * @returns array(STATUS, STATUSMESSAGE) */ -function checkFileStatus(&$media, &$file, $rev='') { - global $MIME, $EXT, $CACHE, $INPUT; - - //media to local file - if(preg_match('#^(https?)://#i',$media)){ - //check hash - if(substr(md5(auth_cookiesalt().$media),0,6) !== $INPUT->str('hash')){ - return array( 412, 'Precondition Failed'); - } - //handle external images - if(strncmp($MIME,'image/',6) == 0) $file = media_get_from_URL($media,$EXT,$CACHE); - if(!$file){ - //download failed - redirect to original URL - return array( 302, $media ); - } - }else{ - $media = cleanID($media); - if(empty($media)){ - return array( 400, 'Bad request' ); +function checkFileStatus(&$media, &$file, $rev = '') { + global $MIME, $EXT, $CACHE, $INPUT; + + //media to local file + if(preg_match('#^(https?)://#i', $media)) { + //check hash + if(substr(md5(auth_cookiesalt().$media), 0, 6) !== $INPUT->str('hash')) { + return array(412, 'Precondition Failed'); + } + //handle external images + if(strncmp($MIME, 'image/', 6) == 0) $file = media_get_from_URL($media, $EXT, $CACHE); + if(!$file) { + //download failed - redirect to original URL + return array(302, $media); + } + } else { + $media = cleanID($media); + if(empty($media)) { + return array(400, 'Bad request'); + } + + //check permissions (namespace only) + if(auth_quickaclcheck(getNS($media).':X') < AUTH_READ) { + return array(403, 'Forbidden'); + } + $file = mediaFN($media, $rev); } - //check permissions (namespace only) - if(auth_quickaclcheck(getNS($media).':X') < AUTH_READ){ - return array( 403, 'Forbidden' ); + //check file existance + if(!@file_exists($file)) { + return array(404, 'Not Found'); } - $file = mediaFN($media, $rev); - } - - //check file existance - if(!@file_exists($file)){ - return array( 404, 'Not Found' ); - } - return array(200, null); + return array(200, null); } /** @@ -194,12 +193,12 @@ function checkFileStatus(&$media, &$file, $rev='') { * * @author Andreas Gohr <andi@splitbrain.org> */ -function calc_cache($cache){ - global $conf; +function calc_cache($cache) { + global $conf; - if(strtolower($cache) == 'nocache') return 0; //never cache - if(strtolower($cache) == 'recache') return $conf['cachetime']; //use standard cache - return -1; //cache endless + if(strtolower($cache) == 'nocache') return 0; //never cache + if(strtolower($cache) == 'recache') return $conf['cachetime']; //use standard cache + return -1; //cache endless } //Setup VIM: ex: et ts=2 : -- cgit v1.2.3 From 36625b969932ea8641dc1fd0461d4302c600a2a1 Mon Sep 17 00:00:00 2001 From: Andreas Gohr <andi@splitbrain.org> Date: Sat, 16 Feb 2013 11:10:40 +0100 Subject: run main code only for non-tests in lib/exe/fetch.php --- lib/exe/fetch.php | 141 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 72 insertions(+), 69 deletions(-) diff --git a/lib/exe/fetch.php b/lib/exe/fetch.php index f86809320..73e74af40 100644 --- a/lib/exe/fetch.php +++ b/lib/exe/fetch.php @@ -9,81 +9,84 @@ if(!defined('DOKU_INC')) define('DOKU_INC', dirname(__FILE__).'/../../'); define('DOKU_DISABLE_GZIP_OUTPUT', 1); require_once(DOKU_INC.'inc/init.php'); -//close session -session_write_close(); - -$mimetypes = getMimeTypes(); - -//get input -$MEDIA = stripctl(getID('media', false)); // no cleaning except control chars - maybe external -$CACHE = calc_cache($INPUT->str('cache')); -$WIDTH = $INPUT->int('w'); -$HEIGHT = $INPUT->int('h'); -$REV = & $INPUT->ref('rev'); -//sanitize revision -$REV = preg_replace('/[^0-9]/', '', $REV); - -list($EXT, $MIME, $DL) = mimetype($MEDIA, false); -if($EXT === false) { - $EXT = 'unknown'; - $MIME = 'application/octet-stream'; - $DL = true; -} - -// check for permissions, preconditions and cache external files -list($STATUS, $STATUSMESSAGE) = checkFileStatus($MEDIA, $FILE, $REV); - -// prepare data for plugin events -$data = array( - 'media' => $MEDIA, - 'file' => $FILE, - 'orig' => $FILE, - 'mime' => $MIME, - 'download' => $DL, - 'cache' => $CACHE, - 'ext' => $EXT, - 'width' => $WIDTH, - 'height' => $HEIGHT, - 'status' => $STATUS, - 'statusmessage' => $STATUSMESSAGE, -); - -// handle the file status -$evt = new Doku_Event('FETCH_MEDIA_STATUS', $data); -if($evt->advise_before()) { - // redirects - if($data['status'] > 300 && $data['status'] <= 304) { - send_redirect($data['statusmessage']); +session_write_close(); //close session + +// BEGIN main (if not testing) +if(!defined('SIMPLE_TEST')) { + $mimetypes = getMimeTypes(); + + //get input + $MEDIA = stripctl(getID('media', false)); // no cleaning except control chars - maybe external + $CACHE = calc_cache($INPUT->str('cache')); + $WIDTH = $INPUT->int('w'); + $HEIGHT = $INPUT->int('h'); + $REV = & $INPUT->ref('rev'); + //sanitize revision + $REV = preg_replace('/[^0-9]/', '', $REV); + + list($EXT, $MIME, $DL) = mimetype($MEDIA, false); + if($EXT === false) { + $EXT = 'unknown'; + $MIME = 'application/octet-stream'; + $DL = true; } - // send any non 200 status - if($data['status'] != 200) { - header('HTTP/1.0 '.$data['status'].' '.$data['statusmessage']); + + // check for permissions, preconditions and cache external files + list($STATUS, $STATUSMESSAGE) = checkFileStatus($MEDIA, $FILE, $REV); + + // prepare data for plugin events + $data = array( + 'media' => $MEDIA, + 'file' => $FILE, + 'orig' => $FILE, + 'mime' => $MIME, + 'download' => $DL, + 'cache' => $CACHE, + 'ext' => $EXT, + 'width' => $WIDTH, + 'height' => $HEIGHT, + 'status' => $STATUS, + 'statusmessage' => $STATUSMESSAGE, + ); + + // handle the file status + $evt = new Doku_Event('FETCH_MEDIA_STATUS', $data); + if($evt->advise_before()) { + // redirects + if($data['status'] > 300 && $data['status'] <= 304) { + send_redirect($data['statusmessage']); + } + // send any non 200 status + if($data['status'] != 200) { + header('HTTP/1.0 '.$data['status'].' '.$data['statusmessage']); + } + // die on errors + if($data['status'] > 203) { + print $data['statusmessage']; + exit; + } } - // die on errors - if($data['status'] > 203) { - print $data['statusmessage']; - exit; + $evt->advise_after(); + unset($evt); + + //handle image resizing/cropping + if((substr($MIME, 0, 5) == 'image') && $WIDTH) { + if($HEIGHT) { + $data['file'] = $FILE = media_crop_image($data['file'], $EXT, $WIDTH, $HEIGHT); + } else { + $data['file'] = $FILE = media_resize_image($data['file'], $EXT, $WIDTH, $HEIGHT); + } } -} -$evt->advise_after(); -unset($evt); -//handle image resizing/cropping -if((substr($MIME, 0, 5) == 'image') && $WIDTH) { - if($HEIGHT) { - $data['file'] = $FILE = media_crop_image($data['file'], $EXT, $WIDTH, $HEIGHT); - } else { - $data['file'] = $FILE = media_resize_image($data['file'], $EXT, $WIDTH, $HEIGHT); + // finally send the file to the client + $evt = new Doku_Event('MEDIA_SENDFILE', $data); + if($evt->advise_before()) { + sendFile($data['file'], $data['mime'], $data['download'], $data['cache']); } -} + // Do something after the download finished. + $evt->advise_after(); -// finally send the file to the client -$evt = new Doku_Event('MEDIA_SENDFILE', $data); -if($evt->advise_before()) { - sendFile($data['file'], $data['mime'], $data['download'], $data['cache']); -} -// Do something after the download finished. -$evt->advise_after(); +}// END DO main /* ------------------------------------------------------------------------ */ -- cgit v1.2.3 From 78361632ede7770a5ee42b88bed0a9506b1fcb66 Mon Sep 17 00:00:00 2001 From: Andreas Gohr <andi@splitbrain.org> Date: Sat, 16 Feb 2013 11:52:05 +0100 Subject: better HTTPClient debug output on CLI --- inc/HTTPClient.php | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/inc/HTTPClient.php b/inc/HTTPClient.php index 51c1de875..8cfb86567 100644 --- a/inc/HTTPClient.php +++ b/inc/HTTPClient.php @@ -669,10 +669,26 @@ class HTTPClient { /** * print debug info * + * Uses _debug_text or _debug_html depending on the SAPI name + * * @author Andreas Gohr <andi@splitbrain.org> */ function _debug($info,$var=null){ if(!$this->debug) return; + if(php_sapi_name() == 'cli'){ + $this->_debug_text($info, $var); + }else{ + $this->_debug_html($info, $var); + } + } + + /** + * print debug info as HTML + * + * @param $info + * @param null $var + */ + function _debug_html($info, $var=null){ print '<b>'.$info.'</b> '.($this->_time() - $this->start).'s<br />'; if(!is_null($var)){ ob_start(); @@ -683,6 +699,18 @@ class HTTPClient { } } + /** + * prints debug info as plain text + * + * @param $info + * @param null $var + */ + function _debug_text($info, $var=null){ + print '*'.$info.'* '.($this->_time() - $this->start)."s\n"; + if(!is_null($var)) print_r($var); + print "\n-----------------------------------------------\n"; + } + /** * Return current timestamp in microsecond resolution */ -- cgit v1.2.3 From 47a8b9192611e3aa3c93f481f9c321a16707df77 Mon Sep 17 00:00:00 2001 From: Andreas Gohr <andi@splitbrain.org> Date: Sat, 16 Feb 2013 13:06:13 +0100 Subject: added another HTTPClient test --- _test/tests/inc/httpclient_http.test.php | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/_test/tests/inc/httpclient_http.test.php b/_test/tests/inc/httpclient_http.test.php index 9959a1f06..252eb6b65 100644 --- a/_test/tests/inc/httpclient_http.test.php +++ b/_test/tests/inc/httpclient_http.test.php @@ -131,6 +131,19 @@ class httpclient_http_test extends DokuWikiTest { $this->assertLessThanOrEqual(251,strlen($data)); } + /** + * @group internet + */ + function test_maxbodyok(){ + $http = new HTTPClient(); + $http->max_bodysize = 500*1024; + $data = $http->get($this->server.'/stream/5'); + $this->assertTrue($data !== false, 'HTTP response'); + $http->max_bodysize_abort = false; + $data = $http->get($this->server.'/stream/5'); + $this->assertTrue($data !== false, 'HTTP response'); + } + /** * @group internet */ -- cgit v1.2.3 From 0fa584c26e2ba6aec1045f55551b2b1865a9fd96 Mon Sep 17 00:00:00 2001 From: Andreas Gohr <andi@splitbrain.org> Date: Sat, 16 Feb 2013 13:07:27 +0100 Subject: HTTPClient: fixed max_bodysize when using keep-alive --- inc/HTTPClient.php | 41 ++++++++++++++++++++++++++++------------- 1 file changed, 28 insertions(+), 13 deletions(-) diff --git a/inc/HTTPClient.php b/inc/HTTPClient.php index 8cfb86567..e36514286 100644 --- a/inc/HTTPClient.php +++ b/inc/HTTPClient.php @@ -215,6 +215,9 @@ class HTTPClient { $this->start = $this->_time(); $this->error = ''; $this->status = 0; + $this->status = 0; + $this->resp_body = ''; + $this->resp_headers = array(); // don't accept gzip if truncated bodies might occur if($this->max_bodysize && @@ -440,9 +443,31 @@ class HTTPClient { $byte = $this->_readData($socket, 2, 'chunk'); // read trailing \r\n } } while ($chunk_size && !$abort); - }elseif($this->max_bodysize){ - // read just over the max_bodysize - $r_body = $this->_readData($socket, $this->max_bodysize+1, 'response', true); + }elseif(isset($this->resp_headers['content-length']) && !isset($this->resp_headers['transfer-encoding'])){ + /* RFC 2616 + * If a message is received with both a Transfer-Encoding header field and a Content-Length + * header field, the latter MUST be ignored. + */ + + // read up to the content-length or max_bodysize + // for keep alive we need to read the whole message to clean up the socket for the next read + if(!$this->keep_alive && $this->max_bodysize && $this->max_bodysize < $this->resp_headers['content-length']){ + $length = $this->max_bodysize; + }else{ + $length = $this->resp_headers['content-length']; + } + + $r_body = $this->_readData($socket, $length, 'response (content-length limited)', true); + }else{ + // read entire socket + $r_size = 0; + while (!feof($socket)) { + $r_body .= $this->_readData($socket, 4096, 'response (unlimited)', true); + } + } + + // recheck body size, we might had to read the whole body, so we abort late or trim here + if($this->max_bodysize){ if(strlen($r_body) > $this->max_bodysize){ if ($this->max_bodysize_abort) { throw new HTTPClientException('Allowed response size exceeded'); @@ -450,16 +475,6 @@ class HTTPClient { $this->error = 'Allowed response size exceeded'; } } - }elseif(isset($this->resp_headers['content-length']) && - !isset($this->resp_headers['transfer-encoding'])){ - // read up to the content-length - $r_body = $this->_readData($socket, $this->resp_headers['content-length'], 'response', true); - }else{ - // read entire socket - $r_size = 0; - while (!feof($socket)) { - $r_body .= $this->_readData($socket, 4096, 'response', true); - } } } catch (HTTPClientException $err) { -- cgit v1.2.3 From 7b9186a5c6e5a5f070396dd6455e8b06b9da16c8 Mon Sep 17 00:00:00 2001 From: Andreas Gohr <andi@splitbrain.org> Date: Sat, 16 Feb 2013 13:14:38 +0100 Subject: HTTPClient: updated function comments --- inc/HTTPClient.php | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/inc/HTTPClient.php b/inc/HTTPClient.php index e36514286..6f00d6d91 100644 --- a/inc/HTTPClient.php +++ b/inc/HTTPClient.php @@ -150,6 +150,7 @@ class HTTPClient { * * @param string $url The URL to fetch * @param bool $sloppy304 Return body on 304 not modified + * @return bool|string response body, false on error * @author Andreas Gohr <andi@splitbrain.org> */ function get($url,$sloppy304=false){ @@ -170,6 +171,7 @@ class HTTPClient { * @param string $url The URL to fetch * @param array $data Associative array of parameters * @param bool $sloppy304 Return body on 304 not modified + * @return bool|string response body, false on error * @author Andreas Gohr <andi@splitbrain.org> */ function dget($url,$data,$sloppy304=false){ @@ -187,6 +189,9 @@ class HTTPClient { * * Returns the resulting page or false on an error; * + * @param string $url The URL to fetch + * @param array $data Associative array of parameters + * @return bool|string response body, false on error * @author Andreas Gohr <andi@splitbrain.org> */ function post($url,$data){ @@ -517,8 +522,8 @@ class HTTPClient { * * Protocol, Servername and Port will be stripped from the request URL when a successful CONNECT happened * - * @param ressource &$socket - * @param string &$requesturl + * @param resource &$socket + * @param string &$requesturl * @return bool true if a tunnel was established */ function _ssltunnel(&$socket, &$requesturl){ @@ -558,9 +563,10 @@ class HTTPClient { /** * Safely write data to a socket * - * @param handle $socket An open socket handle - * @param string $data The data to write - * @param string $message Description of what is being read + * @param resource $socket An open socket handle + * @param string $data The data to write + * @param string $message Description of what is being read + * @throws HTTPClientException * @author Tom N Harris <tnharris@whoopdedo.org> */ function _sendData($socket, $data, $message) { @@ -600,10 +606,12 @@ class HTTPClient { * Reads up to a given number of bytes or throws an exception if the * response times out or ends prematurely. * - * @param handle $socket An open socket handle in non-blocking mode - * @param int $nbytes Number of bytes to read - * @param string $message Description of what is being read - * @param bool $ignore_eof End-of-file is not an error if this is set + * @param resource $socket An open socket handle in non-blocking mode + * @param int $nbytes Number of bytes to read + * @param string $message Description of what is being read + * @param bool $ignore_eof End-of-file is not an error if this is set + * @throws HTTPClientException + * @return string * @author Tom N Harris <tnharris@whoopdedo.org> */ function _readData($socket, $nbytes, $message, $ignore_eof = false) { @@ -650,8 +658,10 @@ class HTTPClient { * * Always returns a complete line, including the terminating \n. * - * @param handle $socket An open socket handle in non-blocking mode - * @param string $message Description of what is being read + * @param resource $socket An open socket handle in non-blocking mode + * @param string $message Description of what is being read + * @throws HTTPClientException + * @return string * @author Tom N Harris <tnharris@whoopdedo.org> */ function _readLine($socket, $message) { @@ -840,6 +850,8 @@ class HTTPClient { /** * Generates a unique identifier for a connection. * + * @param string $server + * @param string $port * @return string unique identifier */ function _uniqueConnectionId($server, $port) { -- cgit v1.2.3 From 8b48b31f60c1acd63fbe9f35207377209faac012 Mon Sep 17 00:00:00 2001 From: Andreas Gohr <andi@splitbrain.org> Date: Sat, 16 Feb 2013 13:17:40 +0100 Subject: HTTPclient: print number of received bytes on error --- inc/HTTPClient.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/inc/HTTPClient.php b/inc/HTTPClient.php index 6f00d6d91..772b580b2 100644 --- a/inc/HTTPClient.php +++ b/inc/HTTPClient.php @@ -628,8 +628,8 @@ class HTTPClient { $time_used = $this->_time() - $this->start; if ($time_used > $this->timeout) throw new HTTPClientException( - sprintf('Timeout while reading %s (%.3fs)', $message, $time_used), - -100); + sprintf('Timeout while reading %s after %d bytes (%.3fs)', $message, + strlen($r_data), $time_used), -100); if(feof($socket)) { if(!$ignore_eof) throw new HTTPClientException("Premature End of File (socket) while reading $message"); -- cgit v1.2.3 From 4def61cfe42f331ab696463fa2fa4cfc452df23b Mon Sep 17 00:00:00 2001 From: Andreas Gohr <andi@splitbrain.org> Date: Sat, 16 Feb 2013 13:27:57 +0100 Subject: test for media downloading (related to FS#2675 --- _test/tests/inc/media_get_from_url.test.php | 80 +++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 _test/tests/inc/media_get_from_url.test.php diff --git a/_test/tests/inc/media_get_from_url.test.php b/_test/tests/inc/media_get_from_url.test.php new file mode 100644 index 000000000..3903b8a05 --- /dev/null +++ b/_test/tests/inc/media_get_from_url.test.php @@ -0,0 +1,80 @@ +<?php + +class media_get_from_url_test extends DokuWikiTest { + + /** + * @group internet + */ + public function test_cache(){ + global $conf; + $conf['fetchsize'] = 500*1024; //500kb + + + $local = media_get_from_URL('http://www.google.com/images/srpr/logo3w.png','png',-1); + $this->assertTrue($local !== false); + $this->assertFileExists($local); + + // remember time stamp + $time = filemtime($local); + clearstatcache(false, $local); + sleep(1); + + // fetch again and make sure we got a cache file + $local = media_get_from_URL('http://www.google.com/images/srpr/logo3w.png','png',-1); + clearstatcache(false, $local); + $this->assertTrue($local !== false); + $this->assertFileExists($local); + $this->assertEquals($time, filemtime($local)); + + unlink($local); + } + + /** + * @group internet + */ + public function test_nocache(){ + global $conf; + $conf['fetchsize'] = 500*1024; //500kb + + $local = media_get_from_URL('http://www.google.com/images/srpr/logo3w.png','png',0); + $this->assertFalse($local); + } + + /** + * @group internet + * @group slow + */ + public function test_recache(){ + global $conf; + $conf['fetchsize'] = 500*1024; //500kb + + + $local = media_get_from_URL('http://www.google.com/images/srpr/logo3w.png','png',5); + $this->assertTrue($local !== false); + $this->assertFileExists($local); + + // remember time stamp + $time = filemtime($local); + clearstatcache(false, $local); + sleep(1); + + // fetch again and make sure we got a cache file + $local = media_get_from_URL('http://www.google.com/images/srpr/logo3w.png','png',5); + clearstatcache(false, $local); + $this->assertTrue($local !== false); + $this->assertFileExists($local); + $this->assertEquals($time, filemtime($local)); + + clearstatcache(false, $local); + sleep(6); + + // fetch again and make sure we got a new file + $local = media_get_from_URL('http://www.google.com/images/srpr/logo3w.png','png',5); + clearstatcache(false, $local); + $this->assertTrue($local !== false); + $this->assertFileExists($local); + $this->assertNotEquals($time, filemtime($local)); + + unlink($local); + } +} \ No newline at end of file -- cgit v1.2.3 From a59514197ff8cbfaeb42520106e7cbd0988f3fb5 Mon Sep 17 00:00:00 2001 From: Andreas Gohr <andi@splitbrain.org> Date: Sat, 16 Feb 2013 13:30:39 +0100 Subject: don't use keep-alive with single shot HTTP clients --- inc/io.php | 1 + inc/media.php | 2 ++ 2 files changed, 3 insertions(+) diff --git a/inc/io.php b/inc/io.php index b4da7d635..5ecc79703 100644 --- a/inc/io.php +++ b/inc/io.php @@ -474,6 +474,7 @@ function io_download($url,$file,$useAttachment=false,$defaultName='',$maxSize=20 $http = new DokuHTTPClient(); $http->max_bodysize = $maxSize; $http->timeout = 25; //max. 25 sec + $http->keep_alive = false; // we do single ops here, no need for keep-alive $data = $http->get($url); if(!$data) return false; diff --git a/inc/media.php b/inc/media.php index 572b1177c..7e1b2152d 100644 --- a/inc/media.php +++ b/inc/media.php @@ -1878,6 +1878,8 @@ function media_get_from_URL($url,$ext,$cache){ function media_image_download($url,$file){ global $conf; $http = new DokuHTTPClient(); + $http->keep_alive = false; // we do single ops here, no need for keep-alive + $http->max_bodysize = $conf['fetchsize']; $http->timeout = 25; //max. 25 sec $http->header_regexp = '!\r\nContent-Type: image/(jpe?g|gif|png)!i'; -- cgit v1.2.3 From 62147bf8b4df365c8f4e0cf74f115edd2d154406 Mon Sep 17 00:00:00 2001 From: Andreas Gohr <andi@splitbrain.org> Date: Sat, 16 Feb 2013 14:02:11 +0100 Subject: don't expose version in info plugin FS#2701 --- lib/plugins/info/plugin.info.txt | 2 +- lib/plugins/info/syntax.php | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/lib/plugins/info/plugin.info.txt b/lib/plugins/info/plugin.info.txt index 5c7d583c0..053743639 100644 --- a/lib/plugins/info/plugin.info.txt +++ b/lib/plugins/info/plugin.info.txt @@ -1,7 +1,7 @@ base info author Andreas Gohr email andi@splitbrain.org -date 2012-02-04 +date 2013-02-16 name Info Plugin desc Displays information about various DokuWiki internals url http://dokuwiki.org/plugin:info diff --git a/lib/plugins/info/syntax.php b/lib/plugins/info/syntax.php index d813aa23a..97b28076b 100644 --- a/lib/plugins/info/syntax.php +++ b/lib/plugins/info/syntax.php @@ -60,9 +60,6 @@ class syntax_plugin_info extends DokuWiki_Syntax_Plugin { if($format == 'xhtml'){ //handle various info stuff switch ($data[0]){ - case 'version': - $renderer->doc .= getVersion(); - break; case 'syntaxmodes': $renderer->doc .= $this->_syntaxmodes_xhtml(); break; -- cgit v1.2.3 From 6a1f928ffcdf160d8bcb569e3f0340816b843874 Mon Sep 17 00:00:00 2001 From: Andreas Gohr <andi@splitbrain.org> Date: Sat, 16 Feb 2013 14:09:43 +0100 Subject: do not expose version in outgoing mails FS#2701 --- inc/Mailer.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inc/Mailer.class.php b/inc/Mailer.class.php index f1492be9b..f87d7dd84 100644 --- a/inc/Mailer.class.php +++ b/inc/Mailer.class.php @@ -51,7 +51,7 @@ class Mailer { $this->allowhtml = (bool)$conf['htmlmail']; // add some default headers for mailfiltering FS#2247 - $this->setHeader('X-Mailer', 'DokuWiki '.getVersion()); + $this->setHeader('X-Mailer', 'DokuWiki'); $this->setHeader('X-DokuWiki-User', $_SERVER['REMOTE_USER']); $this->setHeader('X-DokuWiki-Title', $conf['title']); $this->setHeader('X-DokuWiki-Server', $server); -- cgit v1.2.3 From a9b6a8b59a0be9ff45f5675c3b032ad8d2afd6eb Mon Sep 17 00:00:00 2001 From: Andreas Gohr <andi@splitbrain.org> Date: Sat, 16 Feb 2013 14:37:12 +0100 Subject: allow richer email addresses in notify and registernotify FS#2689 This deprecates the "richemail" config class --- lib/plugins/config/settings/config.class.php | 85 +++++++++++-------------- lib/plugins/config/settings/config.metadata.php | 8 +-- 2 files changed, 41 insertions(+), 52 deletions(-) diff --git a/lib/plugins/config/settings/config.class.php b/lib/plugins/config/settings/config.class.php index 16be9a689..5b81be782 100644 --- a/lib/plugins/config/settings/config.class.php +++ b/lib/plugins/config/settings/config.class.php @@ -79,7 +79,7 @@ if (!class_exists('configuration')) { array_shift($param); } else { $class = 'setting_undefined'; - $param = NULL; + $param = null; } if (!in_array($class, $no_default_check) && !isset($default[$key])) { @@ -353,13 +353,13 @@ if (!class_exists('setting')) { class setting { var $_key = ''; - var $_default = NULL; - var $_local = NULL; - var $_protected = NULL; + var $_default = null; + var $_local = null; + var $_protected = null; var $_pattern = ''; var $_error = false; // only used by those classes which error check - var $_input = NULL; // only used by those classes which error check + var $_input = null; // only used by those classes which error check var $_cautionList = array( 'basedir' => 'danger', 'baseurl' => 'danger', 'savedir' => 'danger', 'cookiedir' => 'danger', 'useacl' => 'danger', 'authtype' => 'danger', 'superuser' => 'danger', 'userewrite' => 'danger', @@ -367,7 +367,7 @@ if (!class_exists('setting')) { 'allowdebug' => 'security', 'htmlok' => 'security', 'phpok' => 'security', 'iexssprotect' => 'security', 'xmlrpc' => 'security', 'fullpath' => 'security' ); - function setting($key, $params=NULL) { + function setting($key, $params=null) { $this->_key = $key; if (is_array($params)) { @@ -656,6 +656,7 @@ if (!class_exists('setting_email')) { class setting_email extends setting_string { var $_pattern = SETTING_EMAIL_PATTERN; // no longer required, retained for backward compatibility - FIXME, may not be necessary var $_multiple = false; + var $_placeholders = false; /** * update setting with user provided value $input @@ -669,15 +670,36 @@ if (!class_exists('setting_email')) { $value = is_null($this->_local) ? $this->_default : $this->_local; if ($value == $input) return false; + if($input === ''){ + $this->_local = $input; + return true; + } + $mail = $input; + + if($this->_placeholders){ + // replace variables with pseudo values + $mail = str_replace('@USER@','joe',$mail); + $mail = str_replace('@NAME@','Joe Schmoe',$mail); + $mail = str_replace('@MAIL@','joe@example.com',$mail); + } + // multiple mail addresses? if ($this->_multiple) { - $mails = array_filter(array_map('trim', explode(',', $input))); + $mails = array_filter(array_map('trim', explode(',', $mail))); } else { - $mails = array($input); + $mails = array($mail); } + // check them all foreach ($mails as $mail) { - if (!mail_isvalid($mail)) { + // only check the address part + if(preg_match('#(.*?)<(.*?)>#', $mail, $matches)){ + $addr = $matches[2]; + }else{ + $addr = $mail; + } + + if (!mail_isvalid($addr)) { $this->_error = true; $this->_input = $input; return false; @@ -690,46 +712,15 @@ if (!class_exists('setting_email')) { } } +/** + * @deprecated 2013-02-16 + */ if (!class_exists('setting_richemail')) { class setting_richemail extends setting_email { - - /** - * update setting with user provided value $input - * if value fails error check, save it - * - * @return boolean true if changed, false otherwise (incl. on error) - */ - function update($input) { - if (is_null($input)) return false; - if ($this->is_protected()) return false; - - $value = is_null($this->_local) ? $this->_default : $this->_local; - if ($value == $input) return false; - - // replace variables with pseudo values - $test = $input; - $test = str_replace('@USER@','joe',$test); - $test = str_replace('@NAME@','Joe Schmoe',$test); - $test = str_replace('@MAIL@','joe@example.com',$test); - - // now only check the address part - if(preg_match('#(.*?)<(.*?)>#',$test,$matches)){ - $text = trim($matches[1]); - $addr = $matches[2]; - }else{ - $addr = $test; - } - - if ($test !== '' && !mail_isvalid($addr)) { - $this->_error = true; - $this->_input = $input; - return false; - } - - $this->_local = $input; - return true; - } - + function update($input) { + $this->_placeholders = true; + return parent::update($input); + } } } diff --git a/lib/plugins/config/settings/config.metadata.php b/lib/plugins/config/settings/config.metadata.php index 585015085..663eab9dd 100644 --- a/lib/plugins/config/settings/config.metadata.php +++ b/lib/plugins/config/settings/config.metadata.php @@ -20,9 +20,7 @@ * 'numericopt' - like above, but accepts empty values * 'onoff' - checkbox input, setting output 0|1 * 'multichoice' - select input (single choice), setting output with quotes, required _choices parameter - * 'email' - text input, input must conform to email address format, setting output in quotes - * 'richemail' - text input, input must conform to email address format but accepts variables and - * emails with a real name prepended (when email address is given in <>) + * 'email' - text input, input must conform to email address format * 'password' - password input, minimal input validation, setting output text in quotes, maybe encoded * according to the _code parameter * 'dirchoice' - as multichoice, selection choices based on folders found at location specified in _dir @@ -177,8 +175,8 @@ $meta['_notifications'] = array('fieldset'); $meta['subscribers'] = array('onoff'); $meta['subscribe_time'] = array('numeric'); $meta['notify'] = array('email', '_multiple' => true); -$meta['registernotify'] = array('email'); -$meta['mailfrom'] = array('richemail'); +$meta['registernotify'] = array('email', '_multiple' => true); +$meta['mailfrom'] = array('email', '_placeholders' => true); $meta['mailprefix'] = array('string'); $meta['htmlmail'] = array('onoff'); -- cgit v1.2.3 From fed6fccbc7ab83ed9c5a79f484d8a6664cb95bc3 Mon Sep 17 00:00:00 2001 From: Anika Henke <anika@selfthinker.org> Date: Sat, 16 Feb 2013 13:33:01 +0000 Subject: fixed media upload not working with QuickPHP (FS#2531 + FS#2673) --- inc/media.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/inc/media.php b/inc/media.php index 7e1b2152d..bd80db577 100644 --- a/inc/media.php +++ b/inc/media.php @@ -237,8 +237,7 @@ function media_upload_xhr($ns,$auth){ $realSize = stream_copy_to_stream($input, $target); fclose($target); fclose($input); - if ($realSize != (int)$_SERVER["CONTENT_LENGTH"]){ - unlink($target); + if (isset($_SERVER["CONTENT_LENGTH"]) && ($realSize != (int)$_SERVER["CONTENT_LENGTH"])){ unlink($path); return false; } -- cgit v1.2.3 From 6d6be32bd1dd668f07fc525a2e679fed98679ccf Mon Sep 17 00:00:00 2001 From: Andreas Gohr <andi@splitbrain.org> Date: Sat, 16 Feb 2013 15:44:29 +0100 Subject: initialize link wizard with current namespace FS#2683 --- lib/scripts/linkwiz.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/scripts/linkwiz.js b/lib/scripts/linkwiz.js index bb04828b4..c55650d68 100644 --- a/lib/scripts/linkwiz.js +++ b/lib/scripts/linkwiz.js @@ -50,6 +50,9 @@ var dw_linkwiz = { jQuery(dw_linkwiz.result).css('position', 'relative'); dw_linkwiz.$entry = jQuery('#link__wiz_entry'); + if(JSINFO.namespace){ + dw_linkwiz.$entry.val(JSINFO.namespace+':'); + } // attach event handlers jQuery('#link__wiz .ui-dialog-titlebar-close').click(dw_linkwiz.hide); @@ -102,7 +105,7 @@ var dw_linkwiz = { /** * Get one of the results by index * - * @param int result div to return + * @param num int result div to return * @returns DOMObject or null */ getResult: function(num){ @@ -113,7 +116,7 @@ var dw_linkwiz = { /** * Get one of the results by index * - * @param int result div to return + * @param num int result div to return * @returns jQuery object */ $getResult: function(num) { -- cgit v1.2.3 From 8a65ef2ef3046b80d45c36abc561cef3ae6ec1b7 Mon Sep 17 00:00:00 2001 From: Anika Henke <anika@selfthinker.org> Date: Sat, 16 Feb 2013 13:49:47 +0000 Subject: fixed edit toolbar being cut off (FS#2715) --- inc/html.php | 2 +- lib/tpl/dokuwiki/css/_edit.css | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/inc/html.php b/inc/html.php index a48f18bff..ddaed2261 100644 --- a/inc/html.php +++ b/inc/html.php @@ -1473,7 +1473,7 @@ function html_edit(){ } ?> <div class="editBox"> - <div class="toolbar"> + <div class="toolbar group"> <div id="draft__status"><?php if(!empty($INFO['draft'])) echo $lang['draftdate'].' '.dformat();?></div> <div id="tool__bar"><?php if ($wr && $data['media_manager']){?><a href="<?php echo DOKU_BASE?>lib/exe/mediamanager.php?ns=<?php echo $INFO['namespace']?>" target="_blank"><?php echo $lang['mediaselect'] ?></a><?php }?></div> diff --git a/lib/tpl/dokuwiki/css/_edit.css b/lib/tpl/dokuwiki/css/_edit.css index 0c66c75b7..92ce62126 100644 --- a/lib/tpl/dokuwiki/css/_edit.css +++ b/lib/tpl/dokuwiki/css/_edit.css @@ -13,7 +13,6 @@ .dokuwiki div.toolbar { margin-bottom: .5em; - overflow: hidden; } #draft__status { float: right; -- cgit v1.2.3 From 73afc609162729f45fdfcc2b04b9a467ccdec71f Mon Sep 17 00:00:00 2001 From: Anika Henke <anika@selfthinker.org> Date: Sat, 16 Feb 2013 14:06:27 +0000 Subject: removed useless css from config manager (causing issues in Opera, FS#2678) --- lib/plugins/config/style.css | 9 --------- 1 file changed, 9 deletions(-) diff --git a/lib/plugins/config/style.css b/lib/plugins/config/style.css index 397328937..054021ed8 100644 --- a/lib/plugins/config/style.css +++ b/lib/plugins/config/style.css @@ -154,15 +154,6 @@ } -/* IE6 correction */ -* html #config__manager .selection label { - padding-top: 2px; -} - -#config__manager .selection input.checkbox { - padding-left: 0.7em; -} - #config__manager .other { clear: both; padding-top: 0.5em; -- cgit v1.2.3 From 21606750a4ae0a46937a589ca323c250f26a2e58 Mon Sep 17 00:00:00 2001 From: Anika Henke <anika@selfthinker.org> Date: Sat, 16 Feb 2013 14:24:44 +0000 Subject: added explaining text to _dummy files (fixes issues with some archivers, FS#2616) --- data/_dummy | 1 + data/attic/_dummy | 1 + data/cache/_dummy | 1 + data/index/_dummy | 1 + data/locks/_dummy | 1 + data/media_attic/_dummy | 1 + data/media_meta/_dummy | 1 + data/meta/_dummy | 1 + data/tmp/_dummy | 1 + 9 files changed, 9 insertions(+) diff --git a/data/_dummy b/data/_dummy index e69de29bb..e492265be 100644 --- a/data/_dummy +++ b/data/_dummy @@ -0,0 +1 @@ +You can safely delete this file. \ No newline at end of file diff --git a/data/attic/_dummy b/data/attic/_dummy index e69de29bb..e492265be 100644 --- a/data/attic/_dummy +++ b/data/attic/_dummy @@ -0,0 +1 @@ +You can safely delete this file. \ No newline at end of file diff --git a/data/cache/_dummy b/data/cache/_dummy index e69de29bb..e492265be 100644 --- a/data/cache/_dummy +++ b/data/cache/_dummy @@ -0,0 +1 @@ +You can safely delete this file. \ No newline at end of file diff --git a/data/index/_dummy b/data/index/_dummy index e69de29bb..e492265be 100644 --- a/data/index/_dummy +++ b/data/index/_dummy @@ -0,0 +1 @@ +You can safely delete this file. \ No newline at end of file diff --git a/data/locks/_dummy b/data/locks/_dummy index e69de29bb..e492265be 100644 --- a/data/locks/_dummy +++ b/data/locks/_dummy @@ -0,0 +1 @@ +You can safely delete this file. \ No newline at end of file diff --git a/data/media_attic/_dummy b/data/media_attic/_dummy index e69de29bb..e492265be 100644 --- a/data/media_attic/_dummy +++ b/data/media_attic/_dummy @@ -0,0 +1 @@ +You can safely delete this file. \ No newline at end of file diff --git a/data/media_meta/_dummy b/data/media_meta/_dummy index e69de29bb..e492265be 100644 --- a/data/media_meta/_dummy +++ b/data/media_meta/_dummy @@ -0,0 +1 @@ +You can safely delete this file. \ No newline at end of file diff --git a/data/meta/_dummy b/data/meta/_dummy index e69de29bb..e492265be 100644 --- a/data/meta/_dummy +++ b/data/meta/_dummy @@ -0,0 +1 @@ +You can safely delete this file. \ No newline at end of file diff --git a/data/tmp/_dummy b/data/tmp/_dummy index e69de29bb..e492265be 100644 --- a/data/tmp/_dummy +++ b/data/tmp/_dummy @@ -0,0 +1 @@ +You can safely delete this file. \ No newline at end of file -- cgit v1.2.3 From 7e9efe5266f592dc927dbf126a901e7dea2b4f5d Mon Sep 17 00:00:00 2001 From: Anika Henke <anika@selfthinker.org> Date: Sat, 16 Feb 2013 15:12:04 +0000 Subject: moved rewrite rules to uncomment together (FS#2484) --- .htaccess.dist | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/.htaccess.dist b/.htaccess.dist index aa2437b95..c90abdc80 100644 --- a/.htaccess.dist +++ b/.htaccess.dist @@ -15,7 +15,16 @@ ## $conf['userewrite'] = 1 - not needed for rewrite mode 2 #RewriteEngine on # -## Not all installations will require the following line. If you do, +#RewriteRule ^_media/(.*) lib/exe/fetch.php?media=$1 [QSA,L] +#RewriteRule ^_detail/(.*) lib/exe/detail.php?media=$1 [QSA,L] +#RewriteRule ^_export/([^/]+)/(.*) doku.php?do=export_$1&id=$2 [QSA,L] +#RewriteRule ^$ doku.php [L] +#RewriteCond %{REQUEST_FILENAME} !-f +#RewriteCond %{REQUEST_FILENAME} !-d +#RewriteRule (.*) doku.php?id=$1 [QSA,L] +#RewriteRule ^index.php$ doku.php +# +## Not all installations will require the following line. If you do, ## change "/dokuwiki" to the path to your dokuwiki directory relative ## to your document root. #RewriteBase /dokuwiki @@ -25,12 +34,3 @@ ## rules if your server setup allows HTTPS. #RewriteCond %{HTTPS} !=on #RewriteRule ^lib/exe/xmlrpc.php$ https://%{SERVER_NAME}%{REQUEST_URI} [L,R=301] -# -#RewriteRule ^_media/(.*) lib/exe/fetch.php?media=$1 [QSA,L] -#RewriteRule ^_detail/(.*) lib/exe/detail.php?media=$1 [QSA,L] -#RewriteRule ^_export/([^/]+)/(.*) doku.php?do=export_$1&id=$2 [QSA,L] -#RewriteRule ^$ doku.php [L] -#RewriteCond %{REQUEST_FILENAME} !-f -#RewriteCond %{REQUEST_FILENAME} !-d -#RewriteRule (.*) doku.php?id=$1 [QSA,L] -#RewriteRule ^index.php$ doku.php -- cgit v1.2.3 From 9d2e1be699d573eebda922cf67f030d3d2aa462d Mon Sep 17 00:00:00 2001 From: Andreas Gohr <andi@splitbrain.org> Date: Sat, 16 Feb 2013 18:29:20 +0100 Subject: introduced http_status() for sending HTTP status code FS#1698 It seems, some servers require a special Status: header for sending the HTTP status code from PHP (F)CGI to the server. This patch introduces a new function (adopted from CodeIgniter) for simplifying the status handling. --- inc/actions.php | 6 ++-- inc/auth.php | 2 +- inc/httputils.php | 71 ++++++++++++++++++++++++++++++++++++++++++++++++ inc/parser/code.php | 2 +- lib/exe/detail.php | 2 +- lib/exe/fetch.php | 4 +-- lib/exe/mediamanager.php | 4 +-- lib/exe/xmlrpc.php | 4 +-- 8 files changed, 83 insertions(+), 12 deletions(-) diff --git a/inc/actions.php b/inc/actions.php index e0ad908b7..da3414eb2 100644 --- a/inc/actions.php +++ b/inc/actions.php @@ -172,7 +172,7 @@ function act_dispatch(){ $evt->advise_after(); // Make sure plugs can handle 'denied' if($conf['send404'] && $ACT == 'denied') { - header('HTTP/1.0 403 Forbidden'); + http_status(403); } unset($evt); @@ -658,7 +658,7 @@ function act_sitemap($act) { global $conf; if ($conf['sitemap'] < 1 || !is_numeric($conf['sitemap'])) { - header("HTTP/1.0 404 Not Found"); + http_status(404); print "Sitemap generation is disabled."; exit; } @@ -690,7 +690,7 @@ function act_sitemap($act) { exit; } - header("HTTP/1.0 500 Internal Server Error"); + http_status(500); print "Could not read the sitemap file - bad permissions?"; exit; } diff --git a/inc/auth.php b/inc/auth.php index 7f427bd8d..9566a2615 100644 --- a/inc/auth.php +++ b/inc/auth.php @@ -267,7 +267,7 @@ function auth_login($user, $pass, $sticky = false, $silent = false) { function auth_validateToken($token) { if(!$token || $token != $_SESSION[DOKU_COOKIE]['auth']['token']) { // bad token - header("HTTP/1.0 401 Unauthorized"); + http_status(401); print 'Invalid auth token - maybe the session timed out'; unset($_SESSION[DOKU_COOKIE]['auth']['token']); // no second chance exit; diff --git a/inc/httputils.php b/inc/httputils.php index 4ba287eb5..d3f3cdde2 100644 --- a/inc/httputils.php +++ b/inc/httputils.php @@ -250,6 +250,11 @@ function http_cached_finish($file, $content) { } } +/** + * Fetches raw, unparsed POST data + * + * @return string + */ function http_get_raw_post_data() { static $postData = null; if ($postData === null) { @@ -257,3 +262,69 @@ function http_get_raw_post_data() { } return $postData; } + +/** + * Set the HTTP response status and takes care of the used PHP SAPI + * + * Inspired by CodeIgniter's set_status_header function + * + * @param int $code + * @param string $text + */ +function http_status($code = 200, $text = '') { + static $stati = array( + 200 => 'OK', + 201 => 'Created', + 202 => 'Accepted', + 203 => 'Non-Authoritative Information', + 204 => 'No Content', + 205 => 'Reset Content', + 206 => 'Partial Content', + + 300 => 'Multiple Choices', + 301 => 'Moved Permanently', + 302 => 'Found', + 304 => 'Not Modified', + 305 => 'Use Proxy', + 307 => 'Temporary Redirect', + + 400 => 'Bad Request', + 401 => 'Unauthorized', + 403 => 'Forbidden', + 404 => 'Not Found', + 405 => 'Method Not Allowed', + 406 => 'Not Acceptable', + 407 => 'Proxy Authentication Required', + 408 => 'Request Timeout', + 409 => 'Conflict', + 410 => 'Gone', + 411 => 'Length Required', + 412 => 'Precondition Failed', + 413 => 'Request Entity Too Large', + 414 => 'Request-URI Too Long', + 415 => 'Unsupported Media Type', + 416 => 'Requested Range Not Satisfiable', + 417 => 'Expectation Failed', + + 500 => 'Internal Server Error', + 501 => 'Not Implemented', + 502 => 'Bad Gateway', + 503 => 'Service Unavailable', + 504 => 'Gateway Timeout', + 505 => 'HTTP Version Not Supported' + ); + + if($text == '' && isset($stati[$code])) { + $text = $stati[$code]; + } + + $server_protocol = (isset($_SERVER['SERVER_PROTOCOL'])) ? $_SERVER['SERVER_PROTOCOL'] : false; + + if(substr(php_sapi_name(), 0, 3) == 'cgi') { + header("Status: {$code} {$text}", true); + } elseif($server_protocol == 'HTTP/1.1' OR $server_protocol == 'HTTP/1.0') { + header($server_protocol." {$code} {$text}", true, $code); + } else { + header("HTTP/1.1 {$code} {$text}", true, $code); + } +} diff --git a/inc/parser/code.php b/inc/parser/code.php index 21fb0dc3c..43d8d703f 100644 --- a/inc/parser/code.php +++ b/inc/parser/code.php @@ -43,7 +43,7 @@ class Doku_Renderer_code extends Doku_Renderer { * This should never be reached, if it is send a 404 */ function document_end() { - header("HTTP/1.0 404 Not Found"); + http_status(404); echo '404 - Not found'; exit; } diff --git a/lib/exe/detail.php b/lib/exe/detail.php index e597db3a2..db635c016 100644 --- a/lib/exe/detail.php +++ b/lib/exe/detail.php @@ -31,7 +31,7 @@ if($AUTH >= AUTH_READ){ $SRC = mediaFN($IMG); if(!@file_exists($SRC)){ //doesn't exist! - header("HTTP/1.0 404 File not Found"); + http_status(404); $ERROR = 'File not found'; } }else{ diff --git a/lib/exe/fetch.php b/lib/exe/fetch.php index 73e74af40..9bac4d272 100644 --- a/lib/exe/fetch.php +++ b/lib/exe/fetch.php @@ -58,7 +58,7 @@ if(!defined('SIMPLE_TEST')) { } // send any non 200 status if($data['status'] != 200) { - header('HTTP/1.0 '.$data['status'].' '.$data['statusmessage']); + http_status($data['status'], $data['statusmessage']); } // die on errors if($data['status'] > 203) { @@ -137,7 +137,7 @@ function sendFile($file, $mime, $dl, $cache) { if($fp) { http_rangeRequest($fp, filesize($file), $mime); } else { - header("HTTP/1.0 500 Internal Server Error"); + http_status(500); print "Could not read $file - bad permissions?"; } } diff --git a/lib/exe/mediamanager.php b/lib/exe/mediamanager.php index 04dd178cc..e0a90a291 100644 --- a/lib/exe/mediamanager.php +++ b/lib/exe/mediamanager.php @@ -36,7 +36,7 @@ // do not display the manager if user does not have read access if($AUTH < AUTH_READ && !$fullscreen) { - header('HTTP/1.0 403 Forbidden'); + http_status(403); die($lang['accessdenied']); } @@ -48,7 +48,7 @@ $_FILES['upload'] =& $_FILES['Filedata']; $JUMPTO = media_upload($NS,$AUTH); if($JUMPTO == false){ - header("HTTP/1.0 400 Bad Request"); + http_status(400); echo 'Upload failed'; } echo 'ok'; diff --git a/lib/exe/xmlrpc.php b/lib/exe/xmlrpc.php index 5e6c197d0..c09daa17c 100644 --- a/lib/exe/xmlrpc.php +++ b/lib/exe/xmlrpc.php @@ -29,10 +29,10 @@ class dokuwiki_xmlrpc_server extends IXR_Server { return $result; } catch (RemoteAccessDeniedException $e) { if (!isset($_SERVER['REMOTE_USER'])) { - header('HTTP/1.1 401 Unauthorized'); + http_status(401); return new IXR_Error(-32603, "server error. not authorized to call method $methodname"); } else { - header('HTTP/1.1 403 Forbidden'); + http_status(403); return new IXR_Error(-32604, "server error. forbidden to call the method $methodname"); } } catch (RemoteException $e) { -- cgit v1.2.3 From 994211890f92c1678536b003354146fbb44b8f2f Mon Sep 17 00:00:00 2001 From: Andreas Gohr <andi@splitbrain.org> Date: Sat, 16 Feb 2013 18:38:11 +0100 Subject: disabled JavaScript compatibility layer this disables the JavaScript compatibility layer which let pre-jQuery migration plugins run with their old code. This will break plugins using outdated JavaScript. These plugins have to be updated according to https://www.dokuwiki.org/devel:jqueryfaq As a courtesy to users, the compatibility.js is not deleted, yet. Undoing this single patch can be used as a temporary workaround. --- lib/exe/js.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/exe/js.php b/lib/exe/js.php index 41d3e735c..4ff48133e 100644 --- a/lib/exe/js.php +++ b/lib/exe/js.php @@ -62,7 +62,7 @@ function js_out(){ DOKU_INC.'lib/scripts/locktimer.js', DOKU_INC.'lib/scripts/linkwiz.js', DOKU_INC.'lib/scripts/media.js', - DOKU_INC.'lib/scripts/compatibility.js', +# deprecated DOKU_INC.'lib/scripts/compatibility.js', # disabled for FS#1958 DOKU_INC.'lib/scripts/hotkeys.js', DOKU_INC.'lib/scripts/behaviour.js', DOKU_INC.'lib/scripts/page.js', -- cgit v1.2.3 From 80faa902000c2bcf4602999e24a6016e1fafb997 Mon Sep 17 00:00:00 2001 From: Anika Henke <anika@selfthinker.org> Date: Sat, 16 Feb 2013 16:58:31 +0000 Subject: corrected some inline documentation in template's js --- lib/tpl/dokuwiki/script.js | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/lib/tpl/dokuwiki/script.js b/lib/tpl/dokuwiki/script.js index 3ed8dbabe..375500f78 100644 --- a/lib/tpl/dokuwiki/script.js +++ b/lib/tpl/dokuwiki/script.js @@ -1,11 +1,10 @@ /** * We handle several device classes based on browser width. - * see http://twitter.github.com/bootstrap/scaffolding.html#responsive * - * - desktop: 980+ - * - mobile: < 980 - * - tablet 481 - 979 (ostensibly for tablets in portrait mode) - * - phone <= 480 + * - desktop: > __tablet_width__ (as set in style.ini) + * - mobile: + * - tablet <= __tablet_width__ + * - phone <= __phone_width__ */ var device_class = ''; // not yet known var device_classes = 'desktop mobile tablet phone'; -- cgit v1.2.3 From 25c4afb8d352fa02fddec2253b301c13d0cd3fb2 Mon Sep 17 00:00:00 2001 From: Christopher Smith <chris@jalakai.co.uk> Date: Sat, 16 Feb 2013 17:02:05 +0000 Subject: FS#2111, improve security check --- inc/html.php | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/inc/html.php b/inc/html.php index ddaed2261..c2723bceb 100644 --- a/inc/html.php +++ b/inc/html.php @@ -1636,11 +1636,16 @@ function html_admin(){ } // data security check - // @todo: could be checked and only displayed if $conf['savedir'] is under the web root - echo '<a style="border:none; float:right;" - href="http://www.dokuwiki.org/security#web_access_security"> - <img src="data/security.png" alt="Your data directory seems to be protected properly." - onerror="this.parentNode.style.display=\'none\'" /></a>'; + // simple check if the 'savedir' is relative and accessible when appended to DOKU_URL + // it verifies either: + // 'savedir' has been moved elsewhere, or + // has protection to prevent the webserver serving files from it + if (substr($conf['savedir'],0,2) == './'){ + echo '<a style="border:none; float:right;" + href="http://www.dokuwiki.org/security#web_access_security"> + <img src="'.DOKU_URL.$conf['savedir'].'/security.png" alt="Your data directory seems to be protected properly." + onerror="this.parentNode.style.display=\'none\'" /></a>'; + } print p_locale_xhtml('admin'); -- cgit v1.2.3 From 71f791fff9c3912682e5e0c8866e695a0749aa82 Mon Sep 17 00:00:00 2001 From: Andreas Gohr <andi@splitbrain.org> Date: Sat, 16 Feb 2013 19:08:57 +0100 Subject: removed deprecated ACL wrapper object --- lib/plugins/acl/script.js | 8 -------- 1 file changed, 8 deletions(-) diff --git a/lib/plugins/acl/script.js b/lib/plugins/acl/script.js index 0ba91cdc9..c3763dc8d 100644 --- a/lib/plugins/acl/script.js +++ b/lib/plugins/acl/script.js @@ -117,11 +117,3 @@ var dw_acl = { }; jQuery(dw_acl.init); - -var acl = { - init: DEPRECATED_WRAP(dw_acl.init, dw_acl), - userselhandler: DEPRECATED_WRAP(dw_acl.userselhandler, dw_acl), - loadinfo: DEPRECATED_WRAP(dw_acl.loadinfo, dw_acl), - parseatt: DEPRECATED_WRAP(dw_acl.parseatt, dw_acl), - treehandler: DEPRECATED_WRAP(dw_acl.treehandler, dw_acl) -}; -- cgit v1.2.3 From dd90013a5a9ce204250f4d94072e089f617e09db Mon Sep 17 00:00:00 2001 From: Michael Hamann <michael@content-space.de> Date: Sat, 16 Feb 2013 18:06:47 +0100 Subject: Media manager: don't create empty namespaces FS#2642 Previously the media manager created an empty namespace whenever you opened a non-existing namespace with upload permissions. Now the current namespace is only displayed in the tree but not actually created. --- inc/media.php | 26 ++++++++++++++++++++++---- lib/exe/mediamanager.php | 3 --- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/inc/media.php b/inc/media.php index bd80db577..db1ca0d57 100644 --- a/inc/media.php +++ b/inc/media.php @@ -1686,18 +1686,36 @@ function media_nstree($ns){ $ns = cleanID($ns); if(empty($ns)){ global $ID; - $ns = dirname(str_replace(':','/',$ID)); - if($ns == '.') $ns =''; + $ns = (string)getNS($ID); } - $ns = utf8_encodeFN(str_replace(':','/',$ns)); + + $ns_dir = utf8_encodeFN(str_replace(':','/',$ns)); $data = array(); - search($data,$conf['mediadir'],'search_index',array('ns' => $ns, 'nofiles' => true)); + search($data,$conf['mediadir'],'search_index',array('ns' => $ns_dir, 'nofiles' => true)); // wrap a list with the root level around the other namespaces array_unshift($data, array('level' => 0, 'id' => '', 'open' =>'true', 'label' => '['.$lang['mediaroot'].']')); + // insert the current ns into the hierarchy if it isn't already part of it + $ns_parts = explode(':', $ns); + $tmp_ns = ''; + $pos = 0; + foreach ($ns_parts as $level => $part) { + if ($tmp_ns) $tmp_ns .= ':'.$part; + else $tmp_ns = $part; + + // find the namespace parts or insert them + while ($data[$pos]['id'] != $tmp_ns) { + if ($pos >= count($data) || ($data[$pos]['level'] <= $level+1 && strnatcmp(utf8_encodeFN($data[$pos]['id']), utf8_encodeFN($tmp_ns)) > 0)) { + array_splice($data, $pos, 0, array(array('level' => $level+1, 'id' => $tmp_ns, 'open' => 'true'))); + break; + } + ++$pos; + } + } + echo html_buildlist($data,'idx','media_nstree_item','media_nstree_li'); } diff --git a/lib/exe/mediamanager.php b/lib/exe/mediamanager.php index e0a90a291..53d438321 100644 --- a/lib/exe/mediamanager.php +++ b/lib/exe/mediamanager.php @@ -40,9 +40,6 @@ die($lang['accessdenied']); } - // create the given namespace (just for beautification) - if($AUTH >= AUTH_UPLOAD) { io_createNamespace("$NS:xxx", 'media'); } - // handle flash upload if(isset($_FILES['Filedata'])){ $_FILES['upload'] =& $_FILES['Filedata']; -- cgit v1.2.3 From b480dd4215925c5e9aaecaa5c086346b009692b4 Mon Sep 17 00:00:00 2001 From: Michael Hamann <michael@content-space.de> Date: Sat, 16 Feb 2013 18:10:00 +0100 Subject: Abort old quick search requests when starting new ones This prevents old requests that need longer than the newer ones (likely, as if you type more less results are returned) from overriding the results list. --- lib/scripts/qsearch.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/scripts/qsearch.js b/lib/scripts/qsearch.js index 0c3609ada..e5cc73b49 100644 --- a/lib/scripts/qsearch.js +++ b/lib/scripts/qsearch.js @@ -12,6 +12,7 @@ var dw_qsearch = { $inObj: null, $outObj: null, timer: null, + curRequest: null, /** * initialize the quick search @@ -35,12 +36,16 @@ var dw_qsearch = { // attach eventhandler to search field do_qsearch = function () { + // abort any previous request + if (dw_qsearch.curRequest != null) { + dw_qsearch.curRequest.abort(); + } var value = dw_qsearch.$inObj.val(); if (value === '') { dw_qsearch.clear_results(); return; } - jQuery.post( + dw_qsearch.curRequest = jQuery.post( DOKU_BASE + 'lib/exe/ajax.php', { call: 'qsearch', @@ -84,6 +89,8 @@ var dw_qsearch = { onCompletion: function(data) { var max, $links, too_big; + dw_qsearch.curRequest = null; + if (data === '') { dw_qsearch.clear_results(); return; -- cgit v1.2.3 From 87bba75a4043643511c89cb89ef9cf11e59fbf2c Mon Sep 17 00:00:00 2001 From: Tom N Harris <tnharris@whoopdedo.org> Date: Sat, 16 Feb 2013 12:53:24 -0500 Subject: Add django compatible hashes to the config options. --- lib/plugins/config/settings/config.metadata.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/plugins/config/settings/config.metadata.php b/lib/plugins/config/settings/config.metadata.php index 663eab9dd..bdbc4311f 100644 --- a/lib/plugins/config/settings/config.metadata.php +++ b/lib/plugins/config/settings/config.metadata.php @@ -127,7 +127,7 @@ $meta['_authentication'] = array('fieldset'); $meta['useacl'] = array('onoff'); $meta['autopasswd'] = array('onoff'); $meta['authtype'] = array('authtype'); -$meta['passcrypt'] = array('multichoice','_choices' => array('smd5','md5','apr1','sha1','ssha','lsmd5','crypt','mysql','my411','kmd5','pmd5','hmd5','mediawiki','bcrypt','sha512')); +$meta['passcrypt'] = array('multichoice','_choices' => array('smd5','md5','apr1','sha1','ssha','lsmd5','crypt','mysql','my411','kmd5','pmd5','hmd5','mediawiki','bcrypt','djangomd5','djangosha1','sha512')); $meta['defaultgroup']= array('string'); $meta['superuser'] = array('string'); $meta['manager'] = array('string'); -- cgit v1.2.3 From 5398a7b652eabdd0a20f154b97b60f89cad72f8c Mon Sep 17 00:00:00 2001 From: Andreas Gohr <andi@splitbrain.org> Date: Sat, 16 Feb 2013 19:57:01 +0100 Subject: fixed language file placeholders FS#2682 --- inc/lang/af/lang.php | 2 +- inc/lang/ar/lang.php | 4 +--- inc/lang/az/lang.php | 2 +- inc/lang/bg/lang.php | 2 +- inc/lang/ca-valencia/lang.php | 2 +- inc/lang/ca/lang.php | 2 +- inc/lang/cs/lang.php | 2 +- inc/lang/da/lang.php | 2 +- inc/lang/el/lang.php | 6 ++---- inc/lang/eo/lang.php | 2 +- inc/lang/es/lang.php | 4 +--- inc/lang/et/lang.php | 2 +- inc/lang/eu/lang.php | 2 +- inc/lang/fa/lang.php | 4 +--- inc/lang/fi/lang.php | 2 +- inc/lang/fo/lang.php | 2 +- inc/lang/gl/lang.php | 4 +--- inc/lang/he/lang.php | 3 +-- inc/lang/hi/lang.php | 1 - inc/lang/hr/lang.php | 2 +- inc/lang/hu/lang.php | 2 +- inc/lang/ia/lang.php | 4 +--- inc/lang/id/lang.php | 2 +- inc/lang/is/lang.php | 2 +- inc/lang/it/lang.php | 4 +--- inc/lang/ja/lang.php | 2 +- inc/lang/km/lang.php | 2 -- inc/lang/ku/lang.php | 2 +- inc/lang/la/lang.php | 4 +--- inc/lang/lb/lang.php | 2 +- inc/lang/lt/lang.php | 2 +- inc/lang/lv/lang.php | 2 +- inc/lang/mg/lang.php | 2 +- inc/lang/mk/lang.php | 4 +--- inc/lang/mr/lang.php | 1 - inc/lang/ms/lang.php | 2 +- inc/lang/ne/lang.php | 1 - inc/lang/nl/lang.php | 2 +- inc/lang/no/lang.php | 5 ++--- inc/lang/pl/lang.php | 4 +--- inc/lang/pt/lang.php | 2 +- inc/lang/ro/lang.php | 2 +- inc/lang/ru/lang.php | 4 +--- inc/lang/sl/lang.php | 2 +- inc/lang/sq/lang.php | 4 +--- inc/lang/sr/lang.php | 2 +- inc/lang/th/lang.php | 2 +- inc/lang/tr/lang.php | 2 +- inc/lang/uk/lang.php | 2 +- inc/lang/vi/lang.php | 2 +- inc/lang/zh-tw/lang.php | 2 +- lib/plugins/plugin/lang/ar/lang.php | 2 +- lib/plugins/plugin/lang/hi/lang.php | 1 - lib/plugins/plugin/lang/pl/lang.php | 2 +- lib/plugins/plugin/lang/zh-tw/lang.php | 2 +- lib/plugins/usermanager/lang/ca-valencia/lang.php | 2 +- 56 files changed, 53 insertions(+), 85 deletions(-) diff --git a/inc/lang/af/lang.php b/inc/lang/af/lang.php index 6de891a63..ab8e5177b 100644 --- a/inc/lang/af/lang.php +++ b/inc/lang/af/lang.php @@ -55,7 +55,7 @@ $lang['current'] = 'huidige'; $lang['line'] = 'Streak'; $lang['youarehere'] = 'Jy is hier'; $lang['by'] = 'by'; -$lang['restored'] = 'Het terug gegaan na vroeëre weergawe'; +$lang['restored'] = 'Het terug gegaan na vroeëre weergawe (%s)'; $lang['summary'] = 'Voorskou'; $lang['qb_bold'] = 'Vetdruk'; $lang['qb_italic'] = 'Skuinsdruk'; diff --git a/inc/lang/ar/lang.php b/inc/lang/ar/lang.php index 4928b3dbd..5b72e0a51 100644 --- a/inc/lang/ar/lang.php +++ b/inc/lang/ar/lang.php @@ -181,7 +181,7 @@ $lang['lastmod'] = 'آخر تعديل'; $lang['by'] = 'بواسطة'; $lang['deleted'] = 'حذفت'; $lang['created'] = 'اُنشئت'; -$lang['restored'] = 'استعيدت نسخة قديمة'; +$lang['restored'] = 'استعيدت نسخة قديمة (%s)'; $lang['external_edit'] = 'تحرير خارجي'; $lang['summary'] = 'ملخص التحرير'; $lang['noflash'] = 'تحتاج إلى<a href="http://www.adobe.com/products/flashplayer/">ملحق فلاش أدوبي</a> لعرض هذا المحتوى.'; @@ -258,8 +258,6 @@ $lang['subscr_m_unsubscribe'] = 'ألغ الاشتراك'; $lang['subscr_m_subscribe'] = 'اشترك'; $lang['subscr_m_receive'] = 'استقبال'; $lang['subscr_style_every'] = 'بريدا على كل تغيير'; -$lang['subscr_style_digest'] = 'بريد ملخص عن تغييرات كل صفحة'; -$lang['subscr_style_list'] = 'قائمة بالصفحات المتغيرة منذ آخر بريد'; $lang['authmodfailed'] = 'إعدادات تصريح فاسدة، يرجى مراسلة المدير.'; $lang['authtempfail'] = 'تصريح المشترك غير متوفر مؤقتاً، إن استمرت هذه الحالة يرجى مراسلة المدير'; $lang['authpwdexpire'] = 'ستنتهي صلاحية كلمة السر في %d . عليك بتغييرها سريعا.'; diff --git a/inc/lang/az/lang.php b/inc/lang/az/lang.php index 6df15a83e..5084d9f60 100644 --- a/inc/lang/az/lang.php +++ b/inc/lang/az/lang.php @@ -136,7 +136,7 @@ $lang['lastmod'] = 'Son dəyişiklər'; $lang['by'] = ' Kimdən'; $lang['deleted'] = 'silinib'; $lang['created'] = 'yaranıb'; -$lang['restored'] = 'köhnə versiya qaytarıldı'; +$lang['restored'] = 'köhnə versiya qaytarıldı (%s)'; $lang['external_edit'] = 'bayırdan dəyişik'; $lang['summary'] = 'Dəyişiklər xülasəsi'; $lang['noflash'] = 'Bu məzmuna baxmaq üçün <a href="http://www.adobe.com/products/flashplayer/">Adobe Flash Plugin</a> tələb olunur.'; diff --git a/inc/lang/bg/lang.php b/inc/lang/bg/lang.php index 47d83c62f..3c0a17a72 100644 --- a/inc/lang/bg/lang.php +++ b/inc/lang/bg/lang.php @@ -190,7 +190,7 @@ $lang['lastmod'] = 'Последна промяна'; $lang['by'] = 'от'; $lang['deleted'] = 'изтрита'; $lang['created'] = 'създадена'; -$lang['restored'] = 'възстановена предишна версия'; +$lang['restored'] = 'възстановена предишна версия (%s)'; $lang['external_edit'] = 'външна редакция'; $lang['summary'] = 'Обобщение'; $lang['noflash'] = 'Необходим е <a href="http://www.adobe.com/products/flashplayer/">Adobe Flash Plugin</a> за изобразяване на съдържанието.'; diff --git a/inc/lang/ca-valencia/lang.php b/inc/lang/ca-valencia/lang.php index 532f6c73d..6e7438f53 100644 --- a/inc/lang/ca-valencia/lang.php +++ b/inc/lang/ca-valencia/lang.php @@ -137,7 +137,7 @@ $lang['lastmod'] = 'Última modificació el'; $lang['by'] = 'per'; $lang['deleted'] = 'borrat'; $lang['created'] = 'creat'; -$lang['restored'] = 'restaurada l\'última versió'; +$lang['restored'] = 'restaurada l\'última versió (%s)'; $lang['external_edit'] = 'edició externa'; $lang['summary'] = 'Editar sumari'; $lang['noflash'] = 'Necessita el <a href="http://www.adobe.com/products/flashplayer/">plúgin d\'Adobe Flash</a> per a vore este contingut.'; diff --git a/inc/lang/ca/lang.php b/inc/lang/ca/lang.php index cb2b64686..a429dc06a 100644 --- a/inc/lang/ca/lang.php +++ b/inc/lang/ca/lang.php @@ -180,7 +180,7 @@ $lang['lastmod'] = 'Darrera modificació'; $lang['by'] = 'per'; $lang['deleted'] = 'suprimit'; $lang['created'] = 'creat'; -$lang['restored'] = 's\'ha restaurat una versió anterior'; +$lang['restored'] = 's\'ha restaurat una versió anterior %s'; $lang['external_edit'] = 'edició externa'; $lang['summary'] = 'Resum d\'edició'; $lang['noflash'] = 'Per a visualitzar aquest contingut necessiteu el <a href="http://www.adobe.com/products/flashplayer/">connector d\'Adobe Flash</a>.'; diff --git a/inc/lang/cs/lang.php b/inc/lang/cs/lang.php index af94424ac..f0b8f3ba4 100644 --- a/inc/lang/cs/lang.php +++ b/inc/lang/cs/lang.php @@ -188,7 +188,7 @@ $lang['lastmod'] = 'Poslední úprava'; $lang['by'] = 'autor:'; $lang['deleted'] = 'odstraněno'; $lang['created'] = 'vytvořeno'; -$lang['restored'] = 'stará verze byla obnovena'; +$lang['restored'] = 'stará verze byla obnovena (%s)'; $lang['external_edit'] = 'upraveno mimo DokuWiki'; $lang['summary'] = 'Komentář k úpravám'; $lang['noflash'] = 'Pro přehrání obsahu potřebujete <a href="http://www.adobe.com/products/flashplayer/">Adobe Flash Plugin</a>.'; diff --git a/inc/lang/da/lang.php b/inc/lang/da/lang.php index f132c133b..022de8127 100644 --- a/inc/lang/da/lang.php +++ b/inc/lang/da/lang.php @@ -188,7 +188,7 @@ $lang['lastmod'] = 'Sidst ændret'; $lang['by'] = 'af'; $lang['deleted'] = 'slettet'; $lang['created'] = 'oprettet'; -$lang['restored'] = 'gammel udgave reetableret'; +$lang['restored'] = 'gammel udgave reetableret (%s)'; $lang['external_edit'] = 'ekstern redigering'; $lang['summary'] = 'Redigerings resumé'; $lang['noflash'] = 'Den <a href="http://www.adobe.com/products/flashplayer/">Adobe Flash Plugin</a> er nødvendig til at vise denne indehold.'; diff --git a/inc/lang/el/lang.php b/inc/lang/el/lang.php index 55b70074f..0fe343026 100644 --- a/inc/lang/el/lang.php +++ b/inc/lang/el/lang.php @@ -148,7 +148,6 @@ $lang['uploadsucc'] = 'Επιτυχής φόρτωση'; $lang['uploadfail'] = 'Η μεταφόρτωση απέτυχε. Πιθανόν αυτό να οφείλεται στις ρυθμίσεις πρόσβασης του αρχείου.'; $lang['uploadwrong'] = 'Η μεταφόρτωση δεν έγινε δεκτή. Δεν επιτρέπονται αρχεία αυτού του τύπου!'; $lang['uploadexist'] = 'Το αρχείο ήδη υπάρχει. Δεν έγινε καμία αλλαγή.'; -$lang['uploadbadcontent'] = 'Το περιεχόμενο του αρχείου δεν ταιριάζει με την επέκτασή του.'; $lang['uploadspam'] = 'Η μεταφόρτωση ακυρώθηκε από το φίλτρο spam.'; $lang['uploadxss'] = 'Η μεταφόρτωση ακυρώθηκε λόγω πιθανού επικίνδυνου περιεχομένου.'; $lang['uploadsize'] = 'Το αρχείο ήταν πολύ μεγάλο. (μέγιστο %s)'; @@ -184,7 +183,7 @@ $lang['lastmod'] = 'Τελευταία τροποποίηση'; $lang['by'] = 'από'; $lang['deleted'] = 'διαγράφηκε'; $lang['created'] = 'δημιουργήθηκε'; -$lang['restored'] = 'παλαιότερη έκδοση επαναφέρθηκε'; +$lang['restored'] = 'παλαιότερη έκδοση επαναφέρθηκε (%s)'; $lang['external_edit'] = 'εξωτερική τροποποίηση'; $lang['summary'] = 'Επεξεργασία σύνοψης'; $lang['noflash'] = 'Το <a href="http://www.adobe.com/products/flashplayer/">Adobe Flash Plugin</a> απαιτείται για την προβολή αυτού του στοιχείου.'; @@ -314,8 +313,7 @@ $lang['media_upload'] = 'Φόρτωση στο <strong>%s</strong> φά $lang['media_search'] = 'Αναζήτηση στο <strong>%s</strong> φάκελο.'; $lang['media_view'] = '%s'; $lang['media_viewold'] = '%s στα %s'; -$lang['media_edit'] = 'Επεξεργασία'; -$lang['media_history'] = 'Αυτές είναι οι παλαιότερες αναθεωρήσεις του αρχείου.'; +$lang['media_edit'] = 'Επεξεργασία %s'; $lang['media_meta_edited'] = 'τα μεταδεδομένα επεξεργάστηκαν'; $lang['media_perm_read'] = 'Συγνώμη, δεν έχετε επαρκή διακαιώματα για να διαβάσετε αυτά τα αρχεία.'; $lang['media_perm_upload'] = 'Συγνώμη, δεν έχετε επαρκή διακαιώματα για να φορτώσετε αυτά τα αρχεία.'; diff --git a/inc/lang/eo/lang.php b/inc/lang/eo/lang.php index 1c3b6f519..2d9b03148 100644 --- a/inc/lang/eo/lang.php +++ b/inc/lang/eo/lang.php @@ -184,7 +184,7 @@ $lang['lastmod'] = 'Lastaj ŝanĝoj'; $lang['by'] = 'de'; $lang['deleted'] = 'forigita'; $lang['created'] = 'kreita'; -$lang['restored'] = 'malnova revizio restarigita'; +$lang['restored'] = 'malnova revizio restarigita (%s)'; $lang['external_edit'] = 'ekstera redakto'; $lang['summary'] = 'Bulteno de ŝanĝoj'; $lang['noflash'] = 'La <a href="http://www.adobe.com/products/flashplayer/">Adobe Flash Plugin</a> necesas por montri tiun ĉi enhavon.'; diff --git a/inc/lang/es/lang.php b/inc/lang/es/lang.php index 20d0284bc..193ec9a7d 100644 --- a/inc/lang/es/lang.php +++ b/inc/lang/es/lang.php @@ -203,7 +203,7 @@ $lang['lastmod'] = 'Última modificación'; $lang['by'] = 'por'; $lang['deleted'] = 'borrado'; $lang['created'] = 'creado'; -$lang['restored'] = 'se ha restaurado la vieja versión'; +$lang['restored'] = 'se ha restaurado la vieja versión (%s)'; $lang['external_edit'] = 'editor externo'; $lang['summary'] = 'Resumen de la edición'; $lang['noflash'] = 'Para mostrar este contenido es necesario el <a href="http://www.adobe.com/products/flashplayer/">Plugin Adobe Flash</a>.'; @@ -280,8 +280,6 @@ $lang['subscr_m_unsubscribe'] = 'Darse de baja'; $lang['subscr_m_subscribe'] = 'Suscribirse'; $lang['subscr_m_receive'] = 'Recibir'; $lang['subscr_style_every'] = 'enviar correo en cada cambio'; -$lang['subscr_style_digest'] = 'recopilar correo de cambios por cada página'; -$lang['subscr_style_list'] = 'lista de páginas con cambios desde el último correo'; $lang['authmodfailed'] = 'Está mal configurada la autenticación de usuarios. Por favor, avisa al administrador del wiki.'; $lang['authtempfail'] = 'La autenticación de usuarios no está disponible temporalmente. Si esta situación persiste, por favor avisa al administrador del wiki.'; $lang['authpwdexpire'] = 'Su contraseña caducara en %d días, debería cambiarla lo antes posible'; diff --git a/inc/lang/et/lang.php b/inc/lang/et/lang.php index 8ae61558a..0a0310832 100644 --- a/inc/lang/et/lang.php +++ b/inc/lang/et/lang.php @@ -163,7 +163,7 @@ $lang['lastmod'] = 'Viimati muutnud'; $lang['by'] = 'persoon'; $lang['deleted'] = 'eemaldatud'; $lang['created'] = 'tekitatud'; -$lang['restored'] = 'vana versioon taastatud'; +$lang['restored'] = 'vana versioon taastatud (%s)'; $lang['external_edit'] = 'väline muutmine'; $lang['summary'] = 'kokkuvõte muudatustest'; $lang['mail_newpage'] = 'leht lisatud:'; diff --git a/inc/lang/eu/lang.php b/inc/lang/eu/lang.php index 5b03dcb97..7aab8b44c 100644 --- a/inc/lang/eu/lang.php +++ b/inc/lang/eu/lang.php @@ -178,7 +178,7 @@ $lang['lastmod'] = 'Azken aldaketa'; $lang['by'] = 'egilea:'; $lang['deleted'] = 'ezabatua'; $lang['created'] = 'sortua'; -$lang['restored'] = 'bertsio zaharra berrezarria'; +$lang['restored'] = 'bertsio zaharra berrezarria (%s)'; $lang['external_edit'] = 'kanpoko aldaketa'; $lang['summary'] = 'Aldatu laburpena'; $lang['noflash'] = '<a href="http://www.adobe.com/products/flashplayer/">Adobe Flash Plugin</a> beharrezkoa da eduki hau bistaratzeko.'; diff --git a/inc/lang/fa/lang.php b/inc/lang/fa/lang.php index 026d6499a..eb828a472 100644 --- a/inc/lang/fa/lang.php +++ b/inc/lang/fa/lang.php @@ -189,7 +189,7 @@ $lang['lastmod'] = 'آخرین ویرایش'; $lang['by'] = 'توسط'; $lang['deleted'] = 'حذف شد'; $lang['created'] = 'ایجاد شد'; -$lang['restored'] = 'یک نگارش پیشین واگردانی شد.'; +$lang['restored'] = 'یک نگارش پیشین واگردانی شد. (%s)'; $lang['external_edit'] = 'ویرایش خارجی'; $lang['summary'] = 'پیش‌نمایش'; $lang['noflash'] = 'برای نمایش محتویات <a href="http://www.adobe.com/products/flashplayer/">افزونه‌ی فلش</a> مورد نیاز است.'; @@ -266,8 +266,6 @@ $lang['subscr_m_unsubscribe'] = 'لغو آبونه'; $lang['subscr_m_subscribe'] = 'آبونه شدن'; $lang['subscr_m_receive'] = 'دریافت کردن'; $lang['subscr_style_every'] = 'ارسال رای‌نامه در تمامی تغییرات'; -$lang['subscr_style_digest'] = 'ارسال ایمیل‌های فشرده برای تغییرات هر صفحه'; -$lang['subscr_style_list'] = 'لیست صفحات تغییر داده شده از آخرین رای‌نامه'; $lang['authmodfailed'] = 'اشکال در نوع معتبرسازی کاربران، مدیر ویکی را باخبر سازید.'; $lang['authtempfail'] = 'معتبرسازی کابران موقتن مسدود می‌باشد. اگر این حالت پایدار بود، مدیر ویکی را باخبر سازید.'; $lang['authpwdexpire'] = 'کلمه عبور شما در %d روز منقضی خواهد شد ، شما باید آن را زود تغییر دهید'; diff --git a/inc/lang/fi/lang.php b/inc/lang/fi/lang.php index 73eb3d4cc..59e4dc6cb 100644 --- a/inc/lang/fi/lang.php +++ b/inc/lang/fi/lang.php @@ -183,7 +183,7 @@ $lang['lastmod'] = 'Viimeksi muutettu'; $lang['by'] = '/'; $lang['deleted'] = 'poistettu'; $lang['created'] = 'luotu'; -$lang['restored'] = 'vanha versio palautettu'; +$lang['restored'] = 'vanha versio palautettu (%s)'; $lang['external_edit'] = 'ulkoinen muokkaus'; $lang['summary'] = 'Yhteenveto muokkauksesta'; $lang['noflash'] = 'Tarvitset <a href="http://www.adobe.com/products/flashplayer/">Adobe Flash-liitännäisen</a> nähdäksesi tämän sisällön.'; diff --git a/inc/lang/fo/lang.php b/inc/lang/fo/lang.php index 14ec8c56b..9f51824db 100644 --- a/inc/lang/fo/lang.php +++ b/inc/lang/fo/lang.php @@ -130,7 +130,7 @@ $lang['lastmod'] = 'Seinast broytt'; $lang['by'] = 'av'; $lang['deleted'] = 'strika'; $lang['created'] = 'stovna'; -$lang['restored'] = 'gomul útgáva endurstovna'; +$lang['restored'] = 'gomul útgáva endurstovna (%s)'; $lang['summary'] = 'Samandráttur'; $lang['mail_newpage'] = 'skjal skoyta uppí:'; $lang['mail_changed'] = 'skjal broytt:'; diff --git a/inc/lang/gl/lang.php b/inc/lang/gl/lang.php index 7cc06a833..fa49c1121 100644 --- a/inc/lang/gl/lang.php +++ b/inc/lang/gl/lang.php @@ -181,7 +181,7 @@ $lang['lastmod'] = 'Última modificación'; $lang['by'] = 'por'; $lang['deleted'] = 'eliminado'; $lang['created'] = 'creado'; -$lang['restored'] = 'revisión antiga restaurada'; +$lang['restored'] = 'revisión antiga restaurada (%s)'; $lang['external_edit'] = 'edición externa'; $lang['summary'] = 'Resumo da edición'; $lang['noflash'] = 'Precísase o <a href="http://www.adobe.com/products/flashplayer/">Extensión Adobe Flash</a> para amosar este contido.'; @@ -258,8 +258,6 @@ $lang['subscr_m_unsubscribe'] = 'Desubscribir'; $lang['subscr_m_subscribe'] = 'Subscribir'; $lang['subscr_m_receive'] = 'Recibir'; $lang['subscr_style_every'] = 'correo-e en cada troco'; -$lang['subscr_style_digest'] = 'correo-e con resumo de trocos para cada páxina'; -$lang['subscr_style_list'] = 'lista de páxinas mudadas dende o último correo-e'; $lang['authmodfailed'] = 'Configuración de autenticación de usuario incorrecta. Por favor, informa ao Administrador do teu Wiki.'; $lang['authtempfail'] = 'A autenticación de usuario non está dispoñible de xeito temporal. De persistir esta situación, por favor, informa ao Administrador do teu Wiki.'; $lang['authpwdexpire'] = 'A túa contrasinal expirará en %d días, deberías cambiala pronto.'; diff --git a/inc/lang/he/lang.php b/inc/lang/he/lang.php index e474501ae..4853a0e2b 100644 --- a/inc/lang/he/lang.php +++ b/inc/lang/he/lang.php @@ -165,7 +165,7 @@ $lang['lastmod'] = 'מועד השינוי האחרון'; $lang['by'] = 'על ידי'; $lang['deleted'] = 'נמחק'; $lang['created'] = 'נוצר'; -$lang['restored'] = 'שוחזר'; +$lang['restored'] = 'שוחזר (%s)'; $lang['external_edit'] = 'עריכה חיצונית'; $lang['summary'] = 'תקציר העריכה'; $lang['noflash'] = '<a href="http://www.adobe.com/products/flashplayer/">תוסף פלאש לדפדפן</a> נדרש כדי להציג תוכן זה.'; @@ -243,7 +243,6 @@ $lang['i_modified'] = 'משיקולי אבטחה סקריפט זה י עליך לחלץ שנית את הקבצים מהחבילה שהורדה או להיעזר בדף <a href="http://dokuwiki.org/install">Dokuwiki installation instructions</a>'; $lang['i_funcna'] = 'פונקציית ה-PHP‏ <code>%s</code> אינה זמינה. יתכן כי מארח האתר חסם אותה מסיבה כלשהי?'; -$lang['i_phpver'] = 'גרסת ה־PHP שלך <code>%s</code> נמוכה מהדרוש. עליך לשדרג את התקנת ה־PHP שלך.'; $lang['i_permfail'] = '<code>%s</code> אינה ניתנת לכתיבה על ידי DokuWiki. עליך לשנות הרשאות תיקייה זו!'; $lang['i_confexists'] = '<code>%s</code> כבר קיים'; $lang['i_writeerr'] = 'אין אפשרות ליצור את <code>%s</code>. נא לבדוק את הרשאות הקובץ/תיקייה וליצור את הקובץ ידנית.'; diff --git a/inc/lang/hi/lang.php b/inc/lang/hi/lang.php index 893457066..d2021fcae 100644 --- a/inc/lang/hi/lang.php +++ b/inc/lang/hi/lang.php @@ -84,7 +84,6 @@ $lang['lastmod'] = 'अंतिम बार संशोधि $lang['by'] = 'के द्वारा'; $lang['deleted'] = 'हटाया'; $lang['created'] = 'निर्मित'; -$lang['restored'] = 'पुराने संशोधन बहाल'; $lang['external_edit'] = 'बाह्य सम्पादित'; $lang['summary'] = 'सारांश संपादित करें'; $lang['mail_newpage'] = 'पृष्ठ जोड़ा:'; diff --git a/inc/lang/hr/lang.php b/inc/lang/hr/lang.php index 97f4cf0c2..a607210d7 100644 --- a/inc/lang/hr/lang.php +++ b/inc/lang/hr/lang.php @@ -165,7 +165,7 @@ $lang['lastmod'] = 'Zadnja izmjena'; $lang['by'] = 'od'; $lang['deleted'] = 'obrisano'; $lang['created'] = 'stvoreno'; -$lang['restored'] = 'vraćena prijašnja inačica'; +$lang['restored'] = 'vraćena prijašnja inačica (%s)'; $lang['external_edit'] = 'vanjsko uređivanje'; $lang['summary'] = 'Sažetak izmjena'; $lang['noflash'] = 'Za prikazivanje ovog sadržaja potreban je <a href="http://www.adobe.com/products/flashplayer/">Adobe Flash Plugin</a>'; diff --git a/inc/lang/hu/lang.php b/inc/lang/hu/lang.php index c59cace77..275fb15d5 100644 --- a/inc/lang/hu/lang.php +++ b/inc/lang/hu/lang.php @@ -169,7 +169,7 @@ $lang['lastmod'] = 'Utolsó módosítás'; $lang['by'] = 'szerkesztette:'; $lang['deleted'] = 'eltávolítva'; $lang['created'] = 'létrehozva'; -$lang['restored'] = 'az előző változat helyreállítva'; +$lang['restored'] = 'az előző változat helyreállítva (%s)'; $lang['external_edit'] = 'külső szerkesztés'; $lang['summary'] = 'A változások összefoglalása'; $lang['noflash'] = 'Ennek a tartalomnak a megtekintéséhez <a href="http://www.adobe.com/products/flashplayer/">Adobe Flash Plugin</a> szükséges.'; diff --git a/inc/lang/ia/lang.php b/inc/lang/ia/lang.php index a9d5c376c..fd63fb5ef 100644 --- a/inc/lang/ia/lang.php +++ b/inc/lang/ia/lang.php @@ -163,7 +163,7 @@ $lang['lastmod'] = 'Ultime modification'; $lang['by'] = 'per'; $lang['deleted'] = 'removite'; $lang['created'] = 'create'; -$lang['restored'] = 'ancian version restaurate'; +$lang['restored'] = 'ancian version restaurate (%s)'; $lang['external_edit'] = 'modification externe'; $lang['summary'] = 'Modificar summario'; $lang['noflash'] = 'Le <a href="http://www.adobe.com/products/flashplayer/">plug-in Flash de Adobe</a> es necessari pro monstrar iste contento.'; @@ -227,8 +227,6 @@ $lang['subscr_m_unsubscribe'] = 'Cancellar subscription'; $lang['subscr_m_subscribe'] = 'Subscriber'; $lang['subscr_m_receive'] = 'Reciper'; $lang['subscr_style_every'] = 'un message pro cata modification'; -$lang['subscr_style_digest'] = 'un digesto de modificationes pro cata pagina'; -$lang['subscr_style_list'] = 'lista de paginas modificate depost le ultime e-mail'; $lang['authmodfailed'] = 'Configuration incorrecte de authentication de usator. Per favor informa le administrator de tu wiki.'; $lang['authtempfail'] = 'Le authentication de usator temporarimente non es disponibile. Si iste situation persiste, per favor informa le administrator de tu wiki.'; $lang['i_chooselang'] = 'Selige tu lingua'; diff --git a/inc/lang/id/lang.php b/inc/lang/id/lang.php index 91ed38e31..e14b9d9f5 100644 --- a/inc/lang/id/lang.php +++ b/inc/lang/id/lang.php @@ -125,7 +125,7 @@ $lang['lastmod'] = 'Terakhir diubah'; $lang['by'] = 'oleh'; $lang['deleted'] = 'terhapus'; $lang['created'] = 'dibuat'; -$lang['restored'] = 'revisi lama ditampilkan kembali'; +$lang['restored'] = 'revisi lama ditampilkan kembali (%s)'; $lang['external_edit'] = 'Perubahan eksternal'; $lang['summary'] = 'Edit summary'; $lang['mail_newpage'] = 'Halaman ditambahkan:'; diff --git a/inc/lang/is/lang.php b/inc/lang/is/lang.php index be20da6b3..78ae7e249 100644 --- a/inc/lang/is/lang.php +++ b/inc/lang/is/lang.php @@ -134,7 +134,7 @@ $lang['lastmod'] = 'Síðast breytt'; $lang['by'] = 'af'; $lang['deleted'] = 'eytt'; $lang['created'] = 'myndað'; -$lang['restored'] = 'Breytt aftur til fyrri útgáfu'; +$lang['restored'] = 'Breytt aftur til fyrri útgáfu (%s)'; $lang['external_edit'] = 'utanaðkomandi breyta'; $lang['summary'] = 'Forskoða'; $lang['noflash'] = 'Það þarf <a href="http://www.adobe.com/products/flashplayer/">Adobe Flash viðbót</a> til að sýna sumt efnið á þessari síðu'; diff --git a/inc/lang/it/lang.php b/inc/lang/it/lang.php index 1ad5ae1bb..307e7292f 100644 --- a/inc/lang/it/lang.php +++ b/inc/lang/it/lang.php @@ -187,7 +187,7 @@ $lang['lastmod'] = 'Ultima modifica'; $lang['by'] = 'da'; $lang['deleted'] = 'eliminata'; $lang['created'] = 'creata'; -$lang['restored'] = 'versione precedente ripristinata'; +$lang['restored'] = 'versione precedente ripristinata (%s)'; $lang['external_edit'] = 'modifica esterna'; $lang['summary'] = 'Oggetto della modifica'; $lang['noflash'] = 'E\' necessario <a href="http://www.adobe.com/products/flashplayer/">il plugin Adobe Flash</a> per visualizzare questo contenuto.'; @@ -263,8 +263,6 @@ $lang['subscr_m_unsubscribe'] = 'Rimuovi sottoscrizione'; $lang['subscr_m_subscribe'] = 'Sottoscrivi'; $lang['subscr_m_receive'] = 'Ricevi'; $lang['subscr_style_every'] = 'email per ogni modifica'; -$lang['subscr_style_digest'] = 'email riassuntiva delle modifiche di ogni pagina'; -$lang['subscr_style_list'] = 'elenco delle pagine modificate dall\'ultima email'; $lang['authmodfailed'] = 'La configurazione dell\'autenticazione non è corretta. Informa l\'amministratore di questo wiki.'; $lang['authtempfail'] = 'L\'autenticazione è temporaneamente non disponibile. Se questa situazione persiste, informa l\'amministratore di questo wiki.'; $lang['authpwdexpire'] = 'La tua password scadrà in %d giorni, dovresti cambiarla quanto prima.'; diff --git a/inc/lang/ja/lang.php b/inc/lang/ja/lang.php index 66de0dab5..7997889e4 100644 --- a/inc/lang/ja/lang.php +++ b/inc/lang/ja/lang.php @@ -181,7 +181,7 @@ $lang['lastmod'] = '最終更新'; $lang['by'] = 'by'; $lang['deleted'] = '削除'; $lang['created'] = '作成'; -$lang['restored'] = '以前のバージョンを復元'; +$lang['restored'] = '以前のバージョンを復元 (%s)'; $lang['external_edit'] = '外部編集'; $lang['summary'] = '編集の概要'; $lang['noflash'] = 'この内容を表示するためには <a href="http://www.adobe.com/products/flashplayer/">Adobe Flash Plugin</a> が必要です。'; diff --git a/inc/lang/km/lang.php b/inc/lang/km/lang.php index 6a5fa223f..85bb6afba 100644 --- a/inc/lang/km/lang.php +++ b/inc/lang/km/lang.php @@ -132,7 +132,6 @@ $lang['lastmod'] = 'ពេលកែចុងក្រោយ'; $lang['by'] = 'និពន្ឋដោយ'; $lang['deleted'] = 'យកចេញ'; $lang['created'] = 'បង្កើត'; -$lang['restored'] = 'ស្ដារបុនរាព្រឹតចាស់'; $lang['external_edit'] = 'កំរេពីក្រៅ'; $lang['summary'] = 'កែតម្រា'; @@ -207,7 +206,6 @@ $lang['i_superuser'] = 'អ្នកកំពូល'; $lang['i_problems'] = 'កម្មវិធី​ដំឡើងបានប៉ះឧបសគ្គ។ អ្នកមិនអាចបន្តទៅទៀត ដល់អ្នកជួសជុលវា។'; $lang['i_modified'] = ''; $lang['i_funcna'] = '<code>%s</code> '; -$lang['i_phpver'] = 'PHP ប្រវត់លេខ<code>%s</code> ជា'; $lang['i_permfail'] = '<code>%s</code> មិនអាចសាស'; $lang['i_confexists'] = '<code>%s</code> មានហាយ'; $lang['i_writeerr'] = 'មិនអាចបណ្កើ<code>%s</code>។ អ្នកត្រវការពិនិត្យអធិក្រឹតិរបស់ថតនឹងឯកសារ។'; diff --git a/inc/lang/ku/lang.php b/inc/lang/ku/lang.php index 63ccafa35..c9d658c6d 100644 --- a/inc/lang/ku/lang.php +++ b/inc/lang/ku/lang.php @@ -95,7 +95,7 @@ $lang['lastmod'] = 'Guherandina dawî'; $lang['by'] = 'by'; $lang['deleted'] = 'hat jê birin'; $lang['created'] = 'hat afirandin'; -$lang['restored'] = 'old revision restored'; +$lang['restored'] = 'old revision restored (%s)'; $lang['summary'] = 'Kurteya guhartinê'; $lang['mail_newpage'] = 'page added:'; diff --git a/inc/lang/la/lang.php b/inc/lang/la/lang.php index 77fec8362..bea921abc 100644 --- a/inc/lang/la/lang.php +++ b/inc/lang/la/lang.php @@ -131,7 +131,6 @@ $lang['uploadsucc'] = 'Oneratum perfectum'; $lang['uploadfail'] = 'Error onerandi.'; $lang['uploadwrong'] = 'Onerare non potest. Genus documenti non legitimum!'; $lang['uploadexist'] = 'Documentum iam est.'; -$lang['uploadbadcontent'] = 'Documentum oneratum cum genere documenti non congruit.'; $lang['uploadspam'] = 'Onerare non potest: nam in indice perscriptionis documentum est.'; $lang['uploadxss'] = 'Onerare non potest: nam forsitan malum scriptum in documento est.'; $lang['uploadsize'] = 'Documentum onerandum ponderosius est. (Maxime "%s")'; @@ -164,7 +163,7 @@ $lang['lastmod'] = 'Extrema mutatio'; $lang['by'] = 'a(b)'; $lang['deleted'] = 'deletur'; $lang['created'] = 'creatur'; -$lang['restored'] = 'Recensio uetus restituta'; +$lang['restored'] = 'Recensio uetus restituta (%s)'; $lang['external_edit'] = 'Externe recensere'; $lang['summary'] = 'Indicem recensere'; $lang['noflash'] = '<a href="http://www.adobe.com/products/flashplayer/">Adobe Flash Plugin</a> necessarium est.'; @@ -254,7 +253,6 @@ $lang['i_pol1'] = 'Publicus uicis (omnes legere, Sodales scribere $lang['i_pol2'] = 'Clausus uicis (Soli Sodales legere scribere et onerare poccunt)'; $lang['i_retry'] = 'Rursum temptas'; $lang['i_license'] = 'Elige facultatem sub qua tuus uicis est:'; -$lang['recent_global'] = 'Mutatione in hoc genere uides. Recentiores mutationes quoque uidere <a href="%s">potes</a>'; $lang['years'] = 'ab annis %d'; $lang['months'] = 'a mensibus %d'; $lang['weeks'] = 'a septimanis %d'; diff --git a/inc/lang/lb/lang.php b/inc/lang/lb/lang.php index e6409b7ff..bced5a50a 100644 --- a/inc/lang/lb/lang.php +++ b/inc/lang/lb/lang.php @@ -124,7 +124,7 @@ $lang['lastmod'] = 'Fir d\'lescht g\'ännert'; $lang['by'] = 'vun'; $lang['deleted'] = 'geläscht'; $lang['created'] = 'erstallt'; -$lang['restored'] = 'al Versioun zeréckgeholl'; +$lang['restored'] = 'al Versioun zeréckgeholl (%s)'; $lang['external_edit'] = 'extern Ännerung'; $lang['summary'] = 'Resumé vun den Ännerungen'; $lang['noflash'] = 'Den <a href="http://www.adobe.com/products/flashplayer/">Adobe Flash Plugin</a> get gebraucht fir dësen Inhalt unzeweisen.'; diff --git a/inc/lang/lt/lang.php b/inc/lang/lt/lang.php index 13ff8c305..8a4c4e6a5 100644 --- a/inc/lang/lt/lang.php +++ b/inc/lang/lt/lang.php @@ -132,7 +132,7 @@ $lang['lastmod'] = 'Keista'; $lang['by'] = 'vartotojo'; $lang['deleted'] = 'ištrintas'; $lang['created'] = 'sukurtas'; -$lang['restored'] = 'atstatyta sena versija'; +$lang['restored'] = 'atstatyta sena versija (%s)'; $lang['external_edit'] = 'redaguoti papildomomis priemonėmis'; $lang['summary'] = 'Redaguoti santrauką'; $lang['noflash'] = '<a href="http://www.adobe.com/products/flashplayer/">Adobe Flash Plugin</a> reikalingas šios medžiagos peržiūrai.'; diff --git a/inc/lang/lv/lang.php b/inc/lang/lv/lang.php index 671e5f52a..2027b87ba 100644 --- a/inc/lang/lv/lang.php +++ b/inc/lang/lv/lang.php @@ -178,7 +178,7 @@ $lang['lastmod'] = 'Labota'; $lang['by'] = ', labojis'; $lang['deleted'] = 'dzēsts'; $lang['created'] = 'izveidots'; -$lang['restored'] = 'vecā versija atjaunota'; +$lang['restored'] = 'vecā versija atjaunota (%s)'; $lang['external_edit'] = 'ārpussistēmas labojums'; $lang['summary'] = 'Anotācija'; $lang['noflash'] = 'Lai attēlotu lapas saturu, vajag <a href="http://www.adobe.com/products/flashplayer/">Adobe Flash Plugin</a>.'; diff --git a/inc/lang/mg/lang.php b/inc/lang/mg/lang.php index 4142f00d0..95589ab21 100644 --- a/inc/lang/mg/lang.php +++ b/inc/lang/mg/lang.php @@ -88,7 +88,7 @@ $lang['lastmod'] = 'Novaina farany:'; $lang['by'] = '/'; $lang['deleted'] = 'voafafa'; $lang['created'] = 'Voamboatra'; -$lang['restored'] = 'Naverina tamin\'ny kinova taloha'; +$lang['restored'] = 'Naverina tamin\'ny kinova taloha (%s)'; $lang['summary'] = 'Fanovana teo'; $lang['mail_newpage'] = 'pejy niampy:'; diff --git a/inc/lang/mk/lang.php b/inc/lang/mk/lang.php index 7482f2512..44bd489b7 100644 --- a/inc/lang/mk/lang.php +++ b/inc/lang/mk/lang.php @@ -136,7 +136,7 @@ $lang['lastmod'] = 'Последно изменета'; $lang['by'] = 'од'; $lang['deleted'] = 'отстранета'; $lang['created'] = 'креирана'; -$lang['restored'] = 'обновена е стара ревизија'; +$lang['restored'] = 'обновена е стара ревизија (%s)'; $lang['external_edit'] = 'надворешно уредување'; $lang['summary'] = 'Уреди го изводот'; $lang['noflash'] = '<a href="http://www.adobe.com/products/flashplayer/">Adobe Flash приклучокот</a> е потребен за да се прикаже оваа содржина.'; @@ -196,8 +196,6 @@ $lang['subscr_m_unsubscribe'] = 'Отплатување'; $lang['subscr_m_subscribe'] = 'Претплата'; $lang['subscr_m_receive'] = 'Прими'; $lang['subscr_style_every'] = 'е-пошта за секоја промена'; -$lang['subscr_style_digest'] = 'е-пошта со преглед од промените за секоја страница'; -$lang['subscr_style_list'] = 'листа на променети страници од последната е-пошта'; $lang['authmodfailed'] = 'Лоша конфигурација за автентикација на корисник. Ве молам информирајте го вики администратор.'; $lang['authtempfail'] = 'Автентикација на корисник е привремено недостапна. Ако оваа ситуација истрајува, ве молам известете го вики администратор.'; $lang['i_chooselang'] = 'Избере јазик'; diff --git a/inc/lang/mr/lang.php b/inc/lang/mr/lang.php index b754a3f1c..d95813efa 100644 --- a/inc/lang/mr/lang.php +++ b/inc/lang/mr/lang.php @@ -180,7 +180,6 @@ $lang['lastmod'] = 'सर्वात शेवटचा बद $lang['by'] = 'द्वारा'; $lang['deleted'] = 'काढून टाकले'; $lang['created'] = 'निर्माण केले'; -$lang['restored'] = 'जुनी आवृत्ति पुनर्स्थापित केली'; $lang['external_edit'] = 'बाहेरून संपादित'; $lang['summary'] = 'सारांश बदला'; $lang['noflash'] = 'ही माहिती दाखवण्यासाठी <a href="http://www.adobe.com/products/flashplayer/">अडोब फ्लॅश प्लेअर</a> ची गरज आहे.'; diff --git a/inc/lang/ms/lang.php b/inc/lang/ms/lang.php index 92dc86b5a..02c0e2c91 100644 --- a/inc/lang/ms/lang.php +++ b/inc/lang/ms/lang.php @@ -93,5 +93,5 @@ $lang['uploadfail'] = 'Ralat muat naik'; $lang['uploadxss'] = 'Fail ini mengandungi kod HTML atau kod skrip yang mungkin boleh disalah tafsir oleh pelayar web.'; $lang['toc'] = 'Jadual Kandungan'; $lang['current'] = 'kini'; -$lang['restored'] = 'Telah dikembalikan ke semakan sebelumnya'; +$lang['restored'] = 'Telah dikembalikan ke semakan sebelumnya (%s)'; $lang['summary'] = 'Paparan'; diff --git a/inc/lang/ne/lang.php b/inc/lang/ne/lang.php index fa6d2f705..b7ca14b0a 100644 --- a/inc/lang/ne/lang.php +++ b/inc/lang/ne/lang.php @@ -128,7 +128,6 @@ $lang['lastmod'] = 'अन्तिम पटक सच्या $lang['by'] = 'द्वारा '; $lang['deleted'] = 'हटाइएको'; $lang['created'] = 'निर्माण गरिएको'; -$lang['restored'] = 'पुरानो संस्करण पुनर्‌प्रयोग गरिएको'; $lang['external_edit'] = 'बाह्य सम्पादन'; $lang['summary'] = 'सम्पादनको बारेमा'; $lang['mail_newpage'] = 'थपिएको पृष्ठ'; diff --git a/inc/lang/nl/lang.php b/inc/lang/nl/lang.php index 0241eab2f..f6192a99b 100644 --- a/inc/lang/nl/lang.php +++ b/inc/lang/nl/lang.php @@ -192,7 +192,7 @@ $lang['lastmod'] = 'Laatst gewijzigd'; $lang['by'] = 'door'; $lang['deleted'] = 'verwijderd'; $lang['created'] = 'aangemaakt'; -$lang['restored'] = 'oude revisie hersteld'; +$lang['restored'] = 'oude revisie hersteld (%s)'; $lang['external_edit'] = 'Externe bewerking'; $lang['summary'] = 'Samenvatting wijziging'; $lang['noflash'] = 'De <a href="http://www.adobe.com/products/flashplayer/">Adobe Flash Plugin</a> is vereist om de pagina te kunnen weergeven.'; diff --git a/inc/lang/no/lang.php b/inc/lang/no/lang.php index 9aa11ac87..8235bfb91 100644 --- a/inc/lang/no/lang.php +++ b/inc/lang/no/lang.php @@ -190,7 +190,7 @@ $lang['lastmod'] = 'Sist endret'; $lang['by'] = 'av'; $lang['deleted'] = 'fjernet'; $lang['created'] = 'opprettet'; -$lang['restored'] = 'gjenopprettet til en tidligere versjon'; +$lang['restored'] = 'gjenopprettet til en tidligere versjon (%s)'; $lang['external_edit'] = 'ekstern redigering'; $lang['summary'] = 'Redigeringskommentar'; $lang['noflash'] = 'For at dette innholdet skal vises må du ha <a href="http://www.adobe.com/products/flashplayer/">Adobe Flash Plugin</a>.'; @@ -316,8 +316,7 @@ $lang['media_upload'] = 'Last opp til navnerommet <strong>%s</strong>.' $lang['media_search'] = 'Søk i navnerommet <strong>%s</strong>.'; $lang['media_view'] = '%s'; $lang['media_viewold'] = '%s på %s'; -$lang['media_edit'] = 'Rediger'; -$lang['media_history'] = 'Dette er de tidligere versjonene av filen.'; +$lang['media_edit'] = 'Rediger %s'; $lang['media_meta_edited'] = 'metadata er endra'; $lang['media_perm_read'] = 'Beklager, du har ikke tilgang til å lese filer.'; $lang['media_perm_upload'] = 'Beklager, du har ikke tilgang til å laste opp filer.'; diff --git a/inc/lang/pl/lang.php b/inc/lang/pl/lang.php index cf9fc6a16..51149e88f 100644 --- a/inc/lang/pl/lang.php +++ b/inc/lang/pl/lang.php @@ -189,7 +189,7 @@ $lang['lastmod'] = 'ostatnio zmienione'; $lang['by'] = 'przez'; $lang['deleted'] = 'usunięto'; $lang['created'] = 'utworzono'; -$lang['restored'] = 'przywrócono poprzednią wersję'; +$lang['restored'] = 'przywrócono poprzednią wersję (%s)'; $lang['external_edit'] = 'edycja zewnętrzna'; $lang['summary'] = 'Opis zmian'; $lang['noflash'] = 'Plugin <a href="http://www.adobe.com/products/flashplayer/">Adobe Flash Plugin</a> jest niezbędny do obejrzenia tej zawartości.'; @@ -265,8 +265,6 @@ $lang['subscr_m_unsubscribe'] = 'Zrezygnuj z subskrypcji'; $lang['subscr_m_subscribe'] = 'Subskrybuj'; $lang['subscr_m_receive'] = 'Otrzymuj'; $lang['subscr_style_every'] = 'email przy każdej zmianie'; -$lang['subscr_style_digest'] = 'email ze streszczeniem zmian dla każdej ze stron'; -$lang['subscr_style_list'] = 'lista zmienionych stron od czasu ostatniego emaila'; $lang['authmodfailed'] = 'Błąd uwierzytelnienia. Powiadom administratora tego wiki.'; $lang['authtempfail'] = 'Uwierzytelnienie użytkownika jest w tej chwili niemożliwe. Jeśli ta sytuacja się powtórzy, powiadom administratora tego wiki.'; $lang['authpwdexpire'] = 'Twoje hasło wygaśnie za %d dni. Należy je zmienić w krótkim czasie.'; diff --git a/inc/lang/pt/lang.php b/inc/lang/pt/lang.php index 1555889f6..ac9c59c3e 100644 --- a/inc/lang/pt/lang.php +++ b/inc/lang/pt/lang.php @@ -179,7 +179,7 @@ $lang['lastmod'] = 'Esta página foi modificada pela última vez e $lang['by'] = 'por'; $lang['deleted'] = 'Documento automaticamente removido.'; $lang['created'] = 'Criação deste novo documento.'; -$lang['restored'] = 'Versão anterior restaurada.'; +$lang['restored'] = 'Versão anterior restaurada (%s)'; $lang['external_edit'] = 'Edição externa'; $lang['summary'] = 'Sumário da Edição'; $lang['noflash'] = 'O <a href="http://www.adobe.com/products/flashplayer/">Plugin Adobe Flash</a> é necessário para exibir este conteúdo.'; diff --git a/inc/lang/ro/lang.php b/inc/lang/ro/lang.php index d6bfcad3a..8b2483daf 100644 --- a/inc/lang/ro/lang.php +++ b/inc/lang/ro/lang.php @@ -184,7 +184,7 @@ $lang['lastmod'] = 'Ultima modificare'; $lang['by'] = 'de către'; $lang['deleted'] = 'şters'; $lang['created'] = 'creat'; -$lang['restored'] = 'versiune veche restaurată'; +$lang['restored'] = 'versiune veche restaurată (%s)'; $lang['external_edit'] = 'editare externă'; $lang['summary'] = 'Editează sumarul'; $lang['noflash'] = 'Plugin-ul <a href="http://www.adobe.com/products/flashplayer/">Adobe Flash Plugin</a> este necesar pentru afişarea corectă a conţinutului.'; diff --git a/inc/lang/ru/lang.php b/inc/lang/ru/lang.php index c391bc6a5..52e0ef3d6 100644 --- a/inc/lang/ru/lang.php +++ b/inc/lang/ru/lang.php @@ -193,7 +193,7 @@ $lang['lastmod'] = 'Последние изменения'; $lang['by'] = ' —'; $lang['deleted'] = 'удалено'; $lang['created'] = 'создано'; -$lang['restored'] = 'старая ревизия восстановлена'; +$lang['restored'] = 'старая ревизия восстановлена (%s)'; $lang['external_edit'] = 'внешнее изменение'; $lang['summary'] = 'Сводка изменений'; $lang['noflash'] = 'Для просмотра этого содержимого требуется <a href="http://www.adobe.com/products/flashplayer/">Adobe Flash Plugin</a>.'; @@ -270,8 +270,6 @@ $lang['subscr_m_unsubscribe'] = 'Отменить подписку'; $lang['subscr_m_subscribe'] = 'Подписаться'; $lang['subscr_m_receive'] = 'Получить'; $lang['subscr_style_every'] = 'уведомлять о каждом изменении'; -$lang['subscr_style_digest'] = 'сводка изменений по каждой странице'; -$lang['subscr_style_list'] = 'перечислять изменившиеся страницы с прошлого уведомления'; $lang['authmodfailed'] = 'Неправильная конфигурация аутентификации пользователя. Пожалуйста, сообщите об этом своему администратору вики.'; $lang['authtempfail'] = 'Аутентификация пользователей временно недоступна. Если проблема продолжается какое-то время, пожалуйста, сообщите об этом своему администратору вики.'; $lang['authpwdexpire'] = 'Действие вашего пароля истекает через %d дней. Вы должны изменить его как можно скорее'; diff --git a/inc/lang/sl/lang.php b/inc/lang/sl/lang.php index 81220b8a2..5c4316b01 100644 --- a/inc/lang/sl/lang.php +++ b/inc/lang/sl/lang.php @@ -177,7 +177,7 @@ $lang['lastmod'] = 'Zadnja sprememba'; $lang['by'] = 'uporabnika'; $lang['deleted'] = 'odstranjena'; $lang['created'] = 'ustvarjena'; -$lang['restored'] = 'povrnjena stara različica'; +$lang['restored'] = 'povrnjena stara različica (%s)'; $lang['external_edit'] = 'urejanje v zunanjem urejevalniku'; $lang['summary'] = 'Povzetek urejanja'; $lang['noflash'] = 'Za prikaz vsebine je treba namestiti <a href="http://www.adobe.com/products/flashplayer/">Adobe Flash Plugin</a>'; diff --git a/inc/lang/sq/lang.php b/inc/lang/sq/lang.php index e190d8404..212f10607 100644 --- a/inc/lang/sq/lang.php +++ b/inc/lang/sq/lang.php @@ -140,7 +140,7 @@ $lang['lastmod'] = 'Redaktuar për herë të fundit'; $lang['by'] = 'nga'; $lang['deleted'] = 'u fshi'; $lang['created'] = 'u krijua'; -$lang['restored'] = 'Kthehu tek një version i vjetër'; +$lang['restored'] = 'Kthehu tek një version i vjetër (%s)'; $lang['external_edit'] = 'redaktim i jashtëm'; $lang['summary'] = 'Përmbledhja redaktimit'; $lang['noflash'] = 'Nevojitet <a href="http://www.adobe.com/products/flashplayer/">Adobe Flash Plugin</a> për të paraqitur këtë përmbajtje.'; @@ -204,8 +204,6 @@ $lang['subscr_m_unsubscribe'] = 'Fshi Abonimin'; $lang['subscr_m_subscribe'] = 'Abonohu'; $lang['subscr_m_receive'] = 'Mer'; $lang['subscr_style_every'] = 'email mbi çdo ndryshim'; -$lang['subscr_style_digest'] = 'pasqyro email-e ndryshimi pér çdo faqe'; -$lang['subscr_style_list'] = 'listë e faqeve të ndryshuara që nga emaili i fundit'; $lang['authmodfailed'] = 'Konfigurim i gabuar i autentikimit të përdoruesit. Ju lutem informoni Administratorin tuaj të Wiki-it.'; $lang['authtempfail'] = 'Autentikimi i përdoruesve është përkohësisht i padisponueshëm. Nëse kjo gjendje vazhdon, ju lutemi të informoni Administratorin tuaj të Wiki-it.'; $lang['i_chooselang'] = 'Zgjidhni gjuhën tuaj'; diff --git a/inc/lang/sr/lang.php b/inc/lang/sr/lang.php index d7f594511..7fbdf1985 100644 --- a/inc/lang/sr/lang.php +++ b/inc/lang/sr/lang.php @@ -162,7 +162,7 @@ $lang['lastmod'] = 'Последњи пут мењано'; $lang['by'] = 'од'; $lang['deleted'] = 'избрисано'; $lang['created'] = 'направљено'; -$lang['restored'] = 'стара верзија повраћена'; +$lang['restored'] = 'стара верзија повраћена (%s)'; $lang['external_edit'] = 'спољна измена'; $lang['summary'] = 'Сажетак измене'; $lang['noflash'] = 'За приказивање ове врсте материјала потребан вам је <a href="http://www.adobe.com/products/flashplayer/">Adobe Flash Plugin</a>.'; diff --git a/inc/lang/th/lang.php b/inc/lang/th/lang.php index c9d526436..627484eab 100644 --- a/inc/lang/th/lang.php +++ b/inc/lang/th/lang.php @@ -144,7 +144,7 @@ $lang['lastmod'] = 'แก้ไขครั้งล่าสุ $lang['by'] = 'โดย'; $lang['deleted'] = 'ถูกถอดออก'; $lang['created'] = 'ถูกสร้าง'; -$lang['restored'] = 'ย้อนไปรุ่นก่อนหน้า'; +$lang['restored'] = 'ย้อนไปรุ่นก่อนหน้า (%s)'; $lang['external_edit'] = 'แก้ไขภายนอก'; $lang['summary'] = 'สรุป(หมายเหตุ)การแก้ไขนี้'; $lang['noflash'] = 'ต้องการตัวเล่นแฟลช <a href="http://www.adobe.com/products/flashplayer/">Adobe Flash Plugin</a> เพื่อแสดงผลเนื้อหานี้'; diff --git a/inc/lang/tr/lang.php b/inc/lang/tr/lang.php index 5430905b1..c6edf74c6 100644 --- a/inc/lang/tr/lang.php +++ b/inc/lang/tr/lang.php @@ -176,7 +176,7 @@ $lang['lastmod'] = 'Son değiştirilme'; $lang['by'] = 'Değiştiren:'; $lang['deleted'] = 'silindi'; $lang['created'] = 'oluşturuldu'; -$lang['restored'] = 'eski sürüme dönüldü'; +$lang['restored'] = 'eski sürüme dönüldü (%s)'; $lang['external_edit'] = 'Dışarıdan düzenle'; $lang['summary'] = 'Özeti düzenle'; $lang['noflash'] = 'Bu içeriği göstermek için <a href="http://www.adobe.com/products/flashplayer/">Adobe Flash Eklentisi</a> gerekmektedir.'; diff --git a/inc/lang/uk/lang.php b/inc/lang/uk/lang.php index 5274a4210..6aa468c50 100644 --- a/inc/lang/uk/lang.php +++ b/inc/lang/uk/lang.php @@ -169,7 +169,7 @@ $lang['lastmod'] = 'В останнє змінено'; $lang['by'] = ' '; $lang['deleted'] = 'знищено'; $lang['created'] = 'створено'; -$lang['restored'] = 'відновлено стару ревізію'; +$lang['restored'] = 'відновлено стару ревізію (%s)'; $lang['external_edit'] = 'зовнішнє редагування'; $lang['summary'] = 'Підсумок змін'; $lang['noflash'] = 'Для перегляду цієї сторінки необхідно встановити <a href="http://www.adobe.com/products/flashplayer/">Adobe Flash Plugin</a>.'; diff --git a/inc/lang/vi/lang.php b/inc/lang/vi/lang.php index 99c4d47e4..c439ca534 100644 --- a/inc/lang/vi/lang.php +++ b/inc/lang/vi/lang.php @@ -176,7 +176,7 @@ $lang['lastmod'] = 'Thời điểm thay đổi'; $lang['by'] = 'do'; $lang['deleted'] = 'bị xoá'; $lang['created'] = 'được tạo ra'; -$lang['restored'] = 'phiên bản cũ đã được khôi phục'; +$lang['restored'] = 'phiên bản cũ đã được khôi phục (%s)'; $lang['external_edit'] = 'external edit'; $lang['summary'] = 'Tóm tắt biên soạn'; $lang['noflash'] = '<a href="http://www.adobe.com/products/flashplayer/">Adobe Flash Plugin</a> cần được cài để có thể xem nội dung này.'; diff --git a/inc/lang/zh-tw/lang.php b/inc/lang/zh-tw/lang.php index ddb35617e..536266971 100644 --- a/inc/lang/zh-tw/lang.php +++ b/inc/lang/zh-tw/lang.php @@ -186,7 +186,7 @@ $lang['lastmod'] = '上一次變更'; $lang['by'] = '由'; $lang['deleted'] = '移除'; $lang['created'] = '建立'; -$lang['restored'] = '恢復為舊版'; +$lang['restored'] = '恢復為舊版 (%s)'; $lang['external_edit'] = '外部編輯'; $lang['summary'] = '編輯摘要'; $lang['noflash'] = '顯示此內容需要 <a href="http://www.adobe.com/products/flashplayer/">Adobe Flash 附加元件</a>。'; diff --git a/lib/plugins/plugin/lang/ar/lang.php b/lib/plugins/plugin/lang/ar/lang.php index 8327e5ce3..a1a778131 100644 --- a/lib/plugins/plugin/lang/ar/lang.php +++ b/lib/plugins/plugin/lang/ar/lang.php @@ -50,4 +50,4 @@ $lang['enabled'] = 'الاضافة %s فُعلت. '; $lang['notenabled'] = 'تعذر تفعيل الاضافة %s، تحقق من اذونات الملف.'; $lang['disabled'] = 'عُطلت الإضافة %s.'; $lang['notdisabled'] = 'تعذر تعطيل الإضافة %s، تحقق من اذونات الملف.'; -$lang['packageinstalled'] = 'حزمة الإضافة (%d plugin(s): %Xs) ثبتت بنجاج.'; +$lang['packageinstalled'] = 'حزمة الإضافة (%d plugin(s): %s) ثبتت بنجاج.'; diff --git a/lib/plugins/plugin/lang/hi/lang.php b/lib/plugins/plugin/lang/hi/lang.php index ab29c6550..67b177256 100644 --- a/lib/plugins/plugin/lang/hi/lang.php +++ b/lib/plugins/plugin/lang/hi/lang.php @@ -6,7 +6,6 @@ * @author yndesai@gmail.com */ $lang['unknown'] = 'अज्ञात'; -$lang['deleted'] = 'मिटाया हुआ'; $lang['date'] = 'दिनांक:'; $lang['author'] = 'लेखक:'; $lang['error'] = 'अज्ञात त्रुटि हुइ'; diff --git a/lib/plugins/plugin/lang/pl/lang.php b/lib/plugins/plugin/lang/pl/lang.php index 1d3bbbc03..faaa69630 100644 --- a/lib/plugins/plugin/lang/pl/lang.php +++ b/lib/plugins/plugin/lang/pl/lang.php @@ -60,4 +60,4 @@ $lang['enabled'] = 'Wtyczka %s włączona.'; $lang['notenabled'] = 'Nie udało się uruchomić wtyczki %s, sprawdź uprawnienia dostępu do plików.'; $lang['disabled'] = 'Wtyczka %s wyłączona.'; $lang['notdisabled'] = 'Nie udało się wyłączyć wtyczki %s, sprawdź uprawnienia dostępu do plików.'; -$lang['packageinstalled'] = 'Pakiet wtyczek (%d wtyczki:% s) zainstalowany pomyślnie.'; +$lang['packageinstalled'] = 'Pakiet wtyczek (%d wtyczki: %s) zainstalowany pomyślnie.'; diff --git a/lib/plugins/plugin/lang/zh-tw/lang.php b/lib/plugins/plugin/lang/zh-tw/lang.php index 7b38a02c8..56149e79e 100644 --- a/lib/plugins/plugin/lang/zh-tw/lang.php +++ b/lib/plugins/plugin/lang/zh-tw/lang.php @@ -56,4 +56,4 @@ $lang['enabled'] = '附加元件 %s 已啟用。'; $lang['notenabled'] = '附加元件 %s 無法啟用,請檢查檔案權限。'; $lang['disabled'] = '附加元件 %s 已停用。'; $lang['notdisabled'] = '附加元件 %s 無法停用,請檢查檔案權限。'; -$lang['packageinstalled'] = '附加元件 (%d 附加元件%s: %s) 已安裝好。'; +$lang['packageinstalled'] = '附加元件 (%d 附加元件: %s) 已安裝好。'; diff --git a/lib/plugins/usermanager/lang/ca-valencia/lang.php b/lib/plugins/usermanager/lang/ca-valencia/lang.php index 5b0c628ed..c39c2f9b3 100644 --- a/lib/plugins/usermanager/lang/ca-valencia/lang.php +++ b/lib/plugins/usermanager/lang/ca-valencia/lang.php @@ -33,7 +33,7 @@ $lang['delete_ok'] = '%d usuaris borrats'; $lang['delete_fail'] = 'Erro borrant %d.'; $lang['update_ok'] = 'Usuari actualisat correctament'; $lang['update_fail'] = 'Erro actualisant usuari'; -$lang['update_exists'] = 'Erro canviant el nom de l\'usuari, el nom d\'usuari que ha donat ya existix (els demés canvis s\'aplicaran).'; +$lang['update_exists'] = 'Erro canviant el nom de l\'usuari (%s), el nom d\'usuari que ha donat ya existix (els demés canvis s\'aplicaran).'; $lang['start'] = 'primera'; $lang['prev'] = 'anterior'; $lang['next'] = 'següent'; -- cgit v1.2.3 From c70d6cee34ddc4be4dc136fe8421929100a13fd8 Mon Sep 17 00:00:00 2001 From: Andreas Gohr <andi@splitbrain.org> Date: Sat, 16 Feb 2013 20:24:25 +0100 Subject: disable additional auth plugins in installer --- install.php | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/install.php b/install.php index f54c25207..2db25bd2f 100644 --- a/install.php +++ b/install.php @@ -54,7 +54,8 @@ $dokuwiki_hash = array( '2011-05-25' => '4241865472edb6fa14a1227721008072', '2011-11-10' => 'b46ff19a7587966ac4df61cbab1b8b31', '2012-01-25' => '72c083c73608fc43c586901fd5dabb74', - '2012-09-10' => 'eb0b3fc90056fbc12bac6f49f7764df3' + '2012-09-10' => 'eb0b3fc90056fbc12bac6f49f7764df3', + 'devel' => '7b62b75245f57f122d3e0f8ed7989623', ); @@ -391,6 +392,24 @@ EOT; @touch(DOKU_INC.'data/cache/autosubmit.txt'); } + // disable auth plugins til needed + $output = <<<EOT +<?php +/* + * Local plugin enable/disable settings + * + * Auto-generated by install script + * Date: $now + */ + +\$plugins['authad'] = 0; +\$plugins['authldap'] = 0; +\$plugins['authmysql'] = 0; +\$plugins['authpgsql'] = 0; + +EOT; + $ok = $ok && fileWrite(DOKU_LOCAL.'plugins.local.php', $output); + return $ok; } -- cgit v1.2.3 From f76724a46dee840092905f3d819423ffd556f14e Mon Sep 17 00:00:00 2001 From: Tom N Harris <tnharris@whoopdedo.org> Date: Sat, 16 Feb 2013 16:07:00 -0500 Subject: Move inline diff headers into a vertical column. --- inc/DifferenceEngine.php | 19 +++++++++++-------- inc/html.php | 27 +++++++++++++++++++++------ 2 files changed, 32 insertions(+), 14 deletions(-) diff --git a/inc/DifferenceEngine.php b/inc/DifferenceEngine.php index 1b68cf6d3..1099f40eb 100644 --- a/inc/DifferenceEngine.php +++ b/inc/DifferenceEngine.php @@ -1070,11 +1070,13 @@ class TableDiffFormatter extends DiffFormatter { } function addedLine($line) { - return '<td>+</td><td '.HTMLDiff::css('diff-addedline').'>' . $line.'</td>'; + return '<td '.HTMLDiff::css('diff-lineheader').'>+</td>'. + '<td '.HTMLDiff::css('diff-addedline').'>' . $line.'</td>'; } function deletedLine($line) { - return '<td>-</td><td '.HTMLDiff::css('diff-deletedline').'>' . $line.'</td>'; + return '<td '.HTMLDiff::css('diff-lineheader').'>-</td>'. + '<td '.HTMLDiff::css('diff-deletedline').'>' . $line.'</td>'; } function emptyLine() { @@ -1082,7 +1084,8 @@ class TableDiffFormatter extends DiffFormatter { } function contextLine($line) { - return '<td> </td><td '.HTMLDiff::css('diff-context').'>'.$line.'</td>'; + return '<td '.HTMLDiff::css('diff-lineheader').'> </td>'. + '<td '.HTMLDiff::css('diff-context').'>'.$line.'</td>'; } function _added($lines) { @@ -1121,7 +1124,7 @@ class TableDiffFormatter extends DiffFormatter { * */ class InlineDiffFormatter extends DiffFormatter { - var $colspan = 4; + var $colspan = 2; function __construct() { $this->leading_context_lines = 2; @@ -1167,19 +1170,19 @@ class InlineDiffFormatter extends DiffFormatter { function _added($lines) { foreach ($lines as $line) { - print('<tr><td colspan="'.$this->colspan.'" '.HTMLDiff::css('diff-addedline').'>'. $line . "</td></tr>\n"); + print('<tr><td '.HTMLDiff::css('diff-lineheader').'>+</td><td colspan="'.($this->colspan-1).'" '.HTMLDiff::css('diff-addedline').'>'. $line . "</td></tr>\n"); } } function _deleted($lines) { foreach ($lines as $line) { - print('<tr><td colspan="'.$this->colspan.'" '.HTMLDiff::css('diff-deletedline').'><del>' . $line . "</del></td></tr>\n"); + print('<tr><td '.HTMLDiff::css('diff-lineheader').'>-</td><td colspan="'.($this->colspan-1).'" '.HTMLDiff::css('diff-deletedline').'><del>' . $line . "</del></td></tr>\n"); } } function _context($lines) { foreach ($lines as $line) { - print('<tr><td colspan="'.$this->colspan.'" '.HTMLDiff::css('diff-context').'>'.$line."</td></tr>\n"); + print('<tr><td '.HTMLDiff::css('diff-lineheader').'> </td><td colspan="'.($this->colspan-1).'" '.HTMLDiff::css('diff-context').'>'.$line."</td></tr>\n"); } } @@ -1188,7 +1191,7 @@ class InlineDiffFormatter extends DiffFormatter { $add = $diff->inline(); foreach ($add as $line) - print('<tr><td colspan="'.$this->colspan.'">'.$line."</td></tr>\n"); + print('<tr><td '.HTMLDiff::css('diff-lineheader').'>!</td><td colspan="'.($this->colspan-1).'">'.$line."</td></tr>\n"); } } diff --git a/inc/html.php b/inc/html.php index c2723bceb..78042cb8b 100644 --- a/inc/html.php +++ b/inc/html.php @@ -1003,14 +1003,16 @@ function html_backlinks(){ * @param string $r_rev Right revision * @param string $id Page id, if null $ID is used * @param bool $media If it is for media files + * @param bool $inline Return the header on a single line * @return array HTML snippets for diff header */ -function html_diff_head($l_rev, $r_rev, $id = null, $media = false) { +function html_diff_head($l_rev, $r_rev, $id = null, $media = false, $inline = false) { global $lang; if ($id === null) { global $ID; $id = $ID; } + $head_separator = $inline ? ' ' : '<br />'; $media_or_wikiFN = $media ? 'mediaFN' : 'wikiFN'; $ml_or_wl = $media ? 'ml' : 'wl'; $l_minor = $r_minor = ''; @@ -1032,7 +1034,7 @@ function html_diff_head($l_rev, $r_rev, $id = null, $media = false) { $l_head_title = ($media) ? dformat($l_rev) : $id.' ['.dformat($l_rev).']'; $l_head = '<a class="wikilink1" href="'.$ml_or_wl($id,"rev=$l_rev").'">'. $l_head_title.'</a>'. - '<br />'.$l_user.' '.$l_sum; + $head_separator.$l_user.' '.$l_sum; } if($r_rev){ @@ -1050,7 +1052,7 @@ function html_diff_head($l_rev, $r_rev, $id = null, $media = false) { $r_head_title = ($media) ? dformat($r_rev) : $id.' ['.dformat($r_rev).']'; $r_head = '<a class="wikilink1" href="'.$ml_or_wl($id,"rev=$r_rev").'">'. $r_head_title.'</a>'. - '<br />'.$r_user.' '.$r_sum; + $head_separator.$r_user.' '.$r_sum; }elseif($_rev = @filemtime($media_or_wikiFN($id))){ $_info = getRevisionInfo($id,$_rev,true, $media); if($_info['user']){ @@ -1067,7 +1069,7 @@ function html_diff_head($l_rev, $r_rev, $id = null, $media = false) { $r_head = '<a class="wikilink1" href="'.$ml_or_wl($id).'">'. $r_head_title.'</a> '. '('.$lang['current'].')'. - '<br />'.$_user.' '.$_sum; + $head_separator.$_user.' '.$_sum; }else{ $r_head = '— ('.$lang['current'].')'; } @@ -1160,7 +1162,7 @@ function html_diff($text='',$intro=true,$type=null){ } $r_text = rawWiki($ID,$r_rev); - list($l_head, $r_head, $l_minor, $r_minor) = html_diff_head($l_rev, $r_rev); + list($l_head, $r_head, $l_minor, $r_minor) = html_diff_head($l_rev, $r_rev, null, false, $type == 'inline'); } $df = new Diff(explode("\n",hsc($l_text)),explode("\n",hsc($r_text))); @@ -1205,6 +1207,18 @@ function html_diff($text='',$intro=true,$type=null){ ?> <div class="table"> <table class="diff diff_<?php echo $type?>"> + <?php if ($type == 'inline') { ?> + <tr> + <th>---</th><th <?php echo $l_minor?>> + <?php echo $l_head?> + </th> + </tr> + <tr> + <th>+++</th><th <?php echo $r_minor?>> + <?php echo $r_head?> + </th> + </tr> + <?php } else { ?> <tr> <th colspan="2" <?php echo $l_minor?>> <?php echo $l_head?> @@ -1213,7 +1227,8 @@ function html_diff($text='',$intro=true,$type=null){ <?php echo $r_head?> </th> </tr> - <?php echo html_insert_softbreaks($tdf->format($df)); ?> + <?php } + echo html_insert_softbreaks($tdf->format($df)); ?> </table> </div> <?php -- cgit v1.2.3 From 1015a57dff9a6f85b8e0534d280aa1e09945a598 Mon Sep 17 00:00:00 2001 From: Christopher Smith <chris@jalakai.co.uk> Date: Sat, 16 Feb 2013 21:08:09 +0000 Subject: FS#2415 add to mediamanager (refactor pageinfo() and shift MEDIAMANAGER_STARTED after mediainfo() sets up ) --- inc/common.php | 68 +++++++++++++++++++++++++++++++++--------------- lib/exe/mediamanager.php | 12 ++++----- 2 files changed, 53 insertions(+), 27 deletions(-) diff --git a/inc/common.php b/inc/common.php index 28b527633..d4265f78c 100644 --- a/inc/common.php +++ b/inc/common.php @@ -86,32 +86,20 @@ function formSecurityToken($print = true) { } /** - * Return info about the current document as associative - * array. + * Determine basic information for a request of $id * - * @author Andreas Gohr <andi@splitbrain.org> + * @param unknown_type $id + * @param unknown_type $httpClient */ -function pageinfo() { - global $ID; - global $REV; - global $RANGE; +function basicinfo($id, $htmlClient=true){ global $USERINFO; - global $lang; - - // include ID & REV not redundant, as some parts of DokuWiki may temporarily change $ID, e.g. p_wiki_xhtml - // FIXME ... perhaps it would be better to ensure the temporary changes weren't necessary - $info['id'] = $ID; - $info['rev'] = $REV; // set info about manager/admin status. $info['isadmin'] = false; $info['ismanager'] = false; if(isset($_SERVER['REMOTE_USER'])) { - $sub = new Subscription(); - $info['userinfo'] = $USERINFO; - $info['perm'] = auth_quickaclcheck($ID); - $info['subscribed'] = $sub->user_subscription(); + $info['perm'] = auth_quickaclcheck($id); $info['client'] = $_SERVER['REMOTE_USER']; if($info['perm'] == AUTH_ADMIN) { @@ -127,12 +115,40 @@ function pageinfo() { } } else { - $info['perm'] = auth_aclcheck($ID, '', null); + $info['perm'] = auth_aclcheck($id, '', null); $info['subscribed'] = false; $info['client'] = clientIP(true); } - $info['namespace'] = getNS($ID); + $info['namespace'] = getNS($id); + + // mobile detection + if ($htmlClient) { + $info['ismobile'] = clientismobile(); + } + + return $info; + } + +/** + * Return info about the current document as associative + * array. + * + * @author Andreas Gohr <andi@splitbrain.org> + */ +function pageinfo() { + global $ID; + global $REV; + global $RANGE; + global $lang; + + $info = basicinfo($ID); + + // include ID & REV not redundant, as some parts of DokuWiki may temporarily change $ID, e.g. p_wiki_xhtml + // FIXME ... perhaps it would be better to ensure the temporary changes weren't necessary + $info['id'] = $ID; + $info['rev'] = $REV; + $info['locked'] = checklock($ID); $info['filepath'] = fullpath(wikiFN($ID)); $info['exists'] = @file_exists($info['filepath']); @@ -210,8 +226,18 @@ function pageinfo() { } } - // mobile detection - $info['ismobile'] = clientismobile(); + return $info; +} + +/** + * Return information about the current media item as an associative array. + */ +function mediainfo(){ + global $NS; + global $IMG; + + $info = basicinfo("$NS:*"); + $info['image'] = $IMG; return $info; } diff --git a/lib/exe/mediamanager.php b/lib/exe/mediamanager.php index 04dd178cc..7e0543540 100644 --- a/lib/exe/mediamanager.php +++ b/lib/exe/mediamanager.php @@ -7,15 +7,11 @@ require_once(DOKU_INC.'inc/init.php'); - trigger_event('MEDIAMANAGER_STARTED',$tmp=array()); - session_write_close(); //close session - global $INPUT; // handle passed message if($INPUT->str('msg1')) msg(hsc($INPUT->str('msg1')),1); if($INPUT->str('err')) msg(hsc($INPUT->str('err')),-1); - // get namespace to display (either direct or from deletion order) if($INPUT->str('delete')){ $DEL = cleanID($INPUT->str('delete')); @@ -29,10 +25,14 @@ $NS = getNS($IMG); }else{ $NS = cleanID($INPUT->str('ns')); + $IMG = null; } - // check auth - $AUTH = auth_quickaclcheck("$NS:*"); + $INFO = mediainfo(); + $AUTH = $INFO['perm']; // shortcut for historical reasons + + trigger_event('MEDIAMANAGER_STARTED',$tmp=array()); + session_write_close(); //close session // do not display the manager if user does not have read access if($AUTH < AUTH_READ && !$fullscreen) { -- cgit v1.2.3 From 07a7d21ae65e4288a32498c9c87dec9a5e39aab9 Mon Sep 17 00:00:00 2001 From: Christopher Smith <chris@jalakai.co.uk> Date: Sat, 16 Feb 2013 21:11:40 +0000 Subject: fix a couple of diff issues: shouldn't be any need to html encode before finding diffs; move quantifier outside regex condition --- inc/html.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/inc/html.php b/inc/html.php index c2723bceb..6c42f6e7b 100644 --- a/inc/html.php +++ b/inc/html.php @@ -1163,7 +1163,7 @@ function html_diff($text='',$intro=true,$type=null){ list($l_head, $r_head, $l_minor, $r_minor) = html_diff_head($l_rev, $r_rev); } - $df = new Diff(explode("\n",hsc($l_text)),explode("\n",hsc($r_text))); + $df = new Diff(explode("\n",$l_text),explode("\n",$r_text)); if($type == 'inline'){ $tdf = new InlineDiffFormatter(); @@ -1238,8 +1238,8 @@ function html_softbreak_callback($match){ &\#?\\w{1,6};) # ... for html entities - we don't want to split them (ok to catch some invalid combinations) &\#?\\w{1,6}; # yes pattern - a quicker match for the html entity, since we know we have one | -[?/,&\#;:]+ # no pattern - any other group of 'special' characters to insert a breaking character after -) # end conditional expression +[?/,&\#;:] # no pattern - any other group of 'special' characters to insert a breaking character after +)+ # end conditional expression REGEX; return preg_replace('<'.$regex.'>xu','\0​',$match[0]); -- cgit v1.2.3 From c0e94f2ae82b91c9a8af05eea8443b37eef52ba7 Mon Sep 17 00:00:00 2001 From: Tom N Harris <tnharris@whoopdedo.org> Date: Sat, 16 Feb 2013 16:28:01 -0500 Subject: Monospace font for header prefix. --- inc/html.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/inc/html.php b/inc/html.php index 78042cb8b..420efd633 100644 --- a/inc/html.php +++ b/inc/html.php @@ -1209,12 +1209,12 @@ function html_diff($text='',$intro=true,$type=null){ <table class="diff diff_<?php echo $type?>"> <?php if ($type == 'inline') { ?> <tr> - <th>---</th><th <?php echo $l_minor?>> + <td>---</td><th <?php echo $l_minor?>> <?php echo $l_head?> </th> </tr> <tr> - <th>+++</th><th <?php echo $r_minor?>> + <td>+++</td><th <?php echo $r_minor?>> <?php echo $r_head?> </th> </tr> -- cgit v1.2.3 From 45970804e69e3d087fe19ad9cefaff0ef44be795 Mon Sep 17 00:00:00 2001 From: Klap-in <klapinklapin@gmail.com> Date: Sat, 16 Feb 2013 22:53:38 +0100 Subject: Complete metadata and defaults of auth plugin configs --- lib/plugins/authad/conf/default.php | 14 +++++++++++++ lib/plugins/authldap/conf/default.php | 20 ++++++++++++++---- lib/plugins/authldap/conf/metadata.php | 1 + lib/plugins/authldap/lang/en/settings.php | 5 ++++- lib/plugins/authmysql/conf/default.php | 33 +++++++++++++++++++++++++++++- lib/plugins/authmysql/conf/metadata.php | 1 + lib/plugins/authmysql/lang/en/settings.php | 1 + lib/plugins/authpgsql/conf/default.php | 32 ++++++++++++++++++++++++++++- 8 files changed, 100 insertions(+), 7 deletions(-) create mode 100644 lib/plugins/authad/conf/default.php diff --git a/lib/plugins/authad/conf/default.php b/lib/plugins/authad/conf/default.php new file mode 100644 index 000000000..05d6c328e --- /dev/null +++ b/lib/plugins/authad/conf/default.php @@ -0,0 +1,14 @@ +<?php + +$conf['account_suffix'] = ''; +$conf['base_dn'] = ''; +$conf['domain_controllers'] = ''; +$conf['sso'] = 0; +$conf['ad_username'] = ''; +$conf['ad_password'] = ''; +$conf['real_primarygroup'] = 0; +$conf['use_ssl'] = 0; +$conf['use_tls'] = 0; +$conf['debug'] = 0; +$conf['expirywarn'] = 0; +$conf['additional'] = ''; \ No newline at end of file diff --git a/lib/plugins/authldap/conf/default.php b/lib/plugins/authldap/conf/default.php index 35971d41d..d07f9c82e 100644 --- a/lib/plugins/authldap/conf/default.php +++ b/lib/plugins/authldap/conf/default.php @@ -1,7 +1,19 @@ <?php -$conf['port'] = 389; - -$conf['groupkey'] = 'cn'; +$conf['server'] = ''; +$conf['port'] = 389; +$conf['usertree'] = ''; +$conf['grouptree'] = ''; +$conf['userfilter'] = ''; +$conf['groupfilter'] = ''; +$conf['version'] = 2; +$conf['starttls'] = 0; +$conf['referrals'] = 0; +$conf['binddn'] = ''; +$conf['bindpw'] = ''; +//$conf['mapping']['name'] unsupported in config manager +//$conf['mapping']['grps'] unsupported in config manager $conf['userscope'] = 'sub'; -$conf['groupscope'] = 'sub'; \ No newline at end of file +$conf['groupscope'] = 'sub'; +$conf['groupkey'] = 'cn'; +$conf['debug'] = array('onoff'); \ No newline at end of file diff --git a/lib/plugins/authldap/conf/metadata.php b/lib/plugins/authldap/conf/metadata.php index e0815f789..fc5b2e63c 100644 --- a/lib/plugins/authldap/conf/metadata.php +++ b/lib/plugins/authldap/conf/metadata.php @@ -14,4 +14,5 @@ $meta['bindpw'] = array('password'); //$meta['mapping']['grps'] unsupported in config manager $meta['userscope'] = array('multichoice','_choices' => array('sub','one','base')); $meta['groupscope'] = array('multichoice','_choices' => array('sub','one','base')); +$meta['groupkey'] = array('string'); $meta['debug'] = array('onoff'); \ No newline at end of file diff --git a/lib/plugins/authldap/lang/en/settings.php b/lib/plugins/authldap/lang/en/settings.php index e3f4bab31..f20b7d2a3 100644 --- a/lib/plugins/authldap/lang/en/settings.php +++ b/lib/plugins/authldap/lang/en/settings.php @@ -12,4 +12,7 @@ $lang['binddn'] = 'DN of an ptional bind user if anonymous bind is not suff $lang['bindpw'] = 'Password of above user'; $lang['userscope'] = 'Limit search scope for user search'; $lang['groupscope'] = 'Limit search scope for group search'; -$lang['debug'] = 'Display additional debug information on errors'; \ No newline at end of file +$lang['groupkey'] = 'Group member ship from any user attribute (instead of standard AD groups) e.g. group from department or telephone number'; +$lang['debug'] = 'Display additional debug information on errors'; + + diff --git a/lib/plugins/authmysql/conf/default.php b/lib/plugins/authmysql/conf/default.php index ea2cdad72..4add3f57c 100644 --- a/lib/plugins/authmysql/conf/default.php +++ b/lib/plugins/authmysql/conf/default.php @@ -1,3 +1,34 @@ <?php -$conf['charset'] = 'utf8'; \ No newline at end of file +$conf['charset'] = 'utf8'; +$conf['server'] = ''; +$conf['user'] =''; +$conf['password'] = ''; +$conf['database'] = ''; +$conf['debug'] = 0; +$conf['forwardClearPass'] = 0; +$conf['TablesToLock'] = ''; +$conf['checkPass'] = ''; +$conf['getUserInfo'] = ''; +$conf['getGroups'] = ''; +$conf['getUsers'] = ''; +$conf['FilterLogin'] = ''; +$conf['FilterName'] = ''; +$conf['FilterEmail'] = ''; +$conf['FilterGroup'] = ''; +$conf['SortOrder'] = ''; +$conf['addUser'] = ''; +$conf['addGroup'] = ''; +$conf['addUserGroup'] = ''; +$conf['delGroup'] = ''; +$conf['getUserID'] = ''; +$conf['delUser'] = ''; +$conf['delUserRefs'] = ''; +$conf['updateUser'] = ''; +$conf['UpdateLogin'] = ''; +$conf['UpdatePass'] = ''; +$conf['UpdateEmail'] = ''; +$conf['UpdateName'] = ''; +$conf['UpdateTarget'] = ''; +$conf['delUserGroup'] = ''; +$conf['getGroupID'] = ''; \ No newline at end of file diff --git a/lib/plugins/authmysql/conf/metadata.php b/lib/plugins/authmysql/conf/metadata.php index f63bbe481..05d150fdf 100644 --- a/lib/plugins/authmysql/conf/metadata.php +++ b/lib/plugins/authmysql/conf/metadata.php @@ -4,6 +4,7 @@ $meta['server'] = array('string'); $meta['user'] = array('string'); $meta['password'] = array('password'); $meta['database'] = array('string'); +$meta['charset'] = array('string'); $meta['debug'] = array('multichoice','_choices' => array(0,1,2)); $meta['forwardClearPass'] = array('onoff'); $meta['TablesToLock'] = array('array'); diff --git a/lib/plugins/authmysql/lang/en/settings.php b/lib/plugins/authmysql/lang/en/settings.php index dcdbbb16b..7b409ee1c 100644 --- a/lib/plugins/authmysql/lang/en/settings.php +++ b/lib/plugins/authmysql/lang/en/settings.php @@ -4,6 +4,7 @@ $lang['server'] = 'Your MySQL server'; $lang['user'] = 'MySQL user name'; $lang['password'] = 'Password for above user'; $lang['database'] = 'Database to use'; +$lang['charset'] = 'Character set used in database'; $lang['debug'] = 'Display additional debug information'; $lang['forwardClearPass'] = 'Pass user passwords as cleartext to the SQL statements below, instead of using the passcrypt option'; $lang['TablesToLock'] = 'Comma separated list of tables that should be locked on write operations'; diff --git a/lib/plugins/authpgsql/conf/default.php b/lib/plugins/authpgsql/conf/default.php index 401da80b7..7f78280f9 100644 --- a/lib/plugins/authpgsql/conf/default.php +++ b/lib/plugins/authpgsql/conf/default.php @@ -1,3 +1,33 @@ <?php -$conf['port'] = 5432; \ No newline at end of file +$conf['server'] = ''; +$conf['port'] = 5432; +$conf['user'] = ''; +$conf['password'] = ''; +$conf['database'] = ''; +$conf['debug'] = 0; +$conf['forwardClearPass'] = 0; +$conf['checkPass'] = ''; +$conf['getUserInfo'] = ''; +$conf['getGroups'] = ''; +$conf['getUsers'] = ''; +$conf['FilterLogin'] = ''; +$conf['FilterName'] = ''; +$conf['FilterEmail'] = ''; +$conf['FilterGroup'] = ''; +$conf['SortOrder'] = ''; +$conf['addUser'] = ''; +$conf['addGroup'] = ''; +$conf['addUserGroup'] = ''; +$conf['delGroup'] = ''; +$conf['getUserID'] = ''; +$conf['delUser'] = ''; +$conf['delUserRefs'] = ''; +$conf['updateUser'] = ''; +$conf['UpdateLogin'] = ''; +$conf['UpdatePass'] = ''; +$conf['UpdateEmail'] = ''; +$conf['UpdateName'] = ''; +$conf['UpdateTarget'] = ''; +$conf['delUserGroup'] = ''; +$conf['getGroupID'] = ''; \ No newline at end of file -- cgit v1.2.3 From a0e625181ad2e2369e8db0e5691f7356363776d0 Mon Sep 17 00:00:00 2001 From: Klap-in <klapinklapin@gmail.com> Date: Sat, 16 Feb 2013 23:03:01 +0100 Subject: separate default settings from non-existing settings setting type read from metadata eqaul to empty string is default 'setting' class (a textarea), everything else should be a existing class otherwise 'setting_no_class' is loaded --- lib/plugins/config/settings/config.class.php | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/lib/plugins/config/settings/config.class.php b/lib/plugins/config/settings/config.class.php index 16be9a689..a3cfae9f8 100644 --- a/lib/plugins/config/settings/config.class.php +++ b/lib/plugins/config/settings/config.class.php @@ -70,9 +70,14 @@ if (!class_exists('configuration')) { foreach ($keys as $key) { if (isset($this->_metadata[$key])) { $class = $this->_metadata[$key][0]; - $class = ($class && class_exists('setting_'.$class)) ? 'setting_'.$class : 'setting'; - if ($class=='setting') { - $this->setting[] = new setting_no_class($key,$param); + + if($class && class_exists('setting_'.$class)){ + $class = 'setting_'.$class; + } else { + if($class != '') { + $this->setting[] = new setting_no_class($key,$param); + } + $class = 'setting'; } $param = $this->_metadata[$key]; -- cgit v1.2.3 From 4005b0809260fbd36cb8652c7d726a5ee417c6f6 Mon Sep 17 00:00:00 2001 From: Anika Henke <anika@selfthinker.org> Date: Sat, 16 Feb 2013 19:42:38 +0000 Subject: fixed html error in plugin lang file --- lib/plugins/authldap/lang/en/settings.php | 4 ++-- lib/plugins/config/lang/en/intro.txt | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/plugins/authldap/lang/en/settings.php b/lib/plugins/authldap/lang/en/settings.php index e3f4bab31..cc9143169 100644 --- a/lib/plugins/authldap/lang/en/settings.php +++ b/lib/plugins/authldap/lang/en/settings.php @@ -3,8 +3,8 @@ $lang['server'] = 'Your LDAP server. Either hostname (<code>localhost</code $lang['port'] = 'LDAP server port if no full URL was given above'; $lang['usertree'] = 'Where to finde the user accounts. Eg. <code>ou=People, dc=server, dc=tld</code>'; $lang['grouptree'] = 'Where to find the user groups. Eg. <code>ou=Group, dc=server, dc=tld</code>'; -$lang['userfilter'] = 'LDAP filter to search for user accounts. Eg. <code>(&(uid=%{user})(objectClass=posixAccount))</code>'; -$lang['groupfilter'] = 'LDAP filter to search for groups. Eg. <code>(&(objectClass=posixGroup)(|(gidNumber=%{gid})(memberUID=%{user})))</code>'; +$lang['userfilter'] = 'LDAP filter to search for user accounts. Eg. <code>(&(uid=%{user})(objectClass=posixAccount))</code>'; +$lang['groupfilter'] = 'LDAP filter to search for groups. Eg. <code>(&(objectClass=posixGroup)(|(gidNumber=%{gid})(memberUID=%{user})))</code>'; $lang['version'] = 'The protocol version to use. You may need to set this to <code>3</code>'; $lang['starttls'] = 'Use TLS connections?'; $lang['referrals'] = 'Shall referrals be followed?'; diff --git a/lib/plugins/config/lang/en/intro.txt b/lib/plugins/config/lang/en/intro.txt index c83a80205..7cf46cee3 100644 --- a/lib/plugins/config/lang/en/intro.txt +++ b/lib/plugins/config/lang/en/intro.txt @@ -4,6 +4,6 @@ Use this page to control the settings of your DokuWiki installation. For help o Settings shown with a light red background are protected and can not be altered with this plugin. Settings shown with a blue background are the default values and settings shown with a white background have been set locally for this particular installation. Both blue and white settings can be altered. -Remember to press the **SAVE** button before leaving this page otherwise your changes will be lost. +Remember to press the **Save** button before leaving this page otherwise your changes will be lost. -- cgit v1.2.3 From 5ebd6fd9156e1bc9b63132f3ec5989856e5a45a1 Mon Sep 17 00:00:00 2001 From: Klap-in <klapinklapin@gmail.com> Date: Sat, 16 Feb 2013 23:55:52 +0100 Subject: litte fixes --- lib/plugins/authldap/lang/en/settings.php | 2 -- lib/plugins/authmysql/conf/default.php | 2 +- lib/plugins/authmysql/lang/en/settings.php | 2 +- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/plugins/authldap/lang/en/settings.php b/lib/plugins/authldap/lang/en/settings.php index bca666e9f..0bb397be5 100644 --- a/lib/plugins/authldap/lang/en/settings.php +++ b/lib/plugins/authldap/lang/en/settings.php @@ -14,5 +14,3 @@ $lang['userscope'] = 'Limit search scope for user search'; $lang['groupscope'] = 'Limit search scope for group search'; $lang['groupkey'] = 'Group member ship from any user attribute (instead of standard AD groups) e.g. group from department or telephone number'; $lang['debug'] = 'Display additional debug information on errors'; - - diff --git a/lib/plugins/authmysql/conf/default.php b/lib/plugins/authmysql/conf/default.php index 4add3f57c..647f3d96c 100644 --- a/lib/plugins/authmysql/conf/default.php +++ b/lib/plugins/authmysql/conf/default.php @@ -2,7 +2,7 @@ $conf['charset'] = 'utf8'; $conf['server'] = ''; -$conf['user'] =''; +$conf['user'] = ''; $conf['password'] = ''; $conf['database'] = ''; $conf['debug'] = 0; diff --git a/lib/plugins/authmysql/lang/en/settings.php b/lib/plugins/authmysql/lang/en/settings.php index 7b409ee1c..77e4806b9 100644 --- a/lib/plugins/authmysql/lang/en/settings.php +++ b/lib/plugins/authmysql/lang/en/settings.php @@ -21,7 +21,7 @@ $lang['addUser'] = 'SQL statement to add a new user'; $lang['addGroup'] = 'SQL statement to add a new group'; $lang['addUserGroup'] = 'SQL statment to add a user to an existing group'; $lang['delGroup'] = 'SQL statement to remove a group'; -$lang['getUserID'] = 'SQL statement to get the primary ey of a user'; +$lang['getUserID'] = 'SQL statement to get the primary key of a user'; $lang['delUser'] = 'SQL statement to delete a user'; $lang['delUserRefs'] = 'SQL statement to remove a user from all groups'; $lang['updateUser'] = 'SQL statement to update a user profile'; -- cgit v1.2.3 From 56133a04d1c5dcd4825f4c0c978b8a9336d603d0 Mon Sep 17 00:00:00 2001 From: Tom N Harris <tnharris@whoopdedo.org> Date: Sat, 16 Feb 2013 18:15:13 -0500 Subject: Fix width of indicator column. --- inc/DifferenceEngine.php | 10 +++++----- inc/html.php | 4 ++-- lib/tpl/default/design.css | 12 +++++++++++- lib/tpl/dokuwiki/css/_diff.css | 12 +++++++++++- 4 files changed, 29 insertions(+), 9 deletions(-) diff --git a/inc/DifferenceEngine.php b/inc/DifferenceEngine.php index 1099f40eb..2125ad879 100644 --- a/inc/DifferenceEngine.php +++ b/inc/DifferenceEngine.php @@ -1151,7 +1151,7 @@ class InlineDiffFormatter extends DiffFormatter { $xbeg .= "," . $xlen; if ($ylen != 1) $ybeg .= "," . $ylen; - $r = '<tr><td colspan="'.$this->colspan.'" '.HTMLDiff::css('diff-blockheader').'>@@ '.$lang['line']." -$xbeg +$ybeg @@"; + $r = '<tr><td colspan="2" '.HTMLDiff::css('diff-blockheader').'>@@ '.$lang['line']." -$xbeg +$ybeg @@"; $r .= ' <span '.HTMLDiff::css('diff-deletedline').'><del>'.$lang['deleted'].'</del></span>'; $r .= ' <span '.HTMLDiff::css('diff-addedline').'>'.$lang['created'].'</span>'; $r .= "</td></tr>\n"; @@ -1170,19 +1170,19 @@ class InlineDiffFormatter extends DiffFormatter { function _added($lines) { foreach ($lines as $line) { - print('<tr><td '.HTMLDiff::css('diff-lineheader').'>+</td><td colspan="'.($this->colspan-1).'" '.HTMLDiff::css('diff-addedline').'>'. $line . "</td></tr>\n"); + print('<tr><td '.HTMLDiff::css('diff-lineheader').'>+</td><td '.HTMLDiff::css('diff-addedline').'>'. $line . "</td></tr>\n"); } } function _deleted($lines) { foreach ($lines as $line) { - print('<tr><td '.HTMLDiff::css('diff-lineheader').'>-</td><td colspan="'.($this->colspan-1).'" '.HTMLDiff::css('diff-deletedline').'><del>' . $line . "</del></td></tr>\n"); + print('<tr><td '.HTMLDiff::css('diff-lineheader').'>-</td><td '.HTMLDiff::css('diff-deletedline').'><del>' . $line . "</del></td></tr>\n"); } } function _context($lines) { foreach ($lines as $line) { - print('<tr><td '.HTMLDiff::css('diff-lineheader').'> </td><td colspan="'.($this->colspan-1).'" '.HTMLDiff::css('diff-context').'>'.$line."</td></tr>\n"); + print('<tr><td '.HTMLDiff::css('diff-lineheader').'> </td><td '.HTMLDiff::css('diff-context').'>'.$line."</td></tr>\n"); } } @@ -1191,7 +1191,7 @@ class InlineDiffFormatter extends DiffFormatter { $add = $diff->inline(); foreach ($add as $line) - print('<tr><td '.HTMLDiff::css('diff-lineheader').'>!</td><td colspan="'.($this->colspan-1).'">'.$line."</td></tr>\n"); + print('<tr><td '.HTMLDiff::css('diff-lineheader').'>!</td><td>'.$line."</td></tr>\n"); } } diff --git a/inc/html.php b/inc/html.php index 420efd633..e657d2c78 100644 --- a/inc/html.php +++ b/inc/html.php @@ -1209,12 +1209,12 @@ function html_diff($text='',$intro=true,$type=null){ <table class="diff diff_<?php echo $type?>"> <?php if ($type == 'inline') { ?> <tr> - <td>---</td><th <?php echo $l_minor?>> + <th class="diff-lineheader">-</th><th <?php echo $l_minor?>> <?php echo $l_head?> </th> </tr> <tr> - <td>+++</td><th <?php echo $r_minor?>> + <th class="diff-lineheader">+</th><th <?php echo $r_minor?>> <?php echo $r_head?> </th> </tr> diff --git a/lib/tpl/default/design.css b/lib/tpl/default/design.css index 3405ec258..4772fd2a5 100644 --- a/lib/tpl/default/design.css +++ b/lib/tpl/default/design.css @@ -632,7 +632,6 @@ div.dokuwiki td.diff-blockheader { div.dokuwiki table.diff th { border-bottom: 1px solid __border__; font-size: 110%; - width: 50%; font-weight: normal; text-align: left; } @@ -650,6 +649,17 @@ div.dokuwiki table.diff th span.sum { div.dokuwiki table.diff th.minor { font-style: italic; } +.dokuwiki table.diff_sidebyside th { + width: 50%; +} +.dokuwiki table.diff .diff-lineheader { + width: .7em; + text-align: right; +} +[dir=rtl] .dokuwiki table.diff .diff-lineheader { + text-align: left; +} +.dokuwiki table.diff .diff-lineheader, div.dokuwiki table.diff td { font-family: monospace; font-size: 100%; diff --git a/lib/tpl/dokuwiki/css/_diff.css b/lib/tpl/dokuwiki/css/_diff.css index 62f831213..58c24b5c7 100644 --- a/lib/tpl/dokuwiki/css/_diff.css +++ b/lib/tpl/dokuwiki/css/_diff.css @@ -21,7 +21,6 @@ .dokuwiki table.diff th { border-bottom: 1px solid __border__; font-size: 110%; - width: 50%; font-weight: normal; } .dokuwiki table.diff th a { @@ -37,8 +36,19 @@ .dokuwiki table.diff th.minor { color: #999; } +.dokuwiki table.diff_sidebyside th { + width: 50%; +} /* table body */ +.dokuwiki table.diff .diff-lineheader { + width: .7em; + text-align: right; +} +[dir=rtl] .dokuwiki table.diff .diff-lineheader { + text-align: left; +} +.dokuwiki table.diff .diff-lineheader, .dokuwiki table.diff td { font-family: Consolas, "Andale Mono WT", "Andale Mono", "Bitstream Vera Sans Mono", "Nimbus Mono L", Monaco, "Courier New", monospace; } -- cgit v1.2.3 From a69506c52fbd9c92500be4f380acc7e68d4d6560 Mon Sep 17 00:00:00 2001 From: Tom N Harris <tnharris@whoopdedo.org> Date: Sat, 16 Feb 2013 18:27:12 -0500 Subject: Remove the prefix from inline diffs. The line prefix was not actually indicating what it should indicate. In particular, anything in a "changed" block would show a "!" even if the entire line was added or deleted. Better to print nothing than something that's wrong. --- inc/DifferenceEngine.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/inc/DifferenceEngine.php b/inc/DifferenceEngine.php index 2125ad879..c15c8b163 100644 --- a/inc/DifferenceEngine.php +++ b/inc/DifferenceEngine.php @@ -1170,13 +1170,13 @@ class InlineDiffFormatter extends DiffFormatter { function _added($lines) { foreach ($lines as $line) { - print('<tr><td '.HTMLDiff::css('diff-lineheader').'>+</td><td '.HTMLDiff::css('diff-addedline').'>'. $line . "</td></tr>\n"); + print('<tr><td '.HTMLDiff::css('diff-lineheader').'> </td><td '.HTMLDiff::css('diff-addedline').'>'. $line . "</td></tr>\n"); } } function _deleted($lines) { foreach ($lines as $line) { - print('<tr><td '.HTMLDiff::css('diff-lineheader').'>-</td><td '.HTMLDiff::css('diff-deletedline').'><del>' . $line . "</del></td></tr>\n"); + print('<tr><td '.HTMLDiff::css('diff-lineheader').'> </td><td '.HTMLDiff::css('diff-deletedline').'><del>' . $line . "</del></td></tr>\n"); } } @@ -1191,7 +1191,7 @@ class InlineDiffFormatter extends DiffFormatter { $add = $diff->inline(); foreach ($add as $line) - print('<tr><td '.HTMLDiff::css('diff-lineheader').'>!</td><td>'.$line."</td></tr>\n"); + print('<tr><td '.HTMLDiff::css('diff-lineheader').'> </td><td>'.$line."</td></tr>\n"); } } -- cgit v1.2.3 From 60056e697fb1666e9b491b6f9f5654b694e3b8c9 Mon Sep 17 00:00:00 2001 From: Christopher Smith <chris@jalakai.co.uk> Date: Sun, 17 Feb 2013 14:56:12 +0000 Subject: ensure diff formatters escape their output --- inc/DifferenceEngine.php | 58 +++++++++++++++++++++++++++++++++++------------- 1 file changed, 42 insertions(+), 16 deletions(-) diff --git a/inc/DifferenceEngine.php b/inc/DifferenceEngine.php index 1b68cf6d3..42975b208 100644 --- a/inc/DifferenceEngine.php +++ b/inc/DifferenceEngine.php @@ -797,7 +797,7 @@ class DiffFormatter { function _lines($lines, $prefix = ' ') { foreach ($lines as $line) - echo "$prefix $line\n"; + echo "$prefix ".$this->_escape($line)."\n"; } function _context($lines) { @@ -816,6 +816,10 @@ class DiffFormatter { echo "---\n"; $this->_added($closing); } + + function _escape($str){ + return $str; + } } /** @@ -871,13 +875,13 @@ class _HWLDF_WordAccumulator { function _flushGroup($new_tag) { if ($this->_group !== '') { if ($this->_tag == 'mark') - $this->_line .= '<strong '.HTMLDiff::css('diff-mark').'>'.$this->_group.'</strong>'; + $this->_line .= '<strong '.HTMLDiff::css('diff-mark').'>'.$this->_escape($this->_group).'</strong>'; elseif ($this->_tag == 'add') - $this->_line .= '<span '.HTMLDiff::css('diff-addedline').'>'.$this->_group.'</span>'; + $this->_line .= '<span '.HTMLDiff::css('diff-addedline').'>'.$this->_escape($this->_group).'</span>'; elseif ($this->_tag == 'del') - $this->_line .= '<span '.HTMLDiff::css('diff-deletedline').'><del>'.$this->_group.'</del></span>'; + $this->_line .= '<span '.HTMLDiff::css('diff-deletedline').'><del>'.$this->_escape($this->_group).'</del></span>'; else - $this->_line .= $this->_group; + $this->_line .= $this->_escape($this->_group); } $this->_group = ''; $this->_tag = $new_tag; @@ -912,6 +916,10 @@ class _HWLDF_WordAccumulator { $this->_flushLine('~done'); return $this->_lines; } + + function _escape($str){ + return hsc($str); + } } class WordLevelDiff extends MappedDiff { @@ -1069,11 +1077,17 @@ class TableDiffFormatter extends DiffFormatter { function _lines($lines, $prefix=' ', $color="white") { } - function addedLine($line) { + function addedLine($line,$escaped=false) { + if (!$escaped){ + $line = $this->_escape($line); + } return '<td>+</td><td '.HTMLDiff::css('diff-addedline').'>' . $line.'</td>'; } - function deletedLine($line) { + function deletedLine($line,$escaped=false) { + if (!$escaped){ + $line = $this->_escape($line); + } return '<td>-</td><td '.HTMLDiff::css('diff-deletedline').'>' . $line.'</td>'; } @@ -1082,12 +1096,16 @@ class TableDiffFormatter extends DiffFormatter { } function contextLine($line) { - return '<td> </td><td '.HTMLDiff::css('diff-context').'>'.$line.'</td>'; + return '<td> </td><td '.HTMLDiff::css('diff-context').'>'.$this->_escape($line).'</td>'; } function _added($lines) { + $this->_addedLines($lines,false); + } + + function _addedLines($lines,$escaped=false){ foreach ($lines as $line) { - print('<tr>' . $this->emptyLine() . $this->addedLine($line) . "</tr>\n"); + print('<tr>' . $this->emptyLine() . $this->addedLine($line,$escaped) . "</tr>\n"); } } @@ -1104,15 +1122,19 @@ class TableDiffFormatter extends DiffFormatter { } function _changed($orig, $closing) { - $diff = new WordLevelDiff($orig, $closing); + $diff = new WordLevelDiff($orig, $closing); // this escapes the diff data $del = $diff->orig(); $add = $diff->closing(); while ($line = array_shift($del)) { $aline = array_shift($add); - print('<tr>' . $this->deletedLine($line) . $this->addedLine($aline) . "</tr>\n"); + print('<tr>' . $this->deletedLine($line,true) . $this->addedLine($aline,true) . "</tr>\n"); } - $this->_added($add); # If any leftovers + $this->_addedLines($add,true); # If any leftovers + } + + function _escape($str) { + return hsc($str); } } @@ -1167,29 +1189,33 @@ class InlineDiffFormatter extends DiffFormatter { function _added($lines) { foreach ($lines as $line) { - print('<tr><td colspan="'.$this->colspan.'" '.HTMLDiff::css('diff-addedline').'>'. $line . "</td></tr>\n"); + print('<tr><td colspan="'.$this->colspan.'" '.HTMLDiff::css('diff-addedline').'>'. $this->_escape($line) . "</td></tr>\n"); } } function _deleted($lines) { foreach ($lines as $line) { - print('<tr><td colspan="'.$this->colspan.'" '.HTMLDiff::css('diff-deletedline').'><del>' . $line . "</del></td></tr>\n"); + print('<tr><td colspan="'.$this->colspan.'" '.HTMLDiff::css('diff-deletedline').'><del>' . $this->_escape($line) . "</del></td></tr>\n"); } } function _context($lines) { foreach ($lines as $line) { - print('<tr><td colspan="'.$this->colspan.'" '.HTMLDiff::css('diff-context').'>'.$line."</td></tr>\n"); + print('<tr><td colspan="'.$this->colspan.'" '.HTMLDiff::css('diff-context').'>'.$this->_escape($line)."</td></tr>\n"); } } function _changed($orig, $closing) { - $diff = new InlineWordLevelDiff($orig, $closing); + $diff = new InlineWordLevelDiff($orig, $closing); // this escapes the diff data $add = $diff->inline(); foreach ($add as $line) print('<tr><td colspan="'.$this->colspan.'">'.$line."</td></tr>\n"); } + + function _escape($str) { + return hsc($str); + } } -- cgit v1.2.3 From 0fc50f81064736071e053d874b60a990fd1af8c2 Mon Sep 17 00:00:00 2001 From: Christopher Smith <chris@jalakai.co.uk> Date: Sun, 17 Feb 2013 15:47:42 +0000 Subject: add property to show disabled plugins, set it to false (to hide by default) --- lib/plugins/config/settings/config.class.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/plugins/config/settings/config.class.php b/lib/plugins/config/settings/config.class.php index 5b81be782..46e27654b 100644 --- a/lib/plugins/config/settings/config.class.php +++ b/lib/plugins/config/settings/config.class.php @@ -20,6 +20,7 @@ if (!class_exists('configuration')) { var $_metadata = array(); // holds metadata describing the settings var $setting = array(); // array of setting objects var $locked = false; // configuration is considered locked if it can't be updated + var $show_disabled_plugins = false; // configuration filenames var $_default_files = array(); @@ -262,7 +263,7 @@ if (!class_exists('configuration')) { function get_plugin_list() { if (is_null($this->_plugin_list)) { - $list = plugin_list('',true); // all plugins, including disabled ones + $list = plugin_list('',$this->show_disabled_plugins); // remove this plugin from the list $idx = array_search('config',$list); -- cgit v1.2.3 From aae735fc981470a44856ec34a838c4910ac68062 Mon Sep 17 00:00:00 2001 From: Christopher Smith <chris@jalakai.co.uk> Date: Sun, 17 Feb 2013 16:54:23 +0000 Subject: tidy up authtype setting class (incl. fix issue with auth change/logoff occurring when only one auth plugin is enabled and other settings are updated) --- lib/plugins/config/settings/extra.class.php | 74 +++++++++++++---------------- 1 file changed, 34 insertions(+), 40 deletions(-) diff --git a/lib/plugins/config/settings/extra.class.php b/lib/plugins/config/settings/extra.class.php index 6998e1fbf..e4b97eb01 100644 --- a/lib/plugins/config/settings/extra.class.php +++ b/lib/plugins/config/settings/extra.class.php @@ -43,56 +43,50 @@ if (!class_exists('setting_authtype')) { class setting_authtype extends setting_multichoice { function initialize($default,$local,$protected) { - global $plugin_controller; + global $plugin_controller; - // retrive auth types provided by plugins - foreach ($plugin_controller->getList('auth') as $plugin) { - $this->_choices[] = $plugin; - } + // retrieve auth types provided by plugins + foreach ($plugin_controller->getList('auth') as $plugin) { + $this->_choices[] = $plugin; + } - parent::initialize($default,$local,$protected); + parent::initialize($default,$local,$protected); } function update($input) { - global $plugin_controller; - - // is an update posible? - $mayUpdate = parent::update($input); - - // is it an auth plugin? - if (in_array($input, $plugin_controller->getList('auth'))) { - // reject disabled plugins - if ($plugin_controller->isdisabled($input)) { - $this->_error = true; - msg('Auth type ' . $input . ' is disabled.', -1); - return false; - } - - // load the plugin - $auth_plugin = $plugin_controller->load('auth', $input); - - // @TODO: throw an error in plugin controller instead of returning null - if (is_null($auth_plugin)) { - $this->_error = true; - msg('Cannot load Auth Plugin "' . $input . '"', -1); - return false; - } - - // verify proper instanciation (is this really a plugin?) @TODO use instanceof? impement interface? - if (is_object($auth_plugin) && !method_exists($auth_plugin, 'getPluginName')) { - $this->_error = true; - msg('Cannot create Auth Plugin "' . $input . '"', -1); - return false; - } - } + global $plugin_controller; + + // is an update possible/requested? + $local = $this->_local; // save this, parent::update() may change it + if (!parent::update($input)) return false; // nothing changed or an error caught by parent + $this->_local = $local; // restore original, more error checking to come + + // attempt to load the plugin + $auth_plugin = $plugin_controller->load('auth', $input); + + // @TODO: throw an error in plugin controller instead of returning null + if (is_null($auth_plugin)) { + $this->_error = true; + msg('Cannot load Auth Plugin "' . $input . '"', -1); + return false; + } + + // verify proper instantiation (is this really a plugin?) @TODO use instanceof? implement interface? + if (is_object($auth_plugin) && !method_exists($auth_plugin, 'getPluginName')) { + $this->_error = true; + msg('Cannot create Auth Plugin "' . $input . '"', -1); + return false; + } // did we change the auth type? logout global $conf; if($conf['authtype'] != $input) { - msg('Authentication system changed. Please re-login.'); - auth_logoff(); + msg('Authentication system changed. Please re-login.'); + auth_logoff(); } - return true; + + $this->_local = $input; + return true; } } } -- cgit v1.2.3 From 22b77eded0c1fe0f6866972d97895a9e9dc26a1f Mon Sep 17 00:00:00 2001 From: Christopher Smith <chris@jalakai.co.uk> Date: Sun, 17 Feb 2013 16:55:12 +0000 Subject: improve comments on settings::update() method --- lib/plugins/config/settings/config.class.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/plugins/config/settings/config.class.php b/lib/plugins/config/settings/config.class.php index 46e27654b..8be53b145 100644 --- a/lib/plugins/config/settings/config.class.php +++ b/lib/plugins/config/settings/config.class.php @@ -388,10 +388,12 @@ if (!class_exists('setting')) { } /** - * update setting with user provided value $input - * if value fails error check, save it + * update changed setting with user provided value $input + * - if changed value fails error check, save it to $this->_input (to allow echoing later) + * - if changed value passes error check, set $this->_local to the new value * - * @return boolean true if changed, false otherwise (incl. on error) + * @param mixed $input the new value + * @return boolean true if changed, false otherwise (incl. on error) */ function update($input) { if (is_null($input)) return false; -- cgit v1.2.3 From 3a4ea35cfcc40e754577cb6a1e41442d14b6a0a6 Mon Sep 17 00:00:00 2001 From: Christopher Smith <chris@jalakai.co.uk> Date: Sun, 17 Feb 2013 19:30:55 +0000 Subject: replace remaining hardcoded 'colspan' values with ->colspan --- inc/DifferenceEngine.php | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/inc/DifferenceEngine.php b/inc/DifferenceEngine.php index f6ed9aa13..e0fbf8e03 100644 --- a/inc/DifferenceEngine.php +++ b/inc/DifferenceEngine.php @@ -1037,6 +1037,7 @@ class UnifiedDiffFormatter extends DiffFormatter { * */ class TableDiffFormatter extends DiffFormatter { + var $colspan = 2; function __construct() { $this->leading_context_lines = 2; @@ -1061,8 +1062,8 @@ class TableDiffFormatter extends DiffFormatter { global $lang; $l1 = $lang['line'].' '.$xbeg; $l2 = $lang['line'].' '.$ybeg; - $r = '<tr><td '.HTMLDiff::css('diff-blockheader').' colspan="2">'.$l1.":</td>\n". - '<td '.HTMLDiff::css('diff-blockheader').' colspan="2">'.$l2.":</td>\n". + $r = '<tr><td '.HTMLDiff::css('diff-blockheader').' colspan="'.$this->colspan.'">'.$l1.":</td>\n". + '<td '.HTMLDiff::css('diff-blockheader').' colspan="'.$this->colspan.'">'.$l2.":</td>\n". "</tr>\n"; return $r; } @@ -1094,7 +1095,7 @@ class TableDiffFormatter extends DiffFormatter { } function emptyLine() { - return '<td colspan="2"> </td>'; + return '<td colspan="'.$this->colspan.'"> </td>'; } function contextLine($line) { @@ -1173,7 +1174,7 @@ class InlineDiffFormatter extends DiffFormatter { $xbeg .= "," . $xlen; if ($ylen != 1) $ybeg .= "," . $ylen; - $r = '<tr><td colspan="2" '.HTMLDiff::css('diff-blockheader').'>@@ '.$lang['line']." -$xbeg +$ybeg @@"; + $r = '<tr><td colspan="'.$this->colspan.'" '.HTMLDiff::css('diff-blockheader').'>@@ '.$lang['line']." -$xbeg +$ybeg @@"; $r .= ' <span '.HTMLDiff::css('diff-deletedline').'><del>'.$lang['deleted'].'</del></span>'; $r .= ' <span '.HTMLDiff::css('diff-addedline').'>'.$lang['created'].'</span>'; $r .= "</td></tr>\n"; -- cgit v1.2.3 From 91328684db89e336404aff4644f8a53a1db64cad Mon Sep 17 00:00:00 2001 From: Michael Hamann <michael@content-space.de> Date: Sun, 17 Feb 2013 20:32:29 +0100 Subject: Display media file size only if file exists (prevents PHP warning) --- inc/parser/xhtml.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inc/parser/xhtml.php b/inc/parser/xhtml.php index 71f3aa4bf..4dd8c5e78 100644 --- a/inc/parser/xhtml.php +++ b/inc/parser/xhtml.php @@ -803,7 +803,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer { $class = preg_replace('/[^_\-a-z0-9]+/i','_',$ext); $link['class'] .= ' mediafile mf_'.$class; $link['url'] = ml($src,array('id'=>$ID,'cache'=>$cache),true); - $link['title'] .= ' (' . filesize_h(filesize(mediaFN($src))).')'; + if ($exists) $link['title'] .= ' (' . filesize_h(filesize(mediaFN($src))).')'; } if($hash) $link['url'] .= '#'.$hash; -- cgit v1.2.3 From 7e87a794494ea987ebc31decd939a25d44a5c00d Mon Sep 17 00:00:00 2001 From: Christopher Smith <chris@jalakai.co.uk> Date: Sun, 17 Feb 2013 20:03:38 +0000 Subject: fix missing 'subscribed' key --- inc/common.php | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/inc/common.php b/inc/common.php index d4265f78c..5c28cf9c3 100644 --- a/inc/common.php +++ b/inc/common.php @@ -88,8 +88,8 @@ function formSecurityToken($print = true) { /** * Determine basic information for a request of $id * - * @param unknown_type $id - * @param unknown_type $httpClient + * @author Andreas Gohr <andi@splitbrain.org> + * @author Chris Smith <chris@jalakai.co.uk> */ function basicinfo($id, $htmlClient=true){ global $USERINFO; @@ -116,7 +116,6 @@ function basicinfo($id, $htmlClient=true){ } else { $info['perm'] = auth_aclcheck($id, '', null); - $info['subscribed'] = false; $info['client'] = clientIP(true); } @@ -149,6 +148,13 @@ function pageinfo() { $info['id'] = $ID; $info['rev'] = $REV; + if(isset($_SERVER['REMOTE_USER'])) { + $sub = new Subscription(); + $info['subscribed'] = $sub->user_subscription(); + } else { + $info['subscribed'] = false; + } + $info['locked'] = checklock($ID); $info['filepath'] = fullpath(wikiFN($ID)); $info['exists'] = @file_exists($info['filepath']); -- cgit v1.2.3 From 1947d1b49884a38ff63ed13d434b64dc4bb777a6 Mon Sep 17 00:00:00 2001 From: Christopher Smith <chris@jalakai.co.uk> Date: Sun, 17 Feb 2013 21:57:53 +0000 Subject: force screen_mode to string type (IE returns a number which is always triggering the default option in the following switch/case block --- lib/tpl/dokuwiki/script.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/tpl/dokuwiki/script.js b/lib/tpl/dokuwiki/script.js index 375500f78..4eb92a417 100644 --- a/lib/tpl/dokuwiki/script.js +++ b/lib/tpl/dokuwiki/script.js @@ -12,7 +12,7 @@ var device_classes = 'desktop mobile tablet phone'; function tpl_dokuwiki_mobile(){ // the z-index in mobile.css is (mis-)used purely for detecting the screen mode here - var screen_mode = jQuery('#screen__mode').css('z-index'); + var screen_mode = jQuery('#screen__mode').css('z-index') + ''; // determine our device pattern // TODO: consider moving into dokuwiki core -- cgit v1.2.3 From e5f0efe2a3ff34ae70388fe8d068935416174f1c Mon Sep 17 00:00:00 2001 From: Anika Henke <anika@selfthinker.org> Date: Sun, 17 Feb 2013 22:52:28 +0000 Subject: improved disabled acl permission styling (FS#2714) --- lib/plugins/acl/style.css | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/plugins/acl/style.css b/lib/plugins/acl/style.css index f4277c341..f8574fe58 100644 --- a/lib/plugins/acl/style.css +++ b/lib/plugins/acl/style.css @@ -116,7 +116,8 @@ div#acl_manager .aclns { } div#acl_manager label.disabled { - color: __text_neu__!important; + opacity: .5; + cursor: auto; } #acl_manager label { -- cgit v1.2.3 From eda319e6664ad3c786312ffee7ce7cfbfa4eda1c Mon Sep 17 00:00:00 2001 From: Anika Henke <anika@selfthinker.org> Date: Sun, 17 Feb 2013 22:55:55 +0000 Subject: removed unnecessary css parts --- lib/plugins/acl/style.css | 58 +++++++++++++++++++++++------------------------ 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/lib/plugins/acl/style.css b/lib/plugins/acl/style.css index f8574fe58..d8f0b53f3 100644 --- a/lib/plugins/acl/style.css +++ b/lib/plugins/acl/style.css @@ -1,5 +1,5 @@ -div#acl_manager div#acl__tree { +#acl__tree { font-size: 90%; width: 25%; height: 300px; @@ -8,61 +8,61 @@ div#acl_manager div#acl__tree { border: 1px solid __border__; text-align: left; } -[dir=rtl] div#acl_manager div#acl__tree { +[dir=rtl] #acl__tree { float: right; text-align: right; } -div#acl_manager div#acl__tree a.cur { +#acl__tree a.cur { background-color: __highlight__; font-weight: bold; } -div#acl_manager div#acl__tree ul { +#acl__tree ul { list-style-type: none; margin: 0; padding: 0; } -div#acl_manager div#acl__tree li { +#acl__tree li { padding-left: 1em; list-style-image: none; } -[dir=rtl] div#acl_manager div#acl__tree li { +[dir=rtl] #acl__tree li { padding-left: 0em; padding-right: 1em; } -div#acl_manager div#acl__tree ul img { +#acl__tree ul img { margin-right: 0.25em; cursor: pointer; } -[dir=rtl] div#acl_manager div#acl__tree ul img { +[dir=rtl] #acl__tree ul img { margin-left: 0.25em; margin-right: 0em; } -div#acl_manager div#acl__detail { +#acl__detail { width: 73%; height: 300px; float: right; overflow: auto; } -[dir=rtl] div#acl_manager div#acl__detail { +[dir=rtl] #acl__detail { float: left; } -div#acl_manager div#acl__detail fieldset { +#acl__detail fieldset { width: 90%; } -div#acl_manager div#acl__detail div#acl__user { +#acl__detail div#acl__user { border: 1px solid __border__; padding: 0.5em; margin-bottom: 0.6em; } -div#acl_manager table.inline { +#acl_manager table.inline { width: 100%; margin: 0; } @@ -75,60 +75,60 @@ div#acl_manager table.inline { text-align: right; } -div#acl_manager .aclgroup { +#acl_manager .aclgroup { background: transparent url(pix/group.png) 0px 1px no-repeat; padding: 1px 0px 1px 18px; } -[dir=rtl] div#acl_manager .aclgroup { +[dir=rtl] #acl_manager .aclgroup { background: transparent url(pix/group.png) right 1px no-repeat; padding: 1px 18px 1px 0px; display: inline-block; /* needed for IE7 */ } -div#acl_manager .acluser { +#acl_manager .acluser { background: transparent url(pix/user.png) 0px 1px no-repeat; padding: 1px 0px 1px 18px; } -[dir=rtl] div#acl_manager .acluser { +[dir=rtl] #acl_manager .acluser { background: transparent url(pix/user.png) right 1px no-repeat; padding: 1px 18px 1px 0px; display: inline-block; /* needed for IE7 */ } -div#acl_manager .aclpage { +#acl_manager .aclpage { background: transparent url(pix/page.png) 0px 1px no-repeat; padding: 1px 0px 1px 18px; } -[dir=rtl] div#acl_manager .aclpage { +[dir=rtl] #acl_manager .aclpage { background: transparent url(pix/page.png) right 1px no-repeat; padding: 1px 18px 1px 0px; display: inline-block; /* needed for IE7 */ } -div#acl_manager .aclns { +#acl_manager .aclns { background: transparent url(pix/ns.png) 0px 1px no-repeat; padding: 1px 0px 1px 18px; } -[dir=rtl] div#acl_manager .aclns { +[dir=rtl] #acl_manager .aclns { background: transparent url(pix/ns.png) right 1px no-repeat; padding: 1px 18px 1px 0px; display: inline-block; /* needed for IE7 */ } -div#acl_manager label.disabled { - opacity: .5; - cursor: auto; +#acl_manager label.disabled { + opacity: .5; + cursor: auto; } #acl_manager label { - text-align: left; - font-weight: normal; - display: inline; + text-align: left; + font-weight: normal; + display: inline; } #acl_manager table { - margin-left: 10%; - width: 80%; + margin-left: 10%; + width: 80%; } #acl_manager table tr { -- cgit v1.2.3 From c33b315b06b3a52a61cb1ecc2b3beadd4ecd0311 Mon Sep 17 00:00:00 2001 From: Anika Henke <anika@selfthinker.org> Date: Mon, 18 Feb 2013 01:08:40 +0000 Subject: removed a bunch of functions which were deprecated in 2005/2006 --- .../Sniffs/PHP/DeprecatedFunctionsSniff.php | 1 + inc/common.php | 21 --- inc/io.php | 19 --- inc/parserutils.php | 78 --------- inc/plugin.php | 7 - inc/search.php | 188 ++------------------- lib/plugins/config/settings/config.metadata.php | 8 - 7 files changed, 15 insertions(+), 307 deletions(-) diff --git a/_cs/DokuWiki/Sniffs/PHP/DeprecatedFunctionsSniff.php b/_cs/DokuWiki/Sniffs/PHP/DeprecatedFunctionsSniff.php index ecd4093b8..c5d14377b 100644 --- a/_cs/DokuWiki/Sniffs/PHP/DeprecatedFunctionsSniff.php +++ b/_cs/DokuWiki/Sniffs/PHP/DeprecatedFunctionsSniff.php @@ -49,6 +49,7 @@ class DokuWiki_Sniffs_PHP_DeprecatedFunctionsSniff extends Generic_Sniffs_PHP_Fo 'search_fulltext' => 'Fulltext Indexer', 'search_regex' => 'Fulltext Indexer', 'tpl_getFavicon' => 'tpl_getMediaFile', + 'p_cached_xhtml' => 'p_cached_output', ); /** diff --git a/inc/common.php b/inc/common.php index 28b527633..471eb91b5 100644 --- a/inc/common.php +++ b/inc/common.php @@ -1174,27 +1174,6 @@ function getGoogleQuery() { return $q; } -/** - * Try to set correct locale - * - * @deprecated No longer used - * @author Andreas Gohr <andi@splitbrain.org> - */ -function setCorrectLocale() { - global $conf; - global $lang; - - $enc = strtoupper($lang['encoding']); - foreach($lang['locales'] as $loc) { - //try locale - if(@setlocale(LC_ALL, $loc)) return; - //try loceale with encoding - if(@setlocale(LC_ALL, "$loc.$enc")) return; - } - //still here? try to set from environment - @setlocale(LC_ALL, ""); -} - /** * Return the human readable size of a file * diff --git a/inc/io.php b/inc/io.php index 5ecc79703..4bd7c3364 100644 --- a/inc/io.php +++ b/inc/io.php @@ -529,25 +529,6 @@ function io_rename($from,$to){ return true; } - -/** - * Runs an external command and returns its output as string - * - * @author Harry Brueckner <harry_b@eml.cc> - * @author Andreas Gohr <andi@splitbrain.org> - * @deprecated - */ -function io_runcmd($cmd){ - $fh = popen($cmd, "r"); - if(!$fh) return false; - $ret = ''; - while (!feof($fh)) { - $ret .= fread($fh, 8192); - } - pclose($fh); - return $ret; -} - /** * Runs an external command with input and output pipes. * Returns the exit code from the process. diff --git a/inc/parserutils.php b/inc/parserutils.php index 1733fcf09..56161af44 100644 --- a/inc/parserutils.php +++ b/inc/parserutils.php @@ -85,67 +85,6 @@ function p_wiki_xhtml($id, $rev='', $excuse=true){ return $ret; } -/** - * Returns starting summary for a page (e.g. the first few - * paragraphs), marked up in XHTML. - * - * If $excuse is true an explanation is returned if the file - * wasn't found - * - * @param string $id wiki page id - * @param string $title populated with page title from heading or page id - * @param string $rev revision string - * @param bool $excuse if an excuse shall be renderer when no content is found - * @return string xhtml code - * @deprecated - * @author Harry Fuecks <hfuecks@gmail.com> - */ -function p_wiki_xhtml_summary($id, &$title, $rev='', $excuse=true){ - $file = wikiFN($id,$rev); - $ret = ''; - $ins = null; - - //ensure $id is in global $ID (needed for parsing) - global $ID; - $keep = $ID; - $ID = $id; - - if($rev){ - if(@file_exists($file)){ - //no caching on old revisions - $ins = p_get_instructions(io_readWikiPage($file,$id,$rev)); - }elseif($excuse){ - $ret = p_locale_xhtml('norev'); - //restore ID (just in case) - $ID = $keep; - return $ret; - } - - }else{ - - if(@file_exists($file)){ - // The XHTML for a summary is not cached so use the instruction cache - $ins = p_cached_instructions($file); - }elseif($excuse){ - $ret = p_locale_xhtml('newpage'); - //restore ID (just in case) - $ID = $keep; - return $ret; - } - } - - $ret = p_render('xhtmlsummary',$ins,$info); - - if ( $info['sum_pagetitle'] ) { - $title = $info['sum_pagetitle']; - } else { - $title = $id; - } - - $ID = $keep; - return $ret; -} - /** * Returns the specified local text in parsed format * @@ -157,23 +96,6 @@ function p_locale_xhtml($id){ return $html; } -/** - * *** DEPRECATED *** - * - * use p_cached_output() - * - * Returns the given file parsed to XHTML - * - * Uses and creates a cachefile - * - * @deprecated - * @author Andreas Gohr <andi@splitbrain.org> - * @todo rewrite to use mode instead of hardcoded XHTML - */ -function p_cached_xhtml($file){ - return p_cached_output($file); -} - /** * Returns the given file parsed into the requested output format * diff --git a/inc/plugin.php b/inc/plugin.php index cd6bd5ac7..4d3d45f62 100644 --- a/inc/plugin.php +++ b/inc/plugin.php @@ -258,11 +258,4 @@ class DokuWiki_Plugin { function isSingleton() { return true; } - - // deprecated functions - function plugin_localFN($id) { return $this->localFN($id); } - function plugin_locale_xhtml($id) { return $this->locale_xhtml($id); } - function plugin_email($e, $n='', $c='', $m='') { return $this->email($e, $n, $c, $m); } - function plugin_link($l, $t='', $c='', $to='', $m='') { return $this->external_link($l, $t, $c, $to, $m); } - function plugin_render($t, $f='xhtml') { return $this->render($t, $f); } } diff --git a/inc/search.php b/inc/search.php index cc3e79006..e4aa3b9eb 100644 --- a/inc/search.php +++ b/inc/search.php @@ -61,15 +61,6 @@ function search(&$data,$base,$func,$opts,$dir='',$lvl=1,$sort='natural'){ } } -/** - * Wrapper around call_user_func_array. - * - * @deprecated - */ -function search_callback($func,&$data,$base,$file,$type,$lvl,$opts){ - return call_user_func_array($func, array(&$data,$base,$file,$type,$lvl,$opts)); -} - /** * The following functions are userfunctions to use with the search * function above. This function is called for every found file or @@ -283,125 +274,25 @@ function search_allpages(&$data,$base,$file,$type,$lvl,$opts){ } /** - * Search for backlinks to a given page + * Reference search + * This fuction searches for existing references to a given media file + * and returns an array with the found pages. It doesn't pay any + * attention to ACL permissions to find every reference. The caller + * must check if the user has the appropriate rights to see the found + * page and eventually have to prevent the result from displaying. * - * $opts['ns'] namespace of the page - * $opts['name'] name of the page without namespace + * @param array $data Reference to the result data structure + * @param string $base Base usually $conf['datadir'] + * @param string $file current file or directory relative to $base + * @param char $type Type either 'd' for directory or 'f' for file + * @param int $lvl Current recursion depht + * @param mixed $opts option array as given to search() * - * @author Andreas Gohr <andi@splitbrain.org> - * @deprecated Replaced by ft_backlinks() - */ -function search_backlinks(&$data,$base,$file,$type,$lvl,$opts){ - //we do nothing with directories - if($type == 'd') return true; - //only search txt files - if(substr($file,-4) != '.txt') return true; - - //absolute search id - $sid = cleanID($opts['ns'].':'.$opts['name']); - - //current id and namespace - $cid = pathID($file); - $cns = getNS($cid); - - //check ACL - if(auth_quickaclcheck($cid) < AUTH_READ){ - return false; - } - - //fetch instructions - $instructions = p_cached_instructions($base.$file,true); - if(is_null($instructions)) return false; - - global $conf; - //check all links for match - foreach($instructions as $ins){ - if($ins[0] == 'internallink' || ($conf['camelcase'] && $ins[0] == 'camelcaselink') ){ - $mid = $ins[1][0]; - resolve_pageid($cns,$mid,$exists); //exists is not used - if($mid == $sid){ - //we have a match - finish - $data[]['id'] = $cid; - break; - } - } - } - - return false; -} - -/** - * Fulltextsearch - * - * $opts['query'] is the search query + * $opts['query'] is the demanded media file name * * @author Andreas Gohr <andi@splitbrain.org> - * @deprecated - fulltext indexer is used instead + * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net> */ -function search_fulltext(&$data,$base,$file,$type,$lvl,$opts){ - //we do nothing with directories - if($type == 'd') return true; - //only search txt files - if(substr($file,-4) != '.txt') return true; - - //check ACL - $id = pathID($file); - if(auth_quickaclcheck($id) < AUTH_READ){ - return false; - } - - //create regexp from queries - $poswords = array(); - $negwords = array(); - $qpreg = preg_split('/\s+/',$opts['query']); - - foreach($qpreg as $word){ - switch(substr($word,0,1)){ - case '-': - if(strlen($word) > 1){ // catch single '-' - array_push($negwords,preg_quote(substr($word,1),'#')); - } - break; - case '+': - if(strlen($word) > 1){ // catch single '+' - array_push($poswords,preg_quote(substr($word,1),'#')); - } - break; - default: - array_push($poswords,preg_quote($word,'#')); - break; - } - } - - // a search without any posword is useless - if (!count($poswords)) return true; - - $reg = '^(?=.*?'.join(')(?=.*?',$poswords).')'; - $reg .= count($negwords) ? '((?!'.join('|',$negwords).').)*$' : '.*$'; - search_regex($data,$base,$file,$reg,$poswords); - return true; - } - - /** - * Reference search - * This fuction searches for existing references to a given media file - * and returns an array with the found pages. It doesn't pay any - * attention to ACL permissions to find every reference. The caller - * must check if the user has the appropriate rights to see the found - * page and eventually have to prevent the result from displaying. - * - * @param array $data Reference to the result data structure - * @param string $base Base usually $conf['datadir'] - * @param string $file current file or directory relative to $base - * @param char $type Type either 'd' for directory or 'f' for file - * @param int $lvl Current recursion depht - * @param mixed $opts option array as given to search() - * - * $opts['query'] is the demanded media file name - * - * @author Andreas Gohr <andi@splitbrain.org> - * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net> - */ function search_reference(&$data,$base,$file,$type,$lvl,$opts){ global $conf; @@ -423,57 +314,6 @@ function search_reference(&$data,$base,$file,$type,$lvl,$opts){ /* ------------- helper functions below -------------- */ -/** - * fulltext search helper - * searches a text file with a given regular expression - * no ACL checks are performed. This have to be done by - * the caller if necessary. - * - * @param array $data reference to array for results - * @param string $base base directory - * @param string $file file name to search in - * @param string $reg regular expression to search for - * @param array $words words that should be marked in the results - * - * @author Andreas Gohr <andi@splitbrain.org> - * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net> - * - * @deprecated - fulltext indexer is used instead - */ -function search_regex(&$data,$base,$file,$reg,$words){ - - //get text - $text = io_readfile($base.'/'.$file); - //lowercase text (u modifier does not help with case) - $lctext = utf8_strtolower($text); - - //do the fulltext search - $matches = array(); - if($cnt = preg_match_all('#'.$reg.'#usi',$lctext,$matches)){ - //this is not the best way for snippet generation but the fastest I could find - $q = $words[0]; //use first word for snippet creation - $p = utf8_strpos($lctext,$q); - $f = $p - 100; - $l = utf8_strlen($q) + 200; - if($f < 0) $f = 0; - $snippet = '<span class="search_sep"> ... </span>'. - htmlspecialchars(utf8_substr($text,$f,$l)). - '<span class="search_sep"> ... </span>'; - $mark = '('.join('|', $words).')'; - $snippet = preg_replace('#'.$mark.'#si','<strong class="search_hit">\\1</strong>',$snippet); - - $data[] = array( - 'id' => pathID($file), - 'count' => preg_match_all('#'.$mark.'#usi',$lctext,$matches), - 'poswords' => join(' ',$words), - 'snippet' => $snippet, - ); - } - - return true; -} - - /** * fulltext sort * diff --git a/lib/plugins/config/settings/config.metadata.php b/lib/plugins/config/settings/config.metadata.php index bdbc4311f..22e76a013 100644 --- a/lib/plugins/config/settings/config.metadata.php +++ b/lib/plugins/config/settings/config.metadata.php @@ -70,14 +70,6 @@ $config['varname'] = 'conf'; // name of the config variable, sans $ // this value can be overriden when calling save_settings() method $config['heading'] = 'Dokuwiki\'s Main Configuration File - Local Settings'; -/* DEPRECATED -// ---------------[ setting files ]-------------------------------------- -// these values can be string expressions, they will be eval'd before use -$file['local'] = "DOKU_CONF.'local.php'"; // mandatory (file doesn't have to exist) -$file['default'] = "DOKU_CONF.'dokuwiki.php'"; // optional -$file['protected'] = "DOKU_CONF.'local.protected.php'"; // optional - */ - // test value (FIXME, remove before publishing) //$meta['test'] = array('multichoice','_choices' => array('')); -- cgit v1.2.3 From 07a30891fae578fc908dc88ad4ee02ee336fffe7 Mon Sep 17 00:00:00 2001 From: Anika Henke <anika@selfthinker.org> Date: Mon, 18 Feb 2013 01:21:07 +0000 Subject: fixed line endings --- bin/.htaccess | 4 ++-- lib/plugins/acl/lang/vi/help.txt | 24 ++++++++++++------------ 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/bin/.htaccess b/bin/.htaccess index 9c96d3742..281d5c33d 100644 --- a/bin/.htaccess +++ b/bin/.htaccess @@ -1,2 +1,2 @@ -order allow,deny -deny from all +order allow,deny +deny from all diff --git a/lib/plugins/acl/lang/vi/help.txt b/lib/plugins/acl/lang/vi/help.txt index 23e258678..816e5ee71 100644 --- a/lib/plugins/acl/lang/vi/help.txt +++ b/lib/plugins/acl/lang/vi/help.txt @@ -1,12 +1,12 @@ -=== Trợ giúp nhanh: === - -Trang này giúp bạn thêm hoặc xóa quyền được cấp cho 1 thư mục hoặc trang wiki của bạn. - -Của sổ bên trái hiển thị tất cả các thư mục và trang văn bản. - -Khung trên đây cho phép bạn xem và sửa quyền của một nhóm hoặc thành viên đã chọn. - -Bảng bên dưới hiển thị tất cả các quyền được cấp. Bạn có thể sửa hoặc hóa các quyền đó một cách nhanh chóng. - -Đọc [[doku>acl|tài liệu chính thức về ACL]] sẽ giúp bạn hiểu hơn về cách phân quyền ở DokuWiki. - +=== Trợ giúp nhanh: === + +Trang này giúp bạn thêm hoặc xóa quyền được cấp cho 1 thư mục hoặc trang wiki của bạn. + +Của sổ bên trái hiển thị tất cả các thư mục và trang văn bản. + +Khung trên đây cho phép bạn xem và sửa quyền của một nhóm hoặc thành viên đã chọn. + +Bảng bên dưới hiển thị tất cả các quyền được cấp. Bạn có thể sửa hoặc hóa các quyền đó một cách nhanh chóng. + +Đọc [[doku>acl|tài liệu chính thức về ACL]] sẽ giúp bạn hiểu hơn về cách phân quyền ở DokuWiki. + -- cgit v1.2.3 From 7a4d121f8568b0aee5f0e117737f3675dcc85100 Mon Sep 17 00:00:00 2001 From: Christopher Smith <chris@jalakai.co.uk> Date: Mon, 18 Feb 2013 18:51:01 +0000 Subject: change tpl_actiondropdown request method to 'get' --- inc/template.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inc/template.php b/inc/template.php index a5bcabf1e..e9c0f1699 100644 --- a/inc/template.php +++ b/inc/template.php @@ -1373,7 +1373,7 @@ function tpl_actiondropdown($empty = '', $button = '>') { global $REV; global $lang; - echo '<form action="'.DOKU_SCRIPT.'" method="post" accept-charset="utf-8">'; + echo '<form action="'.DOKU_SCRIPT.'" method="get" accept-charset="utf-8">'; echo '<div class="no">'; echo '<input type="hidden" name="id" value="'.$ID.'" />'; if($REV) echo '<input type="hidden" name="rev" value="'.$REV.'" />'; -- cgit v1.2.3 From a02e0d0ea02e11f105aeb3b9cc4dabdd5a1bc217 Mon Sep 17 00:00:00 2001 From: Christopher Smith <chris@jalakai.co.uk> Date: Mon, 18 Feb 2013 18:55:33 +0000 Subject: remove security token from tpl_actiondropdown - its not necessary, we're not posting any system change --- inc/template.php | 1 - 1 file changed, 1 deletion(-) diff --git a/inc/template.php b/inc/template.php index e9c0f1699..1734b08a0 100644 --- a/inc/template.php +++ b/inc/template.php @@ -1377,7 +1377,6 @@ function tpl_actiondropdown($empty = '', $button = '>') { echo '<div class="no">'; echo '<input type="hidden" name="id" value="'.$ID.'" />'; if($REV) echo '<input type="hidden" name="rev" value="'.$REV.'" />'; - echo '<input type="hidden" name="sectok" value="'.getSecurityToken().'" />'; echo '<select name="do" class="edit quickselect" title="'.$lang['tools'].'">'; echo '<option value="">'.$empty.'</option>'; -- cgit v1.2.3 From bd4e67d289bd025f1285f39c1a3d29277c4f7102 Mon Sep 17 00:00:00 2001 From: Christopher Smith <chris@jalakai.co.uk> Date: Mon, 18 Feb 2013 21:27:13 +0000 Subject: some unit test, more required --- _test/tests/inc/common_infofunctions.test.php | 112 ++++++++++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 _test/tests/inc/common_infofunctions.test.php diff --git a/_test/tests/inc/common_infofunctions.test.php b/_test/tests/inc/common_infofunctions.test.php new file mode 100644 index 000000000..b66e6f687 --- /dev/null +++ b/_test/tests/inc/common_infofunctions.test.php @@ -0,0 +1,112 @@ +<?php + +class common_infofunctions_test extends DokuWikiTest { + + function setup(){ + parent::setup(); + + global $USERINFO; + $USERINFO = array( + 'pass' => '179ad45c6ce2cb97cf1029e212046e81', + 'name' => 'Arthur Dent', + 'mail' => 'arthur@example.com', + 'grps' => array ('admin','user'), + ); + $_SERVER['REMOTE_USER'] = 'testuser'; + $_SERVER['REMOTE_ADDR'] = '1.2.3.4'; + } + + function _get_info() { + global $USERINFO; + $info = array ( + 'isadmin' => true, + 'ismanager' => true, + 'userinfo' => $USERINFO, + 'perm' => 255, + 'namespace' => false, + 'ismobile' => false, + 'client' => 'testuser', + ); + + return $info; + } + + /** + * Its important to have the correct set of keys. + * Other functions provide the values + */ + function test_basicinfo(){ + // test with REMOTE_USER set and the user an admin user + $info = $this->_get_info(); + $this->assertEquals(basicinfo($ID,true),$info); + + // with $httpclient parameter set to false + unset($info['ismobile']); + $this->assertEquals(basicinfo($ID,false),$info); + + // with anonymous user + unset($_SERVER['REMOTE_USER']); + global $USERINFO; $USERINFO = array(); + + $info = array( + 'isadmin' => false, + 'ismanager' => false, + 'perm' => 8, + 'namespace' => false, + 'ismobile' => false, + 'client' => '1.2.3.4', + ); + $this->assertEquals(basicinfo($ID,true),$info); + } + + /** + * We're interested in the extra keys required for $INFO when its a page request + * and that $REV, $RANGE globals are set/cleared correctly + */ + function test_pageinfo(){ + global $ID,$conf; + $ID = 'wiki:start'; + + $info = $this->_get_info(); + $info['id'] = 'wiki:start'; + $info['namespace'] = 'wiki'; + $info['rev'] = null; + $info['subscribed'] = false; + $info['locked'] = false; + $info['filepath'] = $conf['datadir'].'/wiki/start.txt'; + $info['exists'] = false; + $info['writable'] = true; + $info['editable'] = true; + $info['lastmod'] = false; + $info['meta'] = array(); + $info['ip'] = null; + $info['user'] = null; + $info['sum'] = null; + $info['editor'] = null; + + // basic test, no revision + $this->assertEquals(pageinfo(),$info); + + // TODO: test with revision = current page + + // TODO: test with true revision + + // TODO: test with revision & range + } + + /** + * We're interested in the extra keys for $INFO when its a media request + */ + function test_mediainfo(){ + global $NS, $IMG; + $NS = ''; + $IMG = 'testimage.png'; + + $info = $this->_get_info(); + $info['image'] = 'testimage.png'; + + $this->assertEquals(mediainfo(),$info); + } +} + +//Setup VIM: ex: et ts=4 : -- cgit v1.2.3 From 61efcda114414f2c35c1993c75bc95909282017f Mon Sep 17 00:00:00 2001 From: Christopher Smith <chris@jalakai.co.uk> Date: Tue, 19 Feb 2013 00:13:25 +0000 Subject: add security token back, but not for anonymous users --- inc/template.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/inc/template.php b/inc/template.php index 1734b08a0..4bfc3f572 100644 --- a/inc/template.php +++ b/inc/template.php @@ -1377,6 +1377,9 @@ function tpl_actiondropdown($empty = '', $button = '>') { echo '<div class="no">'; echo '<input type="hidden" name="id" value="'.$ID.'" />'; if($REV) echo '<input type="hidden" name="rev" value="'.$REV.'" />'; + if ($_SERVER['REMOTE_USER']) { + echo '<input type="hidden" name="sectok" value="'.getSecurityToken().'" />'; + } echo '<select name="do" class="edit quickselect" title="'.$lang['tools'].'">'; echo '<option value="">'.$empty.'</option>'; -- cgit v1.2.3 From a4ce95c84dca904abb57d30efa2a9d5d68eeda1b Mon Sep 17 00:00:00 2001 From: Dominik Eckelmann <eckelmann@cosmocode.de> Date: Wed, 20 Feb 2013 10:44:25 +0100 Subject: fixed auth_browseruid on IE9 IE9 send different HTTP_ACCEPT_LANGUAGE header on ajax request. This causes different results from auth_browseruid. This patch removes the HTTP_ACCEPT_LANGUAGE from the browser id calculation. --- _test/tests/inc/auth_browseruid.test.php | 30 ++++++++++++++++++++++++++++++ inc/auth.php | 1 - 2 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 _test/tests/inc/auth_browseruid.test.php diff --git a/_test/tests/inc/auth_browseruid.test.php b/_test/tests/inc/auth_browseruid.test.php new file mode 100644 index 000000000..d33552582 --- /dev/null +++ b/_test/tests/inc/auth_browseruid.test.php @@ -0,0 +1,30 @@ +<?php + +class auth_browseruid_test extends DokuWikiTest { + + + /** + * regression test to ensure correct browser id on IE9. + * + * IE9 send different HTTP_ACCEPT_LANGUAGE header on ajax request. + */ + function testIE9JsVsDefault() { + + // javascript request + $_SERVER['HTTP_USER_AGENT'] = 'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)'; + $_SERVER['HTTP_ACCEPT_ENCODING'] = 'gzip, deflate'; + $_SERVER['HTTP_ACCEPT_LANGUAGE'] = 'de'; + unset($_SERVER['HTTP_ACCEPT_CHARSET']); + $javascriptId = auth_browseruid(); + + // default request + $_SERVER['HTTP_USER_AGENT'] = 'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)'; + $_SERVER['HTTP_ACCEPT_ENCODING'] = 'gzip, deflate'; + $_SERVER['HTTP_ACCEPT_LANGUAGE'] = 'de-DE'; + $normalId = auth_browseruid(); + + $this->assertEquals($normalId, $javascriptId); + + } + +} \ No newline at end of file diff --git a/inc/auth.php b/inc/auth.php index 9566a2615..d82b8b5dd 100644 --- a/inc/auth.php +++ b/inc/auth.php @@ -311,7 +311,6 @@ function auth_browseruid() { $uid = ''; $uid .= $_SERVER['HTTP_USER_AGENT']; $uid .= $_SERVER['HTTP_ACCEPT_ENCODING']; - $uid .= $_SERVER['HTTP_ACCEPT_LANGUAGE']; $uid .= $_SERVER['HTTP_ACCEPT_CHARSET']; $uid .= substr($ip, 0, strpos($ip, '.')); $uid = strtolower($uid); -- cgit v1.2.3 From 64276bbca5e40e5c6e93b98e76bb84b33db4643b Mon Sep 17 00:00:00 2001 From: arbrk1 <arbrk1@gmail.com> Date: Wed, 20 Feb 2013 22:26:45 +0400 Subject: Update inc/template.php changed nonexistant actionOk to actionOK --- inc/template.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inc/template.php b/inc/template.php index a5bcabf1e..e52158a53 100644 --- a/inc/template.php +++ b/inc/template.php @@ -764,7 +764,7 @@ function tpl_searchform($ajax = true, $autocomplete = true) { global $QUERY; // don't print the search form if search action has been disabled - if(!actionOk('search')) return false; + if(!actionOK('search')) return false; print '<form action="'.wl().'" accept-charset="utf-8" class="search" id="dw__search" method="get"><div class="no">'; print '<input type="hidden" name="do" value="search" />'; -- cgit v1.2.3 From 6416b708d3d115a6d7529b6c388c796fcb651d55 Mon Sep 17 00:00:00 2001 From: Michael Hamann <michael@content-space.de> Date: Wed, 20 Feb 2013 19:43:29 +0100 Subject: Fix handling of failed authentication loading In the case of a failed authentication initialization, the authentication setup was simply continued with an unset $auth object. This restores the previous behavior (before merging #141) of simply returning after unsetting $auth. Furthermore this re-introduces the check if $auth is set before checking $auth and removes a useless check if $auth is true (could never be false). --- inc/auth.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/inc/auth.php b/inc/auth.php index d82b8b5dd..92a56e163 100644 --- a/inc/auth.php +++ b/inc/auth.php @@ -54,16 +54,17 @@ function auth_setup() { } } - if(!$auth){ + if(!isset($auth) || !$auth){ msg($lang['authtempfail'], -1); return false; } - if ($auth && $auth->success == false) { + if ($auth->success == false) { // degrade to unauthenticated user unset($auth); auth_logoff(); msg($lang['authtempfail'], -1); + return false; } // do the login either by cookie or provided credentials XXX -- cgit v1.2.3 From 5737a81e37e630de02f54e4e6304ede226159306 Mon Sep 17 00:00:00 2001 From: Michael Hamann <michael@content-space.de> Date: Wed, 20 Feb 2013 20:18:59 +0100 Subject: Revert the search depth behavior changes from #154 This reverts parts of the changes from #154: Before merging the pull request, a depth of 1 returned just the pages in the root namespace. With the changes in the pull request, a depth of 1 also returned pages in subnamespaces of the root namespace (as it was also tested in the test case). This reverts this part of the changes and a depth of 1 returns just the pages in the root namespace again. --- _test/tests/inc/search/search.test.php | 4 ++-- inc/search.php | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/_test/tests/inc/search/search.test.php b/_test/tests/inc/search/search.test.php index 9c854a661..33d4e9d8d 100644 --- a/_test/tests/inc/search/search.test.php +++ b/_test/tests/inc/search/search.test.php @@ -22,9 +22,9 @@ class search_test extends DokuWikiTest { search($data, dirname(__FILE__) . '/data', 'search_allpages', array('depth' => 1), 'ns1/ns3'); $this->assertEquals(0, count($data)); - //depth is 1 so I should get only pages from ns1 + //depth is 2 so I should get only pages from ns1 $data = array(); - search($data, dirname(__FILE__) . '/data', 'search_allpages', array('depth' => 1), 'ns1'); + search($data, dirname(__FILE__) . '/data', 'search_allpages', array('depth' => 2), 'ns1'); $this->assertEquals(2, count($data)); } diff --git a/inc/search.php b/inc/search.php index e4aa3b9eb..6927fff5f 100644 --- a/inc/search.php +++ b/inc/search.php @@ -243,8 +243,8 @@ function search_pagename(&$data,$base,$file,$type,$lvl,$opts){ function search_allpages(&$data,$base,$file,$type,$lvl,$opts){ if(isset($opts['depth']) && $opts['depth']){ $parts = explode('/',ltrim($file,'/')); - if(($type == 'd' && count($parts) > $opts['depth']) - || ($type != 'd' && count($parts) > $opts['depth'] + 1)){ + if(($type == 'd' && count($parts) >= $opts['depth']) + || ($type != 'd' && count($parts) > $opts['depth'])){ return false; // depth reached } } -- cgit v1.2.3 From 00d58927261c5bed6f093ca4aa2064a18139a228 Mon Sep 17 00:00:00 2001 From: Michael Hamann <michael@content-space.de> Date: Wed, 20 Feb 2013 20:26:05 +0100 Subject: Fix remaining missing $INPUT uses FS#2577 This adds $INPUT in all places where it was still missing and available. $INPUT is now also used in places where using $_REQUEST/... was okay in order to make the code consistent. --- doku.php | 2 +- inc/auth.php | 2 +- lib/plugins/authad/auth.php | 5 +++-- lib/plugins/plugin/admin.php | 3 ++- lib/plugins/revert/admin.php | 13 +++++++------ lib/plugins/usermanager/admin.php | 25 +++++++++++++------------ 6 files changed, 27 insertions(+), 23 deletions(-) diff --git a/doku.php b/doku.php index 607303ca4..68976ebb3 100644 --- a/doku.php +++ b/doku.php @@ -29,7 +29,7 @@ if(isset($_SERVER['HTTP_X_DOKUWIKI_DO'])) { require_once(DOKU_INC.'inc/init.php'); //import variables -$_REQUEST['id'] = str_replace("\xC2\xAD", '', $INPUT->str('id')); //soft-hyphen +$INPUT->set('id', str_replace("\xC2\xAD", '', $INPUT->str('id'))); //soft-hyphen $QUERY = trim($INPUT->str('id')); $ID = getID(); diff --git a/inc/auth.php b/inc/auth.php index 92a56e163..68b6b438d 100644 --- a/inc/auth.php +++ b/inc/auth.php @@ -92,7 +92,7 @@ function auth_setup() { // apply cleaning if (true === $auth->success) { - $_REQUEST['u'] = $auth->cleanUser($_REQUEST['u']); + $INPUT->set('u', $auth->cleanUser($INPUT->str('u'))); } if($INPUT->str('authtok')) { diff --git a/lib/plugins/authad/auth.php b/lib/plugins/authad/auth.php index f651d87a1..6c49eafbb 100644 --- a/lib/plugins/authad/auth.php +++ b/lib/plugins/authad/auth.php @@ -71,6 +71,7 @@ class auth_plugin_authad extends DokuWiki_Auth_Plugin { * Constructor */ public function __construct() { + global $INPUT; parent::__construct(); // we load the config early to modify it a bit here @@ -99,8 +100,8 @@ class auth_plugin_authad extends DokuWiki_Auth_Plugin { // we need to simulate a login if(empty($_COOKIE[DOKU_COOKIE])) { - $_REQUEST['u'] = $_SERVER['REMOTE_USER']; - $_REQUEST['p'] = 'sso_only'; + $INPUT->set('u', $_SERVER['REMOTE_USER']); + $INPUT->set('p', 'sso_only'); } } diff --git a/lib/plugins/plugin/admin.php b/lib/plugins/plugin/admin.php index 8b1ee3c7d..de4de6aef 100644 --- a/lib/plugins/plugin/admin.php +++ b/lib/plugins/plugin/admin.php @@ -61,11 +61,12 @@ class admin_plugin_plugin extends DokuWiki_Admin_Plugin { * handle user request */ function handle() { + global $INPUT; // enable direct access to language strings $this->setupLocale(); - $fn = $_REQUEST['fn']; + $fn = $INPUT->param('fn'); if (is_array($fn)) { $this->cmd = key($fn); $this->plugin = is_array($fn[$this->cmd]) ? key($fn[$this->cmd]) : null; diff --git a/lib/plugins/revert/admin.php b/lib/plugins/revert/admin.php index fcdaa230d..847e38876 100644 --- a/lib/plugins/revert/admin.php +++ b/lib/plugins/revert/admin.php @@ -44,15 +44,16 @@ class admin_plugin_revert extends DokuWiki_Admin_Plugin { * output appropriate html */ function html() { + global $INPUT; echo $this->plugin_locale_xhtml('intro'); $this->_searchform(); - if(is_array($_REQUEST['revert']) && checkSecurityToken()){ - $this->_revert($_REQUEST['revert'],$_REQUEST['filter']); - }elseif(isset($_REQUEST['filter'])){ - $this->_list($_REQUEST['filter']); + if(is_array($INPUT->param('revert')) && checkSecurityToken()){ + $this->_revert($INPUT->arr('revert'),$INPUT->str('filter')); + }elseif($INPUT->has('filter')){ + $this->_list($INPUT->str('filter')); } } @@ -60,10 +61,10 @@ class admin_plugin_revert extends DokuWiki_Admin_Plugin { * Display the form for searching spam pages */ function _searchform(){ - global $lang; + global $lang, $INPUT; echo '<form action="" method="post"><div class="no">'; echo '<label>'.$this->getLang('filter').': </label>'; - echo '<input type="text" name="filter" class="edit" value="'.hsc($_REQUEST['filter']).'" />'; + echo '<input type="text" name="filter" class="edit" value="'.hsc($INPUT->str('filter')).'" />'; echo ' <input type="submit" class="button" value="'.$lang['btn_search'].'" />'; echo ' <span>'.$this->getLang('note1').'</span>'; echo '</div></form><br /><br />'; diff --git a/lib/plugins/usermanager/admin.php b/lib/plugins/usermanager/admin.php index cf8963e64..01f4a4cdb 100644 --- a/lib/plugins/usermanager/admin.php +++ b/lib/plugins/usermanager/admin.php @@ -73,11 +73,12 @@ class admin_plugin_usermanager extends DokuWiki_Admin_Plugin { * handle user request */ function handle() { + global $INPUT; if (is_null($this->_auth)) return false; // extract the command and any specific parameters // submit button name is of the form - fn[cmd][param(s)] - $fn = $_REQUEST['fn']; + $fn = $INPUT->param('fn'); if (is_array($fn)) { $cmd = key($fn); @@ -88,8 +89,7 @@ class admin_plugin_usermanager extends DokuWiki_Admin_Plugin { } if ($cmd != "search") { - if (!empty($_REQUEST['start'])) - $this->_start = $_REQUEST['start']; + $this->_start = $INPUT->int('start', 0); $this->_filter = $this->_retrieveFilter(); } @@ -345,6 +345,7 @@ class admin_plugin_usermanager extends DokuWiki_Admin_Plugin { } function _addUser(){ + global $INPUT; if (!checkSecurityToken()) return false; if (!$this->_auth->canDo('addUser')) return false; @@ -353,7 +354,7 @@ class admin_plugin_usermanager extends DokuWiki_Admin_Plugin { if ($this->_auth->canDo('modPass')){ if (empty($pass)){ - if(!empty($_REQUEST['usernotify'])){ + if($INPUT->has('usernotify')){ $pass = auth_pwgen(); } else { msg($this->lang['add_fail'], -1); @@ -393,7 +394,7 @@ class admin_plugin_usermanager extends DokuWiki_Admin_Plugin { msg($this->lang['add_ok'], 1); - if (!empty($_REQUEST['usernotify']) && $pass) { + if ($INPUT->has('usernotify') && $pass) { $this->_notifyUser($user,$pass); } } else { @@ -407,13 +408,13 @@ class admin_plugin_usermanager extends DokuWiki_Admin_Plugin { * Delete user */ function _deleteUser(){ - global $conf; + global $conf, $INPUT; if (!checkSecurityToken()) return false; if (!$this->_auth->canDo('delUser')) return false; - $selected = $_REQUEST['delete']; - if (!is_array($selected) || empty($selected)) return false; + $selected = $INPUT->arr('delete'); + if (empty($selected)) return false; $selected = array_keys($selected); if(in_array($_SERVER['REMOTE_USER'], $selected)) { @@ -463,13 +464,13 @@ class admin_plugin_usermanager extends DokuWiki_Admin_Plugin { * Modify user (modified user data has been recieved) */ function _modifyUser(){ - global $conf; + global $conf, $INPUT; if (!checkSecurityToken()) return false; if (!$this->_auth->canDo('UserMod')) return false; // get currently valid user data - $olduser = cleanID(preg_replace('/.*:/','',$_REQUEST['userid_old'])); + $olduser = cleanID(preg_replace('/.*:/','',$INPUT->str('userid_old'))); $oldinfo = $this->_auth->getUserData($olduser); // get new user data subject to change @@ -494,7 +495,7 @@ class admin_plugin_usermanager extends DokuWiki_Admin_Plugin { } // generate password if left empty and notification is on - if(!empty($_REQUEST['usernotify']) && empty($newpass)){ + if($INPUT->has('usernotify') && empty($newpass)){ $newpass = auth_pwgen(); } @@ -510,7 +511,7 @@ class admin_plugin_usermanager extends DokuWiki_Admin_Plugin { if ($ok = $this->_auth->triggerUserMod('modify', array($olduser, $changes))) { msg($this->lang['update_ok'],1); - if (!empty($_REQUEST['usernotify']) && $newpass) { + if ($INPUT->has('usernotify') && $newpass) { $notify = empty($changes['user']) ? $olduser : $newuser; $this->_notifyUser($notify,$newpass); } -- cgit v1.2.3 From 177daee5492e8c3cdfdb950cdf61a6798f7a9586 Mon Sep 17 00:00:00 2001 From: Christopher Smith <chris@jalakai.co.uk> Date: Thu, 21 Feb 2013 17:22:50 +0000 Subject: another test todo --- _test/tests/inc/common_infofunctions.test.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/_test/tests/inc/common_infofunctions.test.php b/_test/tests/inc/common_infofunctions.test.php index b66e6f687..2e383ef8b 100644 --- a/_test/tests/inc/common_infofunctions.test.php +++ b/_test/tests/inc/common_infofunctions.test.php @@ -92,6 +92,8 @@ class common_infofunctions_test extends DokuWikiTest { // TODO: test with true revision // TODO: test with revision & range + + // TODO: validate against the same test run on master branch pre this change } /** -- cgit v1.2.3 From af2cfd7b82393672123fde194798dbf00541588a Mon Sep 17 00:00:00 2001 From: Christopher Smith <chris@jalakai.co.uk> Date: Thu, 21 Feb 2013 21:59:05 +0000 Subject: add unit test for pageinfo() --- _test/tests/inc/common_pageinfo.test.php | 299 +++++++++++++++++++++++++++++++ 1 file changed, 299 insertions(+) create mode 100644 _test/tests/inc/common_pageinfo.test.php diff --git a/_test/tests/inc/common_pageinfo.test.php b/_test/tests/inc/common_pageinfo.test.php new file mode 100644 index 000000000..c54fbce26 --- /dev/null +++ b/_test/tests/inc/common_pageinfo.test.php @@ -0,0 +1,299 @@ +<?php +/** + * Unit Test for inc/common.php - pageinfo() + * + * @author Christopher Smith <chris@jalakai.co.uk> + */ +class common_pageinfo_test extends DokuWikiTest { + + function setup(){ + parent::setup(); + + global $USERINFO; + $USERINFO = array( + 'pass' => '179ad45c6ce2cb97cf1029e212046e81', + 'name' => 'Arthur Dent', + 'mail' => 'arthur@example.com', + 'grps' => array ('admin','user'), + ); + $_SERVER['REMOTE_USER'] = 'testuser'; + $_SERVER['REMOTE_ADDR'] = '1.2.3.4'; + } + + function _get_expected_pageinfo() { + global $USERINFO; + $info = array ( + 'isadmin' => true, + 'ismanager' => true, + 'userinfo' => $USERINFO, + 'perm' => 255, + 'namespace' => false, + 'ismobile' => false, + 'client' => 'testuser', + ); + $info['rev'] = null; + $info['subscribed'] = false; + $info['locked'] = false; + $info['exists'] = false; + $info['writable'] = true; + $info['editable'] = true; + $info['lastmod'] = false; + $info['meta'] = array(); + $info['ip'] = null; + $info['user'] = null; + $info['sum'] = null; + $info['editor'] = null; + + return $info; + } + + /** + * check info keys and values for a non-existent page & admin user + */ + function test_basic_nonexistentpage(){ + global $ID,$conf; + $ID = 'wiki:start'; + + $info = $this->_get_expected_pageinfo(); + $info['id'] = 'wiki:start'; + $info['namespace'] = 'wiki'; + $info['filepath'] = $conf['datadir'].'/wiki/start.txt'; + + $this->assertEquals($info, pageinfo()); + } + + /** + * check info keys and values for a existing page & admin user + */ + function test_basic_existingpage(){ + global $ID,$conf; + $ID = 'wiki:syntax'; + $filename = $conf['datadir'].'/wiki/syntax.txt'; + $rev = filemtime($filename); + + $info = $this->_get_expected_pageinfo(); + $info['id'] = 'wiki:syntax'; + $info['namespace'] = 'wiki'; + $info['filepath'] = $filename; + $info['exists'] = true; + $info['lastmod'] = $rev; + $info['meta'] = p_get_metadata($ID); + + $this->assertEquals($info, pageinfo()); + } + + /** + * check info keys and values for anonymous user + */ + function test_anonymoususer(){ + global $ID,$conf,$REV; + + unset($_SERVER['REMOTE_USER']); + global $USERINFO; $USERINFO = array(); + + $ID = 'wiki:syntax'; + $filename = $conf['datadir'].'/wiki/syntax.txt'; + $rev = filemtime($filename); + + $info = $this->_get_expected_pageinfo(); + $info['id'] = 'wiki:syntax'; + $info['namespace'] = 'wiki'; + $info['filepath'] = $filename; + $info['exists'] = true; + $info['lastmod'] = $rev; + $info['meta'] = p_get_metadata($ID); + $info['rev'] = ''; + + $info = array_merge($info, array( + 'isadmin' => false, + 'ismanager' => false, + 'perm' => 8, + 'client' => '1.2.3.4', + )); + unset($info['userinfo']); + $this->assertEquals($info, pageinfo()); + } + + /** + * check info keys and values with $REV + * (also see $RANGE tests) + */ + function test_rev(){ + global $ID,$conf,$REV; + + $ID = 'wiki:syntax'; + $filename = $conf['datadir'].'/wiki/syntax.txt'; + $rev = filemtime($filename); + $REV = $rev - 100; + + $info = $this->_get_expected_pageinfo(); + $info['id'] = 'wiki:syntax'; + $info['namespace'] = 'wiki'; + $info['meta'] = p_get_metadata($ID); + $info['rev'] = $REV; + $info['filepath'] = str_replace('pages','attic',substr($filename,0,-3).$REV.'.txt.gz'); + + $this->assertEquals($info, pageinfo()); + $this->assertEquals($rev-100, $REV); + } + + /** + * check info keys and values with $RANGE + */ + function test_range(){ + global $ID,$conf,$REV,$RANGE; + + $ID = 'wiki:syntax'; + $filename = $conf['datadir'].'/wiki/syntax.txt'; + $rev = filemtime($filename); + $range = '1000-2000'; + + $info = $this->_get_expected_pageinfo(); + $info['id'] = 'wiki:syntax'; + $info['namespace'] = 'wiki'; + $info['exists'] = true; + $info['lastmod'] = $rev; + $info['meta'] = p_get_metadata($ID); + $info['filepath'] = $filename; + + // check $RANGE without $REV + // expected result $RANGE unchanged + $RANGE = $range; + + $this->assertEquals($info, pageinfo()); + $this->assertFalse(isset($REV)); + $this->assertEquals($range,$RANGE); + + // check $RANGE with $REV = current + // expected result: $RANGE unchanged, $REV cleared + $REV = $rev; + $info['rev'] = ''; + + $this->assertEquals($info, pageinfo()); + $this->assertEquals('',$REV); + $this->assertEquals($range,$RANGE); + + // check with a real $REV + // expected result: $REV and $RANGE are cleared + $REV = $rev - 100; + + $this->assertEquals($info, pageinfo()); + $this->assertEquals('',$REV); + $this->assertEquals('',$RANGE); + } + + /** + * test editor entry and external edit + */ + function test_editor_and_externaledits(){ + global $ID,$conf; + $ID = 'wiki:syntax'; + $filename = $conf['datadir'].'/wiki/syntax.txt'; + $rev = filemtime($filename); + + $info = $this->_get_expected_pageinfo(); + $info['id'] = 'wiki:syntax'; + $info['namespace'] = 'wiki'; + $info['filepath'] = $filename; + $info['exists'] = true; + $info['lastmod'] = $rev; + $info['meta'] = p_get_metadata($ID); // need $INFO set correctly for addLogEntry() + + global $INFO; + $INFO = $info; + + // add an editor for the current version of $ID + addLogEntry($rev, $ID); + + $info['meta'] = p_get_metadata($ID); + $info['editor'] = $_SERVER['REMOTE_USER']; + $info['user'] = $_SERVER['REMOTE_USER']; + $info['ip'] = $_SERVER['REMOTE_ADDR']; + $info['sum'] = ''; + + // with an editor ... + $this->assertEquals($info, pageinfo()); + + // clear the meta['last_change'] value, pageinfo should restore it + p_set_metadata($ID,array('last_change' => false)); + + $this->assertEquals($info, pageinfo()); + $this->assertEquals($info['meta']['last_change'], p_get_metadata($ID,'last_change')); + + // fake an external edit, pageinfo should clear the last change from meta data + // and not return any editor data + $now = time()+10; + touch($filename,$now); + + $info['lastmod'] = $now; + $info['meta']['last_change'] = false; + $info['ip'] = null; + $info['user'] = null; + $info['sum'] = null; + $info['editor'] = null; + + $this->assertEquals($info, pageinfo()); + $this->assertEquals($info['meta'], p_get_metadata($ID)); // check metadata has been updated correctly + } + + /** + * check draft + */ + function test_draft(){ + global $ID,$conf; + $ID = 'wiki:syntax'; + $filename = $conf['datadir'].'/wiki/syntax.txt'; + $rev = filemtime($filename); + + $info = $this->_get_expected_pageinfo(); + $info['id'] = 'wiki:syntax'; + $info['namespace'] = 'wiki'; + $info['filepath'] = $filename; + $info['exists'] = true; + $info['lastmod'] = $rev; + $info['meta'] = p_get_metadata($ID); + + // setup a draft, make it more recent than the current page + // - pageinfo should recognise it and keep it + $draft = getCacheName($info['client'].$ID,'.draft'); + touch($draft,$rev + 10); + + $info['draft'] = $draft; + + $this->assertEquals($info, pageinfo()); + $this->assertFileExists($draft); + + // make the draft older than the current page + // - pageinfo should remove it and not return the 'draft' key + touch($draft,$rev - 10); + unset($info['draft']); + + $this->assertEquals($info, pageinfo()); + $this->assertFalse(file_exists($draft)); + } + + /** + * check ismobile + */ + function test_ismobile(){ + global $ID,$conf; + $ID = 'wiki:start'; + + $info = $this->_get_expected_pageinfo(); + $info['id'] = 'wiki:start'; + $info['namespace'] = 'wiki'; + $info['filepath'] = $conf['datadir'].'/wiki/start.txt'; + + // overkill, ripped from clientismobile() as we aren't testing detection - but forcing it + $_SERVER['HTTP_X_WAP_PROFILE'] = 'a fake url'; + $_SERVER['HTTP_ACCEPT'] .= ';wap'; + $_SERVER['HTTP_USER_AGENT'] = 'blackberry,symbian,hand,mobi,phone'; + + $info['ismobile'] = clientismobile(); + + $this->assertTrue(clientismobile()); // ensure THIS test fails if clientismobile() returns false + $this->assertEquals($info, pageinfo()); // it would be a test failure not a pageinfo failure. + } +} + +//Setup VIM: ex: et ts=4 : -- cgit v1.2.3 From f00926dd85886b81600997f6b4fbc69af9deacad Mon Sep 17 00:00:00 2001 From: Andreas Gohr <andi@splitbrain.org> Date: Fri, 22 Feb 2013 09:46:43 +0100 Subject: little change to syntax we had on the life site --- data/pages/wiki/syntax.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/data/pages/wiki/syntax.txt b/data/pages/wiki/syntax.txt index 55bbabab2..f2c2864ed 100644 --- a/data/pages/wiki/syntax.txt +++ b/data/pages/wiki/syntax.txt @@ -83,9 +83,9 @@ Windows shares like [[\\server\share|this]] are recognized, too. Please note tha Notes: * For security reasons direct browsing of windows shares only works in Microsoft Internet Explorer per default (and only in the "local zone"). - * For Mozilla and Firefox it can be enabled through different workaround mentioned in the [[http://kb.mozillazine.org/Links_to_local_pages_do_not_work|Mozilla Knowledge Base]]. However, there will still be a JavaScript warning about trying to open a Windows Share. To remove this warning (for all users), put the following line in ''conf/local.protected.php'': + * For Mozilla and Firefox it can be enabled through different workaround mentioned in the [[http://kb.mozillazine.org/Links_to_local_pages_do_not_work|Mozilla Knowledge Base]]. However, there will still be a JavaScript warning about trying to open a Windows Share. To remove this warning (for all users), put the following line in ''conf/userscript.js'': - $lang['js']['nosmblinks'] = ''; + LANG.nosmblinks = ''; ==== Image Links ==== -- cgit v1.2.3 From b9b9b28b2edb54f9a3b3c5b9c69fd37a729007ec Mon Sep 17 00:00:00 2001 From: Michael Hamann <michael@content-space.de> Date: Sat, 23 Feb 2013 12:35:57 +0100 Subject: Fix double encoding in rss syntax FS#2731 --- inc/parser/xhtml.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inc/parser/xhtml.php b/inc/parser/xhtml.php index 4dd8c5e78..84a999e56 100644 --- a/inc/parser/xhtml.php +++ b/inc/parser/xhtml.php @@ -889,7 +889,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer { // title is escaped by SimplePie, we unescape here because it // is escaped again in externallink() FS#1705 $this->externallink($item->get_permalink(), - htmlspecialchars_decode($item->get_title())); + html_entity_decode($item->get_title(), ENT_QUOTES, 'UTF-8')); }else{ $this->doc .= ' '.$item->get_title(); } -- cgit v1.2.3 From d00152be83dd30024aa5dd89b9ad9a70eb25d80f Mon Sep 17 00:00:00 2001 From: Lorenzo Radaelli <lorenzo@mfr-trade.it> Date: Sun, 24 Feb 2013 10:36:18 +0100 Subject: Italian language update --- inc/lang/it/lang.php | 8 ++++++++ lib/plugins/authad/lang/it/settings.php | 5 +++++ lib/plugins/authldap/lang/it/settings.php | 5 +++++ lib/plugins/authmysql/lang/it/settings.php | 5 +++++ lib/plugins/authpgsql/lang/it/settings.php | 5 +++++ lib/plugins/config/lang/it/lang.php | 1 + 6 files changed, 29 insertions(+) create mode 100644 lib/plugins/authad/lang/it/settings.php create mode 100644 lib/plugins/authldap/lang/it/settings.php create mode 100644 lib/plugins/authmysql/lang/it/settings.php create mode 100644 lib/plugins/authpgsql/lang/it/settings.php diff --git a/inc/lang/it/lang.php b/inc/lang/it/lang.php index 307e7292f..92bf5fea8 100644 --- a/inc/lang/it/lang.php +++ b/inc/lang/it/lang.php @@ -205,6 +205,7 @@ $lang['mail_new_user'] = 'nuovo utente:'; $lang['mail_upload'] = 'file caricato:'; $lang['changes_type'] = 'Guarda cambiamenti di'; $lang['pages_changes'] = 'Pagine'; +$lang['media_changes'] = 'File multimediali'; $lang['both_changes'] = 'Sia pagine che media files'; $lang['qb_bold'] = 'Grassetto'; $lang['qb_italic'] = 'Corsivo'; @@ -263,6 +264,8 @@ $lang['subscr_m_unsubscribe'] = 'Rimuovi sottoscrizione'; $lang['subscr_m_subscribe'] = 'Sottoscrivi'; $lang['subscr_m_receive'] = 'Ricevi'; $lang['subscr_style_every'] = 'email per ogni modifica'; +$lang['subscr_style_digest'] = 'email di riassunto dei cambiamenti per ogni pagina (ogni %.2f giorni)'; +$lang['subscr_style_list'] = 'lista delle pagine cambiate dall\'ultima email (ogni %.2f giorni)'; $lang['authmodfailed'] = 'La configurazione dell\'autenticazione non è corretta. Informa l\'amministratore di questo wiki.'; $lang['authtempfail'] = 'L\'autenticazione è temporaneamente non disponibile. Se questa situazione persiste, informa l\'amministratore di questo wiki.'; $lang['authpwdexpire'] = 'La tua password scadrà in %d giorni, dovresti cambiarla quanto prima.'; @@ -290,6 +293,9 @@ $lang['i_pol1'] = 'Wiki Pubblico (lettura per tutti, scrittura e $lang['i_pol2'] = 'Wiki Chiuso (lettura, scrittura, caricamento file solamente per gli utenti registrati)'; $lang['i_retry'] = 'Riprova'; $lang['i_license'] = 'Per favore scegli la licenza sotto cui vuoi rilasciare il contenuto:'; +$lang['i_license_none'] = 'Non mostrare informazioni sulla licenza'; +$lang['i_pop_field'] = 'Per favore, aiutaci ad incrementare la conoscenza di DokuWiki:'; +$lang['i_pop_label'] = 'Mensilmente invia una statistica d\'uso anonima di DokuWiki agli sviluppatori'; $lang['recent_global'] = 'Stai attualmente vedendo le modifiche effettuate nell\'area <b>%s</b>. Puoi anche <a href="%s">vedere le modifiche recenti dell\'intero wiki</a>.'; $lang['years'] = '%d anni fa'; $lang['months'] = '%d mesi fa'; @@ -314,8 +320,10 @@ $lang['media_files'] = 'File in %s'; $lang['media_upload'] = 'Upload al %s'; $lang['media_search'] = 'Cerca in %s'; $lang['media_view'] = '%s'; +$lang['media_viewold'] = '%s a %s'; $lang['media_edit'] = 'Modifica %s'; $lang['media_history'] = 'Storia di %s'; +$lang['media_meta_edited'] = 'metadata modificati'; $lang['media_perm_read'] = 'Spiacente, non hai abbastanza privilegi per leggere i files.'; $lang['media_perm_upload'] = 'Spiacente, non hai abbastanza privilegi per caricare files.'; $lang['media_update'] = 'Carica nuova versione'; diff --git a/lib/plugins/authad/lang/it/settings.php b/lib/plugins/authad/lang/it/settings.php new file mode 100644 index 000000000..10ae72f87 --- /dev/null +++ b/lib/plugins/authad/lang/it/settings.php @@ -0,0 +1,5 @@ +<?php +/** + * Italian language file + * + */ diff --git a/lib/plugins/authldap/lang/it/settings.php b/lib/plugins/authldap/lang/it/settings.php new file mode 100644 index 000000000..10ae72f87 --- /dev/null +++ b/lib/plugins/authldap/lang/it/settings.php @@ -0,0 +1,5 @@ +<?php +/** + * Italian language file + * + */ diff --git a/lib/plugins/authmysql/lang/it/settings.php b/lib/plugins/authmysql/lang/it/settings.php new file mode 100644 index 000000000..10ae72f87 --- /dev/null +++ b/lib/plugins/authmysql/lang/it/settings.php @@ -0,0 +1,5 @@ +<?php +/** + * Italian language file + * + */ diff --git a/lib/plugins/authpgsql/lang/it/settings.php b/lib/plugins/authpgsql/lang/it/settings.php new file mode 100644 index 000000000..10ae72f87 --- /dev/null +++ b/lib/plugins/authpgsql/lang/it/settings.php @@ -0,0 +1,5 @@ +<?php +/** + * Italian language file + * + */ diff --git a/lib/plugins/config/lang/it/lang.php b/lib/plugins/config/lang/it/lang.php index 751e5ee95..62dd00f0c 100644 --- a/lib/plugins/config/lang/it/lang.php +++ b/lib/plugins/config/lang/it/lang.php @@ -39,6 +39,7 @@ $lang['_editing'] = 'Impostazioni Modifica'; $lang['_links'] = 'Impostazioni Collegamenti'; $lang['_media'] = 'Impostazioni File'; $lang['_notifications'] = 'Impostazioni di notifica'; +$lang['_syndication'] = 'Impostazioni di collaborazione'; $lang['_advanced'] = 'Impostazioni Avanzate'; $lang['_network'] = 'Impostazioni Rete'; $lang['_plugin_sufix'] = 'Impostazioni Plugin'; -- cgit v1.2.3 From 292f6d8bd60b850ddf729e3b609b601fa6f9fcb3 Mon Sep 17 00:00:00 2001 From: lainme <lainme993@gmail.com> Date: Sun, 24 Feb 2013 10:37:45 +0100 Subject: Simplified Chinese language update --- inc/lang/zh/lang.php | 3 +++ lib/plugins/authad/lang/zh/settings.php | 18 ++++++++++++++ lib/plugins/authldap/lang/zh/settings.php | 20 +++++++++++++++ lib/plugins/authmysql/lang/zh/settings.php | 40 ++++++++++++++++++++++++++++++ lib/plugins/authpgsql/lang/zh/settings.php | 37 +++++++++++++++++++++++++++ 5 files changed, 118 insertions(+) create mode 100644 lib/plugins/authad/lang/zh/settings.php create mode 100644 lib/plugins/authldap/lang/zh/settings.php create mode 100644 lib/plugins/authmysql/lang/zh/settings.php create mode 100644 lib/plugins/authpgsql/lang/zh/settings.php diff --git a/inc/lang/zh/lang.php b/inc/lang/zh/lang.php index e6e568cb5..f404010ba 100644 --- a/inc/lang/zh/lang.php +++ b/inc/lang/zh/lang.php @@ -298,6 +298,9 @@ $lang['i_pol1'] = '公共的维基(任何人都有读的权限 $lang['i_pol2'] = '关闭的维基(只有注册用户才有读、写、上传的权限)'; $lang['i_retry'] = '重试'; $lang['i_license'] = '请选择您希望的内容发布许可协议:'; +$lang['i_license_none'] = '不要显示任何许可协议信息'; +$lang['i_pop_field'] = '请帮助我们改进 Dokuwiki 的体验:'; +$lang['i_pop_label'] = '每个月向 Dokuwiki 开发者发送匿名的使用数据'; $lang['recent_global'] = '您当前看到的是<b>%s</b> 名称空间的变动。你还可以在<a href="%s">查看整个维基的近期变动</a>。'; $lang['years'] = '%d年前'; $lang['months'] = '%d月前'; diff --git a/lib/plugins/authad/lang/zh/settings.php b/lib/plugins/authad/lang/zh/settings.php new file mode 100644 index 000000000..9fd3c4e35 --- /dev/null +++ b/lib/plugins/authad/lang/zh/settings.php @@ -0,0 +1,18 @@ +<?php +/** + * Chinese language file + * + * @author lainme <lainme993@gmail.com> + */ +$lang['account_suffix'] = '您的账户后缀。例如 <code>@my.domain.org</code>'; +$lang['base_dn'] = '您的基本分辨名。例如 <code>DC=my,DC=domain,DC=org</code>'; +$lang['domain_controllers'] = '逗号分隔的域名控制器列表。例如 <code>srv1.domain.org,srv2.domain.org</code>'; +$lang['ad_username'] = '一个活动目录的特权用户,可以查看其他所有用户的数据。可选,但对某些活动例如发送订阅邮件是必须的。'; +$lang['ad_password'] = '上述用户的密码。'; +$lang['sso'] = '是否使用经由 Kerberos 和 NTLM 的 Single-Sign-On?'; +$lang['real_primarygroup'] = ' 是否解析真实的主要组,而不是假设为“域用户” (较慢)'; +$lang['use_ssl'] = '使用 SSL 连接?如果是,不要激活下面的 TLS。'; +$lang['use_tls'] = '使用 TLS 连接?如果是 ,不要激活上面的 SSL。'; +$lang['debug'] = '有错误时显示额外的调试信息?'; +$lang['expirywarn'] = '提前多少天警告用户密码即将到期。0 则禁用。'; +$lang['additional'] = '需要从用户数据中获取的额外 AD 属性的列表,以逗号分隔。用于某些插件。'; diff --git a/lib/plugins/authldap/lang/zh/settings.php b/lib/plugins/authldap/lang/zh/settings.php new file mode 100644 index 000000000..e84511b42 --- /dev/null +++ b/lib/plugins/authldap/lang/zh/settings.php @@ -0,0 +1,20 @@ +<?php +/** + * Chinese language file + * + * @author lainme <lainme993@gmail.com> + */ +$lang['server'] = '您的 LDAP 服务器。填写主机名 (<code>localhost</code>) 或者完整的 URL (<code>ldap://server.tld:389</code>)'; +$lang['port'] = 'LDAP 服务器端口 (如果上面没有给出完整的 URL)'; +$lang['usertree'] = '何处查找用户账户。例如 <code>ou=People, dc=server, dc=tld</code>'; +$lang['grouptree'] = '何处查找用户组。例如 <code>ou=Group, dc=server, dc=tld</code>'; +$lang['userfilter'] = '用于搜索用户账户的 LDAP 筛选器。例如 <code>(&(uid=%{user})(objectClass=posixAccount))</code>'; +$lang['groupfilter'] = '用于搜索组的 LDAP 筛选器。例如 <code>(&(objectClass=posixGroup)(|(gidNumber=%{gid})(memberUID=%{user})))</code>'; +$lang['version'] = '使用的协议版本。您或许需要设置为 <code>3</code>'; +$lang['starttls'] = '使用 TLS 连接?'; +$lang['referrals'] = '是否允许引用 (referrals)?'; +$lang['binddn'] = '一个可选的绑定用户的 DN (如果匿名绑定不满足要求)。例如 Eg. <code>cn=admin, dc=my, dc=home</code>'; +$lang['bindpw'] = '上述用户的密码'; +$lang['userscope'] = '限制用户搜索的范围'; +$lang['groupscope'] = '限制组搜索的范围'; +$lang['debug'] = '有错误时显示额外的调试信息'; diff --git a/lib/plugins/authmysql/lang/zh/settings.php b/lib/plugins/authmysql/lang/zh/settings.php new file mode 100644 index 000000000..43cfbb3c0 --- /dev/null +++ b/lib/plugins/authmysql/lang/zh/settings.php @@ -0,0 +1,40 @@ +<?php +/** + * Chinese language file + * + * @author lainme <lainme993@gmail.com> + */ +$lang['server'] = '您的 MySQL 服务器'; +$lang['user'] = 'MySQL 用户名'; +$lang['password'] = '上述用户的密码'; +$lang['database'] = '使用的数据库'; +$lang['debug'] = '显示额外调试信息'; +$lang['forwardClearPass'] = '将用户密码以明文形式传送给下面的 SQL 语句,而不使用 passcrypt 密码加密选项'; +$lang['TablesToLock'] = '在写操作时需要锁定的数据表列表,以逗号分隔'; +$lang['checkPass'] = '检查密码的 SQL 语句'; +$lang['getUserInfo'] = '获取用户信息的 SQL 语句'; +$lang['getGroups'] = '或许用户的组成员身份的 SQL 语句'; +$lang['getUsers'] = '列出所有用户的 SQL 语句'; +$lang['FilterLogin'] = '根据登录名筛选用户的 SQL 子句'; +$lang['FilterName'] = '根据全名筛选用户的 SQL 子句'; +$lang['FilterEmail'] = '根据电子邮件地址筛选用户的 SQL 子句'; +$lang['FilterGroup'] = '根据组成员身份筛选用户的 SQL 子句'; +$lang['SortOrder'] = '对用户排序的 SQL 子句'; +$lang['addUser'] = '添加新用户的 SQL 语句'; +$lang['addGroup'] = '添加新组的 SQL 语句'; +$lang['addUserGroup'] = '将用户添加到现有组的 SQL 语句'; +$lang['delGroup'] = '删除组的 SQL 语句'; +$lang['getUserID'] = '获取用户主键的 SQL 语句'; +$lang['delUser'] = '删除用户的 SQL 语句'; +$lang['delUserRefs'] = '从所有组中删除一个用户的 SQL 语句'; +$lang['updateUser'] = '更新用户信息的 SQL 语句'; +$lang['UpdateLogin'] = '更新用户登录名的 Update 子句'; +$lang['UpdatePass'] = '更新用户密码的 Update 子句'; +$lang['UpdateEmail'] = '更新用户电子邮件地址的 Update 子句'; +$lang['UpdateName'] = '更新用户全名的 Update 子句'; +$lang['UpdateTarget'] = '更新时识别用户的 Limit 子句'; +$lang['delUserGroup'] = '从指定组删除用户的 SQL 语句'; +$lang['getGroupID'] = '获取指定组主键的 SQL 语句'; +$lang['debug_o_0'] = '无'; +$lang['debug_o_1'] = '仅在有错误时'; +$lang['debug_o_2'] = '所有 SQL 查询'; diff --git a/lib/plugins/authpgsql/lang/zh/settings.php b/lib/plugins/authpgsql/lang/zh/settings.php new file mode 100644 index 000000000..dc7223d89 --- /dev/null +++ b/lib/plugins/authpgsql/lang/zh/settings.php @@ -0,0 +1,37 @@ +<?php +/** + * Chinese language file + * + * @author lainme <lainme993@gmail.com> + */ +$lang['server'] = '您的 PostgreSQL 服务器'; +$lang['port'] = '您的 PostgreSQL 服务器端口'; +$lang['user'] = 'PostgreSQL 用户名'; +$lang['password'] = '上述用户的密码'; +$lang['database'] = '使用的数据库'; +$lang['debug'] = '显示额外调试信息'; +$lang['forwardClearPass'] = '将用户密码以明文形式传送给下面的 SQL 语句,而不使用 passcrypt 密码加密选项'; +$lang['checkPass'] = '检查密码的 SQL 语句'; +$lang['getUserInfo'] = '获取用户信息的 SQL 语句'; +$lang['getGroups'] = '获取用户的组成员身份的 SQL 语句'; +$lang['getUsers'] = '列出所有用户的 SQL 语句'; +$lang['FilterLogin'] = '根据登录名筛选用户的 SQL 子句'; +$lang['FilterName'] = '根据全名筛选用户的 SQL 子句'; +$lang['FilterEmail'] = '根据电子邮件地址筛选用户的 SQL 子句'; +$lang['FilterGroup'] = '根据组成员身份筛选用户的 SQL 子句'; +$lang['SortOrder'] = '对用户排序的 SQL 子句'; +$lang['addUser'] = '添加新用户的 SQL 语句'; +$lang['addGroup'] = '添加新组的 SQL 语句'; +$lang['addUserGroup'] = '将用户添加到现有组的 SQL 语句'; +$lang['delGroup'] = '删除组的 SQL 语句'; +$lang['getUserID'] = '获取用户主键的 SQL 语句'; +$lang['delUser'] = '删除用户的 SQL 语句'; +$lang['delUserRefs'] = '从所有组中删除一个用户的 SQL 语句'; +$lang['updateUser'] = '更新用户信息的 SQL 语句'; +$lang['UpdateLogin'] = '更新用户登录名的 Update 子句'; +$lang['UpdatePass'] = '更新用户密码的 Update 子句'; +$lang['UpdateEmail'] = '更新用户电子邮件地址的 Update 子句'; +$lang['UpdateName'] = '更新用户全名的 Update 子句'; +$lang['UpdateTarget'] = '更新时识别用户的 Limit 子句'; +$lang['delUserGroup'] = '从指定组删除用户的 SQL 语句'; +$lang['getGroupID'] = '获取指定组主键的 SQL 语句'; -- cgit v1.2.3 From 338ac38c748d94f32ca394dc604dda97ce6762e3 Mon Sep 17 00:00:00 2001 From: Andreas Gohr <andi@splitbrain.org> Date: Sun, 24 Feb 2013 10:39:52 +0100 Subject: fixed typos --- lib/plugins/authldap/lang/en/settings.php | 4 ++-- lib/plugins/authpgsql/lang/en/settings.php | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/plugins/authldap/lang/en/settings.php b/lib/plugins/authldap/lang/en/settings.php index 0bb397be5..ddedf8ae3 100644 --- a/lib/plugins/authldap/lang/en/settings.php +++ b/lib/plugins/authldap/lang/en/settings.php @@ -1,14 +1,14 @@ <?php $lang['server'] = 'Your LDAP server. Either hostname (<code>localhost</code>) or full qualified URL (<code>ldap://server.tld:389</code>)'; $lang['port'] = 'LDAP server port if no full URL was given above'; -$lang['usertree'] = 'Where to finde the user accounts. Eg. <code>ou=People, dc=server, dc=tld</code>'; +$lang['usertree'] = 'Where to find the user accounts. Eg. <code>ou=People, dc=server, dc=tld</code>'; $lang['grouptree'] = 'Where to find the user groups. Eg. <code>ou=Group, dc=server, dc=tld</code>'; $lang['userfilter'] = 'LDAP filter to search for user accounts. Eg. <code>(&(uid=%{user})(objectClass=posixAccount))</code>'; $lang['groupfilter'] = 'LDAP filter to search for groups. Eg. <code>(&(objectClass=posixGroup)(|(gidNumber=%{gid})(memberUID=%{user})))</code>'; $lang['version'] = 'The protocol version to use. You may need to set this to <code>3</code>'; $lang['starttls'] = 'Use TLS connections?'; $lang['referrals'] = 'Shall referrals be followed?'; -$lang['binddn'] = 'DN of an ptional bind user if anonymous bind is not sufficient. Eg. <code>cn=admin, dc=my, dc=home</code>'; +$lang['binddn'] = 'DN of an optional bind user if anonymous bind is not sufficient. Eg. <code>cn=admin, dc=my, dc=home</code>'; $lang['bindpw'] = 'Password of above user'; $lang['userscope'] = 'Limit search scope for user search'; $lang['groupscope'] = 'Limit search scope for group search'; diff --git a/lib/plugins/authpgsql/lang/en/settings.php b/lib/plugins/authpgsql/lang/en/settings.php index 74a1c1cc9..8c048fa0f 100644 --- a/lib/plugins/authpgsql/lang/en/settings.php +++ b/lib/plugins/authpgsql/lang/en/settings.php @@ -20,7 +20,7 @@ $lang['addUser'] = 'SQL statement to add a new user'; $lang['addGroup'] = 'SQL statement to add a new group'; $lang['addUserGroup'] = 'SQL statment to add a user to an existing group'; $lang['delGroup'] = 'SQL statement to remove a group'; -$lang['getUserID'] = 'SQL statement to get the primary ey of a user'; +$lang['getUserID'] = 'SQL statement to get the primary key of a user'; $lang['delUser'] = 'SQL statement to delete a user'; $lang['delUserRefs'] = 'SQL statement to remove a user from all groups'; $lang['updateUser'] = 'SQL statement to update a user profile'; -- cgit v1.2.3 From e0d6578c4fcc8130316f82645446333b06849a0e Mon Sep 17 00:00:00 2001 From: Christopher Smith <chris@jalakai.co.uk> Date: Mon, 18 Feb 2013 17:32:13 +0000 Subject: fix security caution for 'remote' setting (was 'xmlrpc') --- lib/plugins/config/settings/config.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/plugins/config/settings/config.class.php b/lib/plugins/config/settings/config.class.php index e5e09d8f8..8eb99284d 100644 --- a/lib/plugins/config/settings/config.class.php +++ b/lib/plugins/config/settings/config.class.php @@ -370,7 +370,7 @@ if (!class_exists('setting')) { var $_cautionList = array( 'basedir' => 'danger', 'baseurl' => 'danger', 'savedir' => 'danger', 'cookiedir' => 'danger', 'useacl' => 'danger', 'authtype' => 'danger', 'superuser' => 'danger', 'userewrite' => 'danger', 'start' => 'warning', 'camelcase' => 'warning', 'deaccent' => 'warning', 'sepchar' => 'warning', 'compression' => 'warning', 'xsendfile' => 'warning', 'renderer_xhtml' => 'warning', 'fnencode' => 'warning', - 'allowdebug' => 'security', 'htmlok' => 'security', 'phpok' => 'security', 'iexssprotect' => 'security', 'xmlrpc' => 'security', 'fullpath' => 'security' + 'allowdebug' => 'security', 'htmlok' => 'security', 'phpok' => 'security', 'iexssprotect' => 'security', 'remote' => 'security', 'fullpath' => 'security' ); function setting($key, $params=null) { -- cgit v1.2.3 From fd215c0fad082b21c598826c70aa0c5f1e078440 Mon Sep 17 00:00:00 2001 From: Michael Hamann <michael@content-space.de> Date: Sun, 24 Feb 2013 14:03:13 +0100 Subject: Fix sample handling in toolbar in tb_format FS#2691 The previous fix in e38f3066cedb80722b3488e7ab3b2809b6db5363 fixed this bug only in tb_formatln. --- lib/scripts/toolbar.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/scripts/toolbar.js b/lib/scripts/toolbar.js index 059a4ba5c..6d75215e0 100644 --- a/lib/scripts/toolbar.js +++ b/lib/scripts/toolbar.js @@ -72,7 +72,7 @@ function initToolbar(tbid,edid,tb, allowblock){ * @author Andreas Gohr <andi@splitbrain.org> */ function tb_format(btn, props, edid) { - var sample = props.title || props.sample; + var sample = props.sample || props.title; insertTags(edid, fixtxt(props.open), fixtxt(props.close), -- cgit v1.2.3 From 8770796f2519e41d394b3d774bc831b9315e10a8 Mon Sep 17 00:00:00 2001 From: Anika Henke <anika@selfthinker.org> Date: Sun, 24 Feb 2013 19:10:48 +0000 Subject: make scrolling possible in media manager on smaller screens (FS#2723) --- lib/tpl/dokuwiki/css/mobile.css | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/tpl/dokuwiki/css/mobile.css b/lib/tpl/dokuwiki/css/mobile.css index 88333c012..e1d4dda72 100644 --- a/lib/tpl/dokuwiki/css/mobile.css +++ b/lib/tpl/dokuwiki/css/mobile.css @@ -89,6 +89,10 @@ .dokuwiki div.page { padding: 1em; } +/* enable horizontal scrolling in media manager */ +.mode_media div.page { + overflow: auto; +} /* _edit */ .dokuwiki div.section_highlight { -- cgit v1.2.3 From aaec90e43993614263ee747a827f0c8555698958 Mon Sep 17 00:00:00 2001 From: Michael Hamann <michael@content-space.de> Date: Mon, 25 Feb 2013 00:42:45 +0100 Subject: Fix search button in rtl languages in Chrome For some reason without position: relative the search button is hidden in rtl languages. --- lib/tpl/dokuwiki/css/design.css | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/tpl/dokuwiki/css/design.css b/lib/tpl/dokuwiki/css/design.css index 2c2109228..2eb357a59 100644 --- a/lib/tpl/dokuwiki/css/design.css +++ b/lib/tpl/dokuwiki/css/design.css @@ -205,6 +205,7 @@ background-position: 5px 0; margin-left: 0; margin-right: -20px; + position: relative; } #dokuwiki__sitetools ul { -- cgit v1.2.3 From 058fd09655df42c72f3c447e3b9561e4909e978d Mon Sep 17 00:00:00 2001 From: Michael Hamann <michael@content-space.de> Date: Mon, 25 Feb 2013 00:45:46 +0100 Subject: Fix current mode icons in rtl languages --- lib/tpl/dokuwiki/css/pagetools.css | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/tpl/dokuwiki/css/pagetools.css b/lib/tpl/dokuwiki/css/pagetools.css index 60dc43fb1..0c31e283f 100644 --- a/lib/tpl/dokuwiki/css/pagetools.css +++ b/lib/tpl/dokuwiki/css/pagetools.css @@ -222,7 +222,7 @@ [dir=rtl] #dokuwiki__pagetools ul li a.revs:hover, [dir=rtl] #dokuwiki__pagetools ul li a.revs:active, [dir=rtl] #dokuwiki__pagetools ul li a.revs:focus, -.mode_revisions [dir=rtl] #dokuwiki__pagetools ul li a.revs { +[dir=rtl] .mode_revisions #dokuwiki__pagetools ul li a.revs { background-position: left -585px; } @@ -241,7 +241,7 @@ [dir=rtl] #dokuwiki__pagetools ul li a.backlink:hover, [dir=rtl] #dokuwiki__pagetools ul li a.backlink:active, [dir=rtl] #dokuwiki__pagetools ul li a.backlink:focus, -.mode_backlink [dir=rtl] #dokuwiki__pagetools ul li a.backlink { +[dir=rtl] .mode_backlink #dokuwiki__pagetools ul li a.backlink { background-position: left -675px; } @@ -277,7 +277,7 @@ [dir=rtl] #dokuwiki__pagetools ul li a.revert:hover, [dir=rtl] #dokuwiki__pagetools ul li a.revert:active, [dir=rtl] #dokuwiki__pagetools ul li a.revert:focus, -.mode_revert [dir=rtl] #dokuwiki__pagetools ul li a.revert { +[dir=rtl] .mode_revert #dokuwiki__pagetools ul li a.revert { background-position: left -495px; } @@ -296,7 +296,7 @@ [dir=rtl] #dokuwiki__pagetools ul li a.subscribe:hover, [dir=rtl] #dokuwiki__pagetools ul li a.subscribe:active, [dir=rtl] #dokuwiki__pagetools ul li a.subscribe:focus, -.mode_subscribe [dir=rtl] #dokuwiki__pagetools ul li a.subscribe { +[dir=rtl] .mode_subscribe #dokuwiki__pagetools ul li a.subscribe { background-position: left -765px; } -- cgit v1.2.3 From c97b0f20e860cdd8e4dbb72b14ca1588ec7abda1 Mon Sep 17 00:00:00 2001 From: Michael Hamann <michael@content-space.de> Date: Mon, 25 Feb 2013 00:55:01 +0100 Subject: Fix pagetools display without images FS#2634 This makes the pagetools in non-hover/static/active-mode use another image replacement technique that falls back to the text when images are disabled. Furthermore this fixes the :focused-display in IE7 by using :active, too. --- lib/tpl/dokuwiki/css/pagetools.css | 97 ++++++++++++++++++++++++++++++++------ 1 file changed, 82 insertions(+), 15 deletions(-) diff --git a/lib/tpl/dokuwiki/css/pagetools.css b/lib/tpl/dokuwiki/css/pagetools.css index 0c31e283f..41f876d48 100644 --- a/lib/tpl/dokuwiki/css/pagetools.css +++ b/lib/tpl/dokuwiki/css/pagetools.css @@ -72,43 +72,65 @@ display: block; min-height: 20px; /* 30 - 2x5 */ line-height: 20px; - padding: 5px 40px 5px 5px; - background-image: url(images/pagetools-sprite.png); + padding: 0; background-position: right 0; background-repeat: no-repeat; /* add transparent border to prevent jumping when proper border is added on focus */ border: 1px solid transparent; white-space: nowrap; + width: 30px; + height: 30px; + overflow: hidden; + margin-left: auto; /* align right if the ul is larger because one item is focused */ } -[dir=rtl] #dokuwiki__pagetools ul li a { - padding: 5px 5px 5px 40px; - background-position: left 0; + +#dokuwiki__pagetools ul li a:before { + content: url(images/pagetools-sprite.png); + display: inline-block; + font-size: 0; + line-height: 0; } -/* hide labels accessibly when neither on hover nor on focus */ -#dokuwiki__pagetools ul li a span { - position: absolute; - clip: rect(0 0 0 0); /* IE7, IE6 */ - clip: rect(0, 0, 0, 0); +[dir=rtl] #dokuwiki__pagetools ul li a { + background-position: left 0; + margin-right: auto; + margin-left: 0; } /* show all tools on hover and individual tools on focus */ #dokuwiki__pagetools:hover ul, -#dokuwiki__pagetools ul li a:focus { +#dokuwiki__pagetools ul li a:focus, +#dokuwiki__pagetools ul li a:active { background-color: __background__; border-color: __border__; border-radius: 2px; box-shadow: 2px 2px 2px __text_alt__; } + +#dokuwiki__pagetools:hover ul li a, +#dokuwiki__pagetools ul li a:focus, +#dokuwiki__pagetools ul li a:active { + width: auto; + height: auto; + overflow: visible; + padding: 5px 40px 5px 5px; + background-image: url(images/pagetools-sprite.png); +} + +#dokuwiki__pagetools:hover ul li a:before, +#dokuwiki__pagetools ul li a:focus:before { + content: none; +} + [dir=rtl] #dokuwiki__pagetools:hover ul, [dir=rtl] #dokuwiki__pagetools ul li a:focus { box-shadow: -2px 2px 2px __text_alt__; } -#dokuwiki__pagetools:hover ul li a span, -#dokuwiki__pagetools ul li a:focus span { - display: inline; - position: static; +[dir=rtl] #dokuwiki__pagetools:hover li a, +[dir=rtl] #dokuwiki__pagetools ul li a:focus, +[dir=rtl] #dokuwiki__pagetools ul li a:active { + padding: 5px 5px 5px 40px; } #dokuwiki__pagetools ul li a:hover, @@ -139,6 +161,9 @@ background-position: left -45px; } +#dokuwiki__pagetools ul li a.create:before { + margin-top: -90px; +} #dokuwiki__pagetools ul li a.create { background-position: right -90px; } @@ -159,6 +184,9 @@ #dokuwiki__pagetools ul li a.show { background-position: right -270px; } +#dokuwiki__pagetools ul li a.show:before { + margin-top: -270px; +} #dokuwiki__pagetools ul li a.show:hover, #dokuwiki__pagetools ul li a.show:active, #dokuwiki__pagetools ul li a.show:focus { @@ -176,6 +204,9 @@ #dokuwiki__pagetools ul li a.source { background-position: right -360px; } +#dokuwiki__pagetools ul li a.source:before { + margin-top: -360px; +} #dokuwiki__pagetools ul li a.source:hover, #dokuwiki__pagetools ul li a.source:active, #dokuwiki__pagetools ul li a.source:focus { @@ -193,6 +224,9 @@ #dokuwiki__pagetools ul li a.draft { background-position: right -180px; } +#dokuwiki__pagetools ul li a.draft:before { + margin-top: -180px; +} #dokuwiki__pagetools ul li a.draft:hover, #dokuwiki__pagetools ul li a.draft:active, #dokuwiki__pagetools ul li a.draft:focus { @@ -210,12 +244,18 @@ #dokuwiki__pagetools ul li a.revs { background-position: right -540px; } +#dokuwiki__pagetools ul li a.revs:before { + margin-top: -540px; +} #dokuwiki__pagetools ul li a.revs:hover, #dokuwiki__pagetools ul li a.revs:active, #dokuwiki__pagetools ul li a.revs:focus, .mode_revisions #dokuwiki__pagetools ul li a.revs { background-position: right -585px; } +.mode_revisions #dokuwiki__pagetools ul li a.revs:before { + margin-top: -585px; +} [dir=rtl] #dokuwiki__pagetools ul li a.revs { background-position: left -540px; } @@ -229,12 +269,18 @@ #dokuwiki__pagetools ul li a.backlink { background-position: right -630px; } +#dokuwiki__pagetools ul li a.backlink:before { + margin-top: -630px; +} #dokuwiki__pagetools ul li a.backlink:hover, #dokuwiki__pagetools ul li a.backlink:active, #dokuwiki__pagetools ul li a.backlink:focus, .mode_backlink #dokuwiki__pagetools ul li a.backlink { background-position: right -675px; } +.mode_backlink #dokuwiki__pagetools ul li a.backlink:before { + margin-top: -675px; +} [dir=rtl] #dokuwiki__pagetools ul li a.backlink { background-position: left -630px; } @@ -248,6 +294,9 @@ #dokuwiki__pagetools ul li a.top { background-position: right -810px; } +#dokuwiki__pagetools ul li a.top:before{ + margin-top: -810px; +} #dokuwiki__pagetools ul li a.top:hover, #dokuwiki__pagetools ul li a.top:active, #dokuwiki__pagetools ul li a.top:focus { @@ -265,12 +314,18 @@ #dokuwiki__pagetools ul li a.revert { background-position: right -450px; } +#dokuwiki__pagetools ul li a.revert:before { + margin-top: -450px; +} #dokuwiki__pagetools ul li a.revert:hover, #dokuwiki__pagetools ul li a.revert:active, #dokuwiki__pagetools ul li a.revert:focus, .mode_revert #dokuwiki__pagetools ul li a.revert { background-position: right -495px; } +.mode_revert #dokuwiki__pagetools ul li a.revert:before { + margin-top: -450px; +} [dir=rtl] #dokuwiki__pagetools ul li a.revert { background-position: left -450px; } @@ -284,12 +339,18 @@ #dokuwiki__pagetools ul li a.subscribe { background-position: right -720px; } +#dokuwiki__pagetools ul li a.subscribe:before { + margin-top: -720px; +} #dokuwiki__pagetools ul li a.subscribe:hover, #dokuwiki__pagetools ul li a.subscribe:active, #dokuwiki__pagetools ul li a.subscribe:focus, .mode_subscribe #dokuwiki__pagetools ul li a.subscribe { background-position: right -765px; } +.mode_subscribe #dokuwiki__pagetools ul li a.subscribe:before { + margin-top: -765px; +} [dir=rtl] #dokuwiki__pagetools ul li a.subscribe { background-position: left -720px; } @@ -303,6 +364,9 @@ #dokuwiki__pagetools ul li a.mediaManager { background-position: right -900px; } +#dokuwiki__pagetools ul li a.mediaManager:before { + margin-top: -900px; +} #dokuwiki__pagetools ul li a.mediaManager:hover, #dokuwiki__pagetools ul li a.mediaManager:active, #dokuwiki__pagetools ul li a.mediaManager:focus { @@ -320,6 +384,9 @@ #dokuwiki__pagetools ul li a.back { background-position: right -990px; } +#dokuwiki__pagetools ul li a.back { + margin-top: -990px; +} #dokuwiki__pagetools ul li a.back:hover, #dokuwiki__pagetools ul li a.back:active, #dokuwiki__pagetools ul li a.back:focus { -- cgit v1.2.3 From 96e1f756daa0ff09e8a68c74a6fc4f606a723f77 Mon Sep 17 00:00:00 2001 From: Michael Hamann <michael@content-space.de> Date: Mon, 25 Feb 2013 00:56:37 +0100 Subject: Use "old" image replacement for pagetools in IE7 This fixes the image display in IE7 with the disadvantage that now in IE7 with images disabled the text won't be displayed anymore. --- lib/tpl/dokuwiki/css/pagetools.css | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/lib/tpl/dokuwiki/css/pagetools.css b/lib/tpl/dokuwiki/css/pagetools.css index 41f876d48..21e5c13ec 100644 --- a/lib/tpl/dokuwiki/css/pagetools.css +++ b/lib/tpl/dokuwiki/css/pagetools.css @@ -133,6 +133,25 @@ padding: 5px 5px 5px 40px; } +/* IE7 fixes, doesn't work without images */ + +#IE7 #dokuwiki__pagetools ul li a { + background-image: url(images/pagetools-sprite.png); +} + +#IE7 #dokuwiki__pagetools:hover ul li a span, +#IE7 #dokuwiki__pagetools ul li a:focus span, +#IE7 #dokuwiki__pagetools ul li a:active span { + clip: auto; + display: inline; + position: static; +} + +#IE7 #dokuwiki__pagetools ul li a span { + clip: rect(0 0 0 0); + position: absolute; +} + #dokuwiki__pagetools ul li a:hover, #dokuwiki__pagetools ul li a:active, #dokuwiki__pagetools ul li a:focus { -- cgit v1.2.3 From 7ae29fa453970036576e8b18fe228c24a25e94ff Mon Sep 17 00:00:00 2001 From: Christopher Smith <chris@jalakai.co.uk> Date: Mon, 25 Feb 2013 15:00:16 +0000 Subject: refactor info functions test pageinfo() test no longer required, unit test committed elsewhere and verified against both previous and updated versions of pageinfo() fn. basicinfo() and mediainfo() tests separated each into their own test file. --- _test/tests/inc/common_basicinfo.test.php | 114 ++++++++++++++++++++++++++ _test/tests/inc/common_infofunctions.test.php | 114 -------------------------- _test/tests/inc/common_mediainfo.test.php | 49 +++++++++++ 3 files changed, 163 insertions(+), 114 deletions(-) create mode 100644 _test/tests/inc/common_basicinfo.test.php delete mode 100644 _test/tests/inc/common_infofunctions.test.php create mode 100644 _test/tests/inc/common_mediainfo.test.php diff --git a/_test/tests/inc/common_basicinfo.test.php b/_test/tests/inc/common_basicinfo.test.php new file mode 100644 index 000000000..2e383ef8b --- /dev/null +++ b/_test/tests/inc/common_basicinfo.test.php @@ -0,0 +1,114 @@ +<?php + +class common_infofunctions_test extends DokuWikiTest { + + function setup(){ + parent::setup(); + + global $USERINFO; + $USERINFO = array( + 'pass' => '179ad45c6ce2cb97cf1029e212046e81', + 'name' => 'Arthur Dent', + 'mail' => 'arthur@example.com', + 'grps' => array ('admin','user'), + ); + $_SERVER['REMOTE_USER'] = 'testuser'; + $_SERVER['REMOTE_ADDR'] = '1.2.3.4'; + } + + function _get_info() { + global $USERINFO; + $info = array ( + 'isadmin' => true, + 'ismanager' => true, + 'userinfo' => $USERINFO, + 'perm' => 255, + 'namespace' => false, + 'ismobile' => false, + 'client' => 'testuser', + ); + + return $info; + } + + /** + * Its important to have the correct set of keys. + * Other functions provide the values + */ + function test_basicinfo(){ + // test with REMOTE_USER set and the user an admin user + $info = $this->_get_info(); + $this->assertEquals(basicinfo($ID,true),$info); + + // with $httpclient parameter set to false + unset($info['ismobile']); + $this->assertEquals(basicinfo($ID,false),$info); + + // with anonymous user + unset($_SERVER['REMOTE_USER']); + global $USERINFO; $USERINFO = array(); + + $info = array( + 'isadmin' => false, + 'ismanager' => false, + 'perm' => 8, + 'namespace' => false, + 'ismobile' => false, + 'client' => '1.2.3.4', + ); + $this->assertEquals(basicinfo($ID,true),$info); + } + + /** + * We're interested in the extra keys required for $INFO when its a page request + * and that $REV, $RANGE globals are set/cleared correctly + */ + function test_pageinfo(){ + global $ID,$conf; + $ID = 'wiki:start'; + + $info = $this->_get_info(); + $info['id'] = 'wiki:start'; + $info['namespace'] = 'wiki'; + $info['rev'] = null; + $info['subscribed'] = false; + $info['locked'] = false; + $info['filepath'] = $conf['datadir'].'/wiki/start.txt'; + $info['exists'] = false; + $info['writable'] = true; + $info['editable'] = true; + $info['lastmod'] = false; + $info['meta'] = array(); + $info['ip'] = null; + $info['user'] = null; + $info['sum'] = null; + $info['editor'] = null; + + // basic test, no revision + $this->assertEquals(pageinfo(),$info); + + // TODO: test with revision = current page + + // TODO: test with true revision + + // TODO: test with revision & range + + // TODO: validate against the same test run on master branch pre this change + } + + /** + * We're interested in the extra keys for $INFO when its a media request + */ + function test_mediainfo(){ + global $NS, $IMG; + $NS = ''; + $IMG = 'testimage.png'; + + $info = $this->_get_info(); + $info['image'] = 'testimage.png'; + + $this->assertEquals(mediainfo(),$info); + } +} + +//Setup VIM: ex: et ts=4 : diff --git a/_test/tests/inc/common_infofunctions.test.php b/_test/tests/inc/common_infofunctions.test.php deleted file mode 100644 index 2e383ef8b..000000000 --- a/_test/tests/inc/common_infofunctions.test.php +++ /dev/null @@ -1,114 +0,0 @@ -<?php - -class common_infofunctions_test extends DokuWikiTest { - - function setup(){ - parent::setup(); - - global $USERINFO; - $USERINFO = array( - 'pass' => '179ad45c6ce2cb97cf1029e212046e81', - 'name' => 'Arthur Dent', - 'mail' => 'arthur@example.com', - 'grps' => array ('admin','user'), - ); - $_SERVER['REMOTE_USER'] = 'testuser'; - $_SERVER['REMOTE_ADDR'] = '1.2.3.4'; - } - - function _get_info() { - global $USERINFO; - $info = array ( - 'isadmin' => true, - 'ismanager' => true, - 'userinfo' => $USERINFO, - 'perm' => 255, - 'namespace' => false, - 'ismobile' => false, - 'client' => 'testuser', - ); - - return $info; - } - - /** - * Its important to have the correct set of keys. - * Other functions provide the values - */ - function test_basicinfo(){ - // test with REMOTE_USER set and the user an admin user - $info = $this->_get_info(); - $this->assertEquals(basicinfo($ID,true),$info); - - // with $httpclient parameter set to false - unset($info['ismobile']); - $this->assertEquals(basicinfo($ID,false),$info); - - // with anonymous user - unset($_SERVER['REMOTE_USER']); - global $USERINFO; $USERINFO = array(); - - $info = array( - 'isadmin' => false, - 'ismanager' => false, - 'perm' => 8, - 'namespace' => false, - 'ismobile' => false, - 'client' => '1.2.3.4', - ); - $this->assertEquals(basicinfo($ID,true),$info); - } - - /** - * We're interested in the extra keys required for $INFO when its a page request - * and that $REV, $RANGE globals are set/cleared correctly - */ - function test_pageinfo(){ - global $ID,$conf; - $ID = 'wiki:start'; - - $info = $this->_get_info(); - $info['id'] = 'wiki:start'; - $info['namespace'] = 'wiki'; - $info['rev'] = null; - $info['subscribed'] = false; - $info['locked'] = false; - $info['filepath'] = $conf['datadir'].'/wiki/start.txt'; - $info['exists'] = false; - $info['writable'] = true; - $info['editable'] = true; - $info['lastmod'] = false; - $info['meta'] = array(); - $info['ip'] = null; - $info['user'] = null; - $info['sum'] = null; - $info['editor'] = null; - - // basic test, no revision - $this->assertEquals(pageinfo(),$info); - - // TODO: test with revision = current page - - // TODO: test with true revision - - // TODO: test with revision & range - - // TODO: validate against the same test run on master branch pre this change - } - - /** - * We're interested in the extra keys for $INFO when its a media request - */ - function test_mediainfo(){ - global $NS, $IMG; - $NS = ''; - $IMG = 'testimage.png'; - - $info = $this->_get_info(); - $info['image'] = 'testimage.png'; - - $this->assertEquals(mediainfo(),$info); - } -} - -//Setup VIM: ex: et ts=4 : diff --git a/_test/tests/inc/common_mediainfo.test.php b/_test/tests/inc/common_mediainfo.test.php new file mode 100644 index 000000000..0e67fbcd9 --- /dev/null +++ b/_test/tests/inc/common_mediainfo.test.php @@ -0,0 +1,49 @@ +<?php + +class common_basicinfo_test extends DokuWikiTest { + + function setup(){ + parent::setup(); + + global $USERINFO; + $USERINFO = array( + 'pass' => '179ad45c6ce2cb97cf1029e212046e81', + 'name' => 'Arthur Dent', + 'mail' => 'arthur@example.com', + 'grps' => array ('admin','user'), + ); + $_SERVER['REMOTE_USER'] = 'testuser'; + $_SERVER['REMOTE_ADDR'] = '1.2.3.4'; + } + + function _get_info() { + global $USERINFO; + $info = array ( + 'isadmin' => true, + 'ismanager' => true, + 'userinfo' => $USERINFO, + 'perm' => 255, + 'namespace' => false, + 'ismobile' => false, + 'client' => 'testuser', + ); + + return $info; + } + + /** + * We're interested in the extra keys for $INFO when its a media request + */ + function test_mediainfo(){ + global $NS, $IMG; + $NS = ''; + $IMG = 'testimage.png'; + + $info = $this->_get_info(); + $info['image'] = 'testimage.png'; + + $this->assertEquals(mediainfo(),$info); + } +} + +//Setup VIM: ex: et ts=4 : -- cgit v1.2.3 From 5ba389b2134d71e9b0a8b78a465bb4e8849ab664 Mon Sep 17 00:00:00 2001 From: Christopher Smith <chris@jalakai.co.uk> Date: Mon, 25 Feb 2013 15:10:39 +0000 Subject: (incl. the refactored file) --- _test/tests/inc/common_basicinfo.test.php | 50 ------------------------------- 1 file changed, 50 deletions(-) diff --git a/_test/tests/inc/common_basicinfo.test.php b/_test/tests/inc/common_basicinfo.test.php index 2e383ef8b..0369474c9 100644 --- a/_test/tests/inc/common_basicinfo.test.php +++ b/_test/tests/inc/common_basicinfo.test.php @@ -59,56 +59,6 @@ class common_infofunctions_test extends DokuWikiTest { $this->assertEquals(basicinfo($ID,true),$info); } - /** - * We're interested in the extra keys required for $INFO when its a page request - * and that $REV, $RANGE globals are set/cleared correctly - */ - function test_pageinfo(){ - global $ID,$conf; - $ID = 'wiki:start'; - - $info = $this->_get_info(); - $info['id'] = 'wiki:start'; - $info['namespace'] = 'wiki'; - $info['rev'] = null; - $info['subscribed'] = false; - $info['locked'] = false; - $info['filepath'] = $conf['datadir'].'/wiki/start.txt'; - $info['exists'] = false; - $info['writable'] = true; - $info['editable'] = true; - $info['lastmod'] = false; - $info['meta'] = array(); - $info['ip'] = null; - $info['user'] = null; - $info['sum'] = null; - $info['editor'] = null; - - // basic test, no revision - $this->assertEquals(pageinfo(),$info); - - // TODO: test with revision = current page - - // TODO: test with true revision - - // TODO: test with revision & range - - // TODO: validate against the same test run on master branch pre this change - } - - /** - * We're interested in the extra keys for $INFO when its a media request - */ - function test_mediainfo(){ - global $NS, $IMG; - $NS = ''; - $IMG = 'testimage.png'; - - $info = $this->_get_info(); - $info['image'] = 'testimage.png'; - - $this->assertEquals(mediainfo(),$info); - } } //Setup VIM: ex: et ts=4 : -- cgit v1.2.3 From add8678f233ad74892a96444e3013e0465616200 Mon Sep 17 00:00:00 2001 From: Andreas Gohr <andi@splitbrain.org> Date: Fri, 1 Mar 2013 12:54:01 +0100 Subject: alternative fix for FS#2734 --- _test/conf/acl.auth.php | 1 + _test/tests/inc/media_ispublic.test.php | 18 ++++++++++++++++++ inc/media.php | 14 ++++++++++++++ lib/exe/fetch.php | 25 ++++++++++++++++++++----- 4 files changed, 53 insertions(+), 5 deletions(-) create mode 100644 _test/tests/inc/media_ispublic.test.php diff --git a/_test/conf/acl.auth.php b/_test/conf/acl.auth.php index 8a1b01f23..495740720 100644 --- a/_test/conf/acl.auth.php +++ b/_test/conf/acl.auth.php @@ -19,6 +19,7 @@ # delete 16 * @ALL 8 +private:* @ALL 0 # for testing wildcards: users:* @ALL 1 diff --git a/_test/tests/inc/media_ispublic.test.php b/_test/tests/inc/media_ispublic.test.php new file mode 100644 index 000000000..307c64654 --- /dev/null +++ b/_test/tests/inc/media_ispublic.test.php @@ -0,0 +1,18 @@ +<?php + +class media_ispublic_test extends DokuWikiTest { + + + public function test_external(){ + $this->assertTrue(media_ispublic('http://www.example.com/foo.png')); + $this->assertTrue(media_ispublic('https://www.example.com/foo.png')); + $this->assertTrue(media_ispublic('hTTp://www.example.com/foo.png')); + $this->assertTrue(media_ispublic('hTTps://www.example.com/foo.png')); + } + + public function test_internal(){ + $this->assertTrue(media_ispublic('wiki:logo.png')); + $this->assertFalse(media_ispublic('private:logo.png')); + } + +} \ No newline at end of file diff --git a/inc/media.php b/inc/media.php index db1ca0d57..501d170f3 100644 --- a/inc/media.php +++ b/inc/media.php @@ -82,6 +82,20 @@ function media_metasave($id,$auth,$data){ } } +/** + * Check if a media item is public (eg, external URL or readable by @ALL) + * + * @author Andreas Gohr <andi@splitbrain.org> + * @param string $id the media ID or URL + * @return bool + */ +function media_ispublic($id){ + if(preg_match('/^https?:\/\//i',$id)) return true; + $id = cleanID($id); + if(auth_aclcheck(getNS($id).':*', '', array()) >= AUTH_READ) return true; + return false; +} + /** * Display the form to edit image meta data * diff --git a/lib/exe/fetch.php b/lib/exe/fetch.php index 9bac4d272..a9147a6c0 100644 --- a/lib/exe/fetch.php +++ b/lib/exe/fetch.php @@ -47,6 +47,7 @@ if(!defined('SIMPLE_TEST')) { 'height' => $HEIGHT, 'status' => $STATUS, 'statusmessage' => $STATUSMESSAGE, + 'ispublic' => media_ispublic($MEDIA), ); // handle the file status @@ -81,10 +82,13 @@ if(!defined('SIMPLE_TEST')) { // finally send the file to the client $evt = new Doku_Event('MEDIA_SENDFILE', $data); if($evt->advise_before()) { - sendFile($data['file'], $data['mime'], $data['download'], $data['cache']); + $cache = $data['cache']; + if($cache != 0 && !$data['ispublic']) $cache = 0; // no cache headers for private files FS#2734 + + sendFile($data['file'], $data['mime'], $data['download'], $cache); } // Do something after the download finished. - $evt->advise_after(); + $evt->advise_after(); // will not be emitted on 304 or x-sendfile }// END DO main @@ -93,8 +97,18 @@ if(!defined('SIMPLE_TEST')) { /** * Set headers and send the file to the client * + * Unless $cache is set to 0, the data may end up in intermediate proxy servers. Therefor, + * if you're sending (ACL protected) private files, $cache should be 0. + * + * This function will abort the current script when a 304 is sent or file sending is handled + * through x-sendfile + * * @author Andreas Gohr <andi@splitbrain.org> * @author Ben Coburn <btcoburn@silicodon.net> + * @param string $file local file to send + * @param string $mime mime type of the file + * @param bool $dl set to true to force a browser download + * @param int $cache remaining cache time in seconds (-1 for $conf['cache'], 0 for off) */ function sendFile($file, $mime, $dl, $cache) { global $conf; @@ -115,9 +129,10 @@ function sendFile($file, $mime, $dl, $cache) { header('Cache-Control: public, proxy-revalidate, no-transform, max-age='.max($fmtime - time() + $conf['cachetime'] + 10, 0)); header('Pragma: public'); } else if($cache == 0) { - // nocache - header('Cache-Control: must-revalidate, no-transform, post-check=0, pre-check=0'); - header('Pragma: public'); + // nocache, avoid resending files from intermediate caches without revalidation FS#2734 + header('Expires: Thu, 01 Jan 1970 00:00:00 GMT'); + header('Cache-Control: private, no-transform, max-age=0'); + header('Pragma: no-cache'); } //send important headers first, script stops here if '304 Not Modified' response http_conditionalRequest($fmtime); -- cgit v1.2.3 From 6535e29c55fe997fa55a4f755bff8a41fbd9d525 Mon Sep 17 00:00:00 2001 From: Andreas Gohr <andi@splitbrain.org> Date: Fri, 1 Mar 2013 15:11:23 +0100 Subject: fixed loading of old configuration for auth plugins --- lib/plugins/auth.php | 43 ++++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/lib/plugins/auth.php b/lib/plugins/auth.php index c14a04dfb..ec8ed7e58 100644 --- a/lib/plugins/auth.php +++ b/lib/plugins/auth.php @@ -9,8 +9,8 @@ if(!defined('DOKU_INC')) die(); * all auth classes should inherit from this class * * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) - * @author Chris Smith <chris@jalakai.co.uk> - * @author Jan Schumann <js@jschumann-it.com> + * @author Chris Smith <chris@jalakai.co.uk> + * @author Jan Schumann <js@jschumann-it.com> */ class DokuWiki_Auth_Plugin extends DokuWiki_Plugin { public $success = true; @@ -21,18 +21,18 @@ class DokuWiki_Auth_Plugin extends DokuWiki_Plugin { * in the constructor. */ protected $cando = array( - 'addUser' => false, // can Users be created? - 'delUser' => false, // can Users be deleted? - 'modLogin' => false, // can login names be changed? - 'modPass' => false, // can passwords be changed? - 'modName' => false, // can real names be changed? - 'modMail' => false, // can emails be changed? - 'modGroups' => false, // can groups be changed? - 'getUsers' => false, // can a (filtered) list of users be retrieved? - 'getUserCount'=> false, // can the number of users be retrieved? - 'getGroups' => false, // can a list of available groups be retrieved? - 'external' => false, // does the module do external auth checking? - 'logout' => true, // can the user logout again? (eg. not possible with HTTP auth) + 'addUser' => false, // can Users be created? + 'delUser' => false, // can Users be deleted? + 'modLogin' => false, // can login names be changed? + 'modPass' => false, // can passwords be changed? + 'modName' => false, // can real names be changed? + 'modMail' => false, // can emails be changed? + 'modGroups' => false, // can groups be changed? + 'getUsers' => false, // can a (filtered) list of users be retrieved? + 'getUserCount' => false, // can the number of users be retrieved? + 'getGroups' => false, // can a list of available groups be retrieved? + 'external' => false, // does the module do external auth checking? + 'logout' => true, // can the user logout again? (eg. not possible with HTTP auth) ); /** @@ -102,7 +102,7 @@ class DokuWiki_Auth_Plugin extends DokuWiki_Plugin { * example for enforcing a user name schema. * * @author Gabriel Birke <birke@d-scribe.de> - * @param string $type Modification type ('create', 'modify', 'delete') + * @param string $type Modification type ('create', 'modify', 'delete') * @param array $params Parameters for the createUser, modifyUser or deleteUsers method. The content of this array depends on the modification type * @return mixed Result from the modification function or false if an event handler has canceled the action */ @@ -162,7 +162,7 @@ class DokuWiki_Auth_Plugin extends DokuWiki_Plugin { * The function needs to set some globals needed by * DokuWiki like auth_login() does. * - * @see auth_login() + * @see auth_login() * @author Andreas Gohr <andi@splitbrain.org> * * @param string $user Username @@ -425,16 +425,17 @@ class DokuWiki_Auth_Plugin extends DokuWiki_Plugin { * * @deprecated 2012-11-09 */ - public function loadConfig(){ + public function loadConfig() { global $conf; - $plugin = $this->getPluginName(); + $plugin = $this->getPluginName(); + $oldname = preg_replace('/^auth/', '', $plugin); $default = $this->readDefaultSettings(); $oldconf = array(); - if(isset($conf['auth'][$plugin])) $oldconf = (array) $conf['auth'][$plugin]; + if(isset($conf['auth'][$oldname])) $oldconf = (array) $conf['auth'][$oldname]; + $conf['plugin'][$plugin] = array_merge($default, $oldconf, (array) $conf['plugin'][$plugin]); - $conf['plugin'][$plugin] = array_merge($default, $oldconf, $conf['plugin'][$plugin]); - $this->conf =& $conf['plugin'][$plugin]; + $this->conf =& $conf['plugin'][$plugin]; $this->configloaded = true; } } -- cgit v1.2.3 From 4a516840077e2d3bb26c9ffca8316b3c9968d018 Mon Sep 17 00:00:00 2001 From: Andreas Gohr <andi@splitbrain.org> Date: Sun, 3 Mar 2013 12:47:40 +0100 Subject: handle public vs. private ressource in sendFile() --- lib/exe/fetch.php | 66 ++++++++++++++++++++++++++++++++----------------------- 1 file changed, 39 insertions(+), 27 deletions(-) diff --git a/lib/exe/fetch.php b/lib/exe/fetch.php index a9147a6c0..e8853dca7 100644 --- a/lib/exe/fetch.php +++ b/lib/exe/fetch.php @@ -82,10 +82,7 @@ if(!defined('SIMPLE_TEST')) { // finally send the file to the client $evt = new Doku_Event('MEDIA_SENDFILE', $data); if($evt->advise_before()) { - $cache = $data['cache']; - if($cache != 0 && !$data['ispublic']) $cache = 0; // no cache headers for private files FS#2734 - - sendFile($data['file'], $data['mime'], $data['download'], $cache); + sendFile($data['file'], $data['mime'], $data['download'], $cache, $data['ispublic']); } // Do something after the download finished. $evt->advise_after(); // will not be emitted on 304 or x-sendfile @@ -97,44 +94,59 @@ if(!defined('SIMPLE_TEST')) { /** * Set headers and send the file to the client * - * Unless $cache is set to 0, the data may end up in intermediate proxy servers. Therefor, - * if you're sending (ACL protected) private files, $cache should be 0. + * The $cache parameter influences how long files may be kept in caches, the $public parameter + * influences if this caching may happen in public proxis or in the browser cache only FS#2734 * * This function will abort the current script when a 304 is sent or file sending is handled * through x-sendfile * * @author Andreas Gohr <andi@splitbrain.org> * @author Ben Coburn <btcoburn@silicodon.net> - * @param string $file local file to send - * @param string $mime mime type of the file - * @param bool $dl set to true to force a browser download - * @param int $cache remaining cache time in seconds (-1 for $conf['cache'], 0 for off) + * @param string $file local file to send + * @param string $mime mime type of the file + * @param bool $dl set to true to force a browser download + * @param int $cache remaining cache time in seconds (-1 for $conf['cache'], 0 for no-cache) + * @param bool $public is this a public ressource or a private one? */ -function sendFile($file, $mime, $dl, $cache) { +function sendFile($file, $mime, $dl, $cache, $public = false) { global $conf; - $fmtime = @filemtime($file); - // send headers + // send mime headers header("Content-Type: $mime"); - // smart http caching headers + + // calculate cache times if($cache == -1) { - // cache - // cachetime or one hour - header('Expires: '.gmdate("D, d M Y H:i:s", time() + max($conf['cachetime'], 3600)).' GMT'); - header('Cache-Control: public, proxy-revalidate, no-transform, max-age='.max($conf['cachetime'], 3600)); - header('Pragma: public'); + $maxage = max($conf['cachetime'], 3600); // cachetime or one hour + $expires = time() + $maxage; } else if($cache > 0) { - // recache - // remaining cachetime + 10 seconds so the newly recached media is used - header('Expires: '.gmdate("D, d M Y H:i:s", $fmtime + $conf['cachetime'] + 10).' GMT'); - header('Cache-Control: public, proxy-revalidate, no-transform, max-age='.max($fmtime - time() + $conf['cachetime'] + 10, 0)); - header('Pragma: public'); - } else if($cache == 0) { - // nocache, avoid resending files from intermediate caches without revalidation FS#2734 + $maxage = $cache; // given time + $expires = time() + $maxage; + } else { // $cache == 0 + $maxage = 0; + $expires = 0; // 1970-01-01 + } + + // smart http caching headers + if($maxage) { + if($public) { + // cache publically + header('Expires: '.gmdate("D, d M Y H:i:s", $expires).' GMT'); + header('Cache-Control: public, proxy-revalidate, no-transform, max-age='.$maxage); + header('Pragma: public'); + } else { + // cache in browser + header('Expires: '.gmdate("D, d M Y H:i:s", $expires).' GMT'); + header('Cache-Control: private, no-transform, max-age='.$maxage); + header('Pragma: private'); + } + } else { + // no cache at all header('Expires: Thu, 01 Jan 1970 00:00:00 GMT'); header('Cache-Control: private, no-transform, max-age=0'); - header('Pragma: no-cache'); + header('Pragma: no-store'); } + //send important headers first, script stops here if '304 Not Modified' response + $fmtime = @filemtime($file); http_conditionalRequest($fmtime); //download or display? -- cgit v1.2.3 From 1c7d84bee69b8965844a960fa91551634986b35f Mon Sep 17 00:00:00 2001 From: Andreas Gohr <andi@splitbrain.org> Date: Sun, 3 Mar 2013 12:51:16 +0100 Subject: fixed passed cache parameter --- lib/exe/fetch.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/exe/fetch.php b/lib/exe/fetch.php index e8853dca7..28401ab39 100644 --- a/lib/exe/fetch.php +++ b/lib/exe/fetch.php @@ -82,7 +82,7 @@ if(!defined('SIMPLE_TEST')) { // finally send the file to the client $evt = new Doku_Event('MEDIA_SENDFILE', $data); if($evt->advise_before()) { - sendFile($data['file'], $data['mime'], $data['download'], $cache, $data['ispublic']); + sendFile($data['file'], $data['mime'], $data['download'], $data['cache'], $data['ispublic']); } // Do something after the download finished. $evt->advise_after(); // will not be emitted on 304 or x-sendfile -- cgit v1.2.3 From ca22711e6b0caa2525d6134c28bf0af78e8fcda3 Mon Sep 17 00:00:00 2001 From: Christopher Smith <chris@jalakai.co.uk> Date: Sun, 3 Mar 2013 18:30:48 +0000 Subject: make global, ensure created in mediamanager is global and merged with any pre-existing --- lib/exe/mediamanager.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/exe/mediamanager.php b/lib/exe/mediamanager.php index a205c4570..3ec749cd8 100644 --- a/lib/exe/mediamanager.php +++ b/lib/exe/mediamanager.php @@ -12,6 +12,7 @@ if($INPUT->str('msg1')) msg(hsc($INPUT->str('msg1')),1); if($INPUT->str('err')) msg(hsc($INPUT->str('err')),-1); + global $DEL; // get namespace to display (either direct or from deletion order) if($INPUT->str('delete')){ $DEL = cleanID($INPUT->str('delete')); @@ -28,7 +29,8 @@ $IMG = null; } - $INFO = mediainfo(); + global $INFO; + $INFO = !empty($INFO) ? array_merge($INFO, mediainfo()) : mediainfo(); $AUTH = $INFO['perm']; // shortcut for historical reasons trigger_event('MEDIAMANAGER_STARTED',$tmp=array()); -- cgit v1.2.3 From b613287149ac4707ec40a96b1b6fe8b190fa6439 Mon Sep 17 00:00:00 2001 From: Christopher Smith <chris@jalakai.co.uk> Date: Sun, 3 Mar 2013 18:34:33 +0000 Subject: include image info in in detail.php; ensure populated before DETAIL_STARTED event --- lib/exe/detail.php | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/lib/exe/detail.php b/lib/exe/detail.php index db635c016..7008b126f 100644 --- a/lib/exe/detail.php +++ b/lib/exe/detail.php @@ -2,13 +2,18 @@ if(!defined('DOKU_INC')) define('DOKU_INC',dirname(__FILE__).'/../../'); define('DOKU_MEDIADETAIL',1); require_once(DOKU_INC.'inc/init.php'); -trigger_event('DETAIL_STARTED', $tmp=array()); -//close session -session_write_close(); $IMG = getID('media'); $ID = cleanID($INPUT->str('id')); +// this makes some general infos available as well as the info about the +// "parent" page +$INFO = array_merge(pageinfo(),mediainfo()); +trigger_event('DETAIL_STARTED', $tmp=array()); + +//close session +session_write_close(); + if($conf['allowdebug'] && $INPUT->has('debug')){ print '<pre>'; foreach(explode(' ','basedir userewrite baseurl useslash') as $x){ @@ -39,10 +44,6 @@ if($AUTH >= AUTH_READ){ $ERROR = p_locale_xhtml('denied'); } -// this makes some general infos available as well as the info about the -// "parent" page -$INFO = pageinfo(); - //start output and load template header('Content-Type: text/html; charset=utf-8'); include(template('detail.php')); -- cgit v1.2.3 From 3074e3428bd5d1e38078dbac80a1eb9b96f917d7 Mon Sep 17 00:00:00 2001 From: Christopher Smith <chris@jalakai.co.uk> Date: Sun, 3 Mar 2013 18:35:27 +0000 Subject: fix comment grammar --- lib/exe/mediamanager.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/exe/mediamanager.php b/lib/exe/mediamanager.php index 3ec749cd8..66e5ddc82 100644 --- a/lib/exe/mediamanager.php +++ b/lib/exe/mediamanager.php @@ -54,7 +54,7 @@ exit; } - // give info on PHP catched upload errors + // give info on PHP caught upload errors if($_FILES['upload']['error']){ switch($_FILES['upload']['error']){ case 1: -- cgit v1.2.3 From 3b6f95e62fc7049712b96aacd245be507f83d5ee Mon Sep 17 00:00:00 2001 From: Andreas Gohr <andi@splitbrain.org> Date: Sun, 3 Mar 2013 20:03:57 +0100 Subject: adjusted cache=0 headers again --- lib/exe/fetch.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/exe/fetch.php b/lib/exe/fetch.php index 28401ab39..8b77fa0b2 100644 --- a/lib/exe/fetch.php +++ b/lib/exe/fetch.php @@ -141,8 +141,8 @@ function sendFile($file, $mime, $dl, $cache, $public = false) { } else { // no cache at all header('Expires: Thu, 01 Jan 1970 00:00:00 GMT'); - header('Cache-Control: private, no-transform, max-age=0'); - header('Pragma: no-store'); + header('Cache-Control: no-cache, no-transform, max-age=0'); + header('Pragma: no-cache'); } //send important headers first, script stops here if '304 Not Modified' response -- cgit v1.2.3 From a6c362b61d32c897d430e72356b4efe5a399c0ac Mon Sep 17 00:00:00 2001 From: Andreas Gohr <andi@splitbrain.org> Date: Sun, 3 Mar 2013 20:08:57 +0100 Subject: max-age not allowed with no-cache --- lib/exe/fetch.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/exe/fetch.php b/lib/exe/fetch.php index 8b77fa0b2..b9270d277 100644 --- a/lib/exe/fetch.php +++ b/lib/exe/fetch.php @@ -141,7 +141,7 @@ function sendFile($file, $mime, $dl, $cache, $public = false) { } else { // no cache at all header('Expires: Thu, 01 Jan 1970 00:00:00 GMT'); - header('Cache-Control: no-cache, no-transform, max-age=0'); + header('Cache-Control: no-cache, no-transform'); header('Pragma: no-cache'); } -- cgit v1.2.3 From 1b8b28faf419d50137b455d4d9a39cfd0fff3f4c Mon Sep 17 00:00:00 2001 From: Andreas Gohr <andi@splitbrain.org> Date: Sun, 3 Mar 2013 21:01:21 +0100 Subject: there's no pragma: private --- lib/exe/fetch.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/exe/fetch.php b/lib/exe/fetch.php index b9270d277..a558a3db8 100644 --- a/lib/exe/fetch.php +++ b/lib/exe/fetch.php @@ -136,7 +136,7 @@ function sendFile($file, $mime, $dl, $cache, $public = false) { // cache in browser header('Expires: '.gmdate("D, d M Y H:i:s", $expires).' GMT'); header('Cache-Control: private, no-transform, max-age='.$maxage); - header('Pragma: private'); + header('Pragma: no-cache'); } } else { // no cache at all -- cgit v1.2.3 From 5721a1547938df76003c6d91ea003dc1c70abd94 Mon Sep 17 00:00:00 2001 From: Guy Brand <gb@unistra.fr> Date: Wed, 6 Mar 2013 14:02:31 +0100 Subject: Release preparations --- data/deleted.files | 9 +++++++++ doku.php | 2 +- install.php | 2 +- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/data/deleted.files b/data/deleted.files index fada1f29e..4b9657da2 100644 --- a/data/deleted.files +++ b/data/deleted.files @@ -4,6 +4,15 @@ # A copy of this list is maintained at # http://www.dokuwiki.org/install:upgrade#files_to_remove +# removed in 2013-04-06 +inc/adLDAP.php +inc/auth/ad.class.php +inc/auth/basic.class.php +inc/auth/ldap.class.php +inc/auth/mysql.class.php +inc/auth/pgsql.class.php +inc/auth/plain.class.php + # removed in 2012-09-10 lib/images/icon-file.png lib/images/icon-thumb.png diff --git a/doku.php b/doku.php index 68976ebb3..46c64c535 100644 --- a/doku.php +++ b/doku.php @@ -9,7 +9,7 @@ */ // update message version -$updateVersion = 38; +$updateVersion = 39; // xdebug_start_profiling(); diff --git a/install.php b/install.php index 2db25bd2f..330a47d52 100644 --- a/install.php +++ b/install.php @@ -55,7 +55,7 @@ $dokuwiki_hash = array( '2011-11-10' => 'b46ff19a7587966ac4df61cbab1b8b31', '2012-01-25' => '72c083c73608fc43c586901fd5dabb74', '2012-09-10' => 'eb0b3fc90056fbc12bac6f49f7764df3', - 'devel' => '7b62b75245f57f122d3e0f8ed7989623', + '2013-04-06' => '7b62b75245f57f122d3e0f8ed7989623', ); -- cgit v1.2.3 From 08b9e7cabaff74983b2acc2a6bdbf526b17db9dd Mon Sep 17 00:00:00 2001 From: Kiril LastName <neohidra@gmail.com> Date: Wed, 6 Mar 2013 22:27:27 +0200 Subject: Language files: insignificant fixes --- inc/lang/ca-valencia/lang.php | 2 +- inc/lang/en/lang.php | 2 +- inc/lang/ia/lang.php | 2 +- inc/lang/id-ni/lang.php | 2 +- inc/lang/id/lang.php | 2 +- inc/lang/km/lang.php | 2 +- inc/lang/ku/lang.php | 6 +++--- inc/lang/lb/lang.php | 2 +- inc/lang/lt/lang.php | 2 +- inc/lang/mg/lang.php | 2 +- inc/lang/mk/lang.php | 2 +- inc/lang/ne/lang.php | 2 +- inc/lang/sq/lang.php | 2 +- inc/lang/th/lang.php | 2 +- inc/lang/vi/lang.php | 6 +++--- 15 files changed, 19 insertions(+), 19 deletions(-) diff --git a/inc/lang/ca-valencia/lang.php b/inc/lang/ca-valencia/lang.php index 6e7438f53..b7f322796 100644 --- a/inc/lang/ca-valencia/lang.php +++ b/inc/lang/ca-valencia/lang.php @@ -90,7 +90,7 @@ $lang['txt_overwrt'] = 'Sobreescriure archius existents'; $lang['lockedby'] = 'Actualment bloquejat per'; $lang['lockexpire'] = 'El bloqueig venç a les'; $lang['js']['willexpire'] = 'El seu bloqueig per a editar esta pàgina vencerà en un minut.\nPer a evitar conflictes utilise el botó de vista prèvia i reiniciarà el contador.'; -$lang['js']['notsavedyet'] = "Els canvis no guardats es perdran.\n¿Segur que vol continuar?"; +$lang['js']['notsavedyet'] = 'Els canvis no guardats es perdran.\n¿Segur que vol continuar?'; $lang['rssfailed'] = 'Ha ocorregut un erro al solicitar este canal: '; $lang['nothingfound'] = 'No s\'ha trobat res.'; $lang['mediaselect'] = 'Archius de mijos'; diff --git a/inc/lang/en/lang.php b/inc/lang/en/lang.php index 144faf4e1..cdad6c9a6 100644 --- a/inc/lang/en/lang.php +++ b/inc/lang/en/lang.php @@ -38,7 +38,7 @@ $lang['btn_admin'] = 'Admin'; $lang['btn_update'] = 'Update'; $lang['btn_delete'] = 'Delete'; $lang['btn_back'] = 'Back'; -$lang['btn_backlink'] = "Backlinks"; +$lang['btn_backlink'] = 'Backlinks'; $lang['btn_backtomedia'] = 'Back to Mediafile Selection'; $lang['btn_subscribe'] = 'Manage Subscriptions'; $lang['btn_profile'] = 'Update Profile'; diff --git a/inc/lang/ia/lang.php b/inc/lang/ia/lang.php index fd63fb5ef..e8a11479c 100644 --- a/inc/lang/ia/lang.php +++ b/inc/lang/ia/lang.php @@ -94,7 +94,7 @@ $lang['txt_overwrt'] = 'Reimplaciar le file existente'; $lang['lockedby'] = 'Actualmente serrate per'; $lang['lockexpire'] = 'Serratura expira le'; $lang['js']['willexpire'] = 'Tu serratura super le modification de iste pagina expirara post un minuta.\nPro evitar conflictos, usa le button Previsualisar pro reinitialisar le timer del serratura.'; -$lang['js']['notsavedyet'] = "Le modificationes non salveguardate essera perdite.\nRealmente continuar?"; +$lang['js']['notsavedyet'] = 'Le modificationes non salveguardate essera perdite.\nRealmente continuar?'; $lang['rssfailed'] = 'Un error occurreva durante le obtention de iste syndication:'; $lang['nothingfound'] = 'Nihil ha essite trovate.'; $lang['mediaselect'] = 'Files multimedia'; diff --git a/inc/lang/id-ni/lang.php b/inc/lang/id-ni/lang.php index 1a4d03498..7a1179326 100644 --- a/inc/lang/id-ni/lang.php +++ b/inc/lang/id-ni/lang.php @@ -73,5 +73,5 @@ $lang['resendpwdnouser'] = 'Bologö dödöu, lö masöndra zangoguna da\'a $lang['resendpwdconfirm'] = 'No tefaohe\'ö link famaduhu\'ö ba imele.'; $lang['resendpwdsuccess'] = 'No tefa\'ohe\'ö kode sibohou ba imele.'; $lang['txt_upload'] = 'Fili file ni fa\'ohe\'ö'; -$lang['js']['notsavedyet'] = "Famawu\'a si lö mu\'irö\'ö taya. \nSinduhu ötohugö?"; +$lang['js']['notsavedyet'] = 'Famawu\'a si lö mu\'irö\'ö taya. \nSinduhu ötohugö?'; $lang['mediaselect'] = 'Media file'; diff --git a/inc/lang/id/lang.php b/inc/lang/id/lang.php index e14b9d9f5..6c6d1c70f 100644 --- a/inc/lang/id/lang.php +++ b/inc/lang/id/lang.php @@ -84,7 +84,7 @@ $lang['txt_overwrt'] = 'File yang telah ada akan ditindih'; $lang['lockedby'] = 'Sedang dikunci oleh'; $lang['lockexpire'] = 'Penguncian artikel sampai dengan'; $lang['js']['willexpire'] = 'Halaman yang sedang Anda kunci akan berakhir dalam waktu kurang lebih satu menit.\nUntuk menghindari konflik, gunakan tombol Preview untuk me-reset timer pengunci.'; -$lang['js']['notsavedyet'] = "Perubahan yang belum disimpan akan hilang.\nYakin akan dilanjutkan?"; +$lang['js']['notsavedyet'] = 'Perubahan yang belum disimpan akan hilang.\nYakin akan dilanjutkan?'; $lang['rssfailed'] = 'Error terjadi saat mengambil feed: '; $lang['nothingfound'] = 'Tidak menemukan samasekali.'; $lang['mediaselect'] = 'Pilihan Mediafile'; diff --git a/inc/lang/km/lang.php b/inc/lang/km/lang.php index 85bb6afba..1f006f64e 100644 --- a/inc/lang/km/lang.php +++ b/inc/lang/km/lang.php @@ -88,7 +88,7 @@ $lang['lockedby'] = 'ឥឡូវនេះចកជាប់​'; $lang['lockexpire'] = 'សោជាប់ផុត​កំណត់ម៉ោង'; $lang['js']['willexpire'] = 'សោអ្នកចំពោះកែតម្រូវទំព័រនេះ ហួសពែលក្នុងមួយនាទី។\nកុំឲ្យមានជម្លោះ ប្រើ «បង្ហាញ»​ ទៅកំណត់​ឡើង​វិញ។'; -$lang['js']['notsavedyet'] = "កម្រែមិនទានរុក្សាទកត្រូវបោះបង់។\nបន្តទៅទាឬទេ?"; +$lang['js']['notsavedyet'] = 'កម្រែមិនទានរុក្សាទកត្រូវបោះបង់។\nបន្តទៅទាឬទេ?'; $lang['rssfailed'] = 'មានកំហុសពេលទៅ​ប្រមូល​យកមតិ​ព័ត៌មាន៖ '; $lang['nothingfound']= 'រកមិនឃើញអ្វីទេ។'; diff --git a/inc/lang/ku/lang.php b/inc/lang/ku/lang.php index c9d658c6d..51ed6c8bf 100644 --- a/inc/lang/ku/lang.php +++ b/inc/lang/ku/lang.php @@ -30,7 +30,7 @@ $lang['btn_admin'] = 'Admin'; $lang['btn_update'] = 'Rojanekirin'; $lang['btn_delete'] = 'Jê bibe'; $lang['btn_back'] = 'Paş'; -$lang['btn_backlink'] = "Girêdanên paş"; +$lang['btn_backlink'] = 'Girêdanên paş'; $lang['btn_backtomedia'] = 'Back to Mediafile Selection'; $lang['btn_subscribe'] = 'Subscribe Changes'; $lang['btn_unsubscribe'] = 'Unsubscribe Changes'; @@ -62,7 +62,7 @@ $lang['lockedby'] = 'Currently locked by'; $lang['lockexpire'] = 'Lock expires at'; $lang['js']['willexpire'] = 'Your lock for editing this page is about to expire in a minute.\nTo avoid conflicts use the preview button to reset the locktimer.'; -$lang['js']['notsavedyet'] = "Unsaved changes will be lost.\nReally continue?"; +$lang['js']['notsavedyet'] = 'Unsaved changes will be lost.\nReally continue?'; $lang['rssfailed'] = 'An error occured while fetching this feed: '; $lang['nothingfound']= 'Tiştek nehat dîtin.'; @@ -101,7 +101,7 @@ $lang['summary'] = 'Kurteya guhartinê'; $lang['mail_newpage'] = 'page added:'; $lang['mail_changed'] = 'page changed:'; -$lang['js']['nosmblinks'] = "Linking to Windows shares only works in Microsoft Internet Explorer.\nYou still can copy and paste the link."; +$lang['js']['nosmblinks'] = 'Linking to Windows shares only works in Microsoft Internet Explorer.\nYou still can copy and paste the link.'; $lang['qb_bold'] = 'Bold Text'; $lang['qb_italic'] = 'Italic Text'; diff --git a/inc/lang/lb/lang.php b/inc/lang/lb/lang.php index bced5a50a..76dd2ac15 100644 --- a/inc/lang/lb/lang.php +++ b/inc/lang/lb/lang.php @@ -83,7 +83,7 @@ $lang['txt_overwrt'] = 'Bestehend Datei iwwerschreiwen'; $lang['lockedby'] = 'Am Moment gespaart vun'; $lang['lockexpire'] = 'D\'Spär leeft of ëm'; $lang['js']['willexpire'] = 'Deng Spär fir d\'Säit ze änneren leeft an enger Minutt of.\nFir Konflikter ze verhënneren, dréck op Kucken ouni ofzespäicheren.'; -$lang['js']['notsavedyet'] = "Net gespäicher Ännerunge gi verluer.\nWierklech weiderfueren?"; +$lang['js']['notsavedyet'] = 'Net gespäicher Ännerunge gi verluer.\nWierklech weiderfueren?'; $lang['rssfailed'] = 'Et ass e Feeler virkomm beim erofluede vun dësem Feed: '; $lang['nothingfound'] = 'Näischt fond.'; $lang['mediaselect'] = 'Mediadateien'; diff --git a/inc/lang/lt/lang.php b/inc/lang/lt/lang.php index 8a4c4e6a5..d65f30ae0 100644 --- a/inc/lang/lt/lang.php +++ b/inc/lang/lt/lang.php @@ -89,7 +89,7 @@ $lang['txt_overwrt'] = 'Perrašyti egzistuojančią bylą'; $lang['lockedby'] = 'Užrakintas vartotojo'; $lang['lockexpire'] = 'Užraktas bus nuimtas'; $lang['js']['willexpire'] = 'Šio puslapio redagavimo užrakto galiojimo laikas baigsis po minutės.\nNorėdami išvengti nesklandumų naudokite peržiūros mygtuką ir užraktas atsinaujins.'; -$lang['js']['notsavedyet'] = "Pakeitimai nebus išsaugoti.\nTikrai tęsti?"; +$lang['js']['notsavedyet'] = 'Pakeitimai nebus išsaugoti.\nTikrai tęsti?"; $lang['rssfailed'] = 'Siunčiant šį feed\'ą įvyko klaida: '; $lang['nothingfound'] = 'Paieškos rezultatų nėra.'; $lang['mediaselect'] = 'Mediabylos išsirinkimas'; diff --git a/inc/lang/mg/lang.php b/inc/lang/mg/lang.php index 95589ab21..e3c7a0c2b 100644 --- a/inc/lang/mg/lang.php +++ b/inc/lang/mg/lang.php @@ -56,7 +56,7 @@ $lang['lockedby'] = 'Mbola voahidin\'i'; $lang['lockexpire'] = 'Afaka ny hidy amin\'ny'; $lang['js']['willexpire'] = 'Efa ho lany fotoana afaka iray minitra ny hidy ahafahanao manova ny pejy.\nMba hialana amin\'ny conflit dia ampiasao ny bokotra topi-maso hamerenana ny timer-n\'ny hidy.'; -$lang['js']['notsavedyet'] = "Misy fiovana tsy voarakitra, ho very izany ireo.\nAzo antoka fa hotohizana?"; +$lang['js']['notsavedyet'] = 'Misy fiovana tsy voarakitra, ho very izany ireo.\nAzo antoka fa hotohizana?'; $lang['rssfailed'] = 'An error occured while fetching this feed: '; $lang['nothingfound']= 'Tsy nahitana n\'inon\'inona.'; diff --git a/inc/lang/mk/lang.php b/inc/lang/mk/lang.php index 44bd489b7..9e1628562 100644 --- a/inc/lang/mk/lang.php +++ b/inc/lang/mk/lang.php @@ -91,7 +91,7 @@ $lang['txt_overwrt'] = 'Пребриши ја веќе постоеч $lang['lockedby'] = 'Моментално заклучена од'; $lang['lockexpire'] = 'Клучот истекува на'; $lang['js']['willexpire'] = 'Вашиот клуч за уредување на оваа страница ќе истече за една минута.\nЗа да избегнете конфликти и да го ресетирате бројачот за време, искористете го копчето за преглед.'; -$lang['js']['notsavedyet'] = "Незачуваните промени ќе бидат изгубени.\nСакате да продолжите?"; +$lang['js']['notsavedyet'] = 'Незачуваните промени ќе бидат изгубени.\nСакате да продолжите?'; $lang['rssfailed'] = 'Се појави грешка при повлекувањето на овој канал:'; $lang['nothingfound'] = 'Ништо не е пронајдено.'; $lang['mediaselect'] = 'Медиа датотеки'; diff --git a/inc/lang/ne/lang.php b/inc/lang/ne/lang.php index b7ca14b0a..908b1a1dd 100644 --- a/inc/lang/ne/lang.php +++ b/inc/lang/ne/lang.php @@ -86,7 +86,7 @@ $lang['txt_overwrt'] = 'रहेको उहि नामको फ $lang['lockedby'] = 'अहिले ताल्चा लगाइएको'; $lang['lockexpire'] = 'ताल्चा अवधि सकिने :'; $lang['js']['willexpire'] = 'तपाईलले यो पृष्ठ सम्पादन गर्न लगाउनु भएको ताल्चाको अवधि एक मिनेट भित्र सकिदै छ। \n द्वन्द हुन नदिन पूर्वरुप वा ताल्चा समय परिवर्तन गर्नुहोस् ।'; -$lang['js']['notsavedyet'] = "तपाईले वचन गर्नु नभएको परिवर्रन हराउने छ। \n साच्चै जारी गर्नुहुन्छ ।"; +$lang['js']['notsavedyet'] = 'तपाईले वचन गर्नु नभएको परिवर्रन हराउने छ। \n साच्चै जारी गर्नुहुन्छ ।'; $lang['rssfailed'] = 'यो फिड लिइ आउदा गल्ति भयो ।'; $lang['nothingfound'] = 'केहि पनि भेटिएन ।'; $lang['mediaselect'] = 'मिडिया फाइलहरू '; diff --git a/inc/lang/sq/lang.php b/inc/lang/sq/lang.php index 212f10607..36ed436c8 100644 --- a/inc/lang/sq/lang.php +++ b/inc/lang/sq/lang.php @@ -93,7 +93,7 @@ $lang['txt_overwrt'] = 'Zëvendëso skedarin ekzistues'; $lang['lockedby'] = 'Kyçur momentalisht nga'; $lang['lockexpire'] = 'Kyçi skadon në'; $lang['js']['willexpire'] = 'Kyçi juaj për redaktimin e kësaj faqeje është duke skaduar.\nPër të shmangur konflikte përdorni butonin Shiko Paraprakisht për të rivendosur kohën e kyçjes.'; -$lang['js']['notsavedyet'] = "Ndryshimet e paruajtura do të humbasin.\nVazhdo me të vërtetë?"; +$lang['js']['notsavedyet'] = 'Ndryshimet e paruajtura do të humbasin.\nVazhdo me të vërtetë?'; $lang['rssfailed'] = 'Ndoshi një gabim gjatë kapjes së këtij lajmi:'; $lang['nothingfound'] = 'Nuk u gjet asgjë.'; $lang['mediaselect'] = 'Skedarët e Medias'; diff --git a/inc/lang/th/lang.php b/inc/lang/th/lang.php index 627484eab..e008e9e9f 100644 --- a/inc/lang/th/lang.php +++ b/inc/lang/th/lang.php @@ -97,7 +97,7 @@ $lang['txt_overwrt'] = 'เขียนทับไฟล์ที่ $lang['lockedby'] = 'ตอนนี้ถูกล๊อคโดย'; $lang['lockexpire'] = 'การล๊อคจะหมดอายุเมื่อ'; $lang['js']['willexpire'] = 'การล๊อคเพื่อแก้ไขหน้านี้กำลังจะหมดเวลาในอีก \n นาที เพื่อที่จะหลีกเลี่ยงข้อขัดแย้งให้ใช้ปุ่ม "Preview" เพื่อรีเซ็ทเวลาใหม่'; -$lang['js']['notsavedyet'] = "การแก้ไขที่ไม่ได้บันทึกจะสูญหาย \n ต้องการทำต่อจริงๆหรือ?"; +$lang['js']['notsavedyet'] = 'การแก้ไขที่ไม่ได้บันทึกจะสูญหาย \n ต้องการทำต่อจริงๆหรือ?'; $lang['rssfailed'] = 'มีข้อผิดพลาดขณะดูดฟีดนี้'; $lang['nothingfound'] = 'ไม่พบสิ่งใด'; $lang['mediaselect'] = 'ไฟล์สื่อ'; diff --git a/inc/lang/vi/lang.php b/inc/lang/vi/lang.php index c439ca534..c6b61da51 100644 --- a/inc/lang/vi/lang.php +++ b/inc/lang/vi/lang.php @@ -38,7 +38,7 @@ $lang['btn_admin'] = 'Quản lý'; $lang['btn_update'] = 'Cập nhật'; $lang['btn_delete'] = 'Xoá'; $lang['btn_back'] = 'Quay lại'; -$lang['btn_backlink'] = "Liên kết tới đây"; +$lang['btn_backlink'] = 'Liên kết tới đây'; $lang['btn_profile'] = 'Cập nhật hồ sơ'; $lang['btn_reset'] = 'Làm lại'; $lang['btn_resendpwd'] = 'Gửi mật khẩu mới'; @@ -101,7 +101,7 @@ $lang['lockedby'] = 'Đang khoá bởi'; $lang['lockexpire'] = 'Sẽ được mở khóa vào lúc'; $lang['js']['willexpire'] = 'Trong một phút nữa bài viết sẽ được mở khóa để cho phép người khác chỉnh sửa.\nĐể tránh xung đột, bạn nên bấm nút Duyệt trước để lập lại thời gian khoá bài'; -$lang['js']['notsavedyet'] = "Hiện có những thay đổi chưa được bảo lưu, và sẽ mất.\nBạn thật sự muốn tiếp tục?"; +$lang['js']['notsavedyet'] = 'Hiện có những thay đổi chưa được bảo lưu, và sẽ mất.\nBạn thật sự muốn tiếp tục?'; $lang['js']['searchmedia'] = 'Tìm kiếm tập tin'; $lang['js']['keepopen'] = 'Giữ cửa sổ đang mở trên lựa chọn'; $lang['js']['hidedetails'] = 'Ẩn thông tin chi tiết'; @@ -126,7 +126,7 @@ $lang['js']['medialeft'] = 'Căn ảnh sang trái.'; $lang['js']['mediaright'] = 'Căn ảnh sang phải.'; $lang['js']['mediacenter'] = 'Cản ảnh ra giữa.'; $lang['js']['medianoalign'] = 'Không căn.'; -$lang['js']['nosmblinks'] = "Nối với các Windows shares chỉ có hiệu lực với Microsoft Internet Explorer.\nBạn vẫn có thể sao và chép các mốc nối."; +$lang['js']['nosmblinks'] = 'Nối với các Windows shares chỉ có hiệu lực với Microsoft Internet Explorer.\nBạn vẫn có thể sao và chép các mốc nối.'; $lang['js']['linkwiz'] = 'Hộp thoại liên kết'; $lang['js']['linkto'] = 'Liên kết tới:'; $lang['js']['del_confirm']= 'Xoá mục này?'; -- cgit v1.2.3 From 03583750eb3b0245839ba46c1b1fb25eac66f3a0 Mon Sep 17 00:00:00 2001 From: Kiril LastName <neohidra@gmail.com> Date: Wed, 6 Mar 2013 23:10:47 +0200 Subject: Bulgarian language update --- inc/lang/bg/backlinks.txt | 2 +- inc/lang/bg/lang.php | 6 +++++- lib/plugins/authad/lang/bg/settings.php | 18 ++++++++++++++++++ lib/plugins/authldap/lang/bg/settings.php | 19 +++++++++++++++++++ lib/plugins/authmysql/lang/bg/settings.php | 17 +++++++++++++++++ lib/plugins/authpgsql/lang/bg/settings.php | 12 ++++++++++++ 6 files changed, 72 insertions(+), 2 deletions(-) create mode 100644 lib/plugins/authad/lang/bg/settings.php create mode 100644 lib/plugins/authldap/lang/bg/settings.php create mode 100644 lib/plugins/authmysql/lang/bg/settings.php create mode 100644 lib/plugins/authpgsql/lang/bg/settings.php diff --git a/inc/lang/bg/backlinks.txt b/inc/lang/bg/backlinks.txt index dd633d94d..e5016146d 100644 --- a/inc/lang/bg/backlinks.txt +++ b/inc/lang/bg/backlinks.txt @@ -1,3 +1,3 @@ -====== Обратни препратки ====== +====== Какво сочи насам ====== Това е списък на страниците, които препращат обратно към текущата страница. diff --git a/inc/lang/bg/lang.php b/inc/lang/bg/lang.php index 3c0a17a72..f356955cb 100644 --- a/inc/lang/bg/lang.php +++ b/inc/lang/bg/lang.php @@ -37,7 +37,7 @@ $lang['btn_admin'] = 'Настройки'; $lang['btn_update'] = 'Актуализиране'; $lang['btn_delete'] = 'Изтриване'; $lang['btn_back'] = 'Назад'; -$lang['btn_backlink'] = 'Обратни препратки'; +$lang['btn_backlink'] = 'Какво сочи насам'; $lang['btn_backtomedia'] = 'Назад към избора на файл'; $lang['btn_subscribe'] = 'Абонаменти'; $lang['btn_profile'] = 'Профил'; @@ -200,6 +200,7 @@ $lang['user_tools'] = 'Инструменти за потребите $lang['site_tools'] = 'Инструменти за сайта'; $lang['page_tools'] = 'Инструменти за страници'; $lang['skip_to_content'] = 'към съдържанието'; +$lang['sidebar'] = 'Странична лента'; $lang['mail_newpage'] = 'добавена страница: '; $lang['mail_changed'] = 'променена страница: '; @@ -308,6 +309,9 @@ $lang['i_pol1'] = 'Публично Wiki (всеки може д $lang['i_pol2'] = 'Затворено Wiki (само регистрирани четат, пишат и качват)'; $lang['i_retry'] = 'Повторен опит'; $lang['i_license'] = 'Моля, изберете лиценз под който желаете да публикувате съдържанието:'; +$lang['i_license_none'] = 'Без показване на информация относно лиценза'; +$lang['i_pop_field'] = 'Моля, помогнете за усъвършенстването на DokuWiki:'; +$lang['i_pop_label'] = 'Изпращане на анонимна информация до разработчиците на DokuWiki, веднъж седмично'; $lang['recent_global'] = 'В момента преглеждате промените в именно пространство <b>%s</b>. Може да прегледате и <a href="%s">промените в цялото Wiki</a>.'; $lang['years'] = 'преди %d години'; diff --git a/lib/plugins/authad/lang/bg/settings.php b/lib/plugins/authad/lang/bg/settings.php new file mode 100644 index 000000000..d63331078 --- /dev/null +++ b/lib/plugins/authad/lang/bg/settings.php @@ -0,0 +1,18 @@ +<?php +/** + * Bulgarian language file + * + * @author Kiril <neohidra@gmail.com> + */ +$lang['account_suffix'] = 'Наставка на акаунта Ви. Например <code>@някакъв.домейн.org</code>'; +$lang['base_dn'] = 'Вашият основен DN. Например <code>DC=моят,DC=домейн,DC=org</code>'; +$lang['domain_controllers'] = 'Domain controller списък, разделете сървърите със запетая. Например <code>сървър1.домейн.org,сървър2.домейн.org</code>'; +$lang['ad_username'] = 'Привилегирован Active Directory потребител с достъп до данните на останалите потребители. Не е задължително, но е необходимо за някои функционалности като изпращането на имейл за абонаменти.'; +$lang['ad_password'] = 'Паролата на горния потребител.'; +$lang['sso'] = 'Да се ползва ли еднократно вписване чрез Kerberos или NTLM?'; +$lang['real_primarygroup'] = 'Да се извлича ли истинската група вместо да се предполага "Domain Users" (по-бавно)'; +$lang['use_ssl'] = 'Ползване на SSL свързаност? Не отбелязвайте TLS (по-долу) ако включите опцията.'; +$lang['use_tls'] = 'Ползване на TLS свързаност? Не отбелязвайте SSL (по-горе) ако включите опцията.'; +$lang['debug'] = 'Показване на допълнителна debug информация при грешка?'; +$lang['expirywarn'] = 'Предупреждаване на потребителите Х дни преди изтичане валидността на паролата им. Въведете 0 за изключване.'; +$lang['additional'] = 'Списък с допълнителни AD атрибути за извличане от потребителските данни (разделяйте ги със запетая). Ползва се от няколко приставки.'; \ No newline at end of file diff --git a/lib/plugins/authldap/lang/bg/settings.php b/lib/plugins/authldap/lang/bg/settings.php new file mode 100644 index 000000000..644672ca7 --- /dev/null +++ b/lib/plugins/authldap/lang/bg/settings.php @@ -0,0 +1,19 @@ +<?php +/** + * Bulgarian language file + * + * @author Kiril <neohidra@gmail.com> + */ +$lang['server'] = 'Вашият LDAP сървър. Име на хоста (<code>localhost</code>) или целият URL адрес (<code>ldap://сървър.tld:389</code>)'; +$lang['port'] = 'Порт на LDAP сървъра, ако не сте въвели целия URL адрес по-горе'; +$lang['usertree'] = 'Къде да се търси за потребителски акаунти. Например <code>ou=People, dc=server, dc=tld</code>'; +$lang['grouptree'] = 'Къде да се търси за потребителски групи. Например <code>ou=Group, dc=server, dc=tld</code>'; +$lang['userfilter'] = 'LDAP филтър за търсене на потребителски акаунти. Например <code>(&(uid=%{user})(objectClass=posixAccount))</code>'; +$lang['groupfilter'] = 'LDAP филтър за търсене на потребителски групи. Например <code>(&(objectClass=posixGroup)(|(gidNumber=%{gid})(memberUID=%{user})))</code>'; +$lang['version'] = 'Коя версия на протокола да се ползва? Вероятно ще се наложи да зададете <code>3</code>'; +$lang['starttls'] = 'Ползване на TLS свързаност?'; +$lang['referrals'] = 'Да бъдат ли следвани препратките (препращанията)?'; +$lang['bindpw'] = 'Парола за горния потребител'; +$lang['userscope'] = 'Ограничаване на обхвата за търсене на потребители'; +$lang['groupscope'] = 'Ограничаване на обхвата за търсене на потребителски групи'; +$lang['debug'] = 'Показване на допълнителна debug информация при грешка'; \ No newline at end of file diff --git a/lib/plugins/authmysql/lang/bg/settings.php b/lib/plugins/authmysql/lang/bg/settings.php new file mode 100644 index 000000000..fcc7f625d --- /dev/null +++ b/lib/plugins/authmysql/lang/bg/settings.php @@ -0,0 +1,17 @@ +<?php +/** + * Bulgarian language file + * + * @author Kiril <neohidra@gmail.com> + */ +$lang['server'] = 'Вашият MySQL сървър'; +$lang['user'] = 'MySQL потребителско име'; +$lang['password'] = 'Парола за горния потребител'; +$lang['database'] = 'Име на базата от данни'; +$lang['charset'] = 'Набор от знаци, който се ползва в базата от данни'; +$lang['debug'] = 'Показване на допълнителна debug информация'; + + +$lang['debug_o_0'] = 'не'; +$lang['debug_o_1'] = 'само при грешка'; +$lang['debug_o_2'] = 'за всяко SQL запитване'; \ No newline at end of file diff --git a/lib/plugins/authpgsql/lang/bg/settings.php b/lib/plugins/authpgsql/lang/bg/settings.php new file mode 100644 index 000000000..0defdc4ff --- /dev/null +++ b/lib/plugins/authpgsql/lang/bg/settings.php @@ -0,0 +1,12 @@ +<?php +/** + * Bulgarian language file + * + * @author Kiril <neohidra@gmail.com> + */ +$lang['server'] = 'Вашият PostgreSQL сървър'; +$lang['port'] = 'Порт за PostgreSQL сървъра'; +$lang['user'] = 'PostgreSQL потребител'; +$lang['password'] = 'Парола за горния потребител'; +$lang['database'] = 'Име на базата от данни'; +$lang['debug'] = 'Показване на допълнителна debug информация'; \ No newline at end of file -- cgit v1.2.3 From 4e90caaad144f84c8a9e59ddd3ba38a52135e1ad Mon Sep 17 00:00:00 2001 From: Michael Hamann <michael@content-space.de> Date: Fri, 8 Mar 2013 18:15:02 +0100 Subject: Redirect only in the show action to namespace start pages FS#2743 When the current page id ends with ":" (or "/" with useslash enabled) DokuWiki tries to find the start page of namespaces automatically and then redirects to this page. The target of the redirect is always the show action regardless if the current request contains another action or is an ajax request. In practice you can get this problem when your search query ends with ":" (e.g. because you want to match a namespace), then you are redirected to the show action. This change completely disables the redirect when $ACT is undefined or the current action is not "show". --- inc/pageutils.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/inc/pageutils.php b/inc/pageutils.php index ca4936a82..5043d2263 100644 --- a/inc/pageutils.php +++ b/inc/pageutils.php @@ -21,6 +21,7 @@ function getID($param='id',$clean=true){ global $INPUT; global $conf; + global $ACT; $id = $INPUT->str($param); @@ -75,7 +76,7 @@ function getID($param='id',$clean=true){ // fall back to default $id = $id.$conf['start']; } - send_redirect(wl($id,'',true)); + if (isset($ACT) && $ACT === 'show') send_redirect(wl($id,'',true)); } if($clean) $id = cleanID($id); -- cgit v1.2.3 From 19ff1b0b4db62e68869a2b375ae736b4c7a1fe65 Mon Sep 17 00:00:00 2001 From: Anika Henke <anika@selfthinker.org> Date: Sat, 9 Mar 2013 13:47:53 +0000 Subject: fixed use of removed plugin function in revert plugin (FS#2744) --- lib/plugins/revert/admin.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/plugins/revert/admin.php b/lib/plugins/revert/admin.php index 847e38876..ccad6e9de 100644 --- a/lib/plugins/revert/admin.php +++ b/lib/plugins/revert/admin.php @@ -46,7 +46,7 @@ class admin_plugin_revert extends DokuWiki_Admin_Plugin { function html() { global $INPUT; - echo $this->plugin_locale_xhtml('intro'); + echo $this->locale_xhtml('intro'); $this->_searchform(); -- cgit v1.2.3 From 8c447db27f2ba34e86e64fe285e1ecfe08e486f1 Mon Sep 17 00:00:00 2001 From: Anika Henke <anika@selfthinker.org> Date: Sat, 9 Mar 2013 17:33:38 +0000 Subject: increased copyright year in wiki:dokuwiki --- data/pages/wiki/dokuwiki.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/pages/wiki/dokuwiki.txt b/data/pages/wiki/dokuwiki.txt index e6fac5b65..2db4dbef3 100644 --- a/data/pages/wiki/dokuwiki.txt +++ b/data/pages/wiki/dokuwiki.txt @@ -57,7 +57,7 @@ All documentation and additional information besides the [[syntax|syntax descrip ===== Copyright ===== -2004-2010 (c) Andreas Gohr <andi@splitbrain.org>((Please do not contact me for help and support -- use the [[doku>mailinglist]] or [[http://forum.dokuwiki.org|forum]] instead)) and the DokuWiki Community +2004-2013 (c) Andreas Gohr <andi@splitbrain.org>((Please do not contact me for help and support -- use the [[doku>mailinglist]] or [[http://forum.dokuwiki.org|forum]] instead)) and the DokuWiki Community The DokuWiki engine is licensed under [[http://www.gnu.org/licenses/gpl.html|GNU General Public License]] Version 2. If you use DokuWiki in your company, consider [[doku>donate|donating]] a few bucks ;-). -- cgit v1.2.3 From 5b84f8e9c9749b424f3813f7126245330a7deb1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=97=A5=E5=90=91=E5=B0=8F=E9=83=8E?= <syaoranhinata@gmail.com> Date: Mon, 11 Mar 2013 15:33:07 +0100 Subject: Traditional chinese language update --- inc/lang/zh-tw/index.txt | 4 +-- inc/lang/zh-tw/lang.php | 21 ++++++++------ inc/lang/zh-tw/mailtext.txt | 4 +-- inc/lang/zh-tw/password.txt | 2 +- inc/lang/zh-tw/pwconfirm.txt | 2 +- inc/lang/zh-tw/register.txt | 2 +- inc/lang/zh-tw/registermail.txt | 4 +-- inc/lang/zh-tw/resetpwd.txt | 2 +- inc/lang/zh-tw/revisions.txt | 2 +- inc/lang/zh-tw/subscr_digest.txt | 2 +- inc/lang/zh-tw/subscr_list.txt | 2 +- inc/lang/zh-tw/subscr_single.txt | 2 +- inc/lang/zh-tw/uploadmail.txt | 2 +- lib/plugins/authad/lang/zh-tw/settings.php | 18 ++++++++++++ lib/plugins/authldap/lang/zh-tw/settings.php | 21 ++++++++++++++ lib/plugins/authmysql/lang/zh-tw/settings.php | 41 +++++++++++++++++++++++++++ lib/plugins/authpgsql/lang/zh-tw/settings.php | 37 ++++++++++++++++++++++++ lib/plugins/config/lang/zh-tw/lang.php | 26 ++++++++--------- lib/plugins/popularity/lang/zh-tw/intro.txt | 4 +-- lib/plugins/popularity/lang/zh-tw/lang.php | 2 +- lib/plugins/revert/lang/zh-tw/lang.php | 2 +- lib/plugins/usermanager/lang/zh-tw/lang.php | 4 +-- 22 files changed, 163 insertions(+), 43 deletions(-) create mode 100644 lib/plugins/authad/lang/zh-tw/settings.php create mode 100644 lib/plugins/authldap/lang/zh-tw/settings.php create mode 100644 lib/plugins/authmysql/lang/zh-tw/settings.php create mode 100644 lib/plugins/authpgsql/lang/zh-tw/settings.php diff --git a/inc/lang/zh-tw/index.txt b/inc/lang/zh-tw/index.txt index 1b89e0c5d..31e60ac87 100644 --- a/inc/lang/zh-tw/index.txt +++ b/inc/lang/zh-tw/index.txt @@ -1,3 +1,3 @@ -====== 站台地圖 ====== +====== 網站地圖 ====== -這個站台地圖列出了所有允許的頁面,依 [[doku>namespaces|分類名稱]] 排序。 \ No newline at end of file +這個網站地圖列出了所有允許的頁面,依 [[doku>namespaces|分類名稱]] 排序。 \ No newline at end of file diff --git a/inc/lang/zh-tw/lang.php b/inc/lang/zh-tw/lang.php index 536266971..0a3dbf51f 100644 --- a/inc/lang/zh-tw/lang.php +++ b/inc/lang/zh-tw/lang.php @@ -34,7 +34,7 @@ $lang['btn_revs'] = '舊版'; $lang['btn_recent'] = '最近更新'; $lang['btn_upload'] = '上傳'; $lang['btn_cancel'] = '取消'; -$lang['btn_index'] = '站台地圖'; +$lang['btn_index'] = '網站地圖'; $lang['btn_secedit'] = '編輯此段'; $lang['btn_login'] = '登入'; $lang['btn_logout'] = '登出'; @@ -55,7 +55,7 @@ $lang['btn_revert'] = '復原'; $lang['btn_register'] = '註冊'; $lang['btn_apply'] = '套用'; $lang['btn_media'] = '多媒體管理器'; -$lang['loggedinas'] = '登入為'; +$lang['loggedinas'] = '登入成'; $lang['user'] = '帳號'; $lang['pass'] = '密碼'; $lang['newpass'] = '新密碼'; @@ -73,8 +73,8 @@ $lang['regmissing'] = '很抱歉,所有欄位都要填寫。'; $lang['reguexists'] = '很抱歉,有人已使用了這個帳號。'; $lang['regsuccess'] = '使用者帳號已建立,密碼已寄發至該電郵。'; $lang['regsuccess2'] = '使用者帳號已建立。'; -$lang['regmailfail'] = '寄出密碼信似乎發生錯誤,請跟管理員聯絡!'; -$lang['regbadmail'] = '您輸入的電郵似乎不對,如果您認為是正確的,請與管理員聯絡。'; +$lang['regmailfail'] = '寄出密碼信似乎有問題,請跟管理員聯絡!'; +$lang['regbadmail'] = '您輸入的電郵地址似乎不正確。若您覺得是正確的,請與管理員聯絡。'; $lang['regbadpass'] = '兩次輸入的密碼不一致,請再試一次。'; $lang['regpwmail'] = '您的 DokuWiki 帳號密碼'; $lang['reghere'] = '您還沒有帳號嗎?註冊一個吧。'; @@ -164,7 +164,7 @@ $lang['mediausage'] = '使用以下的語法來連結此檔案:'; $lang['mediaview'] = '檢視原始檔案'; $lang['mediaroot'] = 'root'; $lang['mediaupload'] = '上傳檔案至目前分類名稱之下。要建立子分類名稱,請將其名稱加在「上傳並重命名為」檔案名的前面,並用英文冒號隔開。'; -$lang['mediaextchange'] = '檔案類型已由 .%s 變更為 .%s !'; +$lang['mediaextchange'] = '檔案類型已由 .%s 變更作 .%s !'; $lang['reference'] = '引用到本頁的,合計有'; $lang['ref_inuse'] = '此檔案無法刪除,因以下頁面正在使用它:'; $lang['ref_hidden'] = '一些參考內容位於您沒有讀取權限的頁面中'; @@ -186,7 +186,7 @@ $lang['lastmod'] = '上一次變更'; $lang['by'] = '由'; $lang['deleted'] = '移除'; $lang['created'] = '建立'; -$lang['restored'] = '恢復為舊版 (%s)'; +$lang['restored'] = '還原成舊版 (%s)'; $lang['external_edit'] = '外部編輯'; $lang['summary'] = '編輯摘要'; $lang['noflash'] = '顯示此內容需要 <a href="http://www.adobe.com/products/flashplayer/">Adobe Flash 附加元件</a>。'; @@ -266,7 +266,7 @@ $lang['subscr_style_every'] = '每次更改都發送信件'; $lang['subscr_style_digest'] = '對每個頁面發送更改的摘要信件 (每 %.2f 天)'; $lang['subscr_style_list'] = '自上次發信以來更改的頁面的列表 (每 %.2f 天)'; $lang['authmodfailed'] = '帳號認證的設定不正確,請通知該本 wiki 管理員。'; -$lang['authtempfail'] = '帳號認證目前暫不提供。若本狀況持續,請通知本 wiki 管理員。'; +$lang['authtempfail'] = '暫不提供帳號認證。若本狀況持續,請通知本 wiki 管理員。'; $lang['authpwdexpire'] = '您的密碼將在 %d 天內到期,請馬上更換新密碼。'; $lang['i_chooselang'] = '選擇您的語系'; $lang['i_installer'] = 'DokuWiki 安裝工具'; @@ -291,7 +291,10 @@ $lang['i_pol0'] = '開放的 wiki (任何人可讀取、寫入、 $lang['i_pol1'] = '公開的 wiki (任何人可讀取,註冊使用者可寫入與上傳)'; $lang['i_pol2'] = '封閉的 wiki (只有註冊使用者可讀取、寫入、上傳)'; $lang['i_retry'] = '重試'; -$lang['i_license'] = '請選擇您想要的內容發布許可協議:'; +$lang['i_license'] = '請選擇您想要的內容發佈授權方式:'; +$lang['i_license_none'] = '不要顯示任何關於授權方式的訊息'; +$lang['i_pop_field'] = '請協助我們改進 Dokuwiki:'; +$lang['i_pop_label'] = '每月向 Dokuwiki 開發者發送匿名的使用數據'; $lang['recent_global'] = '您正在閱讀分類名稱: <b>%s</b> 中的變更。您亦可觀看本 wiki <a href="%s">所有的最近更新</a>。'; $lang['years'] = '%d 年前'; $lang['months'] = '%d 個月前'; @@ -300,7 +303,7 @@ $lang['days'] = '%d 天前'; $lang['hours'] = '%d 個小時前'; $lang['minutes'] = '%d 分鐘前'; $lang['seconds'] = '%s 秒鐘前'; -$lang['wordblock'] = '無法儲存您的更改,因為它含有受阻擋的文字 (垃圾訊息)。'; +$lang['wordblock'] = '無法儲存您的更改,因它含有受阻擋的文字 (垃圾訊息)。'; $lang['media_uploadtab'] = '上傳'; $lang['media_searchtab'] = '搜尋'; $lang['media_file'] = '檔案'; diff --git a/inc/lang/zh-tw/mailtext.txt b/inc/lang/zh-tw/mailtext.txt index 2a402c2fb..e99858c75 100644 --- a/inc/lang/zh-tw/mailtext.txt +++ b/inc/lang/zh-tw/mailtext.txt @@ -13,5 +13,5 @@ IP 位址 : @IPADDRESS@ -- -本信件由以下 DokuWiki 站台產生: -@DOKUWIKIURL@ +本信件由以下 DokuWiki 網站產生: +@DOKUWIKIURL@ \ No newline at end of file diff --git a/inc/lang/zh-tw/password.txt b/inc/lang/zh-tw/password.txt index 5d383b528..9c5ad2f9d 100644 --- a/inc/lang/zh-tw/password.txt +++ b/inc/lang/zh-tw/password.txt @@ -6,5 +6,5 @@ 密碼 : @PASSWORD@ -- -本信件由以下 DokuWiki 站台產生: +本信件由以下 DokuWiki 網站產生: @DOKUWIKIURL@ diff --git a/inc/lang/zh-tw/pwconfirm.txt b/inc/lang/zh-tw/pwconfirm.txt index fb8a5cb82..6f6dcd3c4 100644 --- a/inc/lang/zh-tw/pwconfirm.txt +++ b/inc/lang/zh-tw/pwconfirm.txt @@ -9,5 +9,5 @@ @CONFIRM@ -- -本信件由以下 DokuWiki 站台產生: +本信件由以下 DokuWiki 網站產生: @DOKUWIKIURL@ \ No newline at end of file diff --git a/inc/lang/zh-tw/register.txt b/inc/lang/zh-tw/register.txt index 3ff68dee3..6f2a75c9a 100644 --- a/inc/lang/zh-tw/register.txt +++ b/inc/lang/zh-tw/register.txt @@ -1,3 +1,3 @@ ====== 註冊新使用者 ====== -若要註冊本 wiki 的帳號,請填寫下列資料。請確定您提供的是**合法的電郵地址**。如果您不必填寫密碼,系統就會為您自動產生登入密碼,並寄送到該電郵地址。登錄名稱須符合正確[[doku>pagename|頁面名稱]]之條件。 +若要註冊本 wiki 的帳號,請填寫下列資料。請確定您提供的是**合法的電郵地址**。如果您不必填寫密碼,系統就會為您自動產生登入密碼,並寄送到該電郵地址。登入名稱須符合正確[[doku>pagename|頁面名稱]]之條件。 diff --git a/inc/lang/zh-tw/registermail.txt b/inc/lang/zh-tw/registermail.txt index fb4951d60..a67835d77 100644 --- a/inc/lang/zh-tw/registermail.txt +++ b/inc/lang/zh-tw/registermail.txt @@ -10,5 +10,5 @@ IP 位址 : @IPADDRESS@ 主機名稱 : @HOSTNAME@ -- -本信件由以下 DokuWiki 站台產生: -@DOKUWIKIURL@ +本信件由以下 DokuWiki 網站產生: +@DOKUWIKIURL@ \ No newline at end of file diff --git a/inc/lang/zh-tw/resetpwd.txt b/inc/lang/zh-tw/resetpwd.txt index f760335af..ef0bff256 100644 --- a/inc/lang/zh-tw/resetpwd.txt +++ b/inc/lang/zh-tw/resetpwd.txt @@ -1,3 +1,3 @@ ====== 設定新密碼 ====== -請為您的帳戶輸入新密碼。 \ No newline at end of file +請為您的帳號輸入新密碼。 \ No newline at end of file diff --git a/inc/lang/zh-tw/revisions.txt b/inc/lang/zh-tw/revisions.txt index 4818839ac..64daa9935 100644 --- a/inc/lang/zh-tw/revisions.txt +++ b/inc/lang/zh-tw/revisions.txt @@ -1,3 +1,3 @@ ====== 舊版 ====== -以下是該文件的舊版本。如要恢復成某個舊版次,就點下它,然後按「編輯本頁」,並存檔起來就可以了。 +以下是該文件的舊版本。如要還原成某個舊版次,就點下它,然後按「編輯本頁」,並存檔起來就可以了。 \ No newline at end of file diff --git a/inc/lang/zh-tw/subscr_digest.txt b/inc/lang/zh-tw/subscr_digest.txt index a17a0551d..1a34087c3 100644 --- a/inc/lang/zh-tw/subscr_digest.txt +++ b/inc/lang/zh-tw/subscr_digest.txt @@ -15,5 +15,5 @@ 並取消訂閱頁面或分類名稱的更改。 -- -本信件由以下 DokuWiki 站台產生: +本信件由以下 DokuWiki 網站產生: @DOKUWIKIURL@ \ No newline at end of file diff --git a/inc/lang/zh-tw/subscr_list.txt b/inc/lang/zh-tw/subscr_list.txt index ea82dd35d..da2fb33e5 100644 --- a/inc/lang/zh-tw/subscr_list.txt +++ b/inc/lang/zh-tw/subscr_list.txt @@ -12,5 +12,5 @@ 並取消訂閱頁面或分類名稱的更改。 -- -本信件由以下 DokuWiki 站台產生: +本信件由以下 DokuWiki 網站產生: @DOKUWIKIURL@ \ No newline at end of file diff --git a/inc/lang/zh-tw/subscr_single.txt b/inc/lang/zh-tw/subscr_single.txt index 14d87bb73..b11841b39 100644 --- a/inc/lang/zh-tw/subscr_single.txt +++ b/inc/lang/zh-tw/subscr_single.txt @@ -18,5 +18,5 @@ 並取消訂閱頁面或分類名稱的更改。 -- -本信件由以下 DokuWiki 站台產生: +本信件由以下 DokuWiki 網站產生: @DOKUWIKIURL@ \ No newline at end of file diff --git a/inc/lang/zh-tw/uploadmail.txt b/inc/lang/zh-tw/uploadmail.txt index 87bac7c9a..0084d7a7a 100644 --- a/inc/lang/zh-tw/uploadmail.txt +++ b/inc/lang/zh-tw/uploadmail.txt @@ -10,5 +10,5 @@ MIME類型 : @MIME@ 使用者 : @USER@ -- -本信件由以下 DokuWiki 站台產生: +本信件由以下 DokuWiki 網站產生: @DOKUWIKIURL@ \ No newline at end of file diff --git a/lib/plugins/authad/lang/zh-tw/settings.php b/lib/plugins/authad/lang/zh-tw/settings.php new file mode 100644 index 000000000..e38a2c007 --- /dev/null +++ b/lib/plugins/authad/lang/zh-tw/settings.php @@ -0,0 +1,18 @@ +<?php +/** + * Chinese Traditional language file + * + * @author syaoranhinata@gmail.com + */ +$lang['account_suffix'] = '您的帳號後綴。如: <code>@my.domain.org</code>'; +$lang['base_dn'] = '您的基本識別名。如: <code>DC=my,DC=domain,DC=org</code>'; +$lang['domain_controllers'] = '以逗號分隔的域名控制器列表。如: <code>srv1.domain.org,srv2.domain.org</code>'; +$lang['ad_username'] = 'Active Directory 的特權使用者,可以查看所有使用者的數據。(非必要,但對發送訂閱郵件等活動來說,這是必須的。)'; +$lang['ad_password'] = '上述使用者的密碼。'; +$lang['sso'] = '是否使用 Kerberos 或 NTLM 的單一登入系統 (Single-Sign-On)?'; +$lang['real_primarygroup'] = '是否視作真正的主要群組,而不是假設為網域使用者 (比較慢)'; +$lang['use_ssl'] = '使用 SSL 連接嗎?如果要使用,請不要啟用下方的 TLS。'; +$lang['use_tls'] = '使用 TLS 連接嗎?如果要使用,請不要啟用上方的 SSL。'; +$lang['debug'] = '有錯誤時,顯示額外除錯資訊嗎?'; +$lang['expirywarn'] = '提前多少天警告使用者密碼即將到期。輸入0表示停用。'; +$lang['additional'] = '從使用者數據中取得額外 AD 屬性列表,以供某些附加元件使用。列表以逗號分隔。'; diff --git a/lib/plugins/authldap/lang/zh-tw/settings.php b/lib/plugins/authldap/lang/zh-tw/settings.php new file mode 100644 index 000000000..e93190516 --- /dev/null +++ b/lib/plugins/authldap/lang/zh-tw/settings.php @@ -0,0 +1,21 @@ +<?php +/** + * Chinese Traditional language file + * + * @author syaoranhinata@gmail.com + */ +$lang['server'] = '您的 LDAP 伺服器。填寫主機名稱 (<code>localhost</code>) 或完整的 URL (<code>ldap://server.tld:389</code>)'; +$lang['port'] = 'LDAP 伺服器端口 (若上方沒填寫完整的 URL)'; +$lang['usertree'] = '到哪裏尋找使用者帳號?如: <code>ou=People, dc=server, dc=tld</code>'; +$lang['grouptree'] = '到哪裏尋找使用者群組?如: <code>ou=Group, dc=server, dc=tld</code>'; +$lang['userfilter'] = '用於搜索使用者賬號的 LDAP 篩選器。如: <code>(&(uid=%{user})(objectClass=posixAccount))</code>'; +$lang['groupfilter'] = '用於搜索群組的 LDAP 篩選器。例如 <code>(&(objectClass=posixGroup)(|(gidNumber=%{gid})(memberUID=%{user})))</code>'; +$lang['version'] = '使用的通訊協定版本。您可能要設置為 <code>3</code>'; +$lang['starttls'] = '使用 TLS 連接嗎?'; +$lang['referrals'] = '是否允許引用 (referrals)?'; +$lang['binddn'] = '非必要綁定使用者 (optional bind user) 的 DN (匿名綁定不能滿足要求時使用)。如: <code>cn=admin, dc=my, dc=home</code>'; +$lang['bindpw'] = '上述使用者的密碼'; +$lang['userscope'] = '限制使用者搜索的範圍'; +$lang['groupscope'] = '限制群組搜索的範圍'; +$lang['groupkey'] = '以其他使用者屬性 (而非標準 AD 群組) 來把使用者分組,例如以部門或電話號碼分類'; +$lang['debug'] = '有錯誤時,顯示額外除錯資訊'; diff --git a/lib/plugins/authmysql/lang/zh-tw/settings.php b/lib/plugins/authmysql/lang/zh-tw/settings.php new file mode 100644 index 000000000..95d068150 --- /dev/null +++ b/lib/plugins/authmysql/lang/zh-tw/settings.php @@ -0,0 +1,41 @@ +<?php +/** + * Chinese Traditional language file + * + * @author syaoranhinata@gmail.com + */ +$lang['server'] = '您的 MySQL 伺服器'; +$lang['user'] = 'MySQL 使用者名稱'; +$lang['password'] = '上述使用者的密碼'; +$lang['database'] = '使用的資料庫'; +$lang['charset'] = '資料庫使用的字符集'; +$lang['debug'] = '顯示額外除錯資訊'; +$lang['forwardClearPass'] = '以明文形式,把使用者密碼傳送给下列的 SQL 語句,而不使用 passcrypt 密碼加密選項'; +$lang['TablesToLock'] = '在寫操作時需要鎖定的數據表列表,以逗號分隔'; +$lang['checkPass'] = '檢查密碼的 SQL 語句'; +$lang['getUserInfo'] = '獲取使用者訊息的 SQL 語句'; +$lang['getGroups'] = '獲取使用者群組成員身份的 SQL 語句'; +$lang['getUsers'] = '把所有使用者列出的 SQL 語句'; +$lang['FilterLogin'] = '根據登入名稱來篩選使用者的 SQL 子句'; +$lang['FilterName'] = '根據全名來篩選使用者的 SQL 子句'; +$lang['FilterEmail'] = '根據電郵地址來篩選使用者的 SQL 子句'; +$lang['FilterGroup'] = '根據群組成員身份來篩選使用者的 SQL 子句'; +$lang['SortOrder'] = '對使用者排序的 SQL 子句'; +$lang['addUser'] = '增加新使用者的 SQL 語句'; +$lang['addGroup'] = '增加新群組的 SQL 語句'; +$lang['addUserGroup'] = '把使用者新增至現有群組的 SQL 語句'; +$lang['delGroup'] = '把群組刪除的 SQL 語句'; +$lang['getUserID'] = '取得使用者主鍵的 SQL 語句'; +$lang['delUser'] = '把使用者刪除的 SQL 語句'; +$lang['delUserRefs'] = '把使用者從所有群組裏刪除的 SQL 語句'; +$lang['updateUser'] = '更新使用者訊息的 SQL 語句'; +$lang['UpdateLogin'] = '更新使用者登入名稱的 Update 子句'; +$lang['UpdatePass'] = '更新帳號密碼的 Update 子句'; +$lang['UpdateEmail'] = '更新使用者電郵地址的 Update 子句'; +$lang['UpdateName'] = '更新使用者全名的 Update 子句'; +$lang['UpdateTarget'] = '在更新時識別使用者的 Limit 子句'; +$lang['delUserGroup'] = '把使用者從指定群組中刪除的 SQL 語句'; +$lang['getGroupID'] = '取得指定群組主鍵的 SQL 語句'; +$lang['debug_o_0'] = '無'; +$lang['debug_o_1'] = '僅在有錯誤時'; +$lang['debug_o_2'] = '所有 SQL 查詢'; diff --git a/lib/plugins/authpgsql/lang/zh-tw/settings.php b/lib/plugins/authpgsql/lang/zh-tw/settings.php new file mode 100644 index 000000000..6a04214ad --- /dev/null +++ b/lib/plugins/authpgsql/lang/zh-tw/settings.php @@ -0,0 +1,37 @@ +<?php +/** + * Chinese Traditional language file + * + * @author syaoranhinata@gmail.com + */ +$lang['server'] = '您的 PostgreSQL 伺服器'; +$lang['port'] = '您的 PostgreSQL 伺服器端口'; +$lang['user'] = 'PostgreSQL 使用者名稱'; +$lang['password'] = '上述使用者的密碼'; +$lang['database'] = '使用的資料庫'; +$lang['debug'] = '顯示額外除錯資訊'; +$lang['forwardClearPass'] = '以明文形式,把使用者密碼傳送给下列的 SQL 語句,而不使用 passcrypt 密碼加密選項'; +$lang['checkPass'] = '檢查密碼的 SQL 語句'; +$lang['getUserInfo'] = '獲取使用者訊息的 SQL 語句'; +$lang['getGroups'] = '獲取使用者群組成員身份的 SQL 語句'; +$lang['getUsers'] = '把所有使用者列出的 SQL 語句'; +$lang['FilterLogin'] = '根據登入名稱來篩選使用者的 SQL 子句'; +$lang['FilterName'] = '根據全名來篩選使用者的 SQL 子句'; +$lang['FilterEmail'] = '根據電郵地址來篩選使用者的 SQL 子句'; +$lang['FilterGroup'] = '根據群組成員身份來篩選使用者的 SQL 子句'; +$lang['SortOrder'] = '對使用者排序的 SQL 子句'; +$lang['addUser'] = '增加新使用者的 SQL 語句'; +$lang['addGroup'] = '增加新群組的 SQL 語句'; +$lang['addUserGroup'] = '把使用者新增至現有群組的 SQL 語句'; +$lang['delGroup'] = '把群組刪除的 SQL 語句'; +$lang['getUserID'] = '取得使用者主鍵的 SQL 語句'; +$lang['delUser'] = '把使用者刪除的 SQL 語句'; +$lang['delUserRefs'] = '把使用者從所有群組裏刪除的 SQL 語句'; +$lang['updateUser'] = '更新使用者訊息的 SQL 語句'; +$lang['UpdateLogin'] = '更新使用者登入名稱的 Update 子句'; +$lang['UpdatePass'] = '更新帳號密碼的 Update 子句'; +$lang['UpdateEmail'] = '更新使用者電郵地址的 Update 子句'; +$lang['UpdateName'] = '更新使用者全名的 Update 子句'; +$lang['UpdateTarget'] = '在更新時識別使用者的 Limit 子句'; +$lang['delUserGroup'] = '把使用者從指定群組中刪除的 SQL 語句'; +$lang['getGroupID'] = '取得指定群組主鍵的 SQL 語句'; diff --git a/lib/plugins/config/lang/zh-tw/lang.php b/lib/plugins/config/lang/zh-tw/lang.php index 8f5b16220..cc6e0246e 100644 --- a/lib/plugins/config/lang/zh-tw/lang.php +++ b/lib/plugins/config/lang/zh-tw/lang.php @@ -46,9 +46,9 @@ $lang['title'] = '本 wiki 的標題'; $lang['start'] = '開始頁面的名稱'; $lang['lang'] = '語系'; $lang['template'] = '樣板'; -$lang['tagline'] = '副標題 (若模板支援此功能)'; -$lang['sidebar'] = '側欄的頁面名稱 (若模板支援此功能) 。若把它留空,則會停用側欄'; -$lang['license'] = '您希望您的內容為何種授權方式?'; +$lang['tagline'] = '副標題 (若樣板支援此功能)'; +$lang['sidebar'] = '側欄的頁面名稱 (若樣板支援此功能) 。若把它留空,則會停用側欄'; +$lang['license'] = '您希望您的內容採用哪種授權方式?'; $lang['savedir'] = '儲存資料的目錄'; $lang['basedir'] = '根目錄'; $lang['baseurl'] = '根路徑 (URL)'; @@ -58,8 +58,8 @@ $lang['fmode'] = '檔案建立模式'; $lang['allowdebug'] = '允許除錯 <b>(不需要請停用!)</b>'; $lang['recent'] = '最近更新'; $lang['recent_days'] = '儲存多少天內的變更'; -$lang['breadcrumbs'] = '導覽鏈數量'; -$lang['youarehere'] = '顯示階層式導覽鏈'; +$lang['breadcrumbs'] = '導覽路徑數量。輸入0表示停用。'; +$lang['youarehere'] = '顯示階層式導覽路徑 (若要用此功能,建議停用上方的選項)'; $lang['fullpath'] = '顯示完整的路徑於頁面底部'; $lang['typography'] = '進行字元替換'; $lang['dformat'] = '日期格式 (參見 PHP 的 <a href="http://www.php.net/strftime">strftime</a> 函數)'; @@ -71,7 +71,7 @@ $lang['maxtoclevel'] = '目錄表顯示的最大層級'; $lang['maxseclevel'] = '可編輯段落的最大層級'; $lang['camelcase'] = '對連結使用 CamelCase'; $lang['deaccent'] = '清理頁面名稱'; -$lang['useheading'] = '使用第一個標題作為頁面名稱'; +$lang['useheading'] = '使用第一個標題作頁面名稱'; $lang['sneaky_index'] = '預設情況下,DokuWiki 會在索引頁會顯示所有分類名稱。啟用此選項,會隱藏使用者沒有閱讀權限的頁面,但也可能將他可以閱讀的子頁面一併隱藏。在特定 ACL 設定下,這可能導致索引無法使用。'; $lang['hidepages'] = '隱藏匹配的界面 (正規式)'; $lang['useacl'] = '使用存取控制名單'; @@ -121,7 +121,7 @@ $lang['registernotify'] = '寄送新使用者註冊資訊到這個電郵 $lang['mailfrom'] = '自動發送郵件時使用的郵件地址'; $lang['mailprefix'] = '自動發送郵件時使用的標題前綴'; $lang['htmlmail'] = '發送更加美觀,但體積會更大的 HTML 多部份電郵。若停用它,表示只發送純文字電郵。'; -$lang['sitemap'] = '產生 Google 站台地圖 (以多少天計算) 。輸入0表示停用'; +$lang['sitemap'] = '產生 Google 網站地圖 (以多少天計算) 。輸入0表示停用'; $lang['rss_type'] = 'XML feed 類型'; $lang['rss_linkto'] = 'XML feed 連結到'; $lang['rss_content'] = 'XML feed 項目中顯示什麼呢?'; @@ -130,7 +130,7 @@ $lang['rss_show_summary'] = '於標題中顯示簡要的 XML feed'; $lang['rss_media'] = '在 XML feed 中應列出哪些變更?'; $lang['updatecheck'] = '檢查更新與安全性警告?DokuWiki 需要聯繫 update.dokuwiki.org 才能使用此功能。'; $lang['userewrite'] = '使用好看的 URL'; -$lang['useslash'] = '在 URL 中使用斜線作為分類名稱的分隔字元'; +$lang['useslash'] = '在 URL 中使用斜線作分類名稱的分隔字元'; $lang['sepchar'] = '頁面名稱中單字的分隔字元'; $lang['canonical'] = '使用最典型的 URL'; $lang['fnencode'] = '非 ASCII 文件名稱的編輯方法。'; @@ -140,12 +140,12 @@ $lang['gzip_output'] = '對 xhtml 使用 gzip 內容編碼'; $lang['compress'] = '壓縮 CSS 與 JavaScript 的輸出'; $lang['cssdatauri'] = '假如 CSS 中所引用的圖片小於該數字大小(bytes),圖片將被直接嵌入 CSS 中,以減少 HTTP Request 的發送。 IE 7 及以下的版本並不支援此功能。推薦把此數值設定成 <code>400</code> 至 <code>600</code> bytes 之間。若輸入 <code>0</code> 則停用此功能。'; $lang['send404'] = '存取不存在的頁面時送出 "HTTP 404/Page Not Found"'; -$lang['broken_iua'] = 'ignore_user_abort 功能失效了?這有可能導致搜索索引不可用。IIS+PHP/CGI 已損壞。請參閱 <a href=\"http://bugs.splitbrain.org/?do=details&task_id=852\">Bug 852</a> 獲取更多信息。'; -$lang['xsendfile'] = '使用 X-Sendfile 頭讓服務器發送狀態文件?您的服務器需要支持該功能。'; -$lang['renderer_xhtml'] = '主要wiki輸出 (xhtml) 的渲染器'; +$lang['broken_iua'] = 'ignore_user_abort 功能失效了?這有可能導致搜索索引不可用。IIS+PHP/CGI 已損壞。請參閱 <a href=\"http://bugs.splitbrain.org/?do=details&task_id=852\">Bug 852</a> 獲取更多訊息。'; +$lang['xsendfile'] = '使用 X-Sendfile 頭讓網頁伺服器發送狀態文件?您的網頁伺服器需要支持該功能。'; +$lang['renderer_xhtml'] = '主要 wiki 輸出 (xhtml) 的渲染器'; $lang['renderer__core'] = '%s (dokuwiki 核心)'; $lang['renderer__plugin'] = '%s (附加元件)'; -$lang['dnslookups'] = 'Dokuwiki 將查詢使用者編輯頁面的遠程 IP 位址主機名稱。若您的 DNS 服務器速度較慢、失效,或者您不想要此功能,请停用此選項'; +$lang['dnslookups'] = 'Dokuwiki 將查詢使用者編輯頁面的遠程 IP 位址主機名稱。若您的 DNS 伺服器速度較慢、失效,或者您不想要此功能,请停用此選項'; $lang['proxy____host'] = 'Proxy 伺服器名稱'; $lang['proxy____port'] = 'Proxy 連接埠'; $lang['proxy____user'] = 'Proxy 使用者名稱'; @@ -188,7 +188,7 @@ $lang['compression_o_0'] = '無'; $lang['compression_o_gz'] = 'gzip'; $lang['compression_o_bz2'] = 'bz2'; $lang['xsendfile_o_0'] = '不使用'; -$lang['xsendfile_o_1'] = '專有 lighttpd 標頭 (1.5 發布前)'; +$lang['xsendfile_o_1'] = '專有 lighttpd 標頭 (1.5 發佈前)'; $lang['xsendfile_o_2'] = '標準 X-Sendfile 標頭'; $lang['xsendfile_o_3'] = '專有 Nginx X-Accel-Redirect 標頭'; $lang['showuseras_o_loginname'] = '登入名稱'; diff --git a/lib/plugins/popularity/lang/zh-tw/intro.txt b/lib/plugins/popularity/lang/zh-tw/intro.txt index 2a6337237..5ba42c5b9 100644 --- a/lib/plugins/popularity/lang/zh-tw/intro.txt +++ b/lib/plugins/popularity/lang/zh-tw/intro.txt @@ -1,8 +1,8 @@ ====== 人氣回饋 ====== -本工具會從您的 wiki 站台收集訊息,並以匿名的方式發送給 DokuWiki 的開發者。這有助於他們了解使用者們如何使用 DokuWiki ,並能基於實際統計資料對未來開發做出更準確的決策。 +本工具會從您的 wiki 網站收集訊息,並以匿名的方式發送給 DokuWiki 的開發者。這有助於他們了解使用者們如何使用 DokuWiki ,並能基於實際統計資料對未來開發做出更準確的決策。 -我們鼓勵您經常重複這個步驟,讓開發者了解您的 wiki 站台的成長情形。您的資料集將會被標識為一個匿名的識別碼 (ID) 。 +我們鼓勵您經常重複這個步驟,讓開發者了解您的 wiki 網站的成長情形。您的資料集將會被標識為一個匿名的識別碼 (ID) 。 收集的資料包括 DokuWiki 版本、頁面數量、檔案大小、安裝的附加元件,以及伺服器的 PHP 資訊。 diff --git a/lib/plugins/popularity/lang/zh-tw/lang.php b/lib/plugins/popularity/lang/zh-tw/lang.php index 890c23bfa..b34efe995 100644 --- a/lib/plugins/popularity/lang/zh-tw/lang.php +++ b/lib/plugins/popularity/lang/zh-tw/lang.php @@ -12,7 +12,7 @@ * @author syaoranhinata@gmail.com * @author Ichirou Uchiki <syaoranhinata@gmail.com> */ -$lang['name'] = '人氣回饋(可能需要一些時間載入)'; +$lang['name'] = '人氣回饋 (可能需要一些時間載入) '; $lang['submit'] = '發送資料'; $lang['autosubmit'] = '每月自動發送'; $lang['submissionFailed'] = '由於以下原因,資料無法發送:'; diff --git a/lib/plugins/revert/lang/zh-tw/lang.php b/lib/plugins/revert/lang/zh-tw/lang.php index afd858455..88a77f7a1 100644 --- a/lib/plugins/revert/lang/zh-tw/lang.php +++ b/lib/plugins/revert/lang/zh-tw/lang.php @@ -15,7 +15,7 @@ $lang['menu'] = '還原管理'; $lang['filter'] = '搜索包含垃圾訊息的頁面'; $lang['revert'] = '還原選取的頁面'; -$lang['reverted'] = '%s 已還原為版本 %s'; +$lang['reverted'] = '%s 已還原成版本 %s'; $lang['removed'] = '%s 已移除'; $lang['revstart'] = '已開始還原操作。有可能需要很長時間。如果程式執行逾時,請嘗試分次還原少量內容。'; $lang['revstop'] = '還原程序已完成。'; diff --git a/lib/plugins/usermanager/lang/zh-tw/lang.php b/lib/plugins/usermanager/lang/zh-tw/lang.php index 1db35cc82..980d974cc 100644 --- a/lib/plugins/usermanager/lang/zh-tw/lang.php +++ b/lib/plugins/usermanager/lang/zh-tw/lang.php @@ -33,7 +33,7 @@ $lang['modify'] = '儲存變更'; $lang['search'] = '搜尋'; $lang['search_prompt'] = '開始搜尋'; $lang['clear'] = '重設篩選條件'; -$lang['filter'] = '篩選條件(Filter)'; +$lang['filter'] = '篩選條件 (Filter)'; $lang['summary'] = '顯示帳號 %1$d-%2$d,共 %3$d 筆符合。共有 %4$d 個帳號。'; $lang['nonefound'] = '找不到帳號。共有 %d 個帳號。'; $lang['delete_ok'] = '已刪除 %d 個帳號'; @@ -49,7 +49,7 @@ $lang['edit_usermissing'] = '找不到選取的帳號,可能已被刪除 $lang['user_notify'] = '通知使用者'; $lang['note_notify'] = '通知信只會在指定使用者新密碼時寄送。'; $lang['note_group'] = '如果沒有指定群組,新使用者將會列入至預設群組(%s)當中。'; -$lang['note_pass'] = '如果沒有輸入這個欄位而且有勾選通知使用者,則會自動產生一組密碼。'; +$lang['note_pass'] = '如果勾選了通知使用者,而沒有輸入這個欄位,則會自動產生一組密碼。'; $lang['add_ok'] = '已新增使用者'; $lang['add_fail'] = '無法新增使用者'; $lang['notify_ok'] = '通知信已寄出'; -- cgit v1.2.3 From df60eba1d79b8a3e9a5dda87cb3466f0b7b9d454 Mon Sep 17 00:00:00 2001 From: Bruno Veilleux <bruno.vey@gmail.com> Date: Mon, 11 Mar 2013 15:34:55 +0100 Subject: French language update --- inc/lang/fr/lang.php | 4 +++ lib/plugins/acl/lang/fr/lang.php | 1 + lib/plugins/authad/lang/fr/settings.php | 18 +++++++++++++ lib/plugins/authldap/lang/fr/settings.php | 21 +++++++++++++++ lib/plugins/authmysql/lang/fr/settings.php | 41 ++++++++++++++++++++++++++++++ lib/plugins/authpgsql/lang/fr/settings.php | 37 +++++++++++++++++++++++++++ lib/plugins/config/lang/fr/lang.php | 1 + lib/plugins/plugin/lang/fr/lang.php | 1 + lib/plugins/popularity/lang/fr/lang.php | 1 + lib/plugins/revert/lang/fr/lang.php | 1 + lib/plugins/usermanager/lang/fr/lang.php | 1 + 11 files changed, 127 insertions(+) create mode 100644 lib/plugins/authad/lang/fr/settings.php create mode 100644 lib/plugins/authldap/lang/fr/settings.php create mode 100644 lib/plugins/authmysql/lang/fr/settings.php create mode 100644 lib/plugins/authpgsql/lang/fr/settings.php diff --git a/inc/lang/fr/lang.php b/inc/lang/fr/lang.php index a60112bc3..adeb175ef 100644 --- a/inc/lang/fr/lang.php +++ b/inc/lang/fr/lang.php @@ -26,6 +26,7 @@ * @author Yannick Aure <yannick.aure@gmail.com> * @author Olivier DUVAL <zorky00@gmail.com> * @author Anael Mobilia <contrib@anael.eu> + * @author Bruno Veilleux <bruno.vey@gmail.com> */ $lang['encoding'] = 'utf-8'; $lang['direction'] = 'ltr'; @@ -303,6 +304,9 @@ $lang['i_pol1'] = 'Wiki public (lecture pour tout le monde, écri $lang['i_pol2'] = 'Wiki fermé (lecture, écriture, envoi de fichiers pour les utilisateurs enregistrés uniquement)'; $lang['i_retry'] = 'Réessayer'; $lang['i_license'] = 'Veuillez choisir la licence sous laquelle vous souhaitez placer votre contenu :'; +$lang['i_license_none'] = 'Ne pas afficher d\'information de licence.'; +$lang['i_pop_field'] = 'Merci de nous aider à améliorer l\'expérience DokuWiki:'; +$lang['i_pop_label'] = 'Une fois par mois, envoyer des données d\'utilisation anonymes aux développeurs DokuWiki'; $lang['recent_global'] = 'Vous êtes actuellement en train de regarder les modifications au sein de la catégorie <strong>%s</strong>. Vous pouvez également <a href="%s">afficher les derniers changements sur l\'ensemble du wiki</a>.'; $lang['years'] = 'il y a %d ans'; $lang['months'] = 'il y a %d mois'; diff --git a/lib/plugins/acl/lang/fr/lang.php b/lib/plugins/acl/lang/fr/lang.php index e52bf51a0..538dd14d3 100644 --- a/lib/plugins/acl/lang/fr/lang.php +++ b/lib/plugins/acl/lang/fr/lang.php @@ -25,6 +25,7 @@ * @author Yannick Aure <yannick.aure@gmail.com> * @author Olivier DUVAL <zorky00@gmail.com> * @author Anael Mobilia <contrib@anael.eu> + * @author Bruno Veilleux <bruno.vey@gmail.com> */ $lang['admin_acl'] = 'Gestion de la liste des contrôles d\'accès (ACL)'; $lang['acl_group'] = 'Groupe'; diff --git a/lib/plugins/authad/lang/fr/settings.php b/lib/plugins/authad/lang/fr/settings.php new file mode 100644 index 000000000..efbca89f9 --- /dev/null +++ b/lib/plugins/authad/lang/fr/settings.php @@ -0,0 +1,18 @@ +<?php +/** + * French language file + * + * @author Bruno Veilleux <bruno.vey@gmail.com> + */ +$lang['account_suffix'] = 'Le suffixe de votre compte. Ex.: <code>@mon.domaine.org</code>'; +$lang['base_dn'] = 'Votre nom de domaine de base. <code>DC=mon,DC=domaine,DC=org</code>'; +$lang['domain_controllers'] = 'Une liste de contrôleurs de domaine séparés par des virgules. Ex.: <code>srv1.domaine.org,srv2.domaine.org</code>'; +$lang['ad_username'] = 'Un utilisateur Active Directory avec accès aux données de tous les autres utilisateurs. Facultatif, mais nécessaire pour certaines actions telles que l\'envoi de courriels d\'abonnement.'; +$lang['ad_password'] = 'Le mot de passe de l\'utilisateur ci-dessus.'; +$lang['sso'] = 'Est-ce que la connexion unique (Single-Sign-On) par Kerberos ou NTLM doit être utilisée?'; +$lang['real_primarygroup'] = 'Est-ce que le véritable groupe principal doit être résolu au lieu de présumer "Domain Users" (plus lent)?'; +$lang['use_ssl'] = 'Utiliser une connexion SSL? Si utilisée, n\'activez pas TLS ci-dessous.'; +$lang['use_tls'] = 'Utiliser une connexion TLS? Si utilisée, n\'activez pas SSL ci-dessus.'; +$lang['debug'] = 'Afficher des informations de débogage supplémentaires pour les erreurs?'; +$lang['expirywarn'] = 'Jours d\'avance pour l\'avertissement envoyé aux utilisateurs lorsque leur mot de passe va expirer. 0 pour désactiver.'; +$lang['additional'] = 'Une liste séparée par des virgules d\'attributs AD supplémentaires à récupérer dans les données utilisateur. Utilisée par certains modules.'; diff --git a/lib/plugins/authldap/lang/fr/settings.php b/lib/plugins/authldap/lang/fr/settings.php new file mode 100644 index 000000000..3df09eb7c --- /dev/null +++ b/lib/plugins/authldap/lang/fr/settings.php @@ -0,0 +1,21 @@ +<?php +/** + * French language file + * + * @author Bruno Veilleux <bruno.vey@gmail.com> + */ +$lang['server'] = 'Votre serveur LDAP. Soit le nom d\'hôte (<code>localhost</code>) ou l\'URL complète (<code>ldap://serveur.dom:389</code>)'; +$lang['port'] = 'Port du serveur LDAP si l\'URL complète n\'a pas été indiquée ci-dessus'; +$lang['usertree'] = 'Où trouver les comptes utilisateur. Ex.: <code>ou=Utilisateurs, dc=serveur, dc=dom</code>'; +$lang['grouptree'] = 'Où trouver les groupes d\'utilisateurs. Ex.: <code>ou=Groupes, dc=serveur, dc=dom</code>'; +$lang['userfilter'] = 'Filtre LDAP pour rechercher les comptes utilisateur. Ex.: <code>(&(uid=%{user})(objectClass=posixAccount))</code>'; +$lang['groupfilter'] = 'Filtre LDAP pour rechercher les groupes. Ex.: <code>(&(objectClass=posixGroup)(|(gidNumber=%{gid})(memberUID=%{user})))</code>'; +$lang['version'] = 'La version de protocole à utiliser. Il se peut que vous deviez utiliser <code>3</code>'; +$lang['starttls'] = 'Utiliser les connexions TLS?'; +$lang['referrals'] = 'Suivre les références?'; +$lang['binddn'] = 'Nom de domaine d\'un utilisateur de connexion facultatif si une connexion anonyme n\'est pas suffisante. Ex. : <code>cn=admin, dc=mon, dc=accueil</code>'; +$lang['bindpw'] = 'Mot de passe de l\'utilisateur ci-dessus.'; +$lang['userscope'] = 'Limiter la portée de recherche d\'utilisateurs'; +$lang['groupscope'] = 'Limiter la portée de recherche de groupes'; +$lang['groupkey'] = 'Affiliation aux groupes à partir de n\'importe quel attribut utilisateur (au lieu des groupes AD standards), p. ex. groupes par département ou numéro de téléphone'; +$lang['debug'] = 'Afficher des informations de bégogage supplémentaires pour les erreurs'; diff --git a/lib/plugins/authmysql/lang/fr/settings.php b/lib/plugins/authmysql/lang/fr/settings.php new file mode 100644 index 000000000..dfb79b545 --- /dev/null +++ b/lib/plugins/authmysql/lang/fr/settings.php @@ -0,0 +1,41 @@ +<?php +/** + * French language file + * + * @author Bruno Veilleux <bruno.vey@gmail.com> + */ +$lang['server'] = 'Votre serveur MySQL'; +$lang['user'] = 'Nom d\'utilisateur MySQL'; +$lang['password'] = 'Mot de passe pour l\'utilisateur ci-dessus'; +$lang['database'] = 'Base de données à utiliser'; +$lang['charset'] = 'Jeu de caractères utilisé dans la base de données'; +$lang['debug'] = 'Afficher des informations de débogage supplémentaires'; +$lang['forwardClearPass'] = 'Passer les mots de passe aux requêtes SQL ci-dessous en cleartext plutôt qu\'avec l\'option passcrypt'; +$lang['TablesToLock'] = 'Liste séparée par des virgules des tables devant être verrouillées par les opérations d\'écriture'; +$lang['checkPass'] = 'Requête SQL pour la vérification des mots de passe'; +$lang['getUserInfo'] = 'Requête SQL pour la récupération des informations d\'un utilisateur'; +$lang['getGroups'] = 'Requête SQL pour la récupération des groupes d\'un utilisateur'; +$lang['getUsers'] = 'Requête SQL pour énumérer tous les utilisateurs'; +$lang['FilterLogin'] = 'Clause SQL pour filtrer les utilisateurs par identifiant'; +$lang['FilterName'] = 'Clause SQL pour filtrer les utilisateurs par nom complet'; +$lang['FilterEmail'] = 'Clause SQL pour filtrer les utilisateurs par adresse électronique'; +$lang['FilterGroup'] = 'Clause SQL pour filtrer les utilisateurs par groupes'; +$lang['SortOrder'] = 'Clause SQL pour trier les utilisateurs'; +$lang['addUser'] = 'Requête SQL pour ajouter un nouvel utilisateur'; +$lang['addGroup'] = 'Requête SQL pour ajouter un nouveau groupe'; +$lang['addUserGroup'] = 'Requête SQL pour ajouter un utilisateur à un groupe existant'; +$lang['delGroup'] = 'Requête SQL pour retirer un groupe'; +$lang['getUserID'] = 'Requête SQL pour obtenir la clé primaire d\'un utilisateur'; +$lang['delUser'] = 'Requête SQL pour supprimer un utilisateur'; +$lang['delUserRefs'] = 'Requête SQL pour retirer un utilisateur de tous les groupes'; +$lang['updateUser'] = 'Requête SQL pour mettre à jour le profil d\'un utilisateur'; +$lang['UpdateLogin'] = 'Clause de mise à jour pour mettre à jour l\'identifiant d\'un utilisateur'; +$lang['UpdatePass'] = 'Clause de mise à jour pour mettre à jour le mot de passe d\'un utilisateur'; +$lang['UpdateEmail'] = 'Clause de mise à jour pour mettre à jour l\'adresse électronique d\'un utilisateur'; +$lang['UpdateName'] = 'Clause de mise à jour pour mettre à jour le nom complet d\'un utilisateur'; +$lang['UpdateTarget'] = 'Clause de limite pour identifier l\'utilisateur durant une mise à jour'; +$lang['delUserGroup'] = 'Requête SQL pour retirer un utilisateur d\'un groupe donné'; +$lang['getGroupID'] = 'Requête SQL pour obtenir la clé primaire d\'un groupe donné'; +$lang['debug_o_0'] = 'aucun'; +$lang['debug_o_1'] = 'sur erreur seulement'; +$lang['debug_o_2'] = 'toutes les requêtes SQL'; diff --git a/lib/plugins/authpgsql/lang/fr/settings.php b/lib/plugins/authpgsql/lang/fr/settings.php new file mode 100644 index 000000000..ec425bd49 --- /dev/null +++ b/lib/plugins/authpgsql/lang/fr/settings.php @@ -0,0 +1,37 @@ +<?php +/** + * French language file + * + * @author Bruno Veilleux <bruno.vey@gmail.com> + */ +$lang['server'] = 'Votre serveur PostgreSQL'; +$lang['port'] = 'Le port de votre serveur PostgreSQL'; +$lang['user'] = 'Nom d\'utilisateur PostgreSQL'; +$lang['password'] = 'Mot de passe pour l\'utilisateur ci-dessus'; +$lang['database'] = 'Base de données à utiliser'; +$lang['debug'] = 'Afficher des informations de débogage supplémentaires'; +$lang['forwardClearPass'] = 'Passer les mots de passe aux requêtes SQL ci-dessous en cleartext plutôt qu\'avec l\'option passcrypt'; +$lang['checkPass'] = 'Requête SQL pour la vérification des mots de passe'; +$lang['getUserInfo'] = 'Requête SQL pour la récupération des informations d\'un utilisateur'; +$lang['getGroups'] = 'Requête SQL pour la récupération des groupes d\'un utilisateur'; +$lang['getUsers'] = 'Requête SQL pour énumérer tous les utilisateurs'; +$lang['FilterLogin'] = 'Clause SQL pour filtrer les utilisateurs par identifiant'; +$lang['FilterName'] = 'Clause SQL pour filtrer les utilisateurs par nom complet'; +$lang['FilterEmail'] = 'Clause SQL pour filtrer les utilisateurs par adresse électronique'; +$lang['FilterGroup'] = 'Clause SQL pour filtrer les utilisateurs par groupes'; +$lang['SortOrder'] = 'Clause SQL pour trier les utilisateurs'; +$lang['addUser'] = 'Requête SQL pour ajouter un nouvel utilisateur'; +$lang['addGroup'] = 'Requête SQL pour ajouter un nouveau groupe'; +$lang['addUserGroup'] = 'Requête SQL pour ajouter un utilisateur à un groupe existant'; +$lang['delGroup'] = 'Requête SQL pour retirer un groupe'; +$lang['getUserID'] = 'Requête SQL pour obtenir la clé primaire d\'un utilisateur'; +$lang['delUser'] = 'Requête SQL pour supprimer un utilisateur'; +$lang['delUserRefs'] = 'Requête SQL pour retirer un utilisateur de tous les groupes'; +$lang['updateUser'] = 'Requête SQL pour mettre à jour le profil d\'un utilisateur'; +$lang['UpdateLogin'] = 'Clause de mise à jour pour mettre à jour l\'identifiant d\'un utilisateur'; +$lang['UpdatePass'] = 'Clause de mise à jour pour mettre à jour le mot de passe d\'un utilisateur'; +$lang['UpdateEmail'] = 'Clause de mise à jour pour mettre à jour l\'adresse électronique d\'un utilisateur'; +$lang['UpdateName'] = 'Clause de mise à jour pour mettre à jour le nom complet d\'un utilisateur'; +$lang['UpdateTarget'] = 'Clause de limite pour identifier l\'utilisateur durant une mise à jour'; +$lang['delUserGroup'] = 'Requête SQL pour retirer un utilisateur d\'un groupe donné'; +$lang['getGroupID'] = 'Requête SQL pour obtenir la clé primaire d\'un groupe donné'; diff --git a/lib/plugins/config/lang/fr/lang.php b/lib/plugins/config/lang/fr/lang.php index c4b521497..f9e89f603 100644 --- a/lib/plugins/config/lang/fr/lang.php +++ b/lib/plugins/config/lang/fr/lang.php @@ -20,6 +20,7 @@ * @author Yannick Aure <yannick.aure@gmail.com> * @author Olivier DUVAL <zorky00@gmail.com> * @author Anael Mobilia <contrib@anael.eu> + * @author Bruno Veilleux <bruno.vey@gmail.com> */ $lang['menu'] = 'Paramètres de configuration'; $lang['error'] = 'Paramètres non modifiés en raison d\'une valeur invalide, vérifiez vos réglages puis réessayez. <br />Les valeurs erronées sont entourées d\'une bordure rouge.'; diff --git a/lib/plugins/plugin/lang/fr/lang.php b/lib/plugins/plugin/lang/fr/lang.php index 06cd1ab8d..2926225ed 100644 --- a/lib/plugins/plugin/lang/fr/lang.php +++ b/lib/plugins/plugin/lang/fr/lang.php @@ -20,6 +20,7 @@ * @author Yannick Aure <yannick.aure@gmail.com> * @author Olivier DUVAL <zorky00@gmail.com> * @author Anael Mobilia <contrib@anael.eu> + * @author Bruno Veilleux <bruno.vey@gmail.com> */ $lang['menu'] = 'Gestion des extensions'; $lang['download'] = 'Télécharger et installer une nouvelle extension'; diff --git a/lib/plugins/popularity/lang/fr/lang.php b/lib/plugins/popularity/lang/fr/lang.php index d5bc92081..b7e053197 100644 --- a/lib/plugins/popularity/lang/fr/lang.php +++ b/lib/plugins/popularity/lang/fr/lang.php @@ -17,6 +17,7 @@ * @author Yannick Aure <yannick.aure@gmail.com> * @author Olivier DUVAL <zorky00@gmail.com> * @author Anael Mobilia <contrib@anael.eu> + * @author Bruno Veilleux <bruno.vey@gmail.com> */ $lang['name'] = 'Enquête de popularité (peut nécessiter un certain temps pour être chargée)'; $lang['submit'] = 'Envoyer les données'; diff --git a/lib/plugins/revert/lang/fr/lang.php b/lib/plugins/revert/lang/fr/lang.php index 07b012e38..a063c8996 100644 --- a/lib/plugins/revert/lang/fr/lang.php +++ b/lib/plugins/revert/lang/fr/lang.php @@ -18,6 +18,7 @@ * @author Yannick Aure <yannick.aure@gmail.com> * @author Olivier DUVAL <zorky00@gmail.com> * @author Anael Mobilia <contrib@anael.eu> + * @author Bruno Veilleux <bruno.vey@gmail.com> */ $lang['menu'] = 'Gestionnaire des réversions'; $lang['filter'] = 'Trouver les pages spammées '; diff --git a/lib/plugins/usermanager/lang/fr/lang.php b/lib/plugins/usermanager/lang/fr/lang.php index 7e602d0ce..40e878bbb 100644 --- a/lib/plugins/usermanager/lang/fr/lang.php +++ b/lib/plugins/usermanager/lang/fr/lang.php @@ -19,6 +19,7 @@ * @author Yannick Aure <yannick.aure@gmail.com> * @author Olivier DUVAL <zorky00@gmail.com> * @author Anael Mobilia <contrib@anael.eu> + * @author Bruno Veilleux <bruno.vey@gmail.com> */ $lang['menu'] = 'Gestion des utilisateurs'; $lang['noauth'] = '(authentification de l\'utilisateur non disponible)'; -- cgit v1.2.3 From f5f59c48d1de4c01eeb7757b5d1f9a0ea186312c Mon Sep 17 00:00:00 2001 From: Andreas Gohr <andi@splitbrain.org> Date: Mon, 11 Mar 2013 15:35:47 +0100 Subject: typo fix --- lib/plugins/authpgsql/lang/en/settings.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/plugins/authpgsql/lang/en/settings.php b/lib/plugins/authpgsql/lang/en/settings.php index 8c048fa0f..e67235cfa 100644 --- a/lib/plugins/authpgsql/lang/en/settings.php +++ b/lib/plugins/authpgsql/lang/en/settings.php @@ -2,7 +2,7 @@ $lang['server'] = 'Your PostgreSQL server'; $lang['port'] = 'Your PostgreSQL server\'s port'; -$lang['user'] = 'PostreSQL user name'; +$lang['user'] = 'PostgreSQL user name'; $lang['password'] = 'Password for above user'; $lang['database'] = 'Database to use'; $lang['debug'] = 'Display additional debug information'; -- cgit v1.2.3 From 421bfa826519712385983d37cb67a4f69b918674 Mon Sep 17 00:00:00 2001 From: Robert Bogenschneider <robog@gmx.de> Date: Mon, 11 Mar 2013 15:37:25 +0100 Subject: Esperanto language update --- inc/lang/eo/lang.php | 4 ++- lib/plugins/authad/lang/eo/settings.php | 17 +++++++++++++ lib/plugins/authldap/lang/eo/settings.php | 20 +++++++++++++++ lib/plugins/authmysql/lang/eo/settings.php | 40 ++++++++++++++++++++++++++++++ lib/plugins/authpgsql/lang/eo/settings.php | 36 +++++++++++++++++++++++++++ 5 files changed, 116 insertions(+), 1 deletion(-) create mode 100644 lib/plugins/authad/lang/eo/settings.php create mode 100644 lib/plugins/authldap/lang/eo/settings.php create mode 100644 lib/plugins/authmysql/lang/eo/settings.php create mode 100644 lib/plugins/authpgsql/lang/eo/settings.php diff --git a/inc/lang/eo/lang.php b/inc/lang/eo/lang.php index 2d9b03148..1bafe5191 100644 --- a/inc/lang/eo/lang.php +++ b/inc/lang/eo/lang.php @@ -289,6 +289,9 @@ $lang['i_pol1'] = 'Publika Vikio (legi povas ĉiuj, skribi kaj al $lang['i_pol2'] = 'Ferma Vikio (legi, skribi, alŝuti nur povas registritaj uzantoj)'; $lang['i_retry'] = 'Reprovi'; $lang['i_license'] = 'Bonvolu elekti la permesilon, sub kiun vi volas meti vian enhavon:'; +$lang['i_license_none'] = 'Ne montri licencinformojn'; +$lang['i_pop_field'] = 'Bonvolu helpi nin plibonigi la DokuWiki-sperton:'; +$lang['i_pop_label'] = 'Sendi unufoje monate anonimajn datumojn pri la uzo al la DokuWiki-evoluigantoj'; $lang['recent_global'] = 'Vi nun rigardas la ŝanĝojn ene de la nomspaco <b>%s</b>. Vi povas ankaŭ <a href="%s">vidi la freŝajn ŝanĝojn de la tuta vikio</a>.'; $lang['years'] = 'antaŭ %d jaroj'; $lang['months'] = 'antaŭ %d monatoj'; @@ -321,4 +324,3 @@ $lang['media_perm_read'] = 'Bedaûrinde viaj rajtoj ne sufiĉas por legi d $lang['media_perm_upload'] = 'Bedaûrinde viaj rajtoj ne sufiĉas por alŝuti dosierojn.'; $lang['media_update'] = 'Alŝuti novan version'; $lang['media_restore'] = 'Restarigi ĉi tiun version'; -$lang['plugin_install_err'] = 'Kromaĵo instalita malĝuste. Renomu la kromaĵan dosierujon \'%s\' al \'%s\'.'; diff --git a/lib/plugins/authad/lang/eo/settings.php b/lib/plugins/authad/lang/eo/settings.php new file mode 100644 index 000000000..85a6abd98 --- /dev/null +++ b/lib/plugins/authad/lang/eo/settings.php @@ -0,0 +1,17 @@ +<?php +/** + * Esperanto language file + * + */ +$lang['account_suffix'] = 'Via konto-aldonaĵo, ekz. <code>@mia.domajno.lando</code>'; +$lang['base_dn'] = 'Via baza DN, ekz. <code>DC=mia,DC=domajno,DC=lando</code>'; +$lang['domain_controllers'] = 'Komodisigita listo de domajno-serviloj, ekz. <code>srv1.domajno.lando,srv2.domajno.lando</code>'; +$lang['ad_username'] = 'Privilegiita Aktiv-Dosieruja uzanto kun aliro al ĉiuj uzantaj datumoj. Libervole, sed necesa por iuj agadoj kiel sendi abonan retpoŝton.'; +$lang['ad_password'] = 'La pasvorto de tiu uzanto.'; +$lang['sso'] = 'Ĉu uzi Sola Aliro tra Kerberos aŭ NTLM?'; +$lang['real_primarygroup'] = 'Ĉu trovi la veran ĉefan grupon anstataŭ supozi "Domajnuzantoj" (pli malrapida)?'; +$lang['use_ssl'] = 'Ĉu uzi SSL-konekton? Se jes, ne aktivigu TLS sube.'; +$lang['use_tls'] = 'Ĉu uzi TLS-konekton? Se jes, ne aktivigu SSL supre.'; +$lang['debug'] = 'Ĉu montri aldonajn informojn dum eraroj?'; +$lang['expirywarn'] = 'Tagoj da antaŭaverto pri malvalidiĝonta pasvorto. 0 por malebligi.'; +$lang['additional'] = 'Komodisigita listo de aldonaj AD-atributoj por preni el uzantaj datumoj. Uzita de iuj kromaĵoj.'; diff --git a/lib/plugins/authldap/lang/eo/settings.php b/lib/plugins/authldap/lang/eo/settings.php new file mode 100644 index 000000000..2863a1125 --- /dev/null +++ b/lib/plugins/authldap/lang/eo/settings.php @@ -0,0 +1,20 @@ +<?php +/** + * Esperanto language file + * + */ +$lang['server'] = 'Via LDAP-servilo. Aŭ servila nomo (<code>localhost</code>) aŭ plene detala URL (<code>ldap://servilo.lando:389</code>)'; +$lang['port'] = 'LDAP-servila pordego, se vi supre ne indikis la plenan URL'; +$lang['usertree'] = 'Kie trovi uzantajn kontojn, ekz. <code>ou=Personoj, dc=servilo, dc=lando</code>'; +$lang['grouptree'] = 'Kie trovi uzantogrupojn, ekz. <code>ou=Grupo, dc=servilo, dc=lando</code>'; +$lang['userfilter'] = 'LDAP-filtrilo por serĉi uzantokontojn, ekz. <code>(&(uid=%{user})(objectClass=posixAccount))</code>'; +$lang['groupfilter'] = 'LDAP-filtrilo por serĉi grupojn, ekz. <code>(&(objectClass=posixGroup)(|(gidNumber=%{gid})(memberUID=%{user})))</code>'; +$lang['version'] = 'La uzenda protokolversio. Eble necesas indiki <code>3</code>'; +$lang['starttls'] = 'Ĉu uzi TLS-konektojn?'; +$lang['referrals'] = 'Ĉu sekvi referencojn?'; +$lang['binddn'] = 'DN de opcie bindita uzanto, se anonima bindado ne sufiĉas, ekz. <code>cn=admin, dc=mia, dc=hejmo</code>'; +$lang['bindpw'] = 'Pasvorto de tiu uzanto'; +$lang['userscope'] = 'Limigi serĉospacon de uzantaj serĉoj'; +$lang['groupscope'] = 'Limigi serĉospacon por grupaj serĉoj'; +$lang['groupkey'] = 'Grupa membreco de iu uzanta atributo (anstataŭ standardaj AD-grupoj), ekz. grupo de departemento aŭ telefonnumero'; +$lang['debug'] = 'Ĉu montri aldonajn erarinformojn?'; diff --git a/lib/plugins/authmysql/lang/eo/settings.php b/lib/plugins/authmysql/lang/eo/settings.php new file mode 100644 index 000000000..907c761f8 --- /dev/null +++ b/lib/plugins/authmysql/lang/eo/settings.php @@ -0,0 +1,40 @@ +<?php +/** + * Esperanto language file + * + */ +$lang['server'] = 'Via MySQL-servilo'; +$lang['user'] = 'MySQL uzantonomo'; +$lang['password'] = 'Pasvorto por tiu uzanto'; +$lang['database'] = 'Uzenda datumbazo'; +$lang['charset'] = 'Uzata tiparo en la datumbazo'; +$lang['debug'] = 'Ĉu montri aldonajn erarinformojn?'; +$lang['forwardClearPass'] = 'Ĉu transdoni pasvortojn klartekste al la SQL-frazoj sube anstataŭ uzi pasvortan kaŝon'; +$lang['TablesToLock'] = 'Komodisigita listo de tabeloj, al kiuj ne eblu skribi'; +$lang['checkPass'] = 'SQL-frazo por testi pasvortojn'; +$lang['getUserInfo'] = 'SQL-frazo por ricevi uzantajn informojn'; +$lang['getGroups'] = 'SQL-frazo por ricevi la grupmembrecojn de uzanto'; +$lang['getUsers'] = 'SQL-frazo por listigi ĉiujn uzantojn'; +$lang['FilterLogin'] = 'SQL-frazo por filtri uzantojn je ensaluta nomo'; +$lang['FilterName'] = 'SQL-frazo por filtri uzantojn je plena nomo'; +$lang['FilterEmail'] = 'SQL-frazo por filtri uzantojn je retpoŝtadreso'; +$lang['FilterGroup'] = 'SQL-frazo por filtri uzantojn je grupmembreco'; +$lang['SortOrder'] = 'SQL-frazo por ordigi uzantojn'; +$lang['addUser'] = 'SQL-frazo por aldoni novan uzanton'; +$lang['addGroup'] = 'SQL-frazo por aldoni novan grupon'; +$lang['addUserGroup'] = 'SQL-frazo por aldoni uzanton al ekzistanta grupo'; +$lang['delGroup'] = 'SQL-frazo por forigi grupon'; +$lang['getUserID'] = 'SQL-frazo por ricevi la ĉefan ŝlosilon de uzanto'; +$lang['delUser'] = 'SQL-frazo por forigi uzanton'; +$lang['delUserRefs'] = 'SQL-frazo por forigi uzanton el ĉiuj grupoj'; +$lang['updateUser'] = 'SQL-frazo por aktualigi uzantan profilon'; +$lang['UpdateLogin'] = 'Aktualiga frazo por uzanta ensalutnomo'; +$lang['UpdatePass'] = 'Aktualiga frazo por uzanta pasvorto'; +$lang['UpdateEmail'] = 'Aktualiga frazo por uzanta retpoŝtadreso'; +$lang['UpdateName'] = 'Aktualiga frazo por plena uzanta nomo'; +$lang['UpdateTarget'] = 'Limiga frazo por identigi la uzanton dum aktualigado'; +$lang['delUserGroup'] = 'SQL-frazo por forigi uzanton el indikita grupo'; +$lang['getGroupID'] = 'SQL-frazo por ricevi la ĉefan ŝlosilon de indikita grupo'; +$lang['debug_o_0'] = 'neniu'; +$lang['debug_o_1'] = 'nur dum eraroj'; +$lang['debug_o_2'] = 'ĉiuj SQL-serĉoj'; diff --git a/lib/plugins/authpgsql/lang/eo/settings.php b/lib/plugins/authpgsql/lang/eo/settings.php new file mode 100644 index 000000000..dbdfdd41b --- /dev/null +++ b/lib/plugins/authpgsql/lang/eo/settings.php @@ -0,0 +1,36 @@ +<?php +/** + * Esperanto language file + * + */ +$lang['server'] = 'Via PostgreSQL-servilo'; +$lang['port'] = 'Via PostgreSQL-servila pordego'; +$lang['user'] = 'PostgreSQL-uzantonomo'; +$lang['password'] = 'Pasvorto por tiu uzanto'; +$lang['database'] = 'Uzenda datumbazo'; +$lang['debug'] = 'Ĉu indiki aldonajn erarinformojn'; +$lang['forwardClearPass'] = 'Ĉu transdoni pasvortojn klartekste al la SQL-frazoj sube anstataŭ uzi pasvortan kaŝon'; +$lang['checkPass'] = 'SQL-frazo por testi pasvortojn'; +$lang['getUserInfo'] = 'SQL-frazo por ricevi uzantajn informojn'; +$lang['getGroups'] = 'SQL-frazo por ricevi la grupmembrecojn de uzanto'; +$lang['getUsers'] = 'SQL-frazo por listigi ĉiujn uzantojn'; +$lang['FilterLogin'] = 'SQL-frazo por filtri uzantojn je ensaluta nomo'; +$lang['FilterName'] = 'SQL-frazo por filtri uzantojn je plena nomo'; +$lang['FilterEmail'] = 'SQL-frazo por filtri uzantojn je retpoŝtadreso'; +$lang['FilterGroup'] = 'SQL-frazo por filtri uzantojn je grupmembreco'; +$lang['SortOrder'] = 'SQL-frazo por ordigi uzantojn'; +$lang['addUser'] = 'SQL-frazo por aldoni novan uzanton'; +$lang['addGroup'] = 'SQL-frazo por aldoni novan grupon'; +$lang['addUserGroup'] = 'SQL-frazo por aldoni uzanton al ekzistanta grupo'; +$lang['delGroup'] = 'SQL-frazo por forigi grupon'; +$lang['getUserID'] = 'SQL-frazo por ricevi la ĉefan ŝlosilon de uzanto'; +$lang['delUser'] = 'SQL-frazo por forigi uzanton'; +$lang['delUserRefs'] = 'SQL-frazo por forigi uzanton el ĉiuj grupoj'; +$lang['updateUser'] = 'SQL-frazo por aktualigi uzantan profilon'; +$lang['UpdateLogin'] = 'Aktualiga frazo por uzanta ensalutnomo'; +$lang['UpdatePass'] = 'Aktualiga frazo por uzanta pasvorto'; +$lang['UpdateEmail'] = 'Aktualiga frazo por uzanta retpoŝtadreso'; +$lang['UpdateName'] = 'Aktualiga frazo por plena uzanta nomo'; +$lang['UpdateTarget'] = 'Limiga frazo por identigi la uzanton dum aktualigado'; +$lang['delUserGroup'] = 'SQL-frazo por forigi uzanton el indikita grupo'; +$lang['getGroupID'] = 'SQL-frazo por ricevi la ĉefan ŝlosilon de indikita grupo'; -- cgit v1.2.3 From 8b5e2fdbb74e3a04fb31fce01b4cd316fa1a1f40 Mon Sep 17 00:00:00 2001 From: lainme <lainme993@gmail.com> Date: Mon, 11 Mar 2013 15:39:37 +0100 Subject: Simplified Chinese language update --- lib/plugins/authldap/lang/zh/settings.php | 1 + lib/plugins/authmysql/lang/zh/settings.php | 1 + 2 files changed, 2 insertions(+) diff --git a/lib/plugins/authldap/lang/zh/settings.php b/lib/plugins/authldap/lang/zh/settings.php index e84511b42..2dfbeb464 100644 --- a/lib/plugins/authldap/lang/zh/settings.php +++ b/lib/plugins/authldap/lang/zh/settings.php @@ -17,4 +17,5 @@ $lang['binddn'] = '一个可选的绑定用户的 DN (如果匿 $lang['bindpw'] = '上述用户的密码'; $lang['userscope'] = '限制用户搜索的范围'; $lang['groupscope'] = '限制组搜索的范围'; +$lang['groupkey'] = '根据任何用户属性得来的组成员(而不是标准的 AD 组),例如根据部门或者电话号码得到的组。'; $lang['debug'] = '有错误时显示额外的调试信息'; diff --git a/lib/plugins/authmysql/lang/zh/settings.php b/lib/plugins/authmysql/lang/zh/settings.php index 43cfbb3c0..772f75ecd 100644 --- a/lib/plugins/authmysql/lang/zh/settings.php +++ b/lib/plugins/authmysql/lang/zh/settings.php @@ -8,6 +8,7 @@ $lang['server'] = '您的 MySQL 服务器'; $lang['user'] = 'MySQL 用户名'; $lang['password'] = '上述用户的密码'; $lang['database'] = '使用的数据库'; +$lang['charset'] = '数据库中使用的字符集'; $lang['debug'] = '显示额外调试信息'; $lang['forwardClearPass'] = '将用户密码以明文形式传送给下面的 SQL 语句,而不使用 passcrypt 密码加密选项'; $lang['TablesToLock'] = '在写操作时需要锁定的数据表列表,以逗号分隔'; -- cgit v1.2.3 From 23ff1b4748bebe2c597a0eb6d838974125692432 Mon Sep 17 00:00:00 2001 From: Alexandru Juncu <alexj@rosedu.org> Date: Wed, 13 Mar 2013 11:16:16 +0200 Subject: Fix Romanian language files by replacing cedilla-below characters with the correct comma-below ones. --- inc/lang/ro/admin.txt | 2 +- inc/lang/ro/adminplugins.txt | 2 +- inc/lang/ro/conflict.txt | 2 +- inc/lang/ro/denied.txt | 2 +- inc/lang/ro/diff.txt | 4 +- inc/lang/ro/draft.txt | 6 +- inc/lang/ro/edit.txt | 2 +- inc/lang/ro/install.html | 10 +-- inc/lang/ro/lang.php | 192 +++++++++++++++++++++--------------------- inc/lang/ro/locked.txt | 2 +- inc/lang/ro/login.txt | 2 +- inc/lang/ro/newpage.txt | 2 +- inc/lang/ro/norev.txt | 2 +- inc/lang/ro/pwconfirm.txt | 4 +- inc/lang/ro/read.txt | 2 +- inc/lang/ro/register.txt | 2 +- inc/lang/ro/resendpwd.txt | 2 +- inc/lang/ro/revisions.txt | 2 +- inc/lang/ro/searchpage.txt | 2 +- inc/lang/ro/stopwords.txt | 4 +- inc/lang/ro/subscr_digest.txt | 6 +- inc/lang/ro/subscr_form.txt | 2 +- inc/lang/ro/subscr_list.txt | 8 +- inc/lang/ro/subscr_single.txt | 6 +- inc/lang/ro/updateprofile.txt | 2 +- inc/lang/ro/uploadmail.txt | 4 +- 26 files changed, 138 insertions(+), 138 deletions(-) diff --git a/inc/lang/ro/admin.txt b/inc/lang/ro/admin.txt index 4b1a9062a..b19a4d804 100644 --- a/inc/lang/ro/admin.txt +++ b/inc/lang/ro/admin.txt @@ -1,3 +1,3 @@ ====== Administrare ====== -Puteţi vedea mai jos o listă cu activităţile administrative disponibile în DokuWiki. \ No newline at end of file +Puteți vedea mai jos o listă cu activitățile administrative disponibile în DokuWiki. \ No newline at end of file diff --git a/inc/lang/ro/adminplugins.txt b/inc/lang/ro/adminplugins.txt index f076c3651..6712d8225 100644 --- a/inc/lang/ro/adminplugins.txt +++ b/inc/lang/ro/adminplugins.txt @@ -1 +1 @@ -===== Plugin-uri Adiţionale ===== \ No newline at end of file +===== Plugin-uri Adiționale ===== \ No newline at end of file diff --git a/inc/lang/ro/conflict.txt b/inc/lang/ro/conflict.txt index d7218ca5f..072f574f4 100644 --- a/inc/lang/ro/conflict.txt +++ b/inc/lang/ro/conflict.txt @@ -2,5 +2,5 @@ Există o versiune nouă a documentului editat. Aceasta se întîmplă cînd un alt utilizator a schimbat documentul în timp ce îl editezi. -Examinează diferenţele arătate mai jos, apoi ia decizia care versiune o reţii. Dacă alegi ''Salvează'', versiunea documentului va fi salvată. Apăsaţi ''Renunţare'' pentru a menţine versiunea curentă. +Examinează diferențele arătate mai jos, apoi ia decizia care versiune o reții. Dacă alegi ''Salvează'', versiunea documentului va fi salvată. Apăsați ''Renunțare'' pentru a menține versiunea curentă. diff --git a/inc/lang/ro/denied.txt b/inc/lang/ro/denied.txt index 8178995e9..430db7610 100644 --- a/inc/lang/ro/denied.txt +++ b/inc/lang/ro/denied.txt @@ -1,4 +1,4 @@ ====== Acces Interzis ====== -Din păcate nu aveţi destule drepturi pentru a continua. Poate aţi uitat să vă logaţi? +Din păcate nu aveți destule drepturi pentru a continua. Poate ați uitat să vă logați? diff --git a/inc/lang/ro/diff.txt b/inc/lang/ro/diff.txt index f33be8afd..197244453 100644 --- a/inc/lang/ro/diff.txt +++ b/inc/lang/ro/diff.txt @@ -1,4 +1,4 @@ -====== Diferenţe ====== +====== Diferențe ====== -Aceasta arată diferenţele dintre revziile selectate şi versiunea curentă a paginii. +Aceasta arată diferențele dintre revziile selectate și versiunea curentă a paginii. diff --git a/inc/lang/ro/draft.txt b/inc/lang/ro/draft.txt index e13671e3e..74badee8e 100644 --- a/inc/lang/ro/draft.txt +++ b/inc/lang/ro/draft.txt @@ -1,5 +1,5 @@ -====== Fişierul schiţă nu a fost găsit ====== +====== Fișierul schiță nu a fost găsit ====== -Ultima dvs. sesiune de editare nu s-a finalizat corect. În timpul lucrului, DocuWiki a salvat automat o schiţă, pe care o puteţi utiliza acum pentru a continua editarea. Mai jos puteţi vedea informaţiile care s-au salvat de la ultima dvs. sesiune. +Ultima dvs. sesiune de editare nu s-a finalizat corect. În timpul lucrului, DocuWiki a salvat automat o schiță, pe care o puteți utiliza acum pentru a continua editarea. Mai jos puteți vedea informațiile care s-au salvat de la ultima dvs. sesiune. -Decideţi dacă vreţi să //recuperaţi// sesiunea de editare pierdută, //ştergeţi// schiţa salvată automat sau să //anulaţi// procesul de editare. \ No newline at end of file +Decideți dacă vreți să //recuperați// sesiunea de editare pierdută, //ștergeți// schița salvată automat sau să //anulați// procesul de editare. \ No newline at end of file diff --git a/inc/lang/ro/edit.txt b/inc/lang/ro/edit.txt index 1e79dc4fc..78761b9c4 100644 --- a/inc/lang/ro/edit.txt +++ b/inc/lang/ro/edit.txt @@ -1,2 +1,2 @@ -Editează pagina şi apasă ''Salvează''. Vezi [[wiki:syntax]] pentru sintaxă. Te rog editează pagina doar pentru a o **îmbunătaţi**. Dacă vrei să testezi cîteva lucruri, învaţă sa faci primii paşi în [[playground:playground]]. +Editează pagina și apasă ''Salvează''. Vezi [[wiki:syntax]] pentru sintaxă. Te rog editează pagina doar pentru a o **îmbunătați**. Dacă vrei să testezi cîteva lucruri, învață sa faci primii pași în [[playground:playground]]. diff --git a/inc/lang/ro/install.html b/inc/lang/ro/install.html index bfa4f496f..7fdc8fc21 100644 --- a/inc/lang/ro/install.html +++ b/inc/lang/ro/install.html @@ -1,10 +1,10 @@ -<p>Această pagină oferă asistenţă la instalarea pentru prima dată a <a href="http://dokuwiki.org">Dokuwiki</a>. Mai multe informaţii privind această instalare găsiţi pe <a href="http://dokuwiki.org/installer">pagina de documentaţie</a>.</p> +<p>Această pagină oferă asistență la instalarea pentru prima dată a <a href="http://dokuwiki.org">Dokuwiki</a>. Mai multe informații privind această instalare găsiți pe <a href="http://dokuwiki.org/installer">pagina de documentație</a>.</p> -<p>DokuWiki foloseşte fişiere obişnuite pentru stocarea paginilor wiki şi a informaţilor asociate acestor pagini (de ex. imagini, indecşi de căutare, versiuni vechi, etc). Pentru a lucra cu succes, DokuWiki <strong>trebuie</strong> să aibă drepturi de scriere în directoarele ce conţin aceste fişiere. +<p>DokuWiki folosește fișiere obișnuite pentru stocarea paginilor wiki și a informaților asociate acestor pagini (de ex. imagini, indecși de căutare, versiuni vechi, etc). Pentru a lucra cu succes, DokuWiki <strong>trebuie</strong> să aibă drepturi de scriere în directoarele ce conțin aceste fișiere. Acest script de instalare nu poate seta drepturile directoarelor. De regulă, aceasta se face direct, în linie de comandă, sau în cazul găzduirii, prin FTP sau prin panoul de control al gazdei (de ex. cPanel).</p> -<p>Acest script de instalare va configura DokuWiki pentru <abbr title="access control list">ACL</abbr>, care permite logarea administratorului şi accesul la meniul de administrare pentru instalarea plugin-urilor, gestiunea utilizatorilor, a accesului la paginile wiki şi modificarea setărilor de configurare. -Nu este necesar pentru ca DokuWiki să funcţioneze, însă face mai uşoară administrarea DokuWiki.</p> +<p>Acest script de instalare va configura DokuWiki pentru <abbr title="access control list">ACL</abbr>, care permite logarea administratorului și accesul la meniul de administrare pentru instalarea plugin-urilor, gestiunea utilizatorilor, a accesului la paginile wiki și modificarea setărilor de configurare. +Nu este necesar pentru ca DokuWiki să funcționeze, însă face mai ușoară administrarea DokuWiki.</p> -<p>Utilizatorii experimentaţi sau utilizatorii ce au nevoie de setări speciale ar putea folosi această legătură privind<a href="http://dokuwiki.org/install">instrucţiunile de instalare</a> şi <a href="http://dokuwiki.org/config">setările de configurare</a>.</p> +<p>Utilizatorii experimentați sau utilizatorii ce au nevoie de setări speciale ar putea folosi această legătură privind<a href="http://dokuwiki.org/install">instrucțiunile de instalare</a> și <a href="http://dokuwiki.org/config">setările de configurare</a>.</p> diff --git a/inc/lang/ro/lang.php b/inc/lang/ro/lang.php index 8b2483daf..797d1a917 100644 --- a/inc/lang/ro/lang.php +++ b/inc/lang/ro/lang.php @@ -6,7 +6,7 @@ * @author Tiberiu Micu <tibimicu@gmx.net> * @author Sergiu Baltariu <s_baltariu@yahoo.com> * @author Emanuel-Emeric Andrași <n30@mandrivausers.ro> - * @author Emanuel-Emeric Andraşi <em.andrasi@mandrivausers.ro> + * @author Emanuel-Emeric Andrași <em.andrasi@mandrivausers.ro> * @author Marius OLAR <olarmariusalex@gmail.com> * @author Marius Olar <olarmariusalex@yahoo.com> * @author Emanuel-Emeric Andrași <em.andrasi@mandrivausers.ro> @@ -31,87 +31,87 @@ $lang['btn_older'] = 'mai vechi>>'; $lang['btn_revs'] = 'Versiuni vechi'; $lang['btn_recent'] = 'Modificări recente'; $lang['btn_upload'] = 'Upload'; -$lang['btn_cancel'] = 'Renunţare'; +$lang['btn_cancel'] = 'Renunțare'; $lang['btn_index'] = 'Index'; $lang['btn_secedit'] = 'Editează'; $lang['btn_login'] = 'Login'; $lang['btn_logout'] = 'Logout'; $lang['btn_admin'] = 'Admin'; $lang['btn_update'] = 'Actualizează'; -$lang['btn_delete'] = 'Şterge'; +$lang['btn_delete'] = 'Șterge'; $lang['btn_back'] = 'Înapoi'; $lang['btn_backlink'] = 'Legătură anterioară'; -$lang['btn_backtomedia'] = 'Înapoi la Selecţia Mediafile'; +$lang['btn_backtomedia'] = 'Înapoi la Selecția Mediafile'; $lang['btn_subscribe'] = 'Subscrie Modificarea Paginii'; $lang['btn_profile'] = 'Actualizează Profil'; $lang['btn_reset'] = 'Resetează'; $lang['btn_resendpwd'] = 'Setează o parolă nouă'; -$lang['btn_draft'] = 'Editează schiţă'; -$lang['btn_recover'] = 'Recuperează schiţă'; -$lang['btn_draftdel'] = 'Şterge schiţă'; +$lang['btn_draft'] = 'Editează schiță'; +$lang['btn_recover'] = 'Recuperează schiță'; +$lang['btn_draftdel'] = 'Șterge schiță'; $lang['btn_revert'] = 'Revenire'; $lang['btn_register'] = 'Înregistrează'; $lang['btn_apply'] = 'Aplică'; $lang['btn_media'] = 'Administrare media'; -$lang['loggedinas'] = 'Logat ca şi'; +$lang['loggedinas'] = 'Logat ca și'; $lang['user'] = 'Utilizator'; $lang['pass'] = 'Parola'; $lang['newpass'] = 'Parola nouă'; $lang['oldpass'] = 'Confirmă parola curentă'; $lang['passchk'] = 'încă o dată'; -$lang['remember'] = 'Ţine-mă minte'; +$lang['remember'] = 'Ține-mă minte'; $lang['fullname'] = 'Nume complet'; $lang['email'] = 'E-Mail'; $lang['profile'] = 'Profil Utilizator'; -$lang['badlogin'] = 'Imi pare rău, utilizatorul şi/sau parola au fost greşite.'; +$lang['badlogin'] = 'Imi pare rău, utilizatorul și/sau parola au fost greșite.'; $lang['minoredit'] = 'Modificare Minoră'; -$lang['draftdate'] = 'Schiţă salvată automat la'; -$lang['nosecedit'] = 'Pagina s-a modificat între timp, secţiunea info a expirat, s-a încărcat pagina întreagă în loc.'; +$lang['draftdate'] = 'Schiță salvată automat la'; +$lang['nosecedit'] = 'Pagina s-a modificat între timp, secțiunea info a expirat, s-a încărcat pagina întreagă în loc.'; $lang['regmissing'] = 'Ne pare rău, trebuie să completezi toate cîmpurile.'; $lang['reguexists'] = 'Ne pare rău, un utilizator cu acest nume există deja logat.'; $lang['regsuccess'] = 'Utilizatorul a fost creat. Parola a fost trimisă prin email.'; $lang['regsuccess2'] = 'Utilizatorul a fost creat.'; -$lang['regmailfail'] = 'Se pare că a fost o eroare la trimiterea parolei prin email. Contactaţi administratorul!'; -$lang['regbadmail'] = 'Adresa de email este invalidă - dacă credeţi că este o eroare contactaţi administratorul.'; -$lang['regbadpass'] = 'Cele două parole furnizate nu sunt identice; încercaţi din nou.'; +$lang['regmailfail'] = 'Se pare că a fost o eroare la trimiterea parolei prin email. Contactați administratorul!'; +$lang['regbadmail'] = 'Adresa de email este invalidă - dacă credeți că este o eroare contactați administratorul.'; +$lang['regbadpass'] = 'Cele două parole furnizate nu sunt identice; încercați din nou.'; $lang['regpwmail'] = 'Parola ta DokuWiki'; -$lang['reghere'] = 'Înca nu ai un cont? Fă-ţi unul'; +$lang['reghere'] = 'Înca nu ai un cont? Fă-ți unul'; $lang['profna'] = 'Această wiki nu suportă modificarea profilului'; $lang['profnochange'] = 'Nici o modificare; nimic de făcut.'; $lang['profnoempty'] = 'Nu sunt admise numele sau adresa de email necompletate.'; $lang['profchanged'] = 'Profilul de utilizator a fost actualizat succes.'; -$lang['pwdforget'] = 'Parola uitată? Luaţi una nouă'; +$lang['pwdforget'] = 'Parola uitată? Luați una nouă'; $lang['resendna'] = 'Această wiki nu suportă retrimiterea parolei.'; $lang['resendpwd'] = 'Setează o parolă nouă pentru'; $lang['resendpwdmissing'] = 'Ne pare rău, trebuie completate toate câmpurile.'; $lang['resendpwdnouser'] = 'Ne pare rău, acest utilizator nu poate fi găsit în baza de date.'; -$lang['resendpwdbadauth'] = 'Ne pare rău, acest cod de autorizare nu este corect. Verificaţi dacă aţi folosit tot link-ul de confirmare.'; +$lang['resendpwdbadauth'] = 'Ne pare rău, acest cod de autorizare nu este corect. Verificați dacă ați folosit tot link-ul de confirmare.'; $lang['resendpwdconfirm'] = 'Un link de confirmare a fost trimis prin email.'; $lang['resendpwdsuccess'] = 'Parola nouă'; -$lang['license'] = 'Exceptând locurile unde este altfel specificat, conţinutul acestui wiki este licenţiat sub următoarea licenţă:'; -$lang['licenseok'] = 'Notă: Prin editarea acestei pagini sunteţi de acord să vă licenţiaţi conţintul sub următoarea licenţă:'; -$lang['searchmedia'] = 'Caută numele fişierului:'; +$lang['license'] = 'Exceptând locurile unde este altfel specificat, conținutul acestui wiki este licențiat sub următoarea licență:'; +$lang['licenseok'] = 'Notă: Prin editarea acestei pagini sunteți de acord să vă licențiați conțintul sub următoarea licență:'; +$lang['searchmedia'] = 'Caută numele fișierului:'; $lang['searchmedia_in'] = 'Caută în %s'; $lang['txt_upload'] = 'Selectează fisierul de încărcat'; -$lang['txt_filename'] = 'Încarcă fişierul ca (opţional)'; -$lang['txt_overwrt'] = 'Suprascrie fişierul existent'; +$lang['txt_filename'] = 'Încarcă fișierul ca (opțional)'; +$lang['txt_overwrt'] = 'Suprascrie fișierul existent'; $lang['lockedby'] = 'Momentan blocat de'; $lang['lockexpire'] = 'Blocarea expiră la'; -$lang['js']['willexpire'] = 'Blocarea pentru editarea paginii expiră intr-un minut.\nPentru a preveni conflictele foloseşte butonul de previzualizare pentru resetarea blocării.'; +$lang['js']['willexpire'] = 'Blocarea pentru editarea paginii expiră intr-un minut.\nPentru a preveni conflictele folosește butonul de previzualizare pentru resetarea blocării.'; $lang['js']['notsavedyet'] = 'Există modificări nesalvate, care se vor pierde. -Doreşti să continui?'; -$lang['js']['searchmedia'] = 'Caută fişiere'; -$lang['js']['keepopen'] = 'Menţine fereastra deschisă la selecţie'; +Dorești să continui?'; +$lang['js']['searchmedia'] = 'Caută fișiere'; +$lang['js']['keepopen'] = 'Menține fereastra deschisă la selecție'; $lang['js']['hidedetails'] = 'Ascunde Detalii'; $lang['js']['mediatitle'] = 'Setări link'; $lang['js']['mediadisplay'] = 'Tip link'; $lang['js']['mediaalign'] = 'Aliniere'; $lang['js']['mediasize'] = 'Mărime imagine'; -$lang['js']['mediatarget'] = 'Ţintă link'; +$lang['js']['mediatarget'] = 'Țintă link'; $lang['js']['mediaclose'] = 'Închide'; $lang['js']['mediainsert'] = 'Inserează'; -$lang['js']['mediadisplayimg'] = 'Afişează imaginea.'; -$lang['js']['mediadisplaylnk'] = 'Afişează doar linkul.'; +$lang['js']['mediadisplayimg'] = 'Afișează imaginea.'; +$lang['js']['mediadisplaylnk'] = 'Afișează doar linkul.'; $lang['js']['mediasmall'] = 'Versiune mică'; $lang['js']['mediamedium'] = 'Versiune medie'; $lang['js']['medialarge'] = 'Versiune mare'; @@ -124,11 +124,11 @@ $lang['js']['medialeft'] = 'Aliniază imaginea la stânga.'; $lang['js']['mediaright'] = 'Aliniază imaginea la dreapta.'; $lang['js']['mediacenter'] = 'Aliniază imaginea la centru.'; $lang['js']['medianoalign'] = 'Nu utiliza aliniere.'; -$lang['js']['nosmblinks'] = 'Legăturile către sharing-uri Windows funcţioneaza numai in Microsoft Internet Explorer. -Puteţi însă copia şi insera legătura.'; +$lang['js']['nosmblinks'] = 'Legăturile către sharing-uri Windows funcționeaza numai in Microsoft Internet Explorer. +Puteți însă copia și insera legătura.'; $lang['js']['linkwiz'] = 'Asistent legătură'; $lang['js']['linkto'] = 'Legătură la:'; -$lang['js']['del_confirm'] = 'Doriţi într-adevăr ştergerea elementelor selectate?'; +$lang['js']['del_confirm'] = 'Doriți într-adevăr ștergerea elementelor selectate?'; $lang['js']['restore_confirm'] = 'Sunteți sigur că doriți restaurarea acestei versiuni?'; $lang['js']['media_diff'] = 'Arată diferențele:'; $lang['js']['media_diff_both'] = 'Unul lângă altul'; @@ -142,52 +142,52 @@ $lang['js']['media_cancel'] = 'înlătură'; $lang['js']['media_overwrt'] = 'Suprascrie fișierele deja existente'; $lang['rssfailed'] = 'A apărut o eroare in timpul descărcării acestui cîmp: '; $lang['nothingfound'] = 'Nu am găsit nimic.'; -$lang['mediaselect'] = 'Selectare fişiere media'; -$lang['fileupload'] = 'Încarcă fişier media'; -$lang['uploadsucc'] = 'Încărcare reuşită'; -$lang['uploadfail'] = 'Încărcare eşuată. Poate din cauza permisiunilor?'; -$lang['uploadwrong'] = 'Încărcare nepermisă. Extensia fişierului e nepermisă'; -$lang['uploadexist'] = 'Fişierul există deja. Nimic nu a fost făcut.'; -$lang['uploadbadcontent'] = 'Conţinutul încărcat nu corespunde extensiei fişierului %s.'; +$lang['mediaselect'] = 'Selectare fișiere media'; +$lang['fileupload'] = 'Încarcă fișier media'; +$lang['uploadsucc'] = 'Încărcare reușită'; +$lang['uploadfail'] = 'Încărcare eșuată. Poate din cauza permisiunilor?'; +$lang['uploadwrong'] = 'Încărcare nepermisă. Extensia fișierului e nepermisă'; +$lang['uploadexist'] = 'Fișierul există deja. Nimic nu a fost făcut.'; +$lang['uploadbadcontent'] = 'Conținutul încărcat nu corespunde extensiei fișierului %s.'; $lang['uploadspam'] = 'Încărcarea a fost blocată datorită listei negre de spam.'; -$lang['uploadxss'] = 'Încărcarea a fost blocată datorită unui posibil conţinut dăunător.'; -$lang['uploadsize'] = 'Fişierul uploadat a fost prea mare. (max %s)'; -$lang['deletesucc'] = 'Fişierul "%s" a fost şters.'; -$lang['deletefail'] = '"%s" nu a putut fi şters - verificaţi drepturile.'; -$lang['mediainuse'] = 'Fişierul "%s" nu a fost şters - este încă în uz.'; -$lang['namespaces'] = 'Spaţii de nume'; -$lang['mediafiles'] = 'Fişiere disponibile în'; -$lang['accessdenied'] = 'Nu vă este permis să vizualizaţi această pagină.'; -$lang['mediausage'] = 'Folosiţi următoarea sintaxă pentru a face referinţă la acest fişier:'; -$lang['mediaview'] = 'Vizualizează fişierul original'; +$lang['uploadxss'] = 'Încărcarea a fost blocată datorită unui posibil conținut dăunător.'; +$lang['uploadsize'] = 'Fișierul uploadat a fost prea mare. (max %s)'; +$lang['deletesucc'] = 'Fișierul "%s" a fost șters.'; +$lang['deletefail'] = '"%s" nu a putut fi șters - verificați drepturile.'; +$lang['mediainuse'] = 'Fișierul "%s" nu a fost șters - este încă în uz.'; +$lang['namespaces'] = 'Spații de nume'; +$lang['mediafiles'] = 'Fișiere disponibile în'; +$lang['accessdenied'] = 'Nu vă este permis să vizualizați această pagină.'; +$lang['mediausage'] = 'Folosiți următoarea sintaxă pentru a face referință la acest fișier:'; +$lang['mediaview'] = 'Vizualizează fișierul original'; $lang['mediaroot'] = 'root'; -$lang['mediaupload'] = 'Încarcă un fişier in acest spaţiu de nume. Pentru a crea sub-spaţii de nume, adaugă-le la fişierul de încărcat, separate de doua puncte (:).'; -$lang['mediaextchange'] = 'Extensia fişierului a fost modificată din .%s în .%s!'; -$lang['reference'] = 'Referinţă pentru'; -$lang['ref_inuse'] = 'Fişierul nu a putut fi şters întrucât este folosit încă de următoarele pagini:'; -$lang['ref_hidden'] = 'Nu aveţi permisiunea să citiţi o parte din referinţele din pagină.'; +$lang['mediaupload'] = 'Încarcă un fișier in acest spațiu de nume. Pentru a crea sub-spații de nume, adaugă-le la fișierul de încărcat, separate de doua puncte (:).'; +$lang['mediaextchange'] = 'Extensia fișierului a fost modificată din .%s în .%s!'; +$lang['reference'] = 'Referință pentru'; +$lang['ref_inuse'] = 'Fișierul nu a putut fi șters întrucât este folosit încă de următoarele pagini:'; +$lang['ref_hidden'] = 'Nu aveți permisiunea să citiți o parte din referințele din pagină.'; $lang['hits'] = 'Hituri'; $lang['quickhits'] = 'Nume de pagini potrivite'; $lang['toc'] = 'Cuprins'; $lang['current'] = 'curent'; $lang['yours'] = 'Versiunea ta'; -$lang['diff'] = 'arată diferenţele faţă de versiunea curentă'; -$lang['diff2'] = 'Arată diferenţele dintre versiunile selectate'; +$lang['diff'] = 'arată diferențele față de versiunea curentă'; +$lang['diff2'] = 'Arată diferențele dintre versiunile selectate'; $lang['difflink'] = 'Link către această vizualizare comparativă'; $lang['diff_type'] = 'Vezi diferențe:'; $lang['diff_inline'] = 'Succesiv'; $lang['diff_side'] = 'Alăturate'; $lang['line'] = 'Linia'; $lang['breadcrumb'] = 'Traseu'; -$lang['youarehere'] = 'Sunteţi aici'; +$lang['youarehere'] = 'Sunteți aici'; $lang['lastmod'] = 'Ultima modificare'; $lang['by'] = 'de către'; -$lang['deleted'] = 'şters'; +$lang['deleted'] = 'șters'; $lang['created'] = 'creat'; $lang['restored'] = 'versiune veche restaurată (%s)'; $lang['external_edit'] = 'editare externă'; $lang['summary'] = 'Editează sumarul'; -$lang['noflash'] = 'Plugin-ul <a href="http://www.adobe.com/products/flashplayer/">Adobe Flash Plugin</a> este necesar pentru afişarea corectă a conţinutului.'; +$lang['noflash'] = 'Plugin-ul <a href="http://www.adobe.com/products/flashplayer/">Adobe Flash Plugin</a> este necesar pentru afișarea corectă a conținutului.'; $lang['download'] = 'Bloc descărcări'; $lang['tools'] = 'Unelte'; $lang['user_tools'] = 'Unelte utilizator'; @@ -196,14 +196,14 @@ $lang['page_tools'] = 'Unelte Pagină'; $lang['skip_to_content'] = 'sari la conținut'; $lang['mail_newpage'] = 'pagina adăugată:'; $lang['mail_changed'] = 'page schimbată:'; -$lang['mail_subscribe_list'] = 'pagini modificate în spaţiul de nume:'; +$lang['mail_subscribe_list'] = 'pagini modificate în spațiul de nume:'; $lang['mail_new_user'] = 'utilizator nou'; -$lang['mail_upload'] = 'fişier încărcat:'; +$lang['mail_upload'] = 'fișier încărcat:'; $lang['changes_type'] = 'Vizualizare modificări'; $lang['pages_changes'] = 'Pagini'; $lang['media_changes'] = 'Fișiere media'; -$lang['both_changes'] = 'Ambele pagini şi fişiere media'; -$lang['qb_bold'] = 'Text Îngroşat'; +$lang['both_changes'] = 'Ambele pagini și fișiere media'; +$lang['qb_bold'] = 'Text Îngroșat'; $lang['qb_italic'] = 'Text Italic'; $lang['qb_underl'] = 'Text Subliniat'; $lang['qb_code'] = 'Text Cod'; @@ -214,29 +214,29 @@ $lang['qb_h3'] = 'Titlu de Nivel 3'; $lang['qb_h4'] = 'Titlu de Nivel 4'; $lang['qb_h5'] = 'Titlu de Nivel 5'; $lang['qb_h'] = 'Titlu'; -$lang['qb_hs'] = 'Selectaţi Titlul'; +$lang['qb_hs'] = 'Selectați Titlul'; $lang['qb_hplus'] = 'Titlu mai mare'; $lang['qb_hminus'] = 'Titlu mai mic'; -$lang['qb_hequal'] = 'Titlu de acelaşi nivel'; +$lang['qb_hequal'] = 'Titlu de același nivel'; $lang['qb_link'] = 'Legătură internă'; $lang['qb_extlink'] = 'Legătura externă'; $lang['qb_hr'] = 'Linie Orizontal'; $lang['qb_ol'] = 'Listă Ordonată'; $lang['qb_ul'] = 'Listă Neordoată'; -$lang['qb_media'] = 'Adaugă imagini şi alte fişiere'; +$lang['qb_media'] = 'Adaugă imagini și alte fișiere'; $lang['qb_sig'] = 'Inserează semnătură'; $lang['qb_smileys'] = 'Smiley-uri'; $lang['qb_chars'] = 'Caractere speciale'; -$lang['upperns'] = 'sari la numele de spaţiu părinte'; +$lang['upperns'] = 'sari la numele de spațiu părinte'; $lang['admin_register'] = 'Adaugă utilizator nou'; $lang['metaedit'] = 'Editează Metadata'; -$lang['metasaveerr'] = 'Scrierea metadatelor a eşuat'; +$lang['metasaveerr'] = 'Scrierea metadatelor a eșuat'; $lang['metasaveok'] = 'Metadatele au fost salvate'; $lang['img_backto'] = 'Înapoi la'; $lang['img_title'] = 'Titlu'; $lang['img_caption'] = 'Legendă'; $lang['img_date'] = 'Data'; -$lang['img_fname'] = 'Nume fişier'; +$lang['img_fname'] = 'Nume fișier'; $lang['img_fsize'] = 'Dimensiune'; $lang['img_artist'] = 'Fotograf'; $lang['img_copyr'] = 'Copyright'; @@ -248,47 +248,47 @@ $lang['img_height'] = 'Înălțime'; $lang['img_manager'] = 'Vizualizează în administratorul media'; $lang['subscr_subscribe_success'] = 'Adăugat %s la lista de abonare pentru %s'; $lang['subscr_subscribe_error'] = 'Eroare la adăugarea %s la lista de abonare pentru %s'; -$lang['subscr_subscribe_noaddress'] = 'Nu există adresa asociată cu logarea dvs., nu puteţi fi adăugat la lista de abonare'; -$lang['subscr_unsubscribe_success'] = 'Şters %s din lista de abonare pentru %s'; -$lang['subscr_unsubscribe_error'] = 'Eroare la ştergerea %s din lista de abonare pentru %s'; +$lang['subscr_subscribe_noaddress'] = 'Nu există adresa asociată cu logarea dvs., nu puteți fi adăugat la lista de abonare'; +$lang['subscr_unsubscribe_success'] = 'Șters %s din lista de abonare pentru %s'; +$lang['subscr_unsubscribe_error'] = 'Eroare la ștergerea %s din lista de abonare pentru %s'; $lang['subscr_already_subscribed'] = '%s este deja abonat la %s'; $lang['subscr_not_subscribed'] = '%s nu este abonat la %s'; -$lang['subscr_m_not_subscribed'] = 'Momentan nu sunteţi abonat la pagina curentă sau la numele de spaţiu.'; +$lang['subscr_m_not_subscribed'] = 'Momentan nu sunteți abonat la pagina curentă sau la numele de spațiu.'; $lang['subscr_m_new_header'] = 'Adaugă abonare'; $lang['subscr_m_current_header'] = 'Abonări curente'; -$lang['subscr_m_unsubscribe'] = 'Dezabonaţi-vă'; -$lang['subscr_m_subscribe'] = 'Abonaţi-vă'; -$lang['subscr_m_receive'] = 'Primiţi'; +$lang['subscr_m_unsubscribe'] = 'Dezabonați-vă'; +$lang['subscr_m_subscribe'] = 'Abonați-vă'; +$lang['subscr_m_receive'] = 'Primiți'; $lang['subscr_style_every'] = 'email la ficare schimbare'; $lang['subscr_style_digest'] = 'digerează email la schimbări pentru fiecare pagină (la fiecare %.2f zile)'; $lang['subscr_style_list'] = 'lista paginilor schimbate de la ultimul email (la fiecare %.2f zile)'; -$lang['authmodfailed'] = 'Configuraţia autentificării utilizatorului este eronată. Anunţaţi Wiki Admin-ul.'; -$lang['authtempfail'] = 'Autentificarea utilizatorului este temporar indisponibilă. Anunţaţi Wiki Admin-ul.'; +$lang['authmodfailed'] = 'Configurația autentificării utilizatorului este eronată. Anunțați Wiki Admin-ul.'; +$lang['authtempfail'] = 'Autentificarea utilizatorului este temporar indisponibilă. Anunțați Wiki Admin-ul.'; $lang['authpwdexpire'] = 'Parola vă va expira în %d zile, ar trebui să o schimbați curând.'; -$lang['i_chooselang'] = 'Alegeţi limba'; +$lang['i_chooselang'] = 'Alegeți limba'; $lang['i_installer'] = 'DokuWiki Installer'; $lang['i_wikiname'] = 'Numele Wiki'; $lang['i_enableacl'] = 'Activează ACL (recomandat)'; $lang['i_superuser'] = 'Superutilizator'; -$lang['i_problems'] = 'Programul de instalare a găsit câteva probleme, indicate mai jos. Nu puteţi continua până nu le rezolvaţi.'; -$lang['i_modified'] = 'Din motive de securitate, acest script va funcţiona doar cu o instalare nouă şi nemodificată a Docuwiki. -Puteţi fie să extrageţi din nou fişierele din arhiva descărcată fie să consultaţi instrucţiunile de instalare Dokuwiki la <a href="http://dokuwiki.org/install">'; -$lang['i_funcna'] = 'Funcţia PHP <code>%s</code> nu este disponibilă. Probabil provider-ul dvs. a inactivat-o pentru un motiv oarecare.'; -$lang['i_phpver'] = 'Versiunea dvs. de PHP <code>%s</code> este mai veche decât cea necesară (<code>%s</code>). Trebuie să vă actualizaţi instalarea PHP.'; -$lang['i_permfail'] = '<code>%s</code> nu poate fi scris de către DokuWiki. Trebuie să modificaţi drepturile acestui director!'; +$lang['i_problems'] = 'Programul de instalare a găsit câteva probleme, indicate mai jos. Nu puteți continua până nu le rezolvați.'; +$lang['i_modified'] = 'Din motive de securitate, acest script va funcționa doar cu o instalare nouă și nemodificată a Docuwiki. +Puteți fie să extrageți din nou fișierele din arhiva descărcată fie să consultați instrucțiunile de instalare Dokuwiki la <a href="http://dokuwiki.org/install">'; +$lang['i_funcna'] = 'Funcția PHP <code>%s</code> nu este disponibilă. Probabil provider-ul dvs. a inactivat-o pentru un motiv oarecare.'; +$lang['i_phpver'] = 'Versiunea dvs. de PHP <code>%s</code> este mai veche decât cea necesară (<code>%s</code>). Trebuie să vă actualizați instalarea PHP.'; +$lang['i_permfail'] = '<code>%s</code> nu poate fi scris de către DokuWiki. Trebuie să modificați drepturile acestui director!'; $lang['i_confexists'] = '<code>%s</code> există deja'; -$lang['i_writeerr'] = 'Nu s-a putut crea <code>%s</code>. Trebuie să verificaţi drepturile directorului/fişierului şi să creaţi fişierul manual.'; +$lang['i_writeerr'] = 'Nu s-a putut crea <code>%s</code>. Trebuie să verificați drepturile directorului/fișierului și să creați fișierul manual.'; $lang['i_badhash'] = 'dokuwiki.php nu a fost recunoscut sau a fost modificat (hash=<code>%s</code>)'; $lang['i_badval'] = '<code>%s</code> - valoare nepemisă sau neintrodusă'; -$lang['i_success'] = 'Configurarea a fost finalizată cu succes. Acum puteţi sterge fişierul install.php. Continuaţi cu <a href="doku.php?id=wiki:welcome">your new DokuWiki</a>.'; -$lang['i_failure'] = 'Au apărut erori la scrierea fişierelor de configurare. Va trebui să le corectaţi manual înainte de a putea folosi <a href="doku.php?id=wiki:welcome">your new DokuWiki</a>.'; -$lang['i_policy'] = 'Politica ACL iniţială'; -$lang['i_pol0'] = 'Wiki Deschisă (citeşte, scrie şi încarcă oricine)'; -$lang['i_pol1'] = 'Wiki Deschisă (citeste oricine, scrie şi încarcă doar utilizatorul înregistrat)'; -$lang['i_pol2'] = 'Wiki Închisă (citeşte, scrie şi încarcă doar utilizatorul înregistrat)'; +$lang['i_success'] = 'Configurarea a fost finalizată cu succes. Acum puteți sterge fișierul install.php. Continuați cu <a href="doku.php?id=wiki:welcome">your new DokuWiki</a>.'; +$lang['i_failure'] = 'Au apărut erori la scrierea fișierelor de configurare. Va trebui să le corectați manual înainte de a putea folosi <a href="doku.php?id=wiki:welcome">your new DokuWiki</a>.'; +$lang['i_policy'] = 'Politica ACL inițială'; +$lang['i_pol0'] = 'Wiki Deschisă (citește, scrie și încarcă oricine)'; +$lang['i_pol1'] = 'Wiki Deschisă (citeste oricine, scrie și încarcă doar utilizatorul înregistrat)'; +$lang['i_pol2'] = 'Wiki Închisă (citește, scrie și încarcă doar utilizatorul înregistrat)'; $lang['i_retry'] = 'Încearcă din nou'; -$lang['i_license'] = 'Vă rugăm alegeţi licenţa sub care doriţi să vă licenţiaţi materialul:'; -$lang['recent_global'] = 'Acum vizualizaţi modificările în interiorul numelui de spaţiu <b>%s</b>. De asemenea puteţi <a href="%s">vizualiza modificările recente ale întregului wiki</a>.'; +$lang['i_license'] = 'Vă rugăm alegeți licența sub care doriți să vă licențiați materialul:'; +$lang['recent_global'] = 'Acum vizualizați modificările în interiorul numelui de spațiu <b>%s</b>. De asemenea puteți <a href="%s">vizualiza modificările recente ale întregului wiki</a>.'; $lang['years'] = 'acum %d ani'; $lang['months'] = 'acum %d luni'; $lang['weeks'] = 'acum %d săptămâni'; @@ -296,7 +296,7 @@ $lang['days'] = 'acum %d zile'; $lang['hours'] = 'acum %d ore'; $lang['minutes'] = 'acum %d minute'; $lang['seconds'] = 'acum %d secunde'; -$lang['wordblock'] = 'Modificarea dvs. nu au fost salvate deoarece conţine text blocat (spam).'; +$lang['wordblock'] = 'Modificarea dvs. nu au fost salvate deoarece conține text blocat (spam).'; $lang['media_uploadtab'] = 'Încarcă'; $lang['media_searchtab'] = 'Căutare'; $lang['media_file'] = 'Fișier'; diff --git a/inc/lang/ro/locked.txt b/inc/lang/ro/locked.txt index 94d6eb2ff..8708157ec 100644 --- a/inc/lang/ro/locked.txt +++ b/inc/lang/ro/locked.txt @@ -1,3 +1,3 @@ ====== Pagină blocată ====== -Pagina este momentan blocată de alt utilizator. Trebuie să aştepţi pînă cînd acest utilizator termină editarea ori expiră blocarea. +Pagina este momentan blocată de alt utilizator. Trebuie să aștepți pînă cînd acest utilizator termină editarea ori expiră blocarea. diff --git a/inc/lang/ro/login.txt b/inc/lang/ro/login.txt index 2f1fda9ad..81bca6298 100644 --- a/inc/lang/ro/login.txt +++ b/inc/lang/ro/login.txt @@ -1,4 +1,4 @@ ====== Login ====== -Nu sînteţi logat! Introduceţi datele de autentificare pentru logare. Trebuie să permiteţi cookie-uri pentru logare. +Nu sînteți logat! Introduceți datele de autentificare pentru logare. Trebuie să permiteți cookie-uri pentru logare. diff --git a/inc/lang/ro/newpage.txt b/inc/lang/ro/newpage.txt index 7fb9d55a6..886258609 100644 --- a/inc/lang/ro/newpage.txt +++ b/inc/lang/ro/newpage.txt @@ -1,3 +1,3 @@ ====== Subiectul nu există încă ====== -Aţi urmat o legătură către un subiect care nu există. O puteţi crea prin apăsarea butonului ''Editează această pagină''. +Ați urmat o legătură către un subiect care nu există. O puteți crea prin apăsarea butonului ''Editează această pagină''. diff --git a/inc/lang/ro/norev.txt b/inc/lang/ro/norev.txt index 926f9144e..4a21abcbf 100644 --- a/inc/lang/ro/norev.txt +++ b/inc/lang/ro/norev.txt @@ -1,4 +1,4 @@ ====== Nu există versiunea ====== -Versiunea specificată nu există. Foloseşte butonul ''Versiuni vechi'' pentru o listă a versiunilor acestui document. +Versiunea specificată nu există. Folosește butonul ''Versiuni vechi'' pentru o listă a versiunilor acestui document. diff --git a/inc/lang/ro/pwconfirm.txt b/inc/lang/ro/pwconfirm.txt index 043e08868..ae2d9f963 100644 --- a/inc/lang/ro/pwconfirm.txt +++ b/inc/lang/ro/pwconfirm.txt @@ -2,9 +2,9 @@ Salut @FULLNAME@! Cineva a cerut o parolă nouă pentru @TITLE@ pentru conectarea la @DOKUWIKIURL@ -Dacă nu aţi solicitat o parolă nouă, ignoraţi acest email. +Dacă nu ați solicitat o parolă nouă, ignorați acest email. -Pentru a confirma că cererea a fost într-adevăr trimisă de dumneavoastră, folosiţi link-ul de mai jos. +Pentru a confirma că cererea a fost într-adevăr trimisă de dumneavoastră, folosiți link-ul de mai jos. @CONFIRM@ diff --git a/inc/lang/ro/read.txt b/inc/lang/ro/read.txt index 2c0aa6d90..72c33c0c0 100644 --- a/inc/lang/ro/read.txt +++ b/inc/lang/ro/read.txt @@ -1,2 +1,2 @@ -Această pagină poate fi doar citită. Poţi vedea sursa, dar n-o poţi modifica. Consultă administratorul dacă crezi că e ceva în neregulă. +Această pagină poate fi doar citită. Poți vedea sursa, dar n-o poți modifica. Consultă administratorul dacă crezi că e ceva în neregulă. diff --git a/inc/lang/ro/register.txt b/inc/lang/ro/register.txt index 9fc6eec65..e062a46bc 100644 --- a/inc/lang/ro/register.txt +++ b/inc/lang/ro/register.txt @@ -1,3 +1,3 @@ ====== Înregistrează-te ca utilizator nou ====== -Pentru a crea un wiki nou completează mai jos toate informaţiile. Asigură-te că ai introdus o adresă de **e-mail validă** unde va fi trimisă noua parolă. Numele de utilizator trebuie de asemenea să fie valid [[doku>pagename|pagename]]. +Pentru a crea un wiki nou completează mai jos toate informațiile. Asigură-te că ai introdus o adresă de **e-mail validă** unde va fi trimisă noua parolă. Numele de utilizator trebuie de asemenea să fie valid [[doku>pagename|pagename]]. diff --git a/inc/lang/ro/resendpwd.txt b/inc/lang/ro/resendpwd.txt index b7de241e9..4a67f9e80 100644 --- a/inc/lang/ro/resendpwd.txt +++ b/inc/lang/ro/resendpwd.txt @@ -1,3 +1,3 @@ ====== Trimite parolă nouă ====== -Introduceţi numele de utilizator în formularul de mai jos pentru a solicita o nouă parolă pentru această wiki. Un link de confirmare va fi trimis la adresa de email înregistrată. \ No newline at end of file +Introduceți numele de utilizator în formularul de mai jos pentru a solicita o nouă parolă pentru această wiki. Un link de confirmare va fi trimis la adresa de email înregistrată. \ No newline at end of file diff --git a/inc/lang/ro/revisions.txt b/inc/lang/ro/revisions.txt index b2ff46f77..d42134c61 100644 --- a/inc/lang/ro/revisions.txt +++ b/inc/lang/ro/revisions.txt @@ -1,4 +1,4 @@ ====== Versiune veche ====== -Acestea sînt versiunile vechi ale documentului curent. Pentru revenirea la o versiune mai veche, selecteaz-o de mai jos, clic pe ''Editează această pagină'' şi salveaz-o. +Acestea sînt versiunile vechi ale documentului curent. Pentru revenirea la o versiune mai veche, selecteaz-o de mai jos, clic pe ''Editează această pagină'' și salveaz-o. diff --git a/inc/lang/ro/searchpage.txt b/inc/lang/ro/searchpage.txt index c1169b88d..8c78c68c3 100644 --- a/inc/lang/ro/searchpage.txt +++ b/inc/lang/ro/searchpage.txt @@ -1,5 +1,5 @@ ====== Căutare ====== -Rezultatele căutării sînt afisate mai jos. Dacă n-aţi găsit ce-aţi căutat, puteţi creea o pagină nouă după căutare prin folosirea butonului ''Editează această pagină''. +Rezultatele căutării sînt afisate mai jos. Dacă n-ați găsit ce-ați căutat, puteți creea o pagină nouă după căutare prin folosirea butonului ''Editează această pagină''. ===== Rezultate ===== diff --git a/inc/lang/ro/stopwords.txt b/inc/lang/ro/stopwords.txt index 29e7452d3..1f0d9536b 100644 --- a/inc/lang/ro/stopwords.txt +++ b/inc/lang/ro/stopwords.txt @@ -1,6 +1,6 @@ # Aceasta este o listă de cuvinte ignorate la indexare, câte un cuvânt pe linie -# Când editaţi acest fişier, asiguraţi-vă că folosiţi sfârşituri de linie UNIX (o singură linie nouă) -# Nu e nevoie să includeţi cuvinte mai scurte de 3 caractere - acestea sunt, oricum, ignorate +# Când editați acest fișier, asigurați-vă că folosiți sfârșituri de linie UNIX (o singură linie nouă) +# Nu e nevoie să includeți cuvinte mai scurte de 3 caractere - acestea sunt, oricum, ignorate # Această listă se bazează pe cele ce pot fi găsite la http://www.ranks.nl/stopwords/ about are diff --git a/inc/lang/ro/subscr_digest.txt b/inc/lang/ro/subscr_digest.txt index b2f7c4ecb..ad0a30708 100644 --- a/inc/lang/ro/subscr_digest.txt +++ b/inc/lang/ro/subscr_digest.txt @@ -10,10 +10,10 @@ Acestea sunt modificările: Vechea revizie: @OLDPAGE@ Noua revizie: @NEWPAGE@ -Pentru a anula notificarea paginii, logaţi-vă pe wiki la -@DOKUWIKIURL@ apoi navigaţi la +Pentru a anula notificarea paginii, logați-vă pe wiki la +@DOKUWIKIURL@ apoi navigați la @SUBSCRIBE@ -şi dezabonaţi-vă de la pagină şi/sau modificările numelui de spaţiu. +și dezabonați-vă de la pagină și/sau modificările numelui de spațiu. -- Acest mail a fost generat de DokuWiki la diff --git a/inc/lang/ro/subscr_form.txt b/inc/lang/ro/subscr_form.txt index 8ce7f09b8..e55dfe6cb 100644 --- a/inc/lang/ro/subscr_form.txt +++ b/inc/lang/ro/subscr_form.txt @@ -1,3 +1,3 @@ ====== Administrarea abonărilor ====== -Această pagină vă permite să vă administraţi abonările pentru pagina curentă şi numele de spaţiu. \ No newline at end of file +Această pagină vă permite să vă administrați abonările pentru pagina curentă și numele de spațiu. \ No newline at end of file diff --git a/inc/lang/ro/subscr_list.txt b/inc/lang/ro/subscr_list.txt index 84a5e1a3e..1b55ea917 100644 --- a/inc/lang/ro/subscr_list.txt +++ b/inc/lang/ro/subscr_list.txt @@ -1,16 +1,16 @@ Bună ziua! -Paginile din numele de spaţiu @PAGE@ al @TITLE@ wiki s-au modificat. +Paginile din numele de spațiu @PAGE@ al @TITLE@ wiki s-au modificat. Acestea sunt modificările: -------------------------------------------------------- @DIFF@ -------------------------------------------------------- -Pentru a anula notificarea paginii, logaţi-vă pe wiki la -@DOKUWIKIURL@ apoi navigaţi la +Pentru a anula notificarea paginii, logați-vă pe wiki la +@DOKUWIKIURL@ apoi navigați la @SUBSCRIBE@ -şi dezabonaţi-vă de la pagină şi/sau modificările numelui de spaţiu. +și dezabonați-vă de la pagină și/sau modificările numelui de spațiu. -- Acest mail a fost generat de DokuWiki la diff --git a/inc/lang/ro/subscr_single.txt b/inc/lang/ro/subscr_single.txt index aa6497b75..006db741d 100644 --- a/inc/lang/ro/subscr_single.txt +++ b/inc/lang/ro/subscr_single.txt @@ -13,10 +13,10 @@ Sumarul editării: @SUMMARY@ Vechea revizie: @OLDPAGE@ Noua revizie: @NEWPAGE@ -Pentru a anula notificarea paginii, logaţi-vă pe wiki la -@DOKUWIKIURL@ apoi navigaţi la +Pentru a anula notificarea paginii, logați-vă pe wiki la +@DOKUWIKIURL@ apoi navigați la @SUBSCRIBE@ -şi dezabonaţi-vă de la pagină şi/sau modificările numelui de spaţiu. +și dezabonați-vă de la pagină și/sau modificările numelui de spațiu. -- Acest mail a fost generat de DokuWiki la diff --git a/inc/lang/ro/updateprofile.txt b/inc/lang/ro/updateprofile.txt index e5988ec51..f3985a1c6 100644 --- a/inc/lang/ro/updateprofile.txt +++ b/inc/lang/ro/updateprofile.txt @@ -1,3 +1,3 @@ ====== Actualizare profil utilizator ====== -Trebuie să completaţi doar câmpurile pe care doriţi să le modificaţi. Nu puteţi modifica numele de utilizator. \ No newline at end of file +Trebuie să completați doar câmpurile pe care doriți să le modificați. Nu puteți modifica numele de utilizator. \ No newline at end of file diff --git a/inc/lang/ro/uploadmail.txt b/inc/lang/ro/uploadmail.txt index 39faed370..c1e5736e2 100644 --- a/inc/lang/ro/uploadmail.txt +++ b/inc/lang/ro/uploadmail.txt @@ -1,6 +1,6 @@ -Un fişier a fost încărcat în DocuWiki. Iată detaliile: +Un fișier a fost încărcat în DocuWiki. Iată detaliile: -Fişier : @MEDIA@ +Fișier : @MEDIA@ Data : @DATE@ Browser : @BROWSER@ Adresă IP : @IPADDRESS@ -- cgit v1.2.3 From e71b0ef705b86bb653fcae43e6845acbe6fd7fd2 Mon Sep 17 00:00:00 2001 From: Guy Brand <gb@unistra.fr> Date: Sun, 17 Mar 2013 19:22:37 +0100 Subject: backward compatibility for old authtype settings --- inc/auth.php | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/inc/auth.php b/inc/auth.php index 68b6b438d..0713ca6af 100644 --- a/inc/auth.php +++ b/inc/auth.php @@ -48,10 +48,15 @@ function auth_setup() { // try to load auth backend from plugins foreach ($plugin_controller->getList('auth') as $plugin) { - if ($conf['authtype'] === $plugin) { - $auth = $plugin_controller->load('auth', $plugin); - break; - } + if ($conf['authtype'] === $plugin) { + $auth = $plugin_controller->load('auth', $plugin); + break; + } elseif ('auth' . $conf['authtype'] === $plugin) { + // matches old auth backends (pre-Weatherwax) + $auth = $plugin_controller->load('auth', $plugin); + msg('Your authtype setting is deprecated. You must set $conf[\'authconfig\'] = ' . "auth" . $conf['authtype'] + . ' in your config (see <a href="https://www.dokuwiki.org/auth">Authentication Backends</a>)',-1); + } } if(!isset($auth) || !$auth){ -- cgit v1.2.3 From d02ff93090ec7ab874d4f61fbef15d5b3a2eb341 Mon Sep 17 00:00:00 2001 From: Christopher Smith <chris@jalakai.co.uk> Date: Mon, 18 Mar 2013 14:32:48 +0000 Subject: correct parenthesis in image crop calculations to ensure integer values --- inc/media.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/inc/media.php b/inc/media.php index 501d170f3..2268ad877 100644 --- a/inc/media.php +++ b/inc/media.php @@ -1831,23 +1831,23 @@ function media_crop_image($file, $ext, $w, $h=0){ if($tr >= 1){ if($tr > $fr){ $cw = $info[0]; - $ch = (int) $info[0]/$tr; + $ch = (int) ($info[0]/$tr); }else{ - $cw = (int) $info[1]*$tr; + $cw = (int) ($info[1]*$tr); $ch = $info[1]; } }else{ if($tr < $fr){ - $cw = (int) $info[1]*$tr; + $cw = (int) ($info[1]*$tr); $ch = $info[1]; }else{ $cw = $info[0]; - $ch = (int) $info[0]/$tr; + $ch = (int) ($info[0]/$tr); } } // calculate crop offset - $cx = (int) ($info[0]-$cw)/2; - $cy = (int) ($info[1]-$ch)/3; + $cx = (int) (($info[0]-$cw)/2); + $cy = (int) (($info[1]-$ch)/3); //cache $local = getCacheName($file,'.media.'.$cw.'x'.$ch.'.crop.'.$ext); -- cgit v1.2.3 From e31bcd2ed7f7f49338e4b8f77ed998c9fd10e780 Mon Sep 17 00:00:00 2001 From: Dominik Eckelmann <deckelmann@gmail.com> Date: Mon, 18 Mar 2013 21:20:30 +0100 Subject: removed unused string in km translation --- inc/lang/km/lang.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inc/lang/km/lang.php b/inc/lang/km/lang.php index 1f006f64e..c056e3acc 100644 --- a/inc/lang/km/lang.php +++ b/inc/lang/km/lang.php @@ -166,7 +166,7 @@ $lang['js']['del_confirm']= 'លុប'; $lang['admin_register']= 'តែមអ្នកប្រើ';//'Add new user'; $lang['spell_start'] = 'ពិនិត្យអក្ខរាវិរុទ្ធ';//'Check Spelling'; -$lang['spell_stop'] = 'បណ្តកំរែ'; 'Resume Editing'; +$lang['spell_stop'] = 'បណ្តកំរែ'; $lang['spell_wait'] = 'សូមចាំ';//'Please wait...'; $lang['spell_noerr'] = 'ឥតមានខុះទេ'; $lang['spell_nosug'] = 'ឥតមានយោបល់'; -- cgit v1.2.3 From 1066753ac288ef252063d426b913dcf30442fed7 Mon Sep 17 00:00:00 2001 From: Dominik Eckelmann <deckelmann@gmail.com> Date: Tue, 19 Mar 2013 12:34:48 +0100 Subject: fixed lithuanian language file --- inc/lang/lt/lang.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inc/lang/lt/lang.php b/inc/lang/lt/lang.php index d65f30ae0..b284555ef 100644 --- a/inc/lang/lt/lang.php +++ b/inc/lang/lt/lang.php @@ -89,7 +89,7 @@ $lang['txt_overwrt'] = 'Perrašyti egzistuojančią bylą'; $lang['lockedby'] = 'Užrakintas vartotojo'; $lang['lockexpire'] = 'Užraktas bus nuimtas'; $lang['js']['willexpire'] = 'Šio puslapio redagavimo užrakto galiojimo laikas baigsis po minutės.\nNorėdami išvengti nesklandumų naudokite peržiūros mygtuką ir užraktas atsinaujins.'; -$lang['js']['notsavedyet'] = 'Pakeitimai nebus išsaugoti.\nTikrai tęsti?"; +$lang['js']['notsavedyet'] = 'Pakeitimai nebus išsaugoti.\nTikrai tęsti?'; $lang['rssfailed'] = 'Siunčiant šį feed\'ą įvyko klaida: '; $lang['nothingfound'] = 'Paieškos rezultatų nėra.'; $lang['mediaselect'] = 'Mediabylos išsirinkimas'; -- cgit v1.2.3 From 2ab296805f9b647d3fe46cad4a7f275c45f171a8 Mon Sep 17 00:00:00 2001 From: Dominik Eckelmann <deckelmann@gmail.com> Date: Tue, 19 Mar 2013 12:42:22 +0100 Subject: removed unsused translation file --- lib/plugins/info/lang/sl/lang.php | 12 ------------ 1 file changed, 12 deletions(-) delete mode 100644 lib/plugins/info/lang/sl/lang.php diff --git a/lib/plugins/info/lang/sl/lang.php b/lib/plugins/info/lang/sl/lang.php deleted file mode 100644 index 62936947c..000000000 --- a/lib/plugins/info/lang/sl/lang.php +++ /dev/null @@ -1,12 +0,0 @@ -<?php -/** - * English language file - * - * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) - * @author Guillaume Turri <guillaume.turri@gmail.com> - */ - -$lang['encoding'] = 'utf-8'; -$lang['direction'] = 'ltr'; -$lang['onHidden'] = 'Click to display ⇲'; -$lang['onVisible'] = 'Click to hide ⇱'; -- cgit v1.2.3 From fd9d3278078df67aab6cee0c2b7b43a27f206983 Mon Sep 17 00:00:00 2001 From: Christopher Smith <chris@jalakai.co.uk> Date: Tue, 19 Mar 2013 17:31:06 +0000 Subject: avoid creating an intermediate crop image when the final image will match a resize --- inc/media.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/inc/media.php b/inc/media.php index 2268ad877..654d31cb4 100644 --- a/inc/media.php +++ b/inc/media.php @@ -1828,6 +1828,13 @@ function media_crop_image($file, $ext, $w, $h=0){ // calculate crop size $fr = $info[0]/$info[1]; $tr = $w/$h; + + // check if the crop can be handled completely by resize, + // i.e. the specified width & height match the aspect ratio of the source image + if ($w == round($h*$fr)) { + return media_resize_image($file, $ext, $w); + } + if($tr >= 1){ if($tr > $fr){ $cw = $info[0]; -- cgit v1.2.3 From 0f4e009215bfa3136d334fa557335266637a7585 Mon Sep 17 00:00:00 2001 From: Christopher Smith <chris@jalakai.co.uk> Date: Wed, 20 Mar 2013 00:06:07 +0000 Subject: add a token to fetch urls requiring image resize/crop to prevent external DDOS via fetch --- inc/common.php | 4 ++++ inc/media.php | 24 ++++++++++++++++++++++++ lib/exe/fetch.php | 8 ++++++-- 3 files changed, 34 insertions(+), 2 deletions(-) diff --git a/inc/common.php b/inc/common.php index 471eb91b5..27f90b53b 100644 --- a/inc/common.php +++ b/inc/common.php @@ -436,6 +436,10 @@ function exportlink($id = '', $format = 'raw', $more = '', $abs = false, $sep = function ml($id = '', $more = '', $direct = true, $sep = '&', $abs = false) { global $conf; if(is_array($more)) { + // add token for resized images + if($more['w'] || $more['h']){ + $more['tok'] = media_get_token($id,$more['w'],$more['h']); + } // strip defaults for shorter URLs if(isset($more['cache']) && $more['cache'] == 'cache') unset($more['cache']); if(!$more['w']) unset($more['w']); diff --git a/inc/media.php b/inc/media.php index 2268ad877..7f2fd2d1d 100644 --- a/inc/media.php +++ b/inc/media.php @@ -1864,6 +1864,30 @@ function media_crop_image($file, $ext, $w, $h=0){ return media_resize_image($file,$ext, $w, $h); } +/** + * Calculate a token to be used to verify fetch requests for resized or + * cropped images have been internally generated - and prevent external + * DDOS attacks via fetch + * + * @param string $id id of the image + * @param int $w resize/crop width + * @param int $h resize/crop height + * + * @author Christopher Smith <chris@jalakai.co.uk> + */ +function media_get_token($id,$w,$h){ + // token is only required for modified images + if ($w || $h) { + $token = auth_cookiesalt().$id; + if ($w) $token .= '.'.$w; + if ($h) $token .= '.'.$h; + + return substr(md5($token),0,6); + } + + return ''; +} + /** * Download a remote file and return local filename * diff --git a/lib/exe/fetch.php b/lib/exe/fetch.php index a558a3db8..48aa22fe2 100644 --- a/lib/exe/fetch.php +++ b/lib/exe/fetch.php @@ -32,7 +32,7 @@ if(!defined('SIMPLE_TEST')) { } // check for permissions, preconditions and cache external files - list($STATUS, $STATUSMESSAGE) = checkFileStatus($MEDIA, $FILE, $REV); + list($STATUS, $STATUSMESSAGE) = checkFileStatus($MEDIA, $FILE, $REV, $WIDTH, $HEIGHT); // prepare data for plugin events $data = array( @@ -180,7 +180,7 @@ function sendFile($file, $mime, $dl, $cache, $public = false) { * @param $file reference to the file variable * @returns array(STATUS, STATUSMESSAGE) */ -function checkFileStatus(&$media, &$file, $rev = '') { +function checkFileStatus(&$media, &$file, $rev = '', $width=0, $height=0) { global $MIME, $EXT, $CACHE, $INPUT; //media to local file @@ -200,6 +200,10 @@ function checkFileStatus(&$media, &$file, $rev = '') { if(empty($media)) { return array(400, 'Bad request'); } + // check token for resized images + if (($width || $height) && media_get_token($media, $width, $height) !== $INPUT->str('tok')) { + return array(412, 'Precondition Failed'); + } //check permissions (namespace only) if(auth_quickaclcheck(getNS($media).':X') < AUTH_READ) { -- cgit v1.2.3 From 7fb7960f92047a9bcadf9d497ae79615979e9a6d Mon Sep 17 00:00:00 2001 From: Christopher Smith <chris@jalakai.co.uk> Date: Fri, 22 Mar 2013 17:45:59 +0000 Subject: refactor fetch to support unittesting --- inc/fetch.functions.php | 149 ++++++++++++++++++++++++++++++++++++++++++++ lib/exe/fetch.php | 160 +++--------------------------------------------- 2 files changed, 159 insertions(+), 150 deletions(-) create mode 100644 inc/fetch.functions.php diff --git a/inc/fetch.functions.php b/inc/fetch.functions.php new file mode 100644 index 000000000..5801e96fa --- /dev/null +++ b/inc/fetch.functions.php @@ -0,0 +1,149 @@ +<?php +/** + * Functions used by lib/exe/fetch.php + * (not included by other parts of dokuwiki) + */ + +/** + * Set headers and send the file to the client + * + * The $cache parameter influences how long files may be kept in caches, the $public parameter + * influences if this caching may happen in public proxis or in the browser cache only FS#2734 + * + * This function will abort the current script when a 304 is sent or file sending is handled + * through x-sendfile + * + * @author Andreas Gohr <andi@splitbrain.org> + * @author Ben Coburn <btcoburn@silicodon.net> + * @param string $file local file to send + * @param string $mime mime type of the file + * @param bool $dl set to true to force a browser download + * @param int $cache remaining cache time in seconds (-1 for $conf['cache'], 0 for no-cache) + * @param bool $public is this a public ressource or a private one? + */ +function sendFile($file, $mime, $dl, $cache, $public = false) { + global $conf; + // send mime headers + header("Content-Type: $mime"); + + // calculate cache times + if($cache == -1) { + $maxage = max($conf['cachetime'], 3600); // cachetime or one hour + $expires = time() + $maxage; + } else if($cache > 0) { + $maxage = $cache; // given time + $expires = time() + $maxage; + } else { // $cache == 0 + $maxage = 0; + $expires = 0; // 1970-01-01 + } + + // smart http caching headers + if($maxage) { + if($public) { + // cache publically + header('Expires: '.gmdate("D, d M Y H:i:s", $expires).' GMT'); + header('Cache-Control: public, proxy-revalidate, no-transform, max-age='.$maxage); + header('Pragma: public'); + } else { + // cache in browser + header('Expires: '.gmdate("D, d M Y H:i:s", $expires).' GMT'); + header('Cache-Control: private, no-transform, max-age='.$maxage); + header('Pragma: no-cache'); + } + } else { + // no cache at all + header('Expires: Thu, 01 Jan 1970 00:00:00 GMT'); + header('Cache-Control: no-cache, no-transform'); + header('Pragma: no-cache'); + } + + //send important headers first, script stops here if '304 Not Modified' response + $fmtime = @filemtime($file); + http_conditionalRequest($fmtime); + + //download or display? + if($dl) { + header('Content-Disposition: attachment; filename="'.utf8_basename($file).'";'); + } else { + header('Content-Disposition: inline; filename="'.utf8_basename($file).'";'); + } + + //use x-sendfile header to pass the delivery to compatible webservers + if(http_sendfile($file)) exit; + + // send file contents + $fp = @fopen($file, "rb"); + if($fp) { + http_rangeRequest($fp, filesize($file), $mime); + } else { + http_status(500); + print "Could not read $file - bad permissions?"; + } +} + +/** + * Check for media for preconditions and return correct status code + * + * READ: MEDIA, MIME, EXT, CACHE + * WRITE: MEDIA, FILE, array( STATUS, STATUSMESSAGE ) + * + * @author Gerry Weissbach <gerry.w@gammaproduction.de> + * @param $media reference to the media id + * @param $file reference to the file variable + * @returns array(STATUS, STATUSMESSAGE) + */ +function checkFileStatus(&$media, &$file, $rev = '', $width=0, $height=0) { + global $MIME, $EXT, $CACHE, $INPUT; + + //media to local file + if(preg_match('#^(https?)://#i', $media)) { + //check hash + if(substr(md5(auth_cookiesalt().$media), 0, 6) !== $INPUT->str('hash')) { + return array(412, 'Precondition Failed'); + } + //handle external images + if(strncmp($MIME, 'image/', 6) == 0) $file = media_get_from_URL($media, $EXT, $CACHE); + if(!$file) { + //download failed - redirect to original URL + return array(302, $media); + } + } else { + $media = cleanID($media); + if(empty($media)) { + return array(400, 'Bad request'); + } + // check token for resized images + if (($width || $height) && media_get_token($media, $width, $height) !== $INPUT->str('tok')) { + return array(412, 'Precondition Failed'); + } + + //check permissions (namespace only) + if(auth_quickaclcheck(getNS($media).':X') < AUTH_READ) { + return array(403, 'Forbidden'); + } + $file = mediaFN($media, $rev); + } + + //check file existance + if(!@file_exists($file)) { + return array(404, 'Not Found'); + } + + return array(200, null); +} + +/** + * Returns the wanted cachetime in seconds + * + * Resolves named constants + * + * @author Andreas Gohr <andi@splitbrain.org> + */ +function calc_cache($cache) { + global $conf; + + if(strtolower($cache) == 'nocache') return 0; //never cache + if(strtolower($cache) == 'recache') return $conf['cachetime']; //use standard cache + return -1; //cache endless +} diff --git a/lib/exe/fetch.php b/lib/exe/fetch.php index 48aa22fe2..7a2250373 100644 --- a/lib/exe/fetch.php +++ b/lib/exe/fetch.php @@ -7,12 +7,17 @@ */ if(!defined('DOKU_INC')) define('DOKU_INC', dirname(__FILE__).'/../../'); -define('DOKU_DISABLE_GZIP_OUTPUT', 1); +if (!defined('DOKU_DISABLE_GZIP_OUTPUT')) define('DOKU_DISABLE_GZIP_OUTPUT', 1); require_once(DOKU_INC.'inc/init.php'); session_write_close(); //close session -// BEGIN main (if not testing) -if(!defined('SIMPLE_TEST')) { +require_once(DOKU_INC.'inc/fetch.functions.php'); + +if (defined('SIMPLE_TEST')) { + $INPUT = new Input(); +} + +// BEGIN main $mimetypes = getMimeTypes(); //get input @@ -64,6 +69,7 @@ if(!defined('SIMPLE_TEST')) { // die on errors if($data['status'] > 203) { print $data['statusmessage']; + if (defined('SIMPLE_TEST')) return; exit; } } @@ -87,152 +93,6 @@ if(!defined('SIMPLE_TEST')) { // Do something after the download finished. $evt->advise_after(); // will not be emitted on 304 or x-sendfile -}// END DO main - -/* ------------------------------------------------------------------------ */ - -/** - * Set headers and send the file to the client - * - * The $cache parameter influences how long files may be kept in caches, the $public parameter - * influences if this caching may happen in public proxis or in the browser cache only FS#2734 - * - * This function will abort the current script when a 304 is sent or file sending is handled - * through x-sendfile - * - * @author Andreas Gohr <andi@splitbrain.org> - * @author Ben Coburn <btcoburn@silicodon.net> - * @param string $file local file to send - * @param string $mime mime type of the file - * @param bool $dl set to true to force a browser download - * @param int $cache remaining cache time in seconds (-1 for $conf['cache'], 0 for no-cache) - * @param bool $public is this a public ressource or a private one? - */ -function sendFile($file, $mime, $dl, $cache, $public = false) { - global $conf; - // send mime headers - header("Content-Type: $mime"); - - // calculate cache times - if($cache == -1) { - $maxage = max($conf['cachetime'], 3600); // cachetime or one hour - $expires = time() + $maxage; - } else if($cache > 0) { - $maxage = $cache; // given time - $expires = time() + $maxage; - } else { // $cache == 0 - $maxage = 0; - $expires = 0; // 1970-01-01 - } - - // smart http caching headers - if($maxage) { - if($public) { - // cache publically - header('Expires: '.gmdate("D, d M Y H:i:s", $expires).' GMT'); - header('Cache-Control: public, proxy-revalidate, no-transform, max-age='.$maxage); - header('Pragma: public'); - } else { - // cache in browser - header('Expires: '.gmdate("D, d M Y H:i:s", $expires).' GMT'); - header('Cache-Control: private, no-transform, max-age='.$maxage); - header('Pragma: no-cache'); - } - } else { - // no cache at all - header('Expires: Thu, 01 Jan 1970 00:00:00 GMT'); - header('Cache-Control: no-cache, no-transform'); - header('Pragma: no-cache'); - } - - //send important headers first, script stops here if '304 Not Modified' response - $fmtime = @filemtime($file); - http_conditionalRequest($fmtime); - - //download or display? - if($dl) { - header('Content-Disposition: attachment; filename="'.utf8_basename($file).'";'); - } else { - header('Content-Disposition: inline; filename="'.utf8_basename($file).'";'); - } - - //use x-sendfile header to pass the delivery to compatible webservers - if(http_sendfile($file)) exit; - - // send file contents - $fp = @fopen($file, "rb"); - if($fp) { - http_rangeRequest($fp, filesize($file), $mime); - } else { - http_status(500); - print "Could not read $file - bad permissions?"; - } -} - -/** - * Check for media for preconditions and return correct status code - * - * READ: MEDIA, MIME, EXT, CACHE - * WRITE: MEDIA, FILE, array( STATUS, STATUSMESSAGE ) - * - * @author Gerry Weissbach <gerry.w@gammaproduction.de> - * @param $media reference to the media id - * @param $file reference to the file variable - * @returns array(STATUS, STATUSMESSAGE) - */ -function checkFileStatus(&$media, &$file, $rev = '', $width=0, $height=0) { - global $MIME, $EXT, $CACHE, $INPUT; - - //media to local file - if(preg_match('#^(https?)://#i', $media)) { - //check hash - if(substr(md5(auth_cookiesalt().$media), 0, 6) !== $INPUT->str('hash')) { - return array(412, 'Precondition Failed'); - } - //handle external images - if(strncmp($MIME, 'image/', 6) == 0) $file = media_get_from_URL($media, $EXT, $CACHE); - if(!$file) { - //download failed - redirect to original URL - return array(302, $media); - } - } else { - $media = cleanID($media); - if(empty($media)) { - return array(400, 'Bad request'); - } - // check token for resized images - if (($width || $height) && media_get_token($media, $width, $height) !== $INPUT->str('tok')) { - return array(412, 'Precondition Failed'); - } - - //check permissions (namespace only) - if(auth_quickaclcheck(getNS($media).':X') < AUTH_READ) { - return array(403, 'Forbidden'); - } - $file = mediaFN($media, $rev); - } - - //check file existance - if(!@file_exists($file)) { - return array(404, 'Not Found'); - } - - return array(200, null); -} - -/** - * Returns the wanted cachetime in seconds - * - * Resolves named constants - * - * @author Andreas Gohr <andi@splitbrain.org> - */ -function calc_cache($cache) { - global $conf; - - if(strtolower($cache) == 'nocache') return 0; //never cache - if(strtolower($cache) == 'recache') return $conf['cachetime']; //use standard cache - return -1; //cache endless -} +// END DO main //Setup VIM: ex: et ts=2 : -- cgit v1.2.3 From b051e9742775994c33cb6570e27605bbe930efe4 Mon Sep 17 00:00:00 2001 From: Christopher Smith <chris@jalakai.co.uk> Date: Fri, 22 Mar 2013 17:55:19 +0000 Subject: code changes in the rest of the code base to support testing fetch --- inc/httputils.php | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/inc/httputils.php b/inc/httputils.php index d3f3cdde2..ca60ed509 100644 --- a/inc/httputils.php +++ b/inc/httputils.php @@ -61,9 +61,9 @@ function http_conditionalRequest($timestamp){ } /** - * Let the webserver send the given file vi x-sendfile method + * Let the webserver send the given file via x-sendfile method * - * @author Chris Smith <chris.eureka@jalakai.co.uk> + * @author Chris Smith <chris@jalakai.co.uk> * @returns void or exits with previously header() commands executed */ function http_sendfile($file) { @@ -177,7 +177,8 @@ function http_rangeRequest($fh,$size,$mime){ echo HTTP_HEADER_LF.'--'.HTTP_MULTIPART_BOUNDARY.'--'.HTTP_HEADER_LF; } - // everything should be done here, exit + // everything should be done here, exit (or return if testing) + if (defined('SIMPLE_TEST')) return; exit; } @@ -320,7 +321,7 @@ function http_status($code = 200, $text = '') { $server_protocol = (isset($_SERVER['SERVER_PROTOCOL'])) ? $_SERVER['SERVER_PROTOCOL'] : false; - if(substr(php_sapi_name(), 0, 3) == 'cgi') { + if(substr(php_sapi_name(), 0, 3) == 'cgi' || defined('SIMPLE_TEST')) { header("Status: {$code} {$text}", true); } elseif($server_protocol == 'HTTP/1.1' OR $server_protocol == 'HTTP/1.0') { header($server_protocol." {$code} {$text}", true, $code); -- cgit v1.2.3 From 9894e7afaae16cc0699afbe839681e023afee65a Mon Sep 17 00:00:00 2001 From: Christopher Smith <chris@jalakai.co.uk> Date: Fri, 22 Mar 2013 17:59:23 +0000 Subject: extend TestRequest class to test fetch & detail; add a test to check it does --- _test/core/TestRequest.php | 19 ++++++++++++------- _test/tests/test/basic.test.php | 18 ++++++++++++++++++ 2 files changed, 30 insertions(+), 7 deletions(-) diff --git a/_test/core/TestRequest.php b/_test/core/TestRequest.php index 172821576..0a54910ed 100644 --- a/_test/core/TestRequest.php +++ b/_test/core/TestRequest.php @@ -18,6 +18,9 @@ function ob_start_callback($buffer) { */ class TestRequest { + private $valid_scripts = array('/doku.php', '/lib/exe/fetch.php', '/lib/exe/detail.php'); + private $script; + private $server = array(); private $session = array(); private $get = array(); @@ -27,6 +30,7 @@ class TestRequest { public function getSession($key) { return $this->session[$key]; } public function getGet($key) { return $this->get[$key]; } public function getPost($key) { return $this->post[$key]; } + public function getScript() { return $this->script; } public function setServer($key, $value) { $this->server[$key] = $value; } public function setSession($key, $value) { $this->session[$key] = $value; } @@ -70,13 +74,13 @@ class TestRequest { // now execute dokuwiki and grep the output header_remove(); ob_start('ob_start_callback'); - include(DOKU_INC.'doku.php'); + include(DOKU_INC.$this->script); ob_end_flush(); // create the response object $response = new TestResponse( $output_buffer, - headers_list() + (function_exists('xdebug_get_headers') ? xdebug_get_headers() : headers_list()) // cli sapi doesn't do headers, prefer xdebug_get_headers() which works under cli ); // reset environment @@ -102,14 +106,15 @@ class TestRequest { * @todo make this work with other end points */ protected function setUri($uri){ - if(substr($uri,0,9) != '/doku.php'){ - throw new Exception("only '/doku.php' is supported currently"); + if(!preg_match('#^('.join('|',$this->valid_scripts).')#',$uri)){ + throw new Exception("$uri \n--- only ".join(', ',$this->valid_scripts)." are supported currently"); } $params = array(); list($uri, $query) = explode('?',$uri,2); if($query) parse_str($query, $params); + $this->script = substr($uri,1); $this->get = array_merge($params, $this->get); if(count($this->get)){ $query = '?'.http_build_query($this->get, '', '&'); @@ -129,7 +134,7 @@ class TestRequest { * Simulate a POST request with the given variables * * @param array $post all the POST parameters to use - * @param string $url end URL to simulate, needs to start with /doku.php currently + * @param string $url end URL to simulate, needs to start with /doku.php, /lib/exe/fetch.php or /lib/exe/detail.php currently * @param return TestResponse */ public function post($post=array(), $uri='/doku.php') { @@ -141,8 +146,8 @@ class TestRequest { /** * Simulate a GET request with the given variables * - * @param array $GET all the POST parameters to use - * @param string $url end URL to simulate, needs to start with /doku.php currently + * @param array $GET all the GET parameters to use + * @param string $url end URL to simulate, needs to start with /doku.php, /lib/exe/fetch.php or /lib/exe/detail.php currently * @param return TestResponse */ public function get($get=array(), $uri='/doku.php') { diff --git a/_test/tests/test/basic.test.php b/_test/tests/test/basic.test.php index a0ea48a3a..c40f2d574 100644 --- a/_test/tests/test/basic.test.php +++ b/_test/tests/test/basic.test.php @@ -101,5 +101,23 @@ class InttestsBasicTest extends DokuWikiTest { $this->assertTrue(strpos($response->getContent(), 'Andreas Gohr') >= 0); } + function testScripts() { + $request = new TestRequest(); + + // doku + $response = $request->get(); + $this->assertEquals('doku.php',$request->getScript()); + + $response = $request->get(array(),'/doku.php?id=wiki:dokuwiki&test=foo'); + $this->assertEquals('doku.php',$request->getScript()); + + // fetch + $response = $request->get(array(),'/lib/exe/fetch.php?media=wiki:dokuwiki-128.png'); + $this->assertEquals('lib/exe/fetch.php',$request->getScript()); + + // detail + $response = $request->get(array(),'/lib/exe/detail.php?id=start&media=wiki:dokuwiki-128.png'); + $this->assertEquals('lib/exe/detail.php',$request->getScript()); + } } -- cgit v1.2.3 From fb0b3fbf03223c8c304608cdb32ee5c9d755eca1 Mon Sep 17 00:00:00 2001 From: Christopher Smith <chris@jalakai.co.uk> Date: Fri, 22 Mar 2013 18:01:45 +0000 Subject: update TestResponse class to return specific headers & status codes (with tests) --- _test/core/TestResponse.php | 38 ++++++++++++++++++++++++++++++++++++++ _test/tests/test/basic.test.php | 41 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+) diff --git a/_test/core/TestResponse.php b/_test/core/TestResponse.php index 6d20afb28..7cc50ee4f 100644 --- a/_test/core/TestResponse.php +++ b/_test/core/TestResponse.php @@ -41,6 +41,44 @@ class TestResponse { return $this->headers; } + /** + * @param $name string, the name of the header without the ':', e.g. 'Content-Type', 'Pragma' + * @return mixed if exactly one header, the header (string); otherwise an array of headers, empty when no headers + */ + public function getHeader($name) { + $result = array(); + foreach ($this->headers as $header) { + if (substr($header,0,strlen($name)+1) == $name.':') { + $result[] = $header; + } + } + + return count($result) == 1 ? $result[0] : $result; + } + + /** + * @return int http status code + * + * in the test environment, only status codes explicitly set by dokuwiki are likely to be returned + * this means succcessful status codes (e.g. 200 OK) will not be present, but error codes will be + */ + public function getStatusCode() { + $headers = $this->getHeader('Status'); + $code = null; + + if ($headers) { + // if there is more than one status header, use the last one + $status = is_array($headers) ? array_pop($headers) : $headers; + $matches = array(); + preg_match('/^Status: ?(\d+)/',$status,$matches); + if ($matches){ + $code = $matches[1]; + } + } + + return $code; + } + /** * Query the response for a JQuery compatible CSS selector * diff --git a/_test/tests/test/basic.test.php b/_test/tests/test/basic.test.php index c40f2d574..1c9d6d516 100644 --- a/_test/tests/test/basic.test.php +++ b/_test/tests/test/basic.test.php @@ -4,6 +4,24 @@ * @group integration */ class InttestsBasicTest extends DokuWikiTest { + + private $some_headers = array( + 'Content-Type: image/png', + 'Date: Fri, 22 Mar 2013 16:10:01 GMT', + 'X-Powered-By: PHP/5.3.15', + 'Expires: Sat, 23 Mar 2013 17:03:46 GMT', + 'Cache-Control: public, proxy-revalidate, no-transform, max-age=86400', + 'Pragma: public', + 'Last-Modified: Fri, 22 Mar 2013 01:48:28 GMT', + 'ETag: "63daab733b38c30c337229b2e587f8fb"', + 'Content-Disposition: inline; filename="fe389b0db8c1088c336abb502d2f9ae7.media.200x200.png', + 'Accept-Ranges: bytes', + 'Content-Type: image/png', + 'Content-Length: 62315', + 'Status: 200 OK', + 'Status: 404 Not Found', + ); + /** * Execute the simplest possible request and expect * a dokuwiki page which obviously has the word "DokuWiki" @@ -120,4 +138,27 @@ class InttestsBasicTest extends DokuWikiTest { $this->assertEquals('lib/exe/detail.php',$request->getScript()); } + function testHeaders(){ + $request = new TestRequest(); + $response = $request->get(array(),'/lib/exe/fetch.php?media=wiki:dokuwiki-128.png'); + $headers = $response->getHeaders(); + $this->assertTrue(!empty($headers)); + } + + function testGetHeader(){ + $response = new TestResponse('',$this->some_headers); + + $this->assertEquals('Pragma: public', $response->getHeader('Pragma')); + $this->assertEmpty($response->getHeader('Junk')); + $this->assertEquals(array('Content-Type: image/png','Content-Type: image/png'), $response->getHeader('Content-Type')); + } + + function testGetStatus(){ + $response = new TestResponse('',$this->some_headers); + $this->assertEquals(404, $response->getStatusCode()); + + $response = new TestResponse('',array_slice($this->some_headers,0,-2)); // slide off the last two headers to leave no status header + $this->assertNull($response->getStatusCode()); + } + } -- cgit v1.2.3 From f56bb251b5bdb3bb4f2793e921cf479d2402a47c Mon Sep 17 00:00:00 2001 From: Christopher Smith <chris@jalakai.co.uk> Date: Fri, 22 Mar 2013 18:02:15 +0000 Subject: add test for fetch using image tokens --- _test/tests/lib/exe/fetch_imagetoken.test.php | 83 +++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 _test/tests/lib/exe/fetch_imagetoken.test.php diff --git a/_test/tests/lib/exe/fetch_imagetoken.test.php b/_test/tests/lib/exe/fetch_imagetoken.test.php new file mode 100644 index 000000000..f94e0479b --- /dev/null +++ b/_test/tests/lib/exe/fetch_imagetoken.test.php @@ -0,0 +1,83 @@ +<?php + +class fetch_imagetoken_test extends DokuWikiTest { + + private $media = 'wiki:dokuwiki-128.png'; + private $width = 200; + private $height = 0; + + function setUp() { + parent::setUp(); + + global $conf; + $conf['sendfile'] = 0; + + global $MIME, $EXT, $CACHE, $INPUT; // variables fetch creates in global scope -- should this be in fetch? + } + + function getUri() { + $w = $this->width ? 'w='.$this->width.'&' : ''; + $h = $this->height ? 'h='.$this->height.'&' : ''; + + return '/lib/exe/fetch.php?'.$w.$h.'{%token%}media='.$this->media; + } + + function fetchResponse($token){ + $request = new TestRequest(); + return $request->get(array(),str_replace('{%token%}',$token,$this->getUri())); + } + + /** + * modified image request with valid token + * expect: header with mime-type + * expect: content + * expect: no error response + */ + function test_valid_token(){ + $valid_token = 'tok='.media_get_token($this->media, $this->width, $this->height).'&'; + $response = $this->fetchResponse($valid_token); + $this->assertTrue((bool)$response->getHeader('Content-Type')); + $this->assertTrue((bool)($response->getContent())); + + $status_code = $response->getStatusCode(); + $this->assertTrue(is_null($status_code) || (200 == $status_code)); + } + + /** + * modified image request with invalid token + * expect: 412 status code + */ + function test_invalid_token(){ + $invalid_token = 'tok='.media_get_token('junk',200,100).'&'; + $this->assertEquals(412,$this->fetchResponse($invalid_token)->getStatusCode()); + } + + /** + * modified image request with no token + * expect: 412 status code + */ + function test_missing_token(){ + $no_token = ''; + $this->assertEquals(412,$this->fetchResponse($notoken)->getStatusCode()); + } + + /** + * native image request which doesn't require a token + */ + function test_no_token_required(){ + $this->width = $this->height = 0; // no width & height, means image request at native dimensions + $any_token = 'tok='.media_get_token('junk',200,100).'&'; + $no_token = ''; + + foreach(array($any_token, $no_token) as $token) { + $response = $this->fetchResponse($token); + $this->assertTrue((bool)$response->getHeader('Content-Type')); + $this->assertTrue((bool)($response->getContent())); + + $status_code = $response->getStatusCode(); + $this->assertTrue(is_null($status_code) || (200 == $status_code)); + } + } + +} +//Setup VIM: ex: et ts=4 : -- cgit v1.2.3 From 3e8bad3a1f8b5d065e170bb12dd224bf18de6897 Mon Sep 17 00:00:00 2001 From: Christopher Smith <chris@jalakai.co.uk> Date: Fri, 22 Mar 2013 18:49:11 +0000 Subject: add some dependency checks with test skips to fetch tests and tests which use TestResponse::headers --- _test/tests/lib/exe/fetch_imagetoken.test.php | 20 ++++++++++++++++++-- _test/tests/test/basic.test.php | 10 +++++++++- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/_test/tests/lib/exe/fetch_imagetoken.test.php b/_test/tests/lib/exe/fetch_imagetoken.test.php index f94e0479b..9e5b6e4a2 100644 --- a/_test/tests/lib/exe/fetch_imagetoken.test.php +++ b/_test/tests/lib/exe/fetch_imagetoken.test.php @@ -7,6 +7,19 @@ class fetch_imagetoken_test extends DokuWikiTest { private $height = 0; function setUp() { + // check we can carry out these tests + if (!file_exists(mediaFN($this->media))) { + $this->markTestSkipped('Source image required for test'); + } + + header('X-Test: check headers working'); + $header_check = function_exists('xdebug_get_headers') ? xdebug_get_headers() : headers_list(); + if (empty($header_check)) { + $this->markTestSkipped('headers not returned, perhaps your sapi does not return headers, try xdebug'); + } else { + header_remove('X-Test'); + } + parent::setUp(); global $conf; @@ -35,7 +48,7 @@ class fetch_imagetoken_test extends DokuWikiTest { */ function test_valid_token(){ $valid_token = 'tok='.media_get_token($this->media, $this->width, $this->height).'&'; - $response = $this->fetchResponse($valid_token); + $response = $this->fetchResponse($valid_token); $this->assertTrue((bool)$response->getHeader('Content-Type')); $this->assertTrue((bool)($response->getContent())); @@ -63,16 +76,19 @@ class fetch_imagetoken_test extends DokuWikiTest { /** * native image request which doesn't require a token + * try: with a token & without a token + * expect: (for both) header with mime-type, content matching source image filesize & no error response */ function test_no_token_required(){ $this->width = $this->height = 0; // no width & height, means image request at native dimensions $any_token = 'tok='.media_get_token('junk',200,100).'&'; $no_token = ''; + $bytes = filesize(mediaFN($this->media)); foreach(array($any_token, $no_token) as $token) { $response = $this->fetchResponse($token); $this->assertTrue((bool)$response->getHeader('Content-Type')); - $this->assertTrue((bool)($response->getContent())); + $this->assertEquals(strlen($response->getContent()), $bytes); $status_code = $response->getStatusCode(); $this->assertTrue(is_null($status_code) || (200 == $status_code)); diff --git a/_test/tests/test/basic.test.php b/_test/tests/test/basic.test.php index 1c9d6d516..05778ccf9 100644 --- a/_test/tests/test/basic.test.php +++ b/_test/tests/test/basic.test.php @@ -139,6 +139,14 @@ class InttestsBasicTest extends DokuWikiTest { } function testHeaders(){ + header('X-Test: check headers working'); + $header_check = function_exists('xdebug_get_headers') ? xdebug_get_headers() : headers_list(); + if (empty($header_check)) { + $this->markTestSkipped('headers not returned, perhaps your sapi does not return headers, try xdebug'); + } else { + header_remove('X-Test'); + } + $request = new TestRequest(); $response = $request->get(array(),'/lib/exe/fetch.php?media=wiki:dokuwiki-128.png'); $headers = $response->getHeaders(); @@ -157,7 +165,7 @@ class InttestsBasicTest extends DokuWikiTest { $response = new TestResponse('',$this->some_headers); $this->assertEquals(404, $response->getStatusCode()); - $response = new TestResponse('',array_slice($this->some_headers,0,-2)); // slide off the last two headers to leave no status header + $response = new TestResponse('',array_slice($this->some_headers,0,-2)); // slice off the last two headers to leave no status header $this->assertNull($response->getStatusCode()); } -- cgit v1.2.3 From f0b65004f2ff928562c2ffdfa31b4d1e4cff3ab7 Mon Sep 17 00:00:00 2001 From: Christopher Smith <chris@jalakai.co.uk> Date: Fri, 22 Mar 2013 19:37:02 +0000 Subject: don't resize images when resize dimensions match native image dimensions --- inc/media.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/inc/media.php b/inc/media.php index 654d31cb4..fc4ad1d67 100644 --- a/inc/media.php +++ b/inc/media.php @@ -1795,6 +1795,9 @@ function media_resize_image($file, $ext, $w, $h=0){ // we wont scale up to infinity if($w > 2000 || $h > 2000) return $file; + // resize necessary? - (w,h) = native dimensions + if(($w == $info[0]) && ($h == $info[1])) return $file; + //cache $local = getCacheName($file,'.media.'.$w.'x'.$h.'.'.$ext); $mtime = @filemtime($local); // 0 if not exists -- cgit v1.2.3 From 64a19076f0888270102a3ae01cfa2bc5824ce03e Mon Sep 17 00:00:00 2001 From: Andreas Gohr <andi@splitbrain.org> Date: Sun, 24 Mar 2013 10:17:24 +0100 Subject: upgrade jQuery scripts jQuery 1.9.0 had a bug in replaceWith() that got fixed in 1.9.1 - to ensure compatibility I upgraded the whole suite to their current releases. --- lib/scripts/jquery/jquery-migrate.js | 139 +- lib/scripts/jquery/jquery-migrate.min.js | 4 +- .../images/ui-bg_flat_0_aaaaaa_40x100.png | Bin 180 -> 212 bytes .../images/ui-bg_flat_75_ffffff_40x100.png | Bin 178 -> 208 bytes .../images/ui-bg_glass_55_fbf9ee_1x400.png | Bin 120 -> 335 bytes .../images/ui-bg_glass_65_ffffff_1x400.png | Bin 105 -> 207 bytes .../images/ui-bg_glass_75_dadada_1x400.png | Bin 159 -> 262 bytes .../images/ui-bg_glass_75_e6e6e6_1x400.png | Bin 151 -> 262 bytes .../images/ui-bg_glass_95_fef1ec_1x400.png | Bin 119 -> 332 bytes .../ui-bg_highlight-soft_75_cccccc_1x100.png | Bin 101 -> 280 bytes .../images/ui-icons_222222_256x240.png | Bin 4369 -> 6922 bytes .../images/ui-icons_2e83ff_256x240.png | Bin 4369 -> 4549 bytes .../images/ui-icons_454545_256x240.png | Bin 4369 -> 6992 bytes .../images/ui-icons_888888_256x240.png | Bin 4369 -> 6999 bytes .../images/ui-icons_cd0a0a_256x240.png | Bin 4369 -> 4549 bytes lib/scripts/jquery/jquery-ui-theme/smoothness.css | 1135 ++- lib/scripts/jquery/jquery-ui.js | 7743 ++++++++++---------- lib/scripts/jquery/jquery-ui.min.js | 13 +- lib/scripts/jquery/jquery.js | 416 +- lib/scripts/jquery/jquery.min.js | 9 +- 20 files changed, 5149 insertions(+), 4310 deletions(-) diff --git a/lib/scripts/jquery/jquery-migrate.js b/lib/scripts/jquery/jquery-migrate.js index 27111d80f..e99f954e6 100644 --- a/lib/scripts/jquery/jquery-migrate.js +++ b/lib/scripts/jquery/jquery-migrate.js @@ -1,10 +1,11 @@ /*! - * jQuery Migrate - v1.0.0 - 2013-01-14 + * jQuery Migrate - v1.1.1 - 2013-02-16 * https://github.com/jquery/jquery-migrate * Copyright 2005, 2013 jQuery Foundation, Inc. and other contributors; Licensed MIT */ (function( jQuery, window, undefined ) { -"use strict"; +// See http://bugs.jquery.com/ticket/13335 +// "use strict"; var warnedAbout = {}; @@ -15,6 +16,16 @@ jQuery.migrateWarnings = []; // Set to true to prevent console output; migrateWarnings still maintained // jQuery.migrateMute = false; +// Show a message on the console so devs know we're active +if ( !jQuery.migrateMute && window.console && console.log ) { + console.log("JQMIGRATE: Logging is active"); +} + +// Set to false to disable traces that appear with warnings +if ( jQuery.migrateTrace === undefined ) { + jQuery.migrateTrace = true; +} + // Forget any warnings we've already given; public jQuery.migrateReset = function() { warnedAbout = {}; @@ -27,6 +38,9 @@ function migrateWarn( msg) { jQuery.migrateWarnings.push( msg ); if ( window.console && console.warn && !jQuery.migrateMute ) { console.warn( "JQMIGRATE: " + msg ); + if ( jQuery.migrateTrace && console.trace ) { + console.trace(); + } } } } @@ -65,8 +79,8 @@ if ( document.compatMode === "BackCompat" ) { } -var attrFn = {}, - attr = jQuery.attr, +var attrFn = jQuery( "<input/>", { size: 1 } ).attr("size") && jQuery.attrFn, + oldAttr = jQuery.attr, valueAttrGet = jQuery.attrHooks.value && jQuery.attrHooks.value.get || function() { return null; }, valueAttrSet = jQuery.attrHooks.value && jQuery.attrHooks.value.set || @@ -77,21 +91,27 @@ var attrFn = {}, ruseDefault = /^(?:checked|selected)$/i; // jQuery.attrFn -migrateWarnProp( jQuery, "attrFn", attrFn, "jQuery.attrFn is deprecated" ); +migrateWarnProp( jQuery, "attrFn", attrFn || {}, "jQuery.attrFn is deprecated" ); jQuery.attr = function( elem, name, value, pass ) { var lowerName = name.toLowerCase(), nType = elem && elem.nodeType; if ( pass ) { - migrateWarn("jQuery.fn.attr( props, pass ) is deprecated"); - if ( elem && !rnoAttrNodeType.test( nType ) && jQuery.isFunction( jQuery.fn[ name ] ) ) { + // Since pass is used internally, we only warn for new jQuery + // versions where there isn't a pass arg in the formal params + if ( oldAttr.length < 4 ) { + migrateWarn("jQuery.fn.attr( props, pass ) is deprecated"); + } + if ( elem && !rnoAttrNodeType.test( nType ) && + (attrFn ? name in attrFn : jQuery.isFunction(jQuery.fn[name])) ) { return jQuery( elem )[ name ]( value ); } } - // Warn if user tries to set `type` since it breaks on IE 6/7/8 - if ( name === "type" && value !== undefined && rnoType.test( elem.nodeName ) ) { + // Warn if user tries to set `type`, since it breaks on IE 6/7/8; by checking + // for disconnected elements we don't warn on $( "<button>", { type: "button" } ). + if ( name === "type" && value !== undefined && rnoType.test( elem.nodeName ) && elem.parentNode ) { migrateWarn("Can't change the 'type' of an input or button in IE 6/7/8"); } @@ -131,11 +151,11 @@ jQuery.attr = function( elem, name, value, pass ) { // Warn only for attributes that can remain distinct from their properties post-1.9 if ( ruseDefault.test( lowerName ) ) { - migrateWarn( "jQuery.fn.attr(" + lowerName + ") may use property instead of attribute" ); + migrateWarn( "jQuery.fn.attr('" + lowerName + "') may use property instead of attribute" ); } } - return attr.call( jQuery, elem, name, value ); + return oldAttr.call( jQuery, elem, name, value ); }; // attrHooks: value @@ -146,7 +166,7 @@ jQuery.attrHooks.value = { return valueAttrGet.apply( this, arguments ); } if ( nodeName !== "input" && nodeName !== "option" ) { - migrateWarn("property-based jQuery.fn.attr('value') is deprecated"); + migrateWarn("jQuery.fn.attr('value') no longer gets properties"); } return name in elem ? elem.value : @@ -158,7 +178,7 @@ jQuery.attrHooks.value = { return valueAttrSet.apply( this, arguments ); } if ( nodeName !== "input" && nodeName !== "option" ) { - migrateWarn("property-based jQuery.fn.attr('value', val) is deprecated"); + migrateWarn("jQuery.fn.attr('value', val) no longer sets properties"); } // Does not return so that setAttribute is also used elem.value = value; @@ -168,8 +188,9 @@ jQuery.attrHooks.value = { var matched, browser, oldInit = jQuery.fn.init, - // Note this does NOT include the # XSS fix from 1.7! - rquickExpr = /^(?:.*(<[\w\W]+>)[^>]*|#([\w\-]*))$/; + oldParseJSON = jQuery.parseJSON, + // Note this does NOT include the #9521 XSS fix from 1.7! + rquickExpr = /^(?:[^<]*(<[\w\W]+>)[^>]*|#([\w\-]*))$/; // $(html) "looks like html" rule change jQuery.fn.init = function( selector, context, rootjQuery ) { @@ -195,6 +216,15 @@ jQuery.fn.init = function( selector, context, rootjQuery ) { }; jQuery.fn.init.prototype = jQuery.fn; +// Let $.parseJSON(falsy_value) return null +jQuery.parseJSON = function( json ) { + if ( !json && json !== null ) { + migrateWarn("jQuery.parseJSON requires a valid JSON string"); + return null; + } + return oldParseJSON.apply( this, arguments ); +}; + jQuery.uaMatch = function( ua ) { ua = ua.toLowerCase(); @@ -211,25 +241,28 @@ jQuery.uaMatch = function( ua ) { }; }; -matched = jQuery.uaMatch( navigator.userAgent ); -browser = {}; +// Don't clobber any existing jQuery.browser in case it's different +if ( !jQuery.browser ) { + matched = jQuery.uaMatch( navigator.userAgent ); + browser = {}; -if ( matched.browser ) { - browser[ matched.browser ] = true; - browser.version = matched.version; -} + if ( matched.browser ) { + browser[ matched.browser ] = true; + browser.version = matched.version; + } -// Chrome is Webkit, but Webkit is also Safari. -if ( browser.chrome ) { - browser.webkit = true; -} else if ( browser.webkit ) { - browser.safari = true; -} + // Chrome is Webkit, but Webkit is also Safari. + if ( browser.chrome ) { + browser.webkit = true; + } else if ( browser.webkit ) { + browser.safari = true; + } -jQuery.browser = browser; + jQuery.browser = browser; +} // Warn if the code tries to get jQuery.browser -migrateWarnProp( jQuery, "browser", browser, "jQuery.browser is deprecated" ); +migrateWarnProp( jQuery, "browser", jQuery.browser, "jQuery.browser is deprecated" ); jQuery.sub = function() { function jQuerySub( selector, context ) { @@ -254,6 +287,14 @@ jQuery.sub = function() { }; +// Ensure that $.ajax gets the new parseJSON defined in core.js +jQuery.ajaxSetup({ + converters: { + "text json": jQuery.parseJSON + } +}); + + var oldFnData = jQuery.fn.data; jQuery.fn.data = function( name ) { @@ -274,8 +315,7 @@ jQuery.fn.data = function( name ) { var rscriptType = /\/(java|ecma)script/i, - oldSelf = jQuery.fn.andSelf || jQuery.fn.addBack, - oldFragment = jQuery.buildFragment; + oldSelf = jQuery.fn.andSelf || jQuery.fn.addBack; jQuery.fn.andSelf = function() { migrateWarn("jQuery.fn.andSelf() replaced by jQuery.fn.addBack()"); @@ -332,35 +372,6 @@ if ( !jQuery.clean ) { }; } -jQuery.buildFragment = function( elems, context, scripts, selection ) { - var ret, - warning = "jQuery.buildFragment() is deprecated"; - - // Set context per 1.8 logic - context = context || document; - context = !context.nodeType && context[0] || context; - context = context.ownerDocument || context; - - try { - ret = oldFragment.call( jQuery, elems, context, scripts, selection ); - - // jQuery < 1.8 required arrayish context; jQuery 1.9 fails on it - } catch( x ) { - ret = oldFragment.call( jQuery, elems, context.nodeType ? [ context ] : context[ 0 ], scripts, selection ); - - // Success from tweaking context means buildFragment was called by the user - migrateWarn( warning ); - } - - // jQuery < 1.9 returned an object instead of the fragment itself - if ( !ret.fragment ) { - migrateWarnProp( ret, "fragment", ret, warning ); - migrateWarnProp( ret, "cacheable", false, warning ); - } - - return ret; -}; - var eventAdd = jQuery.event.add, eventRemove = jQuery.event.remove, eventTrigger = jQuery.event.trigger, @@ -371,7 +382,7 @@ var eventAdd = jQuery.event.add, rajaxEvent = new RegExp( "\\b(?:" + ajaxEvents + ")\\b" ), rhoverHack = /(?:^|\s)hover(\.\S+|)\b/, hoverHack = function( events ) { - if ( typeof( events ) != "string" || jQuery.event.special.hover ) { + if ( typeof( events ) !== "string" || jQuery.event.special.hover ) { return events; } if ( rhoverHack.test( events ) ) { @@ -386,7 +397,9 @@ if ( jQuery.event.props && jQuery.event.props[ 0 ] !== "attrChange" ) { } // Undocumented jQuery.event.handle was "deprecated" in jQuery 1.7 -migrateWarnProp( jQuery.event, "handle", jQuery.event.dispatch, "jQuery.event.handle is undocumented and deprecated" ); +if ( jQuery.event.dispatch ) { + migrateWarnProp( jQuery.event, "handle", jQuery.event.dispatch, "jQuery.event.handle is undocumented and deprecated" ); +} // Support for 'hover' pseudo-event and ajax event warnings jQuery.event.add = function( elem, types, handler, data, selector ){ @@ -464,7 +477,7 @@ jQuery.fn.die = function( types, fn ) { // Turn global events into document-triggered events jQuery.event.trigger = function( event, data, elem, onlyHandlers ){ - if ( !elem & !rajaxEvent.test( event ) ) { + if ( !elem && !rajaxEvent.test( event ) ) { migrateWarn( "Global events are undocumented and deprecated" ); } return eventTrigger.call( this, event, data, elem || document, onlyHandlers ); diff --git a/lib/scripts/jquery/jquery-migrate.min.js b/lib/scripts/jquery/jquery-migrate.min.js index e6782b67f..759f35e85 100644 --- a/lib/scripts/jquery/jquery-migrate.min.js +++ b/lib/scripts/jquery/jquery-migrate.min.js @@ -1,3 +1,3 @@ -/*! jQuery Migrate v1.0.0 | (c) 2005, 2013 jQuery Foundation, Inc. and other contributors | jquery.org/license */ -jQuery.migrateMute===void 0&&(jQuery.migrateMute=!0),function(e,t,n){"use strict";function r(n){o[n]||(o[n]=!0,e.migrateWarnings.push(n),t.console&&console.warn&&!e.migrateMute&&console.warn("JQMIGRATE: "+n))}function a(t,a,o,i){if(Object.defineProperty)try{return Object.defineProperty(t,a,{configurable:!0,enumerable:!0,get:function(){return r(i),o},set:function(e){r(i),o=e}}),n}catch(u){}e._definePropertyBroken=!0,t[a]=o}var o={};e.migrateWarnings=[],e.migrateReset=function(){o={},e.migrateWarnings.length=0},"BackCompat"===document.compatMode&&r("jQuery is not compatible with Quirks Mode");var i={},u=e.attr,s=e.attrHooks.value&&e.attrHooks.value.get||function(){return null},c=e.attrHooks.value&&e.attrHooks.value.set||function(){return n},d=/^(?:input|button)$/i,l=/^[238]$/,p=/^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,f=/^(?:checked|selected)$/i;a(e,"attrFn",i,"jQuery.attrFn is deprecated"),e.attr=function(t,a,o,i){var s=a.toLowerCase(),c=t&&t.nodeType;return i&&(r("jQuery.fn.attr( props, pass ) is deprecated"),t&&!l.test(c)&&e.isFunction(e.fn[a]))?e(t)[a](o):("type"===a&&o!==n&&d.test(t.nodeName)&&r("Can't change the 'type' of an input or button in IE 6/7/8"),!e.attrHooks[s]&&p.test(s)&&(e.attrHooks[s]={get:function(t,r){var a,o=e.prop(t,r);return o===!0||"boolean"!=typeof o&&(a=t.getAttributeNode(r))&&a.nodeValue!==!1?r.toLowerCase():n},set:function(t,n,r){var a;return n===!1?e.removeAttr(t,r):(a=e.propFix[r]||r,a in t&&(t[a]=!0),t.setAttribute(r,r.toLowerCase())),r}},f.test(s)&&r("jQuery.fn.attr("+s+") may use property instead of attribute")),u.call(e,t,a,o))},e.attrHooks.value={get:function(e,t){var n=(e.nodeName||"").toLowerCase();return"button"===n?s.apply(this,arguments):("input"!==n&&"option"!==n&&r("property-based jQuery.fn.attr('value') is deprecated"),t in e?e.value:null)},set:function(e,t){var a=(e.nodeName||"").toLowerCase();return"button"===a?c.apply(this,arguments):("input"!==a&&"option"!==a&&r("property-based jQuery.fn.attr('value', val) is deprecated"),e.value=t,n)}};var g,h,m=e.fn.init,v=/^(?:.*(<[\w\W]+>)[^>]*|#([\w\-]*))$/;e.fn.init=function(t,n,a){var o;return t&&"string"==typeof t&&!e.isPlainObject(n)&&(o=v.exec(t))&&o[1]&&("<"!==t.charAt(0)&&r("$(html) HTML strings must start with '<' character"),n&&n.context&&(n=n.context),e.parseHTML)?m.call(this,e.parseHTML(e.trim(t),n,!0),n,a):m.apply(this,arguments)},e.fn.init.prototype=e.fn,e.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)||0>e.indexOf("compatible")&&/(mozilla)(?:.*? rv:([\w.]+)|)/.exec(e)||[];return{browser:t[1]||"",version:t[2]||"0"}},g=e.uaMatch(navigator.userAgent),h={},g.browser&&(h[g.browser]=!0,h.version=g.version),h.chrome?h.webkit=!0:h.webkit&&(h.safari=!0),e.browser=h,a(e,"browser",h,"jQuery.browser is deprecated"),e.sub=function(){function t(e,n){return new t.fn.init(e,n)}e.extend(!0,t,this),t.superclass=this,t.fn=t.prototype=this(),t.fn.constructor=t,t.sub=this.sub,t.fn.init=function(r,a){return a&&a instanceof e&&!(a instanceof t)&&(a=t(a)),e.fn.init.call(this,r,a,n)},t.fn.init.prototype=t.fn;var n=t(document);return r("jQuery.sub() is deprecated"),t};var y=e.fn.data;e.fn.data=function(t){var a,o,i=this[0];return!i||"events"!==t||1!==arguments.length||(a=e.data(i,t),o=e._data(i,t),a!==n&&a!==o||o===n)?y.apply(this,arguments):(r("Use of jQuery.fn.data('events') is deprecated"),o)};var b=/\/(java|ecma)script/i,w=e.fn.andSelf||e.fn.addBack,j=e.buildFragment;e.fn.andSelf=function(){return r("jQuery.fn.andSelf() replaced by jQuery.fn.addBack()"),w.apply(this,arguments)},e.clean||(e.clean=function(t,a,o,i){a=a||document,a=!a.nodeType&&a[0]||a,a=a.ownerDocument||a,r("jQuery.clean() is deprecated");var u,s,c,d,l=[];if(e.merge(l,e.buildFragment(t,a).childNodes),o)for(c=function(e){return!e.type||b.test(e.type)?i?i.push(e.parentNode?e.parentNode.removeChild(e):e):o.appendChild(e):n},u=0;null!=(s=l[u]);u++)e.nodeName(s,"script")&&c(s)||(o.appendChild(s),s.getElementsByTagName!==n&&(d=e.grep(e.merge([],s.getElementsByTagName("script")),c),l.splice.apply(l,[u+1,0].concat(d)),u+=d.length));return l}),e.buildFragment=function(t,n,o,i){var u,s="jQuery.buildFragment() is deprecated";n=n||document,n=!n.nodeType&&n[0]||n,n=n.ownerDocument||n;try{u=j.call(e,t,n,o,i)}catch(c){u=j.call(e,t,n.nodeType?[n]:n[0],o,i),r(s)}return u.fragment||(a(u,"fragment",u,s),a(u,"cacheable",!1,s)),u};var Q=e.event.add,x=e.event.remove,k=e.event.trigger,C=e.fn.toggle,N=e.fn.live,T=e.fn.die,H="ajaxStart|ajaxStop|ajaxSend|ajaxComplete|ajaxError|ajaxSuccess",M=RegExp("\\b(?:"+H+")\\b"),F=/(?:^|\s)hover(\.\S+|)\b/,A=function(t){return"string"!=typeof t||e.event.special.hover?t:(F.test(t)&&r("'hover' pseudo-event is deprecated, use 'mouseenter mouseleave'"),t&&t.replace(F,"mouseenter$1 mouseleave$1"))};e.event.props&&"attrChange"!==e.event.props[0]&&e.event.props.unshift("attrChange","attrName","relatedNode","srcElement"),a(e.event,"handle",e.event.dispatch,"jQuery.event.handle is undocumented and deprecated"),e.event.add=function(e,t,n,a,o){e!==document&&M.test(t)&&r("AJAX events should be attached to document: "+t),Q.call(this,e,A(t||""),n,a,o)},e.event.remove=function(e,t,n,r,a){x.call(this,e,A(t)||"",n,r,a)},e.fn.error=function(){var e=Array.prototype.slice.call(arguments,0);return r("jQuery.fn.error() is deprecated"),e.splice(0,0,"error"),arguments.length?this.bind.apply(this,e):(this.triggerHandler.apply(this,e),this)},e.fn.toggle=function(t,n){if(!e.isFunction(t)||!e.isFunction(n))return C.apply(this,arguments);r("jQuery.fn.toggle(handler, handler...) is deprecated");var a=arguments,o=t.guid||e.guid++,i=0,u=function(n){var r=(e._data(this,"lastToggle"+t.guid)||0)%i;return e._data(this,"lastToggle"+t.guid,r+1),n.preventDefault(),a[r].apply(this,arguments)||!1};for(u.guid=o;a.length>i;)a[i++].guid=o;return this.click(u)},e.fn.live=function(t,n,a){return r("jQuery.fn.live() is deprecated"),N?N.apply(this,arguments):(e(this.context).on(t,this.selector,n,a),this)},e.fn.die=function(t,n){return r("jQuery.fn.die() is deprecated"),T?T.apply(this,arguments):(e(this.context).off(t,this.selector||"**",n),this)},e.event.trigger=function(e,t,n,a){return!n&!M.test(e)&&r("Global events are undocumented and deprecated"),k.call(this,e,t,n||document,a)},e.each(H.split("|"),function(t,n){e.event.special[n]={setup:function(){var t=this;return t!==document&&(e.event.add(document,n+"."+e.guid,function(){e.event.trigger(n,null,t,!0)}),e._data(this,n,e.guid++)),!1},teardown:function(){return this!==document&&e.event.remove(document,n+"."+e._data(this,n)),!1}}})}(jQuery,window); +/*! jQuery Migrate v1.1.1 | (c) 2005, 2013 jQuery Foundation, Inc. and other contributors | jquery.org/license */ +jQuery.migrateMute===void 0&&(jQuery.migrateMute=!0),function(e,t,n){function r(n){o[n]||(o[n]=!0,e.migrateWarnings.push(n),t.console&&console.warn&&!e.migrateMute&&(console.warn("JQMIGRATE: "+n),e.migrateTrace&&console.trace&&console.trace()))}function a(t,a,o,i){if(Object.defineProperty)try{return Object.defineProperty(t,a,{configurable:!0,enumerable:!0,get:function(){return r(i),o},set:function(e){r(i),o=e}}),n}catch(s){}e._definePropertyBroken=!0,t[a]=o}var o={};e.migrateWarnings=[],!e.migrateMute&&t.console&&console.log&&console.log("JQMIGRATE: Logging is active"),e.migrateTrace===n&&(e.migrateTrace=!0),e.migrateReset=function(){o={},e.migrateWarnings.length=0},"BackCompat"===document.compatMode&&r("jQuery is not compatible with Quirks Mode");var i=e("<input/>",{size:1}).attr("size")&&e.attrFn,s=e.attr,u=e.attrHooks.value&&e.attrHooks.value.get||function(){return null},c=e.attrHooks.value&&e.attrHooks.value.set||function(){return n},l=/^(?:input|button)$/i,d=/^[238]$/,p=/^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,f=/^(?:checked|selected)$/i;a(e,"attrFn",i||{},"jQuery.attrFn is deprecated"),e.attr=function(t,a,o,u){var c=a.toLowerCase(),g=t&&t.nodeType;return u&&(4>s.length&&r("jQuery.fn.attr( props, pass ) is deprecated"),t&&!d.test(g)&&(i?a in i:e.isFunction(e.fn[a])))?e(t)[a](o):("type"===a&&o!==n&&l.test(t.nodeName)&&t.parentNode&&r("Can't change the 'type' of an input or button in IE 6/7/8"),!e.attrHooks[c]&&p.test(c)&&(e.attrHooks[c]={get:function(t,r){var a,o=e.prop(t,r);return o===!0||"boolean"!=typeof o&&(a=t.getAttributeNode(r))&&a.nodeValue!==!1?r.toLowerCase():n},set:function(t,n,r){var a;return n===!1?e.removeAttr(t,r):(a=e.propFix[r]||r,a in t&&(t[a]=!0),t.setAttribute(r,r.toLowerCase())),r}},f.test(c)&&r("jQuery.fn.attr('"+c+"') may use property instead of attribute")),s.call(e,t,a,o))},e.attrHooks.value={get:function(e,t){var n=(e.nodeName||"").toLowerCase();return"button"===n?u.apply(this,arguments):("input"!==n&&"option"!==n&&r("jQuery.fn.attr('value') no longer gets properties"),t in e?e.value:null)},set:function(e,t){var a=(e.nodeName||"").toLowerCase();return"button"===a?c.apply(this,arguments):("input"!==a&&"option"!==a&&r("jQuery.fn.attr('value', val) no longer sets properties"),e.value=t,n)}};var g,h,v=e.fn.init,m=e.parseJSON,y=/^(?:[^<]*(<[\w\W]+>)[^>]*|#([\w\-]*))$/;e.fn.init=function(t,n,a){var o;return t&&"string"==typeof t&&!e.isPlainObject(n)&&(o=y.exec(t))&&o[1]&&("<"!==t.charAt(0)&&r("$(html) HTML strings must start with '<' character"),n&&n.context&&(n=n.context),e.parseHTML)?v.call(this,e.parseHTML(e.trim(t),n,!0),n,a):v.apply(this,arguments)},e.fn.init.prototype=e.fn,e.parseJSON=function(e){return e||null===e?m.apply(this,arguments):(r("jQuery.parseJSON requires a valid JSON string"),null)},e.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)||0>e.indexOf("compatible")&&/(mozilla)(?:.*? rv:([\w.]+)|)/.exec(e)||[];return{browser:t[1]||"",version:t[2]||"0"}},e.browser||(g=e.uaMatch(navigator.userAgent),h={},g.browser&&(h[g.browser]=!0,h.version=g.version),h.chrome?h.webkit=!0:h.webkit&&(h.safari=!0),e.browser=h),a(e,"browser",e.browser,"jQuery.browser is deprecated"),e.sub=function(){function t(e,n){return new t.fn.init(e,n)}e.extend(!0,t,this),t.superclass=this,t.fn=t.prototype=this(),t.fn.constructor=t,t.sub=this.sub,t.fn.init=function(r,a){return a&&a instanceof e&&!(a instanceof t)&&(a=t(a)),e.fn.init.call(this,r,a,n)},t.fn.init.prototype=t.fn;var n=t(document);return r("jQuery.sub() is deprecated"),t},e.ajaxSetup({converters:{"text json":e.parseJSON}});var b=e.fn.data;e.fn.data=function(t){var a,o,i=this[0];return!i||"events"!==t||1!==arguments.length||(a=e.data(i,t),o=e._data(i,t),a!==n&&a!==o||o===n)?b.apply(this,arguments):(r("Use of jQuery.fn.data('events') is deprecated"),o)};var j=/\/(java|ecma)script/i,w=e.fn.andSelf||e.fn.addBack;e.fn.andSelf=function(){return r("jQuery.fn.andSelf() replaced by jQuery.fn.addBack()"),w.apply(this,arguments)},e.clean||(e.clean=function(t,a,o,i){a=a||document,a=!a.nodeType&&a[0]||a,a=a.ownerDocument||a,r("jQuery.clean() is deprecated");var s,u,c,l,d=[];if(e.merge(d,e.buildFragment(t,a).childNodes),o)for(c=function(e){return!e.type||j.test(e.type)?i?i.push(e.parentNode?e.parentNode.removeChild(e):e):o.appendChild(e):n},s=0;null!=(u=d[s]);s++)e.nodeName(u,"script")&&c(u)||(o.appendChild(u),u.getElementsByTagName!==n&&(l=e.grep(e.merge([],u.getElementsByTagName("script")),c),d.splice.apply(d,[s+1,0].concat(l)),s+=l.length));return d});var Q=e.event.add,x=e.event.remove,k=e.event.trigger,N=e.fn.toggle,C=e.fn.live,S=e.fn.die,T="ajaxStart|ajaxStop|ajaxSend|ajaxComplete|ajaxError|ajaxSuccess",M=RegExp("\\b(?:"+T+")\\b"),H=/(?:^|\s)hover(\.\S+|)\b/,A=function(t){return"string"!=typeof t||e.event.special.hover?t:(H.test(t)&&r("'hover' pseudo-event is deprecated, use 'mouseenter mouseleave'"),t&&t.replace(H,"mouseenter$1 mouseleave$1"))};e.event.props&&"attrChange"!==e.event.props[0]&&e.event.props.unshift("attrChange","attrName","relatedNode","srcElement"),e.event.dispatch&&a(e.event,"handle",e.event.dispatch,"jQuery.event.handle is undocumented and deprecated"),e.event.add=function(e,t,n,a,o){e!==document&&M.test(t)&&r("AJAX events should be attached to document: "+t),Q.call(this,e,A(t||""),n,a,o)},e.event.remove=function(e,t,n,r,a){x.call(this,e,A(t)||"",n,r,a)},e.fn.error=function(){var e=Array.prototype.slice.call(arguments,0);return r("jQuery.fn.error() is deprecated"),e.splice(0,0,"error"),arguments.length?this.bind.apply(this,e):(this.triggerHandler.apply(this,e),this)},e.fn.toggle=function(t,n){if(!e.isFunction(t)||!e.isFunction(n))return N.apply(this,arguments);r("jQuery.fn.toggle(handler, handler...) is deprecated");var a=arguments,o=t.guid||e.guid++,i=0,s=function(n){var r=(e._data(this,"lastToggle"+t.guid)||0)%i;return e._data(this,"lastToggle"+t.guid,r+1),n.preventDefault(),a[r].apply(this,arguments)||!1};for(s.guid=o;a.length>i;)a[i++].guid=o;return this.click(s)},e.fn.live=function(t,n,a){return r("jQuery.fn.live() is deprecated"),C?C.apply(this,arguments):(e(this.context).on(t,this.selector,n,a),this)},e.fn.die=function(t,n){return r("jQuery.fn.die() is deprecated"),S?S.apply(this,arguments):(e(this.context).off(t,this.selector||"**",n),this)},e.event.trigger=function(e,t,n,a){return n||M.test(e)||r("Global events are undocumented and deprecated"),k.call(this,e,t,n||document,a)},e.each(T.split("|"),function(t,n){e.event.special[n]={setup:function(){var t=this;return t!==document&&(e.event.add(document,n+"."+e.guid,function(){e.event.trigger(n,null,t,!0)}),e._data(this,n,e.guid++)),!1},teardown:function(){return this!==document&&e.event.remove(document,n+"."+e._data(this,n)),!1}}})}(jQuery,window); //@ sourceMappingURL=dist/jquery-migrate.min.map \ No newline at end of file diff --git a/lib/scripts/jquery/jquery-ui-theme/images/ui-bg_flat_0_aaaaaa_40x100.png b/lib/scripts/jquery/jquery-ui-theme/images/ui-bg_flat_0_aaaaaa_40x100.png index 5b5dab2ab..87f812d7d 100644 Binary files a/lib/scripts/jquery/jquery-ui-theme/images/ui-bg_flat_0_aaaaaa_40x100.png and b/lib/scripts/jquery/jquery-ui-theme/images/ui-bg_flat_0_aaaaaa_40x100.png differ diff --git a/lib/scripts/jquery/jquery-ui-theme/images/ui-bg_flat_75_ffffff_40x100.png b/lib/scripts/jquery/jquery-ui-theme/images/ui-bg_flat_75_ffffff_40x100.png index ac8b229af..4cb0d6d10 100644 Binary files a/lib/scripts/jquery/jquery-ui-theme/images/ui-bg_flat_75_ffffff_40x100.png and b/lib/scripts/jquery/jquery-ui-theme/images/ui-bg_flat_75_ffffff_40x100.png differ diff --git a/lib/scripts/jquery/jquery-ui-theme/images/ui-bg_glass_55_fbf9ee_1x400.png b/lib/scripts/jquery/jquery-ui-theme/images/ui-bg_glass_55_fbf9ee_1x400.png index ad3d6346e..bfe897458 100644 Binary files a/lib/scripts/jquery/jquery-ui-theme/images/ui-bg_glass_55_fbf9ee_1x400.png and b/lib/scripts/jquery/jquery-ui-theme/images/ui-bg_glass_55_fbf9ee_1x400.png differ diff --git a/lib/scripts/jquery/jquery-ui-theme/images/ui-bg_glass_65_ffffff_1x400.png b/lib/scripts/jquery/jquery-ui-theme/images/ui-bg_glass_65_ffffff_1x400.png index 42ccba269..168a18215 100644 Binary files a/lib/scripts/jquery/jquery-ui-theme/images/ui-bg_glass_65_ffffff_1x400.png and b/lib/scripts/jquery/jquery-ui-theme/images/ui-bg_glass_65_ffffff_1x400.png differ diff --git a/lib/scripts/jquery/jquery-ui-theme/images/ui-bg_glass_75_dadada_1x400.png b/lib/scripts/jquery/jquery-ui-theme/images/ui-bg_glass_75_dadada_1x400.png index 1d43b47e6..25bf099b9 100644 Binary files a/lib/scripts/jquery/jquery-ui-theme/images/ui-bg_glass_75_dadada_1x400.png and b/lib/scripts/jquery/jquery-ui-theme/images/ui-bg_glass_75_dadada_1x400.png differ diff --git a/lib/scripts/jquery/jquery-ui-theme/images/ui-bg_glass_75_e6e6e6_1x400.png b/lib/scripts/jquery/jquery-ui-theme/images/ui-bg_glass_75_e6e6e6_1x400.png index 38df73a21..c5dc70aea 100644 Binary files a/lib/scripts/jquery/jquery-ui-theme/images/ui-bg_glass_75_e6e6e6_1x400.png and b/lib/scripts/jquery/jquery-ui-theme/images/ui-bg_glass_75_e6e6e6_1x400.png differ diff --git a/lib/scripts/jquery/jquery-ui-theme/images/ui-bg_glass_95_fef1ec_1x400.png b/lib/scripts/jquery/jquery-ui-theme/images/ui-bg_glass_95_fef1ec_1x400.png index 4443fdc1a..bf1f16451 100644 Binary files a/lib/scripts/jquery/jquery-ui-theme/images/ui-bg_glass_95_fef1ec_1x400.png and b/lib/scripts/jquery/jquery-ui-theme/images/ui-bg_glass_95_fef1ec_1x400.png differ diff --git a/lib/scripts/jquery/jquery-ui-theme/images/ui-bg_highlight-soft_75_cccccc_1x100.png b/lib/scripts/jquery/jquery-ui-theme/images/ui-bg_highlight-soft_75_cccccc_1x100.png index 7c9fa6c6e..11c184168 100644 Binary files a/lib/scripts/jquery/jquery-ui-theme/images/ui-bg_highlight-soft_75_cccccc_1x100.png and b/lib/scripts/jquery/jquery-ui-theme/images/ui-bg_highlight-soft_75_cccccc_1x100.png differ diff --git a/lib/scripts/jquery/jquery-ui-theme/images/ui-icons_222222_256x240.png b/lib/scripts/jquery/jquery-ui-theme/images/ui-icons_222222_256x240.png index b273ff111..294330201 100644 Binary files a/lib/scripts/jquery/jquery-ui-theme/images/ui-icons_222222_256x240.png and b/lib/scripts/jquery/jquery-ui-theme/images/ui-icons_222222_256x240.png differ diff --git a/lib/scripts/jquery/jquery-ui-theme/images/ui-icons_2e83ff_256x240.png b/lib/scripts/jquery/jquery-ui-theme/images/ui-icons_2e83ff_256x240.png index 09d1cdc85..25dfde1f4 100644 Binary files a/lib/scripts/jquery/jquery-ui-theme/images/ui-icons_2e83ff_256x240.png and b/lib/scripts/jquery/jquery-ui-theme/images/ui-icons_2e83ff_256x240.png differ diff --git a/lib/scripts/jquery/jquery-ui-theme/images/ui-icons_454545_256x240.png b/lib/scripts/jquery/jquery-ui-theme/images/ui-icons_454545_256x240.png index 59bd45b90..0063819c4 100644 Binary files a/lib/scripts/jquery/jquery-ui-theme/images/ui-icons_454545_256x240.png and b/lib/scripts/jquery/jquery-ui-theme/images/ui-icons_454545_256x240.png differ diff --git a/lib/scripts/jquery/jquery-ui-theme/images/ui-icons_888888_256x240.png b/lib/scripts/jquery/jquery-ui-theme/images/ui-icons_888888_256x240.png index 6d02426c1..53aaf6f30 100644 Binary files a/lib/scripts/jquery/jquery-ui-theme/images/ui-icons_888888_256x240.png and b/lib/scripts/jquery/jquery-ui-theme/images/ui-icons_888888_256x240.png differ diff --git a/lib/scripts/jquery/jquery-ui-theme/images/ui-icons_cd0a0a_256x240.png b/lib/scripts/jquery/jquery-ui-theme/images/ui-icons_cd0a0a_256x240.png index 2ab019b73..145e3d3c6 100644 Binary files a/lib/scripts/jquery/jquery-ui-theme/images/ui-icons_cd0a0a_256x240.png and b/lib/scripts/jquery/jquery-ui-theme/images/ui-icons_cd0a0a_256x240.png differ diff --git a/lib/scripts/jquery/jquery-ui-theme/smoothness.css b/lib/scripts/jquery/jquery-ui-theme/smoothness.css index 9a5d765ca..bd2adbde8 100644 --- a/lib/scripts/jquery/jquery-ui-theme/smoothness.css +++ b/lib/scripts/jquery/jquery-ui-theme/smoothness.css @@ -1,229 +1,774 @@ -/*! jQuery UI - v1.9.2 - 2012-11-23 +/*! jQuery UI - v1.10.2 - 2013-03-14 * http://jqueryui.com -* Includes: jquery.ui.core.css, jquery.ui.accordion.css, jquery.ui.autocomplete.css, jquery.ui.button.css, jquery.ui.datepicker.css, jquery.ui.dialog.css, jquery.ui.menu.css, jquery.ui.progressbar.css, jquery.ui.resizable.css, jquery.ui.selectable.css, jquery.ui.slider.css, jquery.ui.spinner.css, jquery.ui.tabs.css, jquery.ui.tooltip.css, jquery.ui.theme.css -* Copyright 2012 jQuery Foundation and other contributors; Licensed MIT */ +* Includes: jquery.ui.core.css, jquery.ui.accordion.css, jquery.ui.autocomplete.css, jquery.ui.button.css, jquery.ui.datepicker.css, jquery.ui.dialog.css, jquery.ui.menu.css, jquery.ui.progressbar.css, jquery.ui.resizable.css, jquery.ui.selectable.css, jquery.ui.slider.css, jquery.ui.spinner.css, jquery.ui.tabs.css, jquery.ui.tooltip.css +* To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Verdana%2CArial%2Csans-serif&fwDefault=normal&fsDefault=1.1em&cornerRadius=4px&bgColorHeader=cccccc&bgTextureHeader=highlight_soft&bgImgOpacityHeader=75&borderColorHeader=aaaaaa&fcHeader=222222&iconColorHeader=222222&bgColorContent=ffffff&bgTextureContent=flat&bgImgOpacityContent=75&borderColorContent=aaaaaa&fcContent=222222&iconColorContent=222222&bgColorDefault=e6e6e6&bgTextureDefault=glass&bgImgOpacityDefault=75&borderColorDefault=d3d3d3&fcDefault=555555&iconColorDefault=888888&bgColorHover=dadada&bgTextureHover=glass&bgImgOpacityHover=75&borderColorHover=999999&fcHover=212121&iconColorHover=454545&bgColorActive=ffffff&bgTextureActive=glass&bgImgOpacityActive=65&borderColorActive=aaaaaa&fcActive=212121&iconColorActive=454545&bgColorHighlight=fbf9ee&bgTextureHighlight=glass&bgImgOpacityHighlight=55&borderColorHighlight=fcefa1&fcHighlight=363636&iconColorHighlight=2e83ff&bgColorError=fef1ec&bgTextureError=glass&bgImgOpacityError=95&borderColorError=cd0a0a&fcError=cd0a0a&iconColorError=cd0a0a&bgColorOverlay=aaaaaa&bgTextureOverlay=flat&bgImgOpacityOverlay=0&opacityOverlay=30&bgColorShadow=aaaaaa&bgTextureShadow=flat&bgImgOpacityShadow=0&opacityShadow=30&thicknessShadow=8px&offsetTopShadow=-8px&offsetLeftShadow=-8px&cornerRadiusShadow=8px +* Copyright 2013 jQuery Foundation and other contributors Licensed MIT */ /* Layout helpers ----------------------------------*/ -.ui-helper-hidden { display: none; } -.ui-helper-hidden-accessible { border: 0; clip: rect(0 0 0 0); height: 1px; margin: -1px; overflow: hidden; padding: 0; position: absolute; width: 1px; } -.ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; } -.ui-helper-clearfix:before, .ui-helper-clearfix:after { content: ""; display: table; } -.ui-helper-clearfix:after { clear: both; } -.ui-helper-clearfix { zoom: 1; } -.ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); } +.ui-helper-hidden { + display: none; +} +.ui-helper-hidden-accessible { + border: 0; + clip: rect(0 0 0 0); + height: 1px; + margin: -1px; + overflow: hidden; + padding: 0; + position: absolute; + width: 1px; +} +.ui-helper-reset { + margin: 0; + padding: 0; + border: 0; + outline: 0; + line-height: 1.3; + text-decoration: none; + font-size: 100%; + list-style: none; +} +.ui-helper-clearfix:before, +.ui-helper-clearfix:after { + content: ""; + display: table; + border-collapse: collapse; +} +.ui-helper-clearfix:after { + clear: both; +} +.ui-helper-clearfix { + min-height: 0; /* support: IE7 */ +} +.ui-helper-zfix { + width: 100%; + height: 100%; + top: 0; + left: 0; + position: absolute; + opacity: 0; + filter:Alpha(Opacity=0); +} + +.ui-front { + z-index: 100; +} /* Interaction Cues ----------------------------------*/ -.ui-state-disabled { cursor: default !important; } +.ui-state-disabled { + cursor: default !important; +} /* Icons ----------------------------------*/ /* states and images */ -.ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; } +.ui-icon { + display: block; + text-indent: -99999px; + overflow: hidden; + background-repeat: no-repeat; +} /* Misc visuals ----------------------------------*/ /* Overlays */ -.ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; } - -.ui-accordion .ui-accordion-header { display: block; cursor: pointer; position: relative; margin-top: 2px; padding: .5em .5em .5em .7em; zoom: 1; } -.ui-accordion .ui-accordion-icons { padding-left: 2.2em; } -.ui-accordion .ui-accordion-noicons { padding-left: .7em; } -.ui-accordion .ui-accordion-icons .ui-accordion-icons { padding-left: 2.2em; } -.ui-accordion .ui-accordion-header .ui-accordion-header-icon { position: absolute; left: .5em; top: 50%; margin-top: -8px; } -.ui-accordion .ui-accordion-content { padding: 1em 2.2em; border-top: 0; overflow: auto; zoom: 1; } - +.ui-widget-overlay { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; +} +.ui-accordion .ui-accordion-header { + display: block; + cursor: pointer; + position: relative; + margin-top: 2px; + padding: .5em .5em .5em .7em; + min-height: 0; /* support: IE7 */ +} +.ui-accordion .ui-accordion-icons { + padding-left: 2.2em; +} +.ui-accordion .ui-accordion-noicons { + padding-left: .7em; +} +.ui-accordion .ui-accordion-icons .ui-accordion-icons { + padding-left: 2.2em; +} +.ui-accordion .ui-accordion-header .ui-accordion-header-icon { + position: absolute; + left: .5em; + top: 50%; + margin-top: -8px; +} +.ui-accordion .ui-accordion-content { + padding: 1em 2.2em; + border-top: 0; + overflow: auto; +} .ui-autocomplete { position: absolute; top: 0; left: 0; cursor: default; } +.ui-button { + display: inline-block; + position: relative; + padding: 0; + line-height: normal; + margin-right: .1em; + cursor: pointer; + vertical-align: middle; + text-align: center; + overflow: visible; /* removes extra width in IE */ +} +.ui-button, +.ui-button:link, +.ui-button:visited, +.ui-button:hover, +.ui-button:active { + text-decoration: none; +} +/* to make room for the icon, a width needs to be set here */ +.ui-button-icon-only { + width: 2.2em; +} +/* button elements seem to need a little more width */ +button.ui-button-icon-only { + width: 2.4em; +} +.ui-button-icons-only { + width: 3.4em; +} +button.ui-button-icons-only { + width: 3.7em; +} -/* workarounds */ -* html .ui-autocomplete { width:1px; } /* without this, the menu expands to 100% in IE6 */ - -.ui-button { display: inline-block; position: relative; padding: 0; margin-right: .1em; cursor: pointer; text-align: center; zoom: 1; overflow: visible; } /* the overflow property removes extra width in IE */ -.ui-button, .ui-button:link, .ui-button:visited, .ui-button:hover, .ui-button:active { text-decoration: none; } -.ui-button-icon-only { width: 2.2em; } /* to make room for the icon, a width needs to be set here */ -button.ui-button-icon-only { width: 2.4em; } /* button elements seem to need a little more width */ -.ui-button-icons-only { width: 3.4em; } -button.ui-button-icons-only { width: 3.7em; } - -/*button text element */ -.ui-button .ui-button-text { display: block; line-height: 1.4; } -.ui-button-text-only .ui-button-text { padding: .4em 1em; } -.ui-button-icon-only .ui-button-text, .ui-button-icons-only .ui-button-text { padding: .4em; text-indent: -9999999px; } -.ui-button-text-icon-primary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 1em .4em 2.1em; } -.ui-button-text-icon-secondary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 2.1em .4em 1em; } -.ui-button-text-icons .ui-button-text { padding-left: 2.1em; padding-right: 2.1em; } +/* button text element */ +.ui-button .ui-button-text { + display: block; + line-height: normal; +} +.ui-button-text-only .ui-button-text { + padding: .4em 1em; +} +.ui-button-icon-only .ui-button-text, +.ui-button-icons-only .ui-button-text { + padding: .4em; + text-indent: -9999999px; +} +.ui-button-text-icon-primary .ui-button-text, +.ui-button-text-icons .ui-button-text { + padding: .4em 1em .4em 2.1em; +} +.ui-button-text-icon-secondary .ui-button-text, +.ui-button-text-icons .ui-button-text { + padding: .4em 2.1em .4em 1em; +} +.ui-button-text-icons .ui-button-text { + padding-left: 2.1em; + padding-right: 2.1em; +} /* no icon support for input elements, provide padding by default */ -input.ui-button { padding: .4em 1em; } +input.ui-button { + padding: .4em 1em; +} -/*button icon element(s) */ -.ui-button-icon-only .ui-icon, .ui-button-text-icon-primary .ui-icon, .ui-button-text-icon-secondary .ui-icon, .ui-button-text-icons .ui-icon, .ui-button-icons-only .ui-icon { position: absolute; top: 50%; margin-top: -8px; } -.ui-button-icon-only .ui-icon { left: 50%; margin-left: -8px; } -.ui-button-text-icon-primary .ui-button-icon-primary, .ui-button-text-icons .ui-button-icon-primary, .ui-button-icons-only .ui-button-icon-primary { left: .5em; } -.ui-button-text-icon-secondary .ui-button-icon-secondary, .ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; } -.ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; } +/* button icon element(s) */ +.ui-button-icon-only .ui-icon, +.ui-button-text-icon-primary .ui-icon, +.ui-button-text-icon-secondary .ui-icon, +.ui-button-text-icons .ui-icon, +.ui-button-icons-only .ui-icon { + position: absolute; + top: 50%; + margin-top: -8px; +} +.ui-button-icon-only .ui-icon { + left: 50%; + margin-left: -8px; +} +.ui-button-text-icon-primary .ui-button-icon-primary, +.ui-button-text-icons .ui-button-icon-primary, +.ui-button-icons-only .ui-button-icon-primary { + left: .5em; +} +.ui-button-text-icon-secondary .ui-button-icon-secondary, +.ui-button-text-icons .ui-button-icon-secondary, +.ui-button-icons-only .ui-button-icon-secondary { + right: .5em; +} -/*button sets*/ -.ui-buttonset { margin-right: 7px; } -.ui-buttonset .ui-button { margin-left: 0; margin-right: -.3em; } +/* button sets */ +.ui-buttonset { + margin-right: 7px; +} +.ui-buttonset .ui-button { + margin-left: 0; + margin-right: -.3em; +} /* workarounds */ -button.ui-button::-moz-focus-inner { border: 0; padding: 0; } /* reset extra padding in Firefox */ - -.ui-datepicker { width: 17em; padding: .2em .2em 0; display: none; } -.ui-datepicker .ui-datepicker-header { position:relative; padding:.2em 0; } -.ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next { position:absolute; top: 2px; width: 1.8em; height: 1.8em; } -.ui-datepicker .ui-datepicker-prev-hover, .ui-datepicker .ui-datepicker-next-hover { top: 1px; } -.ui-datepicker .ui-datepicker-prev { left:2px; } -.ui-datepicker .ui-datepicker-next { right:2px; } -.ui-datepicker .ui-datepicker-prev-hover { left:1px; } -.ui-datepicker .ui-datepicker-next-hover { right:1px; } -.ui-datepicker .ui-datepicker-prev span, .ui-datepicker .ui-datepicker-next span { display: block; position: absolute; left: 50%; margin-left: -8px; top: 50%; margin-top: -8px; } -.ui-datepicker .ui-datepicker-title { margin: 0 2.3em; line-height: 1.8em; text-align: center; } -.ui-datepicker .ui-datepicker-title select { font-size:1em; margin:1px 0; } -.ui-datepicker select.ui-datepicker-month-year {width: 100%;} -.ui-datepicker select.ui-datepicker-month, -.ui-datepicker select.ui-datepicker-year { width: 49%;} -.ui-datepicker table {width: 100%; font-size: .9em; border-collapse: collapse; margin:0 0 .4em; } -.ui-datepicker th { padding: .7em .3em; text-align: center; font-weight: bold; border: 0; } -.ui-datepicker td { border: 0; padding: 1px; } -.ui-datepicker td span, .ui-datepicker td a { display: block; padding: .2em; text-align: right; text-decoration: none; } -.ui-datepicker .ui-datepicker-buttonpane { background-image: none; margin: .7em 0 0 0; padding:0 .2em; border-left: 0; border-right: 0; border-bottom: 0; } -.ui-datepicker .ui-datepicker-buttonpane button { float: right; margin: .5em .2em .4em; cursor: pointer; padding: .2em .6em .3em .6em; width:auto; overflow:visible; } -.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { float:left; } +/* reset extra padding in Firefox, see h5bp.com/l */ +input.ui-button::-moz-focus-inner, +button.ui-button::-moz-focus-inner { + border: 0; + padding: 0; +} +.ui-datepicker { + width: 17em; + padding: .2em .2em 0; + display: none; +} +.ui-datepicker .ui-datepicker-header { + position: relative; + padding: .2em 0; +} +.ui-datepicker .ui-datepicker-prev, +.ui-datepicker .ui-datepicker-next { + position: absolute; + top: 2px; + width: 1.8em; + height: 1.8em; +} +.ui-datepicker .ui-datepicker-prev-hover, +.ui-datepicker .ui-datepicker-next-hover { + top: 1px; +} +.ui-datepicker .ui-datepicker-prev { + left: 2px; +} +.ui-datepicker .ui-datepicker-next { + right: 2px; +} +.ui-datepicker .ui-datepicker-prev-hover { + left: 1px; +} +.ui-datepicker .ui-datepicker-next-hover { + right: 1px; +} +.ui-datepicker .ui-datepicker-prev span, +.ui-datepicker .ui-datepicker-next span { + display: block; + position: absolute; + left: 50%; + margin-left: -8px; + top: 50%; + margin-top: -8px; +} +.ui-datepicker .ui-datepicker-title { + margin: 0 2.3em; + line-height: 1.8em; + text-align: center; +} +.ui-datepicker .ui-datepicker-title select { + font-size: 1em; + margin: 1px 0; +} +.ui-datepicker select.ui-datepicker-month-year { + width: 100%; +} +.ui-datepicker select.ui-datepicker-month, +.ui-datepicker select.ui-datepicker-year { + width: 49%; +} +.ui-datepicker table { + width: 100%; + font-size: .9em; + border-collapse: collapse; + margin: 0 0 .4em; +} +.ui-datepicker th { + padding: .7em .3em; + text-align: center; + font-weight: bold; + border: 0; +} +.ui-datepicker td { + border: 0; + padding: 1px; +} +.ui-datepicker td span, +.ui-datepicker td a { + display: block; + padding: .2em; + text-align: right; + text-decoration: none; +} +.ui-datepicker .ui-datepicker-buttonpane { + background-image: none; + margin: .7em 0 0 0; + padding: 0 .2em; + border-left: 0; + border-right: 0; + border-bottom: 0; +} +.ui-datepicker .ui-datepicker-buttonpane button { + float: right; + margin: .5em .2em .4em; + cursor: pointer; + padding: .2em .6em .3em .6em; + width: auto; + overflow: visible; +} +.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { + float: left; +} /* with multiple calendars */ -.ui-datepicker.ui-datepicker-multi { width:auto; } -.ui-datepicker-multi .ui-datepicker-group { float:left; } -.ui-datepicker-multi .ui-datepicker-group table { width:95%; margin:0 auto .4em; } -.ui-datepicker-multi-2 .ui-datepicker-group { width:50%; } -.ui-datepicker-multi-3 .ui-datepicker-group { width:33.3%; } -.ui-datepicker-multi-4 .ui-datepicker-group { width:25%; } -.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header { border-left-width:0; } -.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { border-left-width:0; } -.ui-datepicker-multi .ui-datepicker-buttonpane { clear:left; } -.ui-datepicker-row-break { clear:both; width:100%; font-size:0em; } +.ui-datepicker.ui-datepicker-multi { + width: auto; +} +.ui-datepicker-multi .ui-datepicker-group { + float: left; +} +.ui-datepicker-multi .ui-datepicker-group table { + width: 95%; + margin: 0 auto .4em; +} +.ui-datepicker-multi-2 .ui-datepicker-group { + width: 50%; +} +.ui-datepicker-multi-3 .ui-datepicker-group { + width: 33.3%; +} +.ui-datepicker-multi-4 .ui-datepicker-group { + width: 25%; +} +.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header, +.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { + border-left-width: 0; +} +.ui-datepicker-multi .ui-datepicker-buttonpane { + clear: left; +} +.ui-datepicker-row-break { + clear: both; + width: 100%; + font-size: 0; +} /* RTL support */ -.ui-datepicker-rtl { direction: rtl; } -.ui-datepicker-rtl .ui-datepicker-prev { right: 2px; left: auto; } -.ui-datepicker-rtl .ui-datepicker-next { left: 2px; right: auto; } -.ui-datepicker-rtl .ui-datepicker-prev:hover { right: 1px; left: auto; } -.ui-datepicker-rtl .ui-datepicker-next:hover { left: 1px; right: auto; } -.ui-datepicker-rtl .ui-datepicker-buttonpane { clear:right; } -.ui-datepicker-rtl .ui-datepicker-buttonpane button { float: left; } -.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current { float:right; } -.ui-datepicker-rtl .ui-datepicker-group { float:right; } -.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header { border-right-width:0; border-left-width:1px; } -.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { border-right-width:0; border-left-width:1px; } - -/* IE6 IFRAME FIX (taken from datepicker 1.5.3 */ -.ui-datepicker-cover { - position: absolute; /*must have*/ - z-index: -1; /*must have*/ - filter: mask(); /*must have*/ - top: -4px; /*must have*/ - left: -4px; /*must have*/ - width: 200px; /*must have*/ - height: 200px; /*must have*/ -} -.ui-dialog { position: absolute; top: 0; left: 0; padding: .2em; width: 300px; overflow: hidden; } -.ui-dialog .ui-dialog-titlebar { padding: .4em 1em; position: relative; } -.ui-dialog .ui-dialog-title { float: left; margin: .1em 16px .1em 0; } -.ui-dialog .ui-dialog-titlebar-close { position: absolute; right: .3em; top: 50%; width: 19px; margin: -10px 0 0 0; padding: 1px; height: 18px; } -.ui-dialog .ui-dialog-titlebar-close span { display: block; margin: 1px; } -.ui-dialog .ui-dialog-titlebar-close:hover, .ui-dialog .ui-dialog-titlebar-close:focus { padding: 0; } -.ui-dialog .ui-dialog-content { position: relative; border: 0; padding: .5em 1em; background: none; overflow: auto; zoom: 1; } -.ui-dialog .ui-dialog-buttonpane { text-align: left; border-width: 1px 0 0 0; background-image: none; margin: .5em 0 0 0; padding: .3em 1em .5em .4em; } -.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset { float: right; } -.ui-dialog .ui-dialog-buttonpane button { margin: .5em .4em .5em 0; cursor: pointer; } -.ui-dialog .ui-resizable-se { width: 14px; height: 14px; right: 3px; bottom: 3px; } -.ui-draggable .ui-dialog-titlebar { cursor: move; } - -.ui-menu { list-style:none; padding: 2px; margin: 0; display:block; outline: none; } -.ui-menu .ui-menu { margin-top: -3px; position: absolute; } -.ui-menu .ui-menu-item { margin: 0; padding: 0; zoom: 1; width: 100%; } -.ui-menu .ui-menu-divider { margin: 5px -2px 5px -2px; height: 0; font-size: 0; line-height: 0; border-width: 1px 0 0 0; } -.ui-menu .ui-menu-item a { text-decoration: none; display: block; padding: 2px .4em; line-height: 1.5; zoom: 1; font-weight: normal; } +.ui-datepicker-rtl { + direction: rtl; +} +.ui-datepicker-rtl .ui-datepicker-prev { + right: 2px; + left: auto; +} +.ui-datepicker-rtl .ui-datepicker-next { + left: 2px; + right: auto; +} +.ui-datepicker-rtl .ui-datepicker-prev:hover { + right: 1px; + left: auto; +} +.ui-datepicker-rtl .ui-datepicker-next:hover { + left: 1px; + right: auto; +} +.ui-datepicker-rtl .ui-datepicker-buttonpane { + clear: right; +} +.ui-datepicker-rtl .ui-datepicker-buttonpane button { + float: left; +} +.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current, +.ui-datepicker-rtl .ui-datepicker-group { + float: right; +} +.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header, +.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { + border-right-width: 0; + border-left-width: 1px; +} +.ui-dialog { + position: absolute; + top: 0; + left: 0; + padding: .2em; + outline: 0; +} +.ui-dialog .ui-dialog-titlebar { + padding: .4em 1em; + position: relative; +} +.ui-dialog .ui-dialog-title { + float: left; + margin: .1em 0; + white-space: nowrap; + width: 90%; + overflow: hidden; + text-overflow: ellipsis; +} +.ui-dialog .ui-dialog-titlebar-close { + position: absolute; + right: .3em; + top: 50%; + width: 21px; + margin: -10px 0 0 0; + padding: 1px; + height: 20px; +} +.ui-dialog .ui-dialog-content { + position: relative; + border: 0; + padding: .5em 1em; + background: none; + overflow: auto; +} +.ui-dialog .ui-dialog-buttonpane { + text-align: left; + border-width: 1px 0 0 0; + background-image: none; + margin-top: .5em; + padding: .3em 1em .5em .4em; +} +.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset { + float: right; +} +.ui-dialog .ui-dialog-buttonpane button { + margin: .5em .4em .5em 0; + cursor: pointer; +} +.ui-dialog .ui-resizable-se { + width: 12px; + height: 12px; + right: -5px; + bottom: -5px; + background-position: 16px 16px; +} +.ui-draggable .ui-dialog-titlebar { + cursor: move; +} +.ui-menu { + list-style: none; + padding: 2px; + margin: 0; + display: block; + outline: none; +} +.ui-menu .ui-menu { + margin-top: -3px; + position: absolute; +} +.ui-menu .ui-menu-item { + margin: 0; + padding: 0; + width: 100%; +} +.ui-menu .ui-menu-divider { + margin: 5px -2px 5px -2px; + height: 0; + font-size: 0; + line-height: 0; + border-width: 1px 0 0 0; +} +.ui-menu .ui-menu-item a { + text-decoration: none; + display: block; + padding: 2px .4em; + line-height: 1.5; + min-height: 0; /* support: IE7 */ + font-weight: normal; +} .ui-menu .ui-menu-item a.ui-state-focus, -.ui-menu .ui-menu-item a.ui-state-active { font-weight: normal; margin: -1px; } +.ui-menu .ui-menu-item a.ui-state-active { + font-weight: normal; + margin: -1px; +} -.ui-menu .ui-state-disabled { font-weight: normal; margin: .4em 0 .2em; line-height: 1.5; } -.ui-menu .ui-state-disabled a { cursor: default; } +.ui-menu .ui-state-disabled { + font-weight: normal; + margin: .4em 0 .2em; + line-height: 1.5; +} +.ui-menu .ui-state-disabled a { + cursor: default; +} /* icon support */ -.ui-menu-icons { position: relative; } -.ui-menu-icons .ui-menu-item a { position: relative; padding-left: 2em; } +.ui-menu-icons { + position: relative; +} +.ui-menu-icons .ui-menu-item a { + position: relative; + padding-left: 2em; +} /* left-aligned */ -.ui-menu .ui-icon { position: absolute; top: .2em; left: .2em; } +.ui-menu .ui-icon { + position: absolute; + top: .2em; + left: .2em; +} /* right-aligned */ -.ui-menu .ui-menu-icon { position: static; float: right; } - -.ui-progressbar { height:2em; text-align: left; overflow: hidden; } -.ui-progressbar .ui-progressbar-value {margin: -1px; height:100%; } -.ui-resizable { position: relative;} -.ui-resizable-handle { position: absolute;font-size: 0.1px; display: block; } -.ui-resizable-disabled .ui-resizable-handle, .ui-resizable-autohide .ui-resizable-handle { display: none; } -.ui-resizable-n { cursor: n-resize; height: 7px; width: 100%; top: -5px; left: 0; } -.ui-resizable-s { cursor: s-resize; height: 7px; width: 100%; bottom: -5px; left: 0; } -.ui-resizable-e { cursor: e-resize; width: 7px; right: -5px; top: 0; height: 100%; } -.ui-resizable-w { cursor: w-resize; width: 7px; left: -5px; top: 0; height: 100%; } -.ui-resizable-se { cursor: se-resize; width: 12px; height: 12px; right: 1px; bottom: 1px; } -.ui-resizable-sw { cursor: sw-resize; width: 9px; height: 9px; left: -5px; bottom: -5px; } -.ui-resizable-nw { cursor: nw-resize; width: 9px; height: 9px; left: -5px; top: -5px; } -.ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: -5px; top: -5px;} -.ui-selectable-helper { position: absolute; z-index: 100; border:1px dotted black; } - -.ui-slider { position: relative; text-align: left; } -.ui-slider .ui-slider-handle { position: absolute; z-index: 2; width: 1.2em; height: 1.2em; cursor: default; } -.ui-slider .ui-slider-range { position: absolute; z-index: 1; font-size: .7em; display: block; border: 0; background-position: 0 0; } - -.ui-slider-horizontal { height: .8em; } -.ui-slider-horizontal .ui-slider-handle { top: -.3em; margin-left: -.6em; } -.ui-slider-horizontal .ui-slider-range { top: 0; height: 100%; } -.ui-slider-horizontal .ui-slider-range-min { left: 0; } -.ui-slider-horizontal .ui-slider-range-max { right: 0; } - -.ui-slider-vertical { width: .8em; height: 100px; } -.ui-slider-vertical .ui-slider-handle { left: -.3em; margin-left: 0; margin-bottom: -.6em; } -.ui-slider-vertical .ui-slider-range { left: 0; width: 100%; } -.ui-slider-vertical .ui-slider-range-min { bottom: 0; } -.ui-slider-vertical .ui-slider-range-max { top: 0; } -.ui-spinner { position:relative; display: inline-block; overflow: hidden; padding: 0; vertical-align: middle; } -.ui-spinner-input { border: none; background: none; padding: 0; margin: .2em 0; vertical-align: middle; margin-left: .4em; margin-right: 22px; } -.ui-spinner-button { width: 16px; height: 50%; font-size: .5em; padding: 0; margin: 0; text-align: center; position: absolute; cursor: default; display: block; overflow: hidden; right: 0; } -.ui-spinner a.ui-spinner-button { border-top: none; border-bottom: none; border-right: none; } /* more specificity required here to overide default borders */ -.ui-spinner .ui-icon { position: absolute; margin-top: -8px; top: 50%; left: 0; } /* vertical centre icon */ -.ui-spinner-up { top: 0; } -.ui-spinner-down { bottom: 0; } +.ui-menu .ui-menu-icon { + position: static; + float: right; +} +.ui-progressbar { + height: 2em; + text-align: left; + overflow: hidden; +} +.ui-progressbar .ui-progressbar-value { + margin: -1px; + height: 100%; +} +.ui-progressbar .ui-progressbar-overlay { + background: url("images/animated-overlay.gif"); + height: 100%; + filter: alpha(opacity=25); + opacity: 0.25; +} +.ui-progressbar-indeterminate .ui-progressbar-value { + background-image: none; +} +.ui-resizable { + position: relative; +} +.ui-resizable-handle { + position: absolute; + font-size: 0.1px; + display: block; +} +.ui-resizable-disabled .ui-resizable-handle, +.ui-resizable-autohide .ui-resizable-handle { + display: none; +} +.ui-resizable-n { + cursor: n-resize; + height: 7px; + width: 100%; + top: -5px; + left: 0; +} +.ui-resizable-s { + cursor: s-resize; + height: 7px; + width: 100%; + bottom: -5px; + left: 0; +} +.ui-resizable-e { + cursor: e-resize; + width: 7px; + right: -5px; + top: 0; + height: 100%; +} +.ui-resizable-w { + cursor: w-resize; + width: 7px; + left: -5px; + top: 0; + height: 100%; +} +.ui-resizable-se { + cursor: se-resize; + width: 12px; + height: 12px; + right: 1px; + bottom: 1px; +} +.ui-resizable-sw { + cursor: sw-resize; + width: 9px; + height: 9px; + left: -5px; + bottom: -5px; +} +.ui-resizable-nw { + cursor: nw-resize; + width: 9px; + height: 9px; + left: -5px; + top: -5px; +} +.ui-resizable-ne { + cursor: ne-resize; + width: 9px; + height: 9px; + right: -5px; + top: -5px; +} +.ui-selectable-helper { + position: absolute; + z-index: 100; + border: 1px dotted black; +} +.ui-slider { + position: relative; + text-align: left; +} +.ui-slider .ui-slider-handle { + position: absolute; + z-index: 2; + width: 1.2em; + height: 1.2em; + cursor: default; +} +.ui-slider .ui-slider-range { + position: absolute; + z-index: 1; + font-size: .7em; + display: block; + border: 0; + background-position: 0 0; +} + +/* For IE8 - See #6727 */ +.ui-slider.ui-state-disabled .ui-slider-handle, +.ui-slider.ui-state-disabled .ui-slider-range { + filter: inherit; +} + +.ui-slider-horizontal { + height: .8em; +} +.ui-slider-horizontal .ui-slider-handle { + top: -.3em; + margin-left: -.6em; +} +.ui-slider-horizontal .ui-slider-range { + top: 0; + height: 100%; +} +.ui-slider-horizontal .ui-slider-range-min { + left: 0; +} +.ui-slider-horizontal .ui-slider-range-max { + right: 0; +} + +.ui-slider-vertical { + width: .8em; + height: 100px; +} +.ui-slider-vertical .ui-slider-handle { + left: -.3em; + margin-left: 0; + margin-bottom: -.6em; +} +.ui-slider-vertical .ui-slider-range { + left: 0; + width: 100%; +} +.ui-slider-vertical .ui-slider-range-min { + bottom: 0; +} +.ui-slider-vertical .ui-slider-range-max { + top: 0; +} +.ui-spinner { + position: relative; + display: inline-block; + overflow: hidden; + padding: 0; + vertical-align: middle; +} +.ui-spinner-input { + border: none; + background: none; + color: inherit; + padding: 0; + margin: .2em 0; + vertical-align: middle; + margin-left: .4em; + margin-right: 22px; +} +.ui-spinner-button { + width: 16px; + height: 50%; + font-size: .5em; + padding: 0; + margin: 0; + text-align: center; + position: absolute; + cursor: default; + display: block; + overflow: hidden; + right: 0; +} +/* more specificity required here to overide default borders */ +.ui-spinner a.ui-spinner-button { + border-top: none; + border-bottom: none; + border-right: none; +} +/* vertical centre icon */ +.ui-spinner .ui-icon { + position: absolute; + margin-top: -8px; + top: 50%; + left: 0; +} +.ui-spinner-up { + top: 0; +} +.ui-spinner-down { + bottom: 0; +} /* TR overrides */ .ui-spinner .ui-icon-triangle-1-s { /* need to fix icons sprite */ - background-position:-65px -16px; + background-position: -65px -16px; +} +.ui-tabs { + position: relative;/* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */ + padding: .2em; +} +.ui-tabs .ui-tabs-nav { + margin: 0; + padding: .2em .2em 0; +} +.ui-tabs .ui-tabs-nav li { + list-style: none; + float: left; + position: relative; + top: 0; + margin: 1px .2em 0 0; + border-bottom-width: 0; + padding: 0; + white-space: nowrap; +} +.ui-tabs .ui-tabs-nav li a { + float: left; + padding: .5em 1em; + text-decoration: none; +} +.ui-tabs .ui-tabs-nav li.ui-tabs-active { + margin-bottom: -1px; + padding-bottom: 1px; +} +.ui-tabs .ui-tabs-nav li.ui-tabs-active a, +.ui-tabs .ui-tabs-nav li.ui-state-disabled a, +.ui-tabs .ui-tabs-nav li.ui-tabs-loading a { + cursor: text; +} +.ui-tabs .ui-tabs-nav li a, /* first selector in group seems obsolete, but required to overcome bug in Opera applying cursor: text overall if defined elsewhere... */ +.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-active a { + cursor: pointer; +} +.ui-tabs .ui-tabs-panel { + display: block; + border-width: 0; + padding: 1em 1.4em; + background: none; } - -.ui-tabs { position: relative; padding: .2em; zoom: 1; } /* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */ -.ui-tabs .ui-tabs-nav { margin: 0; padding: .2em .2em 0; } -.ui-tabs .ui-tabs-nav li { list-style: none; float: left; position: relative; top: 0; margin: 1px .2em 0 0; border-bottom: 0; padding: 0; white-space: nowrap; } -.ui-tabs .ui-tabs-nav li a { float: left; padding: .5em 1em; text-decoration: none; } -.ui-tabs .ui-tabs-nav li.ui-tabs-active { margin-bottom: -1px; padding-bottom: 1px; } -.ui-tabs .ui-tabs-nav li.ui-tabs-active a, .ui-tabs .ui-tabs-nav li.ui-state-disabled a, .ui-tabs .ui-tabs-nav li.ui-tabs-loading a { cursor: text; } -.ui-tabs .ui-tabs-nav li a, .ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-active a { cursor: pointer; } /* first selector in group seems obsolete, but required to overcome bug in Opera applying cursor: text overall if defined elsewhere... */ -.ui-tabs .ui-tabs-panel { display: block; border-width: 0; padding: 1em 1.4em; background: none; } - .ui-tooltip { padding: 8px; position: absolute; @@ -232,57 +777,182 @@ button.ui-button::-moz-focus-inner { border: 0; padding: 0; } /* reset extra pad -webkit-box-shadow: 0 0 5px #aaa; box-shadow: 0 0 5px #aaa; } -/* Fades and background-images don't work well together in IE6, drop the image */ -* html .ui-tooltip { - background-image: none; +body .ui-tooltip { + border-width: 2px; } -body .ui-tooltip { border-width: 2px; } /* Component containers ----------------------------------*/ -.ui-widget { font-size: 1.1em; } -.ui-widget .ui-widget { font-size: 1em; } -.ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-size: 1em; } -.ui-widget-content { border: 1px solid #aaaaaa; background: #ffffff url(images/ui-bg_flat_75_ffffff_40x100.png) 50% 50% repeat-x; color: #222222; } -.ui-widget-content a { color: #222222; } -.ui-widget-header { border: 1px solid #aaaaaa; background: #cccccc url(images/ui-bg_highlight-soft_75_cccccc_1x100.png) 50% 50% repeat-x; color: #222222; font-weight: bold; } -.ui-widget-header a { color: #222222; } +.ui-widget { + + font-size: 1.1em; +} +.ui-widget .ui-widget { + font-size: 1em; +} +.ui-widget input, +.ui-widget select, +.ui-widget textarea, +.ui-widget button { + + font-size: 1em; +} +.ui-widget-content { + border: 1px solid #aaaaaa; + background: #ffffff url(images/ui-bg_flat_75_ffffff_40x100.png) 50% 50% repeat-x; + color: #222222; +} +.ui-widget-content a { + color: #222222; +} +.ui-widget-header { + border: 1px solid #aaaaaa; + background: #cccccc url(images/ui-bg_highlight-soft_75_cccccc_1x100.png) 50% 50% repeat-x; + color: #222222; + font-weight: bold; +} +.ui-widget-header a { + color: #222222; +} /* Interaction states ----------------------------------*/ -.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { border: 1px solid #d3d3d3; background: #e6e6e6 url(images/ui-bg_glass_75_e6e6e6_1x400.png) 50% 50% repeat-x; font-weight: normal; color: #555555; } -.ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #555555; text-decoration: none; } -.ui-state-hover, .ui-widget-content .ui-state-hover, .ui-widget-header .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus, .ui-widget-header .ui-state-focus { border: 1px solid #999999; background: #dadada url(images/ui-bg_glass_75_dadada_1x400.png) 50% 50% repeat-x; font-weight: normal; color: #212121; } -.ui-state-hover a, .ui-state-hover a:hover, .ui-state-hover a:link, .ui-state-hover a:visited { color: #212121; text-decoration: none; } -.ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active { border: 1px solid #aaaaaa; background: #ffffff url(images/ui-bg_glass_65_ffffff_1x400.png) 50% 50% repeat-x; font-weight: normal; color: #212121; } -.ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #212121; text-decoration: none; } +.ui-state-default, +.ui-widget-content .ui-state-default, +.ui-widget-header .ui-state-default { + border: 1px solid #d3d3d3; + background: #e6e6e6 url(images/ui-bg_glass_75_e6e6e6_1x400.png) 50% 50% repeat-x; + font-weight: normal; + color: #555555; +} +.ui-state-default a, +.ui-state-default a:link, +.ui-state-default a:visited { + color: #555555; + text-decoration: none; +} +.ui-state-hover, +.ui-widget-content .ui-state-hover, +.ui-widget-header .ui-state-hover, +.ui-state-focus, +.ui-widget-content .ui-state-focus, +.ui-widget-header .ui-state-focus { + border: 1px solid #999999; + background: #dadada url(images/ui-bg_glass_75_dadada_1x400.png) 50% 50% repeat-x; + font-weight: normal; + color: #212121; +} +.ui-state-hover a, +.ui-state-hover a:hover, +.ui-state-hover a:link, +.ui-state-hover a:visited { + color: #212121; + text-decoration: none; +} +.ui-state-active, +.ui-widget-content .ui-state-active, +.ui-widget-header .ui-state-active { + border: 1px solid #aaaaaa; + background: #ffffff url(images/ui-bg_glass_65_ffffff_1x400.png) 50% 50% repeat-x; + font-weight: normal; + color: #212121; +} +.ui-state-active a, +.ui-state-active a:link, +.ui-state-active a:visited { + color: #212121; + text-decoration: none; +} /* Interaction Cues ----------------------------------*/ -.ui-state-highlight, .ui-widget-content .ui-state-highlight, .ui-widget-header .ui-state-highlight {border: 1px solid #fcefa1; background: #fbf9ee url(images/ui-bg_glass_55_fbf9ee_1x400.png) 50% 50% repeat-x; color: #363636; } -.ui-state-highlight a, .ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a { color: #363636; } -.ui-state-error, .ui-widget-content .ui-state-error, .ui-widget-header .ui-state-error {border: 1px solid #cd0a0a; background: #fef1ec url(images/ui-bg_glass_95_fef1ec_1x400.png) 50% 50% repeat-x; color: #cd0a0a; } -.ui-state-error a, .ui-widget-content .ui-state-error a, .ui-widget-header .ui-state-error a { color: #cd0a0a; } -.ui-state-error-text, .ui-widget-content .ui-state-error-text, .ui-widget-header .ui-state-error-text { color: #cd0a0a; } -.ui-priority-primary, .ui-widget-content .ui-priority-primary, .ui-widget-header .ui-priority-primary { font-weight: bold; } -.ui-priority-secondary, .ui-widget-content .ui-priority-secondary, .ui-widget-header .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; } -.ui-state-disabled, .ui-widget-content .ui-state-disabled, .ui-widget-header .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; } -.ui-state-disabled .ui-icon { filter:Alpha(Opacity=35); } /* For IE8 - See #6059 */ +.ui-state-highlight, +.ui-widget-content .ui-state-highlight, +.ui-widget-header .ui-state-highlight { + border: 1px solid #fcefa1; + background: #fbf9ee url(images/ui-bg_glass_55_fbf9ee_1x400.png) 50% 50% repeat-x; + color: #363636; +} +.ui-state-highlight a, +.ui-widget-content .ui-state-highlight a, +.ui-widget-header .ui-state-highlight a { + color: #363636; +} +.ui-state-error, +.ui-widget-content .ui-state-error, +.ui-widget-header .ui-state-error { + border: 1px solid #cd0a0a; + background: #fef1ec url(images/ui-bg_glass_95_fef1ec_1x400.png) 50% 50% repeat-x; + color: #cd0a0a; +} +.ui-state-error a, +.ui-widget-content .ui-state-error a, +.ui-widget-header .ui-state-error a { + color: #cd0a0a; +} +.ui-state-error-text, +.ui-widget-content .ui-state-error-text, +.ui-widget-header .ui-state-error-text { + color: #cd0a0a; +} +.ui-priority-primary, +.ui-widget-content .ui-priority-primary, +.ui-widget-header .ui-priority-primary { + font-weight: bold; +} +.ui-priority-secondary, +.ui-widget-content .ui-priority-secondary, +.ui-widget-header .ui-priority-secondary { + opacity: .7; + filter:Alpha(Opacity=70); + font-weight: normal; +} +.ui-state-disabled, +.ui-widget-content .ui-state-disabled, +.ui-widget-header .ui-state-disabled { + opacity: .35; + filter:Alpha(Opacity=35); + background-image: none; +} +.ui-state-disabled .ui-icon { + filter:Alpha(Opacity=35); /* For IE8 - See #6059 */ +} /* Icons ----------------------------------*/ /* states and images */ -.ui-icon { width: 16px; height: 16px; background-image: url(images/ui-icons_222222_256x240.png); } -.ui-widget-content .ui-icon {background-image: url(images/ui-icons_222222_256x240.png); } -.ui-widget-header .ui-icon {background-image: url(images/ui-icons_222222_256x240.png); } -.ui-state-default .ui-icon { background-image: url(images/ui-icons_888888_256x240.png); } -.ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url(images/ui-icons_454545_256x240.png); } -.ui-state-active .ui-icon {background-image: url(images/ui-icons_454545_256x240.png); } -.ui-state-highlight .ui-icon {background-image: url(images/ui-icons_2e83ff_256x240.png); } -.ui-state-error .ui-icon, .ui-state-error-text .ui-icon {background-image: url(images/ui-icons_cd0a0a_256x240.png); } +.ui-icon { + width: 16px; + height: 16px; +} +.ui-icon, +.ui-widget-content .ui-icon { + background-image: url(images/ui-icons_222222_256x240.png); +} +.ui-widget-header .ui-icon { + background-image: url(images/ui-icons_222222_256x240.png); +} +.ui-state-default .ui-icon { + background-image: url(images/ui-icons_888888_256x240.png); +} +.ui-state-hover .ui-icon, +.ui-state-focus .ui-icon { + background-image: url(images/ui-icons_454545_256x240.png); +} +.ui-state-active .ui-icon { + background-image: url(images/ui-icons_454545_256x240.png); +} +.ui-state-highlight .ui-icon { + background-image: url(images/ui-icons_2e83ff_256x240.png); +} +.ui-state-error .ui-icon, +.ui-state-error-text .ui-icon { + background-image: url(images/ui-icons_cd0a0a_256x240.png); +} /* positioning */ +.ui-icon-blank { background-position: 16px 16px; } .ui-icon-carat-1-n { background-position: 0 0; } .ui-icon-carat-1-ne { background-position: -16px 0; } .ui-icon-carat-1-e { background-position: -32px 0; } @@ -464,11 +1134,42 @@ body .ui-tooltip { border-width: 2px; } ----------------------------------*/ /* Corner radius */ -.ui-corner-all, .ui-corner-top, .ui-corner-left, .ui-corner-tl { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; -khtml-border-top-left-radius: 4px; border-top-left-radius: 4px; } -.ui-corner-all, .ui-corner-top, .ui-corner-right, .ui-corner-tr { -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; -khtml-border-top-right-radius: 4px; border-top-right-radius: 4px; } -.ui-corner-all, .ui-corner-bottom, .ui-corner-left, .ui-corner-bl { -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; -khtml-border-bottom-left-radius: 4px; border-bottom-left-radius: 4px; } -.ui-corner-all, .ui-corner-bottom, .ui-corner-right, .ui-corner-br { -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; -khtml-border-bottom-right-radius: 4px; border-bottom-right-radius: 4px; } +.ui-corner-all, +.ui-corner-top, +.ui-corner-left, +.ui-corner-tl { + border-top-left-radius: 4px; +} +.ui-corner-all, +.ui-corner-top, +.ui-corner-right, +.ui-corner-tr { + border-top-right-radius: 4px; +} +.ui-corner-all, +.ui-corner-bottom, +.ui-corner-left, +.ui-corner-bl { + border-bottom-left-radius: 4px; +} +.ui-corner-all, +.ui-corner-bottom, +.ui-corner-right, +.ui-corner-br { + border-bottom-right-radius: 4px; +} /* Overlays */ -.ui-widget-overlay { background: #aaaaaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x; opacity: .3;filter:Alpha(Opacity=30); } -.ui-widget-shadow { margin: -8px 0 0 -8px; padding: 8px; background: #aaaaaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x; opacity: .3;filter:Alpha(Opacity=30); -moz-border-radius: 8px; -khtml-border-radius: 8px; -webkit-border-radius: 8px; border-radius: 8px; } +.ui-widget-overlay { + background: #aaaaaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x; + opacity: .3; + filter: Alpha(Opacity=30); +} +.ui-widget-shadow { + margin: -8px 0 0 -8px; + padding: 8px; + background: #aaaaaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x; + opacity: .3; + filter: Alpha(Opacity=30); + border-radius: 8px; +} diff --git a/lib/scripts/jquery/jquery-ui.js b/lib/scripts/jquery/jquery-ui.js index 2f83e5a2a..6eccbfec3 100644 --- a/lib/scripts/jquery/jquery-ui.js +++ b/lib/scripts/jquery/jquery-ui.js @@ -1,23 +1,17 @@ -/*! jQuery UI - v1.9.2 - 2012-11-23 +/*! jQuery UI - v1.10.2 - 2013-03-14 * http://jqueryui.com * Includes: jquery.ui.core.js, jquery.ui.widget.js, jquery.ui.mouse.js, jquery.ui.draggable.js, jquery.ui.droppable.js, jquery.ui.resizable.js, jquery.ui.selectable.js, jquery.ui.sortable.js, jquery.ui.effect.js, jquery.ui.accordion.js, jquery.ui.autocomplete.js, jquery.ui.button.js, jquery.ui.datepicker.js, jquery.ui.dialog.js, jquery.ui.effect-blind.js, jquery.ui.effect-bounce.js, jquery.ui.effect-clip.js, jquery.ui.effect-drop.js, jquery.ui.effect-explode.js, jquery.ui.effect-fade.js, jquery.ui.effect-fold.js, jquery.ui.effect-highlight.js, jquery.ui.effect-pulsate.js, jquery.ui.effect-scale.js, jquery.ui.effect-shake.js, jquery.ui.effect-slide.js, jquery.ui.effect-transfer.js, jquery.ui.menu.js, jquery.ui.position.js, jquery.ui.progressbar.js, jquery.ui.slider.js, jquery.ui.spinner.js, jquery.ui.tabs.js, jquery.ui.tooltip.js -* Copyright 2012 jQuery Foundation and other contributors; Licensed MIT */ - +* Copyright 2013 jQuery Foundation and other contributors; Licensed MIT */ (function( $, undefined ) { var uuid = 0, runiqueId = /^ui-id-\d+$/; -// prevent duplicate loading -// this is only a problem because we proxy existing functions -// and we don't want to double proxy them +// $.ui might exist from components with no dependencies, e.g., $.ui.position $.ui = $.ui || {}; -if ( $.ui.version ) { - return; -} $.extend( $.ui, { - version: "1.9.2", + version: "1.10.2", keyCode: { BACKSPACE: 8, @@ -47,34 +41,35 @@ $.extend( $.ui, { // plugins $.fn.extend({ - _focus: $.fn.focus, - focus: function( delay, fn ) { - return typeof delay === "number" ? - this.each(function() { - var elem = this; - setTimeout(function() { - $( elem ).focus(); - if ( fn ) { - fn.call( elem ); - } - }, delay ); - }) : - this._focus.apply( this, arguments ); - }, + focus: (function( orig ) { + return function( delay, fn ) { + return typeof delay === "number" ? + this.each(function() { + var elem = this; + setTimeout(function() { + $( elem ).focus(); + if ( fn ) { + fn.call( elem ); + } + }, delay ); + }) : + orig.apply( this, arguments ); + }; + })( $.fn.focus ), scrollParent: function() { var scrollParent; - if (($.ui.ie && (/(static|relative)/).test(this.css('position'))) || (/absolute/).test(this.css('position'))) { + if (($.ui.ie && (/(static|relative)/).test(this.css("position"))) || (/absolute/).test(this.css("position"))) { scrollParent = this.parents().filter(function() { - return (/(relative|absolute|fixed)/).test($.css(this,'position')) && (/(auto|scroll)/).test($.css(this,'overflow')+$.css(this,'overflow-y')+$.css(this,'overflow-x')); + return (/(relative|absolute|fixed)/).test($.css(this,"position")) && (/(auto|scroll)/).test($.css(this,"overflow")+$.css(this,"overflow-y")+$.css(this,"overflow-x")); }).eq(0); } else { scrollParent = this.parents().filter(function() { - return (/(auto|scroll)/).test($.css(this,'overflow')+$.css(this,'overflow-y')+$.css(this,'overflow-x')); + return (/(auto|scroll)/).test($.css(this,"overflow")+$.css(this,"overflow-y")+$.css(this,"overflow-x")); }).eq(0); } - return (/fixed/).test(this.css('position')) || !scrollParent.length ? $(document) : scrollParent; + return (/fixed/).test(this.css("position")) || !scrollParent.length ? $(document) : scrollParent; }, zIndex: function( zIndex ) { @@ -147,7 +142,7 @@ function focusable( element, isTabIndexNotNaN ) { function visible( element ) { return $.expr.filters.visible( element ) && - !$( element ).parents().andSelf().filter(function() { + !$( element ).parents().addBack().filter(function() { return $.css( this, "visibility" ) === "hidden"; }).length; } @@ -175,31 +170,6 @@ $.extend( $.expr[ ":" ], { } }); -// support -$(function() { - var body = document.body, - div = body.appendChild( div = document.createElement( "div" ) ); - - // access offsetHeight before setting the style to prevent a layout bug - // in IE 9 which causes the element to continue to take up space even - // after it is removed from the DOM (#8026) - div.offsetHeight; - - $.extend( div.style, { - minHeight: "100px", - height: "auto", - padding: 0, - borderWidth: 0 - }); - - $.support.minHeight = div.offsetHeight === 100; - $.support.selectstart = "onselectstart" in div; - - // set display to none to avoid a layout bug in IE - // http://dev.jquery.com/ticket/4014 - body.removeChild( div ).style.display = "none"; -}); - // support: jQuery <1.8 if ( !$( "<a>" ).outerWidth( 1 ).jquery ) { $.each( [ "Width", "Height" ], function( i, name ) { @@ -247,6 +217,15 @@ if ( !$( "<a>" ).outerWidth( 1 ).jquery ) { }); } +// support: jQuery <1.8 +if ( !$.fn.addBack ) { + $.fn.addBack = function( selector ) { + return this.add( selector == null ? + this.prevObject : this.prevObject.filter( selector ) + ); + }; +} + // support: jQuery 1.6.1, 1.6.2 (http://bugs.jquery.com/ticket/9413) if ( $( "<a>" ).data( "a-b", "a" ).removeData( "a-b" ).data( "a-b" ) ) { $.fn.removeData = (function( removeData ) { @@ -265,13 +244,9 @@ if ( $( "<a>" ).data( "a-b", "a" ).removeData( "a-b" ).data( "a-b" ) ) { // deprecated +$.ui.ie = !!/msie [\w.]+/.exec( navigator.userAgent.toLowerCase() ); -(function() { - var uaMatch = /msie ([\w.]+)/.exec( navigator.userAgent.toLowerCase() ) || []; - $.ui.ie = uaMatch.length ? true : false; - $.ui.ie6 = parseFloat( uaMatch[ 1 ], 10 ) === 6; -})(); - +$.support.selectstart = "onselectstart" in document.createElement( "div" ); $.fn.extend({ disableSelection: function() { return this.bind( ( $.support.selectstart ? "selectstart" : "mousedown" ) + @@ -311,8 +286,6 @@ $.extend( $.ui, { } }, - contains: $.contains, - // only used by resizable hasScroll: function( el, a ) { @@ -335,16 +308,6 @@ $.extend( $.ui, { has = ( el[ scroll ] > 0 ); el[ scroll ] = 0; return has; - }, - - // these are odd functions, fix the API or move into individual plugins - isOverAxis: function( x, reference, size ) { - //Determines when x coordinate is over "b" element axis - return ( x > reference ) && ( x < ( reference + size ) ); - }, - isOver: function( y, x, top, left, height, width ) { - //Determines when x, y coordinates is over "b" element - return $.ui.isOverAxis( y, top, height ) && $.ui.isOverAxis( x, left, width ); } }); @@ -367,6 +330,9 @@ $.cleanData = function( elems ) { $.widget = function( name, base, prototype ) { var fullName, existingConstructor, constructor, basePrototype, + // proxiedPrototype allows the provided prototype to remain unmodified + // so that it can be used as a mixin for multiple widgets (#8876) + proxiedPrototype = {}, namespace = name.split( "." )[ 0 ]; name = name.split( "." )[ 1 ]; @@ -413,43 +379,43 @@ $.widget = function( name, base, prototype ) { // inheriting from basePrototype.options = $.widget.extend( {}, basePrototype.options ); $.each( prototype, function( prop, value ) { - if ( $.isFunction( value ) ) { - prototype[ prop ] = (function() { - var _super = function() { - return base.prototype[ prop ].apply( this, arguments ); - }, - _superApply = function( args ) { - return base.prototype[ prop ].apply( this, args ); - }; - return function() { - var __super = this._super, - __superApply = this._superApply, - returnValue; + if ( !$.isFunction( value ) ) { + proxiedPrototype[ prop ] = value; + return; + } + proxiedPrototype[ prop ] = (function() { + var _super = function() { + return base.prototype[ prop ].apply( this, arguments ); + }, + _superApply = function( args ) { + return base.prototype[ prop ].apply( this, args ); + }; + return function() { + var __super = this._super, + __superApply = this._superApply, + returnValue; - this._super = _super; - this._superApply = _superApply; + this._super = _super; + this._superApply = _superApply; - returnValue = value.apply( this, arguments ); + returnValue = value.apply( this, arguments ); - this._super = __super; - this._superApply = __superApply; + this._super = __super; + this._superApply = __superApply; - return returnValue; - }; - })(); - } + return returnValue; + }; + })(); }); constructor.prototype = $.widget.extend( basePrototype, { // TODO: remove support for widgetEventPrefix // always use the name + a colon as the prefix, e.g., draggable:start // don't prefix for widgets that aren't DOM-based widgetEventPrefix: existingConstructor ? basePrototype.widgetEventPrefix : name - }, prototype, { + }, proxiedPrototype, { constructor: constructor, namespace: namespace, widgetName: name, - // TODO remove widgetBaseClass, see #8155 - widgetBaseClass: fullName, widgetFullName: fullName }); @@ -575,9 +541,6 @@ $.Widget.prototype = { this.focusable = $(); if ( element !== this ) { - // 1.9 BC for #7810 - // TODO remove dual storage - $.data( element, this.widgetName, this ); $.data( element, this.widgetFullName, this ); this._on( true, this.element, { remove: function( event ) { @@ -844,7 +807,7 @@ $.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) { if ( options.delay ) { element.delay( options.delay ); } - if ( hasOptions && $.effects && ( $.effects.effect[ effectName ] || $.uiBackCompat !== false && $.effects[ effectName ] ) ) { + if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) { element[ method ]( options ); } else if ( effectName !== method && element[ effectName ] ) { element[ effectName ]( options.duration, options.easing, callback ); @@ -860,26 +823,19 @@ $.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) { }; }); -// DEPRECATED -if ( $.uiBackCompat !== false ) { - $.Widget.prototype._getCreateOptions = function() { - return $.metadata && $.metadata.get( this.element[0] )[ this.widgetName ]; - }; -} - })( jQuery ); (function( $, undefined ) { var mouseHandled = false; -$( document ).mouseup( function( e ) { +$( document ).mouseup( function() { mouseHandled = false; }); $.widget("ui.mouse", { - version: "1.9.2", + version: "1.10.2", options: { - cancel: 'input,textarea,button,select,option', + cancel: "input,textarea,button,select,option", distance: 1, delay: 0 }, @@ -887,12 +843,12 @@ $.widget("ui.mouse", { var that = this; this.element - .bind('mousedown.'+this.widgetName, function(event) { + .bind("mousedown."+this.widgetName, function(event) { return that._mouseDown(event); }) - .bind('click.'+this.widgetName, function(event) { - if (true === $.data(event.target, that.widgetName + '.preventClickEvent')) { - $.removeData(event.target, that.widgetName + '.preventClickEvent'); + .bind("click."+this.widgetName, function(event) { + if (true === $.data(event.target, that.widgetName + ".preventClickEvent")) { + $.removeData(event.target, that.widgetName + ".preventClickEvent"); event.stopImmediatePropagation(); return false; } @@ -904,11 +860,11 @@ $.widget("ui.mouse", { // TODO: make sure destroying one instance of mouse doesn't mess with // other instances of mouse _mouseDestroy: function() { - this.element.unbind('.'+this.widgetName); + this.element.unbind("."+this.widgetName); if ( this._mouseMoveDelegate ) { $(document) - .unbind('mousemove.'+this.widgetName, this._mouseMoveDelegate) - .unbind('mouseup.'+this.widgetName, this._mouseUpDelegate); + .unbind("mousemove."+this.widgetName, this._mouseMoveDelegate) + .unbind("mouseup."+this.widgetName, this._mouseUpDelegate); } }, @@ -946,8 +902,8 @@ $.widget("ui.mouse", { } // Click event may never have fired (Gecko & Opera) - if (true === $.data(event.target, this.widgetName + '.preventClickEvent')) { - $.removeData(event.target, this.widgetName + '.preventClickEvent'); + if (true === $.data(event.target, this.widgetName + ".preventClickEvent")) { + $.removeData(event.target, this.widgetName + ".preventClickEvent"); } // these delegates are required to keep context @@ -958,8 +914,8 @@ $.widget("ui.mouse", { return that._mouseUp(event); }; $(document) - .bind('mousemove.'+this.widgetName, this._mouseMoveDelegate) - .bind('mouseup.'+this.widgetName, this._mouseUpDelegate); + .bind("mousemove."+this.widgetName, this._mouseMoveDelegate) + .bind("mouseup."+this.widgetName, this._mouseUpDelegate); event.preventDefault(); @@ -969,7 +925,7 @@ $.widget("ui.mouse", { _mouseMove: function(event) { // IE mouseup check - mouseup happened when mouse was out of window - if ($.ui.ie && !(document.documentMode >= 9) && !event.button) { + if ($.ui.ie && ( !document.documentMode || document.documentMode < 9 ) && !event.button) { return this._mouseUp(event); } @@ -989,14 +945,14 @@ $.widget("ui.mouse", { _mouseUp: function(event) { $(document) - .unbind('mousemove.'+this.widgetName, this._mouseMoveDelegate) - .unbind('mouseup.'+this.widgetName, this._mouseUpDelegate); + .unbind("mousemove."+this.widgetName, this._mouseMoveDelegate) + .unbind("mouseup."+this.widgetName, this._mouseUpDelegate); if (this._mouseStarted) { this._mouseStarted = false; if (event.target === this._mouseDownEvent.target) { - $.data(event.target, this.widgetName + '.preventClickEvent', true); + $.data(event.target, this.widgetName + ".preventClickEvent", true); } this._mouseStop(event); @@ -1013,15 +969,15 @@ $.widget("ui.mouse", { ); }, - _mouseDelayMet: function(event) { + _mouseDelayMet: function(/* event */) { return this.mouseDelayMet; }, // These are placeholder methods, to be overriden by extending plugin - _mouseStart: function(event) {}, - _mouseDrag: function(event) {}, - _mouseStop: function(event) {}, - _mouseCapture: function(event) { return true; } + _mouseStart: function(/* event */) {}, + _mouseDrag: function(/* event */) {}, + _mouseStop: function(/* event */) {}, + _mouseCapture: function(/* event */) { return true; } }); })(jQuery); @@ -1029,7 +985,7 @@ $.widget("ui.mouse", { (function( $, undefined ) { $.widget("ui.draggable", $.ui.mouse, { - version: "1.9.2", + version: "1.10.2", widgetEventPrefix: "drag", options: { addClasses: true, @@ -1055,15 +1011,24 @@ $.widget("ui.draggable", $.ui.mouse, { snapMode: "both", snapTolerance: 20, stack: false, - zIndex: false + zIndex: false, + + // callbacks + drag: null, + start: null, + stop: null }, _create: function() { - if (this.options.helper == 'original' && !(/^(?:r|a|f)/).test(this.element.css("position"))) - this.element[0].style.position = 'relative'; - - (this.options.addClasses && this.element.addClass("ui-draggable")); - (this.options.disabled && this.element.addClass("ui-draggable-disabled")); + if (this.options.helper === "original" && !(/^(?:r|a|f)/).test(this.element.css("position"))) { + this.element[0].style.position = "relative"; + } + if (this.options.addClasses){ + this.element.addClass("ui-draggable"); + } + if (this.options.disabled){ + this.element.addClass("ui-draggable-disabled"); + } this._mouseInit(); @@ -1079,16 +1044,18 @@ $.widget("ui.draggable", $.ui.mouse, { var o = this.options; // among others, prevent a drag on a resizable-handle - if (this.helper || o.disabled || $(event.target).is('.ui-resizable-handle')) + if (this.helper || o.disabled || $(event.target).closest(".ui-resizable-handle").length > 0) { return false; + } //Quit if we're not on a valid handle this.handle = this._getHandle(event); - if (!this.handle) + if (!this.handle) { return false; + } $(o.iframeFix === true ? "iframe" : o.iframeFix).each(function() { - $('<div class="ui-draggable-iframeFix" style="background: #fff;"></div>') + $("<div class='ui-draggable-iframeFix' style='background: #fff;'></div>") .css({ width: this.offsetWidth+"px", height: this.offsetHeight+"px", position: "absolute", opacity: "0.001", zIndex: 1000 @@ -1114,8 +1081,9 @@ $.widget("ui.draggable", $.ui.mouse, { this._cacheHelperProportions(); //If ddmanager is used for droppables, set the global draggable - if($.ui.ddmanager) + if($.ui.ddmanager) { $.ui.ddmanager.current = this; + } /* * - Position generation - @@ -1150,12 +1118,13 @@ $.widget("ui.draggable", $.ui.mouse, { this.originalPageX = event.pageX; this.originalPageY = event.pageY; - //Adjust the mouse offset relative to the helper if 'cursorAt' is supplied + //Adjust the mouse offset relative to the helper if "cursorAt" is supplied (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt)); //Set a containment if given in the options - if(o.containment) + if(o.containment) { this._setContainment(); + } //Trigger event + callbacks if(this._trigger("start", event) === false) { @@ -1167,14 +1136,17 @@ $.widget("ui.draggable", $.ui.mouse, { this._cacheHelperProportions(); //Prepare the droppable offsets - if ($.ui.ddmanager && !o.dropBehaviour) + if ($.ui.ddmanager && !o.dropBehaviour) { $.ui.ddmanager.prepareOffsets(this, event); + } this._mouseDrag(event, true); //Execute the drag once - this causes the helper not to be visible before getting its correct position //If the ddmanager is used for droppables, inform the manager that dragging has started (see #5003) - if ( $.ui.ddmanager ) $.ui.ddmanager.dragStart(this, event); + if ( $.ui.ddmanager ) { + $.ui.ddmanager.dragStart(this, event); + } return true; }, @@ -1188,16 +1160,22 @@ $.widget("ui.draggable", $.ui.mouse, { //Call plugins and callbacks and use the resulting position if something is returned if (!noPropagation) { var ui = this._uiHash(); - if(this._trigger('drag', event, ui) === false) { + if(this._trigger("drag", event, ui) === false) { this._mouseUp({}); return false; } this.position = ui.position; } - if(!this.options.axis || this.options.axis != "y") this.helper[0].style.left = this.position.left+'px'; - if(!this.options.axis || this.options.axis != "x") this.helper[0].style.top = this.position.top+'px'; - if($.ui.ddmanager) $.ui.ddmanager.drag(this, event); + if(!this.options.axis || this.options.axis !== "y") { + this.helper[0].style.left = this.position.left+"px"; + } + if(!this.options.axis || this.options.axis !== "x") { + this.helper[0].style.top = this.position.top+"px"; + } + if($.ui.ddmanager) { + $.ui.ddmanager.drag(this, event); + } return false; }, @@ -1205,9 +1183,13 @@ $.widget("ui.draggable", $.ui.mouse, { _mouseStop: function(event) { //If we are using droppables, inform the manager about the drop - var dropped = false; - if ($.ui.ddmanager && !this.options.dropBehaviour) + var element, + that = this, + elementInDom = false, + dropped = false; + if ($.ui.ddmanager && !this.options.dropBehaviour) { dropped = $.ui.ddmanager.drop(this, event); + } //if a drop comes from outside (a sortable) if(this.dropped) { @@ -1216,17 +1198,17 @@ $.widget("ui.draggable", $.ui.mouse, { } //if the original element is no longer in the DOM don't bother to continue (see #8269) - var element = this.element[0], elementInDom = false; + element = this.element[0]; while ( element && (element = element.parentNode) ) { - if (element == document ) { + if (element === document ) { elementInDom = true; } } - if ( !elementInDom && this.options.helper === "original" ) + if ( !elementInDom && this.options.helper === "original" ) { return false; + } - if((this.options.revert == "invalid" && !dropped) || (this.options.revert == "valid" && dropped) || this.options.revert === true || ($.isFunction(this.options.revert) && this.options.revert.call(this.element, dropped))) { - var that = this; + if((this.options.revert === "invalid" && !dropped) || (this.options.revert === "valid" && dropped) || this.options.revert === true || ($.isFunction(this.options.revert) && this.options.revert.call(this.element, dropped))) { $(this.helper).animate(this.originalPosition, parseInt(this.options.revertDuration, 10), function() { if(that._trigger("stop", event) !== false) { that._clear(); @@ -1248,7 +1230,9 @@ $.widget("ui.draggable", $.ui.mouse, { }); //If the ddmanager is used for droppables, inform the manager that dragging has stopped (see #5003) - if( $.ui.ddmanager ) $.ui.ddmanager.dragStop(this, event); + if( $.ui.ddmanager ) { + $.ui.ddmanager.dragStop(this, event); + } return $.ui.mouse.prototype._mouseUp.call(this, event); }, @@ -1266,51 +1250,45 @@ $.widget("ui.draggable", $.ui.mouse, { }, _getHandle: function(event) { - - var handle = !this.options.handle || !$(this.options.handle, this.element).length ? true : false; - $(this.options.handle, this.element) - .find("*") - .andSelf() - .each(function() { - if(this == event.target) handle = true; - }); - - return handle; - + return this.options.handle ? + !!$( event.target ).closest( this.element.find( this.options.handle ) ).length : + true; }, _createHelper: function(event) { - var o = this.options; - var helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event])) : (o.helper == 'clone' ? this.element.clone().removeAttr('id') : this.element); + var o = this.options, + helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event])) : (o.helper === "clone" ? this.element.clone().removeAttr("id") : this.element); - if(!helper.parents('body').length) - helper.appendTo((o.appendTo == 'parent' ? this.element[0].parentNode : o.appendTo)); + if(!helper.parents("body").length) { + helper.appendTo((o.appendTo === "parent" ? this.element[0].parentNode : o.appendTo)); + } - if(helper[0] != this.element[0] && !(/(fixed|absolute)/).test(helper.css("position"))) + if(helper[0] !== this.element[0] && !(/(fixed|absolute)/).test(helper.css("position"))) { helper.css("position", "absolute"); + } return helper; }, _adjustOffsetFromHelper: function(obj) { - if (typeof obj == 'string') { - obj = obj.split(' '); + if (typeof obj === "string") { + obj = obj.split(" "); } if ($.isArray(obj)) { obj = {left: +obj[0], top: +obj[1] || 0}; } - if ('left' in obj) { + if ("left" in obj) { this.offset.click.left = obj.left + this.margins.left; } - if ('right' in obj) { + if ("right" in obj) { this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left; } - if ('top' in obj) { + if ("top" in obj) { this.offset.click.top = obj.top + this.margins.top; } - if ('bottom' in obj) { + if ("bottom" in obj) { this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top; } }, @@ -1325,14 +1303,17 @@ $.widget("ui.draggable", $.ui.mouse, { // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag - if(this.cssPosition == 'absolute' && this.scrollParent[0] != document && $.contains(this.scrollParent[0], this.offsetParent[0])) { + if(this.cssPosition === "absolute" && this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) { po.left += this.scrollParent.scrollLeft(); po.top += this.scrollParent.scrollTop(); } - if((this.offsetParent[0] == document.body) //This needs to be actually done for all browsers, since pageX/pageY includes this information - || (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() == 'html' && $.ui.ie)) //Ugly IE fix + //This needs to be actually done for all browsers, since pageX/pageY includes this information + //Ugly IE fix + if((this.offsetParent[0] === document.body) || + (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() === "html" && $.ui.ie)) { po = { top: 0, left: 0 }; + } return { top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0), @@ -1343,7 +1324,7 @@ $.widget("ui.draggable", $.ui.mouse, { _getRelativeOffset: function() { - if(this.cssPosition == "relative") { + if(this.cssPosition === "relative") { var p = this.element.position(); return { top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(), @@ -1373,30 +1354,40 @@ $.widget("ui.draggable", $.ui.mouse, { _setContainment: function() { - var o = this.options; - if(o.containment == 'parent') o.containment = this.helper[0].parentNode; - if(o.containment == 'document' || o.containment == 'window') this.containment = [ - o.containment == 'document' ? 0 : $(window).scrollLeft() - this.offset.relative.left - this.offset.parent.left, - o.containment == 'document' ? 0 : $(window).scrollTop() - this.offset.relative.top - this.offset.parent.top, - (o.containment == 'document' ? 0 : $(window).scrollLeft()) + $(o.containment == 'document' ? document : window).width() - this.helperProportions.width - this.margins.left, - (o.containment == 'document' ? 0 : $(window).scrollTop()) + ($(o.containment == 'document' ? document : window).height() || document.body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top - ]; + var over, c, ce, + o = this.options; + + if(o.containment === "parent") { + o.containment = this.helper[0].parentNode; + } + if(o.containment === "document" || o.containment === "window") { + this.containment = [ + o.containment === "document" ? 0 : $(window).scrollLeft() - this.offset.relative.left - this.offset.parent.left, + o.containment === "document" ? 0 : $(window).scrollTop() - this.offset.relative.top - this.offset.parent.top, + (o.containment === "document" ? 0 : $(window).scrollLeft()) + $(o.containment === "document" ? document : window).width() - this.helperProportions.width - this.margins.left, + (o.containment === "document" ? 0 : $(window).scrollTop()) + ($(o.containment === "document" ? document : window).height() || document.body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top + ]; + } + + if(!(/^(document|window|parent)$/).test(o.containment) && o.containment.constructor !== Array) { + c = $(o.containment); + ce = c[0]; - if(!(/^(document|window|parent)$/).test(o.containment) && o.containment.constructor != Array) { - var c = $(o.containment); - var ce = c[0]; if(!ce) return; - var co = c.offset(); - var over = ($(ce).css("overflow") != 'hidden'); + if(!ce) { + return; + } + + over = ($(ce).css("overflow") !== "hidden"); this.containment = [ (parseInt($(ce).css("borderLeftWidth"),10) || 0) + (parseInt($(ce).css("paddingLeft"),10) || 0), (parseInt($(ce).css("borderTopWidth"),10) || 0) + (parseInt($(ce).css("paddingTop"),10) || 0), - (over ? Math.max(ce.scrollWidth,ce.offsetWidth) : ce.offsetWidth) - (parseInt($(ce).css("borderLeftWidth"),10) || 0) - (parseInt($(ce).css("paddingRight"),10) || 0) - this.helperProportions.width - this.margins.left - this.margins.right, - (over ? Math.max(ce.scrollHeight,ce.offsetHeight) : ce.offsetHeight) - (parseInt($(ce).css("borderTopWidth"),10) || 0) - (parseInt($(ce).css("paddingBottom"),10) || 0) - this.helperProportions.height - this.margins.top - this.margins.bottom + (over ? Math.max(ce.scrollWidth,ce.offsetWidth) : ce.offsetWidth) - (parseInt($(ce).css("borderRightWidth"),10) || 0) - (parseInt($(ce).css("paddingRight"),10) || 0) - this.helperProportions.width - this.margins.left - this.margins.right, + (over ? Math.max(ce.scrollHeight,ce.offsetHeight) : ce.offsetHeight) - (parseInt($(ce).css("borderBottomWidth"),10) || 0) - (parseInt($(ce).css("paddingBottom"),10) || 0) - this.helperProportions.height - this.margins.top - this.margins.bottom ]; this.relative_container = c; - } else if(o.containment.constructor == Array) { + } else if(o.containment.constructor === Array) { this.containment = o.containment; } @@ -1404,22 +1395,25 @@ $.widget("ui.draggable", $.ui.mouse, { _convertPositionTo: function(d, pos) { - if(!pos) pos = this.position; - var mod = d == "absolute" ? 1 : -1; - var o = this.options, scroll = this.cssPosition == 'absolute' && !(this.scrollParent[0] != document && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName); + if(!pos) { + pos = this.position; + } + + var mod = d === "absolute" ? 1 : -1, + scroll = this.cssPosition === "absolute" && !(this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName); return { top: ( - pos.top // The absolute mouse position - + this.offset.relative.top * mod // Only for relative positioned nodes: Relative offset from element to offset parent - + this.offset.parent.top * mod // The offsetParent's offset without borders (offset + border) - - ( ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod) + pos.top + // The absolute mouse position + this.offset.relative.top * mod + // Only for relative positioned nodes: Relative offset from element to offset parent + this.offset.parent.top * mod - // The offsetParent's offset without borders (offset + border) + ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod) ), left: ( - pos.left // The absolute mouse position - + this.offset.relative.left * mod // Only for relative positioned nodes: Relative offset from element to offset parent - + this.offset.parent.left * mod // The offsetParent's offset without borders (offset + border) - - ( ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) * mod) + pos.left + // The absolute mouse position + this.offset.relative.left * mod + // Only for relative positioned nodes: Relative offset from element to offset parent + this.offset.parent.left * mod - // The offsetParent's offset without borders (offset + border) + ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) * mod) ) }; @@ -1427,9 +1421,12 @@ $.widget("ui.draggable", $.ui.mouse, { _generatePosition: function(event) { - var o = this.options, scroll = this.cssPosition == 'absolute' && !(this.scrollParent[0] != document && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName); - var pageX = event.pageX; - var pageY = event.pageY; + var containment, co, top, left, + o = this.options, + scroll = this.cssPosition === "absolute" && !(this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, + scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName), + pageX = event.pageX, + pageY = event.pageY; /* * - Position constraining - @@ -1437,10 +1434,9 @@ $.widget("ui.draggable", $.ui.mouse, { */ if(this.originalPosition) { //If we are not dragging yet, we won't check for options - var containment; if(this.containment) { if (this.relative_container){ - var co = this.relative_container.offset(); + co = this.relative_container.offset(); containment = [ this.containment[0] + co.left, this.containment[1] + co.top, this.containment[2] + co.left, @@ -1450,37 +1446,45 @@ $.widget("ui.draggable", $.ui.mouse, { containment = this.containment; } - if(event.pageX - this.offset.click.left < containment[0]) pageX = containment[0] + this.offset.click.left; - if(event.pageY - this.offset.click.top < containment[1]) pageY = containment[1] + this.offset.click.top; - if(event.pageX - this.offset.click.left > containment[2]) pageX = containment[2] + this.offset.click.left; - if(event.pageY - this.offset.click.top > containment[3]) pageY = containment[3] + this.offset.click.top; + if(event.pageX - this.offset.click.left < containment[0]) { + pageX = containment[0] + this.offset.click.left; + } + if(event.pageY - this.offset.click.top < containment[1]) { + pageY = containment[1] + this.offset.click.top; + } + if(event.pageX - this.offset.click.left > containment[2]) { + pageX = containment[2] + this.offset.click.left; + } + if(event.pageY - this.offset.click.top > containment[3]) { + pageY = containment[3] + this.offset.click.top; + } } if(o.grid) { //Check for grid elements set to 0 to prevent divide by 0 error causing invalid argument errors in IE (see ticket #6950) - var top = o.grid[1] ? this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1] : this.originalPageY; - pageY = containment ? (!(top - this.offset.click.top < containment[1] || top - this.offset.click.top > containment[3]) ? top : (!(top - this.offset.click.top < containment[1]) ? top - o.grid[1] : top + o.grid[1])) : top; + top = o.grid[1] ? this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1] : this.originalPageY; + pageY = containment ? ((top - this.offset.click.top >= containment[1] || top - this.offset.click.top > containment[3]) ? top : ((top - this.offset.click.top >= containment[1]) ? top - o.grid[1] : top + o.grid[1])) : top; - var left = o.grid[0] ? this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0] : this.originalPageX; - pageX = containment ? (!(left - this.offset.click.left < containment[0] || left - this.offset.click.left > containment[2]) ? left : (!(left - this.offset.click.left < containment[0]) ? left - o.grid[0] : left + o.grid[0])) : left; + left = o.grid[0] ? this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0] : this.originalPageX; + pageX = containment ? ((left - this.offset.click.left >= containment[0] || left - this.offset.click.left > containment[2]) ? left : ((left - this.offset.click.left >= containment[0]) ? left - o.grid[0] : left + o.grid[0])) : left; } } return { top: ( - pageY // The absolute mouse position - - this.offset.click.top // Click offset (relative to the element) - - this.offset.relative.top // Only for relative positioned nodes: Relative offset from element to offset parent - - this.offset.parent.top // The offsetParent's offset without borders (offset + border) - + ( ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) )) + pageY - // The absolute mouse position + this.offset.click.top - // Click offset (relative to the element) + this.offset.relative.top - // Only for relative positioned nodes: Relative offset from element to offset parent + this.offset.parent.top + // The offsetParent's offset without borders (offset + border) + ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) )) ), left: ( - pageX // The absolute mouse position - - this.offset.click.left // Click offset (relative to the element) - - this.offset.relative.left // Only for relative positioned nodes: Relative offset from element to offset parent - - this.offset.parent.left // The offsetParent's offset without borders (offset + border) - + ( ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() )) + pageX - // The absolute mouse position + this.offset.click.left - // Click offset (relative to the element) + this.offset.relative.left - // Only for relative positioned nodes: Relative offset from element to offset parent + this.offset.parent.left + // The offsetParent's offset without borders (offset + border) + ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() )) ) }; @@ -1488,8 +1492,9 @@ $.widget("ui.draggable", $.ui.mouse, { _clear: function() { this.helper.removeClass("ui-draggable-dragging"); - if(this.helper[0] != this.element[0] && !this.cancelHelperRemoval) this.helper.remove(); - //if($.ui.ddmanager) $.ui.ddmanager.current = null; + if(this.helper[0] !== this.element[0] && !this.cancelHelperRemoval) { + this.helper.remove(); + } this.helper = null; this.cancelHelperRemoval = false; }, @@ -1499,13 +1504,16 @@ $.widget("ui.draggable", $.ui.mouse, { _trigger: function(type, event, ui) { ui = ui || this._uiHash(); $.ui.plugin.call(this, type, [event, ui]); - if(type == "drag") this.positionAbs = this._convertPositionTo("absolute"); //The absolute position has to be recalculated after plugins + //The absolute position has to be recalculated after plugins + if(type === "drag") { + this.positionAbs = this._convertPositionTo("absolute"); + } return $.Widget.prototype._trigger.call(this, type, event, ui); }, plugins: {}, - _uiHash: function(event) { + _uiHash: function() { return { helper: this.helper, position: this.position, @@ -1519,11 +1527,11 @@ $.widget("ui.draggable", $.ui.mouse, { $.ui.plugin.add("draggable", "connectToSortable", { start: function(event, ui) { - var inst = $(this).data("draggable"), o = inst.options, + var inst = $(this).data("ui-draggable"), o = inst.options, uiSortable = $.extend({}, ui, { item: inst.element }); inst.sortables = []; $(o.connectToSortable).each(function() { - var sortable = $.data(this, 'sortable'); + var sortable = $.data(this, "ui-sortable"); if (sortable && !sortable.options.disabled) { inst.sortables.push({ instance: sortable, @@ -1538,7 +1546,7 @@ $.ui.plugin.add("draggable", "connectToSortable", { stop: function(event, ui) { //If we are still over the sortable, we fake the stop event of the sortable, but also remove helper - var inst = $(this).data("draggable"), + var inst = $(this).data("ui-draggable"), uiSortable = $.extend({}, ui, { item: inst.element }); $.each(inst.sortables, function() { @@ -1549,8 +1557,10 @@ $.ui.plugin.add("draggable", "connectToSortable", { inst.cancelHelperRemoval = true; //Don't remove the helper in the draggable instance this.instance.cancelHelperRemoval = false; //Remove it in the sortable instance (so sortable plugins like revert still work) - //The sortable revert is supported, and we have to set a temporary dropped variable on the draggable to support revert: 'valid/invalid' - if(this.shouldRevert) this.instance.options.revert = true; + //The sortable revert is supported, and we have to set a temporary dropped variable on the draggable to support revert: "valid/invalid" + if(this.shouldRevert) { + this.instance.options.revert = this.shouldRevert; + } //Trigger the stop of the sortable this.instance._mouseStop(event); @@ -1558,8 +1568,9 @@ $.ui.plugin.add("draggable", "connectToSortable", { this.instance.options.helper = this.instance.options._helper; //If the helper has been the original item, restore properties in the sortable - if(inst.options.helper == 'original') - this.instance.currentItem.css({ top: 'auto', left: 'auto' }); + if(inst.options.helper === "original") { + this.instance.currentItem.css({ top: "auto", left: "auto" }); + } } else { this.instance.cancelHelperRemoval = false; //Remove the helper in the sortable instance @@ -1571,21 +1582,13 @@ $.ui.plugin.add("draggable", "connectToSortable", { }, drag: function(event, ui) { - var inst = $(this).data("draggable"), that = this; + var inst = $(this).data("ui-draggable"), that = this; - var checkPos = function(o) { - var dyClick = this.offset.click.top, dxClick = this.offset.click.left; - var helperTop = this.positionAbs.top, helperLeft = this.positionAbs.left; - var itemHeight = o.height, itemWidth = o.width; - var itemTop = o.top, itemLeft = o.left; - - return $.ui.isOver(helperTop + dyClick, helperLeft + dxClick, itemTop, itemLeft, itemHeight, itemWidth); - }; + $.each(inst.sortables, function() { - $.each(inst.sortables, function(i) { + var innermostIntersecting = false, + thisSortable = this; - var innermostIntersecting = false; - var thisSortable = this; //Copy over some variables to allow calling the sortable's native _intersectsWith this.instance.positionAbs = inst.positionAbs; this.instance.helperProportions = inst.helperProportions; @@ -1597,11 +1600,13 @@ $.ui.plugin.add("draggable", "connectToSortable", { this.instance.positionAbs = inst.positionAbs; this.instance.helperProportions = inst.helperProportions; this.instance.offset.click = inst.offset.click; - if (this != thisSortable - && this.instance._intersectsWith(this.instance.containerCache) - && $.ui.contains(thisSortable.instance.element[0], this.instance.element[0])) + if (this !== thisSortable && + this.instance._intersectsWith(this.instance.containerCache) && + $.contains(thisSortable.instance.element[0], this.instance.element[0]) + ) { innermostIntersecting = false; - return innermostIntersecting; + } + return innermostIntersecting; }); } @@ -1614,7 +1619,7 @@ $.ui.plugin.add("draggable", "connectToSortable", { //Now we fake the start of dragging for the sortable instance, //by cloning the list group item, appending it to the sortable and using it as inst.currentItem //We can then fire the start event of the sortable with our passed browser event, and our own helper (so it doesn't create a new one) - this.instance.currentItem = $(that).clone().removeAttr('id').appendTo(this.instance.element).data("sortable-item", true); + this.instance.currentItem = $(that).clone().removeAttr("id").appendTo(this.instance.element).data("ui-sortable-item", true); this.instance.options._helper = this.instance.options.helper; //Store helper option to later restore it this.instance.options.helper = function() { return ui.helper[0]; }; @@ -1637,7 +1642,9 @@ $.ui.plugin.add("draggable", "connectToSortable", { } //Provided we did all the previous steps, we can fire the drag event of the sortable on every draggable drag, when it intersects with the sortable - if(this.instance.currentItem) this.instance._mouseDrag(event); + if(this.instance.currentItem) { + this.instance._mouseDrag(event); + } } else { @@ -1652,20 +1659,22 @@ $.ui.plugin.add("draggable", "connectToSortable", { this.instance.options.revert = false; // The out event needs to be triggered independently - this.instance._trigger('out', event, this.instance._uiHash(this.instance)); + this.instance._trigger("out", event, this.instance._uiHash(this.instance)); this.instance._mouseStop(event, true); this.instance.options.helper = this.instance.options._helper; //Now we remove our currentItem, the list group clone again, and the placeholder, and animate the helper back to it's original size this.instance.currentItem.remove(); - if(this.instance.placeholder) this.instance.placeholder.remove(); + if(this.instance.placeholder) { + this.instance.placeholder.remove(); + } inst._trigger("fromSortable", event); inst.dropped = false; //draggable revert needs that } - }; + } }); @@ -1673,176 +1682,220 @@ $.ui.plugin.add("draggable", "connectToSortable", { }); $.ui.plugin.add("draggable", "cursor", { - start: function(event, ui) { - var t = $('body'), o = $(this).data('draggable').options; - if (t.css("cursor")) o._cursor = t.css("cursor"); + start: function() { + var t = $("body"), o = $(this).data("ui-draggable").options; + if (t.css("cursor")) { + o._cursor = t.css("cursor"); + } t.css("cursor", o.cursor); }, - stop: function(event, ui) { - var o = $(this).data('draggable').options; - if (o._cursor) $('body').css("cursor", o._cursor); + stop: function() { + var o = $(this).data("ui-draggable").options; + if (o._cursor) { + $("body").css("cursor", o._cursor); + } } }); $.ui.plugin.add("draggable", "opacity", { start: function(event, ui) { - var t = $(ui.helper), o = $(this).data('draggable').options; - if(t.css("opacity")) o._opacity = t.css("opacity"); - t.css('opacity', o.opacity); + var t = $(ui.helper), o = $(this).data("ui-draggable").options; + if(t.css("opacity")) { + o._opacity = t.css("opacity"); + } + t.css("opacity", o.opacity); }, stop: function(event, ui) { - var o = $(this).data('draggable').options; - if(o._opacity) $(ui.helper).css('opacity', o._opacity); + var o = $(this).data("ui-draggable").options; + if(o._opacity) { + $(ui.helper).css("opacity", o._opacity); + } } }); $.ui.plugin.add("draggable", "scroll", { - start: function(event, ui) { - var i = $(this).data("draggable"); - if(i.scrollParent[0] != document && i.scrollParent[0].tagName != 'HTML') i.overflowOffset = i.scrollParent.offset(); + start: function() { + var i = $(this).data("ui-draggable"); + if(i.scrollParent[0] !== document && i.scrollParent[0].tagName !== "HTML") { + i.overflowOffset = i.scrollParent.offset(); + } }, - drag: function(event, ui) { + drag: function( event ) { - var i = $(this).data("draggable"), o = i.options, scrolled = false; + var i = $(this).data("ui-draggable"), o = i.options, scrolled = false; - if(i.scrollParent[0] != document && i.scrollParent[0].tagName != 'HTML') { + if(i.scrollParent[0] !== document && i.scrollParent[0].tagName !== "HTML") { - if(!o.axis || o.axis != 'x') { - if((i.overflowOffset.top + i.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity) + if(!o.axis || o.axis !== "x") { + if((i.overflowOffset.top + i.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity) { i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop + o.scrollSpeed; - else if(event.pageY - i.overflowOffset.top < o.scrollSensitivity) + } else if(event.pageY - i.overflowOffset.top < o.scrollSensitivity) { i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop - o.scrollSpeed; + } } - if(!o.axis || o.axis != 'y') { - if((i.overflowOffset.left + i.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity) + if(!o.axis || o.axis !== "y") { + if((i.overflowOffset.left + i.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity) { i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft + o.scrollSpeed; - else if(event.pageX - i.overflowOffset.left < o.scrollSensitivity) + } else if(event.pageX - i.overflowOffset.left < o.scrollSensitivity) { i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft - o.scrollSpeed; + } } } else { - if(!o.axis || o.axis != 'x') { - if(event.pageY - $(document).scrollTop() < o.scrollSensitivity) + if(!o.axis || o.axis !== "x") { + if(event.pageY - $(document).scrollTop() < o.scrollSensitivity) { scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed); - else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity) + } else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity) { scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed); + } } - if(!o.axis || o.axis != 'y') { - if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity) + if(!o.axis || o.axis !== "y") { + if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity) { scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed); - else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity) + } else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity) { scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed); + } } } - if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) + if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) { $.ui.ddmanager.prepareOffsets(i, event); + } } }); $.ui.plugin.add("draggable", "snap", { - start: function(event, ui) { + start: function() { + + var i = $(this).data("ui-draggable"), + o = i.options; - var i = $(this).data("draggable"), o = i.options; i.snapElements = []; - $(o.snap.constructor != String ? ( o.snap.items || ':data(draggable)' ) : o.snap).each(function() { - var $t = $(this); var $o = $t.offset(); - if(this != i.element[0]) i.snapElements.push({ - item: this, - width: $t.outerWidth(), height: $t.outerHeight(), - top: $o.top, left: $o.left - }); + $(o.snap.constructor !== String ? ( o.snap.items || ":data(ui-draggable)" ) : o.snap).each(function() { + var $t = $(this), + $o = $t.offset(); + if(this !== i.element[0]) { + i.snapElements.push({ + item: this, + width: $t.outerWidth(), height: $t.outerHeight(), + top: $o.top, left: $o.left + }); + } }); }, drag: function(event, ui) { - var inst = $(this).data("draggable"), o = inst.options; - var d = o.snapTolerance; - - var x1 = ui.offset.left, x2 = x1 + inst.helperProportions.width, + var ts, bs, ls, rs, l, r, t, b, i, first, + inst = $(this).data("ui-draggable"), + o = inst.options, + d = o.snapTolerance, + x1 = ui.offset.left, x2 = x1 + inst.helperProportions.width, y1 = ui.offset.top, y2 = y1 + inst.helperProportions.height; - for (var i = inst.snapElements.length - 1; i >= 0; i--){ + for (i = inst.snapElements.length - 1; i >= 0; i--){ - var l = inst.snapElements[i].left, r = l + inst.snapElements[i].width, - t = inst.snapElements[i].top, b = t + inst.snapElements[i].height; + l = inst.snapElements[i].left; + r = l + inst.snapElements[i].width; + t = inst.snapElements[i].top; + b = t + inst.snapElements[i].height; //Yes, I know, this is insane ;) if(!((l-d < x1 && x1 < r+d && t-d < y1 && y1 < b+d) || (l-d < x1 && x1 < r+d && t-d < y2 && y2 < b+d) || (l-d < x2 && x2 < r+d && t-d < y1 && y1 < b+d) || (l-d < x2 && x2 < r+d && t-d < y2 && y2 < b+d))) { - if(inst.snapElements[i].snapping) (inst.options.snap.release && inst.options.snap.release.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item }))); + if(inst.snapElements[i].snapping) { + (inst.options.snap.release && inst.options.snap.release.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item }))); + } inst.snapElements[i].snapping = false; continue; } - if(o.snapMode != 'inner') { - var ts = Math.abs(t - y2) <= d; - var bs = Math.abs(b - y1) <= d; - var ls = Math.abs(l - x2) <= d; - var rs = Math.abs(r - x1) <= d; - if(ts) ui.position.top = inst._convertPositionTo("relative", { top: t - inst.helperProportions.height, left: 0 }).top - inst.margins.top; - if(bs) ui.position.top = inst._convertPositionTo("relative", { top: b, left: 0 }).top - inst.margins.top; - if(ls) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l - inst.helperProportions.width }).left - inst.margins.left; - if(rs) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r }).left - inst.margins.left; + if(o.snapMode !== "inner") { + ts = Math.abs(t - y2) <= d; + bs = Math.abs(b - y1) <= d; + ls = Math.abs(l - x2) <= d; + rs = Math.abs(r - x1) <= d; + if(ts) { + ui.position.top = inst._convertPositionTo("relative", { top: t - inst.helperProportions.height, left: 0 }).top - inst.margins.top; + } + if(bs) { + ui.position.top = inst._convertPositionTo("relative", { top: b, left: 0 }).top - inst.margins.top; + } + if(ls) { + ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l - inst.helperProportions.width }).left - inst.margins.left; + } + if(rs) { + ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r }).left - inst.margins.left; + } } - var first = (ts || bs || ls || rs); + first = (ts || bs || ls || rs); - if(o.snapMode != 'outer') { - var ts = Math.abs(t - y1) <= d; - var bs = Math.abs(b - y2) <= d; - var ls = Math.abs(l - x1) <= d; - var rs = Math.abs(r - x2) <= d; - if(ts) ui.position.top = inst._convertPositionTo("relative", { top: t, left: 0 }).top - inst.margins.top; - if(bs) ui.position.top = inst._convertPositionTo("relative", { top: b - inst.helperProportions.height, left: 0 }).top - inst.margins.top; - if(ls) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l }).left - inst.margins.left; - if(rs) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r - inst.helperProportions.width }).left - inst.margins.left; + if(o.snapMode !== "outer") { + ts = Math.abs(t - y1) <= d; + bs = Math.abs(b - y2) <= d; + ls = Math.abs(l - x1) <= d; + rs = Math.abs(r - x2) <= d; + if(ts) { + ui.position.top = inst._convertPositionTo("relative", { top: t, left: 0 }).top - inst.margins.top; + } + if(bs) { + ui.position.top = inst._convertPositionTo("relative", { top: b - inst.helperProportions.height, left: 0 }).top - inst.margins.top; + } + if(ls) { + ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l }).left - inst.margins.left; + } + if(rs) { + ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r - inst.helperProportions.width }).left - inst.margins.left; + } } - if(!inst.snapElements[i].snapping && (ts || bs || ls || rs || first)) + if(!inst.snapElements[i].snapping && (ts || bs || ls || rs || first)) { (inst.options.snap.snap && inst.options.snap.snap.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item }))); + } inst.snapElements[i].snapping = (ts || bs || ls || rs || first); - }; + } } }); $.ui.plugin.add("draggable", "stack", { - start: function(event, ui) { - - var o = $(this).data("draggable").options; + start: function() { + var min, + o = this.data("ui-draggable").options, + group = $.makeArray($(o.stack)).sort(function(a,b) { + return (parseInt($(a).css("zIndex"),10) || 0) - (parseInt($(b).css("zIndex"),10) || 0); + }); - var group = $.makeArray($(o.stack)).sort(function(a,b) { - return (parseInt($(a).css("zIndex"),10) || 0) - (parseInt($(b).css("zIndex"),10) || 0); - }); if (!group.length) { return; } - var min = parseInt(group[0].style.zIndex) || 0; + min = parseInt($(group[0]).css("zIndex"), 10) || 0; $(group).each(function(i) { - this.style.zIndex = min + i; + $(this).css("zIndex", min + i); }); - - this[0].style.zIndex = min + group.length; - + this.css("zIndex", (min + group.length)); } }); $.ui.plugin.add("draggable", "zIndex", { start: function(event, ui) { - var t = $(ui.helper), o = $(this).data("draggable").options; - if(t.css("zIndex")) o._zIndex = t.css("zIndex"); - t.css('zIndex', o.zIndex); + var t = $(ui.helper), o = $(this).data("ui-draggable").options; + if(t.css("zIndex")) { + o._zIndex = t.css("zIndex"); + } + t.css("zIndex", o.zIndex); }, stop: function(event, ui) { - var o = $(this).data("draggable").options; - if(o._zIndex) $(ui.helper).css('zIndex', o._zIndex); + var o = $(this).data("ui-draggable").options; + if(o._zIndex) { + $(ui.helper).css("zIndex", o._zIndex); + } } }); @@ -1850,22 +1903,36 @@ $.ui.plugin.add("draggable", "zIndex", { (function( $, undefined ) { +function isOverAxis( x, reference, size ) { + return ( x > reference ) && ( x < ( reference + size ) ); +} + $.widget("ui.droppable", { - version: "1.9.2", + version: "1.10.2", widgetEventPrefix: "drop", options: { - accept: '*', + accept: "*", activeClass: false, addClasses: true, greedy: false, hoverClass: false, - scope: 'default', - tolerance: 'intersect' + scope: "default", + tolerance: "intersect", + + // callbacks + activate: null, + deactivate: null, + drop: null, + out: null, + over: null }, _create: function() { - var o = this.options, accept = o.accept; - this.isover = 0; this.isout = 1; + var o = this.options, + accept = o.accept; + + this.isover = false; + this.isout = true; this.accept = $.isFunction(accept) ? accept : function(d) { return d.is(accept); @@ -1883,17 +1950,21 @@ $.widget("ui.droppable", { }, _destroy: function() { - var drop = $.ui.ddmanager.droppables[this.options.scope]; - for ( var i = 0; i < drop.length; i++ ) - if ( drop[i] == this ) + var i = 0, + drop = $.ui.ddmanager.droppables[this.options.scope]; + + for ( ; i < drop.length; i++ ) { + if ( drop[i] === this ) { drop.splice(i, 1); + } + } this.element.removeClass("ui-droppable ui-droppable-disabled"); }, _setOption: function(key, value) { - if(key == 'accept') { + if(key === "accept") { this.accept = $.isFunction(value) ? value : function(d) { return d.is(value); }; @@ -1903,24 +1974,38 @@ $.widget("ui.droppable", { _activate: function(event) { var draggable = $.ui.ddmanager.current; - if(this.options.activeClass) this.element.addClass(this.options.activeClass); - (draggable && this._trigger('activate', event, this.ui(draggable))); + if(this.options.activeClass) { + this.element.addClass(this.options.activeClass); + } + if(draggable){ + this._trigger("activate", event, this.ui(draggable)); + } }, _deactivate: function(event) { var draggable = $.ui.ddmanager.current; - if(this.options.activeClass) this.element.removeClass(this.options.activeClass); - (draggable && this._trigger('deactivate', event, this.ui(draggable))); + if(this.options.activeClass) { + this.element.removeClass(this.options.activeClass); + } + if(draggable){ + this._trigger("deactivate", event, this.ui(draggable)); + } }, _over: function(event) { var draggable = $.ui.ddmanager.current; - if (!draggable || (draggable.currentItem || draggable.element)[0] == this.element[0]) return; // Bail if draggable and droppable are same element + + // Bail if draggable and droppable are same element + if (!draggable || (draggable.currentItem || draggable.element)[0] === this.element[0]) { + return; + } if (this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) { - if(this.options.hoverClass) this.element.addClass(this.options.hoverClass); - this._trigger('over', event, this.ui(draggable)); + if(this.options.hoverClass) { + this.element.addClass(this.options.hoverClass); + } + this._trigger("over", event, this.ui(draggable)); } }, @@ -1928,37 +2013,53 @@ $.widget("ui.droppable", { _out: function(event) { var draggable = $.ui.ddmanager.current; - if (!draggable || (draggable.currentItem || draggable.element)[0] == this.element[0]) return; // Bail if draggable and droppable are same element + + // Bail if draggable and droppable are same element + if (!draggable || (draggable.currentItem || draggable.element)[0] === this.element[0]) { + return; + } if (this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) { - if(this.options.hoverClass) this.element.removeClass(this.options.hoverClass); - this._trigger('out', event, this.ui(draggable)); + if(this.options.hoverClass) { + this.element.removeClass(this.options.hoverClass); + } + this._trigger("out", event, this.ui(draggable)); } }, _drop: function(event,custom) { - var draggable = custom || $.ui.ddmanager.current; - if (!draggable || (draggable.currentItem || draggable.element)[0] == this.element[0]) return false; // Bail if draggable and droppable are same element + var draggable = custom || $.ui.ddmanager.current, + childrenIntersection = false; + + // Bail if draggable and droppable are same element + if (!draggable || (draggable.currentItem || draggable.element)[0] === this.element[0]) { + return false; + } - var childrenIntersection = false; - this.element.find(":data(droppable)").not(".ui-draggable-dragging").each(function() { - var inst = $.data(this, 'droppable'); + this.element.find(":data(ui-droppable)").not(".ui-draggable-dragging").each(function() { + var inst = $.data(this, "ui-droppable"); if( - inst.options.greedy - && !inst.options.disabled - && inst.options.scope == draggable.options.scope - && inst.accept.call(inst.element[0], (draggable.currentItem || draggable.element)) - && $.ui.intersect(draggable, $.extend(inst, { offset: inst.element.offset() }), inst.options.tolerance) + inst.options.greedy && + !inst.options.disabled && + inst.options.scope === draggable.options.scope && + inst.accept.call(inst.element[0], (draggable.currentItem || draggable.element)) && + $.ui.intersect(draggable, $.extend(inst, { offset: inst.element.offset() }), inst.options.tolerance) ) { childrenIntersection = true; return false; } }); - if(childrenIntersection) return false; + if(childrenIntersection) { + return false; + } if(this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) { - if(this.options.activeClass) this.element.removeClass(this.options.activeClass); - if(this.options.hoverClass) this.element.removeClass(this.options.hoverClass); - this._trigger('drop', event, this.ui(draggable)); + if(this.options.activeClass) { + this.element.removeClass(this.options.activeClass); + } + if(this.options.hoverClass) { + this.element.removeClass(this.options.hoverClass); + } + this._trigger("drop", event, this.ui(draggable)); return this.element; } @@ -1979,44 +2080,40 @@ $.widget("ui.droppable", { $.ui.intersect = function(draggable, droppable, toleranceMode) { - if (!droppable.offset) return false; + if (!droppable.offset) { + return false; + } - var x1 = (draggable.positionAbs || draggable.position.absolute).left, x2 = x1 + draggable.helperProportions.width, - y1 = (draggable.positionAbs || draggable.position.absolute).top, y2 = y1 + draggable.helperProportions.height; - var l = droppable.offset.left, r = l + droppable.proportions.width, + var draggableLeft, draggableTop, + x1 = (draggable.positionAbs || draggable.position.absolute).left, x2 = x1 + draggable.helperProportions.width, + y1 = (draggable.positionAbs || draggable.position.absolute).top, y2 = y1 + draggable.helperProportions.height, + l = droppable.offset.left, r = l + droppable.proportions.width, t = droppable.offset.top, b = t + droppable.proportions.height; switch (toleranceMode) { - case 'fit': - return (l <= x1 && x2 <= r - && t <= y1 && y2 <= b); - break; - case 'intersect': - return (l < x1 + (draggable.helperProportions.width / 2) // Right Half - && x2 - (draggable.helperProportions.width / 2) < r // Left Half - && t < y1 + (draggable.helperProportions.height / 2) // Bottom Half - && y2 - (draggable.helperProportions.height / 2) < b ); // Top Half - break; - case 'pointer': - var draggableLeft = ((draggable.positionAbs || draggable.position.absolute).left + (draggable.clickOffset || draggable.offset.click).left), - draggableTop = ((draggable.positionAbs || draggable.position.absolute).top + (draggable.clickOffset || draggable.offset.click).top), - isOver = $.ui.isOver(draggableTop, draggableLeft, t, l, droppable.proportions.height, droppable.proportions.width); - return isOver; - break; - case 'touch': + case "fit": + return (l <= x1 && x2 <= r && t <= y1 && y2 <= b); + case "intersect": + return (l < x1 + (draggable.helperProportions.width / 2) && // Right Half + x2 - (draggable.helperProportions.width / 2) < r && // Left Half + t < y1 + (draggable.helperProportions.height / 2) && // Bottom Half + y2 - (draggable.helperProportions.height / 2) < b ); // Top Half + case "pointer": + draggableLeft = ((draggable.positionAbs || draggable.position.absolute).left + (draggable.clickOffset || draggable.offset.click).left); + draggableTop = ((draggable.positionAbs || draggable.position.absolute).top + (draggable.clickOffset || draggable.offset.click).top); + return isOverAxis( draggableTop, t, droppable.proportions.height ) && isOverAxis( draggableLeft, l, droppable.proportions.width ); + case "touch": return ( - (y1 >= t && y1 <= b) || // Top edge touching - (y2 >= t && y2 <= b) || // Bottom edge touching - (y1 < t && y2 > b) // Surrounded vertically - ) && ( - (x1 >= l && x1 <= r) || // Left edge touching - (x2 >= l && x2 <= r) || // Right edge touching - (x1 < l && x2 > r) // Surrounded horizontally - ); - break; + (y1 >= t && y1 <= b) || // Top edge touching + (y2 >= t && y2 <= b) || // Bottom edge touching + (y1 < t && y2 > b) // Surrounded vertically + ) && ( + (x1 >= l && x1 <= r) || // Left edge touching + (x2 >= l && x2 <= r) || // Right edge touching + (x1 < l && x2 > r) // Surrounded horizontally + ); default: return false; - break; } }; @@ -2026,20 +2123,38 @@ $.ui.intersect = function(draggable, droppable, toleranceMode) { */ $.ui.ddmanager = { current: null, - droppables: { 'default': [] }, + droppables: { "default": [] }, prepareOffsets: function(t, event) { - var m = $.ui.ddmanager.droppables[t.options.scope] || []; - var type = event ? event.type : null; // workaround for #2317 - var list = (t.currentItem || t.element).find(":data(droppable)").andSelf(); + var i, j, + m = $.ui.ddmanager.droppables[t.options.scope] || [], + type = event ? event.type : null, // workaround for #2317 + list = (t.currentItem || t.element).find(":data(ui-droppable)").addBack(); + + droppablesLoop: for (i = 0; i < m.length; i++) { + + //No disabled and non-accepted + if(m[i].options.disabled || (t && !m[i].accept.call(m[i].element[0],(t.currentItem || t.element)))) { + continue; + } - droppablesLoop: for (var i = 0; i < m.length; i++) { + // Filter out elements in the current dragged item + for (j=0; j < list.length; j++) { + if(list[j] === m[i].element[0]) { + m[i].proportions.height = 0; + continue droppablesLoop; + } + } - if(m[i].options.disabled || (t && !m[i].accept.call(m[i].element[0],(t.currentItem || t.element)))) continue; //No disabled and non-accepted - for (var j=0; j < list.length; j++) { if(list[j] == m[i].element[0]) { m[i].proportions.height = 0; continue droppablesLoop; } }; //Filter out elements in the current dragged item - m[i].visible = m[i].element.css("display") != "none"; if(!m[i].visible) continue; //If the element is not visible, continue + m[i].visible = m[i].element.css("display") !== "none"; + if(!m[i].visible) { + continue; + } - if(type == "mousedown") m[i]._activate.call(m[i], event); //Activate the droppable if used directly from draggables + //Activate the droppable if used directly from draggables + if(type === "mousedown") { + m[i]._activate.call(m[i], event); + } m[i].offset = m[i].element.offset(); m[i].proportions = { width: m[i].element[0].offsetWidth, height: m[i].element[0].offsetHeight }; @@ -2050,14 +2165,19 @@ $.ui.ddmanager = { drop: function(draggable, event) { var dropped = false; - $.each($.ui.ddmanager.droppables[draggable.options.scope] || [], function() { + // Create a copy of the droppables in case the list changes during the drop (#9116) + $.each(($.ui.ddmanager.droppables[draggable.options.scope] || []).slice(), function() { - if(!this.options) return; - if (!this.options.disabled && this.visible && $.ui.intersect(draggable, this, this.options.tolerance)) + if(!this.options) { + return; + } + if (!this.options.disabled && this.visible && $.ui.intersect(draggable, this, this.options.tolerance)) { dropped = this._drop.call(this, event) || dropped; + } if (!this.options.disabled && this.visible && this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) { - this.isout = 1; this.isover = 0; + this.isout = true; + this.isover = false; this._deactivate.call(this, event); } @@ -2068,51 +2188,60 @@ $.ui.ddmanager = { dragStart: function( draggable, event ) { //Listen for scrolling so that if the dragging causes scrolling the position of the droppables can be recalculated (see #5003) draggable.element.parentsUntil( "body" ).bind( "scroll.droppable", function() { - if( !draggable.options.refreshPositions ) $.ui.ddmanager.prepareOffsets( draggable, event ); + if( !draggable.options.refreshPositions ) { + $.ui.ddmanager.prepareOffsets( draggable, event ); + } }); }, drag: function(draggable, event) { //If you have a highly dynamic page, you might try this option. It renders positions every time you move the mouse. - if(draggable.options.refreshPositions) $.ui.ddmanager.prepareOffsets(draggable, event); + if(draggable.options.refreshPositions) { + $.ui.ddmanager.prepareOffsets(draggable, event); + } //Run through all droppables and check their positions based on specific tolerance options $.each($.ui.ddmanager.droppables[draggable.options.scope] || [], function() { - if(this.options.disabled || this.greedyChild || !this.visible) return; - var intersects = $.ui.intersect(draggable, this, this.options.tolerance); + if(this.options.disabled || this.greedyChild || !this.visible) { + return; + } - var c = !intersects && this.isover == 1 ? 'isout' : (intersects && this.isover == 0 ? 'isover' : null); - if(!c) return; + var parentInstance, scope, parent, + intersects = $.ui.intersect(draggable, this, this.options.tolerance), + c = !intersects && this.isover ? "isout" : (intersects && !this.isover ? "isover" : null); + if(!c) { + return; + } - var parentInstance; if (this.options.greedy) { // find droppable parents with same scope - var scope = this.options.scope; - var parent = this.element.parents(':data(droppable)').filter(function () { - return $.data(this, 'droppable').options.scope === scope; + scope = this.options.scope; + parent = this.element.parents(":data(ui-droppable)").filter(function () { + return $.data(this, "ui-droppable").options.scope === scope; }); if (parent.length) { - parentInstance = $.data(parent[0], 'droppable'); - parentInstance.greedyChild = (c == 'isover' ? 1 : 0); + parentInstance = $.data(parent[0], "ui-droppable"); + parentInstance.greedyChild = (c === "isover"); } } // we just moved into a greedy child - if (parentInstance && c == 'isover') { - parentInstance['isover'] = 0; - parentInstance['isout'] = 1; + if (parentInstance && c === "isover") { + parentInstance.isover = false; + parentInstance.isout = true; parentInstance._out.call(parentInstance, event); } - this[c] = 1; this[c == 'isout' ? 'isover' : 'isout'] = 0; - this[c == "isover" ? "_over" : "_out"].call(this, event); + this[c] = true; + this[c === "isout" ? "isover" : "isout"] = false; + this[c === "isover" ? "_over" : "_out"].call(this, event); // we just moved out of a greedy child - if (parentInstance && c == 'isout') { - parentInstance['isout'] = 0; - parentInstance['isover'] = 1; + if (parentInstance && c === "isout") { + parentInstance.isout = false; + parentInstance.isover = true; parentInstance._over.call(parentInstance, event); } }); @@ -2121,7 +2250,9 @@ $.ui.ddmanager = { dragStop: function( draggable, event ) { draggable.element.parentsUntil( "body" ).unbind( "scroll.droppable" ); //Call prepareOffsets one final time since IE does not fire return scroll events when overflow was caused by drag (see #5003) - if( !draggable.options.refreshPositions ) $.ui.ddmanager.prepareOffsets( draggable, event ); + if( !draggable.options.refreshPositions ) { + $.ui.ddmanager.prepareOffsets( draggable, event ); + } } }; @@ -2129,8 +2260,16 @@ $.ui.ddmanager = { (function( $, undefined ) { +function num(v) { + return parseInt(v, 10) || 0; +} + +function isNumber(value) { + return !isNaN(parseInt(value, 10)); +} + $.widget("ui.resizable", $.ui.mouse, { - version: "1.9.2", + version: "1.10.2", widgetEventPrefix: "resize", options: { alsoResize: false, @@ -2148,11 +2287,19 @@ $.widget("ui.resizable", $.ui.mouse, { maxWidth: null, minHeight: 10, minWidth: 10, - zIndex: 1000 + // See #7960 + zIndex: 90, + + // callbacks + resize: null, + start: null, + stop: null }, _create: function() { - var that = this, o = this.options; + var n, i, handle, axis, hname, + that = this, + o = this.options; this.element.addClass("ui-resizable"); $.extend(this, { @@ -2160,7 +2307,7 @@ $.widget("ui.resizable", $.ui.mouse, { aspectRatio: o.aspectRatio, originalElement: this.element, _proportionallyResizeElements: [], - _helper: o.helper || o.ghost || o.animate ? o.helper || 'ui-resizable-helper' : null + _helper: o.helper || o.ghost || o.animate ? o.helper || "ui-resizable-helper" : null }); //Wrap the element if it cannot hold child nodes @@ -2168,18 +2315,18 @@ $.widget("ui.resizable", $.ui.mouse, { //Create a wrapper element and set the wrapper to the new current internal element this.element.wrap( - $('<div class="ui-wrapper" style="overflow: hidden;"></div>').css({ - position: this.element.css('position'), + $("<div class='ui-wrapper' style='overflow: hidden;'></div>").css({ + position: this.element.css("position"), width: this.element.outerWidth(), height: this.element.outerHeight(), - top: this.element.css('top'), - left: this.element.css('left') + top: this.element.css("top"), + left: this.element.css("left") }) ); //Overwrite the original this.element this.element = this.element.parent().data( - "resizable", this.element.data('resizable') + "ui-resizable", this.element.data("ui-resizable") ); this.elementIsWrapper = true; @@ -2189,41 +2336,46 @@ $.widget("ui.resizable", $.ui.mouse, { this.originalElement.css({ marginLeft: 0, marginTop: 0, marginRight: 0, marginBottom: 0}); //Prevent Safari textarea resize - this.originalResizeStyle = this.originalElement.css('resize'); - this.originalElement.css('resize', 'none'); + this.originalResizeStyle = this.originalElement.css("resize"); + this.originalElement.css("resize", "none"); //Push the actual element to our proportionallyResize internal array - this._proportionallyResizeElements.push(this.originalElement.css({ position: 'static', zoom: 1, display: 'block' })); + this._proportionallyResizeElements.push(this.originalElement.css({ position: "static", zoom: 1, display: "block" })); // avoid IE jump (hard set the margin) - this.originalElement.css({ margin: this.originalElement.css('margin') }); + this.originalElement.css({ margin: this.originalElement.css("margin") }); // fix handlers offset this._proportionallyResize(); } - this.handles = o.handles || (!$('.ui-resizable-handle', this.element).length ? "e,s,se" : { n: '.ui-resizable-n', e: '.ui-resizable-e', s: '.ui-resizable-s', w: '.ui-resizable-w', se: '.ui-resizable-se', sw: '.ui-resizable-sw', ne: '.ui-resizable-ne', nw: '.ui-resizable-nw' }); - if(this.handles.constructor == String) { + this.handles = o.handles || (!$(".ui-resizable-handle", this.element).length ? "e,s,se" : { n: ".ui-resizable-n", e: ".ui-resizable-e", s: ".ui-resizable-s", w: ".ui-resizable-w", se: ".ui-resizable-se", sw: ".ui-resizable-sw", ne: ".ui-resizable-ne", nw: ".ui-resizable-nw" }); + if(this.handles.constructor === String) { + + if ( this.handles === "all") { + this.handles = "n,e,s,w,se,sw,ne,nw"; + } - if(this.handles == 'all') this.handles = 'n,e,s,w,se,sw,ne,nw'; - var n = this.handles.split(","); this.handles = {}; + n = this.handles.split(","); + this.handles = {}; - for(var i = 0; i < n.length; i++) { + for(i = 0; i < n.length; i++) { - var handle = $.trim(n[i]), hname = 'ui-resizable-'+handle; - var axis = $('<div class="ui-resizable-handle ' + hname + '"></div>'); + handle = $.trim(n[i]); + hname = "ui-resizable-"+handle; + axis = $("<div class='ui-resizable-handle " + hname + "'></div>"); // Apply zIndex to all handles - see #7960 axis.css({ zIndex: o.zIndex }); //TODO : What's going on here? - if ('se' == handle) { - axis.addClass('ui-icon ui-icon-gripsmall-diagonal-se'); - }; + if ("se" === handle) { + axis.addClass("ui-icon ui-icon-gripsmall-diagonal-se"); + } //Insert into internal handles object and append to element - this.handles[handle] = '.ui-resizable-'+handle; + this.handles[handle] = ".ui-resizable-"+handle; this.element.append(axis); } @@ -2231,26 +2383,29 @@ $.widget("ui.resizable", $.ui.mouse, { this._renderAxis = function(target) { + var i, axis, padPos, padWrapper; + target = target || this.element; - for(var i in this.handles) { + for(i in this.handles) { - if(this.handles[i].constructor == String) + if(this.handles[i].constructor === String) { this.handles[i] = $(this.handles[i], this.element).show(); + } //Apply pad to wrapper element, needed to fix axis position (textarea, inputs, scrolls) if (this.elementIsWrapper && this.originalElement[0].nodeName.match(/textarea|input|select|button/i)) { - var axis = $(this.handles[i], this.element), padWrapper = 0; + axis = $(this.handles[i], this.element); //Checking the correct pad and border padWrapper = /sw|ne|nw|se|n|s/.test(i) ? axis.outerHeight() : axis.outerWidth(); //The padding type i have to apply... - var padPos = [ 'padding', - /ne|nw|n/.test(i) ? 'Top' : - /se|sw|s/.test(i) ? 'Bottom' : - /^e$/.test(i) ? 'Right' : 'Left' ].join(""); + padPos = [ "padding", + /ne|nw|n/.test(i) ? "Top" : + /se|sw|s/.test(i) ? "Bottom" : + /^e$/.test(i) ? "Right" : "Left" ].join(""); target.css(padPos, padWrapper); @@ -2259,25 +2414,26 @@ $.widget("ui.resizable", $.ui.mouse, { } //TODO: What's that good for? There's not anything to be executed left - if(!$(this.handles[i]).length) + if(!$(this.handles[i]).length) { continue; - + } } }; //TODO: make renderAxis a prototype function this._renderAxis(this.element); - this._handles = $('.ui-resizable-handle', this.element) + this._handles = $(".ui-resizable-handle", this.element) .disableSelection(); //Matching axis name this._handles.mouseover(function() { if (!that.resizing) { - if (this.className) - var axis = this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i); + if (this.className) { + axis = this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i); + } //Axis, default = se - that.axis = axis && axis[1] ? axis[1] : 'se'; + that.axis = axis && axis[1] ? axis[1] : "se"; } }); @@ -2287,12 +2443,16 @@ $.widget("ui.resizable", $.ui.mouse, { $(this.element) .addClass("ui-resizable-autohide") .mouseenter(function() { - if (o.disabled) return; + if (o.disabled) { + return; + } $(this).removeClass("ui-resizable-autohide"); that._handles.show(); }) .mouseleave(function(){ - if (o.disabled) return; + if (o.disabled) { + return; + } if (!that.resizing) { $(this).addClass("ui-resizable-autohide"); that._handles.hide(); @@ -2309,57 +2469,66 @@ $.widget("ui.resizable", $.ui.mouse, { this._mouseDestroy(); - var _destroy = function(exp) { - $(exp).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing") - .removeData("resizable").removeData("ui-resizable").unbind(".resizable").find('.ui-resizable-handle').remove(); - }; + var wrapper, + _destroy = function(exp) { + $(exp).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing") + .removeData("resizable").removeData("ui-resizable").unbind(".resizable").find(".ui-resizable-handle").remove(); + }; //TODO: Unwrap at same DOM position if (this.elementIsWrapper) { _destroy(this.element); - var wrapper = this.element; + wrapper = this.element; this.originalElement.css({ - position: wrapper.css('position'), + position: wrapper.css("position"), width: wrapper.outerWidth(), height: wrapper.outerHeight(), - top: wrapper.css('top'), - left: wrapper.css('left') + top: wrapper.css("top"), + left: wrapper.css("left") }).insertAfter( wrapper ); wrapper.remove(); } - this.originalElement.css('resize', this.originalResizeStyle); + this.originalElement.css("resize", this.originalResizeStyle); _destroy(this.originalElement); return this; }, _mouseCapture: function(event) { - var handle = false; - for (var i in this.handles) { - if ($(this.handles[i])[0] == event.target) { - handle = true; + var i, handle, + capture = false; + + for (i in this.handles) { + handle = $(this.handles[i])[0]; + if (handle === event.target || $.contains(handle, event.target)) { + capture = true; } } - return !this.options.disabled && handle; + return !this.options.disabled && capture; }, _mouseStart: function(event) { - var o = this.options, iniPos = this.element.position(), el = this.element; + var curleft, curtop, cursor, + o = this.options, + iniPos = this.element.position(), + el = this.element; this.resizing = true; - this.documentScroll = { top: $(document).scrollTop(), left: $(document).scrollLeft() }; // bugfix for http://dev.jquery.com/ticket/1749 - if (el.is('.ui-draggable') || (/absolute/).test(el.css('position'))) { - el.css({ position: 'absolute', top: iniPos.top, left: iniPos.left }); + if ( (/absolute/).test( el.css("position") ) ) { + el.css({ position: "absolute", top: el.css("top"), left: el.css("left") }); + } else if (el.is(".ui-draggable")) { + el.css({ position: "absolute", top: iniPos.top, left: iniPos.left }); } this._renderProxy(); - var curleft = num(this.helper.css('left')), curtop = num(this.helper.css('top')); + curleft = num(this.helper.css("left")); + curtop = num(this.helper.css("top")); if (o.containment) { curleft += $(o.containment).scrollLeft() || 0; @@ -2376,10 +2545,10 @@ $.widget("ui.resizable", $.ui.mouse, { this.originalMousePosition = { left: event.pageX, top: event.pageY }; //Aspect Ratio - this.aspectRatio = (typeof o.aspectRatio == 'number') ? o.aspectRatio : ((this.originalSize.width / this.originalSize.height) || 1); + this.aspectRatio = (typeof o.aspectRatio === "number") ? o.aspectRatio : ((this.originalSize.width / this.originalSize.height) || 1); - var cursor = $('.ui-resizable-' + this.axis).css('cursor'); - $('body').css('cursor', cursor == 'auto' ? this.axis + '-resize' : cursor); + cursor = $(".ui-resizable-" + this.axis).css("cursor"); + $("body").css("cursor", cursor === "auto" ? this.axis + "-resize" : cursor); el.addClass("ui-resizable-resizing"); this._propagate("start", event); @@ -2389,38 +2558,60 @@ $.widget("ui.resizable", $.ui.mouse, { _mouseDrag: function(event) { //Increase performance, avoid regex - var el = this.helper, o = this.options, props = {}, - that = this, smp = this.originalMousePosition, a = this.axis; - - var dx = (event.pageX-smp.left)||0, dy = (event.pageY-smp.top)||0; - var trigger = this._change[a]; - if (!trigger) return false; + var data, + el = this.helper, props = {}, + smp = this.originalMousePosition, + a = this.axis, + prevTop = this.position.top, + prevLeft = this.position.left, + prevWidth = this.size.width, + prevHeight = this.size.height, + dx = (event.pageX-smp.left)||0, + dy = (event.pageY-smp.top)||0, + trigger = this._change[a]; + + if (!trigger) { + return false; + } // Calculate the attrs that will be change - var data = trigger.apply(this, [event, dx, dy]); + data = trigger.apply(this, [event, dx, dy]); // Put this in the mouseDrag handler since the user can start pressing shift while resizing this._updateVirtualBoundaries(event.shiftKey); - if (this._aspectRatio || event.shiftKey) + if (this._aspectRatio || event.shiftKey) { data = this._updateRatio(data, event); + } data = this._respectSize(data, event); + this._updateCache(data); + // plugins callbacks need to be called first this._propagate("resize", event); - el.css({ - top: this.position.top + "px", left: this.position.left + "px", - width: this.size.width + "px", height: this.size.height + "px" - }); + if (this.position.top !== prevTop) { + props.top = this.position.top + "px"; + } + if (this.position.left !== prevLeft) { + props.left = this.position.left + "px"; + } + if (this.size.width !== prevWidth) { + props.width = this.size.width + "px"; + } + if (this.size.height !== prevHeight) { + props.height = this.size.height + "px"; + } + el.css(props); - if (!this._helper && this._proportionallyResizeElements.length) + if (!this._helper && this._proportionallyResizeElements.length) { this._proportionallyResize(); + } - this._updateCache(data); - - // calling the user callback at the end - this._trigger('resize', event, this.ui()); + // Call the user callback if the element was resized + if ( ! $.isEmptyObject(props) ) { + this._trigger("resize", event, this.ui()); + } return false; }, @@ -2428,39 +2619,49 @@ $.widget("ui.resizable", $.ui.mouse, { _mouseStop: function(event) { this.resizing = false; - var o = this.options, that = this; + var pr, ista, soffseth, soffsetw, s, left, top, + o = this.options, that = this; if(this._helper) { - var pr = this._proportionallyResizeElements, ista = pr.length && (/textarea/i).test(pr[0].nodeName), - soffseth = ista && $.ui.hasScroll(pr[0], 'left') /* TODO - jump height */ ? 0 : that.sizeDiff.height, - soffsetw = ista ? 0 : that.sizeDiff.width; - var s = { width: (that.helper.width() - soffsetw), height: (that.helper.height() - soffseth) }, - left = (parseInt(that.element.css('left'), 10) + (that.position.left - that.originalPosition.left)) || null, - top = (parseInt(that.element.css('top'), 10) + (that.position.top - that.originalPosition.top)) || null; + pr = this._proportionallyResizeElements; + ista = pr.length && (/textarea/i).test(pr[0].nodeName); + soffseth = ista && $.ui.hasScroll(pr[0], "left") /* TODO - jump height */ ? 0 : that.sizeDiff.height; + soffsetw = ista ? 0 : that.sizeDiff.width; - if (!o.animate) + s = { width: (that.helper.width() - soffsetw), height: (that.helper.height() - soffseth) }; + left = (parseInt(that.element.css("left"), 10) + (that.position.left - that.originalPosition.left)) || null; + top = (parseInt(that.element.css("top"), 10) + (that.position.top - that.originalPosition.top)) || null; + + if (!o.animate) { this.element.css($.extend(s, { top: top, left: left })); + } that.helper.height(that.size.height); that.helper.width(that.size.width); - if (this._helper && !o.animate) this._proportionallyResize(); + if (this._helper && !o.animate) { + this._proportionallyResize(); + } } - $('body').css('cursor', 'auto'); + $("body").css("cursor", "auto"); this.element.removeClass("ui-resizable-resizing"); this._propagate("stop", event); - if (this._helper) this.helper.remove(); + if (this._helper) { + this.helper.remove(); + } + return false; }, _updateVirtualBoundaries: function(forceAspectRatio) { - var o = this.options, pMinWidth, pMaxWidth, pMinHeight, pMaxHeight, b; + var pMinWidth, pMaxWidth, pMinHeight, pMaxHeight, b, + o = this.options; b = { minWidth: isNumber(o.minWidth) ? o.minWidth : 0, @@ -2477,35 +2678,55 @@ $.widget("ui.resizable", $.ui.mouse, { pMaxWidth = b.maxHeight * this.aspectRatio; pMaxHeight = b.maxWidth / this.aspectRatio; - if(pMinWidth > b.minWidth) b.minWidth = pMinWidth; - if(pMinHeight > b.minHeight) b.minHeight = pMinHeight; - if(pMaxWidth < b.maxWidth) b.maxWidth = pMaxWidth; - if(pMaxHeight < b.maxHeight) b.maxHeight = pMaxHeight; + if(pMinWidth > b.minWidth) { + b.minWidth = pMinWidth; + } + if(pMinHeight > b.minHeight) { + b.minHeight = pMinHeight; + } + if(pMaxWidth < b.maxWidth) { + b.maxWidth = pMaxWidth; + } + if(pMaxHeight < b.maxHeight) { + b.maxHeight = pMaxHeight; + } } this._vBoundaries = b; }, _updateCache: function(data) { - var o = this.options; this.offset = this.helper.offset(); - if (isNumber(data.left)) this.position.left = data.left; - if (isNumber(data.top)) this.position.top = data.top; - if (isNumber(data.height)) this.size.height = data.height; - if (isNumber(data.width)) this.size.width = data.width; + if (isNumber(data.left)) { + this.position.left = data.left; + } + if (isNumber(data.top)) { + this.position.top = data.top; + } + if (isNumber(data.height)) { + this.size.height = data.height; + } + if (isNumber(data.width)) { + this.size.width = data.width; + } }, - _updateRatio: function(data, event) { + _updateRatio: function( data ) { - var o = this.options, cpos = this.position, csize = this.size, a = this.axis; + var cpos = this.position, + csize = this.size, + a = this.axis; - if (isNumber(data.height)) data.width = (data.height * this.aspectRatio); - else if (isNumber(data.width)) data.height = (data.width / this.aspectRatio); + if (isNumber(data.height)) { + data.width = (data.height * this.aspectRatio); + } else if (isNumber(data.width)) { + data.height = (data.width / this.aspectRatio); + } - if (a == 'sw') { + if (a === "sw") { data.left = cpos.left + (csize.width - data.width); data.top = null; } - if (a == 'nw') { + if (a === "nw") { data.top = cpos.top + (csize.height - data.height); data.left = cpos.left + (csize.width - data.width); } @@ -2513,51 +2734,72 @@ $.widget("ui.resizable", $.ui.mouse, { return data; }, - _respectSize: function(data, event) { - - var el = this.helper, o = this._vBoundaries, pRatio = this._aspectRatio || event.shiftKey, a = this.axis, - ismaxw = isNumber(data.width) && o.maxWidth && (o.maxWidth < data.width), ismaxh = isNumber(data.height) && o.maxHeight && (o.maxHeight < data.height), - isminw = isNumber(data.width) && o.minWidth && (o.minWidth > data.width), isminh = isNumber(data.height) && o.minHeight && (o.minHeight > data.height); - - if (isminw) data.width = o.minWidth; - if (isminh) data.height = o.minHeight; - if (ismaxw) data.width = o.maxWidth; - if (ismaxh) data.height = o.maxHeight; + _respectSize: function( data ) { - var dw = this.originalPosition.left + this.originalSize.width, dh = this.position.top + this.size.height; - var cw = /sw|nw|w/.test(a), ch = /nw|ne|n/.test(a); + var o = this._vBoundaries, + a = this.axis, + ismaxw = isNumber(data.width) && o.maxWidth && (o.maxWidth < data.width), ismaxh = isNumber(data.height) && o.maxHeight && (o.maxHeight < data.height), + isminw = isNumber(data.width) && o.minWidth && (o.minWidth > data.width), isminh = isNumber(data.height) && o.minHeight && (o.minHeight > data.height), + dw = this.originalPosition.left + this.originalSize.width, + dh = this.position.top + this.size.height, + cw = /sw|nw|w/.test(a), ch = /nw|ne|n/.test(a); + if (isminw) { + data.width = o.minWidth; + } + if (isminh) { + data.height = o.minHeight; + } + if (ismaxw) { + data.width = o.maxWidth; + } + if (ismaxh) { + data.height = o.maxHeight; + } - if (isminw && cw) data.left = dw - o.minWidth; - if (ismaxw && cw) data.left = dw - o.maxWidth; - if (isminh && ch) data.top = dh - o.minHeight; - if (ismaxh && ch) data.top = dh - o.maxHeight; + if (isminw && cw) { + data.left = dw - o.minWidth; + } + if (ismaxw && cw) { + data.left = dw - o.maxWidth; + } + if (isminh && ch) { + data.top = dh - o.minHeight; + } + if (ismaxh && ch) { + data.top = dh - o.maxHeight; + } // fixing jump error on top/left - bug #2330 - var isNotwh = !data.width && !data.height; - if (isNotwh && !data.left && data.top) data.top = null; - else if (isNotwh && !data.top && data.left) data.left = null; + if (!data.width && !data.height && !data.left && data.top) { + data.top = null; + } else if (!data.width && !data.height && !data.top && data.left) { + data.left = null; + } return data; }, _proportionallyResize: function() { - var o = this.options; - if (!this._proportionallyResizeElements.length) return; - var element = this.helper || this.element; + if (!this._proportionallyResizeElements.length) { + return; + } + + var i, j, borders, paddings, prel, + element = this.helper || this.element; - for (var i=0; i < this._proportionallyResizeElements.length; i++) { + for ( i=0; i < this._proportionallyResizeElements.length; i++) { - var prel = this._proportionallyResizeElements[i]; + prel = this._proportionallyResizeElements[i]; if (!this.borderDif) { - var b = [prel.css('borderTopWidth'), prel.css('borderRightWidth'), prel.css('borderBottomWidth'), prel.css('borderLeftWidth')], - p = [prel.css('paddingTop'), prel.css('paddingRight'), prel.css('paddingBottom'), prel.css('paddingLeft')]; + this.borderDif = []; + borders = [prel.css("borderTopWidth"), prel.css("borderRightWidth"), prel.css("borderBottomWidth"), prel.css("borderLeftWidth")]; + paddings = [prel.css("paddingTop"), prel.css("paddingRight"), prel.css("paddingBottom"), prel.css("paddingLeft")]; - this.borderDif = $.map(b, function(v, i) { - var border = parseInt(v,10)||0, padding = parseInt(p[i],10)||0; - return border + padding; - }); + for ( j = 0; j < borders.length; j++ ) { + this.borderDif[ j ] = ( parseInt( borders[ j ], 10 ) || 0 ) + ( parseInt( paddings[ j ], 10 ) || 0 ); + } } prel.css({ @@ -2565,7 +2807,7 @@ $.widget("ui.resizable", $.ui.mouse, { width: (element.width() - this.borderDif[1] - this.borderDif[3]) || 0 }); - }; + } }, @@ -2576,18 +2818,14 @@ $.widget("ui.resizable", $.ui.mouse, { if(this._helper) { - this.helper = this.helper || $('<div style="overflow:hidden;"></div>'); - - // fix ie6 offset TODO: This seems broken - var ie6offset = ($.ui.ie6 ? 1 : 0), - pxyoffset = ( $.ui.ie6 ? 2 : -1 ); + this.helper = this.helper || $("<div style='overflow:hidden;'></div>"); this.helper.addClass(this._helper).css({ - width: this.element.outerWidth() + pxyoffset, - height: this.element.outerHeight() + pxyoffset, - position: 'absolute', - left: this.elementOffset.left - ie6offset +'px', - top: this.elementOffset.top - ie6offset +'px', + width: this.element.outerWidth() - 1, + height: this.element.outerHeight() - 1, + position: "absolute", + left: this.elementOffset.left +"px", + top: this.elementOffset.top +"px", zIndex: ++o.zIndex //TODO: Don't modify option }); @@ -2602,15 +2840,15 @@ $.widget("ui.resizable", $.ui.mouse, { }, _change: { - e: function(event, dx, dy) { + e: function(event, dx) { return { width: this.originalSize.width + dx }; }, - w: function(event, dx, dy) { - var o = this.options, cs = this.originalSize, sp = this.originalPosition; + w: function(event, dx) { + var cs = this.originalSize, sp = this.originalPosition; return { left: sp.left + dx, width: cs.width - dx }; }, n: function(event, dx, dy) { - var o = this.options, cs = this.originalSize, sp = this.originalPosition; + var cs = this.originalSize, sp = this.originalPosition; return { top: sp.top + dy, height: cs.height - dy }; }, s: function(event, dx, dy) { @@ -2632,7 +2870,7 @@ $.widget("ui.resizable", $.ui.mouse, { _propagate: function(n, event) { $.ui.plugin.call(this, n, [event, this.ui()]); - (n != "resize" && this._trigger(n, event, this.ui())); + (n !== "resize" && this._trigger(n, event, this.ui())); }, plugins: {}, @@ -2655,76 +2893,18 @@ $.widget("ui.resizable", $.ui.mouse, { * Resizable Extensions */ -$.ui.plugin.add("resizable", "alsoResize", { - - start: function (event, ui) { - var that = $(this).data("resizable"), o = that.options; - - var _store = function (exp) { - $(exp).each(function() { - var el = $(this); - el.data("resizable-alsoresize", { - width: parseInt(el.width(), 10), height: parseInt(el.height(), 10), - left: parseInt(el.css('left'), 10), top: parseInt(el.css('top'), 10) - }); - }); - }; - - if (typeof(o.alsoResize) == 'object' && !o.alsoResize.parentNode) { - if (o.alsoResize.length) { o.alsoResize = o.alsoResize[0]; _store(o.alsoResize); } - else { $.each(o.alsoResize, function (exp) { _store(exp); }); } - }else{ - _store(o.alsoResize); - } - }, - - resize: function (event, ui) { - var that = $(this).data("resizable"), o = that.options, os = that.originalSize, op = that.originalPosition; - - var delta = { - height: (that.size.height - os.height) || 0, width: (that.size.width - os.width) || 0, - top: (that.position.top - op.top) || 0, left: (that.position.left - op.left) || 0 - }, - - _alsoResize = function (exp, c) { - $(exp).each(function() { - var el = $(this), start = $(this).data("resizable-alsoresize"), style = {}, - css = c && c.length ? c : el.parents(ui.originalElement[0]).length ? ['width', 'height'] : ['width', 'height', 'top', 'left']; - - $.each(css, function (i, prop) { - var sum = (start[prop]||0) + (delta[prop]||0); - if (sum && sum >= 0) - style[prop] = sum || null; - }); - - el.css(style); - }); - }; - - if (typeof(o.alsoResize) == 'object' && !o.alsoResize.nodeType) { - $.each(o.alsoResize, function (exp, c) { _alsoResize(exp, c); }); - }else{ - _alsoResize(o.alsoResize); - } - }, - - stop: function (event, ui) { - $(this).removeData("resizable-alsoresize"); - } -}); - $.ui.plugin.add("resizable", "animate", { - stop: function(event, ui) { - var that = $(this).data("resizable"), o = that.options; - - var pr = that._proportionallyResizeElements, ista = pr.length && (/textarea/i).test(pr[0].nodeName), - soffseth = ista && $.ui.hasScroll(pr[0], 'left') /* TODO - jump height */ ? 0 : that.sizeDiff.height, - soffsetw = ista ? 0 : that.sizeDiff.width; - - var style = { width: (that.size.width - soffsetw), height: (that.size.height - soffseth) }, - left = (parseInt(that.element.css('left'), 10) + (that.position.left - that.originalPosition.left)) || null, - top = (parseInt(that.element.css('top'), 10) + (that.position.top - that.originalPosition.top)) || null; + stop: function( event ) { + var that = $(this).data("ui-resizable"), + o = that.options, + pr = that._proportionallyResizeElements, + ista = pr.length && (/textarea/i).test(pr[0].nodeName), + soffseth = ista && $.ui.hasScroll(pr[0], "left") /* TODO - jump height */ ? 0 : that.sizeDiff.height, + soffsetw = ista ? 0 : that.sizeDiff.width, + style = { width: (that.size.width - soffsetw), height: (that.size.height - soffseth) }, + left = (parseInt(that.element.css("left"), 10) + (that.position.left - that.originalPosition.left)) || null, + top = (parseInt(that.element.css("top"), 10) + (that.position.top - that.originalPosition.top)) || null; that.element.animate( $.extend(style, top && left ? { top: top, left: left } : {}), { @@ -2733,13 +2913,15 @@ $.ui.plugin.add("resizable", "animate", { step: function() { var data = { - width: parseInt(that.element.css('width'), 10), - height: parseInt(that.element.css('height'), 10), - top: parseInt(that.element.css('top'), 10), - left: parseInt(that.element.css('left'), 10) + width: parseInt(that.element.css("width"), 10), + height: parseInt(that.element.css("height"), 10), + top: parseInt(that.element.css("top"), 10), + left: parseInt(that.element.css("left"), 10) }; - if (pr && pr.length) $(pr[0]).css({ width: data.width, height: data.height }); + if (pr && pr.length) { + $(pr[0]).css({ width: data.width, height: data.height }); + } // propagating resize, and updating values for each animation step that._updateCache(data); @@ -2754,14 +2936,21 @@ $.ui.plugin.add("resizable", "animate", { $.ui.plugin.add("resizable", "containment", { - start: function(event, ui) { - var that = $(this).data("resizable"), o = that.options, el = that.element; - var oc = o.containment, ce = (oc instanceof $) ? oc.get(0) : (/parent/.test(oc)) ? el.parent().get(0) : oc; - if (!ce) return; + start: function() { + var element, p, co, ch, cw, width, height, + that = $(this).data("ui-resizable"), + o = that.options, + el = that.element, + oc = o.containment, + ce = (oc instanceof $) ? oc.get(0) : (/parent/.test(oc)) ? el.parent().get(0) : oc; + + if (!ce) { + return; + } that.containerElement = $(ce); - if (/document/.test(oc) || oc == document) { + if (/document/.test(oc) || oc === document) { that.containerOffset = { left: 0, top: 0 }; that.containerPosition = { left: 0, top: 0 }; @@ -2773,15 +2962,19 @@ $.ui.plugin.add("resizable", "containment", { // i'm a node, so compute top, left, right, bottom else { - var element = $(ce), p = []; + element = $(ce); + p = []; $([ "Top", "Right", "Left", "Bottom" ]).each(function(i, name) { p[i] = num(element.css("padding" + name)); }); that.containerOffset = element.offset(); that.containerPosition = element.position(); that.containerSize = { height: (element.innerHeight() - p[3]), width: (element.innerWidth() - p[1]) }; - var co = that.containerOffset, ch = that.containerSize.height, cw = that.containerSize.width, - width = ($.ui.hasScroll(ce, "left") ? ce.scrollWidth : cw ), height = ($.ui.hasScroll(ce) ? ce.scrollHeight : ch); + co = that.containerOffset; + ch = that.containerSize.height; + cw = that.containerSize.width; + width = ($.ui.hasScroll(ce, "left") ? ce.scrollWidth : cw ); + height = ($.ui.hasScroll(ce) ? ce.scrollHeight : ch); that.parentData = { element: ce, left: co.left, top: co.top, width: width, height: height @@ -2789,114 +2982,227 @@ $.ui.plugin.add("resizable", "containment", { } }, - resize: function(event, ui) { - var that = $(this).data("resizable"), o = that.options, - ps = that.containerSize, co = that.containerOffset, cs = that.size, cp = that.position, - pRatio = that._aspectRatio || event.shiftKey, cop = { top:0, left:0 }, ce = that.containerElement; + resize: function( event ) { + var woset, hoset, isParent, isOffsetRelative, + that = $(this).data("ui-resizable"), + o = that.options, + co = that.containerOffset, cp = that.position, + pRatio = that._aspectRatio || event.shiftKey, + cop = { top:0, left:0 }, ce = that.containerElement; - if (ce[0] != document && (/static/).test(ce.css('position'))) cop = co; + if (ce[0] !== document && (/static/).test(ce.css("position"))) { + cop = co; + } if (cp.left < (that._helper ? co.left : 0)) { that.size.width = that.size.width + (that._helper ? (that.position.left - co.left) : (that.position.left - cop.left)); - if (pRatio) that.size.height = that.size.width / that.aspectRatio; + if (pRatio) { + that.size.height = that.size.width / that.aspectRatio; + } that.position.left = o.helper ? co.left : 0; } if (cp.top < (that._helper ? co.top : 0)) { that.size.height = that.size.height + (that._helper ? (that.position.top - co.top) : that.position.top); - if (pRatio) that.size.width = that.size.height * that.aspectRatio; + if (pRatio) { + that.size.width = that.size.height * that.aspectRatio; + } that.position.top = that._helper ? co.top : 0; } that.offset.left = that.parentData.left+that.position.left; that.offset.top = that.parentData.top+that.position.top; - var woset = Math.abs( (that._helper ? that.offset.left - cop.left : (that.offset.left - cop.left)) + that.sizeDiff.width ), - hoset = Math.abs( (that._helper ? that.offset.top - cop.top : (that.offset.top - co.top)) + that.sizeDiff.height ); + woset = Math.abs( (that._helper ? that.offset.left - cop.left : (that.offset.left - cop.left)) + that.sizeDiff.width ); + hoset = Math.abs( (that._helper ? that.offset.top - cop.top : (that.offset.top - co.top)) + that.sizeDiff.height ); - var isParent = that.containerElement.get(0) == that.element.parent().get(0), - isOffsetRelative = /relative|absolute/.test(that.containerElement.css('position')); + isParent = that.containerElement.get(0) === that.element.parent().get(0); + isOffsetRelative = /relative|absolute/.test(that.containerElement.css("position")); - if(isParent && isOffsetRelative) woset -= that.parentData.left; + if(isParent && isOffsetRelative) { + woset -= that.parentData.left; + } if (woset + that.size.width >= that.parentData.width) { that.size.width = that.parentData.width - woset; - if (pRatio) that.size.height = that.size.width / that.aspectRatio; + if (pRatio) { + that.size.height = that.size.width / that.aspectRatio; + } } if (hoset + that.size.height >= that.parentData.height) { that.size.height = that.parentData.height - hoset; - if (pRatio) that.size.width = that.size.height * that.aspectRatio; + if (pRatio) { + that.size.width = that.size.height * that.aspectRatio; + } } }, - stop: function(event, ui){ - var that = $(this).data("resizable"), o = that.options, cp = that.position, - co = that.containerOffset, cop = that.containerPosition, ce = that.containerElement; - - var helper = $(that.helper), ho = helper.offset(), w = helper.outerWidth() - that.sizeDiff.width, h = helper.outerHeight() - that.sizeDiff.height; + stop: function(){ + var that = $(this).data("ui-resizable"), + o = that.options, + co = that.containerOffset, + cop = that.containerPosition, + ce = that.containerElement, + helper = $(that.helper), + ho = helper.offset(), + w = helper.outerWidth() - that.sizeDiff.width, + h = helper.outerHeight() - that.sizeDiff.height; - if (that._helper && !o.animate && (/relative/).test(ce.css('position'))) + if (that._helper && !o.animate && (/relative/).test(ce.css("position"))) { $(this).css({ left: ho.left - cop.left - co.left, width: w, height: h }); + } - if (that._helper && !o.animate && (/static/).test(ce.css('position'))) + if (that._helper && !o.animate && (/static/).test(ce.css("position"))) { $(this).css({ left: ho.left - cop.left - co.left, width: w, height: h }); + } + + } +}); + +$.ui.plugin.add("resizable", "alsoResize", { + + start: function () { + var that = $(this).data("ui-resizable"), + o = that.options, + _store = function (exp) { + $(exp).each(function() { + var el = $(this); + el.data("ui-resizable-alsoresize", { + width: parseInt(el.width(), 10), height: parseInt(el.height(), 10), + left: parseInt(el.css("left"), 10), top: parseInt(el.css("top"), 10) + }); + }); + }; + + if (typeof(o.alsoResize) === "object" && !o.alsoResize.parentNode) { + if (o.alsoResize.length) { o.alsoResize = o.alsoResize[0]; _store(o.alsoResize); } + else { $.each(o.alsoResize, function (exp) { _store(exp); }); } + }else{ + _store(o.alsoResize); + } + }, + + resize: function (event, ui) { + var that = $(this).data("ui-resizable"), + o = that.options, + os = that.originalSize, + op = that.originalPosition, + delta = { + height: (that.size.height - os.height) || 0, width: (that.size.width - os.width) || 0, + top: (that.position.top - op.top) || 0, left: (that.position.left - op.left) || 0 + }, + + _alsoResize = function (exp, c) { + $(exp).each(function() { + var el = $(this), start = $(this).data("ui-resizable-alsoresize"), style = {}, + css = c && c.length ? c : el.parents(ui.originalElement[0]).length ? ["width", "height"] : ["width", "height", "top", "left"]; + + $.each(css, function (i, prop) { + var sum = (start[prop]||0) + (delta[prop]||0); + if (sum && sum >= 0) { + style[prop] = sum || null; + } + }); + + el.css(style); + }); + }; + + if (typeof(o.alsoResize) === "object" && !o.alsoResize.nodeType) { + $.each(o.alsoResize, function (exp, c) { _alsoResize(exp, c); }); + }else{ + _alsoResize(o.alsoResize); + } + }, + stop: function () { + $(this).removeData("resizable-alsoresize"); } }); $.ui.plugin.add("resizable", "ghost", { - start: function(event, ui) { + start: function() { - var that = $(this).data("resizable"), o = that.options, cs = that.size; + var that = $(this).data("ui-resizable"), o = that.options, cs = that.size; that.ghost = that.originalElement.clone(); that.ghost - .css({ opacity: .25, display: 'block', position: 'relative', height: cs.height, width: cs.width, margin: 0, left: 0, top: 0 }) - .addClass('ui-resizable-ghost') - .addClass(typeof o.ghost == 'string' ? o.ghost : ''); + .css({ opacity: 0.25, display: "block", position: "relative", height: cs.height, width: cs.width, margin: 0, left: 0, top: 0 }) + .addClass("ui-resizable-ghost") + .addClass(typeof o.ghost === "string" ? o.ghost : ""); that.ghost.appendTo(that.helper); }, - resize: function(event, ui){ - var that = $(this).data("resizable"), o = that.options; - if (that.ghost) that.ghost.css({ position: 'relative', height: that.size.height, width: that.size.width }); + resize: function(){ + var that = $(this).data("ui-resizable"); + if (that.ghost) { + that.ghost.css({ position: "relative", height: that.size.height, width: that.size.width }); + } }, - stop: function(event, ui){ - var that = $(this).data("resizable"), o = that.options; - if (that.ghost && that.helper) that.helper.get(0).removeChild(that.ghost.get(0)); + stop: function() { + var that = $(this).data("ui-resizable"); + if (that.ghost && that.helper) { + that.helper.get(0).removeChild(that.ghost.get(0)); + } } }); $.ui.plugin.add("resizable", "grid", { - resize: function(event, ui) { - var that = $(this).data("resizable"), o = that.options, cs = that.size, os = that.originalSize, op = that.originalPosition, a = that.axis, ratio = o._aspectRatio || event.shiftKey; - o.grid = typeof o.grid == "number" ? [o.grid, o.grid] : o.grid; - var ox = Math.round((cs.width - os.width) / (o.grid[0]||1)) * (o.grid[0]||1), oy = Math.round((cs.height - os.height) / (o.grid[1]||1)) * (o.grid[1]||1); + resize: function() { + var that = $(this).data("ui-resizable"), + o = that.options, + cs = that.size, + os = that.originalSize, + op = that.originalPosition, + a = that.axis, + grid = typeof o.grid === "number" ? [o.grid, o.grid] : o.grid, + gridX = (grid[0]||1), + gridY = (grid[1]||1), + ox = Math.round((cs.width - os.width) / gridX) * gridX, + oy = Math.round((cs.height - os.height) / gridY) * gridY, + newWidth = os.width + ox, + newHeight = os.height + oy, + isMaxWidth = o.maxWidth && (o.maxWidth < newWidth), + isMaxHeight = o.maxHeight && (o.maxHeight < newHeight), + isMinWidth = o.minWidth && (o.minWidth > newWidth), + isMinHeight = o.minHeight && (o.minHeight > newHeight); + + o.grid = grid; + + if (isMinWidth) { + newWidth = newWidth + gridX; + } + if (isMinHeight) { + newHeight = newHeight + gridY; + } + if (isMaxWidth) { + newWidth = newWidth - gridX; + } + if (isMaxHeight) { + newHeight = newHeight - gridY; + } if (/^(se|s|e)$/.test(a)) { - that.size.width = os.width + ox; - that.size.height = os.height + oy; - } - else if (/^(ne)$/.test(a)) { - that.size.width = os.width + ox; - that.size.height = os.height + oy; + that.size.width = newWidth; + that.size.height = newHeight; + } else if (/^(ne)$/.test(a)) { + that.size.width = newWidth; + that.size.height = newHeight; that.position.top = op.top - oy; - } - else if (/^(sw)$/.test(a)) { - that.size.width = os.width + ox; - that.size.height = os.height + oy; + } else if (/^(sw)$/.test(a)) { + that.size.width = newWidth; + that.size.height = newHeight; that.position.left = op.left - ox; - } - else { - that.size.width = os.width + ox; - that.size.height = os.height + oy; + } else { + that.size.width = newWidth; + that.size.height = newHeight; that.position.top = op.top - oy; that.position.left = op.left - ox; } @@ -2904,42 +3210,42 @@ $.ui.plugin.add("resizable", "grid", { }); -var num = function(v) { - return parseInt(v, 10) || 0; -}; - -var isNumber = function(value) { - return !isNaN(parseInt(value, 10)); -}; - })(jQuery); (function( $, undefined ) { $.widget("ui.selectable", $.ui.mouse, { - version: "1.9.2", + version: "1.10.2", options: { - appendTo: 'body', + appendTo: "body", autoRefresh: true, distance: 0, - filter: '*', - tolerance: 'touch' + filter: "*", + tolerance: "touch", + + // callbacks + selected: null, + selecting: null, + start: null, + stop: null, + unselected: null, + unselecting: null }, _create: function() { - var that = this; + var selectees, + that = this; this.element.addClass("ui-selectable"); this.dragged = false; // cache selectee children based on filter - var selectees; this.refresh = function() { selectees = $(that.options.filter, that.element[0]); selectees.addClass("ui-selectee"); selectees.each(function() { - var $this = $(this); - var pos = $this.offset(); + var $this = $(this), + pos = $this.offset(); $.data(this, "selectable-item", { element: this, $element: $this, @@ -2948,9 +3254,9 @@ $.widget("ui.selectable", $.ui.mouse, { right: pos.left + $this.outerWidth(), bottom: pos.top + $this.outerHeight(), startselected: false, - selected: $this.hasClass('ui-selected'), - selecting: $this.hasClass('ui-selecting'), - unselecting: $this.hasClass('ui-unselecting') + selected: $this.hasClass("ui-selected"), + selecting: $this.hasClass("ui-selecting"), + unselecting: $this.hasClass("ui-unselecting") }); }); }; @@ -2973,14 +3279,14 @@ $.widget("ui.selectable", $.ui.mouse, { }, _mouseStart: function(event) { - var that = this; + var that = this, + options = this.options; this.opos = [event.pageX, event.pageY]; - if (this.options.disabled) + if (this.options.disabled) { return; - - var options = this.options; + } this.selectees = $(options.filter, this.element[0]); @@ -2989,8 +3295,8 @@ $.widget("ui.selectable", $.ui.mouse, { $(options.appendTo).append(this.helper); // position helper (lasso) this.helper.css({ - "left": event.clientX, - "top": event.clientY, + "left": event.pageX, + "top": event.pageY, "width": 0, "height": 0 }); @@ -2999,13 +3305,13 @@ $.widget("ui.selectable", $.ui.mouse, { this.refresh(); } - this.selectees.filter('.ui-selected').each(function() { + this.selectees.filter(".ui-selected").each(function() { var selectee = $.data(this, "selectable-item"); selectee.startselected = true; if (!event.metaKey && !event.ctrlKey) { - selectee.$element.removeClass('ui-selected'); + selectee.$element.removeClass("ui-selected"); selectee.selected = false; - selectee.$element.addClass('ui-unselecting'); + selectee.$element.addClass("ui-unselecting"); selectee.unselecting = true; // selectable UNSELECTING callback that._trigger("unselecting", event, { @@ -3014,10 +3320,11 @@ $.widget("ui.selectable", $.ui.mouse, { } }); - $(event.target).parents().andSelf().each(function() { - var selectee = $.data(this, "selectable-item"); + $(event.target).parents().addBack().each(function() { + var doSelect, + selectee = $.data(this, "selectable-item"); if (selectee) { - var doSelect = (!event.metaKey && !event.ctrlKey) || !selectee.$element.hasClass('ui-selected'); + doSelect = (!event.metaKey && !event.ctrlKey) || !selectee.$element.hasClass("ui-selected"); selectee.$element .removeClass(doSelect ? "ui-unselecting" : "ui-selected") .addClass(doSelect ? "ui-selecting" : "ui-unselecting"); @@ -3041,43 +3348,52 @@ $.widget("ui.selectable", $.ui.mouse, { }, _mouseDrag: function(event) { - var that = this; + this.dragged = true; - if (this.options.disabled) + if (this.options.disabled) { return; + } - var options = this.options; + var tmp, + that = this, + options = this.options, + x1 = this.opos[0], + y1 = this.opos[1], + x2 = event.pageX, + y2 = event.pageY; - var x1 = this.opos[0], y1 = this.opos[1], x2 = event.pageX, y2 = event.pageY; - if (x1 > x2) { var tmp = x2; x2 = x1; x1 = tmp; } - if (y1 > y2) { var tmp = y2; y2 = y1; y1 = tmp; } + if (x1 > x2) { tmp = x2; x2 = x1; x1 = tmp; } + if (y1 > y2) { tmp = y2; y2 = y1; y1 = tmp; } this.helper.css({left: x1, top: y1, width: x2-x1, height: y2-y1}); this.selectees.each(function() { - var selectee = $.data(this, "selectable-item"); + var selectee = $.data(this, "selectable-item"), + hit = false; + //prevent helper from being selected if appendTo: selectable - if (!selectee || selectee.element == that.element[0]) + if (!selectee || selectee.element === that.element[0]) { return; - var hit = false; - if (options.tolerance == 'touch') { + } + + if (options.tolerance === "touch") { hit = ( !(selectee.left > x2 || selectee.right < x1 || selectee.top > y2 || selectee.bottom < y1) ); - } else if (options.tolerance == 'fit') { + } else if (options.tolerance === "fit") { hit = (selectee.left > x1 && selectee.right < x2 && selectee.top > y1 && selectee.bottom < y2); } if (hit) { // SELECT if (selectee.selected) { - selectee.$element.removeClass('ui-selected'); + selectee.$element.removeClass("ui-selected"); selectee.selected = false; } if (selectee.unselecting) { - selectee.$element.removeClass('ui-unselecting'); + selectee.$element.removeClass("ui-unselecting"); selectee.unselecting = false; } if (!selectee.selecting) { - selectee.$element.addClass('ui-selecting'); + selectee.$element.addClass("ui-selecting"); selectee.selecting = true; // selectable SELECTING callback that._trigger("selecting", event, { @@ -3088,15 +3404,15 @@ $.widget("ui.selectable", $.ui.mouse, { // UNSELECT if (selectee.selecting) { if ((event.metaKey || event.ctrlKey) && selectee.startselected) { - selectee.$element.removeClass('ui-selecting'); + selectee.$element.removeClass("ui-selecting"); selectee.selecting = false; - selectee.$element.addClass('ui-selected'); + selectee.$element.addClass("ui-selected"); selectee.selected = true; } else { - selectee.$element.removeClass('ui-selecting'); + selectee.$element.removeClass("ui-selecting"); selectee.selecting = false; if (selectee.startselected) { - selectee.$element.addClass('ui-unselecting'); + selectee.$element.addClass("ui-unselecting"); selectee.unselecting = true; } // selectable UNSELECTING callback @@ -3107,10 +3423,10 @@ $.widget("ui.selectable", $.ui.mouse, { } if (selectee.selected) { if (!event.metaKey && !event.ctrlKey && !selectee.startselected) { - selectee.$element.removeClass('ui-selected'); + selectee.$element.removeClass("ui-selected"); selectee.selected = false; - selectee.$element.addClass('ui-unselecting'); + selectee.$element.addClass("ui-unselecting"); selectee.unselecting = true; // selectable UNSELECTING callback that._trigger("unselecting", event, { @@ -3129,20 +3445,18 @@ $.widget("ui.selectable", $.ui.mouse, { this.dragged = false; - var options = this.options; - - $('.ui-unselecting', this.element[0]).each(function() { + $(".ui-unselecting", this.element[0]).each(function() { var selectee = $.data(this, "selectable-item"); - selectee.$element.removeClass('ui-unselecting'); + selectee.$element.removeClass("ui-unselecting"); selectee.unselecting = false; selectee.startselected = false; that._trigger("unselected", event, { unselected: selectee.element }); }); - $('.ui-selecting', this.element[0]).each(function() { + $(".ui-selecting", this.element[0]).each(function() { var selectee = $.data(this, "selectable-item"); - selectee.$element.removeClass('ui-selecting').addClass('ui-selected'); + selectee.$element.removeClass("ui-selecting").addClass("ui-selected"); selectee.selecting = false; selectee.selected = true; selectee.startselected = true; @@ -3163,8 +3477,18 @@ $.widget("ui.selectable", $.ui.mouse, { (function( $, undefined ) { +/*jshint loopfunc: true */ + +function isOverAxis( x, reference, size ) { + return ( x > reference ) && ( x < ( reference + size ) ); +} + +function isFloating(item) { + return (/left|right/).test(item.css("float")) || (/inline|table-cell/).test(item.css("display")); +} + $.widget("ui.sortable", $.ui.mouse, { - version: "1.9.2", + version: "1.10.2", widgetEventPrefix: "sort", ready: false, options: { @@ -3172,7 +3496,7 @@ $.widget("ui.sortable", $.ui.mouse, { axis: false, connectWith: false, containment: false, - cursor: 'auto', + cursor: "auto", cursorAt: false, dropOnEmpty: true, forcePlaceholderSize: false, @@ -3180,7 +3504,7 @@ $.widget("ui.sortable", $.ui.mouse, { grid: false, handle: false, helper: "original", - items: '> *', + items: "> *", opacity: false, placeholder: false, revert: false, @@ -3189,7 +3513,21 @@ $.widget("ui.sortable", $.ui.mouse, { scrollSpeed: 20, scope: "default", tolerance: "intersect", - zIndex: 1000 + zIndex: 1000, + + // callbacks + activate: null, + beforeStop: null, + change: null, + deactivate: null, + out: null, + over: null, + receive: null, + remove: null, + sort: null, + start: null, + stop: null, + update: null }, _create: function() { @@ -3201,7 +3539,7 @@ $.widget("ui.sortable", $.ui.mouse, { this.refresh(); //Let's determine if the items are being displayed horizontally - this.floating = this.items.length ? o.axis === 'x' || (/left|right/).test(this.items[0].item.css('float')) || (/inline|table-cell/).test(this.items[0].item.css('display')) : false; + this.floating = this.items.length ? o.axis === "x" || isFloating(this.items[0].item) : false; //Let's determine the parent's offset this.offset = this.element.offset(); @@ -3210,7 +3548,7 @@ $.widget("ui.sortable", $.ui.mouse, { this._mouseInit(); //We're ready to go - this.ready = true + this.ready = true; }, @@ -3219,8 +3557,9 @@ $.widget("ui.sortable", $.ui.mouse, { .removeClass("ui-sortable ui-sortable-disabled"); this._mouseDestroy(); - for ( var i = this.items.length - 1; i >= 0; i-- ) + for ( var i = this.items.length - 1; i >= 0; i-- ) { this.items[i].item.removeData(this.widgetName + "-item"); + } return this; }, @@ -3237,32 +3576,44 @@ $.widget("ui.sortable", $.ui.mouse, { }, _mouseCapture: function(event, overrideHandle) { - var that = this; + var currentItem = null, + validHandle = false, + that = this; if (this.reverting) { return false; } - if(this.options.disabled || this.options.type == 'static') return false; + if(this.options.disabled || this.options.type === "static") { + return false; + } //We have to refresh the items data once first this._refreshItems(event); //Find out if the clicked node (or one of its parents) is a actual item in this.items - var currentItem = null, nodes = $(event.target).parents().each(function() { - if($.data(this, that.widgetName + '-item') == that) { + $(event.target).parents().each(function() { + if($.data(this, that.widgetName + "-item") === that) { currentItem = $(this); return false; } }); - if($.data(event.target, that.widgetName + '-item') == that) currentItem = $(event.target); + if($.data(event.target, that.widgetName + "-item") === that) { + currentItem = $(event.target); + } - if(!currentItem) return false; + if(!currentItem) { + return false; + } if(this.options.handle && !overrideHandle) { - var validHandle = false; - - $(this.options.handle, currentItem).find("*").andSelf().each(function() { if(this == event.target) validHandle = true; }); - if(!validHandle) return false; + $(this.options.handle, currentItem).find("*").addBack().each(function() { + if(this === event.target) { + validHandle = true; + } + }); + if(!validHandle) { + return false; + } } this.currentItem = currentItem; @@ -3273,7 +3624,9 @@ $.widget("ui.sortable", $.ui.mouse, { _mouseStart: function(event, overrideHandle, noActivation) { - var o = this.options; + var i, body, + o = this.options; + this.currentContainer = this; //We only need to call refreshPositions, because the refreshItems call has been moved to mouseCapture @@ -3322,14 +3675,14 @@ $.widget("ui.sortable", $.ui.mouse, { this.originalPageX = event.pageX; this.originalPageY = event.pageY; - //Adjust the mouse offset relative to the helper if 'cursorAt' is supplied + //Adjust the mouse offset relative to the helper if "cursorAt" is supplied (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt)); //Cache the former DOM position this.domPosition = { prev: this.currentItem.prev()[0], parent: this.currentItem.parent()[0] }; //If the helper is not the original, hide the original so it's not playing any role during the drag, won't cause anything bad this way - if(this.helper[0] != this.currentItem[0]) { + if(this.helper[0] !== this.currentItem[0]) { this.currentItem.hide(); } @@ -3337,47 +3690,63 @@ $.widget("ui.sortable", $.ui.mouse, { this._createPlaceholder(); //Set a containment if given in the options - if(o.containment) + if(o.containment) { this._setContainment(); + } - if(o.cursor) { // cursor option - if ($('body').css("cursor")) this._storedCursor = $('body').css("cursor"); - $('body').css("cursor", o.cursor); + if( o.cursor && o.cursor !== "auto" ) { // cursor option + body = this.document.find( "body" ); + + // support: IE + this.storedCursor = body.css( "cursor" ); + body.css( "cursor", o.cursor ); + + this.storedStylesheet = $( "<style>*{ cursor: "+o.cursor+" !important; }</style>" ).appendTo( body ); } if(o.opacity) { // opacity option - if (this.helper.css("opacity")) this._storedOpacity = this.helper.css("opacity"); + if (this.helper.css("opacity")) { + this._storedOpacity = this.helper.css("opacity"); + } this.helper.css("opacity", o.opacity); } if(o.zIndex) { // zIndex option - if (this.helper.css("zIndex")) this._storedZIndex = this.helper.css("zIndex"); + if (this.helper.css("zIndex")) { + this._storedZIndex = this.helper.css("zIndex"); + } this.helper.css("zIndex", o.zIndex); } //Prepare scrolling - if(this.scrollParent[0] != document && this.scrollParent[0].tagName != 'HTML') + if(this.scrollParent[0] !== document && this.scrollParent[0].tagName !== "HTML") { this.overflowOffset = this.scrollParent.offset(); + } //Call callbacks this._trigger("start", event, this._uiHash()); //Recache the helper size - if(!this._preserveHelperProportions) + if(!this._preserveHelperProportions) { this._cacheHelperProportions(); + } - //Post 'activate' events to possible containers - if(!noActivation) { - for (var i = this.containers.length - 1; i >= 0; i--) { this.containers[i]._trigger("activate", event, this._uiHash(this)); } + //Post "activate" events to possible containers + if( !noActivation ) { + for ( i = this.containers.length - 1; i >= 0; i-- ) { + this.containers[ i ]._trigger( "activate", event, this._uiHash( this ) ); + } } //Prepare possible droppables - if($.ui.ddmanager) + if($.ui.ddmanager) { $.ui.ddmanager.current = this; + } - if ($.ui.ddmanager && !o.dropBehaviour) + if ($.ui.ddmanager && !o.dropBehaviour) { $.ui.ddmanager.prepareOffsets(this, event); + } this.dragging = true; @@ -3388,6 +3757,9 @@ $.widget("ui.sortable", $.ui.mouse, { }, _mouseDrag: function(event) { + var i, item, itemElement, intersection, + o = this.options, + scrolled = false; //Compute the helpers position this.position = this._generatePosition(event); @@ -3399,50 +3771,62 @@ $.widget("ui.sortable", $.ui.mouse, { //Do scrolling if(this.options.scroll) { - var o = this.options, scrolled = false; - if(this.scrollParent[0] != document && this.scrollParent[0].tagName != 'HTML') { + if(this.scrollParent[0] !== document && this.scrollParent[0].tagName !== "HTML") { - if((this.overflowOffset.top + this.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity) + if((this.overflowOffset.top + this.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity) { this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop + o.scrollSpeed; - else if(event.pageY - this.overflowOffset.top < o.scrollSensitivity) + } else if(event.pageY - this.overflowOffset.top < o.scrollSensitivity) { this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop - o.scrollSpeed; + } - if((this.overflowOffset.left + this.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity) + if((this.overflowOffset.left + this.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity) { this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft + o.scrollSpeed; - else if(event.pageX - this.overflowOffset.left < o.scrollSensitivity) + } else if(event.pageX - this.overflowOffset.left < o.scrollSensitivity) { this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft - o.scrollSpeed; + } } else { - if(event.pageY - $(document).scrollTop() < o.scrollSensitivity) + if(event.pageY - $(document).scrollTop() < o.scrollSensitivity) { scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed); - else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity) + } else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity) { scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed); + } - if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity) + if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity) { scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed); - else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity) + } else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity) { scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed); + } } - if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) + if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) { $.ui.ddmanager.prepareOffsets(this, event); + } } //Regenerate the absolute position used for position checks this.positionAbs = this._convertPositionTo("absolute"); //Set the helper position - if(!this.options.axis || this.options.axis != "y") this.helper[0].style.left = this.position.left+'px'; - if(!this.options.axis || this.options.axis != "x") this.helper[0].style.top = this.position.top+'px'; + if(!this.options.axis || this.options.axis !== "y") { + this.helper[0].style.left = this.position.left+"px"; + } + if(!this.options.axis || this.options.axis !== "x") { + this.helper[0].style.top = this.position.top+"px"; + } //Rearrange - for (var i = this.items.length - 1; i >= 0; i--) { + for (i = this.items.length - 1; i >= 0; i--) { //Cache variables and intersection, continue if no intersection - var item = this.items[i], itemElement = item.item[0], intersection = this._intersectsWithPointer(item); - if (!intersection) continue; + item = this.items[i]; + itemElement = item.item[0]; + intersection = this._intersectsWithPointer(item); + if (!intersection) { + continue; + } // Only put the placeholder inside the current Container, skip all // items form other containers. This works because when moving @@ -3451,18 +3835,22 @@ $.widget("ui.sortable", $.ui.mouse, { // // Without this moving items in "sub-sortables" can cause the placeholder to jitter // beetween the outer and inner container. - if (item.instance !== this.currentContainer) continue; + if (item.instance !== this.currentContainer) { + continue; + } - if (itemElement != this.currentItem[0] //cannot intersect with itself - && this.placeholder[intersection == 1 ? "next" : "prev"]()[0] != itemElement //no useless actions that have been done before - && !$.contains(this.placeholder[0], itemElement) //no action if the item moved is the parent of the item checked - && (this.options.type == 'semi-dynamic' ? !$.contains(this.element[0], itemElement) : true) - //&& itemElement.parentNode == this.placeholder[0].parentNode // only rearrange items within the same container + // cannot intersect with itself + // no useless actions that have been done before + // no action if the item moved is the parent of the item checked + if (itemElement !== this.currentItem[0] && + this.placeholder[intersection === 1 ? "next" : "prev"]()[0] !== itemElement && + !$.contains(this.placeholder[0], itemElement) && + (this.options.type === "semi-dynamic" ? !$.contains(this.element[0], itemElement) : true) ) { - this.direction = intersection == 1 ? "down" : "up"; + this.direction = intersection === 1 ? "down" : "up"; - if (this.options.tolerance == "pointer" || this._intersectsWithSides(item)) { + if (this.options.tolerance === "pointer" || this._intersectsWithSides(item)) { this._rearrange(event, item); } else { break; @@ -3477,10 +3865,12 @@ $.widget("ui.sortable", $.ui.mouse, { this._contactContainers(event); //Interconnect with droppables - if($.ui.ddmanager) $.ui.ddmanager.drag(this, event); + if($.ui.ddmanager) { + $.ui.ddmanager.drag(this, event); + } //Call callbacks - this._trigger('sort', event, this._uiHash()); + this._trigger("sort", event, this._uiHash()); this.lastPositionAbs = this.positionAbs; return false; @@ -3489,22 +3879,29 @@ $.widget("ui.sortable", $.ui.mouse, { _mouseStop: function(event, noPropagation) { - if(!event) return; + if(!event) { + return; + } //If we are using droppables, inform the manager about the drop - if ($.ui.ddmanager && !this.options.dropBehaviour) + if ($.ui.ddmanager && !this.options.dropBehaviour) { $.ui.ddmanager.drop(this, event); + } if(this.options.revert) { - var that = this; - var cur = this.placeholder.offset(); + var that = this, + cur = this.placeholder.offset(), + axis = this.options.axis, + animation = {}; + if ( !axis || axis === "x" ) { + animation.left = cur.left - this.offset.parent.left - this.margins.left + (this.offsetParent[0] === document.body ? 0 : this.offsetParent[0].scrollLeft); + } + if ( !axis || axis === "y" ) { + animation.top = cur.top - this.offset.parent.top - this.margins.top + (this.offsetParent[0] === document.body ? 0 : this.offsetParent[0].scrollTop); + } this.reverting = true; - - $(this.helper).animate({ - left: cur.left - this.offset.parent.left - this.margins.left + (this.offsetParent[0] == document.body ? 0 : this.offsetParent[0].scrollLeft), - top: cur.top - this.offset.parent.top - this.margins.top + (this.offsetParent[0] == document.body ? 0 : this.offsetParent[0].scrollTop) - }, parseInt(this.options.revert, 10) || 500, function() { + $(this.helper).animate( animation, parseInt(this.options.revert, 10) || 500, function() { that._clear(event); }); } else { @@ -3521,10 +3918,11 @@ $.widget("ui.sortable", $.ui.mouse, { this._mouseUp({ target: null }); - if(this.options.helper == "original") + if(this.options.helper === "original") { this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"); - else + } else { this.currentItem.show(); + } //Post deactivating events to containers for (var i = this.containers.length - 1; i >= 0; i--){ @@ -3539,8 +3937,12 @@ $.widget("ui.sortable", $.ui.mouse, { if (this.placeholder) { //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node! - if(this.placeholder[0].parentNode) this.placeholder[0].parentNode.removeChild(this.placeholder[0]); - if(this.options.helper != "original" && this.helper && this.helper[0].parentNode) this.helper.remove(); + if(this.placeholder[0].parentNode) { + this.placeholder[0].parentNode.removeChild(this.placeholder[0]); + } + if(this.options.helper !== "original" && this.helper && this.helper[0].parentNode) { + this.helper.remove(); + } $.extend(this, { helper: null, @@ -3562,28 +3964,33 @@ $.widget("ui.sortable", $.ui.mouse, { serialize: function(o) { - var items = this._getItemsAsjQuery(o && o.connected); - var str = []; o = o || {}; + var items = this._getItemsAsjQuery(o && o.connected), + str = []; + o = o || {}; $(items).each(function() { - var res = ($(o.item || this).attr(o.attribute || 'id') || '').match(o.expression || (/(.+)[-=_](.+)/)); - if(res) str.push((o.key || res[1]+'[]')+'='+(o.key && o.expression ? res[1] : res[2])); + var res = ($(o.item || this).attr(o.attribute || "id") || "").match(o.expression || (/(.+)[\-=_](.+)/)); + if (res) { + str.push((o.key || res[1]+"[]")+"="+(o.key && o.expression ? res[1] : res[2])); + } }); if(!str.length && o.key) { - str.push(o.key + '='); + str.push(o.key + "="); } - return str.join('&'); + return str.join("&"); }, toArray: function(o) { - var items = this._getItemsAsjQuery(o && o.connected); - var ret = []; o = o || {}; + var items = this._getItemsAsjQuery(o && o.connected), + ret = []; + + o = o || {}; - items.each(function() { ret.push($(o.item || this).attr(o.attribute || 'id') || ''); }); + items.each(function() { ret.push($(o.item || this).attr(o.attribute || "id") || ""); }); return ret; }, @@ -3594,73 +4001,71 @@ $.widget("ui.sortable", $.ui.mouse, { var x1 = this.positionAbs.left, x2 = x1 + this.helperProportions.width, y1 = this.positionAbs.top, - y2 = y1 + this.helperProportions.height; - - var l = item.left, + y2 = y1 + this.helperProportions.height, + l = item.left, r = l + item.width, t = item.top, - b = t + item.height; - - var dyClick = this.offset.click.top, - dxClick = this.offset.click.left; - - var isOverElement = (y1 + dyClick) > t && (y1 + dyClick) < b && (x1 + dxClick) > l && (x1 + dxClick) < r; - - if( this.options.tolerance == "pointer" - || this.options.forcePointerForContainers - || (this.options.tolerance != "pointer" && this.helperProportions[this.floating ? 'width' : 'height'] > item[this.floating ? 'width' : 'height']) + b = t + item.height, + dyClick = this.offset.click.top, + dxClick = this.offset.click.left, + isOverElement = (y1 + dyClick) > t && (y1 + dyClick) < b && (x1 + dxClick) > l && (x1 + dxClick) < r; + + if ( this.options.tolerance === "pointer" || + this.options.forcePointerForContainers || + (this.options.tolerance !== "pointer" && this.helperProportions[this.floating ? "width" : "height"] > item[this.floating ? "width" : "height"]) ) { return isOverElement; } else { - return (l < x1 + (this.helperProportions.width / 2) // Right Half - && x2 - (this.helperProportions.width / 2) < r // Left Half - && t < y1 + (this.helperProportions.height / 2) // Bottom Half - && y2 - (this.helperProportions.height / 2) < b ); // Top Half + return (l < x1 + (this.helperProportions.width / 2) && // Right Half + x2 - (this.helperProportions.width / 2) < r && // Left Half + t < y1 + (this.helperProportions.height / 2) && // Bottom Half + y2 - (this.helperProportions.height / 2) < b ); // Top Half } }, _intersectsWithPointer: function(item) { - var isOverElementHeight = (this.options.axis === 'x') || $.ui.isOverAxis(this.positionAbs.top + this.offset.click.top, item.top, item.height), - isOverElementWidth = (this.options.axis === 'y') || $.ui.isOverAxis(this.positionAbs.left + this.offset.click.left, item.left, item.width), + var isOverElementHeight = (this.options.axis === "x") || isOverAxis(this.positionAbs.top + this.offset.click.top, item.top, item.height), + isOverElementWidth = (this.options.axis === "y") || isOverAxis(this.positionAbs.left + this.offset.click.left, item.left, item.width), isOverElement = isOverElementHeight && isOverElementWidth, verticalDirection = this._getDragVerticalDirection(), horizontalDirection = this._getDragHorizontalDirection(); - if (!isOverElement) + if (!isOverElement) { return false; + } return this.floating ? - ( ((horizontalDirection && horizontalDirection == "right") || verticalDirection == "down") ? 2 : 1 ) - : ( verticalDirection && (verticalDirection == "down" ? 2 : 1) ); + ( ((horizontalDirection && horizontalDirection === "right") || verticalDirection === "down") ? 2 : 1 ) + : ( verticalDirection && (verticalDirection === "down" ? 2 : 1) ); }, _intersectsWithSides: function(item) { - var isOverBottomHalf = $.ui.isOverAxis(this.positionAbs.top + this.offset.click.top, item.top + (item.height/2), item.height), - isOverRightHalf = $.ui.isOverAxis(this.positionAbs.left + this.offset.click.left, item.left + (item.width/2), item.width), + var isOverBottomHalf = isOverAxis(this.positionAbs.top + this.offset.click.top, item.top + (item.height/2), item.height), + isOverRightHalf = isOverAxis(this.positionAbs.left + this.offset.click.left, item.left + (item.width/2), item.width), verticalDirection = this._getDragVerticalDirection(), horizontalDirection = this._getDragHorizontalDirection(); if (this.floating && horizontalDirection) { - return ((horizontalDirection == "right" && isOverRightHalf) || (horizontalDirection == "left" && !isOverRightHalf)); + return ((horizontalDirection === "right" && isOverRightHalf) || (horizontalDirection === "left" && !isOverRightHalf)); } else { - return verticalDirection && ((verticalDirection == "down" && isOverBottomHalf) || (verticalDirection == "up" && !isOverBottomHalf)); + return verticalDirection && ((verticalDirection === "down" && isOverBottomHalf) || (verticalDirection === "up" && !isOverBottomHalf)); } }, _getDragVerticalDirection: function() { var delta = this.positionAbs.top - this.lastPositionAbs.top; - return delta != 0 && (delta > 0 ? "down" : "up"); + return delta !== 0 && (delta > 0 ? "down" : "up"); }, _getDragHorizontalDirection: function() { var delta = this.positionAbs.left - this.lastPositionAbs.left; - return delta != 0 && (delta > 0 ? "right" : "left"); + return delta !== 0 && (delta > 0 ? "right" : "left"); }, refresh: function(event) { @@ -3671,36 +4076,35 @@ $.widget("ui.sortable", $.ui.mouse, { _connectWith: function() { var options = this.options; - return options.connectWith.constructor == String - ? [options.connectWith] - : options.connectWith; + return options.connectWith.constructor === String ? [options.connectWith] : options.connectWith; }, _getItemsAsjQuery: function(connected) { - var items = []; - var queries = []; - var connectWith = this._connectWith(); + var i, j, cur, inst, + items = [], + queries = [], + connectWith = this._connectWith(); if(connectWith && connected) { - for (var i = connectWith.length - 1; i >= 0; i--){ - var cur = $(connectWith[i]); - for (var j = cur.length - 1; j >= 0; j--){ - var inst = $.data(cur[j], this.widgetName); - if(inst && inst != this && !inst.options.disabled) { - queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element) : $(inst.options.items, inst.element).not(".ui-sortable-helper").not('.ui-sortable-placeholder'), inst]); + for (i = connectWith.length - 1; i >= 0; i--){ + cur = $(connectWith[i]); + for ( j = cur.length - 1; j >= 0; j--){ + inst = $.data(cur[j], this.widgetFullName); + if(inst && inst !== this && !inst.options.disabled) { + queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element) : $(inst.options.items, inst.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"), inst]); } - }; - }; + } + } } - queries.push([$.isFunction(this.options.items) ? this.options.items.call(this.element, null, { options: this.options, item: this.currentItem }) : $(this.options.items, this.element).not(".ui-sortable-helper").not('.ui-sortable-placeholder'), this]); + queries.push([$.isFunction(this.options.items) ? this.options.items.call(this.element, null, { options: this.options, item: this.currentItem }) : $(this.options.items, this.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"), this]); - for (var i = queries.length - 1; i >= 0; i--){ + for (i = queries.length - 1; i >= 0; i--){ queries[i][0].each(function() { items.push(this); }); - }; + } return $(items); @@ -3712,9 +4116,10 @@ $.widget("ui.sortable", $.ui.mouse, { this.items = $.grep(this.items, function (item) { for (var j=0; j < list.length; j++) { - if(list[j] == item.item[0]) + if(list[j] === item.item[0]) { return false; - }; + } + } return true; }); @@ -3724,31 +4129,33 @@ $.widget("ui.sortable", $.ui.mouse, { this.items = []; this.containers = [this]; - var items = this.items; - var queries = [[$.isFunction(this.options.items) ? this.options.items.call(this.element[0], event, { item: this.currentItem }) : $(this.options.items, this.element), this]]; - var connectWith = this._connectWith(); + + var i, j, cur, inst, targetData, _queries, item, queriesLength, + items = this.items, + queries = [[$.isFunction(this.options.items) ? this.options.items.call(this.element[0], event, { item: this.currentItem }) : $(this.options.items, this.element), this]], + connectWith = this._connectWith(); if(connectWith && this.ready) { //Shouldn't be run the first time through due to massive slow-down - for (var i = connectWith.length - 1; i >= 0; i--){ - var cur = $(connectWith[i]); - for (var j = cur.length - 1; j >= 0; j--){ - var inst = $.data(cur[j], this.widgetName); - if(inst && inst != this && !inst.options.disabled) { + for (i = connectWith.length - 1; i >= 0; i--){ + cur = $(connectWith[i]); + for (j = cur.length - 1; j >= 0; j--){ + inst = $.data(cur[j], this.widgetFullName); + if(inst && inst !== this && !inst.options.disabled) { queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element[0], event, { item: this.currentItem }) : $(inst.options.items, inst.element), inst]); this.containers.push(inst); } - }; - }; + } + } } - for (var i = queries.length - 1; i >= 0; i--) { - var targetData = queries[i][1]; - var _queries = queries[i][0]; + for (i = queries.length - 1; i >= 0; i--) { + targetData = queries[i][1]; + _queries = queries[i][0]; - for (var j=0, queriesLength = _queries.length; j < queriesLength; j++) { - var item = $(_queries[j]); + for (j=0, queriesLength = _queries.length; j < queriesLength; j++) { + item = $(_queries[j]); - item.data(this.widgetName + '-item', targetData); // Data for target checking (mouse manager) + item.data(this.widgetName + "-item", targetData); // Data for target checking (mouse manager) items.push({ item: item, @@ -3756,8 +4163,8 @@ $.widget("ui.sortable", $.ui.mouse, { width: 0, height: 0, left: 0, top: 0 }); - }; - }; + } + } }, @@ -3768,35 +4175,38 @@ $.widget("ui.sortable", $.ui.mouse, { this.offset.parent = this._getParentOffset(); } - for (var i = this.items.length - 1; i >= 0; i--){ - var item = this.items[i]; + var i, item, t, p; + + for (i = this.items.length - 1; i >= 0; i--){ + item = this.items[i]; //We ignore calculating positions of all connected containers when we're not over them - if(item.instance != this.currentContainer && this.currentContainer && item.item[0] != this.currentItem[0]) + if(item.instance !== this.currentContainer && this.currentContainer && item.item[0] !== this.currentItem[0]) { continue; + } - var t = this.options.toleranceElement ? $(this.options.toleranceElement, item.item) : item.item; + t = this.options.toleranceElement ? $(this.options.toleranceElement, item.item) : item.item; if (!fast) { item.width = t.outerWidth(); item.height = t.outerHeight(); } - var p = t.offset(); + p = t.offset(); item.left = p.left; item.top = p.top; - }; + } if(this.options.custom && this.options.custom.refreshContainers) { this.options.custom.refreshContainers.call(this); } else { - for (var i = this.containers.length - 1; i >= 0; i--){ - var p = this.containers[i].element.offset(); + for (i = this.containers.length - 1; i >= 0; i--){ + p = this.containers[i].element.offset(); this.containers[i].containerCache.left = p.left; this.containers[i].containerCache.top = p.top; this.containers[i].containerCache.width = this.containers[i].element.outerWidth(); this.containers[i].containerCache.height = this.containers[i].element.outerHeight(); - }; + } } return this; @@ -3804,31 +4214,45 @@ $.widget("ui.sortable", $.ui.mouse, { _createPlaceholder: function(that) { that = that || this; - var o = that.options; + var className, + o = that.options; - if(!o.placeholder || o.placeholder.constructor == String) { - var className = o.placeholder; + if(!o.placeholder || o.placeholder.constructor === String) { + className = o.placeholder; o.placeholder = { element: function() { - var el = $(document.createElement(that.currentItem[0].nodeName)) - .addClass(className || that.currentItem[0].className+" ui-sortable-placeholder") - .removeClass("ui-sortable-helper")[0]; + var nodeName = that.currentItem[0].nodeName.toLowerCase(), + element = $( that.document[0].createElement( nodeName ) ) + .addClass(className || that.currentItem[0].className+" ui-sortable-placeholder") + .removeClass("ui-sortable-helper"); + + if ( nodeName === "tr" ) { + // Use a high colspan to force the td to expand the full + // width of the table (browsers are smart enough to + // handle this properly) + element.append( "<td colspan='99'> </td>" ); + } else if ( nodeName === "img" ) { + element.attr( "src", that.currentItem.attr( "src" ) ); + } - if(!className) - el.style.visibility = "hidden"; + if ( !className ) { + element.css( "visibility", "hidden" ); + } - return el; + return element; }, update: function(container, p) { // 1. If a className is set as 'placeholder option, we don't force sizes - the class is responsible for that // 2. The option 'forcePlaceholderSize can be enabled to force it even if a class name is specified - if(className && !o.forcePlaceholderSize) return; + if(className && !o.forcePlaceholderSize) { + return; + } //If the element doesn't have a actual height by itself (without styles coming from a stylesheet), it receives the inline height from the dragged item - if(!p.height()) { p.height(that.currentItem.innerHeight() - parseInt(that.currentItem.css('paddingTop')||0, 10) - parseInt(that.currentItem.css('paddingBottom')||0, 10)); }; - if(!p.width()) { p.width(that.currentItem.innerWidth() - parseInt(that.currentItem.css('paddingLeft')||0, 10) - parseInt(that.currentItem.css('paddingRight')||0, 10)); }; + if(!p.height()) { p.height(that.currentItem.innerHeight() - parseInt(that.currentItem.css("paddingTop")||0, 10) - parseInt(that.currentItem.css("paddingBottom")||0, 10)); } + if(!p.width()) { p.width(that.currentItem.innerWidth() - parseInt(that.currentItem.css("paddingLeft")||0, 10) - parseInt(that.currentItem.css("paddingRight")||0, 10)); } } }; } @@ -3845,22 +4269,24 @@ $.widget("ui.sortable", $.ui.mouse, { }, _contactContainers: function(event) { + var i, j, dist, itemWithLeastDistance, posProperty, sizeProperty, base, cur, nearBottom, floating, + innermostContainer = null, + innermostIndex = null; // get innermost container that intersects with item - var innermostContainer = null, innermostIndex = null; - - - for (var i = this.containers.length - 1; i >= 0; i--){ + for (i = this.containers.length - 1; i >= 0; i--) { // never consider a container that's located within the item itself - if($.contains(this.currentItem[0], this.containers[i].element[0])) + if($.contains(this.currentItem[0], this.containers[i].element[0])) { continue; + } if(this._intersectsWith(this.containers[i].containerCache)) { // if we've already found a container and it's more "inner" than this, then continue - if(innermostContainer && $.contains(this.containers[i].element[0], innermostContainer.element[0])) + if(innermostContainer && $.contains(this.containers[i].element[0], innermostContainer.element[0])) { continue; + } innermostContainer = this.containers[i]; innermostIndex = i; @@ -3876,24 +4302,37 @@ $.widget("ui.sortable", $.ui.mouse, { } // if no intersecting containers found, return - if(!innermostContainer) return; + if(!innermostContainer) { + return; + } // move the item into the container if it's not there already if(this.containers.length === 1) { - this.containers[innermostIndex]._trigger("over", event, this._uiHash(this)); - this.containers[innermostIndex].containerCache.over = 1; + if (!this.containers[innermostIndex].containerCache.over) { + this.containers[innermostIndex]._trigger("over", event, this._uiHash(this)); + this.containers[innermostIndex].containerCache.over = 1; + } } else { //When entering a new container, we will find the item with the least distance and append our item near it - var dist = 10000; var itemWithLeastDistance = null; - var posProperty = this.containers[innermostIndex].floating ? 'left' : 'top'; - var sizeProperty = this.containers[innermostIndex].floating ? 'width' : 'height'; - var base = this.positionAbs[posProperty] + this.offset.click[posProperty]; - for (var j = this.items.length - 1; j >= 0; j--) { - if(!$.contains(this.containers[innermostIndex].element[0], this.items[j].item[0])) continue; - if(this.items[j].item[0] == this.currentItem[0]) continue; - var cur = this.items[j].item.offset()[posProperty]; - var nearBottom = false; + dist = 10000; + itemWithLeastDistance = null; + floating = innermostContainer.floating || isFloating(this.currentItem); + posProperty = floating ? "left" : "top"; + sizeProperty = floating ? "width" : "height"; + base = this.positionAbs[posProperty] + this.offset.click[posProperty]; + for (j = this.items.length - 1; j >= 0; j--) { + if(!$.contains(this.containers[innermostIndex].element[0], this.items[j].item[0])) { + continue; + } + if(this.items[j].item[0] === this.currentItem[0]) { + continue; + } + if (floating && !isOverAxis(this.positionAbs.top + this.offset.click.top, this.items[j].top, this.items[j].height)) { + continue; + } + cur = this.items[j].item.offset()[posProperty]; + nearBottom = false; if(Math.abs(cur - base) > Math.abs(cur + this.items[j][sizeProperty] - base)){ nearBottom = true; cur += this.items[j][sizeProperty]; @@ -3905,13 +4344,19 @@ $.widget("ui.sortable", $.ui.mouse, { } } - if(!itemWithLeastDistance && !this.options.dropOnEmpty) //Check if dropOnEmpty is enabled + //Check if dropOnEmpty is enabled + if(!itemWithLeastDistance && !this.options.dropOnEmpty) { return; + } + + if(this.currentContainer === this.containers[innermostIndex]) { + return; + } - this.currentContainer = this.containers[innermostIndex]; itemWithLeastDistance ? this._rearrange(event, itemWithLeastDistance, null, true) : this._rearrange(event, null, this.containers[innermostIndex].element, true); this._trigger("change", event, this._uiHash()); this.containers[innermostIndex]._trigger("change", event, this._uiHash(this)); + this.currentContainer = this.containers[innermostIndex]; //Update the placeholder this.options.placeholder.update(this.currentContainer, this.placeholder); @@ -3925,39 +4370,46 @@ $.widget("ui.sortable", $.ui.mouse, { _createHelper: function(event) { - var o = this.options; - var helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event, this.currentItem])) : (o.helper == 'clone' ? this.currentItem.clone() : this.currentItem); + var o = this.options, + helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event, this.currentItem])) : (o.helper === "clone" ? this.currentItem.clone() : this.currentItem); - if(!helper.parents('body').length) //Add the helper to the DOM if that didn't happen already - $(o.appendTo != 'parent' ? o.appendTo : this.currentItem[0].parentNode)[0].appendChild(helper[0]); + //Add the helper to the DOM if that didn't happen already + if(!helper.parents("body").length) { + $(o.appendTo !== "parent" ? o.appendTo : this.currentItem[0].parentNode)[0].appendChild(helper[0]); + } - if(helper[0] == this.currentItem[0]) + if(helper[0] === this.currentItem[0]) { this._storedCSS = { width: this.currentItem[0].style.width, height: this.currentItem[0].style.height, position: this.currentItem.css("position"), top: this.currentItem.css("top"), left: this.currentItem.css("left") }; + } - if(helper[0].style.width == '' || o.forceHelperSize) helper.width(this.currentItem.width()); - if(helper[0].style.height == '' || o.forceHelperSize) helper.height(this.currentItem.height()); + if(!helper[0].style.width || o.forceHelperSize) { + helper.width(this.currentItem.width()); + } + if(!helper[0].style.height || o.forceHelperSize) { + helper.height(this.currentItem.height()); + } return helper; }, _adjustOffsetFromHelper: function(obj) { - if (typeof obj == 'string') { - obj = obj.split(' '); + if (typeof obj === "string") { + obj = obj.split(" "); } if ($.isArray(obj)) { obj = {left: +obj[0], top: +obj[1] || 0}; } - if ('left' in obj) { + if ("left" in obj) { this.offset.click.left = obj.left + this.margins.left; } - if ('right' in obj) { + if ("right" in obj) { this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left; } - if ('top' in obj) { + if ("top" in obj) { this.offset.click.top = obj.top + this.margins.top; } - if ('bottom' in obj) { + if ("bottom" in obj) { this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top; } }, @@ -3973,14 +4425,16 @@ $.widget("ui.sortable", $.ui.mouse, { // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag - if(this.cssPosition == 'absolute' && this.scrollParent[0] != document && $.contains(this.scrollParent[0], this.offsetParent[0])) { + if(this.cssPosition === "absolute" && this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) { po.left += this.scrollParent.scrollLeft(); po.top += this.scrollParent.scrollTop(); } - if((this.offsetParent[0] == document.body) //This needs to be actually done for all browsers, since pageX/pageY includes this information - || (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() == 'html' && $.ui.ie)) //Ugly IE fix + // This needs to be actually done for all browsers, since pageX/pageY includes this information + // with an ugly IE fix + if( this.offsetParent[0] === document.body || (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() === "html" && $.ui.ie)) { po = { top: 0, left: 0 }; + } return { top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0), @@ -3991,7 +4445,7 @@ $.widget("ui.sortable", $.ui.mouse, { _getRelativeOffset: function() { - if(this.cssPosition == "relative") { + if(this.cssPosition === "relative") { var p = this.currentItem.position(); return { top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(), @@ -4019,19 +4473,24 @@ $.widget("ui.sortable", $.ui.mouse, { _setContainment: function() { - var o = this.options; - if(o.containment == 'parent') o.containment = this.helper[0].parentNode; - if(o.containment == 'document' || o.containment == 'window') this.containment = [ - 0 - this.offset.relative.left - this.offset.parent.left, - 0 - this.offset.relative.top - this.offset.parent.top, - $(o.containment == 'document' ? document : window).width() - this.helperProportions.width - this.margins.left, - ($(o.containment == 'document' ? document : window).height() || document.body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top - ]; + var ce, co, over, + o = this.options; + if(o.containment === "parent") { + o.containment = this.helper[0].parentNode; + } + if(o.containment === "document" || o.containment === "window") { + this.containment = [ + 0 - this.offset.relative.left - this.offset.parent.left, + 0 - this.offset.relative.top - this.offset.parent.top, + $(o.containment === "document" ? document : window).width() - this.helperProportions.width - this.margins.left, + ($(o.containment === "document" ? document : window).height() || document.body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top + ]; + } if(!(/^(document|window|parent)$/).test(o.containment)) { - var ce = $(o.containment)[0]; - var co = $(o.containment).offset(); - var over = ($(ce).css("overflow") != 'hidden'); + ce = $(o.containment)[0]; + co = $(o.containment).offset(); + over = ($(ce).css("overflow") !== "hidden"); this.containment = [ co.left + (parseInt($(ce).css("borderLeftWidth"),10) || 0) + (parseInt($(ce).css("paddingLeft"),10) || 0) - this.margins.left, @@ -4045,22 +4504,25 @@ $.widget("ui.sortable", $.ui.mouse, { _convertPositionTo: function(d, pos) { - if(!pos) pos = this.position; - var mod = d == "absolute" ? 1 : -1; - var o = this.options, scroll = this.cssPosition == 'absolute' && !(this.scrollParent[0] != document && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName); + if(!pos) { + pos = this.position; + } + var mod = d === "absolute" ? 1 : -1, + scroll = this.cssPosition === "absolute" && !(this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, + scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName); return { top: ( - pos.top // The absolute mouse position - + this.offset.relative.top * mod // Only for relative positioned nodes: Relative offset from element to offset parent - + this.offset.parent.top * mod // The offsetParent's offset without borders (offset + border) - - ( ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod) + pos.top + // The absolute mouse position + this.offset.relative.top * mod + // Only for relative positioned nodes: Relative offset from element to offset parent + this.offset.parent.top * mod - // The offsetParent's offset without borders (offset + border) + ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod) ), left: ( - pos.left // The absolute mouse position - + this.offset.relative.left * mod // Only for relative positioned nodes: Relative offset from element to offset parent - + this.offset.parent.left * mod // The offsetParent's offset without borders (offset + border) - - ( ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) * mod) + pos.left + // The absolute mouse position + this.offset.relative.left * mod + // Only for relative positioned nodes: Relative offset from element to offset parent + this.offset.parent.left * mod - // The offsetParent's offset without borders (offset + border) + ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) * mod) ) }; @@ -4068,19 +4530,20 @@ $.widget("ui.sortable", $.ui.mouse, { _generatePosition: function(event) { - var o = this.options, scroll = this.cssPosition == 'absolute' && !(this.scrollParent[0] != document && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName); + var top, left, + o = this.options, + pageX = event.pageX, + pageY = event.pageY, + scroll = this.cssPosition === "absolute" && !(this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName); // This is another very weird special case that only happens for relative elements: // 1. If the css position is relative // 2. and the scroll parent is the document or similar to the offset parent // we have to refresh the relative offset during the scroll so there are no jumps - if(this.cssPosition == 'relative' && !(this.scrollParent[0] != document && this.scrollParent[0] != this.offsetParent[0])) { + if(this.cssPosition === "relative" && !(this.scrollParent[0] !== document && this.scrollParent[0] !== this.offsetParent[0])) { this.offset.relative = this._getRelativeOffset(); } - var pageX = event.pageX; - var pageY = event.pageY; - /* * - Position constraining - * Constrain the position to a mix of grid, containment. @@ -4089,36 +4552,44 @@ $.widget("ui.sortable", $.ui.mouse, { if(this.originalPosition) { //If we are not dragging yet, we won't check for options if(this.containment) { - if(event.pageX - this.offset.click.left < this.containment[0]) pageX = this.containment[0] + this.offset.click.left; - if(event.pageY - this.offset.click.top < this.containment[1]) pageY = this.containment[1] + this.offset.click.top; - if(event.pageX - this.offset.click.left > this.containment[2]) pageX = this.containment[2] + this.offset.click.left; - if(event.pageY - this.offset.click.top > this.containment[3]) pageY = this.containment[3] + this.offset.click.top; + if(event.pageX - this.offset.click.left < this.containment[0]) { + pageX = this.containment[0] + this.offset.click.left; + } + if(event.pageY - this.offset.click.top < this.containment[1]) { + pageY = this.containment[1] + this.offset.click.top; + } + if(event.pageX - this.offset.click.left > this.containment[2]) { + pageX = this.containment[2] + this.offset.click.left; + } + if(event.pageY - this.offset.click.top > this.containment[3]) { + pageY = this.containment[3] + this.offset.click.top; + } } if(o.grid) { - var top = this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1]; - pageY = this.containment ? (!(top - this.offset.click.top < this.containment[1] || top - this.offset.click.top > this.containment[3]) ? top : (!(top - this.offset.click.top < this.containment[1]) ? top - o.grid[1] : top + o.grid[1])) : top; + top = this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1]; + pageY = this.containment ? ( (top - this.offset.click.top >= this.containment[1] && top - this.offset.click.top <= this.containment[3]) ? top : ((top - this.offset.click.top >= this.containment[1]) ? top - o.grid[1] : top + o.grid[1])) : top; - var left = this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0]; - pageX = this.containment ? (!(left - this.offset.click.left < this.containment[0] || left - this.offset.click.left > this.containment[2]) ? left : (!(left - this.offset.click.left < this.containment[0]) ? left - o.grid[0] : left + o.grid[0])) : left; + left = this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0]; + pageX = this.containment ? ( (left - this.offset.click.left >= this.containment[0] && left - this.offset.click.left <= this.containment[2]) ? left : ((left - this.offset.click.left >= this.containment[0]) ? left - o.grid[0] : left + o.grid[0])) : left; } } return { top: ( - pageY // The absolute mouse position - - this.offset.click.top // Click offset (relative to the element) - - this.offset.relative.top // Only for relative positioned nodes: Relative offset from element to offset parent - - this.offset.parent.top // The offsetParent's offset without borders (offset + border) - + ( ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) )) + pageY - // The absolute mouse position + this.offset.click.top - // Click offset (relative to the element) + this.offset.relative.top - // Only for relative positioned nodes: Relative offset from element to offset parent + this.offset.parent.top + // The offsetParent's offset without borders (offset + border) + ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) )) ), left: ( - pageX // The absolute mouse position - - this.offset.click.left // Click offset (relative to the element) - - this.offset.relative.left // Only for relative positioned nodes: Relative offset from element to offset parent - - this.offset.parent.left // The offsetParent's offset without borders (offset + border) - + ( ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() )) + pageX - // The absolute mouse position + this.offset.click.left - // Click offset (relative to the element) + this.offset.relative.left - // Only for relative positioned nodes: Relative offset from element to offset parent + this.offset.parent.left + // The offsetParent's offset without borders (offset + border) + ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() )) ) }; @@ -4126,7 +4597,7 @@ $.widget("ui.sortable", $.ui.mouse, { _rearrange: function(event, i, a, hardRefresh) { - a ? a[0].appendChild(this.placeholder[0]) : i.item[0].parentNode.insertBefore(this.placeholder[0], (this.direction == 'down' ? i.item[0] : i.item[0].nextSibling)); + a ? a[0].appendChild(this.placeholder[0]) : i.item[0].parentNode.insertBefore(this.placeholder[0], (this.direction === "down" ? i.item[0] : i.item[0].nextSibling)); //Various things done here to improve the performance: // 1. we create a setTimeout, that calls refreshPositions @@ -4137,7 +4608,9 @@ $.widget("ui.sortable", $.ui.mouse, { var counter = this.counter; this._delay(function() { - if(counter == this.counter) this.refreshPositions(!hardRefresh); //Precompute after each DOM insertion, NOT on mousemove + if(counter === this.counter) { + this.refreshPositions(!hardRefresh); //Precompute after each DOM insertion, NOT on mousemove + } }); }, @@ -4147,24 +4620,33 @@ $.widget("ui.sortable", $.ui.mouse, { this.reverting = false; // We delay all events that have to be triggered to after the point where the placeholder has been removed and // everything else normalized again - var delayedTriggers = []; + var i, + delayedTriggers = []; // We first have to update the dom position of the actual currentItem // Note: don't do it if the current item is already removed (by a user), or it gets reappended (see #4088) - if(!this._noFinalSort && this.currentItem.parent().length) this.placeholder.before(this.currentItem); + if(!this._noFinalSort && this.currentItem.parent().length) { + this.placeholder.before(this.currentItem); + } this._noFinalSort = null; - if(this.helper[0] == this.currentItem[0]) { - for(var i in this._storedCSS) { - if(this._storedCSS[i] == 'auto' || this._storedCSS[i] == 'static') this._storedCSS[i] = ''; + if(this.helper[0] === this.currentItem[0]) { + for(i in this._storedCSS) { + if(this._storedCSS[i] === "auto" || this._storedCSS[i] === "static") { + this._storedCSS[i] = ""; + } } this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"); } else { this.currentItem.show(); } - if(this.fromOutside && !noPropagation) delayedTriggers.push(function(event) { this._trigger("receive", event, this._uiHash(this.fromOutside)); }); - if((this.fromOutside || this.domPosition.prev != this.currentItem.prev().not(".ui-sortable-helper")[0] || this.domPosition.parent != this.currentItem.parent()[0]) && !noPropagation) delayedTriggers.push(function(event) { this._trigger("update", event, this._uiHash()); }); //Trigger update callback if the DOM position has changed + if(this.fromOutside && !noPropagation) { + delayedTriggers.push(function(event) { this._trigger("receive", event, this._uiHash(this.fromOutside)); }); + } + if((this.fromOutside || this.domPosition.prev !== this.currentItem.prev().not(".ui-sortable-helper")[0] || this.domPosition.parent !== this.currentItem.parent()[0]) && !noPropagation) { + delayedTriggers.push(function(event) { this._trigger("update", event, this._uiHash()); }); //Trigger update callback if the DOM position has changed + } // Check if the items Container has Changed and trigger appropriate // events. @@ -4178,8 +4660,10 @@ $.widget("ui.sortable", $.ui.mouse, { //Post events to containers - for (var i = this.containers.length - 1; i >= 0; i--){ - if(!noPropagation) delayedTriggers.push((function(c) { return function(event) { c._trigger("deactivate", event, this._uiHash(this)); }; }).call(this, this.containers[i])); + for (i = this.containers.length - 1; i >= 0; i--){ + if(!noPropagation) { + delayedTriggers.push((function(c) { return function(event) { c._trigger("deactivate", event, this._uiHash(this)); }; }).call(this, this.containers[i])); + } if(this.containers[i].containerCache.over) { delayedTriggers.push((function(c) { return function(event) { c._trigger("out", event, this._uiHash(this)); }; }).call(this, this.containers[i])); this.containers[i].containerCache.over = 0; @@ -4187,15 +4671,24 @@ $.widget("ui.sortable", $.ui.mouse, { } //Do what was originally in plugins - if(this._storedCursor) $('body').css("cursor", this._storedCursor); //Reset cursor - if(this._storedOpacity) this.helper.css("opacity", this._storedOpacity); //Reset opacity - if(this._storedZIndex) this.helper.css("zIndex", this._storedZIndex == 'auto' ? '' : this._storedZIndex); //Reset z-index + if ( this.storedCursor ) { + this.document.find( "body" ).css( "cursor", this.storedCursor ); + this.storedStylesheet.remove(); + } + if(this._storedOpacity) { + this.helper.css("opacity", this._storedOpacity); + } + if(this._storedZIndex) { + this.helper.css("zIndex", this._storedZIndex === "auto" ? "" : this._storedZIndex); + } this.dragging = false; if(this.cancelHelperRemoval) { if(!noPropagation) { this._trigger("beforeStop", event, this._uiHash()); - for (var i=0; i < delayedTriggers.length; i++) { delayedTriggers[i].call(this, event); }; //Trigger all delayed events + for (i=0; i < delayedTriggers.length; i++) { + delayedTriggers[i].call(this, event); + } //Trigger all delayed events this._trigger("stop", event, this._uiHash()); } @@ -4203,15 +4696,22 @@ $.widget("ui.sortable", $.ui.mouse, { return false; } - if(!noPropagation) this._trigger("beforeStop", event, this._uiHash()); + if(!noPropagation) { + this._trigger("beforeStop", event, this._uiHash()); + } //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node! this.placeholder[0].parentNode.removeChild(this.placeholder[0]); - if(this.helper[0] != this.currentItem[0]) this.helper.remove(); this.helper = null; + if(this.helper[0] !== this.currentItem[0]) { + this.helper.remove(); + } + this.helper = null; if(!noPropagation) { - for (var i=0; i < delayedTriggers.length; i++) { delayedTriggers[i].call(this, event); }; //Trigger all delayed events + for (i=0; i < delayedTriggers.length; i++) { + delayedTriggers[i].call(this, event); + } //Trigger all delayed events this._trigger("stop", event, this._uiHash()); } @@ -4243,35 +4743,33 @@ $.widget("ui.sortable", $.ui.mouse, { })(jQuery); -;(jQuery.effects || (function($, undefined) { +(function($, undefined) { -var backCompat = $.uiBackCompat !== false, - // prefix used for storing data on .data() - dataSpace = "ui-effects-"; +var dataSpace = "ui-effects-"; $.effects = { effect: {} }; /*! - * jQuery Color Animations v2.0.0 - * http://jquery.com/ + * jQuery Color Animations v2.1.2 + * https://github.com/jquery/jquery-color * - * Copyright 2012 jQuery Foundation and other contributors + * Copyright 2013 jQuery Foundation and other contributors * Released under the MIT license. * http://jquery.org/license * - * Date: Mon Aug 13 13:41:02 2012 -0500 + * Date: Wed Jan 16 08:47:09 2013 -0600 */ (function( jQuery, undefined ) { - var stepHooks = "backgroundColor borderBottomColor borderLeftColor borderRightColor borderTopColor color columnRuleColor outlineColor textDecorationColor textEmphasisColor".split(" "), + var stepHooks = "backgroundColor borderBottomColor borderLeftColor borderRightColor borderTopColor color columnRuleColor outlineColor textDecorationColor textEmphasisColor", // plusequals test for += 100 -= 100 rplusequals = /^([\-+])=\s*(\d+\.?\d*)/, // a set of RE's that can match strings and generate color tuples. stringParsers = [{ - re: /rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d+(?:\.\d+)?)\s*)?\)/, + re: /rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/, parse: function( execResult ) { return [ execResult[ 1 ], @@ -4281,7 +4779,7 @@ $.effects = { ]; } }, { - re: /rgba?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d+(?:\.\d+)?)\s*)?\)/, + re: /rgba?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/, parse: function( execResult ) { return [ execResult[ 1 ] * 2.55, @@ -4311,7 +4809,7 @@ $.effects = { ]; } }, { - re: /hsla?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d+(?:\.\d+)?)\s*)?\)/, + re: /hsla?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/, space: "hsla", parse: function( execResult ) { return [ @@ -4528,7 +5026,7 @@ color.fn = jQuery.extend( color.prototype, { }); // everything defined but alpha? - if ( inst[ cache ] && $.inArray( null, inst[ cache ].slice( 0, 3 ) ) < 0 ) { + if ( inst[ cache ] && jQuery.inArray( null, inst[ cache ].slice( 0, 3 ) ) < 0 ) { // use the default of 1 inst[ cache ][ 3 ] = 1; if ( space.from ) { @@ -4716,8 +5214,10 @@ spaces.hsla.to = function ( rgba ) { h = ( 60 * ( r - g ) / diff ) + 240; } - if ( l === 0 || l === 1 ) { - s = l; + // chroma (diff) == 0 means greyscale which, by definition, saturation = 0% + // otherwise, saturation is based on the ratio of chroma (diff) to lightness (add) + if ( diff === 0 ) { + s = 0; } else if ( l <= 0.5 ) { s = diff / add; } else { @@ -4821,51 +5321,58 @@ each( spaces, function( spaceName, space ) { }); }); -// add .fx.step functions -each( stepHooks, function( i, hook ) { - jQuery.cssHooks[ hook ] = { - set: function( elem, value ) { - var parsed, curElem, - backgroundColor = ""; - - if ( jQuery.type( value ) !== "string" || ( parsed = stringParse( value ) ) ) { - value = color( parsed || value ); - if ( !support.rgba && value._rgba[ 3 ] !== 1 ) { - curElem = hook === "backgroundColor" ? elem.parentNode : elem; - while ( - (backgroundColor === "" || backgroundColor === "transparent") && - curElem && curElem.style - ) { - try { - backgroundColor = jQuery.css( curElem, "backgroundColor" ); - curElem = curElem.parentNode; - } catch ( e ) { +// add cssHook and .fx.step function for each named hook. +// accept a space separated string of properties +color.hook = function( hook ) { + var hooks = hook.split( " " ); + each( hooks, function( i, hook ) { + jQuery.cssHooks[ hook ] = { + set: function( elem, value ) { + var parsed, curElem, + backgroundColor = ""; + + if ( value !== "transparent" && ( jQuery.type( value ) !== "string" || ( parsed = stringParse( value ) ) ) ) { + value = color( parsed || value ); + if ( !support.rgba && value._rgba[ 3 ] !== 1 ) { + curElem = hook === "backgroundColor" ? elem.parentNode : elem; + while ( + (backgroundColor === "" || backgroundColor === "transparent") && + curElem && curElem.style + ) { + try { + backgroundColor = jQuery.css( curElem, "backgroundColor" ); + curElem = curElem.parentNode; + } catch ( e ) { + } } + + value = value.blend( backgroundColor && backgroundColor !== "transparent" ? + backgroundColor : + "_default" ); } - value = value.blend( backgroundColor && backgroundColor !== "transparent" ? - backgroundColor : - "_default" ); + value = value.toRgbaString(); + } + try { + elem.style[ hook ] = value; + } catch( e ) { + // wrapped to prevent IE from throwing errors on "invalid" values like 'auto' or 'inherit' } - - value = value.toRgbaString(); } - try { - elem.style[ hook ] = value; - } catch( error ) { - // wrapped to prevent IE from throwing errors on "invalid" values like 'auto' or 'inherit' + }; + jQuery.fx.step[ hook ] = function( fx ) { + if ( !fx.colorInit ) { + fx.start = color( fx.elem, hook ); + fx.end = color( fx.end ); + fx.colorInit = true; } - } - }; - jQuery.fx.step[ hook ] = function( fx ) { - if ( !fx.colorInit ) { - fx.start = color( fx.elem, hook ); - fx.end = color( fx.end ); - fx.colorInit = true; - } - jQuery.cssHooks[ hook ].set( fx.elem, fx.start.transition( fx.end, fx.pos ) ); - }; -}); + jQuery.cssHooks[ hook ].set( fx.elem, fx.start.transition( fx.end, fx.pos ) ); + }; + }); + +}; + +color.hook( stepHooks ); jQuery.cssHooks.borderColor = { expand: function( value ) { @@ -4909,7 +5416,6 @@ colors = jQuery.Color.names = { })( jQuery ); - /******************************************************************************/ /****************************** CLASS ANIMATIONS ******************************/ /******************************************************************************/ @@ -4937,32 +5443,31 @@ $.each([ "borderLeftStyle", "borderRightStyle", "borderBottomStyle", "borderTopS }; }); -function getElementStyles() { - var style = this.ownerDocument.defaultView ? - this.ownerDocument.defaultView.getComputedStyle( this, null ) : - this.currentStyle, - newStyle = {}, - key, - len; +function getElementStyles( elem ) { + var key, len, + style = elem.ownerDocument.defaultView ? + elem.ownerDocument.defaultView.getComputedStyle( elem, null ) : + elem.currentStyle, + styles = {}; - // webkit enumerates style porperties if ( style && style.length && style[ 0 ] && style[ style[ 0 ] ] ) { len = style.length; while ( len-- ) { key = style[ len ]; if ( typeof style[ key ] === "string" ) { - newStyle[ $.camelCase( key ) ] = style[ key ]; + styles[ $.camelCase( key ) ] = style[ key ]; } } + // support: Opera, IE <9 } else { for ( key in style ) { if ( typeof style[ key ] === "string" ) { - newStyle[ key ] = style[ key ]; + styles[ key ] = style[ key ]; } } } - return newStyle; + return styles; } @@ -4984,6 +5489,15 @@ function styleDifference( oldStyle, newStyle ) { return diff; } +// support: jQuery <1.8 +if ( !$.fn.addBack ) { + $.fn.addBack = function( selector ) { + return this.add( selector == null ? + this.prevObject : this.prevObject.filter( selector ) + ); + }; +} + $.effects.animateClass = function( value, duration, easing, callback ) { var o = $.speed( duration, easing, callback ); @@ -4991,14 +5505,14 @@ $.effects.animateClass = function( value, duration, easing, callback ) { var animated = $( this ), baseClass = animated.attr( "class" ) || "", applyClassChange, - allAnimations = o.children ? animated.find( "*" ).andSelf() : animated; + allAnimations = o.children ? animated.find( "*" ).addBack() : animated; // map the animated objects to store the original styles. allAnimations = allAnimations.map(function() { var el = $( this ); return { el: el, - start: getElementStyles.call( this ) + start: getElementStyles( this ) }; }); @@ -5014,7 +5528,7 @@ $.effects.animateClass = function( value, duration, easing, callback ) { // map all animated objects again - calculate new styles and diff allAnimations = allAnimations.map(function() { - this.end = getElementStyles.call( this.el[ 0 ] ); + this.end = getElementStyles( this.el[ 0 ] ); this.diff = styleDifference( this.start, this.end ); return this; }); @@ -5026,7 +5540,7 @@ $.effects.animateClass = function( value, duration, easing, callback ) { allAnimations = allAnimations.map(function() { var styleInfo = this, dfd = $.Deferred(), - opts = jQuery.extend({}, o, { + opts = $.extend({}, o, { queue: false, complete: function() { dfd.resolve( styleInfo ); @@ -5048,7 +5562,7 @@ $.effects.animateClass = function( value, duration, easing, callback ) { $.each( arguments, function() { var el = this.el; $.each( this.diff, function(key) { - el.css( key, '' ); + el.css( key, "" ); }); }); @@ -5060,39 +5574,42 @@ $.effects.animateClass = function( value, duration, easing, callback ) { }; $.fn.extend({ - _addClass: $.fn.addClass, - addClass: function( classNames, speed, easing, callback ) { - return speed ? - $.effects.animateClass.call( this, - { add: classNames }, speed, easing, callback ) : - this._addClass( classNames ); - }, - - _removeClass: $.fn.removeClass, - removeClass: function( classNames, speed, easing, callback ) { - return speed ? - $.effects.animateClass.call( this, - { remove: classNames }, speed, easing, callback ) : - this._removeClass( classNames ); - }, - - _toggleClass: $.fn.toggleClass, - toggleClass: function( classNames, force, speed, easing, callback ) { - if ( typeof force === "boolean" || force === undefined ) { - if ( !speed ) { - // without speed parameter - return this._toggleClass( classNames, force ); + addClass: (function( orig ) { + return function( classNames, speed, easing, callback ) { + return speed ? + $.effects.animateClass.call( this, + { add: classNames }, speed, easing, callback ) : + orig.apply( this, arguments ); + }; + })( $.fn.addClass ), + + removeClass: (function( orig ) { + return function( classNames, speed, easing, callback ) { + return arguments.length > 1 ? + $.effects.animateClass.call( this, + { remove: classNames }, speed, easing, callback ) : + orig.apply( this, arguments ); + }; + })( $.fn.removeClass ), + + toggleClass: (function( orig ) { + return function( classNames, force, speed, easing, callback ) { + if ( typeof force === "boolean" || force === undefined ) { + if ( !speed ) { + // without speed parameter + return orig.apply( this, arguments ); + } else { + return $.effects.animateClass.call( this, + (force ? { add: classNames } : { remove: classNames }), + speed, easing, callback ); + } } else { + // without force parameter return $.effects.animateClass.call( this, - (force ? { add: classNames } : { remove: classNames }), - speed, easing, callback ); + { toggle: classNames }, force, speed, easing ); } - } else { - // without force parameter - return $.effects.animateClass.call( this, - { toggle: classNames }, force, speed, easing ); - } - }, + }; + })( $.fn.toggleClass ), switchClass: function( remove, add, speed, easing, callback) { return $.effects.animateClass.call( this, { @@ -5111,7 +5628,7 @@ $.fn.extend({ (function() { $.extend( $.effects, { - version: "1.9.2", + version: "1.10.2", // Saves a set of properties in a data storage save: function( element, set ) { @@ -5327,21 +5844,28 @@ function _normalizeArguments( effect, options, speed, callback ) { return effect; } -function standardSpeed( speed ) { - // valid standard speeds - if ( !speed || typeof speed === "number" || $.fx.speeds[ speed ] ) { +function standardAnimationOption( option ) { + // Valid standard speeds (nothing, number, named speed) + if ( !option || typeof option === "number" || $.fx.speeds[ option ] ) { return true; } - // invalid strings - treat as "normal" speed - if ( typeof speed === "string" && !$.effects.effect[ speed ] ) { - // TODO: remove in 2.0 (#7115) - if ( backCompat && $.effects[ speed ] ) { - return false; - } + // Invalid strings - treat as "normal" speed + if ( typeof option === "string" && !$.effects.effect[ option ] ) { + return true; + } + + // Complete callback + if ( $.isFunction( option ) ) { return true; } + // Options hash (but not naming an effect) + if ( typeof option === "object" && !option.effect ) { + return true; + } + + // Didn't match any standard API return false; } @@ -5350,12 +5874,9 @@ $.fn.extend({ var args = _normalizeArguments.apply( this, arguments ), mode = args.mode, queue = args.queue, - effectMethod = $.effects.effect[ args.effect ], - - // DEPRECATED: remove in 2.0 (#7115) - oldEffectMethod = !effectMethod && backCompat && $.effects[ args.effect ]; + effectMethod = $.effects.effect[ args.effect ]; - if ( $.fx.off || !( effectMethod || oldEffectMethod ) ) { + if ( $.fx.off || !effectMethod ) { // delegate to the original method (e.g., .show()) if possible if ( mode ) { return this[ mode ]( args.duration, args.complete ); @@ -5382,62 +5903,54 @@ $.fn.extend({ } } - // if the element is hiddden and mode is hide, - // or element is visible and mode is show + // If the element already has the correct final state, delegate to + // the core methods so the internal tracking of "olddisplay" works. if ( elem.is( ":hidden" ) ? mode === "hide" : mode === "show" ) { + elem[ mode ](); done(); } else { effectMethod.call( elem[0], args, done ); } } - // TODO: remove this check in 2.0, effectMethod will always be true - if ( effectMethod ) { - return queue === false ? this.each( run ) : this.queue( queue || "fx", run ); - } else { - // DEPRECATED: remove in 2.0 (#7115) - return oldEffectMethod.call(this, { - options: args, - duration: args.duration, - callback: args.complete, - mode: args.mode - }); - } + return queue === false ? this.each( run ) : this.queue( queue || "fx", run ); }, - _show: $.fn.show, - show: function( speed ) { - if ( standardSpeed( speed ) ) { - return this._show.apply( this, arguments ); - } else { - var args = _normalizeArguments.apply( this, arguments ); - args.mode = "show"; - return this.effect.call( this, args ); - } - }, + show: (function( orig ) { + return function( option ) { + if ( standardAnimationOption( option ) ) { + return orig.apply( this, arguments ); + } else { + var args = _normalizeArguments.apply( this, arguments ); + args.mode = "show"; + return this.effect.call( this, args ); + } + }; + })( $.fn.show ), - _hide: $.fn.hide, - hide: function( speed ) { - if ( standardSpeed( speed ) ) { - return this._hide.apply( this, arguments ); - } else { - var args = _normalizeArguments.apply( this, arguments ); - args.mode = "hide"; - return this.effect.call( this, args ); - } - }, + hide: (function( orig ) { + return function( option ) { + if ( standardAnimationOption( option ) ) { + return orig.apply( this, arguments ); + } else { + var args = _normalizeArguments.apply( this, arguments ); + args.mode = "hide"; + return this.effect.call( this, args ); + } + }; + })( $.fn.hide ), - // jQuery core overloads toggle and creates _toggle - __toggle: $.fn.toggle, - toggle: function( speed ) { - if ( standardSpeed( speed ) || typeof speed === "boolean" || $.isFunction( speed ) ) { - return this.__toggle.apply( this, arguments ); - } else { - var args = _normalizeArguments.apply( this, arguments ); - args.mode = "toggle"; - return this.effect.call( this, args ); - } - }, + toggle: (function( orig ) { + return function( option ) { + if ( standardAnimationOption( option ) || typeof option === "boolean" ) { + return orig.apply( this, arguments ); + } else { + var args = _normalizeArguments.apply( this, arguments ); + args.mode = "toggle"; + return this.effect.call( this, args ); + } + }; + })( $.fn.toggle ), // helper functions cssUnit: function(key) { @@ -5508,7 +6021,7 @@ $.each( baseEasings, function( name, easeIn ) { })(); -})(jQuery)); +})(jQuery); (function( $, undefined ) { @@ -5522,7 +6035,7 @@ showProps.height = showProps.paddingTop = showProps.paddingBottom = showProps.borderTopWidth = showProps.borderBottomWidth = "show"; $.widget( "ui.accordion", { - version: "1.9.2", + version: "1.10.2", options: { active: 0, animate: {}, @@ -5541,100 +6054,29 @@ $.widget( "ui.accordion", { }, _create: function() { - var accordionId = this.accordionId = "ui-accordion-" + - (this.element.attr( "id" ) || ++uid), - options = this.options; - + var options = this.options; this.prevShow = this.prevHide = $(); - this.element.addClass( "ui-accordion ui-widget ui-helper-reset" ); - - this.headers = this.element.find( options.header ) - .addClass( "ui-accordion-header ui-helper-reset ui-state-default ui-corner-all" ); - this._hoverable( this.headers ); - this._focusable( this.headers ); - - this.headers.next() - .addClass( "ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom" ) - .hide(); + this.element.addClass( "ui-accordion ui-widget ui-helper-reset" ) + // ARIA + .attr( "role", "tablist" ); // don't allow collapsible: false and active: false / null if ( !options.collapsible && (options.active === false || options.active == null) ) { options.active = 0; } + + this._processPanels(); // handle negative values if ( options.active < 0 ) { options.active += this.headers.length; } - this.active = this._findActive( options.active ) - .addClass( "ui-accordion-header-active ui-state-active" ) - .toggleClass( "ui-corner-all ui-corner-top" ); - this.active.next() - .addClass( "ui-accordion-content-active" ) - .show(); - - this._createIcons(); - this.refresh(); - - // ARIA - this.element.attr( "role", "tablist" ); - - this.headers - .attr( "role", "tab" ) - .each(function( i ) { - var header = $( this ), - headerId = header.attr( "id" ), - panel = header.next(), - panelId = panel.attr( "id" ); - if ( !headerId ) { - headerId = accordionId + "-header-" + i; - header.attr( "id", headerId ); - } - if ( !panelId ) { - panelId = accordionId + "-panel-" + i; - panel.attr( "id", panelId ); - } - header.attr( "aria-controls", panelId ); - panel.attr( "aria-labelledby", headerId ); - }) - .next() - .attr( "role", "tabpanel" ); - - this.headers - .not( this.active ) - .attr({ - "aria-selected": "false", - tabIndex: -1 - }) - .next() - .attr({ - "aria-expanded": "false", - "aria-hidden": "true" - }) - .hide(); - - // make sure at least one header is in the tab order - if ( !this.active.length ) { - this.headers.eq( 0 ).attr( "tabIndex", 0 ); - } else { - this.active.attr({ - "aria-selected": "true", - tabIndex: 0 - }) - .next() - .attr({ - "aria-expanded": "true", - "aria-hidden": "false" - }); - } - - this._on( this.headers, { keydown: "_keydown" }); - this._on( this.headers.next(), { keydown: "_panelKeyDown" }); - this._setupEvents( options.event ); + this._refresh(); }, _getCreateEventData: function() { return { header: this.active, + panel: !this.active.length ? $() : this.active.next(), content: !this.active.length ? $() : this.active.next() }; }, @@ -5736,6 +6178,7 @@ $.widget( "ui.accordion", { }, _keydown: function( event ) { + /*jshint maxcomplexity:15*/ if ( event.altKey || event.ctrlKey ) { return; } @@ -5781,85 +6224,184 @@ $.widget( "ui.accordion", { }, refresh: function() { - var maxHeight, overflow, - heightStyle = this.options.heightStyle, - parent = this.element.parent(); - - - if ( heightStyle === "fill" ) { - // IE 6 treats height like minHeight, so we need to turn off overflow - // in order to get a reliable height - // we use the minHeight support test because we assume that only - // browsers that don't support minHeight will treat height as minHeight - if ( !$.support.minHeight ) { - overflow = parent.css( "overflow" ); - parent.css( "overflow", "hidden"); - } - maxHeight = parent.height(); - this.element.siblings( ":visible" ).each(function() { - var elem = $( this ), - position = elem.css( "position" ); + var options = this.options; + this._processPanels(); - if ( position === "absolute" || position === "fixed" ) { - return; - } - maxHeight -= elem.outerHeight( true ); - }); - if ( overflow ) { - parent.css( "overflow", overflow ); + // was collapsed or no panel + if ( ( options.active === false && options.collapsible === true ) || !this.headers.length ) { + options.active = false; + this.active = $(); + // active false only when collapsible is true + } if ( options.active === false ) { + this._activate( 0 ); + // was active, but active panel is gone + } else if ( this.active.length && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) { + // all remaining panel are disabled + if ( this.headers.length === this.headers.find(".ui-state-disabled").length ) { + options.active = false; + this.active = $(); + // activate previous panel + } else { + this._activate( Math.max( 0, options.active - 1 ) ); } - - this.headers.each(function() { - maxHeight -= $( this ).outerHeight( true ); - }); - - this.headers.next() - .each(function() { - $( this ).height( Math.max( 0, maxHeight - - $( this ).innerHeight() + $( this ).height() ) ); - }) - .css( "overflow", "auto" ); - } else if ( heightStyle === "auto" ) { - maxHeight = 0; - this.headers.next() - .each(function() { - maxHeight = Math.max( maxHeight, $( this ).css( "height", "" ).height() ); - }) - .height( maxHeight ); + // was active, active panel still exists + } else { + // make sure active index is correct + options.active = this.headers.index( this.active ); } - }, - _activate: function( index ) { - var active = this._findActive( index )[ 0 ]; + this._destroyIcons(); - // trying to activate the already active panel - if ( active === this.active[ 0 ] ) { - return; - } + this._refresh(); + }, - // trying to collapse, simulate a click on the currently active header - active = active || this.active[ 0 ]; + _processPanels: function() { + this.headers = this.element.find( this.options.header ) + .addClass( "ui-accordion-header ui-helper-reset ui-state-default ui-corner-all" ); - this._eventHandler({ - target: active, - currentTarget: active, - preventDefault: $.noop - }); + this.headers.next() + .addClass( "ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom" ) + .filter(":not(.ui-accordion-content-active)") + .hide(); }, - _findActive: function( selector ) { - return typeof selector === "number" ? this.headers.eq( selector ) : $(); + _refresh: function() { + var maxHeight, + options = this.options, + heightStyle = options.heightStyle, + parent = this.element.parent(), + accordionId = this.accordionId = "ui-accordion-" + + (this.element.attr( "id" ) || ++uid); + + this.active = this._findActive( options.active ) + .addClass( "ui-accordion-header-active ui-state-active ui-corner-top" ) + .removeClass( "ui-corner-all" ); + this.active.next() + .addClass( "ui-accordion-content-active" ) + .show(); + + this.headers + .attr( "role", "tab" ) + .each(function( i ) { + var header = $( this ), + headerId = header.attr( "id" ), + panel = header.next(), + panelId = panel.attr( "id" ); + if ( !headerId ) { + headerId = accordionId + "-header-" + i; + header.attr( "id", headerId ); + } + if ( !panelId ) { + panelId = accordionId + "-panel-" + i; + panel.attr( "id", panelId ); + } + header.attr( "aria-controls", panelId ); + panel.attr( "aria-labelledby", headerId ); + }) + .next() + .attr( "role", "tabpanel" ); + + this.headers + .not( this.active ) + .attr({ + "aria-selected": "false", + tabIndex: -1 + }) + .next() + .attr({ + "aria-expanded": "false", + "aria-hidden": "true" + }) + .hide(); + + // make sure at least one header is in the tab order + if ( !this.active.length ) { + this.headers.eq( 0 ).attr( "tabIndex", 0 ); + } else { + this.active.attr({ + "aria-selected": "true", + tabIndex: 0 + }) + .next() + .attr({ + "aria-expanded": "true", + "aria-hidden": "false" + }); + } + + this._createIcons(); + + this._setupEvents( options.event ); + + if ( heightStyle === "fill" ) { + maxHeight = parent.height(); + this.element.siblings( ":visible" ).each(function() { + var elem = $( this ), + position = elem.css( "position" ); + + if ( position === "absolute" || position === "fixed" ) { + return; + } + maxHeight -= elem.outerHeight( true ); + }); + + this.headers.each(function() { + maxHeight -= $( this ).outerHeight( true ); + }); + + this.headers.next() + .each(function() { + $( this ).height( Math.max( 0, maxHeight - + $( this ).innerHeight() + $( this ).height() ) ); + }) + .css( "overflow", "auto" ); + } else if ( heightStyle === "auto" ) { + maxHeight = 0; + this.headers.next() + .each(function() { + maxHeight = Math.max( maxHeight, $( this ).css( "height", "" ).height() ); + }) + .height( maxHeight ); + } }, - _setupEvents: function( event ) { - var events = {}; - if ( !event ) { + _activate: function( index ) { + var active = this._findActive( index )[ 0 ]; + + // trying to activate the already active panel + if ( active === this.active[ 0 ] ) { return; } - $.each( event.split(" "), function( index, eventName ) { - events[ eventName ] = "_eventHandler"; + + // trying to collapse, simulate a click on the currently active header + active = active || this.active[ 0 ]; + + this._eventHandler({ + target: active, + currentTarget: active, + preventDefault: $.noop }); + }, + + _findActive: function( selector ) { + return typeof selector === "number" ? this.headers.eq( selector ) : $(); + }, + + _setupEvents: function( event ) { + var events = { + keydown: "_keydown" + }; + if ( event ) { + $.each( event.split(" "), function( index, eventName ) { + events[ eventName ] = "_eventHandler"; + }); + } + + this._off( this.headers.add( this.headers.next() ) ); this._on( this.headers, events ); + this._on( this.headers.next(), { keydown: "_panelKeyDown" }); + this._hoverable( this.headers ); + this._focusable( this.headers ); }, _eventHandler: function( event ) { @@ -6038,194 +6580,6 @@ $.widget( "ui.accordion", { } }); - - -// DEPRECATED -if ( $.uiBackCompat !== false ) { - // navigation options - (function( $, prototype ) { - $.extend( prototype.options, { - navigation: false, - navigationFilter: function() { - return this.href.toLowerCase() === location.href.toLowerCase(); - } - }); - - var _create = prototype._create; - prototype._create = function() { - if ( this.options.navigation ) { - var that = this, - headers = this.element.find( this.options.header ), - content = headers.next(), - current = headers.add( content ) - .find( "a" ) - .filter( this.options.navigationFilter ) - [ 0 ]; - if ( current ) { - headers.add( content ).each( function( index ) { - if ( $.contains( this, current ) ) { - that.options.active = Math.floor( index / 2 ); - return false; - } - }); - } - } - _create.call( this ); - }; - }( jQuery, jQuery.ui.accordion.prototype ) ); - - // height options - (function( $, prototype ) { - $.extend( prototype.options, { - heightStyle: null, // remove default so we fall back to old values - autoHeight: true, // use heightStyle: "auto" - clearStyle: false, // use heightStyle: "content" - fillSpace: false // use heightStyle: "fill" - }); - - var _create = prototype._create, - _setOption = prototype._setOption; - - $.extend( prototype, { - _create: function() { - this.options.heightStyle = this.options.heightStyle || - this._mergeHeightStyle(); - - _create.call( this ); - }, - - _setOption: function( key ) { - if ( key === "autoHeight" || key === "clearStyle" || key === "fillSpace" ) { - this.options.heightStyle = this._mergeHeightStyle(); - } - _setOption.apply( this, arguments ); - }, - - _mergeHeightStyle: function() { - var options = this.options; - - if ( options.fillSpace ) { - return "fill"; - } - - if ( options.clearStyle ) { - return "content"; - } - - if ( options.autoHeight ) { - return "auto"; - } - } - }); - }( jQuery, jQuery.ui.accordion.prototype ) ); - - // icon options - (function( $, prototype ) { - $.extend( prototype.options.icons, { - activeHeader: null, // remove default so we fall back to old values - headerSelected: "ui-icon-triangle-1-s" - }); - - var _createIcons = prototype._createIcons; - prototype._createIcons = function() { - if ( this.options.icons ) { - this.options.icons.activeHeader = this.options.icons.activeHeader || - this.options.icons.headerSelected; - } - _createIcons.call( this ); - }; - }( jQuery, jQuery.ui.accordion.prototype ) ); - - // expanded active option, activate method - (function( $, prototype ) { - prototype.activate = prototype._activate; - - var _findActive = prototype._findActive; - prototype._findActive = function( index ) { - if ( index === -1 ) { - index = false; - } - if ( index && typeof index !== "number" ) { - index = this.headers.index( this.headers.filter( index ) ); - if ( index === -1 ) { - index = false; - } - } - return _findActive.call( this, index ); - }; - }( jQuery, jQuery.ui.accordion.prototype ) ); - - // resize method - jQuery.ui.accordion.prototype.resize = jQuery.ui.accordion.prototype.refresh; - - // change events - (function( $, prototype ) { - $.extend( prototype.options, { - change: null, - changestart: null - }); - - var _trigger = prototype._trigger; - prototype._trigger = function( type, event, data ) { - var ret = _trigger.apply( this, arguments ); - if ( !ret ) { - return false; - } - - if ( type === "beforeActivate" ) { - ret = _trigger.call( this, "changestart", event, { - oldHeader: data.oldHeader, - oldContent: data.oldPanel, - newHeader: data.newHeader, - newContent: data.newPanel - }); - } else if ( type === "activate" ) { - ret = _trigger.call( this, "change", event, { - oldHeader: data.oldHeader, - oldContent: data.oldPanel, - newHeader: data.newHeader, - newContent: data.newPanel - }); - } - return ret; - }; - }( jQuery, jQuery.ui.accordion.prototype ) ); - - // animated option - // NOTE: this only provides support for "slide", "bounceslide", and easings - // not the full $.ui.accordion.animations API - (function( $, prototype ) { - $.extend( prototype.options, { - animate: null, - animated: "slide" - }); - - var _create = prototype._create; - prototype._create = function() { - var options = this.options; - if ( options.animate === null ) { - if ( !options.animated ) { - options.animate = false; - } else if ( options.animated === "slide" ) { - options.animate = 300; - } else if ( options.animated === "bounceslide" ) { - options.animate = { - duration: 200, - down: { - easing: "easeOutBounce", - duration: 1000 - } - }; - } else { - options.animate = options.animated; - } - } - - _create.call( this ); - }; - }( jQuery, jQuery.ui.accordion.prototype ) ); -} - })( jQuery ); (function( $, undefined ) { @@ -6234,10 +6588,10 @@ if ( $.uiBackCompat !== false ) { var requestIndex = 0; $.widget( "ui.autocomplete", { - version: "1.9.2", + version: "1.10.2", defaultElement: "<input>", options: { - appendTo: "body", + appendTo: null, autoFocus: false, delay: 300, minLength: 1, @@ -6268,10 +6622,21 @@ $.widget( "ui.autocomplete", { // so we use the suppressKeyPressRepeat flag to avoid handling keypress // events when we know the keydown event was used to modify the // search term. #7799 - var suppressKeyPress, suppressKeyPressRepeat, suppressInput; - - this.isMultiLine = this._isMultiLine(); - this.valueMethod = this.element[ this.element.is( "input,textarea" ) ? "val" : "text" ]; + var suppressKeyPress, suppressKeyPressRepeat, suppressInput, + nodeName = this.element[0].nodeName.toLowerCase(), + isTextarea = nodeName === "textarea", + isInput = nodeName === "input"; + + this.isMultiLine = + // Textareas are always multi-line + isTextarea ? true : + // Inputs are always single-line, even if inside a contentEditable element + // IE also treats inputs as contentEditable + isInput ? false : + // All other element types are determined by whether or not they're contentEditable + this.element.prop( "isContentEditable" ); + + this.valueMethod = this.element[ isTextarea || isInput ? "val" : "text" ]; this.isNewMenu = true; this.element @@ -6280,6 +6645,7 @@ $.widget( "ui.autocomplete", { this._on( this.element, { keydown: function( event ) { + /*jshint maxcomplexity:15*/ if ( this.element.prop( "readOnly" ) ) { suppressKeyPress = true; suppressInput = true; @@ -6394,17 +6760,16 @@ $.widget( "ui.autocomplete", { this._initSource(); this.menu = $( "<ul>" ) - .addClass( "ui-autocomplete" ) - .appendTo( this.document.find( this.options.appendTo || "body" )[ 0 ] ) + .addClass( "ui-autocomplete ui-front" ) + .appendTo( this._appendTo() ) .menu({ // custom key handling for now input: $(), // disable ARIA support, the live region takes care of that role: null }) - .zIndex( this.element.zIndex() + 1 ) .hide() - .data( "menu" ); + .data( "ui-menu" ); this._on( this.menu.element, { mousedown: function( event ) { @@ -6437,7 +6802,8 @@ $.widget( "ui.autocomplete", { } }, menufocus: function( event, ui ) { - // #7024 - Prevent accidental activation of menu items in Firefox + // support: Firefox + // Prevent accidental activation of menu items in Firefox (#7024 #9118) if ( this.isNewMenu ) { this.isNewMenu = false; if ( event.originalEvent && /^mouse/.test( event.originalEvent.type ) ) { @@ -6451,9 +6817,7 @@ $.widget( "ui.autocomplete", { } } - // back compat for _renderItem using item.autocomplete, via #7810 - // TODO remove the fallback, see #8156 - var item = ui.item.data( "ui-autocomplete-item" ) || ui.item.data( "item.autocomplete" ); + var item = ui.item.data( "ui-autocomplete-item" ); if ( false !== this._trigger( "focus", event, { item: item } ) ) { // use value to match what will end up in the input, if it was a key event if ( event.originalEvent && /^key/.test( event.originalEvent.type ) ) { @@ -6469,9 +6833,7 @@ $.widget( "ui.autocomplete", { } }, menuselect: function( event, ui ) { - // back compat for _renderItem using item.autocomplete, via #7810 - // TODO remove the fallback, see #8156 - var item = ui.item.data( "ui-autocomplete-item" ) || ui.item.data( "item.autocomplete" ), + var item = ui.item.data( "ui-autocomplete-item" ), previous = this.previous; // only trigger when focus was lost (click on menu) @@ -6506,10 +6868,6 @@ $.widget( "ui.autocomplete", { .addClass( "ui-helper-hidden-accessible" ) .insertAfter( this.element ); - if ( $.fn.bgiframe ) { - this.menu.element.bgiframe(); - } - // turning off autocomplete prevents the browser from remembering the // value when navigating through history, so we re-enable autocomplete // if the page is unloaded before the widget is destroyed. #7790 @@ -6535,25 +6893,31 @@ $.widget( "ui.autocomplete", { this._initSource(); } if ( key === "appendTo" ) { - this.menu.element.appendTo( this.document.find( value || "body" )[0] ); + this.menu.element.appendTo( this._appendTo() ); } if ( key === "disabled" && value && this.xhr ) { this.xhr.abort(); } }, - _isMultiLine: function() { - // Textareas are always multi-line - if ( this.element.is( "textarea" ) ) { - return true; + _appendTo: function() { + var element = this.options.appendTo; + + if ( element ) { + element = element.jquery || element.nodeType ? + $( element ) : + this.document.find( element ).eq( 0 ); } - // Inputs are always single-line, even if inside a contentEditable element - // IE also treats inputs as contentEditable - if ( this.element.is( "input" ) ) { - return false; + + if ( !element ) { + element = this.element.closest( ".ui-front" ); } - // All other element types are determined by whether or not they're contentEditable - return this.element.prop( "isContentEditable" ); + + if ( !element.length ) { + element = this.document[0].body; + } + + return element; }, _initSource: function() { @@ -6693,10 +7057,9 @@ $.widget( "ui.autocomplete", { }, _suggest: function( items ) { - var ul = this.menu.element - .empty() - .zIndex( this.element.zIndex() + 1 ); + var ul = this.menu.element.empty(); this._renderMenu( ul, items ); + this.isNewMenu = true; this.menu.refresh(); // size and position menu @@ -6812,7 +7175,6 @@ $.widget( "ui.autocomplete", $.ui.autocomplete, { } }); - }( jQuery )); (function( $, undefined ) { @@ -6832,6 +7194,7 @@ var lastActive, startXPos, startYPos, clickDragged, form = radio.form, radios = $( [] ); if ( name ) { + name = name.replace( /'/g, "\\'" ); if ( form ) { radios = $( form ).find( "[name='" + name + "']" ); } else { @@ -6845,7 +7208,7 @@ var lastActive, startXPos, startYPos, clickDragged, }; $.widget( "ui.button", { - version: "1.9.2", + version: "1.10.2", defaultElement: "<button>", options: { disabled: null, @@ -6949,8 +7312,6 @@ $.widget( "ui.button", { if ( options.disabled || clickDragged ) { return false; } - $( this ).toggleClass( "ui-state-active" ); - that.buttonElement.attr( "aria-pressed", that.element[0].checked ); }); } else if ( this.type === "radio" ) { this.buttonElement.bind( "click" + this.eventNamespace, function() { @@ -6995,7 +7356,9 @@ $.widget( "ui.button", { $( this ).addClass( "ui-state-active" ); } }) - .bind( "keyup" + this.eventNamespace, function() { + // see #8559, we bind to blur here in case the button element loses + // focus between keydown and keyup, it would be left in an "active" state + .bind( "keyup" + this.eventNamespace + " blur" + this.eventNamespace, function() { $( this ).removeClass( "ui-state-active" ); }); @@ -7162,9 +7525,9 @@ $.widget( "ui.button", { }); $.widget( "ui.buttonset", { - version: "1.9.2", + version: "1.10.2", options: { - items: "button, input[type=button], input[type=submit], input[type=reset], input[type=checkbox], input[type=radio], a, :data(button)" + items: "button, input[type=button], input[type=submit], input[type=reset], input[type=checkbox], input[type=radio], a, :data(ui-button)" }, _create: function() { @@ -7222,11 +7585,11 @@ $.widget( "ui.buttonset", { (function( $, undefined ) { -$.extend($.ui, { datepicker: { version: "1.9.2" } }); +$.extend($.ui, { datepicker: { version: "1.10.2" } }); -var PROP_NAME = 'datepicker'; -var dpuuid = new Date().getTime(); -var instActive; +var PROP_NAME = "datepicker", + dpuuid = new Date().getTime(), + instActive; /* Date picker manager. Use the singleton instance of this class, $.datepicker, to interact with the date picker. @@ -7234,50 +7597,49 @@ var instActive; allowing multiple different settings on the same page. */ function Datepicker() { - this.debug = false; // Change this to true to start debugging this._curInst = null; // The current instance in use this._keyEvent = false; // If the last event was a key event this._disabledInputs = []; // List of date picker inputs that have been disabled this._datepickerShowing = false; // True if the popup picker is showing , false if not this._inDialog = false; // True if showing within a "dialog", false if not - this._mainDivId = 'ui-datepicker-div'; // The ID of the main datepicker division - this._inlineClass = 'ui-datepicker-inline'; // The name of the inline marker class - this._appendClass = 'ui-datepicker-append'; // The name of the append marker class - this._triggerClass = 'ui-datepicker-trigger'; // The name of the trigger marker class - this._dialogClass = 'ui-datepicker-dialog'; // The name of the dialog marker class - this._disableClass = 'ui-datepicker-disabled'; // The name of the disabled covering marker class - this._unselectableClass = 'ui-datepicker-unselectable'; // The name of the unselectable cell marker class - this._currentClass = 'ui-datepicker-current-day'; // The name of the current day marker class - this._dayOverClass = 'ui-datepicker-days-cell-over'; // The name of the day hover marker class + this._mainDivId = "ui-datepicker-div"; // The ID of the main datepicker division + this._inlineClass = "ui-datepicker-inline"; // The name of the inline marker class + this._appendClass = "ui-datepicker-append"; // The name of the append marker class + this._triggerClass = "ui-datepicker-trigger"; // The name of the trigger marker class + this._dialogClass = "ui-datepicker-dialog"; // The name of the dialog marker class + this._disableClass = "ui-datepicker-disabled"; // The name of the disabled covering marker class + this._unselectableClass = "ui-datepicker-unselectable"; // The name of the unselectable cell marker class + this._currentClass = "ui-datepicker-current-day"; // The name of the current day marker class + this._dayOverClass = "ui-datepicker-days-cell-over"; // The name of the day hover marker class this.regional = []; // Available regional settings, indexed by language code - this.regional[''] = { // Default regional settings - closeText: 'Done', // Display text for close link - prevText: 'Prev', // Display text for previous month link - nextText: 'Next', // Display text for next month link - currentText: 'Today', // Display text for current month link - monthNames: ['January','February','March','April','May','June', - 'July','August','September','October','November','December'], // Names of months for drop-down and formatting - monthNamesShort: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], // For formatting - dayNames: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], // For formatting - dayNamesShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], // For formatting - dayNamesMin: ['Su','Mo','Tu','We','Th','Fr','Sa'], // Column headings for days starting at Sunday - weekHeader: 'Wk', // Column header for week of the year - dateFormat: 'mm/dd/yy', // See format options on parseDate + this.regional[""] = { // Default regional settings + closeText: "Done", // Display text for close link + prevText: "Prev", // Display text for previous month link + nextText: "Next", // Display text for next month link + currentText: "Today", // Display text for current month link + monthNames: ["January","February","March","April","May","June", + "July","August","September","October","November","December"], // Names of months for drop-down and formatting + monthNamesShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"], // For formatting + dayNames: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], // For formatting + dayNamesShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], // For formatting + dayNamesMin: ["Su","Mo","Tu","We","Th","Fr","Sa"], // Column headings for days starting at Sunday + weekHeader: "Wk", // Column header for week of the year + dateFormat: "mm/dd/yy", // See format options on parseDate firstDay: 0, // The first day of the week, Sun = 0, Mon = 1, ... isRTL: false, // True if right-to-left language, false if left-to-right showMonthAfterYear: false, // True if the year select precedes month, false for month then year - yearSuffix: '' // Additional text to append to the year in the month headers + yearSuffix: "" // Additional text to append to the year in the month headers }; this._defaults = { // Global defaults for all the date picker instances - showOn: 'focus', // 'focus' for popup on focus, - // 'button' for trigger button, or 'both' for either - showAnim: 'fadeIn', // Name of jQuery animation for popup + showOn: "focus", // "focus" for popup on focus, + // "button" for trigger button, or "both" for either + showAnim: "fadeIn", // Name of jQuery animation for popup showOptions: {}, // Options for enhanced animations defaultDate: null, // Used when field is blank: actual date, // +/-number for offset from today, null for today - appendText: '', // Display text following the input box, e.g. showing the format - buttonText: '...', // Text for trigger button - buttonImage: '', // URL for trigger button image + appendText: "", // Display text following the input box, e.g. showing the format + buttonText: "...", // Text for trigger button + buttonImage: "", // URL for trigger button image buttonImageOnly: false, // True if the image appears alone, false if it appears on a button hideIfNoPrevNext: false, // True to hide next/previous month links // if not applicable, false to just disable them @@ -7285,7 +7647,7 @@ function Datepicker() { gotoCurrent: false, // True if today link goes back to current selection instead changeMonth: false, // True if month can be selected directly, false if only prev/next changeYear: false, // True if year can be selected directly, false if only prev/next - yearRange: 'c-10:c+10', // Range of years to display in drop-down, + yearRange: "c-10:c+10", // Range of years to display in drop-down, // either relative to today's year (-nn:+nn), relative to currently displayed year // (c-nn:c+nn), absolute (nnnn:nnnn), or a combination of the above (nnnn:-n) showOtherMonths: false, // True to show dates in other months, false to leave blank @@ -7293,14 +7655,14 @@ function Datepicker() { showWeek: false, // True to show week of the year, false to not show it calculateWeek: this.iso8601Week, // How to calculate the week of the year, // takes a Date and returns the number of the week for it - shortYearCutoff: '+10', // Short year values < this are in the current century, + shortYearCutoff: "+10", // Short year values < this are in the current century, // > this are in the previous century, - // string value starting with '+' for current year + value + // string value starting with "+" for current year + value minDate: null, // The earliest selectable date, or null for no limit maxDate: null, // The latest selectable date, or null for no limit - duration: 'fast', // Duration of display/closure + duration: "fast", // Duration of display/closure beforeShowDay: null, // Function that takes a date and returns an array with - // [0] = true if selectable, false if not, [1] = custom CSS class name(s) or '', + // [0] = true if selectable, false if not, [1] = custom CSS class name(s) or "", // [2] = cell title (optional), e.g. $.datepicker.noWeekends beforeShow: null, // Function that takes an input field and // returns a set of custom settings for the date picker @@ -7311,69 +7673,53 @@ function Datepicker() { showCurrentAtPos: 0, // The position in multipe months at which to show the current month (starting at 0) stepMonths: 1, // Number of months to step back/forward stepBigMonths: 12, // Number of months to step back/forward for the big links - altField: '', // Selector for an alternate field to store selected dates into - altFormat: '', // The date format to use for the alternate field + altField: "", // Selector for an alternate field to store selected dates into + altFormat: "", // The date format to use for the alternate field constrainInput: true, // The input is constrained by the current date format showButtonPanel: false, // True to show button panel, false to not show it autoSize: false, // True to size the input for the date format, false to leave as is disabled: false // The initial disabled state }; - $.extend(this._defaults, this.regional['']); - this.dpDiv = bindHover($('<div id="' + this._mainDivId + '" class="ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all"></div>')); + $.extend(this._defaults, this.regional[""]); + this.dpDiv = bindHover($("<div id='" + this._mainDivId + "' class='ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>")); } $.extend(Datepicker.prototype, { /* Class name added to elements to indicate already configured with a date picker. */ - markerClassName: 'hasDatepicker', + markerClassName: "hasDatepicker", //Keep track of the maximum number of rows displayed (see #7043) maxRows: 4, - /* Debug logging (if enabled). */ - log: function () { - if (this.debug) - console.log.apply('', arguments); - }, - // TODO rename to "widget" when switching to widget factory _widgetDatepicker: function() { return this.dpDiv; }, /* Override the default settings for all instances of the date picker. - @param settings object - the new settings to use as defaults (anonymous object) - @return the manager object */ + * @param settings object - the new settings to use as defaults (anonymous object) + * @return the manager object + */ setDefaults: function(settings) { extendRemove(this._defaults, settings || {}); return this; }, /* Attach the date picker to a jQuery selection. - @param target element - the target input field or division or span - @param settings object - the new settings to use for this date picker instance (anonymous) */ + * @param target element - the target input field or division or span + * @param settings object - the new settings to use for this date picker instance (anonymous) + */ _attachDatepicker: function(target, settings) { - // check for settings on the control itself - in namespace 'date:' - var inlineSettings = null; - for (var attrName in this._defaults) { - var attrValue = target.getAttribute('date:' + attrName); - if (attrValue) { - inlineSettings = inlineSettings || {}; - try { - inlineSettings[attrName] = eval(attrValue); - } catch (err) { - inlineSettings[attrName] = attrValue; - } - } - } - var nodeName = target.nodeName.toLowerCase(); - var inline = (nodeName == 'div' || nodeName == 'span'); + var nodeName, inline, inst; + nodeName = target.nodeName.toLowerCase(); + inline = (nodeName === "div" || nodeName === "span"); if (!target.id) { this.uuid += 1; - target.id = 'dp' + this.uuid; + target.id = "dp" + this.uuid; } - var inst = this._newInst($(target), inline); - inst.settings = $.extend({}, settings || {}, inlineSettings || {}); - if (nodeName == 'input') { + inst = this._newInst($(target), inline); + inst.settings = $.extend({}, settings || {}); + if (nodeName === "input") { this._connectDatepicker(target, inst); } else if (inline) { this._inlineDatepicker(target, inst); @@ -7382,13 +7728,13 @@ $.extend(Datepicker.prototype, { /* Create a new instance object. */ _newInst: function(target, inline) { - var id = target[0].id.replace(/([^A-Za-z0-9_-])/g, '\\\\$1'); // escape jQuery meta chars + var id = target[0].id.replace(/([^A-Za-z0-9_\-])/g, "\\\\$1"); // escape jQuery meta chars return {id: id, input: target, // associated target selectedDay: 0, selectedMonth: 0, selectedYear: 0, // current selection drawMonth: 0, drawYear: 0, // month being drawn inline: inline, // is datepicker inline or not dpDiv: (!inline ? this.dpDiv : // presentation div - bindHover($('<div class="' + this._inlineClass + ' ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all"></div>')))}; + bindHover($("<div class='" + this._inlineClass + " ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>")))}; }, /* Attach the date picker to an input field. */ @@ -7396,16 +7742,12 @@ $.extend(Datepicker.prototype, { var input = $(target); inst.append = $([]); inst.trigger = $([]); - if (input.hasClass(this.markerClassName)) + if (input.hasClass(this.markerClassName)) { return; + } this._attachments(input, inst); input.addClass(this.markerClassName).keydown(this._doKeyDown). - keypress(this._doKeyPress).keyup(this._doKeyUp). - bind("setData.datepicker", function(event, key, value) { - inst.settings[key] = value; - }).bind("getData.datepicker", function(event, key) { - return this._get(inst, key); - }); + keypress(this._doKeyPress).keyup(this._doKeyUp); this._autoSize(inst); $.data(target, PROP_NAME, inst); //If disabled option is true, disable the datepicker once it has been attached to the input (see ticket #5665) @@ -7416,38 +7758,47 @@ $.extend(Datepicker.prototype, { /* Make attachments based on settings. */ _attachments: function(input, inst) { - var appendText = this._get(inst, 'appendText'); - var isRTL = this._get(inst, 'isRTL'); - if (inst.append) + var showOn, buttonText, buttonImage, + appendText = this._get(inst, "appendText"), + isRTL = this._get(inst, "isRTL"); + + if (inst.append) { inst.append.remove(); + } if (appendText) { - inst.append = $('<span class="' + this._appendClass + '">' + appendText + '</span>'); - input[isRTL ? 'before' : 'after'](inst.append); + inst.append = $("<span class='" + this._appendClass + "'>" + appendText + "</span>"); + input[isRTL ? "before" : "after"](inst.append); } - input.unbind('focus', this._showDatepicker); - if (inst.trigger) + + input.unbind("focus", this._showDatepicker); + + if (inst.trigger) { inst.trigger.remove(); - var showOn = this._get(inst, 'showOn'); - if (showOn == 'focus' || showOn == 'both') // pop-up date picker when in the marked field + } + + showOn = this._get(inst, "showOn"); + if (showOn === "focus" || showOn === "both") { // pop-up date picker when in the marked field input.focus(this._showDatepicker); - if (showOn == 'button' || showOn == 'both') { // pop-up date picker when button clicked - var buttonText = this._get(inst, 'buttonText'); - var buttonImage = this._get(inst, 'buttonImage'); - inst.trigger = $(this._get(inst, 'buttonImageOnly') ? - $('<img/>').addClass(this._triggerClass). + } + if (showOn === "button" || showOn === "both") { // pop-up date picker when button clicked + buttonText = this._get(inst, "buttonText"); + buttonImage = this._get(inst, "buttonImage"); + inst.trigger = $(this._get(inst, "buttonImageOnly") ? + $("<img/>").addClass(this._triggerClass). attr({ src: buttonImage, alt: buttonText, title: buttonText }) : - $('<button type="button"></button>').addClass(this._triggerClass). - html(buttonImage == '' ? buttonText : $('<img/>').attr( + $("<button type='button'></button>").addClass(this._triggerClass). + html(!buttonImage ? buttonText : $("<img/>").attr( { src:buttonImage, alt:buttonText, title:buttonText }))); - input[isRTL ? 'before' : 'after'](inst.trigger); + input[isRTL ? "before" : "after"](inst.trigger); inst.trigger.click(function() { - if ($.datepicker._datepickerShowing && $.datepicker._lastInput == input[0]) + if ($.datepicker._datepickerShowing && $.datepicker._lastInput === input[0]) { $.datepicker._hideDatepicker(); - else if ($.datepicker._datepickerShowing && $.datepicker._lastInput != input[0]) { + } else if ($.datepicker._datepickerShowing && $.datepicker._lastInput !== input[0]) { $.datepicker._hideDatepicker(); $.datepicker._showDatepicker(input[0]); - } else + } else { $.datepicker._showDatepicker(input[0]); + } return false; }); } @@ -7455,14 +7806,16 @@ $.extend(Datepicker.prototype, { /* Apply the maximum length for the date format. */ _autoSize: function(inst) { - if (this._get(inst, 'autoSize') && !inst.inline) { - var date = new Date(2009, 12 - 1, 20); // Ensure double digits - var dateFormat = this._get(inst, 'dateFormat'); + if (this._get(inst, "autoSize") && !inst.inline) { + var findMax, max, maxI, i, + date = new Date(2009, 12 - 1, 20), // Ensure double digits + dateFormat = this._get(inst, "dateFormat"); + if (dateFormat.match(/[DM]/)) { - var findMax = function(names) { - var max = 0; - var maxI = 0; - for (var i = 0; i < names.length; i++) { + findMax = function(names) { + max = 0; + maxI = 0; + for (i = 0; i < names.length; i++) { if (names[i].length > max) { max = names[i].length; maxI = i; @@ -7471,25 +7824,21 @@ $.extend(Datepicker.prototype, { return maxI; }; date.setMonth(findMax(this._get(inst, (dateFormat.match(/MM/) ? - 'monthNames' : 'monthNamesShort')))); + "monthNames" : "monthNamesShort")))); date.setDate(findMax(this._get(inst, (dateFormat.match(/DD/) ? - 'dayNames' : 'dayNamesShort'))) + 20 - date.getDay()); + "dayNames" : "dayNamesShort"))) + 20 - date.getDay()); } - inst.input.attr('size', this._formatDate(inst, date).length); + inst.input.attr("size", this._formatDate(inst, date).length); } }, /* Attach an inline date picker to a div. */ _inlineDatepicker: function(target, inst) { var divSpan = $(target); - if (divSpan.hasClass(this.markerClassName)) + if (divSpan.hasClass(this.markerClassName)) { return; - divSpan.addClass(this.markerClassName).append(inst.dpDiv). - bind("setData.datepicker", function(event, key, value){ - inst.settings[key] = value; - }).bind("getData.datepicker", function(event, key){ - return this._get(inst, key); - }); + } + divSpan.addClass(this.markerClassName).append(inst.dpDiv); $.data(target, PROP_NAME, inst); this._setDate(inst, this._getDefaultDate(inst), true); this._updateDatepicker(inst); @@ -7504,186 +7853,219 @@ $.extend(Datepicker.prototype, { }, /* Pop-up the date picker in a "dialog" box. - @param input element - ignored - @param date string or Date - the initial date to display - @param onSelect function - the function to call when a date is selected - @param settings object - update the dialog date picker instance's settings (anonymous object) - @param pos int[2] - coordinates for the dialog's position within the screen or - event - with x/y coordinates or - leave empty for default (screen centre) - @return the manager object */ + * @param input element - ignored + * @param date string or Date - the initial date to display + * @param onSelect function - the function to call when a date is selected + * @param settings object - update the dialog date picker instance's settings (anonymous object) + * @param pos int[2] - coordinates for the dialog's position within the screen or + * event - with x/y coordinates or + * leave empty for default (screen centre) + * @return the manager object + */ _dialogDatepicker: function(input, date, onSelect, settings, pos) { - var inst = this._dialogInst; // internal instance + var id, browserWidth, browserHeight, scrollX, scrollY, + inst = this._dialogInst; // internal instance + if (!inst) { this.uuid += 1; - var id = 'dp' + this.uuid; - this._dialogInput = $('<input type="text" id="' + id + - '" style="position: absolute; top: -100px; width: 0px;"/>'); + id = "dp" + this.uuid; + this._dialogInput = $("<input type='text' id='" + id + + "' style='position: absolute; top: -100px; width: 0px;'/>"); this._dialogInput.keydown(this._doKeyDown); - $('body').append(this._dialogInput); + $("body").append(this._dialogInput); inst = this._dialogInst = this._newInst(this._dialogInput, false); inst.settings = {}; $.data(this._dialogInput[0], PROP_NAME, inst); } extendRemove(inst.settings, settings || {}); - date = (date && date.constructor == Date ? this._formatDate(inst, date) : date); + date = (date && date.constructor === Date ? this._formatDate(inst, date) : date); this._dialogInput.val(date); this._pos = (pos ? (pos.length ? pos : [pos.pageX, pos.pageY]) : null); if (!this._pos) { - var browserWidth = document.documentElement.clientWidth; - var browserHeight = document.documentElement.clientHeight; - var scrollX = document.documentElement.scrollLeft || document.body.scrollLeft; - var scrollY = document.documentElement.scrollTop || document.body.scrollTop; + browserWidth = document.documentElement.clientWidth; + browserHeight = document.documentElement.clientHeight; + scrollX = document.documentElement.scrollLeft || document.body.scrollLeft; + scrollY = document.documentElement.scrollTop || document.body.scrollTop; this._pos = // should use actual width/height below [(browserWidth / 2) - 100 + scrollX, (browserHeight / 2) - 150 + scrollY]; } // move input on screen for focus, but hidden behind dialog - this._dialogInput.css('left', (this._pos[0] + 20) + 'px').css('top', this._pos[1] + 'px'); + this._dialogInput.css("left", (this._pos[0] + 20) + "px").css("top", this._pos[1] + "px"); inst.settings.onSelect = onSelect; this._inDialog = true; this.dpDiv.addClass(this._dialogClass); this._showDatepicker(this._dialogInput[0]); - if ($.blockUI) + if ($.blockUI) { $.blockUI(this.dpDiv); + } $.data(this._dialogInput[0], PROP_NAME, inst); return this; }, /* Detach a datepicker from its control. - @param target element - the target input field or division or span */ + * @param target element - the target input field or division or span + */ _destroyDatepicker: function(target) { - var $target = $(target); - var inst = $.data(target, PROP_NAME); + var nodeName, + $target = $(target), + inst = $.data(target, PROP_NAME); + if (!$target.hasClass(this.markerClassName)) { return; } - var nodeName = target.nodeName.toLowerCase(); + + nodeName = target.nodeName.toLowerCase(); $.removeData(target, PROP_NAME); - if (nodeName == 'input') { + if (nodeName === "input") { inst.append.remove(); inst.trigger.remove(); $target.removeClass(this.markerClassName). - unbind('focus', this._showDatepicker). - unbind('keydown', this._doKeyDown). - unbind('keypress', this._doKeyPress). - unbind('keyup', this._doKeyUp); - } else if (nodeName == 'div' || nodeName == 'span') + unbind("focus", this._showDatepicker). + unbind("keydown", this._doKeyDown). + unbind("keypress", this._doKeyPress). + unbind("keyup", this._doKeyUp); + } else if (nodeName === "div" || nodeName === "span") { $target.removeClass(this.markerClassName).empty(); + } }, /* Enable the date picker to a jQuery selection. - @param target element - the target input field or division or span */ + * @param target element - the target input field or division or span + */ _enableDatepicker: function(target) { - var $target = $(target); - var inst = $.data(target, PROP_NAME); + var nodeName, inline, + $target = $(target), + inst = $.data(target, PROP_NAME); + if (!$target.hasClass(this.markerClassName)) { return; } - var nodeName = target.nodeName.toLowerCase(); - if (nodeName == 'input') { + + nodeName = target.nodeName.toLowerCase(); + if (nodeName === "input") { target.disabled = false; - inst.trigger.filter('button'). + inst.trigger.filter("button"). each(function() { this.disabled = false; }).end(). - filter('img').css({opacity: '1.0', cursor: ''}); - } - else if (nodeName == 'div' || nodeName == 'span') { - var inline = $target.children('.' + this._inlineClass); - inline.children().removeClass('ui-state-disabled'); + filter("img").css({opacity: "1.0", cursor: ""}); + } else if (nodeName === "div" || nodeName === "span") { + inline = $target.children("." + this._inlineClass); + inline.children().removeClass("ui-state-disabled"); inline.find("select.ui-datepicker-month, select.ui-datepicker-year"). prop("disabled", false); } this._disabledInputs = $.map(this._disabledInputs, - function(value) { return (value == target ? null : value); }); // delete entry + function(value) { return (value === target ? null : value); }); // delete entry }, /* Disable the date picker to a jQuery selection. - @param target element - the target input field or division or span */ + * @param target element - the target input field or division or span + */ _disableDatepicker: function(target) { - var $target = $(target); - var inst = $.data(target, PROP_NAME); + var nodeName, inline, + $target = $(target), + inst = $.data(target, PROP_NAME); + if (!$target.hasClass(this.markerClassName)) { return; } - var nodeName = target.nodeName.toLowerCase(); - if (nodeName == 'input') { + + nodeName = target.nodeName.toLowerCase(); + if (nodeName === "input") { target.disabled = true; - inst.trigger.filter('button'). + inst.trigger.filter("button"). each(function() { this.disabled = true; }).end(). - filter('img').css({opacity: '0.5', cursor: 'default'}); - } - else if (nodeName == 'div' || nodeName == 'span') { - var inline = $target.children('.' + this._inlineClass); - inline.children().addClass('ui-state-disabled'); + filter("img").css({opacity: "0.5", cursor: "default"}); + } else if (nodeName === "div" || nodeName === "span") { + inline = $target.children("." + this._inlineClass); + inline.children().addClass("ui-state-disabled"); inline.find("select.ui-datepicker-month, select.ui-datepicker-year"). prop("disabled", true); } this._disabledInputs = $.map(this._disabledInputs, - function(value) { return (value == target ? null : value); }); // delete entry + function(value) { return (value === target ? null : value); }); // delete entry this._disabledInputs[this._disabledInputs.length] = target; }, /* Is the first field in a jQuery collection disabled as a datepicker? - @param target element - the target input field or division or span - @return boolean - true if disabled, false if enabled */ + * @param target element - the target input field or division or span + * @return boolean - true if disabled, false if enabled + */ _isDisabledDatepicker: function(target) { if (!target) { return false; } for (var i = 0; i < this._disabledInputs.length; i++) { - if (this._disabledInputs[i] == target) + if (this._disabledInputs[i] === target) { return true; + } } return false; }, /* Retrieve the instance data for the target control. - @param target element - the target input field or division or span - @return object - the associated instance data - @throws error if a jQuery problem getting data */ + * @param target element - the target input field or division or span + * @return object - the associated instance data + * @throws error if a jQuery problem getting data + */ _getInst: function(target) { try { return $.data(target, PROP_NAME); } catch (err) { - throw 'Missing instance data for this datepicker'; + throw "Missing instance data for this datepicker"; } }, /* Update or retrieve the settings for a date picker attached to an input field or division. - @param target element - the target input field or division or span - @param name object - the new settings to update or - string - the name of the setting to change or retrieve, - when retrieving also 'all' for all instance settings or - 'defaults' for all global defaults - @param value any - the new value for the setting - (omit if above is an object or to retrieve a value) */ + * @param target element - the target input field or division or span + * @param name object - the new settings to update or + * string - the name of the setting to change or retrieve, + * when retrieving also "all" for all instance settings or + * "defaults" for all global defaults + * @param value any - the new value for the setting + * (omit if above is an object or to retrieve a value) + */ _optionDatepicker: function(target, name, value) { - var inst = this._getInst(target); - if (arguments.length == 2 && typeof name == 'string') { - return (name == 'defaults' ? $.extend({}, $.datepicker._defaults) : - (inst ? (name == 'all' ? $.extend({}, inst.settings) : + var settings, date, minDate, maxDate, + inst = this._getInst(target); + + if (arguments.length === 2 && typeof name === "string") { + return (name === "defaults" ? $.extend({}, $.datepicker._defaults) : + (inst ? (name === "all" ? $.extend({}, inst.settings) : this._get(inst, name)) : null)); } - var settings = name || {}; - if (typeof name == 'string') { + + settings = name || {}; + if (typeof name === "string") { settings = {}; settings[name] = value; } + if (inst) { - if (this._curInst == inst) { + if (this._curInst === inst) { this._hideDatepicker(); } - var date = this._getDateDatepicker(target, true); - var minDate = this._getMinMaxDate(inst, 'min'); - var maxDate = this._getMinMaxDate(inst, 'max'); + + date = this._getDateDatepicker(target, true); + minDate = this._getMinMaxDate(inst, "min"); + maxDate = this._getMinMaxDate(inst, "max"); extendRemove(inst.settings, settings); // reformat the old minDate/maxDate values if dateFormat changes and a new minDate/maxDate isn't provided - if (minDate !== null && settings['dateFormat'] !== undefined && settings['minDate'] === undefined) + if (minDate !== null && settings.dateFormat !== undefined && settings.minDate === undefined) { inst.settings.minDate = this._formatDate(inst, minDate); - if (maxDate !== null && settings['dateFormat'] !== undefined && settings['maxDate'] === undefined) + } + if (maxDate !== null && settings.dateFormat !== undefined && settings.maxDate === undefined) { inst.settings.maxDate = this._formatDate(inst, maxDate); + } + if ( "disabled" in settings ) { + if ( settings.disabled ) { + this._disableDatepicker(target); + } else { + this._enableDatepicker(target); + } + } this._attachments($(target), inst); this._autoSize(inst); this._setDate(inst, date); @@ -7698,7 +8080,8 @@ $.extend(Datepicker.prototype, { }, /* Redraw the date picker attached to an input field or division. - @param target element - the target input field or division or span */ + * @param target element - the target input field or division or span + */ _refreshDatepicker: function(target) { var inst = this._getInst(target); if (inst) { @@ -7707,8 +8090,9 @@ $.extend(Datepicker.prototype, { }, /* Set the dates for a jQuery selection. - @param target element - the target input field or division or span - @param date Date - the new date */ + * @param target element - the target input field or division or span + * @param date Date - the new date + */ _setDateDatepicker: function(target, date) { var inst = this._getInst(target); if (inst) { @@ -7719,87 +8103,110 @@ $.extend(Datepicker.prototype, { }, /* Get the date(s) for the first entry in a jQuery selection. - @param target element - the target input field or division or span - @param noDefault boolean - true if no default date is to be used - @return Date - the current date */ + * @param target element - the target input field or division or span + * @param noDefault boolean - true if no default date is to be used + * @return Date - the current date + */ _getDateDatepicker: function(target, noDefault) { var inst = this._getInst(target); - if (inst && !inst.inline) + if (inst && !inst.inline) { this._setDateFromField(inst, noDefault); + } return (inst ? this._getDate(inst) : null); }, /* Handle keystrokes. */ _doKeyDown: function(event) { - var inst = $.datepicker._getInst(event.target); - var handled = true; - var isRTL = inst.dpDiv.is('.ui-datepicker-rtl'); + var onSelect, dateStr, sel, + inst = $.datepicker._getInst(event.target), + handled = true, + isRTL = inst.dpDiv.is(".ui-datepicker-rtl"); + inst._keyEvent = true; - if ($.datepicker._datepickerShowing) + if ($.datepicker._datepickerShowing) { switch (event.keyCode) { case 9: $.datepicker._hideDatepicker(); handled = false; break; // hide on tab out - case 13: var sel = $('td.' + $.datepicker._dayOverClass + ':not(.' + - $.datepicker._currentClass + ')', inst.dpDiv); - if (sel[0]) + case 13: sel = $("td." + $.datepicker._dayOverClass + ":not(." + + $.datepicker._currentClass + ")", inst.dpDiv); + if (sel[0]) { $.datepicker._selectDay(event.target, inst.selectedMonth, inst.selectedYear, sel[0]); - var onSelect = $.datepicker._get(inst, 'onSelect'); - if (onSelect) { - var dateStr = $.datepicker._formatDate(inst); + } - // trigger custom callback - onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]); - } - else + onSelect = $.datepicker._get(inst, "onSelect"); + if (onSelect) { + dateStr = $.datepicker._formatDate(inst); + + // trigger custom callback + onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]); + } else { $.datepicker._hideDatepicker(); + } + return false; // don't submit the form - break; // select the value on enter case 27: $.datepicker._hideDatepicker(); break; // hide on escape case 33: $.datepicker._adjustDate(event.target, (event.ctrlKey ? - -$.datepicker._get(inst, 'stepBigMonths') : - -$.datepicker._get(inst, 'stepMonths')), 'M'); + -$.datepicker._get(inst, "stepBigMonths") : + -$.datepicker._get(inst, "stepMonths")), "M"); break; // previous month/year on page up/+ ctrl case 34: $.datepicker._adjustDate(event.target, (event.ctrlKey ? - +$.datepicker._get(inst, 'stepBigMonths') : - +$.datepicker._get(inst, 'stepMonths')), 'M'); + +$.datepicker._get(inst, "stepBigMonths") : + +$.datepicker._get(inst, "stepMonths")), "M"); break; // next month/year on page down/+ ctrl - case 35: if (event.ctrlKey || event.metaKey) $.datepicker._clearDate(event.target); + case 35: if (event.ctrlKey || event.metaKey) { + $.datepicker._clearDate(event.target); + } handled = event.ctrlKey || event.metaKey; break; // clear on ctrl or command +end - case 36: if (event.ctrlKey || event.metaKey) $.datepicker._gotoToday(event.target); + case 36: if (event.ctrlKey || event.metaKey) { + $.datepicker._gotoToday(event.target); + } handled = event.ctrlKey || event.metaKey; break; // current on ctrl or command +home - case 37: if (event.ctrlKey || event.metaKey) $.datepicker._adjustDate(event.target, (isRTL ? +1 : -1), 'D'); + case 37: if (event.ctrlKey || event.metaKey) { + $.datepicker._adjustDate(event.target, (isRTL ? +1 : -1), "D"); + } handled = event.ctrlKey || event.metaKey; // -1 day on ctrl or command +left - if (event.originalEvent.altKey) $.datepicker._adjustDate(event.target, (event.ctrlKey ? - -$.datepicker._get(inst, 'stepBigMonths') : - -$.datepicker._get(inst, 'stepMonths')), 'M'); + if (event.originalEvent.altKey) { + $.datepicker._adjustDate(event.target, (event.ctrlKey ? + -$.datepicker._get(inst, "stepBigMonths") : + -$.datepicker._get(inst, "stepMonths")), "M"); + } // next month/year on alt +left on Mac break; - case 38: if (event.ctrlKey || event.metaKey) $.datepicker._adjustDate(event.target, -7, 'D'); + case 38: if (event.ctrlKey || event.metaKey) { + $.datepicker._adjustDate(event.target, -7, "D"); + } handled = event.ctrlKey || event.metaKey; break; // -1 week on ctrl or command +up - case 39: if (event.ctrlKey || event.metaKey) $.datepicker._adjustDate(event.target, (isRTL ? -1 : +1), 'D'); + case 39: if (event.ctrlKey || event.metaKey) { + $.datepicker._adjustDate(event.target, (isRTL ? -1 : +1), "D"); + } handled = event.ctrlKey || event.metaKey; // +1 day on ctrl or command +right - if (event.originalEvent.altKey) $.datepicker._adjustDate(event.target, (event.ctrlKey ? - +$.datepicker._get(inst, 'stepBigMonths') : - +$.datepicker._get(inst, 'stepMonths')), 'M'); + if (event.originalEvent.altKey) { + $.datepicker._adjustDate(event.target, (event.ctrlKey ? + +$.datepicker._get(inst, "stepBigMonths") : + +$.datepicker._get(inst, "stepMonths")), "M"); + } // next month/year on alt +right break; - case 40: if (event.ctrlKey || event.metaKey) $.datepicker._adjustDate(event.target, +7, 'D'); + case 40: if (event.ctrlKey || event.metaKey) { + $.datepicker._adjustDate(event.target, +7, "D"); + } handled = event.ctrlKey || event.metaKey; break; // +1 week on ctrl or command +down default: handled = false; } - else if (event.keyCode == 36 && event.ctrlKey) // display the date picker on ctrl+home + } else if (event.keyCode === 36 && event.ctrlKey) { // display the date picker on ctrl+home $.datepicker._showDatepicker(this); - else { + } else { handled = false; } + if (handled) { event.preventDefault(); event.stopPropagation(); @@ -7808,22 +8215,27 @@ $.extend(Datepicker.prototype, { /* Filter entered characters - based on date format. */ _doKeyPress: function(event) { - var inst = $.datepicker._getInst(event.target); - if ($.datepicker._get(inst, 'constrainInput')) { - var chars = $.datepicker._possibleChars($.datepicker._get(inst, 'dateFormat')); - var chr = String.fromCharCode(event.charCode == undefined ? event.keyCode : event.charCode); - return event.ctrlKey || event.metaKey || (chr < ' ' || !chars || chars.indexOf(chr) > -1); + var chars, chr, + inst = $.datepicker._getInst(event.target); + + if ($.datepicker._get(inst, "constrainInput")) { + chars = $.datepicker._possibleChars($.datepicker._get(inst, "dateFormat")); + chr = String.fromCharCode(event.charCode == null ? event.keyCode : event.charCode); + return event.ctrlKey || event.metaKey || (chr < " " || !chars || chars.indexOf(chr) > -1); } }, /* Synchronise manual entry and field/alternate field. */ _doKeyUp: function(event) { - var inst = $.datepicker._getInst(event.target); - if (inst.input.val() != inst.lastVal) { + var date, + inst = $.datepicker._getInst(event.target); + + if (inst.input.val() !== inst.lastVal) { try { - var date = $.datepicker.parseDate($.datepicker._get(inst, 'dateFormat'), + date = $.datepicker.parseDate($.datepicker._get(inst, "dateFormat"), (inst.input ? inst.input.val() : null), $.datepicker._getFormatConfig(inst)); + if (date) { // only if valid $.datepicker._setDateFromField(inst); $.datepicker._updateAlternate(inst); @@ -7831,86 +8243,91 @@ $.extend(Datepicker.prototype, { } } catch (err) { - $.datepicker.log(err); } } return true; }, /* Pop-up the date picker for a given input field. - If false returned from beforeShow event handler do not show. - @param input element - the input field attached to the date picker or - event - if triggered by focus */ + * If false returned from beforeShow event handler do not show. + * @param input element - the input field attached to the date picker or + * event - if triggered by focus + */ _showDatepicker: function(input) { input = input.target || input; - if (input.nodeName.toLowerCase() != 'input') // find from button/image trigger - input = $('input', input.parentNode)[0]; - if ($.datepicker._isDisabledDatepicker(input) || $.datepicker._lastInput == input) // already here + if (input.nodeName.toLowerCase() !== "input") { // find from button/image trigger + input = $("input", input.parentNode)[0]; + } + + if ($.datepicker._isDisabledDatepicker(input) || $.datepicker._lastInput === input) { // already here return; - var inst = $.datepicker._getInst(input); - if ($.datepicker._curInst && $.datepicker._curInst != inst) { + } + + var inst, beforeShow, beforeShowSettings, isFixed, + offset, showAnim, duration; + + inst = $.datepicker._getInst(input); + if ($.datepicker._curInst && $.datepicker._curInst !== inst) { $.datepicker._curInst.dpDiv.stop(true, true); if ( inst && $.datepicker._datepickerShowing ) { $.datepicker._hideDatepicker( $.datepicker._curInst.input[0] ); } } - var beforeShow = $.datepicker._get(inst, 'beforeShow'); - var beforeShowSettings = beforeShow ? beforeShow.apply(input, [input, inst]) : {}; + + beforeShow = $.datepicker._get(inst, "beforeShow"); + beforeShowSettings = beforeShow ? beforeShow.apply(input, [input, inst]) : {}; if(beforeShowSettings === false){ - //false return; } extendRemove(inst.settings, beforeShowSettings); + inst.lastVal = null; $.datepicker._lastInput = input; $.datepicker._setDateFromField(inst); - if ($.datepicker._inDialog) // hide cursor - input.value = ''; + + if ($.datepicker._inDialog) { // hide cursor + input.value = ""; + } if (!$.datepicker._pos) { // position below input $.datepicker._pos = $.datepicker._findPos(input); $.datepicker._pos[1] += input.offsetHeight; // add the height } - var isFixed = false; + + isFixed = false; $(input).parents().each(function() { - isFixed |= $(this).css('position') == 'fixed'; + isFixed |= $(this).css("position") === "fixed"; return !isFixed; }); - var offset = {left: $.datepicker._pos[0], top: $.datepicker._pos[1]}; + + offset = {left: $.datepicker._pos[0], top: $.datepicker._pos[1]}; $.datepicker._pos = null; //to avoid flashes on Firefox inst.dpDiv.empty(); // determine sizing offscreen - inst.dpDiv.css({position: 'absolute', display: 'block', top: '-1000px'}); + inst.dpDiv.css({position: "absolute", display: "block", top: "-1000px"}); $.datepicker._updateDatepicker(inst); // fix width for dynamic number of date pickers // and adjust position before showing offset = $.datepicker._checkOffset(inst, offset, isFixed); inst.dpDiv.css({position: ($.datepicker._inDialog && $.blockUI ? - 'static' : (isFixed ? 'fixed' : 'absolute')), display: 'none', - left: offset.left + 'px', top: offset.top + 'px'}); + "static" : (isFixed ? "fixed" : "absolute")), display: "none", + left: offset.left + "px", top: offset.top + "px"}); + if (!inst.inline) { - var showAnim = $.datepicker._get(inst, 'showAnim'); - var duration = $.datepicker._get(inst, 'duration'); - var postProcess = function() { - var cover = inst.dpDiv.find('iframe.ui-datepicker-cover'); // IE6- only - if( !! cover.length ){ - var borders = $.datepicker._getBorders(inst.dpDiv); - cover.css({left: -borders[0], top: -borders[1], - width: inst.dpDiv.outerWidth(), height: inst.dpDiv.outerHeight()}); - } - }; + showAnim = $.datepicker._get(inst, "showAnim"); + duration = $.datepicker._get(inst, "duration"); inst.dpDiv.zIndex($(input).zIndex()+1); $.datepicker._datepickerShowing = true; - // DEPRECATED: after BC for 1.8.x $.effects[ showAnim ] is not needed - if ( $.effects && ( $.effects.effect[ showAnim ] || $.effects[ showAnim ] ) ) - inst.dpDiv.show(showAnim, $.datepicker._get(inst, 'showOptions'), duration, postProcess); - else - inst.dpDiv[showAnim || 'show']((showAnim ? duration : null), postProcess); - if (!showAnim || !duration) - postProcess(); - if (inst.input.is(':visible') && !inst.input.is(':disabled')) + if ( $.effects && $.effects.effect[ showAnim ] ) { + inst.dpDiv.show(showAnim, $.datepicker._get(inst, "showOptions"), duration); + } else { + inst.dpDiv[showAnim || "show"](showAnim ? duration : null); + } + + if (inst.input.is(":visible") && !inst.input.is(":disabled")) { inst.input.focus(); + } $.datepicker._curInst = inst; } }, @@ -7918,37 +8335,39 @@ $.extend(Datepicker.prototype, { /* Generate the date picker content. */ _updateDatepicker: function(inst) { this.maxRows = 4; //Reset the max number of rows being displayed (see #7043) - var borders = $.datepicker._getBorders(inst.dpDiv); instActive = inst; // for delegate hover events inst.dpDiv.empty().append(this._generateHTML(inst)); this._attachHandlers(inst); - var cover = inst.dpDiv.find('iframe.ui-datepicker-cover'); // IE6- only - if( !!cover.length ){ //avoid call to outerXXXX() when not in IE6 - cover.css({left: -borders[0], top: -borders[1], width: inst.dpDiv.outerWidth(), height: inst.dpDiv.outerHeight()}) - } - inst.dpDiv.find('.' + this._dayOverClass + ' a').mouseover(); - var numMonths = this._getNumberOfMonths(inst); - var cols = numMonths[1]; - var width = 17; - inst.dpDiv.removeClass('ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4').width(''); - if (cols > 1) - inst.dpDiv.addClass('ui-datepicker-multi-' + cols).css('width', (width * cols) + 'em'); - inst.dpDiv[(numMonths[0] != 1 || numMonths[1] != 1 ? 'add' : 'remove') + - 'Class']('ui-datepicker-multi'); - inst.dpDiv[(this._get(inst, 'isRTL') ? 'add' : 'remove') + - 'Class']('ui-datepicker-rtl'); - if (inst == $.datepicker._curInst && $.datepicker._datepickerShowing && inst.input && - // #6694 - don't focus the input if it's already focused - // this breaks the change event in IE - inst.input.is(':visible') && !inst.input.is(':disabled') && inst.input[0] != document.activeElement) + inst.dpDiv.find("." + this._dayOverClass + " a").mouseover(); + + var origyearshtml, + numMonths = this._getNumberOfMonths(inst), + cols = numMonths[1], + width = 17; + + inst.dpDiv.removeClass("ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4").width(""); + if (cols > 1) { + inst.dpDiv.addClass("ui-datepicker-multi-" + cols).css("width", (width * cols) + "em"); + } + inst.dpDiv[(numMonths[0] !== 1 || numMonths[1] !== 1 ? "add" : "remove") + + "Class"]("ui-datepicker-multi"); + inst.dpDiv[(this._get(inst, "isRTL") ? "add" : "remove") + + "Class"]("ui-datepicker-rtl"); + + // #6694 - don't focus the input if it's already focused + // this breaks the change event in IE + if (inst === $.datepicker._curInst && $.datepicker._datepickerShowing && inst.input && + inst.input.is(":visible") && !inst.input.is(":disabled") && inst.input[0] !== document.activeElement) { inst.input.focus(); + } + // deffered render of the years select (to avoid flashes on Firefox) if( inst.yearshtml ){ - var origyearshtml = inst.yearshtml; + origyearshtml = inst.yearshtml; setTimeout(function(){ //assure that inst.yearshtml didn't change. if( origyearshtml === inst.yearshtml && inst.yearshtml ){ - inst.dpDiv.find('select.ui-datepicker-year:first').replaceWith(inst.yearshtml); + inst.dpDiv.find("select.ui-datepicker-year:first").replaceWith(inst.yearshtml); } origyearshtml = inst.yearshtml = null; }, 0); @@ -7956,28 +8375,29 @@ $.extend(Datepicker.prototype, { }, /* Retrieve the size of left and top borders for an element. - @param elem (jQuery object) the element of interest - @return (number[2]) the left and top borders */ + * @param elem (jQuery object) the element of interest + * @return (number[2]) the left and top borders + */ _getBorders: function(elem) { var convert = function(value) { return {thin: 1, medium: 2, thick: 3}[value] || value; }; - return [parseFloat(convert(elem.css('border-left-width'))), - parseFloat(convert(elem.css('border-top-width')))]; + return [parseFloat(convert(elem.css("border-left-width"))), + parseFloat(convert(elem.css("border-top-width")))]; }, /* Check positioning to remain on screen. */ _checkOffset: function(inst, offset, isFixed) { - var dpWidth = inst.dpDiv.outerWidth(); - var dpHeight = inst.dpDiv.outerHeight(); - var inputWidth = inst.input ? inst.input.outerWidth() : 0; - var inputHeight = inst.input ? inst.input.outerHeight() : 0; - var viewWidth = document.documentElement.clientWidth + (isFixed ? 0 : $(document).scrollLeft()); - var viewHeight = document.documentElement.clientHeight + (isFixed ? 0 : $(document).scrollTop()); + var dpWidth = inst.dpDiv.outerWidth(), + dpHeight = inst.dpDiv.outerHeight(), + inputWidth = inst.input ? inst.input.outerWidth() : 0, + inputHeight = inst.input ? inst.input.outerHeight() : 0, + viewWidth = document.documentElement.clientWidth + (isFixed ? 0 : $(document).scrollLeft()), + viewHeight = document.documentElement.clientHeight + (isFixed ? 0 : $(document).scrollTop()); - offset.left -= (this._get(inst, 'isRTL') ? (dpWidth - inputWidth) : 0); - offset.left -= (isFixed && offset.left == inst.input.offset().left) ? $(document).scrollLeft() : 0; - offset.top -= (isFixed && offset.top == (inst.input.offset().top + inputHeight)) ? $(document).scrollTop() : 0; + offset.left -= (this._get(inst, "isRTL") ? (dpWidth - inputWidth) : 0); + offset.left -= (isFixed && offset.left === inst.input.offset().left) ? $(document).scrollLeft() : 0; + offset.top -= (isFixed && offset.top === (inst.input.offset().top + inputHeight)) ? $(document).scrollTop() : 0; // now check if datepicker is showing outside window viewport - move to a better place if so. offset.left -= Math.min(offset.left, (offset.left + dpWidth > viewWidth && viewWidth > dpWidth) ? @@ -7990,47 +8410,60 @@ $.extend(Datepicker.prototype, { /* Find an object's position on the screen. */ _findPos: function(obj) { - var inst = this._getInst(obj); - var isRTL = this._get(inst, 'isRTL'); - while (obj && (obj.type == 'hidden' || obj.nodeType != 1 || $.expr.filters.hidden(obj))) { - obj = obj[isRTL ? 'previousSibling' : 'nextSibling']; + var position, + inst = this._getInst(obj), + isRTL = this._get(inst, "isRTL"); + + while (obj && (obj.type === "hidden" || obj.nodeType !== 1 || $.expr.filters.hidden(obj))) { + obj = obj[isRTL ? "previousSibling" : "nextSibling"]; } - var position = $(obj).offset(); + + position = $(obj).offset(); return [position.left, position.top]; }, /* Hide the date picker from view. - @param input element - the input field attached to the date picker */ + * @param input element - the input field attached to the date picker + */ _hideDatepicker: function(input) { - var inst = this._curInst; - if (!inst || (input && inst != $.data(input, PROP_NAME))) + var showAnim, duration, postProcess, onClose, + inst = this._curInst; + + if (!inst || (input && inst !== $.data(input, PROP_NAME))) { return; + } + if (this._datepickerShowing) { - var showAnim = this._get(inst, 'showAnim'); - var duration = this._get(inst, 'duration'); - var postProcess = function() { + showAnim = this._get(inst, "showAnim"); + duration = this._get(inst, "duration"); + postProcess = function() { $.datepicker._tidyDialog(inst); }; // DEPRECATED: after BC for 1.8.x $.effects[ showAnim ] is not needed - if ( $.effects && ( $.effects.effect[ showAnim ] || $.effects[ showAnim ] ) ) - inst.dpDiv.hide(showAnim, $.datepicker._get(inst, 'showOptions'), duration, postProcess); - else - inst.dpDiv[(showAnim == 'slideDown' ? 'slideUp' : - (showAnim == 'fadeIn' ? 'fadeOut' : 'hide'))]((showAnim ? duration : null), postProcess); - if (!showAnim) + if ( $.effects && ( $.effects.effect[ showAnim ] || $.effects[ showAnim ] ) ) { + inst.dpDiv.hide(showAnim, $.datepicker._get(inst, "showOptions"), duration, postProcess); + } else { + inst.dpDiv[(showAnim === "slideDown" ? "slideUp" : + (showAnim === "fadeIn" ? "fadeOut" : "hide"))]((showAnim ? duration : null), postProcess); + } + + if (!showAnim) { postProcess(); + } this._datepickerShowing = false; - var onClose = this._get(inst, 'onClose'); - if (onClose) - onClose.apply((inst.input ? inst.input[0] : null), - [(inst.input ? inst.input.val() : ''), inst]); + + onClose = this._get(inst, "onClose"); + if (onClose) { + onClose.apply((inst.input ? inst.input[0] : null), [(inst.input ? inst.input.val() : ""), inst]); + } + this._lastInput = null; if (this._inDialog) { - this._dialogInput.css({ position: 'absolute', left: '0', top: '-100px' }); + this._dialogInput.css({ position: "absolute", left: "0", top: "-100px" }); if ($.blockUI) { $.unblockUI(); - $('body').append(this.dpDiv); + $("body").append(this.dpDiv); } } this._inDialog = false; @@ -8039,50 +8472,54 @@ $.extend(Datepicker.prototype, { /* Tidy up after a dialog display. */ _tidyDialog: function(inst) { - inst.dpDiv.removeClass(this._dialogClass).unbind('.ui-datepicker-calendar'); + inst.dpDiv.removeClass(this._dialogClass).unbind(".ui-datepicker-calendar"); }, /* Close date picker if clicked elsewhere. */ _checkExternalClick: function(event) { - if (!$.datepicker._curInst) + if (!$.datepicker._curInst) { return; + } var $target = $(event.target), inst = $.datepicker._getInst($target[0]); - if ( ( ( $target[0].id != $.datepicker._mainDivId && - $target.parents('#' + $.datepicker._mainDivId).length == 0 && + if ( ( ( $target[0].id !== $.datepicker._mainDivId && + $target.parents("#" + $.datepicker._mainDivId).length === 0 && !$target.hasClass($.datepicker.markerClassName) && !$target.closest("." + $.datepicker._triggerClass).length && $.datepicker._datepickerShowing && !($.datepicker._inDialog && $.blockUI) ) ) || - ( $target.hasClass($.datepicker.markerClassName) && $.datepicker._curInst != inst ) ) - $.datepicker._hideDatepicker(); + ( $target.hasClass($.datepicker.markerClassName) && $.datepicker._curInst !== inst ) ) { + $.datepicker._hideDatepicker(); + } }, /* Adjust one of the date sub-fields. */ _adjustDate: function(id, offset, period) { - var target = $(id); - var inst = this._getInst(target[0]); + var target = $(id), + inst = this._getInst(target[0]); + if (this._isDisabledDatepicker(target[0])) { return; } this._adjustInstDate(inst, offset + - (period == 'M' ? this._get(inst, 'showCurrentAtPos') : 0), // undo positioning + (period === "M" ? this._get(inst, "showCurrentAtPos") : 0), // undo positioning period); this._updateDatepicker(inst); }, /* Action for current link. */ _gotoToday: function(id) { - var target = $(id); - var inst = this._getInst(target[0]); - if (this._get(inst, 'gotoCurrent') && inst.currentDay) { + var date, + target = $(id), + inst = this._getInst(target[0]); + + if (this._get(inst, "gotoCurrent") && inst.currentDay) { inst.selectedDay = inst.currentDay; inst.drawMonth = inst.selectedMonth = inst.currentMonth; inst.drawYear = inst.selectedYear = inst.currentYear; - } - else { - var date = new Date(); + } else { + date = new Date(); inst.selectedDay = date.getDate(); inst.drawMonth = inst.selectedMonth = date.getMonth(); inst.drawYear = inst.selectedYear = date.getFullYear(); @@ -8093,23 +8530,28 @@ $.extend(Datepicker.prototype, { /* Action for selecting a new month/year. */ _selectMonthYear: function(id, select, period) { - var target = $(id); - var inst = this._getInst(target[0]); - inst['selected' + (period == 'M' ? 'Month' : 'Year')] = - inst['draw' + (period == 'M' ? 'Month' : 'Year')] = + var target = $(id), + inst = this._getInst(target[0]); + + inst["selected" + (period === "M" ? "Month" : "Year")] = + inst["draw" + (period === "M" ? "Month" : "Year")] = parseInt(select.options[select.selectedIndex].value,10); + this._notifyChange(inst); this._adjustDate(target); }, /* Action for selecting a day. */ _selectDay: function(id, month, year, td) { - var target = $(id); + var inst, + target = $(id); + if ($(td).hasClass(this._unselectableClass) || this._isDisabledDatepicker(target[0])) { return; } - var inst = this._getInst(target[0]); - inst.selectedDay = inst.currentDay = $('a', td).html(); + + inst = this._getInst(target[0]); + inst.selectedDay = inst.currentDay = $("a", td).html(); inst.selectedMonth = inst.currentMonth = month; inst.selectedYear = inst.currentYear = year; this._selectDate(id, this._formatDate(inst, @@ -8119,372 +8561,427 @@ $.extend(Datepicker.prototype, { /* Erase the input field and hide the date picker. */ _clearDate: function(id) { var target = $(id); - var inst = this._getInst(target[0]); - this._selectDate(target, ''); + this._selectDate(target, ""); }, /* Update the input field with the selected date. */ _selectDate: function(id, dateStr) { - var target = $(id); - var inst = this._getInst(target[0]); + var onSelect, + target = $(id), + inst = this._getInst(target[0]); + dateStr = (dateStr != null ? dateStr : this._formatDate(inst)); - if (inst.input) + if (inst.input) { inst.input.val(dateStr); + } this._updateAlternate(inst); - var onSelect = this._get(inst, 'onSelect'); - if (onSelect) + + onSelect = this._get(inst, "onSelect"); + if (onSelect) { onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]); // trigger custom callback - else if (inst.input) - inst.input.trigger('change'); // fire the change event - if (inst.inline) + } else if (inst.input) { + inst.input.trigger("change"); // fire the change event + } + + if (inst.inline){ this._updateDatepicker(inst); - else { + } else { this._hideDatepicker(); this._lastInput = inst.input[0]; - if (typeof(inst.input[0]) != 'object') + if (typeof(inst.input[0]) !== "object") { inst.input.focus(); // restore focus + } this._lastInput = null; } }, /* Update any alternate field to synchronise with the main field. */ _updateAlternate: function(inst) { - var altField = this._get(inst, 'altField'); + var altFormat, date, dateStr, + altField = this._get(inst, "altField"); + if (altField) { // update alternate field too - var altFormat = this._get(inst, 'altFormat') || this._get(inst, 'dateFormat'); - var date = this._getDate(inst); - var dateStr = this.formatDate(altFormat, date, this._getFormatConfig(inst)); + altFormat = this._get(inst, "altFormat") || this._get(inst, "dateFormat"); + date = this._getDate(inst); + dateStr = this.formatDate(altFormat, date, this._getFormatConfig(inst)); $(altField).each(function() { $(this).val(dateStr); }); } }, /* Set as beforeShowDay function to prevent selection of weekends. - @param date Date - the date to customise - @return [boolean, string] - is this date selectable?, what is its CSS class? */ + * @param date Date - the date to customise + * @return [boolean, string] - is this date selectable?, what is its CSS class? + */ noWeekends: function(date) { var day = date.getDay(); - return [(day > 0 && day < 6), '']; + return [(day > 0 && day < 6), ""]; }, /* Set as calculateWeek to determine the week of the year based on the ISO 8601 definition. - @param date Date - the date to get the week for - @return number - the number of the week within the year that contains this date */ + * @param date Date - the date to get the week for + * @return number - the number of the week within the year that contains this date + */ iso8601Week: function(date) { - var checkDate = new Date(date.getTime()); + var time, + checkDate = new Date(date.getTime()); + // Find Thursday of this week starting on Monday checkDate.setDate(checkDate.getDate() + 4 - (checkDate.getDay() || 7)); - var time = checkDate.getTime(); + + time = checkDate.getTime(); checkDate.setMonth(0); // Compare with Jan 1 checkDate.setDate(1); return Math.floor(Math.round((time - checkDate) / 86400000) / 7) + 1; }, /* Parse a string value into a date object. - See formatDate below for the possible formats. - - @param format string - the expected format of the date - @param value string - the date in the above format - @param settings Object - attributes include: - shortYearCutoff number - the cutoff year for determining the century (optional) - dayNamesShort string[7] - abbreviated names of the days from Sunday (optional) - dayNames string[7] - names of the days from Sunday (optional) - monthNamesShort string[12] - abbreviated names of the months (optional) - monthNames string[12] - names of the months (optional) - @return Date - the extracted date value or null if value is blank */ + * See formatDate below for the possible formats. + * + * @param format string - the expected format of the date + * @param value string - the date in the above format + * @param settings Object - attributes include: + * shortYearCutoff number - the cutoff year for determining the century (optional) + * dayNamesShort string[7] - abbreviated names of the days from Sunday (optional) + * dayNames string[7] - names of the days from Sunday (optional) + * monthNamesShort string[12] - abbreviated names of the months (optional) + * monthNames string[12] - names of the months (optional) + * @return Date - the extracted date value or null if value is blank + */ parseDate: function (format, value, settings) { - if (format == null || value == null) - throw 'Invalid arguments'; - value = (typeof value == 'object' ? value.toString() : value + ''); - if (value == '') + if (format == null || value == null) { + throw "Invalid arguments"; + } + + value = (typeof value === "object" ? value.toString() : value + ""); + if (value === "") { return null; - var shortYearCutoff = (settings ? settings.shortYearCutoff : null) || this._defaults.shortYearCutoff; - shortYearCutoff = (typeof shortYearCutoff != 'string' ? shortYearCutoff : - new Date().getFullYear() % 100 + parseInt(shortYearCutoff, 10)); - var dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort; - var dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames; - var monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort; - var monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames; - var year = -1; - var month = -1; - var day = -1; - var doy = -1; - var literal = false; - // Check whether a format character is doubled - var lookAhead = function(match) { - var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) == match); - if (matches) - iFormat++; - return matches; - }; - // Extract a number from the string value - var getNumber = function(match) { - var isDoubled = lookAhead(match); - var size = (match == '@' ? 14 : (match == '!' ? 20 : - (match == 'y' && isDoubled ? 4 : (match == 'o' ? 3 : 2)))); - var digits = new RegExp('^\\d{1,' + size + '}'); - var num = value.substring(iValue).match(digits); - if (!num) - throw 'Missing number at position ' + iValue; - iValue += num[0].length; - return parseInt(num[0], 10); - }; - // Extract a name from the string value and convert to an index - var getName = function(match, shortNames, longNames) { - var names = $.map(lookAhead(match) ? longNames : shortNames, function (v, k) { - return [ [k, v] ]; - }).sort(function (a, b) { - return -(a[1].length - b[1].length); - }); - var index = -1; - $.each(names, function (i, pair) { - var name = pair[1]; - if (value.substr(iValue, name.length).toLowerCase() == name.toLowerCase()) { - index = pair[0]; - iValue += name.length; - return false; + } + + var iFormat, dim, extra, + iValue = 0, + shortYearCutoffTemp = (settings ? settings.shortYearCutoff : null) || this._defaults.shortYearCutoff, + shortYearCutoff = (typeof shortYearCutoffTemp !== "string" ? shortYearCutoffTemp : + new Date().getFullYear() % 100 + parseInt(shortYearCutoffTemp, 10)), + dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort, + dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames, + monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort, + monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames, + year = -1, + month = -1, + day = -1, + doy = -1, + literal = false, + date, + // Check whether a format character is doubled + lookAhead = function(match) { + var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match); + if (matches) { + iFormat++; + } + return matches; + }, + // Extract a number from the string value + getNumber = function(match) { + var isDoubled = lookAhead(match), + size = (match === "@" ? 14 : (match === "!" ? 20 : + (match === "y" && isDoubled ? 4 : (match === "o" ? 3 : 2)))), + digits = new RegExp("^\\d{1," + size + "}"), + num = value.substring(iValue).match(digits); + if (!num) { + throw "Missing number at position " + iValue; + } + iValue += num[0].length; + return parseInt(num[0], 10); + }, + // Extract a name from the string value and convert to an index + getName = function(match, shortNames, longNames) { + var index = -1, + names = $.map(lookAhead(match) ? longNames : shortNames, function (v, k) { + return [ [k, v] ]; + }).sort(function (a, b) { + return -(a[1].length - b[1].length); + }); + + $.each(names, function (i, pair) { + var name = pair[1]; + if (value.substr(iValue, name.length).toLowerCase() === name.toLowerCase()) { + index = pair[0]; + iValue += name.length; + return false; + } + }); + if (index !== -1) { + return index + 1; + } else { + throw "Unknown name at position " + iValue; } - }); - if (index != -1) - return index + 1; - else - throw 'Unknown name at position ' + iValue; - }; - // Confirm that a literal character matches the string value - var checkLiteral = function() { - if (value.charAt(iValue) != format.charAt(iFormat)) - throw 'Unexpected literal at position ' + iValue; - iValue++; - }; - var iValue = 0; - for (var iFormat = 0; iFormat < format.length; iFormat++) { - if (literal) - if (format.charAt(iFormat) == "'" && !lookAhead("'")) + }, + // Confirm that a literal character matches the string value + checkLiteral = function() { + if (value.charAt(iValue) !== format.charAt(iFormat)) { + throw "Unexpected literal at position " + iValue; + } + iValue++; + }; + + for (iFormat = 0; iFormat < format.length; iFormat++) { + if (literal) { + if (format.charAt(iFormat) === "'" && !lookAhead("'")) { literal = false; - else + } else { checkLiteral(); - else + } + } else { switch (format.charAt(iFormat)) { - case 'd': - day = getNumber('d'); + case "d": + day = getNumber("d"); break; - case 'D': - getName('D', dayNamesShort, dayNames); + case "D": + getName("D", dayNamesShort, dayNames); break; - case 'o': - doy = getNumber('o'); + case "o": + doy = getNumber("o"); break; - case 'm': - month = getNumber('m'); + case "m": + month = getNumber("m"); break; - case 'M': - month = getName('M', monthNamesShort, monthNames); + case "M": + month = getName("M", monthNamesShort, monthNames); break; - case 'y': - year = getNumber('y'); + case "y": + year = getNumber("y"); break; - case '@': - var date = new Date(getNumber('@')); + case "@": + date = new Date(getNumber("@")); year = date.getFullYear(); month = date.getMonth() + 1; day = date.getDate(); break; - case '!': - var date = new Date((getNumber('!') - this._ticksTo1970) / 10000); + case "!": + date = new Date((getNumber("!") - this._ticksTo1970) / 10000); year = date.getFullYear(); month = date.getMonth() + 1; day = date.getDate(); break; case "'": - if (lookAhead("'")) + if (lookAhead("'")){ checkLiteral(); - else + } else { literal = true; + } break; default: checkLiteral(); } + } } + if (iValue < value.length){ - var extra = value.substr(iValue); + extra = value.substr(iValue); if (!/^\s+/.test(extra)) { throw "Extra/unparsed characters found in date: " + extra; } } - if (year == -1) + + if (year === -1) { year = new Date().getFullYear(); - else if (year < 100) + } else if (year < 100) { year += new Date().getFullYear() - new Date().getFullYear() % 100 + (year <= shortYearCutoff ? 0 : -100); + } + if (doy > -1) { month = 1; day = doy; do { - var dim = this._getDaysInMonth(year, month - 1); - if (day <= dim) + dim = this._getDaysInMonth(year, month - 1); + if (day <= dim) { break; + } month++; day -= dim; } while (true); } - var date = this._daylightSavingAdjust(new Date(year, month - 1, day)); - if (date.getFullYear() != year || date.getMonth() + 1 != month || date.getDate() != day) - throw 'Invalid date'; // E.g. 31/02/00 + + date = this._daylightSavingAdjust(new Date(year, month - 1, day)); + if (date.getFullYear() !== year || date.getMonth() + 1 !== month || date.getDate() !== day) { + throw "Invalid date"; // E.g. 31/02/00 + } return date; }, /* Standard date formats. */ - ATOM: 'yy-mm-dd', // RFC 3339 (ISO 8601) - COOKIE: 'D, dd M yy', - ISO_8601: 'yy-mm-dd', - RFC_822: 'D, d M y', - RFC_850: 'DD, dd-M-y', - RFC_1036: 'D, d M y', - RFC_1123: 'D, d M yy', - RFC_2822: 'D, d M yy', - RSS: 'D, d M y', // RFC 822 - TICKS: '!', - TIMESTAMP: '@', - W3C: 'yy-mm-dd', // ISO 8601 + ATOM: "yy-mm-dd", // RFC 3339 (ISO 8601) + COOKIE: "D, dd M yy", + ISO_8601: "yy-mm-dd", + RFC_822: "D, d M y", + RFC_850: "DD, dd-M-y", + RFC_1036: "D, d M y", + RFC_1123: "D, d M yy", + RFC_2822: "D, d M yy", + RSS: "D, d M y", // RFC 822 + TICKS: "!", + TIMESTAMP: "@", + W3C: "yy-mm-dd", // ISO 8601 _ticksTo1970: (((1970 - 1) * 365 + Math.floor(1970 / 4) - Math.floor(1970 / 100) + Math.floor(1970 / 400)) * 24 * 60 * 60 * 10000000), /* Format a date object into a string value. - The format can be combinations of the following: - d - day of month (no leading zero) - dd - day of month (two digit) - o - day of year (no leading zeros) - oo - day of year (three digit) - D - day name short - DD - day name long - m - month of year (no leading zero) - mm - month of year (two digit) - M - month name short - MM - month name long - y - year (two digit) - yy - year (four digit) - @ - Unix timestamp (ms since 01/01/1970) - ! - Windows ticks (100ns since 01/01/0001) - '...' - literal text - '' - single quote - - @param format string - the desired format of the date - @param date Date - the date value to format - @param settings Object - attributes include: - dayNamesShort string[7] - abbreviated names of the days from Sunday (optional) - dayNames string[7] - names of the days from Sunday (optional) - monthNamesShort string[12] - abbreviated names of the months (optional) - monthNames string[12] - names of the months (optional) - @return string - the date in the above format */ + * The format can be combinations of the following: + * d - day of month (no leading zero) + * dd - day of month (two digit) + * o - day of year (no leading zeros) + * oo - day of year (three digit) + * D - day name short + * DD - day name long + * m - month of year (no leading zero) + * mm - month of year (two digit) + * M - month name short + * MM - month name long + * y - year (two digit) + * yy - year (four digit) + * @ - Unix timestamp (ms since 01/01/1970) + * ! - Windows ticks (100ns since 01/01/0001) + * "..." - literal text + * '' - single quote + * + * @param format string - the desired format of the date + * @param date Date - the date value to format + * @param settings Object - attributes include: + * dayNamesShort string[7] - abbreviated names of the days from Sunday (optional) + * dayNames string[7] - names of the days from Sunday (optional) + * monthNamesShort string[12] - abbreviated names of the months (optional) + * monthNames string[12] - names of the months (optional) + * @return string - the date in the above format + */ formatDate: function (format, date, settings) { - if (!date) - return ''; - var dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort; - var dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames; - var monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort; - var monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames; - // Check whether a format character is doubled - var lookAhead = function(match) { - var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) == match); - if (matches) - iFormat++; - return matches; - }; - // Format a number, with leading zero if necessary - var formatNumber = function(match, value, len) { - var num = '' + value; - if (lookAhead(match)) - while (num.length < len) - num = '0' + num; - return num; - }; - // Format a name, short or long as requested - var formatName = function(match, value, shortNames, longNames) { - return (lookAhead(match) ? longNames[value] : shortNames[value]); - }; - var output = ''; - var literal = false; - if (date) - for (var iFormat = 0; iFormat < format.length; iFormat++) { - if (literal) - if (format.charAt(iFormat) == "'" && !lookAhead("'")) + if (!date) { + return ""; + } + + var iFormat, + dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort, + dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames, + monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort, + monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames, + // Check whether a format character is doubled + lookAhead = function(match) { + var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match); + if (matches) { + iFormat++; + } + return matches; + }, + // Format a number, with leading zero if necessary + formatNumber = function(match, value, len) { + var num = "" + value; + if (lookAhead(match)) { + while (num.length < len) { + num = "0" + num; + } + } + return num; + }, + // Format a name, short or long as requested + formatName = function(match, value, shortNames, longNames) { + return (lookAhead(match) ? longNames[value] : shortNames[value]); + }, + output = "", + literal = false; + + if (date) { + for (iFormat = 0; iFormat < format.length; iFormat++) { + if (literal) { + if (format.charAt(iFormat) === "'" && !lookAhead("'")) { literal = false; - else + } else { output += format.charAt(iFormat); - else + } + } else { switch (format.charAt(iFormat)) { - case 'd': - output += formatNumber('d', date.getDate(), 2); + case "d": + output += formatNumber("d", date.getDate(), 2); break; - case 'D': - output += formatName('D', date.getDay(), dayNamesShort, dayNames); + case "D": + output += formatName("D", date.getDay(), dayNamesShort, dayNames); break; - case 'o': - output += formatNumber('o', + case "o": + output += formatNumber("o", Math.round((new Date(date.getFullYear(), date.getMonth(), date.getDate()).getTime() - new Date(date.getFullYear(), 0, 0).getTime()) / 86400000), 3); break; - case 'm': - output += formatNumber('m', date.getMonth() + 1, 2); + case "m": + output += formatNumber("m", date.getMonth() + 1, 2); break; - case 'M': - output += formatName('M', date.getMonth(), monthNamesShort, monthNames); + case "M": + output += formatName("M", date.getMonth(), monthNamesShort, monthNames); break; - case 'y': - output += (lookAhead('y') ? date.getFullYear() : - (date.getYear() % 100 < 10 ? '0' : '') + date.getYear() % 100); + case "y": + output += (lookAhead("y") ? date.getFullYear() : + (date.getYear() % 100 < 10 ? "0" : "") + date.getYear() % 100); break; - case '@': + case "@": output += date.getTime(); break; - case '!': + case "!": output += date.getTime() * 10000 + this._ticksTo1970; break; case "'": - if (lookAhead("'")) + if (lookAhead("'")) { output += "'"; - else + } else { literal = true; + } break; default: output += format.charAt(iFormat); } + } } + } return output; }, /* Extract all possible characters from the date format. */ _possibleChars: function (format) { - var chars = ''; - var literal = false; - // Check whether a format character is doubled - var lookAhead = function(match) { - var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) == match); - if (matches) - iFormat++; - return matches; - }; - for (var iFormat = 0; iFormat < format.length; iFormat++) - if (literal) - if (format.charAt(iFormat) == "'" && !lookAhead("'")) + var iFormat, + chars = "", + literal = false, + // Check whether a format character is doubled + lookAhead = function(match) { + var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match); + if (matches) { + iFormat++; + } + return matches; + }; + + for (iFormat = 0; iFormat < format.length; iFormat++) { + if (literal) { + if (format.charAt(iFormat) === "'" && !lookAhead("'")) { literal = false; - else + } else { chars += format.charAt(iFormat); - else + } + } else { switch (format.charAt(iFormat)) { - case 'd': case 'm': case 'y': case '@': - chars += '0123456789'; + case "d": case "m": case "y": case "@": + chars += "0123456789"; break; - case 'D': case 'M': + case "D": case "M": return null; // Accept anything case "'": - if (lookAhead("'")) + if (lookAhead("'")) { chars += "'"; - else + } else { literal = true; + } break; default: chars += format.charAt(iFormat); } + } + } return chars; }, @@ -8496,19 +8993,20 @@ $.extend(Datepicker.prototype, { /* Parse existing date and initialise date picker. */ _setDateFromField: function(inst, noDefault) { - if (inst.input.val() == inst.lastVal) { + if (inst.input.val() === inst.lastVal) { return; } - var dateFormat = this._get(inst, 'dateFormat'); - var dates = inst.lastVal = inst.input ? inst.input.val() : null; - var date, defaultDate; - date = defaultDate = this._getDefaultDate(inst); - var settings = this._getFormatConfig(inst); + + var dateFormat = this._get(inst, "dateFormat"), + dates = inst.lastVal = inst.input ? inst.input.val() : null, + defaultDate = this._getDefaultDate(inst), + date = defaultDate, + settings = this._getFormatConfig(inst); + try { date = this.parseDate(dateFormat, dates, settings) || defaultDate; } catch (event) { - this.log(event); - dates = (noDefault ? '' : dates); + dates = (noDefault ? "" : dates); } inst.selectedDay = date.getDate(); inst.drawMonth = inst.selectedMonth = date.getMonth(); @@ -8522,53 +9020,56 @@ $.extend(Datepicker.prototype, { /* Retrieve the default date shown on opening. */ _getDefaultDate: function(inst) { return this._restrictMinMax(inst, - this._determineDate(inst, this._get(inst, 'defaultDate'), new Date())); + this._determineDate(inst, this._get(inst, "defaultDate"), new Date())); }, /* A date may be specified as an exact value or a relative one. */ _determineDate: function(inst, date, defaultDate) { var offsetNumeric = function(offset) { - var date = new Date(); - date.setDate(date.getDate() + offset); - return date; - }; - var offsetString = function(offset) { - try { - return $.datepicker.parseDate($.datepicker._get(inst, 'dateFormat'), - offset, $.datepicker._getFormatConfig(inst)); - } - catch (e) { - // Ignore - } - var date = (offset.toLowerCase().match(/^c/) ? - $.datepicker._getDate(inst) : null) || new Date(); - var year = date.getFullYear(); - var month = date.getMonth(); - var day = date.getDate(); - var pattern = /([+-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g; - var matches = pattern.exec(offset); - while (matches) { - switch (matches[2] || 'd') { - case 'd' : case 'D' : - day += parseInt(matches[1],10); break; - case 'w' : case 'W' : - day += parseInt(matches[1],10) * 7; break; - case 'm' : case 'M' : - month += parseInt(matches[1],10); - day = Math.min(day, $.datepicker._getDaysInMonth(year, month)); - break; - case 'y': case 'Y' : - year += parseInt(matches[1],10); - day = Math.min(day, $.datepicker._getDaysInMonth(year, month)); - break; + var date = new Date(); + date.setDate(date.getDate() + offset); + return date; + }, + offsetString = function(offset) { + try { + return $.datepicker.parseDate($.datepicker._get(inst, "dateFormat"), + offset, $.datepicker._getFormatConfig(inst)); + } + catch (e) { + // Ignore + } + + var date = (offset.toLowerCase().match(/^c/) ? + $.datepicker._getDate(inst) : null) || new Date(), + year = date.getFullYear(), + month = date.getMonth(), + day = date.getDate(), + pattern = /([+\-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g, + matches = pattern.exec(offset); + + while (matches) { + switch (matches[2] || "d") { + case "d" : case "D" : + day += parseInt(matches[1],10); break; + case "w" : case "W" : + day += parseInt(matches[1],10) * 7; break; + case "m" : case "M" : + month += parseInt(matches[1],10); + day = Math.min(day, $.datepicker._getDaysInMonth(year, month)); + break; + case "y": case "Y" : + year += parseInt(matches[1],10); + day = Math.min(day, $.datepicker._getDaysInMonth(year, month)); + break; + } + matches = pattern.exec(offset); } - matches = pattern.exec(offset); - } - return new Date(year, month, day); - }; - var newDate = (date == null || date === '' ? defaultDate : (typeof date == 'string' ? offsetString(date) : - (typeof date == 'number' ? (isNaN(date) ? defaultDate : offsetNumeric(date)) : new Date(date.getTime())))); - newDate = (newDate && newDate.toString() == 'Invalid Date' ? defaultDate : newDate); + return new Date(year, month, day); + }, + newDate = (date == null || date === "" ? defaultDate : (typeof date === "string" ? offsetString(date) : + (typeof date === "number" ? (isNaN(date) ? defaultDate : offsetNumeric(date)) : new Date(date.getTime())))); + + newDate = (newDate && newDate.toString() === "Invalid Date" ? defaultDate : newDate); if (newDate) { newDate.setHours(0); newDate.setMinutes(0); @@ -8579,37 +9080,42 @@ $.extend(Datepicker.prototype, { }, /* Handle switch to/from daylight saving. - Hours may be non-zero on daylight saving cut-over: - > 12 when midnight changeover, but then cannot generate - midnight datetime, so jump to 1AM, otherwise reset. - @param date (Date) the date to check - @return (Date) the corrected date */ + * Hours may be non-zero on daylight saving cut-over: + * > 12 when midnight changeover, but then cannot generate + * midnight datetime, so jump to 1AM, otherwise reset. + * @param date (Date) the date to check + * @return (Date) the corrected date + */ _daylightSavingAdjust: function(date) { - if (!date) return null; + if (!date) { + return null; + } date.setHours(date.getHours() > 12 ? date.getHours() + 2 : 0); return date; }, /* Set the date(s) directly. */ _setDate: function(inst, date, noChange) { - var clear = !date; - var origMonth = inst.selectedMonth; - var origYear = inst.selectedYear; - var newDate = this._restrictMinMax(inst, this._determineDate(inst, date, new Date())); + var clear = !date, + origMonth = inst.selectedMonth, + origYear = inst.selectedYear, + newDate = this._restrictMinMax(inst, this._determineDate(inst, date, new Date())); + inst.selectedDay = inst.currentDay = newDate.getDate(); inst.drawMonth = inst.selectedMonth = inst.currentMonth = newDate.getMonth(); inst.drawYear = inst.selectedYear = inst.currentYear = newDate.getFullYear(); - if ((origMonth != inst.selectedMonth || origYear != inst.selectedYear) && !noChange) + if ((origMonth !== inst.selectedMonth || origYear !== inst.selectedYear) && !noChange) { this._notifyChange(inst); + } this._adjustInstDate(inst); if (inst.input) { - inst.input.val(clear ? '' : this._formatDate(inst)); + inst.input.val(clear ? "" : this._formatDate(inst)); } }, /* Retrieve the date(s) directly. */ _getDate: function(inst) { - var startDate = (!inst.currentYear || (inst.input && inst.input.val() == '') ? null : + var startDate = (!inst.currentYear || (inst.input && inst.input.val() === "") ? null : this._daylightSavingAdjust(new Date( inst.currentYear, inst.currentMonth, inst.currentDay))); return startDate; @@ -8619,64 +9125,71 @@ $.extend(Datepicker.prototype, { * they work with static code transformers like Caja. */ _attachHandlers: function(inst) { - var stepMonths = this._get(inst, 'stepMonths'); - var id = '#' + inst.id.replace( /\\\\/g, "\\" ); - inst.dpDiv.find('[data-handler]').map(function () { + var stepMonths = this._get(inst, "stepMonths"), + id = "#" + inst.id.replace( /\\\\/g, "\\" ); + inst.dpDiv.find("[data-handler]").map(function () { var handler = { prev: function () { - window['DP_jQuery_' + dpuuid].datepicker._adjustDate(id, -stepMonths, 'M'); + window["DP_jQuery_" + dpuuid].datepicker._adjustDate(id, -stepMonths, "M"); }, next: function () { - window['DP_jQuery_' + dpuuid].datepicker._adjustDate(id, +stepMonths, 'M'); + window["DP_jQuery_" + dpuuid].datepicker._adjustDate(id, +stepMonths, "M"); }, hide: function () { - window['DP_jQuery_' + dpuuid].datepicker._hideDatepicker(); + window["DP_jQuery_" + dpuuid].datepicker._hideDatepicker(); }, today: function () { - window['DP_jQuery_' + dpuuid].datepicker._gotoToday(id); + window["DP_jQuery_" + dpuuid].datepicker._gotoToday(id); }, selectDay: function () { - window['DP_jQuery_' + dpuuid].datepicker._selectDay(id, +this.getAttribute('data-month'), +this.getAttribute('data-year'), this); + window["DP_jQuery_" + dpuuid].datepicker._selectDay(id, +this.getAttribute("data-month"), +this.getAttribute("data-year"), this); return false; }, selectMonth: function () { - window['DP_jQuery_' + dpuuid].datepicker._selectMonthYear(id, this, 'M'); + window["DP_jQuery_" + dpuuid].datepicker._selectMonthYear(id, this, "M"); return false; }, selectYear: function () { - window['DP_jQuery_' + dpuuid].datepicker._selectMonthYear(id, this, 'Y'); + window["DP_jQuery_" + dpuuid].datepicker._selectMonthYear(id, this, "Y"); return false; } }; - $(this).bind(this.getAttribute('data-event'), handler[this.getAttribute('data-handler')]); + $(this).bind(this.getAttribute("data-event"), handler[this.getAttribute("data-handler")]); }); }, /* Generate the HTML for the current state of the date picker. */ _generateHTML: function(inst) { - var today = new Date(); - today = this._daylightSavingAdjust( - new Date(today.getFullYear(), today.getMonth(), today.getDate())); // clear time - var isRTL = this._get(inst, 'isRTL'); - var showButtonPanel = this._get(inst, 'showButtonPanel'); - var hideIfNoPrevNext = this._get(inst, 'hideIfNoPrevNext'); - var navigationAsDateFormat = this._get(inst, 'navigationAsDateFormat'); - var numMonths = this._getNumberOfMonths(inst); - var showCurrentAtPos = this._get(inst, 'showCurrentAtPos'); - var stepMonths = this._get(inst, 'stepMonths'); - var isMultiMonth = (numMonths[0] != 1 || numMonths[1] != 1); - var currentDate = this._daylightSavingAdjust((!inst.currentDay ? new Date(9999, 9, 9) : - new Date(inst.currentYear, inst.currentMonth, inst.currentDay))); - var minDate = this._getMinMaxDate(inst, 'min'); - var maxDate = this._getMinMaxDate(inst, 'max'); - var drawMonth = inst.drawMonth - showCurrentAtPos; - var drawYear = inst.drawYear; + var maxDraw, prevText, prev, nextText, next, currentText, gotoDate, + controls, buttonPanel, firstDay, showWeek, dayNames, dayNamesMin, + monthNames, monthNamesShort, beforeShowDay, showOtherMonths, + selectOtherMonths, defaultDate, html, dow, row, group, col, selectedDate, + cornerClass, calender, thead, day, daysInMonth, leadDays, curRows, numRows, + printDate, dRow, tbody, daySettings, otherMonth, unselectable, + tempDate = new Date(), + today = this._daylightSavingAdjust( + new Date(tempDate.getFullYear(), tempDate.getMonth(), tempDate.getDate())), // clear time + isRTL = this._get(inst, "isRTL"), + showButtonPanel = this._get(inst, "showButtonPanel"), + hideIfNoPrevNext = this._get(inst, "hideIfNoPrevNext"), + navigationAsDateFormat = this._get(inst, "navigationAsDateFormat"), + numMonths = this._getNumberOfMonths(inst), + showCurrentAtPos = this._get(inst, "showCurrentAtPos"), + stepMonths = this._get(inst, "stepMonths"), + isMultiMonth = (numMonths[0] !== 1 || numMonths[1] !== 1), + currentDate = this._daylightSavingAdjust((!inst.currentDay ? new Date(9999, 9, 9) : + new Date(inst.currentYear, inst.currentMonth, inst.currentDay))), + minDate = this._getMinMaxDate(inst, "min"), + maxDate = this._getMinMaxDate(inst, "max"), + drawMonth = inst.drawMonth - showCurrentAtPos, + drawYear = inst.drawYear; + if (drawMonth < 0) { drawMonth += 12; drawYear--; } if (maxDate) { - var maxDraw = this._daylightSavingAdjust(new Date(maxDate.getFullYear(), + maxDraw = this._daylightSavingAdjust(new Date(maxDate.getFullYear(), maxDate.getMonth() - (numMonths[0] * numMonths[1]) + 1, maxDate.getDate())); maxDraw = (minDate && maxDraw < minDate ? minDate : maxDraw); while (this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1)) > maxDraw) { @@ -8689,133 +9202,142 @@ $.extend(Datepicker.prototype, { } inst.drawMonth = drawMonth; inst.drawYear = drawYear; - var prevText = this._get(inst, 'prevText'); + + prevText = this._get(inst, "prevText"); prevText = (!navigationAsDateFormat ? prevText : this.formatDate(prevText, this._daylightSavingAdjust(new Date(drawYear, drawMonth - stepMonths, 1)), this._getFormatConfig(inst))); - var prev = (this._canAdjustMonth(inst, -1, drawYear, drawMonth) ? - '<a class="ui-datepicker-prev ui-corner-all" data-handler="prev" data-event="click"' + - ' title="' + prevText + '"><span class="ui-icon ui-icon-circle-triangle-' + ( isRTL ? 'e' : 'w') + '">' + prevText + '</span></a>' : - (hideIfNoPrevNext ? '' : '<a class="ui-datepicker-prev ui-corner-all ui-state-disabled" title="'+ prevText +'"><span class="ui-icon ui-icon-circle-triangle-' + ( isRTL ? 'e' : 'w') + '">' + prevText + '</span></a>')); - var nextText = this._get(inst, 'nextText'); + + prev = (this._canAdjustMonth(inst, -1, drawYear, drawMonth) ? + "<a class='ui-datepicker-prev ui-corner-all' data-handler='prev' data-event='click'" + + " title='" + prevText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "e" : "w") + "'>" + prevText + "</span></a>" : + (hideIfNoPrevNext ? "" : "<a class='ui-datepicker-prev ui-corner-all ui-state-disabled' title='"+ prevText +"'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "e" : "w") + "'>" + prevText + "</span></a>")); + + nextText = this._get(inst, "nextText"); nextText = (!navigationAsDateFormat ? nextText : this.formatDate(nextText, this._daylightSavingAdjust(new Date(drawYear, drawMonth + stepMonths, 1)), this._getFormatConfig(inst))); - var next = (this._canAdjustMonth(inst, +1, drawYear, drawMonth) ? - '<a class="ui-datepicker-next ui-corner-all" data-handler="next" data-event="click"' + - ' title="' + nextText + '"><span class="ui-icon ui-icon-circle-triangle-' + ( isRTL ? 'w' : 'e') + '">' + nextText + '</span></a>' : - (hideIfNoPrevNext ? '' : '<a class="ui-datepicker-next ui-corner-all ui-state-disabled" title="'+ nextText + '"><span class="ui-icon ui-icon-circle-triangle-' + ( isRTL ? 'w' : 'e') + '">' + nextText + '</span></a>')); - var currentText = this._get(inst, 'currentText'); - var gotoDate = (this._get(inst, 'gotoCurrent') && inst.currentDay ? currentDate : today); + + next = (this._canAdjustMonth(inst, +1, drawYear, drawMonth) ? + "<a class='ui-datepicker-next ui-corner-all' data-handler='next' data-event='click'" + + " title='" + nextText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "w" : "e") + "'>" + nextText + "</span></a>" : + (hideIfNoPrevNext ? "" : "<a class='ui-datepicker-next ui-corner-all ui-state-disabled' title='"+ nextText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "w" : "e") + "'>" + nextText + "</span></a>")); + + currentText = this._get(inst, "currentText"); + gotoDate = (this._get(inst, "gotoCurrent") && inst.currentDay ? currentDate : today); currentText = (!navigationAsDateFormat ? currentText : this.formatDate(currentText, gotoDate, this._getFormatConfig(inst))); - var controls = (!inst.inline ? '<button type="button" class="ui-datepicker-close ui-state-default ui-priority-primary ui-corner-all" data-handler="hide" data-event="click">' + - this._get(inst, 'closeText') + '</button>' : ''); - var buttonPanel = (showButtonPanel) ? '<div class="ui-datepicker-buttonpane ui-widget-content">' + (isRTL ? controls : '') + - (this._isInRange(inst, gotoDate) ? '<button type="button" class="ui-datepicker-current ui-state-default ui-priority-secondary ui-corner-all" data-handler="today" data-event="click"' + - '>' + currentText + '</button>' : '') + (isRTL ? '' : controls) + '</div>' : ''; - var firstDay = parseInt(this._get(inst, 'firstDay'),10); + + controls = (!inst.inline ? "<button type='button' class='ui-datepicker-close ui-state-default ui-priority-primary ui-corner-all' data-handler='hide' data-event='click'>" + + this._get(inst, "closeText") + "</button>" : ""); + + buttonPanel = (showButtonPanel) ? "<div class='ui-datepicker-buttonpane ui-widget-content'>" + (isRTL ? controls : "") + + (this._isInRange(inst, gotoDate) ? "<button type='button' class='ui-datepicker-current ui-state-default ui-priority-secondary ui-corner-all' data-handler='today' data-event='click'" + + ">" + currentText + "</button>" : "") + (isRTL ? "" : controls) + "</div>" : ""; + + firstDay = parseInt(this._get(inst, "firstDay"),10); firstDay = (isNaN(firstDay) ? 0 : firstDay); - var showWeek = this._get(inst, 'showWeek'); - var dayNames = this._get(inst, 'dayNames'); - var dayNamesShort = this._get(inst, 'dayNamesShort'); - var dayNamesMin = this._get(inst, 'dayNamesMin'); - var monthNames = this._get(inst, 'monthNames'); - var monthNamesShort = this._get(inst, 'monthNamesShort'); - var beforeShowDay = this._get(inst, 'beforeShowDay'); - var showOtherMonths = this._get(inst, 'showOtherMonths'); - var selectOtherMonths = this._get(inst, 'selectOtherMonths'); - var calculateWeek = this._get(inst, 'calculateWeek') || this.iso8601Week; - var defaultDate = this._getDefaultDate(inst); - var html = ''; - for (var row = 0; row < numMonths[0]; row++) { - var group = ''; + + showWeek = this._get(inst, "showWeek"); + dayNames = this._get(inst, "dayNames"); + dayNamesMin = this._get(inst, "dayNamesMin"); + monthNames = this._get(inst, "monthNames"); + monthNamesShort = this._get(inst, "monthNamesShort"); + beforeShowDay = this._get(inst, "beforeShowDay"); + showOtherMonths = this._get(inst, "showOtherMonths"); + selectOtherMonths = this._get(inst, "selectOtherMonths"); + defaultDate = this._getDefaultDate(inst); + html = ""; + dow; + for (row = 0; row < numMonths[0]; row++) { + group = ""; this.maxRows = 4; - for (var col = 0; col < numMonths[1]; col++) { - var selectedDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, inst.selectedDay)); - var cornerClass = ' ui-corner-all'; - var calender = ''; + for (col = 0; col < numMonths[1]; col++) { + selectedDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, inst.selectedDay)); + cornerClass = " ui-corner-all"; + calender = ""; if (isMultiMonth) { - calender += '<div class="ui-datepicker-group'; - if (numMonths[1] > 1) + calender += "<div class='ui-datepicker-group"; + if (numMonths[1] > 1) { switch (col) { - case 0: calender += ' ui-datepicker-group-first'; - cornerClass = ' ui-corner-' + (isRTL ? 'right' : 'left'); break; - case numMonths[1]-1: calender += ' ui-datepicker-group-last'; - cornerClass = ' ui-corner-' + (isRTL ? 'left' : 'right'); break; - default: calender += ' ui-datepicker-group-middle'; cornerClass = ''; break; + case 0: calender += " ui-datepicker-group-first"; + cornerClass = " ui-corner-" + (isRTL ? "right" : "left"); break; + case numMonths[1]-1: calender += " ui-datepicker-group-last"; + cornerClass = " ui-corner-" + (isRTL ? "left" : "right"); break; + default: calender += " ui-datepicker-group-middle"; cornerClass = ""; break; } - calender += '">'; + } + calender += "'>"; } - calender += '<div class="ui-datepicker-header ui-widget-header ui-helper-clearfix' + cornerClass + '">' + - (/all|left/.test(cornerClass) && row == 0 ? (isRTL ? next : prev) : '') + - (/all|right/.test(cornerClass) && row == 0 ? (isRTL ? prev : next) : '') + + calender += "<div class='ui-datepicker-header ui-widget-header ui-helper-clearfix" + cornerClass + "'>" + + (/all|left/.test(cornerClass) && row === 0 ? (isRTL ? next : prev) : "") + + (/all|right/.test(cornerClass) && row === 0 ? (isRTL ? prev : next) : "") + this._generateMonthYearHeader(inst, drawMonth, drawYear, minDate, maxDate, row > 0 || col > 0, monthNames, monthNamesShort) + // draw month headers - '</div><table class="ui-datepicker-calendar"><thead>' + - '<tr>'; - var thead = (showWeek ? '<th class="ui-datepicker-week-col">' + this._get(inst, 'weekHeader') + '</th>' : ''); - for (var dow = 0; dow < 7; dow++) { // days of the week - var day = (dow + firstDay) % 7; - thead += '<th' + ((dow + firstDay + 6) % 7 >= 5 ? ' class="ui-datepicker-week-end"' : '') + '>' + - '<span title="' + dayNames[day] + '">' + dayNamesMin[day] + '</span></th>'; - } - calender += thead + '</tr></thead><tbody>'; - var daysInMonth = this._getDaysInMonth(drawYear, drawMonth); - if (drawYear == inst.selectedYear && drawMonth == inst.selectedMonth) + "</div><table class='ui-datepicker-calendar'><thead>" + + "<tr>"; + thead = (showWeek ? "<th class='ui-datepicker-week-col'>" + this._get(inst, "weekHeader") + "</th>" : ""); + for (dow = 0; dow < 7; dow++) { // days of the week + day = (dow + firstDay) % 7; + thead += "<th" + ((dow + firstDay + 6) % 7 >= 5 ? " class='ui-datepicker-week-end'" : "") + ">" + + "<span title='" + dayNames[day] + "'>" + dayNamesMin[day] + "</span></th>"; + } + calender += thead + "</tr></thead><tbody>"; + daysInMonth = this._getDaysInMonth(drawYear, drawMonth); + if (drawYear === inst.selectedYear && drawMonth === inst.selectedMonth) { inst.selectedDay = Math.min(inst.selectedDay, daysInMonth); - var leadDays = (this._getFirstDayOfMonth(drawYear, drawMonth) - firstDay + 7) % 7; - var curRows = Math.ceil((leadDays + daysInMonth) / 7); // calculate the number of rows to generate - var numRows = (isMultiMonth ? this.maxRows > curRows ? this.maxRows : curRows : curRows); //If multiple months, use the higher number of rows (see #7043) + } + leadDays = (this._getFirstDayOfMonth(drawYear, drawMonth) - firstDay + 7) % 7; + curRows = Math.ceil((leadDays + daysInMonth) / 7); // calculate the number of rows to generate + numRows = (isMultiMonth ? this.maxRows > curRows ? this.maxRows : curRows : curRows); //If multiple months, use the higher number of rows (see #7043) this.maxRows = numRows; - var printDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1 - leadDays)); - for (var dRow = 0; dRow < numRows; dRow++) { // create date picker rows - calender += '<tr>'; - var tbody = (!showWeek ? '' : '<td class="ui-datepicker-week-col">' + - this._get(inst, 'calculateWeek')(printDate) + '</td>'); - for (var dow = 0; dow < 7; dow++) { // create date picker days - var daySettings = (beforeShowDay ? - beforeShowDay.apply((inst.input ? inst.input[0] : null), [printDate]) : [true, '']); - var otherMonth = (printDate.getMonth() != drawMonth); - var unselectable = (otherMonth && !selectOtherMonths) || !daySettings[0] || + printDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1 - leadDays)); + for (dRow = 0; dRow < numRows; dRow++) { // create date picker rows + calender += "<tr>"; + tbody = (!showWeek ? "" : "<td class='ui-datepicker-week-col'>" + + this._get(inst, "calculateWeek")(printDate) + "</td>"); + for (dow = 0; dow < 7; dow++) { // create date picker days + daySettings = (beforeShowDay ? + beforeShowDay.apply((inst.input ? inst.input[0] : null), [printDate]) : [true, ""]); + otherMonth = (printDate.getMonth() !== drawMonth); + unselectable = (otherMonth && !selectOtherMonths) || !daySettings[0] || (minDate && printDate < minDate) || (maxDate && printDate > maxDate); - tbody += '<td class="' + - ((dow + firstDay + 6) % 7 >= 5 ? ' ui-datepicker-week-end' : '') + // highlight weekends - (otherMonth ? ' ui-datepicker-other-month' : '') + // highlight days from other months - ((printDate.getTime() == selectedDate.getTime() && drawMonth == inst.selectedMonth && inst._keyEvent) || // user pressed key - (defaultDate.getTime() == printDate.getTime() && defaultDate.getTime() == selectedDate.getTime()) ? + tbody += "<td class='" + + ((dow + firstDay + 6) % 7 >= 5 ? " ui-datepicker-week-end" : "") + // highlight weekends + (otherMonth ? " ui-datepicker-other-month" : "") + // highlight days from other months + ((printDate.getTime() === selectedDate.getTime() && drawMonth === inst.selectedMonth && inst._keyEvent) || // user pressed key + (defaultDate.getTime() === printDate.getTime() && defaultDate.getTime() === selectedDate.getTime()) ? // or defaultDate is current printedDate and defaultDate is selectedDate - ' ' + this._dayOverClass : '') + // highlight selected day - (unselectable ? ' ' + this._unselectableClass + ' ui-state-disabled': '') + // highlight unselectable days - (otherMonth && !showOtherMonths ? '' : ' ' + daySettings[1] + // highlight custom dates - (printDate.getTime() == currentDate.getTime() ? ' ' + this._currentClass : '') + // highlight selected day - (printDate.getTime() == today.getTime() ? ' ui-datepicker-today' : '')) + '"' + // highlight today (if different) - ((!otherMonth || showOtherMonths) && daySettings[2] ? ' title="' + daySettings[2] + '"' : '') + // cell title - (unselectable ? '' : ' data-handler="selectDay" data-event="click" data-month="' + printDate.getMonth() + '" data-year="' + printDate.getFullYear() + '"') + '>' + // actions - (otherMonth && !showOtherMonths ? ' ' : // display for other months - (unselectable ? '<span class="ui-state-default">' + printDate.getDate() + '</span>' : '<a class="ui-state-default' + - (printDate.getTime() == today.getTime() ? ' ui-state-highlight' : '') + - (printDate.getTime() == currentDate.getTime() ? ' ui-state-active' : '') + // highlight selected day - (otherMonth ? ' ui-priority-secondary' : '') + // distinguish dates from other months - '" href="#">' + printDate.getDate() + '</a>')) + '</td>'; // display selectable date + " " + this._dayOverClass : "") + // highlight selected day + (unselectable ? " " + this._unselectableClass + " ui-state-disabled": "") + // highlight unselectable days + (otherMonth && !showOtherMonths ? "" : " " + daySettings[1] + // highlight custom dates + (printDate.getTime() === currentDate.getTime() ? " " + this._currentClass : "") + // highlight selected day + (printDate.getTime() === today.getTime() ? " ui-datepicker-today" : "")) + "'" + // highlight today (if different) + ((!otherMonth || showOtherMonths) && daySettings[2] ? " title='" + daySettings[2].replace(/'/g, "'") + "'" : "") + // cell title + (unselectable ? "" : " data-handler='selectDay' data-event='click' data-month='" + printDate.getMonth() + "' data-year='" + printDate.getFullYear() + "'") + ">" + // actions + (otherMonth && !showOtherMonths ? " " : // display for other months + (unselectable ? "<span class='ui-state-default'>" + printDate.getDate() + "</span>" : "<a class='ui-state-default" + + (printDate.getTime() === today.getTime() ? " ui-state-highlight" : "") + + (printDate.getTime() === currentDate.getTime() ? " ui-state-active" : "") + // highlight selected day + (otherMonth ? " ui-priority-secondary" : "") + // distinguish dates from other months + "' href='#'>" + printDate.getDate() + "</a>")) + "</td>"; // display selectable date printDate.setDate(printDate.getDate() + 1); printDate = this._daylightSavingAdjust(printDate); } - calender += tbody + '</tr>'; + calender += tbody + "</tr>"; } drawMonth++; if (drawMonth > 11) { drawMonth = 0; drawYear++; } - calender += '</tbody></table>' + (isMultiMonth ? '</div>' + - ((numMonths[0] > 0 && col == numMonths[1]-1) ? '<div class="ui-datepicker-row-break"></div>' : '') : ''); + calender += "</tbody></table>" + (isMultiMonth ? "</div>" + + ((numMonths[0] > 0 && col === numMonths[1]-1) ? "<div class='ui-datepicker-row-break'></div>" : "") : ""); group += calender; } html += group; } - html += buttonPanel + ($.ui.ie6 && !inst.inline ? - '<iframe src="javascript:false;" class="ui-datepicker-cover" frameborder="0"></iframe>' : ''); + html += buttonPanel; inst._keyEvent = false; return html; }, @@ -8823,108 +9345,116 @@ $.extend(Datepicker.prototype, { /* Generate the month and year header. */ _generateMonthYearHeader: function(inst, drawMonth, drawYear, minDate, maxDate, secondary, monthNames, monthNamesShort) { - var changeMonth = this._get(inst, 'changeMonth'); - var changeYear = this._get(inst, 'changeYear'); - var showMonthAfterYear = this._get(inst, 'showMonthAfterYear'); - var html = '<div class="ui-datepicker-title">'; - var monthHtml = ''; + + var inMinYear, inMaxYear, month, years, thisYear, determineYear, year, endYear, + changeMonth = this._get(inst, "changeMonth"), + changeYear = this._get(inst, "changeYear"), + showMonthAfterYear = this._get(inst, "showMonthAfterYear"), + html = "<div class='ui-datepicker-title'>", + monthHtml = ""; + // month selection - if (secondary || !changeMonth) - monthHtml += '<span class="ui-datepicker-month">' + monthNames[drawMonth] + '</span>'; - else { - var inMinYear = (minDate && minDate.getFullYear() == drawYear); - var inMaxYear = (maxDate && maxDate.getFullYear() == drawYear); - monthHtml += '<select class="ui-datepicker-month" data-handler="selectMonth" data-event="change">'; - for (var month = 0; month < 12; month++) { - if ((!inMinYear || month >= minDate.getMonth()) && - (!inMaxYear || month <= maxDate.getMonth())) - monthHtml += '<option value="' + month + '"' + - (month == drawMonth ? ' selected="selected"' : '') + - '>' + monthNamesShort[month] + '</option>'; - } - monthHtml += '</select>'; - } - if (!showMonthAfterYear) - html += monthHtml + (secondary || !(changeMonth && changeYear) ? ' ' : ''); + if (secondary || !changeMonth) { + monthHtml += "<span class='ui-datepicker-month'>" + monthNames[drawMonth] + "</span>"; + } else { + inMinYear = (minDate && minDate.getFullYear() === drawYear); + inMaxYear = (maxDate && maxDate.getFullYear() === drawYear); + monthHtml += "<select class='ui-datepicker-month' data-handler='selectMonth' data-event='change'>"; + for ( month = 0; month < 12; month++) { + if ((!inMinYear || month >= minDate.getMonth()) && (!inMaxYear || month <= maxDate.getMonth())) { + monthHtml += "<option value='" + month + "'" + + (month === drawMonth ? " selected='selected'" : "") + + ">" + monthNamesShort[month] + "</option>"; + } + } + monthHtml += "</select>"; + } + + if (!showMonthAfterYear) { + html += monthHtml + (secondary || !(changeMonth && changeYear) ? " " : ""); + } + // year selection if ( !inst.yearshtml ) { - inst.yearshtml = ''; - if (secondary || !changeYear) - html += '<span class="ui-datepicker-year">' + drawYear + '</span>'; - else { + inst.yearshtml = ""; + if (secondary || !changeYear) { + html += "<span class='ui-datepicker-year'>" + drawYear + "</span>"; + } else { // determine range of years to display - var years = this._get(inst, 'yearRange').split(':'); - var thisYear = new Date().getFullYear(); - var determineYear = function(value) { - var year = (value.match(/c[+-].*/) ? drawYear + parseInt(value.substring(1), 10) : - (value.match(/[+-].*/) ? thisYear + parseInt(value, 10) : + years = this._get(inst, "yearRange").split(":"); + thisYear = new Date().getFullYear(); + determineYear = function(value) { + var year = (value.match(/c[+\-].*/) ? drawYear + parseInt(value.substring(1), 10) : + (value.match(/[+\-].*/) ? thisYear + parseInt(value, 10) : parseInt(value, 10))); return (isNaN(year) ? thisYear : year); }; - var year = determineYear(years[0]); - var endYear = Math.max(year, determineYear(years[1] || '')); + year = determineYear(years[0]); + endYear = Math.max(year, determineYear(years[1] || "")); year = (minDate ? Math.max(year, minDate.getFullYear()) : year); endYear = (maxDate ? Math.min(endYear, maxDate.getFullYear()) : endYear); - inst.yearshtml += '<select class="ui-datepicker-year" data-handler="selectYear" data-event="change">'; + inst.yearshtml += "<select class='ui-datepicker-year' data-handler='selectYear' data-event='change'>"; for (; year <= endYear; year++) { - inst.yearshtml += '<option value="' + year + '"' + - (year == drawYear ? ' selected="selected"' : '') + - '>' + year + '</option>'; + inst.yearshtml += "<option value='" + year + "'" + + (year === drawYear ? " selected='selected'" : "") + + ">" + year + "</option>"; } - inst.yearshtml += '</select>'; + inst.yearshtml += "</select>"; html += inst.yearshtml; inst.yearshtml = null; } } - html += this._get(inst, 'yearSuffix'); - if (showMonthAfterYear) - html += (secondary || !(changeMonth && changeYear) ? ' ' : '') + monthHtml; - html += '</div>'; // Close datepicker_header + + html += this._get(inst, "yearSuffix"); + if (showMonthAfterYear) { + html += (secondary || !(changeMonth && changeYear) ? " " : "") + monthHtml; + } + html += "</div>"; // Close datepicker_header return html; }, /* Adjust one of the date sub-fields. */ _adjustInstDate: function(inst, offset, period) { - var year = inst.drawYear + (period == 'Y' ? offset : 0); - var month = inst.drawMonth + (period == 'M' ? offset : 0); - var day = Math.min(inst.selectedDay, this._getDaysInMonth(year, month)) + - (period == 'D' ? offset : 0); - var date = this._restrictMinMax(inst, - this._daylightSavingAdjust(new Date(year, month, day))); + var year = inst.drawYear + (period === "Y" ? offset : 0), + month = inst.drawMonth + (period === "M" ? offset : 0), + day = Math.min(inst.selectedDay, this._getDaysInMonth(year, month)) + (period === "D" ? offset : 0), + date = this._restrictMinMax(inst, this._daylightSavingAdjust(new Date(year, month, day))); + inst.selectedDay = date.getDate(); inst.drawMonth = inst.selectedMonth = date.getMonth(); inst.drawYear = inst.selectedYear = date.getFullYear(); - if (period == 'M' || period == 'Y') + if (period === "M" || period === "Y") { this._notifyChange(inst); + } }, /* Ensure a date is within any min/max bounds. */ _restrictMinMax: function(inst, date) { - var minDate = this._getMinMaxDate(inst, 'min'); - var maxDate = this._getMinMaxDate(inst, 'max'); - var newDate = (minDate && date < minDate ? minDate : date); - newDate = (maxDate && newDate > maxDate ? maxDate : newDate); - return newDate; + var minDate = this._getMinMaxDate(inst, "min"), + maxDate = this._getMinMaxDate(inst, "max"), + newDate = (minDate && date < minDate ? minDate : date); + return (maxDate && newDate > maxDate ? maxDate : newDate); }, /* Notify change of month/year. */ _notifyChange: function(inst) { - var onChange = this._get(inst, 'onChangeMonthYear'); - if (onChange) + var onChange = this._get(inst, "onChangeMonthYear"); + if (onChange) { onChange.apply((inst.input ? inst.input[0] : null), [inst.selectedYear, inst.selectedMonth + 1, inst]); + } }, /* Determine the number of months to show. */ _getNumberOfMonths: function(inst) { - var numMonths = this._get(inst, 'numberOfMonths'); - return (numMonths == null ? [1, 1] : (typeof numMonths == 'number' ? [1, numMonths] : numMonths)); + var numMonths = this._get(inst, "numberOfMonths"); + return (numMonths == null ? [1, 1] : (typeof numMonths === "number" ? [1, numMonths] : numMonths)); }, /* Determine the current maximum date - ensure no time components are set. */ _getMinMaxDate: function(inst, minMax) { - return this._determineDate(inst, this._get(inst, minMax + 'Date'), null); + return this._determineDate(inst, this._get(inst, minMax + "Date"), null); }, /* Find the number of days in a given month. */ @@ -8939,30 +9469,51 @@ $.extend(Datepicker.prototype, { /* Determines if we should allow a "next/prev" month display change. */ _canAdjustMonth: function(inst, offset, curYear, curMonth) { - var numMonths = this._getNumberOfMonths(inst); - var date = this._daylightSavingAdjust(new Date(curYear, + var numMonths = this._getNumberOfMonths(inst), + date = this._daylightSavingAdjust(new Date(curYear, curMonth + (offset < 0 ? offset : numMonths[0] * numMonths[1]), 1)); - if (offset < 0) + + if (offset < 0) { date.setDate(this._getDaysInMonth(date.getFullYear(), date.getMonth())); + } return this._isInRange(inst, date); }, /* Is the given date in the accepted range? */ _isInRange: function(inst, date) { - var minDate = this._getMinMaxDate(inst, 'min'); - var maxDate = this._getMinMaxDate(inst, 'max'); + var yearSplit, currentYear, + minDate = this._getMinMaxDate(inst, "min"), + maxDate = this._getMinMaxDate(inst, "max"), + minYear = null, + maxYear = null, + years = this._get(inst, "yearRange"); + if (years){ + yearSplit = years.split(":"); + currentYear = new Date().getFullYear(); + minYear = parseInt(yearSplit[0], 10); + maxYear = parseInt(yearSplit[1], 10); + if ( yearSplit[0].match(/[+\-].*/) ) { + minYear += currentYear; + } + if ( yearSplit[1].match(/[+\-].*/) ) { + maxYear += currentYear; + } + } + return ((!minDate || date.getTime() >= minDate.getTime()) && - (!maxDate || date.getTime() <= maxDate.getTime())); + (!maxDate || date.getTime() <= maxDate.getTime()) && + (!minYear || date.getFullYear() >= minYear) && + (!maxYear || date.getFullYear() <= maxYear)); }, /* Provide the configuration settings for formatting/parsing. */ _getFormatConfig: function(inst) { - var shortYearCutoff = this._get(inst, 'shortYearCutoff'); - shortYearCutoff = (typeof shortYearCutoff != 'string' ? shortYearCutoff : + var shortYearCutoff = this._get(inst, "shortYearCutoff"); + shortYearCutoff = (typeof shortYearCutoff !== "string" ? shortYearCutoff : new Date().getFullYear() % 100 + parseInt(shortYearCutoff, 10)); return {shortYearCutoff: shortYearCutoff, - dayNamesShort: this._get(inst, 'dayNamesShort'), dayNames: this._get(inst, 'dayNames'), - monthNamesShort: this._get(inst, 'monthNamesShort'), monthNames: this._get(inst, 'monthNames')}; + dayNamesShort: this._get(inst, "dayNamesShort"), dayNames: this._get(inst, "dayNames"), + monthNamesShort: this._get(inst, "monthNamesShort"), monthNames: this._get(inst, "monthNames")}; }, /* Format the given date for display. */ @@ -8972,10 +9523,10 @@ $.extend(Datepicker.prototype, { inst.currentMonth = inst.selectedMonth; inst.currentYear = inst.selectedYear; } - var date = (day ? (typeof day == 'object' ? day : + var date = (day ? (typeof day === "object" ? day : this._daylightSavingAdjust(new Date(year, month, day))) : this._daylightSavingAdjust(new Date(inst.currentYear, inst.currentMonth, inst.currentDay))); - return this.formatDate(this._get(inst, 'dateFormat'), date, this._getFormatConfig(inst)); + return this.formatDate(this._get(inst, "dateFormat"), date, this._getFormatConfig(inst)); } }); @@ -8985,18 +9536,26 @@ $.extend(Datepicker.prototype, { * Global instActive, set by _updateDatepicker allows the handlers to find their way back to the active picker. */ function bindHover(dpDiv) { - var selector = 'button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a'; - return dpDiv.delegate(selector, 'mouseout', function() { - $(this).removeClass('ui-state-hover'); - if (this.className.indexOf('ui-datepicker-prev') != -1) $(this).removeClass('ui-datepicker-prev-hover'); - if (this.className.indexOf('ui-datepicker-next') != -1) $(this).removeClass('ui-datepicker-next-hover'); + var selector = "button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a"; + return dpDiv.delegate(selector, "mouseout", function() { + $(this).removeClass("ui-state-hover"); + if (this.className.indexOf("ui-datepicker-prev") !== -1) { + $(this).removeClass("ui-datepicker-prev-hover"); + } + if (this.className.indexOf("ui-datepicker-next") !== -1) { + $(this).removeClass("ui-datepicker-next-hover"); + } }) - .delegate(selector, 'mouseover', function(){ + .delegate(selector, "mouseover", function(){ if (!$.datepicker._isDisabledDatepicker( instActive.inline ? dpDiv.parent()[0] : instActive.input[0])) { - $(this).parents('.ui-datepicker-calendar').find('a').removeClass('ui-state-hover'); - $(this).addClass('ui-state-hover'); - if (this.className.indexOf('ui-datepicker-prev') != -1) $(this).addClass('ui-datepicker-prev-hover'); - if (this.className.indexOf('ui-datepicker-next') != -1) $(this).addClass('ui-datepicker-next-hover'); + $(this).parents(".ui-datepicker-calendar").find("a").removeClass("ui-state-hover"); + $(this).addClass("ui-state-hover"); + if (this.className.indexOf("ui-datepicker-prev") !== -1) { + $(this).addClass("ui-datepicker-prev-hover"); + } + if (this.className.indexOf("ui-datepicker-next") !== -1) { + $(this).addClass("ui-datepicker-next-hover"); + } } }); } @@ -9004,15 +9563,17 @@ function bindHover(dpDiv) { /* jQuery extend now ignores nulls! */ function extendRemove(target, props) { $.extend(target, props); - for (var name in props) - if (props[name] == null || props[name] == undefined) + for (var name in props) { + if (props[name] == null) { target[name] = props[name]; + } + } return target; -}; +} /* Invoke the datepicker functionality. @param options string - a command, optionally followed by additional parameters or - Object - settings for attaching new datepicker functionality + Object - settings for attaching new datepicker functionality @return jQuery object */ $.fn.datepicker = function(options){ @@ -9023,21 +9584,27 @@ $.fn.datepicker = function(options){ /* Initialise the date picker. */ if (!$.datepicker.initialized) { - $(document).mousedown($.datepicker._checkExternalClick). - find(document.body).append($.datepicker.dpDiv); + $(document).mousedown($.datepicker._checkExternalClick); $.datepicker.initialized = true; } + /* Append datepicker main container to body if not exist. */ + if ($("#"+$.datepicker._mainDivId).length === 0) { + $("body").append($.datepicker.dpDiv); + } + var otherArgs = Array.prototype.slice.call(arguments, 1); - if (typeof options == 'string' && (options == 'isDisabled' || options == 'getDate' || options == 'widget')) - return $.datepicker['_' + options + 'Datepicker']. + if (typeof options === "string" && (options === "isDisabled" || options === "getDate" || options === "widget")) { + return $.datepicker["_" + options + "Datepicker"]. apply($.datepicker, [this[0]].concat(otherArgs)); - if (options == 'option' && arguments.length == 2 && typeof arguments[1] == 'string') - return $.datepicker['_' + options + 'Datepicker']. + } + if (options === "option" && arguments.length === 2 && typeof arguments[1] === "string") { + return $.datepicker["_" + options + "Datepicker"]. apply($.datepicker, [this[0]].concat(otherArgs)); + } return this.each(function() { - typeof options == 'string' ? - $.datepicker['_' + options + 'Datepicker']. + typeof options === "string" ? + $.datepicker["_" + options + "Datepicker"]. apply($.datepicker, [this].concat(otherArgs)) : $.datepicker._attachDatepicker(this, options); }); @@ -9046,18 +9613,17 @@ $.fn.datepicker = function(options){ $.datepicker = new Datepicker(); // singleton instance $.datepicker.initialized = false; $.datepicker.uuid = new Date().getTime(); -$.datepicker.version = "1.9.2"; +$.datepicker.version = "1.10.2"; // Workaround for #4055 // Add another global to avoid noConflict issues with inline event handlers -window['DP_jQuery_' + dpuuid] = $; +window["DP_jQuery_" + dpuuid] = $; })(jQuery); (function( $, undefined ) { -var uiDialogClasses = "ui-dialog ui-widget ui-widget-content ui-corner-all ", - sizeRelatedOptions = { +var sizeRelatedOptions = { buttons: true, height: true, maxHeight: true, @@ -9073,19 +9639,20 @@ var uiDialogClasses = "ui-dialog ui-widget ui-widget-content ui-corner-all ", minWidth: true }; -$.widget("ui.dialog", { - version: "1.9.2", +$.widget( "ui.dialog", { + version: "1.10.2", options: { + appendTo: "body", autoOpen: true, - buttons: {}, + buttons: [], closeOnEscape: true, closeText: "close", dialogClass: "", draggable: true, hide: null, height: "auto", - maxHeight: false, - maxWidth: false, + maxHeight: null, + maxWidth: null, minHeight: 150, minWidth: 150, modal: false, @@ -9094,7 +9661,7 @@ $.widget("ui.dialog", { at: "center", of: window, collision: "fit", - // ensure that the titlebar is never outside the document + // Ensure the titlebar is always visible using: function( pos ) { var topOffset = $( this ).css( pos ).offset().top; if ( topOffset < 0 ) { @@ -9104,137 +9671,56 @@ $.widget("ui.dialog", { }, resizable: true, show: null, - stack: true, - title: "", + title: null, width: 300, - zIndex: 1000 + + // callbacks + beforeClose: null, + close: null, + drag: null, + dragStart: null, + dragStop: null, + focus: null, + open: null, + resize: null, + resizeStart: null, + resizeStop: null }, _create: function() { - this.originalTitle = this.element.attr( "title" ); - // #5742 - .attr() might return a DOMElement - if ( typeof this.originalTitle !== "string" ) { - this.originalTitle = ""; - } - this.oldPosition = { + this.originalCss = { + display: this.element[0].style.display, + width: this.element[0].style.width, + minHeight: this.element[0].style.minHeight, + maxHeight: this.element[0].style.maxHeight, + height: this.element[0].style.height + }; + this.originalPosition = { parent: this.element.parent(), index: this.element.parent().children().index( this.element ) }; + this.originalTitle = this.element.attr("title"); this.options.title = this.options.title || this.originalTitle; - var that = this, - options = this.options, - - title = options.title || " ", - uiDialog, - uiDialogTitlebar, - uiDialogTitlebarClose, - uiDialogTitle, - uiDialogButtonPane; - uiDialog = ( this.uiDialog = $( "<div>" ) ) - .addClass( uiDialogClasses + options.dialogClass ) - .css({ - display: "none", - outline: 0, // TODO: move to stylesheet - zIndex: options.zIndex - }) - // setting tabIndex makes the div focusable - .attr( "tabIndex", -1) - .keydown(function( event ) { - if ( options.closeOnEscape && !event.isDefaultPrevented() && event.keyCode && - event.keyCode === $.ui.keyCode.ESCAPE ) { - that.close( event ); - event.preventDefault(); - } - }) - .mousedown(function( event ) { - that.moveToTop( false, event ); - }) - .appendTo( "body" ); - - this.element - .show() - .removeAttr( "title" ) - .addClass( "ui-dialog-content ui-widget-content" ) - .appendTo( uiDialog ); - - uiDialogTitlebar = ( this.uiDialogTitlebar = $( "<div>" ) ) - .addClass( "ui-dialog-titlebar ui-widget-header " + - "ui-corner-all ui-helper-clearfix" ) - .bind( "mousedown", function() { - // Dialog isn't getting focus when dragging (#8063) - uiDialog.focus(); - }) - .prependTo( uiDialog ); + this._createWrapper(); - uiDialogTitlebarClose = $( "<a href='#'></a>" ) - .addClass( "ui-dialog-titlebar-close ui-corner-all" ) - .attr( "role", "button" ) - .click(function( event ) { - event.preventDefault(); - that.close( event ); - }) - .appendTo( uiDialogTitlebar ); - - ( this.uiDialogTitlebarCloseText = $( "<span>" ) ) - .addClass( "ui-icon ui-icon-closethick" ) - .text( options.closeText ) - .appendTo( uiDialogTitlebarClose ); - - uiDialogTitle = $( "<span>" ) - .uniqueId() - .addClass( "ui-dialog-title" ) - .html( title ) - .prependTo( uiDialogTitlebar ); - - uiDialogButtonPane = ( this.uiDialogButtonPane = $( "<div>" ) ) - .addClass( "ui-dialog-buttonpane ui-widget-content ui-helper-clearfix" ); - - ( this.uiButtonSet = $( "<div>" ) ) - .addClass( "ui-dialog-buttonset" ) - .appendTo( uiDialogButtonPane ); - - uiDialog.attr({ - role: "dialog", - "aria-labelledby": uiDialogTitle.attr( "id" ) - }); + this.element + .show() + .removeAttr("title") + .addClass("ui-dialog-content ui-widget-content") + .appendTo( this.uiDialog ); - uiDialogTitlebar.find( "*" ).add( uiDialogTitlebar ).disableSelection(); - this._hoverable( uiDialogTitlebarClose ); - this._focusable( uiDialogTitlebarClose ); + this._createTitlebar(); + this._createButtonPane(); - if ( options.draggable && $.fn.draggable ) { + if ( this.options.draggable && $.fn.draggable ) { this._makeDraggable(); } - if ( options.resizable && $.fn.resizable ) { + if ( this.options.resizable && $.fn.resizable ) { this._makeResizable(); } - this._createButtons( options.buttons ); this._isOpen = false; - - if ( $.fn.bgiframe ) { - uiDialog.bgiframe(); - } - - // prevent tabbing out of modal dialogs - this._on( uiDialog, { keydown: function( event ) { - if ( !options.modal || event.keyCode !== $.ui.keyCode.TAB ) { - return; - } - - var tabbables = $( ":tabbable", uiDialog ), - first = tabbables.filter( ":first" ), - last = tabbables.filter( ":last" ); - - if ( event.target === last[0] && !event.shiftKey ) { - first.focus( 1 ); - return false; - } else if ( event.target === first[0] && event.shiftKey ) { - last.focus( 1 ); - return false; - } - }}); }, _init: function() { @@ -9243,30 +9729,39 @@ $.widget("ui.dialog", { } }, + _appendTo: function() { + var element = this.options.appendTo; + if ( element && (element.jquery || element.nodeType) ) { + return $( element ); + } + return this.document.find( element || "body" ).eq( 0 ); + }, + _destroy: function() { var next, - oldPosition = this.oldPosition; + originalPosition = this.originalPosition; + + this._destroyOverlay(); - if ( this.overlay ) { - this.overlay.destroy(); - } - this.uiDialog.hide(); this.element - .removeClass( "ui-dialog-content ui-widget-content" ) - .hide() - .appendTo( "body" ); - this.uiDialog.remove(); + .removeUniqueId() + .removeClass("ui-dialog-content ui-widget-content") + .css( this.originalCss ) + // Without detaching first, the following becomes really slow + .detach(); + + this.uiDialog.stop( true, true ).remove(); if ( this.originalTitle ) { this.element.attr( "title", this.originalTitle ); } - next = oldPosition.parent.children().eq( oldPosition.index ); + next = originalPosition.parent.children().eq( originalPosition.index ); // Don't try to place the dialog next to itself (#8613) - if ( next.length && next[ 0 ] !== this.element[ 0 ] ) { + if ( next.length && next[0] !== this.element[0] ) { next.before( this.element ); } else { - oldPosition.parent.append( this.element ); + originalPosition.parent.append( this.element ); } }, @@ -9274,160 +9769,266 @@ $.widget("ui.dialog", { return this.uiDialog; }, - close: function( event ) { - var that = this, - maxZ, thisZ; + disable: $.noop, + enable: $.noop, - if ( !this._isOpen ) { - return; - } + close: function( event ) { + var that = this; - if ( false === this._trigger( "beforeClose", event ) ) { + if ( !this._isOpen || this._trigger( "beforeClose", event ) === false ) { return; } this._isOpen = false; + this._destroyOverlay(); - if ( this.overlay ) { - this.overlay.destroy(); - } - - if ( this.options.hide ) { - this._hide( this.uiDialog, this.options.hide, function() { - that._trigger( "close", event ); - }); - } else { - this.uiDialog.hide(); - this._trigger( "close", event ); - } - - $.ui.dialog.overlay.resize(); - - // adjust the maxZ to allow other modal dialogs to continue to work (see #4309) - if ( this.options.modal ) { - maxZ = 0; - $( ".ui-dialog" ).each(function() { - if ( this !== that.uiDialog[0] ) { - thisZ = $( this ).css( "z-index" ); - if ( !isNaN( thisZ ) ) { - maxZ = Math.max( maxZ, thisZ ); - } - } - }); - $.ui.dialog.maxZ = maxZ; + if ( !this.opener.filter(":focusable").focus().length ) { + // Hiding a focused element doesn't trigger blur in WebKit + // so in case we have nothing to focus on, explicitly blur the active element + // https://bugs.webkit.org/show_bug.cgi?id=47182 + $( this.document[0].activeElement ).blur(); } - return this; + this._hide( this.uiDialog, this.options.hide, function() { + that._trigger( "close", event ); + }); }, isOpen: function() { return this._isOpen; }, - // the force parameter allows us to move modal dialogs to their correct - // position on open - moveToTop: function( force, event ) { - var options = this.options, - saveScroll; - - if ( ( options.modal && !force ) || - ( !options.stack && !options.modal ) ) { - return this._trigger( "focus", event ); - } + moveToTop: function() { + this._moveToTop(); + }, - if ( options.zIndex > $.ui.dialog.maxZ ) { - $.ui.dialog.maxZ = options.zIndex; + _moveToTop: function( event, silent ) { + var moved = !!this.uiDialog.nextAll(":visible").insertBefore( this.uiDialog ).length; + if ( moved && !silent ) { + this._trigger( "focus", event ); } - if ( this.overlay ) { - $.ui.dialog.maxZ += 1; - $.ui.dialog.overlay.maxZ = $.ui.dialog.maxZ; - this.overlay.$el.css( "z-index", $.ui.dialog.overlay.maxZ ); - } - - // Save and then restore scroll - // Opera 9.5+ resets when parent z-index is changed. - // http://bugs.jqueryui.com/ticket/3193 - saveScroll = { - scrollTop: this.element.scrollTop(), - scrollLeft: this.element.scrollLeft() - }; - $.ui.dialog.maxZ += 1; - this.uiDialog.css( "z-index", $.ui.dialog.maxZ ); - this.element.attr( saveScroll ); - this._trigger( "focus", event ); - - return this; + return moved; }, open: function() { + var that = this; if ( this._isOpen ) { + if ( this._moveToTop() ) { + this._focusTabbable(); + } return; } - var hasFocus, - options = this.options, - uiDialog = this.uiDialog; + this._isOpen = true; + this.opener = $( this.document[0].activeElement ); this._size(); - this._position( options.position ); - uiDialog.show( options.show ); - this.overlay = options.modal ? new $.ui.dialog.overlay( this ) : null; - this.moveToTop( true ); - - // set focus to the first tabbable element in the content area or the first button - // if there are no tabbable elements, set focus on the dialog itself - hasFocus = this.element.find( ":tabbable" ); + this._position(); + this._createOverlay(); + this._moveToTop( null, true ); + this._show( this.uiDialog, this.options.show, function() { + that._focusTabbable(); + that._trigger("focus"); + }); + + this._trigger("open"); + }, + + _focusTabbable: function() { + // Set focus to the first match: + // 1. First element inside the dialog matching [autofocus] + // 2. Tabbable element inside the content element + // 3. Tabbable element inside the buttonpane + // 4. The close button + // 5. The dialog itself + var hasFocus = this.element.find("[autofocus]"); if ( !hasFocus.length ) { - hasFocus = this.uiDialogButtonPane.find( ":tabbable" ); - if ( !hasFocus.length ) { - hasFocus = uiDialog; - } + hasFocus = this.element.find(":tabbable"); + } + if ( !hasFocus.length ) { + hasFocus = this.uiDialogButtonPane.find(":tabbable"); + } + if ( !hasFocus.length ) { + hasFocus = this.uiDialogTitlebarClose.filter(":tabbable"); + } + if ( !hasFocus.length ) { + hasFocus = this.uiDialog; } hasFocus.eq( 0 ).focus(); + }, - this._isOpen = true; - this._trigger( "open" ); + _keepFocus: function( event ) { + function checkFocus() { + var activeElement = this.document[0].activeElement, + isActive = this.uiDialog[0] === activeElement || + $.contains( this.uiDialog[0], activeElement ); + if ( !isActive ) { + this._focusTabbable(); + } + } + event.preventDefault(); + checkFocus.call( this ); + // support: IE + // IE <= 8 doesn't prevent moving focus even with event.preventDefault() + // so we check again later + this._delay( checkFocus ); + }, - return this; + _createWrapper: function() { + this.uiDialog = $("<div>") + .addClass( "ui-dialog ui-widget ui-widget-content ui-corner-all ui-front " + + this.options.dialogClass ) + .hide() + .attr({ + // Setting tabIndex makes the div focusable + tabIndex: -1, + role: "dialog" + }) + .appendTo( this._appendTo() ); + + this._on( this.uiDialog, { + keydown: function( event ) { + if ( this.options.closeOnEscape && !event.isDefaultPrevented() && event.keyCode && + event.keyCode === $.ui.keyCode.ESCAPE ) { + event.preventDefault(); + this.close( event ); + return; + } + + // prevent tabbing out of dialogs + if ( event.keyCode !== $.ui.keyCode.TAB ) { + return; + } + var tabbables = this.uiDialog.find(":tabbable"), + first = tabbables.filter(":first"), + last = tabbables.filter(":last"); + + if ( ( event.target === last[0] || event.target === this.uiDialog[0] ) && !event.shiftKey ) { + first.focus( 1 ); + event.preventDefault(); + } else if ( ( event.target === first[0] || event.target === this.uiDialog[0] ) && event.shiftKey ) { + last.focus( 1 ); + event.preventDefault(); + } + }, + mousedown: function( event ) { + if ( this._moveToTop( event ) ) { + this._focusTabbable(); + } + } + }); + + // We assume that any existing aria-describedby attribute means + // that the dialog content is marked up properly + // otherwise we brute force the content as the description + if ( !this.element.find("[aria-describedby]").length ) { + this.uiDialog.attr({ + "aria-describedby": this.element.uniqueId().attr("id") + }); + } }, - _createButtons: function( buttons ) { + _createTitlebar: function() { + var uiDialogTitle; + + this.uiDialogTitlebar = $("<div>") + .addClass("ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix") + .prependTo( this.uiDialog ); + this._on( this.uiDialogTitlebar, { + mousedown: function( event ) { + // Don't prevent click on close button (#8838) + // Focusing a dialog that is partially scrolled out of view + // causes the browser to scroll it into view, preventing the click event + if ( !$( event.target ).closest(".ui-dialog-titlebar-close") ) { + // Dialog isn't getting focus when dragging (#8063) + this.uiDialog.focus(); + } + } + }); + + this.uiDialogTitlebarClose = $("<button></button>") + .button({ + label: this.options.closeText, + icons: { + primary: "ui-icon-closethick" + }, + text: false + }) + .addClass("ui-dialog-titlebar-close") + .appendTo( this.uiDialogTitlebar ); + this._on( this.uiDialogTitlebarClose, { + click: function( event ) { + event.preventDefault(); + this.close( event ); + } + }); + + uiDialogTitle = $("<span>") + .uniqueId() + .addClass("ui-dialog-title") + .prependTo( this.uiDialogTitlebar ); + this._title( uiDialogTitle ); + + this.uiDialog.attr({ + "aria-labelledby": uiDialogTitle.attr("id") + }); + }, + + _title: function( title ) { + if ( !this.options.title ) { + title.html(" "); + } + title.text( this.options.title ); + }, + + _createButtonPane: function() { + this.uiDialogButtonPane = $("<div>") + .addClass("ui-dialog-buttonpane ui-widget-content ui-helper-clearfix"); + + this.uiButtonSet = $("<div>") + .addClass("ui-dialog-buttonset") + .appendTo( this.uiDialogButtonPane ); + + this._createButtons(); + }, + + _createButtons: function() { var that = this, - hasButtons = false; + buttons = this.options.buttons; // if we already have a button pane, remove it this.uiDialogButtonPane.remove(); this.uiButtonSet.empty(); - if ( typeof buttons === "object" && buttons !== null ) { - $.each( buttons, function() { - return !(hasButtons = true); - }); - } - if ( hasButtons ) { - $.each( buttons, function( name, props ) { - var button, click; - props = $.isFunction( props ) ? - { click: props, text: name } : - props; - // Default to a non-submitting button - props = $.extend( { type: "button" }, props ); - // Change the context for the click callback to be the main element - click = props.click; - props.click = function() { - click.apply( that.element[0], arguments ); - }; - button = $( "<button></button>", props ) - .appendTo( that.uiButtonSet ); - if ( $.fn.button ) { - button.button(); - } - }); - this.uiDialog.addClass( "ui-dialog-buttons" ); - this.uiDialogButtonPane.appendTo( this.uiDialog ); - } else { - this.uiDialog.removeClass( "ui-dialog-buttons" ); + if ( $.isEmptyObject( buttons ) || ($.isArray( buttons ) && !buttons.length) ) { + this.uiDialog.removeClass("ui-dialog-buttons"); + return; } + + $.each( buttons, function( name, props ) { + var click, buttonOptions; + props = $.isFunction( props ) ? + { click: props, text: name } : + props; + // Default to a non-submitting button + props = $.extend( { type: "button" }, props ); + // Change the context for the click callback to be the main element + click = props.click; + props.click = function() { + click.apply( that.element[0], arguments ); + }; + buttonOptions = { + icons: props.icons, + text: props.showText + }; + delete props.icons; + delete props.showText; + $( "<button></button>", props ) + .button( buttonOptions ) + .appendTo( that.uiButtonSet ); + }); + this.uiDialog.addClass("ui-dialog-buttons"); + this.uiDialogButtonPane.appendTo( this.uiDialog ); }, _makeDraggable: function() { @@ -9446,8 +10047,8 @@ $.widget("ui.dialog", { handle: ".ui-dialog-titlebar", containment: "document", start: function( event, ui ) { - $( this ) - .addClass( "ui-dialog-dragging" ); + $( this ).addClass("ui-dialog-dragging"); + that._blockFrames(); that._trigger( "dragStart", event, filteredUi( ui ) ); }, drag: function( event, ui ) { @@ -9458,22 +10059,21 @@ $.widget("ui.dialog", { ui.position.left - that.document.scrollLeft(), ui.position.top - that.document.scrollTop() ]; - $( this ) - .removeClass( "ui-dialog-dragging" ); + $( this ).removeClass("ui-dialog-dragging"); + that._unblockFrames(); that._trigger( "dragStop", event, filteredUi( ui ) ); - $.ui.dialog.overlay.resize(); } }); }, - _makeResizable: function( handles ) { - handles = (handles === undefined ? this.options.resizable : handles); + _makeResizable: function() { var that = this, options = this.options, + handles = options.resizable, // .ui-resizable has position: relative defined in the stylesheet // but dialogs have to use absolute or fixed positioning - position = this.uiDialog.css( "position" ), - resizeHandles = typeof handles === 'string' ? + position = this.uiDialog.css("position"), + resizeHandles = typeof handles === "string" ? handles : "n,e,s,w,se,sw,ne,nw"; @@ -9496,76 +10096,39 @@ $.widget("ui.dialog", { minHeight: this._minHeight(), handles: resizeHandles, start: function( event, ui ) { - $( this ).addClass( "ui-dialog-resizing" ); + $( this ).addClass("ui-dialog-resizing"); + that._blockFrames(); that._trigger( "resizeStart", event, filteredUi( ui ) ); }, resize: function( event, ui ) { that._trigger( "resize", event, filteredUi( ui ) ); }, stop: function( event, ui ) { - $( this ).removeClass( "ui-dialog-resizing" ); options.height = $( this ).height(); options.width = $( this ).width(); + $( this ).removeClass("ui-dialog-resizing"); + that._unblockFrames(); that._trigger( "resizeStop", event, filteredUi( ui ) ); - $.ui.dialog.overlay.resize(); } }) - .css( "position", position ) - .find( ".ui-resizable-se" ) - .addClass( "ui-icon ui-icon-grip-diagonal-se" ); + .css( "position", position ); }, _minHeight: function() { var options = this.options; - if ( options.height === "auto" ) { - return options.minHeight; - } else { - return Math.min( options.minHeight, options.height ); - } + return options.height === "auto" ? + options.minHeight : + Math.min( options.minHeight, options.height ); }, - _position: function( position ) { - var myAt = [], - offset = [ 0, 0 ], - isVisible; - - if ( position ) { - // deep extending converts arrays to objects in jQuery <= 1.3.2 :-( - // if (typeof position == 'string' || $.isArray(position)) { - // myAt = $.isArray(position) ? position : position.split(' '); - - if ( typeof position === "string" || (typeof position === "object" && "0" in position ) ) { - myAt = position.split ? position.split( " " ) : [ position[ 0 ], position[ 1 ] ]; - if ( myAt.length === 1 ) { - myAt[ 1 ] = myAt[ 0 ]; - } - - $.each( [ "left", "top" ], function( i, offsetPosition ) { - if ( +myAt[ i ] === myAt[ i ] ) { - offset[ i ] = myAt[ i ]; - myAt[ i ] = offsetPosition; - } - }); - - position = { - my: myAt[0] + (offset[0] < 0 ? offset[0] : "+" + offset[0]) + " " + - myAt[1] + (offset[1] < 0 ? offset[1] : "+" + offset[1]), - at: myAt.join( " " ) - }; - } - - position = $.extend( {}, $.ui.dialog.prototype.options.position, position ); - } else { - position = $.ui.dialog.prototype.options.position; - } - - // need to show the dialog to get the actual offset in the position plugin - isVisible = this.uiDialog.is( ":visible" ); + _position: function() { + // Need to show the dialog to get the actual offset in the position plugin + var isVisible = this.uiDialog.is(":visible"); if ( !isVisible ) { this.uiDialog.show(); } - this.uiDialog.position( position ); + this.uiDialog.position( this.options.position ); if ( !isVisible ) { this.uiDialog.hide(); } @@ -9573,8 +10136,8 @@ $.widget("ui.dialog", { _setOptions: function( options ) { var that = this, - resizableOptions = {}, - resize = false; + resize = false, + resizableOptions = {}; $.each( options, function( key, value ) { that._setOption( key, value ); @@ -9589,88 +10152,94 @@ $.widget("ui.dialog", { if ( resize ) { this._size(); + this._position(); } - if ( this.uiDialog.is( ":data(resizable)" ) ) { + if ( this.uiDialog.is(":data(ui-resizable)") ) { this.uiDialog.resizable( "option", resizableOptions ); } }, _setOption: function( key, value ) { + /*jshint maxcomplexity:15*/ var isDraggable, isResizable, uiDialog = this.uiDialog; - switch ( key ) { - case "buttons": - this._createButtons( value ); - break; - case "closeText": - // ensure that we always pass a string - this.uiDialogTitlebarCloseText.text( "" + value ); - break; - case "dialogClass": - uiDialog - .removeClass( this.options.dialogClass ) - .addClass( uiDialogClasses + value ); - break; - case "disabled": - if ( value ) { - uiDialog.addClass( "ui-dialog-disabled" ); - } else { - uiDialog.removeClass( "ui-dialog-disabled" ); - } - break; - case "draggable": - isDraggable = uiDialog.is( ":data(draggable)" ); - if ( isDraggable && !value ) { - uiDialog.draggable( "destroy" ); - } + if ( key === "dialogClass" ) { + uiDialog + .removeClass( this.options.dialogClass ) + .addClass( value ); + } - if ( !isDraggable && value ) { - this._makeDraggable(); - } - break; - case "position": - this._position( value ); - break; - case "resizable": - // currently resizable, becoming non-resizable - isResizable = uiDialog.is( ":data(resizable)" ); - if ( isResizable && !value ) { - uiDialog.resizable( "destroy" ); - } + if ( key === "disabled" ) { + return; + } - // currently resizable, changing handles - if ( isResizable && typeof value === "string" ) { - uiDialog.resizable( "option", "handles", value ); - } + this._super( key, value ); - // currently non-resizable, becoming resizable - if ( !isResizable && value !== false ) { - this._makeResizable( value ); - } - break; - case "title": - // convert whatever was passed in o a string, for html() to not throw up - $( ".ui-dialog-title", this.uiDialogTitlebar ) - .html( "" + ( value || " " ) ); - break; + if ( key === "appendTo" ) { + this.uiDialog.appendTo( this._appendTo() ); } - this._super( key, value ); + if ( key === "buttons" ) { + this._createButtons(); + } + + if ( key === "closeText" ) { + this.uiDialogTitlebarClose.button({ + // Ensure that we always pass a string + label: "" + value + }); + } + + if ( key === "draggable" ) { + isDraggable = uiDialog.is(":data(ui-draggable)"); + if ( isDraggable && !value ) { + uiDialog.draggable("destroy"); + } + + if ( !isDraggable && value ) { + this._makeDraggable(); + } + } + + if ( key === "position" ) { + this._position(); + } + + if ( key === "resizable" ) { + // currently resizable, becoming non-resizable + isResizable = uiDialog.is(":data(ui-resizable)"); + if ( isResizable && !value ) { + uiDialog.resizable("destroy"); + } + + // currently resizable, changing handles + if ( isResizable && typeof value === "string" ) { + uiDialog.resizable( "option", "handles", value ); + } + + // currently non-resizable, becoming resizable + if ( !isResizable && value !== false ) { + this._makeResizable(); + } + } + + if ( key === "title" ) { + this._title( this.uiDialogTitlebar.find(".ui-dialog-title") ); + } }, _size: function() { - /* If the user has resized the dialog, the .ui-dialog and .ui-dialog-content - * divs will both have width and height set, so we need to reset them - */ - var nonContentHeight, minContentHeight, autoHeight, - options = this.options, - isVisible = this.uiDialog.is( ":visible" ); + // If the user has resized the dialog, the .ui-dialog and .ui-dialog-content + // divs will both have width and height set, so we need to reset them + var nonContentHeight, minContentHeight, maxContentHeight, + options = this.options; - // reset content sizing + // Reset content sizing this.element.show().css({ width: "auto", minHeight: 0, + maxHeight: "none", height: 0 }); @@ -9686,211 +10255,159 @@ $.widget("ui.dialog", { }) .outerHeight(); minContentHeight = Math.max( 0, options.minHeight - nonContentHeight ); + maxContentHeight = typeof options.maxHeight === "number" ? + Math.max( 0, options.maxHeight - nonContentHeight ) : + "none"; if ( options.height === "auto" ) { - // only needed for IE6 support - if ( $.support.minHeight ) { - this.element.css({ - minHeight: minContentHeight, - height: "auto" - }); - } else { - this.uiDialog.show(); - autoHeight = this.element.css( "height", "auto" ).height(); - if ( !isVisible ) { - this.uiDialog.hide(); - } - this.element.height( Math.max( autoHeight, minContentHeight ) ); - } + this.element.css({ + minHeight: minContentHeight, + maxHeight: maxContentHeight, + height: "auto" + }); } else { - this.element.height( Math.max( options.height - nonContentHeight, 0 ) ); + this.element.height( Math.max( 0, options.height - nonContentHeight ) ); } - if (this.uiDialog.is( ":data(resizable)" ) ) { + if (this.uiDialog.is(":data(ui-resizable)") ) { this.uiDialog.resizable( "option", "minHeight", this._minHeight() ); } - } -}); + }, -$.extend($.ui.dialog, { - uuid: 0, - maxZ: 0, + _blockFrames: function() { + this.iframeBlocks = this.document.find( "iframe" ).map(function() { + var iframe = $( this ); - getTitleId: function($el) { - var id = $el.attr( "id" ); - if ( !id ) { - this.uuid += 1; - id = this.uuid; + return $( "<div>" ) + .css({ + position: "absolute", + width: iframe.outerWidth(), + height: iframe.outerHeight() + }) + .appendTo( iframe.parent() ) + .offset( iframe.offset() )[0]; + }); + }, + + _unblockFrames: function() { + if ( this.iframeBlocks ) { + this.iframeBlocks.remove(); + delete this.iframeBlocks; } - return "ui-dialog-title-" + id; }, - overlay: function( dialog ) { - this.$el = $.ui.dialog.overlay.create( dialog ); - } -}); + _allowInteraction: function( event ) { + if ( $( event.target ).closest(".ui-dialog").length ) { + return true; + } -$.extend( $.ui.dialog.overlay, { - instances: [], - // reuse old instances due to IE memory leak with alpha transparency (see #5185) - oldInstances: [], - maxZ: 0, - events: $.map( - "focus,mousedown,mouseup,keydown,keypress,click".split( "," ), - function( event ) { - return event + ".dialog-overlay"; - } - ).join( " " ), - create: function( dialog ) { - if ( this.instances.length === 0 ) { - // prevent use of anchors and inputs - // we use a setTimeout in case the overlay is created from an - // event that we're going to be cancelling (see #2804) - setTimeout(function() { - // handle $(el).dialog().dialog('close') (see #4065) - if ( $.ui.dialog.overlay.instances.length ) { - $( document ).bind( $.ui.dialog.overlay.events, function( event ) { - // stop events if the z-index of the target is < the z-index of the overlay - // we cannot return true when we don't want to cancel the event (#3523) - if ( $( event.target ).zIndex() < $.ui.dialog.overlay.maxZ ) { - return false; + // TODO: Remove hack when datepicker implements + // the .ui-front logic (#8989) + return !!$( event.target ).closest(".ui-datepicker").length; + }, + + _createOverlay: function() { + if ( !this.options.modal ) { + return; + } + + var that = this, + widgetFullName = this.widgetFullName; + if ( !$.ui.dialog.overlayInstances ) { + // Prevent use of anchors and inputs. + // We use a delay in case the overlay is created from an + // event that we're going to be cancelling. (#2804) + this._delay(function() { + // Handle .dialog().dialog("close") (#4065) + if ( $.ui.dialog.overlayInstances ) { + this.document.bind( "focusin.dialog", function( event ) { + if ( !that._allowInteraction( event ) ) { + event.preventDefault(); + $(".ui-dialog:visible:last .ui-dialog-content") + .data( widgetFullName )._focusTabbable(); } }); } - }, 1 ); - - // handle window resize - $( window ).bind( "resize.dialog-overlay", $.ui.dialog.overlay.resize ); + }); } - var $el = ( this.oldInstances.pop() || $( "<div>" ).addClass( "ui-widget-overlay" ) ); - - // allow closing by pressing the escape key - $( document ).bind( "keydown.dialog-overlay", function( event ) { - var instances = $.ui.dialog.overlay.instances; - // only react to the event if we're the top overlay - if ( instances.length !== 0 && instances[ instances.length - 1 ] === $el && - dialog.options.closeOnEscape && !event.isDefaultPrevented() && event.keyCode && - event.keyCode === $.ui.keyCode.ESCAPE ) { - - dialog.close( event ); - event.preventDefault(); - } - }); - - $el.appendTo( document.body ).css({ - width: this.width(), - height: this.height() + this.overlay = $("<div>") + .addClass("ui-widget-overlay ui-front") + .appendTo( this._appendTo() ); + this._on( this.overlay, { + mousedown: "_keepFocus" }); + $.ui.dialog.overlayInstances++; + }, - if ( $.fn.bgiframe ) { - $el.bgiframe(); + _destroyOverlay: function() { + if ( !this.options.modal ) { + return; } - this.instances.push( $el ); - return $el; - }, - - destroy: function( $el ) { - var indexOf = $.inArray( $el, this.instances ), - maxZ = 0; + if ( this.overlay ) { + $.ui.dialog.overlayInstances--; - if ( indexOf !== -1 ) { - this.oldInstances.push( this.instances.splice( indexOf, 1 )[ 0 ] ); + if ( !$.ui.dialog.overlayInstances ) { + this.document.unbind( "focusin.dialog" ); + } + this.overlay.remove(); + this.overlay = null; } + } +}); - if ( this.instances.length === 0 ) { - $( [ document, window ] ).unbind( ".dialog-overlay" ); - } +$.ui.dialog.overlayInstances = 0; - $el.height( 0 ).width( 0 ).remove(); +// DEPRECATED +if ( $.uiBackCompat !== false ) { + // position option with array notation + // just override with old implementation + $.widget( "ui.dialog", $.ui.dialog, { + _position: function() { + var position = this.options.position, + myAt = [], + offset = [ 0, 0 ], + isVisible; + + if ( position ) { + if ( typeof position === "string" || (typeof position === "object" && "0" in position ) ) { + myAt = position.split ? position.split(" ") : [ position[0], position[1] ]; + if ( myAt.length === 1 ) { + myAt[1] = myAt[0]; + } - // adjust the maxZ to allow other modal dialogs to continue to work (see #4309) - $.each( this.instances, function() { - maxZ = Math.max( maxZ, this.css( "z-index" ) ); - }); - this.maxZ = maxZ; - }, + $.each( [ "left", "top" ], function( i, offsetPosition ) { + if ( +myAt[ i ] === myAt[ i ] ) { + offset[ i ] = myAt[ i ]; + myAt[ i ] = offsetPosition; + } + }); - height: function() { - var scrollHeight, - offsetHeight; - // handle IE - if ( $.ui.ie ) { - scrollHeight = Math.max( - document.documentElement.scrollHeight, - document.body.scrollHeight - ); - offsetHeight = Math.max( - document.documentElement.offsetHeight, - document.body.offsetHeight - ); + position = { + my: myAt[0] + (offset[0] < 0 ? offset[0] : "+" + offset[0]) + " " + + myAt[1] + (offset[1] < 0 ? offset[1] : "+" + offset[1]), + at: myAt.join(" ") + }; + } - if ( scrollHeight < offsetHeight ) { - return $( window ).height() + "px"; + position = $.extend( {}, $.ui.dialog.prototype.options.position, position ); } else { - return scrollHeight + "px"; + position = $.ui.dialog.prototype.options.position; } - // handle "good" browsers - } else { - return $( document ).height() + "px"; - } - }, - - width: function() { - var scrollWidth, - offsetWidth; - // handle IE - if ( $.ui.ie ) { - scrollWidth = Math.max( - document.documentElement.scrollWidth, - document.body.scrollWidth - ); - offsetWidth = Math.max( - document.documentElement.offsetWidth, - document.body.offsetWidth - ); - if ( scrollWidth < offsetWidth ) { - return $( window ).width() + "px"; - } else { - return scrollWidth + "px"; + // need to show the dialog to get the actual offset in the position plugin + isVisible = this.uiDialog.is(":visible"); + if ( !isVisible ) { + this.uiDialog.show(); + } + this.uiDialog.position( position ); + if ( !isVisible ) { + this.uiDialog.hide(); } - // handle "good" browsers - } else { - return $( document ).width() + "px"; } - }, - - resize: function() { - /* If the dialog is draggable and the user drags it past the - * right edge of the window, the document becomes wider so we - * need to stretch the overlay. If the user then drags the - * dialog back to the left, the document will become narrower, - * so we need to shrink the overlay to the appropriate size. - * This is handled by shrinking the overlay before setting it - * to the full document size. - */ - var $overlays = $( [] ); - $.each( $.ui.dialog.overlay.instances, function() { - $overlays = $overlays.add( this ); - }); - - $overlays.css({ - width: 0, - height: 0 - }).css({ - width: $.ui.dialog.overlay.width(), - height: $.ui.dialog.overlay.height() - }); - } -}); - -$.extend( $.ui.dialog.overlay.prototype, { - destroy: function() { - $.ui.dialog.overlay.destroy( this.$el ); - } -}); + }); +} }( jQuery ) ); @@ -10866,7 +11383,7 @@ $.effects.effect.transfer = function( o, done ) { width: target.innerWidth() }, startPosition = elem.offset(), - transfer = $( '<div class="ui-effects-transfer"></div>' ) + transfer = $( "<div class='ui-effects-transfer'></div>" ) .appendTo( document.body ) .addClass( o.className ) .css({ @@ -10886,10 +11403,8 @@ $.effects.effect.transfer = function( o, done ) { (function( $, undefined ) { -var mouseHandled = false; - $.widget( "ui.menu", { - version: "1.9.2", + version: "1.10.2", defaultElement: "<ul>", delay: 300, options: { @@ -10911,6 +11426,9 @@ $.widget( "ui.menu", { _create: function() { this.activeMenu = this.element; + // flag used to prevent firing of the click handler + // as the event bubbles up through nested menus + this.mouseHandled = false; this.element .uniqueId() .addClass( "ui-menu ui-widget ui-widget-content ui-corner-all" ) @@ -10944,8 +11462,8 @@ $.widget( "ui.menu", { }, "click .ui-menu-item:has(a)": function( event ) { var target = $( event.target ).closest( ".ui-menu-item" ); - if ( !mouseHandled && target.not( ".ui-state-disabled" ).length ) { - mouseHandled = true; + if ( !this.mouseHandled && target.not( ".ui-state-disabled" ).length ) { + this.mouseHandled = true; this.select( event ); // Open submenu on click @@ -11001,7 +11519,7 @@ $.widget( "ui.menu", { } // Reset the mouseHandled flag - mouseHandled = false; + this.mouseHandled = false; } }); }, @@ -11010,7 +11528,7 @@ $.widget( "ui.menu", { // Destroy (sub)menus this.element .removeAttr( "aria-activedescendant" ) - .find( ".ui-menu" ).andSelf() + .find( ".ui-menu" ).addBack() .removeClass( "ui-menu ui-widget ui-widget-content ui-corner-all ui-menu-icons" ) .removeAttr( "role" ) .removeAttr( "tabIndex" ) @@ -11044,6 +11562,7 @@ $.widget( "ui.menu", { }, _keydown: function( event ) { + /*jshint maxcomplexity:20*/ var match, prev, character, skip, regex, preventDefault = true; @@ -11192,7 +11711,7 @@ $.widget( "ui.menu", { menus.children( ":not(.ui-menu-item)" ).each(function() { var item = $( this ); // hyphen, em dash, en dash - if ( !/[^\-—–\s]/.test( item.text() ) ) { + if ( !/[^\-\u2014\u2013\s]/.test( item.text() ) ) { item.addClass( "ui-widget-content ui-menu-divider" ); } }); @@ -11213,6 +11732,15 @@ $.widget( "ui.menu", { }[ this.options.role ]; }, + _setOption: function( key, value ) { + if ( key === "icons" ) { + this.element.find( ".ui-menu-icon" ) + .removeClass( this.options.icons.submenu ) + .addClass( value.submenu ); + } + this._super( key, value ); + }, + focus: function( event, item ) { var nested, focused; this.blur( event, event && event.type === "focus" ); @@ -11490,21 +12018,52 @@ var cachedScrollbarWidth, round = Math.round, rhorizontal = /left|center|right/, rvertical = /top|center|bottom/, - roffset = /[\+\-]\d+%?/, + roffset = /[\+\-]\d+(\.[\d]+)?%?/, rposition = /^\w+/, rpercent = /%$/, _position = $.fn.position; function getOffsets( offsets, width, height ) { return [ - parseInt( offsets[ 0 ], 10 ) * ( rpercent.test( offsets[ 0 ] ) ? width / 100 : 1 ), - parseInt( offsets[ 1 ], 10 ) * ( rpercent.test( offsets[ 1 ] ) ? height / 100 : 1 ) + parseFloat( offsets[ 0 ] ) * ( rpercent.test( offsets[ 0 ] ) ? width / 100 : 1 ), + parseFloat( offsets[ 1 ] ) * ( rpercent.test( offsets[ 1 ] ) ? height / 100 : 1 ) ]; } + function parseCss( element, property ) { return parseInt( $.css( element, property ), 10 ) || 0; } +function getDimensions( elem ) { + var raw = elem[0]; + if ( raw.nodeType === 9 ) { + return { + width: elem.width(), + height: elem.height(), + offset: { top: 0, left: 0 } + }; + } + if ( $.isWindow( raw ) ) { + return { + width: elem.width(), + height: elem.height(), + offset: { top: elem.scrollTop(), left: elem.scrollLeft() } + }; + } + if ( raw.preventDefault ) { + return { + width: 0, + height: 0, + offset: { top: raw.pageY, left: raw.pageX } + }; + } + return { + width: elem.outerWidth(), + height: elem.outerHeight(), + offset: elem.offset() + }; +} + $.position = { scrollbarWidth: function() { if ( cachedScrollbarWidth !== undefined ) { @@ -11536,8 +12095,8 @@ $.position = { hasOverflowY = overflowY === "scroll" || ( overflowY === "auto" && within.height < within.element[0].scrollHeight ); return { - width: hasOverflowX ? $.position.scrollbarWidth() : 0, - height: hasOverflowY ? $.position.scrollbarWidth() : 0 + width: hasOverflowY ? $.position.scrollbarWidth() : 0, + height: hasOverflowX ? $.position.scrollbarWidth() : 0 }; }, getWithinInfo: function( element ) { @@ -11563,32 +12122,21 @@ $.fn.position = function( options ) { // make a copy, we don't want to modify arguments options = $.extend( {}, options ); - var atOffset, targetWidth, targetHeight, targetOffset, basePosition, + var atOffset, targetWidth, targetHeight, targetOffset, basePosition, dimensions, target = $( options.of ), within = $.position.getWithinInfo( options.within ), scrollInfo = $.position.getScrollInfo( within ), - targetElem = target[0], collision = ( options.collision || "flip" ).split( " " ), offsets = {}; - if ( targetElem.nodeType === 9 ) { - targetWidth = target.width(); - targetHeight = target.height(); - targetOffset = { top: 0, left: 0 }; - } else if ( $.isWindow( targetElem ) ) { - targetWidth = target.width(); - targetHeight = target.height(); - targetOffset = { top: target.scrollTop(), left: target.scrollLeft() }; - } else if ( targetElem.preventDefault ) { + dimensions = getDimensions( target ); + if ( target[0].preventDefault ) { // force left top to allow flipping options.at = "left top"; - targetWidth = targetHeight = 0; - targetOffset = { top: targetElem.pageY, left: targetElem.pageX }; - } else { - targetWidth = target.outerWidth(); - targetHeight = target.outerHeight(); - targetOffset = target.offset(); } + targetWidth = dimensions.width; + targetHeight = dimensions.height; + targetOffset = dimensions.offset; // clone to reuse original targetOffset later basePosition = $.extend( {}, targetOffset ); @@ -11702,10 +12250,6 @@ $.fn.position = function( options ) { } }); - if ( $.fn.bgiframe ) { - elem.bgiframe(); - } - if ( options.using ) { // adds feedback as second argument to using callback, if present using = function( props ) { @@ -11950,69 +12494,38 @@ $.ui.position = { testElementParent.removeChild( testElement ); })(); -// DEPRECATED -if ( $.uiBackCompat !== false ) { - // offset option - (function( $ ) { - var _position = $.fn.position; - $.fn.position = function( options ) { - if ( !options || !options.offset ) { - return _position.call( this, options ); - } - var offset = options.offset.split( " " ), - at = options.at.split( " " ); - if ( offset.length === 1 ) { - offset[ 1 ] = offset[ 0 ]; - } - if ( /^\d/.test( offset[ 0 ] ) ) { - offset[ 0 ] = "+" + offset[ 0 ]; - } - if ( /^\d/.test( offset[ 1 ] ) ) { - offset[ 1 ] = "+" + offset[ 1 ]; - } - if ( at.length === 1 ) { - if ( /left|center|right/.test( at[ 0 ] ) ) { - at[ 1 ] = "center"; - } else { - at[ 1 ] = at[ 0 ]; - at[ 0 ] = "center"; - } - } - return _position.call( this, $.extend( options, { - at: at[ 0 ] + offset[ 0 ] + " " + at[ 1 ] + offset[ 1 ], - offset: undefined - } ) ); - }; - }( jQuery ) ); -} - }( jQuery ) ); (function( $, undefined ) { $.widget( "ui.progressbar", { - version: "1.9.2", + version: "1.10.2", options: { + max: 100, value: 0, - max: 100 + + change: null, + complete: null }, min: 0, _create: function() { + // Constrain initial value + this.oldValue = this.options.value = this._constrainedValue(); + this.element .addClass( "ui-progressbar ui-widget ui-widget-content ui-corner-all" ) .attr({ + // Only set static values, aria-valuenow and aria-valuemax are + // set inside _refreshValue() role: "progressbar", - "aria-valuemin": this.min, - "aria-valuemax": this.options.max, - "aria-valuenow": this._value() + "aria-valuemin": this.min }); this.valueDiv = $( "<div class='ui-progressbar-value ui-widget-header ui-corner-left'></div>" ) .appendTo( this.element ); - this.oldValue = this._value(); this._refreshValue(); }, @@ -12029,52 +12542,87 @@ $.widget( "ui.progressbar", { value: function( newValue ) { if ( newValue === undefined ) { - return this._value(); + return this.options.value; } - this._setOption( "value", newValue ); - return this; + this.options.value = this._constrainedValue( newValue ); + this._refreshValue(); }, - _setOption: function( key, value ) { - if ( key === "value" ) { - this.options.value = value; - this._refreshValue(); - if ( this._value() === this.options.max ) { - this._trigger( "complete" ); - } + _constrainedValue: function( newValue ) { + if ( newValue === undefined ) { + newValue = this.options.value; } - this._super( key, value ); + this.indeterminate = newValue === false; + + // sanitize value + if ( typeof newValue !== "number" ) { + newValue = 0; + } + + return this.indeterminate ? false : + Math.min( this.options.max, Math.max( this.min, newValue ) ); }, - _value: function() { - var val = this.options.value; - // normalize invalid value - if ( typeof val !== "number" ) { - val = 0; + _setOptions: function( options ) { + // Ensure "value" option is set after other values (like max) + var value = options.value; + delete options.value; + + this._super( options ); + + this.options.value = this._constrainedValue( value ); + this._refreshValue(); + }, + + _setOption: function( key, value ) { + if ( key === "max" ) { + // Don't allow a max less than min + value = Math.max( this.min, value ); } - return Math.min( this.options.max, Math.max( this.min, val ) ); + + this._super( key, value ); }, _percentage: function() { - return 100 * this._value() / this.options.max; + return this.indeterminate ? 100 : 100 * ( this.options.value - this.min ) / ( this.options.max - this.min ); }, _refreshValue: function() { - var value = this.value(), + var value = this.options.value, percentage = this._percentage(); + this.valueDiv + .toggle( this.indeterminate || value > this.min ) + .toggleClass( "ui-corner-right", value === this.options.max ) + .width( percentage.toFixed(0) + "%" ); + + this.element.toggleClass( "ui-progressbar-indeterminate", this.indeterminate ); + + if ( this.indeterminate ) { + this.element.removeAttr( "aria-valuenow" ); + if ( !this.overlayDiv ) { + this.overlayDiv = $( "<div class='ui-progressbar-overlay'></div>" ).appendTo( this.valueDiv ); + } + } else { + this.element.attr({ + "aria-valuemax": this.options.max, + "aria-valuenow": value + }); + if ( this.overlayDiv ) { + this.overlayDiv.remove(); + this.overlayDiv = null; + } + } + if ( this.oldValue !== value ) { this.oldValue = value; this._trigger( "change" ); } - - this.valueDiv - .toggle( value > this.min ) - .toggleClass( "ui-corner-right", value === this.options.max ) - .width( percentage.toFixed(0) + "%" ); - this.element.attr( "aria-valuenow", value ); + if ( value === this.options.max ) { + this._trigger( "complete" ); + } } }); @@ -12087,7 +12635,7 @@ $.widget( "ui.progressbar", { var numPages = 5; $.widget( "ui.slider", $.ui.mouse, { - version: "1.9.2", + version: "1.10.2", widgetEventPrefix: "slide", options: { @@ -12099,16 +12647,16 @@ $.widget( "ui.slider", $.ui.mouse, { range: false, step: 1, value: 0, - values: null + values: null, + + // callbacks + change: null, + slide: null, + start: null, + stop: null }, _create: function() { - var i, handleCount, - o = this.options, - existingHandles = this.element.find( ".ui-slider-handle" ).addClass( "ui-state-default ui-corner-all" ), - handle = "<a class='ui-slider-handle ui-state-default ui-corner-all' href='#'></a>", - handles = []; - this._keySliding = false; this._mouseSliding = false; this._animateOff = true; @@ -12121,31 +12669,34 @@ $.widget( "ui.slider", $.ui.mouse, { " ui-slider-" + this.orientation + " ui-widget" + " ui-widget-content" + - " ui-corner-all" + - ( o.disabled ? " ui-slider-disabled ui-disabled" : "" ) ); + " ui-corner-all"); - this.range = $([]); + this._refresh(); + this._setOption( "disabled", this.options.disabled ); - if ( o.range ) { - if ( o.range === true ) { - if ( !o.values ) { - o.values = [ this._valueMin(), this._valueMin() ]; - } - if ( o.values.length && o.values.length !== 2 ) { - o.values = [ o.values[0], o.values[0] ]; - } - } + this._animateOff = false; + }, - this.range = $( "<div></div>" ) - .appendTo( this.element ) - .addClass( "ui-slider-range" + - // note: this isn't the most fittingly semantic framework class for this element, - // but worked best visually with a variety of themes - " ui-widget-header" + - ( ( o.range === "min" || o.range === "max" ) ? " ui-slider-range-" + o.range : "" ) ); - } + _refresh: function() { + this._createRange(); + this._createHandles(); + this._setupEvents(); + this._refreshValue(); + }, - handleCount = ( o.values && o.values.length ) || 1; + _createHandles: function() { + var i, handleCount, + options = this.options, + existingHandles = this.element.find( ".ui-slider-handle" ).addClass( "ui-state-default ui-corner-all" ), + handle = "<a class='ui-slider-handle ui-state-default ui-corner-all' href='#'></a>", + handles = []; + + handleCount = ( options.values && options.values.length ) || 1; + + if ( existingHandles.length > handleCount ) { + existingHandles.slice( handleCount ).remove(); + existingHandles = existingHandles.slice( 0, handleCount ); + } for ( i = existingHandles.length; i < handleCount; i++ ) { handles.push( handle ); @@ -12155,113 +12706,56 @@ $.widget( "ui.slider", $.ui.mouse, { this.handle = this.handles.eq( 0 ); - this.handles.add( this.range ).filter( "a" ) - .click(function( event ) { - event.preventDefault(); - }) - .mouseenter(function() { - if ( !o.disabled ) { - $( this ).addClass( "ui-state-hover" ); - } - }) - .mouseleave(function() { - $( this ).removeClass( "ui-state-hover" ); - }) - .focus(function() { - if ( !o.disabled ) { - $( ".ui-slider .ui-state-focus" ).removeClass( "ui-state-focus" ); - $( this ).addClass( "ui-state-focus" ); - } else { - $( this ).blur(); - } - }) - .blur(function() { - $( this ).removeClass( "ui-state-focus" ); - }); - this.handles.each(function( i ) { $( this ).data( "ui-slider-handle-index", i ); }); + }, - this._on( this.handles, { - keydown: function( event ) { - var allowed, curVal, newVal, step, - index = $( event.target ).data( "ui-slider-handle-index" ); - - switch ( event.keyCode ) { - case $.ui.keyCode.HOME: - case $.ui.keyCode.END: - case $.ui.keyCode.PAGE_UP: - case $.ui.keyCode.PAGE_DOWN: - case $.ui.keyCode.UP: - case $.ui.keyCode.RIGHT: - case $.ui.keyCode.DOWN: - case $.ui.keyCode.LEFT: - event.preventDefault(); - if ( !this._keySliding ) { - this._keySliding = true; - $( event.target ).addClass( "ui-state-active" ); - allowed = this._start( event, index ); - if ( allowed === false ) { - return; - } - } - break; - } - - step = this.options.step; - if ( this.options.values && this.options.values.length ) { - curVal = newVal = this.values( index ); - } else { - curVal = newVal = this.value(); - } + _createRange: function() { + var options = this.options, + classes = ""; - switch ( event.keyCode ) { - case $.ui.keyCode.HOME: - newVal = this._valueMin(); - break; - case $.ui.keyCode.END: - newVal = this._valueMax(); - break; - case $.ui.keyCode.PAGE_UP: - newVal = this._trimAlignValue( curVal + ( (this._valueMax() - this._valueMin()) / numPages ) ); - break; - case $.ui.keyCode.PAGE_DOWN: - newVal = this._trimAlignValue( curVal - ( (this._valueMax() - this._valueMin()) / numPages ) ); - break; - case $.ui.keyCode.UP: - case $.ui.keyCode.RIGHT: - if ( curVal === this._valueMax() ) { - return; - } - newVal = this._trimAlignValue( curVal + step ); - break; - case $.ui.keyCode.DOWN: - case $.ui.keyCode.LEFT: - if ( curVal === this._valueMin() ) { - return; - } - newVal = this._trimAlignValue( curVal - step ); - break; + if ( options.range ) { + if ( options.range === true ) { + if ( !options.values ) { + options.values = [ this._valueMin(), this._valueMin() ]; + } else if ( options.values.length && options.values.length !== 2 ) { + options.values = [ options.values[0], options.values[0] ]; + } else if ( $.isArray( options.values ) ) { + options.values = options.values.slice(0); } + } - this._slide( event, index, newVal ); - }, - keyup: function( event ) { - var index = $( event.target ).data( "ui-slider-handle-index" ); + if ( !this.range || !this.range.length ) { + this.range = $( "<div></div>" ) + .appendTo( this.element ); - if ( this._keySliding ) { - this._keySliding = false; - this._stop( event, index ); - this._change( event, index ); - $( event.target ).removeClass( "ui-state-active" ); - } + classes = "ui-slider-range" + + // note: this isn't the most fittingly semantic framework class for this element, + // but worked best visually with a variety of themes + " ui-widget-header ui-corner-all"; + } else { + this.range.removeClass( "ui-slider-range-min ui-slider-range-max" ) + // Handle range switching from true to min/max + .css({ + "left": "", + "bottom": "" + }); } - }); - this._refreshValue(); + this.range.addClass( classes + + ( ( options.range === "min" || options.range === "max" ) ? " ui-slider-range-" + options.range : "" ) ); + } else { + this.range = $([]); + } + }, - this._animateOff = false; + _setupEvents: function() { + var elements = this.handles.add( this.range ).filter( "a" ); + this._off( elements ); + this._on( elements, this._handleEvents ); + this._hoverable( elements ); + this._focusable( elements ); }, _destroy: function() { @@ -12272,7 +12766,6 @@ $.widget( "ui.slider", $.ui.mouse, { .removeClass( "ui-slider" + " ui-slider-horizontal" + " ui-slider-vertical" + - " ui-slider-disabled" + " ui-widget" + " ui-widget-content" + " ui-corner-all" ); @@ -12300,21 +12793,15 @@ $.widget( "ui.slider", $.ui.mouse, { distance = this._valueMax() - this._valueMin() + 1; this.handles.each(function( i ) { var thisDistance = Math.abs( normValue - that.values(i) ); - if ( distance > thisDistance ) { + if (( distance > thisDistance ) || + ( distance === thisDistance && + (i === that._lastChangedValue || that.values(i) === o.min ))) { distance = thisDistance; closestHandle = $( this ); index = i; } }); - // workaround for bug #3736 (if both handles of a range are at 0, - // the first is always used as the one with least distance, - // and moving it is obviously prevented by preventing negative ranges) - if( o.range === true && this.values(1) === o.min ) { - index += 1; - closestHandle = $( this.handles[index] ); - } - allowed = this._start( event, index ); if ( allowed === false ) { return false; @@ -12328,7 +12815,7 @@ $.widget( "ui.slider", $.ui.mouse, { .focus(); offset = closestHandle.offset(); - mouseOverHandle = !$( event.target ).parents().andSelf().is( ".ui-slider-handle" ); + mouseOverHandle = !$( event.target ).parents().addBack().is( ".ui-slider-handle" ); this._clickOffset = mouseOverHandle ? { left: 0, top: 0 } : { left: event.pageX - offset.left - ( closestHandle.width() / 2 ), top: event.pageY - offset.top - @@ -12486,6 +12973,9 @@ $.widget( "ui.slider", $.ui.mouse, { uiHash.values = this.values(); } + //store the last changed value index for reference when handles overlap + this._lastChangedValue = index; + this._trigger( "change", event, uiHash ); } }, @@ -12538,6 +13028,16 @@ $.widget( "ui.slider", $.ui.mouse, { var i, valsLength = 0; + if ( key === "range" && this.options.range === true ) { + if ( value === "min" ) { + this.options.value = this._values( 0 ); + this.options.values = null; + } else if ( value === "max" ) { + this.options.value = this._values( this.options.values.length-1 ); + this.options.values = null; + } + } + if ( $.isArray( this.options.values ) ) { valsLength = this.options.values.length; } @@ -12545,17 +13045,6 @@ $.widget( "ui.slider", $.ui.mouse, { $.Widget.prototype._setOption.apply( this, arguments ); switch ( key ) { - case "disabled": - if ( value ) { - this.handles.filter( ".ui-state-focus" ).blur(); - this.handles.removeClass( "ui-state-hover" ); - this.handles.prop( "disabled", true ); - this.element.addClass( "ui-disabled" ); - } else { - this.handles.prop( "disabled", false ); - this.element.removeClass( "ui-disabled" ); - } - break; case "orientation": this._detectOrientation(); this.element @@ -12583,6 +13072,11 @@ $.widget( "ui.slider", $.ui.mouse, { this._refreshValue(); this._animateOff = false; break; + case "range": + this._animateOff = true; + this._refresh(); + this._animateOff = false; + break; } }, @@ -12608,7 +13102,7 @@ $.widget( "ui.slider", $.ui.mouse, { val = this._trimAlignValue( val ); return val; - } else { + } else if ( this.options.values && this.options.values.length ) { // .slice() creates a copy of the array // this copy gets trimmed by min and max and then returned vals = this.options.values.slice(); @@ -12617,6 +13111,8 @@ $.widget( "ui.slider", $.ui.mouse, { } return vals; + } else { + return []; } }, @@ -12704,6 +13200,86 @@ $.widget( "ui.slider", $.ui.mouse, { this.range[ animate ? "animate" : "css" ]( { height: ( 100 - valPercent ) + "%" }, { queue: false, duration: o.animate } ); } } + }, + + _handleEvents: { + keydown: function( event ) { + /*jshint maxcomplexity:25*/ + var allowed, curVal, newVal, step, + index = $( event.target ).data( "ui-slider-handle-index" ); + + switch ( event.keyCode ) { + case $.ui.keyCode.HOME: + case $.ui.keyCode.END: + case $.ui.keyCode.PAGE_UP: + case $.ui.keyCode.PAGE_DOWN: + case $.ui.keyCode.UP: + case $.ui.keyCode.RIGHT: + case $.ui.keyCode.DOWN: + case $.ui.keyCode.LEFT: + event.preventDefault(); + if ( !this._keySliding ) { + this._keySliding = true; + $( event.target ).addClass( "ui-state-active" ); + allowed = this._start( event, index ); + if ( allowed === false ) { + return; + } + } + break; + } + + step = this.options.step; + if ( this.options.values && this.options.values.length ) { + curVal = newVal = this.values( index ); + } else { + curVal = newVal = this.value(); + } + + switch ( event.keyCode ) { + case $.ui.keyCode.HOME: + newVal = this._valueMin(); + break; + case $.ui.keyCode.END: + newVal = this._valueMax(); + break; + case $.ui.keyCode.PAGE_UP: + newVal = this._trimAlignValue( curVal + ( (this._valueMax() - this._valueMin()) / numPages ) ); + break; + case $.ui.keyCode.PAGE_DOWN: + newVal = this._trimAlignValue( curVal - ( (this._valueMax() - this._valueMin()) / numPages ) ); + break; + case $.ui.keyCode.UP: + case $.ui.keyCode.RIGHT: + if ( curVal === this._valueMax() ) { + return; + } + newVal = this._trimAlignValue( curVal + step ); + break; + case $.ui.keyCode.DOWN: + case $.ui.keyCode.LEFT: + if ( curVal === this._valueMin() ) { + return; + } + newVal = this._trimAlignValue( curVal - step ); + break; + } + + this._slide( event, index, newVal ); + }, + click: function( event ) { + event.preventDefault(); + }, + keyup: function( event ) { + var index = $( event.target ).data( "ui-slider-handle-index" ); + + if ( this._keySliding ) { + this._keySliding = false; + this._stop( event, index ); + this._change( event, index ); + $( event.target ).removeClass( "ui-state-active" ); + } + } } }); @@ -12724,7 +13300,7 @@ function modifier( fn ) { } $.widget( "ui.spinner", { - version: "1.9.2", + version: "1.10.2", defaultElement: "<input>", widgetEventPrefix: "spin", options: { @@ -12799,6 +13375,7 @@ $.widget( "ui.spinner", { return; } + this._stop(); this._refresh(); if ( this.previous !== this.element.val() ) { this._trigger( "change", event ); @@ -13065,6 +13642,14 @@ $.widget( "ui.spinner", { value = this._parse( value ); } } + if ( key === "icons" ) { + this.buttons.first().find( ".ui-icon" ) + .removeClass( this.options.icons.up ) + .addClass( value.up ); + this.buttons.last().find( ".ui-icon" ) + .removeClass( this.options.icons.down ) + .addClass( value.down ); + } this._super( key, value ); @@ -13142,14 +13727,20 @@ $.widget( "ui.spinner", { this._stepUp( steps ); }), _stepUp: function( steps ) { - this._spin( (steps || 1) * this.options.step ); + if ( this._start() ) { + this._spin( (steps || 1) * this.options.step ); + this._stop(); + } }, stepDown: modifier(function( steps ) { this._stepDown( steps ); }), _stepDown: function( steps ) { - this._spin( (steps || 1) * -this.options.step ); + if ( this._start() ) { + this._spin( (steps || 1) * -this.options.step ); + this._stop(); + } }, pageUp: modifier(function( pages ) { @@ -13185,16 +13776,12 @@ function getNextTabId() { function isLocal( anchor ) { return anchor.hash.length > 1 && - anchor.href.replace( rhash, "" ) === - location.href.replace( rhash, "" ) - // support: Safari 5.1 - // Safari 5.1 doesn't encode spaces in window.location - // but it does encode spaces from anchors (#8777) - .replace( /\s/g, "%20" ); + decodeURIComponent( anchor.href.replace( rhash, "" ) ) === + decodeURIComponent( location.href.replace( rhash, "" ) ); } $.widget( "ui.tabs", { - version: "1.9.2", + version: "1.10.2", delay: 300, options: { active: null, @@ -13213,9 +13800,7 @@ $.widget( "ui.tabs", { _create: function() { var that = this, - options = this.options, - active = options.active, - locationHash = location.hash.substring( 1 ); + options = this.options; this.running = false; @@ -13241,6 +13826,36 @@ $.widget( "ui.tabs", { }); this._processTabs(); + options.active = this._initialActive(); + + // Take disabling tabs via class attribute from HTML + // into account and update option properly. + if ( $.isArray( options.disabled ) ) { + options.disabled = $.unique( options.disabled.concat( + $.map( this.tabs.filter( ".ui-state-disabled" ), function( li ) { + return that.tabs.index( li ); + }) + ) ).sort(); + } + + // check for length avoids error when initializing empty list + if ( this.options.active !== false && this.anchors.length ) { + this.active = this._findActive( options.active ); + } else { + this.active = $(); + } + + this._refresh(); + + if ( this.active.length ) { + this.load( options.active ); + } + }, + + _initialActive: function() { + var active = this.options.active, + collapsible = this.options.collapsible, + locationHash = location.hash.substring( 1 ); if ( active === null ) { // check the fragment identifier in the URL @@ -13268,38 +13883,16 @@ $.widget( "ui.tabs", { if ( active !== false ) { active = this.tabs.index( this.tabs.eq( active ) ); if ( active === -1 ) { - active = options.collapsible ? false : 0; + active = collapsible ? false : 0; } } - options.active = active; // don't allow collapsible: false and active: false - if ( !options.collapsible && options.active === false && this.anchors.length ) { - options.active = 0; - } - - // Take disabling tabs via class attribute from HTML - // into account and update option properly. - if ( $.isArray( options.disabled ) ) { - options.disabled = $.unique( options.disabled.concat( - $.map( this.tabs.filter( ".ui-state-disabled" ), function( li ) { - return that.tabs.index( li ); - }) - ) ).sort(); + if ( !collapsible && active === false && this.anchors.length ) { + active = 0; } - // check for length avoids error when initializing empty list - if ( this.options.active !== false && this.anchors.length ) { - this.active = this._findActive( this.options.active ); - } else { - this.active = $(); - } - - this._refresh(); - - if ( this.active.length ) { - this.load( options.active ); - } + return active; }, _getCreateEventData: function() { @@ -13310,6 +13903,7 @@ $.widget( "ui.tabs", { }, _tabKeydown: function( event ) { + /*jshint maxcomplexity:15*/ var focusedTab = $( this.document[0].activeElement ).closest( "li" ), selectedIndex = this.tabs.index( focusedTab ), goingForward = true; @@ -13654,19 +14248,13 @@ $.widget( "ui.tabs", { }, _setupHeightStyle: function( heightStyle ) { - var maxHeight, overflow, + var maxHeight, parent = this.element.parent(); if ( heightStyle === "fill" ) { - // IE 6 treats height like minHeight, so we need to turn off overflow - // in order to get a reliable height - // we use the minHeight support test because we assume that only - // browsers that don't support minHeight will treat height as minHeight - if ( !$.support.minHeight ) { - overflow = parent.css( "overflow" ); - parent.css( "overflow", "hidden"); - } maxHeight = parent.height(); + maxHeight -= this.element.outerHeight() - this.element.height(); + this.element.siblings( ":visible" ).each(function() { var elem = $( this ), position = elem.css( "position" ); @@ -13676,9 +14264,6 @@ $.widget( "ui.tabs", { } maxHeight -= elem.outerHeight( true ); }); - if ( overflow ) { - parent.css( "overflow", overflow ); - } this.element.children().not( this.panels ).each(function() { maxHeight -= $( this ).outerHeight( true ); @@ -13857,8 +14442,6 @@ $.widget( "ui.tabs", { .removeClass( "ui-tabs-anchor" ) .removeAttr( "role" ) .removeAttr( "tabIndex" ) - .removeData( "href.tabs" ) - .removeData( "load.tabs" ) .removeUniqueId(); this.tabs.add( this.panels ).each(function() { @@ -13883,7 +14466,9 @@ $.widget( "ui.tabs", { var li = $( this ), prev = li.data( "ui-tabs-aria-controls" ); if ( prev ) { - li.attr( "aria-controls", prev ); + li + .attr( "aria-controls", prev ) + .removeData( "ui-tabs-aria-controls" ); } else { li.removeAttr( "aria-controls" ); } @@ -13994,7 +14579,6 @@ $.widget( "ui.tabs", { } }, - // TODO: Remove this function in 1.10 when ajaxOptions is removed _ajaxSettings: function( anchor, event, eventData ) { var that = this; return { @@ -14012,519 +14596,6 @@ $.widget( "ui.tabs", { } }); -// DEPRECATED -if ( $.uiBackCompat !== false ) { - - // helper method for a lot of the back compat extensions - $.ui.tabs.prototype._ui = function( tab, panel ) { - return { - tab: tab, - panel: panel, - index: this.anchors.index( tab ) - }; - }; - - // url method - $.widget( "ui.tabs", $.ui.tabs, { - url: function( index, url ) { - this.anchors.eq( index ).attr( "href", url ); - } - }); - - // TODO: Remove _ajaxSettings() method when removing this extension - // ajaxOptions and cache options - $.widget( "ui.tabs", $.ui.tabs, { - options: { - ajaxOptions: null, - cache: false - }, - - _create: function() { - this._super(); - - var that = this; - - this._on({ tabsbeforeload: function( event, ui ) { - // tab is already cached - if ( $.data( ui.tab[ 0 ], "cache.tabs" ) ) { - event.preventDefault(); - return; - } - - ui.jqXHR.success(function() { - if ( that.options.cache ) { - $.data( ui.tab[ 0 ], "cache.tabs", true ); - } - }); - }}); - }, - - _ajaxSettings: function( anchor, event, ui ) { - var ajaxOptions = this.options.ajaxOptions; - return $.extend( {}, ajaxOptions, { - error: function( xhr, status ) { - try { - // Passing index avoid a race condition when this method is - // called after the user has selected another tab. - // Pass the anchor that initiated this request allows - // loadError to manipulate the tab content panel via $(a.hash) - ajaxOptions.error( - xhr, status, ui.tab.closest( "li" ).index(), ui.tab[ 0 ] ); - } - catch ( error ) {} - } - }, this._superApply( arguments ) ); - }, - - _setOption: function( key, value ) { - // reset cache if switching from cached to not cached - if ( key === "cache" && value === false ) { - this.anchors.removeData( "cache.tabs" ); - } - this._super( key, value ); - }, - - _destroy: function() { - this.anchors.removeData( "cache.tabs" ); - this._super(); - }, - - url: function( index ){ - this.anchors.eq( index ).removeData( "cache.tabs" ); - this._superApply( arguments ); - } - }); - - // abort method - $.widget( "ui.tabs", $.ui.tabs, { - abort: function() { - if ( this.xhr ) { - this.xhr.abort(); - } - } - }); - - // spinner - $.widget( "ui.tabs", $.ui.tabs, { - options: { - spinner: "<em>Loading…</em>" - }, - _create: function() { - this._super(); - this._on({ - tabsbeforeload: function( event, ui ) { - // Don't react to nested tabs or tabs that don't use a spinner - if ( event.target !== this.element[ 0 ] || - !this.options.spinner ) { - return; - } - - var span = ui.tab.find( "span" ), - html = span.html(); - span.html( this.options.spinner ); - ui.jqXHR.complete(function() { - span.html( html ); - }); - } - }); - } - }); - - // enable/disable events - $.widget( "ui.tabs", $.ui.tabs, { - options: { - enable: null, - disable: null - }, - - enable: function( index ) { - var options = this.options, - trigger; - - if ( index && options.disabled === true || - ( $.isArray( options.disabled ) && $.inArray( index, options.disabled ) !== -1 ) ) { - trigger = true; - } - - this._superApply( arguments ); - - if ( trigger ) { - this._trigger( "enable", null, this._ui( this.anchors[ index ], this.panels[ index ] ) ); - } - }, - - disable: function( index ) { - var options = this.options, - trigger; - - if ( index && options.disabled === false || - ( $.isArray( options.disabled ) && $.inArray( index, options.disabled ) === -1 ) ) { - trigger = true; - } - - this._superApply( arguments ); - - if ( trigger ) { - this._trigger( "disable", null, this._ui( this.anchors[ index ], this.panels[ index ] ) ); - } - } - }); - - // add/remove methods and events - $.widget( "ui.tabs", $.ui.tabs, { - options: { - add: null, - remove: null, - tabTemplate: "<li><a href='#{href}'><span>#{label}</span></a></li>" - }, - - add: function( url, label, index ) { - if ( index === undefined ) { - index = this.anchors.length; - } - - var doInsertAfter, panel, - options = this.options, - li = $( options.tabTemplate - .replace( /#\{href\}/g, url ) - .replace( /#\{label\}/g, label ) ), - id = !url.indexOf( "#" ) ? - url.replace( "#", "" ) : - this._tabId( li ); - - li.addClass( "ui-state-default ui-corner-top" ).data( "ui-tabs-destroy", true ); - li.attr( "aria-controls", id ); - - doInsertAfter = index >= this.tabs.length; - - // try to find an existing element before creating a new one - panel = this.element.find( "#" + id ); - if ( !panel.length ) { - panel = this._createPanel( id ); - if ( doInsertAfter ) { - if ( index > 0 ) { - panel.insertAfter( this.panels.eq( -1 ) ); - } else { - panel.appendTo( this.element ); - } - } else { - panel.insertBefore( this.panels[ index ] ); - } - } - panel.addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" ).hide(); - - if ( doInsertAfter ) { - li.appendTo( this.tablist ); - } else { - li.insertBefore( this.tabs[ index ] ); - } - - options.disabled = $.map( options.disabled, function( n ) { - return n >= index ? ++n : n; - }); - - this.refresh(); - if ( this.tabs.length === 1 && options.active === false ) { - this.option( "active", 0 ); - } - - this._trigger( "add", null, this._ui( this.anchors[ index ], this.panels[ index ] ) ); - return this; - }, - - remove: function( index ) { - index = this._getIndex( index ); - var options = this.options, - tab = this.tabs.eq( index ).remove(), - panel = this._getPanelForTab( tab ).remove(); - - // If selected tab was removed focus tab to the right or - // in case the last tab was removed the tab to the left. - // We check for more than 2 tabs, because if there are only 2, - // then when we remove this tab, there will only be one tab left - // so we don't need to detect which tab to activate. - if ( tab.hasClass( "ui-tabs-active" ) && this.anchors.length > 2 ) { - this._activate( index + ( index + 1 < this.anchors.length ? 1 : -1 ) ); - } - - options.disabled = $.map( - $.grep( options.disabled, function( n ) { - return n !== index; - }), - function( n ) { - return n >= index ? --n : n; - }); - - this.refresh(); - - this._trigger( "remove", null, this._ui( tab.find( "a" )[ 0 ], panel[ 0 ] ) ); - return this; - } - }); - - // length method - $.widget( "ui.tabs", $.ui.tabs, { - length: function() { - return this.anchors.length; - } - }); - - // panel ids (idPrefix option + title attribute) - $.widget( "ui.tabs", $.ui.tabs, { - options: { - idPrefix: "ui-tabs-" - }, - - _tabId: function( tab ) { - var a = tab.is( "li" ) ? tab.find( "a[href]" ) : tab; - a = a[0]; - return $( a ).closest( "li" ).attr( "aria-controls" ) || - a.title && a.title.replace( /\s/g, "_" ).replace( /[^\w\u00c0-\uFFFF\-]/g, "" ) || - this.options.idPrefix + getNextTabId(); - } - }); - - // _createPanel method - $.widget( "ui.tabs", $.ui.tabs, { - options: { - panelTemplate: "<div></div>" - }, - - _createPanel: function( id ) { - return $( this.options.panelTemplate ) - .attr( "id", id ) - .addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" ) - .data( "ui-tabs-destroy", true ); - } - }); - - // selected option - $.widget( "ui.tabs", $.ui.tabs, { - _create: function() { - var options = this.options; - if ( options.active === null && options.selected !== undefined ) { - options.active = options.selected === -1 ? false : options.selected; - } - this._super(); - options.selected = options.active; - if ( options.selected === false ) { - options.selected = -1; - } - }, - - _setOption: function( key, value ) { - if ( key !== "selected" ) { - return this._super( key, value ); - } - - var options = this.options; - this._super( "active", value === -1 ? false : value ); - options.selected = options.active; - if ( options.selected === false ) { - options.selected = -1; - } - }, - - _eventHandler: function() { - this._superApply( arguments ); - this.options.selected = this.options.active; - if ( this.options.selected === false ) { - this.options.selected = -1; - } - } - }); - - // show and select event - $.widget( "ui.tabs", $.ui.tabs, { - options: { - show: null, - select: null - }, - _create: function() { - this._super(); - if ( this.options.active !== false ) { - this._trigger( "show", null, this._ui( - this.active.find( ".ui-tabs-anchor" )[ 0 ], - this._getPanelForTab( this.active )[ 0 ] ) ); - } - }, - _trigger: function( type, event, data ) { - var tab, panel, - ret = this._superApply( arguments ); - - if ( !ret ) { - return false; - } - - if ( type === "beforeActivate" ) { - tab = data.newTab.length ? data.newTab : data.oldTab; - panel = data.newPanel.length ? data.newPanel : data.oldPanel; - ret = this._super( "select", event, { - tab: tab.find( ".ui-tabs-anchor" )[ 0], - panel: panel[ 0 ], - index: tab.closest( "li" ).index() - }); - } else if ( type === "activate" && data.newTab.length ) { - ret = this._super( "show", event, { - tab: data.newTab.find( ".ui-tabs-anchor" )[ 0 ], - panel: data.newPanel[ 0 ], - index: data.newTab.closest( "li" ).index() - }); - } - return ret; - } - }); - - // select method - $.widget( "ui.tabs", $.ui.tabs, { - select: function( index ) { - index = this._getIndex( index ); - if ( index === -1 ) { - if ( this.options.collapsible && this.options.selected !== -1 ) { - index = this.options.selected; - } else { - return; - } - } - this.anchors.eq( index ).trigger( this.options.event + this.eventNamespace ); - } - }); - - // cookie option - (function() { - - var listId = 0; - - $.widget( "ui.tabs", $.ui.tabs, { - options: { - cookie: null // e.g. { expires: 7, path: '/', domain: 'jquery.com', secure: true } - }, - _create: function() { - var options = this.options, - active; - if ( options.active == null && options.cookie ) { - active = parseInt( this._cookie(), 10 ); - if ( active === -1 ) { - active = false; - } - options.active = active; - } - this._super(); - }, - _cookie: function( active ) { - var cookie = [ this.cookie || - ( this.cookie = this.options.cookie.name || "ui-tabs-" + (++listId) ) ]; - if ( arguments.length ) { - cookie.push( active === false ? -1 : active ); - cookie.push( this.options.cookie ); - } - return $.cookie.apply( null, cookie ); - }, - _refresh: function() { - this._super(); - if ( this.options.cookie ) { - this._cookie( this.options.active, this.options.cookie ); - } - }, - _eventHandler: function() { - this._superApply( arguments ); - if ( this.options.cookie ) { - this._cookie( this.options.active, this.options.cookie ); - } - }, - _destroy: function() { - this._super(); - if ( this.options.cookie ) { - this._cookie( null, this.options.cookie ); - } - } - }); - - })(); - - // load event - $.widget( "ui.tabs", $.ui.tabs, { - _trigger: function( type, event, data ) { - var _data = $.extend( {}, data ); - if ( type === "load" ) { - _data.panel = _data.panel[ 0 ]; - _data.tab = _data.tab.find( ".ui-tabs-anchor" )[ 0 ]; - } - return this._super( type, event, _data ); - } - }); - - // fx option - // The new animation options (show, hide) conflict with the old show callback. - // The old fx option wins over show/hide anyway (always favor back-compat). - // If a user wants to use the new animation API, they must give up the old API. - $.widget( "ui.tabs", $.ui.tabs, { - options: { - fx: null // e.g. { height: "toggle", opacity: "toggle", duration: 200 } - }, - - _getFx: function() { - var hide, show, - fx = this.options.fx; - - if ( fx ) { - if ( $.isArray( fx ) ) { - hide = fx[ 0 ]; - show = fx[ 1 ]; - } else { - hide = show = fx; - } - } - - return fx ? { show: show, hide: hide } : null; - }, - - _toggle: function( event, eventData ) { - var that = this, - toShow = eventData.newPanel, - toHide = eventData.oldPanel, - fx = this._getFx(); - - if ( !fx ) { - return this._super( event, eventData ); - } - - that.running = true; - - function complete() { - that.running = false; - that._trigger( "activate", event, eventData ); - } - - function show() { - eventData.newTab.closest( "li" ).addClass( "ui-tabs-active ui-state-active" ); - - if ( toShow.length && fx.show ) { - toShow - .animate( fx.show, fx.show.duration, function() { - complete(); - }); - } else { - toShow.show(); - complete(); - } - } - - // start out by hiding, then showing, then completing - if ( toHide.length && fx.hide ) { - toHide.animate( fx.hide, fx.hide.duration, function() { - eventData.oldTab.closest( "li" ).removeClass( "ui-tabs-active ui-state-active" ); - show(); - }); - } else { - eventData.oldTab.closest( "li" ).removeClass( "ui-tabs-active ui-state-active" ); - toHide.hide(); - show(); - } - } - }); -} - })( jQuery ); (function( $ ) { @@ -14557,10 +14628,14 @@ function removeDescribedBy( elem ) { } $.widget( "ui.tooltip", { - version: "1.9.2", + version: "1.10.2", options: { content: function() { - return $( this ).attr( "title" ); + // support: IE<9, Opera in jQuery <1.7 + // .text() can't accept undefined, so coerce to a string + var title = $( this ).attr( "title" ) || ""; + // Escape title, since we're going from an attribute to raw HTML + return $( "<a>" ).text( title ).html(); }, hide: true, // Disabled elements have inconsistent behavior across browsers (#8661) @@ -14625,7 +14700,7 @@ $.widget( "ui.tooltip", { }); // remove title attributes to prevent native tooltips - this.element.find( this.options.items ).andSelf().each(function() { + this.element.find( this.options.items ).addBack().each(function() { var element = $( this ); if ( element.is( "[title]" ) ) { element @@ -14637,7 +14712,7 @@ $.widget( "ui.tooltip", { _enable: function() { // restore title attributes - this.element.find( this.options.items ).andSelf().each(function() { + this.element.find( this.options.items ).addBack().each(function() { var element = $( this ); if ( element.data( "ui-tooltip-title" ) ) { element.attr( "title", element.data( "ui-tooltip-title" ) ); @@ -14782,7 +14857,7 @@ $.widget( "ui.tooltip", { // as the tooltip is visible, position the tooltip using the most recent // event. if ( this.options.show && this.options.show.delay ) { - delayedShow = setInterval(function() { + delayedShow = this.delayedShow = setInterval(function() { if ( tooltip.is( ":visible" ) ) { position( positionOption.of ); clearInterval( delayedShow ); @@ -14824,6 +14899,9 @@ $.widget( "ui.tooltip", { return; } + // Clear the interval for delayed tracking tooltips + clearInterval( this.delayedShow ); + // only set title if we had one before (see comment in _open()) if ( target.data( "ui-tooltip-title" ) ) { target.attr( "title", target.data( "ui-tooltip-title" ) ); @@ -14869,9 +14947,6 @@ $.widget( "ui.tooltip", { .addClass( "ui-tooltip-content" ) .appendTo( tooltip ); tooltip.appendTo( this.document[0].body ); - if ( $.fn.bgiframe ) { - tooltip.bgiframe(); - } this.tooltips[ id ] = element; return tooltip; }, diff --git a/lib/scripts/jquery/jquery-ui.min.js b/lib/scripts/jquery/jquery-ui.min.js index bc013548d..629f140cd 100644 --- a/lib/scripts/jquery/jquery-ui.min.js +++ b/lib/scripts/jquery/jquery-ui.min.js @@ -1,5 +1,12 @@ -/*! jQuery UI - v1.9.2 - 2012-11-23 +/*! jQuery UI - v1.10.2 - 2013-03-14 * http://jqueryui.com * Includes: jquery.ui.core.js, jquery.ui.widget.js, jquery.ui.mouse.js, jquery.ui.draggable.js, jquery.ui.droppable.js, jquery.ui.resizable.js, jquery.ui.selectable.js, jquery.ui.sortable.js, jquery.ui.effect.js, jquery.ui.accordion.js, jquery.ui.autocomplete.js, jquery.ui.button.js, jquery.ui.datepicker.js, jquery.ui.dialog.js, jquery.ui.effect-blind.js, jquery.ui.effect-bounce.js, jquery.ui.effect-clip.js, jquery.ui.effect-drop.js, jquery.ui.effect-explode.js, jquery.ui.effect-fade.js, jquery.ui.effect-fold.js, jquery.ui.effect-highlight.js, jquery.ui.effect-pulsate.js, jquery.ui.effect-scale.js, jquery.ui.effect-shake.js, jquery.ui.effect-slide.js, jquery.ui.effect-transfer.js, jquery.ui.menu.js, jquery.ui.position.js, jquery.ui.progressbar.js, jquery.ui.slider.js, jquery.ui.spinner.js, jquery.ui.tabs.js, jquery.ui.tooltip.js -* Copyright 2012 jQuery Foundation and other contributors; Licensed MIT */ -(function(e,t){function i(t,n){var r,i,o,u=t.nodeName.toLowerCase();return"area"===u?(r=t.parentNode,i=r.name,!t.href||!i||r.nodeName.toLowerCase()!=="map"?!1:(o=e("img[usemap=#"+i+"]")[0],!!o&&s(o))):(/input|select|textarea|button|object/.test(u)?!t.disabled:"a"===u?t.href||n:n)&&s(t)}function s(t){return e.expr.filters.visible(t)&&!e(t).parents().andSelf().filter(function(){return e.css(this,"visibility")==="hidden"}).length}var n=0,r=/^ui-id-\d+$/;e.ui=e.ui||{};if(e.ui.version)return;e.extend(e.ui,{version:"1.9.2",keyCode:{BACKSPACE:8,COMMA:188,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,LEFT:37,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SPACE:32,TAB:9,UP:38}}),e.fn.extend({_focus:e.fn.focus,focus:function(t,n){return typeof t=="number"?this.each(function(){var r=this;setTimeout(function(){e(r).focus(),n&&n.call(r)},t)}):this._focus.apply(this,arguments)},scrollParent:function(){var t;return e.ui.ie&&/(static|relative)/.test(this.css("position"))||/absolute/.test(this.css("position"))?t=this.parents().filter(function(){return/(relative|absolute|fixed)/.test(e.css(this,"position"))&&/(auto|scroll)/.test(e.css(this,"overflow")+e.css(this,"overflow-y")+e.css(this,"overflow-x"))}).eq(0):t=this.parents().filter(function(){return/(auto|scroll)/.test(e.css(this,"overflow")+e.css(this,"overflow-y")+e.css(this,"overflow-x"))}).eq(0),/fixed/.test(this.css("position"))||!t.length?e(document):t},zIndex:function(n){if(n!==t)return this.css("zIndex",n);if(this.length){var r=e(this[0]),i,s;while(r.length&&r[0]!==document){i=r.css("position");if(i==="absolute"||i==="relative"||i==="fixed"){s=parseInt(r.css("zIndex"),10);if(!isNaN(s)&&s!==0)return s}r=r.parent()}}return 0},uniqueId:function(){return this.each(function(){this.id||(this.id="ui-id-"+ ++n)})},removeUniqueId:function(){return this.each(function(){r.test(this.id)&&e(this).removeAttr("id")})}}),e.extend(e.expr[":"],{data:e.expr.createPseudo?e.expr.createPseudo(function(t){return function(n){return!!e.data(n,t)}}):function(t,n,r){return!!e.data(t,r[3])},focusable:function(t){return i(t,!isNaN(e.attr(t,"tabindex")))},tabbable:function(t){var n=e.attr(t,"tabindex"),r=isNaN(n);return(r||n>=0)&&i(t,!r)}}),e(function(){var t=document.body,n=t.appendChild(n=document.createElement("div"));n.offsetHeight,e.extend(n.style,{minHeight:"100px",height:"auto",padding:0,borderWidth:0}),e.support.minHeight=n.offsetHeight===100,e.support.selectstart="onselectstart"in n,t.removeChild(n).style.display="none"}),e("<a>").outerWidth(1).jquery||e.each(["Width","Height"],function(n,r){function u(t,n,r,s){return e.each(i,function(){n-=parseFloat(e.css(t,"padding"+this))||0,r&&(n-=parseFloat(e.css(t,"border"+this+"Width"))||0),s&&(n-=parseFloat(e.css(t,"margin"+this))||0)}),n}var i=r==="Width"?["Left","Right"]:["Top","Bottom"],s=r.toLowerCase(),o={innerWidth:e.fn.innerWidth,innerHeight:e.fn.innerHeight,outerWidth:e.fn.outerWidth,outerHeight:e.fn.outerHeight};e.fn["inner"+r]=function(n){return n===t?o["inner"+r].call(this):this.each(function(){e(this).css(s,u(this,n)+"px")})},e.fn["outer"+r]=function(t,n){return typeof t!="number"?o["outer"+r].call(this,t):this.each(function(){e(this).css(s,u(this,t,!0,n)+"px")})}}),e("<a>").data("a-b","a").removeData("a-b").data("a-b")&&(e.fn.removeData=function(t){return function(n){return arguments.length?t.call(this,e.camelCase(n)):t.call(this)}}(e.fn.removeData)),function(){var t=/msie ([\w.]+)/.exec(navigator.userAgent.toLowerCase())||[];e.ui.ie=t.length?!0:!1,e.ui.ie6=parseFloat(t[1],10)===6}(),e.fn.extend({disableSelection:function(){return this.bind((e.support.selectstart?"selectstart":"mousedown")+".ui-disableSelection",function(e){e.preventDefault()})},enableSelection:function(){return this.unbind(".ui-disableSelection")}}),e.extend(e.ui,{plugin:{add:function(t,n,r){var i,s=e.ui[t].prototype;for(i in r)s.plugins[i]=s.plugins[i]||[],s.plugins[i].push([n,r[i]])},call:function(e,t,n){var r,i=e.plugins[t];if(!i||!e.element[0].parentNode||e.element[0].parentNode.nodeType===11)return;for(r=0;r<i.length;r++)e.options[i[r][0]]&&i[r][1].apply(e.element,n)}},contains:e.contains,hasScroll:function(t,n){if(e(t).css("overflow")==="hidden")return!1;var r=n&&n==="left"?"scrollLeft":"scrollTop",i=!1;return t[r]>0?!0:(t[r]=1,i=t[r]>0,t[r]=0,i)},isOverAxis:function(e,t,n){return e>t&&e<t+n},isOver:function(t,n,r,i,s,o){return e.ui.isOverAxis(t,r,s)&&e.ui.isOverAxis(n,i,o)}})})(jQuery),function(e,t){var n=0,r=Array.prototype.slice,i=e.cleanData;e.cleanData=function(t){for(var n=0,r;(r=t[n])!=null;n++)try{e(r).triggerHandler("remove")}catch(s){}i(t)},e.widget=function(t,n,r){var i,s,o,u,a=t.split(".")[0];t=t.split(".")[1],i=a+"-"+t,r||(r=n,n=e.Widget),e.expr[":"][i.toLowerCase()]=function(t){return!!e.data(t,i)},e[a]=e[a]||{},s=e[a][t],o=e[a][t]=function(e,t){if(!this._createWidget)return new o(e,t);arguments.length&&this._createWidget(e,t)},e.extend(o,s,{version:r.version,_proto:e.extend({},r),_childConstructors:[]}),u=new n,u.options=e.widget.extend({},u.options),e.each(r,function(t,i){e.isFunction(i)&&(r[t]=function(){var e=function(){return n.prototype[t].apply(this,arguments)},r=function(e){return n.prototype[t].apply(this,e)};return function(){var t=this._super,n=this._superApply,s;return this._super=e,this._superApply=r,s=i.apply(this,arguments),this._super=t,this._superApply=n,s}}())}),o.prototype=e.widget.extend(u,{widgetEventPrefix:s?u.widgetEventPrefix:t},r,{constructor:o,namespace:a,widgetName:t,widgetBaseClass:i,widgetFullName:i}),s?(e.each(s._childConstructors,function(t,n){var r=n.prototype;e.widget(r.namespace+"."+r.widgetName,o,n._proto)}),delete s._childConstructors):n._childConstructors.push(o),e.widget.bridge(t,o)},e.widget.extend=function(n){var i=r.call(arguments,1),s=0,o=i.length,u,a;for(;s<o;s++)for(u in i[s])a=i[s][u],i[s].hasOwnProperty(u)&&a!==t&&(e.isPlainObject(a)?n[u]=e.isPlainObject(n[u])?e.widget.extend({},n[u],a):e.widget.extend({},a):n[u]=a);return n},e.widget.bridge=function(n,i){var s=i.prototype.widgetFullName||n;e.fn[n]=function(o){var u=typeof o=="string",a=r.call(arguments,1),f=this;return o=!u&&a.length?e.widget.extend.apply(null,[o].concat(a)):o,u?this.each(function(){var r,i=e.data(this,s);if(!i)return e.error("cannot call methods on "+n+" prior to initialization; "+"attempted to call method '"+o+"'");if(!e.isFunction(i[o])||o.charAt(0)==="_")return e.error("no such method '"+o+"' for "+n+" widget instance");r=i[o].apply(i,a);if(r!==i&&r!==t)return f=r&&r.jquery?f.pushStack(r.get()):r,!1}):this.each(function(){var t=e.data(this,s);t?t.option(o||{})._init():e.data(this,s,new i(o,this))}),f}},e.Widget=function(){},e.Widget._childConstructors=[],e.Widget.prototype={widgetName:"widget",widgetEventPrefix:"",defaultElement:"<div>",options:{disabled:!1,create:null},_createWidget:function(t,r){r=e(r||this.defaultElement||this)[0],this.element=e(r),this.uuid=n++,this.eventNamespace="."+this.widgetName+this.uuid,this.options=e.widget.extend({},this.options,this._getCreateOptions(),t),this.bindings=e(),this.hoverable=e(),this.focusable=e(),r!==this&&(e.data(r,this.widgetName,this),e.data(r,this.widgetFullName,this),this._on(!0,this.element,{remove:function(e){e.target===r&&this.destroy()}}),this.document=e(r.style?r.ownerDocument:r.document||r),this.window=e(this.document[0].defaultView||this.document[0].parentWindow)),this._create(),this._trigger("create",null,this._getCreateEventData()),this._init()},_getCreateOptions:e.noop,_getCreateEventData:e.noop,_create:e.noop,_init:e.noop,destroy:function(){this._destroy(),this.element.unbind(this.eventNamespace).removeData(this.widgetName).removeData(this.widgetFullName).removeData(e.camelCase(this.widgetFullName)),this.widget().unbind(this.eventNamespace).removeAttr("aria-disabled").removeClass(this.widgetFullName+"-disabled "+"ui-state-disabled"),this.bindings.unbind(this.eventNamespace),this.hoverable.removeClass("ui-state-hover"),this.focusable.removeClass("ui-state-focus")},_destroy:e.noop,widget:function(){return this.element},option:function(n,r){var i=n,s,o,u;if(arguments.length===0)return e.widget.extend({},this.options);if(typeof n=="string"){i={},s=n.split("."),n=s.shift();if(s.length){o=i[n]=e.widget.extend({},this.options[n]);for(u=0;u<s.length-1;u++)o[s[u]]=o[s[u]]||{},o=o[s[u]];n=s.pop();if(r===t)return o[n]===t?null:o[n];o[n]=r}else{if(r===t)return this.options[n]===t?null:this.options[n];i[n]=r}}return this._setOptions(i),this},_setOptions:function(e){var t;for(t in e)this._setOption(t,e[t]);return this},_setOption:function(e,t){return this.options[e]=t,e==="disabled"&&(this.widget().toggleClass(this.widgetFullName+"-disabled ui-state-disabled",!!t).attr("aria-disabled",t),this.hoverable.removeClass("ui-state-hover"),this.focusable.removeClass("ui-state-focus")),this},enable:function(){return this._setOption("disabled",!1)},disable:function(){return this._setOption("disabled",!0)},_on:function(t,n,r){var i,s=this;typeof t!="boolean"&&(r=n,n=t,t=!1),r?(n=i=e(n),this.bindings=this.bindings.add(n)):(r=n,n=this.element,i=this.widget()),e.each(r,function(r,o){function u(){if(!t&&(s.options.disabled===!0||e(this).hasClass("ui-state-disabled")))return;return(typeof o=="string"?s[o]:o).apply(s,arguments)}typeof o!="string"&&(u.guid=o.guid=o.guid||u.guid||e.guid++);var a=r.match(/^(\w+)\s*(.*)$/),f=a[1]+s.eventNamespace,l=a[2];l?i.delegate(l,f,u):n.bind(f,u)})},_off:function(e,t){t=(t||"").split(" ").join(this.eventNamespace+" ")+this.eventNamespace,e.unbind(t).undelegate(t)},_delay:function(e,t){function n(){return(typeof e=="string"?r[e]:e).apply(r,arguments)}var r=this;return setTimeout(n,t||0)},_hoverable:function(t){this.hoverable=this.hoverable.add(t),this._on(t,{mouseenter:function(t){e(t.currentTarget).addClass("ui-state-hover")},mouseleave:function(t){e(t.currentTarget).removeClass("ui-state-hover")}})},_focusable:function(t){this.focusable=this.focusable.add(t),this._on(t,{focusin:function(t){e(t.currentTarget).addClass("ui-state-focus")},focusout:function(t){e(t.currentTarget).removeClass("ui-state-focus")}})},_trigger:function(t,n,r){var i,s,o=this.options[t];r=r||{},n=e.Event(n),n.type=(t===this.widgetEventPrefix?t:this.widgetEventPrefix+t).toLowerCase(),n.target=this.element[0],s=n.originalEvent;if(s)for(i in s)i in n||(n[i]=s[i]);return this.element.trigger(n,r),!(e.isFunction(o)&&o.apply(this.element[0],[n].concat(r))===!1||n.isDefaultPrevented())}},e.each({show:"fadeIn",hide:"fadeOut"},function(t,n){e.Widget.prototype["_"+t]=function(r,i,s){typeof i=="string"&&(i={effect:i});var o,u=i?i===!0||typeof i=="number"?n:i.effect||n:t;i=i||{},typeof i=="number"&&(i={duration:i}),o=!e.isEmptyObject(i),i.complete=s,i.delay&&r.delay(i.delay),o&&e.effects&&(e.effects.effect[u]||e.uiBackCompat!==!1&&e.effects[u])?r[t](i):u!==t&&r[u]?r[u](i.duration,i.easing,s):r.queue(function(n){e(this)[t](),s&&s.call(r[0]),n()})}}),e.uiBackCompat!==!1&&(e.Widget.prototype._getCreateOptions=function(){return e.metadata&&e.metadata.get(this.element[0])[this.widgetName]})}(jQuery),function(e,t){var n=!1;e(document).mouseup(function(e){n=!1}),e.widget("ui.mouse",{version:"1.9.2",options:{cancel:"input,textarea,button,select,option",distance:1,delay:0},_mouseInit:function(){var t=this;this.element.bind("mousedown."+this.widgetName,function(e){return t._mouseDown(e)}).bind("click."+this.widgetName,function(n){if(!0===e.data(n.target,t.widgetName+".preventClickEvent"))return e.removeData(n.target,t.widgetName+".preventClickEvent"),n.stopImmediatePropagation(),!1}),this.started=!1},_mouseDestroy:function(){this.element.unbind("."+this.widgetName),this._mouseMoveDelegate&&e(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate)},_mouseDown:function(t){if(n)return;this._mouseStarted&&this._mouseUp(t),this._mouseDownEvent=t;var r=this,i=t.which===1,s=typeof this.options.cancel=="string"&&t.target.nodeName?e(t.target).closest(this.options.cancel).length:!1;if(!i||s||!this._mouseCapture(t))return!0;this.mouseDelayMet=!this.options.delay,this.mouseDelayMet||(this._mouseDelayTimer=setTimeout(function(){r.mouseDelayMet=!0},this.options.delay));if(this._mouseDistanceMet(t)&&this._mouseDelayMet(t)){this._mouseStarted=this._mouseStart(t)!==!1;if(!this._mouseStarted)return t.preventDefault(),!0}return!0===e.data(t.target,this.widgetName+".preventClickEvent")&&e.removeData(t.target,this.widgetName+".preventClickEvent"),this._mouseMoveDelegate=function(e){return r._mouseMove(e)},this._mouseUpDelegate=function(e){return r._mouseUp(e)},e(document).bind("mousemove."+this.widgetName,this._mouseMoveDelegate).bind("mouseup."+this.widgetName,this._mouseUpDelegate),t.preventDefault(),n=!0,!0},_mouseMove:function(t){return!e.ui.ie||document.documentMode>=9||!!t.button?this._mouseStarted?(this._mouseDrag(t),t.preventDefault()):(this._mouseDistanceMet(t)&&this._mouseDelayMet(t)&&(this._mouseStarted=this._mouseStart(this._mouseDownEvent,t)!==!1,this._mouseStarted?this._mouseDrag(t):this._mouseUp(t)),!this._mouseStarted):this._mouseUp(t)},_mouseUp:function(t){return e(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate),this._mouseStarted&&(this._mouseStarted=!1,t.target===this._mouseDownEvent.target&&e.data(t.target,this.widgetName+".preventClickEvent",!0),this._mouseStop(t)),!1},_mouseDistanceMet:function(e){return Math.max(Math.abs(this._mouseDownEvent.pageX-e.pageX),Math.abs(this._mouseDownEvent.pageY-e.pageY))>=this.options.distance},_mouseDelayMet:function(e){return this.mouseDelayMet},_mouseStart:function(e){},_mouseDrag:function(e){},_mouseStop:function(e){},_mouseCapture:function(e){return!0}})}(jQuery),function(e,t){e.widget("ui.draggable",e.ui.mouse,{version:"1.9.2",widgetEventPrefix:"drag",options:{addClasses:!0,appendTo:"parent",axis:!1,connectToSortable:!1,containment:!1,cursor:"auto",cursorAt:!1,grid:!1,handle:!1,helper:"original",iframeFix:!1,opacity:!1,refreshPositions:!1,revert:!1,revertDuration:500,scope:"default",scroll:!0,scrollSensitivity:20,scrollSpeed:20,snap:!1,snapMode:"both",snapTolerance:20,stack:!1,zIndex:!1},_create:function(){this.options.helper=="original"&&!/^(?:r|a|f)/.test(this.element.css("position"))&&(this.element[0].style.position="relative"),this.options.addClasses&&this.element.addClass("ui-draggable"),this.options.disabled&&this.element.addClass("ui-draggable-disabled"),this._mouseInit()},_destroy:function(){this.element.removeClass("ui-draggable ui-draggable-dragging ui-draggable-disabled"),this._mouseDestroy()},_mouseCapture:function(t){var n=this.options;return this.helper||n.disabled||e(t.target).is(".ui-resizable-handle")?!1:(this.handle=this._getHandle(t),this.handle?(e(n.iframeFix===!0?"iframe":n.iframeFix).each(function(){e('<div class="ui-draggable-iframeFix" style="background: #fff;"></div>').css({width:this.offsetWidth+"px",height:this.offsetHeight+"px",position:"absolute",opacity:"0.001",zIndex:1e3}).css(e(this).offset()).appendTo("body")}),!0):!1)},_mouseStart:function(t){var n=this.options;return this.helper=this._createHelper(t),this.helper.addClass("ui-draggable-dragging"),this._cacheHelperProportions(),e.ui.ddmanager&&(e.ui.ddmanager.current=this),this._cacheMargins(),this.cssPosition=this.helper.css("position"),this.scrollParent=this.helper.scrollParent(),this.offset=this.positionAbs=this.element.offset(),this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left},e.extend(this.offset,{click:{left:t.pageX-this.offset.left,top:t.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()}),this.originalPosition=this.position=this._generatePosition(t),this.originalPageX=t.pageX,this.originalPageY=t.pageY,n.cursorAt&&this._adjustOffsetFromHelper(n.cursorAt),n.containment&&this._setContainment(),this._trigger("start",t)===!1?(this._clear(),!1):(this._cacheHelperProportions(),e.ui.ddmanager&&!n.dropBehaviour&&e.ui.ddmanager.prepareOffsets(this,t),this._mouseDrag(t,!0),e.ui.ddmanager&&e.ui.ddmanager.dragStart(this,t),!0)},_mouseDrag:function(t,n){this.position=this._generatePosition(t),this.positionAbs=this._convertPositionTo("absolute");if(!n){var r=this._uiHash();if(this._trigger("drag",t,r)===!1)return this._mouseUp({}),!1;this.position=r.position}if(!this.options.axis||this.options.axis!="y")this.helper[0].style.left=this.position.left+"px";if(!this.options.axis||this.options.axis!="x")this.helper[0].style.top=this.position.top+"px";return e.ui.ddmanager&&e.ui.ddmanager.drag(this,t),!1},_mouseStop:function(t){var n=!1;e.ui.ddmanager&&!this.options.dropBehaviour&&(n=e.ui.ddmanager.drop(this,t)),this.dropped&&(n=this.dropped,this.dropped=!1);var r=this.element[0],i=!1;while(r&&(r=r.parentNode))r==document&&(i=!0);if(!i&&this.options.helper==="original")return!1;if(this.options.revert=="invalid"&&!n||this.options.revert=="valid"&&n||this.options.revert===!0||e.isFunction(this.options.revert)&&this.options.revert.call(this.element,n)){var s=this;e(this.helper).animate(this.originalPosition,parseInt(this.options.revertDuration,10),function(){s._trigger("stop",t)!==!1&&s._clear()})}else this._trigger("stop",t)!==!1&&this._clear();return!1},_mouseUp:function(t){return e("div.ui-draggable-iframeFix").each(function(){this.parentNode.removeChild(this)}),e.ui.ddmanager&&e.ui.ddmanager.dragStop(this,t),e.ui.mouse.prototype._mouseUp.call(this,t)},cancel:function(){return this.helper.is(".ui-draggable-dragging")?this._mouseUp({}):this._clear(),this},_getHandle:function(t){var n=!this.options.handle||!e(this.options.handle,this.element).length?!0:!1;return e(this.options.handle,this.element).find("*").andSelf().each(function(){this==t.target&&(n=!0)}),n},_createHelper:function(t){var n=this.options,r=e.isFunction(n.helper)?e(n.helper.apply(this.element[0],[t])):n.helper=="clone"?this.element.clone().removeAttr("id"):this.element;return r.parents("body").length||r.appendTo(n.appendTo=="parent"?this.element[0].parentNode:n.appendTo),r[0]!=this.element[0]&&!/(fixed|absolute)/.test(r.css("position"))&&r.css("position","absolute"),r},_adjustOffsetFromHelper:function(t){typeof t=="string"&&(t=t.split(" ")),e.isArray(t)&&(t={left:+t[0],top:+t[1]||0}),"left"in t&&(this.offset.click.left=t.left+this.margins.left),"right"in t&&(this.offset.click.left=this.helperProportions.width-t.right+this.margins.left),"top"in t&&(this.offset.click.top=t.top+this.margins.top),"bottom"in t&&(this.offset.click.top=this.helperProportions.height-t.bottom+this.margins.top)},_getParentOffset:function(){this.offsetParent=this.helper.offsetParent();var t=this.offsetParent.offset();this.cssPosition=="absolute"&&this.scrollParent[0]!=document&&e.contains(this.scrollParent[0],this.offsetParent[0])&&(t.left+=this.scrollParent.scrollLeft(),t.top+=this.scrollParent.scrollTop());if(this.offsetParent[0]==document.body||this.offsetParent[0].tagName&&this.offsetParent[0].tagName.toLowerCase()=="html"&&e.ui.ie)t={top:0,left:0};return{top:t.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:t.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if(this.cssPosition=="relative"){var e=this.element.position();return{top:e.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:e.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.element.css("marginLeft"),10)||0,top:parseInt(this.element.css("marginTop"),10)||0,right:parseInt(this.element.css("marginRight"),10)||0,bottom:parseInt(this.element.css("marginBottom"),10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var t=this.options;t.containment=="parent"&&(t.containment=this.helper[0].parentNode);if(t.containment=="document"||t.containment=="window")this.containment=[t.containment=="document"?0:e(window).scrollLeft()-this.offset.relative.left-this.offset.parent.left,t.containment=="document"?0:e(window).scrollTop()-this.offset.relative.top-this.offset.parent.top,(t.containment=="document"?0:e(window).scrollLeft())+e(t.containment=="document"?document:window).width()-this.helperProportions.width-this.margins.left,(t.containment=="document"?0:e(window).scrollTop())+(e(t.containment=="document"?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top];if(!/^(document|window|parent)$/.test(t.containment)&&t.containment.constructor!=Array){var n=e(t.containment),r=n[0];if(!r)return;var i=n.offset(),s=e(r).css("overflow")!="hidden";this.containment=[(parseInt(e(r).css("borderLeftWidth"),10)||0)+(parseInt(e(r).css("paddingLeft"),10)||0),(parseInt(e(r).css("borderTopWidth"),10)||0)+(parseInt(e(r).css("paddingTop"),10)||0),(s?Math.max(r.scrollWidth,r.offsetWidth):r.offsetWidth)-(parseInt(e(r).css("borderLeftWidth"),10)||0)-(parseInt(e(r).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left-this.margins.right,(s?Math.max(r.scrollHeight,r.offsetHeight):r.offsetHeight)-(parseInt(e(r).css("borderTopWidth"),10)||0)-(parseInt(e(r).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top-this.margins.bottom],this.relative_container=n}else t.containment.constructor==Array&&(this.containment=t.containment)},_convertPositionTo:function(t,n){n||(n=this.position);var r=t=="absolute"?1:-1,i=this.options,s=this.cssPosition!="absolute"||this.scrollParent[0]!=document&&!!e.contains(this.scrollParent[0],this.offsetParent[0])?this.scrollParent:this.offsetParent,o=/(html|body)/i.test(s[0].tagName);return{top:n.top+this.offset.relative.top*r+this.offset.parent.top*r-(this.cssPosition=="fixed"?-this.scrollParent.scrollTop():o?0:s.scrollTop())*r,left:n.left+this.offset.relative.left*r+this.offset.parent.left*r-(this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():o?0:s.scrollLeft())*r}},_generatePosition:function(t){var n=this.options,r=this.cssPosition!="absolute"||this.scrollParent[0]!=document&&!!e.contains(this.scrollParent[0],this.offsetParent[0])?this.scrollParent:this.offsetParent,i=/(html|body)/i.test(r[0].tagName),s=t.pageX,o=t.pageY;if(this.originalPosition){var u;if(this.containment){if(this.relative_container){var a=this.relative_container.offset();u=[this.containment[0]+a.left,this.containment[1]+a.top,this.containment[2]+a.left,this.containment[3]+a.top]}else u=this.containment;t.pageX-this.offset.click.left<u[0]&&(s=u[0]+this.offset.click.left),t.pageY-this.offset.click.top<u[1]&&(o=u[1]+this.offset.click.top),t.pageX-this.offset.click.left>u[2]&&(s=u[2]+this.offset.click.left),t.pageY-this.offset.click.top>u[3]&&(o=u[3]+this.offset.click.top)}if(n.grid){var f=n.grid[1]?this.originalPageY+Math.round((o-this.originalPageY)/n.grid[1])*n.grid[1]:this.originalPageY;o=u?f-this.offset.click.top<u[1]||f-this.offset.click.top>u[3]?f-this.offset.click.top<u[1]?f+n.grid[1]:f-n.grid[1]:f:f;var l=n.grid[0]?this.originalPageX+Math.round((s-this.originalPageX)/n.grid[0])*n.grid[0]:this.originalPageX;s=u?l-this.offset.click.left<u[0]||l-this.offset.click.left>u[2]?l-this.offset.click.left<u[0]?l+n.grid[0]:l-n.grid[0]:l:l}}return{top:o-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+(this.cssPosition=="fixed"?-this.scrollParent.scrollTop():i?0:r.scrollTop()),left:s-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+(this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():i?0:r.scrollLeft())}},_clear:function(){this.helper.removeClass("ui-draggable-dragging"),this.helper[0]!=this.element[0]&&!this.cancelHelperRemoval&&this.helper.remove(),this.helper=null,this.cancelHelperRemoval=!1},_trigger:function(t,n,r){return r=r||this._uiHash(),e.ui.plugin.call(this,t,[n,r]),t=="drag"&&(this.positionAbs=this._convertPositionTo("absolute")),e.Widget.prototype._trigger.call(this,t,n,r)},plugins:{},_uiHash:function(e){return{helper:this.helper,position:this.position,originalPosition:this.originalPosition,offset:this.positionAbs}}}),e.ui.plugin.add("draggable","connectToSortable",{start:function(t,n){var r=e(this).data("draggable"),i=r.options,s=e.extend({},n,{item:r.element});r.sortables=[],e(i.connectToSortable).each(function(){var n=e.data(this,"sortable");n&&!n.options.disabled&&(r.sortables.push({instance:n,shouldRevert:n.options.revert}),n.refreshPositions(),n._trigger("activate",t,s))})},stop:function(t,n){var r=e(this).data("draggable"),i=e.extend({},n,{item:r.element});e.each(r.sortables,function(){this.instance.isOver?(this.instance.isOver=0,r.cancelHelperRemoval=!0,this.instance.cancelHelperRemoval=!1,this.shouldRevert&&(this.instance.options.revert=!0),this.instance._mouseStop(t),this.instance.options.helper=this.instance.options._helper,r.options.helper=="original"&&this.instance.currentItem.css({top:"auto",left:"auto"})):(this.instance.cancelHelperRemoval=!1,this.instance._trigger("deactivate",t,i))})},drag:function(t,n){var r=e(this).data("draggable"),i=this,s=function(t){var n=this.offset.click.top,r=this.offset.click.left,i=this.positionAbs.top,s=this.positionAbs.left,o=t.height,u=t.width,a=t.top,f=t.left;return e.ui.isOver(i+n,s+r,a,f,o,u)};e.each(r.sortables,function(s){var o=!1,u=this;this.instance.positionAbs=r.positionAbs,this.instance.helperProportions=r.helperProportions,this.instance.offset.click=r.offset.click,this.instance._intersectsWith(this.instance.containerCache)&&(o=!0,e.each(r.sortables,function(){return this.instance.positionAbs=r.positionAbs,this.instance.helperProportions=r.helperProportions,this.instance.offset.click=r.offset.click,this!=u&&this.instance._intersectsWith(this.instance.containerCache)&&e.ui.contains(u.instance.element[0],this.instance.element[0])&&(o=!1),o})),o?(this.instance.isOver||(this.instance.isOver=1,this.instance.currentItem=e(i).clone().removeAttr("id").appendTo(this.instance.element).data("sortable-item",!0),this.instance.options._helper=this.instance.options.helper,this.instance.options.helper=function(){return n.helper[0]},t.target=this.instance.currentItem[0],this.instance._mouseCapture(t,!0),this.instance._mouseStart(t,!0,!0),this.instance.offset.click.top=r.offset.click.top,this.instance.offset.click.left=r.offset.click.left,this.instance.offset.parent.left-=r.offset.parent.left-this.instance.offset.parent.left,this.instance.offset.parent.top-=r.offset.parent.top-this.instance.offset.parent.top,r._trigger("toSortable",t),r.dropped=this.instance.element,r.currentItem=r.element,this.instance.fromOutside=r),this.instance.currentItem&&this.instance._mouseDrag(t)):this.instance.isOver&&(this.instance.isOver=0,this.instance.cancelHelperRemoval=!0,this.instance.options.revert=!1,this.instance._trigger("out",t,this.instance._uiHash(this.instance)),this.instance._mouseStop(t,!0),this.instance.options.helper=this.instance.options._helper,this.instance.currentItem.remove(),this.instance.placeholder&&this.instance.placeholder.remove(),r._trigger("fromSortable",t),r.dropped=!1)})}}),e.ui.plugin.add("draggable","cursor",{start:function(t,n){var r=e("body"),i=e(this).data("draggable").options;r.css("cursor")&&(i._cursor=r.css("cursor")),r.css("cursor",i.cursor)},stop:function(t,n){var r=e(this).data("draggable").options;r._cursor&&e("body").css("cursor",r._cursor)}}),e.ui.plugin.add("draggable","opacity",{start:function(t,n){var r=e(n.helper),i=e(this).data("draggable").options;r.css("opacity")&&(i._opacity=r.css("opacity")),r.css("opacity",i.opacity)},stop:function(t,n){var r=e(this).data("draggable").options;r._opacity&&e(n.helper).css("opacity",r._opacity)}}),e.ui.plugin.add("draggable","scroll",{start:function(t,n){var r=e(this).data("draggable");r.scrollParent[0]!=document&&r.scrollParent[0].tagName!="HTML"&&(r.overflowOffset=r.scrollParent.offset())},drag:function(t,n){var r=e(this).data("draggable"),i=r.options,s=!1;if(r.scrollParent[0]!=document&&r.scrollParent[0].tagName!="HTML"){if(!i.axis||i.axis!="x")r.overflowOffset.top+r.scrollParent[0].offsetHeight-t.pageY<i.scrollSensitivity?r.scrollParent[0].scrollTop=s=r.scrollParent[0].scrollTop+i.scrollSpeed:t.pageY-r.overflowOffset.top<i.scrollSensitivity&&(r.scrollParent[0].scrollTop=s=r.scrollParent[0].scrollTop-i.scrollSpeed);if(!i.axis||i.axis!="y")r.overflowOffset.left+r.scrollParent[0].offsetWidth-t.pageX<i.scrollSensitivity?r.scrollParent[0].scrollLeft=s=r.scrollParent[0].scrollLeft+i.scrollSpeed:t.pageX-r.overflowOffset.left<i.scrollSensitivity&&(r.scrollParent[0].scrollLeft=s=r.scrollParent[0].scrollLeft-i.scrollSpeed)}else{if(!i.axis||i.axis!="x")t.pageY-e(document).scrollTop()<i.scrollSensitivity?s=e(document).scrollTop(e(document).scrollTop()-i.scrollSpeed):e(window).height()-(t.pageY-e(document).scrollTop())<i.scrollSensitivity&&(s=e(document).scrollTop(e(document).scrollTop()+i.scrollSpeed));if(!i.axis||i.axis!="y")t.pageX-e(document).scrollLeft()<i.scrollSensitivity?s=e(document).scrollLeft(e(document).scrollLeft()-i.scrollSpeed):e(window).width()-(t.pageX-e(document).scrollLeft())<i.scrollSensitivity&&(s=e(document).scrollLeft(e(document).scrollLeft()+i.scrollSpeed))}s!==!1&&e.ui.ddmanager&&!i.dropBehaviour&&e.ui.ddmanager.prepareOffsets(r,t)}}),e.ui.plugin.add("draggable","snap",{start:function(t,n){var r=e(this).data("draggable"),i=r.options;r.snapElements=[],e(i.snap.constructor!=String?i.snap.items||":data(draggable)":i.snap).each(function(){var t=e(this),n=t.offset();this!=r.element[0]&&r.snapElements.push({item:this,width:t.outerWidth(),height:t.outerHeight(),top:n.top,left:n.left})})},drag:function(t,n){var r=e(this).data("draggable"),i=r.options,s=i.snapTolerance,o=n.offset.left,u=o+r.helperProportions.width,a=n.offset.top,f=a+r.helperProportions.height;for(var l=r.snapElements.length-1;l>=0;l--){var c=r.snapElements[l].left,h=c+r.snapElements[l].width,p=r.snapElements[l].top,d=p+r.snapElements[l].height;if(!(c-s<o&&o<h+s&&p-s<a&&a<d+s||c-s<o&&o<h+s&&p-s<f&&f<d+s||c-s<u&&u<h+s&&p-s<a&&a<d+s||c-s<u&&u<h+s&&p-s<f&&f<d+s)){r.snapElements[l].snapping&&r.options.snap.release&&r.options.snap.release.call(r.element,t,e.extend(r._uiHash(),{snapItem:r.snapElements[l].item})),r.snapElements[l].snapping=!1;continue}if(i.snapMode!="inner"){var v=Math.abs(p-f)<=s,m=Math.abs(d-a)<=s,g=Math.abs(c-u)<=s,y=Math.abs(h-o)<=s;v&&(n.position.top=r._convertPositionTo("relative",{top:p-r.helperProportions.height,left:0}).top-r.margins.top),m&&(n.position.top=r._convertPositionTo("relative",{top:d,left:0}).top-r.margins.top),g&&(n.position.left=r._convertPositionTo("relative",{top:0,left:c-r.helperProportions.width}).left-r.margins.left),y&&(n.position.left=r._convertPositionTo("relative",{top:0,left:h}).left-r.margins.left)}var b=v||m||g||y;if(i.snapMode!="outer"){var v=Math.abs(p-a)<=s,m=Math.abs(d-f)<=s,g=Math.abs(c-o)<=s,y=Math.abs(h-u)<=s;v&&(n.position.top=r._convertPositionTo("relative",{top:p,left:0}).top-r.margins.top),m&&(n.position.top=r._convertPositionTo("relative",{top:d-r.helperProportions.height,left:0}).top-r.margins.top),g&&(n.position.left=r._convertPositionTo("relative",{top:0,left:c}).left-r.margins.left),y&&(n.position.left=r._convertPositionTo("relative",{top:0,left:h-r.helperProportions.width}).left-r.margins.left)}!r.snapElements[l].snapping&&(v||m||g||y||b)&&r.options.snap.snap&&r.options.snap.snap.call(r.element,t,e.extend(r._uiHash(),{snapItem:r.snapElements[l].item})),r.snapElements[l].snapping=v||m||g||y||b}}}),e.ui.plugin.add("draggable","stack",{start:function(t,n){var r=e(this).data("draggable").options,i=e.makeArray(e(r.stack)).sort(function(t,n){return(parseInt(e(t).css("zIndex"),10)||0)-(parseInt(e(n).css("zIndex"),10)||0)});if(!i.length)return;var s=parseInt(i[0].style.zIndex)||0;e(i).each(function(e){this.style.zIndex=s+e}),this[0].style.zIndex=s+i.length}}),e.ui.plugin.add("draggable","zIndex",{start:function(t,n){var r=e(n.helper),i=e(this).data("draggable").options;r.css("zIndex")&&(i._zIndex=r.css("zIndex")),r.css("zIndex",i.zIndex)},stop:function(t,n){var r=e(this).data("draggable").options;r._zIndex&&e(n.helper).css("zIndex",r._zIndex)}})}(jQuery),function(e,t){e.widget("ui.droppable",{version:"1.9.2",widgetEventPrefix:"drop",options:{accept:"*",activeClass:!1,addClasses:!0,greedy:!1,hoverClass:!1,scope:"default",tolerance:"intersect"},_create:function(){var t=this.options,n=t.accept;this.isover=0,this.isout=1,this.accept=e.isFunction(n)?n:function(e){return e.is(n)},this.proportions={width:this.element[0].offsetWidth,height:this.element[0].offsetHeight},e.ui.ddmanager.droppables[t.scope]=e.ui.ddmanager.droppables[t.scope]||[],e.ui.ddmanager.droppables[t.scope].push(this),t.addClasses&&this.element.addClass("ui-droppable")},_destroy:function(){var t=e.ui.ddmanager.droppables[this.options.scope];for(var n=0;n<t.length;n++)t[n]==this&&t.splice(n,1);this.element.removeClass("ui-droppable ui-droppable-disabled")},_setOption:function(t,n){t=="accept"&&(this.accept=e.isFunction(n)?n:function(e){return e.is(n)}),e.Widget.prototype._setOption.apply(this,arguments)},_activate:function(t){var n=e.ui.ddmanager.current;this.options.activeClass&&this.element.addClass(this.options.activeClass),n&&this._trigger("activate",t,this.ui(n))},_deactivate:function(t){var n=e.ui.ddmanager.current;this.options.activeClass&&this.element.removeClass(this.options.activeClass),n&&this._trigger("deactivate",t,this.ui(n))},_over:function(t){var n=e.ui.ddmanager.current;if(!n||(n.currentItem||n.element)[0]==this.element[0])return;this.accept.call(this.element[0],n.currentItem||n.element)&&(this.options.hoverClass&&this.element.addClass(this.options.hoverClass),this._trigger("over",t,this.ui(n)))},_out:function(t){var n=e.ui.ddmanager.current;if(!n||(n.currentItem||n.element)[0]==this.element[0])return;this.accept.call(this.element[0],n.currentItem||n.element)&&(this.options.hoverClass&&this.element.removeClass(this.options.hoverClass),this._trigger("out",t,this.ui(n)))},_drop:function(t,n){var r=n||e.ui.ddmanager.current;if(!r||(r.currentItem||r.element)[0]==this.element[0])return!1;var i=!1;return this.element.find(":data(droppable)").not(".ui-draggable-dragging").each(function(){var t=e.data(this,"droppable");if(t.options.greedy&&!t.options.disabled&&t.options.scope==r.options.scope&&t.accept.call(t.element[0],r.currentItem||r.element)&&e.ui.intersect(r,e.extend(t,{offset:t.element.offset()}),t.options.tolerance))return i=!0,!1}),i?!1:this.accept.call(this.element[0],r.currentItem||r.element)?(this.options.activeClass&&this.element.removeClass(this.options.activeClass),this.options.hoverClass&&this.element.removeClass(this.options.hoverClass),this._trigger("drop",t,this.ui(r)),this.element):!1},ui:function(e){return{draggable:e.currentItem||e.element,helper:e.helper,position:e.position,offset:e.positionAbs}}}),e.ui.intersect=function(t,n,r){if(!n.offset)return!1;var i=(t.positionAbs||t.position.absolute).left,s=i+t.helperProportions.width,o=(t.positionAbs||t.position.absolute).top,u=o+t.helperProportions.height,a=n.offset.left,f=a+n.proportions.width,l=n.offset.top,c=l+n.proportions.height;switch(r){case"fit":return a<=i&&s<=f&&l<=o&&u<=c;case"intersect":return a<i+t.helperProportions.width/2&&s-t.helperProportions.width/2<f&&l<o+t.helperProportions.height/2&&u-t.helperProportions.height/2<c;case"pointer":var h=(t.positionAbs||t.position.absolute).left+(t.clickOffset||t.offset.click).left,p=(t.positionAbs||t.position.absolute).top+(t.clickOffset||t.offset.click).top,d=e.ui.isOver(p,h,l,a,n.proportions.height,n.proportions.width);return d;case"touch":return(o>=l&&o<=c||u>=l&&u<=c||o<l&&u>c)&&(i>=a&&i<=f||s>=a&&s<=f||i<a&&s>f);default:return!1}},e.ui.ddmanager={current:null,droppables:{"default":[]},prepareOffsets:function(t,n){var r=e.ui.ddmanager.droppables[t.options.scope]||[],i=n?n.type:null,s=(t.currentItem||t.element).find(":data(droppable)").andSelf();e:for(var o=0;o<r.length;o++){if(r[o].options.disabled||t&&!r[o].accept.call(r[o].element[0],t.currentItem||t.element))continue;for(var u=0;u<s.length;u++)if(s[u]==r[o].element[0]){r[o].proportions.height=0;continue e}r[o].visible=r[o].element.css("display")!="none";if(!r[o].visible)continue;i=="mousedown"&&r[o]._activate.call(r[o],n),r[o].offset=r[o].element.offset(),r[o].proportions={width:r[o].element[0].offsetWidth,height:r[o].element[0].offsetHeight}}},drop:function(t,n){var r=!1;return e.each(e.ui.ddmanager.droppables[t.options.scope]||[],function(){if(!this.options)return;!this.options.disabled&&this.visible&&e.ui.intersect(t,this,this.options.tolerance)&&(r=this._drop.call(this,n)||r),!this.options.disabled&&this.visible&&this.accept.call(this.element[0],t.currentItem||t.element)&&(this.isout=1,this.isover=0,this._deactivate.call(this,n))}),r},dragStart:function(t,n){t.element.parentsUntil("body").bind("scroll.droppable",function(){t.options.refreshPositions||e.ui.ddmanager.prepareOffsets(t,n)})},drag:function(t,n){t.options.refreshPositions&&e.ui.ddmanager.prepareOffsets(t,n),e.each(e.ui.ddmanager.droppables[t.options.scope]||[],function(){if(this.options.disabled||this.greedyChild||!this.visible)return;var r=e.ui.intersect(t,this,this.options.tolerance),i=!r&&this.isover==1?"isout":r&&this.isover==0?"isover":null;if(!i)return;var s;if(this.options.greedy){var o=this.options.scope,u=this.element.parents(":data(droppable)").filter(function(){return e.data(this,"droppable").options.scope===o});u.length&&(s=e.data(u[0],"droppable"),s.greedyChild=i=="isover"?1:0)}s&&i=="isover"&&(s.isover=0,s.isout=1,s._out.call(s,n)),this[i]=1,this[i=="isout"?"isover":"isout"]=0,this[i=="isover"?"_over":"_out"].call(this,n),s&&i=="isout"&&(s.isout=0,s.isover=1,s._over.call(s,n))})},dragStop:function(t,n){t.element.parentsUntil("body").unbind("scroll.droppable"),t.options.refreshPositions||e.ui.ddmanager.prepareOffsets(t,n)}}}(jQuery),function(e,t){e.widget("ui.resizable",e.ui.mouse,{version:"1.9.2",widgetEventPrefix:"resize",options:{alsoResize:!1,animate:!1,animateDuration:"slow",animateEasing:"swing",aspectRatio:!1,autoHide:!1,containment:!1,ghost:!1,grid:!1,handles:"e,s,se",helper:!1,maxHeight:null,maxWidth:null,minHeight:10,minWidth:10,zIndex:1e3},_create:function(){var t=this,n=this.options;this.element.addClass("ui-resizable"),e.extend(this,{_aspectRatio:!!n.aspectRatio,aspectRatio:n.aspectRatio,originalElement:this.element,_proportionallyResizeElements:[],_helper:n.helper||n.ghost||n.animate?n.helper||"ui-resizable-helper":null}),this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)&&(this.element.wrap(e('<div class="ui-wrapper" style="overflow: hidden;"></div>').css({position:this.element.css("position"),width:this.element.outerWidth(),height:this.element.outerHeight(),top:this.element.css("top"),left:this.element.css("left")})),this.element=this.element.parent().data("resizable",this.element.data("resizable")),this.elementIsWrapper=!0,this.element.css({marginLeft:this.originalElement.css("marginLeft"),marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom")}),this.originalElement.css({marginLeft:0,marginTop:0,marginRight:0,marginBottom:0}),this.originalResizeStyle=this.originalElement.css("resize"),this.originalElement.css("resize","none"),this._proportionallyResizeElements.push(this.originalElement.css({position:"static",zoom:1,display:"block"})),this.originalElement.css({margin:this.originalElement.css("margin")}),this._proportionallyResize()),this.handles=n.handles||(e(".ui-resizable-handle",this.element).length?{n:".ui-resizable-n",e:".ui-resizable-e",s:".ui-resizable-s",w:".ui-resizable-w",se:".ui-resizable-se",sw:".ui-resizable-sw",ne:".ui-resizable-ne",nw:".ui-resizable-nw"}:"e,s,se");if(this.handles.constructor==String){this.handles=="all"&&(this.handles="n,e,s,w,se,sw,ne,nw");var r=this.handles.split(",");this.handles={};for(var i=0;i<r.length;i++){var s=e.trim(r[i]),o="ui-resizable-"+s,u=e('<div class="ui-resizable-handle '+o+'"></div>');u.css({zIndex:n.zIndex}),"se"==s&&u.addClass("ui-icon ui-icon-gripsmall-diagonal-se"),this.handles[s]=".ui-resizable-"+s,this.element.append(u)}}this._renderAxis=function(t){t=t||this.element;for(var n in this.handles){this.handles[n].constructor==String&&(this.handles[n]=e(this.handles[n],this.element).show());if(this.elementIsWrapper&&this.originalElement[0].nodeName.match(/textarea|input|select|button/i)){var r=e(this.handles[n],this.element),i=0;i=/sw|ne|nw|se|n|s/.test(n)?r.outerHeight():r.outerWidth();var s=["padding",/ne|nw|n/.test(n)?"Top":/se|sw|s/.test(n)?"Bottom":/^e$/.test(n)?"Right":"Left"].join("");t.css(s,i),this._proportionallyResize()}if(!e(this.handles[n]).length)continue}},this._renderAxis(this.element),this._handles=e(".ui-resizable-handle",this.element).disableSelection(),this._handles.mouseover(function(){if(!t.resizing){if(this.className)var e=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i);t.axis=e&&e[1]?e[1]:"se"}}),n.autoHide&&(this._handles.hide(),e(this.element).addClass("ui-resizable-autohide").mouseenter(function(){if(n.disabled)return;e(this).removeClass("ui-resizable-autohide"),t._handles.show()}).mouseleave(function(){if(n.disabled)return;t.resizing||(e(this).addClass("ui-resizable-autohide"),t._handles.hide())})),this._mouseInit()},_destroy:function(){this._mouseDestroy();var t=function(t){e(t).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing").removeData("resizable").removeData("ui-resizable").unbind(".resizable").find(".ui-resizable-handle").remove()};if(this.elementIsWrapper){t(this.element);var n=this.element;this.originalElement.css({position:n.css("position"),width:n.outerWidth(),height:n.outerHeight(),top:n.css("top"),left:n.css("left")}).insertAfter(n),n.remove()}return this.originalElement.css("resize",this.originalResizeStyle),t(this.originalElement),this},_mouseCapture:function(t){var n=!1;for(var r in this.handles)e(this.handles[r])[0]==t.target&&(n=!0);return!this.options.disabled&&n},_mouseStart:function(t){var r=this.options,i=this.element.position(),s=this.element;this.resizing=!0,this.documentScroll={top:e(document).scrollTop(),left:e(document).scrollLeft()},(s.is(".ui-draggable")||/absolute/.test(s.css("position")))&&s.css({position:"absolute",top:i.top,left:i.left}),this._renderProxy();var o=n(this.helper.css("left")),u=n(this.helper.css("top"));r.containment&&(o+=e(r.containment).scrollLeft()||0,u+=e(r.containment).scrollTop()||0),this.offset=this.helper.offset(),this.position={left:o,top:u},this.size=this._helper?{width:s.outerWidth(),height:s.outerHeight()}:{width:s.width(),height:s.height()},this.originalSize=this._helper?{width:s.outerWidth(),height:s.outerHeight()}:{width:s.width(),height:s.height()},this.originalPosition={left:o,top:u},this.sizeDiff={width:s.outerWidth()-s.width(),height:s.outerHeight()-s.height()},this.originalMousePosition={left:t.pageX,top:t.pageY},this.aspectRatio=typeof r.aspectRatio=="number"?r.aspectRatio:this.originalSize.width/this.originalSize.height||1;var a=e(".ui-resizable-"+this.axis).css("cursor");return e("body").css("cursor",a=="auto"?this.axis+"-resize":a),s.addClass("ui-resizable-resizing"),this._propagate("start",t),!0},_mouseDrag:function(e){var t=this.helper,n=this.options,r={},i=this,s=this.originalMousePosition,o=this.axis,u=e.pageX-s.left||0,a=e.pageY-s.top||0,f=this._change[o];if(!f)return!1;var l=f.apply(this,[e,u,a]);this._updateVirtualBoundaries(e.shiftKey);if(this._aspectRatio||e.shiftKey)l=this._updateRatio(l,e);return l=this._respectSize(l,e),this._propagate("resize",e),t.css({top:this.position.top+"px",left:this.position.left+"px",width:this.size.width+"px",height:this.size.height+"px"}),!this._helper&&this._proportionallyResizeElements.length&&this._proportionallyResize(),this._updateCache(l),this._trigger("resize",e,this.ui()),!1},_mouseStop:function(t){this.resizing=!1;var n=this.options,r=this;if(this._helper){var i=this._proportionallyResizeElements,s=i.length&&/textarea/i.test(i[0].nodeName),o=s&&e.ui.hasScroll(i[0],"left")?0:r.sizeDiff.height,u=s?0:r.sizeDiff.width,a={width:r.helper.width()-u,height:r.helper.height()-o},f=parseInt(r.element.css("left"),10)+(r.position.left-r.originalPosition.left)||null,l=parseInt(r.element.css("top"),10)+(r.position.top-r.originalPosition.top)||null;n.animate||this.element.css(e.extend(a,{top:l,left:f})),r.helper.height(r.size.height),r.helper.width(r.size.width),this._helper&&!n.animate&&this._proportionallyResize()}return e("body").css("cursor","auto"),this.element.removeClass("ui-resizable-resizing"),this._propagate("stop",t),this._helper&&this.helper.remove(),!1},_updateVirtualBoundaries:function(e){var t=this.options,n,i,s,o,u;u={minWidth:r(t.minWidth)?t.minWidth:0,maxWidth:r(t.maxWidth)?t.maxWidth:Infinity,minHeight:r(t.minHeight)?t.minHeight:0,maxHeight:r(t.maxHeight)?t.maxHeight:Infinity};if(this._aspectRatio||e)n=u.minHeight*this.aspectRatio,s=u.minWidth/this.aspectRatio,i=u.maxHeight*this.aspectRatio,o=u.maxWidth/this.aspectRatio,n>u.minWidth&&(u.minWidth=n),s>u.minHeight&&(u.minHeight=s),i<u.maxWidth&&(u.maxWidth=i),o<u.maxHeight&&(u.maxHeight=o);this._vBoundaries=u},_updateCache:function(e){var t=this.options;this.offset=this.helper.offset(),r(e.left)&&(this.position.left=e.left),r(e.top)&&(this.position.top=e.top),r(e.height)&&(this.size.height=e.height),r(e.width)&&(this.size.width=e.width)},_updateRatio:function(e,t){var n=this.options,i=this.position,s=this.size,o=this.axis;return r(e.height)?e.width=e.height*this.aspectRatio:r(e.width)&&(e.height=e.width/this.aspectRatio),o=="sw"&&(e.left=i.left+(s.width-e.width),e.top=null),o=="nw"&&(e.top=i.top+(s.height-e.height),e.left=i.left+(s.width-e.width)),e},_respectSize:function(e,t){var n=this.helper,i=this._vBoundaries,s=this._aspectRatio||t.shiftKey,o=this.axis,u=r(e.width)&&i.maxWidth&&i.maxWidth<e.width,a=r(e.height)&&i.maxHeight&&i.maxHeight<e.height,f=r(e.width)&&i.minWidth&&i.minWidth>e.width,l=r(e.height)&&i.minHeight&&i.minHeight>e.height;f&&(e.width=i.minWidth),l&&(e.height=i.minHeight),u&&(e.width=i.maxWidth),a&&(e.height=i.maxHeight);var c=this.originalPosition.left+this.originalSize.width,h=this.position.top+this.size.height,p=/sw|nw|w/.test(o),d=/nw|ne|n/.test(o);f&&p&&(e.left=c-i.minWidth),u&&p&&(e.left=c-i.maxWidth),l&&d&&(e.top=h-i.minHeight),a&&d&&(e.top=h-i.maxHeight);var v=!e.width&&!e.height;return v&&!e.left&&e.top?e.top=null:v&&!e.top&&e.left&&(e.left=null),e},_proportionallyResize:function(){var t=this.options;if(!this._proportionallyResizeElements.length)return;var n=this.helper||this.element;for(var r=0;r<this._proportionallyResizeElements.length;r++){var i=this._proportionallyResizeElements[r];if(!this.borderDif){var s=[i.css("borderTopWidth"),i.css("borderRightWidth"),i.css("borderBottomWidth"),i.css("borderLeftWidth")],o=[i.css("paddingTop"),i.css("paddingRight"),i.css("paddingBottom"),i.css("paddingLeft")];this.borderDif=e.map(s,function(e,t){var n=parseInt(e,10)||0,r=parseInt(o[t],10)||0;return n+r})}i.css({height:n.height()-this.borderDif[0]-this.borderDif[2]||0,width:n.width()-this.borderDif[1]-this.borderDif[3]||0})}},_renderProxy:function(){var t=this.element,n=this.options;this.elementOffset=t.offset();if(this._helper){this.helper=this.helper||e('<div style="overflow:hidden;"></div>');var r=e.ui.ie6?1:0,i=e.ui.ie6?2:-1;this.helper.addClass(this._helper).css({width:this.element.outerWidth()+i,height:this.element.outerHeight()+i,position:"absolute",left:this.elementOffset.left-r+"px",top:this.elementOffset.top-r+"px",zIndex:++n.zIndex}),this.helper.appendTo("body").disableSelection()}else this.helper=this.element},_change:{e:function(e,t,n){return{width:this.originalSize.width+t}},w:function(e,t,n){var r=this.options,i=this.originalSize,s=this.originalPosition;return{left:s.left+t,width:i.width-t}},n:function(e,t,n){var r=this.options,i=this.originalSize,s=this.originalPosition;return{top:s.top+n,height:i.height-n}},s:function(e,t,n){return{height:this.originalSize.height+n}},se:function(t,n,r){return e.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[t,n,r]))},sw:function(t,n,r){return e.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[t,n,r]))},ne:function(t,n,r){return e.extend(this._change.n.apply(this,arguments),this._change.e.apply(this,[t,n,r]))},nw:function(t,n,r){return e.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[t,n,r]))}},_propagate:function(t,n){e.ui.plugin.call(this,t,[n,this.ui()]),t!="resize"&&this._trigger(t,n,this.ui())},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize,originalPosition:this.originalPosition}}}),e.ui.plugin.add("resizable","alsoResize",{start:function(t,n){var r=e(this).data("resizable"),i=r.options,s=function(t){e(t).each(function(){var t=e(this);t.data("resizable-alsoresize",{width:parseInt(t.width(),10),height:parseInt(t.height(),10),left:parseInt(t.css("left"),10),top:parseInt(t.css("top"),10)})})};typeof i.alsoResize=="object"&&!i.alsoResize.parentNode?i.alsoResize.length?(i.alsoResize=i.alsoResize[0],s(i.alsoResize)):e.each(i.alsoResize,function(e){s(e)}):s(i.alsoResize)},resize:function(t,n){var r=e(this).data("resizable"),i=r.options,s=r.originalSize,o=r.originalPosition,u={height:r.size.height-s.height||0,width:r.size.width-s.width||0,top:r.position.top-o.top||0,left:r.position.left-o.left||0},a=function(t,r){e(t).each(function(){var t=e(this),i=e(this).data("resizable-alsoresize"),s={},o=r&&r.length?r:t.parents(n.originalElement[0]).length?["width","height"]:["width","height","top","left"];e.each(o,function(e,t){var n=(i[t]||0)+(u[t]||0);n&&n>=0&&(s[t]=n||null)}),t.css(s)})};typeof i.alsoResize=="object"&&!i.alsoResize.nodeType?e.each(i.alsoResize,function(e,t){a(e,t)}):a(i.alsoResize)},stop:function(t,n){e(this).removeData("resizable-alsoresize")}}),e.ui.plugin.add("resizable","animate",{stop:function(t,n){var r=e(this).data("resizable"),i=r.options,s=r._proportionallyResizeElements,o=s.length&&/textarea/i.test(s[0].nodeName),u=o&&e.ui.hasScroll(s[0],"left")?0:r.sizeDiff.height,a=o?0:r.sizeDiff.width,f={width:r.size.width-a,height:r.size.height-u},l=parseInt(r.element.css("left"),10)+(r.position.left-r.originalPosition.left)||null,c=parseInt(r.element.css("top"),10)+(r.position.top-r.originalPosition.top)||null;r.element.animate(e.extend(f,c&&l?{top:c,left:l}:{}),{duration:i.animateDuration,easing:i.animateEasing,step:function(){var n={width:parseInt(r.element.css("width"),10),height:parseInt(r.element.css("height"),10),top:parseInt(r.element.css("top"),10),left:parseInt(r.element.css("left"),10)};s&&s.length&&e(s[0]).css({width:n.width,height:n.height}),r._updateCache(n),r._propagate("resize",t)}})}}),e.ui.plugin.add("resizable","containment",{start:function(t,r){var i=e(this).data("resizable"),s=i.options,o=i.element,u=s.containment,a=u instanceof e?u.get(0):/parent/.test(u)?o.parent().get(0):u;if(!a)return;i.containerElement=e(a);if(/document/.test(u)||u==document)i.containerOffset={left:0,top:0},i.containerPosition={left:0,top:0},i.parentData={element:e(document),left:0,top:0,width:e(document).width(),height:e(document).height()||document.body.parentNode.scrollHeight};else{var f=e(a),l=[];e(["Top","Right","Left","Bottom"]).each(function(e,t){l[e]=n(f.css("padding"+t))}),i.containerOffset=f.offset(),i.containerPosition=f.position(),i.containerSize={height:f.innerHeight()-l[3],width:f.innerWidth()-l[1]};var c=i.containerOffset,h=i.containerSize.height,p=i.containerSize.width,d=e.ui.hasScroll(a,"left")?a.scrollWidth:p,v=e.ui.hasScroll(a)?a.scrollHeight:h;i.parentData={element:a,left:c.left,top:c.top,width:d,height:v}}},resize:function(t,n){var r=e(this).data("resizable"),i=r.options,s=r.containerSize,o=r.containerOffset,u=r.size,a=r.position,f=r._aspectRatio||t.shiftKey,l={top:0,left:0},c=r.containerElement;c[0]!=document&&/static/.test(c.css("position"))&&(l=o),a.left<(r._helper?o.left:0)&&(r.size.width=r.size.width+(r._helper?r.position.left-o.left:r.position.left-l.left),f&&(r.size.height=r.size.width/r.aspectRatio),r.position.left=i.helper?o.left:0),a.top<(r._helper?o.top:0)&&(r.size.height=r.size.height+(r._helper?r.position.top-o.top:r.position.top),f&&(r.size.width=r.size.height*r.aspectRatio),r.position.top=r._helper?o.top:0),r.offset.left=r.parentData.left+r.position.left,r.offset.top=r.parentData.top+r.position.top;var h=Math.abs((r._helper?r.offset.left-l.left:r.offset.left-l.left)+r.sizeDiff.width),p=Math.abs((r._helper?r.offset.top-l.top:r.offset.top-o.top)+r.sizeDiff.height),d=r.containerElement.get(0)==r.element.parent().get(0),v=/relative|absolute/.test(r.containerElement.css("position"));d&&v&&(h-=r.parentData.left),h+r.size.width>=r.parentData.width&&(r.size.width=r.parentData.width-h,f&&(r.size.height=r.size.width/r.aspectRatio)),p+r.size.height>=r.parentData.height&&(r.size.height=r.parentData.height-p,f&&(r.size.width=r.size.height*r.aspectRatio))},stop:function(t,n){var r=e(this).data("resizable"),i=r.options,s=r.position,o=r.containerOffset,u=r.containerPosition,a=r.containerElement,f=e(r.helper),l=f.offset(),c=f.outerWidth()-r.sizeDiff.width,h=f.outerHeight()-r.sizeDiff.height;r._helper&&!i.animate&&/relative/.test(a.css("position"))&&e(this).css({left:l.left-u.left-o.left,width:c,height:h}),r._helper&&!i.animate&&/static/.test(a.css("position"))&&e(this).css({left:l.left-u.left-o.left,width:c,height:h})}}),e.ui.plugin.add("resizable","ghost",{start:function(t,n){var r=e(this).data("resizable"),i=r.options,s=r.size;r.ghost=r.originalElement.clone(),r.ghost.css({opacity:.25,display:"block",position:"relative",height:s.height,width:s.width,margin:0,left:0,top:0}).addClass("ui-resizable-ghost").addClass(typeof i.ghost=="string"?i.ghost:""),r.ghost.appendTo(r.helper)},resize:function(t,n){var r=e(this).data("resizable"),i=r.options;r.ghost&&r.ghost.css({position:"relative",height:r.size.height,width:r.size.width})},stop:function(t,n){var r=e(this).data("resizable"),i=r.options;r.ghost&&r.helper&&r.helper.get(0).removeChild(r.ghost.get(0))}}),e.ui.plugin.add("resizable","grid",{resize:function(t,n){var r=e(this).data("resizable"),i=r.options,s=r.size,o=r.originalSize,u=r.originalPosition,a=r.axis,f=i._aspectRatio||t.shiftKey;i.grid=typeof i.grid=="number"?[i.grid,i.grid]:i.grid;var l=Math.round((s.width-o.width)/(i.grid[0]||1))*(i.grid[0]||1),c=Math.round((s.height-o.height)/(i.grid[1]||1))*(i.grid[1]||1);/^(se|s|e)$/.test(a)?(r.size.width=o.width+l,r.size.height=o.height+c):/^(ne)$/.test(a)?(r.size.width=o.width+l,r.size.height=o.height+c,r.position.top=u.top-c):/^(sw)$/.test(a)?(r.size.width=o.width+l,r.size.height=o.height+c,r.position.left=u.left-l):(r.size.width=o.width+l,r.size.height=o.height+c,r.position.top=u.top-c,r.position.left=u.left-l)}});var n=function(e){return parseInt(e,10)||0},r=function(e){return!isNaN(parseInt(e,10))}}(jQuery),function(e,t){e.widget("ui.selectable",e.ui.mouse,{version:"1.9.2",options:{appendTo:"body",autoRefresh:!0,distance:0,filter:"*",tolerance:"touch"},_create:function(){var t=this;this.element.addClass("ui-selectable"),this.dragged=!1;var n;this.refresh=function(){n=e(t.options.filter,t.element[0]),n.addClass("ui-selectee"),n.each(function(){var t=e(this),n=t.offset();e.data(this,"selectable-item",{element:this,$element:t,left:n.left,top:n.top,right:n.left+t.outerWidth(),bottom:n.top+t.outerHeight(),startselected:!1,selected:t.hasClass("ui-selected"),selecting:t.hasClass("ui-selecting"),unselecting:t.hasClass("ui-unselecting")})})},this.refresh(),this.selectees=n.addClass("ui-selectee"),this._mouseInit(),this.helper=e("<div class='ui-selectable-helper'></div>")},_destroy:function(){this.selectees.removeClass("ui-selectee").removeData("selectable-item"),this.element.removeClass("ui-selectable ui-selectable-disabled"),this._mouseDestroy()},_mouseStart:function(t){var n=this;this.opos=[t.pageX,t.pageY];if(this.options.disabled)return;var r=this.options;this.selectees=e(r.filter,this.element[0]),this._trigger("start",t),e(r.appendTo).append(this.helper),this.helper.css({left:t.clientX,top:t.clientY,width:0,height:0}),r.autoRefresh&&this.refresh(),this.selectees.filter(".ui-selected").each(function(){var r=e.data(this,"selectable-item");r.startselected=!0,!t.metaKey&&!t.ctrlKey&&(r.$element.removeClass("ui-selected"),r.selected=!1,r.$element.addClass("ui-unselecting"),r.unselecting=!0,n._trigger("unselecting",t,{unselecting:r.element}))}),e(t.target).parents().andSelf().each(function(){var r=e.data(this,"selectable-item");if(r){var i=!t.metaKey&&!t.ctrlKey||!r.$element.hasClass("ui-selected");return r.$element.removeClass(i?"ui-unselecting":"ui-selected").addClass(i?"ui-selecting":"ui-unselecting"),r.unselecting=!i,r.selecting=i,r.selected=i,i?n._trigger("selecting",t,{selecting:r.element}):n._trigger("unselecting",t,{unselecting:r.element}),!1}})},_mouseDrag:function(t){var n=this;this.dragged=!0;if(this.options.disabled)return;var r=this.options,i=this.opos[0],s=this.opos[1],o=t.pageX,u=t.pageY;if(i>o){var a=o;o=i,i=a}if(s>u){var a=u;u=s,s=a}return this.helper.css({left:i,top:s,width:o-i,height:u-s}),this.selectees.each(function(){var a=e.data(this,"selectable-item");if(!a||a.element==n.element[0])return;var f=!1;r.tolerance=="touch"?f=!(a.left>o||a.right<i||a.top>u||a.bottom<s):r.tolerance=="fit"&&(f=a.left>i&&a.right<o&&a.top>s&&a.bottom<u),f?(a.selected&&(a.$element.removeClass("ui-selected"),a.selected=!1),a.unselecting&&(a.$element.removeClass("ui-unselecting"),a.unselecting=!1),a.selecting||(a.$element.addClass("ui-selecting"),a.selecting=!0,n._trigger("selecting",t,{selecting:a.element}))):(a.selecting&&((t.metaKey||t.ctrlKey)&&a.startselected?(a.$element.removeClass("ui-selecting"),a.selecting=!1,a.$element.addClass("ui-selected"),a.selected=!0):(a.$element.removeClass("ui-selecting"),a.selecting=!1,a.startselected&&(a.$element.addClass("ui-unselecting"),a.unselecting=!0),n._trigger("unselecting",t,{unselecting:a.element}))),a.selected&&!t.metaKey&&!t.ctrlKey&&!a.startselected&&(a.$element.removeClass("ui-selected"),a.selected=!1,a.$element.addClass("ui-unselecting"),a.unselecting=!0,n._trigger("unselecting",t,{unselecting:a.element})))}),!1},_mouseStop:function(t){var n=this;this.dragged=!1;var r=this.options;return e(".ui-unselecting",this.element[0]).each(function(){var r=e.data(this,"selectable-item");r.$element.removeClass("ui-unselecting"),r.unselecting=!1,r.startselected=!1,n._trigger("unselected",t,{unselected:r.element})}),e(".ui-selecting",this.element[0]).each(function(){var r=e.data(this,"selectable-item");r.$element.removeClass("ui-selecting").addClass("ui-selected"),r.selecting=!1,r.selected=!0,r.startselected=!0,n._trigger("selected",t,{selected:r.element})}),this._trigger("stop",t),this.helper.remove(),!1}})}(jQuery),function(e,t){e.widget("ui.sortable",e.ui.mouse,{version:"1.9.2",widgetEventPrefix:"sort",ready:!1,options:{appendTo:"parent",axis:!1,connectWith:!1,containment:!1,cursor:"auto",cursorAt:!1,dropOnEmpty:!0,forcePlaceholderSize:!1,forceHelperSize:!1,grid:!1,handle:!1,helper:"original",items:"> *",opacity:!1,placeholder:!1,revert:!1,scroll:!0,scrollSensitivity:20,scrollSpeed:20,scope:"default",tolerance:"intersect",zIndex:1e3},_create:function(){var e=this.options;this.containerCache={},this.element.addClass("ui-sortable"),this.refresh(),this.floating=this.items.length?e.axis==="x"||/left|right/.test(this.items[0].item.css("float"))||/inline|table-cell/.test(this.items[0].item.css("display")):!1,this.offset=this.element.offset(),this._mouseInit(),this.ready=!0},_destroy:function(){this.element.removeClass("ui-sortable ui-sortable-disabled"),this._mouseDestroy();for(var e=this.items.length-1;e>=0;e--)this.items[e].item.removeData(this.widgetName+"-item");return this},_setOption:function(t,n){t==="disabled"?(this.options[t]=n,this.widget().toggleClass("ui-sortable-disabled",!!n)):e.Widget.prototype._setOption.apply(this,arguments)},_mouseCapture:function(t,n){var r=this;if(this.reverting)return!1;if(this.options.disabled||this.options.type=="static")return!1;this._refreshItems(t);var i=null,s=e(t.target).parents().each(function(){if(e.data(this,r.widgetName+"-item")==r)return i=e(this),!1});e.data(t.target,r.widgetName+"-item")==r&&(i=e(t.target));if(!i)return!1;if(this.options.handle&&!n){var o=!1;e(this.options.handle,i).find("*").andSelf().each(function(){this==t.target&&(o=!0)});if(!o)return!1}return this.currentItem=i,this._removeCurrentsFromItems(),!0},_mouseStart:function(t,n,r){var i=this.options;this.currentContainer=this,this.refreshPositions(),this.helper=this._createHelper(t),this._cacheHelperProportions(),this._cacheMargins(),this.scrollParent=this.helper.scrollParent(),this.offset=this.currentItem.offset(),this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left},e.extend(this.offset,{click:{left:t.pageX-this.offset.left,top:t.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()}),this.helper.css("position","absolute"),this.cssPosition=this.helper.css("position"),this.originalPosition=this._generatePosition(t),this.originalPageX=t.pageX,this.originalPageY=t.pageY,i.cursorAt&&this._adjustOffsetFromHelper(i.cursorAt),this.domPosition={prev:this.currentItem.prev()[0],parent:this.currentItem.parent()[0]},this.helper[0]!=this.currentItem[0]&&this.currentItem.hide(),this._createPlaceholder(),i.containment&&this._setContainment(),i.cursor&&(e("body").css("cursor")&&(this._storedCursor=e("body").css("cursor")),e("body").css("cursor",i.cursor)),i.opacity&&(this.helper.css("opacity")&&(this._storedOpacity=this.helper.css("opacity")),this.helper.css("opacity",i.opacity)),i.zIndex&&(this.helper.css("zIndex")&&(this._storedZIndex=this.helper.css("zIndex")),this.helper.css("zIndex",i.zIndex)),this.scrollParent[0]!=document&&this.scrollParent[0].tagName!="HTML"&&(this.overflowOffset=this.scrollParent.offset()),this._trigger("start",t,this._uiHash()),this._preserveHelperProportions||this._cacheHelperProportions();if(!r)for(var s=this.containers.length-1;s>=0;s--)this.containers[s]._trigger("activate",t,this._uiHash(this));return e.ui.ddmanager&&(e.ui.ddmanager.current=this),e.ui.ddmanager&&!i.dropBehaviour&&e.ui.ddmanager.prepareOffsets(this,t),this.dragging=!0,this.helper.addClass("ui-sortable-helper"),this._mouseDrag(t),!0},_mouseDrag:function(t){this.position=this._generatePosition(t),this.positionAbs=this._convertPositionTo("absolute"),this.lastPositionAbs||(this.lastPositionAbs=this.positionAbs);if(this.options.scroll){var n=this.options,r=!1;this.scrollParent[0]!=document&&this.scrollParent[0].tagName!="HTML"?(this.overflowOffset.top+this.scrollParent[0].offsetHeight-t.pageY<n.scrollSensitivity?this.scrollParent[0].scrollTop=r=this.scrollParent[0].scrollTop+n.scrollSpeed:t.pageY-this.overflowOffset.top<n.scrollSensitivity&&(this.scrollParent[0].scrollTop=r=this.scrollParent[0].scrollTop-n.scrollSpeed),this.overflowOffset.left+this.scrollParent[0].offsetWidth-t.pageX<n.scrollSensitivity?this.scrollParent[0].scrollLeft=r=this.scrollParent[0].scrollLeft+n.scrollSpeed:t.pageX-this.overflowOffset.left<n.scrollSensitivity&&(this.scrollParent[0].scrollLeft=r=this.scrollParent[0].scrollLeft-n.scrollSpeed)):(t.pageY-e(document).scrollTop()<n.scrollSensitivity?r=e(document).scrollTop(e(document).scrollTop()-n.scrollSpeed):e(window).height()-(t.pageY-e(document).scrollTop())<n.scrollSensitivity&&(r=e(document).scrollTop(e(document).scrollTop()+n.scrollSpeed)),t.pageX-e(document).scrollLeft()<n.scrollSensitivity?r=e(document).scrollLeft(e(document).scrollLeft()-n.scrollSpeed):e(window).width()-(t.pageX-e(document).scrollLeft())<n.scrollSensitivity&&(r=e(document).scrollLeft(e(document).scrollLeft()+n.scrollSpeed))),r!==!1&&e.ui.ddmanager&&!n.dropBehaviour&&e.ui.ddmanager.prepareOffsets(this,t)}this.positionAbs=this._convertPositionTo("absolute");if(!this.options.axis||this.options.axis!="y")this.helper[0].style.left=this.position.left+"px";if(!this.options.axis||this.options.axis!="x")this.helper[0].style.top=this.position.top+"px";for(var i=this.items.length-1;i>=0;i--){var s=this.items[i],o=s.item[0],u=this._intersectsWithPointer(s);if(!u)continue;if(s.instance!==this.currentContainer)continue;if(o!=this.currentItem[0]&&this.placeholder[u==1?"next":"prev"]()[0]!=o&&!e.contains(this.placeholder[0],o)&&(this.options.type=="semi-dynamic"?!e.contains(this.element[0],o):!0)){this.direction=u==1?"down":"up";if(this.options.tolerance!="pointer"&&!this._intersectsWithSides(s))break;this._rearrange(t,s),this._trigger("change",t,this._uiHash());break}}return this._contactContainers(t),e.ui.ddmanager&&e.ui.ddmanager.drag(this,t),this._trigger("sort",t,this._uiHash()),this.lastPositionAbs=this.positionAbs,!1},_mouseStop:function(t,n){if(!t)return;e.ui.ddmanager&&!this.options.dropBehaviour&&e.ui.ddmanager.drop(this,t);if(this.options.revert){var r=this,i=this.placeholder.offset();this.reverting=!0,e(this.helper).animate({left:i.left-this.offset.parent.left-this.margins.left+(this.offsetParent[0]==document.body?0:this.offsetParent[0].scrollLeft),top:i.top-this.offset.parent.top-this.margins.top+(this.offsetParent[0]==document.body?0:this.offsetParent[0].scrollTop)},parseInt(this.options.revert,10)||500,function(){r._clear(t)})}else this._clear(t,n);return!1},cancel:function(){if(this.dragging){this._mouseUp({target:null}),this.options.helper=="original"?this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"):this.currentItem.show();for(var t=this.containers.length-1;t>=0;t--)this.containers[t]._trigger("deactivate",null,this._uiHash(this)),this.containers[t].containerCache.over&&(this.containers[t]._trigger("out",null,this._uiHash(this)),this.containers[t].containerCache.over=0)}return this.placeholder&&(this.placeholder[0].parentNode&&this.placeholder[0].parentNode.removeChild(this.placeholder[0]),this.options.helper!="original"&&this.helper&&this.helper[0].parentNode&&this.helper.remove(),e.extend(this,{helper:null,dragging:!1,reverting:!1,_noFinalSort:null}),this.domPosition.prev?e(this.domPosition.prev).after(this.currentItem):e(this.domPosition.parent).prepend(this.currentItem)),this},serialize:function(t){var n=this._getItemsAsjQuery(t&&t.connected),r=[];return t=t||{},e(n).each(function(){var n=(e(t.item||this).attr(t.attribute||"id")||"").match(t.expression||/(.+)[-=_](.+)/);n&&r.push((t.key||n[1]+"[]")+"="+(t.key&&t.expression?n[1]:n[2]))}),!r.length&&t.key&&r.push(t.key+"="),r.join("&")},toArray:function(t){var n=this._getItemsAsjQuery(t&&t.connected),r=[];return t=t||{},n.each(function(){r.push(e(t.item||this).attr(t.attribute||"id")||"")}),r},_intersectsWith:function(e){var t=this.positionAbs.left,n=t+this.helperProportions.width,r=this.positionAbs.top,i=r+this.helperProportions.height,s=e.left,o=s+e.width,u=e.top,a=u+e.height,f=this.offset.click.top,l=this.offset.click.left,c=r+f>u&&r+f<a&&t+l>s&&t+l<o;return this.options.tolerance=="pointer"||this.options.forcePointerForContainers||this.options.tolerance!="pointer"&&this.helperProportions[this.floating?"width":"height"]>e[this.floating?"width":"height"]?c:s<t+this.helperProportions.width/2&&n-this.helperProportions.width/2<o&&u<r+this.helperProportions.height/2&&i-this.helperProportions.height/2<a},_intersectsWithPointer:function(t){var n=this.options.axis==="x"||e.ui.isOverAxis(this.positionAbs.top+this.offset.click.top,t.top,t.height),r=this.options.axis==="y"||e.ui.isOverAxis(this.positionAbs.left+this.offset.click.left,t.left,t.width),i=n&&r,s=this._getDragVerticalDirection(),o=this._getDragHorizontalDirection();return i?this.floating?o&&o=="right"||s=="down"?2:1:s&&(s=="down"?2:1):!1},_intersectsWithSides:function(t){var n=e.ui.isOverAxis(this.positionAbs.top+this.offset.click.top,t.top+t.height/2,t.height),r=e.ui.isOverAxis(this.positionAbs.left+this.offset.click.left,t.left+t.width/2,t.width),i=this._getDragVerticalDirection(),s=this._getDragHorizontalDirection();return this.floating&&s?s=="right"&&r||s=="left"&&!r:i&&(i=="down"&&n||i=="up"&&!n)},_getDragVerticalDirection:function(){var e=this.positionAbs.top-this.lastPositionAbs.top;return e!=0&&(e>0?"down":"up")},_getDragHorizontalDirection:function(){var e=this.positionAbs.left-this.lastPositionAbs.left;return e!=0&&(e>0?"right":"left")},refresh:function(e){return this._refreshItems(e),this.refreshPositions(),this},_connectWith:function(){var e=this.options;return e.connectWith.constructor==String?[e.connectWith]:e.connectWith},_getItemsAsjQuery:function(t){var n=[],r=[],i=this._connectWith();if(i&&t)for(var s=i.length-1;s>=0;s--){var o=e(i[s]);for(var u=o.length-1;u>=0;u--){var a=e.data(o[u],this.widgetName);a&&a!=this&&!a.options.disabled&&r.push([e.isFunction(a.options.items)?a.options.items.call(a.element):e(a.options.items,a.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),a])}}r.push([e.isFunction(this.options.items)?this.options.items.call(this.element,null,{options:this.options,item:this.currentItem}):e(this.options.items,this.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),this]);for(var s=r.length-1;s>=0;s--)r[s][0].each(function(){n.push(this)});return e(n)},_removeCurrentsFromItems:function(){var t=this.currentItem.find(":data("+this.widgetName+"-item)");this.items=e.grep(this.items,function(e){for(var n=0;n<t.length;n++)if(t[n]==e.item[0])return!1;return!0})},_refreshItems:function(t){this.items=[],this.containers=[this];var n=this.items,r=[[e.isFunction(this.options.items)?this.options.items.call(this.element[0],t,{item:this.currentItem}):e(this.options.items,this.element),this]],i=this._connectWith();if(i&&this.ready)for(var s=i.length-1;s>=0;s--){var o=e(i[s]);for(var u=o.length-1;u>=0;u--){var a=e.data(o[u],this.widgetName);a&&a!=this&&!a.options.disabled&&(r.push([e.isFunction(a.options.items)?a.options.items.call(a.element[0],t,{item:this.currentItem}):e(a.options.items,a.element),a]),this.containers.push(a))}}for(var s=r.length-1;s>=0;s--){var f=r[s][1],l=r[s][0];for(var u=0,c=l.length;u<c;u++){var h=e(l[u]);h.data(this.widgetName+"-item",f),n.push({item:h,instance:f,width:0,height:0,left:0,top:0})}}},refreshPositions:function(t){this.offsetParent&&this.helper&&(this.offset.parent=this._getParentOffset());for(var n=this.items.length-1;n>=0;n--){var r=this.items[n];if(r.instance!=this.currentContainer&&this.currentContainer&&r.item[0]!=this.currentItem[0])continue;var i=this.options.toleranceElement?e(this.options.toleranceElement,r.item):r.item;t||(r.width=i.outerWidth(),r.height=i.outerHeight());var s=i.offset();r.left=s.left,r.top=s.top}if(this.options.custom&&this.options.custom.refreshContainers)this.options.custom.refreshContainers.call(this);else for(var n=this.containers.length-1;n>=0;n--){var s=this.containers[n].element.offset();this.containers[n].containerCache.left=s.left,this.containers[n].containerCache.top=s.top,this.containers[n].containerCache.width=this.containers[n].element.outerWidth(),this.containers[n].containerCache.height=this.containers[n].element.outerHeight()}return this},_createPlaceholder:function(t){t=t||this;var n=t.options;if(!n.placeholder||n.placeholder.constructor==String){var r=n.placeholder;n.placeholder={element:function(){var n=e(document.createElement(t.currentItem[0].nodeName)).addClass(r||t.currentItem[0].className+" ui-sortable-placeholder").removeClass("ui-sortable-helper")[0];return r||(n.style.visibility="hidden"),n},update:function(e,i){if(r&&!n.forcePlaceholderSize)return;i.height()||i.height(t.currentItem.innerHeight()-parseInt(t.currentItem.css("paddingTop")||0,10)-parseInt(t.currentItem.css("paddingBottom")||0,10)),i.width()||i.width(t.currentItem.innerWidth()-parseInt(t.currentItem.css("paddingLeft")||0,10)-parseInt(t.currentItem.css("paddingRight")||0,10))}}}t.placeholder=e(n.placeholder.element.call(t.element,t.currentItem)),t.currentItem.after(t.placeholder),n.placeholder.update(t,t.placeholder)},_contactContainers:function(t){var n=null,r=null;for(var i=this.containers.length-1;i>=0;i--){if(e.contains(this.currentItem[0],this.containers[i].element[0]))continue;if(this._intersectsWith(this.containers[i].containerCache)){if(n&&e.contains(this.containers[i].element[0],n.element[0]))continue;n=this.containers[i],r=i}else this.containers[i].containerCache.over&&(this.containers[i]._trigger("out",t,this._uiHash(this)),this.containers[i].containerCache.over=0)}if(!n)return;if(this.containers.length===1)this.containers[r]._trigger("over",t,this._uiHash(this)),this.containers[r].containerCache.over=1;else{var s=1e4,o=null,u=this.containers[r].floating?"left":"top",a=this.containers[r].floating?"width":"height",f=this.positionAbs[u]+this.offset.click[u];for(var l=this.items.length-1;l>=0;l--){if(!e.contains(this.containers[r].element[0],this.items[l].item[0]))continue;if(this.items[l].item[0]==this.currentItem[0])continue;var c=this.items[l].item.offset()[u],h=!1;Math.abs(c-f)>Math.abs(c+this.items[l][a]-f)&&(h=!0,c+=this.items[l][a]),Math.abs(c-f)<s&&(s=Math.abs(c-f),o=this.items[l],this.direction=h?"up":"down")}if(!o&&!this.options.dropOnEmpty)return;this.currentContainer=this.containers[r],o?this._rearrange(t,o,null,!0):this._rearrange(t,null,this.containers[r].element,!0),this._trigger("change",t,this._uiHash()),this.containers[r]._trigger("change",t,this._uiHash(this)),this.options.placeholder.update(this.currentContainer,this.placeholder),this.containers[r]._trigger("over",t,this._uiHash(this)),this.containers[r].containerCache.over=1}},_createHelper:function(t){var n=this.options,r=e.isFunction(n.helper)?e(n.helper.apply(this.element[0],[t,this.currentItem])):n.helper=="clone"?this.currentItem.clone():this.currentItem;return r.parents("body").length||e(n.appendTo!="parent"?n.appendTo:this.currentItem[0].parentNode)[0].appendChild(r[0]),r[0]==this.currentItem[0]&&(this._storedCSS={width:this.currentItem[0].style.width,height:this.currentItem[0].style.height,position:this.currentItem.css("position"),top:this.currentItem.css("top"),left:this.currentItem.css("left")}),(r[0].style.width==""||n.forceHelperSize)&&r.width(this.currentItem.width()),(r[0].style.height==""||n.forceHelperSize)&&r.height(this.currentItem.height()),r},_adjustOffsetFromHelper:function(t){typeof t=="string"&&(t=t.split(" ")),e.isArray(t)&&(t={left:+t[0],top:+t[1]||0}),"left"in t&&(this.offset.click.left=t.left+this.margins.left),"right"in t&&(this.offset.click.left=this.helperProportions.width-t.right+this.margins.left),"top"in t&&(this.offset.click.top=t.top+this.margins.top),"bottom"in t&&(this.offset.click.top=this.helperProportions.height-t.bottom+this.margins.top)},_getParentOffset:function(){this.offsetParent=this.helper.offsetParent();var t=this.offsetParent.offset();this.cssPosition=="absolute"&&this.scrollParent[0]!=document&&e.contains(this.scrollParent[0],this.offsetParent[0])&&(t.left+=this.scrollParent.scrollLeft(),t.top+=this.scrollParent.scrollTop());if(this.offsetParent[0]==document.body||this.offsetParent[0].tagName&&this.offsetParent[0].tagName.toLowerCase()=="html"&&e.ui.ie)t={top:0,left:0};return{top:t.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:t.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if(this.cssPosition=="relative"){var e=this.currentItem.position();return{top:e.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:e.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.currentItem.css("marginLeft"),10)||0,top:parseInt(this.currentItem.css("marginTop"),10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var t=this.options;t.containment=="parent"&&(t.containment=this.helper[0].parentNode);if(t.containment=="document"||t.containment=="window")this.containment=[0-this.offset.relative.left-this.offset.parent.left,0-this.offset.relative.top-this.offset.parent.top,e(t.containment=="document"?document:window).width()-this.helperProportions.width-this.margins.left,(e(t.containment=="document"?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top];if(!/^(document|window|parent)$/.test(t.containment)){var n=e(t.containment)[0],r=e(t.containment).offset(),i=e(n).css("overflow")!="hidden";this.containment=[r.left+(parseInt(e(n).css("borderLeftWidth"),10)||0)+(parseInt(e(n).css("paddingLeft"),10)||0)-this.margins.left,r.top+(parseInt(e(n).css("borderTopWidth"),10)||0)+(parseInt(e(n).css("paddingTop"),10)||0)-this.margins.top,r.left+(i?Math.max(n.scrollWidth,n.offsetWidth):n.offsetWidth)-(parseInt(e(n).css("borderLeftWidth"),10)||0)-(parseInt(e(n).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left,r.top+(i?Math.max(n.scrollHeight,n.offsetHeight):n.offsetHeight)-(parseInt(e(n).css("borderTopWidth"),10)||0)-(parseInt(e(n).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top]}},_convertPositionTo:function(t,n){n||(n=this.position);var r=t=="absolute"?1:-1,i=this.options,s=this.cssPosition!="absolute"||this.scrollParent[0]!=document&&!!e.contains(this.scrollParent[0],this.offsetParent[0])?this.scrollParent:this.offsetParent,o=/(html|body)/i.test(s[0].tagName);return{top:n.top+this.offset.relative.top*r+this.offset.parent.top*r-(this.cssPosition=="fixed"?-this.scrollParent.scrollTop():o?0:s.scrollTop())*r,left:n.left+this.offset.relative.left*r+this.offset.parent.left*r-(this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():o?0:s.scrollLeft())*r}},_generatePosition:function(t){var n=this.options,r=this.cssPosition!="absolute"||this.scrollParent[0]!=document&&!!e.contains(this.scrollParent[0],this.offsetParent[0])?this.scrollParent:this.offsetParent,i=/(html|body)/i.test(r[0].tagName);this.cssPosition=="relative"&&(this.scrollParent[0]==document||this.scrollParent[0]==this.offsetParent[0])&&(this.offset.relative=this._getRelativeOffset());var s=t.pageX,o=t.pageY;if(this.originalPosition){this.containment&&(t.pageX-this.offset.click.left<this.containment[0]&&(s=this.containment[0]+this.offset.click.left),t.pageY-this.offset.click.top<this.containment[1]&&(o=this.containment[1]+this.offset.click.top),t.pageX-this.offset.click.left>this.containment[2]&&(s=this.containment[2]+this.offset.click.left),t.pageY-this.offset.click.top>this.containment[3]&&(o=this.containment[3]+this.offset.click.top));if(n.grid){var u=this.originalPageY+Math.round((o-this.originalPageY)/n.grid[1])*n.grid[1];o=this.containment?u-this.offset.click.top<this.containment[1]||u-this.offset.click.top>this.containment[3]?u-this.offset.click.top<this.containment[1]?u+n.grid[1]:u-n.grid[1]:u:u;var a=this.originalPageX+Math.round((s-this.originalPageX)/n.grid[0])*n.grid[0];s=this.containment?a-this.offset.click.left<this.containment[0]||a-this.offset.click.left>this.containment[2]?a-this.offset.click.left<this.containment[0]?a+n.grid[0]:a-n.grid[0]:a:a}}return{top:o-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+(this.cssPosition=="fixed"?-this.scrollParent.scrollTop():i?0:r.scrollTop()),left:s-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+(this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():i?0:r.scrollLeft())}},_rearrange:function(e,t,n,r){n?n[0].appendChild(this.placeholder[0]):t.item[0].parentNode.insertBefore(this.placeholder[0],this.direction=="down"?t.item[0]:t.item[0].nextSibling),this.counter=this.counter?++this.counter:1;var i=this.counter;this._delay(function(){i==this.counter&&this.refreshPositions(!r)})},_clear:function(t,n){this.reverting=!1;var r=[];!this._noFinalSort&&this.currentItem.parent().length&&this.placeholder.before(this.currentItem),this._noFinalSort=null;if(this.helper[0]==this.currentItem[0]){for(var i in this._storedCSS)if(this._storedCSS[i]=="auto"||this._storedCSS[i]=="static")this._storedCSS[i]="";this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper")}else this.currentItem.show();this.fromOutside&&!n&&r.push(function(e){this._trigger("receive",e,this._uiHash(this.fromOutside))}),(this.fromOutside||this.domPosition.prev!=this.currentItem.prev().not(".ui-sortable-helper")[0]||this.domPosition.parent!=this.currentItem.parent()[0])&&!n&&r.push(function(e){this._trigger("update",e,this._uiHash())}),this!==this.currentContainer&&(n||(r.push(function(e){this._trigger("remove",e,this._uiHash())}),r.push(function(e){return function(t){e._trigger("receive",t,this._uiHash(this))}}.call(this,this.currentContainer)),r.push(function(e){return function(t){e._trigger("update",t,this._uiHash(this))}}.call(this,this.currentContainer))));for(var i=this.containers.length-1;i>=0;i--)n||r.push(function(e){return function(t){e._trigger("deactivate",t,this._uiHash(this))}}.call(this,this.containers[i])),this.containers[i].containerCache.over&&(r.push(function(e){return function(t){e._trigger("out",t,this._uiHash(this))}}.call(this,this.containers[i])),this.containers[i].containerCache.over=0);this._storedCursor&&e("body").css("cursor",this._storedCursor),this._storedOpacity&&this.helper.css("opacity",this._storedOpacity),this._storedZIndex&&this.helper.css("zIndex",this._storedZIndex=="auto"?"":this._storedZIndex),this.dragging=!1;if(this.cancelHelperRemoval){if(!n){this._trigger("beforeStop",t,this._uiHash());for(var i=0;i<r.length;i++)r[i].call(this,t);this._trigger("stop",t,this._uiHash())}return this.fromOutside=!1,!1}n||this._trigger("beforeStop",t,this._uiHash()),this.placeholder[0].parentNode.removeChild(this.placeholder[0]),this.helper[0]!=this.currentItem[0]&&this.helper.remove(),this.helper=null;if(!n){for(var i=0;i<r.length;i++)r[i].call(this,t);this._trigger("stop",t,this._uiHash())}return this.fromOutside=!1,!0},_trigger:function(){e.Widget.prototype._trigger.apply(this,arguments)===!1&&this.cancel()},_uiHash:function(t){var n=t||this;return{helper:n.helper,placeholder:n.placeholder||e([]),position:n.position,originalPosition:n.originalPosition,offset:n.positionAbs,item:n.currentItem,sender:t?t.element:null}}})}(jQuery),jQuery.effects||function(e,t){var n=e.uiBackCompat!==!1,r="ui-effects-";e.effects={effect:{}},function(t,n){function p(e,t,n){var r=a[t.type]||{};return e==null?n||!t.def?null:t.def:(e=r.floor?~~e:parseFloat(e),isNaN(e)?t.def:r.mod?(e+r.mod)%r.mod:0>e?0:r.max<e?r.max:e)}function d(e){var n=o(),r=n._rgba=[];return e=e.toLowerCase(),h(s,function(t,i){var s,o=i.re.exec(e),a=o&&i.parse(o),f=i.space||"rgba";if(a)return s=n[f](a),n[u[f].cache]=s[u[f].cache],r=n._rgba=s._rgba,!1}),r.length?(r.join()==="0,0,0,0"&&t.extend(r,c.transparent),n):c[e]}function v(e,t,n){return n=(n+1)%1,n*6<1?e+(t-e)*n*6:n*2<1?t:n*3<2?e+(t-e)*(2/3-n)*6:e}var r="backgroundColor borderBottomColor borderLeftColor borderRightColor borderTopColor color columnRuleColor outlineColor textDecorationColor textEmphasisColor".split(" "),i=/^([\-+])=\s*(\d+\.?\d*)/,s=[{re:/rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d+(?:\.\d+)?)\s*)?\)/,parse:function(e){return[e[1],e[2],e[3],e[4]]}},{re:/rgba?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d+(?:\.\d+)?)\s*)?\)/,parse:function(e){return[e[1]*2.55,e[2]*2.55,e[3]*2.55,e[4]]}},{re:/#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})/,parse:function(e){return[parseInt(e[1],16),parseInt(e[2],16),parseInt(e[3],16)]}},{re:/#([a-f0-9])([a-f0-9])([a-f0-9])/,parse:function(e){return[parseInt(e[1]+e[1],16),parseInt(e[2]+e[2],16),parseInt(e[3]+e[3],16)]}},{re:/hsla?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d+(?:\.\d+)?)\s*)?\)/,space:"hsla",parse:function(e){return[e[1],e[2]/100,e[3]/100,e[4]]}}],o=t.Color=function(e,n,r,i){return new t.Color.fn.parse(e,n,r,i)},u={rgba:{props:{red:{idx:0,type:"byte"},green:{idx:1,type:"byte"},blue:{idx:2,type:"byte"}}},hsla:{props:{hue:{idx:0,type:"degrees"},saturation:{idx:1,type:"percent"},lightness:{idx:2,type:"percent"}}}},a={"byte":{floor:!0,max:255},percent:{max:1},degrees:{mod:360,floor:!0}},f=o.support={},l=t("<p>")[0],c,h=t.each;l.style.cssText="background-color:rgba(1,1,1,.5)",f.rgba=l.style.backgroundColor.indexOf("rgba")>-1,h(u,function(e,t){t.cache="_"+e,t.props.alpha={idx:3,type:"percent",def:1}}),o.fn=t.extend(o.prototype,{parse:function(r,i,s,a){if(r===n)return this._rgba=[null,null,null,null],this;if(r.jquery||r.nodeType)r=t(r).css(i),i=n;var f=this,l=t.type(r),v=this._rgba=[];i!==n&&(r=[r,i,s,a],l="array");if(l==="string")return this.parse(d(r)||c._default);if(l==="array")return h(u.rgba.props,function(e,t){v[t.idx]=p(r[t.idx],t)}),this;if(l==="object")return r instanceof o?h(u,function(e,t){r[t.cache]&&(f[t.cache]=r[t.cache].slice())}):h(u,function(t,n){var i=n.cache;h(n.props,function(e,t){if(!f[i]&&n.to){if(e==="alpha"||r[e]==null)return;f[i]=n.to(f._rgba)}f[i][t.idx]=p(r[e],t,!0)}),f[i]&&e.inArray(null,f[i].slice(0,3))<0&&(f[i][3]=1,n.from&&(f._rgba=n.from(f[i])))}),this},is:function(e){var t=o(e),n=!0,r=this;return h(u,function(e,i){var s,o=t[i.cache];return o&&(s=r[i.cache]||i.to&&i.to(r._rgba)||[],h(i.props,function(e,t){if(o[t.idx]!=null)return n=o[t.idx]===s[t.idx],n})),n}),n},_space:function(){var e=[],t=this;return h(u,function(n,r){t[r.cache]&&e.push(n)}),e.pop()},transition:function(e,t){var n=o(e),r=n._space(),i=u[r],s=this.alpha()===0?o("transparent"):this,f=s[i.cache]||i.to(s._rgba),l=f.slice();return n=n[i.cache],h(i.props,function(e,r){var i=r.idx,s=f[i],o=n[i],u=a[r.type]||{};if(o===null)return;s===null?l[i]=o:(u.mod&&(o-s>u.mod/2?s+=u.mod:s-o>u.mod/2&&(s-=u.mod)),l[i]=p((o-s)*t+s,r))}),this[r](l)},blend:function(e){if(this._rgba[3]===1)return this;var n=this._rgba.slice(),r=n.pop(),i=o(e)._rgba;return o(t.map(n,function(e,t){return(1-r)*i[t]+r*e}))},toRgbaString:function(){var e="rgba(",n=t.map(this._rgba,function(e,t){return e==null?t>2?1:0:e});return n[3]===1&&(n.pop(),e="rgb("),e+n.join()+")"},toHslaString:function(){var e="hsla(",n=t.map(this.hsla(),function(e,t){return e==null&&(e=t>2?1:0),t&&t<3&&(e=Math.round(e*100)+"%"),e});return n[3]===1&&(n.pop(),e="hsl("),e+n.join()+")"},toHexString:function(e){var n=this._rgba.slice(),r=n.pop();return e&&n.push(~~(r*255)),"#"+t.map(n,function(e){return e=(e||0).toString(16),e.length===1?"0"+e:e}).join("")},toString:function(){return this._rgba[3]===0?"transparent":this.toRgbaString()}}),o.fn.parse.prototype=o.fn,u.hsla.to=function(e){if(e[0]==null||e[1]==null||e[2]==null)return[null,null,null,e[3]];var t=e[0]/255,n=e[1]/255,r=e[2]/255,i=e[3],s=Math.max(t,n,r),o=Math.min(t,n,r),u=s-o,a=s+o,f=a*.5,l,c;return o===s?l=0:t===s?l=60*(n-r)/u+360:n===s?l=60*(r-t)/u+120:l=60*(t-n)/u+240,f===0||f===1?c=f:f<=.5?c=u/a:c=u/(2-a),[Math.round(l)%360,c,f,i==null?1:i]},u.hsla.from=function(e){if(e[0]==null||e[1]==null||e[2]==null)return[null,null,null,e[3]];var t=e[0]/360,n=e[1],r=e[2],i=e[3],s=r<=.5?r*(1+n):r+n-r*n,o=2*r-s;return[Math.round(v(o,s,t+1/3)*255),Math.round(v(o,s,t)*255),Math.round(v(o,s,t-1/3)*255),i]},h(u,function(e,r){var s=r.props,u=r.cache,a=r.to,f=r.from;o.fn[e]=function(e){a&&!this[u]&&(this[u]=a(this._rgba));if(e===n)return this[u].slice();var r,i=t.type(e),l=i==="array"||i==="object"?e:arguments,c=this[u].slice();return h(s,function(e,t){var n=l[i==="object"?e:t.idx];n==null&&(n=c[t.idx]),c[t.idx]=p(n,t)}),f?(r=o(f(c)),r[u]=c,r):o(c)},h(s,function(n,r){if(o.fn[n])return;o.fn[n]=function(s){var o=t.type(s),u=n==="alpha"?this._hsla?"hsla":"rgba":e,a=this[u](),f=a[r.idx],l;return o==="undefined"?f:(o==="function"&&(s=s.call(this,f),o=t.type(s)),s==null&&r.empty?this:(o==="string"&&(l=i.exec(s),l&&(s=f+parseFloat(l[2])*(l[1]==="+"?1:-1))),a[r.idx]=s,this[u](a)))}})}),h(r,function(e,n){t.cssHooks[n]={set:function(e,r){var i,s,u="";if(t.type(r)!=="string"||(i=d(r))){r=o(i||r);if(!f.rgba&&r._rgba[3]!==1){s=n==="backgroundColor"?e.parentNode:e;while((u===""||u==="transparent")&&s&&s.style)try{u=t.css(s,"backgroundColor"),s=s.parentNode}catch(a){}r=r.blend(u&&u!=="transparent"?u:"_default")}r=r.toRgbaString()}try{e.style[n]=r}catch(l){}}},t.fx.step[n]=function(e){e.colorInit||(e.start=o(e.elem,n),e.end=o(e.end),e.colorInit=!0),t.cssHooks[n].set(e.elem,e.start.transition(e.end,e.pos))}}),t.cssHooks.borderColor={expand:function(e){var t={};return h(["Top","Right","Bottom","Left"],function(n,r){t["border"+r+"Color"]=e}),t}},c=t.Color.names={aqua:"#00ffff",black:"#000000",blue:"#0000ff",fuchsia:"#ff00ff",gray:"#808080",green:"#008000",lime:"#00ff00",maroon:"#800000",navy:"#000080",olive:"#808000",purple:"#800080",red:"#ff0000",silver:"#c0c0c0",teal:"#008080",white:"#ffffff",yellow:"#ffff00",transparent:[null,null,null,0],_default:"#ffffff"}}(jQuery),function(){function i(){var t=this.ownerDocument.defaultView?this.ownerDocument.defaultView.getComputedStyle(this,null):this.currentStyle,n={},r,i;if(t&&t.length&&t[0]&&t[t[0]]){i=t.length;while(i--)r=t[i],typeof t[r]=="string"&&(n[e.camelCase(r)]=t[r])}else for(r in t)typeof t[r]=="string"&&(n[r]=t[r]);return n}function s(t,n){var i={},s,o;for(s in n)o=n[s],t[s]!==o&&!r[s]&&(e.fx.step[s]||!isNaN(parseFloat(o)))&&(i[s]=o);return i}var n=["add","remove","toggle"],r={border:1,borderBottom:1,borderColor:1,borderLeft:1,borderRight:1,borderTop:1,borderWidth:1,margin:1,padding:1};e.each(["borderLeftStyle","borderRightStyle","borderBottomStyle","borderTopStyle"],function(t,n){e.fx.step[n]=function(e){if(e.end!=="none"&&!e.setAttr||e.pos===1&&!e.setAttr)jQuery.style(e.elem,n,e.end),e.setAttr=!0}}),e.effects.animateClass=function(t,r,o,u){var a=e.speed(r,o,u);return this.queue(function(){var r=e(this),o=r.attr("class")||"",u,f=a.children?r.find("*").andSelf():r;f=f.map(function(){var t=e(this);return{el:t,start:i.call(this)}}),u=function(){e.each(n,function(e,n){t[n]&&r[n+"Class"](t[n])})},u(),f=f.map(function(){return this.end=i.call(this.el[0]),this.diff=s(this.start,this.end),this}),r.attr("class",o),f=f.map(function(){var t=this,n=e.Deferred(),r=jQuery.extend({},a,{queue:!1,complete:function(){n.resolve(t)}});return this.el.animate(this.diff,r),n.promise()}),e.when.apply(e,f.get()).done(function(){u(),e.each(arguments,function(){var t=this.el;e.each(this.diff,function(e){t.css(e,"")})}),a.complete.call(r[0])})})},e.fn.extend({_addClass:e.fn.addClass,addClass:function(t,n,r,i){return n?e.effects.animateClass.call(this,{add:t},n,r,i):this._addClass(t)},_removeClass:e.fn.removeClass,removeClass:function(t,n,r,i){return n?e.effects.animateClass.call(this,{remove:t},n,r,i):this._removeClass(t)},_toggleClass:e.fn.toggleClass,toggleClass:function(n,r,i,s,o){return typeof r=="boolean"||r===t?i?e.effects.animateClass.call(this,r?{add:n}:{remove:n},i,s,o):this._toggleClass(n,r):e.effects.animateClass.call(this,{toggle:n},r,i,s)},switchClass:function(t,n,r,i,s){return e.effects.animateClass.call(this,{add:n,remove:t},r,i,s)}})}(),function(){function i(t,n,r,i){e.isPlainObject(t)&&(n=t,t=t.effect),t={effect:t},n==null&&(n={}),e.isFunction(n)&&(i=n,r=null,n={});if(typeof n=="number"||e.fx.speeds[n])i=r,r=n,n={};return e.isFunction(r)&&(i=r,r=null),n&&e.extend(t,n),r=r||n.duration,t.duration=e.fx.off?0:typeof r=="number"?r:r in e.fx.speeds?e.fx.speeds[r]:e.fx.speeds._default,t.complete=i||n.complete,t}function s(t){return!t||typeof t=="number"||e.fx.speeds[t]?!0:typeof t=="string"&&!e.effects.effect[t]?n&&e.effects[t]?!1:!0:!1}e.extend(e.effects,{version:"1.9.2",save:function(e,t){for(var n=0;n<t.length;n++)t[n]!==null&&e.data(r+t[n],e[0].style[t[n]])},restore:function(e,n){var i,s;for(s=0;s<n.length;s++)n[s]!==null&&(i=e.data(r+n[s]),i===t&&(i=""),e.css(n[s],i))},setMode:function(e,t){return t==="toggle"&&(t=e.is(":hidden")?"show":"hide"),t},getBaseline:function(e,t){var n,r;switch(e[0]){case"top":n=0;break;case"middle":n=.5;break;case"bottom":n=1;break;default:n=e[0]/t.height}switch(e[1]){case"left":r=0;break;case"center":r=.5;break;case"right":r=1;break;default:r=e[1]/t.width}return{x:r,y:n}},createWrapper:function(t){if(t.parent().is(".ui-effects-wrapper"))return t.parent();var n={width:t.outerWidth(!0),height:t.outerHeight(!0),"float":t.css("float")},r=e("<div></div>").addClass("ui-effects-wrapper").css({fontSize:"100%",background:"transparent",border:"none",margin:0,padding:0}),i={width:t.width(),height:t.height()},s=document.activeElement;try{s.id}catch(o){s=document.body}return t.wrap(r),(t[0]===s||e.contains(t[0],s))&&e(s).focus(),r=t.parent(),t.css("position")==="static"?(r.css({position:"relative"}),t.css({position:"relative"})):(e.extend(n,{position:t.css("position"),zIndex:t.css("z-index")}),e.each(["top","left","bottom","right"],function(e,r){n[r]=t.css(r),isNaN(parseInt(n[r],10))&&(n[r]="auto")}),t.css({position:"relative",top:0,left:0,right:"auto",bottom:"auto"})),t.css(i),r.css(n).show()},removeWrapper:function(t){var n=document.activeElement;return t.parent().is(".ui-effects-wrapper")&&(t.parent().replaceWith(t),(t[0]===n||e.contains(t[0],n))&&e(n).focus()),t},setTransition:function(t,n,r,i){return i=i||{},e.each(n,function(e,n){var s=t.cssUnit(n);s[0]>0&&(i[n]=s[0]*r+s[1])}),i}}),e.fn.extend({effect:function(){function a(n){function u(){e.isFunction(i)&&i.call(r[0]),e.isFunction(n)&&n()}var r=e(this),i=t.complete,s=t.mode;(r.is(":hidden")?s==="hide":s==="show")?u():o.call(r[0],t,u)}var t=i.apply(this,arguments),r=t.mode,s=t.queue,o=e.effects.effect[t.effect],u=!o&&n&&e.effects[t.effect];return e.fx.off||!o&&!u?r?this[r](t.duration,t.complete):this.each(function(){t.complete&&t.complete.call(this)}):o?s===!1?this.each(a):this.queue(s||"fx",a):u.call(this,{options:t,duration:t.duration,callback:t.complete,mode:t.mode})},_show:e.fn.show,show:function(e){if(s(e))return this._show.apply(this,arguments);var t=i.apply(this,arguments);return t.mode="show",this.effect.call(this,t)},_hide:e.fn.hide,hide:function(e){if(s(e))return this._hide.apply(this,arguments);var t=i.apply(this,arguments);return t.mode="hide",this.effect.call(this,t)},__toggle:e.fn.toggle,toggle:function(t){if(s(t)||typeof t=="boolean"||e.isFunction(t))return this.__toggle.apply(this,arguments);var n=i.apply(this,arguments);return n.mode="toggle",this.effect.call(this,n)},cssUnit:function(t){var n=this.css(t),r=[];return e.each(["em","px","%","pt"],function(e,t){n.indexOf(t)>0&&(r=[parseFloat(n),t])}),r}})}(),function(){var t={};e.each(["Quad","Cubic","Quart","Quint","Expo"],function(e,n){t[n]=function(t){return Math.pow(t,e+2)}}),e.extend(t,{Sine:function(e){return 1-Math.cos(e*Math.PI/2)},Circ:function(e){return 1-Math.sqrt(1-e*e)},Elastic:function(e){return e===0||e===1?e:-Math.pow(2,8*(e-1))*Math.sin(((e-1)*80-7.5)*Math.PI/15)},Back:function(e){return e*e*(3*e-2)},Bounce:function(e){var t,n=4;while(e<((t=Math.pow(2,--n))-1)/11);return 1/Math.pow(4,3-n)-7.5625*Math.pow((t*3-2)/22-e,2)}}),e.each(t,function(t,n){e.easing["easeIn"+t]=n,e.easing["easeOut"+t]=function(e){return 1-n(1-e)},e.easing["easeInOut"+t]=function(e){return e<.5?n(e*2)/2:1-n(e*-2+2)/2}})}()}(jQuery),function(e,t){var n=0,r={},i={};r.height=r.paddingTop=r.paddingBottom=r.borderTopWidth=r.borderBottomWidth="hide",i.height=i.paddingTop=i.paddingBottom=i.borderTopWidth=i.borderBottomWidth="show",e.widget("ui.accordion",{version:"1.9.2",options:{active:0,animate:{},collapsible:!1,event:"click",header:"> li > :first-child,> :not(li):even",heightStyle:"auto",icons:{activeHeader:"ui-icon-triangle-1-s",header:"ui-icon-triangle-1-e"},activate:null,beforeActivate:null},_create:function(){var t=this.accordionId="ui-accordion-"+(this.element.attr("id")||++n),r=this.options;this.prevShow=this.prevHide=e(),this.element.addClass("ui-accordion ui-widget ui-helper-reset"),this.headers=this.element.find(r.header).addClass("ui-accordion-header ui-helper-reset ui-state-default ui-corner-all"),this._hoverable(this.headers),this._focusable(this.headers),this.headers.next().addClass("ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom").hide(),!r.collapsible&&(r.active===!1||r.active==null)&&(r.active=0),r.active<0&&(r.active+=this.headers.length),this.active=this._findActive(r.active).addClass("ui-accordion-header-active ui-state-active").toggleClass("ui-corner-all ui-corner-top"),this.active.next().addClass("ui-accordion-content-active").show(),this._createIcons(),this.refresh(),this.element.attr("role","tablist"),this.headers.attr("role","tab").each(function(n){var r=e(this),i=r.attr("id"),s=r.next(),o=s.attr("id");i||(i=t+"-header-"+n,r.attr("id",i)),o||(o=t+"-panel-"+n,s.attr("id",o)),r.attr("aria-controls",o),s.attr("aria-labelledby",i)}).next().attr("role","tabpanel"),this.headers.not(this.active).attr({"aria-selected":"false",tabIndex:-1}).next().attr({"aria-expanded":"false","aria-hidden":"true"}).hide(),this.active.length?this.active.attr({"aria-selected":"true",tabIndex:0}).next().attr({"aria-expanded":"true","aria-hidden":"false"}):this.headers.eq(0).attr("tabIndex",0),this._on(this.headers,{keydown:"_keydown"}),this._on(this.headers.next(),{keydown:"_panelKeyDown"}),this._setupEvents(r.event)},_getCreateEventData:function(){return{header:this.active,content:this.active.length?this.active.next():e()}},_createIcons:function(){var t=this.options.icons;t&&(e("<span>").addClass("ui-accordion-header-icon ui-icon "+t.header).prependTo(this.headers),this.active.children(".ui-accordion-header-icon").removeClass(t.header).addClass(t.activeHeader),this.headers.addClass("ui-accordion-icons"))},_destroyIcons:function(){this.headers.removeClass("ui-accordion-icons").children(".ui-accordion-header-icon").remove()},_destroy:function(){var e;this.element.removeClass("ui-accordion ui-widget ui-helper-reset").removeAttr("role"),this.headers.removeClass("ui-accordion-header ui-accordion-header-active ui-helper-reset ui-state-default ui-corner-all ui-state-active ui-state-disabled ui-corner-top").removeAttr("role").removeAttr("aria-selected").removeAttr("aria-controls").removeAttr("tabIndex").each(function(){/^ui-accordion/.test(this.id)&&this.removeAttribute("id")}),this._destroyIcons(),e=this.headers.next().css("display","").removeAttr("role").removeAttr("aria-expanded").removeAttr("aria-hidden").removeAttr("aria-labelledby").removeClass("ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active ui-state-disabled").each(function(){/^ui-accordion/.test(this.id)&&this.removeAttribute("id")}),this.options.heightStyle!=="content"&&e.css("height","")},_setOption:function(e,t){if(e==="active"){this._activate(t);return}e==="event"&&(this.options.event&&this._off(this.headers,this.options.event),this._setupEvents(t)),this._super(e,t),e==="collapsible"&&!t&&this.options.active===!1&&this._activate(0),e==="icons"&&(this._destroyIcons(),t&&this._createIcons()),e==="disabled"&&this.headers.add(this.headers.next()).toggleClass("ui-state-disabled",!!t)},_keydown:function(t){if(t.altKey||t.ctrlKey)return;var n=e.ui.keyCode,r=this.headers.length,i=this.headers.index(t.target),s=!1;switch(t.keyCode){case n.RIGHT:case n.DOWN:s=this.headers[(i+1)%r];break;case n.LEFT:case n.UP:s=this.headers[(i-1+r)%r];break;case n.SPACE:case n.ENTER:this._eventHandler(t);break;case n.HOME:s=this.headers[0];break;case n.END:s=this.headers[r-1]}s&&(e(t.target).attr("tabIndex",-1),e(s).attr("tabIndex",0),s.focus(),t.preventDefault())},_panelKeyDown:function(t){t.keyCode===e.ui.keyCode.UP&&t.ctrlKey&&e(t.currentTarget).prev().focus()},refresh:function(){var t,n,r=this.options.heightStyle,i=this.element.parent();r==="fill"?(e.support.minHeight||(n=i.css("overflow"),i.css("overflow","hidden")),t=i.height(),this.element.siblings(":visible").each(function(){var n=e(this),r=n.css("position");if(r==="absolute"||r==="fixed")return;t-=n.outerHeight(!0)}),n&&i.css("overflow",n),this.headers.each(function(){t-=e(this).outerHeight(!0)}),this.headers.next().each(function(){e(this).height(Math.max(0,t-e(this).innerHeight()+e(this).height()))}).css("overflow","auto")):r==="auto"&&(t=0,this.headers.next().each(function(){t=Math.max(t,e(this).css("height","").height())}).height(t))},_activate:function(t){var n=this._findActive(t)[0];if(n===this.active[0])return;n=n||this.active[0],this._eventHandler({target:n,currentTarget:n,preventDefault:e.noop})},_findActive:function(t){return typeof t=="number"?this.headers.eq(t):e()},_setupEvents:function(t){var n={};if(!t)return;e.each(t.split(" "),function(e,t){n[t]="_eventHandler"}),this._on(this.headers,n)},_eventHandler:function(t){var n=this.options,r=this.active,i=e(t.currentTarget),s=i[0]===r[0],o=s&&n.collapsible,u=o?e():i.next(),a=r.next(),f={oldHeader:r,oldPanel:a,newHeader:o?e():i,newPanel:u};t.preventDefault();if(s&&!n.collapsible||this._trigger("beforeActivate",t,f)===!1)return;n.active=o?!1:this.headers.index(i),this.active=s?e():i,this._toggle(f),r.removeClass("ui-accordion-header-active ui-state-active"),n.icons&&r.children(".ui-accordion-header-icon").removeClass(n.icons.activeHeader).addClass(n.icons.header),s||(i.removeClass("ui-corner-all").addClass("ui-accordion-header-active ui-state-active ui-corner-top"),n.icons&&i.children(".ui-accordion-header-icon").removeClass(n.icons.header).addClass(n.icons.activeHeader),i.next().addClass("ui-accordion-content-active"))},_toggle:function(t){var n=t.newPanel,r=this.prevShow.length?this.prevShow:t.oldPanel;this.prevShow.add(this.prevHide).stop(!0,!0),this.prevShow=n,this.prevHide=r,this.options.animate?this._animate(n,r,t):(r.hide(),n.show(),this._toggleComplete(t)),r.attr({"aria-expanded":"false","aria-hidden":"true"}),r.prev().attr("aria-selected","false"),n.length&&r.length?r.prev().attr("tabIndex",-1):n.length&&this.headers.filter(function(){return e(this).attr("tabIndex")===0}).attr("tabIndex",-1),n.attr({"aria-expanded":"true","aria-hidden":"false"}).prev().attr({"aria-selected":"true",tabIndex:0})},_animate:function(e,t,n){var s,o,u,a=this,f=0,l=e.length&&(!t.length||e.index()<t.index()),c=this.options.animate||{},h=l&&c.down||c,p=function(){a._toggleComplete(n)};typeof h=="number"&&(u=h),typeof h=="string"&&(o=h),o=o||h.easing||c.easing,u=u||h.duration||c.duration;if(!t.length)return e.animate(i,u,o,p);if(!e.length)return t.animate(r,u,o,p);s=e.show().outerHeight(),t.animate(r,{duration:u,easing:o,step:function(e,t){t.now=Math.round(e)}}),e.hide().animate(i,{duration:u,easing:o,complete:p,step:function(e,n){n.now=Math.round(e),n.prop!=="height"?f+=n.now:a.options.heightStyle!=="content"&&(n.now=Math.round(s-t.outerHeight()-f),f=0)}})},_toggleComplete:function(e){var t=e.oldPanel;t.removeClass("ui-accordion-content-active").prev().removeClass("ui-corner-top").addClass("ui-corner-all"),t.length&&(t.parent()[0].className=t.parent()[0].className),this._trigger("activate",null,e)}}),e.uiBackCompat!==!1&&(function(e,t){e.extend(t.options,{navigation:!1,navigationFilter:function(){return this.href.toLowerCase()===location.href.toLowerCase()}});var n=t._create;t._create=function(){if(this.options.navigation){var t=this,r=this.element.find(this.options.header),i=r.next(),s=r.add(i).find("a").filter(this.options.navigationFilter)[0];s&&r.add(i).each(function(n){if(e.contains(this,s))return t.options.active=Math.floor(n/2),!1})}n.call(this)}}(jQuery,jQuery.ui.accordion.prototype),function(e,t){e.extend(t.options,{heightStyle:null,autoHeight:!0,clearStyle:!1,fillSpace:!1});var n=t._create,r=t._setOption;e.extend(t,{_create:function(){this.options.heightStyle=this.options.heightStyle||this._mergeHeightStyle(),n.call(this)},_setOption:function(e){if(e==="autoHeight"||e==="clearStyle"||e==="fillSpace")this.options.heightStyle=this._mergeHeightStyle();r.apply(this,arguments)},_mergeHeightStyle:function(){var e=this.options;if(e.fillSpace)return"fill";if(e.clearStyle)return"content";if(e.autoHeight)return"auto"}})}(jQuery,jQuery.ui.accordion.prototype),function(e,t){e.extend(t.options.icons,{activeHeader:null,headerSelected:"ui-icon-triangle-1-s"});var n=t._createIcons;t._createIcons=function(){this.options.icons&&(this.options.icons.activeHeader=this.options.icons.activeHeader||this.options.icons.headerSelected),n.call(this)}}(jQuery,jQuery.ui.accordion.prototype),function(e,t){t.activate=t._activate;var n=t._findActive;t._findActive=function(e){return e===-1&&(e=!1),e&&typeof e!="number"&&(e=this.headers.index(this.headers.filter(e)),e===-1&&(e=!1)),n.call(this,e)}}(jQuery,jQuery.ui.accordion.prototype),jQuery.ui.accordion.prototype.resize=jQuery.ui.accordion.prototype.refresh,function(e,t){e.extend(t.options,{change:null,changestart:null});var n=t._trigger;t._trigger=function(e,t,r){var i=n.apply(this,arguments);return i?(e==="beforeActivate"?i=n.call(this,"changestart",t,{oldHeader:r.oldHeader,oldContent:r.oldPanel,newHeader:r.newHeader,newContent:r.newPanel}):e==="activate"&&(i=n.call(this,"change",t,{oldHeader:r.oldHeader,oldContent:r.oldPanel,newHeader:r.newHeader,newContent:r.newPanel})),i):!1}}(jQuery,jQuery.ui.accordion.prototype),function(e,t){e.extend(t.options,{animate:null,animated:"slide"});var n=t._create;t._create=function(){var e=this.options;e.animate===null&&(e.animated?e.animated==="slide"?e.animate=300:e.animated==="bounceslide"?e.animate={duration:200,down:{easing:"easeOutBounce",duration:1e3}}:e.animate=e.animated:e.animate=!1),n.call(this)}}(jQuery,jQuery.ui.accordion.prototype))}(jQuery),function(e,t){var n=0;e.widget("ui.autocomplete",{version:"1.9.2",defaultElement:"<input>",options:{appendTo:"body",autoFocus:!1,delay:300,minLength:1,position:{my:"left top",at:"left bottom",collision:"none"},source:null,change:null,close:null,focus:null,open:null,response:null,search:null,select:null},pending:0,_create:function(){var t,n,r;this.isMultiLine=this._isMultiLine(),this.valueMethod=this.element[this.element.is("input,textarea")?"val":"text"],this.isNewMenu=!0,this.element.addClass("ui-autocomplete-input").attr("autocomplete","off"),this._on(this.element,{keydown:function(i){if(this.element.prop("readOnly")){t=!0,r=!0,n=!0;return}t=!1,r=!1,n=!1;var s=e.ui.keyCode;switch(i.keyCode){case s.PAGE_UP:t=!0,this._move("previousPage",i);break;case s.PAGE_DOWN:t=!0,this._move("nextPage",i);break;case s.UP:t=!0,this._keyEvent("previous",i);break;case s.DOWN:t=!0,this._keyEvent("next",i);break;case s.ENTER:case s.NUMPAD_ENTER:this.menu.active&&(t=!0,i.preventDefault(),this.menu.select(i));break;case s.TAB:this.menu.active&&this.menu.select(i);break;case s.ESCAPE:this.menu.element.is(":visible")&&(this._value(this.term),this.close(i),i.preventDefault());break;default:n=!0,this._searchTimeout(i)}},keypress:function(r){if(t){t=!1,r.preventDefault();return}if(n)return;var i=e.ui.keyCode;switch(r.keyCode){case i.PAGE_UP:this._move("previousPage",r);break;case i.PAGE_DOWN:this._move("nextPage",r);break;case i.UP:this._keyEvent("previous",r);break;case i.DOWN:this._keyEvent("next",r)}},input:function(e){if(r){r=!1,e.preventDefault();return}this._searchTimeout(e)},focus:function(){this.selectedItem=null,this.previous=this._value()},blur:function(e){if(this.cancelBlur){delete this.cancelBlur;return}clearTimeout(this.searching),this.close(e),this._change(e)}}),this._initSource(),this.menu=e("<ul>").addClass("ui-autocomplete").appendTo(this.document.find(this.options.appendTo||"body")[0]).menu({input:e(),role:null}).zIndex(this.element.zIndex()+1).hide().data("menu"),this._on(this.menu.element,{mousedown:function(t){t.preventDefault(),this.cancelBlur=!0,this._delay(function(){delete this.cancelBlur});var n=this.menu.element[0];e(t.target).closest(".ui-menu-item").length||this._delay(function(){var t=this;this.document.one("mousedown",function(r){r.target!==t.element[0]&&r.target!==n&&!e.contains(n,r.target)&&t.close()})})},menufocus:function(t,n){if(this.isNewMenu){this.isNewMenu=!1;if(t.originalEvent&&/^mouse/.test(t.originalEvent.type)){this.menu.blur(),this.document.one("mousemove",function(){e(t.target).trigger(t.originalEvent)});return}}var r=n.item.data("ui-autocomplete-item")||n.item.data("item.autocomplete");!1!==this._trigger("focus",t,{item:r})?t.originalEvent&&/^key/.test(t.originalEvent.type)&&this._value(r.value):this.liveRegion.text(r.value)},menuselect:function(e,t){var n=t.item.data("ui-autocomplete-item")||t.item.data("item.autocomplete"),r=this.previous;this.element[0]!==this.document[0].activeElement&&(this.element.focus(),this.previous=r,this._delay(function(){this.previous=r,this.selectedItem=n})),!1!==this._trigger("select",e,{item:n})&&this._value(n.value),this.term=this._value(),this.close(e),this.selectedItem=n}}),this.liveRegion=e("<span>",{role:"status","aria-live":"polite"}).addClass("ui-helper-hidden-accessible").insertAfter(this.element),e.fn.bgiframe&&this.menu.element.bgiframe(),this._on(this.window,{beforeunload:function(){this.element.removeAttr("autocomplete")}})},_destroy:function(){clearTimeout(this.searching),this.element.removeClass("ui-autocomplete-input").removeAttr("autocomplete"),this.menu.element.remove(),this.liveRegion.remove()},_setOption:function(e,t){this._super(e,t),e==="source"&&this._initSource(),e==="appendTo"&&this.menu.element.appendTo(this.document.find(t||"body")[0]),e==="disabled"&&t&&this.xhr&&this.xhr.abort()},_isMultiLine:function(){return this.element.is("textarea")?!0:this.element.is("input")?!1:this.element.prop("isContentEditable")},_initSource:function(){var t,n,r=this;e.isArray(this.options.source)?(t=this.options.source,this.source=function(n,r){r(e.ui.autocomplete.filter(t,n.term))}):typeof this.options.source=="string"?(n=this.options.source,this.source=function(t,i){r.xhr&&r.xhr.abort(),r.xhr=e.ajax({url:n,data:t,dataType:"json",success:function(e){i(e)},error:function(){i([])}})}):this.source=this.options.source},_searchTimeout:function(e){clearTimeout(this.searching),this.searching=this._delay(function(){this.term!==this._value()&&(this.selectedItem=null,this.search(null,e))},this.options.delay)},search:function(e,t){e=e!=null?e:this._value(),this.term=this._value();if(e.length<this.options.minLength)return this.close(t);if(this._trigger("search",t)===!1)return;return this._search(e)},_search:function(e){this.pending++,this.element.addClass("ui-autocomplete-loading"),this.cancelSearch=!1,this.source({term:e},this._response())},_response:function(){var e=this,t=++n;return function(r){t===n&&e.__response(r),e.pending--,e.pending||e.element.removeClass("ui-autocomplete-loading")}},__response:function(e){e&&(e=this._normalize(e)),this._trigger("response",null,{content:e}),!this.options.disabled&&e&&e.length&&!this.cancelSearch?(this._suggest(e),this._trigger("open")):this._close()},close:function(e){this.cancelSearch=!0,this._close(e)},_close:function(e){this.menu.element.is(":visible")&&(this.menu.element.hide(),this.menu.blur(),this.isNewMenu=!0,this._trigger("close",e))},_change:function(e){this.previous!==this._value()&&this._trigger("change",e,{item:this.selectedItem})},_normalize:function(t){return t.length&&t[0].label&&t[0].value?t:e.map(t,function(t){return typeof t=="string"?{label:t,value:t}:e.extend({label:t.label||t.value,value:t.value||t.label},t)})},_suggest:function(t){var n=this.menu.element.empty().zIndex(this.element.zIndex()+1);this._renderMenu(n,t),this.menu.refresh(),n.show(),this._resizeMenu(),n.position(e.extend({of:this.element},this.options.position)),this.options.autoFocus&&this.menu.next()},_resizeMenu:function(){var e=this.menu.element;e.outerWidth(Math.max(e.width("").outerWidth()+1,this.element.outerWidth()))},_renderMenu:function(t,n){var r=this;e.each(n,function(e,n){r._renderItemData(t,n)})},_renderItemData:function(e,t){return this._renderItem(e,t).data("ui-autocomplete-item",t)},_renderItem:function(t,n){return e("<li>").append(e("<a>").text(n.label)).appendTo(t)},_move:function(e,t){if(!this.menu.element.is(":visible")){this.search(null,t);return}if(this.menu.isFirstItem()&&/^previous/.test(e)||this.menu.isLastItem()&&/^next/.test(e)){this._value(this.term),this.menu.blur();return}this.menu[e](t)},widget:function(){return this.menu.element},_value:function(){return this.valueMethod.apply(this.element,arguments)},_keyEvent:function(e,t){if(!this.isMultiLine||this.menu.element.is(":visible"))this._move(e,t),t.preventDefault()}}),e.extend(e.ui.autocomplete,{escapeRegex:function(e){return e.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g,"\\$&")},filter:function(t,n){var r=new RegExp(e.ui.autocomplete.escapeRegex(n),"i");return e.grep(t,function(e){return r.test(e.label||e.value||e)})}}),e.widget("ui.autocomplete",e.ui.autocomplete,{options:{messages:{noResults:"No search results.",results:function(e){return e+(e>1?" results are":" result is")+" available, use up and down arrow keys to navigate."}}},__response:function(e){var t;this._superApply(arguments);if(this.options.disabled||this.cancelSearch)return;e&&e.length?t=this.options.messages.results(e.length):t=this.options.messages.noResults,this.liveRegion.text(t)}})}(jQuery),function(e,t){var n,r,i,s,o="ui-button ui-widget ui-state-default ui-corner-all",u="ui-state-hover ui-state-active ",a="ui-button-icons-only ui-button-icon-only ui-button-text-icons ui-button-text-icon-primary ui-button-text-icon-secondary ui-button-text-only",f=function(){var t=e(this).find(":ui-button");setTimeout(function(){t.button("refresh")},1)},l=function(t){var n=t.name,r=t.form,i=e([]);return n&&(r?i=e(r).find("[name='"+n+"']"):i=e("[name='"+n+"']",t.ownerDocument).filter(function(){return!this.form})),i};e.widget("ui.button",{version:"1.9.2",defaultElement:"<button>",options:{disabled:null,text:!0,label:null,icons:{primary:null,secondary:null}},_create:function(){this.element.closest("form").unbind("reset"+this.eventNamespace).bind("reset"+this.eventNamespace,f),typeof this.options.disabled!="boolean"?this.options.disabled=!!this.element.prop("disabled"):this.element.prop("disabled",this.options.disabled),this._determineButtonType(),this.hasTitle=!!this.buttonElement.attr("title");var t=this,u=this.options,a=this.type==="checkbox"||this.type==="radio",c=a?"":"ui-state-active",h="ui-state-focus";u.label===null&&(u.label=this.type==="input"?this.buttonElement.val():this.buttonElement.html()),this._hoverable(this.buttonElement),this.buttonElement.addClass(o).attr("role","button").bind("mouseenter"+this.eventNamespace,function(){if(u.disabled)return;this===n&&e(this).addClass("ui-state-active")}).bind("mouseleave"+this.eventNamespace,function(){if(u.disabled)return;e(this).removeClass(c)}).bind("click"+this.eventNamespace,function(e){u.disabled&&(e.preventDefault(),e.stopImmediatePropagation())}),this.element.bind("focus"+this.eventNamespace,function(){t.buttonElement.addClass(h)}).bind("blur"+this.eventNamespace,function(){t.buttonElement.removeClass(h)}),a&&(this.element.bind("change"+this.eventNamespace,function(){if(s)return;t.refresh()}),this.buttonElement.bind("mousedown"+this.eventNamespace,function(e){if(u.disabled)return;s=!1,r=e.pageX,i=e.pageY}).bind("mouseup"+this.eventNamespace,function(e){if(u.disabled)return;if(r!==e.pageX||i!==e.pageY)s=!0})),this.type==="checkbox"?this.buttonElement.bind("click"+this.eventNamespace,function(){if(u.disabled||s)return!1;e(this).toggleClass("ui-state-active"),t.buttonElement.attr("aria-pressed",t.element[0].checked)}):this.type==="radio"?this.buttonElement.bind("click"+this.eventNamespace,function(){if(u.disabled||s)return!1;e(this).addClass("ui-state-active"),t.buttonElement.attr("aria-pressed","true");var n=t.element[0];l(n).not(n).map(function(){return e(this).button("widget")[0]}).removeClass("ui-state-active").attr("aria-pressed","false")}):(this.buttonElement.bind("mousedown"+this.eventNamespace,function(){if(u.disabled)return!1;e(this).addClass("ui-state-active"),n=this,t.document.one("mouseup",function(){n=null})}).bind("mouseup"+this.eventNamespace,function(){if(u.disabled)return!1;e(this).removeClass("ui-state-active")}).bind("keydown"+this.eventNamespace,function(t){if(u.disabled)return!1;(t.keyCode===e.ui.keyCode.SPACE||t.keyCode===e.ui.keyCode.ENTER)&&e(this).addClass("ui-state-active")}).bind("keyup"+this.eventNamespace,function(){e(this).removeClass("ui-state-active")}),this.buttonElement.is("a")&&this.buttonElement.keyup(function(t){t.keyCode===e.ui.keyCode.SPACE&&e(this).click()})),this._setOption("disabled",u.disabled),this._resetButton()},_determineButtonType:function(){var e,t,n;this.element.is("[type=checkbox]")?this.type="checkbox":this.element.is("[type=radio]")?this.type="radio":this.element.is("input")?this.type="input":this.type="button",this.type==="checkbox"||this.type==="radio"?(e=this.element.parents().last(),t="label[for='"+this.element.attr("id")+"']",this.buttonElement=e.find(t),this.buttonElement.length||(e=e.length?e.siblings():this.element.siblings(),this.buttonElement=e.filter(t),this.buttonElement.length||(this.buttonElement=e.find(t))),this.element.addClass("ui-helper-hidden-accessible"),n=this.element.is(":checked"),n&&this.buttonElement.addClass("ui-state-active"),this.buttonElement.prop("aria-pressed",n)):this.buttonElement=this.element},widget:function(){return this.buttonElement},_destroy:function(){this.element.removeClass("ui-helper-hidden-accessible"),this.buttonElement.removeClass(o+" "+u+" "+a).removeAttr("role").removeAttr("aria-pressed").html(this.buttonElement.find(".ui-button-text").html()),this.hasTitle||this.buttonElement.removeAttr("title")},_setOption:function(e,t){this._super(e,t);if(e==="disabled"){t?this.element.prop("disabled",!0):this.element.prop("disabled",!1);return}this._resetButton()},refresh:function(){var t=this.element.is("input, button")?this.element.is(":disabled"):this.element.hasClass("ui-button-disabled");t!==this.options.disabled&&this._setOption("disabled",t),this.type==="radio"?l(this.element[0]).each(function(){e(this).is(":checked")?e(this).button("widget").addClass("ui-state-active").attr("aria-pressed","true"):e(this).button("widget").removeClass("ui-state-active").attr("aria-pressed","false")}):this.type==="checkbox"&&(this.element.is(":checked")?this.buttonElement.addClass("ui-state-active").attr("aria-pressed","true"):this.buttonElement.removeClass("ui-state-active").attr("aria-pressed","false"))},_resetButton:function(){if(this.type==="input"){this.options.label&&this.element.val(this.options.label);return}var t=this.buttonElement.removeClass(a),n=e("<span></span>",this.document[0]).addClass("ui-button-text").html(this.options.label).appendTo(t.empty()).text(),r=this.options.icons,i=r.primary&&r.secondary,s=[];r.primary||r.secondary?(this.options.text&&s.push("ui-button-text-icon"+(i?"s":r.primary?"-primary":"-secondary")),r.primary&&t.prepend("<span class='ui-button-icon-primary ui-icon "+r.primary+"'></span>"),r.secondary&&t.append("<span class='ui-button-icon-secondary ui-icon "+r.secondary+"'></span>"),this.options.text||(s.push(i?"ui-button-icons-only":"ui-button-icon-only"),this.hasTitle||t.attr("title",e.trim(n)))):s.push("ui-button-text-only"),t.addClass(s.join(" "))}}),e.widget("ui.buttonset",{version:"1.9.2",options:{items:"button, input[type=button], input[type=submit], input[type=reset], input[type=checkbox], input[type=radio], a, :data(button)"},_create:function(){this.element.addClass("ui-buttonset")},_init:function(){this.refresh()},_setOption:function(e,t){e==="disabled"&&this.buttons.button("option",e,t),this._super(e,t)},refresh:function(){var t=this.element.css("direction")==="rtl";this.buttons=this.element.find(this.options.items).filter(":ui-button").button("refresh").end().not(":ui-button").button().end().map(function(){return e(this).button("widget")[0]}).removeClass("ui-corner-all ui-corner-left ui-corner-right").filter(":first").addClass(t?"ui-corner-right":"ui-corner-left").end().filter(":last").addClass(t?"ui-corner-left":"ui-corner-right").end().end()},_destroy:function(){this.element.removeClass("ui-buttonset"),this.buttons.map(function(){return e(this).button("widget")[0]}).removeClass("ui-corner-left ui-corner-right").end().button("destroy")}})}(jQuery),function($,undefined){function Datepicker(){this.debug=!1,this._curInst=null,this._keyEvent=!1,this._disabledInputs=[],this._datepickerShowing=!1,this._inDialog=!1,this._mainDivId="ui-datepicker-div",this._inlineClass="ui-datepicker-inline",this._appendClass="ui-datepicker-append",this._triggerClass="ui-datepicker-trigger",this._dialogClass="ui-datepicker-dialog",this._disableClass="ui-datepicker-disabled",this._unselectableClass="ui-datepicker-unselectable",this._currentClass="ui-datepicker-current-day",this._dayOverClass="ui-datepicker-days-cell-over",this.regional=[],this.regional[""]={closeText:"Done",prevText:"Prev",nextText:"Next",currentText:"Today",monthNames:["January","February","March","April","May","June","July","August","September","October","November","December"],monthNamesShort:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],dayNames:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],dayNamesShort:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],dayNamesMin:["Su","Mo","Tu","We","Th","Fr","Sa"],weekHeader:"Wk",dateFormat:"mm/dd/yy",firstDay:0,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""},this._defaults={showOn:"focus",showAnim:"fadeIn",showOptions:{},defaultDate:null,appendText:"",buttonText:"...",buttonImage:"",buttonImageOnly:!1,hideIfNoPrevNext:!1,navigationAsDateFormat:!1,gotoCurrent:!1,changeMonth:!1,changeYear:!1,yearRange:"c-10:c+10",showOtherMonths:!1,selectOtherMonths:!1,showWeek:!1,calculateWeek:this.iso8601Week,shortYearCutoff:"+10",minDate:null,maxDate:null,duration:"fast",beforeShowDay:null,beforeShow:null,onSelect:null,onChangeMonthYear:null,onClose:null,numberOfMonths:1,showCurrentAtPos:0,stepMonths:1,stepBigMonths:12,altField:"",altFormat:"",constrainInput:!0,showButtonPanel:!1,autoSize:!1,disabled:!1},$.extend(this._defaults,this.regional[""]),this.dpDiv=bindHover($('<div id="'+this._mainDivId+'" class="ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all"></div>'))}function bindHover(e){var t="button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a";return e.delegate(t,"mouseout",function(){$(this).removeClass("ui-state-hover"),this.className.indexOf("ui-datepicker-prev")!=-1&&$(this).removeClass("ui-datepicker-prev-hover"),this.className.indexOf("ui-datepicker-next")!=-1&&$(this).removeClass("ui-datepicker-next-hover")}).delegate(t,"mouseover",function(){$.datepicker._isDisabledDatepicker(instActive.inline?e.parent()[0]:instActive.input[0])||($(this).parents(".ui-datepicker-calendar").find("a").removeClass("ui-state-hover"),$(this).addClass("ui-state-hover"),this.className.indexOf("ui-datepicker-prev")!=-1&&$(this).addClass("ui-datepicker-prev-hover"),this.className.indexOf("ui-datepicker-next")!=-1&&$(this).addClass("ui-datepicker-next-hover"))})}function extendRemove(e,t){$.extend(e,t);for(var n in t)if(t[n]==null||t[n]==undefined)e[n]=t[n];return e}$.extend($.ui,{datepicker:{version:"1.9.2"}});var PROP_NAME="datepicker",dpuuid=(new Date).getTime(),instActive;$.extend(Datepicker.prototype,{markerClassName:"hasDatepicker",maxRows:4,log:function(){this.debug&&console.log.apply("",arguments)},_widgetDatepicker:function(){return this.dpDiv},setDefaults:function(e){return extendRemove(this._defaults,e||{}),this},_attachDatepicker:function(target,settings){var inlineSettings=null;for(var attrName in this._defaults){var attrValue=target.getAttribute("date:"+attrName);if(attrValue){inlineSettings=inlineSettings||{};try{inlineSettings[attrName]=eval(attrValue)}catch(err){inlineSettings[attrName]=attrValue}}}var nodeName=target.nodeName.toLowerCase(),inline=nodeName=="div"||nodeName=="span";target.id||(this.uuid+=1,target.id="dp"+this.uuid);var inst=this._newInst($(target),inline);inst.settings=$.extend({},settings||{},inlineSettings||{}),nodeName=="input"?this._connectDatepicker(target,inst):inline&&this._inlineDatepicker(target,inst)},_newInst:function(e,t){var n=e[0].id.replace(/([^A-Za-z0-9_-])/g,"\\\\$1");return{id:n,input:e,selectedDay:0,selectedMonth:0,selectedYear:0,drawMonth:0,drawYear:0,inline:t,dpDiv:t?bindHover($('<div class="'+this._inlineClass+' ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all"></div>')):this.dpDiv}},_connectDatepicker:function(e,t){var n=$(e);t.append=$([]),t.trigger=$([]);if(n.hasClass(this.markerClassName))return;this._attachments(n,t),n.addClass(this.markerClassName).keydown(this._doKeyDown).keypress(this._doKeyPress).keyup(this._doKeyUp).bind("setData.datepicker",function(e,n,r){t.settings[n]=r}).bind("getData.datepicker",function(e,n){return this._get(t,n)}),this._autoSize(t),$.data(e,PROP_NAME,t),t.settings.disabled&&this._disableDatepicker(e)},_attachments:function(e,t){var n=this._get(t,"appendText"),r=this._get(t,"isRTL");t.append&&t.append.remove(),n&&(t.append=$('<span class="'+this._appendClass+'">'+n+"</span>"),e[r?"before":"after"](t.append)),e.unbind("focus",this._showDatepicker),t.trigger&&t.trigger.remove();var i=this._get(t,"showOn");(i=="focus"||i=="both")&&e.focus(this._showDatepicker);if(i=="button"||i=="both"){var s=this._get(t,"buttonText"),o=this._get(t,"buttonImage");t.trigger=$(this._get(t,"buttonImageOnly")?$("<img/>").addClass(this._triggerClass).attr({src:o,alt:s,title:s}):$('<button type="button"></button>').addClass(this._triggerClass).html(o==""?s:$("<img/>").attr({src:o,alt:s,title:s}))),e[r?"before":"after"](t.trigger),t.trigger.click(function(){return $.datepicker._datepickerShowing&&$.datepicker._lastInput==e[0]?$.datepicker._hideDatepicker():$.datepicker._datepickerShowing&&$.datepicker._lastInput!=e[0]?($.datepicker._hideDatepicker(),$.datepicker._showDatepicker(e[0])):$.datepicker._showDatepicker(e[0]),!1})}},_autoSize:function(e){if(this._get(e,"autoSize")&&!e.inline){var t=new Date(2009,11,20),n=this._get(e,"dateFormat");if(n.match(/[DM]/)){var r=function(e){var t=0,n=0;for(var r=0;r<e.length;r++)e[r].length>t&&(t=e[r].length,n=r);return n};t.setMonth(r(this._get(e,n.match(/MM/)?"monthNames":"monthNamesShort"))),t.setDate(r(this._get(e,n.match(/DD/)?"dayNames":"dayNamesShort"))+20-t.getDay())}e.input.attr("size",this._formatDate(e,t).length)}},_inlineDatepicker:function(e,t){var n=$(e);if(n.hasClass(this.markerClassName))return;n.addClass(this.markerClassName).append(t.dpDiv).bind("setData.datepicker",function(e,n,r){t.settings[n]=r}).bind("getData.datepicker",function(e,n){return this._get(t,n)}),$.data(e,PROP_NAME,t),this._setDate(t,this._getDefaultDate(t),!0),this._updateDatepicker(t),this._updateAlternate(t),t.settings.disabled&&this._disableDatepicker(e),t.dpDiv.css("display","block")},_dialogDatepicker:function(e,t,n,r,i){var s=this._dialogInst;if(!s){this.uuid+=1;var o="dp"+this.uuid;this._dialogInput=$('<input type="text" id="'+o+'" style="position: absolute; top: -100px; width: 0px;"/>'),this._dialogInput.keydown(this._doKeyDown),$("body").append(this._dialogInput),s=this._dialogInst=this._newInst(this._dialogInput,!1),s.settings={},$.data(this._dialogInput[0],PROP_NAME,s)}extendRemove(s.settings,r||{}),t=t&&t.constructor==Date?this._formatDate(s,t):t,this._dialogInput.val(t),this._pos=i?i.length?i:[i.pageX,i.pageY]:null;if(!this._pos){var u=document.documentElement.clientWidth,a=document.documentElement.clientHeight,f=document.documentElement.scrollLeft||document.body.scrollLeft,l=document.documentElement.scrollTop||document.body.scrollTop;this._pos=[u/2-100+f,a/2-150+l]}return this._dialogInput.css("left",this._pos[0]+20+"px").css("top",this._pos[1]+"px"),s.settings.onSelect=n,this._inDialog=!0,this.dpDiv.addClass(this._dialogClass),this._showDatepicker(this._dialogInput[0]),$.blockUI&&$.blockUI(this.dpDiv),$.data(this._dialogInput[0],PROP_NAME,s),this},_destroyDatepicker:function(e){var t=$(e),n=$.data(e,PROP_NAME);if(!t.hasClass(this.markerClassName))return;var r=e.nodeName.toLowerCase();$.removeData(e,PROP_NAME),r=="input"?(n.append.remove(),n.trigger.remove(),t.removeClass(this.markerClassName).unbind("focus",this._showDatepicker).unbind("keydown",this._doKeyDown).unbind("keypress",this._doKeyPress).unbind("keyup",this._doKeyUp)):(r=="div"||r=="span")&&t.removeClass(this.markerClassName).empty()},_enableDatepicker:function(e){var t=$(e),n=$.data(e,PROP_NAME);if(!t.hasClass(this.markerClassName))return;var r=e.nodeName.toLowerCase();if(r=="input")e.disabled=!1,n.trigger.filter("button").each(function(){this.disabled=!1}).end().filter("img").css({opacity:"1.0",cursor:""});else if(r=="div"||r=="span"){var i=t.children("."+this._inlineClass);i.children().removeClass("ui-state-disabled"),i.find("select.ui-datepicker-month, select.ui-datepicker-year").prop("disabled",!1)}this._disabledInputs=$.map(this._disabledInputs,function(t){return t==e?null:t})},_disableDatepicker:function(e){var t=$(e),n=$.data(e,PROP_NAME);if(!t.hasClass(this.markerClassName))return;var r=e.nodeName.toLowerCase();if(r=="input")e.disabled=!0,n.trigger.filter("button").each(function(){this.disabled=!0}).end().filter("img").css({opacity:"0.5",cursor:"default"});else if(r=="div"||r=="span"){var i=t.children("."+this._inlineClass);i.children().addClass("ui-state-disabled"),i.find("select.ui-datepicker-month, select.ui-datepicker-year").prop("disabled",!0)}this._disabledInputs=$.map(this._disabledInputs,function(t){return t==e?null:t}),this._disabledInputs[this._disabledInputs.length]=e},_isDisabledDatepicker:function(e){if(!e)return!1;for(var t=0;t<this._disabledInputs.length;t++)if(this._disabledInputs[t]==e)return!0;return!1},_getInst:function(e){try{return $.data(e,PROP_NAME)}catch(t){throw"Missing instance data for this datepicker"}},_optionDatepicker:function(e,t,n){var r=this._getInst(e);if(arguments.length==2&&typeof t=="string")return t=="defaults"?$.extend({},$.datepicker._defaults):r?t=="all"?$.extend({},r.settings):this._get(r,t):null;var i=t||{};typeof t=="string"&&(i={},i[t]=n);if(r){this._curInst==r&&this._hideDatepicker();var s=this._getDateDatepicker(e,!0),o=this._getMinMaxDate(r,"min"),u=this._getMinMaxDate(r,"max");extendRemove(r.settings,i),o!==null&&i.dateFormat!==undefined&&i.minDate===undefined&&(r.settings.minDate=this._formatDate(r,o)),u!==null&&i.dateFormat!==undefined&&i.maxDate===undefined&&(r.settings.maxDate=this._formatDate(r,u)),this._attachments($(e),r),this._autoSize(r),this._setDate(r,s),this._updateAlternate(r),this._updateDatepicker(r)}},_changeDatepicker:function(e,t,n){this._optionDatepicker(e,t,n)},_refreshDatepicker:function(e){var t=this._getInst(e);t&&this._updateDatepicker(t)},_setDateDatepicker:function(e,t){var n=this._getInst(e);n&&(this._setDate(n,t),this._updateDatepicker(n),this._updateAlternate(n))},_getDateDatepicker:function(e,t){var n=this._getInst(e);return n&&!n.inline&&this._setDateFromField(n,t),n?this._getDate(n):null},_doKeyDown:function(e){var t=$.datepicker._getInst(e.target),n=!0,r=t.dpDiv.is(".ui-datepicker-rtl");t._keyEvent=!0;if($.datepicker._datepickerShowing)switch(e.keyCode){case 9:$.datepicker._hideDatepicker(),n=!1;break;case 13:var i=$("td."+$.datepicker._dayOverClass+":not(."+$.datepicker._currentClass+")",t.dpDiv);i[0]&&$.datepicker._selectDay(e.target,t.selectedMonth,t.selectedYear,i[0]);var s=$.datepicker._get(t,"onSelect");if(s){var o=$.datepicker._formatDate(t);s.apply(t.input?t.input[0]:null,[o,t])}else $.datepicker._hideDatepicker();return!1;case 27:$.datepicker._hideDatepicker();break;case 33:$.datepicker._adjustDate(e.target,e.ctrlKey?-$.datepicker._get(t,"stepBigMonths"):-$.datepicker._get(t,"stepMonths"),"M");break;case 34:$.datepicker._adjustDate(e.target,e.ctrlKey?+$.datepicker._get(t,"stepBigMonths"):+$.datepicker._get(t,"stepMonths"),"M");break;case 35:(e.ctrlKey||e.metaKey)&&$.datepicker._clearDate(e.target),n=e.ctrlKey||e.metaKey;break;case 36:(e.ctrlKey||e.metaKey)&&$.datepicker._gotoToday(e.target),n=e.ctrlKey||e.metaKey;break;case 37:(e.ctrlKey||e.metaKey)&&$.datepicker._adjustDate(e.target,r?1:-1,"D"),n=e.ctrlKey||e.metaKey,e.originalEvent.altKey&&$.datepicker._adjustDate(e.target,e.ctrlKey?-$.datepicker._get(t,"stepBigMonths"):-$.datepicker._get(t,"stepMonths"),"M");break;case 38:(e.ctrlKey||e.metaKey)&&$.datepicker._adjustDate(e.target,-7,"D"),n=e.ctrlKey||e.metaKey;break;case 39:(e.ctrlKey||e.metaKey)&&$.datepicker._adjustDate(e.target,r?-1:1,"D"),n=e.ctrlKey||e.metaKey,e.originalEvent.altKey&&$.datepicker._adjustDate(e.target,e.ctrlKey?+$.datepicker._get(t,"stepBigMonths"):+$.datepicker._get(t,"stepMonths"),"M");break;case 40:(e.ctrlKey||e.metaKey)&&$.datepicker._adjustDate(e.target,7,"D"),n=e.ctrlKey||e.metaKey;break;default:n=!1}else e.keyCode==36&&e.ctrlKey?$.datepicker._showDatepicker(this):n=!1;n&&(e.preventDefault(),e.stopPropagation())},_doKeyPress:function(e){var t=$.datepicker._getInst(e.target);if($.datepicker._get(t,"constrainInput")){var n=$.datepicker._possibleChars($.datepicker._get(t,"dateFormat")),r=String.fromCharCode(e.charCode==undefined?e.keyCode:e.charCode);return e.ctrlKey||e.metaKey||r<" "||!n||n.indexOf(r)>-1}},_doKeyUp:function(e){var t=$.datepicker._getInst(e.target);if(t.input.val()!=t.lastVal)try{var n=$.datepicker.parseDate($.datepicker._get(t,"dateFormat"),t.input?t.input.val():null,$.datepicker._getFormatConfig(t));n&&($.datepicker._setDateFromField(t),$.datepicker._updateAlternate(t),$.datepicker._updateDatepicker(t))}catch(r){$.datepicker.log(r)}return!0},_showDatepicker:function(e){e=e.target||e,e.nodeName.toLowerCase()!="input"&&(e=$("input",e.parentNode)[0]);if($.datepicker._isDisabledDatepicker(e)||$.datepicker._lastInput==e)return;var t=$.datepicker._getInst(e);$.datepicker._curInst&&$.datepicker._curInst!=t&&($.datepicker._curInst.dpDiv.stop(!0,!0),t&&$.datepicker._datepickerShowing&&$.datepicker._hideDatepicker($.datepicker._curInst.input[0]));var n=$.datepicker._get(t,"beforeShow"),r=n?n.apply(e,[e,t]):{};if(r===!1)return;extendRemove(t.settings,r),t.lastVal=null,$.datepicker._lastInput=e,$.datepicker._setDateFromField(t),$.datepicker._inDialog&&(e.value=""),$.datepicker._pos||($.datepicker._pos=$.datepicker._findPos(e),$.datepicker._pos[1]+=e.offsetHeight);var i=!1;$(e).parents().each(function(){return i|=$(this).css("position")=="fixed",!i});var s={left:$.datepicker._pos[0],top:$.datepicker._pos[1]};$.datepicker._pos=null,t.dpDiv.empty(),t.dpDiv.css({position:"absolute",display:"block",top:"-1000px"}),$.datepicker._updateDatepicker(t),s=$.datepicker._checkOffset(t,s,i),t.dpDiv.css({position:$.datepicker._inDialog&&$.blockUI?"static":i?"fixed":"absolute",display:"none",left:s.left+"px",top:s.top+"px"});if(!t.inline){var o=$.datepicker._get(t,"showAnim"),u=$.datepicker._get(t,"duration"),a=function(){var e=t.dpDiv.find("iframe.ui-datepicker-cover");if(!!e.length){var n=$.datepicker._getBorders(t.dpDiv);e.css({left:-n[0],top:-n[1],width:t.dpDiv.outerWidth(),height:t.dpDiv.outerHeight()})}};t.dpDiv.zIndex($(e).zIndex()+1),$.datepicker._datepickerShowing=!0,$.effects&&($.effects.effect[o]||$.effects[o])?t.dpDiv.show(o,$.datepicker._get(t,"showOptions"),u,a):t.dpDiv[o||"show"](o?u:null,a),(!o||!u)&&a(),t.input.is(":visible")&&!t.input.is(":disabled")&&t.input.focus(),$.datepicker._curInst=t}},_updateDatepicker:function(e){this.maxRows=4;var t=$.datepicker._getBorders(e.dpDiv);instActive=e,e.dpDiv.empty().append(this._generateHTML(e)),this._attachHandlers(e);var n=e.dpDiv.find("iframe.ui-datepicker-cover");!n.length||n.css({left:-t[0],top:-t[1],width:e.dpDiv.outerWidth(),height:e.dpDiv.outerHeight()}),e.dpDiv.find("."+this._dayOverClass+" a").mouseover();var r=this._getNumberOfMonths(e),i=r[1],s=17;e.dpDiv.removeClass("ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4").width(""),i>1&&e.dpDiv.addClass("ui-datepicker-multi-"+i).css("width",s*i+"em"),e.dpDiv[(r[0]!=1||r[1]!=1?"add":"remove")+"Class"]("ui-datepicker-multi"),e.dpDiv[(this._get(e,"isRTL")?"add":"remove")+"Class"]("ui-datepicker-rtl"),e==$.datepicker._curInst&&$.datepicker._datepickerShowing&&e.input&&e.input.is(":visible")&&!e.input.is(":disabled")&&e.input[0]!=document.activeElement&&e.input.focus();if(e.yearshtml){var o=e.yearshtml;setTimeout(function(){o===e.yearshtml&&e.yearshtml&&e.dpDiv.find("select.ui-datepicker-year:first").replaceWith(e.yearshtml),o=e.yearshtml=null},0)}},_getBorders:function(e){var t=function(e){return{thin:1,medium:2,thick:3}[e]||e};return[parseFloat(t(e.css("border-left-width"))),parseFloat(t(e.css("border-top-width")))]},_checkOffset:function(e,t,n){var r=e.dpDiv.outerWidth(),i=e.dpDiv.outerHeight(),s=e.input?e.input.outerWidth():0,o=e.input?e.input.outerHeight():0,u=document.documentElement.clientWidth+(n?0:$(document).scrollLeft()),a=document.documentElement.clientHeight+(n?0:$(document).scrollTop());return t.left-=this._get(e,"isRTL")?r-s:0,t.left-=n&&t.left==e.input.offset().left?$(document).scrollLeft():0,t.top-=n&&t.top==e.input.offset().top+o?$(document).scrollTop():0,t.left-=Math.min(t.left,t.left+r>u&&u>r?Math.abs(t.left+r-u):0),t.top-=Math.min(t.top,t.top+i>a&&a>i?Math.abs(i+o):0),t},_findPos:function(e){var t=this._getInst(e),n=this._get(t,"isRTL");while(e&&(e.type=="hidden"||e.nodeType!=1||$.expr.filters.hidden(e)))e=e[n?"previousSibling":"nextSibling"];var r=$(e).offset();return[r.left,r.top]},_hideDatepicker:function(e){var t=this._curInst;if(!t||e&&t!=$.data(e,PROP_NAME))return;if(this._datepickerShowing){var n=this._get(t,"showAnim"),r=this._get(t,"duration"),i=function(){$.datepicker._tidyDialog(t)};$.effects&&($.effects.effect[n]||$.effects[n])?t.dpDiv.hide(n,$.datepicker._get(t,"showOptions"),r,i):t.dpDiv[n=="slideDown"?"slideUp":n=="fadeIn"?"fadeOut":"hide"](n?r:null,i),n||i(),this._datepickerShowing=!1;var s=this._get(t,"onClose");s&&s.apply(t.input?t.input[0]:null,[t.input?t.input.val():"",t]),this._lastInput=null,this._inDialog&&(this._dialogInput.css({position:"absolute",left:"0",top:"-100px"}),$.blockUI&&($.unblockUI(),$("body").append(this.dpDiv))),this._inDialog=!1}},_tidyDialog:function(e){e.dpDiv.removeClass(this._dialogClass).unbind(".ui-datepicker-calendar")},_checkExternalClick:function(e){if(!$.datepicker._curInst)return;var t=$(e.target),n=$.datepicker._getInst(t[0]);(t[0].id!=$.datepicker._mainDivId&&t.parents("#"+$.datepicker._mainDivId).length==0&&!t.hasClass($.datepicker.markerClassName)&&!t.closest("."+$.datepicker._triggerClass).length&&$.datepicker._datepickerShowing&&(!$.datepicker._inDialog||!$.blockUI)||t.hasClass($.datepicker.markerClassName)&&$.datepicker._curInst!=n)&&$.datepicker._hideDatepicker()},_adjustDate:function(e,t,n){var r=$(e),i=this._getInst(r[0]);if(this._isDisabledDatepicker(r[0]))return;this._adjustInstDate(i,t+(n=="M"?this._get(i,"showCurrentAtPos"):0),n),this._updateDatepicker(i)},_gotoToday:function(e){var t=$(e),n=this._getInst(t[0]);if(this._get(n,"gotoCurrent")&&n.currentDay)n.selectedDay=n.currentDay,n.drawMonth=n.selectedMonth=n.currentMonth,n.drawYear=n.selectedYear=n.currentYear;else{var r=new Date;n.selectedDay=r.getDate(),n.drawMonth=n.selectedMonth=r.getMonth(),n.drawYear=n.selectedYear=r.getFullYear()}this._notifyChange(n),this._adjustDate(t)},_selectMonthYear:function(e,t,n){var r=$(e),i=this._getInst(r[0]);i["selected"+(n=="M"?"Month":"Year")]=i["draw"+(n=="M"?"Month":"Year")]=parseInt(t.options[t.selectedIndex].value,10),this._notifyChange(i),this._adjustDate(r)},_selectDay:function(e,t,n,r){var i=$(e);if($(r).hasClass(this._unselectableClass)||this._isDisabledDatepicker(i[0]))return;var s=this._getInst(i[0]);s.selectedDay=s.currentDay=$("a",r).html(),s.selectedMonth=s.currentMonth=t,s.selectedYear=s.currentYear=n,this._selectDate(e,this._formatDate(s,s.currentDay,s.currentMonth,s.currentYear))},_clearDate:function(e){var t=$(e),n=this._getInst(t[0]);this._selectDate(t,"")},_selectDate:function(e,t){var n=$(e),r=this._getInst(n[0]);t=t!=null?t:this._formatDate(r),r.input&&r.input.val(t),this._updateAlternate(r);var i=this._get(r,"onSelect");i?i.apply(r.input?r.input[0]:null,[t,r]):r.input&&r.input.trigger("change"),r.inline?this._updateDatepicker(r):(this._hideDatepicker(),this._lastInput=r.input[0],typeof r.input[0]!="object"&&r.input.focus(),this._lastInput=null)},_updateAlternate:function(e){var t=this._get(e,"altField");if(t){var n=this._get(e,"altFormat")||this._get(e,"dateFormat"),r=this._getDate(e),i=this.formatDate(n,r,this._getFormatConfig(e));$(t).each(function(){$(this).val(i)})}},noWeekends:function(e){var t=e.getDay();return[t>0&&t<6,""]},iso8601Week:function(e){var t=new Date(e.getTime());t.setDate(t.getDate()+4-(t.getDay()||7));var n=t.getTime();return t.setMonth(0),t.setDate(1),Math.floor(Math.round((n-t)/864e5)/7)+1},parseDate:function(e,t,n){if(e==null||t==null)throw"Invalid arguments";t=typeof t=="object"?t.toString():t+"";if(t=="")return null;var r=(n?n.shortYearCutoff:null)||this._defaults.shortYearCutoff;r=typeof r!="string"?r:(new Date).getFullYear()%100+parseInt(r,10);var i=(n?n.dayNamesShort:null)||this._defaults.dayNamesShort,s=(n?n.dayNames:null)||this._defaults.dayNames,o=(n?n.monthNamesShort:null)||this._defaults.monthNamesShort,u=(n?n.monthNames:null)||this._defaults.monthNames,a=-1,f=-1,l=-1,c=-1,h=!1,p=function(t){var n=y+1<e.length&&e.charAt(y+1)==t;return n&&y++,n},d=function(e){var n=p(e),r=e=="@"?14:e=="!"?20:e=="y"&&n?4:e=="o"?3:2,i=new RegExp("^\\d{1,"+r+"}"),s=t.substring(g).match(i);if(!s)throw"Missing number at position "+g;return g+=s[0].length,parseInt(s[0],10)},v=function(e,n,r){var i=$.map(p(e)?r:n,function(e,t){return[[t,e]]}).sort(function(e,t){return-(e[1].length-t[1].length)}),s=-1;$.each(i,function(e,n){var r=n[1];if(t.substr(g,r.length).toLowerCase()==r.toLowerCase())return s=n[0],g+=r.length,!1});if(s!=-1)return s+1;throw"Unknown name at position "+g},m=function(){if(t.charAt(g)!=e.charAt(y))throw"Unexpected literal at position "+g;g++},g=0;for(var y=0;y<e.length;y++)if(h)e.charAt(y)=="'"&&!p("'")?h=!1:m();else switch(e.charAt(y)){case"d":l=d("d");break;case"D":v("D",i,s);break;case"o":c=d("o");break;case"m":f=d("m");break;case"M":f=v("M",o,u);break;case"y":a=d("y");break;case"@":var b=new Date(d("@"));a=b.getFullYear(),f=b.getMonth()+1,l=b.getDate();break;case"!":var b=new Date((d("!")-this._ticksTo1970)/1e4);a=b.getFullYear(),f=b.getMonth()+1,l=b.getDate();break;case"'":p("'")?m():h=!0;break;default:m()}if(g<t.length){var w=t.substr(g);if(!/^\s+/.test(w))throw"Extra/unparsed characters found in date: "+w}a==-1?a=(new Date).getFullYear():a<100&&(a+=(new Date).getFullYear()-(new Date).getFullYear()%100+(a<=r?0:-100));if(c>-1){f=1,l=c;do{var E=this._getDaysInMonth(a,f-1);if(l<=E)break;f++,l-=E}while(!0)}var b=this._daylightSavingAdjust(new Date(a,f-1,l));if(b.getFullYear()!=a||b.getMonth()+1!=f||b.getDate()!=l)throw"Invalid date";return b},ATOM:"yy-mm-dd",COOKIE:"D, dd M yy",ISO_8601:"yy-mm-dd",RFC_822:"D, d M y",RFC_850:"DD, dd-M-y",RFC_1036:"D, d M y",RFC_1123:"D, d M yy",RFC_2822:"D, d M yy",RSS:"D, d M y",TICKS:"!",TIMESTAMP:"@",W3C:"yy-mm-dd",_ticksTo1970:(718685+Math.floor(492.5)-Math.floor(19.7)+Math.floor(4.925))*24*60*60*1e7,formatDate:function(e,t,n){if(!t)return"";var r=(n?n.dayNamesShort:null)||this._defaults.dayNamesShort,i=(n?n.dayNames:null)||this._defaults.dayNames,s=(n?n.monthNamesShort:null)||this._defaults.monthNamesShort,o=(n?n.monthNames:null)||this._defaults.monthNames,u=function(t){var n=h+1<e.length&&e.charAt(h+1)==t;return n&&h++,n},a=function(e,t,n){var r=""+t;if(u(e))while(r.length<n)r="0"+r;return r},f=function(e,t,n,r){return u(e)?r[t]:n[t]},l="",c=!1;if(t)for(var h=0;h<e.length;h++)if(c)e.charAt(h)=="'"&&!u("'")?c=!1:l+=e.charAt(h);else switch(e.charAt(h)){case"d":l+=a("d",t.getDate(),2);break;case"D":l+=f("D",t.getDay(),r,i);break;case"o":l+=a("o",Math.round(((new Date(t.getFullYear(),t.getMonth(),t.getDate())).getTime()-(new Date(t.getFullYear(),0,0)).getTime())/864e5),3);break;case"m":l+=a("m",t.getMonth()+1,2);break;case"M":l+=f("M",t.getMonth(),s,o);break;case"y":l+=u("y")?t.getFullYear():(t.getYear()%100<10?"0":"")+t.getYear()%100;break;case"@":l+=t.getTime();break;case"!":l+=t.getTime()*1e4+this._ticksTo1970;break;case"'":u("'")?l+="'":c=!0;break;default:l+=e.charAt(h)}return l},_possibleChars:function(e){var t="",n=!1,r=function(t){var n=i+1<e.length&&e.charAt(i+1)==t;return n&&i++,n};for(var i=0;i<e.length;i++)if(n)e.charAt(i)=="'"&&!r("'")?n=!1:t+=e.charAt(i);else switch(e.charAt(i)){case"d":case"m":case"y":case"@":t+="0123456789";break;case"D":case"M":return null;case"'":r("'")?t+="'":n=!0;break;default:t+=e.charAt(i)}return t},_get:function(e,t){return e.settings[t]!==undefined?e.settings[t]:this._defaults[t]},_setDateFromField:function(e,t){if(e.input.val()==e.lastVal)return;var n=this._get(e,"dateFormat"),r=e.lastVal=e.input?e.input.val():null,i,s;i=s=this._getDefaultDate(e);var o=this._getFormatConfig(e);try{i=this.parseDate(n,r,o)||s}catch(u){this.log(u),r=t?"":r}e.selectedDay=i.getDate(),e.drawMonth=e.selectedMonth=i.getMonth(),e.drawYear=e.selectedYear=i.getFullYear(),e.currentDay=r?i.getDate():0,e.currentMonth=r?i.getMonth():0,e.currentYear=r?i.getFullYear():0,this._adjustInstDate(e)},_getDefaultDate:function(e){return this._restrictMinMax(e,this._determineDate(e,this._get(e,"defaultDate"),new Date))},_determineDate:function(e,t,n){var r=function(e){var t=new Date;return t.setDate(t.getDate()+e),t},i=function(t){try{return $.datepicker.parseDate($.datepicker._get(e,"dateFormat"),t,$.datepicker._getFormatConfig(e))}catch(n){}var r=(t.toLowerCase().match(/^c/)?$.datepicker._getDate(e):null)||new Date,i=r.getFullYear(),s=r.getMonth(),o=r.getDate(),u=/([+-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g,a=u.exec(t);while(a){switch(a[2]||"d"){case"d":case"D":o+=parseInt(a[1],10);break;case"w":case"W":o+=parseInt(a[1],10)*7;break;case"m":case"M":s+=parseInt(a[1],10),o=Math.min(o,$.datepicker._getDaysInMonth(i,s));break;case"y":case"Y":i+=parseInt(a[1],10),o=Math.min(o,$.datepicker._getDaysInMonth(i,s))}a=u.exec(t)}return new Date(i,s,o)},s=t==null||t===""?n:typeof t=="string"?i(t):typeof t=="number"?isNaN(t)?n:r(t):new Date(t.getTime());return s=s&&s.toString()=="Invalid Date"?n:s,s&&(s.setHours(0),s.setMinutes(0),s.setSeconds(0),s.setMilliseconds(0)),this._daylightSavingAdjust(s)},_daylightSavingAdjust:function(e){return e?(e.setHours(e.getHours()>12?e.getHours()+2:0),e):null},_setDate:function(e,t,n){var r=!t,i=e.selectedMonth,s=e.selectedYear,o=this._restrictMinMax(e,this._determineDate(e,t,new Date));e.selectedDay=e.currentDay=o.getDate(),e.drawMonth=e.selectedMonth=e.currentMonth=o.getMonth(),e.drawYear=e.selectedYear=e.currentYear=o.getFullYear(),(i!=e.selectedMonth||s!=e.selectedYear)&&!n&&this._notifyChange(e),this._adjustInstDate(e),e.input&&e.input.val(r?"":this._formatDate(e))},_getDate:function(e){var t=!e.currentYear||e.input&&e.input.val()==""?null:this._daylightSavingAdjust(new Date(e.currentYear,e.currentMonth,e.currentDay));return t},_attachHandlers:function(e){var t=this._get(e,"stepMonths"),n="#"+e.id.replace(/\\\\/g,"\\");e.dpDiv.find("[data-handler]").map(function(){var e={prev:function(){window["DP_jQuery_"+dpuuid].datepicker._adjustDate(n,-t,"M")},next:function(){window["DP_jQuery_"+dpuuid].datepicker._adjustDate(n,+t,"M")},hide:function(){window["DP_jQuery_"+dpuuid].datepicker._hideDatepicker()},today:function(){window["DP_jQuery_"+dpuuid].datepicker._gotoToday(n)},selectDay:function(){return window["DP_jQuery_"+dpuuid].datepicker._selectDay(n,+this.getAttribute("data-month"),+this.getAttribute("data-year"),this),!1},selectMonth:function(){return window["DP_jQuery_"+dpuuid].datepicker._selectMonthYear(n,this,"M"),!1},selectYear:function(){return window["DP_jQuery_"+dpuuid].datepicker._selectMonthYear(n,this,"Y"),!1}};$(this).bind(this.getAttribute("data-event"),e[this.getAttribute("data-handler")])})},_generateHTML:function(e){var t=new Date;t=this._daylightSavingAdjust(new Date(t.getFullYear(),t.getMonth(),t.getDate()));var n=this._get(e,"isRTL"),r=this._get(e,"showButtonPanel"),i=this._get(e,"hideIfNoPrevNext"),s=this._get(e,"navigationAsDateFormat"),o=this._getNumberOfMonths(e),u=this._get(e,"showCurrentAtPos"),a=this._get(e,"stepMonths"),f=o[0]!=1||o[1]!=1,l=this._daylightSavingAdjust(e.currentDay?new Date(e.currentYear,e.currentMonth,e.currentDay):new Date(9999,9,9)),c=this._getMinMaxDate(e,"min"),h=this._getMinMaxDate(e,"max"),p=e.drawMonth-u,d=e.drawYear;p<0&&(p+=12,d--);if(h){var v=this._daylightSavingAdjust(new Date(h.getFullYear(),h.getMonth()-o[0]*o[1]+1,h.getDate()));v=c&&v<c?c:v;while(this._daylightSavingAdjust(new Date(d,p,1))>v)p--,p<0&&(p=11,d--)}e.drawMonth=p,e.drawYear=d;var m=this._get(e,"prevText");m=s?this.formatDate(m,this._daylightSavingAdjust(new Date(d,p-a,1)),this._getFormatConfig(e)):m;var g=this._canAdjustMonth(e,-1,d,p)?'<a class="ui-datepicker-prev ui-corner-all" data-handler="prev" data-event="click" title="'+m+'"><span class="ui-icon ui-icon-circle-triangle-'+(n?"e":"w")+'">'+m+"</span></a>":i?"":'<a class="ui-datepicker-prev ui-corner-all ui-state-disabled" title="'+m+'"><span class="ui-icon ui-icon-circle-triangle-'+(n?"e":"w")+'">'+m+"</span></a>",y=this._get(e,"nextText");y=s?this.formatDate(y,this._daylightSavingAdjust(new Date(d,p+a,1)),this._getFormatConfig(e)):y;var b=this._canAdjustMonth(e,1,d,p)?'<a class="ui-datepicker-next ui-corner-all" data-handler="next" data-event="click" title="'+y+'"><span class="ui-icon ui-icon-circle-triangle-'+(n?"w":"e")+'">'+y+"</span></a>":i?"":'<a class="ui-datepicker-next ui-corner-all ui-state-disabled" title="'+y+'"><span class="ui-icon ui-icon-circle-triangle-'+(n?"w":"e")+'">'+y+"</span></a>",w=this._get(e,"currentText"),E=this._get(e,"gotoCurrent")&&e.currentDay?l:t;w=s?this.formatDate(w,E,this._getFormatConfig(e)):w;var S=e.inline?"":'<button type="button" class="ui-datepicker-close ui-state-default ui-priority-primary ui-corner-all" data-handler="hide" data-event="click">'+this._get(e,"closeText")+"</button>",x=r?'<div class="ui-datepicker-buttonpane ui-widget-content">'+(n?S:"")+(this._isInRange(e,E)?'<button type="button" class="ui-datepicker-current ui-state-default ui-priority-secondary ui-corner-all" data-handler="today" data-event="click">'+w+"</button>":"")+(n?"":S)+"</div>":"",T=parseInt(this._get(e,"firstDay"),10);T=isNaN(T)?0:T;var N=this._get(e,"showWeek"),C=this._get(e,"dayNames"),k=this._get(e,"dayNamesShort"),L=this._get(e,"dayNamesMin"),A=this._get(e,"monthNames"),O=this._get(e,"monthNamesShort"),M=this._get(e,"beforeShowDay"),_=this._get(e,"showOtherMonths"),D=this._get(e,"selectOtherMonths"),P=this._get(e,"calculateWeek")||this.iso8601Week,H=this._getDefaultDate(e),B="";for(var j=0;j<o[0];j++){var F="";this.maxRows=4;for(var I=0;I<o[1];I++){var q=this._daylightSavingAdjust(new Date(d,p,e.selectedDay)),R=" ui-corner-all",U="";if(f){U+='<div class="ui-datepicker-group';if(o[1]>1)switch(I){case 0:U+=" ui-datepicker-group-first",R=" ui-corner-"+(n?"right":"left");break;case o[1]-1:U+=" ui-datepicker-group-last",R=" ui-corner-"+(n?"left":"right");break;default:U+=" ui-datepicker-group-middle",R=""}U+='">'}U+='<div class="ui-datepicker-header ui-widget-header ui-helper-clearfix'+R+'">'+(/all|left/.test(R)&&j==0?n?b:g:"")+(/all|right/.test(R)&&j==0?n?g:b:"")+this._generateMonthYearHeader(e,p,d,c,h,j>0||I>0,A,O)+'</div><table class="ui-datepicker-calendar"><thead>'+"<tr>";var z=N?'<th class="ui-datepicker-week-col">'+this._get(e,"weekHeader")+"</th>":"";for(var W=0;W<7;W++){var X=(W+T)%7;z+="<th"+((W+T+6)%7>=5?' class="ui-datepicker-week-end"':"")+">"+'<span title="'+C[X]+'">'+L[X]+"</span></th>"}U+=z+"</tr></thead><tbody>";var V=this._getDaysInMonth(d,p);d==e.selectedYear&&p==e.selectedMonth&&(e.selectedDay=Math.min(e.selectedDay,V));var J=(this._getFirstDayOfMonth(d,p)-T+7)%7,K=Math.ceil((J+V)/7),Q=f?this.maxRows>K?this.maxRows:K:K;this.maxRows=Q;var G=this._daylightSavingAdjust(new Date(d,p,1-J));for(var Y=0;Y<Q;Y++){U+="<tr>";var Z=N?'<td class="ui-datepicker-week-col">'+this._get(e,"calculateWeek")(G)+"</td>":"";for(var W=0;W<7;W++){var et=M?M.apply(e.input?e.input[0]:null,[G]):[!0,""],tt=G.getMonth()!=p,nt=tt&&!D||!et[0]||c&&G<c||h&&G>h;Z+='<td class="'+((W+T+6)%7>=5?" ui-datepicker-week-end":"")+(tt?" ui-datepicker-other-month":"")+(G.getTime()==q.getTime()&&p==e.selectedMonth&&e._keyEvent||H.getTime()==G.getTime()&&H.getTime()==q.getTime()?" "+this._dayOverClass:"")+(nt?" "+this._unselectableClass+" ui-state-disabled":"")+(tt&&!_?"":" "+et[1]+(G.getTime()==l.getTime()?" "+this._currentClass:"")+(G.getTime()==t.getTime()?" ui-datepicker-today":""))+'"'+((!tt||_)&&et[2]?' title="'+et[2]+'"':"")+(nt?"":' data-handler="selectDay" data-event="click" data-month="'+G.getMonth()+'" data-year="'+G.getFullYear()+'"')+">"+(tt&&!_?" ":nt?'<span class="ui-state-default">'+G.getDate()+"</span>":'<a class="ui-state-default'+(G.getTime()==t.getTime()?" ui-state-highlight":"")+(G.getTime()==l.getTime()?" ui-state-active":"")+(tt?" ui-priority-secondary":"")+'" href="#">'+G.getDate()+"</a>")+"</td>",G.setDate(G.getDate()+1),G=this._daylightSavingAdjust(G)}U+=Z+"</tr>"}p++,p>11&&(p=0,d++),U+="</tbody></table>"+(f?"</div>"+(o[0]>0&&I==o[1]-1?'<div class="ui-datepicker-row-break"></div>':""):""),F+=U}B+=F}return B+=x+($.ui.ie6&&!e.inline?'<iframe src="javascript:false;" class="ui-datepicker-cover" frameborder="0"></iframe>':""),e._keyEvent=!1,B},_generateMonthYearHeader:function(e,t,n,r,i,s,o,u){var a=this._get(e,"changeMonth"),f=this._get(e,"changeYear"),l=this._get(e,"showMonthAfterYear"),c='<div class="ui-datepicker-title">',h="";if(s||!a)h+='<span class="ui-datepicker-month">'+o[t]+"</span>";else{var p=r&&r.getFullYear()==n,d=i&&i.getFullYear()==n;h+='<select class="ui-datepicker-month" data-handler="selectMonth" data-event="change">';for(var v=0;v<12;v++)(!p||v>=r.getMonth())&&(!d||v<=i.getMonth())&&(h+='<option value="'+v+'"'+(v==t?' selected="selected"':"")+">"+u[v]+"</option>");h+="</select>"}l||(c+=h+(s||!a||!f?" ":""));if(!e.yearshtml){e.yearshtml="";if(s||!f)c+='<span class="ui-datepicker-year">'+n+"</span>";else{var m=this._get(e,"yearRange").split(":"),g=(new Date).getFullYear(),y=function(e){var t=e.match(/c[+-].*/)?n+parseInt(e.substring(1),10):e.match(/[+-].*/)?g+parseInt(e,10):parseInt(e,10);return isNaN(t)?g:t},b=y(m[0]),w=Math.max(b,y(m[1]||""));b=r?Math.max(b,r.getFullYear()):b,w=i?Math.min(w,i.getFullYear()):w,e.yearshtml+='<select class="ui-datepicker-year" data-handler="selectYear" data-event="change">';for(;b<=w;b++)e.yearshtml+='<option value="'+b+'"'+(b==n?' selected="selected"':"")+">"+b+"</option>";e.yearshtml+="</select>",c+=e.yearshtml,e.yearshtml=null}}return c+=this._get(e,"yearSuffix"),l&&(c+=(s||!a||!f?" ":"")+h),c+="</div>",c},_adjustInstDate:function(e,t,n){var r=e.drawYear+(n=="Y"?t:0),i=e.drawMonth+(n=="M"?t:0),s=Math.min(e.selectedDay,this._getDaysInMonth(r,i))+(n=="D"?t:0),o=this._restrictMinMax(e,this._daylightSavingAdjust(new Date(r,i,s)));e.selectedDay=o.getDate(),e.drawMonth=e.selectedMonth=o.getMonth(),e.drawYear=e.selectedYear=o.getFullYear(),(n=="M"||n=="Y")&&this._notifyChange(e)},_restrictMinMax:function(e,t){var n=this._getMinMaxDate(e,"min"),r=this._getMinMaxDate(e,"max"),i=n&&t<n?n:t;return i=r&&i>r?r:i,i},_notifyChange:function(e){var t=this._get(e,"onChangeMonthYear");t&&t.apply(e.input?e.input[0]:null,[e.selectedYear,e.selectedMonth+1,e])},_getNumberOfMonths:function(e){var t=this._get(e,"numberOfMonths");return t==null?[1,1]:typeof t=="number"?[1,t]:t},_getMinMaxDate:function(e,t){return this._determineDate(e,this._get(e,t+"Date"),null)},_getDaysInMonth:function(e,t){return 32-this._daylightSavingAdjust(new Date(e,t,32)).getDate()},_getFirstDayOfMonth:function(e,t){return(new Date(e,t,1)).getDay()},_canAdjustMonth:function(e,t,n,r){var i=this._getNumberOfMonths(e),s=this._daylightSavingAdjust(new Date(n,r+(t<0?t:i[0]*i[1]),1));return t<0&&s.setDate(this._getDaysInMonth(s.getFullYear(),s.getMonth())),this._isInRange(e,s)},_isInRange:function(e,t){var n=this._getMinMaxDate(e,"min"),r=this._getMinMaxDate(e,"max");return(!n||t.getTime()>=n.getTime())&&(!r||t.getTime()<=r.getTime())},_getFormatConfig:function(e){var t=this._get(e,"shortYearCutoff");return t=typeof t!="string"?t:(new Date).getFullYear()%100+parseInt(t,10),{shortYearCutoff:t,dayNamesShort:this._get(e,"dayNamesShort"),dayNames:this._get(e,"dayNames"),monthNamesShort:this._get(e,"monthNamesShort"),monthNames:this._get(e,"monthNames")}},_formatDate:function(e,t,n,r){t||(e.currentDay=e.selectedDay,e.currentMonth=e.selectedMonth,e.currentYear=e.selectedYear);var i=t?typeof t=="object"?t:this._daylightSavingAdjust(new Date(r,n,t)):this._daylightSavingAdjust(new Date(e.currentYear,e.currentMonth,e.currentDay));return this.formatDate(this._get(e,"dateFormat"),i,this._getFormatConfig(e))}}),$.fn.datepicker=function(e){if(!this.length)return this;$.datepicker.initialized||($(document).mousedown($.datepicker._checkExternalClick).find(document.body).append($.datepicker.dpDiv),$.datepicker.initialized=!0);var t=Array.prototype.slice.call(arguments,1);return typeof e!="string"||e!="isDisabled"&&e!="getDate"&&e!="widget"?e=="option"&&arguments.length==2&&typeof arguments[1]=="string"?$.datepicker["_"+e+"Datepicker"].apply($.datepicker,[this[0]].concat(t)):this.each(function(){typeof e=="string"?$.datepicker["_"+e+"Datepicker"].apply($.datepicker,[this].concat(t)):$.datepicker._attachDatepicker(this,e)}):$.datepicker["_"+e+"Datepicker"].apply($.datepicker,[this[0]].concat(t))},$.datepicker=new Datepicker,$.datepicker.initialized=!1,$.datepicker.uuid=(new Date).getTime(),$.datepicker.version="1.9.2",window["DP_jQuery_"+dpuuid]=$}(jQuery),function(e,t){var n="ui-dialog ui-widget ui-widget-content ui-corner-all ",r={buttons:!0,height:!0,maxHeight:!0,maxWidth:!0,minHeight:!0,minWidth:!0,width:!0},i={maxHeight:!0,maxWidth:!0,minHeight:!0,minWidth:!0};e.widget("ui.dialog",{version:"1.9.2",options:{autoOpen:!0,buttons:{},closeOnEscape:!0,closeText:"close",dialogClass:"",draggable:!0,hide:null,height:"auto",maxHeight:!1,maxWidth:!1,minHeight:150,minWidth:150,modal:!1,position:{my:"center",at:"center",of:window,collision:"fit",using:function(t){var n=e(this).css(t).offset().top;n<0&&e(this).css("top",t.top-n)}},resizable:!0,show:null,stack:!0,title:"",width:300,zIndex:1e3},_create:function(){this.originalTitle=this.element.attr("title"),typeof this.originalTitle!="string"&&(this.originalTitle=""),this.oldPosition={parent:this.element.parent(),index:this.element.parent().children().index(this.element)},this.options.title=this.options.title||this.originalTitle;var t=this,r=this.options,i=r.title||" ",s,o,u,a,f;s=(this.uiDialog=e("<div>")).addClass(n+r.dialogClass).css({display:"none",outline:0,zIndex:r.zIndex}).attr("tabIndex",-1).keydown(function(n){r.closeOnEscape&&!n.isDefaultPrevented()&&n.keyCode&&n.keyCode===e.ui.keyCode.ESCAPE&&(t.close(n),n.preventDefault())}).mousedown(function(e){t.moveToTop(!1,e)}).appendTo("body"),this.element.show().removeAttr("title").addClass("ui-dialog-content ui-widget-content").appendTo(s),o=(this.uiDialogTitlebar=e("<div>")).addClass("ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix").bind("mousedown",function(){s.focus()}).prependTo(s),u=e("<a href='#'></a>").addClass("ui-dialog-titlebar-close ui-corner-all").attr("role","button").click(function(e){e.preventDefault(),t.close(e)}).appendTo(o),(this.uiDialogTitlebarCloseText=e("<span>")).addClass("ui-icon ui-icon-closethick").text(r.closeText).appendTo(u),a=e("<span>").uniqueId().addClass("ui-dialog-title").html(i).prependTo(o),f=(this.uiDialogButtonPane=e("<div>")).addClass("ui-dialog-buttonpane ui-widget-content ui-helper-clearfix"),(this.uiButtonSet=e("<div>")).addClass("ui-dialog-buttonset").appendTo(f),s.attr({role:"dialog","aria-labelledby":a.attr("id")}),o.find("*").add(o).disableSelection(),this._hoverable(u),this._focusable(u),r.draggable&&e.fn.draggable&&this._makeDraggable(),r.resizable&&e.fn.resizable&&this._makeResizable(),this._createButtons(r.buttons),this._isOpen=!1,e.fn.bgiframe&&s.bgiframe(),this._on(s,{keydown:function(t){if(!r.modal||t.keyCode!==e.ui.keyCode.TAB)return;var n=e(":tabbable",s),i=n.filter(":first"),o=n.filter(":last");if(t.target===o[0]&&!t.shiftKey)return i.focus(1),!1;if(t.target===i[0]&&t.shiftKey)return o.focus(1),!1}})},_init:function(){this.options.autoOpen&&this.open()},_destroy:function(){var e,t=this.oldPosition;this.overlay&&this.overlay.destroy(),this.uiDialog.hide(),this.element.removeClass("ui-dialog-content ui-widget-content").hide().appendTo("body"),this.uiDialog.remove(),this.originalTitle&&this.element.attr("title",this.originalTitle),e=t.parent.children().eq(t.index),e.length&&e[0]!==this.element[0]?e.before(this.element):t.parent.append(this.element)},widget:function(){return this.uiDialog},close:function(t){var n=this,r,i;if(!this._isOpen)return;if(!1===this._trigger("beforeClose",t))return;return this._isOpen=!1,this.overlay&&this.overlay.destroy(),this.options.hide?this._hide(this.uiDialog,this.options.hide,function(){n._trigger("close",t)}):(this.uiDialog.hide(),this._trigger("close",t)),e.ui.dialog.overlay.resize(),this.options.modal&&(r=0,e(".ui-dialog").each(function(){this!==n.uiDialog[0]&&(i=e(this).css("z-index"),isNaN(i)||(r=Math.max(r,i)))}),e.ui.dialog.maxZ=r),this},isOpen:function(){return this._isOpen},moveToTop:function(t,n){var r=this.options,i;return r.modal&&!t||!r.stack&&!r.modal?this._trigger("focus",n):(r.zIndex>e.ui.dialog.maxZ&&(e.ui.dialog.maxZ=r.zIndex),this.overlay&&(e.ui.dialog.maxZ+=1,e.ui.dialog.overlay.maxZ=e.ui.dialog.maxZ,this.overlay.$el.css("z-index",e.ui.dialog.overlay.maxZ)),i={scrollTop:this.element.scrollTop(),scrollLeft:this.element.scrollLeft()},e.ui.dialog.maxZ+=1,this.uiDialog.css("z-index",e.ui.dialog.maxZ),this.element.attr(i),this._trigger("focus",n),this)},open:function(){if(this._isOpen)return;var t,n=this.options,r=this.uiDialog;return this._size(),this._position(n.position),r.show(n.show),this.overlay=n.modal?new e.ui.dialog.overlay(this):null,this.moveToTop(!0),t=this.element.find(":tabbable"),t.length||(t=this.uiDialogButtonPane.find(":tabbable"),t.length||(t=r)),t.eq(0).focus(),this._isOpen=!0,this._trigger("open"),this},_createButtons:function(t){var n=this,r=!1;this.uiDialogButtonPane.remove(),this.uiButtonSet.empty(),typeof t=="object"&&t!==null&&e.each(t,function(){return!(r=!0)}),r?(e.each(t,function(t,r){var i,s;r=e.isFunction(r)?{click:r,text:t}:r,r=e.extend({type:"button"},r),s=r.click,r.click=function(){s.apply(n.element[0],arguments)},i=e("<button></button>",r).appendTo(n.uiButtonSet),e.fn.button&&i.button()}),this.uiDialog.addClass("ui-dialog-buttons"),this.uiDialogButtonPane.appendTo(this.uiDialog)):this.uiDialog.removeClass("ui-dialog-buttons")},_makeDraggable:function(){function r(e){return{position:e.position,offset:e.offset}}var t=this,n=this.options;this.uiDialog.draggable({cancel:".ui-dialog-content, .ui-dialog-titlebar-close",handle:".ui-dialog-titlebar",containment:"document",start:function(n,i){e(this).addClass("ui-dialog-dragging"),t._trigger("dragStart",n,r(i))},drag:function(e,n){t._trigger("drag",e,r(n))},stop:function(i,s){n.position=[s.position.left-t.document.scrollLeft(),s.position.top-t.document.scrollTop()],e(this).removeClass("ui-dialog-dragging"),t._trigger("dragStop",i,r(s)),e.ui.dialog.overlay.resize()}})},_makeResizable:function(n){function u(e){return{originalPosition:e.originalPosition,originalSize:e.originalSize,position:e.position,size:e.size}}n=n===t?this.options.resizable:n;var r=this,i=this.options,s=this.uiDialog.css("position"),o=typeof n=="string"?n:"n,e,s,w,se,sw,ne,nw";this.uiDialog.resizable({cancel:".ui-dialog-content",containment:"document",alsoResize:this.element,maxWidth:i.maxWidth,maxHeight:i.maxHeight,minWidth:i.minWidth,minHeight:this._minHeight(),handles:o,start:function(t,n){e(this).addClass("ui-dialog-resizing"),r._trigger("resizeStart",t,u(n))},resize:function(e,t){r._trigger("resize",e,u(t))},stop:function(t,n){e(this).removeClass("ui-dialog-resizing"),i.height=e(this).height(),i.width=e(this).width(),r._trigger("resizeStop",t,u(n)),e.ui.dialog.overlay.resize()}}).css("position",s).find(".ui-resizable-se").addClass("ui-icon ui-icon-grip-diagonal-se")},_minHeight:function(){var e=this.options;return e.height==="auto"?e.minHeight:Math.min(e.minHeight,e.height)},_position:function(t){var n=[],r=[0,0],i;if(t){if(typeof t=="string"||typeof t=="object"&&"0"in t)n=t.split?t.split(" "):[t[0],t[1]],n.length===1&&(n[1]=n[0]),e.each(["left","top"],function(e,t){+n[e]===n[e]&&(r[e]=n[e],n[e]=t)}),t={my:n[0]+(r[0]<0?r[0]:"+"+r[0])+" "+n[1]+(r[1]<0?r[1]:"+"+r[1]),at:n.join(" ")};t=e.extend({},e.ui.dialog.prototype.options.position,t)}else t=e.ui.dialog.prototype.options.position;i=this.uiDialog.is(":visible"),i||this.uiDialog.show(),this.uiDialog.position(t),i||this.uiDialog.hide()},_setOptions:function(t){var n=this,s={},o=!1;e.each(t,function(e,t){n._setOption(e,t),e in r&&(o=!0),e in i&&(s[e]=t)}),o&&this._size(),this.uiDialog.is(":data(resizable)")&&this.uiDialog.resizable("option",s)},_setOption:function(t,r){var i,s,o=this.uiDialog;switch(t){case"buttons":this._createButtons(r);break;case"closeText":this.uiDialogTitlebarCloseText.text(""+r);break;case"dialogClass":o.removeClass(this.options.dialogClass).addClass(n+r);break;case"disabled":r?o.addClass("ui-dialog-disabled"):o.removeClass("ui-dialog-disabled");break;case"draggable":i=o.is(":data(draggable)"),i&&!r&&o.draggable("destroy"),!i&&r&&this._makeDraggable();break;case"position":this._position(r);break;case"resizable":s=o.is(":data(resizable)"),s&&!r&&o.resizable("destroy"),s&&typeof r=="string"&&o.resizable("option","handles",r),!s&&r!==!1&&this._makeResizable(r);break;case"title":e(".ui-dialog-title",this.uiDialogTitlebar).html(""+(r||" "))}this._super(t,r)},_size:function(){var t,n,r,i=this.options,s=this.uiDialog.is(":visible");this.element.show().css({width:"auto",minHeight:0,height:0}),i.minWidth>i.width&&(i.width=i.minWidth),t=this.uiDialog.css({height:"auto",width:i.width}).outerHeight(),n=Math.max(0,i.minHeight-t),i.height==="auto"?e.support.minHeight?this.element.css({minHeight:n,height:"auto"}):(this.uiDialog.show(),r=this.element.css("height","auto").height(),s||this.uiDialog.hide(),this.element.height(Math.max(r,n))):this.element.height(Math.max(i.height-t,0)),this.uiDialog.is(":data(resizable)")&&this.uiDialog.resizable("option","minHeight",this._minHeight())}}),e.extend(e.ui.dialog,{uuid:0,maxZ:0,getTitleId:function(e){var t=e.attr("id");return t||(this.uuid+=1,t=this.uuid),"ui-dialog-title-"+t},overlay:function(t){this.$el=e.ui.dialog.overlay.create(t)}}),e.extend(e.ui.dialog.overlay,{instances:[],oldInstances:[],maxZ:0,events:e.map("focus,mousedown,mouseup,keydown,keypress,click".split(","),function(e){return e+".dialog-overlay"}).join(" "),create:function(t){this.instances.length===0&&(setTimeout(function(){e.ui.dialog.overlay.instances.length&&e(document).bind(e.ui.dialog.overlay.events,function(t){if(e(t.target).zIndex()<e.ui.dialog.overlay.maxZ)return!1})},1),e(window).bind("resize.dialog-overlay",e.ui.dialog.overlay.resize));var n=this.oldInstances.pop()||e("<div>").addClass("ui-widget-overlay");return e(document).bind("keydown.dialog-overlay",function(r){var i=e.ui.dialog.overlay.instances;i.length!==0&&i[i.length-1]===n&&t.options.closeOnEscape&&!r.isDefaultPrevented()&&r.keyCode&&r.keyCode===e.ui.keyCode.ESCAPE&&(t.close(r),r.preventDefault())}),n.appendTo(document.body).css({width:this.width(),height:this.height()}),e.fn.bgiframe&&n.bgiframe(),this.instances.push(n),n},destroy:function(t){var n=e.inArray(t,this.instances),r=0;n!==-1&&this.oldInstances.push(this.instances.splice(n,1)[0]),this.instances.length===0&&e([document,window]).unbind(".dialog-overlay"),t.height(0).width(0).remove(),e.each(this.instances,function(){r=Math.max(r,this.css("z-index"))}),this.maxZ=r},height:function(){var t,n;return e.ui.ie?(t=Math.max(document.documentElement.scrollHeight,document.body.scrollHeight),n=Math.max(document.documentElement.offsetHeight,document.body.offsetHeight),t<n?e(window).height()+"px":t+"px"):e(document).height()+"px"},width:function(){var t,n;return e.ui.ie?(t=Math.max(document.documentElement.scrollWidth,document.body.scrollWidth),n=Math.max(document.documentElement.offsetWidth,document.body.offsetWidth),t<n?e(window).width()+"px":t+"px"):e(document).width()+"px"},resize:function(){var t=e([]);e.each(e.ui.dialog.overlay.instances,function(){t=t.add(this)}),t.css({width:0,height:0}).css({width:e.ui.dialog.overlay.width(),height:e.ui.dialog.overlay.height()})}}),e.extend(e.ui.dialog.overlay.prototype,{destroy:function(){e.ui.dialog.overlay.destroy(this.$el)}})}(jQuery),function(e,t){var n=/up|down|vertical/,r=/up|left|vertical|horizontal/;e.effects.effect.blind=function(t,i){var s=e(this),o=["position","top","bottom","left","right","height","width"],u=e.effects.setMode(s,t.mode||"hide"),a=t.direction||"up",f=n.test(a),l=f?"height":"width",c=f?"top":"left",h=r.test(a),p={},d=u==="show",v,m,g;s.parent().is(".ui-effects-wrapper")?e.effects.save(s.parent(),o):e.effects.save(s,o),s.show(),v=e.effects.createWrapper(s).css({overflow:"hidden"}),m=v[l](),g=parseFloat(v.css(c))||0,p[l]=d?m:0,h||(s.css(f?"bottom":"right",0).css(f?"top":"left","auto").css({position:"absolute"}),p[c]=d?g:m+g),d&&(v.css(l,0),h||v.css(c,g+m)),v.animate(p,{duration:t.duration,easing:t.easing,queue:!1,complete:function(){u==="hide"&&s.hide(),e.effects.restore(s,o),e.effects.removeWrapper(s),i()}})}}(jQuery),function(e,t){e.effects.effect.bounce=function(t,n){var r=e(this),i=["position","top","bottom","left","right","height","width"],s=e.effects.setMode(r,t.mode||"effect"),o=s==="hide",u=s==="show",a=t.direction||"up",f=t.distance,l=t.times||5,c=l*2+(u||o?1:0),h=t.duration/c,p=t.easing,d=a==="up"||a==="down"?"top":"left",v=a==="up"||a==="left",m,g,y,b=r.queue(),w=b.length;(u||o)&&i.push("opacity"),e.effects.save(r,i),r.show(),e.effects.createWrapper(r),f||(f=r[d==="top"?"outerHeight":"outerWidth"]()/3),u&&(y={opacity:1},y[d]=0,r.css("opacity",0).css(d,v?-f*2:f*2).animate(y,h,p)),o&&(f/=Math.pow(2,l-1)),y={},y[d]=0;for(m=0;m<l;m++)g={},g[d]=(v?"-=":"+=")+f,r.animate(g,h,p).animate(y,h,p),f=o?f*2:f/2;o&&(g={opacity:0},g[d]=(v?"-=":"+=")+f,r.animate(g,h,p)),r.queue(function(){o&&r.hide(),e.effects.restore(r,i),e.effects.removeWrapper(r),n()}),w>1&&b.splice.apply(b,[1,0].concat(b.splice(w,c+1))),r.dequeue()}}(jQuery),function(e,t){e.effects.effect.clip=function(t,n){var r=e(this),i=["position","top","bottom","left","right","height","width"],s=e.effects.setMode(r,t.mode||"hide"),o=s==="show",u=t.direction||"vertical",a=u==="vertical",f=a?"height":"width",l=a?"top":"left",c={},h,p,d;e.effects.save(r,i),r.show(),h=e.effects.createWrapper(r).css({overflow:"hidden"}),p=r[0].tagName==="IMG"?h:r,d=p[f](),o&&(p.css(f,0),p.css(l,d/2)),c[f]=o?d:0,c[l]=o?0:d/2,p.animate(c,{queue:!1,duration:t.duration,easing:t.easing,complete:function(){o||r.hide(),e.effects.restore(r,i),e.effects.removeWrapper(r),n()}})}}(jQuery),function(e,t){e.effects.effect.drop=function(t,n){var r=e(this),i=["position","top","bottom","left","right","opacity","height","width"],s=e.effects.setMode(r,t.mode||"hide"),o=s==="show",u=t.direction||"left",a=u==="up"||u==="down"?"top":"left",f=u==="up"||u==="left"?"pos":"neg",l={opacity:o?1:0},c;e.effects.save(r,i),r.show(),e.effects.createWrapper(r),c=t.distance||r[a==="top"?"outerHeight":"outerWidth"](!0)/2,o&&r.css("opacity",0).css(a,f==="pos"?-c:c),l[a]=(o?f==="pos"?"+=":"-=":f==="pos"?"-=":"+=")+c,r.animate(l,{queue:!1,duration:t.duration,easing:t.easing,complete:function(){s==="hide"&&r.hide(),e.effects.restore(r,i),e.effects.removeWrapper(r),n()}})}}(jQuery),function(e,t){e.effects.effect.explode=function(t,n){function y(){c.push(this),c.length===r*i&&b()}function b(){s.css({visibility:"visible"}),e(c).remove(),u||s.hide(),n()}var r=t.pieces?Math.round(Math.sqrt(t.pieces)):3,i=r,s=e(this),o=e.effects.setMode(s,t.mode||"hide"),u=o==="show",a=s.show().css("visibility","hidden").offset(),f=Math.ceil(s.outerWidth()/i),l=Math.ceil(s.outerHeight()/r),c=[],h,p,d,v,m,g;for(h=0;h<r;h++){v=a.top+h*l,g=h-(r-1)/2;for(p=0;p<i;p++)d=a.left+p*f,m=p-(i-1)/2,s.clone().appendTo("body").wrap("<div></div>").css({position:"absolute",visibility:"visible",left:-p*f,top:-h*l}).parent().addClass("ui-effects-explode").css({position:"absolute",overflow:"hidden",width:f,height:l,left:d+(u?m*f:0),top:v+(u?g*l:0),opacity:u?0:1}).animate({left:d+(u?0:m*f),top:v+(u?0:g*l),opacity:u?1:0},t.duration||500,t.easing,y)}}}(jQuery),function(e,t){e.effects.effect.fade=function(t,n){var r=e(this),i=e.effects.setMode(r,t.mode||"toggle");r.animate({opacity:i},{queue:!1,duration:t.duration,easing:t.easing,complete:n})}}(jQuery),function(e,t){e.effects.effect.fold=function(t,n){var r=e(this),i=["position","top","bottom","left","right","height","width"],s=e.effects.setMode(r,t.mode||"hide"),o=s==="show",u=s==="hide",a=t.size||15,f=/([0-9]+)%/.exec(a),l=!!t.horizFirst,c=o!==l,h=c?["width","height"]:["height","width"],p=t.duration/2,d,v,m={},g={};e.effects.save(r,i),r.show(),d=e.effects.createWrapper(r).css({overflow:"hidden"}),v=c?[d.width(),d.height()]:[d.height(),d.width()],f&&(a=parseInt(f[1],10)/100*v[u?0:1]),o&&d.css(l?{height:0,width:a}:{height:a,width:0}),m[h[0]]=o?v[0]:a,g[h[1]]=o?v[1]:0,d.animate(m,p,t.easing).animate(g,p,t.easing,function(){u&&r.hide(),e.effects.restore(r,i),e.effects.removeWrapper(r),n()})}}(jQuery),function(e,t){e.effects.effect.highlight=function(t,n){var r=e(this),i=["backgroundImage","backgroundColor","opacity"],s=e.effects.setMode(r,t.mode||"show"),o={backgroundColor:r.css("backgroundColor")};s==="hide"&&(o.opacity=0),e.effects.save(r,i),r.show().css({backgroundImage:"none",backgroundColor:t.color||"#ffff99"}).animate(o,{queue:!1,duration:t.duration,easing:t.easing,complete:function(){s==="hide"&&r.hide(),e.effects.restore(r,i),n()}})}}(jQuery),function(e,t){e.effects.effect.pulsate=function(t,n){var r=e(this),i=e.effects.setMode(r,t.mode||"show"),s=i==="show",o=i==="hide",u=s||i==="hide",a=(t.times||5)*2+(u?1:0),f=t.duration/a,l=0,c=r.queue(),h=c.length,p;if(s||!r.is(":visible"))r.css("opacity",0).show(),l=1;for(p=1;p<a;p++)r.animate({opacity:l},f,t.easing),l=1-l;r.animate({opacity:l},f,t.easing),r.queue(function(){o&&r.hide(),n()}),h>1&&c.splice.apply(c,[1,0].concat(c.splice(h,a+1))),r.dequeue()}}(jQuery),function(e,t){e.effects.effect.puff=function(t,n){var r=e(this),i=e.effects.setMode(r,t.mode||"hide"),s=i==="hide",o=parseInt(t.percent,10)||150,u=o/100,a={height:r.height(),width:r.width(),outerHeight:r.outerHeight(),outerWidth:r.outerWidth()};e.extend(t,{effect:"scale",queue:!1,fade:!0,mode:i,complete:n,percent:s?o:100,from:s?a:{height:a.height*u,width:a.width*u,outerHeight:a.outerHeight*u,outerWidth:a.outerWidth*u}}),r.effect(t)},e.effects.effect.scale=function(t,n){var r=e(this),i=e.extend(!0,{},t),s=e.effects.setMode(r,t.mode||"effect"),o=parseInt(t.percent,10)||(parseInt(t.percent,10)===0?0:s==="hide"?0:100),u=t.direction||"both",a=t.origin,f={height:r.height(),width:r.width(),outerHeight:r.outerHeight(),outerWidth:r.outerWidth()},l={y:u!=="horizontal"?o/100:1,x:u!=="vertical"?o/100:1};i.effect="size",i.queue=!1,i.complete=n,s!=="effect"&&(i.origin=a||["middle","center"],i.restore=!0),i.from=t.from||(s==="show"?{height:0,width:0,outerHeight:0,outerWidth:0}:f),i.to={height:f.height*l.y,width:f.width*l.x,outerHeight:f.outerHeight*l.y,outerWidth:f.outerWidth*l.x},i.fade&&(s==="show"&&(i.from.opacity=0,i.to.opacity=1),s==="hide"&&(i.from.opacity=1,i.to.opacity=0)),r.effect(i)},e.effects.effect.size=function(t,n){var r,i,s,o=e(this),u=["position","top","bottom","left","right","width","height","overflow","opacity"],a=["position","top","bottom","left","right","overflow","opacity"],f=["width","height","overflow"],l=["fontSize"],c=["borderTopWidth","borderBottomWidth","paddingTop","paddingBottom"],h=["borderLeftWidth","borderRightWidth","paddingLeft","paddingRight"],p=e.effects.setMode(o,t.mode||"effect"),d=t.restore||p!=="effect",v=t.scale||"both",m=t.origin||["middle","center"],g=o.css("position"),y=d?u:a,b={height:0,width:0,outerHeight:0,outerWidth:0};p==="show"&&o.show(),r={height:o.height(),width:o.width(),outerHeight:o.outerHeight(),outerWidth:o.outerWidth()},t.mode==="toggle"&&p==="show"?(o.from=t.to||b,o.to=t.from||r):(o.from=t.from||(p==="show"?b:r),o.to=t.to||(p==="hide"?b:r)),s={from:{y:o.from.height/r.height,x:o.from.width/r.width},to:{y:o.to.height/r.height,x:o.to.width/r.width}};if(v==="box"||v==="both")s.from.y!==s.to.y&&(y=y.concat(c),o.from=e.effects.setTransition(o,c,s.from.y,o.from),o.to=e.effects.setTransition(o,c,s.to.y,o.to)),s.from.x!==s.to.x&&(y=y.concat(h),o.from=e.effects.setTransition(o,h,s.from.x,o.from),o.to=e.effects.setTransition(o,h,s.to.x,o.to));(v==="content"||v==="both")&&s.from.y!==s.to.y&&(y=y.concat(l).concat(f),o.from=e.effects.setTransition(o,l,s.from.y,o.from),o.to=e.effects.setTransition(o,l,s.to.y,o.to)),e.effects.save(o,y),o.show(),e.effects.createWrapper(o),o.css("overflow","hidden").css(o.from),m&&(i=e.effects.getBaseline(m,r),o.from.top=(r.outerHeight-o.outerHeight())*i.y,o.from.left=(r.outerWidth-o.outerWidth())*i.x,o.to.top=(r.outerHeight-o.to.outerHeight)*i.y,o.to.left=(r.outerWidth-o.to.outerWidth)*i.x),o.css(o.from);if(v==="content"||v==="both")c=c.concat(["marginTop","marginBottom"]).concat(l),h=h.concat(["marginLeft","marginRight"]),f=u.concat(c).concat(h),o.find("*[width]").each(function(){var n=e(this),r={height:n.height(),width:n.width(),outerHeight:n.outerHeight(),outerWidth:n.outerWidth()};d&&e.effects.save(n,f),n.from={height:r.height*s.from.y,width:r.width*s.from.x,outerHeight:r.outerHeight*s.from.y,outerWidth:r.outerWidth*s.from.x},n.to={height:r.height*s.to.y,width:r.width*s.to.x,outerHeight:r.height*s.to.y,outerWidth:r.width*s.to.x},s.from.y!==s.to.y&&(n.from=e.effects.setTransition(n,c,s.from.y,n.from),n.to=e.effects.setTransition(n,c,s.to.y,n.to)),s.from.x!==s.to.x&&(n.from=e.effects.setTransition(n,h,s.from.x,n.from),n.to=e.effects.setTransition(n,h,s.to.x,n.to)),n.css(n.from),n.animate(n.to,t.duration,t.easing,function(){d&&e.effects.restore(n,f)})});o.animate(o.to,{queue:!1,duration:t.duration,easing:t.easing,complete:function(){o.to.opacity===0&&o.css("opacity",o.from.opacity),p==="hide"&&o.hide(),e.effects.restore(o,y),d||(g==="static"?o.css({position:"relative",top:o.to.top,left:o.to.left}):e.each(["top","left"],function(e,t){o.css(t,function(t,n){var r=parseInt(n,10),i=e?o.to.left:o.to.top;return n==="auto"?i+"px":r+i+"px"})})),e.effects.removeWrapper(o),n()}})}}(jQuery),function(e,t){e.effects.effect.shake=function(t,n){var r=e(this),i=["position","top","bottom","left","right","height","width"],s=e.effects.setMode(r,t.mode||"effect"),o=t.direction||"left",u=t.distance||20,a=t.times||3,f=a*2+1,l=Math.round(t.duration/f),c=o==="up"||o==="down"?"top":"left",h=o==="up"||o==="left",p={},d={},v={},m,g=r.queue(),y=g.length;e.effects.save(r,i),r.show(),e.effects.createWrapper(r),p[c]=(h?"-=":"+=")+u,d[c]=(h?"+=":"-=")+u*2,v[c]=(h?"-=":"+=")+u*2,r.animate(p,l,t.easing);for(m=1;m<a;m++)r.animate(d,l,t.easing).animate(v,l,t.easing);r.animate(d,l,t.easing).animate(p,l/2,t.easing).queue(function(){s==="hide"&&r.hide(),e.effects.restore(r,i),e.effects.removeWrapper(r),n()}),y>1&&g.splice.apply(g,[1,0].concat(g.splice(y,f+1))),r.dequeue()}}(jQuery),function(e,t){e.effects.effect.slide=function(t,n){var r=e(this),i=["position","top","bottom","left","right","width","height"],s=e.effects.setMode(r,t.mode||"show"),o=s==="show",u=t.direction||"left",a=u==="up"||u==="down"?"top":"left",f=u==="up"||u==="left",l,c={};e.effects.save(r,i),r.show(),l=t.distance||r[a==="top"?"outerHeight":"outerWidth"](!0),e.effects.createWrapper(r).css({overflow:"hidden"}),o&&r.css(a,f?isNaN(l)?"-"+l:-l:l),c[a]=(o?f?"+=":"-=":f?"-=":"+=")+l,r.animate(c,{queue:!1,duration:t.duration,easing:t.easing,complete:function(){s==="hide"&&r.hide(),e.effects.restore(r,i),e.effects.removeWrapper(r),n()}})}}(jQuery),function(e,t){e.effects.effect.transfer=function(t,n){var r=e(this),i=e(t.to),s=i.css("position")==="fixed",o=e("body"),u=s?o.scrollTop():0,a=s?o.scrollLeft():0,f=i.offset(),l={top:f.top-u,left:f.left-a,height:i.innerHeight(),width:i.innerWidth()},c=r.offset(),h=e('<div class="ui-effects-transfer"></div>').appendTo(document.body).addClass(t.className).css({top:c.top-u,left:c.left-a,height:r.innerHeight(),width:r.innerWidth(),position:s?"fixed":"absolute"}).animate(l,t.duration,t.easing,function(){h.remove(),n()})}}(jQuery),function(e,t){var n=!1;e.widget("ui.menu",{version:"1.9.2",defaultElement:"<ul>",delay:300,options:{icons:{submenu:"ui-icon-carat-1-e"},menus:"ul",position:{my:"left top",at:"right top"},role:"menu",blur:null,focus:null,select:null},_create:function(){this.activeMenu=this.element,this.element.uniqueId().addClass("ui-menu ui-widget ui-widget-content ui-corner-all").toggleClass("ui-menu-icons",!!this.element.find(".ui-icon").length).attr({role:this.options.role,tabIndex:0}).bind("click"+this.eventNamespace,e.proxy(function(e){this.options.disabled&&e.preventDefault()},this)),this.options.disabled&&this.element.addClass("ui-state-disabled").attr("aria-disabled","true"),this._on({"mousedown .ui-menu-item > a":function(e){e.preventDefault()},"click .ui-state-disabled > a":function(e){e.preventDefault()},"click .ui-menu-item:has(a)":function(t){var r=e(t.target).closest(".ui-menu-item");!n&&r.not(".ui-state-disabled").length&&(n=!0,this.select(t),r.has(".ui-menu").length?this.expand(t):this.element.is(":focus")||(this.element.trigger("focus",[!0]),this.active&&this.active.parents(".ui-menu").length===1&&clearTimeout(this.timer)))},"mouseenter .ui-menu-item":function(t){var n=e(t.currentTarget);n.siblings().children(".ui-state-active").removeClass("ui-state-active"),this.focus(t,n)},mouseleave:"collapseAll","mouseleave .ui-menu":"collapseAll",focus:function(e,t){var n=this.active||this.element.children(".ui-menu-item").eq(0);t||this.focus(e,n)},blur:function(t){this._delay(function(){e.contains(this.element[0],this.document[0].activeElement)||this.collapseAll(t)})},keydown:"_keydown"}),this.refresh(),this._on(this.document,{click:function(t){e(t.target).closest(".ui-menu").length||this.collapseAll(t),n=!1}})},_destroy:function(){this.element.removeAttr("aria-activedescendant").find(".ui-menu").andSelf().removeClass("ui-menu ui-widget ui-widget-content ui-corner-all ui-menu-icons").removeAttr("role").removeAttr("tabIndex").removeAttr("aria-labelledby").removeAttr("aria-expanded").removeAttr("aria-hidden").removeAttr("aria-disabled").removeUniqueId().show(),this.element.find(".ui-menu-item").removeClass("ui-menu-item").removeAttr("role").removeAttr("aria-disabled").children("a").removeUniqueId().removeClass("ui-corner-all ui-state-hover").removeAttr("tabIndex").removeAttr("role").removeAttr("aria-haspopup").children().each(function(){var t=e(this);t.data("ui-menu-submenu-carat")&&t.remove()}),this.element.find(".ui-menu-divider").removeClass("ui-menu-divider ui-widget-content")},_keydown:function(t){function a(e){return e.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g,"\\$&")}var n,r,i,s,o,u=!0;switch(t.keyCode){case e.ui.keyCode.PAGE_UP:this.previousPage(t);break;case e.ui.keyCode.PAGE_DOWN:this.nextPage(t);break;case e.ui.keyCode.HOME:this._move("first","first",t);break;case e.ui.keyCode.END:this._move("last","last",t);break;case e.ui.keyCode.UP:this.previous(t);break;case e.ui.keyCode.DOWN:this.next(t);break;case e.ui.keyCode.LEFT:this.collapse(t);break;case e.ui.keyCode.RIGHT:this.active&&!this.active.is(".ui-state-disabled")&&this.expand(t);break;case e.ui.keyCode.ENTER:case e.ui.keyCode.SPACE:this._activate(t);break;case e.ui.keyCode.ESCAPE:this.collapse(t);break;default:u=!1,r=this.previousFilter||"",i=String.fromCharCode(t.keyCode),s=!1,clearTimeout(this.filterTimer),i===r?s=!0:i=r+i,o=new RegExp("^"+a(i),"i"),n=this.activeMenu.children(".ui-menu-item").filter(function(){return o.test(e(this).children("a").text())}),n=s&&n.index(this.active.next())!==-1?this.active.nextAll(".ui-menu-item"):n,n.length||(i=String.fromCharCode(t.keyCode),o=new RegExp("^"+a(i),"i"),n=this.activeMenu.children(".ui-menu-item").filter(function(){return o.test(e(this).children("a").text())})),n.length?(this.focus(t,n),n.length>1?(this.previousFilter=i,this.filterTimer=this._delay(function(){delete this.previousFilter},1e3)):delete this.previousFilter):delete this.previousFilter}u&&t.preventDefault()},_activate:function(e){this.active.is(".ui-state-disabled")||(this.active.children("a[aria-haspopup='true']").length?this.expand(e):this.select(e))},refresh:function(){var t,n=this.options.icons.submenu,r=this.element.find(this.options.menus);r.filter(":not(.ui-menu)").addClass("ui-menu ui-widget ui-widget-content ui-corner-all").hide().attr({role:this.options.role,"aria-hidden":"true","aria-expanded":"false"}).each(function(){var t=e(this),r=t.prev("a"),i=e("<span>").addClass("ui-menu-icon ui-icon "+n).data("ui-menu-submenu-carat",!0);r.attr("aria-haspopup","true").prepend(i),t.attr("aria-labelledby",r.attr("id"))}),t=r.add(this.element),t.children(":not(.ui-menu-item):has(a)").addClass("ui-menu-item").attr("role","presentation").children("a").uniqueId().addClass("ui-corner-all").attr({tabIndex:-1,role:this._itemRole()}),t.children(":not(.ui-menu-item)").each(function(){var t=e(this);/[^\-—–\s]/.test(t.text())||t.addClass("ui-widget-content ui-menu-divider")}),t.children(".ui-state-disabled").attr("aria-disabled","true"),this.active&&!e.contains(this.element[0],this.active[0])&&this.blur()},_itemRole:function(){return{menu:"menuitem",listbox:"option"}[this.options.role]},focus:function(e,t){var n,r;this.blur(e,e&&e.type==="focus"),this._scrollIntoView(t),this.active=t.first(),r=this.active.children("a").addClass("ui-state-focus"),this.options.role&&this.element.attr("aria-activedescendant",r.attr("id")),this.active.parent().closest(".ui-menu-item").children("a:first").addClass("ui-state-active"),e&&e.type==="keydown"?this._close():this.timer=this._delay(function(){this._close()},this.delay),n=t.children(".ui-menu"),n.length&&/^mouse/.test(e.type)&&this._startOpening(n),this.activeMenu=t.parent(),this._trigger("focus",e,{item:t})},_scrollIntoView:function(t){var n,r,i,s,o,u;this._hasScroll()&&(n=parseFloat(e.css(this.activeMenu[0],"borderTopWidth"))||0,r=parseFloat(e.css(this.activeMenu[0],"paddingTop"))||0,i=t.offset().top-this.activeMenu.offset().top-n-r,s=this.activeMenu.scrollTop(),o=this.activeMenu.height(),u=t.height(),i<0?this.activeMenu.scrollTop(s+i):i+u>o&&this.activeMenu.scrollTop(s+i-o+u))},blur:function(e,t){t||clearTimeout(this.timer);if(!this.active)return;this.active.children("a").removeClass("ui-state-focus"),this.active=null,this._trigger("blur",e,{item:this.active})},_startOpening:function(e){clearTimeout(this.timer);if(e.attr("aria-hidden")!=="true")return;this.timer=this._delay(function(){this._close(),this._open(e)},this.delay)},_open:function(t){var n=e.extend({of:this.active},this.options.position);clearTimeout(this.timer),this.element.find(".ui-menu").not(t.parents(".ui-menu")).hide().attr("aria-hidden","true"),t.show().removeAttr("aria-hidden").attr("aria-expanded","true").position(n)},collapseAll:function(t,n){clearTimeout(this.timer),this.timer=this._delay(function(){var r=n?this.element:e(t&&t.target).closest(this.element.find(".ui-menu"));r.length||(r=this.element),this._close(r),this.blur(t),this.activeMenu=r},this.delay)},_close:function(e){e||(e=this.active?this.active.parent():this.element),e.find(".ui-menu").hide().attr("aria-hidden","true").attr("aria-expanded","false").end().find("a.ui-state-active").removeClass("ui-state-active")},collapse:function(e){var t=this.active&&this.active.parent().closest(".ui-menu-item",this.element);t&&t.length&&(this._close(),this.focus(e,t))},expand:function(e){var t=this.active&&this.active.children(".ui-menu ").children(".ui-menu-item").first();t&&t.length&&(this._open(t.parent()),this._delay(function(){this.focus(e,t)}))},next:function(e){this._move("next","first",e)},previous:function(e){this._move("prev","last",e)},isFirstItem:function(){return this.active&&!this.active.prevAll(".ui-menu-item").length},isLastItem:function(){return this.active&&!this.active.nextAll(".ui-menu-item").length},_move:function(e,t,n){var r;this.active&&(e==="first"||e==="last"?r=this.active[e==="first"?"prevAll":"nextAll"](".ui-menu-item").eq(-1):r=this.active[e+"All"](".ui-menu-item").eq(0));if(!r||!r.length||!this.active)r=this.activeMenu.children(".ui-menu-item")[t]();this.focus(n,r)},nextPage:function(t){var n,r,i;if(!this.active){this.next(t);return}if(this.isLastItem())return;this._hasScroll()?(r=this.active.offset().top,i=this.element.height(),this.active.nextAll(".ui-menu-item").each(function(){return n=e(this),n.offset().top-r-i<0}),this.focus(t,n)):this.focus(t,this.activeMenu.children(".ui-menu-item")[this.active?"last":"first"]())},previousPage:function(t){var n,r,i;if(!this.active){this.next(t);return}if(this.isFirstItem())return;this._hasScroll()?(r=this.active.offset().top,i=this.element.height(),this.active.prevAll(".ui-menu-item").each(function(){return n=e(this),n.offset().top-r+i>0}),this.focus(t,n)):this.focus(t,this.activeMenu.children(".ui-menu-item").first())},_hasScroll:function(){return this.element.outerHeight()<this.element.prop("scrollHeight")},select:function(t){this.active=this.active||e(t.target).closest(".ui-menu-item");var n={item:this.active};this.active.has(".ui-menu").length||this.collapseAll(t,!0),this._trigger("select",t,n)}})}(jQuery),function(e,t){function h(e,t,n){return[parseInt(e[0],10)*(l.test(e[0])?t/100:1),parseInt(e[1],10)*(l.test(e[1])?n/100:1)]}function p(t,n){return parseInt(e.css(t,n),10)||0}e.ui=e.ui||{};var n,r=Math.max,i=Math.abs,s=Math.round,o=/left|center|right/,u=/top|center|bottom/,a=/[\+\-]\d+%?/,f=/^\w+/,l=/%$/,c=e.fn.position;e.position={scrollbarWidth:function(){if(n!==t)return n;var r,i,s=e("<div style='display:block;width:50px;height:50px;overflow:hidden;'><div style='height:100px;width:auto;'></div></div>"),o=s.children()[0];return e("body").append(s),r=o.offsetWidth,s.css("overflow","scroll"),i=o.offsetWidth,r===i&&(i=s[0].clientWidth),s.remove(),n=r-i},getScrollInfo:function(t){var n=t.isWindow?"":t.element.css("overflow-x"),r=t.isWindow?"":t.element.css("overflow-y"),i=n==="scroll"||n==="auto"&&t.width<t.element[0].scrollWidth,s=r==="scroll"||r==="auto"&&t.height<t.element[0].scrollHeight;return{width:i?e.position.scrollbarWidth():0,height:s?e.position.scrollbarWidth():0}},getWithinInfo:function(t){var n=e(t||window),r=e.isWindow(n[0]);return{element:n,isWindow:r,offset:n.offset()||{left:0,top:0},scrollLeft:n.scrollLeft(),scrollTop:n.scrollTop(),width:r?n.width():n.outerWidth(),height:r?n.height():n.outerHeight()}}},e.fn.position=function(t){if(!t||!t.of)return c.apply(this,arguments);t=e.extend({},t);var n,l,d,v,m,g=e(t.of),y=e.position.getWithinInfo(t.within),b=e.position.getScrollInfo(y),w=g[0],E=(t.collision||"flip").split(" "),S={};return w.nodeType===9?(l=g.width(),d=g.height(),v={top:0,left:0}):e.isWindow(w)?(l=g.width(),d=g.height(),v={top:g.scrollTop(),left:g.scrollLeft()}):w.preventDefault?(t.at="left top",l=d=0,v={top:w.pageY,left:w.pageX}):(l=g.outerWidth(),d=g.outerHeight(),v=g.offset()),m=e.extend({},v),e.each(["my","at"],function(){var e=(t[this]||"").split(" "),n,r;e.length===1&&(e=o.test(e[0])?e.concat(["center"]):u.test(e[0])?["center"].concat(e):["center","center"]),e[0]=o.test(e[0])?e[0]:"center",e[1]=u.test(e[1])?e[1]:"center",n=a.exec(e[0]),r=a.exec(e[1]),S[this]=[n?n[0]:0,r?r[0]:0],t[this]=[f.exec(e[0])[0],f.exec(e[1])[0]]}),E.length===1&&(E[1]=E[0]),t.at[0]==="right"?m.left+=l:t.at[0]==="center"&&(m.left+=l/2),t.at[1]==="bottom"?m.top+=d:t.at[1]==="center"&&(m.top+=d/2),n=h(S.at,l,d),m.left+=n[0],m.top+=n[1],this.each(function(){var o,u,a=e(this),f=a.outerWidth(),c=a.outerHeight(),w=p(this,"marginLeft"),x=p(this,"marginTop"),T=f+w+p(this,"marginRight")+b.width,N=c+x+p(this,"marginBottom")+b.height,C=e.extend({},m),k=h(S.my,a.outerWidth(),a.outerHeight());t.my[0]==="right"?C.left-=f:t.my[0]==="center"&&(C.left-=f/2),t.my[1]==="bottom"?C.top-=c:t.my[1]==="center"&&(C.top-=c/2),C.left+=k[0],C.top+=k[1],e.support.offsetFractions||(C.left=s(C.left),C.top=s(C.top)),o={marginLeft:w,marginTop:x},e.each(["left","top"],function(r,i){e.ui.position[E[r]]&&e.ui.position[E[r]][i](C,{targetWidth:l,targetHeight:d,elemWidth:f,elemHeight:c,collisionPosition:o,collisionWidth:T,collisionHeight:N,offset:[n[0]+k[0],n[1]+k[1]],my:t.my,at:t.at,within:y,elem:a})}),e.fn.bgiframe&&a.bgiframe(),t.using&&(u=function(e){var n=v.left-C.left,s=n+l-f,o=v.top-C.top,u=o+d-c,h={target:{element:g,left:v.left,top:v.top,width:l,height:d},element:{element:a,left:C.left,top:C.top,width:f,height:c},horizontal:s<0?"left":n>0?"right":"center",vertical:u<0?"top":o>0?"bottom":"middle"};l<f&&i(n+s)<l&&(h.horizontal="center"),d<c&&i(o+u)<d&&(h.vertical="middle"),r(i(n),i(s))>r(i(o),i(u))?h.important="horizontal":h.important="vertical",t.using.call(this,e,h)}),a.offset(e.extend(C,{using:u}))})},e.ui.position={fit:{left:function(e,t){var n=t.within,i=n.isWindow?n.scrollLeft:n.offset.left,s=n.width,o=e.left-t.collisionPosition.marginLeft,u=i-o,a=o+t.collisionWidth-s-i,f;t.collisionWidth>s?u>0&&a<=0?(f=e.left+u+t.collisionWidth-s-i,e.left+=u-f):a>0&&u<=0?e.left=i:u>a?e.left=i+s-t.collisionWidth:e.left=i:u>0?e.left+=u:a>0?e.left-=a:e.left=r(e.left-o,e.left)},top:function(e,t){var n=t.within,i=n.isWindow?n.scrollTop:n.offset.top,s=t.within.height,o=e.top-t.collisionPosition.marginTop,u=i-o,a=o+t.collisionHeight-s-i,f;t.collisionHeight>s?u>0&&a<=0?(f=e.top+u+t.collisionHeight-s-i,e.top+=u-f):a>0&&u<=0?e.top=i:u>a?e.top=i+s-t.collisionHeight:e.top=i:u>0?e.top+=u:a>0?e.top-=a:e.top=r(e.top-o,e.top)}},flip:{left:function(e,t){var n=t.within,r=n.offset.left+n.scrollLeft,s=n.width,o=n.isWindow?n.scrollLeft:n.offset.left,u=e.left-t.collisionPosition.marginLeft,a=u-o,f=u+t.collisionWidth-s-o,l=t.my[0]==="left"?-t.elemWidth:t.my[0]==="right"?t.elemWidth:0,c=t.at[0]==="left"?t.targetWidth:t.at[0]==="right"?-t.targetWidth:0,h=-2*t.offset[0],p,d;if(a<0){p=e.left+l+c+h+t.collisionWidth-s-r;if(p<0||p<i(a))e.left+=l+c+h}else if(f>0){d=e.left-t.collisionPosition.marginLeft+l+c+h-o;if(d>0||i(d)<f)e.left+=l+c+h}},top:function(e,t){var n=t.within,r=n.offset.top+n.scrollTop,s=n.height,o=n.isWindow?n.scrollTop:n.offset.top,u=e.top-t.collisionPosition.marginTop,a=u-o,f=u+t.collisionHeight-s-o,l=t.my[1]==="top",c=l?-t.elemHeight:t.my[1]==="bottom"?t.elemHeight:0,h=t.at[1]==="top"?t.targetHeight:t.at[1]==="bottom"?-t.targetHeight:0,p=-2*t.offset[1],d,v;a<0?(v=e.top+c+h+p+t.collisionHeight-s-r,e.top+c+h+p>a&&(v<0||v<i(a))&&(e.top+=c+h+p)):f>0&&(d=e.top-t.collisionPosition.marginTop+c+h+p-o,e.top+c+h+p>f&&(d>0||i(d)<f)&&(e.top+=c+h+p))}},flipfit:{left:function(){e.ui.position.flip.left.apply(this,arguments),e.ui.position.fit.left.apply(this,arguments)},top:function(){e.ui.position.flip.top.apply(this,arguments),e.ui.position.fit.top.apply(this,arguments)}}},function(){var t,n,r,i,s,o=document.getElementsByTagName("body")[0],u=document.createElement("div");t=document.createElement(o?"div":"body"),r={visibility:"hidden",width:0,height:0,border:0,margin:0,background:"none"},o&&e.extend(r,{position:"absolute",left:"-1000px",top:"-1000px"});for(s in r)t.style[s]=r[s];t.appendChild(u),n=o||document.documentElement,n.insertBefore(t,n.firstChild),u.style.cssText="position: absolute; left: 10.7432222px;",i=e(u).offset().left,e.support.offsetFractions=i>10&&i<11,t.innerHTML="",n.removeChild(t)}(),e.uiBackCompat!==!1&&function(e){var n=e.fn.position;e.fn.position=function(r){if(!r||!r.offset)return n.call(this,r);var i=r.offset.split(" "),s=r.at.split(" ");return i.length===1&&(i[1]=i[0]),/^\d/.test(i[0])&&(i[0]="+"+i[0]),/^\d/.test(i[1])&&(i[1]="+"+i[1]),s.length===1&&(/left|center|right/.test(s[0])?s[1]="center":(s[1]=s[0],s[0]="center")),n.call(this,e.extend(r,{at:s[0]+i[0]+" "+s[1]+i[1],offset:t}))}}(jQuery)}(jQuery),function(e,t){e.widget("ui.progressbar",{version:"1.9.2",options:{value:0,max:100},min:0,_create:function(){this.element.addClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").attr({role:"progressbar","aria-valuemin":this.min,"aria-valuemax":this.options.max,"aria-valuenow":this._value()}),this.valueDiv=e("<div class='ui-progressbar-value ui-widget-header ui-corner-left'></div>").appendTo(this.element),this.oldValue=this._value(),this._refreshValue()},_destroy:function(){this.element.removeClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").removeAttr("role").removeAttr("aria-valuemin").removeAttr("aria-valuemax").removeAttr("aria-valuenow"),this.valueDiv.remove()},value:function(e){return e===t?this._value():(this._setOption("value",e),this)},_setOption:function(e,t){e==="value"&&(this.options.value=t,this._refreshValue(),this._value()===this.options.max&&this._trigger("complete")),this._super(e,t)},_value:function(){var e=this.options.value;return typeof e!="number"&&(e=0),Math.min(this.options.max,Math.max(this.min,e))},_percentage:function(){return 100*this._value()/this.options.max},_refreshValue:function(){var e=this.value(),t=this._percentage();this.oldValue!==e&&(this.oldValue=e,this._trigger("change")),this.valueDiv.toggle(e>this.min).toggleClass("ui-corner-right",e===this.options.max).width(t.toFixed(0)+"%"),this.element.attr("aria-valuenow",e)}})}(jQuery),function(e,t){var n=5;e.widget("ui.slider",e.ui.mouse,{version:"1.9.2",widgetEventPrefix:"slide",options:{animate:!1,distance:0,max:100,min:0,orientation:"horizontal",range:!1,step:1,value:0,values:null},_create:function(){var t,r,i=this.options,s=this.element.find(".ui-slider-handle").addClass("ui-state-default ui-corner-all"),o="<a class='ui-slider-handle ui-state-default ui-corner-all' href='#'></a>",u=[];this._keySliding=!1,this._mouseSliding=!1,this._animateOff=!0,this._handleIndex=null,this._detectOrientation(),this._mouseInit(),this.element.addClass("ui-slider ui-slider-"+this.orientation+" ui-widget"+" ui-widget-content"+" ui-corner-all"+(i.disabled?" ui-slider-disabled ui-disabled":"")),this.range=e([]),i.range&&(i.range===!0&&(i.values||(i.values=[this._valueMin(),this._valueMin()]),i.values.length&&i.values.length!==2&&(i.values=[i.values[0],i.values[0]])),this.range=e("<div></div>").appendTo(this.element).addClass("ui-slider-range ui-widget-header"+(i.range==="min"||i.range==="max"?" ui-slider-range-"+i.range:""))),r=i.values&&i.values.length||1;for(t=s.length;t<r;t++)u.push(o);this.handles=s.add(e(u.join("")).appendTo(this.element)),this.handle=this.handles.eq(0),this.handles.add(this.range).filter("a").click(function(e){e.preventDefault()}).mouseenter(function(){i.disabled||e(this).addClass("ui-state-hover")}).mouseleave(function(){e(this).removeClass("ui-state-hover")}).focus(function(){i.disabled?e(this).blur():(e(".ui-slider .ui-state-focus").removeClass("ui-state-focus"),e(this).addClass("ui-state-focus"))}).blur(function(){e(this).removeClass("ui-state-focus")}),this.handles.each(function(t){e(this).data("ui-slider-handle-index",t)}),this._on(this.handles,{keydown:function(t){var r,i,s,o,u=e(t.target).data("ui-slider-handle-index");switch(t.keyCode){case e.ui.keyCode.HOME:case e.ui.keyCode.END:case e.ui.keyCode.PAGE_UP:case e.ui.keyCode.PAGE_DOWN:case e.ui.keyCode.UP:case e.ui.keyCode.RIGHT:case e.ui.keyCode.DOWN:case e.ui.keyCode.LEFT:t.preventDefault();if(!this._keySliding){this._keySliding=!0,e(t.target).addClass("ui-state-active"),r=this._start(t,u);if(r===!1)return}}o=this.options.step,this.options.values&&this.options.values.length?i=s=this.values(u):i=s=this.value();switch(t.keyCode){case e.ui.keyCode.HOME:s=this._valueMin();break;case e.ui.keyCode.END:s=this._valueMax();break;case e.ui.keyCode.PAGE_UP:s=this._trimAlignValue(i+(this._valueMax()-this._valueMin())/n);break;case e.ui.keyCode.PAGE_DOWN:s=this._trimAlignValue(i-(this._valueMax()-this._valueMin())/n);break;case e.ui.keyCode.UP:case e.ui.keyCode.RIGHT:if(i===this._valueMax())return;s=this._trimAlignValue(i+o);break;case e.ui.keyCode.DOWN:case e.ui.keyCode.LEFT:if(i===this._valueMin())return;s=this._trimAlignValue(i-o)}this._slide(t,u,s)},keyup:function(t){var n=e(t.target).data("ui-slider-handle-index");this._keySliding&&(this._keySliding=!1,this._stop(t,n),this._change(t,n),e(t.target).removeClass("ui-state-active"))}}),this._refreshValue(),this._animateOff=!1},_destroy:function(){this.handles.remove(),this.range.remove(),this.element.removeClass("ui-slider ui-slider-horizontal ui-slider-vertical ui-slider-disabled ui-widget ui-widget-content ui-corner-all"),this._mouseDestroy()},_mouseCapture:function(t){var n,r,i,s,o,u,a,f,l=this,c=this.options;return c.disabled?!1:(this.elementSize={width:this.element.outerWidth(),height:this.element.outerHeight()},this.elementOffset=this.element.offset(),n={x:t.pageX,y:t.pageY},r=this._normValueFromMouse(n),i=this._valueMax()-this._valueMin()+1,this.handles.each(function(t){var n=Math.abs(r-l.values(t));i>n&&(i=n,s=e(this),o=t)}),c.range===!0&&this.values(1)===c.min&&(o+=1,s=e(this.handles[o])),u=this._start(t,o),u===!1?!1:(this._mouseSliding=!0,this._handleIndex=o,s.addClass("ui-state-active").focus(),a=s.offset(),f=!e(t.target).parents().andSelf().is(".ui-slider-handle"),this._clickOffset=f?{left:0,top:0}:{left:t.pageX-a.left-s.width()/2,top:t.pageY-a.top-s.height()/2-(parseInt(s.css("borderTopWidth"),10)||0)-(parseInt(s.css("borderBottomWidth"),10)||0)+(parseInt(s.css("marginTop"),10)||0)},this.handles.hasClass("ui-state-hover")||this._slide(t,o,r),this._animateOff=!0,!0))},_mouseStart:function(){return!0},_mouseDrag:function(e){var t={x:e.pageX,y:e.pageY},n=this._normValueFromMouse(t);return this._slide(e,this._handleIndex,n),!1},_mouseStop:function(e){return this.handles.removeClass("ui-state-active"),this._mouseSliding=!1,this._stop(e,this._handleIndex),this._change(e,this._handleIndex),this._handleIndex=null,this._clickOffset=null,this._animateOff=!1,!1},_detectOrientation:function(){this.orientation=this.options.orientation==="vertical"?"vertical":"horizontal"},_normValueFromMouse:function(e){var t,n,r,i,s;return this.orientation==="horizontal"?(t=this.elementSize.width,n=e.x-this.elementOffset.left-(this._clickOffset?this._clickOffset.left:0)):(t=this.elementSize.height,n=e.y-this.elementOffset.top-(this._clickOffset?this._clickOffset.top:0)),r=n/t,r>1&&(r=1),r<0&&(r=0),this.orientation==="vertical"&&(r=1-r),i=this._valueMax()-this._valueMin(),s=this._valueMin()+r*i,this._trimAlignValue(s)},_start:function(e,t){var n={handle:this.handles[t],value:this.value()};return this.options.values&&this.options.values.length&&(n.value=this.values(t),n.values=this.values()),this._trigger("start",e,n)},_slide:function(e,t,n){var r,i,s;this.options.values&&this.options.values.length?(r=this.values(t?0:1),this.options.values.length===2&&this.options.range===!0&&(t===0&&n>r||t===1&&n<r)&&(n=r),n!==this.values(t)&&(i=this.values(),i[t]=n,s=this._trigger("slide",e,{handle:this.handles[t],value:n,values:i}),r=this.values(t?0:1),s!==!1&&this.values(t,n,!0))):n!==this.value()&&(s=this._trigger("slide",e,{handle:this.handles[t],value:n}),s!==!1&&this.value(n))},_stop:function(e,t){var n={handle:this.handles[t],value:this.value()};this.options.values&&this.options.values.length&&(n.value=this.values(t),n.values=this.values()),this._trigger("stop",e,n)},_change:function(e,t){if(!this._keySliding&&!this._mouseSliding){var n={handle:this.handles[t],value:this.value()};this.options.values&&this.options.values.length&&(n.value=this.values(t),n.values=this.values()),this._trigger("change",e,n)}},value:function(e){if(arguments.length){this.options.value=this._trimAlignValue(e),this._refreshValue(),this._change(null,0);return}return this._value()},values:function(t,n){var r,i,s;if(arguments.length>1){this.options.values[t]=this._trimAlignValue(n),this._refreshValue(),this._change(null,t);return}if(!arguments.length)return this._values();if(!e.isArray(arguments[0]))return this.options.values&&this.options.values.length?this._values(t):this.value();r=this.options.values,i=arguments[0];for(s=0;s<r.length;s+=1)r[s]=this._trimAlignValue(i[s]),this._change(null,s);this._refreshValue()},_setOption:function(t,n){var r,i=0;e.isArray(this.options.values)&&(i=this.options.values.length),e.Widget.prototype._setOption.apply(this,arguments);switch(t){case"disabled":n?(this.handles.filter(".ui-state-focus").blur(),this.handles.removeClass("ui-state-hover"),this.handles.prop("disabled",!0),this.element.addClass("ui-disabled")):(this.handles.prop("disabled",!1),this.element.removeClass("ui-disabled"));break;case"orientation":this._detectOrientation(),this.element.removeClass("ui-slider-horizontal ui-slider-vertical").addClass("ui-slider-"+this.orientation),this._refreshValue();break;case"value":this._animateOff=!0,this._refreshValue(),this._change(null,0),this._animateOff=!1;break;case"values":this._animateOff=!0,this._refreshValue();for(r=0;r<i;r+=1)this._change(null,r);this._animateOff=!1;break;case"min":case"max":this._animateOff=!0,this._refreshValue(),this._animateOff=!1}},_value:function(){var e=this.options.value;return e=this._trimAlignValue(e),e},_values:function(e){var t,n,r;if(arguments.length)return t=this.options.values[e],t=this._trimAlignValue(t),t;n=this.options.values.slice();for(r=0;r<n.length;r+=1)n[r]=this._trimAlignValue(n[r]);return n},_trimAlignValue:function(e){if(e<=this._valueMin())return this._valueMin();if(e>=this._valueMax())return this._valueMax();var t=this.options.step>0?this.options.step:1,n=(e-this._valueMin())%t,r=e-n;return Math.abs(n)*2>=t&&(r+=n>0?t:-t),parseFloat(r.toFixed(5))},_valueMin:function(){return this.options.min},_valueMax:function(){return this.options.max},_refreshValue:function(){var t,n,r,i,s,o=this.options.range,u=this.options,a=this,f=this._animateOff?!1:u.animate,l={};this.options.values&&this.options.values.length?this.handles.each(function(r){n=(a.values(r)-a._valueMin())/(a._valueMax()-a._valueMin())*100,l[a.orientation==="horizontal"?"left":"bottom"]=n+"%",e(this).stop(1,1)[f?"animate":"css"](l,u.animate),a.options.range===!0&&(a.orientation==="horizontal"?(r===0&&a.range.stop(1,1)[f?"animate":"css"]({left:n+"%"},u.animate),r===1&&a.range[f?"animate":"css"]({width:n-t+"%"},{queue:!1,duration:u.animate})):(r===0&&a.range.stop(1,1)[f?"animate":"css"]({bottom:n+"%"},u.animate),r===1&&a.range[f?"animate":"css"]({height:n-t+"%"},{queue:!1,duration:u.animate}))),t=n}):(r=this.value(),i=this._valueMin(),s=this._valueMax(),n=s!==i?(r-i)/(s-i)*100:0,l[this.orientation==="horizontal"?"left":"bottom"]=n+"%",this.handle.stop(1,1)[f?"animate":"css"](l,u.animate),o==="min"&&this.orientation==="horizontal"&&this.range.stop(1,1)[f?"animate":"css"]({width:n+"%"},u.animate),o==="max"&&this.orientation==="horizontal"&&this.range[f?"animate":"css"]({width:100-n+"%"},{queue:!1,duration:u.animate}),o==="min"&&this.orientation==="vertical"&&this.range.stop(1,1)[f?"animate":"css"]({height:n+"%"},u.animate),o==="max"&&this.orientation==="vertical"&&this.range[f?"animate":"css"]({height:100-n+"%"},{queue:!1,duration:u.animate}))}})}(jQuery),function(e){function t(e){return function(){var t=this.element.val();e.apply(this,arguments),this._refresh(),t!==this.element.val()&&this._trigger("change")}}e.widget("ui.spinner",{version:"1.9.2",defaultElement:"<input>",widgetEventPrefix:"spin",options:{culture:null,icons:{down:"ui-icon-triangle-1-s",up:"ui-icon-triangle-1-n"},incremental:!0,max:null,min:null,numberFormat:null,page:10,step:1,change:null,spin:null,start:null,stop:null},_create:function(){this._setOption("max",this.options.max),this._setOption("min",this.options.min),this._setOption("step",this.options.step),this._value(this.element.val(),!0),this._draw(),this._on(this._events),this._refresh(),this._on(this.window,{beforeunload:function(){this.element.removeAttr("autocomplete")}})},_getCreateOptions:function(){var t={},n=this.element;return e.each(["min","max","step"],function(e,r){var i=n.attr(r);i!==undefined&&i.length&&(t[r]=i)}),t},_events:{keydown:function(e){this._start(e)&&this._keydown(e)&&e.preventDefault()},keyup:"_stop",focus:function(){this.previous=this.element.val()},blur:function(e){if(this.cancelBlur){delete this.cancelBlur;return}this._refresh(),this.previous!==this.element.val()&&this._trigger("change",e)},mousewheel:function(e,t){if(!t)return;if(!this.spinning&&!this._start(e))return!1;this._spin((t>0?1:-1)*this.options.step,e),clearTimeout(this.mousewheelTimer),this.mousewheelTimer=this._delay(function(){this.spinning&&this._stop(e)},100),e.preventDefault()},"mousedown .ui-spinner-button":function(t){function r(){var e=this.element[0]===this.document[0].activeElement;e||(this.element.focus(),this.previous=n,this._delay(function(){this.previous=n}))}var n;n=this.element[0]===this.document[0].activeElement?this.previous:this.element.val(),t.preventDefault(),r.call(this),this.cancelBlur=!0,this._delay(function(){delete this.cancelBlur,r.call(this)});if(this._start(t)===!1)return;this._repeat(null,e(t.currentTarget).hasClass("ui-spinner-up")?1:-1,t)},"mouseup .ui-spinner-button":"_stop","mouseenter .ui-spinner-button":function(t){if(!e(t.currentTarget).hasClass("ui-state-active"))return;if(this._start(t)===!1)return!1;this._repeat(null,e(t.currentTarget).hasClass("ui-spinner-up")?1:-1,t)},"mouseleave .ui-spinner-button":"_stop"},_draw:function(){var e=this.uiSpinner=this.element.addClass("ui-spinner-input").attr("autocomplete","off").wrap(this._uiSpinnerHtml()).parent().append(this._buttonHtml());this.element.attr("role","spinbutton"),this.buttons=e.find(".ui-spinner-button").attr("tabIndex",-1).button().removeClass("ui-corner-all"),this.buttons.height()>Math.ceil(e.height()*.5)&&e.height()>0&&e.height(e.height()),this.options.disabled&&this.disable()},_keydown:function(t){var n=this.options,r=e.ui.keyCode;switch(t.keyCode){case r.UP:return this._repeat(null,1,t),!0;case r.DOWN:return this._repeat(null,-1,t),!0;case r.PAGE_UP:return this._repeat(null,n.page,t),!0;case r.PAGE_DOWN:return this._repeat(null,-n.page,t),!0}return!1},_uiSpinnerHtml:function(){return"<span class='ui-spinner ui-widget ui-widget-content ui-corner-all'></span>"},_buttonHtml:function(){return"<a class='ui-spinner-button ui-spinner-up ui-corner-tr'><span class='ui-icon "+this.options.icons.up+"'>▲</span>"+"</a>"+"<a class='ui-spinner-button ui-spinner-down ui-corner-br'>"+"<span class='ui-icon "+this.options.icons.down+"'>▼</span>"+"</a>"},_start:function(e){return!this.spinning&&this._trigger("start",e)===!1?!1:(this.counter||(this.counter=1),this.spinning=!0,!0)},_repeat:function(e,t,n){e=e||500,clearTimeout(this.timer),this.timer=this._delay(function(){this._repeat(40,t,n)},e),this._spin(t*this.options.step,n)},_spin:function(e,t){var n=this.value()||0;this.counter||(this.counter=1),n=this._adjustValue(n+e*this._increment(this.counter));if(!this.spinning||this._trigger("spin",t,{value:n})!==!1)this._value(n),this.counter++},_increment:function(t){var n=this.options.incremental;return n?e.isFunction(n)?n(t):Math.floor(t*t*t/5e4-t*t/500+17*t/200+1):1},_precision:function(){var e=this._precisionOf(this.options.step);return this.options.min!==null&&(e=Math.max(e,this._precisionOf(this.options.min))),e},_precisionOf:function(e){var t=e.toString(),n=t.indexOf(".");return n===-1?0:t.length-n-1},_adjustValue:function(e){var t,n,r=this.options;return t=r.min!==null?r.min:0,n=e-t,n=Math.round(n/r.step)*r.step,e=t+n,e=parseFloat(e.toFixed(this._precision())),r.max!==null&&e>r.max?r.max:r.min!==null&&e<r.min?r.min:e},_stop:function(e){if(!this.spinning)return;clearTimeout(this.timer),clearTimeout(this.mousewheelTimer),this.counter=0,this.spinning=!1,this._trigger("stop",e)},_setOption:function(e,t){if(e==="culture"||e==="numberFormat"){var n=this._parse(this.element.val());this.options[e]=t,this.element.val(this._format(n));return}(e==="max"||e==="min"||e==="step")&&typeof t=="string"&&(t=this._parse(t)),this._super(e,t),e==="disabled"&&(t?(this.element.prop("disabled",!0),this.buttons.button("disable")):(this.element.prop("disabled",!1),this.buttons.button("enable")))},_setOptions:t(function(e){this._super(e),this._value(this.element.val())}),_parse:function(e){return typeof e=="string"&&e!==""&&(e=window.Globalize&&this.options.numberFormat?Globalize.parseFloat(e,10,this.options.culture):+e),e===""||isNaN(e)?null:e},_format:function(e){return e===""?"":window.Globalize&&this.options.numberFormat?Globalize.format(e,this.options.numberFormat,this.options.culture):e},_refresh:function(){this.element.attr({"aria-valuemin":this.options.min,"aria-valuemax":this.options.max,"aria-valuenow":this._parse(this.element.val())})},_value:function(e,t){var n;e!==""&&(n=this._parse(e),n!==null&&(t||(n=this._adjustValue(n)),e=this._format(n))),this.element.val(e),this._refresh()},_destroy:function(){this.element.removeClass("ui-spinner-input").prop("disabled",!1).removeAttr("autocomplete").removeAttr("role").removeAttr("aria-valuemin").removeAttr("aria-valuemax").removeAttr("aria-valuenow"),this.uiSpinner.replaceWith(this.element)},stepUp:t(function(e){this._stepUp(e)}),_stepUp:function(e){this._spin((e||1)*this.options.step)},stepDown:t(function(e){this._stepDown(e)}),_stepDown:function(e){this._spin((e||1)*-this.options.step)},pageUp:t(function(e){this._stepUp((e||1)*this.options.page)}),pageDown:t(function(e){this._stepDown((e||1)*this.options.page)}),value:function(e){if(!arguments.length)return this._parse(this.element.val());t(this._value).call(this,e)},widget:function(){return this.uiSpinner}})}(jQuery),function(e,t){function i(){return++n}function s(e){return e.hash.length>1&&e.href.replace(r,"")===location.href.replace(r,"").replace(/\s/g,"%20")}var n=0,r=/#.*$/;e.widget("ui.tabs",{version:"1.9.2",delay:300,options:{active:null,collapsible:!1,event:"click",heightStyle:"content",hide:null,show:null,activate:null,beforeActivate:null,beforeLoad:null,load:null},_create:function(){var t=this,n=this.options,r=n.active,i=location.hash.substring(1);this.running=!1,this.element.addClass("ui-tabs ui-widget ui-widget-content ui-corner-all").toggleClass("ui-tabs-collapsible",n.collapsible).delegate(".ui-tabs-nav > li","mousedown"+this.eventNamespace,function(t){e(this).is(".ui-state-disabled")&&t.preventDefault()}).delegate(".ui-tabs-anchor","focus"+this.eventNamespace,function(){e(this).closest("li").is(".ui-state-disabled")&&this.blur()}),this._processTabs();if(r===null){i&&this.tabs.each(function(t,n){if(e(n).attr("aria-controls")===i)return r=t,!1}),r===null&&(r=this.tabs.index(this.tabs.filter(".ui-tabs-active")));if(r===null||r===-1)r=this.tabs.length?0:!1}r!==!1&&(r=this.tabs.index(this.tabs.eq(r)),r===-1&&(r=n.collapsible?!1:0)),n.active=r,!n.collapsible&&n.active===!1&&this.anchors.length&&(n.active=0),e.isArray(n.disabled)&&(n.disabled=e.unique(n.disabled.concat(e.map(this.tabs.filter(".ui-state-disabled"),function(e){return t.tabs.index(e)}))).sort()),this.options.active!==!1&&this.anchors.length?this.active=this._findActive(this.options.active):this.active=e(),this._refresh(),this.active.length&&this.load(n.active)},_getCreateEventData:function(){return{tab:this.active,panel:this.active.length?this._getPanelForTab(this.active):e()}},_tabKeydown:function(t){var n=e(this.document[0].activeElement).closest("li"),r=this.tabs.index(n),i=!0;if(this._handlePageNav(t))return;switch(t.keyCode){case e.ui.keyCode.RIGHT:case e.ui.keyCode.DOWN:r++;break;case e.ui.keyCode.UP:case e.ui.keyCode.LEFT:i=!1,r--;break;case e.ui.keyCode.END:r=this.anchors.length-1;break;case e.ui.keyCode.HOME:r=0;break;case e.ui.keyCode.SPACE:t.preventDefault(),clearTimeout(this.activating),this._activate(r);return;case e.ui.keyCode.ENTER:t.preventDefault(),clearTimeout(this.activating),this._activate(r===this.options.active?!1:r);return;default:return}t.preventDefault(),clearTimeout(this.activating),r=this._focusNextTab(r,i),t.ctrlKey||(n.attr("aria-selected","false"),this.tabs.eq(r).attr("aria-selected","true"),this.activating=this._delay(function(){this.option("active",r)},this.delay))},_panelKeydown:function(t){if(this._handlePageNav(t))return;t.ctrlKey&&t.keyCode===e.ui.keyCode.UP&&(t.preventDefault(),this.active.focus())},_handlePageNav:function(t){if(t.altKey&&t.keyCode===e.ui.keyCode.PAGE_UP)return this._activate(this._focusNextTab(this.options.active-1,!1)),!0;if(t.altKey&&t.keyCode===e.ui.keyCode.PAGE_DOWN)return this._activate(this._focusNextTab(this.options.active+1,!0)),!0},_findNextTab:function(t,n){function i(){return t>r&&(t=0),t<0&&(t=r),t}var r=this.tabs.length-1;while(e.inArray(i(),this.options.disabled)!==-1)t=n?t+1:t-1;return t},_focusNextTab:function(e,t){return e=this._findNextTab(e,t),this.tabs.eq(e).focus(),e},_setOption:function(e,t){if(e==="active"){this._activate(t);return}if(e==="disabled"){this._setupDisabled(t);return}this._super(e,t),e==="collapsible"&&(this.element.toggleClass("ui-tabs-collapsible",t),!t&&this.options.active===!1&&this._activate(0)),e==="event"&&this._setupEvents(t),e==="heightStyle"&&this._setupHeightStyle(t)},_tabId:function(e){return e.attr("aria-controls")||"ui-tabs-"+i()},_sanitizeSelector:function(e){return e?e.replace(/[!"$%&'()*+,.\/:;<=>?@\[\]\^`{|}~]/g,"\\$&"):""},refresh:function(){var t=this.options,n=this.tablist.children(":has(a[href])");t.disabled=e.map(n.filter(".ui-state-disabled"),function(e){return n.index(e)}),this._processTabs(),t.active===!1||!this.anchors.length?(t.active=!1,this.active=e()):this.active.length&&!e.contains(this.tablist[0],this.active[0])?this.tabs.length===t.disabled.length?(t.active=!1,this.active=e()):this._activate(this._findNextTab(Math.max(0,t.active-1),!1)):t.active=this.tabs.index(this.active),this._refresh()},_refresh:function(){this._setupDisabled(this.options.disabled),this._setupEvents(this.options.event),this._setupHeightStyle(this.options.heightStyle),this.tabs.not(this.active).attr({"aria-selected":"false",tabIndex:-1}),this.panels.not(this._getPanelForTab(this.active)).hide().attr({"aria-expanded":"false","aria-hidden":"true"}),this.active.length?(this.active.addClass("ui-tabs-active ui-state-active").attr({"aria-selected":"true",tabIndex:0}),this._getPanelForTab(this.active).show().attr({"aria-expanded":"true","aria-hidden":"false"})):this.tabs.eq(0).attr("tabIndex",0)},_processTabs:function(){var t=this;this.tablist=this._getList().addClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all").attr("role","tablist"),this.tabs=this.tablist.find("> li:has(a[href])").addClass("ui-state-default ui-corner-top").attr({role:"tab",tabIndex:-1}),this.anchors=this.tabs.map(function(){return e("a",this)[0]}).addClass("ui-tabs-anchor").attr({role:"presentation",tabIndex:-1}),this.panels=e(),this.anchors.each(function(n,r){var i,o,u,a=e(r).uniqueId().attr("id"),f=e(r).closest("li"),l=f.attr("aria-controls");s(r)?(i=r.hash,o=t.element.find(t._sanitizeSelector(i))):(u=t._tabId(f),i="#"+u,o=t.element.find(i),o.length||(o=t._createPanel(u),o.insertAfter(t.panels[n-1]||t.tablist)),o.attr("aria-live","polite")),o.length&&(t.panels=t.panels.add(o)),l&&f.data("ui-tabs-aria-controls",l),f.attr({"aria-controls":i.substring(1),"aria-labelledby":a}),o.attr("aria-labelledby",a)}),this.panels.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom").attr("role","tabpanel")},_getList:function(){return this.element.find("ol,ul").eq(0)},_createPanel:function(t){return e("<div>").attr("id",t).addClass("ui-tabs-panel ui-widget-content ui-corner-bottom").data("ui-tabs-destroy",!0)},_setupDisabled:function(t){e.isArray(t)&&(t.length?t.length===this.anchors.length&&(t=!0):t=!1);for(var n=0,r;r=this.tabs[n];n++)t===!0||e.inArray(n,t)!==-1?e(r).addClass("ui-state-disabled").attr("aria-disabled","true"):e(r).removeClass("ui-state-disabled").removeAttr("aria-disabled");this.options.disabled=t},_setupEvents:function(t){var n={click:function(e){e.preventDefault()}};t&&e.each(t.split(" "),function(e,t){n[t]="_eventHandler"}),this._off(this.anchors.add(this.tabs).add(this.panels)),this._on(this.anchors,n),this._on(this.tabs,{keydown:"_tabKeydown"}),this._on(this.panels,{keydown:"_panelKeydown"}),this._focusable(this.tabs),this._hoverable(this.tabs)},_setupHeightStyle:function(t){var n,r,i=this.element.parent();t==="fill"?(e.support.minHeight||(r=i.css("overflow"),i.css("overflow","hidden")),n=i.height(),this.element.siblings(":visible").each(function(){var t=e(this),r=t.css("position");if(r==="absolute"||r==="fixed")return;n-=t.outerHeight(!0)}),r&&i.css("overflow",r),this.element.children().not(this.panels).each(function(){n-=e(this).outerHeight(!0)}),this.panels.each(function(){e(this).height(Math.max(0,n-e(this).innerHeight()+e(this).height()))}).css("overflow","auto")):t==="auto"&&(n=0,this.panels.each(function(){n=Math.max(n,e(this).height("").height())}).height(n))},_eventHandler:function(t){var n=this.options,r=this.active,i=e(t.currentTarget),s=i.closest("li"),o=s[0]===r[0],u=o&&n.collapsible,a=u?e():this._getPanelForTab(s),f=r.length?this._getPanelForTab(r):e(),l={oldTab:r,oldPanel:f,newTab:u?e():s,newPanel:a};t.preventDefault();if(s.hasClass("ui-state-disabled")||s.hasClass("ui-tabs-loading")||this.running||o&&!n.collapsible||this._trigger("beforeActivate",t,l)===!1)return;n.active=u?!1:this.tabs.index(s),this.active=o?e():s,this.xhr&&this.xhr.abort(),!f.length&&!a.length&&e.error("jQuery UI Tabs: Mismatching fragment identifier."),a.length&&this.load(this.tabs.index(s),t),this._toggle(t,l)},_toggle:function(t,n){function o(){r.running=!1,r._trigger("activate",t,n)}function u(){n.newTab.closest("li").addClass("ui-tabs-active ui-state-active"),i.length&&r.options.show?r._show(i,r.options.show,o):(i.show(),o())}var r=this,i=n.newPanel,s=n.oldPanel;this.running=!0,s.length&&this.options.hide?this._hide(s,this.options.hide,function(){n.oldTab.closest("li").removeClass("ui-tabs-active ui-state-active"),u()}):(n.oldTab.closest("li").removeClass("ui-tabs-active ui-state-active"),s.hide(),u()),s.attr({"aria-expanded":"false","aria-hidden":"true"}),n.oldTab.attr("aria-selected","false"),i.length&&s.length?n.oldTab.attr("tabIndex",-1):i.length&&this.tabs.filter(function(){return e(this).attr("tabIndex")===0}).attr("tabIndex",-1),i.attr({"aria-expanded":"true","aria-hidden":"false"}),n.newTab.attr({"aria-selected":"true",tabIndex:0})},_activate:function(t){var n,r=this._findActive(t);if(r[0]===this.active[0])return;r.length||(r=this.active),n=r.find(".ui-tabs-anchor")[0],this._eventHandler({target:n,currentTarget:n,preventDefault:e.noop})},_findActive:function(t){return t===!1?e():this.tabs.eq(t)},_getIndex:function(e){return typeof e=="string"&&(e=this.anchors.index(this.anchors.filter("[href$='"+e+"']"))),e},_destroy:function(){this.xhr&&this.xhr.abort(),this.element.removeClass("ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible"),this.tablist.removeClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all").removeAttr("role"),this.anchors.removeClass("ui-tabs-anchor").removeAttr("role").removeAttr("tabIndex").removeData("href.tabs").removeData("load.tabs").removeUniqueId(),this.tabs.add(this.panels).each(function(){e.data(this,"ui-tabs-destroy")?e(this).remove():e(this).removeClass("ui-state-default ui-state-active ui-state-disabled ui-corner-top ui-corner-bottom ui-widget-content ui-tabs-active ui-tabs-panel").removeAttr("tabIndex").removeAttr("aria-live").removeAttr("aria-busy").removeAttr("aria-selected").removeAttr("aria-labelledby").removeAttr("aria-hidden").removeAttr("aria-expanded").removeAttr("role")}),this.tabs.each(function(){var t=e(this),n=t.data("ui-tabs-aria-controls");n?t.attr("aria-controls",n):t.removeAttr("aria-controls")}),this.panels.show(),this.options.heightStyle!=="content"&&this.panels.css("height","")},enable:function(n){var r=this.options.disabled;if(r===!1)return;n===t?r=!1:(n=this._getIndex(n),e.isArray(r)?r=e.map(r,function(e){return e!==n?e:null}):r=e.map(this.tabs,function(e,t){return t!==n?t:null})),this._setupDisabled(r)},disable:function(n){var r=this.options.disabled;if(r===!0)return;if(n===t)r=!0;else{n=this._getIndex(n);if(e.inArray(n,r)!==-1)return;e.isArray(r)?r=e.merge([n],r).sort():r=[n]}this._setupDisabled(r)},load:function(t,n){t=this._getIndex(t);var r=this,i=this.tabs.eq(t),o=i.find(".ui-tabs-anchor"),u=this._getPanelForTab(i),a={tab:i,panel:u};if(s(o[0]))return;this.xhr=e.ajax(this._ajaxSettings(o,n,a)),this.xhr&&this.xhr.statusText!=="canceled"&&(i.addClass("ui-tabs-loading"),u.attr("aria-busy","true"),this.xhr.success(function(e){setTimeout(function(){u.html(e),r._trigger("load",n,a)},1)}).complete(function(e,t){setTimeout(function(){t==="abort"&&r.panels.stop(!1,!0),i.removeClass("ui-tabs-loading"),u.removeAttr("aria-busy"),e===r.xhr&&delete r.xhr},1)}))},_ajaxSettings:function(t,n,r){var i=this;return{url:t.attr("href"),beforeSend:function(t,s){return i._trigger("beforeLoad",n,e.extend({jqXHR:t,ajaxSettings:s},r))}}},_getPanelForTab:function(t){var n=e(t).attr("aria-controls");return this.element.find(this._sanitizeSelector("#"+n))}}),e.uiBackCompat!==!1&&(e.ui.tabs.prototype._ui=function(e,t){return{tab:e,panel:t,index:this.anchors.index(e)}},e.widget("ui.tabs",e.ui.tabs,{url:function(e,t){this.anchors.eq(e).attr("href",t)}}),e.widget("ui.tabs",e.ui.tabs,{options:{ajaxOptions:null,cache:!1},_create:function(){this._super();var t=this;this._on({tabsbeforeload:function(n,r){if(e.data(r.tab[0],"cache.tabs")){n.preventDefault();return}r.jqXHR.success(function(){t.options.cache&&e.data(r.tab[0],"cache.tabs",!0)})}})},_ajaxSettings:function(t,n,r){var i=this.options.ajaxOptions;return e.extend({},i,{error:function(e,t){try{i.error(e,t,r.tab.closest("li").index(),r.tab[0])}catch(n){}}},this._superApply(arguments))},_setOption:function(e,t){e==="cache"&&t===!1&&this.anchors.removeData("cache.tabs"),this._super(e,t)},_destroy:function(){this.anchors.removeData("cache.tabs"),this._super()},url:function(e){this.anchors.eq(e).removeData("cache.tabs"),this._superApply(arguments)}}),e.widget("ui.tabs",e.ui.tabs,{abort:function(){this.xhr&&this.xhr.abort()}}),e.widget("ui.tabs",e.ui.tabs,{options:{spinner:"<em>Loading…</em>"},_create:function(){this._super(),this._on({tabsbeforeload:function(e,t){if(e.target!==this.element[0]||!this.options.spinner)return;var n=t.tab.find("span"),r=n.html();n.html(this.options.spinner),t.jqXHR.complete(function(){n.html(r)})}})}}),e.widget("ui.tabs",e.ui.tabs,{options:{enable:null,disable:null},enable:function(t){var n=this.options,r;if(t&&n.disabled===!0||e.isArray(n.disabled)&&e.inArray(t,n.disabled)!==-1)r=!0;this._superApply(arguments),r&&this._trigger("enable",null,this._ui(this.anchors[t],this.panels[t]))},disable:function(t){var n=this.options,r;if(t&&n.disabled===!1||e.isArray(n.disabled)&&e.inArray(t,n.disabled)===-1)r=!0;this._superApply(arguments),r&&this._trigger("disable",null,this._ui(this.anchors[t],this.panels[t]))}}),e.widget("ui.tabs",e.ui.tabs,{options:{add:null,remove:null,tabTemplate:"<li><a href='#{href}'><span>#{label}</span></a></li>"},add:function(n,r,i){i===t&&(i=this.anchors.length);var s,o,u=this.options,a=e(u.tabTemplate.replace(/#\{href\}/g,n).replace(/#\{label\}/g,r)),f=n.indexOf("#")?this._tabId(a):n.replace("#","");return a.addClass("ui-state-default ui-corner-top").data("ui-tabs-destroy",!0),a.attr("aria-controls",f),s=i>=this.tabs.length,o=this.element.find("#"+f),o.length||(o=this._createPanel(f),s?i>0?o.insertAfter(this.panels.eq(-1)):o.appendTo(this.element):o.insertBefore(this.panels[i])),o.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom").hide(),s?a.appendTo(this.tablist):a.insertBefore(this.tabs[i]),u.disabled=e.map(u.disabled,function(e){return e>=i?++e:e}),this.refresh(),this.tabs.length===1&&u.active===!1&&this.option("active",0),this._trigger("add",null,this._ui(this.anchors[i],this.panels[i])),this},remove:function(t){t=this._getIndex(t);var n=this.options,r=this.tabs.eq(t).remove(),i=this._getPanelForTab(r).remove();return r.hasClass("ui-tabs-active")&&this.anchors.length>2&&this._activate(t+(t+1<this.anchors.length?1:-1)),n.disabled=e.map(e.grep(n.disabled,function(e){return e!==t}),function(e){return e>=t?--e:e}),this.refresh(),this._trigger("remove",null,this._ui(r.find("a")[0],i[0])),this}}),e.widget("ui.tabs",e.ui.tabs,{length:function(){return this.anchors.length}}),e.widget("ui.tabs",e.ui.tabs,{options:{idPrefix:"ui-tabs-"},_tabId:function(t){var n=t.is("li")?t.find("a[href]"):t;return n=n[0],e(n).closest("li").attr("aria-controls")||n.title&&n.title.replace(/\s/g,"_").replace(/[^\w\u00c0-\uFFFF\-]/g,"")||this.options.idPrefix+i()}}),e.widget("ui.tabs",e.ui.tabs,{options:{panelTemplate:"<div></div>"},_createPanel:function(t){return e(this.options.panelTemplate).attr("id",t).addClass("ui-tabs-panel ui-widget-content ui-corner-bottom").data("ui-tabs-destroy",!0)}}),e.widget("ui.tabs",e.ui.tabs,{_create:function(){var e=this.options;e.active===null&&e.selected!==t&&(e.active=e.selected===-1?!1:e.selected),this._super(),e.selected=e.active,e.selected===!1&&(e.selected=-1)},_setOption:function(e,t){if(e!=="selected")return this._super(e,t);var n=this.options;this._super("active",t===-1?!1:t),n.selected=n.active,n.selected===!1&&(n.selected=-1)},_eventHandler:function(){this._superApply(arguments),this.options.selected=this.options.active,this.options.selected===!1&&(this.options.selected=-1)}}),e.widget("ui.tabs",e.ui.tabs,{options:{show:null,select:null},_create:function(){this._super(),this.options.active!==!1&&this._trigger("show",null,this._ui(this.active.find(".ui-tabs-anchor")[0],this._getPanelForTab(this.active)[0]))},_trigger:function(e,t,n){var r,i,s=this._superApply(arguments);return s?(e==="beforeActivate"?(r=n.newTab.length?n.newTab:n.oldTab,i=n.newPanel.length?n.newPanel:n.oldPanel,s=this._super("select",t,{tab:r.find(".ui-tabs-anchor")[0],panel:i[0],index:r.closest("li").index()})):e==="activate"&&n.newTab.length&&(s=this._super("show",t,{tab:n.newTab.find(".ui-tabs-anchor")[0],panel:n.newPanel[0],index:n.newTab.closest("li").index()})),s):!1}}),e.widget("ui.tabs",e.ui.tabs,{select:function(e){e=this._getIndex(e);if(e===-1){if(!this.options.collapsible||this.options.selected===-1)return;e=this.options.selected}this.anchors.eq(e).trigger(this.options.event+this.eventNamespace)}}),function(){var t=0;e.widget("ui.tabs",e.ui.tabs,{options:{cookie:null},_create:function(){var e=this.options,t;e.active==null&&e.cookie&&(t=parseInt(this._cookie(),10),t===-1&&(t=!1),e.active=t),this._super()},_cookie:function(n){var r=[this.cookie||(this.cookie=this.options.cookie.name||"ui-tabs-"+ ++t)];return arguments.length&&(r.push(n===!1?-1:n),r.push(this.options.cookie)),e.cookie.apply(null,r)},_refresh:function(){this._super(),this.options.cookie&&this._cookie(this.options.active,this.options.cookie)},_eventHandler:function(){this._superApply(arguments),this.options.cookie&&this._cookie(this.options.active,this.options.cookie)},_destroy:function(){this._super(),this.options.cookie&&this._cookie(null,this.options.cookie)}})}(),e.widget("ui.tabs",e.ui.tabs,{_trigger:function(t,n,r){var i=e.extend({},r);return t==="load"&&(i.panel=i.panel[0],i.tab=i.tab.find(".ui-tabs-anchor")[0]),this._super(t,n,i)}}),e.widget("ui.tabs",e.ui.tabs,{options:{fx:null},_getFx:function(){var t,n,r=this.options.fx;return r&&(e.isArray(r)?(t=r[0],n=r[1]):t=n=r),r?{show:n,hide:t}:null},_toggle:function(e,t){function o(){n.running=!1,n._trigger("activate",e,t)}function u(){t.newTab.closest("li").addClass("ui-tabs-active ui-state-active"),r.length&&s.show?r.animate(s.show,s.show.duration,function(){o()}):(r.show(),o())}var n=this,r=t.newPanel,i=t.oldPanel,s=this._getFx();if(!s)return this._super(e,t);n.running=!0,i.length&&s.hide?i.animate(s.hide,s.hide.duration,function(){t.oldTab.closest("li").removeClass("ui-tabs-active ui-state-active"),u()}):(t.oldTab.closest("li").removeClass("ui-tabs-active ui-state-active"),i.hide(),u())}}))}(jQuery),function(e){function n(t,n){var r=(t.attr("aria-describedby")||"").split(/\s+/);r.push(n),t.data("ui-tooltip-id",n).attr("aria-describedby",e.trim(r.join(" ")))}function r(t){var n=t.data("ui-tooltip-id"),r=(t.attr("aria-describedby")||"").split(/\s+/),i=e.inArray(n,r);i!==-1&&r.splice(i,1),t.removeData("ui-tooltip-id"),r=e.trim(r.join(" ")),r?t.attr("aria-describedby",r):t.removeAttr("aria-describedby")}var t=0;e.widget("ui.tooltip",{version:"1.9.2",options:{content:function(){return e(this).attr("title")},hide:!0,items:"[title]:not([disabled])",position:{my:"left top+15",at:"left bottom",collision:"flipfit flip"},show:!0,tooltipClass:null,track:!1,close:null,open:null},_create:function(){this._on({mouseover:"open",focusin:"open"}),this.tooltips={},this.parents={},this.options.disabled&&this._disable()},_setOption:function(t,n){var r=this;if(t==="disabled"){this[n?"_disable":"_enable"](),this.options[t]=n;return}this._super(t,n),t==="content"&&e.each(this.tooltips,function(e,t){r._updateContent(t)})},_disable:function(){var t=this;e.each(this.tooltips,function(n,r){var i=e.Event("blur");i.target=i.currentTarget=r[0],t.close(i,!0)}),this.element.find(this.options.items).andSelf().each(function(){var t=e(this);t.is("[title]")&&t.data("ui-tooltip-title",t.attr("title")).attr("title","")})},_enable:function(){this.element.find(this.options.items).andSelf().each(function(){var t=e(this);t.data("ui-tooltip-title")&&t.attr("title",t.data("ui-tooltip-title"))})},open:function(t){var n=this,r=e(t?t.target:this.element).closest(this.options.items);if(!r.length||r.data("ui-tooltip-id"))return;r.attr("title")&&r.data("ui-tooltip-title",r.attr("title")),r.data("ui-tooltip-open",!0),t&&t.type==="mouseover"&&r.parents().each(function(){var t=e(this),r;t.data("ui-tooltip-open")&&(r=e.Event("blur"),r.target=r.currentTarget=this,n.close(r,!0)),t.attr("title")&&(t.uniqueId(),n.parents[this.id]={element:this,title:t.attr("title")},t.attr("title",""))}),this._updateContent(r,t)},_updateContent:function(e,t){var n,r=this.options.content,i=this,s=t?t.type:null;if(typeof r=="string")return this._open(t,e,r);n=r.call(e[0],function(n){if(!e.data("ui-tooltip-open"))return;i._delay(function(){t&&(t.type=s),this._open(t,e,n)})}),n&&this._open(t,e,n)},_open:function(t,r,i){function f(e){a.of=e;if(s.is(":hidden"))return;s.position(a)}var s,o,u,a=e.extend({},this.options.position);if(!i)return;s=this._find(r);if(s.length){s.find(".ui-tooltip-content").html(i);return}r.is("[title]")&&(t&&t.type==="mouseover"?r.attr("title",""):r.removeAttr("title")),s=this._tooltip(r),n(r,s.attr("id")),s.find(".ui-tooltip-content").html(i),this.options.track&&t&&/^mouse/.test(t.type)?(this._on(this.document,{mousemove:f}),f(t)):s.position(e.extend({of:r},this.options.position)),s.hide(),this._show(s,this.options.show),this.options.show&&this.options.show.delay&&(u=setInterval(function(){s.is(":visible")&&(f(a.of),clearInterval(u))},e.fx.interval)),this._trigger("open",t,{tooltip:s}),o={keyup:function(t){if(t.keyCode===e.ui.keyCode.ESCAPE){var n=e.Event(t);n.currentTarget=r[0],this.close(n,!0)}},remove:function(){this._removeTooltip(s)}};if(!t||t.type==="mouseover")o.mouseleave="close";if(!t||t.type==="focusin")o.focusout="close";this._on(!0,r,o)},close:function(t){var n=this,i=e(t?t.currentTarget:this.element),s=this._find(i);if(this.closing)return;i.data("ui-tooltip-title")&&i.attr("title",i.data("ui-tooltip-title")),r(i),s.stop(!0),this._hide(s,this.options.hide,function(){n._removeTooltip(e(this))}),i.removeData("ui-tooltip-open"),this._off(i,"mouseleave focusout keyup"),i[0]!==this.element[0]&&this._off(i,"remove"),this._off(this.document,"mousemove"),t&&t.type==="mouseleave"&&e.each(this.parents,function(t,r){e(r.element).attr("title",r.title),delete n.parents[t]}),this.closing=!0,this._trigger("close",t,{tooltip:s}),this.closing=!1},_tooltip:function(n){var r="ui-tooltip-"+t++,i=e("<div>").attr({id:r,role:"tooltip"}).addClass("ui-tooltip ui-widget ui-corner-all ui-widget-content "+(this.options.tooltipClass||""));return e("<div>").addClass("ui-tooltip-content").appendTo(i),i.appendTo(this.document[0].body),e.fn.bgiframe&&i.bgiframe(),this.tooltips[r]=n,i},_find:function(t){var n=t.data("ui-tooltip-id");return n?e("#"+n):e()},_removeTooltip:function(e){e.remove(),delete this.tooltips[e.attr("id")]},_destroy:function(){var t=this;e.each(this.tooltips,function(n,r){var i=e.Event("blur");i.target=i.currentTarget=r[0],t.close(i,!0),e("#"+n).remove(),r.data("ui-tooltip-title")&&(r.attr("title",r.data("ui-tooltip-title")),r.removeData("ui-tooltip-title"))})}})}(jQuery); \ No newline at end of file +* Copyright 2013 jQuery Foundation and other contributors; Licensed MIT */ +(function(t,e){function i(e,i){var n,o,a,r=e.nodeName.toLowerCase();return"area"===r?(n=e.parentNode,o=n.name,e.href&&o&&"map"===n.nodeName.toLowerCase()?(a=t("img[usemap=#"+o+"]")[0],!!a&&s(a)):!1):(/input|select|textarea|button|object/.test(r)?!e.disabled:"a"===r?e.href||i:i)&&s(e)}function s(e){return t.expr.filters.visible(e)&&!t(e).parents().addBack().filter(function(){return"hidden"===t.css(this,"visibility")}).length}var n=0,o=/^ui-id-\d+$/;t.ui=t.ui||{},t.extend(t.ui,{version:"1.10.2",keyCode:{BACKSPACE:8,COMMA:188,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,LEFT:37,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SPACE:32,TAB:9,UP:38}}),t.fn.extend({focus:function(e){return function(i,s){return"number"==typeof i?this.each(function(){var e=this;setTimeout(function(){t(e).focus(),s&&s.call(e)},i)}):e.apply(this,arguments)}}(t.fn.focus),scrollParent:function(){var e;return e=t.ui.ie&&/(static|relative)/.test(this.css("position"))||/absolute/.test(this.css("position"))?this.parents().filter(function(){return/(relative|absolute|fixed)/.test(t.css(this,"position"))&&/(auto|scroll)/.test(t.css(this,"overflow")+t.css(this,"overflow-y")+t.css(this,"overflow-x"))}).eq(0):this.parents().filter(function(){return/(auto|scroll)/.test(t.css(this,"overflow")+t.css(this,"overflow-y")+t.css(this,"overflow-x"))}).eq(0),/fixed/.test(this.css("position"))||!e.length?t(document):e},zIndex:function(i){if(i!==e)return this.css("zIndex",i);if(this.length)for(var s,n,o=t(this[0]);o.length&&o[0]!==document;){if(s=o.css("position"),("absolute"===s||"relative"===s||"fixed"===s)&&(n=parseInt(o.css("zIndex"),10),!isNaN(n)&&0!==n))return n;o=o.parent()}return 0},uniqueId:function(){return this.each(function(){this.id||(this.id="ui-id-"+ ++n)})},removeUniqueId:function(){return this.each(function(){o.test(this.id)&&t(this).removeAttr("id")})}}),t.extend(t.expr[":"],{data:t.expr.createPseudo?t.expr.createPseudo(function(e){return function(i){return!!t.data(i,e)}}):function(e,i,s){return!!t.data(e,s[3])},focusable:function(e){return i(e,!isNaN(t.attr(e,"tabindex")))},tabbable:function(e){var s=t.attr(e,"tabindex"),n=isNaN(s);return(n||s>=0)&&i(e,!n)}}),t("<a>").outerWidth(1).jquery||t.each(["Width","Height"],function(i,s){function n(e,i,s,n){return t.each(o,function(){i-=parseFloat(t.css(e,"padding"+this))||0,s&&(i-=parseFloat(t.css(e,"border"+this+"Width"))||0),n&&(i-=parseFloat(t.css(e,"margin"+this))||0)}),i}var o="Width"===s?["Left","Right"]:["Top","Bottom"],a=s.toLowerCase(),r={innerWidth:t.fn.innerWidth,innerHeight:t.fn.innerHeight,outerWidth:t.fn.outerWidth,outerHeight:t.fn.outerHeight};t.fn["inner"+s]=function(i){return i===e?r["inner"+s].call(this):this.each(function(){t(this).css(a,n(this,i)+"px")})},t.fn["outer"+s]=function(e,i){return"number"!=typeof e?r["outer"+s].call(this,e):this.each(function(){t(this).css(a,n(this,e,!0,i)+"px")})}}),t.fn.addBack||(t.fn.addBack=function(t){return this.add(null==t?this.prevObject:this.prevObject.filter(t))}),t("<a>").data("a-b","a").removeData("a-b").data("a-b")&&(t.fn.removeData=function(e){return function(i){return arguments.length?e.call(this,t.camelCase(i)):e.call(this)}}(t.fn.removeData)),t.ui.ie=!!/msie [\w.]+/.exec(navigator.userAgent.toLowerCase()),t.support.selectstart="onselectstart"in document.createElement("div"),t.fn.extend({disableSelection:function(){return this.bind((t.support.selectstart?"selectstart":"mousedown")+".ui-disableSelection",function(t){t.preventDefault()})},enableSelection:function(){return this.unbind(".ui-disableSelection")}}),t.extend(t.ui,{plugin:{add:function(e,i,s){var n,o=t.ui[e].prototype;for(n in s)o.plugins[n]=o.plugins[n]||[],o.plugins[n].push([i,s[n]])},call:function(t,e,i){var s,n=t.plugins[e];if(n&&t.element[0].parentNode&&11!==t.element[0].parentNode.nodeType)for(s=0;n.length>s;s++)t.options[n[s][0]]&&n[s][1].apply(t.element,i)}},hasScroll:function(e,i){if("hidden"===t(e).css("overflow"))return!1;var s=i&&"left"===i?"scrollLeft":"scrollTop",n=!1;return e[s]>0?!0:(e[s]=1,n=e[s]>0,e[s]=0,n)}})})(jQuery),function(t,e){var i=0,s=Array.prototype.slice,n=t.cleanData;t.cleanData=function(e){for(var i,s=0;null!=(i=e[s]);s++)try{t(i).triggerHandler("remove")}catch(o){}n(e)},t.widget=function(i,s,n){var o,a,r,h,l={},c=i.split(".")[0];i=i.split(".")[1],o=c+"-"+i,n||(n=s,s=t.Widget),t.expr[":"][o.toLowerCase()]=function(e){return!!t.data(e,o)},t[c]=t[c]||{},a=t[c][i],r=t[c][i]=function(t,i){return this._createWidget?(arguments.length&&this._createWidget(t,i),e):new r(t,i)},t.extend(r,a,{version:n.version,_proto:t.extend({},n),_childConstructors:[]}),h=new s,h.options=t.widget.extend({},h.options),t.each(n,function(i,n){return t.isFunction(n)?(l[i]=function(){var t=function(){return s.prototype[i].apply(this,arguments)},e=function(t){return s.prototype[i].apply(this,t)};return function(){var i,s=this._super,o=this._superApply;return this._super=t,this._superApply=e,i=n.apply(this,arguments),this._super=s,this._superApply=o,i}}(),e):(l[i]=n,e)}),r.prototype=t.widget.extend(h,{widgetEventPrefix:a?h.widgetEventPrefix:i},l,{constructor:r,namespace:c,widgetName:i,widgetFullName:o}),a?(t.each(a._childConstructors,function(e,i){var s=i.prototype;t.widget(s.namespace+"."+s.widgetName,r,i._proto)}),delete a._childConstructors):s._childConstructors.push(r),t.widget.bridge(i,r)},t.widget.extend=function(i){for(var n,o,a=s.call(arguments,1),r=0,h=a.length;h>r;r++)for(n in a[r])o=a[r][n],a[r].hasOwnProperty(n)&&o!==e&&(i[n]=t.isPlainObject(o)?t.isPlainObject(i[n])?t.widget.extend({},i[n],o):t.widget.extend({},o):o);return i},t.widget.bridge=function(i,n){var o=n.prototype.widgetFullName||i;t.fn[i]=function(a){var r="string"==typeof a,h=s.call(arguments,1),l=this;return a=!r&&h.length?t.widget.extend.apply(null,[a].concat(h)):a,r?this.each(function(){var s,n=t.data(this,o);return n?t.isFunction(n[a])&&"_"!==a.charAt(0)?(s=n[a].apply(n,h),s!==n&&s!==e?(l=s&&s.jquery?l.pushStack(s.get()):s,!1):e):t.error("no such method '"+a+"' for "+i+" widget instance"):t.error("cannot call methods on "+i+" prior to initialization; "+"attempted to call method '"+a+"'")}):this.each(function(){var e=t.data(this,o);e?e.option(a||{})._init():t.data(this,o,new n(a,this))}),l}},t.Widget=function(){},t.Widget._childConstructors=[],t.Widget.prototype={widgetName:"widget",widgetEventPrefix:"",defaultElement:"<div>",options:{disabled:!1,create:null},_createWidget:function(e,s){s=t(s||this.defaultElement||this)[0],this.element=t(s),this.uuid=i++,this.eventNamespace="."+this.widgetName+this.uuid,this.options=t.widget.extend({},this.options,this._getCreateOptions(),e),this.bindings=t(),this.hoverable=t(),this.focusable=t(),s!==this&&(t.data(s,this.widgetFullName,this),this._on(!0,this.element,{remove:function(t){t.target===s&&this.destroy()}}),this.document=t(s.style?s.ownerDocument:s.document||s),this.window=t(this.document[0].defaultView||this.document[0].parentWindow)),this._create(),this._trigger("create",null,this._getCreateEventData()),this._init()},_getCreateOptions:t.noop,_getCreateEventData:t.noop,_create:t.noop,_init:t.noop,destroy:function(){this._destroy(),this.element.unbind(this.eventNamespace).removeData(this.widgetName).removeData(this.widgetFullName).removeData(t.camelCase(this.widgetFullName)),this.widget().unbind(this.eventNamespace).removeAttr("aria-disabled").removeClass(this.widgetFullName+"-disabled "+"ui-state-disabled"),this.bindings.unbind(this.eventNamespace),this.hoverable.removeClass("ui-state-hover"),this.focusable.removeClass("ui-state-focus")},_destroy:t.noop,widget:function(){return this.element},option:function(i,s){var n,o,a,r=i;if(0===arguments.length)return t.widget.extend({},this.options);if("string"==typeof i)if(r={},n=i.split("."),i=n.shift(),n.length){for(o=r[i]=t.widget.extend({},this.options[i]),a=0;n.length-1>a;a++)o[n[a]]=o[n[a]]||{},o=o[n[a]];if(i=n.pop(),s===e)return o[i]===e?null:o[i];o[i]=s}else{if(s===e)return this.options[i]===e?null:this.options[i];r[i]=s}return this._setOptions(r),this},_setOptions:function(t){var e;for(e in t)this._setOption(e,t[e]);return this},_setOption:function(t,e){return this.options[t]=e,"disabled"===t&&(this.widget().toggleClass(this.widgetFullName+"-disabled ui-state-disabled",!!e).attr("aria-disabled",e),this.hoverable.removeClass("ui-state-hover"),this.focusable.removeClass("ui-state-focus")),this},enable:function(){return this._setOption("disabled",!1)},disable:function(){return this._setOption("disabled",!0)},_on:function(i,s,n){var o,a=this;"boolean"!=typeof i&&(n=s,s=i,i=!1),n?(s=o=t(s),this.bindings=this.bindings.add(s)):(n=s,s=this.element,o=this.widget()),t.each(n,function(n,r){function h(){return i||a.options.disabled!==!0&&!t(this).hasClass("ui-state-disabled")?("string"==typeof r?a[r]:r).apply(a,arguments):e}"string"!=typeof r&&(h.guid=r.guid=r.guid||h.guid||t.guid++);var l=n.match(/^(\w+)\s*(.*)$/),c=l[1]+a.eventNamespace,u=l[2];u?o.delegate(u,c,h):s.bind(c,h)})},_off:function(t,e){e=(e||"").split(" ").join(this.eventNamespace+" ")+this.eventNamespace,t.unbind(e).undelegate(e)},_delay:function(t,e){function i(){return("string"==typeof t?s[t]:t).apply(s,arguments)}var s=this;return setTimeout(i,e||0)},_hoverable:function(e){this.hoverable=this.hoverable.add(e),this._on(e,{mouseenter:function(e){t(e.currentTarget).addClass("ui-state-hover")},mouseleave:function(e){t(e.currentTarget).removeClass("ui-state-hover")}})},_focusable:function(e){this.focusable=this.focusable.add(e),this._on(e,{focusin:function(e){t(e.currentTarget).addClass("ui-state-focus")},focusout:function(e){t(e.currentTarget).removeClass("ui-state-focus")}})},_trigger:function(e,i,s){var n,o,a=this.options[e];if(s=s||{},i=t.Event(i),i.type=(e===this.widgetEventPrefix?e:this.widgetEventPrefix+e).toLowerCase(),i.target=this.element[0],o=i.originalEvent)for(n in o)n in i||(i[n]=o[n]);return this.element.trigger(i,s),!(t.isFunction(a)&&a.apply(this.element[0],[i].concat(s))===!1||i.isDefaultPrevented())}},t.each({show:"fadeIn",hide:"fadeOut"},function(e,i){t.Widget.prototype["_"+e]=function(s,n,o){"string"==typeof n&&(n={effect:n});var a,r=n?n===!0||"number"==typeof n?i:n.effect||i:e;n=n||{},"number"==typeof n&&(n={duration:n}),a=!t.isEmptyObject(n),n.complete=o,n.delay&&s.delay(n.delay),a&&t.effects&&t.effects.effect[r]?s[e](n):r!==e&&s[r]?s[r](n.duration,n.easing,o):s.queue(function(i){t(this)[e](),o&&o.call(s[0]),i()})}})}(jQuery),function(t){var e=!1;t(document).mouseup(function(){e=!1}),t.widget("ui.mouse",{version:"1.10.2",options:{cancel:"input,textarea,button,select,option",distance:1,delay:0},_mouseInit:function(){var e=this;this.element.bind("mousedown."+this.widgetName,function(t){return e._mouseDown(t)}).bind("click."+this.widgetName,function(i){return!0===t.data(i.target,e.widgetName+".preventClickEvent")?(t.removeData(i.target,e.widgetName+".preventClickEvent"),i.stopImmediatePropagation(),!1):undefined}),this.started=!1},_mouseDestroy:function(){this.element.unbind("."+this.widgetName),this._mouseMoveDelegate&&t(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate)},_mouseDown:function(i){if(!e){this._mouseStarted&&this._mouseUp(i),this._mouseDownEvent=i;var s=this,n=1===i.which,o="string"==typeof this.options.cancel&&i.target.nodeName?t(i.target).closest(this.options.cancel).length:!1;return n&&!o&&this._mouseCapture(i)?(this.mouseDelayMet=!this.options.delay,this.mouseDelayMet||(this._mouseDelayTimer=setTimeout(function(){s.mouseDelayMet=!0},this.options.delay)),this._mouseDistanceMet(i)&&this._mouseDelayMet(i)&&(this._mouseStarted=this._mouseStart(i)!==!1,!this._mouseStarted)?(i.preventDefault(),!0):(!0===t.data(i.target,this.widgetName+".preventClickEvent")&&t.removeData(i.target,this.widgetName+".preventClickEvent"),this._mouseMoveDelegate=function(t){return s._mouseMove(t)},this._mouseUpDelegate=function(t){return s._mouseUp(t)},t(document).bind("mousemove."+this.widgetName,this._mouseMoveDelegate).bind("mouseup."+this.widgetName,this._mouseUpDelegate),i.preventDefault(),e=!0,!0)):!0}},_mouseMove:function(e){return t.ui.ie&&(!document.documentMode||9>document.documentMode)&&!e.button?this._mouseUp(e):this._mouseStarted?(this._mouseDrag(e),e.preventDefault()):(this._mouseDistanceMet(e)&&this._mouseDelayMet(e)&&(this._mouseStarted=this._mouseStart(this._mouseDownEvent,e)!==!1,this._mouseStarted?this._mouseDrag(e):this._mouseUp(e)),!this._mouseStarted)},_mouseUp:function(e){return t(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate),this._mouseStarted&&(this._mouseStarted=!1,e.target===this._mouseDownEvent.target&&t.data(e.target,this.widgetName+".preventClickEvent",!0),this._mouseStop(e)),!1},_mouseDistanceMet:function(t){return Math.max(Math.abs(this._mouseDownEvent.pageX-t.pageX),Math.abs(this._mouseDownEvent.pageY-t.pageY))>=this.options.distance},_mouseDelayMet:function(){return this.mouseDelayMet},_mouseStart:function(){},_mouseDrag:function(){},_mouseStop:function(){},_mouseCapture:function(){return!0}})}(jQuery),function(t){t.widget("ui.draggable",t.ui.mouse,{version:"1.10.2",widgetEventPrefix:"drag",options:{addClasses:!0,appendTo:"parent",axis:!1,connectToSortable:!1,containment:!1,cursor:"auto",cursorAt:!1,grid:!1,handle:!1,helper:"original",iframeFix:!1,opacity:!1,refreshPositions:!1,revert:!1,revertDuration:500,scope:"default",scroll:!0,scrollSensitivity:20,scrollSpeed:20,snap:!1,snapMode:"both",snapTolerance:20,stack:!1,zIndex:!1,drag:null,start:null,stop:null},_create:function(){"original"!==this.options.helper||/^(?:r|a|f)/.test(this.element.css("position"))||(this.element[0].style.position="relative"),this.options.addClasses&&this.element.addClass("ui-draggable"),this.options.disabled&&this.element.addClass("ui-draggable-disabled"),this._mouseInit()},_destroy:function(){this.element.removeClass("ui-draggable ui-draggable-dragging ui-draggable-disabled"),this._mouseDestroy()},_mouseCapture:function(e){var i=this.options;return this.helper||i.disabled||t(e.target).closest(".ui-resizable-handle").length>0?!1:(this.handle=this._getHandle(e),this.handle?(t(i.iframeFix===!0?"iframe":i.iframeFix).each(function(){t("<div class='ui-draggable-iframeFix' style='background: #fff;'></div>").css({width:this.offsetWidth+"px",height:this.offsetHeight+"px",position:"absolute",opacity:"0.001",zIndex:1e3}).css(t(this).offset()).appendTo("body")}),!0):!1)},_mouseStart:function(e){var i=this.options;return this.helper=this._createHelper(e),this.helper.addClass("ui-draggable-dragging"),this._cacheHelperProportions(),t.ui.ddmanager&&(t.ui.ddmanager.current=this),this._cacheMargins(),this.cssPosition=this.helper.css("position"),this.scrollParent=this.helper.scrollParent(),this.offset=this.positionAbs=this.element.offset(),this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left},t.extend(this.offset,{click:{left:e.pageX-this.offset.left,top:e.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()}),this.originalPosition=this.position=this._generatePosition(e),this.originalPageX=e.pageX,this.originalPageY=e.pageY,i.cursorAt&&this._adjustOffsetFromHelper(i.cursorAt),i.containment&&this._setContainment(),this._trigger("start",e)===!1?(this._clear(),!1):(this._cacheHelperProportions(),t.ui.ddmanager&&!i.dropBehaviour&&t.ui.ddmanager.prepareOffsets(this,e),this._mouseDrag(e,!0),t.ui.ddmanager&&t.ui.ddmanager.dragStart(this,e),!0)},_mouseDrag:function(e,i){if(this.position=this._generatePosition(e),this.positionAbs=this._convertPositionTo("absolute"),!i){var s=this._uiHash();if(this._trigger("drag",e,s)===!1)return this._mouseUp({}),!1;this.position=s.position}return this.options.axis&&"y"===this.options.axis||(this.helper[0].style.left=this.position.left+"px"),this.options.axis&&"x"===this.options.axis||(this.helper[0].style.top=this.position.top+"px"),t.ui.ddmanager&&t.ui.ddmanager.drag(this,e),!1},_mouseStop:function(e){var i,s=this,n=!1,o=!1;for(t.ui.ddmanager&&!this.options.dropBehaviour&&(o=t.ui.ddmanager.drop(this,e)),this.dropped&&(o=this.dropped,this.dropped=!1),i=this.element[0];i&&(i=i.parentNode);)i===document&&(n=!0);return n||"original"!==this.options.helper?("invalid"===this.options.revert&&!o||"valid"===this.options.revert&&o||this.options.revert===!0||t.isFunction(this.options.revert)&&this.options.revert.call(this.element,o)?t(this.helper).animate(this.originalPosition,parseInt(this.options.revertDuration,10),function(){s._trigger("stop",e)!==!1&&s._clear()}):this._trigger("stop",e)!==!1&&this._clear(),!1):!1},_mouseUp:function(e){return t("div.ui-draggable-iframeFix").each(function(){this.parentNode.removeChild(this)}),t.ui.ddmanager&&t.ui.ddmanager.dragStop(this,e),t.ui.mouse.prototype._mouseUp.call(this,e)},cancel:function(){return this.helper.is(".ui-draggable-dragging")?this._mouseUp({}):this._clear(),this},_getHandle:function(e){return this.options.handle?!!t(e.target).closest(this.element.find(this.options.handle)).length:!0},_createHelper:function(e){var i=this.options,s=t.isFunction(i.helper)?t(i.helper.apply(this.element[0],[e])):"clone"===i.helper?this.element.clone().removeAttr("id"):this.element;return s.parents("body").length||s.appendTo("parent"===i.appendTo?this.element[0].parentNode:i.appendTo),s[0]===this.element[0]||/(fixed|absolute)/.test(s.css("position"))||s.css("position","absolute"),s},_adjustOffsetFromHelper:function(e){"string"==typeof e&&(e=e.split(" ")),t.isArray(e)&&(e={left:+e[0],top:+e[1]||0}),"left"in e&&(this.offset.click.left=e.left+this.margins.left),"right"in e&&(this.offset.click.left=this.helperProportions.width-e.right+this.margins.left),"top"in e&&(this.offset.click.top=e.top+this.margins.top),"bottom"in e&&(this.offset.click.top=this.helperProportions.height-e.bottom+this.margins.top)},_getParentOffset:function(){this.offsetParent=this.helper.offsetParent();var e=this.offsetParent.offset();return"absolute"===this.cssPosition&&this.scrollParent[0]!==document&&t.contains(this.scrollParent[0],this.offsetParent[0])&&(e.left+=this.scrollParent.scrollLeft(),e.top+=this.scrollParent.scrollTop()),(this.offsetParent[0]===document.body||this.offsetParent[0].tagName&&"html"===this.offsetParent[0].tagName.toLowerCase()&&t.ui.ie)&&(e={top:0,left:0}),{top:e.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:e.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if("relative"===this.cssPosition){var t=this.element.position();return{top:t.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:t.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.element.css("marginLeft"),10)||0,top:parseInt(this.element.css("marginTop"),10)||0,right:parseInt(this.element.css("marginRight"),10)||0,bottom:parseInt(this.element.css("marginBottom"),10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var e,i,s,n=this.options;if("parent"===n.containment&&(n.containment=this.helper[0].parentNode),("document"===n.containment||"window"===n.containment)&&(this.containment=["document"===n.containment?0:t(window).scrollLeft()-this.offset.relative.left-this.offset.parent.left,"document"===n.containment?0:t(window).scrollTop()-this.offset.relative.top-this.offset.parent.top,("document"===n.containment?0:t(window).scrollLeft())+t("document"===n.containment?document:window).width()-this.helperProportions.width-this.margins.left,("document"===n.containment?0:t(window).scrollTop())+(t("document"===n.containment?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top]),/^(document|window|parent)$/.test(n.containment)||n.containment.constructor===Array)n.containment.constructor===Array&&(this.containment=n.containment);else{if(i=t(n.containment),s=i[0],!s)return;e="hidden"!==t(s).css("overflow"),this.containment=[(parseInt(t(s).css("borderLeftWidth"),10)||0)+(parseInt(t(s).css("paddingLeft"),10)||0),(parseInt(t(s).css("borderTopWidth"),10)||0)+(parseInt(t(s).css("paddingTop"),10)||0),(e?Math.max(s.scrollWidth,s.offsetWidth):s.offsetWidth)-(parseInt(t(s).css("borderRightWidth"),10)||0)-(parseInt(t(s).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left-this.margins.right,(e?Math.max(s.scrollHeight,s.offsetHeight):s.offsetHeight)-(parseInt(t(s).css("borderBottomWidth"),10)||0)-(parseInt(t(s).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top-this.margins.bottom],this.relative_container=i}},_convertPositionTo:function(e,i){i||(i=this.position);var s="absolute"===e?1:-1,n="absolute"!==this.cssPosition||this.scrollParent[0]!==document&&t.contains(this.scrollParent[0],this.offsetParent[0])?this.scrollParent:this.offsetParent,o=/(html|body)/i.test(n[0].tagName);return{top:i.top+this.offset.relative.top*s+this.offset.parent.top*s-("fixed"===this.cssPosition?-this.scrollParent.scrollTop():o?0:n.scrollTop())*s,left:i.left+this.offset.relative.left*s+this.offset.parent.left*s-("fixed"===this.cssPosition?-this.scrollParent.scrollLeft():o?0:n.scrollLeft())*s}},_generatePosition:function(e){var i,s,n,o,a=this.options,r="absolute"!==this.cssPosition||this.scrollParent[0]!==document&&t.contains(this.scrollParent[0],this.offsetParent[0])?this.scrollParent:this.offsetParent,h=/(html|body)/i.test(r[0].tagName),l=e.pageX,c=e.pageY;return this.originalPosition&&(this.containment&&(this.relative_container?(s=this.relative_container.offset(),i=[this.containment[0]+s.left,this.containment[1]+s.top,this.containment[2]+s.left,this.containment[3]+s.top]):i=this.containment,e.pageX-this.offset.click.left<i[0]&&(l=i[0]+this.offset.click.left),e.pageY-this.offset.click.top<i[1]&&(c=i[1]+this.offset.click.top),e.pageX-this.offset.click.left>i[2]&&(l=i[2]+this.offset.click.left),e.pageY-this.offset.click.top>i[3]&&(c=i[3]+this.offset.click.top)),a.grid&&(n=a.grid[1]?this.originalPageY+Math.round((c-this.originalPageY)/a.grid[1])*a.grid[1]:this.originalPageY,c=i?n-this.offset.click.top>=i[1]||n-this.offset.click.top>i[3]?n:n-this.offset.click.top>=i[1]?n-a.grid[1]:n+a.grid[1]:n,o=a.grid[0]?this.originalPageX+Math.round((l-this.originalPageX)/a.grid[0])*a.grid[0]:this.originalPageX,l=i?o-this.offset.click.left>=i[0]||o-this.offset.click.left>i[2]?o:o-this.offset.click.left>=i[0]?o-a.grid[0]:o+a.grid[0]:o)),{top:c-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+("fixed"===this.cssPosition?-this.scrollParent.scrollTop():h?0:r.scrollTop()),left:l-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+("fixed"===this.cssPosition?-this.scrollParent.scrollLeft():h?0:r.scrollLeft())}},_clear:function(){this.helper.removeClass("ui-draggable-dragging"),this.helper[0]===this.element[0]||this.cancelHelperRemoval||this.helper.remove(),this.helper=null,this.cancelHelperRemoval=!1},_trigger:function(e,i,s){return s=s||this._uiHash(),t.ui.plugin.call(this,e,[i,s]),"drag"===e&&(this.positionAbs=this._convertPositionTo("absolute")),t.Widget.prototype._trigger.call(this,e,i,s)},plugins:{},_uiHash:function(){return{helper:this.helper,position:this.position,originalPosition:this.originalPosition,offset:this.positionAbs}}}),t.ui.plugin.add("draggable","connectToSortable",{start:function(e,i){var s=t(this).data("ui-draggable"),n=s.options,o=t.extend({},i,{item:s.element});s.sortables=[],t(n.connectToSortable).each(function(){var i=t.data(this,"ui-sortable");i&&!i.options.disabled&&(s.sortables.push({instance:i,shouldRevert:i.options.revert}),i.refreshPositions(),i._trigger("activate",e,o))})},stop:function(e,i){var s=t(this).data("ui-draggable"),n=t.extend({},i,{item:s.element});t.each(s.sortables,function(){this.instance.isOver?(this.instance.isOver=0,s.cancelHelperRemoval=!0,this.instance.cancelHelperRemoval=!1,this.shouldRevert&&(this.instance.options.revert=this.shouldRevert),this.instance._mouseStop(e),this.instance.options.helper=this.instance.options._helper,"original"===s.options.helper&&this.instance.currentItem.css({top:"auto",left:"auto"})):(this.instance.cancelHelperRemoval=!1,this.instance._trigger("deactivate",e,n))})},drag:function(e,i){var s=t(this).data("ui-draggable"),n=this;t.each(s.sortables,function(){var o=!1,a=this;this.instance.positionAbs=s.positionAbs,this.instance.helperProportions=s.helperProportions,this.instance.offset.click=s.offset.click,this.instance._intersectsWith(this.instance.containerCache)&&(o=!0,t.each(s.sortables,function(){return this.instance.positionAbs=s.positionAbs,this.instance.helperProportions=s.helperProportions,this.instance.offset.click=s.offset.click,this!==a&&this.instance._intersectsWith(this.instance.containerCache)&&t.contains(a.instance.element[0],this.instance.element[0])&&(o=!1),o})),o?(this.instance.isOver||(this.instance.isOver=1,this.instance.currentItem=t(n).clone().removeAttr("id").appendTo(this.instance.element).data("ui-sortable-item",!0),this.instance.options._helper=this.instance.options.helper,this.instance.options.helper=function(){return i.helper[0]},e.target=this.instance.currentItem[0],this.instance._mouseCapture(e,!0),this.instance._mouseStart(e,!0,!0),this.instance.offset.click.top=s.offset.click.top,this.instance.offset.click.left=s.offset.click.left,this.instance.offset.parent.left-=s.offset.parent.left-this.instance.offset.parent.left,this.instance.offset.parent.top-=s.offset.parent.top-this.instance.offset.parent.top,s._trigger("toSortable",e),s.dropped=this.instance.element,s.currentItem=s.element,this.instance.fromOutside=s),this.instance.currentItem&&this.instance._mouseDrag(e)):this.instance.isOver&&(this.instance.isOver=0,this.instance.cancelHelperRemoval=!0,this.instance.options.revert=!1,this.instance._trigger("out",e,this.instance._uiHash(this.instance)),this.instance._mouseStop(e,!0),this.instance.options.helper=this.instance.options._helper,this.instance.currentItem.remove(),this.instance.placeholder&&this.instance.placeholder.remove(),s._trigger("fromSortable",e),s.dropped=!1)})}}),t.ui.plugin.add("draggable","cursor",{start:function(){var e=t("body"),i=t(this).data("ui-draggable").options;e.css("cursor")&&(i._cursor=e.css("cursor")),e.css("cursor",i.cursor)},stop:function(){var e=t(this).data("ui-draggable").options;e._cursor&&t("body").css("cursor",e._cursor)}}),t.ui.plugin.add("draggable","opacity",{start:function(e,i){var s=t(i.helper),n=t(this).data("ui-draggable").options;s.css("opacity")&&(n._opacity=s.css("opacity")),s.css("opacity",n.opacity)},stop:function(e,i){var s=t(this).data("ui-draggable").options;s._opacity&&t(i.helper).css("opacity",s._opacity)}}),t.ui.plugin.add("draggable","scroll",{start:function(){var e=t(this).data("ui-draggable");e.scrollParent[0]!==document&&"HTML"!==e.scrollParent[0].tagName&&(e.overflowOffset=e.scrollParent.offset())},drag:function(e){var i=t(this).data("ui-draggable"),s=i.options,n=!1;i.scrollParent[0]!==document&&"HTML"!==i.scrollParent[0].tagName?(s.axis&&"x"===s.axis||(i.overflowOffset.top+i.scrollParent[0].offsetHeight-e.pageY<s.scrollSensitivity?i.scrollParent[0].scrollTop=n=i.scrollParent[0].scrollTop+s.scrollSpeed:e.pageY-i.overflowOffset.top<s.scrollSensitivity&&(i.scrollParent[0].scrollTop=n=i.scrollParent[0].scrollTop-s.scrollSpeed)),s.axis&&"y"===s.axis||(i.overflowOffset.left+i.scrollParent[0].offsetWidth-e.pageX<s.scrollSensitivity?i.scrollParent[0].scrollLeft=n=i.scrollParent[0].scrollLeft+s.scrollSpeed:e.pageX-i.overflowOffset.left<s.scrollSensitivity&&(i.scrollParent[0].scrollLeft=n=i.scrollParent[0].scrollLeft-s.scrollSpeed))):(s.axis&&"x"===s.axis||(e.pageY-t(document).scrollTop()<s.scrollSensitivity?n=t(document).scrollTop(t(document).scrollTop()-s.scrollSpeed):t(window).height()-(e.pageY-t(document).scrollTop())<s.scrollSensitivity&&(n=t(document).scrollTop(t(document).scrollTop()+s.scrollSpeed))),s.axis&&"y"===s.axis||(e.pageX-t(document).scrollLeft()<s.scrollSensitivity?n=t(document).scrollLeft(t(document).scrollLeft()-s.scrollSpeed):t(window).width()-(e.pageX-t(document).scrollLeft())<s.scrollSensitivity&&(n=t(document).scrollLeft(t(document).scrollLeft()+s.scrollSpeed)))),n!==!1&&t.ui.ddmanager&&!s.dropBehaviour&&t.ui.ddmanager.prepareOffsets(i,e)}}),t.ui.plugin.add("draggable","snap",{start:function(){var e=t(this).data("ui-draggable"),i=e.options;e.snapElements=[],t(i.snap.constructor!==String?i.snap.items||":data(ui-draggable)":i.snap).each(function(){var i=t(this),s=i.offset();this!==e.element[0]&&e.snapElements.push({item:this,width:i.outerWidth(),height:i.outerHeight(),top:s.top,left:s.left})})},drag:function(e,i){var s,n,o,a,r,h,l,c,u,d,p=t(this).data("ui-draggable"),f=p.options,g=f.snapTolerance,m=i.offset.left,v=m+p.helperProportions.width,_=i.offset.top,b=_+p.helperProportions.height;for(u=p.snapElements.length-1;u>=0;u--)r=p.snapElements[u].left,h=r+p.snapElements[u].width,l=p.snapElements[u].top,c=l+p.snapElements[u].height,m>r-g&&h+g>m&&_>l-g&&c+g>_||m>r-g&&h+g>m&&b>l-g&&c+g>b||v>r-g&&h+g>v&&_>l-g&&c+g>_||v>r-g&&h+g>v&&b>l-g&&c+g>b?("inner"!==f.snapMode&&(s=g>=Math.abs(l-b),n=g>=Math.abs(c-_),o=g>=Math.abs(r-v),a=g>=Math.abs(h-m),s&&(i.position.top=p._convertPositionTo("relative",{top:l-p.helperProportions.height,left:0}).top-p.margins.top),n&&(i.position.top=p._convertPositionTo("relative",{top:c,left:0}).top-p.margins.top),o&&(i.position.left=p._convertPositionTo("relative",{top:0,left:r-p.helperProportions.width}).left-p.margins.left),a&&(i.position.left=p._convertPositionTo("relative",{top:0,left:h}).left-p.margins.left)),d=s||n||o||a,"outer"!==f.snapMode&&(s=g>=Math.abs(l-_),n=g>=Math.abs(c-b),o=g>=Math.abs(r-m),a=g>=Math.abs(h-v),s&&(i.position.top=p._convertPositionTo("relative",{top:l,left:0}).top-p.margins.top),n&&(i.position.top=p._convertPositionTo("relative",{top:c-p.helperProportions.height,left:0}).top-p.margins.top),o&&(i.position.left=p._convertPositionTo("relative",{top:0,left:r}).left-p.margins.left),a&&(i.position.left=p._convertPositionTo("relative",{top:0,left:h-p.helperProportions.width}).left-p.margins.left)),!p.snapElements[u].snapping&&(s||n||o||a||d)&&p.options.snap.snap&&p.options.snap.snap.call(p.element,e,t.extend(p._uiHash(),{snapItem:p.snapElements[u].item})),p.snapElements[u].snapping=s||n||o||a||d):(p.snapElements[u].snapping&&p.options.snap.release&&p.options.snap.release.call(p.element,e,t.extend(p._uiHash(),{snapItem:p.snapElements[u].item})),p.snapElements[u].snapping=!1)}}),t.ui.plugin.add("draggable","stack",{start:function(){var e,i=this.data("ui-draggable").options,s=t.makeArray(t(i.stack)).sort(function(e,i){return(parseInt(t(e).css("zIndex"),10)||0)-(parseInt(t(i).css("zIndex"),10)||0)});s.length&&(e=parseInt(t(s[0]).css("zIndex"),10)||0,t(s).each(function(i){t(this).css("zIndex",e+i)}),this.css("zIndex",e+s.length))}}),t.ui.plugin.add("draggable","zIndex",{start:function(e,i){var s=t(i.helper),n=t(this).data("ui-draggable").options;s.css("zIndex")&&(n._zIndex=s.css("zIndex")),s.css("zIndex",n.zIndex)},stop:function(e,i){var s=t(this).data("ui-draggable").options;s._zIndex&&t(i.helper).css("zIndex",s._zIndex)}})}(jQuery),function(t){function e(t,e,i){return t>e&&e+i>t}t.widget("ui.droppable",{version:"1.10.2",widgetEventPrefix:"drop",options:{accept:"*",activeClass:!1,addClasses:!0,greedy:!1,hoverClass:!1,scope:"default",tolerance:"intersect",activate:null,deactivate:null,drop:null,out:null,over:null},_create:function(){var e=this.options,i=e.accept;this.isover=!1,this.isout=!0,this.accept=t.isFunction(i)?i:function(t){return t.is(i)},this.proportions={width:this.element[0].offsetWidth,height:this.element[0].offsetHeight},t.ui.ddmanager.droppables[e.scope]=t.ui.ddmanager.droppables[e.scope]||[],t.ui.ddmanager.droppables[e.scope].push(this),e.addClasses&&this.element.addClass("ui-droppable") +},_destroy:function(){for(var e=0,i=t.ui.ddmanager.droppables[this.options.scope];i.length>e;e++)i[e]===this&&i.splice(e,1);this.element.removeClass("ui-droppable ui-droppable-disabled")},_setOption:function(e,i){"accept"===e&&(this.accept=t.isFunction(i)?i:function(t){return t.is(i)}),t.Widget.prototype._setOption.apply(this,arguments)},_activate:function(e){var i=t.ui.ddmanager.current;this.options.activeClass&&this.element.addClass(this.options.activeClass),i&&this._trigger("activate",e,this.ui(i))},_deactivate:function(e){var i=t.ui.ddmanager.current;this.options.activeClass&&this.element.removeClass(this.options.activeClass),i&&this._trigger("deactivate",e,this.ui(i))},_over:function(e){var i=t.ui.ddmanager.current;i&&(i.currentItem||i.element)[0]!==this.element[0]&&this.accept.call(this.element[0],i.currentItem||i.element)&&(this.options.hoverClass&&this.element.addClass(this.options.hoverClass),this._trigger("over",e,this.ui(i)))},_out:function(e){var i=t.ui.ddmanager.current;i&&(i.currentItem||i.element)[0]!==this.element[0]&&this.accept.call(this.element[0],i.currentItem||i.element)&&(this.options.hoverClass&&this.element.removeClass(this.options.hoverClass),this._trigger("out",e,this.ui(i)))},_drop:function(e,i){var s=i||t.ui.ddmanager.current,n=!1;return s&&(s.currentItem||s.element)[0]!==this.element[0]?(this.element.find(":data(ui-droppable)").not(".ui-draggable-dragging").each(function(){var e=t.data(this,"ui-droppable");return e.options.greedy&&!e.options.disabled&&e.options.scope===s.options.scope&&e.accept.call(e.element[0],s.currentItem||s.element)&&t.ui.intersect(s,t.extend(e,{offset:e.element.offset()}),e.options.tolerance)?(n=!0,!1):undefined}),n?!1:this.accept.call(this.element[0],s.currentItem||s.element)?(this.options.activeClass&&this.element.removeClass(this.options.activeClass),this.options.hoverClass&&this.element.removeClass(this.options.hoverClass),this._trigger("drop",e,this.ui(s)),this.element):!1):!1},ui:function(t){return{draggable:t.currentItem||t.element,helper:t.helper,position:t.position,offset:t.positionAbs}}}),t.ui.intersect=function(t,i,s){if(!i.offset)return!1;var n,o,a=(t.positionAbs||t.position.absolute).left,r=a+t.helperProportions.width,h=(t.positionAbs||t.position.absolute).top,l=h+t.helperProportions.height,c=i.offset.left,u=c+i.proportions.width,d=i.offset.top,p=d+i.proportions.height;switch(s){case"fit":return a>=c&&u>=r&&h>=d&&p>=l;case"intersect":return a+t.helperProportions.width/2>c&&u>r-t.helperProportions.width/2&&h+t.helperProportions.height/2>d&&p>l-t.helperProportions.height/2;case"pointer":return n=(t.positionAbs||t.position.absolute).left+(t.clickOffset||t.offset.click).left,o=(t.positionAbs||t.position.absolute).top+(t.clickOffset||t.offset.click).top,e(o,d,i.proportions.height)&&e(n,c,i.proportions.width);case"touch":return(h>=d&&p>=h||l>=d&&p>=l||d>h&&l>p)&&(a>=c&&u>=a||r>=c&&u>=r||c>a&&r>u);default:return!1}},t.ui.ddmanager={current:null,droppables:{"default":[]},prepareOffsets:function(e,i){var s,n,o=t.ui.ddmanager.droppables[e.options.scope]||[],a=i?i.type:null,r=(e.currentItem||e.element).find(":data(ui-droppable)").addBack();t:for(s=0;o.length>s;s++)if(!(o[s].options.disabled||e&&!o[s].accept.call(o[s].element[0],e.currentItem||e.element))){for(n=0;r.length>n;n++)if(r[n]===o[s].element[0]){o[s].proportions.height=0;continue t}o[s].visible="none"!==o[s].element.css("display"),o[s].visible&&("mousedown"===a&&o[s]._activate.call(o[s],i),o[s].offset=o[s].element.offset(),o[s].proportions={width:o[s].element[0].offsetWidth,height:o[s].element[0].offsetHeight})}},drop:function(e,i){var s=!1;return t.each((t.ui.ddmanager.droppables[e.options.scope]||[]).slice(),function(){this.options&&(!this.options.disabled&&this.visible&&t.ui.intersect(e,this,this.options.tolerance)&&(s=this._drop.call(this,i)||s),!this.options.disabled&&this.visible&&this.accept.call(this.element[0],e.currentItem||e.element)&&(this.isout=!0,this.isover=!1,this._deactivate.call(this,i)))}),s},dragStart:function(e,i){e.element.parentsUntil("body").bind("scroll.droppable",function(){e.options.refreshPositions||t.ui.ddmanager.prepareOffsets(e,i)})},drag:function(e,i){e.options.refreshPositions&&t.ui.ddmanager.prepareOffsets(e,i),t.each(t.ui.ddmanager.droppables[e.options.scope]||[],function(){if(!this.options.disabled&&!this.greedyChild&&this.visible){var s,n,o,a=t.ui.intersect(e,this,this.options.tolerance),r=!a&&this.isover?"isout":a&&!this.isover?"isover":null;r&&(this.options.greedy&&(n=this.options.scope,o=this.element.parents(":data(ui-droppable)").filter(function(){return t.data(this,"ui-droppable").options.scope===n}),o.length&&(s=t.data(o[0],"ui-droppable"),s.greedyChild="isover"===r)),s&&"isover"===r&&(s.isover=!1,s.isout=!0,s._out.call(s,i)),this[r]=!0,this["isout"===r?"isover":"isout"]=!1,this["isover"===r?"_over":"_out"].call(this,i),s&&"isout"===r&&(s.isout=!1,s.isover=!0,s._over.call(s,i)))}})},dragStop:function(e,i){e.element.parentsUntil("body").unbind("scroll.droppable"),e.options.refreshPositions||t.ui.ddmanager.prepareOffsets(e,i)}}}(jQuery),function(t){function e(t){return parseInt(t,10)||0}function i(t){return!isNaN(parseInt(t,10))}t.widget("ui.resizable",t.ui.mouse,{version:"1.10.2",widgetEventPrefix:"resize",options:{alsoResize:!1,animate:!1,animateDuration:"slow",animateEasing:"swing",aspectRatio:!1,autoHide:!1,containment:!1,ghost:!1,grid:!1,handles:"e,s,se",helper:!1,maxHeight:null,maxWidth:null,minHeight:10,minWidth:10,zIndex:90,resize:null,start:null,stop:null},_create:function(){var e,i,s,n,o,a=this,r=this.options;if(this.element.addClass("ui-resizable"),t.extend(this,{_aspectRatio:!!r.aspectRatio,aspectRatio:r.aspectRatio,originalElement:this.element,_proportionallyResizeElements:[],_helper:r.helper||r.ghost||r.animate?r.helper||"ui-resizable-helper":null}),this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)&&(this.element.wrap(t("<div class='ui-wrapper' style='overflow: hidden;'></div>").css({position:this.element.css("position"),width:this.element.outerWidth(),height:this.element.outerHeight(),top:this.element.css("top"),left:this.element.css("left")})),this.element=this.element.parent().data("ui-resizable",this.element.data("ui-resizable")),this.elementIsWrapper=!0,this.element.css({marginLeft:this.originalElement.css("marginLeft"),marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom")}),this.originalElement.css({marginLeft:0,marginTop:0,marginRight:0,marginBottom:0}),this.originalResizeStyle=this.originalElement.css("resize"),this.originalElement.css("resize","none"),this._proportionallyResizeElements.push(this.originalElement.css({position:"static",zoom:1,display:"block"})),this.originalElement.css({margin:this.originalElement.css("margin")}),this._proportionallyResize()),this.handles=r.handles||(t(".ui-resizable-handle",this.element).length?{n:".ui-resizable-n",e:".ui-resizable-e",s:".ui-resizable-s",w:".ui-resizable-w",se:".ui-resizable-se",sw:".ui-resizable-sw",ne:".ui-resizable-ne",nw:".ui-resizable-nw"}:"e,s,se"),this.handles.constructor===String)for("all"===this.handles&&(this.handles="n,e,s,w,se,sw,ne,nw"),e=this.handles.split(","),this.handles={},i=0;e.length>i;i++)s=t.trim(e[i]),o="ui-resizable-"+s,n=t("<div class='ui-resizable-handle "+o+"'></div>"),n.css({zIndex:r.zIndex}),"se"===s&&n.addClass("ui-icon ui-icon-gripsmall-diagonal-se"),this.handles[s]=".ui-resizable-"+s,this.element.append(n);this._renderAxis=function(e){var i,s,n,o;e=e||this.element;for(i in this.handles)this.handles[i].constructor===String&&(this.handles[i]=t(this.handles[i],this.element).show()),this.elementIsWrapper&&this.originalElement[0].nodeName.match(/textarea|input|select|button/i)&&(s=t(this.handles[i],this.element),o=/sw|ne|nw|se|n|s/.test(i)?s.outerHeight():s.outerWidth(),n=["padding",/ne|nw|n/.test(i)?"Top":/se|sw|s/.test(i)?"Bottom":/^e$/.test(i)?"Right":"Left"].join(""),e.css(n,o),this._proportionallyResize()),t(this.handles[i]).length},this._renderAxis(this.element),this._handles=t(".ui-resizable-handle",this.element).disableSelection(),this._handles.mouseover(function(){a.resizing||(this.className&&(n=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i)),a.axis=n&&n[1]?n[1]:"se")}),r.autoHide&&(this._handles.hide(),t(this.element).addClass("ui-resizable-autohide").mouseenter(function(){r.disabled||(t(this).removeClass("ui-resizable-autohide"),a._handles.show())}).mouseleave(function(){r.disabled||a.resizing||(t(this).addClass("ui-resizable-autohide"),a._handles.hide())})),this._mouseInit()},_destroy:function(){this._mouseDestroy();var e,i=function(e){t(e).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing").removeData("resizable").removeData("ui-resizable").unbind(".resizable").find(".ui-resizable-handle").remove()};return this.elementIsWrapper&&(i(this.element),e=this.element,this.originalElement.css({position:e.css("position"),width:e.outerWidth(),height:e.outerHeight(),top:e.css("top"),left:e.css("left")}).insertAfter(e),e.remove()),this.originalElement.css("resize",this.originalResizeStyle),i(this.originalElement),this},_mouseCapture:function(e){var i,s,n=!1;for(i in this.handles)s=t(this.handles[i])[0],(s===e.target||t.contains(s,e.target))&&(n=!0);return!this.options.disabled&&n},_mouseStart:function(i){var s,n,o,a=this.options,r=this.element.position(),h=this.element;return this.resizing=!0,/absolute/.test(h.css("position"))?h.css({position:"absolute",top:h.css("top"),left:h.css("left")}):h.is(".ui-draggable")&&h.css({position:"absolute",top:r.top,left:r.left}),this._renderProxy(),s=e(this.helper.css("left")),n=e(this.helper.css("top")),a.containment&&(s+=t(a.containment).scrollLeft()||0,n+=t(a.containment).scrollTop()||0),this.offset=this.helper.offset(),this.position={left:s,top:n},this.size=this._helper?{width:h.outerWidth(),height:h.outerHeight()}:{width:h.width(),height:h.height()},this.originalSize=this._helper?{width:h.outerWidth(),height:h.outerHeight()}:{width:h.width(),height:h.height()},this.originalPosition={left:s,top:n},this.sizeDiff={width:h.outerWidth()-h.width(),height:h.outerHeight()-h.height()},this.originalMousePosition={left:i.pageX,top:i.pageY},this.aspectRatio="number"==typeof a.aspectRatio?a.aspectRatio:this.originalSize.width/this.originalSize.height||1,o=t(".ui-resizable-"+this.axis).css("cursor"),t("body").css("cursor","auto"===o?this.axis+"-resize":o),h.addClass("ui-resizable-resizing"),this._propagate("start",i),!0},_mouseDrag:function(e){var i,s=this.helper,n={},o=this.originalMousePosition,a=this.axis,r=this.position.top,h=this.position.left,l=this.size.width,c=this.size.height,u=e.pageX-o.left||0,d=e.pageY-o.top||0,p=this._change[a];return p?(i=p.apply(this,[e,u,d]),this._updateVirtualBoundaries(e.shiftKey),(this._aspectRatio||e.shiftKey)&&(i=this._updateRatio(i,e)),i=this._respectSize(i,e),this._updateCache(i),this._propagate("resize",e),this.position.top!==r&&(n.top=this.position.top+"px"),this.position.left!==h&&(n.left=this.position.left+"px"),this.size.width!==l&&(n.width=this.size.width+"px"),this.size.height!==c&&(n.height=this.size.height+"px"),s.css(n),!this._helper&&this._proportionallyResizeElements.length&&this._proportionallyResize(),t.isEmptyObject(n)||this._trigger("resize",e,this.ui()),!1):!1},_mouseStop:function(e){this.resizing=!1;var i,s,n,o,a,r,h,l=this.options,c=this;return this._helper&&(i=this._proportionallyResizeElements,s=i.length&&/textarea/i.test(i[0].nodeName),n=s&&t.ui.hasScroll(i[0],"left")?0:c.sizeDiff.height,o=s?0:c.sizeDiff.width,a={width:c.helper.width()-o,height:c.helper.height()-n},r=parseInt(c.element.css("left"),10)+(c.position.left-c.originalPosition.left)||null,h=parseInt(c.element.css("top"),10)+(c.position.top-c.originalPosition.top)||null,l.animate||this.element.css(t.extend(a,{top:h,left:r})),c.helper.height(c.size.height),c.helper.width(c.size.width),this._helper&&!l.animate&&this._proportionallyResize()),t("body").css("cursor","auto"),this.element.removeClass("ui-resizable-resizing"),this._propagate("stop",e),this._helper&&this.helper.remove(),!1},_updateVirtualBoundaries:function(t){var e,s,n,o,a,r=this.options;a={minWidth:i(r.minWidth)?r.minWidth:0,maxWidth:i(r.maxWidth)?r.maxWidth:1/0,minHeight:i(r.minHeight)?r.minHeight:0,maxHeight:i(r.maxHeight)?r.maxHeight:1/0},(this._aspectRatio||t)&&(e=a.minHeight*this.aspectRatio,n=a.minWidth/this.aspectRatio,s=a.maxHeight*this.aspectRatio,o=a.maxWidth/this.aspectRatio,e>a.minWidth&&(a.minWidth=e),n>a.minHeight&&(a.minHeight=n),a.maxWidth>s&&(a.maxWidth=s),a.maxHeight>o&&(a.maxHeight=o)),this._vBoundaries=a},_updateCache:function(t){this.offset=this.helper.offset(),i(t.left)&&(this.position.left=t.left),i(t.top)&&(this.position.top=t.top),i(t.height)&&(this.size.height=t.height),i(t.width)&&(this.size.width=t.width)},_updateRatio:function(t){var e=this.position,s=this.size,n=this.axis;return i(t.height)?t.width=t.height*this.aspectRatio:i(t.width)&&(t.height=t.width/this.aspectRatio),"sw"===n&&(t.left=e.left+(s.width-t.width),t.top=null),"nw"===n&&(t.top=e.top+(s.height-t.height),t.left=e.left+(s.width-t.width)),t},_respectSize:function(t){var e=this._vBoundaries,s=this.axis,n=i(t.width)&&e.maxWidth&&e.maxWidth<t.width,o=i(t.height)&&e.maxHeight&&e.maxHeight<t.height,a=i(t.width)&&e.minWidth&&e.minWidth>t.width,r=i(t.height)&&e.minHeight&&e.minHeight>t.height,h=this.originalPosition.left+this.originalSize.width,l=this.position.top+this.size.height,c=/sw|nw|w/.test(s),u=/nw|ne|n/.test(s);return a&&(t.width=e.minWidth),r&&(t.height=e.minHeight),n&&(t.width=e.maxWidth),o&&(t.height=e.maxHeight),a&&c&&(t.left=h-e.minWidth),n&&c&&(t.left=h-e.maxWidth),r&&u&&(t.top=l-e.minHeight),o&&u&&(t.top=l-e.maxHeight),t.width||t.height||t.left||!t.top?t.width||t.height||t.top||!t.left||(t.left=null):t.top=null,t},_proportionallyResize:function(){if(this._proportionallyResizeElements.length){var t,e,i,s,n,o=this.helper||this.element;for(t=0;this._proportionallyResizeElements.length>t;t++){if(n=this._proportionallyResizeElements[t],!this.borderDif)for(this.borderDif=[],i=[n.css("borderTopWidth"),n.css("borderRightWidth"),n.css("borderBottomWidth"),n.css("borderLeftWidth")],s=[n.css("paddingTop"),n.css("paddingRight"),n.css("paddingBottom"),n.css("paddingLeft")],e=0;i.length>e;e++)this.borderDif[e]=(parseInt(i[e],10)||0)+(parseInt(s[e],10)||0);n.css({height:o.height()-this.borderDif[0]-this.borderDif[2]||0,width:o.width()-this.borderDif[1]-this.borderDif[3]||0})}}},_renderProxy:function(){var e=this.element,i=this.options;this.elementOffset=e.offset(),this._helper?(this.helper=this.helper||t("<div style='overflow:hidden;'></div>"),this.helper.addClass(this._helper).css({width:this.element.outerWidth()-1,height:this.element.outerHeight()-1,position:"absolute",left:this.elementOffset.left+"px",top:this.elementOffset.top+"px",zIndex:++i.zIndex}),this.helper.appendTo("body").disableSelection()):this.helper=this.element},_change:{e:function(t,e){return{width:this.originalSize.width+e}},w:function(t,e){var i=this.originalSize,s=this.originalPosition;return{left:s.left+e,width:i.width-e}},n:function(t,e,i){var s=this.originalSize,n=this.originalPosition;return{top:n.top+i,height:s.height-i}},s:function(t,e,i){return{height:this.originalSize.height+i}},se:function(e,i,s){return t.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[e,i,s]))},sw:function(e,i,s){return t.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[e,i,s]))},ne:function(e,i,s){return t.extend(this._change.n.apply(this,arguments),this._change.e.apply(this,[e,i,s]))},nw:function(e,i,s){return t.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[e,i,s]))}},_propagate:function(e,i){t.ui.plugin.call(this,e,[i,this.ui()]),"resize"!==e&&this._trigger(e,i,this.ui())},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize,originalPosition:this.originalPosition}}}),t.ui.plugin.add("resizable","animate",{stop:function(e){var i=t(this).data("ui-resizable"),s=i.options,n=i._proportionallyResizeElements,o=n.length&&/textarea/i.test(n[0].nodeName),a=o&&t.ui.hasScroll(n[0],"left")?0:i.sizeDiff.height,r=o?0:i.sizeDiff.width,h={width:i.size.width-r,height:i.size.height-a},l=parseInt(i.element.css("left"),10)+(i.position.left-i.originalPosition.left)||null,c=parseInt(i.element.css("top"),10)+(i.position.top-i.originalPosition.top)||null;i.element.animate(t.extend(h,c&&l?{top:c,left:l}:{}),{duration:s.animateDuration,easing:s.animateEasing,step:function(){var s={width:parseInt(i.element.css("width"),10),height:parseInt(i.element.css("height"),10),top:parseInt(i.element.css("top"),10),left:parseInt(i.element.css("left"),10)};n&&n.length&&t(n[0]).css({width:s.width,height:s.height}),i._updateCache(s),i._propagate("resize",e)}})}}),t.ui.plugin.add("resizable","containment",{start:function(){var i,s,n,o,a,r,h,l=t(this).data("ui-resizable"),c=l.options,u=l.element,d=c.containment,p=d instanceof t?d.get(0):/parent/.test(d)?u.parent().get(0):d;p&&(l.containerElement=t(p),/document/.test(d)||d===document?(l.containerOffset={left:0,top:0},l.containerPosition={left:0,top:0},l.parentData={element:t(document),left:0,top:0,width:t(document).width(),height:t(document).height()||document.body.parentNode.scrollHeight}):(i=t(p),s=[],t(["Top","Right","Left","Bottom"]).each(function(t,n){s[t]=e(i.css("padding"+n))}),l.containerOffset=i.offset(),l.containerPosition=i.position(),l.containerSize={height:i.innerHeight()-s[3],width:i.innerWidth()-s[1]},n=l.containerOffset,o=l.containerSize.height,a=l.containerSize.width,r=t.ui.hasScroll(p,"left")?p.scrollWidth:a,h=t.ui.hasScroll(p)?p.scrollHeight:o,l.parentData={element:p,left:n.left,top:n.top,width:r,height:h}))},resize:function(e){var i,s,n,o,a=t(this).data("ui-resizable"),r=a.options,h=a.containerOffset,l=a.position,c=a._aspectRatio||e.shiftKey,u={top:0,left:0},d=a.containerElement;d[0]!==document&&/static/.test(d.css("position"))&&(u=h),l.left<(a._helper?h.left:0)&&(a.size.width=a.size.width+(a._helper?a.position.left-h.left:a.position.left-u.left),c&&(a.size.height=a.size.width/a.aspectRatio),a.position.left=r.helper?h.left:0),l.top<(a._helper?h.top:0)&&(a.size.height=a.size.height+(a._helper?a.position.top-h.top:a.position.top),c&&(a.size.width=a.size.height*a.aspectRatio),a.position.top=a._helper?h.top:0),a.offset.left=a.parentData.left+a.position.left,a.offset.top=a.parentData.top+a.position.top,i=Math.abs((a._helper?a.offset.left-u.left:a.offset.left-u.left)+a.sizeDiff.width),s=Math.abs((a._helper?a.offset.top-u.top:a.offset.top-h.top)+a.sizeDiff.height),n=a.containerElement.get(0)===a.element.parent().get(0),o=/relative|absolute/.test(a.containerElement.css("position")),n&&o&&(i-=a.parentData.left),i+a.size.width>=a.parentData.width&&(a.size.width=a.parentData.width-i,c&&(a.size.height=a.size.width/a.aspectRatio)),s+a.size.height>=a.parentData.height&&(a.size.height=a.parentData.height-s,c&&(a.size.width=a.size.height*a.aspectRatio))},stop:function(){var e=t(this).data("ui-resizable"),i=e.options,s=e.containerOffset,n=e.containerPosition,o=e.containerElement,a=t(e.helper),r=a.offset(),h=a.outerWidth()-e.sizeDiff.width,l=a.outerHeight()-e.sizeDiff.height;e._helper&&!i.animate&&/relative/.test(o.css("position"))&&t(this).css({left:r.left-n.left-s.left,width:h,height:l}),e._helper&&!i.animate&&/static/.test(o.css("position"))&&t(this).css({left:r.left-n.left-s.left,width:h,height:l})}}),t.ui.plugin.add("resizable","alsoResize",{start:function(){var e=t(this).data("ui-resizable"),i=e.options,s=function(e){t(e).each(function(){var e=t(this);e.data("ui-resizable-alsoresize",{width:parseInt(e.width(),10),height:parseInt(e.height(),10),left:parseInt(e.css("left"),10),top:parseInt(e.css("top"),10)})})};"object"!=typeof i.alsoResize||i.alsoResize.parentNode?s(i.alsoResize):i.alsoResize.length?(i.alsoResize=i.alsoResize[0],s(i.alsoResize)):t.each(i.alsoResize,function(t){s(t)})},resize:function(e,i){var s=t(this).data("ui-resizable"),n=s.options,o=s.originalSize,a=s.originalPosition,r={height:s.size.height-o.height||0,width:s.size.width-o.width||0,top:s.position.top-a.top||0,left:s.position.left-a.left||0},h=function(e,s){t(e).each(function(){var e=t(this),n=t(this).data("ui-resizable-alsoresize"),o={},a=s&&s.length?s:e.parents(i.originalElement[0]).length?["width","height"]:["width","height","top","left"];t.each(a,function(t,e){var i=(n[e]||0)+(r[e]||0);i&&i>=0&&(o[e]=i||null)}),e.css(o)})};"object"!=typeof n.alsoResize||n.alsoResize.nodeType?h(n.alsoResize):t.each(n.alsoResize,function(t,e){h(t,e)})},stop:function(){t(this).removeData("resizable-alsoresize")}}),t.ui.plugin.add("resizable","ghost",{start:function(){var e=t(this).data("ui-resizable"),i=e.options,s=e.size;e.ghost=e.originalElement.clone(),e.ghost.css({opacity:.25,display:"block",position:"relative",height:s.height,width:s.width,margin:0,left:0,top:0}).addClass("ui-resizable-ghost").addClass("string"==typeof i.ghost?i.ghost:""),e.ghost.appendTo(e.helper)},resize:function(){var e=t(this).data("ui-resizable");e.ghost&&e.ghost.css({position:"relative",height:e.size.height,width:e.size.width})},stop:function(){var e=t(this).data("ui-resizable");e.ghost&&e.helper&&e.helper.get(0).removeChild(e.ghost.get(0))}}),t.ui.plugin.add("resizable","grid",{resize:function(){var e=t(this).data("ui-resizable"),i=e.options,s=e.size,n=e.originalSize,o=e.originalPosition,a=e.axis,r="number"==typeof i.grid?[i.grid,i.grid]:i.grid,h=r[0]||1,l=r[1]||1,c=Math.round((s.width-n.width)/h)*h,u=Math.round((s.height-n.height)/l)*l,d=n.width+c,p=n.height+u,f=i.maxWidth&&d>i.maxWidth,g=i.maxHeight&&p>i.maxHeight,m=i.minWidth&&i.minWidth>d,v=i.minHeight&&i.minHeight>p;i.grid=r,m&&(d+=h),v&&(p+=l),f&&(d-=h),g&&(p-=l),/^(se|s|e)$/.test(a)?(e.size.width=d,e.size.height=p):/^(ne)$/.test(a)?(e.size.width=d,e.size.height=p,e.position.top=o.top-u):/^(sw)$/.test(a)?(e.size.width=d,e.size.height=p,e.position.left=o.left-c):(e.size.width=d,e.size.height=p,e.position.top=o.top-u,e.position.left=o.left-c)}})}(jQuery),function(t){t.widget("ui.selectable",t.ui.mouse,{version:"1.10.2",options:{appendTo:"body",autoRefresh:!0,distance:0,filter:"*",tolerance:"touch",selected:null,selecting:null,start:null,stop:null,unselected:null,unselecting:null},_create:function(){var e,i=this;this.element.addClass("ui-selectable"),this.dragged=!1,this.refresh=function(){e=t(i.options.filter,i.element[0]),e.addClass("ui-selectee"),e.each(function(){var e=t(this),i=e.offset();t.data(this,"selectable-item",{element:this,$element:e,left:i.left,top:i.top,right:i.left+e.outerWidth(),bottom:i.top+e.outerHeight(),startselected:!1,selected:e.hasClass("ui-selected"),selecting:e.hasClass("ui-selecting"),unselecting:e.hasClass("ui-unselecting")})})},this.refresh(),this.selectees=e.addClass("ui-selectee"),this._mouseInit(),this.helper=t("<div class='ui-selectable-helper'></div>")},_destroy:function(){this.selectees.removeClass("ui-selectee").removeData("selectable-item"),this.element.removeClass("ui-selectable ui-selectable-disabled"),this._mouseDestroy()},_mouseStart:function(e){var i=this,s=this.options;this.opos=[e.pageX,e.pageY],this.options.disabled||(this.selectees=t(s.filter,this.element[0]),this._trigger("start",e),t(s.appendTo).append(this.helper),this.helper.css({left:e.pageX,top:e.pageY,width:0,height:0}),s.autoRefresh&&this.refresh(),this.selectees.filter(".ui-selected").each(function(){var s=t.data(this,"selectable-item");s.startselected=!0,e.metaKey||e.ctrlKey||(s.$element.removeClass("ui-selected"),s.selected=!1,s.$element.addClass("ui-unselecting"),s.unselecting=!0,i._trigger("unselecting",e,{unselecting:s.element}))}),t(e.target).parents().addBack().each(function(){var s,n=t.data(this,"selectable-item");return n?(s=!e.metaKey&&!e.ctrlKey||!n.$element.hasClass("ui-selected"),n.$element.removeClass(s?"ui-unselecting":"ui-selected").addClass(s?"ui-selecting":"ui-unselecting"),n.unselecting=!s,n.selecting=s,n.selected=s,s?i._trigger("selecting",e,{selecting:n.element}):i._trigger("unselecting",e,{unselecting:n.element}),!1):undefined}))},_mouseDrag:function(e){if(this.dragged=!0,!this.options.disabled){var i,s=this,n=this.options,o=this.opos[0],a=this.opos[1],r=e.pageX,h=e.pageY;return o>r&&(i=r,r=o,o=i),a>h&&(i=h,h=a,a=i),this.helper.css({left:o,top:a,width:r-o,height:h-a}),this.selectees.each(function(){var i=t.data(this,"selectable-item"),l=!1;i&&i.element!==s.element[0]&&("touch"===n.tolerance?l=!(i.left>r||o>i.right||i.top>h||a>i.bottom):"fit"===n.tolerance&&(l=i.left>o&&r>i.right&&i.top>a&&h>i.bottom),l?(i.selected&&(i.$element.removeClass("ui-selected"),i.selected=!1),i.unselecting&&(i.$element.removeClass("ui-unselecting"),i.unselecting=!1),i.selecting||(i.$element.addClass("ui-selecting"),i.selecting=!0,s._trigger("selecting",e,{selecting:i.element}))):(i.selecting&&((e.metaKey||e.ctrlKey)&&i.startselected?(i.$element.removeClass("ui-selecting"),i.selecting=!1,i.$element.addClass("ui-selected"),i.selected=!0):(i.$element.removeClass("ui-selecting"),i.selecting=!1,i.startselected&&(i.$element.addClass("ui-unselecting"),i.unselecting=!0),s._trigger("unselecting",e,{unselecting:i.element}))),i.selected&&(e.metaKey||e.ctrlKey||i.startselected||(i.$element.removeClass("ui-selected"),i.selected=!1,i.$element.addClass("ui-unselecting"),i.unselecting=!0,s._trigger("unselecting",e,{unselecting:i.element})))))}),!1}},_mouseStop:function(e){var i=this;return this.dragged=!1,t(".ui-unselecting",this.element[0]).each(function(){var s=t.data(this,"selectable-item");s.$element.removeClass("ui-unselecting"),s.unselecting=!1,s.startselected=!1,i._trigger("unselected",e,{unselected:s.element})}),t(".ui-selecting",this.element[0]).each(function(){var s=t.data(this,"selectable-item");s.$element.removeClass("ui-selecting").addClass("ui-selected"),s.selecting=!1,s.selected=!0,s.startselected=!0,i._trigger("selected",e,{selected:s.element})}),this._trigger("stop",e),this.helper.remove(),!1}})}(jQuery),function(t){function e(t,e,i){return t>e&&e+i>t}function i(t){return/left|right/.test(t.css("float"))||/inline|table-cell/.test(t.css("display"))}t.widget("ui.sortable",t.ui.mouse,{version:"1.10.2",widgetEventPrefix:"sort",ready:!1,options:{appendTo:"parent",axis:!1,connectWith:!1,containment:!1,cursor:"auto",cursorAt:!1,dropOnEmpty:!0,forcePlaceholderSize:!1,forceHelperSize:!1,grid:!1,handle:!1,helper:"original",items:"> *",opacity:!1,placeholder:!1,revert:!1,scroll:!0,scrollSensitivity:20,scrollSpeed:20,scope:"default",tolerance:"intersect",zIndex:1e3,activate:null,beforeStop:null,change:null,deactivate:null,out:null,over:null,receive:null,remove:null,sort:null,start:null,stop:null,update:null},_create:function(){var t=this.options;this.containerCache={},this.element.addClass("ui-sortable"),this.refresh(),this.floating=this.items.length?"x"===t.axis||i(this.items[0].item):!1,this.offset=this.element.offset(),this._mouseInit(),this.ready=!0},_destroy:function(){this.element.removeClass("ui-sortable ui-sortable-disabled"),this._mouseDestroy();for(var t=this.items.length-1;t>=0;t--)this.items[t].item.removeData(this.widgetName+"-item");return this},_setOption:function(e,i){"disabled"===e?(this.options[e]=i,this.widget().toggleClass("ui-sortable-disabled",!!i)):t.Widget.prototype._setOption.apply(this,arguments)},_mouseCapture:function(e,i){var s=null,n=!1,o=this;return this.reverting?!1:this.options.disabled||"static"===this.options.type?!1:(this._refreshItems(e),t(e.target).parents().each(function(){return t.data(this,o.widgetName+"-item")===o?(s=t(this),!1):undefined}),t.data(e.target,o.widgetName+"-item")===o&&(s=t(e.target)),s?!this.options.handle||i||(t(this.options.handle,s).find("*").addBack().each(function(){this===e.target&&(n=!0)}),n)?(this.currentItem=s,this._removeCurrentsFromItems(),!0):!1:!1)},_mouseStart:function(e,i,s){var n,o,a=this.options;if(this.currentContainer=this,this.refreshPositions(),this.helper=this._createHelper(e),this._cacheHelperProportions(),this._cacheMargins(),this.scrollParent=this.helper.scrollParent(),this.offset=this.currentItem.offset(),this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left},t.extend(this.offset,{click:{left:e.pageX-this.offset.left,top:e.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()}),this.helper.css("position","absolute"),this.cssPosition=this.helper.css("position"),this.originalPosition=this._generatePosition(e),this.originalPageX=e.pageX,this.originalPageY=e.pageY,a.cursorAt&&this._adjustOffsetFromHelper(a.cursorAt),this.domPosition={prev:this.currentItem.prev()[0],parent:this.currentItem.parent()[0]},this.helper[0]!==this.currentItem[0]&&this.currentItem.hide(),this._createPlaceholder(),a.containment&&this._setContainment(),a.cursor&&"auto"!==a.cursor&&(o=this.document.find("body"),this.storedCursor=o.css("cursor"),o.css("cursor",a.cursor),this.storedStylesheet=t("<style>*{ cursor: "+a.cursor+" !important; }</style>").appendTo(o)),a.opacity&&(this.helper.css("opacity")&&(this._storedOpacity=this.helper.css("opacity")),this.helper.css("opacity",a.opacity)),a.zIndex&&(this.helper.css("zIndex")&&(this._storedZIndex=this.helper.css("zIndex")),this.helper.css("zIndex",a.zIndex)),this.scrollParent[0]!==document&&"HTML"!==this.scrollParent[0].tagName&&(this.overflowOffset=this.scrollParent.offset()),this._trigger("start",e,this._uiHash()),this._preserveHelperProportions||this._cacheHelperProportions(),!s)for(n=this.containers.length-1;n>=0;n--)this.containers[n]._trigger("activate",e,this._uiHash(this));return t.ui.ddmanager&&(t.ui.ddmanager.current=this),t.ui.ddmanager&&!a.dropBehaviour&&t.ui.ddmanager.prepareOffsets(this,e),this.dragging=!0,this.helper.addClass("ui-sortable-helper"),this._mouseDrag(e),!0},_mouseDrag:function(e){var i,s,n,o,a=this.options,r=!1;for(this.position=this._generatePosition(e),this.positionAbs=this._convertPositionTo("absolute"),this.lastPositionAbs||(this.lastPositionAbs=this.positionAbs),this.options.scroll&&(this.scrollParent[0]!==document&&"HTML"!==this.scrollParent[0].tagName?(this.overflowOffset.top+this.scrollParent[0].offsetHeight-e.pageY<a.scrollSensitivity?this.scrollParent[0].scrollTop=r=this.scrollParent[0].scrollTop+a.scrollSpeed:e.pageY-this.overflowOffset.top<a.scrollSensitivity&&(this.scrollParent[0].scrollTop=r=this.scrollParent[0].scrollTop-a.scrollSpeed),this.overflowOffset.left+this.scrollParent[0].offsetWidth-e.pageX<a.scrollSensitivity?this.scrollParent[0].scrollLeft=r=this.scrollParent[0].scrollLeft+a.scrollSpeed:e.pageX-this.overflowOffset.left<a.scrollSensitivity&&(this.scrollParent[0].scrollLeft=r=this.scrollParent[0].scrollLeft-a.scrollSpeed)):(e.pageY-t(document).scrollTop()<a.scrollSensitivity?r=t(document).scrollTop(t(document).scrollTop()-a.scrollSpeed):t(window).height()-(e.pageY-t(document).scrollTop())<a.scrollSensitivity&&(r=t(document).scrollTop(t(document).scrollTop()+a.scrollSpeed)),e.pageX-t(document).scrollLeft()<a.scrollSensitivity?r=t(document).scrollLeft(t(document).scrollLeft()-a.scrollSpeed):t(window).width()-(e.pageX-t(document).scrollLeft())<a.scrollSensitivity&&(r=t(document).scrollLeft(t(document).scrollLeft()+a.scrollSpeed))),r!==!1&&t.ui.ddmanager&&!a.dropBehaviour&&t.ui.ddmanager.prepareOffsets(this,e)),this.positionAbs=this._convertPositionTo("absolute"),this.options.axis&&"y"===this.options.axis||(this.helper[0].style.left=this.position.left+"px"),this.options.axis&&"x"===this.options.axis||(this.helper[0].style.top=this.position.top+"px"),i=this.items.length-1;i>=0;i--)if(s=this.items[i],n=s.item[0],o=this._intersectsWithPointer(s),o&&s.instance===this.currentContainer&&n!==this.currentItem[0]&&this.placeholder[1===o?"next":"prev"]()[0]!==n&&!t.contains(this.placeholder[0],n)&&("semi-dynamic"===this.options.type?!t.contains(this.element[0],n):!0)){if(this.direction=1===o?"down":"up","pointer"!==this.options.tolerance&&!this._intersectsWithSides(s))break; +this._rearrange(e,s),this._trigger("change",e,this._uiHash());break}return this._contactContainers(e),t.ui.ddmanager&&t.ui.ddmanager.drag(this,e),this._trigger("sort",e,this._uiHash()),this.lastPositionAbs=this.positionAbs,!1},_mouseStop:function(e,i){if(e){if(t.ui.ddmanager&&!this.options.dropBehaviour&&t.ui.ddmanager.drop(this,e),this.options.revert){var s=this,n=this.placeholder.offset(),o=this.options.axis,a={};o&&"x"!==o||(a.left=n.left-this.offset.parent.left-this.margins.left+(this.offsetParent[0]===document.body?0:this.offsetParent[0].scrollLeft)),o&&"y"!==o||(a.top=n.top-this.offset.parent.top-this.margins.top+(this.offsetParent[0]===document.body?0:this.offsetParent[0].scrollTop)),this.reverting=!0,t(this.helper).animate(a,parseInt(this.options.revert,10)||500,function(){s._clear(e)})}else this._clear(e,i);return!1}},cancel:function(){if(this.dragging){this._mouseUp({target:null}),"original"===this.options.helper?this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"):this.currentItem.show();for(var e=this.containers.length-1;e>=0;e--)this.containers[e]._trigger("deactivate",null,this._uiHash(this)),this.containers[e].containerCache.over&&(this.containers[e]._trigger("out",null,this._uiHash(this)),this.containers[e].containerCache.over=0)}return this.placeholder&&(this.placeholder[0].parentNode&&this.placeholder[0].parentNode.removeChild(this.placeholder[0]),"original"!==this.options.helper&&this.helper&&this.helper[0].parentNode&&this.helper.remove(),t.extend(this,{helper:null,dragging:!1,reverting:!1,_noFinalSort:null}),this.domPosition.prev?t(this.domPosition.prev).after(this.currentItem):t(this.domPosition.parent).prepend(this.currentItem)),this},serialize:function(e){var i=this._getItemsAsjQuery(e&&e.connected),s=[];return e=e||{},t(i).each(function(){var i=(t(e.item||this).attr(e.attribute||"id")||"").match(e.expression||/(.+)[\-=_](.+)/);i&&s.push((e.key||i[1]+"[]")+"="+(e.key&&e.expression?i[1]:i[2]))}),!s.length&&e.key&&s.push(e.key+"="),s.join("&")},toArray:function(e){var i=this._getItemsAsjQuery(e&&e.connected),s=[];return e=e||{},i.each(function(){s.push(t(e.item||this).attr(e.attribute||"id")||"")}),s},_intersectsWith:function(t){var e=this.positionAbs.left,i=e+this.helperProportions.width,s=this.positionAbs.top,n=s+this.helperProportions.height,o=t.left,a=o+t.width,r=t.top,h=r+t.height,l=this.offset.click.top,c=this.offset.click.left,u=s+l>r&&h>s+l&&e+c>o&&a>e+c;return"pointer"===this.options.tolerance||this.options.forcePointerForContainers||"pointer"!==this.options.tolerance&&this.helperProportions[this.floating?"width":"height"]>t[this.floating?"width":"height"]?u:e+this.helperProportions.width/2>o&&a>i-this.helperProportions.width/2&&s+this.helperProportions.height/2>r&&h>n-this.helperProportions.height/2},_intersectsWithPointer:function(t){var i="x"===this.options.axis||e(this.positionAbs.top+this.offset.click.top,t.top,t.height),s="y"===this.options.axis||e(this.positionAbs.left+this.offset.click.left,t.left,t.width),n=i&&s,o=this._getDragVerticalDirection(),a=this._getDragHorizontalDirection();return n?this.floating?a&&"right"===a||"down"===o?2:1:o&&("down"===o?2:1):!1},_intersectsWithSides:function(t){var i=e(this.positionAbs.top+this.offset.click.top,t.top+t.height/2,t.height),s=e(this.positionAbs.left+this.offset.click.left,t.left+t.width/2,t.width),n=this._getDragVerticalDirection(),o=this._getDragHorizontalDirection();return this.floating&&o?"right"===o&&s||"left"===o&&!s:n&&("down"===n&&i||"up"===n&&!i)},_getDragVerticalDirection:function(){var t=this.positionAbs.top-this.lastPositionAbs.top;return 0!==t&&(t>0?"down":"up")},_getDragHorizontalDirection:function(){var t=this.positionAbs.left-this.lastPositionAbs.left;return 0!==t&&(t>0?"right":"left")},refresh:function(t){return this._refreshItems(t),this.refreshPositions(),this},_connectWith:function(){var t=this.options;return t.connectWith.constructor===String?[t.connectWith]:t.connectWith},_getItemsAsjQuery:function(e){var i,s,n,o,a=[],r=[],h=this._connectWith();if(h&&e)for(i=h.length-1;i>=0;i--)for(n=t(h[i]),s=n.length-1;s>=0;s--)o=t.data(n[s],this.widgetFullName),o&&o!==this&&!o.options.disabled&&r.push([t.isFunction(o.options.items)?o.options.items.call(o.element):t(o.options.items,o.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),o]);for(r.push([t.isFunction(this.options.items)?this.options.items.call(this.element,null,{options:this.options,item:this.currentItem}):t(this.options.items,this.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),this]),i=r.length-1;i>=0;i--)r[i][0].each(function(){a.push(this)});return t(a)},_removeCurrentsFromItems:function(){var e=this.currentItem.find(":data("+this.widgetName+"-item)");this.items=t.grep(this.items,function(t){for(var i=0;e.length>i;i++)if(e[i]===t.item[0])return!1;return!0})},_refreshItems:function(e){this.items=[],this.containers=[this];var i,s,n,o,a,r,h,l,c=this.items,u=[[t.isFunction(this.options.items)?this.options.items.call(this.element[0],e,{item:this.currentItem}):t(this.options.items,this.element),this]],d=this._connectWith();if(d&&this.ready)for(i=d.length-1;i>=0;i--)for(n=t(d[i]),s=n.length-1;s>=0;s--)o=t.data(n[s],this.widgetFullName),o&&o!==this&&!o.options.disabled&&(u.push([t.isFunction(o.options.items)?o.options.items.call(o.element[0],e,{item:this.currentItem}):t(o.options.items,o.element),o]),this.containers.push(o));for(i=u.length-1;i>=0;i--)for(a=u[i][1],r=u[i][0],s=0,l=r.length;l>s;s++)h=t(r[s]),h.data(this.widgetName+"-item",a),c.push({item:h,instance:a,width:0,height:0,left:0,top:0})},refreshPositions:function(e){this.offsetParent&&this.helper&&(this.offset.parent=this._getParentOffset());var i,s,n,o;for(i=this.items.length-1;i>=0;i--)s=this.items[i],s.instance!==this.currentContainer&&this.currentContainer&&s.item[0]!==this.currentItem[0]||(n=this.options.toleranceElement?t(this.options.toleranceElement,s.item):s.item,e||(s.width=n.outerWidth(),s.height=n.outerHeight()),o=n.offset(),s.left=o.left,s.top=o.top);if(this.options.custom&&this.options.custom.refreshContainers)this.options.custom.refreshContainers.call(this);else for(i=this.containers.length-1;i>=0;i--)o=this.containers[i].element.offset(),this.containers[i].containerCache.left=o.left,this.containers[i].containerCache.top=o.top,this.containers[i].containerCache.width=this.containers[i].element.outerWidth(),this.containers[i].containerCache.height=this.containers[i].element.outerHeight();return this},_createPlaceholder:function(e){e=e||this;var i,s=e.options;s.placeholder&&s.placeholder.constructor!==String||(i=s.placeholder,s.placeholder={element:function(){var s=e.currentItem[0].nodeName.toLowerCase(),n=t(e.document[0].createElement(s)).addClass(i||e.currentItem[0].className+" ui-sortable-placeholder").removeClass("ui-sortable-helper");return"tr"===s?n.append("<td colspan='99'> </td>"):"img"===s&&n.attr("src",e.currentItem.attr("src")),i||n.css("visibility","hidden"),n},update:function(t,n){(!i||s.forcePlaceholderSize)&&(n.height()||n.height(e.currentItem.innerHeight()-parseInt(e.currentItem.css("paddingTop")||0,10)-parseInt(e.currentItem.css("paddingBottom")||0,10)),n.width()||n.width(e.currentItem.innerWidth()-parseInt(e.currentItem.css("paddingLeft")||0,10)-parseInt(e.currentItem.css("paddingRight")||0,10)))}}),e.placeholder=t(s.placeholder.element.call(e.element,e.currentItem)),e.currentItem.after(e.placeholder),s.placeholder.update(e,e.placeholder)},_contactContainers:function(s){var n,o,a,r,h,l,c,u,d,p,f=null,g=null;for(n=this.containers.length-1;n>=0;n--)if(!t.contains(this.currentItem[0],this.containers[n].element[0]))if(this._intersectsWith(this.containers[n].containerCache)){if(f&&t.contains(this.containers[n].element[0],f.element[0]))continue;f=this.containers[n],g=n}else this.containers[n].containerCache.over&&(this.containers[n]._trigger("out",s,this._uiHash(this)),this.containers[n].containerCache.over=0);if(f)if(1===this.containers.length)this.containers[g].containerCache.over||(this.containers[g]._trigger("over",s,this._uiHash(this)),this.containers[g].containerCache.over=1);else{for(a=1e4,r=null,p=f.floating||i(this.currentItem),h=p?"left":"top",l=p?"width":"height",c=this.positionAbs[h]+this.offset.click[h],o=this.items.length-1;o>=0;o--)t.contains(this.containers[g].element[0],this.items[o].item[0])&&this.items[o].item[0]!==this.currentItem[0]&&(!p||e(this.positionAbs.top+this.offset.click.top,this.items[o].top,this.items[o].height))&&(u=this.items[o].item.offset()[h],d=!1,Math.abs(u-c)>Math.abs(u+this.items[o][l]-c)&&(d=!0,u+=this.items[o][l]),a>Math.abs(u-c)&&(a=Math.abs(u-c),r=this.items[o],this.direction=d?"up":"down"));if(!r&&!this.options.dropOnEmpty)return;if(this.currentContainer===this.containers[g])return;r?this._rearrange(s,r,null,!0):this._rearrange(s,null,this.containers[g].element,!0),this._trigger("change",s,this._uiHash()),this.containers[g]._trigger("change",s,this._uiHash(this)),this.currentContainer=this.containers[g],this.options.placeholder.update(this.currentContainer,this.placeholder),this.containers[g]._trigger("over",s,this._uiHash(this)),this.containers[g].containerCache.over=1}},_createHelper:function(e){var i=this.options,s=t.isFunction(i.helper)?t(i.helper.apply(this.element[0],[e,this.currentItem])):"clone"===i.helper?this.currentItem.clone():this.currentItem;return s.parents("body").length||t("parent"!==i.appendTo?i.appendTo:this.currentItem[0].parentNode)[0].appendChild(s[0]),s[0]===this.currentItem[0]&&(this._storedCSS={width:this.currentItem[0].style.width,height:this.currentItem[0].style.height,position:this.currentItem.css("position"),top:this.currentItem.css("top"),left:this.currentItem.css("left")}),(!s[0].style.width||i.forceHelperSize)&&s.width(this.currentItem.width()),(!s[0].style.height||i.forceHelperSize)&&s.height(this.currentItem.height()),s},_adjustOffsetFromHelper:function(e){"string"==typeof e&&(e=e.split(" ")),t.isArray(e)&&(e={left:+e[0],top:+e[1]||0}),"left"in e&&(this.offset.click.left=e.left+this.margins.left),"right"in e&&(this.offset.click.left=this.helperProportions.width-e.right+this.margins.left),"top"in e&&(this.offset.click.top=e.top+this.margins.top),"bottom"in e&&(this.offset.click.top=this.helperProportions.height-e.bottom+this.margins.top)},_getParentOffset:function(){this.offsetParent=this.helper.offsetParent();var e=this.offsetParent.offset();return"absolute"===this.cssPosition&&this.scrollParent[0]!==document&&t.contains(this.scrollParent[0],this.offsetParent[0])&&(e.left+=this.scrollParent.scrollLeft(),e.top+=this.scrollParent.scrollTop()),(this.offsetParent[0]===document.body||this.offsetParent[0].tagName&&"html"===this.offsetParent[0].tagName.toLowerCase()&&t.ui.ie)&&(e={top:0,left:0}),{top:e.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:e.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if("relative"===this.cssPosition){var t=this.currentItem.position();return{top:t.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:t.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.currentItem.css("marginLeft"),10)||0,top:parseInt(this.currentItem.css("marginTop"),10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var e,i,s,n=this.options;"parent"===n.containment&&(n.containment=this.helper[0].parentNode),("document"===n.containment||"window"===n.containment)&&(this.containment=[0-this.offset.relative.left-this.offset.parent.left,0-this.offset.relative.top-this.offset.parent.top,t("document"===n.containment?document:window).width()-this.helperProportions.width-this.margins.left,(t("document"===n.containment?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top]),/^(document|window|parent)$/.test(n.containment)||(e=t(n.containment)[0],i=t(n.containment).offset(),s="hidden"!==t(e).css("overflow"),this.containment=[i.left+(parseInt(t(e).css("borderLeftWidth"),10)||0)+(parseInt(t(e).css("paddingLeft"),10)||0)-this.margins.left,i.top+(parseInt(t(e).css("borderTopWidth"),10)||0)+(parseInt(t(e).css("paddingTop"),10)||0)-this.margins.top,i.left+(s?Math.max(e.scrollWidth,e.offsetWidth):e.offsetWidth)-(parseInt(t(e).css("borderLeftWidth"),10)||0)-(parseInt(t(e).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left,i.top+(s?Math.max(e.scrollHeight,e.offsetHeight):e.offsetHeight)-(parseInt(t(e).css("borderTopWidth"),10)||0)-(parseInt(t(e).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top])},_convertPositionTo:function(e,i){i||(i=this.position);var s="absolute"===e?1:-1,n="absolute"!==this.cssPosition||this.scrollParent[0]!==document&&t.contains(this.scrollParent[0],this.offsetParent[0])?this.scrollParent:this.offsetParent,o=/(html|body)/i.test(n[0].tagName);return{top:i.top+this.offset.relative.top*s+this.offset.parent.top*s-("fixed"===this.cssPosition?-this.scrollParent.scrollTop():o?0:n.scrollTop())*s,left:i.left+this.offset.relative.left*s+this.offset.parent.left*s-("fixed"===this.cssPosition?-this.scrollParent.scrollLeft():o?0:n.scrollLeft())*s}},_generatePosition:function(e){var i,s,n=this.options,o=e.pageX,a=e.pageY,r="absolute"!==this.cssPosition||this.scrollParent[0]!==document&&t.contains(this.scrollParent[0],this.offsetParent[0])?this.scrollParent:this.offsetParent,h=/(html|body)/i.test(r[0].tagName);return"relative"!==this.cssPosition||this.scrollParent[0]!==document&&this.scrollParent[0]!==this.offsetParent[0]||(this.offset.relative=this._getRelativeOffset()),this.originalPosition&&(this.containment&&(e.pageX-this.offset.click.left<this.containment[0]&&(o=this.containment[0]+this.offset.click.left),e.pageY-this.offset.click.top<this.containment[1]&&(a=this.containment[1]+this.offset.click.top),e.pageX-this.offset.click.left>this.containment[2]&&(o=this.containment[2]+this.offset.click.left),e.pageY-this.offset.click.top>this.containment[3]&&(a=this.containment[3]+this.offset.click.top)),n.grid&&(i=this.originalPageY+Math.round((a-this.originalPageY)/n.grid[1])*n.grid[1],a=this.containment?i-this.offset.click.top>=this.containment[1]&&i-this.offset.click.top<=this.containment[3]?i:i-this.offset.click.top>=this.containment[1]?i-n.grid[1]:i+n.grid[1]:i,s=this.originalPageX+Math.round((o-this.originalPageX)/n.grid[0])*n.grid[0],o=this.containment?s-this.offset.click.left>=this.containment[0]&&s-this.offset.click.left<=this.containment[2]?s:s-this.offset.click.left>=this.containment[0]?s-n.grid[0]:s+n.grid[0]:s)),{top:a-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+("fixed"===this.cssPosition?-this.scrollParent.scrollTop():h?0:r.scrollTop()),left:o-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+("fixed"===this.cssPosition?-this.scrollParent.scrollLeft():h?0:r.scrollLeft())}},_rearrange:function(t,e,i,s){i?i[0].appendChild(this.placeholder[0]):e.item[0].parentNode.insertBefore(this.placeholder[0],"down"===this.direction?e.item[0]:e.item[0].nextSibling),this.counter=this.counter?++this.counter:1;var n=this.counter;this._delay(function(){n===this.counter&&this.refreshPositions(!s)})},_clear:function(t,e){this.reverting=!1;var i,s=[];if(!this._noFinalSort&&this.currentItem.parent().length&&this.placeholder.before(this.currentItem),this._noFinalSort=null,this.helper[0]===this.currentItem[0]){for(i in this._storedCSS)("auto"===this._storedCSS[i]||"static"===this._storedCSS[i])&&(this._storedCSS[i]="");this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper")}else this.currentItem.show();for(this.fromOutside&&!e&&s.push(function(t){this._trigger("receive",t,this._uiHash(this.fromOutside))}),!this.fromOutside&&this.domPosition.prev===this.currentItem.prev().not(".ui-sortable-helper")[0]&&this.domPosition.parent===this.currentItem.parent()[0]||e||s.push(function(t){this._trigger("update",t,this._uiHash())}),this!==this.currentContainer&&(e||(s.push(function(t){this._trigger("remove",t,this._uiHash())}),s.push(function(t){return function(e){t._trigger("receive",e,this._uiHash(this))}}.call(this,this.currentContainer)),s.push(function(t){return function(e){t._trigger("update",e,this._uiHash(this))}}.call(this,this.currentContainer)))),i=this.containers.length-1;i>=0;i--)e||s.push(function(t){return function(e){t._trigger("deactivate",e,this._uiHash(this))}}.call(this,this.containers[i])),this.containers[i].containerCache.over&&(s.push(function(t){return function(e){t._trigger("out",e,this._uiHash(this))}}.call(this,this.containers[i])),this.containers[i].containerCache.over=0);if(this.storedCursor&&(this.document.find("body").css("cursor",this.storedCursor),this.storedStylesheet.remove()),this._storedOpacity&&this.helper.css("opacity",this._storedOpacity),this._storedZIndex&&this.helper.css("zIndex","auto"===this._storedZIndex?"":this._storedZIndex),this.dragging=!1,this.cancelHelperRemoval){if(!e){for(this._trigger("beforeStop",t,this._uiHash()),i=0;s.length>i;i++)s[i].call(this,t);this._trigger("stop",t,this._uiHash())}return this.fromOutside=!1,!1}if(e||this._trigger("beforeStop",t,this._uiHash()),this.placeholder[0].parentNode.removeChild(this.placeholder[0]),this.helper[0]!==this.currentItem[0]&&this.helper.remove(),this.helper=null,!e){for(i=0;s.length>i;i++)s[i].call(this,t);this._trigger("stop",t,this._uiHash())}return this.fromOutside=!1,!0},_trigger:function(){t.Widget.prototype._trigger.apply(this,arguments)===!1&&this.cancel()},_uiHash:function(e){var i=e||this;return{helper:i.helper,placeholder:i.placeholder||t([]),position:i.position,originalPosition:i.originalPosition,offset:i.positionAbs,item:i.currentItem,sender:e?e.element:null}}})}(jQuery),function(t,e){var i="ui-effects-";t.effects={effect:{}},function(t,e){function i(t,e,i){var s=u[e.type]||{};return null==t?i||!e.def?null:e.def:(t=s.floor?~~t:parseFloat(t),isNaN(t)?e.def:s.mod?(t+s.mod)%s.mod:0>t?0:t>s.max?s.max:t)}function s(i){var s=l(),n=s._rgba=[];return i=i.toLowerCase(),f(h,function(t,o){var a,r=o.re.exec(i),h=r&&o.parse(r),l=o.space||"rgba";return h?(a=s[l](h),s[c[l].cache]=a[c[l].cache],n=s._rgba=a._rgba,!1):e}),n.length?("0,0,0,0"===n.join()&&t.extend(n,o.transparent),s):o[i]}function n(t,e,i){return i=(i+1)%1,1>6*i?t+6*(e-t)*i:1>2*i?e:2>3*i?t+6*(e-t)*(2/3-i):t}var o,a="backgroundColor borderBottomColor borderLeftColor borderRightColor borderTopColor color columnRuleColor outlineColor textDecorationColor textEmphasisColor",r=/^([\-+])=\s*(\d+\.?\d*)/,h=[{re:/rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,parse:function(t){return[t[1],t[2],t[3],t[4]]}},{re:/rgba?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,parse:function(t){return[2.55*t[1],2.55*t[2],2.55*t[3],t[4]]}},{re:/#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})/,parse:function(t){return[parseInt(t[1],16),parseInt(t[2],16),parseInt(t[3],16)]}},{re:/#([a-f0-9])([a-f0-9])([a-f0-9])/,parse:function(t){return[parseInt(t[1]+t[1],16),parseInt(t[2]+t[2],16),parseInt(t[3]+t[3],16)]}},{re:/hsla?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,space:"hsla",parse:function(t){return[t[1],t[2]/100,t[3]/100,t[4]]}}],l=t.Color=function(e,i,s,n){return new t.Color.fn.parse(e,i,s,n)},c={rgba:{props:{red:{idx:0,type:"byte"},green:{idx:1,type:"byte"},blue:{idx:2,type:"byte"}}},hsla:{props:{hue:{idx:0,type:"degrees"},saturation:{idx:1,type:"percent"},lightness:{idx:2,type:"percent"}}}},u={"byte":{floor:!0,max:255},percent:{max:1},degrees:{mod:360,floor:!0}},d=l.support={},p=t("<p>")[0],f=t.each;p.style.cssText="background-color:rgba(1,1,1,.5)",d.rgba=p.style.backgroundColor.indexOf("rgba")>-1,f(c,function(t,e){e.cache="_"+t,e.props.alpha={idx:3,type:"percent",def:1}}),l.fn=t.extend(l.prototype,{parse:function(n,a,r,h){if(n===e)return this._rgba=[null,null,null,null],this;(n.jquery||n.nodeType)&&(n=t(n).css(a),a=e);var u=this,d=t.type(n),p=this._rgba=[];return a!==e&&(n=[n,a,r,h],d="array"),"string"===d?this.parse(s(n)||o._default):"array"===d?(f(c.rgba.props,function(t,e){p[e.idx]=i(n[e.idx],e)}),this):"object"===d?(n instanceof l?f(c,function(t,e){n[e.cache]&&(u[e.cache]=n[e.cache].slice())}):f(c,function(e,s){var o=s.cache;f(s.props,function(t,e){if(!u[o]&&s.to){if("alpha"===t||null==n[t])return;u[o]=s.to(u._rgba)}u[o][e.idx]=i(n[t],e,!0)}),u[o]&&0>t.inArray(null,u[o].slice(0,3))&&(u[o][3]=1,s.from&&(u._rgba=s.from(u[o])))}),this):e},is:function(t){var i=l(t),s=!0,n=this;return f(c,function(t,o){var a,r=i[o.cache];return r&&(a=n[o.cache]||o.to&&o.to(n._rgba)||[],f(o.props,function(t,i){return null!=r[i.idx]?s=r[i.idx]===a[i.idx]:e})),s}),s},_space:function(){var t=[],e=this;return f(c,function(i,s){e[s.cache]&&t.push(i)}),t.pop()},transition:function(t,e){var s=l(t),n=s._space(),o=c[n],a=0===this.alpha()?l("transparent"):this,r=a[o.cache]||o.to(a._rgba),h=r.slice();return s=s[o.cache],f(o.props,function(t,n){var o=n.idx,a=r[o],l=s[o],c=u[n.type]||{};null!==l&&(null===a?h[o]=l:(c.mod&&(l-a>c.mod/2?a+=c.mod:a-l>c.mod/2&&(a-=c.mod)),h[o]=i((l-a)*e+a,n)))}),this[n](h)},blend:function(e){if(1===this._rgba[3])return this;var i=this._rgba.slice(),s=i.pop(),n=l(e)._rgba;return l(t.map(i,function(t,e){return(1-s)*n[e]+s*t}))},toRgbaString:function(){var e="rgba(",i=t.map(this._rgba,function(t,e){return null==t?e>2?1:0:t});return 1===i[3]&&(i.pop(),e="rgb("),e+i.join()+")"},toHslaString:function(){var e="hsla(",i=t.map(this.hsla(),function(t,e){return null==t&&(t=e>2?1:0),e&&3>e&&(t=Math.round(100*t)+"%"),t});return 1===i[3]&&(i.pop(),e="hsl("),e+i.join()+")"},toHexString:function(e){var i=this._rgba.slice(),s=i.pop();return e&&i.push(~~(255*s)),"#"+t.map(i,function(t){return t=(t||0).toString(16),1===t.length?"0"+t:t}).join("")},toString:function(){return 0===this._rgba[3]?"transparent":this.toRgbaString()}}),l.fn.parse.prototype=l.fn,c.hsla.to=function(t){if(null==t[0]||null==t[1]||null==t[2])return[null,null,null,t[3]];var e,i,s=t[0]/255,n=t[1]/255,o=t[2]/255,a=t[3],r=Math.max(s,n,o),h=Math.min(s,n,o),l=r-h,c=r+h,u=.5*c;return e=h===r?0:s===r?60*(n-o)/l+360:n===r?60*(o-s)/l+120:60*(s-n)/l+240,i=0===l?0:.5>=u?l/c:l/(2-c),[Math.round(e)%360,i,u,null==a?1:a]},c.hsla.from=function(t){if(null==t[0]||null==t[1]||null==t[2])return[null,null,null,t[3]];var e=t[0]/360,i=t[1],s=t[2],o=t[3],a=.5>=s?s*(1+i):s+i-s*i,r=2*s-a;return[Math.round(255*n(r,a,e+1/3)),Math.round(255*n(r,a,e)),Math.round(255*n(r,a,e-1/3)),o]},f(c,function(s,n){var o=n.props,a=n.cache,h=n.to,c=n.from;l.fn[s]=function(s){if(h&&!this[a]&&(this[a]=h(this._rgba)),s===e)return this[a].slice();var n,r=t.type(s),u="array"===r||"object"===r?s:arguments,d=this[a].slice();return f(o,function(t,e){var s=u["object"===r?t:e.idx];null==s&&(s=d[e.idx]),d[e.idx]=i(s,e)}),c?(n=l(c(d)),n[a]=d,n):l(d)},f(o,function(e,i){l.fn[e]||(l.fn[e]=function(n){var o,a=t.type(n),h="alpha"===e?this._hsla?"hsla":"rgba":s,l=this[h](),c=l[i.idx];return"undefined"===a?c:("function"===a&&(n=n.call(this,c),a=t.type(n)),null==n&&i.empty?this:("string"===a&&(o=r.exec(n),o&&(n=c+parseFloat(o[2])*("+"===o[1]?1:-1))),l[i.idx]=n,this[h](l)))})})}),l.hook=function(e){var i=e.split(" ");f(i,function(e,i){t.cssHooks[i]={set:function(e,n){var o,a,r="";if("transparent"!==n&&("string"!==t.type(n)||(o=s(n)))){if(n=l(o||n),!d.rgba&&1!==n._rgba[3]){for(a="backgroundColor"===i?e.parentNode:e;(""===r||"transparent"===r)&&a&&a.style;)try{r=t.css(a,"backgroundColor"),a=a.parentNode}catch(h){}n=n.blend(r&&"transparent"!==r?r:"_default")}n=n.toRgbaString()}try{e.style[i]=n}catch(h){}}},t.fx.step[i]=function(e){e.colorInit||(e.start=l(e.elem,i),e.end=l(e.end),e.colorInit=!0),t.cssHooks[i].set(e.elem,e.start.transition(e.end,e.pos))}})},l.hook(a),t.cssHooks.borderColor={expand:function(t){var e={};return f(["Top","Right","Bottom","Left"],function(i,s){e["border"+s+"Color"]=t}),e}},o=t.Color.names={aqua:"#00ffff",black:"#000000",blue:"#0000ff",fuchsia:"#ff00ff",gray:"#808080",green:"#008000",lime:"#00ff00",maroon:"#800000",navy:"#000080",olive:"#808000",purple:"#800080",red:"#ff0000",silver:"#c0c0c0",teal:"#008080",white:"#ffffff",yellow:"#ffff00",transparent:[null,null,null,0],_default:"#ffffff"}}(jQuery),function(){function i(e){var i,s,n=e.ownerDocument.defaultView?e.ownerDocument.defaultView.getComputedStyle(e,null):e.currentStyle,o={};if(n&&n.length&&n[0]&&n[n[0]])for(s=n.length;s--;)i=n[s],"string"==typeof n[i]&&(o[t.camelCase(i)]=n[i]);else for(i in n)"string"==typeof n[i]&&(o[i]=n[i]);return o}function s(e,i){var s,n,a={};for(s in i)n=i[s],e[s]!==n&&(o[s]||(t.fx.step[s]||!isNaN(parseFloat(n)))&&(a[s]=n));return a}var n=["add","remove","toggle"],o={border:1,borderBottom:1,borderColor:1,borderLeft:1,borderRight:1,borderTop:1,borderWidth:1,margin:1,padding:1};t.each(["borderLeftStyle","borderRightStyle","borderBottomStyle","borderTopStyle"],function(e,i){t.fx.step[i]=function(t){("none"!==t.end&&!t.setAttr||1===t.pos&&!t.setAttr)&&(jQuery.style(t.elem,i,t.end),t.setAttr=!0)}}),t.fn.addBack||(t.fn.addBack=function(t){return this.add(null==t?this.prevObject:this.prevObject.filter(t))}),t.effects.animateClass=function(e,o,a,r){var h=t.speed(o,a,r);return this.queue(function(){var o,a=t(this),r=a.attr("class")||"",l=h.children?a.find("*").addBack():a;l=l.map(function(){var e=t(this);return{el:e,start:i(this)}}),o=function(){t.each(n,function(t,i){e[i]&&a[i+"Class"](e[i])})},o(),l=l.map(function(){return this.end=i(this.el[0]),this.diff=s(this.start,this.end),this}),a.attr("class",r),l=l.map(function(){var e=this,i=t.Deferred(),s=t.extend({},h,{queue:!1,complete:function(){i.resolve(e)}});return this.el.animate(this.diff,s),i.promise()}),t.when.apply(t,l.get()).done(function(){o(),t.each(arguments,function(){var e=this.el;t.each(this.diff,function(t){e.css(t,"")})}),h.complete.call(a[0])})})},t.fn.extend({addClass:function(e){return function(i,s,n,o){return s?t.effects.animateClass.call(this,{add:i},s,n,o):e.apply(this,arguments)}}(t.fn.addClass),removeClass:function(e){return function(i,s,n,o){return arguments.length>1?t.effects.animateClass.call(this,{remove:i},s,n,o):e.apply(this,arguments)}}(t.fn.removeClass),toggleClass:function(i){return function(s,n,o,a,r){return"boolean"==typeof n||n===e?o?t.effects.animateClass.call(this,n?{add:s}:{remove:s},o,a,r):i.apply(this,arguments):t.effects.animateClass.call(this,{toggle:s},n,o,a)}}(t.fn.toggleClass),switchClass:function(e,i,s,n,o){return t.effects.animateClass.call(this,{add:i,remove:e},s,n,o)}})}(),function(){function s(e,i,s,n){return t.isPlainObject(e)&&(i=e,e=e.effect),e={effect:e},null==i&&(i={}),t.isFunction(i)&&(n=i,s=null,i={}),("number"==typeof i||t.fx.speeds[i])&&(n=s,s=i,i={}),t.isFunction(s)&&(n=s,s=null),i&&t.extend(e,i),s=s||i.duration,e.duration=t.fx.off?0:"number"==typeof s?s:s in t.fx.speeds?t.fx.speeds[s]:t.fx.speeds._default,e.complete=n||i.complete,e}function n(e){return!e||"number"==typeof e||t.fx.speeds[e]?!0:"string"!=typeof e||t.effects.effect[e]?t.isFunction(e)?!0:"object"!=typeof e||e.effect?!1:!0:!0}t.extend(t.effects,{version:"1.10.2",save:function(t,e){for(var s=0;e.length>s;s++)null!==e[s]&&t.data(i+e[s],t[0].style[e[s]])},restore:function(t,s){var n,o;for(o=0;s.length>o;o++)null!==s[o]&&(n=t.data(i+s[o]),n===e&&(n=""),t.css(s[o],n))},setMode:function(t,e){return"toggle"===e&&(e=t.is(":hidden")?"show":"hide"),e},getBaseline:function(t,e){var i,s;switch(t[0]){case"top":i=0;break;case"middle":i=.5;break;case"bottom":i=1;break;default:i=t[0]/e.height}switch(t[1]){case"left":s=0;break;case"center":s=.5;break;case"right":s=1;break;default:s=t[1]/e.width}return{x:s,y:i}},createWrapper:function(e){if(e.parent().is(".ui-effects-wrapper"))return e.parent();var i={width:e.outerWidth(!0),height:e.outerHeight(!0),"float":e.css("float")},s=t("<div></div>").addClass("ui-effects-wrapper").css({fontSize:"100%",background:"transparent",border:"none",margin:0,padding:0}),n={width:e.width(),height:e.height()},o=document.activeElement;try{o.id}catch(a){o=document.body}return e.wrap(s),(e[0]===o||t.contains(e[0],o))&&t(o).focus(),s=e.parent(),"static"===e.css("position")?(s.css({position:"relative"}),e.css({position:"relative"})):(t.extend(i,{position:e.css("position"),zIndex:e.css("z-index")}),t.each(["top","left","bottom","right"],function(t,s){i[s]=e.css(s),isNaN(parseInt(i[s],10))&&(i[s]="auto")}),e.css({position:"relative",top:0,left:0,right:"auto",bottom:"auto"})),e.css(n),s.css(i).show()},removeWrapper:function(e){var i=document.activeElement;return e.parent().is(".ui-effects-wrapper")&&(e.parent().replaceWith(e),(e[0]===i||t.contains(e[0],i))&&t(i).focus()),e},setTransition:function(e,i,s,n){return n=n||{},t.each(i,function(t,i){var o=e.cssUnit(i);o[0]>0&&(n[i]=o[0]*s+o[1])}),n}}),t.fn.extend({effect:function(){function e(e){function s(){t.isFunction(o)&&o.call(n[0]),t.isFunction(e)&&e()}var n=t(this),o=i.complete,r=i.mode;(n.is(":hidden")?"hide"===r:"show"===r)?(n[r](),s()):a.call(n[0],i,s)}var i=s.apply(this,arguments),n=i.mode,o=i.queue,a=t.effects.effect[i.effect];return t.fx.off||!a?n?this[n](i.duration,i.complete):this.each(function(){i.complete&&i.complete.call(this)}):o===!1?this.each(e):this.queue(o||"fx",e)},show:function(t){return function(e){if(n(e))return t.apply(this,arguments);var i=s.apply(this,arguments);return i.mode="show",this.effect.call(this,i)}}(t.fn.show),hide:function(t){return function(e){if(n(e))return t.apply(this,arguments);var i=s.apply(this,arguments);return i.mode="hide",this.effect.call(this,i)}}(t.fn.hide),toggle:function(t){return function(e){if(n(e)||"boolean"==typeof e)return t.apply(this,arguments);var i=s.apply(this,arguments);return i.mode="toggle",this.effect.call(this,i)}}(t.fn.toggle),cssUnit:function(e){var i=this.css(e),s=[];return t.each(["em","px","%","pt"],function(t,e){i.indexOf(e)>0&&(s=[parseFloat(i),e])}),s}})}(),function(){var e={};t.each(["Quad","Cubic","Quart","Quint","Expo"],function(t,i){e[i]=function(e){return Math.pow(e,t+2)}}),t.extend(e,{Sine:function(t){return 1-Math.cos(t*Math.PI/2)},Circ:function(t){return 1-Math.sqrt(1-t*t)},Elastic:function(t){return 0===t||1===t?t:-Math.pow(2,8*(t-1))*Math.sin((80*(t-1)-7.5)*Math.PI/15)},Back:function(t){return t*t*(3*t-2)},Bounce:function(t){for(var e,i=4;((e=Math.pow(2,--i))-1)/11>t;);return 1/Math.pow(4,3-i)-7.5625*Math.pow((3*e-2)/22-t,2)}}),t.each(e,function(e,i){t.easing["easeIn"+e]=i,t.easing["easeOut"+e]=function(t){return 1-i(1-t)},t.easing["easeInOut"+e]=function(t){return.5>t?i(2*t)/2:1-i(-2*t+2)/2}})}()}(jQuery),function(t){var e=0,i={},s={};i.height=i.paddingTop=i.paddingBottom=i.borderTopWidth=i.borderBottomWidth="hide",s.height=s.paddingTop=s.paddingBottom=s.borderTopWidth=s.borderBottomWidth="show",t.widget("ui.accordion",{version:"1.10.2",options:{active:0,animate:{},collapsible:!1,event:"click",header:"> li > :first-child,> :not(li):even",heightStyle:"auto",icons:{activeHeader:"ui-icon-triangle-1-s",header:"ui-icon-triangle-1-e"},activate:null,beforeActivate:null},_create:function(){var e=this.options;this.prevShow=this.prevHide=t(),this.element.addClass("ui-accordion ui-widget ui-helper-reset").attr("role","tablist"),e.collapsible||e.active!==!1&&null!=e.active||(e.active=0),this._processPanels(),0>e.active&&(e.active+=this.headers.length),this._refresh()},_getCreateEventData:function(){return{header:this.active,panel:this.active.length?this.active.next():t(),content:this.active.length?this.active.next():t()}},_createIcons:function(){var e=this.options.icons;e&&(t("<span>").addClass("ui-accordion-header-icon ui-icon "+e.header).prependTo(this.headers),this.active.children(".ui-accordion-header-icon").removeClass(e.header).addClass(e.activeHeader),this.headers.addClass("ui-accordion-icons"))},_destroyIcons:function(){this.headers.removeClass("ui-accordion-icons").children(".ui-accordion-header-icon").remove() +},_destroy:function(){var t;this.element.removeClass("ui-accordion ui-widget ui-helper-reset").removeAttr("role"),this.headers.removeClass("ui-accordion-header ui-accordion-header-active ui-helper-reset ui-state-default ui-corner-all ui-state-active ui-state-disabled ui-corner-top").removeAttr("role").removeAttr("aria-selected").removeAttr("aria-controls").removeAttr("tabIndex").each(function(){/^ui-accordion/.test(this.id)&&this.removeAttribute("id")}),this._destroyIcons(),t=this.headers.next().css("display","").removeAttr("role").removeAttr("aria-expanded").removeAttr("aria-hidden").removeAttr("aria-labelledby").removeClass("ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active ui-state-disabled").each(function(){/^ui-accordion/.test(this.id)&&this.removeAttribute("id")}),"content"!==this.options.heightStyle&&t.css("height","")},_setOption:function(t,e){return"active"===t?(this._activate(e),undefined):("event"===t&&(this.options.event&&this._off(this.headers,this.options.event),this._setupEvents(e)),this._super(t,e),"collapsible"!==t||e||this.options.active!==!1||this._activate(0),"icons"===t&&(this._destroyIcons(),e&&this._createIcons()),"disabled"===t&&this.headers.add(this.headers.next()).toggleClass("ui-state-disabled",!!e),undefined)},_keydown:function(e){if(!e.altKey&&!e.ctrlKey){var i=t.ui.keyCode,s=this.headers.length,n=this.headers.index(e.target),o=!1;switch(e.keyCode){case i.RIGHT:case i.DOWN:o=this.headers[(n+1)%s];break;case i.LEFT:case i.UP:o=this.headers[(n-1+s)%s];break;case i.SPACE:case i.ENTER:this._eventHandler(e);break;case i.HOME:o=this.headers[0];break;case i.END:o=this.headers[s-1]}o&&(t(e.target).attr("tabIndex",-1),t(o).attr("tabIndex",0),o.focus(),e.preventDefault())}},_panelKeyDown:function(e){e.keyCode===t.ui.keyCode.UP&&e.ctrlKey&&t(e.currentTarget).prev().focus()},refresh:function(){var e=this.options;this._processPanels(),(e.active===!1&&e.collapsible===!0||!this.headers.length)&&(e.active=!1,this.active=t()),e.active===!1?this._activate(0):this.active.length&&!t.contains(this.element[0],this.active[0])?this.headers.length===this.headers.find(".ui-state-disabled").length?(e.active=!1,this.active=t()):this._activate(Math.max(0,e.active-1)):e.active=this.headers.index(this.active),this._destroyIcons(),this._refresh()},_processPanels:function(){this.headers=this.element.find(this.options.header).addClass("ui-accordion-header ui-helper-reset ui-state-default ui-corner-all"),this.headers.next().addClass("ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom").filter(":not(.ui-accordion-content-active)").hide()},_refresh:function(){var i,s=this.options,n=s.heightStyle,o=this.element.parent(),a=this.accordionId="ui-accordion-"+(this.element.attr("id")||++e);this.active=this._findActive(s.active).addClass("ui-accordion-header-active ui-state-active ui-corner-top").removeClass("ui-corner-all"),this.active.next().addClass("ui-accordion-content-active").show(),this.headers.attr("role","tab").each(function(e){var i=t(this),s=i.attr("id"),n=i.next(),o=n.attr("id");s||(s=a+"-header-"+e,i.attr("id",s)),o||(o=a+"-panel-"+e,n.attr("id",o)),i.attr("aria-controls",o),n.attr("aria-labelledby",s)}).next().attr("role","tabpanel"),this.headers.not(this.active).attr({"aria-selected":"false",tabIndex:-1}).next().attr({"aria-expanded":"false","aria-hidden":"true"}).hide(),this.active.length?this.active.attr({"aria-selected":"true",tabIndex:0}).next().attr({"aria-expanded":"true","aria-hidden":"false"}):this.headers.eq(0).attr("tabIndex",0),this._createIcons(),this._setupEvents(s.event),"fill"===n?(i=o.height(),this.element.siblings(":visible").each(function(){var e=t(this),s=e.css("position");"absolute"!==s&&"fixed"!==s&&(i-=e.outerHeight(!0))}),this.headers.each(function(){i-=t(this).outerHeight(!0)}),this.headers.next().each(function(){t(this).height(Math.max(0,i-t(this).innerHeight()+t(this).height()))}).css("overflow","auto")):"auto"===n&&(i=0,this.headers.next().each(function(){i=Math.max(i,t(this).css("height","").height())}).height(i))},_activate:function(e){var i=this._findActive(e)[0];i!==this.active[0]&&(i=i||this.active[0],this._eventHandler({target:i,currentTarget:i,preventDefault:t.noop}))},_findActive:function(e){return"number"==typeof e?this.headers.eq(e):t()},_setupEvents:function(e){var i={keydown:"_keydown"};e&&t.each(e.split(" "),function(t,e){i[e]="_eventHandler"}),this._off(this.headers.add(this.headers.next())),this._on(this.headers,i),this._on(this.headers.next(),{keydown:"_panelKeyDown"}),this._hoverable(this.headers),this._focusable(this.headers)},_eventHandler:function(e){var i=this.options,s=this.active,n=t(e.currentTarget),o=n[0]===s[0],a=o&&i.collapsible,r=a?t():n.next(),h=s.next(),l={oldHeader:s,oldPanel:h,newHeader:a?t():n,newPanel:r};e.preventDefault(),o&&!i.collapsible||this._trigger("beforeActivate",e,l)===!1||(i.active=a?!1:this.headers.index(n),this.active=o?t():n,this._toggle(l),s.removeClass("ui-accordion-header-active ui-state-active"),i.icons&&s.children(".ui-accordion-header-icon").removeClass(i.icons.activeHeader).addClass(i.icons.header),o||(n.removeClass("ui-corner-all").addClass("ui-accordion-header-active ui-state-active ui-corner-top"),i.icons&&n.children(".ui-accordion-header-icon").removeClass(i.icons.header).addClass(i.icons.activeHeader),n.next().addClass("ui-accordion-content-active")))},_toggle:function(e){var i=e.newPanel,s=this.prevShow.length?this.prevShow:e.oldPanel;this.prevShow.add(this.prevHide).stop(!0,!0),this.prevShow=i,this.prevHide=s,this.options.animate?this._animate(i,s,e):(s.hide(),i.show(),this._toggleComplete(e)),s.attr({"aria-expanded":"false","aria-hidden":"true"}),s.prev().attr("aria-selected","false"),i.length&&s.length?s.prev().attr("tabIndex",-1):i.length&&this.headers.filter(function(){return 0===t(this).attr("tabIndex")}).attr("tabIndex",-1),i.attr({"aria-expanded":"true","aria-hidden":"false"}).prev().attr({"aria-selected":"true",tabIndex:0})},_animate:function(t,e,n){var o,a,r,h=this,l=0,c=t.length&&(!e.length||t.index()<e.index()),u=this.options.animate||{},d=c&&u.down||u,p=function(){h._toggleComplete(n)};return"number"==typeof d&&(r=d),"string"==typeof d&&(a=d),a=a||d.easing||u.easing,r=r||d.duration||u.duration,e.length?t.length?(o=t.show().outerHeight(),e.animate(i,{duration:r,easing:a,step:function(t,e){e.now=Math.round(t)}}),t.hide().animate(s,{duration:r,easing:a,complete:p,step:function(t,i){i.now=Math.round(t),"height"!==i.prop?l+=i.now:"content"!==h.options.heightStyle&&(i.now=Math.round(o-e.outerHeight()-l),l=0)}}),undefined):e.animate(i,r,a,p):t.animate(s,r,a,p)},_toggleComplete:function(t){var e=t.oldPanel;e.removeClass("ui-accordion-content-active").prev().removeClass("ui-corner-top").addClass("ui-corner-all"),e.length&&(e.parent()[0].className=e.parent()[0].className),this._trigger("activate",null,t)}})}(jQuery),function(t){var e=0;t.widget("ui.autocomplete",{version:"1.10.2",defaultElement:"<input>",options:{appendTo:null,autoFocus:!1,delay:300,minLength:1,position:{my:"left top",at:"left bottom",collision:"none"},source:null,change:null,close:null,focus:null,open:null,response:null,search:null,select:null},pending:0,_create:function(){var e,i,s,n=this.element[0].nodeName.toLowerCase(),o="textarea"===n,a="input"===n;this.isMultiLine=o?!0:a?!1:this.element.prop("isContentEditable"),this.valueMethod=this.element[o||a?"val":"text"],this.isNewMenu=!0,this.element.addClass("ui-autocomplete-input").attr("autocomplete","off"),this._on(this.element,{keydown:function(n){if(this.element.prop("readOnly"))return e=!0,s=!0,i=!0,undefined;e=!1,s=!1,i=!1;var o=t.ui.keyCode;switch(n.keyCode){case o.PAGE_UP:e=!0,this._move("previousPage",n);break;case o.PAGE_DOWN:e=!0,this._move("nextPage",n);break;case o.UP:e=!0,this._keyEvent("previous",n);break;case o.DOWN:e=!0,this._keyEvent("next",n);break;case o.ENTER:case o.NUMPAD_ENTER:this.menu.active&&(e=!0,n.preventDefault(),this.menu.select(n));break;case o.TAB:this.menu.active&&this.menu.select(n);break;case o.ESCAPE:this.menu.element.is(":visible")&&(this._value(this.term),this.close(n),n.preventDefault());break;default:i=!0,this._searchTimeout(n)}},keypress:function(s){if(e)return e=!1,s.preventDefault(),undefined;if(!i){var n=t.ui.keyCode;switch(s.keyCode){case n.PAGE_UP:this._move("previousPage",s);break;case n.PAGE_DOWN:this._move("nextPage",s);break;case n.UP:this._keyEvent("previous",s);break;case n.DOWN:this._keyEvent("next",s)}}},input:function(t){return s?(s=!1,t.preventDefault(),undefined):(this._searchTimeout(t),undefined)},focus:function(){this.selectedItem=null,this.previous=this._value()},blur:function(t){return this.cancelBlur?(delete this.cancelBlur,undefined):(clearTimeout(this.searching),this.close(t),this._change(t),undefined)}}),this._initSource(),this.menu=t("<ul>").addClass("ui-autocomplete ui-front").appendTo(this._appendTo()).menu({input:t(),role:null}).hide().data("ui-menu"),this._on(this.menu.element,{mousedown:function(e){e.preventDefault(),this.cancelBlur=!0,this._delay(function(){delete this.cancelBlur});var i=this.menu.element[0];t(e.target).closest(".ui-menu-item").length||this._delay(function(){var e=this;this.document.one("mousedown",function(s){s.target===e.element[0]||s.target===i||t.contains(i,s.target)||e.close()})})},menufocus:function(e,i){if(this.isNewMenu&&(this.isNewMenu=!1,e.originalEvent&&/^mouse/.test(e.originalEvent.type)))return this.menu.blur(),this.document.one("mousemove",function(){t(e.target).trigger(e.originalEvent)}),undefined;var s=i.item.data("ui-autocomplete-item");!1!==this._trigger("focus",e,{item:s})?e.originalEvent&&/^key/.test(e.originalEvent.type)&&this._value(s.value):this.liveRegion.text(s.value)},menuselect:function(t,e){var i=e.item.data("ui-autocomplete-item"),s=this.previous;this.element[0]!==this.document[0].activeElement&&(this.element.focus(),this.previous=s,this._delay(function(){this.previous=s,this.selectedItem=i})),!1!==this._trigger("select",t,{item:i})&&this._value(i.value),this.term=this._value(),this.close(t),this.selectedItem=i}}),this.liveRegion=t("<span>",{role:"status","aria-live":"polite"}).addClass("ui-helper-hidden-accessible").insertAfter(this.element),this._on(this.window,{beforeunload:function(){this.element.removeAttr("autocomplete")}})},_destroy:function(){clearTimeout(this.searching),this.element.removeClass("ui-autocomplete-input").removeAttr("autocomplete"),this.menu.element.remove(),this.liveRegion.remove()},_setOption:function(t,e){this._super(t,e),"source"===t&&this._initSource(),"appendTo"===t&&this.menu.element.appendTo(this._appendTo()),"disabled"===t&&e&&this.xhr&&this.xhr.abort()},_appendTo:function(){var e=this.options.appendTo;return e&&(e=e.jquery||e.nodeType?t(e):this.document.find(e).eq(0)),e||(e=this.element.closest(".ui-front")),e.length||(e=this.document[0].body),e},_initSource:function(){var e,i,s=this;t.isArray(this.options.source)?(e=this.options.source,this.source=function(i,s){s(t.ui.autocomplete.filter(e,i.term))}):"string"==typeof this.options.source?(i=this.options.source,this.source=function(e,n){s.xhr&&s.xhr.abort(),s.xhr=t.ajax({url:i,data:e,dataType:"json",success:function(t){n(t)},error:function(){n([])}})}):this.source=this.options.source},_searchTimeout:function(t){clearTimeout(this.searching),this.searching=this._delay(function(){this.term!==this._value()&&(this.selectedItem=null,this.search(null,t))},this.options.delay)},search:function(t,e){return t=null!=t?t:this._value(),this.term=this._value(),t.length<this.options.minLength?this.close(e):this._trigger("search",e)!==!1?this._search(t):undefined},_search:function(t){this.pending++,this.element.addClass("ui-autocomplete-loading"),this.cancelSearch=!1,this.source({term:t},this._response())},_response:function(){var t=this,i=++e;return function(s){i===e&&t.__response(s),t.pending--,t.pending||t.element.removeClass("ui-autocomplete-loading")}},__response:function(t){t&&(t=this._normalize(t)),this._trigger("response",null,{content:t}),!this.options.disabled&&t&&t.length&&!this.cancelSearch?(this._suggest(t),this._trigger("open")):this._close()},close:function(t){this.cancelSearch=!0,this._close(t)},_close:function(t){this.menu.element.is(":visible")&&(this.menu.element.hide(),this.menu.blur(),this.isNewMenu=!0,this._trigger("close",t))},_change:function(t){this.previous!==this._value()&&this._trigger("change",t,{item:this.selectedItem})},_normalize:function(e){return e.length&&e[0].label&&e[0].value?e:t.map(e,function(e){return"string"==typeof e?{label:e,value:e}:t.extend({label:e.label||e.value,value:e.value||e.label},e)})},_suggest:function(e){var i=this.menu.element.empty();this._renderMenu(i,e),this.isNewMenu=!0,this.menu.refresh(),i.show(),this._resizeMenu(),i.position(t.extend({of:this.element},this.options.position)),this.options.autoFocus&&this.menu.next()},_resizeMenu:function(){var t=this.menu.element;t.outerWidth(Math.max(t.width("").outerWidth()+1,this.element.outerWidth()))},_renderMenu:function(e,i){var s=this;t.each(i,function(t,i){s._renderItemData(e,i)})},_renderItemData:function(t,e){return this._renderItem(t,e).data("ui-autocomplete-item",e)},_renderItem:function(e,i){return t("<li>").append(t("<a>").text(i.label)).appendTo(e)},_move:function(t,e){return this.menu.element.is(":visible")?this.menu.isFirstItem()&&/^previous/.test(t)||this.menu.isLastItem()&&/^next/.test(t)?(this._value(this.term),this.menu.blur(),undefined):(this.menu[t](e),undefined):(this.search(null,e),undefined)},widget:function(){return this.menu.element},_value:function(){return this.valueMethod.apply(this.element,arguments)},_keyEvent:function(t,e){(!this.isMultiLine||this.menu.element.is(":visible"))&&(this._move(t,e),e.preventDefault())}}),t.extend(t.ui.autocomplete,{escapeRegex:function(t){return t.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g,"\\$&")},filter:function(e,i){var s=RegExp(t.ui.autocomplete.escapeRegex(i),"i");return t.grep(e,function(t){return s.test(t.label||t.value||t)})}}),t.widget("ui.autocomplete",t.ui.autocomplete,{options:{messages:{noResults:"No search results.",results:function(t){return t+(t>1?" results are":" result is")+" available, use up and down arrow keys to navigate."}}},__response:function(t){var e;this._superApply(arguments),this.options.disabled||this.cancelSearch||(e=t&&t.length?this.options.messages.results(t.length):this.options.messages.noResults,this.liveRegion.text(e))}})}(jQuery),function(t){var e,i,s,n,o="ui-button ui-widget ui-state-default ui-corner-all",a="ui-state-hover ui-state-active ",r="ui-button-icons-only ui-button-icon-only ui-button-text-icons ui-button-text-icon-primary ui-button-text-icon-secondary ui-button-text-only",h=function(){var e=t(this).find(":ui-button");setTimeout(function(){e.button("refresh")},1)},l=function(e){var i=e.name,s=e.form,n=t([]);return i&&(i=i.replace(/'/g,"\\'"),n=s?t(s).find("[name='"+i+"']"):t("[name='"+i+"']",e.ownerDocument).filter(function(){return!this.form})),n};t.widget("ui.button",{version:"1.10.2",defaultElement:"<button>",options:{disabled:null,text:!0,label:null,icons:{primary:null,secondary:null}},_create:function(){this.element.closest("form").unbind("reset"+this.eventNamespace).bind("reset"+this.eventNamespace,h),"boolean"!=typeof this.options.disabled?this.options.disabled=!!this.element.prop("disabled"):this.element.prop("disabled",this.options.disabled),this._determineButtonType(),this.hasTitle=!!this.buttonElement.attr("title");var a=this,r=this.options,c="checkbox"===this.type||"radio"===this.type,u=c?"":"ui-state-active",d="ui-state-focus";null===r.label&&(r.label="input"===this.type?this.buttonElement.val():this.buttonElement.html()),this._hoverable(this.buttonElement),this.buttonElement.addClass(o).attr("role","button").bind("mouseenter"+this.eventNamespace,function(){r.disabled||this===e&&t(this).addClass("ui-state-active")}).bind("mouseleave"+this.eventNamespace,function(){r.disabled||t(this).removeClass(u)}).bind("click"+this.eventNamespace,function(t){r.disabled&&(t.preventDefault(),t.stopImmediatePropagation())}),this.element.bind("focus"+this.eventNamespace,function(){a.buttonElement.addClass(d)}).bind("blur"+this.eventNamespace,function(){a.buttonElement.removeClass(d)}),c&&(this.element.bind("change"+this.eventNamespace,function(){n||a.refresh()}),this.buttonElement.bind("mousedown"+this.eventNamespace,function(t){r.disabled||(n=!1,i=t.pageX,s=t.pageY)}).bind("mouseup"+this.eventNamespace,function(t){r.disabled||(i!==t.pageX||s!==t.pageY)&&(n=!0)})),"checkbox"===this.type?this.buttonElement.bind("click"+this.eventNamespace,function(){return r.disabled||n?!1:undefined}):"radio"===this.type?this.buttonElement.bind("click"+this.eventNamespace,function(){if(r.disabled||n)return!1;t(this).addClass("ui-state-active"),a.buttonElement.attr("aria-pressed","true");var e=a.element[0];l(e).not(e).map(function(){return t(this).button("widget")[0]}).removeClass("ui-state-active").attr("aria-pressed","false")}):(this.buttonElement.bind("mousedown"+this.eventNamespace,function(){return r.disabled?!1:(t(this).addClass("ui-state-active"),e=this,a.document.one("mouseup",function(){e=null}),undefined)}).bind("mouseup"+this.eventNamespace,function(){return r.disabled?!1:(t(this).removeClass("ui-state-active"),undefined)}).bind("keydown"+this.eventNamespace,function(e){return r.disabled?!1:((e.keyCode===t.ui.keyCode.SPACE||e.keyCode===t.ui.keyCode.ENTER)&&t(this).addClass("ui-state-active"),undefined)}).bind("keyup"+this.eventNamespace+" blur"+this.eventNamespace,function(){t(this).removeClass("ui-state-active")}),this.buttonElement.is("a")&&this.buttonElement.keyup(function(e){e.keyCode===t.ui.keyCode.SPACE&&t(this).click()})),this._setOption("disabled",r.disabled),this._resetButton()},_determineButtonType:function(){var t,e,i;this.type=this.element.is("[type=checkbox]")?"checkbox":this.element.is("[type=radio]")?"radio":this.element.is("input")?"input":"button","checkbox"===this.type||"radio"===this.type?(t=this.element.parents().last(),e="label[for='"+this.element.attr("id")+"']",this.buttonElement=t.find(e),this.buttonElement.length||(t=t.length?t.siblings():this.element.siblings(),this.buttonElement=t.filter(e),this.buttonElement.length||(this.buttonElement=t.find(e))),this.element.addClass("ui-helper-hidden-accessible"),i=this.element.is(":checked"),i&&this.buttonElement.addClass("ui-state-active"),this.buttonElement.prop("aria-pressed",i)):this.buttonElement=this.element},widget:function(){return this.buttonElement},_destroy:function(){this.element.removeClass("ui-helper-hidden-accessible"),this.buttonElement.removeClass(o+" "+a+" "+r).removeAttr("role").removeAttr("aria-pressed").html(this.buttonElement.find(".ui-button-text").html()),this.hasTitle||this.buttonElement.removeAttr("title")},_setOption:function(t,e){return this._super(t,e),"disabled"===t?(e?this.element.prop("disabled",!0):this.element.prop("disabled",!1),undefined):(this._resetButton(),undefined)},refresh:function(){var e=this.element.is("input, button")?this.element.is(":disabled"):this.element.hasClass("ui-button-disabled");e!==this.options.disabled&&this._setOption("disabled",e),"radio"===this.type?l(this.element[0]).each(function(){t(this).is(":checked")?t(this).button("widget").addClass("ui-state-active").attr("aria-pressed","true"):t(this).button("widget").removeClass("ui-state-active").attr("aria-pressed","false")}):"checkbox"===this.type&&(this.element.is(":checked")?this.buttonElement.addClass("ui-state-active").attr("aria-pressed","true"):this.buttonElement.removeClass("ui-state-active").attr("aria-pressed","false"))},_resetButton:function(){if("input"===this.type)return this.options.label&&this.element.val(this.options.label),undefined;var e=this.buttonElement.removeClass(r),i=t("<span></span>",this.document[0]).addClass("ui-button-text").html(this.options.label).appendTo(e.empty()).text(),s=this.options.icons,n=s.primary&&s.secondary,o=[];s.primary||s.secondary?(this.options.text&&o.push("ui-button-text-icon"+(n?"s":s.primary?"-primary":"-secondary")),s.primary&&e.prepend("<span class='ui-button-icon-primary ui-icon "+s.primary+"'></span>"),s.secondary&&e.append("<span class='ui-button-icon-secondary ui-icon "+s.secondary+"'></span>"),this.options.text||(o.push(n?"ui-button-icons-only":"ui-button-icon-only"),this.hasTitle||e.attr("title",t.trim(i)))):o.push("ui-button-text-only"),e.addClass(o.join(" "))}}),t.widget("ui.buttonset",{version:"1.10.2",options:{items:"button, input[type=button], input[type=submit], input[type=reset], input[type=checkbox], input[type=radio], a, :data(ui-button)"},_create:function(){this.element.addClass("ui-buttonset")},_init:function(){this.refresh()},_setOption:function(t,e){"disabled"===t&&this.buttons.button("option",t,e),this._super(t,e)},refresh:function(){var e="rtl"===this.element.css("direction");this.buttons=this.element.find(this.options.items).filter(":ui-button").button("refresh").end().not(":ui-button").button().end().map(function(){return t(this).button("widget")[0]}).removeClass("ui-corner-all ui-corner-left ui-corner-right").filter(":first").addClass(e?"ui-corner-right":"ui-corner-left").end().filter(":last").addClass(e?"ui-corner-left":"ui-corner-right").end().end()},_destroy:function(){this.element.removeClass("ui-buttonset"),this.buttons.map(function(){return t(this).button("widget")[0]}).removeClass("ui-corner-left ui-corner-right").end().button("destroy")}})}(jQuery),function(t,e){function i(){this._curInst=null,this._keyEvent=!1,this._disabledInputs=[],this._datepickerShowing=!1,this._inDialog=!1,this._mainDivId="ui-datepicker-div",this._inlineClass="ui-datepicker-inline",this._appendClass="ui-datepicker-append",this._triggerClass="ui-datepicker-trigger",this._dialogClass="ui-datepicker-dialog",this._disableClass="ui-datepicker-disabled",this._unselectableClass="ui-datepicker-unselectable",this._currentClass="ui-datepicker-current-day",this._dayOverClass="ui-datepicker-days-cell-over",this.regional=[],this.regional[""]={closeText:"Done",prevText:"Prev",nextText:"Next",currentText:"Today",monthNames:["January","February","March","April","May","June","July","August","September","October","November","December"],monthNamesShort:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],dayNames:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],dayNamesShort:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],dayNamesMin:["Su","Mo","Tu","We","Th","Fr","Sa"],weekHeader:"Wk",dateFormat:"mm/dd/yy",firstDay:0,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""},this._defaults={showOn:"focus",showAnim:"fadeIn",showOptions:{},defaultDate:null,appendText:"",buttonText:"...",buttonImage:"",buttonImageOnly:!1,hideIfNoPrevNext:!1,navigationAsDateFormat:!1,gotoCurrent:!1,changeMonth:!1,changeYear:!1,yearRange:"c-10:c+10",showOtherMonths:!1,selectOtherMonths:!1,showWeek:!1,calculateWeek:this.iso8601Week,shortYearCutoff:"+10",minDate:null,maxDate:null,duration:"fast",beforeShowDay:null,beforeShow:null,onSelect:null,onChangeMonthYear:null,onClose:null,numberOfMonths:1,showCurrentAtPos:0,stepMonths:1,stepBigMonths:12,altField:"",altFormat:"",constrainInput:!0,showButtonPanel:!1,autoSize:!1,disabled:!1},t.extend(this._defaults,this.regional[""]),this.dpDiv=s(t("<div id='"+this._mainDivId+"' class='ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>"))}function s(e){var i="button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a";return e.delegate(i,"mouseout",function(){t(this).removeClass("ui-state-hover"),-1!==this.className.indexOf("ui-datepicker-prev")&&t(this).removeClass("ui-datepicker-prev-hover"),-1!==this.className.indexOf("ui-datepicker-next")&&t(this).removeClass("ui-datepicker-next-hover")}).delegate(i,"mouseover",function(){t.datepicker._isDisabledDatepicker(o.inline?e.parent()[0]:o.input[0])||(t(this).parents(".ui-datepicker-calendar").find("a").removeClass("ui-state-hover"),t(this).addClass("ui-state-hover"),-1!==this.className.indexOf("ui-datepicker-prev")&&t(this).addClass("ui-datepicker-prev-hover"),-1!==this.className.indexOf("ui-datepicker-next")&&t(this).addClass("ui-datepicker-next-hover"))})}function n(e,i){t.extend(e,i);for(var s in i)null==i[s]&&(e[s]=i[s]);return e}t.extend(t.ui,{datepicker:{version:"1.10.2"}});var o,a="datepicker",r=(new Date).getTime();t.extend(i.prototype,{markerClassName:"hasDatepicker",maxRows:4,_widgetDatepicker:function(){return this.dpDiv},setDefaults:function(t){return n(this._defaults,t||{}),this},_attachDatepicker:function(e,i){var s,n,o;s=e.nodeName.toLowerCase(),n="div"===s||"span"===s,e.id||(this.uuid+=1,e.id="dp"+this.uuid),o=this._newInst(t(e),n),o.settings=t.extend({},i||{}),"input"===s?this._connectDatepicker(e,o):n&&this._inlineDatepicker(e,o)},_newInst:function(e,i){var n=e[0].id.replace(/([^A-Za-z0-9_\-])/g,"\\\\$1");return{id:n,input:e,selectedDay:0,selectedMonth:0,selectedYear:0,drawMonth:0,drawYear:0,inline:i,dpDiv:i?s(t("<div class='"+this._inlineClass+" ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>")):this.dpDiv}},_connectDatepicker:function(e,i){var s=t(e);i.append=t([]),i.trigger=t([]),s.hasClass(this.markerClassName)||(this._attachments(s,i),s.addClass(this.markerClassName).keydown(this._doKeyDown).keypress(this._doKeyPress).keyup(this._doKeyUp),this._autoSize(i),t.data(e,a,i),i.settings.disabled&&this._disableDatepicker(e))},_attachments:function(e,i){var s,n,o,a=this._get(i,"appendText"),r=this._get(i,"isRTL");i.append&&i.append.remove(),a&&(i.append=t("<span class='"+this._appendClass+"'>"+a+"</span>"),e[r?"before":"after"](i.append)),e.unbind("focus",this._showDatepicker),i.trigger&&i.trigger.remove(),s=this._get(i,"showOn"),("focus"===s||"both"===s)&&e.focus(this._showDatepicker),("button"===s||"both"===s)&&(n=this._get(i,"buttonText"),o=this._get(i,"buttonImage"),i.trigger=t(this._get(i,"buttonImageOnly")?t("<img/>").addClass(this._triggerClass).attr({src:o,alt:n,title:n}):t("<button type='button'></button>").addClass(this._triggerClass).html(o?t("<img/>").attr({src:o,alt:n,title:n}):n)),e[r?"before":"after"](i.trigger),i.trigger.click(function(){return t.datepicker._datepickerShowing&&t.datepicker._lastInput===e[0]?t.datepicker._hideDatepicker():t.datepicker._datepickerShowing&&t.datepicker._lastInput!==e[0]?(t.datepicker._hideDatepicker(),t.datepicker._showDatepicker(e[0])):t.datepicker._showDatepicker(e[0]),!1}))},_autoSize:function(t){if(this._get(t,"autoSize")&&!t.inline){var e,i,s,n,o=new Date(2009,11,20),a=this._get(t,"dateFormat");a.match(/[DM]/)&&(e=function(t){for(i=0,s=0,n=0;t.length>n;n++)t[n].length>i&&(i=t[n].length,s=n);return s},o.setMonth(e(this._get(t,a.match(/MM/)?"monthNames":"monthNamesShort"))),o.setDate(e(this._get(t,a.match(/DD/)?"dayNames":"dayNamesShort"))+20-o.getDay())),t.input.attr("size",this._formatDate(t,o).length)}},_inlineDatepicker:function(e,i){var s=t(e);s.hasClass(this.markerClassName)||(s.addClass(this.markerClassName).append(i.dpDiv),t.data(e,a,i),this._setDate(i,this._getDefaultDate(i),!0),this._updateDatepicker(i),this._updateAlternate(i),i.settings.disabled&&this._disableDatepicker(e),i.dpDiv.css("display","block"))},_dialogDatepicker:function(e,i,s,o,r){var h,l,c,u,d,p=this._dialogInst;return p||(this.uuid+=1,h="dp"+this.uuid,this._dialogInput=t("<input type='text' id='"+h+"' style='position: absolute; top: -100px; width: 0px;'/>"),this._dialogInput.keydown(this._doKeyDown),t("body").append(this._dialogInput),p=this._dialogInst=this._newInst(this._dialogInput,!1),p.settings={},t.data(this._dialogInput[0],a,p)),n(p.settings,o||{}),i=i&&i.constructor===Date?this._formatDate(p,i):i,this._dialogInput.val(i),this._pos=r?r.length?r:[r.pageX,r.pageY]:null,this._pos||(l=document.documentElement.clientWidth,c=document.documentElement.clientHeight,u=document.documentElement.scrollLeft||document.body.scrollLeft,d=document.documentElement.scrollTop||document.body.scrollTop,this._pos=[l/2-100+u,c/2-150+d]),this._dialogInput.css("left",this._pos[0]+20+"px").css("top",this._pos[1]+"px"),p.settings.onSelect=s,this._inDialog=!0,this.dpDiv.addClass(this._dialogClass),this._showDatepicker(this._dialogInput[0]),t.blockUI&&t.blockUI(this.dpDiv),t.data(this._dialogInput[0],a,p),this},_destroyDatepicker:function(e){var i,s=t(e),n=t.data(e,a);s.hasClass(this.markerClassName)&&(i=e.nodeName.toLowerCase(),t.removeData(e,a),"input"===i?(n.append.remove(),n.trigger.remove(),s.removeClass(this.markerClassName).unbind("focus",this._showDatepicker).unbind("keydown",this._doKeyDown).unbind("keypress",this._doKeyPress).unbind("keyup",this._doKeyUp)):("div"===i||"span"===i)&&s.removeClass(this.markerClassName).empty())},_enableDatepicker:function(e){var i,s,n=t(e),o=t.data(e,a);n.hasClass(this.markerClassName)&&(i=e.nodeName.toLowerCase(),"input"===i?(e.disabled=!1,o.trigger.filter("button").each(function(){this.disabled=!1}).end().filter("img").css({opacity:"1.0",cursor:""})):("div"===i||"span"===i)&&(s=n.children("."+this._inlineClass),s.children().removeClass("ui-state-disabled"),s.find("select.ui-datepicker-month, select.ui-datepicker-year").prop("disabled",!1)),this._disabledInputs=t.map(this._disabledInputs,function(t){return t===e?null:t}))},_disableDatepicker:function(e){var i,s,n=t(e),o=t.data(e,a);n.hasClass(this.markerClassName)&&(i=e.nodeName.toLowerCase(),"input"===i?(e.disabled=!0,o.trigger.filter("button").each(function(){this.disabled=!0}).end().filter("img").css({opacity:"0.5",cursor:"default"})):("div"===i||"span"===i)&&(s=n.children("."+this._inlineClass),s.children().addClass("ui-state-disabled"),s.find("select.ui-datepicker-month, select.ui-datepicker-year").prop("disabled",!0)),this._disabledInputs=t.map(this._disabledInputs,function(t){return t===e?null:t}),this._disabledInputs[this._disabledInputs.length]=e)},_isDisabledDatepicker:function(t){if(!t)return!1;for(var e=0;this._disabledInputs.length>e;e++)if(this._disabledInputs[e]===t)return!0;return!1},_getInst:function(e){try{return t.data(e,a)}catch(i){throw"Missing instance data for this datepicker"}},_optionDatepicker:function(i,s,o){var a,r,h,l,c=this._getInst(i);return 2===arguments.length&&"string"==typeof s?"defaults"===s?t.extend({},t.datepicker._defaults):c?"all"===s?t.extend({},c.settings):this._get(c,s):null:(a=s||{},"string"==typeof s&&(a={},a[s]=o),c&&(this._curInst===c&&this._hideDatepicker(),r=this._getDateDatepicker(i,!0),h=this._getMinMaxDate(c,"min"),l=this._getMinMaxDate(c,"max"),n(c.settings,a),null!==h&&a.dateFormat!==e&&a.minDate===e&&(c.settings.minDate=this._formatDate(c,h)),null!==l&&a.dateFormat!==e&&a.maxDate===e&&(c.settings.maxDate=this._formatDate(c,l)),"disabled"in a&&(a.disabled?this._disableDatepicker(i):this._enableDatepicker(i)),this._attachments(t(i),c),this._autoSize(c),this._setDate(c,r),this._updateAlternate(c),this._updateDatepicker(c)),e)},_changeDatepicker:function(t,e,i){this._optionDatepicker(t,e,i)},_refreshDatepicker:function(t){var e=this._getInst(t);e&&this._updateDatepicker(e)},_setDateDatepicker:function(t,e){var i=this._getInst(t);i&&(this._setDate(i,e),this._updateDatepicker(i),this._updateAlternate(i))},_getDateDatepicker:function(t,e){var i=this._getInst(t);return i&&!i.inline&&this._setDateFromField(i,e),i?this._getDate(i):null},_doKeyDown:function(e){var i,s,n,o=t.datepicker._getInst(e.target),a=!0,r=o.dpDiv.is(".ui-datepicker-rtl");if(o._keyEvent=!0,t.datepicker._datepickerShowing)switch(e.keyCode){case 9:t.datepicker._hideDatepicker(),a=!1;break;case 13:return n=t("td."+t.datepicker._dayOverClass+":not(."+t.datepicker._currentClass+")",o.dpDiv),n[0]&&t.datepicker._selectDay(e.target,o.selectedMonth,o.selectedYear,n[0]),i=t.datepicker._get(o,"onSelect"),i?(s=t.datepicker._formatDate(o),i.apply(o.input?o.input[0]:null,[s,o])):t.datepicker._hideDatepicker(),!1;case 27:t.datepicker._hideDatepicker();break;case 33:t.datepicker._adjustDate(e.target,e.ctrlKey?-t.datepicker._get(o,"stepBigMonths"):-t.datepicker._get(o,"stepMonths"),"M"); +break;case 34:t.datepicker._adjustDate(e.target,e.ctrlKey?+t.datepicker._get(o,"stepBigMonths"):+t.datepicker._get(o,"stepMonths"),"M");break;case 35:(e.ctrlKey||e.metaKey)&&t.datepicker._clearDate(e.target),a=e.ctrlKey||e.metaKey;break;case 36:(e.ctrlKey||e.metaKey)&&t.datepicker._gotoToday(e.target),a=e.ctrlKey||e.metaKey;break;case 37:(e.ctrlKey||e.metaKey)&&t.datepicker._adjustDate(e.target,r?1:-1,"D"),a=e.ctrlKey||e.metaKey,e.originalEvent.altKey&&t.datepicker._adjustDate(e.target,e.ctrlKey?-t.datepicker._get(o,"stepBigMonths"):-t.datepicker._get(o,"stepMonths"),"M");break;case 38:(e.ctrlKey||e.metaKey)&&t.datepicker._adjustDate(e.target,-7,"D"),a=e.ctrlKey||e.metaKey;break;case 39:(e.ctrlKey||e.metaKey)&&t.datepicker._adjustDate(e.target,r?-1:1,"D"),a=e.ctrlKey||e.metaKey,e.originalEvent.altKey&&t.datepicker._adjustDate(e.target,e.ctrlKey?+t.datepicker._get(o,"stepBigMonths"):+t.datepicker._get(o,"stepMonths"),"M");break;case 40:(e.ctrlKey||e.metaKey)&&t.datepicker._adjustDate(e.target,7,"D"),a=e.ctrlKey||e.metaKey;break;default:a=!1}else 36===e.keyCode&&e.ctrlKey?t.datepicker._showDatepicker(this):a=!1;a&&(e.preventDefault(),e.stopPropagation())},_doKeyPress:function(i){var s,n,o=t.datepicker._getInst(i.target);return t.datepicker._get(o,"constrainInput")?(s=t.datepicker._possibleChars(t.datepicker._get(o,"dateFormat")),n=String.fromCharCode(null==i.charCode?i.keyCode:i.charCode),i.ctrlKey||i.metaKey||" ">n||!s||s.indexOf(n)>-1):e},_doKeyUp:function(e){var i,s=t.datepicker._getInst(e.target);if(s.input.val()!==s.lastVal)try{i=t.datepicker.parseDate(t.datepicker._get(s,"dateFormat"),s.input?s.input.val():null,t.datepicker._getFormatConfig(s)),i&&(t.datepicker._setDateFromField(s),t.datepicker._updateAlternate(s),t.datepicker._updateDatepicker(s))}catch(n){}return!0},_showDatepicker:function(e){if(e=e.target||e,"input"!==e.nodeName.toLowerCase()&&(e=t("input",e.parentNode)[0]),!t.datepicker._isDisabledDatepicker(e)&&t.datepicker._lastInput!==e){var i,s,o,a,r,h,l;i=t.datepicker._getInst(e),t.datepicker._curInst&&t.datepicker._curInst!==i&&(t.datepicker._curInst.dpDiv.stop(!0,!0),i&&t.datepicker._datepickerShowing&&t.datepicker._hideDatepicker(t.datepicker._curInst.input[0])),s=t.datepicker._get(i,"beforeShow"),o=s?s.apply(e,[e,i]):{},o!==!1&&(n(i.settings,o),i.lastVal=null,t.datepicker._lastInput=e,t.datepicker._setDateFromField(i),t.datepicker._inDialog&&(e.value=""),t.datepicker._pos||(t.datepicker._pos=t.datepicker._findPos(e),t.datepicker._pos[1]+=e.offsetHeight),a=!1,t(e).parents().each(function(){return a|="fixed"===t(this).css("position"),!a}),r={left:t.datepicker._pos[0],top:t.datepicker._pos[1]},t.datepicker._pos=null,i.dpDiv.empty(),i.dpDiv.css({position:"absolute",display:"block",top:"-1000px"}),t.datepicker._updateDatepicker(i),r=t.datepicker._checkOffset(i,r,a),i.dpDiv.css({position:t.datepicker._inDialog&&t.blockUI?"static":a?"fixed":"absolute",display:"none",left:r.left+"px",top:r.top+"px"}),i.inline||(h=t.datepicker._get(i,"showAnim"),l=t.datepicker._get(i,"duration"),i.dpDiv.zIndex(t(e).zIndex()+1),t.datepicker._datepickerShowing=!0,t.effects&&t.effects.effect[h]?i.dpDiv.show(h,t.datepicker._get(i,"showOptions"),l):i.dpDiv[h||"show"](h?l:null),i.input.is(":visible")&&!i.input.is(":disabled")&&i.input.focus(),t.datepicker._curInst=i))}},_updateDatepicker:function(e){this.maxRows=4,o=e,e.dpDiv.empty().append(this._generateHTML(e)),this._attachHandlers(e),e.dpDiv.find("."+this._dayOverClass+" a").mouseover();var i,s=this._getNumberOfMonths(e),n=s[1],a=17;e.dpDiv.removeClass("ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4").width(""),n>1&&e.dpDiv.addClass("ui-datepicker-multi-"+n).css("width",a*n+"em"),e.dpDiv[(1!==s[0]||1!==s[1]?"add":"remove")+"Class"]("ui-datepicker-multi"),e.dpDiv[(this._get(e,"isRTL")?"add":"remove")+"Class"]("ui-datepicker-rtl"),e===t.datepicker._curInst&&t.datepicker._datepickerShowing&&e.input&&e.input.is(":visible")&&!e.input.is(":disabled")&&e.input[0]!==document.activeElement&&e.input.focus(),e.yearshtml&&(i=e.yearshtml,setTimeout(function(){i===e.yearshtml&&e.yearshtml&&e.dpDiv.find("select.ui-datepicker-year:first").replaceWith(e.yearshtml),i=e.yearshtml=null},0))},_getBorders:function(t){var e=function(t){return{thin:1,medium:2,thick:3}[t]||t};return[parseFloat(e(t.css("border-left-width"))),parseFloat(e(t.css("border-top-width")))]},_checkOffset:function(e,i,s){var n=e.dpDiv.outerWidth(),o=e.dpDiv.outerHeight(),a=e.input?e.input.outerWidth():0,r=e.input?e.input.outerHeight():0,h=document.documentElement.clientWidth+(s?0:t(document).scrollLeft()),l=document.documentElement.clientHeight+(s?0:t(document).scrollTop());return i.left-=this._get(e,"isRTL")?n-a:0,i.left-=s&&i.left===e.input.offset().left?t(document).scrollLeft():0,i.top-=s&&i.top===e.input.offset().top+r?t(document).scrollTop():0,i.left-=Math.min(i.left,i.left+n>h&&h>n?Math.abs(i.left+n-h):0),i.top-=Math.min(i.top,i.top+o>l&&l>o?Math.abs(o+r):0),i},_findPos:function(e){for(var i,s=this._getInst(e),n=this._get(s,"isRTL");e&&("hidden"===e.type||1!==e.nodeType||t.expr.filters.hidden(e));)e=e[n?"previousSibling":"nextSibling"];return i=t(e).offset(),[i.left,i.top]},_hideDatepicker:function(e){var i,s,n,o,r=this._curInst;!r||e&&r!==t.data(e,a)||this._datepickerShowing&&(i=this._get(r,"showAnim"),s=this._get(r,"duration"),n=function(){t.datepicker._tidyDialog(r)},t.effects&&(t.effects.effect[i]||t.effects[i])?r.dpDiv.hide(i,t.datepicker._get(r,"showOptions"),s,n):r.dpDiv["slideDown"===i?"slideUp":"fadeIn"===i?"fadeOut":"hide"](i?s:null,n),i||n(),this._datepickerShowing=!1,o=this._get(r,"onClose"),o&&o.apply(r.input?r.input[0]:null,[r.input?r.input.val():"",r]),this._lastInput=null,this._inDialog&&(this._dialogInput.css({position:"absolute",left:"0",top:"-100px"}),t.blockUI&&(t.unblockUI(),t("body").append(this.dpDiv))),this._inDialog=!1)},_tidyDialog:function(t){t.dpDiv.removeClass(this._dialogClass).unbind(".ui-datepicker-calendar")},_checkExternalClick:function(e){if(t.datepicker._curInst){var i=t(e.target),s=t.datepicker._getInst(i[0]);(i[0].id!==t.datepicker._mainDivId&&0===i.parents("#"+t.datepicker._mainDivId).length&&!i.hasClass(t.datepicker.markerClassName)&&!i.closest("."+t.datepicker._triggerClass).length&&t.datepicker._datepickerShowing&&(!t.datepicker._inDialog||!t.blockUI)||i.hasClass(t.datepicker.markerClassName)&&t.datepicker._curInst!==s)&&t.datepicker._hideDatepicker()}},_adjustDate:function(e,i,s){var n=t(e),o=this._getInst(n[0]);this._isDisabledDatepicker(n[0])||(this._adjustInstDate(o,i+("M"===s?this._get(o,"showCurrentAtPos"):0),s),this._updateDatepicker(o))},_gotoToday:function(e){var i,s=t(e),n=this._getInst(s[0]);this._get(n,"gotoCurrent")&&n.currentDay?(n.selectedDay=n.currentDay,n.drawMonth=n.selectedMonth=n.currentMonth,n.drawYear=n.selectedYear=n.currentYear):(i=new Date,n.selectedDay=i.getDate(),n.drawMonth=n.selectedMonth=i.getMonth(),n.drawYear=n.selectedYear=i.getFullYear()),this._notifyChange(n),this._adjustDate(s)},_selectMonthYear:function(e,i,s){var n=t(e),o=this._getInst(n[0]);o["selected"+("M"===s?"Month":"Year")]=o["draw"+("M"===s?"Month":"Year")]=parseInt(i.options[i.selectedIndex].value,10),this._notifyChange(o),this._adjustDate(n)},_selectDay:function(e,i,s,n){var o,a=t(e);t(n).hasClass(this._unselectableClass)||this._isDisabledDatepicker(a[0])||(o=this._getInst(a[0]),o.selectedDay=o.currentDay=t("a",n).html(),o.selectedMonth=o.currentMonth=i,o.selectedYear=o.currentYear=s,this._selectDate(e,this._formatDate(o,o.currentDay,o.currentMonth,o.currentYear)))},_clearDate:function(e){var i=t(e);this._selectDate(i,"")},_selectDate:function(e,i){var s,n=t(e),o=this._getInst(n[0]);i=null!=i?i:this._formatDate(o),o.input&&o.input.val(i),this._updateAlternate(o),s=this._get(o,"onSelect"),s?s.apply(o.input?o.input[0]:null,[i,o]):o.input&&o.input.trigger("change"),o.inline?this._updateDatepicker(o):(this._hideDatepicker(),this._lastInput=o.input[0],"object"!=typeof o.input[0]&&o.input.focus(),this._lastInput=null)},_updateAlternate:function(e){var i,s,n,o=this._get(e,"altField");o&&(i=this._get(e,"altFormat")||this._get(e,"dateFormat"),s=this._getDate(e),n=this.formatDate(i,s,this._getFormatConfig(e)),t(o).each(function(){t(this).val(n)}))},noWeekends:function(t){var e=t.getDay();return[e>0&&6>e,""]},iso8601Week:function(t){var e,i=new Date(t.getTime());return i.setDate(i.getDate()+4-(i.getDay()||7)),e=i.getTime(),i.setMonth(0),i.setDate(1),Math.floor(Math.round((e-i)/864e5)/7)+1},parseDate:function(i,s,n){if(null==i||null==s)throw"Invalid arguments";if(s="object"==typeof s?""+s:s+"",""===s)return null;var o,a,r,h,l=0,c=(n?n.shortYearCutoff:null)||this._defaults.shortYearCutoff,u="string"!=typeof c?c:(new Date).getFullYear()%100+parseInt(c,10),d=(n?n.dayNamesShort:null)||this._defaults.dayNamesShort,p=(n?n.dayNames:null)||this._defaults.dayNames,f=(n?n.monthNamesShort:null)||this._defaults.monthNamesShort,g=(n?n.monthNames:null)||this._defaults.monthNames,m=-1,v=-1,_=-1,b=-1,y=!1,w=function(t){var e=i.length>o+1&&i.charAt(o+1)===t;return e&&o++,e},k=function(t){var e=w(t),i="@"===t?14:"!"===t?20:"y"===t&&e?4:"o"===t?3:2,n=RegExp("^\\d{1,"+i+"}"),o=s.substring(l).match(n);if(!o)throw"Missing number at position "+l;return l+=o[0].length,parseInt(o[0],10)},x=function(i,n,o){var a=-1,r=t.map(w(i)?o:n,function(t,e){return[[e,t]]}).sort(function(t,e){return-(t[1].length-e[1].length)});if(t.each(r,function(t,i){var n=i[1];return s.substr(l,n.length).toLowerCase()===n.toLowerCase()?(a=i[0],l+=n.length,!1):e}),-1!==a)return a+1;throw"Unknown name at position "+l},D=function(){if(s.charAt(l)!==i.charAt(o))throw"Unexpected literal at position "+l;l++};for(o=0;i.length>o;o++)if(y)"'"!==i.charAt(o)||w("'")?D():y=!1;else switch(i.charAt(o)){case"d":_=k("d");break;case"D":x("D",d,p);break;case"o":b=k("o");break;case"m":v=k("m");break;case"M":v=x("M",f,g);break;case"y":m=k("y");break;case"@":h=new Date(k("@")),m=h.getFullYear(),v=h.getMonth()+1,_=h.getDate();break;case"!":h=new Date((k("!")-this._ticksTo1970)/1e4),m=h.getFullYear(),v=h.getMonth()+1,_=h.getDate();break;case"'":w("'")?D():y=!0;break;default:D()}if(s.length>l&&(r=s.substr(l),!/^\s+/.test(r)))throw"Extra/unparsed characters found in date: "+r;if(-1===m?m=(new Date).getFullYear():100>m&&(m+=(new Date).getFullYear()-(new Date).getFullYear()%100+(u>=m?0:-100)),b>-1)for(v=1,_=b;;){if(a=this._getDaysInMonth(m,v-1),a>=_)break;v++,_-=a}if(h=this._daylightSavingAdjust(new Date(m,v-1,_)),h.getFullYear()!==m||h.getMonth()+1!==v||h.getDate()!==_)throw"Invalid date";return h},ATOM:"yy-mm-dd",COOKIE:"D, dd M yy",ISO_8601:"yy-mm-dd",RFC_822:"D, d M y",RFC_850:"DD, dd-M-y",RFC_1036:"D, d M y",RFC_1123:"D, d M yy",RFC_2822:"D, d M yy",RSS:"D, d M y",TICKS:"!",TIMESTAMP:"@",W3C:"yy-mm-dd",_ticksTo1970:1e7*60*60*24*(718685+Math.floor(492.5)-Math.floor(19.7)+Math.floor(4.925)),formatDate:function(t,e,i){if(!e)return"";var s,n=(i?i.dayNamesShort:null)||this._defaults.dayNamesShort,o=(i?i.dayNames:null)||this._defaults.dayNames,a=(i?i.monthNamesShort:null)||this._defaults.monthNamesShort,r=(i?i.monthNames:null)||this._defaults.monthNames,h=function(e){var i=t.length>s+1&&t.charAt(s+1)===e;return i&&s++,i},l=function(t,e,i){var s=""+e;if(h(t))for(;i>s.length;)s="0"+s;return s},c=function(t,e,i,s){return h(t)?s[e]:i[e]},u="",d=!1;if(e)for(s=0;t.length>s;s++)if(d)"'"!==t.charAt(s)||h("'")?u+=t.charAt(s):d=!1;else switch(t.charAt(s)){case"d":u+=l("d",e.getDate(),2);break;case"D":u+=c("D",e.getDay(),n,o);break;case"o":u+=l("o",Math.round((new Date(e.getFullYear(),e.getMonth(),e.getDate()).getTime()-new Date(e.getFullYear(),0,0).getTime())/864e5),3);break;case"m":u+=l("m",e.getMonth()+1,2);break;case"M":u+=c("M",e.getMonth(),a,r);break;case"y":u+=h("y")?e.getFullYear():(10>e.getYear()%100?"0":"")+e.getYear()%100;break;case"@":u+=e.getTime();break;case"!":u+=1e4*e.getTime()+this._ticksTo1970;break;case"'":h("'")?u+="'":d=!0;break;default:u+=t.charAt(s)}return u},_possibleChars:function(t){var e,i="",s=!1,n=function(i){var s=t.length>e+1&&t.charAt(e+1)===i;return s&&e++,s};for(e=0;t.length>e;e++)if(s)"'"!==t.charAt(e)||n("'")?i+=t.charAt(e):s=!1;else switch(t.charAt(e)){case"d":case"m":case"y":case"@":i+="0123456789";break;case"D":case"M":return null;case"'":n("'")?i+="'":s=!0;break;default:i+=t.charAt(e)}return i},_get:function(t,i){return t.settings[i]!==e?t.settings[i]:this._defaults[i]},_setDateFromField:function(t,e){if(t.input.val()!==t.lastVal){var i=this._get(t,"dateFormat"),s=t.lastVal=t.input?t.input.val():null,n=this._getDefaultDate(t),o=n,a=this._getFormatConfig(t);try{o=this.parseDate(i,s,a)||n}catch(r){s=e?"":s}t.selectedDay=o.getDate(),t.drawMonth=t.selectedMonth=o.getMonth(),t.drawYear=t.selectedYear=o.getFullYear(),t.currentDay=s?o.getDate():0,t.currentMonth=s?o.getMonth():0,t.currentYear=s?o.getFullYear():0,this._adjustInstDate(t)}},_getDefaultDate:function(t){return this._restrictMinMax(t,this._determineDate(t,this._get(t,"defaultDate"),new Date))},_determineDate:function(e,i,s){var n=function(t){var e=new Date;return e.setDate(e.getDate()+t),e},o=function(i){try{return t.datepicker.parseDate(t.datepicker._get(e,"dateFormat"),i,t.datepicker._getFormatConfig(e))}catch(s){}for(var n=(i.toLowerCase().match(/^c/)?t.datepicker._getDate(e):null)||new Date,o=n.getFullYear(),a=n.getMonth(),r=n.getDate(),h=/([+\-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g,l=h.exec(i);l;){switch(l[2]||"d"){case"d":case"D":r+=parseInt(l[1],10);break;case"w":case"W":r+=7*parseInt(l[1],10);break;case"m":case"M":a+=parseInt(l[1],10),r=Math.min(r,t.datepicker._getDaysInMonth(o,a));break;case"y":case"Y":o+=parseInt(l[1],10),r=Math.min(r,t.datepicker._getDaysInMonth(o,a))}l=h.exec(i)}return new Date(o,a,r)},a=null==i||""===i?s:"string"==typeof i?o(i):"number"==typeof i?isNaN(i)?s:n(i):new Date(i.getTime());return a=a&&"Invalid Date"==""+a?s:a,a&&(a.setHours(0),a.setMinutes(0),a.setSeconds(0),a.setMilliseconds(0)),this._daylightSavingAdjust(a)},_daylightSavingAdjust:function(t){return t?(t.setHours(t.getHours()>12?t.getHours()+2:0),t):null},_setDate:function(t,e,i){var s=!e,n=t.selectedMonth,o=t.selectedYear,a=this._restrictMinMax(t,this._determineDate(t,e,new Date));t.selectedDay=t.currentDay=a.getDate(),t.drawMonth=t.selectedMonth=t.currentMonth=a.getMonth(),t.drawYear=t.selectedYear=t.currentYear=a.getFullYear(),n===t.selectedMonth&&o===t.selectedYear||i||this._notifyChange(t),this._adjustInstDate(t),t.input&&t.input.val(s?"":this._formatDate(t))},_getDate:function(t){var e=!t.currentYear||t.input&&""===t.input.val()?null:this._daylightSavingAdjust(new Date(t.currentYear,t.currentMonth,t.currentDay));return e},_attachHandlers:function(e){var i=this._get(e,"stepMonths"),s="#"+e.id.replace(/\\\\/g,"\\");e.dpDiv.find("[data-handler]").map(function(){var e={prev:function(){window["DP_jQuery_"+r].datepicker._adjustDate(s,-i,"M")},next:function(){window["DP_jQuery_"+r].datepicker._adjustDate(s,+i,"M")},hide:function(){window["DP_jQuery_"+r].datepicker._hideDatepicker()},today:function(){window["DP_jQuery_"+r].datepicker._gotoToday(s)},selectDay:function(){return window["DP_jQuery_"+r].datepicker._selectDay(s,+this.getAttribute("data-month"),+this.getAttribute("data-year"),this),!1},selectMonth:function(){return window["DP_jQuery_"+r].datepicker._selectMonthYear(s,this,"M"),!1},selectYear:function(){return window["DP_jQuery_"+r].datepicker._selectMonthYear(s,this,"Y"),!1}};t(this).bind(this.getAttribute("data-event"),e[this.getAttribute("data-handler")])})},_generateHTML:function(t){var e,i,s,n,o,a,r,h,l,c,u,d,p,f,g,m,v,_,b,y,w,k,x,D,C,I,P,T,M,S,z,A,H,N,E,W,O,F,R,j=new Date,L=this._daylightSavingAdjust(new Date(j.getFullYear(),j.getMonth(),j.getDate())),Y=this._get(t,"isRTL"),B=this._get(t,"showButtonPanel"),V=this._get(t,"hideIfNoPrevNext"),K=this._get(t,"navigationAsDateFormat"),U=this._getNumberOfMonths(t),q=this._get(t,"showCurrentAtPos"),Q=this._get(t,"stepMonths"),X=1!==U[0]||1!==U[1],$=this._daylightSavingAdjust(t.currentDay?new Date(t.currentYear,t.currentMonth,t.currentDay):new Date(9999,9,9)),G=this._getMinMaxDate(t,"min"),J=this._getMinMaxDate(t,"max"),Z=t.drawMonth-q,te=t.drawYear;if(0>Z&&(Z+=12,te--),J)for(e=this._daylightSavingAdjust(new Date(J.getFullYear(),J.getMonth()-U[0]*U[1]+1,J.getDate())),e=G&&G>e?G:e;this._daylightSavingAdjust(new Date(te,Z,1))>e;)Z--,0>Z&&(Z=11,te--);for(t.drawMonth=Z,t.drawYear=te,i=this._get(t,"prevText"),i=K?this.formatDate(i,this._daylightSavingAdjust(new Date(te,Z-Q,1)),this._getFormatConfig(t)):i,s=this._canAdjustMonth(t,-1,te,Z)?"<a class='ui-datepicker-prev ui-corner-all' data-handler='prev' data-event='click' title='"+i+"'><span class='ui-icon ui-icon-circle-triangle-"+(Y?"e":"w")+"'>"+i+"</span></a>":V?"":"<a class='ui-datepicker-prev ui-corner-all ui-state-disabled' title='"+i+"'><span class='ui-icon ui-icon-circle-triangle-"+(Y?"e":"w")+"'>"+i+"</span></a>",n=this._get(t,"nextText"),n=K?this.formatDate(n,this._daylightSavingAdjust(new Date(te,Z+Q,1)),this._getFormatConfig(t)):n,o=this._canAdjustMonth(t,1,te,Z)?"<a class='ui-datepicker-next ui-corner-all' data-handler='next' data-event='click' title='"+n+"'><span class='ui-icon ui-icon-circle-triangle-"+(Y?"w":"e")+"'>"+n+"</span></a>":V?"":"<a class='ui-datepicker-next ui-corner-all ui-state-disabled' title='"+n+"'><span class='ui-icon ui-icon-circle-triangle-"+(Y?"w":"e")+"'>"+n+"</span></a>",a=this._get(t,"currentText"),r=this._get(t,"gotoCurrent")&&t.currentDay?$:L,a=K?this.formatDate(a,r,this._getFormatConfig(t)):a,h=t.inline?"":"<button type='button' class='ui-datepicker-close ui-state-default ui-priority-primary ui-corner-all' data-handler='hide' data-event='click'>"+this._get(t,"closeText")+"</button>",l=B?"<div class='ui-datepicker-buttonpane ui-widget-content'>"+(Y?h:"")+(this._isInRange(t,r)?"<button type='button' class='ui-datepicker-current ui-state-default ui-priority-secondary ui-corner-all' data-handler='today' data-event='click'>"+a+"</button>":"")+(Y?"":h)+"</div>":"",c=parseInt(this._get(t,"firstDay"),10),c=isNaN(c)?0:c,u=this._get(t,"showWeek"),d=this._get(t,"dayNames"),p=this._get(t,"dayNamesMin"),f=this._get(t,"monthNames"),g=this._get(t,"monthNamesShort"),m=this._get(t,"beforeShowDay"),v=this._get(t,"showOtherMonths"),_=this._get(t,"selectOtherMonths"),b=this._getDefaultDate(t),y="",k=0;U[0]>k;k++){for(x="",this.maxRows=4,D=0;U[1]>D;D++){if(C=this._daylightSavingAdjust(new Date(te,Z,t.selectedDay)),I=" ui-corner-all",P="",X){if(P+="<div class='ui-datepicker-group",U[1]>1)switch(D){case 0:P+=" ui-datepicker-group-first",I=" ui-corner-"+(Y?"right":"left");break;case U[1]-1:P+=" ui-datepicker-group-last",I=" ui-corner-"+(Y?"left":"right");break;default:P+=" ui-datepicker-group-middle",I=""}P+="'>"}for(P+="<div class='ui-datepicker-header ui-widget-header ui-helper-clearfix"+I+"'>"+(/all|left/.test(I)&&0===k?Y?o:s:"")+(/all|right/.test(I)&&0===k?Y?s:o:"")+this._generateMonthYearHeader(t,Z,te,G,J,k>0||D>0,f,g)+"</div><table class='ui-datepicker-calendar'><thead>"+"<tr>",T=u?"<th class='ui-datepicker-week-col'>"+this._get(t,"weekHeader")+"</th>":"",w=0;7>w;w++)M=(w+c)%7,T+="<th"+((w+c+6)%7>=5?" class='ui-datepicker-week-end'":"")+">"+"<span title='"+d[M]+"'>"+p[M]+"</span></th>";for(P+=T+"</tr></thead><tbody>",S=this._getDaysInMonth(te,Z),te===t.selectedYear&&Z===t.selectedMonth&&(t.selectedDay=Math.min(t.selectedDay,S)),z=(this._getFirstDayOfMonth(te,Z)-c+7)%7,A=Math.ceil((z+S)/7),H=X?this.maxRows>A?this.maxRows:A:A,this.maxRows=H,N=this._daylightSavingAdjust(new Date(te,Z,1-z)),E=0;H>E;E++){for(P+="<tr>",W=u?"<td class='ui-datepicker-week-col'>"+this._get(t,"calculateWeek")(N)+"</td>":"",w=0;7>w;w++)O=m?m.apply(t.input?t.input[0]:null,[N]):[!0,""],F=N.getMonth()!==Z,R=F&&!_||!O[0]||G&&G>N||J&&N>J,W+="<td class='"+((w+c+6)%7>=5?" ui-datepicker-week-end":"")+(F?" ui-datepicker-other-month":"")+(N.getTime()===C.getTime()&&Z===t.selectedMonth&&t._keyEvent||b.getTime()===N.getTime()&&b.getTime()===C.getTime()?" "+this._dayOverClass:"")+(R?" "+this._unselectableClass+" ui-state-disabled":"")+(F&&!v?"":" "+O[1]+(N.getTime()===$.getTime()?" "+this._currentClass:"")+(N.getTime()===L.getTime()?" ui-datepicker-today":""))+"'"+(F&&!v||!O[2]?"":" title='"+O[2].replace(/'/g,"'")+"'")+(R?"":" data-handler='selectDay' data-event='click' data-month='"+N.getMonth()+"' data-year='"+N.getFullYear()+"'")+">"+(F&&!v?" ":R?"<span class='ui-state-default'>"+N.getDate()+"</span>":"<a class='ui-state-default"+(N.getTime()===L.getTime()?" ui-state-highlight":"")+(N.getTime()===$.getTime()?" ui-state-active":"")+(F?" ui-priority-secondary":"")+"' href='#'>"+N.getDate()+"</a>")+"</td>",N.setDate(N.getDate()+1),N=this._daylightSavingAdjust(N);P+=W+"</tr>"}Z++,Z>11&&(Z=0,te++),P+="</tbody></table>"+(X?"</div>"+(U[0]>0&&D===U[1]-1?"<div class='ui-datepicker-row-break'></div>":""):""),x+=P}y+=x}return y+=l,t._keyEvent=!1,y},_generateMonthYearHeader:function(t,e,i,s,n,o,a,r){var h,l,c,u,d,p,f,g,m=this._get(t,"changeMonth"),v=this._get(t,"changeYear"),_=this._get(t,"showMonthAfterYear"),b="<div class='ui-datepicker-title'>",y="";if(o||!m)y+="<span class='ui-datepicker-month'>"+a[e]+"</span>";else{for(h=s&&s.getFullYear()===i,l=n&&n.getFullYear()===i,y+="<select class='ui-datepicker-month' data-handler='selectMonth' data-event='change'>",c=0;12>c;c++)(!h||c>=s.getMonth())&&(!l||n.getMonth()>=c)&&(y+="<option value='"+c+"'"+(c===e?" selected='selected'":"")+">"+r[c]+"</option>");y+="</select>"}if(_||(b+=y+(!o&&m&&v?"":" ")),!t.yearshtml)if(t.yearshtml="",o||!v)b+="<span class='ui-datepicker-year'>"+i+"</span>";else{for(u=this._get(t,"yearRange").split(":"),d=(new Date).getFullYear(),p=function(t){var e=t.match(/c[+\-].*/)?i+parseInt(t.substring(1),10):t.match(/[+\-].*/)?d+parseInt(t,10):parseInt(t,10);return isNaN(e)?d:e},f=p(u[0]),g=Math.max(f,p(u[1]||"")),f=s?Math.max(f,s.getFullYear()):f,g=n?Math.min(g,n.getFullYear()):g,t.yearshtml+="<select class='ui-datepicker-year' data-handler='selectYear' data-event='change'>";g>=f;f++)t.yearshtml+="<option value='"+f+"'"+(f===i?" selected='selected'":"")+">"+f+"</option>";t.yearshtml+="</select>",b+=t.yearshtml,t.yearshtml=null}return b+=this._get(t,"yearSuffix"),_&&(b+=(!o&&m&&v?"":" ")+y),b+="</div>"},_adjustInstDate:function(t,e,i){var s=t.drawYear+("Y"===i?e:0),n=t.drawMonth+("M"===i?e:0),o=Math.min(t.selectedDay,this._getDaysInMonth(s,n))+("D"===i?e:0),a=this._restrictMinMax(t,this._daylightSavingAdjust(new Date(s,n,o)));t.selectedDay=a.getDate(),t.drawMonth=t.selectedMonth=a.getMonth(),t.drawYear=t.selectedYear=a.getFullYear(),("M"===i||"Y"===i)&&this._notifyChange(t)},_restrictMinMax:function(t,e){var i=this._getMinMaxDate(t,"min"),s=this._getMinMaxDate(t,"max"),n=i&&i>e?i:e;return s&&n>s?s:n},_notifyChange:function(t){var e=this._get(t,"onChangeMonthYear");e&&e.apply(t.input?t.input[0]:null,[t.selectedYear,t.selectedMonth+1,t])},_getNumberOfMonths:function(t){var e=this._get(t,"numberOfMonths");return null==e?[1,1]:"number"==typeof e?[1,e]:e},_getMinMaxDate:function(t,e){return this._determineDate(t,this._get(t,e+"Date"),null)},_getDaysInMonth:function(t,e){return 32-this._daylightSavingAdjust(new Date(t,e,32)).getDate()},_getFirstDayOfMonth:function(t,e){return new Date(t,e,1).getDay()},_canAdjustMonth:function(t,e,i,s){var n=this._getNumberOfMonths(t),o=this._daylightSavingAdjust(new Date(i,s+(0>e?e:n[0]*n[1]),1));return 0>e&&o.setDate(this._getDaysInMonth(o.getFullYear(),o.getMonth())),this._isInRange(t,o)},_isInRange:function(t,e){var i,s,n=this._getMinMaxDate(t,"min"),o=this._getMinMaxDate(t,"max"),a=null,r=null,h=this._get(t,"yearRange");return h&&(i=h.split(":"),s=(new Date).getFullYear(),a=parseInt(i[0],10),r=parseInt(i[1],10),i[0].match(/[+\-].*/)&&(a+=s),i[1].match(/[+\-].*/)&&(r+=s)),(!n||e.getTime()>=n.getTime())&&(!o||e.getTime()<=o.getTime())&&(!a||e.getFullYear()>=a)&&(!r||r>=e.getFullYear())},_getFormatConfig:function(t){var e=this._get(t,"shortYearCutoff");return e="string"!=typeof e?e:(new Date).getFullYear()%100+parseInt(e,10),{shortYearCutoff:e,dayNamesShort:this._get(t,"dayNamesShort"),dayNames:this._get(t,"dayNames"),monthNamesShort:this._get(t,"monthNamesShort"),monthNames:this._get(t,"monthNames")}},_formatDate:function(t,e,i,s){e||(t.currentDay=t.selectedDay,t.currentMonth=t.selectedMonth,t.currentYear=t.selectedYear);var n=e?"object"==typeof e?e:this._daylightSavingAdjust(new Date(s,i,e)):this._daylightSavingAdjust(new Date(t.currentYear,t.currentMonth,t.currentDay));return this.formatDate(this._get(t,"dateFormat"),n,this._getFormatConfig(t))}}),t.fn.datepicker=function(e){if(!this.length)return this;t.datepicker.initialized||(t(document).mousedown(t.datepicker._checkExternalClick),t.datepicker.initialized=!0),0===t("#"+t.datepicker._mainDivId).length&&t("body").append(t.datepicker.dpDiv);var i=Array.prototype.slice.call(arguments,1);return"string"!=typeof e||"isDisabled"!==e&&"getDate"!==e&&"widget"!==e?"option"===e&&2===arguments.length&&"string"==typeof arguments[1]?t.datepicker["_"+e+"Datepicker"].apply(t.datepicker,[this[0]].concat(i)):this.each(function(){"string"==typeof e?t.datepicker["_"+e+"Datepicker"].apply(t.datepicker,[this].concat(i)):t.datepicker._attachDatepicker(this,e)}):t.datepicker["_"+e+"Datepicker"].apply(t.datepicker,[this[0]].concat(i))},t.datepicker=new i,t.datepicker.initialized=!1,t.datepicker.uuid=(new Date).getTime(),t.datepicker.version="1.10.2",window["DP_jQuery_"+r]=t}(jQuery),function(t){var e={buttons:!0,height:!0,maxHeight:!0,maxWidth:!0,minHeight:!0,minWidth:!0,width:!0},i={maxHeight:!0,maxWidth:!0,minHeight:!0,minWidth:!0};t.widget("ui.dialog",{version:"1.10.2",options:{appendTo:"body",autoOpen:!0,buttons:[],closeOnEscape:!0,closeText:"close",dialogClass:"",draggable:!0,hide:null,height:"auto",maxHeight:null,maxWidth:null,minHeight:150,minWidth:150,modal:!1,position:{my:"center",at:"center",of:window,collision:"fit",using:function(e){var i=t(this).css(e).offset().top;0>i&&t(this).css("top",e.top-i)}},resizable:!0,show:null,title:null,width:300,beforeClose:null,close:null,drag:null,dragStart:null,dragStop:null,focus:null,open:null,resize:null,resizeStart:null,resizeStop:null},_create:function(){this.originalCss={display:this.element[0].style.display,width:this.element[0].style.width,minHeight:this.element[0].style.minHeight,maxHeight:this.element[0].style.maxHeight,height:this.element[0].style.height},this.originalPosition={parent:this.element.parent(),index:this.element.parent().children().index(this.element)},this.originalTitle=this.element.attr("title"),this.options.title=this.options.title||this.originalTitle,this._createWrapper(),this.element.show().removeAttr("title").addClass("ui-dialog-content ui-widget-content").appendTo(this.uiDialog),this._createTitlebar(),this._createButtonPane(),this.options.draggable&&t.fn.draggable&&this._makeDraggable(),this.options.resizable&&t.fn.resizable&&this._makeResizable(),this._isOpen=!1},_init:function(){this.options.autoOpen&&this.open()},_appendTo:function(){var e=this.options.appendTo;return e&&(e.jquery||e.nodeType)?t(e):this.document.find(e||"body").eq(0)},_destroy:function(){var t,e=this.originalPosition;this._destroyOverlay(),this.element.removeUniqueId().removeClass("ui-dialog-content ui-widget-content").css(this.originalCss).detach(),this.uiDialog.stop(!0,!0).remove(),this.originalTitle&&this.element.attr("title",this.originalTitle),t=e.parent.children().eq(e.index),t.length&&t[0]!==this.element[0]?t.before(this.element):e.parent.append(this.element)},widget:function(){return this.uiDialog},disable:t.noop,enable:t.noop,close:function(e){var i=this;this._isOpen&&this._trigger("beforeClose",e)!==!1&&(this._isOpen=!1,this._destroyOverlay(),this.opener.filter(":focusable").focus().length||t(this.document[0].activeElement).blur(),this._hide(this.uiDialog,this.options.hide,function(){i._trigger("close",e)}))},isOpen:function(){return this._isOpen},moveToTop:function(){this._moveToTop()},_moveToTop:function(t,e){var i=!!this.uiDialog.nextAll(":visible").insertBefore(this.uiDialog).length;return i&&!e&&this._trigger("focus",t),i},open:function(){var e=this;return this._isOpen?(this._moveToTop()&&this._focusTabbable(),undefined):(this._isOpen=!0,this.opener=t(this.document[0].activeElement),this._size(),this._position(),this._createOverlay(),this._moveToTop(null,!0),this._show(this.uiDialog,this.options.show,function(){e._focusTabbable(),e._trigger("focus")}),this._trigger("open"),undefined)},_focusTabbable:function(){var t=this.element.find("[autofocus]");t.length||(t=this.element.find(":tabbable")),t.length||(t=this.uiDialogButtonPane.find(":tabbable")),t.length||(t=this.uiDialogTitlebarClose.filter(":tabbable")),t.length||(t=this.uiDialog),t.eq(0).focus()},_keepFocus:function(e){function i(){var e=this.document[0].activeElement,i=this.uiDialog[0]===e||t.contains(this.uiDialog[0],e);i||this._focusTabbable()}e.preventDefault(),i.call(this),this._delay(i)},_createWrapper:function(){this.uiDialog=t("<div>").addClass("ui-dialog ui-widget ui-widget-content ui-corner-all ui-front "+this.options.dialogClass).hide().attr({tabIndex:-1,role:"dialog"}).appendTo(this._appendTo()),this._on(this.uiDialog,{keydown:function(e){if(this.options.closeOnEscape&&!e.isDefaultPrevented()&&e.keyCode&&e.keyCode===t.ui.keyCode.ESCAPE)return e.preventDefault(),this.close(e),undefined;if(e.keyCode===t.ui.keyCode.TAB){var i=this.uiDialog.find(":tabbable"),s=i.filter(":first"),n=i.filter(":last");e.target!==n[0]&&e.target!==this.uiDialog[0]||e.shiftKey?e.target!==s[0]&&e.target!==this.uiDialog[0]||!e.shiftKey||(n.focus(1),e.preventDefault()):(s.focus(1),e.preventDefault())}},mousedown:function(t){this._moveToTop(t)&&this._focusTabbable()}}),this.element.find("[aria-describedby]").length||this.uiDialog.attr({"aria-describedby":this.element.uniqueId().attr("id")})},_createTitlebar:function(){var e;this.uiDialogTitlebar=t("<div>").addClass("ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix").prependTo(this.uiDialog),this._on(this.uiDialogTitlebar,{mousedown:function(e){t(e.target).closest(".ui-dialog-titlebar-close")||this.uiDialog.focus()}}),this.uiDialogTitlebarClose=t("<button></button>").button({label:this.options.closeText,icons:{primary:"ui-icon-closethick"},text:!1}).addClass("ui-dialog-titlebar-close").appendTo(this.uiDialogTitlebar),this._on(this.uiDialogTitlebarClose,{click:function(t){t.preventDefault(),this.close(t)}}),e=t("<span>").uniqueId().addClass("ui-dialog-title").prependTo(this.uiDialogTitlebar),this._title(e),this.uiDialog.attr({"aria-labelledby":e.attr("id")})},_title:function(t){this.options.title||t.html(" "),t.text(this.options.title)},_createButtonPane:function(){this.uiDialogButtonPane=t("<div>").addClass("ui-dialog-buttonpane ui-widget-content ui-helper-clearfix"),this.uiButtonSet=t("<div>").addClass("ui-dialog-buttonset").appendTo(this.uiDialogButtonPane),this._createButtons()},_createButtons:function(){var e=this,i=this.options.buttons;return this.uiDialogButtonPane.remove(),this.uiButtonSet.empty(),t.isEmptyObject(i)||t.isArray(i)&&!i.length?(this.uiDialog.removeClass("ui-dialog-buttons"),undefined):(t.each(i,function(i,s){var n,o;s=t.isFunction(s)?{click:s,text:i}:s,s=t.extend({type:"button"},s),n=s.click,s.click=function(){n.apply(e.element[0],arguments)},o={icons:s.icons,text:s.showText},delete s.icons,delete s.showText,t("<button></button>",s).button(o).appendTo(e.uiButtonSet)}),this.uiDialog.addClass("ui-dialog-buttons"),this.uiDialogButtonPane.appendTo(this.uiDialog),undefined)},_makeDraggable:function(){function e(t){return{position:t.position,offset:t.offset}}var i=this,s=this.options;this.uiDialog.draggable({cancel:".ui-dialog-content, .ui-dialog-titlebar-close",handle:".ui-dialog-titlebar",containment:"document",start:function(s,n){t(this).addClass("ui-dialog-dragging"),i._blockFrames(),i._trigger("dragStart",s,e(n))},drag:function(t,s){i._trigger("drag",t,e(s))},stop:function(n,o){s.position=[o.position.left-i.document.scrollLeft(),o.position.top-i.document.scrollTop()],t(this).removeClass("ui-dialog-dragging"),i._unblockFrames(),i._trigger("dragStop",n,e(o)) +}})},_makeResizable:function(){function e(t){return{originalPosition:t.originalPosition,originalSize:t.originalSize,position:t.position,size:t.size}}var i=this,s=this.options,n=s.resizable,o=this.uiDialog.css("position"),a="string"==typeof n?n:"n,e,s,w,se,sw,ne,nw";this.uiDialog.resizable({cancel:".ui-dialog-content",containment:"document",alsoResize:this.element,maxWidth:s.maxWidth,maxHeight:s.maxHeight,minWidth:s.minWidth,minHeight:this._minHeight(),handles:a,start:function(s,n){t(this).addClass("ui-dialog-resizing"),i._blockFrames(),i._trigger("resizeStart",s,e(n))},resize:function(t,s){i._trigger("resize",t,e(s))},stop:function(n,o){s.height=t(this).height(),s.width=t(this).width(),t(this).removeClass("ui-dialog-resizing"),i._unblockFrames(),i._trigger("resizeStop",n,e(o))}}).css("position",o)},_minHeight:function(){var t=this.options;return"auto"===t.height?t.minHeight:Math.min(t.minHeight,t.height)},_position:function(){var t=this.uiDialog.is(":visible");t||this.uiDialog.show(),this.uiDialog.position(this.options.position),t||this.uiDialog.hide()},_setOptions:function(s){var n=this,o=!1,a={};t.each(s,function(t,s){n._setOption(t,s),t in e&&(o=!0),t in i&&(a[t]=s)}),o&&(this._size(),this._position()),this.uiDialog.is(":data(ui-resizable)")&&this.uiDialog.resizable("option",a)},_setOption:function(t,e){var i,s,n=this.uiDialog;"dialogClass"===t&&n.removeClass(this.options.dialogClass).addClass(e),"disabled"!==t&&(this._super(t,e),"appendTo"===t&&this.uiDialog.appendTo(this._appendTo()),"buttons"===t&&this._createButtons(),"closeText"===t&&this.uiDialogTitlebarClose.button({label:""+e}),"draggable"===t&&(i=n.is(":data(ui-draggable)"),i&&!e&&n.draggable("destroy"),!i&&e&&this._makeDraggable()),"position"===t&&this._position(),"resizable"===t&&(s=n.is(":data(ui-resizable)"),s&&!e&&n.resizable("destroy"),s&&"string"==typeof e&&n.resizable("option","handles",e),s||e===!1||this._makeResizable()),"title"===t&&this._title(this.uiDialogTitlebar.find(".ui-dialog-title")))},_size:function(){var t,e,i,s=this.options;this.element.show().css({width:"auto",minHeight:0,maxHeight:"none",height:0}),s.minWidth>s.width&&(s.width=s.minWidth),t=this.uiDialog.css({height:"auto",width:s.width}).outerHeight(),e=Math.max(0,s.minHeight-t),i="number"==typeof s.maxHeight?Math.max(0,s.maxHeight-t):"none","auto"===s.height?this.element.css({minHeight:e,maxHeight:i,height:"auto"}):this.element.height(Math.max(0,s.height-t)),this.uiDialog.is(":data(ui-resizable)")&&this.uiDialog.resizable("option","minHeight",this._minHeight())},_blockFrames:function(){this.iframeBlocks=this.document.find("iframe").map(function(){var e=t(this);return t("<div>").css({position:"absolute",width:e.outerWidth(),height:e.outerHeight()}).appendTo(e.parent()).offset(e.offset())[0]})},_unblockFrames:function(){this.iframeBlocks&&(this.iframeBlocks.remove(),delete this.iframeBlocks)},_allowInteraction:function(e){return t(e.target).closest(".ui-dialog").length?!0:!!t(e.target).closest(".ui-datepicker").length},_createOverlay:function(){if(this.options.modal){var e=this,i=this.widgetFullName;t.ui.dialog.overlayInstances||this._delay(function(){t.ui.dialog.overlayInstances&&this.document.bind("focusin.dialog",function(s){e._allowInteraction(s)||(s.preventDefault(),t(".ui-dialog:visible:last .ui-dialog-content").data(i)._focusTabbable())})}),this.overlay=t("<div>").addClass("ui-widget-overlay ui-front").appendTo(this._appendTo()),this._on(this.overlay,{mousedown:"_keepFocus"}),t.ui.dialog.overlayInstances++}},_destroyOverlay:function(){this.options.modal&&this.overlay&&(t.ui.dialog.overlayInstances--,t.ui.dialog.overlayInstances||this.document.unbind("focusin.dialog"),this.overlay.remove(),this.overlay=null)}}),t.ui.dialog.overlayInstances=0,t.uiBackCompat!==!1&&t.widget("ui.dialog",t.ui.dialog,{_position:function(){var e,i=this.options.position,s=[],n=[0,0];i?(("string"==typeof i||"object"==typeof i&&"0"in i)&&(s=i.split?i.split(" "):[i[0],i[1]],1===s.length&&(s[1]=s[0]),t.each(["left","top"],function(t,e){+s[t]===s[t]&&(n[t]=s[t],s[t]=e)}),i={my:s[0]+(0>n[0]?n[0]:"+"+n[0])+" "+s[1]+(0>n[1]?n[1]:"+"+n[1]),at:s.join(" ")}),i=t.extend({},t.ui.dialog.prototype.options.position,i)):i=t.ui.dialog.prototype.options.position,e=this.uiDialog.is(":visible"),e||this.uiDialog.show(),this.uiDialog.position(i),e||this.uiDialog.hide()}})}(jQuery),function(t){var e=/up|down|vertical/,i=/up|left|vertical|horizontal/;t.effects.effect.blind=function(s,n){var o,a,r,h=t(this),l=["position","top","bottom","left","right","height","width"],c=t.effects.setMode(h,s.mode||"hide"),u=s.direction||"up",d=e.test(u),p=d?"height":"width",f=d?"top":"left",g=i.test(u),m={},v="show"===c;h.parent().is(".ui-effects-wrapper")?t.effects.save(h.parent(),l):t.effects.save(h,l),h.show(),o=t.effects.createWrapper(h).css({overflow:"hidden"}),a=o[p](),r=parseFloat(o.css(f))||0,m[p]=v?a:0,g||(h.css(d?"bottom":"right",0).css(d?"top":"left","auto").css({position:"absolute"}),m[f]=v?r:a+r),v&&(o.css(p,0),g||o.css(f,r+a)),o.animate(m,{duration:s.duration,easing:s.easing,queue:!1,complete:function(){"hide"===c&&h.hide(),t.effects.restore(h,l),t.effects.removeWrapper(h),n()}})}}(jQuery),function(t){t.effects.effect.bounce=function(e,i){var s,n,o,a=t(this),r=["position","top","bottom","left","right","height","width"],h=t.effects.setMode(a,e.mode||"effect"),l="hide"===h,c="show"===h,u=e.direction||"up",d=e.distance,p=e.times||5,f=2*p+(c||l?1:0),g=e.duration/f,m=e.easing,v="up"===u||"down"===u?"top":"left",_="up"===u||"left"===u,b=a.queue(),y=b.length;for((c||l)&&r.push("opacity"),t.effects.save(a,r),a.show(),t.effects.createWrapper(a),d||(d=a["top"===v?"outerHeight":"outerWidth"]()/3),c&&(o={opacity:1},o[v]=0,a.css("opacity",0).css(v,_?2*-d:2*d).animate(o,g,m)),l&&(d/=Math.pow(2,p-1)),o={},o[v]=0,s=0;p>s;s++)n={},n[v]=(_?"-=":"+=")+d,a.animate(n,g,m).animate(o,g,m),d=l?2*d:d/2;l&&(n={opacity:0},n[v]=(_?"-=":"+=")+d,a.animate(n,g,m)),a.queue(function(){l&&a.hide(),t.effects.restore(a,r),t.effects.removeWrapper(a),i()}),y>1&&b.splice.apply(b,[1,0].concat(b.splice(y,f+1))),a.dequeue()}}(jQuery),function(t){t.effects.effect.clip=function(e,i){var s,n,o,a=t(this),r=["position","top","bottom","left","right","height","width"],h=t.effects.setMode(a,e.mode||"hide"),l="show"===h,c=e.direction||"vertical",u="vertical"===c,d=u?"height":"width",p=u?"top":"left",f={};t.effects.save(a,r),a.show(),s=t.effects.createWrapper(a).css({overflow:"hidden"}),n="IMG"===a[0].tagName?s:a,o=n[d](),l&&(n.css(d,0),n.css(p,o/2)),f[d]=l?o:0,f[p]=l?0:o/2,n.animate(f,{queue:!1,duration:e.duration,easing:e.easing,complete:function(){l||a.hide(),t.effects.restore(a,r),t.effects.removeWrapper(a),i()}})}}(jQuery),function(t){t.effects.effect.drop=function(e,i){var s,n=t(this),o=["position","top","bottom","left","right","opacity","height","width"],a=t.effects.setMode(n,e.mode||"hide"),r="show"===a,h=e.direction||"left",l="up"===h||"down"===h?"top":"left",c="up"===h||"left"===h?"pos":"neg",u={opacity:r?1:0};t.effects.save(n,o),n.show(),t.effects.createWrapper(n),s=e.distance||n["top"===l?"outerHeight":"outerWidth"](!0)/2,r&&n.css("opacity",0).css(l,"pos"===c?-s:s),u[l]=(r?"pos"===c?"+=":"-=":"pos"===c?"-=":"+=")+s,n.animate(u,{queue:!1,duration:e.duration,easing:e.easing,complete:function(){"hide"===a&&n.hide(),t.effects.restore(n,o),t.effects.removeWrapper(n),i()}})}}(jQuery),function(t){t.effects.effect.explode=function(e,i){function s(){b.push(this),b.length===u*d&&n()}function n(){p.css({visibility:"visible"}),t(b).remove(),g||p.hide(),i()}var o,a,r,h,l,c,u=e.pieces?Math.round(Math.sqrt(e.pieces)):3,d=u,p=t(this),f=t.effects.setMode(p,e.mode||"hide"),g="show"===f,m=p.show().css("visibility","hidden").offset(),v=Math.ceil(p.outerWidth()/d),_=Math.ceil(p.outerHeight()/u),b=[];for(o=0;u>o;o++)for(h=m.top+o*_,c=o-(u-1)/2,a=0;d>a;a++)r=m.left+a*v,l=a-(d-1)/2,p.clone().appendTo("body").wrap("<div></div>").css({position:"absolute",visibility:"visible",left:-a*v,top:-o*_}).parent().addClass("ui-effects-explode").css({position:"absolute",overflow:"hidden",width:v,height:_,left:r+(g?l*v:0),top:h+(g?c*_:0),opacity:g?0:1}).animate({left:r+(g?0:l*v),top:h+(g?0:c*_),opacity:g?1:0},e.duration||500,e.easing,s)}}(jQuery),function(t){t.effects.effect.fade=function(e,i){var s=t(this),n=t.effects.setMode(s,e.mode||"toggle");s.animate({opacity:n},{queue:!1,duration:e.duration,easing:e.easing,complete:i})}}(jQuery),function(t){t.effects.effect.fold=function(e,i){var s,n,o=t(this),a=["position","top","bottom","left","right","height","width"],r=t.effects.setMode(o,e.mode||"hide"),h="show"===r,l="hide"===r,c=e.size||15,u=/([0-9]+)%/.exec(c),d=!!e.horizFirst,p=h!==d,f=p?["width","height"]:["height","width"],g=e.duration/2,m={},v={};t.effects.save(o,a),o.show(),s=t.effects.createWrapper(o).css({overflow:"hidden"}),n=p?[s.width(),s.height()]:[s.height(),s.width()],u&&(c=parseInt(u[1],10)/100*n[l?0:1]),h&&s.css(d?{height:0,width:c}:{height:c,width:0}),m[f[0]]=h?n[0]:c,v[f[1]]=h?n[1]:0,s.animate(m,g,e.easing).animate(v,g,e.easing,function(){l&&o.hide(),t.effects.restore(o,a),t.effects.removeWrapper(o),i()})}}(jQuery),function(t){t.effects.effect.highlight=function(e,i){var s=t(this),n=["backgroundImage","backgroundColor","opacity"],o=t.effects.setMode(s,e.mode||"show"),a={backgroundColor:s.css("backgroundColor")};"hide"===o&&(a.opacity=0),t.effects.save(s,n),s.show().css({backgroundImage:"none",backgroundColor:e.color||"#ffff99"}).animate(a,{queue:!1,duration:e.duration,easing:e.easing,complete:function(){"hide"===o&&s.hide(),t.effects.restore(s,n),i()}})}}(jQuery),function(t){t.effects.effect.pulsate=function(e,i){var s,n=t(this),o=t.effects.setMode(n,e.mode||"show"),a="show"===o,r="hide"===o,h=a||"hide"===o,l=2*(e.times||5)+(h?1:0),c=e.duration/l,u=0,d=n.queue(),p=d.length;for((a||!n.is(":visible"))&&(n.css("opacity",0).show(),u=1),s=1;l>s;s++)n.animate({opacity:u},c,e.easing),u=1-u;n.animate({opacity:u},c,e.easing),n.queue(function(){r&&n.hide(),i()}),p>1&&d.splice.apply(d,[1,0].concat(d.splice(p,l+1))),n.dequeue()}}(jQuery),function(t){t.effects.effect.puff=function(e,i){var s=t(this),n=t.effects.setMode(s,e.mode||"hide"),o="hide"===n,a=parseInt(e.percent,10)||150,r=a/100,h={height:s.height(),width:s.width(),outerHeight:s.outerHeight(),outerWidth:s.outerWidth()};t.extend(e,{effect:"scale",queue:!1,fade:!0,mode:n,complete:i,percent:o?a:100,from:o?h:{height:h.height*r,width:h.width*r,outerHeight:h.outerHeight*r,outerWidth:h.outerWidth*r}}),s.effect(e)},t.effects.effect.scale=function(e,i){var s=t(this),n=t.extend(!0,{},e),o=t.effects.setMode(s,e.mode||"effect"),a=parseInt(e.percent,10)||(0===parseInt(e.percent,10)?0:"hide"===o?0:100),r=e.direction||"both",h=e.origin,l={height:s.height(),width:s.width(),outerHeight:s.outerHeight(),outerWidth:s.outerWidth()},c={y:"horizontal"!==r?a/100:1,x:"vertical"!==r?a/100:1};n.effect="size",n.queue=!1,n.complete=i,"effect"!==o&&(n.origin=h||["middle","center"],n.restore=!0),n.from=e.from||("show"===o?{height:0,width:0,outerHeight:0,outerWidth:0}:l),n.to={height:l.height*c.y,width:l.width*c.x,outerHeight:l.outerHeight*c.y,outerWidth:l.outerWidth*c.x},n.fade&&("show"===o&&(n.from.opacity=0,n.to.opacity=1),"hide"===o&&(n.from.opacity=1,n.to.opacity=0)),s.effect(n)},t.effects.effect.size=function(e,i){var s,n,o,a=t(this),r=["position","top","bottom","left","right","width","height","overflow","opacity"],h=["position","top","bottom","left","right","overflow","opacity"],l=["width","height","overflow"],c=["fontSize"],u=["borderTopWidth","borderBottomWidth","paddingTop","paddingBottom"],d=["borderLeftWidth","borderRightWidth","paddingLeft","paddingRight"],p=t.effects.setMode(a,e.mode||"effect"),f=e.restore||"effect"!==p,g=e.scale||"both",m=e.origin||["middle","center"],v=a.css("position"),_=f?r:h,b={height:0,width:0,outerHeight:0,outerWidth:0};"show"===p&&a.show(),s={height:a.height(),width:a.width(),outerHeight:a.outerHeight(),outerWidth:a.outerWidth()},"toggle"===e.mode&&"show"===p?(a.from=e.to||b,a.to=e.from||s):(a.from=e.from||("show"===p?b:s),a.to=e.to||("hide"===p?b:s)),o={from:{y:a.from.height/s.height,x:a.from.width/s.width},to:{y:a.to.height/s.height,x:a.to.width/s.width}},("box"===g||"both"===g)&&(o.from.y!==o.to.y&&(_=_.concat(u),a.from=t.effects.setTransition(a,u,o.from.y,a.from),a.to=t.effects.setTransition(a,u,o.to.y,a.to)),o.from.x!==o.to.x&&(_=_.concat(d),a.from=t.effects.setTransition(a,d,o.from.x,a.from),a.to=t.effects.setTransition(a,d,o.to.x,a.to))),("content"===g||"both"===g)&&o.from.y!==o.to.y&&(_=_.concat(c).concat(l),a.from=t.effects.setTransition(a,c,o.from.y,a.from),a.to=t.effects.setTransition(a,c,o.to.y,a.to)),t.effects.save(a,_),a.show(),t.effects.createWrapper(a),a.css("overflow","hidden").css(a.from),m&&(n=t.effects.getBaseline(m,s),a.from.top=(s.outerHeight-a.outerHeight())*n.y,a.from.left=(s.outerWidth-a.outerWidth())*n.x,a.to.top=(s.outerHeight-a.to.outerHeight)*n.y,a.to.left=(s.outerWidth-a.to.outerWidth)*n.x),a.css(a.from),("content"===g||"both"===g)&&(u=u.concat(["marginTop","marginBottom"]).concat(c),d=d.concat(["marginLeft","marginRight"]),l=r.concat(u).concat(d),a.find("*[width]").each(function(){var i=t(this),s={height:i.height(),width:i.width(),outerHeight:i.outerHeight(),outerWidth:i.outerWidth()};f&&t.effects.save(i,l),i.from={height:s.height*o.from.y,width:s.width*o.from.x,outerHeight:s.outerHeight*o.from.y,outerWidth:s.outerWidth*o.from.x},i.to={height:s.height*o.to.y,width:s.width*o.to.x,outerHeight:s.height*o.to.y,outerWidth:s.width*o.to.x},o.from.y!==o.to.y&&(i.from=t.effects.setTransition(i,u,o.from.y,i.from),i.to=t.effects.setTransition(i,u,o.to.y,i.to)),o.from.x!==o.to.x&&(i.from=t.effects.setTransition(i,d,o.from.x,i.from),i.to=t.effects.setTransition(i,d,o.to.x,i.to)),i.css(i.from),i.animate(i.to,e.duration,e.easing,function(){f&&t.effects.restore(i,l)})})),a.animate(a.to,{queue:!1,duration:e.duration,easing:e.easing,complete:function(){0===a.to.opacity&&a.css("opacity",a.from.opacity),"hide"===p&&a.hide(),t.effects.restore(a,_),f||("static"===v?a.css({position:"relative",top:a.to.top,left:a.to.left}):t.each(["top","left"],function(t,e){a.css(e,function(e,i){var s=parseInt(i,10),n=t?a.to.left:a.to.top;return"auto"===i?n+"px":s+n+"px"})})),t.effects.removeWrapper(a),i()}})}}(jQuery),function(t){t.effects.effect.shake=function(e,i){var s,n=t(this),o=["position","top","bottom","left","right","height","width"],a=t.effects.setMode(n,e.mode||"effect"),r=e.direction||"left",h=e.distance||20,l=e.times||3,c=2*l+1,u=Math.round(e.duration/c),d="up"===r||"down"===r?"top":"left",p="up"===r||"left"===r,f={},g={},m={},v=n.queue(),_=v.length;for(t.effects.save(n,o),n.show(),t.effects.createWrapper(n),f[d]=(p?"-=":"+=")+h,g[d]=(p?"+=":"-=")+2*h,m[d]=(p?"-=":"+=")+2*h,n.animate(f,u,e.easing),s=1;l>s;s++)n.animate(g,u,e.easing).animate(m,u,e.easing);n.animate(g,u,e.easing).animate(f,u/2,e.easing).queue(function(){"hide"===a&&n.hide(),t.effects.restore(n,o),t.effects.removeWrapper(n),i()}),_>1&&v.splice.apply(v,[1,0].concat(v.splice(_,c+1))),n.dequeue()}}(jQuery),function(t){t.effects.effect.slide=function(e,i){var s,n=t(this),o=["position","top","bottom","left","right","width","height"],a=t.effects.setMode(n,e.mode||"show"),r="show"===a,h=e.direction||"left",l="up"===h||"down"===h?"top":"left",c="up"===h||"left"===h,u={};t.effects.save(n,o),n.show(),s=e.distance||n["top"===l?"outerHeight":"outerWidth"](!0),t.effects.createWrapper(n).css({overflow:"hidden"}),r&&n.css(l,c?isNaN(s)?"-"+s:-s:s),u[l]=(r?c?"+=":"-=":c?"-=":"+=")+s,n.animate(u,{queue:!1,duration:e.duration,easing:e.easing,complete:function(){"hide"===a&&n.hide(),t.effects.restore(n,o),t.effects.removeWrapper(n),i()}})}}(jQuery),function(t){t.effects.effect.transfer=function(e,i){var s=t(this),n=t(e.to),o="fixed"===n.css("position"),a=t("body"),r=o?a.scrollTop():0,h=o?a.scrollLeft():0,l=n.offset(),c={top:l.top-r,left:l.left-h,height:n.innerHeight(),width:n.innerWidth()},u=s.offset(),d=t("<div class='ui-effects-transfer'></div>").appendTo(document.body).addClass(e.className).css({top:u.top-r,left:u.left-h,height:s.innerHeight(),width:s.innerWidth(),position:o?"fixed":"absolute"}).animate(c,e.duration,e.easing,function(){d.remove(),i()})}}(jQuery),function(t){t.widget("ui.menu",{version:"1.10.2",defaultElement:"<ul>",delay:300,options:{icons:{submenu:"ui-icon-carat-1-e"},menus:"ul",position:{my:"left top",at:"right top"},role:"menu",blur:null,focus:null,select:null},_create:function(){this.activeMenu=this.element,this.mouseHandled=!1,this.element.uniqueId().addClass("ui-menu ui-widget ui-widget-content ui-corner-all").toggleClass("ui-menu-icons",!!this.element.find(".ui-icon").length).attr({role:this.options.role,tabIndex:0}).bind("click"+this.eventNamespace,t.proxy(function(t){this.options.disabled&&t.preventDefault()},this)),this.options.disabled&&this.element.addClass("ui-state-disabled").attr("aria-disabled","true"),this._on({"mousedown .ui-menu-item > a":function(t){t.preventDefault()},"click .ui-state-disabled > a":function(t){t.preventDefault()},"click .ui-menu-item:has(a)":function(e){var i=t(e.target).closest(".ui-menu-item");!this.mouseHandled&&i.not(".ui-state-disabled").length&&(this.mouseHandled=!0,this.select(e),i.has(".ui-menu").length?this.expand(e):this.element.is(":focus")||(this.element.trigger("focus",[!0]),this.active&&1===this.active.parents(".ui-menu").length&&clearTimeout(this.timer)))},"mouseenter .ui-menu-item":function(e){var i=t(e.currentTarget);i.siblings().children(".ui-state-active").removeClass("ui-state-active"),this.focus(e,i)},mouseleave:"collapseAll","mouseleave .ui-menu":"collapseAll",focus:function(t,e){var i=this.active||this.element.children(".ui-menu-item").eq(0);e||this.focus(t,i)},blur:function(e){this._delay(function(){t.contains(this.element[0],this.document[0].activeElement)||this.collapseAll(e)})},keydown:"_keydown"}),this.refresh(),this._on(this.document,{click:function(e){t(e.target).closest(".ui-menu").length||this.collapseAll(e),this.mouseHandled=!1}})},_destroy:function(){this.element.removeAttr("aria-activedescendant").find(".ui-menu").addBack().removeClass("ui-menu ui-widget ui-widget-content ui-corner-all ui-menu-icons").removeAttr("role").removeAttr("tabIndex").removeAttr("aria-labelledby").removeAttr("aria-expanded").removeAttr("aria-hidden").removeAttr("aria-disabled").removeUniqueId().show(),this.element.find(".ui-menu-item").removeClass("ui-menu-item").removeAttr("role").removeAttr("aria-disabled").children("a").removeUniqueId().removeClass("ui-corner-all ui-state-hover").removeAttr("tabIndex").removeAttr("role").removeAttr("aria-haspopup").children().each(function(){var e=t(this);e.data("ui-menu-submenu-carat")&&e.remove()}),this.element.find(".ui-menu-divider").removeClass("ui-menu-divider ui-widget-content")},_keydown:function(e){function i(t){return t.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g,"\\$&")}var s,n,o,a,r,h=!0;switch(e.keyCode){case t.ui.keyCode.PAGE_UP:this.previousPage(e);break;case t.ui.keyCode.PAGE_DOWN:this.nextPage(e);break;case t.ui.keyCode.HOME:this._move("first","first",e);break;case t.ui.keyCode.END:this._move("last","last",e);break;case t.ui.keyCode.UP:this.previous(e);break;case t.ui.keyCode.DOWN:this.next(e);break;case t.ui.keyCode.LEFT:this.collapse(e);break;case t.ui.keyCode.RIGHT:this.active&&!this.active.is(".ui-state-disabled")&&this.expand(e);break;case t.ui.keyCode.ENTER:case t.ui.keyCode.SPACE:this._activate(e);break;case t.ui.keyCode.ESCAPE:this.collapse(e);break;default:h=!1,n=this.previousFilter||"",o=String.fromCharCode(e.keyCode),a=!1,clearTimeout(this.filterTimer),o===n?a=!0:o=n+o,r=RegExp("^"+i(o),"i"),s=this.activeMenu.children(".ui-menu-item").filter(function(){return r.test(t(this).children("a").text())}),s=a&&-1!==s.index(this.active.next())?this.active.nextAll(".ui-menu-item"):s,s.length||(o=String.fromCharCode(e.keyCode),r=RegExp("^"+i(o),"i"),s=this.activeMenu.children(".ui-menu-item").filter(function(){return r.test(t(this).children("a").text())})),s.length?(this.focus(e,s),s.length>1?(this.previousFilter=o,this.filterTimer=this._delay(function(){delete this.previousFilter},1e3)):delete this.previousFilter):delete this.previousFilter}h&&e.preventDefault()},_activate:function(t){this.active.is(".ui-state-disabled")||(this.active.children("a[aria-haspopup='true']").length?this.expand(t):this.select(t))},refresh:function(){var e,i=this.options.icons.submenu,s=this.element.find(this.options.menus);s.filter(":not(.ui-menu)").addClass("ui-menu ui-widget ui-widget-content ui-corner-all").hide().attr({role:this.options.role,"aria-hidden":"true","aria-expanded":"false"}).each(function(){var e=t(this),s=e.prev("a"),n=t("<span>").addClass("ui-menu-icon ui-icon "+i).data("ui-menu-submenu-carat",!0);s.attr("aria-haspopup","true").prepend(n),e.attr("aria-labelledby",s.attr("id"))}),e=s.add(this.element),e.children(":not(.ui-menu-item):has(a)").addClass("ui-menu-item").attr("role","presentation").children("a").uniqueId().addClass("ui-corner-all").attr({tabIndex:-1,role:this._itemRole()}),e.children(":not(.ui-menu-item)").each(function(){var e=t(this);/[^\-\u2014\u2013\s]/.test(e.text())||e.addClass("ui-widget-content ui-menu-divider")}),e.children(".ui-state-disabled").attr("aria-disabled","true"),this.active&&!t.contains(this.element[0],this.active[0])&&this.blur()},_itemRole:function(){return{menu:"menuitem",listbox:"option"}[this.options.role]},_setOption:function(t,e){"icons"===t&&this.element.find(".ui-menu-icon").removeClass(this.options.icons.submenu).addClass(e.submenu),this._super(t,e)},focus:function(t,e){var i,s;this.blur(t,t&&"focus"===t.type),this._scrollIntoView(e),this.active=e.first(),s=this.active.children("a").addClass("ui-state-focus"),this.options.role&&this.element.attr("aria-activedescendant",s.attr("id")),this.active.parent().closest(".ui-menu-item").children("a:first").addClass("ui-state-active"),t&&"keydown"===t.type?this._close():this.timer=this._delay(function(){this._close()},this.delay),i=e.children(".ui-menu"),i.length&&/^mouse/.test(t.type)&&this._startOpening(i),this.activeMenu=e.parent(),this._trigger("focus",t,{item:e})},_scrollIntoView:function(e){var i,s,n,o,a,r;this._hasScroll()&&(i=parseFloat(t.css(this.activeMenu[0],"borderTopWidth"))||0,s=parseFloat(t.css(this.activeMenu[0],"paddingTop"))||0,n=e.offset().top-this.activeMenu.offset().top-i-s,o=this.activeMenu.scrollTop(),a=this.activeMenu.height(),r=e.height(),0>n?this.activeMenu.scrollTop(o+n):n+r>a&&this.activeMenu.scrollTop(o+n-a+r))},blur:function(t,e){e||clearTimeout(this.timer),this.active&&(this.active.children("a").removeClass("ui-state-focus"),this.active=null,this._trigger("blur",t,{item:this.active}))},_startOpening:function(t){clearTimeout(this.timer),"true"===t.attr("aria-hidden")&&(this.timer=this._delay(function(){this._close(),this._open(t)},this.delay))},_open:function(e){var i=t.extend({of:this.active},this.options.position);clearTimeout(this.timer),this.element.find(".ui-menu").not(e.parents(".ui-menu")).hide().attr("aria-hidden","true"),e.show().removeAttr("aria-hidden").attr("aria-expanded","true").position(i)},collapseAll:function(e,i){clearTimeout(this.timer),this.timer=this._delay(function(){var s=i?this.element:t(e&&e.target).closest(this.element.find(".ui-menu"));s.length||(s=this.element),this._close(s),this.blur(e),this.activeMenu=s},this.delay)},_close:function(t){t||(t=this.active?this.active.parent():this.element),t.find(".ui-menu").hide().attr("aria-hidden","true").attr("aria-expanded","false").end().find("a.ui-state-active").removeClass("ui-state-active")},collapse:function(t){var e=this.active&&this.active.parent().closest(".ui-menu-item",this.element);e&&e.length&&(this._close(),this.focus(t,e))},expand:function(t){var e=this.active&&this.active.children(".ui-menu ").children(".ui-menu-item").first();e&&e.length&&(this._open(e.parent()),this._delay(function(){this.focus(t,e)}))},next:function(t){this._move("next","first",t)},previous:function(t){this._move("prev","last",t)},isFirstItem:function(){return this.active&&!this.active.prevAll(".ui-menu-item").length},isLastItem:function(){return this.active&&!this.active.nextAll(".ui-menu-item").length},_move:function(t,e,i){var s;this.active&&(s="first"===t||"last"===t?this.active["first"===t?"prevAll":"nextAll"](".ui-menu-item").eq(-1):this.active[t+"All"](".ui-menu-item").eq(0)),s&&s.length&&this.active||(s=this.activeMenu.children(".ui-menu-item")[e]()),this.focus(i,s)},nextPage:function(e){var i,s,n;return this.active?(this.isLastItem()||(this._hasScroll()?(s=this.active.offset().top,n=this.element.height(),this.active.nextAll(".ui-menu-item").each(function(){return i=t(this),0>i.offset().top-s-n}),this.focus(e,i)):this.focus(e,this.activeMenu.children(".ui-menu-item")[this.active?"last":"first"]())),undefined):(this.next(e),undefined)},previousPage:function(e){var i,s,n;return this.active?(this.isFirstItem()||(this._hasScroll()?(s=this.active.offset().top,n=this.element.height(),this.active.prevAll(".ui-menu-item").each(function(){return i=t(this),i.offset().top-s+n>0}),this.focus(e,i)):this.focus(e,this.activeMenu.children(".ui-menu-item").first())),undefined):(this.next(e),undefined)},_hasScroll:function(){return this.element.outerHeight()<this.element.prop("scrollHeight")},select:function(e){this.active=this.active||t(e.target).closest(".ui-menu-item");var i={item:this.active};this.active.has(".ui-menu").length||this.collapseAll(e,!0),this._trigger("select",e,i)}})}(jQuery),function(t,e){function i(t,e,i){return[parseFloat(t[0])*(p.test(t[0])?e/100:1),parseFloat(t[1])*(p.test(t[1])?i/100:1)]}function s(e,i){return parseInt(t.css(e,i),10)||0}function n(e){var i=e[0];return 9===i.nodeType?{width:e.width(),height:e.height(),offset:{top:0,left:0}}:t.isWindow(i)?{width:e.width(),height:e.height(),offset:{top:e.scrollTop(),left:e.scrollLeft()}}:i.preventDefault?{width:0,height:0,offset:{top:i.pageY,left:i.pageX}}:{width:e.outerWidth(),height:e.outerHeight(),offset:e.offset()}}t.ui=t.ui||{};var o,a=Math.max,r=Math.abs,h=Math.round,l=/left|center|right/,c=/top|center|bottom/,u=/[\+\-]\d+(\.[\d]+)?%?/,d=/^\w+/,p=/%$/,f=t.fn.position;t.position={scrollbarWidth:function(){if(o!==e)return o;var i,s,n=t("<div style='display:block;width:50px;height:50px;overflow:hidden;'><div style='height:100px;width:auto;'></div></div>"),a=n.children()[0];return t("body").append(n),i=a.offsetWidth,n.css("overflow","scroll"),s=a.offsetWidth,i===s&&(s=n[0].clientWidth),n.remove(),o=i-s},getScrollInfo:function(e){var i=e.isWindow?"":e.element.css("overflow-x"),s=e.isWindow?"":e.element.css("overflow-y"),n="scroll"===i||"auto"===i&&e.width<e.element[0].scrollWidth,o="scroll"===s||"auto"===s&&e.height<e.element[0].scrollHeight;return{width:o?t.position.scrollbarWidth():0,height:n?t.position.scrollbarWidth():0}},getWithinInfo:function(e){var i=t(e||window),s=t.isWindow(i[0]);return{element:i,isWindow:s,offset:i.offset()||{left:0,top:0},scrollLeft:i.scrollLeft(),scrollTop:i.scrollTop(),width:s?i.width():i.outerWidth(),height:s?i.height():i.outerHeight()}}},t.fn.position=function(e){if(!e||!e.of)return f.apply(this,arguments);e=t.extend({},e);var o,p,g,m,v,_,b=t(e.of),y=t.position.getWithinInfo(e.within),w=t.position.getScrollInfo(y),k=(e.collision||"flip").split(" "),x={};return _=n(b),b[0].preventDefault&&(e.at="left top"),p=_.width,g=_.height,m=_.offset,v=t.extend({},m),t.each(["my","at"],function(){var t,i,s=(e[this]||"").split(" ");1===s.length&&(s=l.test(s[0])?s.concat(["center"]):c.test(s[0])?["center"].concat(s):["center","center"]),s[0]=l.test(s[0])?s[0]:"center",s[1]=c.test(s[1])?s[1]:"center",t=u.exec(s[0]),i=u.exec(s[1]),x[this]=[t?t[0]:0,i?i[0]:0],e[this]=[d.exec(s[0])[0],d.exec(s[1])[0]]}),1===k.length&&(k[1]=k[0]),"right"===e.at[0]?v.left+=p:"center"===e.at[0]&&(v.left+=p/2),"bottom"===e.at[1]?v.top+=g:"center"===e.at[1]&&(v.top+=g/2),o=i(x.at,p,g),v.left+=o[0],v.top+=o[1],this.each(function(){var n,l,c=t(this),u=c.outerWidth(),d=c.outerHeight(),f=s(this,"marginLeft"),_=s(this,"marginTop"),D=u+f+s(this,"marginRight")+w.width,C=d+_+s(this,"marginBottom")+w.height,I=t.extend({},v),P=i(x.my,c.outerWidth(),c.outerHeight());"right"===e.my[0]?I.left-=u:"center"===e.my[0]&&(I.left-=u/2),"bottom"===e.my[1]?I.top-=d:"center"===e.my[1]&&(I.top-=d/2),I.left+=P[0],I.top+=P[1],t.support.offsetFractions||(I.left=h(I.left),I.top=h(I.top)),n={marginLeft:f,marginTop:_},t.each(["left","top"],function(i,s){t.ui.position[k[i]]&&t.ui.position[k[i]][s](I,{targetWidth:p,targetHeight:g,elemWidth:u,elemHeight:d,collisionPosition:n,collisionWidth:D,collisionHeight:C,offset:[o[0]+P[0],o[1]+P[1]],my:e.my,at:e.at,within:y,elem:c})}),e.using&&(l=function(t){var i=m.left-I.left,s=i+p-u,n=m.top-I.top,o=n+g-d,h={target:{element:b,left:m.left,top:m.top,width:p,height:g},element:{element:c,left:I.left,top:I.top,width:u,height:d},horizontal:0>s?"left":i>0?"right":"center",vertical:0>o?"top":n>0?"bottom":"middle"};u>p&&p>r(i+s)&&(h.horizontal="center"),d>g&&g>r(n+o)&&(h.vertical="middle"),h.important=a(r(i),r(s))>a(r(n),r(o))?"horizontal":"vertical",e.using.call(this,t,h)}),c.offset(t.extend(I,{using:l}))})},t.ui.position={fit:{left:function(t,e){var i,s=e.within,n=s.isWindow?s.scrollLeft:s.offset.left,o=s.width,r=t.left-e.collisionPosition.marginLeft,h=n-r,l=r+e.collisionWidth-o-n;e.collisionWidth>o?h>0&&0>=l?(i=t.left+h+e.collisionWidth-o-n,t.left+=h-i):t.left=l>0&&0>=h?n:h>l?n+o-e.collisionWidth:n:h>0?t.left+=h:l>0?t.left-=l:t.left=a(t.left-r,t.left)},top:function(t,e){var i,s=e.within,n=s.isWindow?s.scrollTop:s.offset.top,o=e.within.height,r=t.top-e.collisionPosition.marginTop,h=n-r,l=r+e.collisionHeight-o-n;e.collisionHeight>o?h>0&&0>=l?(i=t.top+h+e.collisionHeight-o-n,t.top+=h-i):t.top=l>0&&0>=h?n:h>l?n+o-e.collisionHeight:n:h>0?t.top+=h:l>0?t.top-=l:t.top=a(t.top-r,t.top)}},flip:{left:function(t,e){var i,s,n=e.within,o=n.offset.left+n.scrollLeft,a=n.width,h=n.isWindow?n.scrollLeft:n.offset.left,l=t.left-e.collisionPosition.marginLeft,c=l-h,u=l+e.collisionWidth-a-h,d="left"===e.my[0]?-e.elemWidth:"right"===e.my[0]?e.elemWidth:0,p="left"===e.at[0]?e.targetWidth:"right"===e.at[0]?-e.targetWidth:0,f=-2*e.offset[0];0>c?(i=t.left+d+p+f+e.collisionWidth-a-o,(0>i||r(c)>i)&&(t.left+=d+p+f)):u>0&&(s=t.left-e.collisionPosition.marginLeft+d+p+f-h,(s>0||u>r(s))&&(t.left+=d+p+f))},top:function(t,e){var i,s,n=e.within,o=n.offset.top+n.scrollTop,a=n.height,h=n.isWindow?n.scrollTop:n.offset.top,l=t.top-e.collisionPosition.marginTop,c=l-h,u=l+e.collisionHeight-a-h,d="top"===e.my[1],p=d?-e.elemHeight:"bottom"===e.my[1]?e.elemHeight:0,f="top"===e.at[1]?e.targetHeight:"bottom"===e.at[1]?-e.targetHeight:0,g=-2*e.offset[1];0>c?(s=t.top+p+f+g+e.collisionHeight-a-o,t.top+p+f+g>c&&(0>s||r(c)>s)&&(t.top+=p+f+g)):u>0&&(i=t.top-e.collisionPosition.marginTop+p+f+g-h,t.top+p+f+g>u&&(i>0||u>r(i))&&(t.top+=p+f+g))}},flipfit:{left:function(){t.ui.position.flip.left.apply(this,arguments),t.ui.position.fit.left.apply(this,arguments)},top:function(){t.ui.position.flip.top.apply(this,arguments),t.ui.position.fit.top.apply(this,arguments)}}},function(){var e,i,s,n,o,a=document.getElementsByTagName("body")[0],r=document.createElement("div");e=document.createElement(a?"div":"body"),s={visibility:"hidden",width:0,height:0,border:0,margin:0,background:"none"},a&&t.extend(s,{position:"absolute",left:"-1000px",top:"-1000px"});for(o in s)e.style[o]=s[o];e.appendChild(r),i=a||document.documentElement,i.insertBefore(e,i.firstChild),r.style.cssText="position: absolute; left: 10.7432222px;",n=t(r).offset().left,t.support.offsetFractions=n>10&&11>n,e.innerHTML="",i.removeChild(e)}()}(jQuery),function(t,e){t.widget("ui.progressbar",{version:"1.10.2",options:{max:100,value:0,change:null,complete:null},min:0,_create:function(){this.oldValue=this.options.value=this._constrainedValue(),this.element.addClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").attr({role:"progressbar","aria-valuemin":this.min}),this.valueDiv=t("<div class='ui-progressbar-value ui-widget-header ui-corner-left'></div>").appendTo(this.element),this._refreshValue() +},_destroy:function(){this.element.removeClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").removeAttr("role").removeAttr("aria-valuemin").removeAttr("aria-valuemax").removeAttr("aria-valuenow"),this.valueDiv.remove()},value:function(t){return t===e?this.options.value:(this.options.value=this._constrainedValue(t),this._refreshValue(),e)},_constrainedValue:function(t){return t===e&&(t=this.options.value),this.indeterminate=t===!1,"number"!=typeof t&&(t=0),this.indeterminate?!1:Math.min(this.options.max,Math.max(this.min,t))},_setOptions:function(t){var e=t.value;delete t.value,this._super(t),this.options.value=this._constrainedValue(e),this._refreshValue()},_setOption:function(t,e){"max"===t&&(e=Math.max(this.min,e)),this._super(t,e)},_percentage:function(){return this.indeterminate?100:100*(this.options.value-this.min)/(this.options.max-this.min)},_refreshValue:function(){var e=this.options.value,i=this._percentage();this.valueDiv.toggle(this.indeterminate||e>this.min).toggleClass("ui-corner-right",e===this.options.max).width(i.toFixed(0)+"%"),this.element.toggleClass("ui-progressbar-indeterminate",this.indeterminate),this.indeterminate?(this.element.removeAttr("aria-valuenow"),this.overlayDiv||(this.overlayDiv=t("<div class='ui-progressbar-overlay'></div>").appendTo(this.valueDiv))):(this.element.attr({"aria-valuemax":this.options.max,"aria-valuenow":e}),this.overlayDiv&&(this.overlayDiv.remove(),this.overlayDiv=null)),this.oldValue!==e&&(this.oldValue=e,this._trigger("change")),e===this.options.max&&this._trigger("complete")}})}(jQuery),function(t){var e=5;t.widget("ui.slider",t.ui.mouse,{version:"1.10.2",widgetEventPrefix:"slide",options:{animate:!1,distance:0,max:100,min:0,orientation:"horizontal",range:!1,step:1,value:0,values:null,change:null,slide:null,start:null,stop:null},_create:function(){this._keySliding=!1,this._mouseSliding=!1,this._animateOff=!0,this._handleIndex=null,this._detectOrientation(),this._mouseInit(),this.element.addClass("ui-slider ui-slider-"+this.orientation+" ui-widget"+" ui-widget-content"+" ui-corner-all"),this._refresh(),this._setOption("disabled",this.options.disabled),this._animateOff=!1},_refresh:function(){this._createRange(),this._createHandles(),this._setupEvents(),this._refreshValue()},_createHandles:function(){var e,i,s=this.options,n=this.element.find(".ui-slider-handle").addClass("ui-state-default ui-corner-all"),o="<a class='ui-slider-handle ui-state-default ui-corner-all' href='#'></a>",a=[];for(i=s.values&&s.values.length||1,n.length>i&&(n.slice(i).remove(),n=n.slice(0,i)),e=n.length;i>e;e++)a.push(o);this.handles=n.add(t(a.join("")).appendTo(this.element)),this.handle=this.handles.eq(0),this.handles.each(function(e){t(this).data("ui-slider-handle-index",e)})},_createRange:function(){var e=this.options,i="";e.range?(e.range===!0&&(e.values?e.values.length&&2!==e.values.length?e.values=[e.values[0],e.values[0]]:t.isArray(e.values)&&(e.values=e.values.slice(0)):e.values=[this._valueMin(),this._valueMin()]),this.range&&this.range.length?this.range.removeClass("ui-slider-range-min ui-slider-range-max").css({left:"",bottom:""}):(this.range=t("<div></div>").appendTo(this.element),i="ui-slider-range ui-widget-header ui-corner-all"),this.range.addClass(i+("min"===e.range||"max"===e.range?" ui-slider-range-"+e.range:""))):this.range=t([])},_setupEvents:function(){var t=this.handles.add(this.range).filter("a");this._off(t),this._on(t,this._handleEvents),this._hoverable(t),this._focusable(t)},_destroy:function(){this.handles.remove(),this.range.remove(),this.element.removeClass("ui-slider ui-slider-horizontal ui-slider-vertical ui-widget ui-widget-content ui-corner-all"),this._mouseDestroy()},_mouseCapture:function(e){var i,s,n,o,a,r,h,l,c=this,u=this.options;return u.disabled?!1:(this.elementSize={width:this.element.outerWidth(),height:this.element.outerHeight()},this.elementOffset=this.element.offset(),i={x:e.pageX,y:e.pageY},s=this._normValueFromMouse(i),n=this._valueMax()-this._valueMin()+1,this.handles.each(function(e){var i=Math.abs(s-c.values(e));(n>i||n===i&&(e===c._lastChangedValue||c.values(e)===u.min))&&(n=i,o=t(this),a=e)}),r=this._start(e,a),r===!1?!1:(this._mouseSliding=!0,this._handleIndex=a,o.addClass("ui-state-active").focus(),h=o.offset(),l=!t(e.target).parents().addBack().is(".ui-slider-handle"),this._clickOffset=l?{left:0,top:0}:{left:e.pageX-h.left-o.width()/2,top:e.pageY-h.top-o.height()/2-(parseInt(o.css("borderTopWidth"),10)||0)-(parseInt(o.css("borderBottomWidth"),10)||0)+(parseInt(o.css("marginTop"),10)||0)},this.handles.hasClass("ui-state-hover")||this._slide(e,a,s),this._animateOff=!0,!0))},_mouseStart:function(){return!0},_mouseDrag:function(t){var e={x:t.pageX,y:t.pageY},i=this._normValueFromMouse(e);return this._slide(t,this._handleIndex,i),!1},_mouseStop:function(t){return this.handles.removeClass("ui-state-active"),this._mouseSliding=!1,this._stop(t,this._handleIndex),this._change(t,this._handleIndex),this._handleIndex=null,this._clickOffset=null,this._animateOff=!1,!1},_detectOrientation:function(){this.orientation="vertical"===this.options.orientation?"vertical":"horizontal"},_normValueFromMouse:function(t){var e,i,s,n,o;return"horizontal"===this.orientation?(e=this.elementSize.width,i=t.x-this.elementOffset.left-(this._clickOffset?this._clickOffset.left:0)):(e=this.elementSize.height,i=t.y-this.elementOffset.top-(this._clickOffset?this._clickOffset.top:0)),s=i/e,s>1&&(s=1),0>s&&(s=0),"vertical"===this.orientation&&(s=1-s),n=this._valueMax()-this._valueMin(),o=this._valueMin()+s*n,this._trimAlignValue(o)},_start:function(t,e){var i={handle:this.handles[e],value:this.value()};return this.options.values&&this.options.values.length&&(i.value=this.values(e),i.values=this.values()),this._trigger("start",t,i)},_slide:function(t,e,i){var s,n,o;this.options.values&&this.options.values.length?(s=this.values(e?0:1),2===this.options.values.length&&this.options.range===!0&&(0===e&&i>s||1===e&&s>i)&&(i=s),i!==this.values(e)&&(n=this.values(),n[e]=i,o=this._trigger("slide",t,{handle:this.handles[e],value:i,values:n}),s=this.values(e?0:1),o!==!1&&this.values(e,i,!0))):i!==this.value()&&(o=this._trigger("slide",t,{handle:this.handles[e],value:i}),o!==!1&&this.value(i))},_stop:function(t,e){var i={handle:this.handles[e],value:this.value()};this.options.values&&this.options.values.length&&(i.value=this.values(e),i.values=this.values()),this._trigger("stop",t,i)},_change:function(t,e){if(!this._keySliding&&!this._mouseSliding){var i={handle:this.handles[e],value:this.value()};this.options.values&&this.options.values.length&&(i.value=this.values(e),i.values=this.values()),this._lastChangedValue=e,this._trigger("change",t,i)}},value:function(t){return arguments.length?(this.options.value=this._trimAlignValue(t),this._refreshValue(),this._change(null,0),undefined):this._value()},values:function(e,i){var s,n,o;if(arguments.length>1)return this.options.values[e]=this._trimAlignValue(i),this._refreshValue(),this._change(null,e),undefined;if(!arguments.length)return this._values();if(!t.isArray(arguments[0]))return this.options.values&&this.options.values.length?this._values(e):this.value();for(s=this.options.values,n=arguments[0],o=0;s.length>o;o+=1)s[o]=this._trimAlignValue(n[o]),this._change(null,o);this._refreshValue()},_setOption:function(e,i){var s,n=0;switch("range"===e&&this.options.range===!0&&("min"===i?(this.options.value=this._values(0),this.options.values=null):"max"===i&&(this.options.value=this._values(this.options.values.length-1),this.options.values=null)),t.isArray(this.options.values)&&(n=this.options.values.length),t.Widget.prototype._setOption.apply(this,arguments),e){case"orientation":this._detectOrientation(),this.element.removeClass("ui-slider-horizontal ui-slider-vertical").addClass("ui-slider-"+this.orientation),this._refreshValue();break;case"value":this._animateOff=!0,this._refreshValue(),this._change(null,0),this._animateOff=!1;break;case"values":for(this._animateOff=!0,this._refreshValue(),s=0;n>s;s+=1)this._change(null,s);this._animateOff=!1;break;case"min":case"max":this._animateOff=!0,this._refreshValue(),this._animateOff=!1;break;case"range":this._animateOff=!0,this._refresh(),this._animateOff=!1}},_value:function(){var t=this.options.value;return t=this._trimAlignValue(t)},_values:function(t){var e,i,s;if(arguments.length)return e=this.options.values[t],e=this._trimAlignValue(e);if(this.options.values&&this.options.values.length){for(i=this.options.values.slice(),s=0;i.length>s;s+=1)i[s]=this._trimAlignValue(i[s]);return i}return[]},_trimAlignValue:function(t){if(this._valueMin()>=t)return this._valueMin();if(t>=this._valueMax())return this._valueMax();var e=this.options.step>0?this.options.step:1,i=(t-this._valueMin())%e,s=t-i;return 2*Math.abs(i)>=e&&(s+=i>0?e:-e),parseFloat(s.toFixed(5))},_valueMin:function(){return this.options.min},_valueMax:function(){return this.options.max},_refreshValue:function(){var e,i,s,n,o,a=this.options.range,r=this.options,h=this,l=this._animateOff?!1:r.animate,c={};this.options.values&&this.options.values.length?this.handles.each(function(s){i=100*((h.values(s)-h._valueMin())/(h._valueMax()-h._valueMin())),c["horizontal"===h.orientation?"left":"bottom"]=i+"%",t(this).stop(1,1)[l?"animate":"css"](c,r.animate),h.options.range===!0&&("horizontal"===h.orientation?(0===s&&h.range.stop(1,1)[l?"animate":"css"]({left:i+"%"},r.animate),1===s&&h.range[l?"animate":"css"]({width:i-e+"%"},{queue:!1,duration:r.animate})):(0===s&&h.range.stop(1,1)[l?"animate":"css"]({bottom:i+"%"},r.animate),1===s&&h.range[l?"animate":"css"]({height:i-e+"%"},{queue:!1,duration:r.animate}))),e=i}):(s=this.value(),n=this._valueMin(),o=this._valueMax(),i=o!==n?100*((s-n)/(o-n)):0,c["horizontal"===this.orientation?"left":"bottom"]=i+"%",this.handle.stop(1,1)[l?"animate":"css"](c,r.animate),"min"===a&&"horizontal"===this.orientation&&this.range.stop(1,1)[l?"animate":"css"]({width:i+"%"},r.animate),"max"===a&&"horizontal"===this.orientation&&this.range[l?"animate":"css"]({width:100-i+"%"},{queue:!1,duration:r.animate}),"min"===a&&"vertical"===this.orientation&&this.range.stop(1,1)[l?"animate":"css"]({height:i+"%"},r.animate),"max"===a&&"vertical"===this.orientation&&this.range[l?"animate":"css"]({height:100-i+"%"},{queue:!1,duration:r.animate}))},_handleEvents:{keydown:function(i){var s,n,o,a,r=t(i.target).data("ui-slider-handle-index");switch(i.keyCode){case t.ui.keyCode.HOME:case t.ui.keyCode.END:case t.ui.keyCode.PAGE_UP:case t.ui.keyCode.PAGE_DOWN:case t.ui.keyCode.UP:case t.ui.keyCode.RIGHT:case t.ui.keyCode.DOWN:case t.ui.keyCode.LEFT:if(i.preventDefault(),!this._keySliding&&(this._keySliding=!0,t(i.target).addClass("ui-state-active"),s=this._start(i,r),s===!1))return}switch(a=this.options.step,n=o=this.options.values&&this.options.values.length?this.values(r):this.value(),i.keyCode){case t.ui.keyCode.HOME:o=this._valueMin();break;case t.ui.keyCode.END:o=this._valueMax();break;case t.ui.keyCode.PAGE_UP:o=this._trimAlignValue(n+(this._valueMax()-this._valueMin())/e);break;case t.ui.keyCode.PAGE_DOWN:o=this._trimAlignValue(n-(this._valueMax()-this._valueMin())/e);break;case t.ui.keyCode.UP:case t.ui.keyCode.RIGHT:if(n===this._valueMax())return;o=this._trimAlignValue(n+a);break;case t.ui.keyCode.DOWN:case t.ui.keyCode.LEFT:if(n===this._valueMin())return;o=this._trimAlignValue(n-a)}this._slide(i,r,o)},click:function(t){t.preventDefault()},keyup:function(e){var i=t(e.target).data("ui-slider-handle-index");this._keySliding&&(this._keySliding=!1,this._stop(e,i),this._change(e,i),t(e.target).removeClass("ui-state-active"))}}})}(jQuery),function(t){function e(t){return function(){var e=this.element.val();t.apply(this,arguments),this._refresh(),e!==this.element.val()&&this._trigger("change")}}t.widget("ui.spinner",{version:"1.10.2",defaultElement:"<input>",widgetEventPrefix:"spin",options:{culture:null,icons:{down:"ui-icon-triangle-1-s",up:"ui-icon-triangle-1-n"},incremental:!0,max:null,min:null,numberFormat:null,page:10,step:1,change:null,spin:null,start:null,stop:null},_create:function(){this._setOption("max",this.options.max),this._setOption("min",this.options.min),this._setOption("step",this.options.step),this._value(this.element.val(),!0),this._draw(),this._on(this._events),this._refresh(),this._on(this.window,{beforeunload:function(){this.element.removeAttr("autocomplete")}})},_getCreateOptions:function(){var e={},i=this.element;return t.each(["min","max","step"],function(t,s){var n=i.attr(s);void 0!==n&&n.length&&(e[s]=n)}),e},_events:{keydown:function(t){this._start(t)&&this._keydown(t)&&t.preventDefault()},keyup:"_stop",focus:function(){this.previous=this.element.val()},blur:function(t){return this.cancelBlur?(delete this.cancelBlur,void 0):(this._stop(),this._refresh(),this.previous!==this.element.val()&&this._trigger("change",t),void 0)},mousewheel:function(t,e){if(e){if(!this.spinning&&!this._start(t))return!1;this._spin((e>0?1:-1)*this.options.step,t),clearTimeout(this.mousewheelTimer),this.mousewheelTimer=this._delay(function(){this.spinning&&this._stop(t)},100),t.preventDefault()}},"mousedown .ui-spinner-button":function(e){function i(){var t=this.element[0]===this.document[0].activeElement;t||(this.element.focus(),this.previous=s,this._delay(function(){this.previous=s}))}var s;s=this.element[0]===this.document[0].activeElement?this.previous:this.element.val(),e.preventDefault(),i.call(this),this.cancelBlur=!0,this._delay(function(){delete this.cancelBlur,i.call(this)}),this._start(e)!==!1&&this._repeat(null,t(e.currentTarget).hasClass("ui-spinner-up")?1:-1,e)},"mouseup .ui-spinner-button":"_stop","mouseenter .ui-spinner-button":function(e){return t(e.currentTarget).hasClass("ui-state-active")?this._start(e)===!1?!1:(this._repeat(null,t(e.currentTarget).hasClass("ui-spinner-up")?1:-1,e),void 0):void 0},"mouseleave .ui-spinner-button":"_stop"},_draw:function(){var t=this.uiSpinner=this.element.addClass("ui-spinner-input").attr("autocomplete","off").wrap(this._uiSpinnerHtml()).parent().append(this._buttonHtml());this.element.attr("role","spinbutton"),this.buttons=t.find(".ui-spinner-button").attr("tabIndex",-1).button().removeClass("ui-corner-all"),this.buttons.height()>Math.ceil(.5*t.height())&&t.height()>0&&t.height(t.height()),this.options.disabled&&this.disable()},_keydown:function(e){var i=this.options,s=t.ui.keyCode;switch(e.keyCode){case s.UP:return this._repeat(null,1,e),!0;case s.DOWN:return this._repeat(null,-1,e),!0;case s.PAGE_UP:return this._repeat(null,i.page,e),!0;case s.PAGE_DOWN:return this._repeat(null,-i.page,e),!0}return!1},_uiSpinnerHtml:function(){return"<span class='ui-spinner ui-widget ui-widget-content ui-corner-all'></span>"},_buttonHtml:function(){return"<a class='ui-spinner-button ui-spinner-up ui-corner-tr'><span class='ui-icon "+this.options.icons.up+"'>▲</span>"+"</a>"+"<a class='ui-spinner-button ui-spinner-down ui-corner-br'>"+"<span class='ui-icon "+this.options.icons.down+"'>▼</span>"+"</a>"},_start:function(t){return this.spinning||this._trigger("start",t)!==!1?(this.counter||(this.counter=1),this.spinning=!0,!0):!1},_repeat:function(t,e,i){t=t||500,clearTimeout(this.timer),this.timer=this._delay(function(){this._repeat(40,e,i)},t),this._spin(e*this.options.step,i)},_spin:function(t,e){var i=this.value()||0;this.counter||(this.counter=1),i=this._adjustValue(i+t*this._increment(this.counter)),this.spinning&&this._trigger("spin",e,{value:i})===!1||(this._value(i),this.counter++)},_increment:function(e){var i=this.options.incremental;return i?t.isFunction(i)?i(e):Math.floor(e*e*e/5e4-e*e/500+17*e/200+1):1},_precision:function(){var t=this._precisionOf(this.options.step);return null!==this.options.min&&(t=Math.max(t,this._precisionOf(this.options.min))),t},_precisionOf:function(t){var e=""+t,i=e.indexOf(".");return-1===i?0:e.length-i-1},_adjustValue:function(t){var e,i,s=this.options;return e=null!==s.min?s.min:0,i=t-e,i=Math.round(i/s.step)*s.step,t=e+i,t=parseFloat(t.toFixed(this._precision())),null!==s.max&&t>s.max?s.max:null!==s.min&&s.min>t?s.min:t},_stop:function(t){this.spinning&&(clearTimeout(this.timer),clearTimeout(this.mousewheelTimer),this.counter=0,this.spinning=!1,this._trigger("stop",t))},_setOption:function(t,e){if("culture"===t||"numberFormat"===t){var i=this._parse(this.element.val());return this.options[t]=e,this.element.val(this._format(i)),void 0}("max"===t||"min"===t||"step"===t)&&"string"==typeof e&&(e=this._parse(e)),"icons"===t&&(this.buttons.first().find(".ui-icon").removeClass(this.options.icons.up).addClass(e.up),this.buttons.last().find(".ui-icon").removeClass(this.options.icons.down).addClass(e.down)),this._super(t,e),"disabled"===t&&(e?(this.element.prop("disabled",!0),this.buttons.button("disable")):(this.element.prop("disabled",!1),this.buttons.button("enable")))},_setOptions:e(function(t){this._super(t),this._value(this.element.val())}),_parse:function(t){return"string"==typeof t&&""!==t&&(t=window.Globalize&&this.options.numberFormat?Globalize.parseFloat(t,10,this.options.culture):+t),""===t||isNaN(t)?null:t},_format:function(t){return""===t?"":window.Globalize&&this.options.numberFormat?Globalize.format(t,this.options.numberFormat,this.options.culture):t},_refresh:function(){this.element.attr({"aria-valuemin":this.options.min,"aria-valuemax":this.options.max,"aria-valuenow":this._parse(this.element.val())})},_value:function(t,e){var i;""!==t&&(i=this._parse(t),null!==i&&(e||(i=this._adjustValue(i)),t=this._format(i))),this.element.val(t),this._refresh()},_destroy:function(){this.element.removeClass("ui-spinner-input").prop("disabled",!1).removeAttr("autocomplete").removeAttr("role").removeAttr("aria-valuemin").removeAttr("aria-valuemax").removeAttr("aria-valuenow"),this.uiSpinner.replaceWith(this.element)},stepUp:e(function(t){this._stepUp(t)}),_stepUp:function(t){this._start()&&(this._spin((t||1)*this.options.step),this._stop())},stepDown:e(function(t){this._stepDown(t)}),_stepDown:function(t){this._start()&&(this._spin((t||1)*-this.options.step),this._stop())},pageUp:e(function(t){this._stepUp((t||1)*this.options.page)}),pageDown:e(function(t){this._stepDown((t||1)*this.options.page)}),value:function(t){return arguments.length?(e(this._value).call(this,t),void 0):this._parse(this.element.val())},widget:function(){return this.uiSpinner}})}(jQuery),function(t,e){function i(){return++n}function s(t){return t.hash.length>1&&decodeURIComponent(t.href.replace(o,""))===decodeURIComponent(location.href.replace(o,""))}var n=0,o=/#.*$/;t.widget("ui.tabs",{version:"1.10.2",delay:300,options:{active:null,collapsible:!1,event:"click",heightStyle:"content",hide:null,show:null,activate:null,beforeActivate:null,beforeLoad:null,load:null},_create:function(){var e=this,i=this.options;this.running=!1,this.element.addClass("ui-tabs ui-widget ui-widget-content ui-corner-all").toggleClass("ui-tabs-collapsible",i.collapsible).delegate(".ui-tabs-nav > li","mousedown"+this.eventNamespace,function(e){t(this).is(".ui-state-disabled")&&e.preventDefault()}).delegate(".ui-tabs-anchor","focus"+this.eventNamespace,function(){t(this).closest("li").is(".ui-state-disabled")&&this.blur()}),this._processTabs(),i.active=this._initialActive(),t.isArray(i.disabled)&&(i.disabled=t.unique(i.disabled.concat(t.map(this.tabs.filter(".ui-state-disabled"),function(t){return e.tabs.index(t)}))).sort()),this.active=this.options.active!==!1&&this.anchors.length?this._findActive(i.active):t(),this._refresh(),this.active.length&&this.load(i.active)},_initialActive:function(){var i=this.options.active,s=this.options.collapsible,n=location.hash.substring(1);return null===i&&(n&&this.tabs.each(function(s,o){return t(o).attr("aria-controls")===n?(i=s,!1):e}),null===i&&(i=this.tabs.index(this.tabs.filter(".ui-tabs-active"))),(null===i||-1===i)&&(i=this.tabs.length?0:!1)),i!==!1&&(i=this.tabs.index(this.tabs.eq(i)),-1===i&&(i=s?!1:0)),!s&&i===!1&&this.anchors.length&&(i=0),i},_getCreateEventData:function(){return{tab:this.active,panel:this.active.length?this._getPanelForTab(this.active):t()}},_tabKeydown:function(i){var s=t(this.document[0].activeElement).closest("li"),n=this.tabs.index(s),o=!0;if(!this._handlePageNav(i)){switch(i.keyCode){case t.ui.keyCode.RIGHT:case t.ui.keyCode.DOWN:n++;break;case t.ui.keyCode.UP:case t.ui.keyCode.LEFT:o=!1,n--;break;case t.ui.keyCode.END:n=this.anchors.length-1;break;case t.ui.keyCode.HOME:n=0;break;case t.ui.keyCode.SPACE:return i.preventDefault(),clearTimeout(this.activating),this._activate(n),e;case t.ui.keyCode.ENTER:return i.preventDefault(),clearTimeout(this.activating),this._activate(n===this.options.active?!1:n),e;default:return}i.preventDefault(),clearTimeout(this.activating),n=this._focusNextTab(n,o),i.ctrlKey||(s.attr("aria-selected","false"),this.tabs.eq(n).attr("aria-selected","true"),this.activating=this._delay(function(){this.option("active",n)},this.delay))}},_panelKeydown:function(e){this._handlePageNav(e)||e.ctrlKey&&e.keyCode===t.ui.keyCode.UP&&(e.preventDefault(),this.active.focus())},_handlePageNav:function(i){return i.altKey&&i.keyCode===t.ui.keyCode.PAGE_UP?(this._activate(this._focusNextTab(this.options.active-1,!1)),!0):i.altKey&&i.keyCode===t.ui.keyCode.PAGE_DOWN?(this._activate(this._focusNextTab(this.options.active+1,!0)),!0):e},_findNextTab:function(e,i){function s(){return e>n&&(e=0),0>e&&(e=n),e}for(var n=this.tabs.length-1;-1!==t.inArray(s(),this.options.disabled);)e=i?e+1:e-1;return e},_focusNextTab:function(t,e){return t=this._findNextTab(t,e),this.tabs.eq(t).focus(),t},_setOption:function(t,i){return"active"===t?(this._activate(i),e):"disabled"===t?(this._setupDisabled(i),e):(this._super(t,i),"collapsible"===t&&(this.element.toggleClass("ui-tabs-collapsible",i),i||this.options.active!==!1||this._activate(0)),"event"===t&&this._setupEvents(i),"heightStyle"===t&&this._setupHeightStyle(i),e)},_tabId:function(t){return t.attr("aria-controls")||"ui-tabs-"+i()},_sanitizeSelector:function(t){return t?t.replace(/[!"$%&'()*+,.\/:;<=>?@\[\]\^`{|}~]/g,"\\$&"):""},refresh:function(){var e=this.options,i=this.tablist.children(":has(a[href])");e.disabled=t.map(i.filter(".ui-state-disabled"),function(t){return i.index(t)}),this._processTabs(),e.active!==!1&&this.anchors.length?this.active.length&&!t.contains(this.tablist[0],this.active[0])?this.tabs.length===e.disabled.length?(e.active=!1,this.active=t()):this._activate(this._findNextTab(Math.max(0,e.active-1),!1)):e.active=this.tabs.index(this.active):(e.active=!1,this.active=t()),this._refresh()},_refresh:function(){this._setupDisabled(this.options.disabled),this._setupEvents(this.options.event),this._setupHeightStyle(this.options.heightStyle),this.tabs.not(this.active).attr({"aria-selected":"false",tabIndex:-1}),this.panels.not(this._getPanelForTab(this.active)).hide().attr({"aria-expanded":"false","aria-hidden":"true"}),this.active.length?(this.active.addClass("ui-tabs-active ui-state-active").attr({"aria-selected":"true",tabIndex:0}),this._getPanelForTab(this.active).show().attr({"aria-expanded":"true","aria-hidden":"false"})):this.tabs.eq(0).attr("tabIndex",0)},_processTabs:function(){var e=this;this.tablist=this._getList().addClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all").attr("role","tablist"),this.tabs=this.tablist.find("> li:has(a[href])").addClass("ui-state-default ui-corner-top").attr({role:"tab",tabIndex:-1}),this.anchors=this.tabs.map(function(){return t("a",this)[0]}).addClass("ui-tabs-anchor").attr({role:"presentation",tabIndex:-1}),this.panels=t(),this.anchors.each(function(i,n){var o,a,r,h=t(n).uniqueId().attr("id"),l=t(n).closest("li"),c=l.attr("aria-controls");s(n)?(o=n.hash,a=e.element.find(e._sanitizeSelector(o))):(r=e._tabId(l),o="#"+r,a=e.element.find(o),a.length||(a=e._createPanel(r),a.insertAfter(e.panels[i-1]||e.tablist)),a.attr("aria-live","polite")),a.length&&(e.panels=e.panels.add(a)),c&&l.data("ui-tabs-aria-controls",c),l.attr({"aria-controls":o.substring(1),"aria-labelledby":h}),a.attr("aria-labelledby",h)}),this.panels.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom").attr("role","tabpanel")},_getList:function(){return this.element.find("ol,ul").eq(0)},_createPanel:function(e){return t("<div>").attr("id",e).addClass("ui-tabs-panel ui-widget-content ui-corner-bottom").data("ui-tabs-destroy",!0)},_setupDisabled:function(e){t.isArray(e)&&(e.length?e.length===this.anchors.length&&(e=!0):e=!1);for(var i,s=0;i=this.tabs[s];s++)e===!0||-1!==t.inArray(s,e)?t(i).addClass("ui-state-disabled").attr("aria-disabled","true"):t(i).removeClass("ui-state-disabled").removeAttr("aria-disabled");this.options.disabled=e},_setupEvents:function(e){var i={click:function(t){t.preventDefault()}};e&&t.each(e.split(" "),function(t,e){i[e]="_eventHandler"}),this._off(this.anchors.add(this.tabs).add(this.panels)),this._on(this.anchors,i),this._on(this.tabs,{keydown:"_tabKeydown"}),this._on(this.panels,{keydown:"_panelKeydown"}),this._focusable(this.tabs),this._hoverable(this.tabs)},_setupHeightStyle:function(e){var i,s=this.element.parent();"fill"===e?(i=s.height(),i-=this.element.outerHeight()-this.element.height(),this.element.siblings(":visible").each(function(){var e=t(this),s=e.css("position");"absolute"!==s&&"fixed"!==s&&(i-=e.outerHeight(!0))}),this.element.children().not(this.panels).each(function(){i-=t(this).outerHeight(!0)}),this.panels.each(function(){t(this).height(Math.max(0,i-t(this).innerHeight()+t(this).height()))}).css("overflow","auto")):"auto"===e&&(i=0,this.panels.each(function(){i=Math.max(i,t(this).height("").height())}).height(i))},_eventHandler:function(e){var i=this.options,s=this.active,n=t(e.currentTarget),o=n.closest("li"),a=o[0]===s[0],r=a&&i.collapsible,h=r?t():this._getPanelForTab(o),l=s.length?this._getPanelForTab(s):t(),c={oldTab:s,oldPanel:l,newTab:r?t():o,newPanel:h};e.preventDefault(),o.hasClass("ui-state-disabled")||o.hasClass("ui-tabs-loading")||this.running||a&&!i.collapsible||this._trigger("beforeActivate",e,c)===!1||(i.active=r?!1:this.tabs.index(o),this.active=a?t():o,this.xhr&&this.xhr.abort(),l.length||h.length||t.error("jQuery UI Tabs: Mismatching fragment identifier."),h.length&&this.load(this.tabs.index(o),e),this._toggle(e,c))},_toggle:function(e,i){function s(){o.running=!1,o._trigger("activate",e,i)}function n(){i.newTab.closest("li").addClass("ui-tabs-active ui-state-active"),a.length&&o.options.show?o._show(a,o.options.show,s):(a.show(),s())}var o=this,a=i.newPanel,r=i.oldPanel;this.running=!0,r.length&&this.options.hide?this._hide(r,this.options.hide,function(){i.oldTab.closest("li").removeClass("ui-tabs-active ui-state-active"),n()}):(i.oldTab.closest("li").removeClass("ui-tabs-active ui-state-active"),r.hide(),n()),r.attr({"aria-expanded":"false","aria-hidden":"true"}),i.oldTab.attr("aria-selected","false"),a.length&&r.length?i.oldTab.attr("tabIndex",-1):a.length&&this.tabs.filter(function(){return 0===t(this).attr("tabIndex")}).attr("tabIndex",-1),a.attr({"aria-expanded":"true","aria-hidden":"false"}),i.newTab.attr({"aria-selected":"true",tabIndex:0})},_activate:function(e){var i,s=this._findActive(e);s[0]!==this.active[0]&&(s.length||(s=this.active),i=s.find(".ui-tabs-anchor")[0],this._eventHandler({target:i,currentTarget:i,preventDefault:t.noop}))},_findActive:function(e){return e===!1?t():this.tabs.eq(e)},_getIndex:function(t){return"string"==typeof t&&(t=this.anchors.index(this.anchors.filter("[href$='"+t+"']"))),t},_destroy:function(){this.xhr&&this.xhr.abort(),this.element.removeClass("ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible"),this.tablist.removeClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all").removeAttr("role"),this.anchors.removeClass("ui-tabs-anchor").removeAttr("role").removeAttr("tabIndex").removeUniqueId(),this.tabs.add(this.panels).each(function(){t.data(this,"ui-tabs-destroy")?t(this).remove():t(this).removeClass("ui-state-default ui-state-active ui-state-disabled ui-corner-top ui-corner-bottom ui-widget-content ui-tabs-active ui-tabs-panel").removeAttr("tabIndex").removeAttr("aria-live").removeAttr("aria-busy").removeAttr("aria-selected").removeAttr("aria-labelledby").removeAttr("aria-hidden").removeAttr("aria-expanded").removeAttr("role")}),this.tabs.each(function(){var e=t(this),i=e.data("ui-tabs-aria-controls");i?e.attr("aria-controls",i).removeData("ui-tabs-aria-controls"):e.removeAttr("aria-controls")}),this.panels.show(),"content"!==this.options.heightStyle&&this.panels.css("height","")},enable:function(i){var s=this.options.disabled;s!==!1&&(i===e?s=!1:(i=this._getIndex(i),s=t.isArray(s)?t.map(s,function(t){return t!==i?t:null}):t.map(this.tabs,function(t,e){return e!==i?e:null})),this._setupDisabled(s))},disable:function(i){var s=this.options.disabled;if(s!==!0){if(i===e)s=!0;else{if(i=this._getIndex(i),-1!==t.inArray(i,s))return;s=t.isArray(s)?t.merge([i],s).sort():[i]}this._setupDisabled(s)}},load:function(e,i){e=this._getIndex(e);var n=this,o=this.tabs.eq(e),a=o.find(".ui-tabs-anchor"),r=this._getPanelForTab(o),h={tab:o,panel:r};s(a[0])||(this.xhr=t.ajax(this._ajaxSettings(a,i,h)),this.xhr&&"canceled"!==this.xhr.statusText&&(o.addClass("ui-tabs-loading"),r.attr("aria-busy","true"),this.xhr.success(function(t){setTimeout(function(){r.html(t),n._trigger("load",i,h)},1)}).complete(function(t,e){setTimeout(function(){"abort"===e&&n.panels.stop(!1,!0),o.removeClass("ui-tabs-loading"),r.removeAttr("aria-busy"),t===n.xhr&&delete n.xhr},1)})))},_ajaxSettings:function(e,i,s){var n=this;return{url:e.attr("href"),beforeSend:function(e,o){return n._trigger("beforeLoad",i,t.extend({jqXHR:e,ajaxSettings:o},s))}}},_getPanelForTab:function(e){var i=t(e).attr("aria-controls");return this.element.find(this._sanitizeSelector("#"+i))}})}(jQuery),function(t){function e(e,i){var s=(e.attr("aria-describedby")||"").split(/\s+/);s.push(i),e.data("ui-tooltip-id",i).attr("aria-describedby",t.trim(s.join(" ")))}function i(e){var i=e.data("ui-tooltip-id"),s=(e.attr("aria-describedby")||"").split(/\s+/),n=t.inArray(i,s);-1!==n&&s.splice(n,1),e.removeData("ui-tooltip-id"),s=t.trim(s.join(" ")),s?e.attr("aria-describedby",s):e.removeAttr("aria-describedby")}var s=0;t.widget("ui.tooltip",{version:"1.10.2",options:{content:function(){var e=t(this).attr("title")||"";return t("<a>").text(e).html()},hide:!0,items:"[title]:not([disabled])",position:{my:"left top+15",at:"left bottom",collision:"flipfit flip"},show:!0,tooltipClass:null,track:!1,close:null,open:null},_create:function(){this._on({mouseover:"open",focusin:"open"}),this.tooltips={},this.parents={},this.options.disabled&&this._disable()},_setOption:function(e,i){var s=this;return"disabled"===e?(this[i?"_disable":"_enable"](),this.options[e]=i,void 0):(this._super(e,i),"content"===e&&t.each(this.tooltips,function(t,e){s._updateContent(e)}),void 0)},_disable:function(){var e=this;t.each(this.tooltips,function(i,s){var n=t.Event("blur");n.target=n.currentTarget=s[0],e.close(n,!0)}),this.element.find(this.options.items).addBack().each(function(){var e=t(this);e.is("[title]")&&e.data("ui-tooltip-title",e.attr("title")).attr("title","")})},_enable:function(){this.element.find(this.options.items).addBack().each(function(){var e=t(this);e.data("ui-tooltip-title")&&e.attr("title",e.data("ui-tooltip-title"))})},open:function(e){var i=this,s=t(e?e.target:this.element).closest(this.options.items);s.length&&!s.data("ui-tooltip-id")&&(s.attr("title")&&s.data("ui-tooltip-title",s.attr("title")),s.data("ui-tooltip-open",!0),e&&"mouseover"===e.type&&s.parents().each(function(){var e,s=t(this);s.data("ui-tooltip-open")&&(e=t.Event("blur"),e.target=e.currentTarget=this,i.close(e,!0)),s.attr("title")&&(s.uniqueId(),i.parents[this.id]={element:this,title:s.attr("title")},s.attr("title",""))}),this._updateContent(s,e))},_updateContent:function(t,e){var i,s=this.options.content,n=this,o=e?e.type:null;return"string"==typeof s?this._open(e,t,s):(i=s.call(t[0],function(i){t.data("ui-tooltip-open")&&n._delay(function(){e&&(e.type=o),this._open(e,t,i) +})}),i&&this._open(e,t,i),void 0)},_open:function(i,s,n){function o(t){l.of=t,a.is(":hidden")||a.position(l)}var a,r,h,l=t.extend({},this.options.position);if(n){if(a=this._find(s),a.length)return a.find(".ui-tooltip-content").html(n),void 0;s.is("[title]")&&(i&&"mouseover"===i.type?s.attr("title",""):s.removeAttr("title")),a=this._tooltip(s),e(s,a.attr("id")),a.find(".ui-tooltip-content").html(n),this.options.track&&i&&/^mouse/.test(i.type)?(this._on(this.document,{mousemove:o}),o(i)):a.position(t.extend({of:s},this.options.position)),a.hide(),this._show(a,this.options.show),this.options.show&&this.options.show.delay&&(h=this.delayedShow=setInterval(function(){a.is(":visible")&&(o(l.of),clearInterval(h))},t.fx.interval)),this._trigger("open",i,{tooltip:a}),r={keyup:function(e){if(e.keyCode===t.ui.keyCode.ESCAPE){var i=t.Event(e);i.currentTarget=s[0],this.close(i,!0)}},remove:function(){this._removeTooltip(a)}},i&&"mouseover"!==i.type||(r.mouseleave="close"),i&&"focusin"!==i.type||(r.focusout="close"),this._on(!0,s,r)}},close:function(e){var s=this,n=t(e?e.currentTarget:this.element),o=this._find(n);this.closing||(clearInterval(this.delayedShow),n.data("ui-tooltip-title")&&n.attr("title",n.data("ui-tooltip-title")),i(n),o.stop(!0),this._hide(o,this.options.hide,function(){s._removeTooltip(t(this))}),n.removeData("ui-tooltip-open"),this._off(n,"mouseleave focusout keyup"),n[0]!==this.element[0]&&this._off(n,"remove"),this._off(this.document,"mousemove"),e&&"mouseleave"===e.type&&t.each(this.parents,function(e,i){t(i.element).attr("title",i.title),delete s.parents[e]}),this.closing=!0,this._trigger("close",e,{tooltip:o}),this.closing=!1)},_tooltip:function(e){var i="ui-tooltip-"+s++,n=t("<div>").attr({id:i,role:"tooltip"}).addClass("ui-tooltip ui-widget ui-corner-all ui-widget-content "+(this.options.tooltipClass||""));return t("<div>").addClass("ui-tooltip-content").appendTo(n),n.appendTo(this.document[0].body),this.tooltips[i]=e,n},_find:function(e){var i=e.data("ui-tooltip-id");return i?t("#"+i):t()},_removeTooltip:function(t){t.remove(),delete this.tooltips[t.attr("id")]},_destroy:function(){var e=this;t.each(this.tooltips,function(i,s){var n=t.Event("blur");n.target=n.currentTarget=s[0],e.close(n,!0),t("#"+i).remove(),s.data("ui-tooltip-title")&&(s.attr("title",s.data("ui-tooltip-title")),s.removeData("ui-tooltip-title"))})}})}(jQuery); \ No newline at end of file diff --git a/lib/scripts/jquery/jquery.js b/lib/scripts/jquery/jquery.js index 67e31603d..e2c203fe9 100644 --- a/lib/scripts/jquery/jquery.js +++ b/lib/scripts/jquery/jquery.js @@ -1,5 +1,5 @@ /*! - * jQuery JavaScript Library v1.9.0 + * jQuery JavaScript Library v1.9.1 * http://jquery.com/ * * Includes Sizzle.js @@ -9,16 +9,25 @@ * Released under the MIT license * http://jquery.org/license * - * Date: 2013-1-14 + * Date: 2013-2-4 */ (function( window, undefined ) { -"use strict"; + +// Can't do this because several apps including ASP.NET trace +// the stack via arguments.caller.callee and Firefox dies if +// you try to trace through "use strict" call chains. (#13335) +// Support: Firefox 18+ +//"use strict"; var + // The deferred used on DOM ready + readyList, + // A central reference to the root jQuery(document) rootjQuery, - // The deferred used on DOM ready - readyList, + // Support: IE<9 + // For `typeof node.method` instead of `node.method !== undefined` + core_strundefined = typeof undefined, // Use the correct document accordingly with window argument (sandbox) document = window.document, @@ -36,7 +45,7 @@ var // List of deleted data cache ids, so we can reuse them core_deletedIds = [], - core_version = "1.9.0", + core_version = "1.9.1", // Save a reference to some core methods core_concat = core_deletedIds.concat, @@ -85,17 +94,25 @@ var return letter.toUpperCase(); }, - // The ready event handler and self cleanup method - DOMContentLoaded = function() { - if ( document.addEventListener ) { - document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false ); - jQuery.ready(); - } else if ( document.readyState === "complete" ) { - // we're here because readyState === "complete" in oldIE - // which is good enough for us to call the dom ready! - document.detachEvent( "onreadystatechange", DOMContentLoaded ); + // The ready event handler + completed = function( event ) { + + // readyState === "complete" is good enough for us to call the dom ready in oldIE + if ( document.addEventListener || event.type === "load" || document.readyState === "complete" ) { + detach(); jQuery.ready(); } + }, + // Clean-up method for dom ready events + detach = function() { + if ( document.addEventListener ) { + document.removeEventListener( "DOMContentLoaded", completed, false ); + window.removeEventListener( "load", completed, false ); + + } else { + document.detachEvent( "onreadystatechange", completed ); + window.detachEvent( "onload", completed ); + } }; jQuery.fn = jQuery.prototype = { @@ -299,7 +316,7 @@ jQuery.fn = jQuery.prototype = { jQuery.fn.init.prototype = jQuery.fn; jQuery.extend = jQuery.fn.extend = function() { - var options, name, src, copy, copyIsArray, clone, + var src, copyIsArray, copy, name, options, clone, target = arguments[0] || {}, i = 1, length = arguments.length, @@ -781,7 +798,7 @@ jQuery.extend({ // Bind a function to a context, optionally partially applying any // arguments. proxy: function( fn, context ) { - var tmp, args, proxy; + var args, proxy, tmp; if ( typeof context === "string" ) { tmp = fn[ context ]; @@ -880,18 +897,18 @@ jQuery.ready.promise = function( obj ) { // Standards-based browsers support DOMContentLoaded } else if ( document.addEventListener ) { // Use the handy event callback - document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false ); + document.addEventListener( "DOMContentLoaded", completed, false ); // A fallback to window.onload, that will always work - window.addEventListener( "load", jQuery.ready, false ); + window.addEventListener( "load", completed, false ); // If IE event model is used } else { // Ensure firing before onload, maybe late but safe also for iframes - document.attachEvent( "onreadystatechange", DOMContentLoaded ); + document.attachEvent( "onreadystatechange", completed ); // A fallback to window.onload, that will always work - window.attachEvent( "onload", jQuery.ready ); + window.attachEvent( "onload", completed ); // If IE and not a frame // continually check to see if the document is ready @@ -913,6 +930,9 @@ jQuery.ready.promise = function( obj ) { return setTimeout( doScrollCheck, 50 ); } + // detach all dom ready events + detach(); + // and execute any waiting functions jQuery.ready(); } @@ -989,18 +1009,18 @@ jQuery.Callbacks = function( options ) { ( optionsCache[ options ] || createOptions( options ) ) : jQuery.extend( {}, options ); - var // Last fire value (for non-forgettable lists) + var // Flag to know if list is currently firing + firing, + // Last fire value (for non-forgettable lists) memory, // Flag to know if list was already fired fired, - // Flag to know if list is currently firing - firing, - // First callback to fire (used internally by add and fireWith) - firingStart, // End of the loop when firing firingLength, // Index of currently firing callback (modified by remove if needed) firingIndex, + // First callback to fire (used internally by add and fireWith) + firingStart, // Actual callback list list = [], // Stack of fire calls for repeatable lists @@ -1086,9 +1106,10 @@ jQuery.Callbacks = function( options ) { } return this; }, - // Control if a given callback is in the list + // Check if a given callback is in the list. + // If no argument is given, return whether or not list has callbacks attached. has: function( fn ) { - return jQuery.inArray( fn, list ) > -1; + return fn ? jQuery.inArray( fn, list ) > -1 : !!( list && list.length ); }, // Remove all callbacks from the list empty: function() { @@ -1285,7 +1306,9 @@ jQuery.extend({ }); jQuery.support = (function() { - var support, all, a, select, opt, input, fragment, eventName, isSupported, i, + var support, all, a, + input, select, fragment, + opt, eventName, isSupported, i, div = document.createElement("div"); // Setup @@ -1486,7 +1509,7 @@ jQuery.support = (function() { !parseFloat( ( window.getComputedStyle( marginDiv, null ) || {} ).marginRight ); } - if ( typeof div.style.zoom !== "undefined" ) { + if ( typeof div.style.zoom !== core_strundefined ) { // Support: IE<8 // Check if natively block-level elements act like inline-block // elements when setting their display to 'inline' and giving @@ -1502,9 +1525,12 @@ jQuery.support = (function() { div.firstChild.style.width = "5px"; support.shrinkWrapBlocks = ( div.offsetWidth !== 3 ); - // Prevent IE 6 from affecting layout for positioned elements #11048 - // Prevent IE from shrinking the body in IE 7 mode #12869 - body.style.zoom = 1; + if ( support.inlineBlockNeedsLayout ) { + // Prevent IE 6 from affecting layout for positioned elements #11048 + // Prevent IE from shrinking the body in IE 7 mode #12869 + // Support: IE<8 + body.style.zoom = 1; + } } body.removeChild( container ); @@ -1521,7 +1547,7 @@ jQuery.support = (function() { var rbrace = /(?:\{[\s\S]*\}|\[[\s\S]*\])$/, rmultiDash = /([A-Z])/g; - + function internalData( elem, name, data, pvt /* Internal Use Only */ ){ if ( !jQuery.acceptData( elem ) ) { return; @@ -1616,13 +1642,12 @@ function internalData( elem, name, data, pvt /* Internal Use Only */ ){ return ret; } -function internalRemoveData( elem, name, pvt /* For internal use only */ ){ +function internalRemoveData( elem, name, pvt ) { if ( !jQuery.acceptData( elem ) ) { return; } - var thisCache, i, l, - + var i, l, thisCache, isNode = elem.nodeType, // See jQuery.data for more information @@ -1726,24 +1751,29 @@ jQuery.extend({ }, data: function( elem, name, data ) { - return internalData( elem, name, data, false ); + return internalData( elem, name, data ); }, removeData: function( elem, name ) { - return internalRemoveData( elem, name, false ); + return internalRemoveData( elem, name ); }, // For internal use only. _data: function( elem, name, data ) { return internalData( elem, name, data, true ); }, - + _removeData: function( elem, name ) { return internalRemoveData( elem, name, true ); }, // A method for determining if a DOM node can handle the data expando acceptData: function( elem ) { + // Do not set data on non-element because it will not be cleared (#8335). + if ( elem.nodeType && elem.nodeType !== 1 && elem.nodeType !== 9 ) { + return false; + } + var noData = elem.nodeName && jQuery.noData[ elem.nodeName.toLowerCase() ]; // nodes accept data unless otherwise specified; rejection can be conditional @@ -1769,7 +1799,7 @@ jQuery.fn.extend({ name = attrs[i].name; if ( !name.indexOf( "data-" ) ) { - name = jQuery.camelCase( name.substring(5) ); + name = jQuery.camelCase( name.slice(5) ); dataAttr( elem, name, data[ name ] ); } @@ -1820,12 +1850,12 @@ function dataAttr( elem, key, data ) { if ( typeof data === "string" ) { try { data = data === "true" ? true : - data === "false" ? false : - data === "null" ? null : - // Only convert to a number if it doesn't change the string - +data + "" === data ? +data : - rbrace.test( data ) ? jQuery.parseJSON( data ) : - data; + data === "false" ? false : + data === "null" ? null : + // Only convert to a number if it doesn't change the string + +data + "" === data ? +data : + rbrace.test( data ) ? jQuery.parseJSON( data ) : + data; } catch( e ) {} // Make sure we set the data so it isn't changed later @@ -2141,7 +2171,7 @@ jQuery.fn.extend({ } // Toggle whole class name - } else if ( type === "undefined" || type === "boolean" ) { + } else if ( type === core_strundefined || type === "boolean" ) { if ( this.className ) { // store className if set jQuery._data( this, "__className__", this.className ); @@ -2170,7 +2200,7 @@ jQuery.fn.extend({ }, val: function( value ) { - var hooks, ret, isFunction, + var ret, hooks, isFunction, elem = this[0]; if ( !arguments.length ) { @@ -2294,7 +2324,7 @@ jQuery.extend({ }, attr: function( elem, name, value ) { - var ret, hooks, notxml, + var hooks, notxml, ret, nType = elem.nodeType; // don't get/set attributes on text, comment and attribute nodes @@ -2303,7 +2333,7 @@ jQuery.extend({ } // Fallback to prop when attributes are not supported - if ( typeof elem.getAttribute === "undefined" ) { + if ( typeof elem.getAttribute === core_strundefined ) { return jQuery.prop( elem, name, value ); } @@ -2336,7 +2366,7 @@ jQuery.extend({ // In IE9+, Flash objects don't have .getAttribute (#12945) // Support: IE9+ - if ( typeof elem.getAttribute !== "undefined" ) { + if ( typeof elem.getAttribute !== core_strundefined ) { ret = elem.getAttribute( name ); } @@ -2686,13 +2716,12 @@ jQuery.event = { global: {}, add: function( elem, types, handler, data, selector ) { + var tmp, events, t, handleObjIn, + special, eventHandle, handleObj, + handlers, type, namespaces, origType, + elemData = jQuery._data( elem ); - var handleObjIn, eventHandle, tmp, - events, t, handleObj, - special, handlers, type, namespaces, origType, - // Don't attach events to noData or text/comment nodes (but allow plain objects) - elemData = elem.nodeType !== 3 && elem.nodeType !== 8 && jQuery._data( elem ); - + // Don't attach events to noData or text/comment nodes (but allow plain objects) if ( !elemData ) { return; } @@ -2717,7 +2746,7 @@ jQuery.event = { eventHandle = elemData.handle = function( e ) { // Discard the second event of a jQuery.event.trigger() and // when an event is called after a page has unloaded - return typeof jQuery !== "undefined" && (!e || jQuery.event.triggered !== e.type) ? + return typeof jQuery !== core_strundefined && (!e || jQuery.event.triggered !== e.type) ? jQuery.event.dispatch.apply( eventHandle.elem, arguments ) : undefined; }; @@ -2797,10 +2826,10 @@ jQuery.event = { // Detach an event or set of events from an element remove: function( elem, types, handler, selector, mappedTypes ) { - - var j, origCount, tmp, - events, t, handleObj, - special, handlers, type, namespaces, origType, + var j, handleObj, tmp, + origCount, t, events, + special, handlers, type, + namespaces, origType, elemData = jQuery.hasData( elem ) && jQuery._data( elem ); if ( !elemData || !(events = elemData.events) ) { @@ -2870,11 +2899,11 @@ jQuery.event = { }, trigger: function( event, data, elem, onlyHandlers ) { - - var i, cur, tmp, bubbleType, ontype, handle, special, + var handle, ontype, cur, + bubbleType, special, tmp, i, eventPath = [ elem || document ], - type = event.type || event, - namespaces = event.namespace ? event.namespace.split(".") : []; + type = core_hasOwn.call( event, "type" ) ? event.type : event, + namespaces = core_hasOwn.call( event, "namespace" ) ? event.namespace.split(".") : []; cur = tmp = elem = elem || document; @@ -3008,7 +3037,7 @@ jQuery.event = { // Make a writable jQuery.Event from the native event object event = jQuery.event.fix( event ); - var i, j, ret, matched, handleObj, + var i, ret, handleObj, matched, j, handlerQueue = [], args = core_slice.call( arguments ), handlers = ( jQuery._data( this, "events" ) || {} )[ event.type ] || [], @@ -3063,7 +3092,7 @@ jQuery.event = { }, handlers: function( event, handlers ) { - var i, matches, sel, handleObj, + var sel, handleObj, matches, i, handlerQueue = [], delegateCount = handlers.delegateCount, cur = event.target; @@ -3075,8 +3104,9 @@ jQuery.event = { for ( ; cur != this; cur = cur.parentNode || this ) { + // Don't check non-elements (#13208) // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764) - if ( cur.disabled !== true || event.type !== "click" ) { + if ( cur.nodeType === 1 && (cur.disabled !== true || event.type !== "click") ) { matches = []; for ( i = 0; i < delegateCount; i++ ) { handleObj = handlers[ i ]; @@ -3114,10 +3144,18 @@ jQuery.event = { } // Create a writable copy of the event object and normalize some properties - var i, prop, + var i, prop, copy, + type = event.type, originalEvent = event, - fixHook = jQuery.event.fixHooks[ event.type ] || {}, - copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props; + fixHook = this.fixHooks[ type ]; + + if ( !fixHook ) { + this.fixHooks[ type ] = fixHook = + rmouseEvent.test( type ) ? this.mouseHooks : + rkeyEvent.test( type ) ? this.keyHooks : + {}; + } + copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props; event = new jQuery.Event( originalEvent ); @@ -3167,7 +3205,7 @@ jQuery.event = { mouseHooks: { props: "button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "), filter: function( event, original ) { - var eventDoc, doc, body, + var body, eventDoc, doc, button = original.button, fromElement = original.fromElement; @@ -3283,7 +3321,7 @@ jQuery.removeEvent = document.removeEventListener ? // #8545, #7054, preventing memory leaks for custom events in IE6-8 // detachEvent needed property on element, by name of that event, to properly expose it to GC - if ( typeof elem[ name ] === "undefined" ) { + if ( typeof elem[ name ] === core_strundefined ) { elem[ name ] = null; } @@ -3532,7 +3570,7 @@ if ( !jQuery.support.focusinBubbles ) { jQuery.fn.extend({ on: function( types, selector, data, fn, /*INTERNAL*/ one ) { - var origFn, type; + var type, origFn; // Types can be a map of types/handlers if ( typeof types === "object" ) { @@ -3644,30 +3682,6 @@ jQuery.fn.extend({ if ( elem ) { return jQuery.event.trigger( type, data, elem, true ); } - }, - - hover: function( fnOver, fnOut ) { - return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver ); - } -}); - -jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " + - "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " + - "change select submit keydown keypress keyup error contextmenu").split(" "), function( i, name ) { - - // Handle event binding - jQuery.fn[ name ] = function( data, fn ) { - return arguments.length > 0 ? - this.on( name, null, data, fn ) : - this.trigger( name ); - }; - - if ( rkeyEvent.test( name ) ) { - jQuery.event.fixHooks[ name ] = jQuery.event.keyHooks; - } - - if ( rmouseEvent.test( name ) ) { - jQuery.event.fixHooks[ name ] = jQuery.event.mouseHooks; } }); /*! @@ -3781,7 +3795,7 @@ var i, rsibling = /[\x20\t\r\n\f]*[+~]/, - rnative = /\{\s*\[native code\]\s*\}/, + rnative = /^[^{]+\{\s*\[native code/, // Easily-parseable/retrievable ID or TAG or CLASS selectors rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, @@ -3808,12 +3822,12 @@ var i, // Use a stripped-down slice if we can't use a native one try { - slice.call( docElem.childNodes, 0 )[0].nodeType; + slice.call( preferredDoc.documentElement.childNodes, 0 )[0].nodeType; } catch ( e ) { slice = function( i ) { var elem, results = []; - for ( ; (elem = this[i]); i++ ) { + while ( (elem = this[i++]) ) { results.push( elem ); } return results; @@ -4132,7 +4146,7 @@ setDocument = Sizzle.setDocument = function( node ) { // Filter out possible comments if ( tag === "*" ) { - for ( ; (elem = results[i]); i++ ) { + while ( (elem = results[i++]) ) { if ( elem.nodeType === 1 ) { tmp.push( elem ); } @@ -4290,15 +4304,11 @@ setDocument = Sizzle.setDocument = function( node ) { ap = [ a ], bp = [ b ]; - // The nodes are identical, we can exit early + // Exit early if the nodes are identical if ( a === b ) { hasDuplicate = true; return 0; - // Fallback to using sourceIndex (in IE) if it's available on both nodes - } else if ( a.sourceIndex && b.sourceIndex ) { - return ( ~b.sourceIndex || MAX_NEGATIVE ) - ( contains( preferredDoc, a ) && ~a.sourceIndex || MAX_NEGATIVE ); - // Parentless nodes are either documents or disconnected } else if ( !aup || !bup ) { return a === doc ? -1 : @@ -4437,11 +4447,20 @@ Sizzle.uniqueSort = function( results ) { }; function siblingCheck( a, b ) { - var cur = a && b && a.nextSibling; + var cur = b && a, + diff = cur && ( ~b.sourceIndex || MAX_NEGATIVE ) - ( ~a.sourceIndex || MAX_NEGATIVE ); - for ( ; cur; cur = cur.nextSibling ) { - if ( cur === b ) { - return -1; + // Use IE sourceIndex if available on both nodes + if ( diff ) { + return diff; + } + + // Check if b follows a + if ( cur ) { + while ( (cur = cur.nextSibling) ) { + if ( cur === b ) { + return -1; + } } } @@ -4651,9 +4670,9 @@ Expr = Sizzle.selectors = { operator === "!=" ? result !== check : operator === "^=" ? check && result.indexOf( check ) === 0 : operator === "*=" ? check && result.indexOf( check ) > -1 : - operator === "$=" ? check && result.substr( result.length - check.length ) === check : + operator === "$=" ? check && result.slice( -check.length ) === check : operator === "~=" ? ( " " + result + " " ).indexOf( check ) > -1 : - operator === "|=" ? result === check || result.substr( 0, check.length + 1 ) === check + "-" : + operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" : false; }; }, @@ -5071,7 +5090,7 @@ function toSelector( tokens ) { function addCombinator( matcher, combinator, base ) { var dir = combinator.dir, - checkNonElements = base && combinator.dir === "parentNode", + checkNonElements = base && dir === "parentNode", doneName = done++; return combinator.first ? @@ -5314,8 +5333,8 @@ function matcherFromGroupMatchers( elementMatchers, setMatchers ) { contextBackup = outermostContext, // We must always have either seed elements or context elems = seed || byElement && Expr.find["TAG"]( "*", expandContext && context.parentNode || context ), - // Nested matchers should use non-integer dirruns - dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.E); + // Use integer dirruns iff this is the outermost matcher + dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1); if ( outermost ) { outermostContext = context !== document && context; @@ -5323,9 +5342,11 @@ function matcherFromGroupMatchers( elementMatchers, setMatchers ) { } // Add elements passing elementMatchers directly to results + // Keep `i` a string if there are no elements so `matchedCount` will be "00" below for ( ; (elem = elems[i]) != null; i++ ) { if ( byElement && elem ) { - for ( j = 0; (matcher = elementMatchers[j]); j++ ) { + j = 0; + while ( (matcher = elementMatchers[j++]) ) { if ( matcher( elem, context, xml ) ) { results.push( elem ); break; @@ -5352,10 +5373,10 @@ function matcherFromGroupMatchers( elementMatchers, setMatchers ) { } // Apply set filters to unmatched elements - // `i` starts as a string, so matchedCount would equal "00" if there are no elements matchedCount += i; if ( bySet && i !== matchedCount ) { - for ( j = 0; (matcher = setMatchers[j]); j++ ) { + j = 0; + while ( (matcher = setMatchers[j++]) ) { matcher( unmatched, setMatched, context, xml ); } @@ -5457,7 +5478,8 @@ function select( selector, context, results, seed ) { } // Fetch a seed set for right-to-left matching - for ( i = matchExpr["needsContext"].test( selector ) ? -1 : tokens.length - 1; i >= 0; i-- ) { + i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length; + while ( i-- ) { token = tokens[i]; // Abort if we hit a combinator @@ -5535,12 +5557,13 @@ var runtil = /Until$/, jQuery.fn.extend({ find: function( selector ) { - var i, ret, self; + var i, ret, self, + len = this.length; if ( typeof selector !== "string" ) { self = this; return this.pushStack( jQuery( selector ).filter(function() { - for ( i = 0; i < self.length; i++ ) { + for ( i = 0; i < len; i++ ) { if ( jQuery.contains( self[ i ], this ) ) { return true; } @@ -5549,12 +5572,12 @@ jQuery.fn.extend({ } ret = []; - for ( i = 0; i < this.length; i++ ) { + for ( i = 0; i < len; i++ ) { jQuery.find( selector, this[ i ], ret ); } // Needed because $( selector, context ) becomes $( context ).find( selector ) - ret = this.pushStack( jQuery.unique( ret ) ); + ret = this.pushStack( len > 1 ? jQuery.unique( ret ) : ret ); ret.selector = ( this.selector ? this.selector + " " : "" ) + selector; return ret; }, @@ -6066,15 +6089,9 @@ jQuery.fn.extend({ var next = this.nextSibling, parent = this.parentNode; - if ( parent && this.nodeType === 1 || this.nodeType === 11 ) { - + if ( parent ) { jQuery( this ).remove(); - - if ( next ) { - next.parentNode.insertBefore( elem, next ); - } else { - parent.appendChild( elem ); - } + parent.insertBefore( elem, next ); } }); }, @@ -6088,7 +6105,8 @@ jQuery.fn.extend({ // Flatten any nested arrays args = core_concat.apply( [], args ); - var fragment, first, scripts, hasScripts, node, doc, + var first, node, hasScripts, + scripts, doc, fragment, i = 0, l = this.length, set = this, @@ -6239,7 +6257,7 @@ function cloneCopyEvent( src, dest ) { } function fixCloneNodeIssues( src, dest ) { - var nodeName, data, e; + var nodeName, e, data; // We do not need to do anything for non-Elements if ( dest.nodeType !== 1 ) { @@ -6334,8 +6352,8 @@ jQuery.each({ function getAll( context, tag ) { var elems, elem, i = 0, - found = typeof context.getElementsByTagName !== "undefined" ? context.getElementsByTagName( tag || "*" ) : - typeof context.querySelectorAll !== "undefined" ? context.querySelectorAll( tag || "*" ) : + found = typeof context.getElementsByTagName !== core_strundefined ? context.getElementsByTagName( tag || "*" ) : + typeof context.querySelectorAll !== core_strundefined ? context.querySelectorAll( tag || "*" ) : undefined; if ( !found ) { @@ -6362,7 +6380,7 @@ function fixDefaultChecked( elem ) { jQuery.extend({ clone: function( elem, dataAndEvents, deepDataAndEvents ) { - var destElements, srcElements, node, i, clone, + var destElements, node, clone, i, srcElements, inPage = jQuery.contains( elem.ownerDocument, elem ); if ( jQuery.support.html5Clone || jQuery.isXMLDoc(elem) || !rnoshimcache.test( "<" + elem.nodeName + ">" ) ) { @@ -6417,7 +6435,8 @@ jQuery.extend({ }, buildFragment: function( elems, context, scripts, selection ) { - var contains, elem, tag, tmp, wrap, tbody, j, + var j, elem, contains, + tmp, tag, tbody, wrap, l = elems.length, // Ensure a safe fragment @@ -6543,7 +6562,7 @@ jQuery.extend({ }, cleanData: function( elems, /* internal */ acceptData ) { - var data, id, elem, type, + var elem, type, id, data, i = 0, internalKey = jQuery.expando, cache = jQuery.cache, @@ -6581,7 +6600,7 @@ jQuery.extend({ if ( deleteExpando ) { delete elem[ internalKey ]; - } else if ( typeof elem.removeAttribute !== "undefined" ) { + } else if ( typeof elem.removeAttribute !== core_strundefined ) { elem.removeAttribute( internalKey ); } else { @@ -6595,7 +6614,7 @@ jQuery.extend({ } } }); -var curCSS, getStyles, iframe, +var iframe, getStyles, curCSS, ralpha = /alpha\([^)]*\)/i, ropacity = /opacity\s*=\s*([^)]*)/, rposition = /^(top|right|bottom|left)$/, @@ -6648,7 +6667,7 @@ function isHidden( elem, el ) { } function showHide( elements, show ) { - var elem, + var display, elem, hidden, values = [], index = 0, length = elements.length; @@ -6658,11 +6677,13 @@ function showHide( elements, show ) { if ( !elem.style ) { continue; } + values[ index ] = jQuery._data( elem, "olddisplay" ); + display = elem.style.display; if ( show ) { // Reset the inline display of this element to learn if it is // being hidden by cascaded rules or not - if ( !values[ index ] && elem.style.display === "none" ) { + if ( !values[ index ] && display === "none" ) { elem.style.display = ""; } @@ -6672,8 +6693,15 @@ function showHide( elements, show ) { if ( elem.style.display === "" && isHidden( elem ) ) { values[ index ] = jQuery._data( elem, "olddisplay", css_defaultDisplay(elem.nodeName) ); } - } else if ( !values[ index ] && !isHidden( elem ) ) { - jQuery._data( elem, "olddisplay", jQuery.css( elem, "display" ) ); + } else { + + if ( !values[ index ] ) { + hidden = isHidden( elem ); + + if ( display && display !== "none" || !hidden ) { + jQuery._data( elem, "olddisplay", hidden ? display : jQuery.css( elem, "display" ) ); + } + } } } @@ -6695,7 +6723,7 @@ function showHide( elements, show ) { jQuery.fn.extend({ css: function( name, value ) { return jQuery.access( this, function( elem, name, value ) { - var styles, len, + var len, styles, map = {}, i = 0; @@ -6836,7 +6864,7 @@ jQuery.extend({ }, css: function( elem, name, extra, styles ) { - var val, num, hooks, + var num, val, hooks, origName = jQuery.camelCase( name ); // Make sure that we're working with the right name @@ -6862,7 +6890,7 @@ jQuery.extend({ } // Return, converting to number if forced or a qualifier was provided and val looks numeric - if ( extra ) { + if ( extra === "" || extra ) { num = parseFloat( val ); return extra === true || jQuery.isNumeric( num ) ? num || 0 : val; } @@ -7227,7 +7255,10 @@ jQuery(function() { if ( jQuery.expr && jQuery.expr.filters ) { jQuery.expr.filters.hidden = function( elem ) { - return ( elem.offsetWidth === 0 && elem.offsetHeight === 0 ) || (!jQuery.support.reliableHiddenOffsets && ((elem.style && elem.style.display) || jQuery.css( elem, "display" )) === "none"); + // Support: Opera <= 12.12 + // Opera reports offsetWidths and offsetHeights less than zero on some elements + return elem.offsetWidth <= 0 && elem.offsetHeight <= 0 || + (!jQuery.support.reliableHiddenOffsets && ((elem.style && elem.style.display) || jQuery.css( elem, "display" )) === "none"); }; jQuery.expr.filters.visible = function( elem ) { @@ -7265,7 +7296,7 @@ jQuery.each({ var r20 = /%20/g, rbracket = /\[\]$/, rCRLF = /\r?\n/g, - rsubmitterTypes = /^(?:submit|button|image|reset)$/i, + rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i, rsubmittable = /^(?:input|select|textarea|keygen)/i; jQuery.fn.extend({ @@ -7361,11 +7392,25 @@ function buildParams( prefix, obj, traditional, add ) { add( prefix, obj ); } } +jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " + + "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " + + "change select submit keydown keypress keyup error contextmenu").split(" "), function( i, name ) { + + // Handle event binding + jQuery.fn[ name ] = function( data, fn ) { + return arguments.length > 0 ? + this.on( name, null, data, fn ) : + this.trigger( name ); + }; +}); + +jQuery.fn.hover = function( fnOver, fnOut ) { + return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver ); +}; var // Document location ajaxLocParts, ajaxLocation, - ajax_nonce = jQuery.now(), ajax_rquery = /\?/, @@ -7478,7 +7523,7 @@ function inspectPrefiltersOrTransports( structure, options, originalOptions, jqX // that takes "flat" options (not to be deep extended) // Fixes #9887 function ajaxExtend( target, src ) { - var key, deep, + var deep, key, flatOptions = jQuery.ajaxSettings.flatOptions || {}; for ( key in src ) { @@ -7498,7 +7543,7 @@ jQuery.fn.load = function( url, params, callback ) { return _load.apply( this, arguments ); } - var selector, type, response, + var selector, response, type, self = this, off = url.indexOf(" "); @@ -7679,20 +7724,23 @@ jQuery.extend({ // Force options to be an object options = options || {}; - var transport, + var // Cross-domain detection vars + parts, + // Loop variable + i, // URL without anti-cache param cacheURL, - // Response headers + // Response headers as string responseHeadersString, - responseHeaders, // timeout handle timeoutTimer, - // Cross-domain detection vars - parts, + // To know if global events are to be dispatched fireGlobals, - // Loop variable - i, + + transport, + // Response headers + responseHeaders, // Create the final options object s = jQuery.ajaxSetup( {}, options ), // Callbacks context @@ -7987,12 +8035,17 @@ jQuery.extend({ } } - // If not modified - if ( status === 304 ) { + // if no content + if ( status === 204 ) { + isSuccess = true; + statusText = "nocontent"; + + // if not modified + } else if ( status === 304 ) { isSuccess = true; statusText = "notmodified"; - // If we have data + // If we have data, let's convert it } else { isSuccess = ajaxConvert( s, response ); statusText = isSuccess.state; @@ -8062,8 +8115,7 @@ jQuery.extend({ * - returns the corresponding response */ function ajaxHandleResponses( s, jqXHR, responses ) { - - var ct, type, finalDataType, firstDataType, + var firstDataType, ct, finalDataType, type, contents = s.contents, dataTypes = s.dataTypes, responseFields = s.responseFields; @@ -8124,8 +8176,7 @@ function ajaxHandleResponses( s, jqXHR, responses ) { // Chain conversions given the request and the original response function ajaxConvert( s, response ) { - - var conv, conv2, current, tmp, + var conv2, current, conv, tmp, converters = {}, i = 0, // Work with a copy of dataTypes in case we need to modify it for conversion @@ -8476,12 +8527,7 @@ if ( xhrSupported ) { // Listener callback = function( _, isAbort ) { - - var status, - statusText, - responseHeaders, - responses, - xml; + var status, responseHeaders, statusText, responses; // Firefox throws exceptions when accessing properties // of an xhr when a network error occurred @@ -8511,14 +8557,8 @@ if ( xhrSupported ) { } else { responses = {}; status = xhr.status; - xml = xhr.responseXML; responseHeaders = xhr.getAllResponseHeaders(); - // Construct response list - if ( xml && xml.documentElement /* #4958 */ ) { - responses.xml = xml; - } - // When requesting binary data, IE6-9 will throw an exception // on any attempt to access responseText (#11426) if ( typeof xhr.responseText === "string" ) { @@ -8768,7 +8808,7 @@ function Animation( elem, properties, options ) { } function propFilter( props, specialEasing ) { - var index, name, easing, value, hooks; + var value, name, index, easing, hooks; // camelCase, specialEasing and expand cssHook pass for ( index in props ) { @@ -8836,7 +8876,9 @@ jQuery.Animation = jQuery.extend( Animation, { function defaultPrefilter( elem, props, opts ) { /*jshint validthis:true */ - var index, prop, value, length, dataShow, toggle, tween, hooks, oldfire, + var prop, index, length, + value, dataShow, toggle, + tween, hooks, oldfire, anim = this, style = elem.style, orig = {}, @@ -8896,7 +8938,7 @@ function defaultPrefilter( elem, props, opts ) { if ( opts.overflow ) { style.overflow = "hidden"; if ( !jQuery.support.shrinkWrapBlocks ) { - anim.done(function() { + anim.always(function() { style.overflow = opts.overflow[ 0 ]; style.overflowX = opts.overflow[ 1 ]; style.overflowY = opts.overflow[ 2 ]; @@ -9020,11 +9062,11 @@ Tween.propHooks = { return tween.elem[ tween.prop ]; } - // passing a non empty string as a 3rd parameter to .css will automatically + // passing an empty string as a 3rd parameter to .css will automatically // attempt a parseFloat and fallback to a string if the parse fails // so, simple values such as "10px" are parsed to Float. // complex values such as "rotate(1rad)" are returned as is. - result = jQuery.css( tween.elem, tween.prop, "auto" ); + result = jQuery.css( tween.elem, tween.prop, "" ); // Empty strings, null, undefined and "auto" are converted to 0. return !result || result === "auto" ? 0 : result; }, @@ -9346,7 +9388,7 @@ jQuery.fn.offset = function( options ) { // If we don't have gBCR, just use 0,0 rather than error // BlackBerry 5, iOS 3 (original iPhone) - if ( typeof elem.getBoundingClientRect !== "undefined" ) { + if ( typeof elem.getBoundingClientRect !== core_strundefined ) { box = elem.getBoundingClientRect(); } win = getWindow( doc ); diff --git a/lib/scripts/jquery/jquery.min.js b/lib/scripts/jquery/jquery.min.js index 50d1b22f2..006e95310 100644 --- a/lib/scripts/jquery/jquery.min.js +++ b/lib/scripts/jquery/jquery.min.js @@ -1,4 +1,5 @@ -/*! jQuery v1.9.0 | (c) 2005, 2012 jQuery Foundation, Inc. | jquery.org/license */(function(e,t){"use strict";function n(e){var t=e.length,n=st.type(e);return st.isWindow(e)?!1:1===e.nodeType&&t?!0:"array"===n||"function"!==n&&(0===t||"number"==typeof t&&t>0&&t-1 in e)}function r(e){var t=Tt[e]={};return st.each(e.match(lt)||[],function(e,n){t[n]=!0}),t}function i(e,n,r,i){if(st.acceptData(e)){var o,a,s=st.expando,u="string"==typeof n,l=e.nodeType,c=l?st.cache:e,f=l?e[s]:e[s]&&s;if(f&&c[f]&&(i||c[f].data)||!u||r!==t)return f||(l?e[s]=f=K.pop()||st.guid++:f=s),c[f]||(c[f]={},l||(c[f].toJSON=st.noop)),("object"==typeof n||"function"==typeof n)&&(i?c[f]=st.extend(c[f],n):c[f].data=st.extend(c[f].data,n)),o=c[f],i||(o.data||(o.data={}),o=o.data),r!==t&&(o[st.camelCase(n)]=r),u?(a=o[n],null==a&&(a=o[st.camelCase(n)])):a=o,a}}function o(e,t,n){if(st.acceptData(e)){var r,i,o,a=e.nodeType,u=a?st.cache:e,l=a?e[st.expando]:st.expando;if(u[l]){if(t&&(r=n?u[l]:u[l].data)){st.isArray(t)?t=t.concat(st.map(t,st.camelCase)):t in r?t=[t]:(t=st.camelCase(t),t=t in r?[t]:t.split(" "));for(i=0,o=t.length;o>i;i++)delete r[t[i]];if(!(n?s:st.isEmptyObject)(r))return}(n||(delete u[l].data,s(u[l])))&&(a?st.cleanData([e],!0):st.support.deleteExpando||u!=u.window?delete u[l]:u[l]=null)}}}function a(e,n,r){if(r===t&&1===e.nodeType){var i="data-"+n.replace(Nt,"-$1").toLowerCase();if(r=e.getAttribute(i),"string"==typeof r){try{r="true"===r?!0:"false"===r?!1:"null"===r?null:+r+""===r?+r:wt.test(r)?st.parseJSON(r):r}catch(o){}st.data(e,n,r)}else r=t}return r}function s(e){var t;for(t in e)if(("data"!==t||!st.isEmptyObject(e[t]))&&"toJSON"!==t)return!1;return!0}function u(){return!0}function l(){return!1}function c(e,t){do e=e[t];while(e&&1!==e.nodeType);return e}function f(e,t,n){if(t=t||0,st.isFunction(t))return st.grep(e,function(e,r){var i=!!t.call(e,r,e);return i===n});if(t.nodeType)return st.grep(e,function(e){return e===t===n});if("string"==typeof t){var r=st.grep(e,function(e){return 1===e.nodeType});if(Wt.test(t))return st.filter(t,r,!n);t=st.filter(t,r)}return st.grep(e,function(e){return st.inArray(e,t)>=0===n})}function p(e){var t=zt.split("|"),n=e.createDocumentFragment();if(n.createElement)for(;t.length;)n.createElement(t.pop());return n}function d(e,t){return e.getElementsByTagName(t)[0]||e.appendChild(e.ownerDocument.createElement(t))}function h(e){var t=e.getAttributeNode("type");return e.type=(t&&t.specified)+"/"+e.type,e}function g(e){var t=nn.exec(e.type);return t?e.type=t[1]:e.removeAttribute("type"),e}function m(e,t){for(var n,r=0;null!=(n=e[r]);r++)st._data(n,"globalEval",!t||st._data(t[r],"globalEval"))}function y(e,t){if(1===t.nodeType&&st.hasData(e)){var n,r,i,o=st._data(e),a=st._data(t,o),s=o.events;if(s){delete a.handle,a.events={};for(n in s)for(r=0,i=s[n].length;i>r;r++)st.event.add(t,n,s[n][r])}a.data&&(a.data=st.extend({},a.data))}}function v(e,t){var n,r,i;if(1===t.nodeType){if(n=t.nodeName.toLowerCase(),!st.support.noCloneEvent&&t[st.expando]){r=st._data(t);for(i in r.events)st.removeEvent(t,i,r.handle);t.removeAttribute(st.expando)}"script"===n&&t.text!==e.text?(h(t).text=e.text,g(t)):"object"===n?(t.parentNode&&(t.outerHTML=e.outerHTML),st.support.html5Clone&&e.innerHTML&&!st.trim(t.innerHTML)&&(t.innerHTML=e.innerHTML)):"input"===n&&Zt.test(e.type)?(t.defaultChecked=t.checked=e.checked,t.value!==e.value&&(t.value=e.value)):"option"===n?t.defaultSelected=t.selected=e.defaultSelected:("input"===n||"textarea"===n)&&(t.defaultValue=e.defaultValue)}}function b(e,n){var r,i,o=0,a=e.getElementsByTagName!==t?e.getElementsByTagName(n||"*"):e.querySelectorAll!==t?e.querySelectorAll(n||"*"):t;if(!a)for(a=[],r=e.childNodes||e;null!=(i=r[o]);o++)!n||st.nodeName(i,n)?a.push(i):st.merge(a,b(i,n));return n===t||n&&st.nodeName(e,n)?st.merge([e],a):a}function x(e){Zt.test(e.type)&&(e.defaultChecked=e.checked)}function T(e,t){if(t in e)return t;for(var n=t.charAt(0).toUpperCase()+t.slice(1),r=t,i=Nn.length;i--;)if(t=Nn[i]+n,t in e)return t;return r}function w(e,t){return e=t||e,"none"===st.css(e,"display")||!st.contains(e.ownerDocument,e)}function N(e,t){for(var n,r=[],i=0,o=e.length;o>i;i++)n=e[i],n.style&&(r[i]=st._data(n,"olddisplay"),t?(r[i]||"none"!==n.style.display||(n.style.display=""),""===n.style.display&&w(n)&&(r[i]=st._data(n,"olddisplay",S(n.nodeName)))):r[i]||w(n)||st._data(n,"olddisplay",st.css(n,"display")));for(i=0;o>i;i++)n=e[i],n.style&&(t&&"none"!==n.style.display&&""!==n.style.display||(n.style.display=t?r[i]||"":"none"));return e}function C(e,t,n){var r=mn.exec(t);return r?Math.max(0,r[1]-(n||0))+(r[2]||"px"):t}function k(e,t,n,r,i){for(var o=n===(r?"border":"content")?4:"width"===t?1:0,a=0;4>o;o+=2)"margin"===n&&(a+=st.css(e,n+wn[o],!0,i)),r?("content"===n&&(a-=st.css(e,"padding"+wn[o],!0,i)),"margin"!==n&&(a-=st.css(e,"border"+wn[o]+"Width",!0,i))):(a+=st.css(e,"padding"+wn[o],!0,i),"padding"!==n&&(a+=st.css(e,"border"+wn[o]+"Width",!0,i)));return a}function E(e,t,n){var r=!0,i="width"===t?e.offsetWidth:e.offsetHeight,o=ln(e),a=st.support.boxSizing&&"border-box"===st.css(e,"boxSizing",!1,o);if(0>=i||null==i){if(i=un(e,t,o),(0>i||null==i)&&(i=e.style[t]),yn.test(i))return i;r=a&&(st.support.boxSizingReliable||i===e.style[t]),i=parseFloat(i)||0}return i+k(e,t,n||(a?"border":"content"),r,o)+"px"}function S(e){var t=V,n=bn[e];return n||(n=A(e,t),"none"!==n&&n||(cn=(cn||st("<iframe frameborder='0' width='0' height='0'/>").css("cssText","display:block !important")).appendTo(t.documentElement),t=(cn[0].contentWindow||cn[0].contentDocument).document,t.write("<!doctype html><html><body>"),t.close(),n=A(e,t),cn.detach()),bn[e]=n),n}function A(e,t){var n=st(t.createElement(e)).appendTo(t.body),r=st.css(n[0],"display");return n.remove(),r}function j(e,t,n,r){var i;if(st.isArray(t))st.each(t,function(t,i){n||kn.test(e)?r(e,i):j(e+"["+("object"==typeof i?t:"")+"]",i,n,r)});else if(n||"object"!==st.type(t))r(e,t);else for(i in t)j(e+"["+i+"]",t[i],n,r)}function D(e){return function(t,n){"string"!=typeof t&&(n=t,t="*");var r,i=0,o=t.toLowerCase().match(lt)||[];if(st.isFunction(n))for(;r=o[i++];)"+"===r[0]?(r=r.slice(1)||"*",(e[r]=e[r]||[]).unshift(n)):(e[r]=e[r]||[]).push(n)}}function L(e,n,r,i){function o(u){var l;return a[u]=!0,st.each(e[u]||[],function(e,u){var c=u(n,r,i);return"string"!=typeof c||s||a[c]?s?!(l=c):t:(n.dataTypes.unshift(c),o(c),!1)}),l}var a={},s=e===$n;return o(n.dataTypes[0])||!a["*"]&&o("*")}function H(e,n){var r,i,o=st.ajaxSettings.flatOptions||{};for(r in n)n[r]!==t&&((o[r]?e:i||(i={}))[r]=n[r]);return i&&st.extend(!0,e,i),e}function M(e,n,r){var i,o,a,s,u=e.contents,l=e.dataTypes,c=e.responseFields;for(o in c)o in r&&(n[c[o]]=r[o]);for(;"*"===l[0];)l.shift(),i===t&&(i=e.mimeType||n.getResponseHeader("Content-Type"));if(i)for(o in u)if(u[o]&&u[o].test(i)){l.unshift(o);break}if(l[0]in r)a=l[0];else{for(o in r){if(!l[0]||e.converters[o+" "+l[0]]){a=o;break}s||(s=o)}a=a||s}return a?(a!==l[0]&&l.unshift(a),r[a]):t}function q(e,t){var n,r,i,o,a={},s=0,u=e.dataTypes.slice(),l=u[0];if(e.dataFilter&&(t=e.dataFilter(t,e.dataType)),u[1])for(n in e.converters)a[n.toLowerCase()]=e.converters[n];for(;i=u[++s];)if("*"!==i){if("*"!==l&&l!==i){if(n=a[l+" "+i]||a["* "+i],!n)for(r in a)if(o=r.split(" "),o[1]===i&&(n=a[l+" "+o[0]]||a["* "+o[0]])){n===!0?n=a[r]:a[r]!==!0&&(i=o[0],u.splice(s--,0,i));break}if(n!==!0)if(n&&e["throws"])t=n(t);else try{t=n(t)}catch(c){return{state:"parsererror",error:n?c:"No conversion from "+l+" to "+i}}}l=i}return{state:"success",data:t}}function _(){try{return new e.XMLHttpRequest}catch(t){}}function F(){try{return new e.ActiveXObject("Microsoft.XMLHTTP")}catch(t){}}function O(){return setTimeout(function(){Qn=t}),Qn=st.now()}function B(e,t){st.each(t,function(t,n){for(var r=(rr[t]||[]).concat(rr["*"]),i=0,o=r.length;o>i;i++)if(r[i].call(e,t,n))return})}function P(e,t,n){var r,i,o=0,a=nr.length,s=st.Deferred().always(function(){delete u.elem}),u=function(){if(i)return!1;for(var t=Qn||O(),n=Math.max(0,l.startTime+l.duration-t),r=n/l.duration||0,o=1-r,a=0,u=l.tweens.length;u>a;a++)l.tweens[a].run(o);return s.notifyWith(e,[l,o,n]),1>o&&u?n:(s.resolveWith(e,[l]),!1)},l=s.promise({elem:e,props:st.extend({},t),opts:st.extend(!0,{specialEasing:{}},n),originalProperties:t,originalOptions:n,startTime:Qn||O(),duration:n.duration,tweens:[],createTween:function(t,n){var r=st.Tween(e,l.opts,t,n,l.opts.specialEasing[t]||l.opts.easing);return l.tweens.push(r),r},stop:function(t){var n=0,r=t?l.tweens.length:0;if(i)return this;for(i=!0;r>n;n++)l.tweens[n].run(1);return t?s.resolveWith(e,[l,t]):s.rejectWith(e,[l,t]),this}}),c=l.props;for(R(c,l.opts.specialEasing);a>o;o++)if(r=nr[o].call(l,e,c,l.opts))return r;return B(l,c),st.isFunction(l.opts.start)&&l.opts.start.call(e,l),st.fx.timer(st.extend(u,{elem:e,anim:l,queue:l.opts.queue})),l.progress(l.opts.progress).done(l.opts.done,l.opts.complete).fail(l.opts.fail).always(l.opts.always)}function R(e,t){var n,r,i,o,a;for(n in e)if(r=st.camelCase(n),i=t[r],o=e[n],st.isArray(o)&&(i=o[1],o=e[n]=o[0]),n!==r&&(e[r]=o,delete e[n]),a=st.cssHooks[r],a&&"expand"in a){o=a.expand(o),delete e[r];for(n in o)n in e||(e[n]=o[n],t[n]=i)}else t[r]=i}function W(e,t,n){var r,i,o,a,s,u,l,c,f,p=this,d=e.style,h={},g=[],m=e.nodeType&&w(e);n.queue||(c=st._queueHooks(e,"fx"),null==c.unqueued&&(c.unqueued=0,f=c.empty.fire,c.empty.fire=function(){c.unqueued||f()}),c.unqueued++,p.always(function(){p.always(function(){c.unqueued--,st.queue(e,"fx").length||c.empty.fire()})})),1===e.nodeType&&("height"in t||"width"in t)&&(n.overflow=[d.overflow,d.overflowX,d.overflowY],"inline"===st.css(e,"display")&&"none"===st.css(e,"float")&&(st.support.inlineBlockNeedsLayout&&"inline"!==S(e.nodeName)?d.zoom=1:d.display="inline-block")),n.overflow&&(d.overflow="hidden",st.support.shrinkWrapBlocks||p.done(function(){d.overflow=n.overflow[0],d.overflowX=n.overflow[1],d.overflowY=n.overflow[2]}));for(r in t)if(o=t[r],Zn.exec(o)){if(delete t[r],u=u||"toggle"===o,o===(m?"hide":"show"))continue;g.push(r)}if(a=g.length){s=st._data(e,"fxshow")||st._data(e,"fxshow",{}),"hidden"in s&&(m=s.hidden),u&&(s.hidden=!m),m?st(e).show():p.done(function(){st(e).hide()}),p.done(function(){var t;st._removeData(e,"fxshow");for(t in h)st.style(e,t,h[t])});for(r=0;a>r;r++)i=g[r],l=p.createTween(i,m?s[i]:0),h[i]=s[i]||st.style(e,i),i in s||(s[i]=l.start,m&&(l.end=l.start,l.start="width"===i||"height"===i?1:0))}}function $(e,t,n,r,i){return new $.prototype.init(e,t,n,r,i)}function I(e,t){var n,r={height:e},i=0;for(t=t?1:0;4>i;i+=2-t)n=wn[i],r["margin"+n]=r["padding"+n]=e;return t&&(r.opacity=r.width=e),r}function z(e){return st.isWindow(e)?e:9===e.nodeType?e.defaultView||e.parentWindow:!1}var X,U,V=e.document,Y=e.location,J=e.jQuery,G=e.$,Q={},K=[],Z="1.9.0",et=K.concat,tt=K.push,nt=K.slice,rt=K.indexOf,it=Q.toString,ot=Q.hasOwnProperty,at=Z.trim,st=function(e,t){return new st.fn.init(e,t,X)},ut=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,lt=/\S+/g,ct=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,ft=/^(?:(<[\w\W]+>)[^>]*|#([\w-]*))$/,pt=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,dt=/^[\],:{}\s]*$/,ht=/(?:^|:|,)(?:\s*\[)+/g,gt=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,mt=/"[^"\\\r\n]*"|true|false|null|-?(?:\d+\.|)\d+(?:[eE][+-]?\d+|)/g,yt=/^-ms-/,vt=/-([\da-z])/gi,bt=function(e,t){return t.toUpperCase()},xt=function(){V.addEventListener?(V.removeEventListener("DOMContentLoaded",xt,!1),st.ready()):"complete"===V.readyState&&(V.detachEvent("onreadystatechange",xt),st.ready())};st.fn=st.prototype={jquery:Z,constructor:st,init:function(e,n,r){var i,o;if(!e)return this;if("string"==typeof e){if(i="<"===e.charAt(0)&&">"===e.charAt(e.length-1)&&e.length>=3?[null,e,null]:ft.exec(e),!i||!i[1]&&n)return!n||n.jquery?(n||r).find(e):this.constructor(n).find(e);if(i[1]){if(n=n instanceof st?n[0]:n,st.merge(this,st.parseHTML(i[1],n&&n.nodeType?n.ownerDocument||n:V,!0)),pt.test(i[1])&&st.isPlainObject(n))for(i in n)st.isFunction(this[i])?this[i](n[i]):this.attr(i,n[i]);return this}if(o=V.getElementById(i[2]),o&&o.parentNode){if(o.id!==i[2])return r.find(e);this.length=1,this[0]=o}return this.context=V,this.selector=e,this}return e.nodeType?(this.context=this[0]=e,this.length=1,this):st.isFunction(e)?r.ready(e):(e.selector!==t&&(this.selector=e.selector,this.context=e.context),st.makeArray(e,this))},selector:"",length:0,size:function(){return this.length},toArray:function(){return nt.call(this)},get:function(e){return null==e?this.toArray():0>e?this[this.length+e]:this[e]},pushStack:function(e){var t=st.merge(this.constructor(),e);return t.prevObject=this,t.context=this.context,t},each:function(e,t){return st.each(this,e,t)},ready:function(e){return st.ready.promise().done(e),this},slice:function(){return this.pushStack(nt.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(0>e?t:0);return this.pushStack(n>=0&&t>n?[this[n]]:[])},map:function(e){return this.pushStack(st.map(this,function(t,n){return e.call(t,n,t)}))},end:function(){return this.prevObject||this.constructor(null)},push:tt,sort:[].sort,splice:[].splice},st.fn.init.prototype=st.fn,st.extend=st.fn.extend=function(){var e,n,r,i,o,a,s=arguments[0]||{},u=1,l=arguments.length,c=!1;for("boolean"==typeof s&&(c=s,s=arguments[1]||{},u=2),"object"==typeof s||st.isFunction(s)||(s={}),l===u&&(s=this,--u);l>u;u++)if(null!=(e=arguments[u]))for(n in e)r=s[n],i=e[n],s!==i&&(c&&i&&(st.isPlainObject(i)||(o=st.isArray(i)))?(o?(o=!1,a=r&&st.isArray(r)?r:[]):a=r&&st.isPlainObject(r)?r:{},s[n]=st.extend(c,a,i)):i!==t&&(s[n]=i));return s},st.extend({noConflict:function(t){return e.$===st&&(e.$=G),t&&e.jQuery===st&&(e.jQuery=J),st},isReady:!1,readyWait:1,holdReady:function(e){e?st.readyWait++:st.ready(!0)},ready:function(e){if(e===!0?!--st.readyWait:!st.isReady){if(!V.body)return setTimeout(st.ready);st.isReady=!0,e!==!0&&--st.readyWait>0||(U.resolveWith(V,[st]),st.fn.trigger&&st(V).trigger("ready").off("ready"))}},isFunction:function(e){return"function"===st.type(e)},isArray:Array.isArray||function(e){return"array"===st.type(e)},isWindow:function(e){return null!=e&&e==e.window},isNumeric:function(e){return!isNaN(parseFloat(e))&&isFinite(e)},type:function(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?Q[it.call(e)]||"object":typeof e},isPlainObject:function(e){if(!e||"object"!==st.type(e)||e.nodeType||st.isWindow(e))return!1;try{if(e.constructor&&!ot.call(e,"constructor")&&!ot.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(n){return!1}var r;for(r in e);return r===t||ot.call(e,r)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},error:function(e){throw Error(e)},parseHTML:function(e,t,n){if(!e||"string"!=typeof e)return null;"boolean"==typeof t&&(n=t,t=!1),t=t||V;var r=pt.exec(e),i=!n&&[];return r?[t.createElement(r[1])]:(r=st.buildFragment([e],t,i),i&&st(i).remove(),st.merge([],r.childNodes))},parseJSON:function(n){return e.JSON&&e.JSON.parse?e.JSON.parse(n):null===n?n:"string"==typeof n&&(n=st.trim(n),n&&dt.test(n.replace(gt,"@").replace(mt,"]").replace(ht,"")))?Function("return "+n)():(st.error("Invalid JSON: "+n),t)},parseXML:function(n){var r,i;if(!n||"string"!=typeof n)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(o){r=t}return r&&r.documentElement&&!r.getElementsByTagName("parsererror").length||st.error("Invalid XML: "+n),r},noop:function(){},globalEval:function(t){t&&st.trim(t)&&(e.execScript||function(t){e.eval.call(e,t)})(t)},camelCase:function(e){return e.replace(yt,"ms-").replace(vt,bt)},nodeName:function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()},each:function(e,t,r){var i,o=0,a=e.length,s=n(e);if(r){if(s)for(;a>o&&(i=t.apply(e[o],r),i!==!1);o++);else for(o in e)if(i=t.apply(e[o],r),i===!1)break}else if(s)for(;a>o&&(i=t.call(e[o],o,e[o]),i!==!1);o++);else for(o in e)if(i=t.call(e[o],o,e[o]),i===!1)break;return e},trim:at&&!at.call("\ufeff\u00a0")?function(e){return null==e?"":at.call(e)}:function(e){return null==e?"":(e+"").replace(ct,"")},makeArray:function(e,t){var r=t||[];return null!=e&&(n(Object(e))?st.merge(r,"string"==typeof e?[e]:e):tt.call(r,e)),r},inArray:function(e,t,n){var r;if(t){if(rt)return rt.call(t,e,n);for(r=t.length,n=n?0>n?Math.max(0,r+n):n:0;r>n;n++)if(n in t&&t[n]===e)return n}return-1},merge:function(e,n){var r=n.length,i=e.length,o=0;if("number"==typeof r)for(;r>o;o++)e[i++]=n[o];else for(;n[o]!==t;)e[i++]=n[o++];return e.length=i,e},grep:function(e,t,n){var r,i=[],o=0,a=e.length;for(n=!!n;a>o;o++)r=!!t(e[o],o),n!==r&&i.push(e[o]);return i},map:function(e,t,r){var i,o=0,a=e.length,s=n(e),u=[];if(s)for(;a>o;o++)i=t(e[o],o,r),null!=i&&(u[u.length]=i);else for(o in e)i=t(e[o],o,r),null!=i&&(u[u.length]=i);return et.apply([],u)},guid:1,proxy:function(e,n){var r,i,o;return"string"==typeof n&&(r=e[n],n=e,e=r),st.isFunction(e)?(i=nt.call(arguments,2),o=function(){return e.apply(n||this,i.concat(nt.call(arguments)))},o.guid=e.guid=e.guid||st.guid++,o):t},access:function(e,n,r,i,o,a,s){var u=0,l=e.length,c=null==r;if("object"===st.type(r)){o=!0;for(u in r)st.access(e,n,u,r[u],!0,a,s)}else if(i!==t&&(o=!0,st.isFunction(i)||(s=!0),c&&(s?(n.call(e,i),n=null):(c=n,n=function(e,t,n){return c.call(st(e),n)})),n))for(;l>u;u++)n(e[u],r,s?i:i.call(e[u],u,n(e[u],r)));return o?e:c?n.call(e):l?n(e[0],r):a},now:function(){return(new Date).getTime()}}),st.ready.promise=function(t){if(!U)if(U=st.Deferred(),"complete"===V.readyState)setTimeout(st.ready);else if(V.addEventListener)V.addEventListener("DOMContentLoaded",xt,!1),e.addEventListener("load",st.ready,!1);else{V.attachEvent("onreadystatechange",xt),e.attachEvent("onload",st.ready);var n=!1;try{n=null==e.frameElement&&V.documentElement}catch(r){}n&&n.doScroll&&function i(){if(!st.isReady){try{n.doScroll("left")}catch(e){return setTimeout(i,50)}st.ready()}}()}return U.promise(t)},st.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(e,t){Q["[object "+t+"]"]=t.toLowerCase()}),X=st(V);var Tt={};st.Callbacks=function(e){e="string"==typeof e?Tt[e]||r(e):st.extend({},e);var n,i,o,a,s,u,l=[],c=!e.once&&[],f=function(t){for(n=e.memory&&t,i=!0,u=a||0,a=0,s=l.length,o=!0;l&&s>u;u++)if(l[u].apply(t[0],t[1])===!1&&e.stopOnFalse){n=!1;break}o=!1,l&&(c?c.length&&f(c.shift()):n?l=[]:p.disable())},p={add:function(){if(l){var t=l.length;(function r(t){st.each(t,function(t,n){var i=st.type(n);"function"===i?e.unique&&p.has(n)||l.push(n):n&&n.length&&"string"!==i&&r(n)})})(arguments),o?s=l.length:n&&(a=t,f(n))}return this},remove:function(){return l&&st.each(arguments,function(e,t){for(var n;(n=st.inArray(t,l,n))>-1;)l.splice(n,1),o&&(s>=n&&s--,u>=n&&u--)}),this},has:function(e){return st.inArray(e,l)>-1},empty:function(){return l=[],this},disable:function(){return l=c=n=t,this},disabled:function(){return!l},lock:function(){return c=t,n||p.disable(),this},locked:function(){return!c},fireWith:function(e,t){return t=t||[],t=[e,t.slice?t.slice():t],!l||i&&!c||(o?c.push(t):f(t)),this},fire:function(){return p.fireWith(this,arguments),this},fired:function(){return!!i}};return p},st.extend({Deferred:function(e){var t=[["resolve","done",st.Callbacks("once memory"),"resolved"],["reject","fail",st.Callbacks("once memory"),"rejected"],["notify","progress",st.Callbacks("memory")]],n="pending",r={state:function(){return n},always:function(){return i.done(arguments).fail(arguments),this},then:function(){var e=arguments;return st.Deferred(function(n){st.each(t,function(t,o){var a=o[0],s=st.isFunction(e[t])&&e[t];i[o[1]](function(){var e=s&&s.apply(this,arguments);e&&st.isFunction(e.promise)?e.promise().done(n.resolve).fail(n.reject).progress(n.notify):n[a+"With"](this===r?n.promise():this,s?[e]:arguments)})}),e=null}).promise()},promise:function(e){return null!=e?st.extend(e,r):r}},i={};return r.pipe=r.then,st.each(t,function(e,o){var a=o[2],s=o[3];r[o[1]]=a.add,s&&a.add(function(){n=s},t[1^e][2].disable,t[2][2].lock),i[o[0]]=function(){return i[o[0]+"With"](this===i?r:this,arguments),this},i[o[0]+"With"]=a.fireWith}),r.promise(i),e&&e.call(i,i),i},when:function(e){var t,n,r,i=0,o=nt.call(arguments),a=o.length,s=1!==a||e&&st.isFunction(e.promise)?a:0,u=1===s?e:st.Deferred(),l=function(e,n,r){return function(i){n[e]=this,r[e]=arguments.length>1?nt.call(arguments):i,r===t?u.notifyWith(n,r):--s||u.resolveWith(n,r)}};if(a>1)for(t=Array(a),n=Array(a),r=Array(a);a>i;i++)o[i]&&st.isFunction(o[i].promise)?o[i].promise().done(l(i,r,o)).fail(u.reject).progress(l(i,n,t)):--s;return s||u.resolveWith(r,o),u.promise()}}),st.support=function(){var n,r,i,o,a,s,u,l,c,f,p=V.createElement("div");if(p.setAttribute("className","t"),p.innerHTML=" <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",r=p.getElementsByTagName("*"),i=p.getElementsByTagName("a")[0],!r||!i||!r.length)return{};o=V.createElement("select"),a=o.appendChild(V.createElement("option")),s=p.getElementsByTagName("input")[0],i.style.cssText="top:1px;float:left;opacity:.5",n={getSetAttribute:"t"!==p.className,leadingWhitespace:3===p.firstChild.nodeType,tbody:!p.getElementsByTagName("tbody").length,htmlSerialize:!!p.getElementsByTagName("link").length,style:/top/.test(i.getAttribute("style")),hrefNormalized:"/a"===i.getAttribute("href"),opacity:/^0.5/.test(i.style.opacity),cssFloat:!!i.style.cssFloat,checkOn:!!s.value,optSelected:a.selected,enctype:!!V.createElement("form").enctype,html5Clone:"<:nav></:nav>"!==V.createElement("nav").cloneNode(!0).outerHTML,boxModel:"CSS1Compat"===V.compatMode,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0,boxSizingReliable:!0,pixelPosition:!1},s.checked=!0,n.noCloneChecked=s.cloneNode(!0).checked,o.disabled=!0,n.optDisabled=!a.disabled;try{delete p.test}catch(d){n.deleteExpando=!1}s=V.createElement("input"),s.setAttribute("value",""),n.input=""===s.getAttribute("value"),s.value="t",s.setAttribute("type","radio"),n.radioValue="t"===s.value,s.setAttribute("checked","t"),s.setAttribute("name","t"),u=V.createDocumentFragment(),u.appendChild(s),n.appendChecked=s.checked,n.checkClone=u.cloneNode(!0).cloneNode(!0).lastChild.checked,p.attachEvent&&(p.attachEvent("onclick",function(){n.noCloneEvent=!1}),p.cloneNode(!0).click());for(f in{submit:!0,change:!0,focusin:!0})p.setAttribute(l="on"+f,"t"),n[f+"Bubbles"]=l in e||p.attributes[l].expando===!1;return p.style.backgroundClip="content-box",p.cloneNode(!0).style.backgroundClip="",n.clearCloneStyle="content-box"===p.style.backgroundClip,st(function(){var r,i,o,a="padding:0;margin:0;border:0;display:block;box-sizing:content-box;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;",s=V.getElementsByTagName("body")[0];s&&(r=V.createElement("div"),r.style.cssText="border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px",s.appendChild(r).appendChild(p),p.innerHTML="<table><tr><td></td><td>t</td></tr></table>",o=p.getElementsByTagName("td"),o[0].style.cssText="padding:0;margin:0;border:0;display:none",c=0===o[0].offsetHeight,o[0].style.display="",o[1].style.display="none",n.reliableHiddenOffsets=c&&0===o[0].offsetHeight,p.innerHTML="",p.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%;",n.boxSizing=4===p.offsetWidth,n.doesNotIncludeMarginInBodyOffset=1!==s.offsetTop,e.getComputedStyle&&(n.pixelPosition="1%"!==(e.getComputedStyle(p,null)||{}).top,n.boxSizingReliable="4px"===(e.getComputedStyle(p,null)||{width:"4px"}).width,i=p.appendChild(V.createElement("div")),i.style.cssText=p.style.cssText=a,i.style.marginRight=i.style.width="0",p.style.width="1px",n.reliableMarginRight=!parseFloat((e.getComputedStyle(i,null)||{}).marginRight)),p.style.zoom!==t&&(p.innerHTML="",p.style.cssText=a+"width:1px;padding:1px;display:inline;zoom:1",n.inlineBlockNeedsLayout=3===p.offsetWidth,p.style.display="block",p.innerHTML="<div></div>",p.firstChild.style.width="5px",n.shrinkWrapBlocks=3!==p.offsetWidth,s.style.zoom=1),s.removeChild(r),r=p=o=i=null)}),r=o=u=a=i=s=null,n}();var wt=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,Nt=/([A-Z])/g;st.extend({cache:{},expando:"jQuery"+(Z+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(e){return e=e.nodeType?st.cache[e[st.expando]]:e[st.expando],!!e&&!s(e)},data:function(e,t,n){return i(e,t,n,!1)},removeData:function(e,t){return o(e,t,!1)},_data:function(e,t,n){return i(e,t,n,!0)},_removeData:function(e,t){return o(e,t,!0)},acceptData:function(e){var t=e.nodeName&&st.noData[e.nodeName.toLowerCase()];return!t||t!==!0&&e.getAttribute("classid")===t}}),st.fn.extend({data:function(e,n){var r,i,o=this[0],s=0,u=null;if(e===t){if(this.length&&(u=st.data(o),1===o.nodeType&&!st._data(o,"parsedAttrs"))){for(r=o.attributes;r.length>s;s++)i=r[s].name,i.indexOf("data-")||(i=st.camelCase(i.substring(5)),a(o,i,u[i]));st._data(o,"parsedAttrs",!0)}return u}return"object"==typeof e?this.each(function(){st.data(this,e)}):st.access(this,function(n){return n===t?o?a(o,e,st.data(o,e)):null:(this.each(function(){st.data(this,e,n)}),t)},null,n,arguments.length>1,null,!0)},removeData:function(e){return this.each(function(){st.removeData(this,e)})}}),st.extend({queue:function(e,n,r){var i;return e?(n=(n||"fx")+"queue",i=st._data(e,n),r&&(!i||st.isArray(r)?i=st._data(e,n,st.makeArray(r)):i.push(r)),i||[]):t},dequeue:function(e,t){t=t||"fx";var n=st.queue(e,t),r=n.length,i=n.shift(),o=st._queueHooks(e,t),a=function(){st.dequeue(e,t)};"inprogress"===i&&(i=n.shift(),r--),o.cur=i,i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,a,o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return st._data(e,n)||st._data(e,n,{empty:st.Callbacks("once memory").add(function(){st._removeData(e,t+"queue"),st._removeData(e,n)})})}}),st.fn.extend({queue:function(e,n){var r=2;return"string"!=typeof e&&(n=e,e="fx",r--),r>arguments.length?st.queue(this[0],e):n===t?this:this.each(function(){var t=st.queue(this,e,n);st._queueHooks(this,e),"fx"===e&&"inprogress"!==t[0]&&st.dequeue(this,e)})},dequeue:function(e){return this.each(function(){st.dequeue(this,e)})},delay:function(e,t){return e=st.fx?st.fx.speeds[e]||e:e,t=t||"fx",this.queue(t,function(t,n){var r=setTimeout(t,e);n.stop=function(){clearTimeout(r)}})},clearQueue:function(e){return this.queue(e||"fx",[])},promise:function(e,n){var r,i=1,o=st.Deferred(),a=this,s=this.length,u=function(){--i||o.resolveWith(a,[a])};for("string"!=typeof e&&(n=e,e=t),e=e||"fx";s--;)r=st._data(a[s],e+"queueHooks"),r&&r.empty&&(i++,r.empty.add(u));return u(),o.promise(n)}});var Ct,kt,Et=/[\t\r\n]/g,St=/\r/g,At=/^(?:input|select|textarea|button|object)$/i,jt=/^(?:a|area)$/i,Dt=/^(?:checked|selected|autofocus|autoplay|async|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped)$/i,Lt=/^(?:checked|selected)$/i,Ht=st.support.getSetAttribute,Mt=st.support.input;st.fn.extend({attr:function(e,t){return st.access(this,st.attr,e,t,arguments.length>1)},removeAttr:function(e){return this.each(function(){st.removeAttr(this,e)})},prop:function(e,t){return st.access(this,st.prop,e,t,arguments.length>1)},removeProp:function(e){return e=st.propFix[e]||e,this.each(function(){try{this[e]=t,delete this[e]}catch(n){}})},addClass:function(e){var t,n,r,i,o,a=0,s=this.length,u="string"==typeof e&&e;if(st.isFunction(e))return this.each(function(t){st(this).addClass(e.call(this,t,this.className))});if(u)for(t=(e||"").match(lt)||[];s>a;a++)if(n=this[a],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(Et," "):" ")){for(o=0;i=t[o++];)0>r.indexOf(" "+i+" ")&&(r+=i+" ");n.className=st.trim(r)}return this},removeClass:function(e){var t,n,r,i,o,a=0,s=this.length,u=0===arguments.length||"string"==typeof e&&e;if(st.isFunction(e))return this.each(function(t){st(this).removeClass(e.call(this,t,this.className))});if(u)for(t=(e||"").match(lt)||[];s>a;a++)if(n=this[a],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(Et," "):"")){for(o=0;i=t[o++];)for(;r.indexOf(" "+i+" ")>=0;)r=r.replace(" "+i+" "," ");n.className=e?st.trim(r):""}return this},toggleClass:function(e,t){var n=typeof e,r="boolean"==typeof t;return st.isFunction(e)?this.each(function(n){st(this).toggleClass(e.call(this,n,this.className,t),t)}):this.each(function(){if("string"===n)for(var i,o=0,a=st(this),s=t,u=e.match(lt)||[];i=u[o++];)s=r?s:!a.hasClass(i),a[s?"addClass":"removeClass"](i);else("undefined"===n||"boolean"===n)&&(this.className&&st._data(this,"__className__",this.className),this.className=this.className||e===!1?"":st._data(this,"__className__")||"")})},hasClass:function(e){for(var t=" "+e+" ",n=0,r=this.length;r>n;n++)if(1===this[n].nodeType&&(" "+this[n].className+" ").replace(Et," ").indexOf(t)>=0)return!0;return!1},val:function(e){var n,r,i,o=this[0];{if(arguments.length)return i=st.isFunction(e),this.each(function(r){var o,a=st(this);1===this.nodeType&&(o=i?e.call(this,r,a.val()):e,null==o?o="":"number"==typeof o?o+="":st.isArray(o)&&(o=st.map(o,function(e){return null==e?"":e+""})),n=st.valHooks[this.type]||st.valHooks[this.nodeName.toLowerCase()],n&&"set"in n&&n.set(this,o,"value")!==t||(this.value=o))});if(o)return n=st.valHooks[o.type]||st.valHooks[o.nodeName.toLowerCase()],n&&"get"in n&&(r=n.get(o,"value"))!==t?r:(r=o.value,"string"==typeof r?r.replace(St,""):null==r?"":r)}}}),st.extend({valHooks:{option:{get:function(e){var t=e.attributes.value;return!t||t.specified?e.value:e.text}},select:{get:function(e){for(var t,n,r=e.options,i=e.selectedIndex,o="select-one"===e.type||0>i,a=o?null:[],s=o?i+1:r.length,u=0>i?s:o?i:0;s>u;u++)if(n=r[u],!(!n.selected&&u!==i||(st.support.optDisabled?n.disabled:null!==n.getAttribute("disabled"))||n.parentNode.disabled&&st.nodeName(n.parentNode,"optgroup"))){if(t=st(n).val(),o)return t;a.push(t)}return a},set:function(e,t){var n=st.makeArray(t);return st(e).find("option").each(function(){this.selected=st.inArray(st(this).val(),n)>=0}),n.length||(e.selectedIndex=-1),n}}},attr:function(e,n,r){var i,o,a,s=e.nodeType;if(e&&3!==s&&8!==s&&2!==s)return e.getAttribute===t?st.prop(e,n,r):(a=1!==s||!st.isXMLDoc(e),a&&(n=n.toLowerCase(),o=st.attrHooks[n]||(Dt.test(n)?kt:Ct)),r===t?o&&a&&"get"in o&&null!==(i=o.get(e,n))?i:(e.getAttribute!==t&&(i=e.getAttribute(n)),null==i?t:i):null!==r?o&&a&&"set"in o&&(i=o.set(e,r,n))!==t?i:(e.setAttribute(n,r+""),r):(st.removeAttr(e,n),t))},removeAttr:function(e,t){var n,r,i=0,o=t&&t.match(lt);if(o&&1===e.nodeType)for(;n=o[i++];)r=st.propFix[n]||n,Dt.test(n)?!Ht&&Lt.test(n)?e[st.camelCase("default-"+n)]=e[r]=!1:e[r]=!1:st.attr(e,n,""),e.removeAttribute(Ht?n:r)},attrHooks:{type:{set:function(e,t){if(!st.support.radioValue&&"radio"===t&&st.nodeName(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},propFix:{tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},prop:function(e,n,r){var i,o,a,s=e.nodeType;if(e&&3!==s&&8!==s&&2!==s)return a=1!==s||!st.isXMLDoc(e),a&&(n=st.propFix[n]||n,o=st.propHooks[n]),r!==t?o&&"set"in o&&(i=o.set(e,r,n))!==t?i:e[n]=r:o&&"get"in o&&null!==(i=o.get(e,n))?i:e[n]},propHooks:{tabIndex:{get:function(e){var n=e.getAttributeNode("tabindex");return n&&n.specified?parseInt(n.value,10):At.test(e.nodeName)||jt.test(e.nodeName)&&e.href?0:t}}}}),kt={get:function(e,n){var r=st.prop(e,n),i="boolean"==typeof r&&e.getAttribute(n),o="boolean"==typeof r?Mt&&Ht?null!=i:Lt.test(n)?e[st.camelCase("default-"+n)]:!!i:e.getAttributeNode(n);return o&&o.value!==!1?n.toLowerCase():t},set:function(e,t,n){return t===!1?st.removeAttr(e,n):Mt&&Ht||!Lt.test(n)?e.setAttribute(!Ht&&st.propFix[n]||n,n):e[st.camelCase("default-"+n)]=e[n]=!0,n}},Mt&&Ht||(st.attrHooks.value={get:function(e,n){var r=e.getAttributeNode(n);return st.nodeName(e,"input")?e.defaultValue:r&&r.specified?r.value:t -},set:function(e,n,r){return st.nodeName(e,"input")?(e.defaultValue=n,t):Ct&&Ct.set(e,n,r)}}),Ht||(Ct=st.valHooks.button={get:function(e,n){var r=e.getAttributeNode(n);return r&&("id"===n||"name"===n||"coords"===n?""!==r.value:r.specified)?r.value:t},set:function(e,n,r){var i=e.getAttributeNode(r);return i||e.setAttributeNode(i=e.ownerDocument.createAttribute(r)),i.value=n+="","value"===r||n===e.getAttribute(r)?n:t}},st.attrHooks.contenteditable={get:Ct.get,set:function(e,t,n){Ct.set(e,""===t?!1:t,n)}},st.each(["width","height"],function(e,n){st.attrHooks[n]=st.extend(st.attrHooks[n],{set:function(e,r){return""===r?(e.setAttribute(n,"auto"),r):t}})})),st.support.hrefNormalized||(st.each(["href","src","width","height"],function(e,n){st.attrHooks[n]=st.extend(st.attrHooks[n],{get:function(e){var r=e.getAttribute(n,2);return null==r?t:r}})}),st.each(["href","src"],function(e,t){st.propHooks[t]={get:function(e){return e.getAttribute(t,4)}}})),st.support.style||(st.attrHooks.style={get:function(e){return e.style.cssText||t},set:function(e,t){return e.style.cssText=t+""}}),st.support.optSelected||(st.propHooks.selected=st.extend(st.propHooks.selected,{get:function(e){var t=e.parentNode;return t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex),null}})),st.support.enctype||(st.propFix.enctype="encoding"),st.support.checkOn||st.each(["radio","checkbox"],function(){st.valHooks[this]={get:function(e){return null===e.getAttribute("value")?"on":e.value}}}),st.each(["radio","checkbox"],function(){st.valHooks[this]=st.extend(st.valHooks[this],{set:function(e,n){return st.isArray(n)?e.checked=st.inArray(st(e).val(),n)>=0:t}})});var qt=/^(?:input|select|textarea)$/i,_t=/^key/,Ft=/^(?:mouse|contextmenu)|click/,Ot=/^(?:focusinfocus|focusoutblur)$/,Bt=/^([^.]*)(?:\.(.+)|)$/;st.event={global:{},add:function(e,n,r,i,o){var a,s,u,l,c,f,p,d,h,g,m,y=3!==e.nodeType&&8!==e.nodeType&&st._data(e);if(y){for(r.handler&&(a=r,r=a.handler,o=a.selector),r.guid||(r.guid=st.guid++),(l=y.events)||(l=y.events={}),(s=y.handle)||(s=y.handle=function(e){return st===t||e&&st.event.triggered===e.type?t:st.event.dispatch.apply(s.elem,arguments)},s.elem=e),n=(n||"").match(lt)||[""],c=n.length;c--;)u=Bt.exec(n[c])||[],h=m=u[1],g=(u[2]||"").split(".").sort(),p=st.event.special[h]||{},h=(o?p.delegateType:p.bindType)||h,p=st.event.special[h]||{},f=st.extend({type:h,origType:m,data:i,handler:r,guid:r.guid,selector:o,needsContext:o&&st.expr.match.needsContext.test(o),namespace:g.join(".")},a),(d=l[h])||(d=l[h]=[],d.delegateCount=0,p.setup&&p.setup.call(e,i,g,s)!==!1||(e.addEventListener?e.addEventListener(h,s,!1):e.attachEvent&&e.attachEvent("on"+h,s))),p.add&&(p.add.call(e,f),f.handler.guid||(f.handler.guid=r.guid)),o?d.splice(d.delegateCount++,0,f):d.push(f),st.event.global[h]=!0;e=null}},remove:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,m=st.hasData(e)&&st._data(e);if(m&&(u=m.events)){for(t=(t||"").match(lt)||[""],l=t.length;l--;)if(s=Bt.exec(t[l])||[],d=g=s[1],h=(s[2]||"").split(".").sort(),d){for(f=st.event.special[d]||{},d=(r?f.delegateType:f.bindType)||d,p=u[d]||[],s=s[2]&&RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),a=o=p.length;o--;)c=p[o],!i&&g!==c.origType||n&&n.guid!==c.guid||s&&!s.test(c.namespace)||r&&r!==c.selector&&("**"!==r||!c.selector)||(p.splice(o,1),c.selector&&p.delegateCount--,f.remove&&f.remove.call(e,c));a&&!p.length&&(f.teardown&&f.teardown.call(e,h,m.handle)!==!1||st.removeEvent(e,d,m.handle),delete u[d])}else for(d in u)st.event.remove(e,d+t[l],n,r,!0);st.isEmptyObject(u)&&(delete m.handle,st._removeData(e,"events"))}},trigger:function(n,r,i,o){var a,s,u,l,c,f,p,d=[i||V],h=n.type||n,g=n.namespace?n.namespace.split("."):[];if(s=u=i=i||V,3!==i.nodeType&&8!==i.nodeType&&!Ot.test(h+st.event.triggered)&&(h.indexOf(".")>=0&&(g=h.split("."),h=g.shift(),g.sort()),c=0>h.indexOf(":")&&"on"+h,n=n[st.expando]?n:new st.Event(h,"object"==typeof n&&n),n.isTrigger=!0,n.namespace=g.join("."),n.namespace_re=n.namespace?RegExp("(^|\\.)"+g.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,n.result=t,n.target||(n.target=i),r=null==r?[n]:st.makeArray(r,[n]),p=st.event.special[h]||{},o||!p.trigger||p.trigger.apply(i,r)!==!1)){if(!o&&!p.noBubble&&!st.isWindow(i)){for(l=p.delegateType||h,Ot.test(l+h)||(s=s.parentNode);s;s=s.parentNode)d.push(s),u=s;u===(i.ownerDocument||V)&&d.push(u.defaultView||u.parentWindow||e)}for(a=0;(s=d[a++])&&!n.isPropagationStopped();)n.type=a>1?l:p.bindType||h,f=(st._data(s,"events")||{})[n.type]&&st._data(s,"handle"),f&&f.apply(s,r),f=c&&s[c],f&&st.acceptData(s)&&f.apply&&f.apply(s,r)===!1&&n.preventDefault();if(n.type=h,!(o||n.isDefaultPrevented()||p._default&&p._default.apply(i.ownerDocument,r)!==!1||"click"===h&&st.nodeName(i,"a")||!st.acceptData(i)||!c||!i[h]||st.isWindow(i))){u=i[c],u&&(i[c]=null),st.event.triggered=h;try{i[h]()}catch(m){}st.event.triggered=t,u&&(i[c]=u)}return n.result}},dispatch:function(e){e=st.event.fix(e);var n,r,i,o,a,s=[],u=nt.call(arguments),l=(st._data(this,"events")||{})[e.type]||[],c=st.event.special[e.type]||{};if(u[0]=e,e.delegateTarget=this,!c.preDispatch||c.preDispatch.call(this,e)!==!1){for(s=st.event.handlers.call(this,e,l),n=0;(o=s[n++])&&!e.isPropagationStopped();)for(e.currentTarget=o.elem,r=0;(a=o.handlers[r++])&&!e.isImmediatePropagationStopped();)(!e.namespace_re||e.namespace_re.test(a.namespace))&&(e.handleObj=a,e.data=a.data,i=((st.event.special[a.origType]||{}).handle||a.handler).apply(o.elem,u),i!==t&&(e.result=i)===!1&&(e.preventDefault(),e.stopPropagation()));return c.postDispatch&&c.postDispatch.call(this,e),e.result}},handlers:function(e,n){var r,i,o,a,s=[],u=n.delegateCount,l=e.target;if(u&&l.nodeType&&(!e.button||"click"!==e.type))for(;l!=this;l=l.parentNode||this)if(l.disabled!==!0||"click"!==e.type){for(i=[],r=0;u>r;r++)a=n[r],o=a.selector+" ",i[o]===t&&(i[o]=a.needsContext?st(o,this).index(l)>=0:st.find(o,this,null,[l]).length),i[o]&&i.push(a);i.length&&s.push({elem:l,handlers:i})}return n.length>u&&s.push({elem:this,handlers:n.slice(u)}),s},fix:function(e){if(e[st.expando])return e;var t,n,r=e,i=st.event.fixHooks[e.type]||{},o=i.props?this.props.concat(i.props):this.props;for(e=new st.Event(r),t=o.length;t--;)n=o[t],e[n]=r[n];return e.target||(e.target=r.srcElement||V),3===e.target.nodeType&&(e.target=e.target.parentNode),e.metaKey=!!e.metaKey,i.filter?i.filter(e,r):e},props:"altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(e,t){return null==e.which&&(e.which=null!=t.charCode?t.charCode:t.keyCode),e}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(e,n){var r,i,o,a=n.button,s=n.fromElement;return null==e.pageX&&null!=n.clientX&&(r=e.target.ownerDocument||V,i=r.documentElement,o=r.body,e.pageX=n.clientX+(i&&i.scrollLeft||o&&o.scrollLeft||0)-(i&&i.clientLeft||o&&o.clientLeft||0),e.pageY=n.clientY+(i&&i.scrollTop||o&&o.scrollTop||0)-(i&&i.clientTop||o&&o.clientTop||0)),!e.relatedTarget&&s&&(e.relatedTarget=s===e.target?n.toElement:s),e.which||a===t||(e.which=1&a?1:2&a?3:4&a?2:0),e}},special:{load:{noBubble:!0},click:{trigger:function(){return st.nodeName(this,"input")&&"checkbox"===this.type&&this.click?(this.click(),!1):t}},focus:{trigger:function(){if(this!==V.activeElement&&this.focus)try{return this.focus(),!1}catch(e){}},delegateType:"focusin"},blur:{trigger:function(){return this===V.activeElement&&this.blur?(this.blur(),!1):t},delegateType:"focusout"},beforeunload:{postDispatch:function(e){e.result!==t&&(e.originalEvent.returnValue=e.result)}}},simulate:function(e,t,n,r){var i=st.extend(new st.Event,n,{type:e,isSimulated:!0,originalEvent:{}});r?st.event.trigger(i,null,t):st.event.dispatch.call(t,i),i.isDefaultPrevented()&&n.preventDefault()}},st.removeEvent=V.removeEventListener?function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n,!1)}:function(e,n,r){var i="on"+n;e.detachEvent&&(e[i]===t&&(e[i]=null),e.detachEvent(i,r))},st.Event=function(e,n){return this instanceof st.Event?(e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||e.returnValue===!1||e.getPreventDefault&&e.getPreventDefault()?u:l):this.type=e,n&&st.extend(this,n),this.timeStamp=e&&e.timeStamp||st.now(),this[st.expando]=!0,t):new st.Event(e,n)},st.Event.prototype={isDefaultPrevented:l,isPropagationStopped:l,isImmediatePropagationStopped:l,preventDefault:function(){var e=this.originalEvent;this.isDefaultPrevented=u,e&&(e.preventDefault?e.preventDefault():e.returnValue=!1)},stopPropagation:function(){var e=this.originalEvent;this.isPropagationStopped=u,e&&(e.stopPropagation&&e.stopPropagation(),e.cancelBubble=!0)},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=u,this.stopPropagation()}},st.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(e,t){st.event.special[e]={delegateType:t,bindType:t,handle:function(e){var n,r=this,i=e.relatedTarget,o=e.handleObj;return(!i||i!==r&&!st.contains(r,i))&&(e.type=o.origType,n=o.handler.apply(this,arguments),e.type=t),n}}}),st.support.submitBubbles||(st.event.special.submit={setup:function(){return st.nodeName(this,"form")?!1:(st.event.add(this,"click._submit keypress._submit",function(e){var n=e.target,r=st.nodeName(n,"input")||st.nodeName(n,"button")?n.form:t;r&&!st._data(r,"submitBubbles")&&(st.event.add(r,"submit._submit",function(e){e._submit_bubble=!0}),st._data(r,"submitBubbles",!0))}),t)},postDispatch:function(e){e._submit_bubble&&(delete e._submit_bubble,this.parentNode&&!e.isTrigger&&st.event.simulate("submit",this.parentNode,e,!0))},teardown:function(){return st.nodeName(this,"form")?!1:(st.event.remove(this,"._submit"),t)}}),st.support.changeBubbles||(st.event.special.change={setup:function(){return qt.test(this.nodeName)?(("checkbox"===this.type||"radio"===this.type)&&(st.event.add(this,"propertychange._change",function(e){"checked"===e.originalEvent.propertyName&&(this._just_changed=!0)}),st.event.add(this,"click._change",function(e){this._just_changed&&!e.isTrigger&&(this._just_changed=!1),st.event.simulate("change",this,e,!0)})),!1):(st.event.add(this,"beforeactivate._change",function(e){var t=e.target;qt.test(t.nodeName)&&!st._data(t,"changeBubbles")&&(st.event.add(t,"change._change",function(e){!this.parentNode||e.isSimulated||e.isTrigger||st.event.simulate("change",this.parentNode,e,!0)}),st._data(t,"changeBubbles",!0))}),t)},handle:function(e){var n=e.target;return this!==n||e.isSimulated||e.isTrigger||"radio"!==n.type&&"checkbox"!==n.type?e.handleObj.handler.apply(this,arguments):t},teardown:function(){return st.event.remove(this,"._change"),!qt.test(this.nodeName)}}),st.support.focusinBubbles||st.each({focus:"focusin",blur:"focusout"},function(e,t){var n=0,r=function(e){st.event.simulate(t,e.target,st.event.fix(e),!0)};st.event.special[t]={setup:function(){0===n++&&V.addEventListener(e,r,!0)},teardown:function(){0===--n&&V.removeEventListener(e,r,!0)}}}),st.fn.extend({on:function(e,n,r,i,o){var a,s;if("object"==typeof e){"string"!=typeof n&&(r=r||n,n=t);for(s in e)this.on(s,n,r,e[s],o);return this}if(null==r&&null==i?(i=n,r=n=t):null==i&&("string"==typeof n?(i=r,r=t):(i=r,r=n,n=t)),i===!1)i=l;else if(!i)return this;return 1===o&&(a=i,i=function(e){return st().off(e),a.apply(this,arguments)},i.guid=a.guid||(a.guid=st.guid++)),this.each(function(){st.event.add(this,e,i,r,n)})},one:function(e,t,n,r){return this.on(e,t,n,r,1)},off:function(e,n,r){var i,o;if(e&&e.preventDefault&&e.handleObj)return i=e.handleObj,st(e.delegateTarget).off(i.namespace?i.origType+"."+i.namespace:i.origType,i.selector,i.handler),this;if("object"==typeof e){for(o in e)this.off(o,n,e[o]);return this}return(n===!1||"function"==typeof n)&&(r=n,n=t),r===!1&&(r=l),this.each(function(){st.event.remove(this,e,r,n)})},bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},trigger:function(e,t){return this.each(function(){st.event.trigger(e,t,this)})},triggerHandler:function(e,n){var r=this[0];return r?st.event.trigger(e,n,r,!0):t},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),st.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(e,t){st.fn[t]=function(e,n){return arguments.length>0?this.on(t,null,e,n):this.trigger(t)},_t.test(t)&&(st.event.fixHooks[t]=st.event.keyHooks),Ft.test(t)&&(st.event.fixHooks[t]=st.event.mouseHooks)}),function(e,t){function n(e){return ht.test(e+"")}function r(){var e,t=[];return e=function(n,r){return t.push(n+=" ")>C.cacheLength&&delete e[t.shift()],e[n]=r}}function i(e){return e[P]=!0,e}function o(e){var t=L.createElement("div");try{return e(t)}catch(n){return!1}finally{t=null}}function a(e,t,n,r){var i,o,a,s,u,l,c,d,h,g;if((t?t.ownerDocument||t:R)!==L&&D(t),t=t||L,n=n||[],!e||"string"!=typeof e)return n;if(1!==(s=t.nodeType)&&9!==s)return[];if(!M&&!r){if(i=gt.exec(e))if(a=i[1]){if(9===s){if(o=t.getElementById(a),!o||!o.parentNode)return n;if(o.id===a)return n.push(o),n}else if(t.ownerDocument&&(o=t.ownerDocument.getElementById(a))&&O(t,o)&&o.id===a)return n.push(o),n}else{if(i[2])return Q.apply(n,K.call(t.getElementsByTagName(e),0)),n;if((a=i[3])&&W.getByClassName&&t.getElementsByClassName)return Q.apply(n,K.call(t.getElementsByClassName(a),0)),n}if(W.qsa&&!q.test(e)){if(c=!0,d=P,h=t,g=9===s&&e,1===s&&"object"!==t.nodeName.toLowerCase()){for(l=f(e),(c=t.getAttribute("id"))?d=c.replace(vt,"\\$&"):t.setAttribute("id",d),d="[id='"+d+"'] ",u=l.length;u--;)l[u]=d+p(l[u]);h=dt.test(e)&&t.parentNode||t,g=l.join(",")}if(g)try{return Q.apply(n,K.call(h.querySelectorAll(g),0)),n}catch(m){}finally{c||t.removeAttribute("id")}}}return x(e.replace(at,"$1"),t,n,r)}function s(e,t){for(var n=e&&t&&e.nextSibling;n;n=n.nextSibling)if(n===t)return-1;return e?1:-1}function u(e){return function(t){var n=t.nodeName.toLowerCase();return"input"===n&&t.type===e}}function l(e){return function(t){var n=t.nodeName.toLowerCase();return("input"===n||"button"===n)&&t.type===e}}function c(e){return i(function(t){return t=+t,i(function(n,r){for(var i,o=e([],n.length,t),a=o.length;a--;)n[i=o[a]]&&(n[i]=!(r[i]=n[i]))})})}function f(e,t){var n,r,i,o,s,u,l,c=X[e+" "];if(c)return t?0:c.slice(0);for(s=e,u=[],l=C.preFilter;s;){(!n||(r=ut.exec(s)))&&(r&&(s=s.slice(r[0].length)||s),u.push(i=[])),n=!1,(r=lt.exec(s))&&(n=r.shift(),i.push({value:n,type:r[0].replace(at," ")}),s=s.slice(n.length));for(o in C.filter)!(r=pt[o].exec(s))||l[o]&&!(r=l[o](r))||(n=r.shift(),i.push({value:n,type:o,matches:r}),s=s.slice(n.length));if(!n)break}return t?s.length:s?a.error(e):X(e,u).slice(0)}function p(e){for(var t=0,n=e.length,r="";n>t;t++)r+=e[t].value;return r}function d(e,t,n){var r=t.dir,i=n&&"parentNode"===t.dir,o=I++;return t.first?function(t,n,o){for(;t=t[r];)if(1===t.nodeType||i)return e(t,n,o)}:function(t,n,a){var s,u,l,c=$+" "+o;if(a){for(;t=t[r];)if((1===t.nodeType||i)&&e(t,n,a))return!0}else for(;t=t[r];)if(1===t.nodeType||i)if(l=t[P]||(t[P]={}),(u=l[r])&&u[0]===c){if((s=u[1])===!0||s===N)return s===!0}else if(u=l[r]=[c],u[1]=e(t,n,a)||N,u[1]===!0)return!0}}function h(e){return e.length>1?function(t,n,r){for(var i=e.length;i--;)if(!e[i](t,n,r))return!1;return!0}:e[0]}function g(e,t,n,r,i){for(var o,a=[],s=0,u=e.length,l=null!=t;u>s;s++)(o=e[s])&&(!n||n(o,r,i))&&(a.push(o),l&&t.push(s));return a}function m(e,t,n,r,o,a){return r&&!r[P]&&(r=m(r)),o&&!o[P]&&(o=m(o,a)),i(function(i,a,s,u){var l,c,f,p=[],d=[],h=a.length,m=i||b(t||"*",s.nodeType?[s]:s,[]),y=!e||!i&&t?m:g(m,p,e,s,u),v=n?o||(i?e:h||r)?[]:a:y;if(n&&n(y,v,s,u),r)for(l=g(v,d),r(l,[],s,u),c=l.length;c--;)(f=l[c])&&(v[d[c]]=!(y[d[c]]=f));if(i){if(o||e){if(o){for(l=[],c=v.length;c--;)(f=v[c])&&l.push(y[c]=f);o(null,v=[],l,u)}for(c=v.length;c--;)(f=v[c])&&(l=o?Z.call(i,f):p[c])>-1&&(i[l]=!(a[l]=f))}}else v=g(v===a?v.splice(h,v.length):v),o?o(null,a,v,u):Q.apply(a,v)})}function y(e){for(var t,n,r,i=e.length,o=C.relative[e[0].type],a=o||C.relative[" "],s=o?1:0,u=d(function(e){return e===t},a,!0),l=d(function(e){return Z.call(t,e)>-1},a,!0),c=[function(e,n,r){return!o&&(r||n!==j)||((t=n).nodeType?u(e,n,r):l(e,n,r))}];i>s;s++)if(n=C.relative[e[s].type])c=[d(h(c),n)];else{if(n=C.filter[e[s].type].apply(null,e[s].matches),n[P]){for(r=++s;i>r&&!C.relative[e[r].type];r++);return m(s>1&&h(c),s>1&&p(e.slice(0,s-1)).replace(at,"$1"),n,r>s&&y(e.slice(s,r)),i>r&&y(e=e.slice(r)),i>r&&p(e))}c.push(n)}return h(c)}function v(e,t){var n=0,r=t.length>0,o=e.length>0,s=function(i,s,u,l,c){var f,p,d,h=[],m=0,y="0",v=i&&[],b=null!=c,x=j,T=i||o&&C.find.TAG("*",c&&s.parentNode||s),w=$+=null==x?1:Math.E;for(b&&(j=s!==L&&s,N=n);null!=(f=T[y]);y++){if(o&&f){for(p=0;d=e[p];p++)if(d(f,s,u)){l.push(f);break}b&&($=w,N=++n)}r&&((f=!d&&f)&&m--,i&&v.push(f))}if(m+=y,r&&y!==m){for(p=0;d=t[p];p++)d(v,h,s,u);if(i){if(m>0)for(;y--;)v[y]||h[y]||(h[y]=G.call(l));h=g(h)}Q.apply(l,h),b&&!i&&h.length>0&&m+t.length>1&&a.uniqueSort(l)}return b&&($=w,j=x),v};return r?i(s):s}function b(e,t,n){for(var r=0,i=t.length;i>r;r++)a(e,t[r],n);return n}function x(e,t,n,r){var i,o,a,s,u,l=f(e);if(!r&&1===l.length){if(o=l[0]=l[0].slice(0),o.length>2&&"ID"===(a=o[0]).type&&9===t.nodeType&&!M&&C.relative[o[1].type]){if(t=C.find.ID(a.matches[0].replace(xt,Tt),t)[0],!t)return n;e=e.slice(o.shift().value.length)}for(i=pt.needsContext.test(e)?-1:o.length-1;i>=0&&(a=o[i],!C.relative[s=a.type]);i--)if((u=C.find[s])&&(r=u(a.matches[0].replace(xt,Tt),dt.test(o[0].type)&&t.parentNode||t))){if(o.splice(i,1),e=r.length&&p(o),!e)return Q.apply(n,K.call(r,0)),n;break}}return S(e,l)(r,t,M,n,dt.test(e)),n}function T(){}var w,N,C,k,E,S,A,j,D,L,H,M,q,_,F,O,B,P="sizzle"+-new Date,R=e.document,W={},$=0,I=0,z=r(),X=r(),U=r(),V=typeof t,Y=1<<31,J=[],G=J.pop,Q=J.push,K=J.slice,Z=J.indexOf||function(e){for(var t=0,n=this.length;n>t;t++)if(this[t]===e)return t;return-1},et="[\\x20\\t\\r\\n\\f]",tt="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",nt=tt.replace("w","w#"),rt="([*^$|!~]?=)",it="\\["+et+"*("+tt+")"+et+"*(?:"+rt+et+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+nt+")|)|)"+et+"*\\]",ot=":("+tt+")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|"+it.replace(3,8)+")*)|.*)\\)|)",at=RegExp("^"+et+"+|((?:^|[^\\\\])(?:\\\\.)*)"+et+"+$","g"),ut=RegExp("^"+et+"*,"+et+"*"),lt=RegExp("^"+et+"*([\\x20\\t\\r\\n\\f>+~])"+et+"*"),ct=RegExp(ot),ft=RegExp("^"+nt+"$"),pt={ID:RegExp("^#("+tt+")"),CLASS:RegExp("^\\.("+tt+")"),NAME:RegExp("^\\[name=['\"]?("+tt+")['\"]?\\]"),TAG:RegExp("^("+tt.replace("w","w*")+")"),ATTR:RegExp("^"+it),PSEUDO:RegExp("^"+ot),CHILD:RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+et+"*(even|odd|(([+-]|)(\\d*)n|)"+et+"*(?:([+-]|)"+et+"*(\\d+)|))"+et+"*\\)|)","i"),needsContext:RegExp("^"+et+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+et+"*((?:-\\d)?\\d*)"+et+"*\\)|)(?=[^-]|$)","i")},dt=/[\x20\t\r\n\f]*[+~]/,ht=/\{\s*\[native code\]\s*\}/,gt=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,mt=/^(?:input|select|textarea|button)$/i,yt=/^h\d$/i,vt=/'|\\/g,bt=/\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g,xt=/\\([\da-fA-F]{1,6}[\x20\t\r\n\f]?|.)/g,Tt=function(e,t){var n="0x"+t-65536;return n!==n?t:0>n?String.fromCharCode(n+65536):String.fromCharCode(55296|n>>10,56320|1023&n)};try{K.call(H.childNodes,0)[0].nodeType}catch(wt){K=function(e){for(var t,n=[];t=this[e];e++)n.push(t);return n}}E=a.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return t?"HTML"!==t.nodeName:!1},D=a.setDocument=function(e){var r=e?e.ownerDocument||e:R;return r!==L&&9===r.nodeType&&r.documentElement?(L=r,H=r.documentElement,M=E(r),W.tagNameNoComments=o(function(e){return e.appendChild(r.createComment("")),!e.getElementsByTagName("*").length}),W.attributes=o(function(e){e.innerHTML="<select></select>";var t=typeof e.lastChild.getAttribute("multiple");return"boolean"!==t&&"string"!==t}),W.getByClassName=o(function(e){return e.innerHTML="<div class='hidden e'></div><div class='hidden'></div>",e.getElementsByClassName&&e.getElementsByClassName("e").length?(e.lastChild.className="e",2===e.getElementsByClassName("e").length):!1}),W.getByName=o(function(e){e.id=P+0,e.innerHTML="<a name='"+P+"'></a><div name='"+P+"'></div>",H.insertBefore(e,H.firstChild);var t=r.getElementsByName&&r.getElementsByName(P).length===2+r.getElementsByName(P+0).length;return W.getIdNotName=!r.getElementById(P),H.removeChild(e),t}),C.attrHandle=o(function(e){return e.innerHTML="<a href='#'></a>",e.firstChild&&typeof e.firstChild.getAttribute!==V&&"#"===e.firstChild.getAttribute("href")})?{}:{href:function(e){return e.getAttribute("href",2)},type:function(e){return e.getAttribute("type")}},W.getIdNotName?(C.find.ID=function(e,t){if(typeof t.getElementById!==V&&!M){var n=t.getElementById(e);return n&&n.parentNode?[n]:[]}},C.filter.ID=function(e){var t=e.replace(xt,Tt);return function(e){return e.getAttribute("id")===t}}):(C.find.ID=function(e,n){if(typeof n.getElementById!==V&&!M){var r=n.getElementById(e);return r?r.id===e||typeof r.getAttributeNode!==V&&r.getAttributeNode("id").value===e?[r]:t:[]}},C.filter.ID=function(e){var t=e.replace(xt,Tt);return function(e){var n=typeof e.getAttributeNode!==V&&e.getAttributeNode("id");return n&&n.value===t}}),C.find.TAG=W.tagNameNoComments?function(e,n){return typeof n.getElementsByTagName!==V?n.getElementsByTagName(e):t}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){for(;n=o[i];i++)1===n.nodeType&&r.push(n);return r}return o},C.find.NAME=W.getByName&&function(e,n){return typeof n.getElementsByName!==V?n.getElementsByName(name):t},C.find.CLASS=W.getByClassName&&function(e,n){return typeof n.getElementsByClassName===V||M?t:n.getElementsByClassName(e)},_=[],q=[":focus"],(W.qsa=n(r.querySelectorAll))&&(o(function(e){e.innerHTML="<select><option selected=''></option></select>",e.querySelectorAll("[selected]").length||q.push("\\["+et+"*(?:checked|disabled|ismap|multiple|readonly|selected|value)"),e.querySelectorAll(":checked").length||q.push(":checked")}),o(function(e){e.innerHTML="<input type='hidden' i=''/>",e.querySelectorAll("[i^='']").length&&q.push("[*^$]="+et+"*(?:\"\"|'')"),e.querySelectorAll(":enabled").length||q.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),q.push(",.*:")})),(W.matchesSelector=n(F=H.matchesSelector||H.mozMatchesSelector||H.webkitMatchesSelector||H.oMatchesSelector||H.msMatchesSelector))&&o(function(e){W.disconnectedMatch=F.call(e,"div"),F.call(e,"[s!='']:x"),_.push("!=",ot)}),q=RegExp(q.join("|")),_=RegExp(_.join("|")),O=n(H.contains)||H.compareDocumentPosition?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)for(;t=t.parentNode;)if(t===e)return!0;return!1},B=H.compareDocumentPosition?function(e,t){var n;return e===t?(A=!0,0):(n=t.compareDocumentPosition&&e.compareDocumentPosition&&e.compareDocumentPosition(t))?1&n||e.parentNode&&11===e.parentNode.nodeType?e===r||O(R,e)?-1:t===r||O(R,t)?1:0:4&n?-1:1:e.compareDocumentPosition?-1:1}:function(e,t){var n,i=0,o=e.parentNode,a=t.parentNode,u=[e],l=[t];if(e===t)return A=!0,0;if(e.sourceIndex&&t.sourceIndex)return(~t.sourceIndex||Y)-(O(R,e)&&~e.sourceIndex||Y);if(!o||!a)return e===r?-1:t===r?1:o?-1:a?1:0;if(o===a)return s(e,t);for(n=e;n=n.parentNode;)u.unshift(n);for(n=t;n=n.parentNode;)l.unshift(n);for(;u[i]===l[i];)i++;return i?s(u[i],l[i]):u[i]===R?-1:l[i]===R?1:0},A=!1,[0,0].sort(B),W.detectDuplicates=A,L):L},a.matches=function(e,t){return a(e,null,null,t)},a.matchesSelector=function(e,t){if((e.ownerDocument||e)!==L&&D(e),t=t.replace(bt,"='$1']"),!(!W.matchesSelector||M||_&&_.test(t)||q.test(t)))try{var n=F.call(e,t);if(n||W.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(r){}return a(t,L,null,[e]).length>0},a.contains=function(e,t){return(e.ownerDocument||e)!==L&&D(e),O(e,t)},a.attr=function(e,t){var n;return(e.ownerDocument||e)!==L&&D(e),M||(t=t.toLowerCase()),(n=C.attrHandle[t])?n(e):M||W.attributes?e.getAttribute(t):((n=e.getAttributeNode(t))||e.getAttribute(t))&&e[t]===!0?t:n&&n.specified?n.value:null},a.error=function(e){throw Error("Syntax error, unrecognized expression: "+e)},a.uniqueSort=function(e){var t,n=[],r=1,i=0;if(A=!W.detectDuplicates,e.sort(B),A){for(;t=e[r];r++)t===e[r-1]&&(i=n.push(r));for(;i--;)e.splice(n[i],1)}return e},k=a.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(1===i||9===i||11===i){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=k(e)}else if(3===i||4===i)return e.nodeValue}else for(;t=e[r];r++)n+=k(t);return n},C=a.selectors={cacheLength:50,createPseudo:i,match:pt,find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(xt,Tt),e[3]=(e[4]||e[5]||"").replace(xt,Tt),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||a.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&a.error(e[0]),e},PSEUDO:function(e){var t,n=!e[5]&&e[2];return pt.CHILD.test(e[0])?null:(e[4]?e[2]=e[4]:n&&ct.test(n)&&(t=f(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){return"*"===e?function(){return!0}:(e=e.replace(xt,Tt).toLowerCase(),function(t){return t.nodeName&&t.nodeName.toLowerCase()===e})},CLASS:function(e){var t=z[e+" "];return t||(t=RegExp("(^|"+et+")"+e+"("+et+"|$)"))&&z(e,function(e){return t.test(e.className||typeof e.getAttribute!==V&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r){var i=a.attr(r,e);return null==i?"!="===t:t?(i+="","="===t?i===n:"!="===t?i!==n:"^="===t?n&&0===i.indexOf(n):"*="===t?n&&i.indexOf(n)>-1:"$="===t?n&&i.substr(i.length-n.length)===n:"~="===t?(" "+i+" ").indexOf(n)>-1:"|="===t?i===n||i.substr(0,n.length+1)===n+"-":!1):!0}},CHILD:function(e,t,n,r,i){var o="nth"!==e.slice(0,3),a="last"!==e.slice(-4),s="of-type"===t;return 1===r&&0===i?function(e){return!!e.parentNode}:function(t,n,u){var l,c,f,p,d,h,g=o!==a?"nextSibling":"previousSibling",m=t.parentNode,y=s&&t.nodeName.toLowerCase(),v=!u&&!s;if(m){if(o){for(;g;){for(f=t;f=f[g];)if(s?f.nodeName.toLowerCase()===y:1===f.nodeType)return!1;h=g="only"===e&&!h&&"nextSibling"}return!0}if(h=[a?m.firstChild:m.lastChild],a&&v){for(c=m[P]||(m[P]={}),l=c[e]||[],d=l[0]===$&&l[1],p=l[0]===$&&l[2],f=d&&m.childNodes[d];f=++d&&f&&f[g]||(p=d=0)||h.pop();)if(1===f.nodeType&&++p&&f===t){c[e]=[$,d,p];break}}else if(v&&(l=(t[P]||(t[P]={}))[e])&&l[0]===$)p=l[1];else for(;(f=++d&&f&&f[g]||(p=d=0)||h.pop())&&((s?f.nodeName.toLowerCase()!==y:1!==f.nodeType)||!++p||(v&&((f[P]||(f[P]={}))[e]=[$,p]),f!==t)););return p-=i,p===r||0===p%r&&p/r>=0}}},PSEUDO:function(e,t){var n,r=C.pseudos[e]||C.setFilters[e.toLowerCase()]||a.error("unsupported pseudo: "+e);return r[P]?r(t):r.length>1?(n=[e,e,"",t],C.setFilters.hasOwnProperty(e.toLowerCase())?i(function(e,n){for(var i,o=r(e,t),a=o.length;a--;)i=Z.call(e,o[a]),e[i]=!(n[i]=o[a])}):function(e){return r(e,0,n)}):r}},pseudos:{not:i(function(e){var t=[],n=[],r=S(e.replace(at,"$1"));return r[P]?i(function(e,t,n,i){for(var o,a=r(e,null,i,[]),s=e.length;s--;)(o=a[s])&&(e[s]=!(t[s]=o))}):function(e,i,o){return t[0]=e,r(t,null,o,n),!n.pop()}}),has:i(function(e){return function(t){return a(e,t).length>0}}),contains:i(function(e){return function(t){return(t.textContent||t.innerText||k(t)).indexOf(e)>-1}}),lang:i(function(e){return ft.test(e||"")||a.error("unsupported lang: "+e),e=e.replace(xt,Tt).toLowerCase(),function(t){var n;do if(n=M?t.getAttribute("xml:lang")||t.getAttribute("lang"):t.lang)return n=n.toLowerCase(),n===e||0===n.indexOf(e+"-");while((t=t.parentNode)&&1===t.nodeType);return!1}}),target:function(t){var n=e.location&&e.location.hash;return n&&n.slice(1)===t.id},root:function(e){return e===H},focus:function(e){return e===L.activeElement&&(!L.hasFocus||L.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:function(e){return e.disabled===!1},disabled:function(e){return e.disabled===!0},checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,e.selected===!0},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeName>"@"||3===e.nodeType||4===e.nodeType)return!1;return!0},parent:function(e){return!C.pseudos.empty(e)},header:function(e){return yt.test(e.nodeName)},input:function(e){return mt.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||t.toLowerCase()===e.type)},first:c(function(){return[0]}),last:c(function(e,t){return[t-1]}),eq:c(function(e,t,n){return[0>n?n+t:n]}),even:c(function(e,t){for(var n=0;t>n;n+=2)e.push(n);return e}),odd:c(function(e,t){for(var n=1;t>n;n+=2)e.push(n);return e}),lt:c(function(e,t,n){for(var r=0>n?n+t:n;--r>=0;)e.push(r);return e}),gt:c(function(e,t,n){for(var r=0>n?n+t:n;t>++r;)e.push(r);return e})}};for(w in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})C.pseudos[w]=u(w);for(w in{submit:!0,reset:!0})C.pseudos[w]=l(w);S=a.compile=function(e,t){var n,r=[],i=[],o=U[e+" "];if(!o){for(t||(t=f(e)),n=t.length;n--;)o=y(t[n]),o[P]?r.push(o):i.push(o);o=U(e,v(i,r))}return o},C.pseudos.nth=C.pseudos.eq,C.filters=T.prototype=C.pseudos,C.setFilters=new T,D(),a.attr=st.attr,st.find=a,st.expr=a.selectors,st.expr[":"]=st.expr.pseudos,st.unique=a.uniqueSort,st.text=a.getText,st.isXMLDoc=a.isXML,st.contains=a.contains}(e);var Pt=/Until$/,Rt=/^(?:parents|prev(?:Until|All))/,Wt=/^.[^:#\[\.,]*$/,$t=st.expr.match.needsContext,It={children:!0,contents:!0,next:!0,prev:!0};st.fn.extend({find:function(e){var t,n,r;if("string"!=typeof e)return r=this,this.pushStack(st(e).filter(function(){for(t=0;r.length>t;t++)if(st.contains(r[t],this))return!0}));for(n=[],t=0;this.length>t;t++)st.find(e,this[t],n);return n=this.pushStack(st.unique(n)),n.selector=(this.selector?this.selector+" ":"")+e,n},has:function(e){var t,n=st(e,this),r=n.length;return this.filter(function(){for(t=0;r>t;t++)if(st.contains(this,n[t]))return!0})},not:function(e){return this.pushStack(f(this,e,!1))},filter:function(e){return this.pushStack(f(this,e,!0))},is:function(e){return!!e&&("string"==typeof e?$t.test(e)?st(e,this.context).index(this[0])>=0:st.filter(e,this).length>0:this.filter(e).length>0)},closest:function(e,t){for(var n,r=0,i=this.length,o=[],a=$t.test(e)||"string"!=typeof e?st(e,t||this.context):0;i>r;r++)for(n=this[r];n&&n.ownerDocument&&n!==t&&11!==n.nodeType;){if(a?a.index(n)>-1:st.find.matchesSelector(n,e)){o.push(n);break}n=n.parentNode}return this.pushStack(o.length>1?st.unique(o):o)},index:function(e){return e?"string"==typeof e?st.inArray(this[0],st(e)):st.inArray(e.jquery?e[0]:e,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){var n="string"==typeof e?st(e,t):st.makeArray(e&&e.nodeType?[e]:e),r=st.merge(this.get(),n);return this.pushStack(st.unique(r))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}}),st.fn.andSelf=st.fn.addBack,st.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return st.dir(e,"parentNode")},parentsUntil:function(e,t,n){return st.dir(e,"parentNode",n)},next:function(e){return c(e,"nextSibling")},prev:function(e){return c(e,"previousSibling") -},nextAll:function(e){return st.dir(e,"nextSibling")},prevAll:function(e){return st.dir(e,"previousSibling")},nextUntil:function(e,t,n){return st.dir(e,"nextSibling",n)},prevUntil:function(e,t,n){return st.dir(e,"previousSibling",n)},siblings:function(e){return st.sibling((e.parentNode||{}).firstChild,e)},children:function(e){return st.sibling(e.firstChild)},contents:function(e){return st.nodeName(e,"iframe")?e.contentDocument||e.contentWindow.document:st.merge([],e.childNodes)}},function(e,t){st.fn[e]=function(n,r){var i=st.map(this,t,n);return Pt.test(e)||(r=n),r&&"string"==typeof r&&(i=st.filter(r,i)),i=this.length>1&&!It[e]?st.unique(i):i,this.length>1&&Rt.test(e)&&(i=i.reverse()),this.pushStack(i)}}),st.extend({filter:function(e,t,n){return n&&(e=":not("+e+")"),1===t.length?st.find.matchesSelector(t[0],e)?[t[0]]:[]:st.find.matches(e,t)},dir:function(e,n,r){for(var i=[],o=e[n];o&&9!==o.nodeType&&(r===t||1!==o.nodeType||!st(o).is(r));)1===o.nodeType&&i.push(o),o=o[n];return i},sibling:function(e,t){for(var n=[];e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n}});var zt="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",Xt=/ jQuery\d+="(?:null|\d+)"/g,Ut=RegExp("<(?:"+zt+")[\\s/>]","i"),Vt=/^\s+/,Yt=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,Jt=/<([\w:]+)/,Gt=/<tbody/i,Qt=/<|&#?\w+;/,Kt=/<(?:script|style|link)/i,Zt=/^(?:checkbox|radio)$/i,en=/checked\s*(?:[^=]|=\s*.checked.)/i,tn=/^$|\/(?:java|ecma)script/i,nn=/^true\/(.*)/,rn=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,on={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],area:[1,"<map>","</map>"],param:[1,"<object>","</object>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:st.support.htmlSerialize?[0,"",""]:[1,"X<div>","</div>"]},an=p(V),sn=an.appendChild(V.createElement("div"));on.optgroup=on.option,on.tbody=on.tfoot=on.colgroup=on.caption=on.thead,on.th=on.td,st.fn.extend({text:function(e){return st.access(this,function(e){return e===t?st.text(this):this.empty().append((this[0]&&this[0].ownerDocument||V).createTextNode(e))},null,e,arguments.length)},wrapAll:function(e){if(st.isFunction(e))return this.each(function(t){st(this).wrapAll(e.call(this,t))});if(this[0]){var t=st(e,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){for(var e=this;e.firstChild&&1===e.firstChild.nodeType;)e=e.firstChild;return e}).append(this)}return this},wrapInner:function(e){return st.isFunction(e)?this.each(function(t){st(this).wrapInner(e.call(this,t))}):this.each(function(){var t=st(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=st.isFunction(e);return this.each(function(n){st(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(){return this.parent().each(function(){st.nodeName(this,"body")||st(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(e){(1===this.nodeType||11===this.nodeType||9===this.nodeType)&&this.appendChild(e)})},prepend:function(){return this.domManip(arguments,!0,function(e){(1===this.nodeType||11===this.nodeType||9===this.nodeType)&&this.insertBefore(e,this.firstChild)})},before:function(){return this.domManip(arguments,!1,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return this.domManip(arguments,!1,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},remove:function(e,t){for(var n,r=0;null!=(n=this[r]);r++)(!e||st.filter(e,[n]).length>0)&&(t||1!==n.nodeType||st.cleanData(b(n)),n.parentNode&&(t&&st.contains(n.ownerDocument,n)&&m(b(n,"script")),n.parentNode.removeChild(n)));return this},empty:function(){for(var e,t=0;null!=(e=this[t]);t++){for(1===e.nodeType&&st.cleanData(b(e,!1));e.firstChild;)e.removeChild(e.firstChild);e.options&&st.nodeName(e,"select")&&(e.options.length=0)}return this},clone:function(e,t){return e=null==e?!1:e,t=null==t?e:t,this.map(function(){return st.clone(this,e,t)})},html:function(e){return st.access(this,function(e){var n=this[0]||{},r=0,i=this.length;if(e===t)return 1===n.nodeType?n.innerHTML.replace(Xt,""):t;if(!("string"!=typeof e||Kt.test(e)||!st.support.htmlSerialize&&Ut.test(e)||!st.support.leadingWhitespace&&Vt.test(e)||on[(Jt.exec(e)||["",""])[1].toLowerCase()])){e=e.replace(Yt,"<$1></$2>");try{for(;i>r;r++)n=this[r]||{},1===n.nodeType&&(st.cleanData(b(n,!1)),n.innerHTML=e);n=0}catch(o){}}n&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(e){var t=st.isFunction(e);return t||"string"==typeof e||(e=st(e).not(this).detach()),this.domManip([e],!0,function(e){var t=this.nextSibling,n=this.parentNode;(n&&1===this.nodeType||11===this.nodeType)&&(st(this).remove(),t?t.parentNode.insertBefore(e,t):n.appendChild(e))})},detach:function(e){return this.remove(e,!0)},domManip:function(e,n,r){e=et.apply([],e);var i,o,a,s,u,l,c=0,f=this.length,p=this,m=f-1,y=e[0],v=st.isFunction(y);if(v||!(1>=f||"string"!=typeof y||st.support.checkClone)&&en.test(y))return this.each(function(i){var o=p.eq(i);v&&(e[0]=y.call(this,i,n?o.html():t)),o.domManip(e,n,r)});if(f&&(i=st.buildFragment(e,this[0].ownerDocument,!1,this),o=i.firstChild,1===i.childNodes.length&&(i=o),o)){for(n=n&&st.nodeName(o,"tr"),a=st.map(b(i,"script"),h),s=a.length;f>c;c++)u=i,c!==m&&(u=st.clone(u,!0,!0),s&&st.merge(a,b(u,"script"))),r.call(n&&st.nodeName(this[c],"table")?d(this[c],"tbody"):this[c],u,c);if(s)for(l=a[a.length-1].ownerDocument,st.map(a,g),c=0;s>c;c++)u=a[c],tn.test(u.type||"")&&!st._data(u,"globalEval")&&st.contains(l,u)&&(u.src?st.ajax({url:u.src,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0}):st.globalEval((u.text||u.textContent||u.innerHTML||"").replace(rn,"")));i=o=null}return this}}),st.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(e,t){st.fn[e]=function(e){for(var n,r=0,i=[],o=st(e),a=o.length-1;a>=r;r++)n=r===a?this:this.clone(!0),st(o[r])[t](n),tt.apply(i,n.get());return this.pushStack(i)}}),st.extend({clone:function(e,t,n){var r,i,o,a,s,u=st.contains(e.ownerDocument,e);if(st.support.html5Clone||st.isXMLDoc(e)||!Ut.test("<"+e.nodeName+">")?s=e.cloneNode(!0):(sn.innerHTML=e.outerHTML,sn.removeChild(s=sn.firstChild)),!(st.support.noCloneEvent&&st.support.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||st.isXMLDoc(e)))for(r=b(s),i=b(e),a=0;null!=(o=i[a]);++a)r[a]&&v(o,r[a]);if(t)if(n)for(i=i||b(e),r=r||b(s),a=0;null!=(o=i[a]);a++)y(o,r[a]);else y(e,s);return r=b(s,"script"),r.length>0&&m(r,!u&&b(e,"script")),r=i=o=null,s},buildFragment:function(e,t,n,r){for(var i,o,a,s,u,l,c,f=e.length,d=p(t),h=[],g=0;f>g;g++)if(o=e[g],o||0===o)if("object"===st.type(o))st.merge(h,o.nodeType?[o]:o);else if(Qt.test(o)){for(s=s||d.appendChild(t.createElement("div")),a=(Jt.exec(o)||["",""])[1].toLowerCase(),u=on[a]||on._default,s.innerHTML=u[1]+o.replace(Yt,"<$1></$2>")+u[2],c=u[0];c--;)s=s.lastChild;if(!st.support.leadingWhitespace&&Vt.test(o)&&h.push(t.createTextNode(Vt.exec(o)[0])),!st.support.tbody)for(o="table"!==a||Gt.test(o)?"<table>"!==u[1]||Gt.test(o)?0:s:s.firstChild,c=o&&o.childNodes.length;c--;)st.nodeName(l=o.childNodes[c],"tbody")&&!l.childNodes.length&&o.removeChild(l);for(st.merge(h,s.childNodes),s.textContent="";s.firstChild;)s.removeChild(s.firstChild);s=d.lastChild}else h.push(t.createTextNode(o));for(s&&d.removeChild(s),st.support.appendChecked||st.grep(b(h,"input"),x),g=0;o=h[g++];)if((!r||-1===st.inArray(o,r))&&(i=st.contains(o.ownerDocument,o),s=b(d.appendChild(o),"script"),i&&m(s),n))for(c=0;o=s[c++];)tn.test(o.type||"")&&n.push(o);return s=null,d},cleanData:function(e,n){for(var r,i,o,a,s=0,u=st.expando,l=st.cache,c=st.support.deleteExpando,f=st.event.special;null!=(o=e[s]);s++)if((n||st.acceptData(o))&&(i=o[u],r=i&&l[i])){if(r.events)for(a in r.events)f[a]?st.event.remove(o,a):st.removeEvent(o,a,r.handle);l[i]&&(delete l[i],c?delete o[u]:o.removeAttribute!==t?o.removeAttribute(u):o[u]=null,K.push(i))}}});var un,ln,cn,fn=/alpha\([^)]*\)/i,pn=/opacity\s*=\s*([^)]*)/,dn=/^(top|right|bottom|left)$/,hn=/^(none|table(?!-c[ea]).+)/,gn=/^margin/,mn=RegExp("^("+ut+")(.*)$","i"),yn=RegExp("^("+ut+")(?!px)[a-z%]+$","i"),vn=RegExp("^([+-])=("+ut+")","i"),bn={BODY:"block"},xn={position:"absolute",visibility:"hidden",display:"block"},Tn={letterSpacing:0,fontWeight:400},wn=["Top","Right","Bottom","Left"],Nn=["Webkit","O","Moz","ms"];st.fn.extend({css:function(e,n){return st.access(this,function(e,n,r){var i,o,a={},s=0;if(st.isArray(n)){for(i=ln(e),o=n.length;o>s;s++)a[n[s]]=st.css(e,n[s],!1,i);return a}return r!==t?st.style(e,n,r):st.css(e,n)},e,n,arguments.length>1)},show:function(){return N(this,!0)},hide:function(){return N(this)},toggle:function(e){var t="boolean"==typeof e;return this.each(function(){(t?e:w(this))?st(this).show():st(this).hide()})}}),st.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=un(e,"opacity");return""===n?"1":n}}}},cssNumber:{columnCount:!0,fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":st.support.cssFloat?"cssFloat":"styleFloat"},style:function(e,n,r,i){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var o,a,s,u=st.camelCase(n),l=e.style;if(n=st.cssProps[u]||(st.cssProps[u]=T(l,u)),s=st.cssHooks[n]||st.cssHooks[u],r===t)return s&&"get"in s&&(o=s.get(e,!1,i))!==t?o:l[n];if(a=typeof r,"string"===a&&(o=vn.exec(r))&&(r=(o[1]+1)*o[2]+parseFloat(st.css(e,n)),a="number"),!(null==r||"number"===a&&isNaN(r)||("number"!==a||st.cssNumber[u]||(r+="px"),st.support.clearCloneStyle||""!==r||0!==n.indexOf("background")||(l[n]="inherit"),s&&"set"in s&&(r=s.set(e,r,i))===t)))try{l[n]=r}catch(c){}}},css:function(e,n,r,i){var o,a,s,u=st.camelCase(n);return n=st.cssProps[u]||(st.cssProps[u]=T(e.style,u)),s=st.cssHooks[n]||st.cssHooks[u],s&&"get"in s&&(o=s.get(e,!0,r)),o===t&&(o=un(e,n,i)),"normal"===o&&n in Tn&&(o=Tn[n]),r?(a=parseFloat(o),r===!0||st.isNumeric(a)?a||0:o):o},swap:function(e,t,n,r){var i,o,a={};for(o in t)a[o]=e.style[o],e.style[o]=t[o];i=n.apply(e,r||[]);for(o in t)e.style[o]=a[o];return i}}),e.getComputedStyle?(ln=function(t){return e.getComputedStyle(t,null)},un=function(e,n,r){var i,o,a,s=r||ln(e),u=s?s.getPropertyValue(n)||s[n]:t,l=e.style;return s&&(""!==u||st.contains(e.ownerDocument,e)||(u=st.style(e,n)),yn.test(u)&&gn.test(n)&&(i=l.width,o=l.minWidth,a=l.maxWidth,l.minWidth=l.maxWidth=l.width=u,u=s.width,l.width=i,l.minWidth=o,l.maxWidth=a)),u}):V.documentElement.currentStyle&&(ln=function(e){return e.currentStyle},un=function(e,n,r){var i,o,a,s=r||ln(e),u=s?s[n]:t,l=e.style;return null==u&&l&&l[n]&&(u=l[n]),yn.test(u)&&!dn.test(n)&&(i=l.left,o=e.runtimeStyle,a=o&&o.left,a&&(o.left=e.currentStyle.left),l.left="fontSize"===n?"1em":u,u=l.pixelLeft+"px",l.left=i,a&&(o.left=a)),""===u?"auto":u}),st.each(["height","width"],function(e,n){st.cssHooks[n]={get:function(e,r,i){return r?0===e.offsetWidth&&hn.test(st.css(e,"display"))?st.swap(e,xn,function(){return E(e,n,i)}):E(e,n,i):t},set:function(e,t,r){var i=r&&ln(e);return C(e,t,r?k(e,n,r,st.support.boxSizing&&"border-box"===st.css(e,"boxSizing",!1,i),i):0)}}}),st.support.opacity||(st.cssHooks.opacity={get:function(e,t){return pn.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=st.isNumeric(t)?"alpha(opacity="+100*t+")":"",o=r&&r.filter||n.filter||"";n.zoom=1,(t>=1||""===t)&&""===st.trim(o.replace(fn,""))&&n.removeAttribute&&(n.removeAttribute("filter"),""===t||r&&!r.filter)||(n.filter=fn.test(o)?o.replace(fn,i):o+" "+i)}}),st(function(){st.support.reliableMarginRight||(st.cssHooks.marginRight={get:function(e,n){return n?st.swap(e,{display:"inline-block"},un,[e,"marginRight"]):t}}),!st.support.pixelPosition&&st.fn.position&&st.each(["top","left"],function(e,n){st.cssHooks[n]={get:function(e,r){return r?(r=un(e,n),yn.test(r)?st(e).position()[n]+"px":r):t}}})}),st.expr&&st.expr.filters&&(st.expr.filters.hidden=function(e){return 0===e.offsetWidth&&0===e.offsetHeight||!st.support.reliableHiddenOffsets&&"none"===(e.style&&e.style.display||st.css(e,"display"))},st.expr.filters.visible=function(e){return!st.expr.filters.hidden(e)}),st.each({margin:"",padding:"",border:"Width"},function(e,t){st.cssHooks[e+t]={expand:function(n){for(var r=0,i={},o="string"==typeof n?n.split(" "):[n];4>r;r++)i[e+wn[r]+t]=o[r]||o[r-2]||o[0];return i}},gn.test(e)||(st.cssHooks[e+t].set=C)});var Cn=/%20/g,kn=/\[\]$/,En=/\r?\n/g,Sn=/^(?:submit|button|image|reset)$/i,An=/^(?:input|select|textarea|keygen)/i;st.fn.extend({serialize:function(){return st.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var e=st.prop(this,"elements");return e?st.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!st(this).is(":disabled")&&An.test(this.nodeName)&&!Sn.test(e)&&(this.checked||!Zt.test(e))}).map(function(e,t){var n=st(this).val();return null==n?null:st.isArray(n)?st.map(n,function(e){return{name:t.name,value:e.replace(En,"\r\n")}}):{name:t.name,value:n.replace(En,"\r\n")}}).get()}}),st.param=function(e,n){var r,i=[],o=function(e,t){t=st.isFunction(t)?t():null==t?"":t,i[i.length]=encodeURIComponent(e)+"="+encodeURIComponent(t)};if(n===t&&(n=st.ajaxSettings&&st.ajaxSettings.traditional),st.isArray(e)||e.jquery&&!st.isPlainObject(e))st.each(e,function(){o(this.name,this.value)});else for(r in e)j(r,e[r],n,o);return i.join("&").replace(Cn,"+")};var jn,Dn,Ln=st.now(),Hn=/\?/,Mn=/#.*$/,qn=/([?&])_=[^&]*/,_n=/^(.*?):[ \t]*([^\r\n]*)\r?$/gm,Fn=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,On=/^(?:GET|HEAD)$/,Bn=/^\/\//,Pn=/^([\w.+-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,Rn=st.fn.load,Wn={},$n={},In="*/".concat("*");try{Dn=Y.href}catch(zn){Dn=V.createElement("a"),Dn.href="",Dn=Dn.href}jn=Pn.exec(Dn.toLowerCase())||[],st.fn.load=function(e,n,r){if("string"!=typeof e&&Rn)return Rn.apply(this,arguments);var i,o,a,s=this,u=e.indexOf(" ");return u>=0&&(i=e.slice(u,e.length),e=e.slice(0,u)),st.isFunction(n)?(r=n,n=t):n&&"object"==typeof n&&(o="POST"),s.length>0&&st.ajax({url:e,type:o,dataType:"html",data:n}).done(function(e){a=arguments,s.html(i?st("<div>").append(st.parseHTML(e)).find(i):e)}).complete(r&&function(e,t){s.each(r,a||[e.responseText,t,e])}),this},st.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){st.fn[t]=function(e){return this.on(t,e)}}),st.each(["get","post"],function(e,n){st[n]=function(e,r,i,o){return st.isFunction(r)&&(o=o||i,i=r,r=t),st.ajax({url:e,type:n,dataType:o,data:r,success:i})}}),st.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:Dn,type:"GET",isLocal:Fn.test(jn[1]),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":In,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":e.String,"text html":!0,"text json":st.parseJSON,"text xml":st.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?H(H(e,st.ajaxSettings),t):H(st.ajaxSettings,e)},ajaxPrefilter:D(Wn),ajaxTransport:D($n),ajax:function(e,n){function r(e,n,r,s){var l,f,v,b,T,N=n;2!==x&&(x=2,u&&clearTimeout(u),i=t,a=s||"",w.readyState=e>0?4:0,r&&(b=M(p,w,r)),e>=200&&300>e||304===e?(p.ifModified&&(T=w.getResponseHeader("Last-Modified"),T&&(st.lastModified[o]=T),T=w.getResponseHeader("etag"),T&&(st.etag[o]=T)),304===e?(l=!0,N="notmodified"):(l=q(p,b),N=l.state,f=l.data,v=l.error,l=!v)):(v=N,(e||!N)&&(N="error",0>e&&(e=0))),w.status=e,w.statusText=(n||N)+"",l?g.resolveWith(d,[f,N,w]):g.rejectWith(d,[w,N,v]),w.statusCode(y),y=t,c&&h.trigger(l?"ajaxSuccess":"ajaxError",[w,p,l?f:v]),m.fireWith(d,[w,N]),c&&(h.trigger("ajaxComplete",[w,p]),--st.active||st.event.trigger("ajaxStop")))}"object"==typeof e&&(n=e,e=t),n=n||{};var i,o,a,s,u,l,c,f,p=st.ajaxSetup({},n),d=p.context||p,h=p.context&&(d.nodeType||d.jquery)?st(d):st.event,g=st.Deferred(),m=st.Callbacks("once memory"),y=p.statusCode||{},v={},b={},x=0,T="canceled",w={readyState:0,getResponseHeader:function(e){var t;if(2===x){if(!s)for(s={};t=_n.exec(a);)s[t[1].toLowerCase()]=t[2];t=s[e.toLowerCase()]}return null==t?null:t},getAllResponseHeaders:function(){return 2===x?a:null},setRequestHeader:function(e,t){var n=e.toLowerCase();return x||(e=b[n]=b[n]||e,v[e]=t),this},overrideMimeType:function(e){return x||(p.mimeType=e),this},statusCode:function(e){var t;if(e)if(2>x)for(t in e)y[t]=[y[t],e[t]];else w.always(e[w.status]);return this},abort:function(e){var t=e||T;return i&&i.abort(t),r(0,t),this}};if(g.promise(w).complete=m.add,w.success=w.done,w.error=w.fail,p.url=((e||p.url||Dn)+"").replace(Mn,"").replace(Bn,jn[1]+"//"),p.type=n.method||n.type||p.method||p.type,p.dataTypes=st.trim(p.dataType||"*").toLowerCase().match(lt)||[""],null==p.crossDomain&&(l=Pn.exec(p.url.toLowerCase()),p.crossDomain=!(!l||l[1]===jn[1]&&l[2]===jn[2]&&(l[3]||("http:"===l[1]?80:443))==(jn[3]||("http:"===jn[1]?80:443)))),p.data&&p.processData&&"string"!=typeof p.data&&(p.data=st.param(p.data,p.traditional)),L(Wn,p,n,w),2===x)return w;c=p.global,c&&0===st.active++&&st.event.trigger("ajaxStart"),p.type=p.type.toUpperCase(),p.hasContent=!On.test(p.type),o=p.url,p.hasContent||(p.data&&(o=p.url+=(Hn.test(o)?"&":"?")+p.data,delete p.data),p.cache===!1&&(p.url=qn.test(o)?o.replace(qn,"$1_="+Ln++):o+(Hn.test(o)?"&":"?")+"_="+Ln++)),p.ifModified&&(st.lastModified[o]&&w.setRequestHeader("If-Modified-Since",st.lastModified[o]),st.etag[o]&&w.setRequestHeader("If-None-Match",st.etag[o])),(p.data&&p.hasContent&&p.contentType!==!1||n.contentType)&&w.setRequestHeader("Content-Type",p.contentType),w.setRequestHeader("Accept",p.dataTypes[0]&&p.accepts[p.dataTypes[0]]?p.accepts[p.dataTypes[0]]+("*"!==p.dataTypes[0]?", "+In+"; q=0.01":""):p.accepts["*"]);for(f in p.headers)w.setRequestHeader(f,p.headers[f]);if(p.beforeSend&&(p.beforeSend.call(d,w,p)===!1||2===x))return w.abort();T="abort";for(f in{success:1,error:1,complete:1})w[f](p[f]);if(i=L($n,p,n,w)){w.readyState=1,c&&h.trigger("ajaxSend",[w,p]),p.async&&p.timeout>0&&(u=setTimeout(function(){w.abort("timeout")},p.timeout));try{x=1,i.send(v,r)}catch(N){if(!(2>x))throw N;r(-1,N)}}else r(-1,"No Transport");return w},getScript:function(e,n){return st.get(e,t,n,"script")},getJSON:function(e,t,n){return st.get(e,t,n,"json")}}),st.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/(?:java|ecma)script/},converters:{"text script":function(e){return st.globalEval(e),e}}}),st.ajaxPrefilter("script",function(e){e.cache===t&&(e.cache=!1),e.crossDomain&&(e.type="GET",e.global=!1)}),st.ajaxTransport("script",function(e){if(e.crossDomain){var n,r=V.head||st("head")[0]||V.documentElement;return{send:function(t,i){n=V.createElement("script"),n.async=!0,e.scriptCharset&&(n.charset=e.scriptCharset),n.src=e.url,n.onload=n.onreadystatechange=function(e,t){(t||!n.readyState||/loaded|complete/.test(n.readyState))&&(n.onload=n.onreadystatechange=null,n.parentNode&&n.parentNode.removeChild(n),n=null,t||i(200,"success"))},r.insertBefore(n,r.firstChild)},abort:function(){n&&n.onload(t,!0)}}}});var Xn=[],Un=/(=)\?(?=&|$)|\?\?/;st.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Xn.pop()||st.expando+"_"+Ln++;return this[e]=!0,e}}),st.ajaxPrefilter("json jsonp",function(n,r,i){var o,a,s,u=n.jsonp!==!1&&(Un.test(n.url)?"url":"string"==typeof n.data&&!(n.contentType||"").indexOf("application/x-www-form-urlencoded")&&Un.test(n.data)&&"data");return u||"jsonp"===n.dataTypes[0]?(o=n.jsonpCallback=st.isFunction(n.jsonpCallback)?n.jsonpCallback():n.jsonpCallback,u?n[u]=n[u].replace(Un,"$1"+o):n.jsonp!==!1&&(n.url+=(Hn.test(n.url)?"&":"?")+n.jsonp+"="+o),n.converters["script json"]=function(){return s||st.error(o+" was not called"),s[0]},n.dataTypes[0]="json",a=e[o],e[o]=function(){s=arguments},i.always(function(){e[o]=a,n[o]&&(n.jsonpCallback=r.jsonpCallback,Xn.push(o)),s&&st.isFunction(a)&&a(s[0]),s=a=t}),"script"):t});var Vn,Yn,Jn=0,Gn=e.ActiveXObject&&function(){var e;for(e in Vn)Vn[e](t,!0)};st.ajaxSettings.xhr=e.ActiveXObject?function(){return!this.isLocal&&_()||F()}:_,Yn=st.ajaxSettings.xhr(),st.support.cors=!!Yn&&"withCredentials"in Yn,Yn=st.support.ajax=!!Yn,Yn&&st.ajaxTransport(function(n){if(!n.crossDomain||st.support.cors){var r;return{send:function(i,o){var a,s,u=n.xhr();if(n.username?u.open(n.type,n.url,n.async,n.username,n.password):u.open(n.type,n.url,n.async),n.xhrFields)for(s in n.xhrFields)u[s]=n.xhrFields[s];n.mimeType&&u.overrideMimeType&&u.overrideMimeType(n.mimeType),n.crossDomain||i["X-Requested-With"]||(i["X-Requested-With"]="XMLHttpRequest");try{for(s in i)u.setRequestHeader(s,i[s])}catch(l){}u.send(n.hasContent&&n.data||null),r=function(e,i){var s,l,c,f,p;try{if(r&&(i||4===u.readyState))if(r=t,a&&(u.onreadystatechange=st.noop,Gn&&delete Vn[a]),i)4!==u.readyState&&u.abort();else{f={},s=u.status,p=u.responseXML,c=u.getAllResponseHeaders(),p&&p.documentElement&&(f.xml=p),"string"==typeof u.responseText&&(f.text=u.responseText);try{l=u.statusText}catch(d){l=""}s||!n.isLocal||n.crossDomain?1223===s&&(s=204):s=f.text?200:404}}catch(h){i||o(-1,h)}f&&o(s,l,f,c)},n.async?4===u.readyState?setTimeout(r):(a=++Jn,Gn&&(Vn||(Vn={},st(e).unload(Gn)),Vn[a]=r),u.onreadystatechange=r):r()},abort:function(){r&&r(t,!0)}}}});var Qn,Kn,Zn=/^(?:toggle|show|hide)$/,er=RegExp("^(?:([+-])=|)("+ut+")([a-z%]*)$","i"),tr=/queueHooks$/,nr=[W],rr={"*":[function(e,t){var n,r,i=this.createTween(e,t),o=er.exec(t),a=i.cur(),s=+a||0,u=1,l=20;if(o){if(n=+o[2],r=o[3]||(st.cssNumber[e]?"":"px"),"px"!==r&&s){s=st.css(i.elem,e,!0)||n||1;do u=u||".5",s/=u,st.style(i.elem,e,s+r);while(u!==(u=i.cur()/a)&&1!==u&&--l)}i.unit=r,i.start=s,i.end=o[1]?s+(o[1]+1)*n:n}return i}]};st.Animation=st.extend(P,{tweener:function(e,t){st.isFunction(e)?(t=e,e=["*"]):e=e.split(" ");for(var n,r=0,i=e.length;i>r;r++)n=e[r],rr[n]=rr[n]||[],rr[n].unshift(t)},prefilter:function(e,t){t?nr.unshift(e):nr.push(e)}}),st.Tween=$,$.prototype={constructor:$,init:function(e,t,n,r,i,o){this.elem=e,this.prop=n,this.easing=i||"swing",this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=o||(st.cssNumber[n]?"":"px")},cur:function(){var e=$.propHooks[this.prop];return e&&e.get?e.get(this):$.propHooks._default.get(this)},run:function(e){var t,n=$.propHooks[this.prop];return this.pos=t=this.options.duration?st.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):$.propHooks._default.set(this),this}},$.prototype.init.prototype=$.prototype,$.propHooks={_default:{get:function(e){var t;return null==e.elem[e.prop]||e.elem.style&&null!=e.elem.style[e.prop]?(t=st.css(e.elem,e.prop,"auto"),t&&"auto"!==t?t:0):e.elem[e.prop]},set:function(e){st.fx.step[e.prop]?st.fx.step[e.prop](e):e.elem.style&&(null!=e.elem.style[st.cssProps[e.prop]]||st.cssHooks[e.prop])?st.style(e.elem,e.prop,e.now+e.unit):e.elem[e.prop]=e.now}}},$.propHooks.scrollTop=$.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},st.each(["toggle","show","hide"],function(e,t){var n=st.fn[t];st.fn[t]=function(e,r,i){return null==e||"boolean"==typeof e?n.apply(this,arguments):this.animate(I(t,!0),e,r,i)}}),st.fn.extend({fadeTo:function(e,t,n,r){return this.filter(w).css("opacity",0).show().end().animate({opacity:t},e,n,r)},animate:function(e,t,n,r){var i=st.isEmptyObject(e),o=st.speed(t,n,r),a=function(){var t=P(this,st.extend({},e),o);a.finish=function(){t.stop(!0)},(i||st._data(this,"finish"))&&t.stop(!0)};return a.finish=a,i||o.queue===!1?this.each(a):this.queue(o.queue,a)},stop:function(e,n,r){var i=function(e){var t=e.stop;delete e.stop,t(r)};return"string"!=typeof e&&(r=n,n=e,e=t),n&&e!==!1&&this.queue(e||"fx",[]),this.each(function(){var t=!0,n=null!=e&&e+"queueHooks",o=st.timers,a=st._data(this);if(n)a[n]&&a[n].stop&&i(a[n]);else for(n in a)a[n]&&a[n].stop&&tr.test(n)&&i(a[n]);for(n=o.length;n--;)o[n].elem!==this||null!=e&&o[n].queue!==e||(o[n].anim.stop(r),t=!1,o.splice(n,1));(t||!r)&&st.dequeue(this,e)})},finish:function(e){return e!==!1&&(e=e||"fx"),this.each(function(){var t,n=st._data(this),r=n[e+"queue"],i=n[e+"queueHooks"],o=st.timers,a=r?r.length:0;for(n.finish=!0,st.queue(this,e,[]),i&&i.cur&&i.cur.finish&&i.cur.finish.call(this),t=o.length;t--;)o[t].elem===this&&o[t].queue===e&&(o[t].anim.stop(!0),o.splice(t,1));for(t=0;a>t;t++)r[t]&&r[t].finish&&r[t].finish.call(this);delete n.finish})}}),st.each({slideDown:I("show"),slideUp:I("hide"),slideToggle:I("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(e,t){st.fn[e]=function(e,n,r){return this.animate(t,e,n,r)}}),st.speed=function(e,t,n){var r=e&&"object"==typeof e?st.extend({},e):{complete:n||!n&&t||st.isFunction(e)&&e,duration:e,easing:n&&t||t&&!st.isFunction(t)&&t};return r.duration=st.fx.off?0:"number"==typeof r.duration?r.duration:r.duration in st.fx.speeds?st.fx.speeds[r.duration]:st.fx.speeds._default,(null==r.queue||r.queue===!0)&&(r.queue="fx"),r.old=r.complete,r.complete=function(){st.isFunction(r.old)&&r.old.call(this),r.queue&&st.dequeue(this,r.queue)},r},st.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2}},st.timers=[],st.fx=$.prototype.init,st.fx.tick=function(){var e,n=st.timers,r=0;for(Qn=st.now();n.length>r;r++)e=n[r],e()||n[r]!==e||n.splice(r--,1);n.length||st.fx.stop(),Qn=t},st.fx.timer=function(e){e()&&st.timers.push(e)&&st.fx.start()},st.fx.interval=13,st.fx.start=function(){Kn||(Kn=setInterval(st.fx.tick,st.fx.interval))},st.fx.stop=function(){clearInterval(Kn),Kn=null},st.fx.speeds={slow:600,fast:200,_default:400},st.fx.step={},st.expr&&st.expr.filters&&(st.expr.filters.animated=function(e){return st.grep(st.timers,function(t){return e===t.elem}).length}),st.fn.offset=function(e){if(arguments.length)return e===t?this:this.each(function(t){st.offset.setOffset(this,e,t)});var n,r,i={top:0,left:0},o=this[0],a=o&&o.ownerDocument;if(a)return n=a.documentElement,st.contains(n,o)?(o.getBoundingClientRect!==t&&(i=o.getBoundingClientRect()),r=z(a),{top:i.top+(r.pageYOffset||n.scrollTop)-(n.clientTop||0),left:i.left+(r.pageXOffset||n.scrollLeft)-(n.clientLeft||0)}):i},st.offset={setOffset:function(e,t,n){var r=st.css(e,"position");"static"===r&&(e.style.position="relative");var i,o,a=st(e),s=a.offset(),u=st.css(e,"top"),l=st.css(e,"left"),c=("absolute"===r||"fixed"===r)&&st.inArray("auto",[u,l])>-1,f={},p={};c?(p=a.position(),i=p.top,o=p.left):(i=parseFloat(u)||0,o=parseFloat(l)||0),st.isFunction(t)&&(t=t.call(e,n,s)),null!=t.top&&(f.top=t.top-s.top+i),null!=t.left&&(f.left=t.left-s.left+o),"using"in t?t.using.call(e,f):a.css(f)}},st.fn.extend({position:function(){if(this[0]){var e,t,n={top:0,left:0},r=this[0];return"fixed"===st.css(r,"position")?t=r.getBoundingClientRect():(e=this.offsetParent(),t=this.offset(),st.nodeName(e[0],"html")||(n=e.offset()),n.top+=st.css(e[0],"borderTopWidth",!0),n.left+=st.css(e[0],"borderLeftWidth",!0)),{top:t.top-n.top-st.css(r,"marginTop",!0),left:t.left-n.left-st.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){for(var e=this.offsetParent||V.documentElement;e&&!st.nodeName(e,"html")&&"static"===st.css(e,"position");)e=e.offsetParent;return e||V.documentElement})}}),st.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(e,n){var r=/Y/.test(n);st.fn[e]=function(i){return st.access(this,function(e,i,o){var a=z(e);return o===t?a?n in a?a[n]:a.document.documentElement[i]:e[i]:(a?a.scrollTo(r?st(a).scrollLeft():o,r?o:st(a).scrollTop()):e[i]=o,t)},e,i,arguments.length,null)}}),st.each({Height:"height",Width:"width"},function(e,n){st.each({padding:"inner"+e,content:n,"":"outer"+e},function(r,i){st.fn[i]=function(i,o){var a=arguments.length&&(r||"boolean"!=typeof i),s=r||(i===!0||o===!0?"margin":"border");return st.access(this,function(n,r,i){var o;return st.isWindow(n)?n.document.documentElement["client"+e]:9===n.nodeType?(o=n.documentElement,Math.max(n.body["scroll"+e],o["scroll"+e],n.body["offset"+e],o["offset"+e],o["client"+e])):i===t?st.css(n,r,s):st.style(n,r,i,s)},n,a?i:t,a,null)}})}),e.jQuery=e.$=st,"function"==typeof define&&define.amd&&define.amd.jQuery&&define("jquery",[],function(){return st})})(window); -//@ sourceMappingURL=jquery.min.map \ No newline at end of file +/*! jQuery v1.9.1 | (c) 2005, 2012 jQuery Foundation, Inc. | jquery.org/license +//@ sourceMappingURL=jquery.min.map +*/(function(e,t){var n,r,i=typeof t,o=e.document,a=e.location,s=e.jQuery,u=e.$,l={},c=[],p="1.9.1",f=c.concat,d=c.push,h=c.slice,g=c.indexOf,m=l.toString,y=l.hasOwnProperty,v=p.trim,b=function(e,t){return new b.fn.init(e,t,r)},x=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,w=/\S+/g,T=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,N=/^(?:(<[\w\W]+>)[^>]*|#([\w-]*))$/,C=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,k=/^[\],:{}\s]*$/,E=/(?:^|:|,)(?:\s*\[)+/g,S=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,A=/"[^"\\\r\n]*"|true|false|null|-?(?:\d+\.|)\d+(?:[eE][+-]?\d+|)/g,j=/^-ms-/,D=/-([\da-z])/gi,L=function(e,t){return t.toUpperCase()},H=function(e){(o.addEventListener||"load"===e.type||"complete"===o.readyState)&&(q(),b.ready())},q=function(){o.addEventListener?(o.removeEventListener("DOMContentLoaded",H,!1),e.removeEventListener("load",H,!1)):(o.detachEvent("onreadystatechange",H),e.detachEvent("onload",H))};b.fn=b.prototype={jquery:p,constructor:b,init:function(e,n,r){var i,a;if(!e)return this;if("string"==typeof e){if(i="<"===e.charAt(0)&&">"===e.charAt(e.length-1)&&e.length>=3?[null,e,null]:N.exec(e),!i||!i[1]&&n)return!n||n.jquery?(n||r).find(e):this.constructor(n).find(e);if(i[1]){if(n=n instanceof b?n[0]:n,b.merge(this,b.parseHTML(i[1],n&&n.nodeType?n.ownerDocument||n:o,!0)),C.test(i[1])&&b.isPlainObject(n))for(i in n)b.isFunction(this[i])?this[i](n[i]):this.attr(i,n[i]);return this}if(a=o.getElementById(i[2]),a&&a.parentNode){if(a.id!==i[2])return r.find(e);this.length=1,this[0]=a}return this.context=o,this.selector=e,this}return e.nodeType?(this.context=this[0]=e,this.length=1,this):b.isFunction(e)?r.ready(e):(e.selector!==t&&(this.selector=e.selector,this.context=e.context),b.makeArray(e,this))},selector:"",length:0,size:function(){return this.length},toArray:function(){return h.call(this)},get:function(e){return null==e?this.toArray():0>e?this[this.length+e]:this[e]},pushStack:function(e){var t=b.merge(this.constructor(),e);return t.prevObject=this,t.context=this.context,t},each:function(e,t){return b.each(this,e,t)},ready:function(e){return b.ready.promise().done(e),this},slice:function(){return this.pushStack(h.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(0>e?t:0);return this.pushStack(n>=0&&t>n?[this[n]]:[])},map:function(e){return this.pushStack(b.map(this,function(t,n){return e.call(t,n,t)}))},end:function(){return this.prevObject||this.constructor(null)},push:d,sort:[].sort,splice:[].splice},b.fn.init.prototype=b.fn,b.extend=b.fn.extend=function(){var e,n,r,i,o,a,s=arguments[0]||{},u=1,l=arguments.length,c=!1;for("boolean"==typeof s&&(c=s,s=arguments[1]||{},u=2),"object"==typeof s||b.isFunction(s)||(s={}),l===u&&(s=this,--u);l>u;u++)if(null!=(o=arguments[u]))for(i in o)e=s[i],r=o[i],s!==r&&(c&&r&&(b.isPlainObject(r)||(n=b.isArray(r)))?(n?(n=!1,a=e&&b.isArray(e)?e:[]):a=e&&b.isPlainObject(e)?e:{},s[i]=b.extend(c,a,r)):r!==t&&(s[i]=r));return s},b.extend({noConflict:function(t){return e.$===b&&(e.$=u),t&&e.jQuery===b&&(e.jQuery=s),b},isReady:!1,readyWait:1,holdReady:function(e){e?b.readyWait++:b.ready(!0)},ready:function(e){if(e===!0?!--b.readyWait:!b.isReady){if(!o.body)return setTimeout(b.ready);b.isReady=!0,e!==!0&&--b.readyWait>0||(n.resolveWith(o,[b]),b.fn.trigger&&b(o).trigger("ready").off("ready"))}},isFunction:function(e){return"function"===b.type(e)},isArray:Array.isArray||function(e){return"array"===b.type(e)},isWindow:function(e){return null!=e&&e==e.window},isNumeric:function(e){return!isNaN(parseFloat(e))&&isFinite(e)},type:function(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?l[m.call(e)]||"object":typeof e},isPlainObject:function(e){if(!e||"object"!==b.type(e)||e.nodeType||b.isWindow(e))return!1;try{if(e.constructor&&!y.call(e,"constructor")&&!y.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(n){return!1}var r;for(r in e);return r===t||y.call(e,r)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},error:function(e){throw Error(e)},parseHTML:function(e,t,n){if(!e||"string"!=typeof e)return null;"boolean"==typeof t&&(n=t,t=!1),t=t||o;var r=C.exec(e),i=!n&&[];return r?[t.createElement(r[1])]:(r=b.buildFragment([e],t,i),i&&b(i).remove(),b.merge([],r.childNodes))},parseJSON:function(n){return e.JSON&&e.JSON.parse?e.JSON.parse(n):null===n?n:"string"==typeof n&&(n=b.trim(n),n&&k.test(n.replace(S,"@").replace(A,"]").replace(E,"")))?Function("return "+n)():(b.error("Invalid JSON: "+n),t)},parseXML:function(n){var r,i;if(!n||"string"!=typeof n)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(o){r=t}return r&&r.documentElement&&!r.getElementsByTagName("parsererror").length||b.error("Invalid XML: "+n),r},noop:function(){},globalEval:function(t){t&&b.trim(t)&&(e.execScript||function(t){e.eval.call(e,t)})(t)},camelCase:function(e){return e.replace(j,"ms-").replace(D,L)},nodeName:function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()},each:function(e,t,n){var r,i=0,o=e.length,a=M(e);if(n){if(a){for(;o>i;i++)if(r=t.apply(e[i],n),r===!1)break}else for(i in e)if(r=t.apply(e[i],n),r===!1)break}else if(a){for(;o>i;i++)if(r=t.call(e[i],i,e[i]),r===!1)break}else for(i in e)if(r=t.call(e[i],i,e[i]),r===!1)break;return e},trim:v&&!v.call("\ufeff\u00a0")?function(e){return null==e?"":v.call(e)}:function(e){return null==e?"":(e+"").replace(T,"")},makeArray:function(e,t){var n=t||[];return null!=e&&(M(Object(e))?b.merge(n,"string"==typeof e?[e]:e):d.call(n,e)),n},inArray:function(e,t,n){var r;if(t){if(g)return g.call(t,e,n);for(r=t.length,n=n?0>n?Math.max(0,r+n):n:0;r>n;n++)if(n in t&&t[n]===e)return n}return-1},merge:function(e,n){var r=n.length,i=e.length,o=0;if("number"==typeof r)for(;r>o;o++)e[i++]=n[o];else while(n[o]!==t)e[i++]=n[o++];return e.length=i,e},grep:function(e,t,n){var r,i=[],o=0,a=e.length;for(n=!!n;a>o;o++)r=!!t(e[o],o),n!==r&&i.push(e[o]);return i},map:function(e,t,n){var r,i=0,o=e.length,a=M(e),s=[];if(a)for(;o>i;i++)r=t(e[i],i,n),null!=r&&(s[s.length]=r);else for(i in e)r=t(e[i],i,n),null!=r&&(s[s.length]=r);return f.apply([],s)},guid:1,proxy:function(e,n){var r,i,o;return"string"==typeof n&&(o=e[n],n=e,e=o),b.isFunction(e)?(r=h.call(arguments,2),i=function(){return e.apply(n||this,r.concat(h.call(arguments)))},i.guid=e.guid=e.guid||b.guid++,i):t},access:function(e,n,r,i,o,a,s){var u=0,l=e.length,c=null==r;if("object"===b.type(r)){o=!0;for(u in r)b.access(e,n,u,r[u],!0,a,s)}else if(i!==t&&(o=!0,b.isFunction(i)||(s=!0),c&&(s?(n.call(e,i),n=null):(c=n,n=function(e,t,n){return c.call(b(e),n)})),n))for(;l>u;u++)n(e[u],r,s?i:i.call(e[u],u,n(e[u],r)));return o?e:c?n.call(e):l?n(e[0],r):a},now:function(){return(new Date).getTime()}}),b.ready.promise=function(t){if(!n)if(n=b.Deferred(),"complete"===o.readyState)setTimeout(b.ready);else if(o.addEventListener)o.addEventListener("DOMContentLoaded",H,!1),e.addEventListener("load",H,!1);else{o.attachEvent("onreadystatechange",H),e.attachEvent("onload",H);var r=!1;try{r=null==e.frameElement&&o.documentElement}catch(i){}r&&r.doScroll&&function a(){if(!b.isReady){try{r.doScroll("left")}catch(e){return setTimeout(a,50)}q(),b.ready()}}()}return n.promise(t)},b.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(e,t){l["[object "+t+"]"]=t.toLowerCase()});function M(e){var t=e.length,n=b.type(e);return b.isWindow(e)?!1:1===e.nodeType&&t?!0:"array"===n||"function"!==n&&(0===t||"number"==typeof t&&t>0&&t-1 in e)}r=b(o);var _={};function F(e){var t=_[e]={};return b.each(e.match(w)||[],function(e,n){t[n]=!0}),t}b.Callbacks=function(e){e="string"==typeof e?_[e]||F(e):b.extend({},e);var n,r,i,o,a,s,u=[],l=!e.once&&[],c=function(t){for(r=e.memory&&t,i=!0,a=s||0,s=0,o=u.length,n=!0;u&&o>a;a++)if(u[a].apply(t[0],t[1])===!1&&e.stopOnFalse){r=!1;break}n=!1,u&&(l?l.length&&c(l.shift()):r?u=[]:p.disable())},p={add:function(){if(u){var t=u.length;(function i(t){b.each(t,function(t,n){var r=b.type(n);"function"===r?e.unique&&p.has(n)||u.push(n):n&&n.length&&"string"!==r&&i(n)})})(arguments),n?o=u.length:r&&(s=t,c(r))}return this},remove:function(){return u&&b.each(arguments,function(e,t){var r;while((r=b.inArray(t,u,r))>-1)u.splice(r,1),n&&(o>=r&&o--,a>=r&&a--)}),this},has:function(e){return e?b.inArray(e,u)>-1:!(!u||!u.length)},empty:function(){return u=[],this},disable:function(){return u=l=r=t,this},disabled:function(){return!u},lock:function(){return l=t,r||p.disable(),this},locked:function(){return!l},fireWith:function(e,t){return t=t||[],t=[e,t.slice?t.slice():t],!u||i&&!l||(n?l.push(t):c(t)),this},fire:function(){return p.fireWith(this,arguments),this},fired:function(){return!!i}};return p},b.extend({Deferred:function(e){var t=[["resolve","done",b.Callbacks("once memory"),"resolved"],["reject","fail",b.Callbacks("once memory"),"rejected"],["notify","progress",b.Callbacks("memory")]],n="pending",r={state:function(){return n},always:function(){return i.done(arguments).fail(arguments),this},then:function(){var e=arguments;return b.Deferred(function(n){b.each(t,function(t,o){var a=o[0],s=b.isFunction(e[t])&&e[t];i[o[1]](function(){var e=s&&s.apply(this,arguments);e&&b.isFunction(e.promise)?e.promise().done(n.resolve).fail(n.reject).progress(n.notify):n[a+"With"](this===r?n.promise():this,s?[e]:arguments)})}),e=null}).promise()},promise:function(e){return null!=e?b.extend(e,r):r}},i={};return r.pipe=r.then,b.each(t,function(e,o){var a=o[2],s=o[3];r[o[1]]=a.add,s&&a.add(function(){n=s},t[1^e][2].disable,t[2][2].lock),i[o[0]]=function(){return i[o[0]+"With"](this===i?r:this,arguments),this},i[o[0]+"With"]=a.fireWith}),r.promise(i),e&&e.call(i,i),i},when:function(e){var t=0,n=h.call(arguments),r=n.length,i=1!==r||e&&b.isFunction(e.promise)?r:0,o=1===i?e:b.Deferred(),a=function(e,t,n){return function(r){t[e]=this,n[e]=arguments.length>1?h.call(arguments):r,n===s?o.notifyWith(t,n):--i||o.resolveWith(t,n)}},s,u,l;if(r>1)for(s=Array(r),u=Array(r),l=Array(r);r>t;t++)n[t]&&b.isFunction(n[t].promise)?n[t].promise().done(a(t,l,n)).fail(o.reject).progress(a(t,u,s)):--i;return i||o.resolveWith(l,n),o.promise()}}),b.support=function(){var t,n,r,a,s,u,l,c,p,f,d=o.createElement("div");if(d.setAttribute("className","t"),d.innerHTML=" <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",n=d.getElementsByTagName("*"),r=d.getElementsByTagName("a")[0],!n||!r||!n.length)return{};s=o.createElement("select"),l=s.appendChild(o.createElement("option")),a=d.getElementsByTagName("input")[0],r.style.cssText="top:1px;float:left;opacity:.5",t={getSetAttribute:"t"!==d.className,leadingWhitespace:3===d.firstChild.nodeType,tbody:!d.getElementsByTagName("tbody").length,htmlSerialize:!!d.getElementsByTagName("link").length,style:/top/.test(r.getAttribute("style")),hrefNormalized:"/a"===r.getAttribute("href"),opacity:/^0.5/.test(r.style.opacity),cssFloat:!!r.style.cssFloat,checkOn:!!a.value,optSelected:l.selected,enctype:!!o.createElement("form").enctype,html5Clone:"<:nav></:nav>"!==o.createElement("nav").cloneNode(!0).outerHTML,boxModel:"CSS1Compat"===o.compatMode,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0,boxSizingReliable:!0,pixelPosition:!1},a.checked=!0,t.noCloneChecked=a.cloneNode(!0).checked,s.disabled=!0,t.optDisabled=!l.disabled;try{delete d.test}catch(h){t.deleteExpando=!1}a=o.createElement("input"),a.setAttribute("value",""),t.input=""===a.getAttribute("value"),a.value="t",a.setAttribute("type","radio"),t.radioValue="t"===a.value,a.setAttribute("checked","t"),a.setAttribute("name","t"),u=o.createDocumentFragment(),u.appendChild(a),t.appendChecked=a.checked,t.checkClone=u.cloneNode(!0).cloneNode(!0).lastChild.checked,d.attachEvent&&(d.attachEvent("onclick",function(){t.noCloneEvent=!1}),d.cloneNode(!0).click());for(f in{submit:!0,change:!0,focusin:!0})d.setAttribute(c="on"+f,"t"),t[f+"Bubbles"]=c in e||d.attributes[c].expando===!1;return d.style.backgroundClip="content-box",d.cloneNode(!0).style.backgroundClip="",t.clearCloneStyle="content-box"===d.style.backgroundClip,b(function(){var n,r,a,s="padding:0;margin:0;border:0;display:block;box-sizing:content-box;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;",u=o.getElementsByTagName("body")[0];u&&(n=o.createElement("div"),n.style.cssText="border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px",u.appendChild(n).appendChild(d),d.innerHTML="<table><tr><td></td><td>t</td></tr></table>",a=d.getElementsByTagName("td"),a[0].style.cssText="padding:0;margin:0;border:0;display:none",p=0===a[0].offsetHeight,a[0].style.display="",a[1].style.display="none",t.reliableHiddenOffsets=p&&0===a[0].offsetHeight,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%;",t.boxSizing=4===d.offsetWidth,t.doesNotIncludeMarginInBodyOffset=1!==u.offsetTop,e.getComputedStyle&&(t.pixelPosition="1%"!==(e.getComputedStyle(d,null)||{}).top,t.boxSizingReliable="4px"===(e.getComputedStyle(d,null)||{width:"4px"}).width,r=d.appendChild(o.createElement("div")),r.style.cssText=d.style.cssText=s,r.style.marginRight=r.style.width="0",d.style.width="1px",t.reliableMarginRight=!parseFloat((e.getComputedStyle(r,null)||{}).marginRight)),typeof d.style.zoom!==i&&(d.innerHTML="",d.style.cssText=s+"width:1px;padding:1px;display:inline;zoom:1",t.inlineBlockNeedsLayout=3===d.offsetWidth,d.style.display="block",d.innerHTML="<div></div>",d.firstChild.style.width="5px",t.shrinkWrapBlocks=3!==d.offsetWidth,t.inlineBlockNeedsLayout&&(u.style.zoom=1)),u.removeChild(n),n=d=a=r=null)}),n=s=u=l=r=a=null,t}();var O=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,B=/([A-Z])/g;function P(e,n,r,i){if(b.acceptData(e)){var o,a,s=b.expando,u="string"==typeof n,l=e.nodeType,p=l?b.cache:e,f=l?e[s]:e[s]&&s;if(f&&p[f]&&(i||p[f].data)||!u||r!==t)return f||(l?e[s]=f=c.pop()||b.guid++:f=s),p[f]||(p[f]={},l||(p[f].toJSON=b.noop)),("object"==typeof n||"function"==typeof n)&&(i?p[f]=b.extend(p[f],n):p[f].data=b.extend(p[f].data,n)),o=p[f],i||(o.data||(o.data={}),o=o.data),r!==t&&(o[b.camelCase(n)]=r),u?(a=o[n],null==a&&(a=o[b.camelCase(n)])):a=o,a}}function R(e,t,n){if(b.acceptData(e)){var r,i,o,a=e.nodeType,s=a?b.cache:e,u=a?e[b.expando]:b.expando;if(s[u]){if(t&&(o=n?s[u]:s[u].data)){b.isArray(t)?t=t.concat(b.map(t,b.camelCase)):t in o?t=[t]:(t=b.camelCase(t),t=t in o?[t]:t.split(" "));for(r=0,i=t.length;i>r;r++)delete o[t[r]];if(!(n?$:b.isEmptyObject)(o))return}(n||(delete s[u].data,$(s[u])))&&(a?b.cleanData([e],!0):b.support.deleteExpando||s!=s.window?delete s[u]:s[u]=null)}}}b.extend({cache:{},expando:"jQuery"+(p+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(e){return e=e.nodeType?b.cache[e[b.expando]]:e[b.expando],!!e&&!$(e)},data:function(e,t,n){return P(e,t,n)},removeData:function(e,t){return R(e,t)},_data:function(e,t,n){return P(e,t,n,!0)},_removeData:function(e,t){return R(e,t,!0)},acceptData:function(e){if(e.nodeType&&1!==e.nodeType&&9!==e.nodeType)return!1;var t=e.nodeName&&b.noData[e.nodeName.toLowerCase()];return!t||t!==!0&&e.getAttribute("classid")===t}}),b.fn.extend({data:function(e,n){var r,i,o=this[0],a=0,s=null;if(e===t){if(this.length&&(s=b.data(o),1===o.nodeType&&!b._data(o,"parsedAttrs"))){for(r=o.attributes;r.length>a;a++)i=r[a].name,i.indexOf("data-")||(i=b.camelCase(i.slice(5)),W(o,i,s[i]));b._data(o,"parsedAttrs",!0)}return s}return"object"==typeof e?this.each(function(){b.data(this,e)}):b.access(this,function(n){return n===t?o?W(o,e,b.data(o,e)):null:(this.each(function(){b.data(this,e,n)}),t)},null,n,arguments.length>1,null,!0)},removeData:function(e){return this.each(function(){b.removeData(this,e)})}});function W(e,n,r){if(r===t&&1===e.nodeType){var i="data-"+n.replace(B,"-$1").toLowerCase();if(r=e.getAttribute(i),"string"==typeof r){try{r="true"===r?!0:"false"===r?!1:"null"===r?null:+r+""===r?+r:O.test(r)?b.parseJSON(r):r}catch(o){}b.data(e,n,r)}else r=t}return r}function $(e){var t;for(t in e)if(("data"!==t||!b.isEmptyObject(e[t]))&&"toJSON"!==t)return!1;return!0}b.extend({queue:function(e,n,r){var i;return e?(n=(n||"fx")+"queue",i=b._data(e,n),r&&(!i||b.isArray(r)?i=b._data(e,n,b.makeArray(r)):i.push(r)),i||[]):t},dequeue:function(e,t){t=t||"fx";var n=b.queue(e,t),r=n.length,i=n.shift(),o=b._queueHooks(e,t),a=function(){b.dequeue(e,t)};"inprogress"===i&&(i=n.shift(),r--),o.cur=i,i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,a,o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return b._data(e,n)||b._data(e,n,{empty:b.Callbacks("once memory").add(function(){b._removeData(e,t+"queue"),b._removeData(e,n)})})}}),b.fn.extend({queue:function(e,n){var r=2;return"string"!=typeof e&&(n=e,e="fx",r--),r>arguments.length?b.queue(this[0],e):n===t?this:this.each(function(){var t=b.queue(this,e,n);b._queueHooks(this,e),"fx"===e&&"inprogress"!==t[0]&&b.dequeue(this,e)})},dequeue:function(e){return this.each(function(){b.dequeue(this,e)})},delay:function(e,t){return e=b.fx?b.fx.speeds[e]||e:e,t=t||"fx",this.queue(t,function(t,n){var r=setTimeout(t,e);n.stop=function(){clearTimeout(r)}})},clearQueue:function(e){return this.queue(e||"fx",[])},promise:function(e,n){var r,i=1,o=b.Deferred(),a=this,s=this.length,u=function(){--i||o.resolveWith(a,[a])};"string"!=typeof e&&(n=e,e=t),e=e||"fx";while(s--)r=b._data(a[s],e+"queueHooks"),r&&r.empty&&(i++,r.empty.add(u));return u(),o.promise(n)}});var I,z,X=/[\t\r\n]/g,U=/\r/g,V=/^(?:input|select|textarea|button|object)$/i,Y=/^(?:a|area)$/i,J=/^(?:checked|selected|autofocus|autoplay|async|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped)$/i,G=/^(?:checked|selected)$/i,Q=b.support.getSetAttribute,K=b.support.input;b.fn.extend({attr:function(e,t){return b.access(this,b.attr,e,t,arguments.length>1)},removeAttr:function(e){return this.each(function(){b.removeAttr(this,e)})},prop:function(e,t){return b.access(this,b.prop,e,t,arguments.length>1)},removeProp:function(e){return e=b.propFix[e]||e,this.each(function(){try{this[e]=t,delete this[e]}catch(n){}})},addClass:function(e){var t,n,r,i,o,a=0,s=this.length,u="string"==typeof e&&e;if(b.isFunction(e))return this.each(function(t){b(this).addClass(e.call(this,t,this.className))});if(u)for(t=(e||"").match(w)||[];s>a;a++)if(n=this[a],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(X," "):" ")){o=0;while(i=t[o++])0>r.indexOf(" "+i+" ")&&(r+=i+" ");n.className=b.trim(r)}return this},removeClass:function(e){var t,n,r,i,o,a=0,s=this.length,u=0===arguments.length||"string"==typeof e&&e;if(b.isFunction(e))return this.each(function(t){b(this).removeClass(e.call(this,t,this.className))});if(u)for(t=(e||"").match(w)||[];s>a;a++)if(n=this[a],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(X," "):"")){o=0;while(i=t[o++])while(r.indexOf(" "+i+" ")>=0)r=r.replace(" "+i+" "," ");n.className=e?b.trim(r):""}return this},toggleClass:function(e,t){var n=typeof e,r="boolean"==typeof t;return b.isFunction(e)?this.each(function(n){b(this).toggleClass(e.call(this,n,this.className,t),t)}):this.each(function(){if("string"===n){var o,a=0,s=b(this),u=t,l=e.match(w)||[];while(o=l[a++])u=r?u:!s.hasClass(o),s[u?"addClass":"removeClass"](o)}else(n===i||"boolean"===n)&&(this.className&&b._data(this,"__className__",this.className),this.className=this.className||e===!1?"":b._data(this,"__className__")||"")})},hasClass:function(e){var t=" "+e+" ",n=0,r=this.length;for(;r>n;n++)if(1===this[n].nodeType&&(" "+this[n].className+" ").replace(X," ").indexOf(t)>=0)return!0;return!1},val:function(e){var n,r,i,o=this[0];{if(arguments.length)return i=b.isFunction(e),this.each(function(n){var o,a=b(this);1===this.nodeType&&(o=i?e.call(this,n,a.val()):e,null==o?o="":"number"==typeof o?o+="":b.isArray(o)&&(o=b.map(o,function(e){return null==e?"":e+""})),r=b.valHooks[this.type]||b.valHooks[this.nodeName.toLowerCase()],r&&"set"in r&&r.set(this,o,"value")!==t||(this.value=o))});if(o)return r=b.valHooks[o.type]||b.valHooks[o.nodeName.toLowerCase()],r&&"get"in r&&(n=r.get(o,"value"))!==t?n:(n=o.value,"string"==typeof n?n.replace(U,""):null==n?"":n)}}}),b.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,o="select-one"===e.type||0>i,a=o?null:[],s=o?i+1:r.length,u=0>i?s:o?i:0;for(;s>u;u++)if(n=r[u],!(!n.selected&&u!==i||(b.support.optDisabled?n.disabled:null!==n.getAttribute("disabled"))||n.parentNode.disabled&&b.nodeName(n.parentNode,"optgroup"))){if(t=b(n).val(),o)return t;a.push(t)}return a},set:function(e,t){var n=b.makeArray(t);return b(e).find("option").each(function(){this.selected=b.inArray(b(this).val(),n)>=0}),n.length||(e.selectedIndex=-1),n}}},attr:function(e,n,r){var o,a,s,u=e.nodeType;if(e&&3!==u&&8!==u&&2!==u)return typeof e.getAttribute===i?b.prop(e,n,r):(a=1!==u||!b.isXMLDoc(e),a&&(n=n.toLowerCase(),o=b.attrHooks[n]||(J.test(n)?z:I)),r===t?o&&a&&"get"in o&&null!==(s=o.get(e,n))?s:(typeof e.getAttribute!==i&&(s=e.getAttribute(n)),null==s?t:s):null!==r?o&&a&&"set"in o&&(s=o.set(e,r,n))!==t?s:(e.setAttribute(n,r+""),r):(b.removeAttr(e,n),t))},removeAttr:function(e,t){var n,r,i=0,o=t&&t.match(w);if(o&&1===e.nodeType)while(n=o[i++])r=b.propFix[n]||n,J.test(n)?!Q&&G.test(n)?e[b.camelCase("default-"+n)]=e[r]=!1:e[r]=!1:b.attr(e,n,""),e.removeAttribute(Q?n:r)},attrHooks:{type:{set:function(e,t){if(!b.support.radioValue&&"radio"===t&&b.nodeName(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},propFix:{tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},prop:function(e,n,r){var i,o,a,s=e.nodeType;if(e&&3!==s&&8!==s&&2!==s)return a=1!==s||!b.isXMLDoc(e),a&&(n=b.propFix[n]||n,o=b.propHooks[n]),r!==t?o&&"set"in o&&(i=o.set(e,r,n))!==t?i:e[n]=r:o&&"get"in o&&null!==(i=o.get(e,n))?i:e[n]},propHooks:{tabIndex:{get:function(e){var n=e.getAttributeNode("tabindex");return n&&n.specified?parseInt(n.value,10):V.test(e.nodeName)||Y.test(e.nodeName)&&e.href?0:t}}}}),z={get:function(e,n){var r=b.prop(e,n),i="boolean"==typeof r&&e.getAttribute(n),o="boolean"==typeof r?K&&Q?null!=i:G.test(n)?e[b.camelCase("default-"+n)]:!!i:e.getAttributeNode(n);return o&&o.value!==!1?n.toLowerCase():t},set:function(e,t,n){return t===!1?b.removeAttr(e,n):K&&Q||!G.test(n)?e.setAttribute(!Q&&b.propFix[n]||n,n):e[b.camelCase("default-"+n)]=e[n]=!0,n}},K&&Q||(b.attrHooks.value={get:function(e,n){var r=e.getAttributeNode(n);return b.nodeName(e,"input")?e.defaultValue:r&&r.specified?r.value:t},set:function(e,n,r){return b.nodeName(e,"input")?(e.defaultValue=n,t):I&&I.set(e,n,r)}}),Q||(I=b.valHooks.button={get:function(e,n){var r=e.getAttributeNode(n);return r&&("id"===n||"name"===n||"coords"===n?""!==r.value:r.specified)?r.value:t},set:function(e,n,r){var i=e.getAttributeNode(r);return i||e.setAttributeNode(i=e.ownerDocument.createAttribute(r)),i.value=n+="","value"===r||n===e.getAttribute(r)?n:t}},b.attrHooks.contenteditable={get:I.get,set:function(e,t,n){I.set(e,""===t?!1:t,n)}},b.each(["width","height"],function(e,n){b.attrHooks[n]=b.extend(b.attrHooks[n],{set:function(e,r){return""===r?(e.setAttribute(n,"auto"),r):t}})})),b.support.hrefNormalized||(b.each(["href","src","width","height"],function(e,n){b.attrHooks[n]=b.extend(b.attrHooks[n],{get:function(e){var r=e.getAttribute(n,2);return null==r?t:r}})}),b.each(["href","src"],function(e,t){b.propHooks[t]={get:function(e){return e.getAttribute(t,4)}}})),b.support.style||(b.attrHooks.style={get:function(e){return e.style.cssText||t},set:function(e,t){return e.style.cssText=t+""}}),b.support.optSelected||(b.propHooks.selected=b.extend(b.propHooks.selected,{get:function(e){var t=e.parentNode;return t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex),null}})),b.support.enctype||(b.propFix.enctype="encoding"),b.support.checkOn||b.each(["radio","checkbox"],function(){b.valHooks[this]={get:function(e){return null===e.getAttribute("value")?"on":e.value}}}),b.each(["radio","checkbox"],function(){b.valHooks[this]=b.extend(b.valHooks[this],{set:function(e,n){return b.isArray(n)?e.checked=b.inArray(b(e).val(),n)>=0:t}})});var Z=/^(?:input|select|textarea)$/i,et=/^key/,tt=/^(?:mouse|contextmenu)|click/,nt=/^(?:focusinfocus|focusoutblur)$/,rt=/^([^.]*)(?:\.(.+)|)$/;function it(){return!0}function ot(){return!1}b.event={global:{},add:function(e,n,r,o,a){var s,u,l,c,p,f,d,h,g,m,y,v=b._data(e);if(v){r.handler&&(c=r,r=c.handler,a=c.selector),r.guid||(r.guid=b.guid++),(u=v.events)||(u=v.events={}),(f=v.handle)||(f=v.handle=function(e){return typeof b===i||e&&b.event.triggered===e.type?t:b.event.dispatch.apply(f.elem,arguments)},f.elem=e),n=(n||"").match(w)||[""],l=n.length;while(l--)s=rt.exec(n[l])||[],g=y=s[1],m=(s[2]||"").split(".").sort(),p=b.event.special[g]||{},g=(a?p.delegateType:p.bindType)||g,p=b.event.special[g]||{},d=b.extend({type:g,origType:y,data:o,handler:r,guid:r.guid,selector:a,needsContext:a&&b.expr.match.needsContext.test(a),namespace:m.join(".")},c),(h=u[g])||(h=u[g]=[],h.delegateCount=0,p.setup&&p.setup.call(e,o,m,f)!==!1||(e.addEventListener?e.addEventListener(g,f,!1):e.attachEvent&&e.attachEvent("on"+g,f))),p.add&&(p.add.call(e,d),d.handler.guid||(d.handler.guid=r.guid)),a?h.splice(h.delegateCount++,0,d):h.push(d),b.event.global[g]=!0;e=null}},remove:function(e,t,n,r,i){var o,a,s,u,l,c,p,f,d,h,g,m=b.hasData(e)&&b._data(e);if(m&&(c=m.events)){t=(t||"").match(w)||[""],l=t.length;while(l--)if(s=rt.exec(t[l])||[],d=g=s[1],h=(s[2]||"").split(".").sort(),d){p=b.event.special[d]||{},d=(r?p.delegateType:p.bindType)||d,f=c[d]||[],s=s[2]&&RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),u=o=f.length;while(o--)a=f[o],!i&&g!==a.origType||n&&n.guid!==a.guid||s&&!s.test(a.namespace)||r&&r!==a.selector&&("**"!==r||!a.selector)||(f.splice(o,1),a.selector&&f.delegateCount--,p.remove&&p.remove.call(e,a));u&&!f.length&&(p.teardown&&p.teardown.call(e,h,m.handle)!==!1||b.removeEvent(e,d,m.handle),delete c[d])}else for(d in c)b.event.remove(e,d+t[l],n,r,!0);b.isEmptyObject(c)&&(delete m.handle,b._removeData(e,"events"))}},trigger:function(n,r,i,a){var s,u,l,c,p,f,d,h=[i||o],g=y.call(n,"type")?n.type:n,m=y.call(n,"namespace")?n.namespace.split("."):[];if(l=f=i=i||o,3!==i.nodeType&&8!==i.nodeType&&!nt.test(g+b.event.triggered)&&(g.indexOf(".")>=0&&(m=g.split("."),g=m.shift(),m.sort()),u=0>g.indexOf(":")&&"on"+g,n=n[b.expando]?n:new b.Event(g,"object"==typeof n&&n),n.isTrigger=!0,n.namespace=m.join("."),n.namespace_re=n.namespace?RegExp("(^|\\.)"+m.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,n.result=t,n.target||(n.target=i),r=null==r?[n]:b.makeArray(r,[n]),p=b.event.special[g]||{},a||!p.trigger||p.trigger.apply(i,r)!==!1)){if(!a&&!p.noBubble&&!b.isWindow(i)){for(c=p.delegateType||g,nt.test(c+g)||(l=l.parentNode);l;l=l.parentNode)h.push(l),f=l;f===(i.ownerDocument||o)&&h.push(f.defaultView||f.parentWindow||e)}d=0;while((l=h[d++])&&!n.isPropagationStopped())n.type=d>1?c:p.bindType||g,s=(b._data(l,"events")||{})[n.type]&&b._data(l,"handle"),s&&s.apply(l,r),s=u&&l[u],s&&b.acceptData(l)&&s.apply&&s.apply(l,r)===!1&&n.preventDefault();if(n.type=g,!(a||n.isDefaultPrevented()||p._default&&p._default.apply(i.ownerDocument,r)!==!1||"click"===g&&b.nodeName(i,"a")||!b.acceptData(i)||!u||!i[g]||b.isWindow(i))){f=i[u],f&&(i[u]=null),b.event.triggered=g;try{i[g]()}catch(v){}b.event.triggered=t,f&&(i[u]=f)}return n.result}},dispatch:function(e){e=b.event.fix(e);var n,r,i,o,a,s=[],u=h.call(arguments),l=(b._data(this,"events")||{})[e.type]||[],c=b.event.special[e.type]||{};if(u[0]=e,e.delegateTarget=this,!c.preDispatch||c.preDispatch.call(this,e)!==!1){s=b.event.handlers.call(this,e,l),n=0;while((o=s[n++])&&!e.isPropagationStopped()){e.currentTarget=o.elem,a=0;while((i=o.handlers[a++])&&!e.isImmediatePropagationStopped())(!e.namespace_re||e.namespace_re.test(i.namespace))&&(e.handleObj=i,e.data=i.data,r=((b.event.special[i.origType]||{}).handle||i.handler).apply(o.elem,u),r!==t&&(e.result=r)===!1&&(e.preventDefault(),e.stopPropagation()))}return c.postDispatch&&c.postDispatch.call(this,e),e.result}},handlers:function(e,n){var r,i,o,a,s=[],u=n.delegateCount,l=e.target;if(u&&l.nodeType&&(!e.button||"click"!==e.type))for(;l!=this;l=l.parentNode||this)if(1===l.nodeType&&(l.disabled!==!0||"click"!==e.type)){for(o=[],a=0;u>a;a++)i=n[a],r=i.selector+" ",o[r]===t&&(o[r]=i.needsContext?b(r,this).index(l)>=0:b.find(r,this,null,[l]).length),o[r]&&o.push(i);o.length&&s.push({elem:l,handlers:o})}return n.length>u&&s.push({elem:this,handlers:n.slice(u)}),s},fix:function(e){if(e[b.expando])return e;var t,n,r,i=e.type,a=e,s=this.fixHooks[i];s||(this.fixHooks[i]=s=tt.test(i)?this.mouseHooks:et.test(i)?this.keyHooks:{}),r=s.props?this.props.concat(s.props):this.props,e=new b.Event(a),t=r.length;while(t--)n=r[t],e[n]=a[n];return e.target||(e.target=a.srcElement||o),3===e.target.nodeType&&(e.target=e.target.parentNode),e.metaKey=!!e.metaKey,s.filter?s.filter(e,a):e},props:"altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(e,t){return null==e.which&&(e.which=null!=t.charCode?t.charCode:t.keyCode),e}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(e,n){var r,i,a,s=n.button,u=n.fromElement;return null==e.pageX&&null!=n.clientX&&(i=e.target.ownerDocument||o,a=i.documentElement,r=i.body,e.pageX=n.clientX+(a&&a.scrollLeft||r&&r.scrollLeft||0)-(a&&a.clientLeft||r&&r.clientLeft||0),e.pageY=n.clientY+(a&&a.scrollTop||r&&r.scrollTop||0)-(a&&a.clientTop||r&&r.clientTop||0)),!e.relatedTarget&&u&&(e.relatedTarget=u===e.target?n.toElement:u),e.which||s===t||(e.which=1&s?1:2&s?3:4&s?2:0),e}},special:{load:{noBubble:!0},click:{trigger:function(){return b.nodeName(this,"input")&&"checkbox"===this.type&&this.click?(this.click(),!1):t}},focus:{trigger:function(){if(this!==o.activeElement&&this.focus)try{return this.focus(),!1}catch(e){}},delegateType:"focusin"},blur:{trigger:function(){return this===o.activeElement&&this.blur?(this.blur(),!1):t},delegateType:"focusout"},beforeunload:{postDispatch:function(e){e.result!==t&&(e.originalEvent.returnValue=e.result)}}},simulate:function(e,t,n,r){var i=b.extend(new b.Event,n,{type:e,isSimulated:!0,originalEvent:{}});r?b.event.trigger(i,null,t):b.event.dispatch.call(t,i),i.isDefaultPrevented()&&n.preventDefault()}},b.removeEvent=o.removeEventListener?function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n,!1)}:function(e,t,n){var r="on"+t;e.detachEvent&&(typeof e[r]===i&&(e[r]=null),e.detachEvent(r,n))},b.Event=function(e,n){return this instanceof b.Event?(e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||e.returnValue===!1||e.getPreventDefault&&e.getPreventDefault()?it:ot):this.type=e,n&&b.extend(this,n),this.timeStamp=e&&e.timeStamp||b.now(),this[b.expando]=!0,t):new b.Event(e,n)},b.Event.prototype={isDefaultPrevented:ot,isPropagationStopped:ot,isImmediatePropagationStopped:ot,preventDefault:function(){var e=this.originalEvent;this.isDefaultPrevented=it,e&&(e.preventDefault?e.preventDefault():e.returnValue=!1)},stopPropagation:function(){var e=this.originalEvent;this.isPropagationStopped=it,e&&(e.stopPropagation&&e.stopPropagation(),e.cancelBubble=!0)},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=it,this.stopPropagation()}},b.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(e,t){b.event.special[e]={delegateType:t,bindType:t,handle:function(e){var n,r=this,i=e.relatedTarget,o=e.handleObj; +return(!i||i!==r&&!b.contains(r,i))&&(e.type=o.origType,n=o.handler.apply(this,arguments),e.type=t),n}}}),b.support.submitBubbles||(b.event.special.submit={setup:function(){return b.nodeName(this,"form")?!1:(b.event.add(this,"click._submit keypress._submit",function(e){var n=e.target,r=b.nodeName(n,"input")||b.nodeName(n,"button")?n.form:t;r&&!b._data(r,"submitBubbles")&&(b.event.add(r,"submit._submit",function(e){e._submit_bubble=!0}),b._data(r,"submitBubbles",!0))}),t)},postDispatch:function(e){e._submit_bubble&&(delete e._submit_bubble,this.parentNode&&!e.isTrigger&&b.event.simulate("submit",this.parentNode,e,!0))},teardown:function(){return b.nodeName(this,"form")?!1:(b.event.remove(this,"._submit"),t)}}),b.support.changeBubbles||(b.event.special.change={setup:function(){return Z.test(this.nodeName)?(("checkbox"===this.type||"radio"===this.type)&&(b.event.add(this,"propertychange._change",function(e){"checked"===e.originalEvent.propertyName&&(this._just_changed=!0)}),b.event.add(this,"click._change",function(e){this._just_changed&&!e.isTrigger&&(this._just_changed=!1),b.event.simulate("change",this,e,!0)})),!1):(b.event.add(this,"beforeactivate._change",function(e){var t=e.target;Z.test(t.nodeName)&&!b._data(t,"changeBubbles")&&(b.event.add(t,"change._change",function(e){!this.parentNode||e.isSimulated||e.isTrigger||b.event.simulate("change",this.parentNode,e,!0)}),b._data(t,"changeBubbles",!0))}),t)},handle:function(e){var n=e.target;return this!==n||e.isSimulated||e.isTrigger||"radio"!==n.type&&"checkbox"!==n.type?e.handleObj.handler.apply(this,arguments):t},teardown:function(){return b.event.remove(this,"._change"),!Z.test(this.nodeName)}}),b.support.focusinBubbles||b.each({focus:"focusin",blur:"focusout"},function(e,t){var n=0,r=function(e){b.event.simulate(t,e.target,b.event.fix(e),!0)};b.event.special[t]={setup:function(){0===n++&&o.addEventListener(e,r,!0)},teardown:function(){0===--n&&o.removeEventListener(e,r,!0)}}}),b.fn.extend({on:function(e,n,r,i,o){var a,s;if("object"==typeof e){"string"!=typeof n&&(r=r||n,n=t);for(a in e)this.on(a,n,r,e[a],o);return this}if(null==r&&null==i?(i=n,r=n=t):null==i&&("string"==typeof n?(i=r,r=t):(i=r,r=n,n=t)),i===!1)i=ot;else if(!i)return this;return 1===o&&(s=i,i=function(e){return b().off(e),s.apply(this,arguments)},i.guid=s.guid||(s.guid=b.guid++)),this.each(function(){b.event.add(this,e,i,r,n)})},one:function(e,t,n,r){return this.on(e,t,n,r,1)},off:function(e,n,r){var i,o;if(e&&e.preventDefault&&e.handleObj)return i=e.handleObj,b(e.delegateTarget).off(i.namespace?i.origType+"."+i.namespace:i.origType,i.selector,i.handler),this;if("object"==typeof e){for(o in e)this.off(o,n,e[o]);return this}return(n===!1||"function"==typeof n)&&(r=n,n=t),r===!1&&(r=ot),this.each(function(){b.event.remove(this,e,r,n)})},bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},trigger:function(e,t){return this.each(function(){b.event.trigger(e,t,this)})},triggerHandler:function(e,n){var r=this[0];return r?b.event.trigger(e,n,r,!0):t}}),function(e,t){var n,r,i,o,a,s,u,l,c,p,f,d,h,g,m,y,v,x="sizzle"+-new Date,w=e.document,T={},N=0,C=0,k=it(),E=it(),S=it(),A=typeof t,j=1<<31,D=[],L=D.pop,H=D.push,q=D.slice,M=D.indexOf||function(e){var t=0,n=this.length;for(;n>t;t++)if(this[t]===e)return t;return-1},_="[\\x20\\t\\r\\n\\f]",F="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",O=F.replace("w","w#"),B="([*^$|!~]?=)",P="\\["+_+"*("+F+")"+_+"*(?:"+B+_+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+O+")|)|)"+_+"*\\]",R=":("+F+")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|"+P.replace(3,8)+")*)|.*)\\)|)",W=RegExp("^"+_+"+|((?:^|[^\\\\])(?:\\\\.)*)"+_+"+$","g"),$=RegExp("^"+_+"*,"+_+"*"),I=RegExp("^"+_+"*([\\x20\\t\\r\\n\\f>+~])"+_+"*"),z=RegExp(R),X=RegExp("^"+O+"$"),U={ID:RegExp("^#("+F+")"),CLASS:RegExp("^\\.("+F+")"),NAME:RegExp("^\\[name=['\"]?("+F+")['\"]?\\]"),TAG:RegExp("^("+F.replace("w","w*")+")"),ATTR:RegExp("^"+P),PSEUDO:RegExp("^"+R),CHILD:RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+_+"*(even|odd|(([+-]|)(\\d*)n|)"+_+"*(?:([+-]|)"+_+"*(\\d+)|))"+_+"*\\)|)","i"),needsContext:RegExp("^"+_+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+_+"*((?:-\\d)?\\d*)"+_+"*\\)|)(?=[^-]|$)","i")},V=/[\x20\t\r\n\f]*[+~]/,Y=/^[^{]+\{\s*\[native code/,J=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,G=/^(?:input|select|textarea|button)$/i,Q=/^h\d$/i,K=/'|\\/g,Z=/\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g,et=/\\([\da-fA-F]{1,6}[\x20\t\r\n\f]?|.)/g,tt=function(e,t){var n="0x"+t-65536;return n!==n?t:0>n?String.fromCharCode(n+65536):String.fromCharCode(55296|n>>10,56320|1023&n)};try{q.call(w.documentElement.childNodes,0)[0].nodeType}catch(nt){q=function(e){var t,n=[];while(t=this[e++])n.push(t);return n}}function rt(e){return Y.test(e+"")}function it(){var e,t=[];return e=function(n,r){return t.push(n+=" ")>i.cacheLength&&delete e[t.shift()],e[n]=r}}function ot(e){return e[x]=!0,e}function at(e){var t=p.createElement("div");try{return e(t)}catch(n){return!1}finally{t=null}}function st(e,t,n,r){var i,o,a,s,u,l,f,g,m,v;if((t?t.ownerDocument||t:w)!==p&&c(t),t=t||p,n=n||[],!e||"string"!=typeof e)return n;if(1!==(s=t.nodeType)&&9!==s)return[];if(!d&&!r){if(i=J.exec(e))if(a=i[1]){if(9===s){if(o=t.getElementById(a),!o||!o.parentNode)return n;if(o.id===a)return n.push(o),n}else if(t.ownerDocument&&(o=t.ownerDocument.getElementById(a))&&y(t,o)&&o.id===a)return n.push(o),n}else{if(i[2])return H.apply(n,q.call(t.getElementsByTagName(e),0)),n;if((a=i[3])&&T.getByClassName&&t.getElementsByClassName)return H.apply(n,q.call(t.getElementsByClassName(a),0)),n}if(T.qsa&&!h.test(e)){if(f=!0,g=x,m=t,v=9===s&&e,1===s&&"object"!==t.nodeName.toLowerCase()){l=ft(e),(f=t.getAttribute("id"))?g=f.replace(K,"\\$&"):t.setAttribute("id",g),g="[id='"+g+"'] ",u=l.length;while(u--)l[u]=g+dt(l[u]);m=V.test(e)&&t.parentNode||t,v=l.join(",")}if(v)try{return H.apply(n,q.call(m.querySelectorAll(v),0)),n}catch(b){}finally{f||t.removeAttribute("id")}}}return wt(e.replace(W,"$1"),t,n,r)}a=st.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return t?"HTML"!==t.nodeName:!1},c=st.setDocument=function(e){var n=e?e.ownerDocument||e:w;return n!==p&&9===n.nodeType&&n.documentElement?(p=n,f=n.documentElement,d=a(n),T.tagNameNoComments=at(function(e){return e.appendChild(n.createComment("")),!e.getElementsByTagName("*").length}),T.attributes=at(function(e){e.innerHTML="<select></select>";var t=typeof e.lastChild.getAttribute("multiple");return"boolean"!==t&&"string"!==t}),T.getByClassName=at(function(e){return e.innerHTML="<div class='hidden e'></div><div class='hidden'></div>",e.getElementsByClassName&&e.getElementsByClassName("e").length?(e.lastChild.className="e",2===e.getElementsByClassName("e").length):!1}),T.getByName=at(function(e){e.id=x+0,e.innerHTML="<a name='"+x+"'></a><div name='"+x+"'></div>",f.insertBefore(e,f.firstChild);var t=n.getElementsByName&&n.getElementsByName(x).length===2+n.getElementsByName(x+0).length;return T.getIdNotName=!n.getElementById(x),f.removeChild(e),t}),i.attrHandle=at(function(e){return e.innerHTML="<a href='#'></a>",e.firstChild&&typeof e.firstChild.getAttribute!==A&&"#"===e.firstChild.getAttribute("href")})?{}:{href:function(e){return e.getAttribute("href",2)},type:function(e){return e.getAttribute("type")}},T.getIdNotName?(i.find.ID=function(e,t){if(typeof t.getElementById!==A&&!d){var n=t.getElementById(e);return n&&n.parentNode?[n]:[]}},i.filter.ID=function(e){var t=e.replace(et,tt);return function(e){return e.getAttribute("id")===t}}):(i.find.ID=function(e,n){if(typeof n.getElementById!==A&&!d){var r=n.getElementById(e);return r?r.id===e||typeof r.getAttributeNode!==A&&r.getAttributeNode("id").value===e?[r]:t:[]}},i.filter.ID=function(e){var t=e.replace(et,tt);return function(e){var n=typeof e.getAttributeNode!==A&&e.getAttributeNode("id");return n&&n.value===t}}),i.find.TAG=T.tagNameNoComments?function(e,n){return typeof n.getElementsByTagName!==A?n.getElementsByTagName(e):t}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},i.find.NAME=T.getByName&&function(e,n){return typeof n.getElementsByName!==A?n.getElementsByName(name):t},i.find.CLASS=T.getByClassName&&function(e,n){return typeof n.getElementsByClassName===A||d?t:n.getElementsByClassName(e)},g=[],h=[":focus"],(T.qsa=rt(n.querySelectorAll))&&(at(function(e){e.innerHTML="<select><option selected=''></option></select>",e.querySelectorAll("[selected]").length||h.push("\\["+_+"*(?:checked|disabled|ismap|multiple|readonly|selected|value)"),e.querySelectorAll(":checked").length||h.push(":checked")}),at(function(e){e.innerHTML="<input type='hidden' i=''/>",e.querySelectorAll("[i^='']").length&&h.push("[*^$]="+_+"*(?:\"\"|'')"),e.querySelectorAll(":enabled").length||h.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),h.push(",.*:")})),(T.matchesSelector=rt(m=f.matchesSelector||f.mozMatchesSelector||f.webkitMatchesSelector||f.oMatchesSelector||f.msMatchesSelector))&&at(function(e){T.disconnectedMatch=m.call(e,"div"),m.call(e,"[s!='']:x"),g.push("!=",R)}),h=RegExp(h.join("|")),g=RegExp(g.join("|")),y=rt(f.contains)||f.compareDocumentPosition?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},v=f.compareDocumentPosition?function(e,t){var r;return e===t?(u=!0,0):(r=t.compareDocumentPosition&&e.compareDocumentPosition&&e.compareDocumentPosition(t))?1&r||e.parentNode&&11===e.parentNode.nodeType?e===n||y(w,e)?-1:t===n||y(w,t)?1:0:4&r?-1:1:e.compareDocumentPosition?-1:1}:function(e,t){var r,i=0,o=e.parentNode,a=t.parentNode,s=[e],l=[t];if(e===t)return u=!0,0;if(!o||!a)return e===n?-1:t===n?1:o?-1:a?1:0;if(o===a)return ut(e,t);r=e;while(r=r.parentNode)s.unshift(r);r=t;while(r=r.parentNode)l.unshift(r);while(s[i]===l[i])i++;return i?ut(s[i],l[i]):s[i]===w?-1:l[i]===w?1:0},u=!1,[0,0].sort(v),T.detectDuplicates=u,p):p},st.matches=function(e,t){return st(e,null,null,t)},st.matchesSelector=function(e,t){if((e.ownerDocument||e)!==p&&c(e),t=t.replace(Z,"='$1']"),!(!T.matchesSelector||d||g&&g.test(t)||h.test(t)))try{var n=m.call(e,t);if(n||T.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(r){}return st(t,p,null,[e]).length>0},st.contains=function(e,t){return(e.ownerDocument||e)!==p&&c(e),y(e,t)},st.attr=function(e,t){var n;return(e.ownerDocument||e)!==p&&c(e),d||(t=t.toLowerCase()),(n=i.attrHandle[t])?n(e):d||T.attributes?e.getAttribute(t):((n=e.getAttributeNode(t))||e.getAttribute(t))&&e[t]===!0?t:n&&n.specified?n.value:null},st.error=function(e){throw Error("Syntax error, unrecognized expression: "+e)},st.uniqueSort=function(e){var t,n=[],r=1,i=0;if(u=!T.detectDuplicates,e.sort(v),u){for(;t=e[r];r++)t===e[r-1]&&(i=n.push(r));while(i--)e.splice(n[i],1)}return e};function ut(e,t){var n=t&&e,r=n&&(~t.sourceIndex||j)-(~e.sourceIndex||j);if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function lt(e){return function(t){var n=t.nodeName.toLowerCase();return"input"===n&&t.type===e}}function ct(e){return function(t){var n=t.nodeName.toLowerCase();return("input"===n||"button"===n)&&t.type===e}}function pt(e){return ot(function(t){return t=+t,ot(function(n,r){var i,o=e([],n.length,t),a=o.length;while(a--)n[i=o[a]]&&(n[i]=!(r[i]=n[i]))})})}o=st.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(1===i||9===i||11===i){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=o(e)}else if(3===i||4===i)return e.nodeValue}else for(;t=e[r];r++)n+=o(t);return n},i=st.selectors={cacheLength:50,createPseudo:ot,match:U,find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(et,tt),e[3]=(e[4]||e[5]||"").replace(et,tt),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||st.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&st.error(e[0]),e},PSEUDO:function(e){var t,n=!e[5]&&e[2];return U.CHILD.test(e[0])?null:(e[4]?e[2]=e[4]:n&&z.test(n)&&(t=ft(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){return"*"===e?function(){return!0}:(e=e.replace(et,tt).toLowerCase(),function(t){return t.nodeName&&t.nodeName.toLowerCase()===e})},CLASS:function(e){var t=k[e+" "];return t||(t=RegExp("(^|"+_+")"+e+"("+_+"|$)"))&&k(e,function(e){return t.test(e.className||typeof e.getAttribute!==A&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r){var i=st.attr(r,e);return null==i?"!="===t:t?(i+="","="===t?i===n:"!="===t?i!==n:"^="===t?n&&0===i.indexOf(n):"*="===t?n&&i.indexOf(n)>-1:"$="===t?n&&i.slice(-n.length)===n:"~="===t?(" "+i+" ").indexOf(n)>-1:"|="===t?i===n||i.slice(0,n.length+1)===n+"-":!1):!0}},CHILD:function(e,t,n,r,i){var o="nth"!==e.slice(0,3),a="last"!==e.slice(-4),s="of-type"===t;return 1===r&&0===i?function(e){return!!e.parentNode}:function(t,n,u){var l,c,p,f,d,h,g=o!==a?"nextSibling":"previousSibling",m=t.parentNode,y=s&&t.nodeName.toLowerCase(),v=!u&&!s;if(m){if(o){while(g){p=t;while(p=p[g])if(s?p.nodeName.toLowerCase()===y:1===p.nodeType)return!1;h=g="only"===e&&!h&&"nextSibling"}return!0}if(h=[a?m.firstChild:m.lastChild],a&&v){c=m[x]||(m[x]={}),l=c[e]||[],d=l[0]===N&&l[1],f=l[0]===N&&l[2],p=d&&m.childNodes[d];while(p=++d&&p&&p[g]||(f=d=0)||h.pop())if(1===p.nodeType&&++f&&p===t){c[e]=[N,d,f];break}}else if(v&&(l=(t[x]||(t[x]={}))[e])&&l[0]===N)f=l[1];else while(p=++d&&p&&p[g]||(f=d=0)||h.pop())if((s?p.nodeName.toLowerCase()===y:1===p.nodeType)&&++f&&(v&&((p[x]||(p[x]={}))[e]=[N,f]),p===t))break;return f-=i,f===r||0===f%r&&f/r>=0}}},PSEUDO:function(e,t){var n,r=i.pseudos[e]||i.setFilters[e.toLowerCase()]||st.error("unsupported pseudo: "+e);return r[x]?r(t):r.length>1?(n=[e,e,"",t],i.setFilters.hasOwnProperty(e.toLowerCase())?ot(function(e,n){var i,o=r(e,t),a=o.length;while(a--)i=M.call(e,o[a]),e[i]=!(n[i]=o[a])}):function(e){return r(e,0,n)}):r}},pseudos:{not:ot(function(e){var t=[],n=[],r=s(e.replace(W,"$1"));return r[x]?ot(function(e,t,n,i){var o,a=r(e,null,i,[]),s=e.length;while(s--)(o=a[s])&&(e[s]=!(t[s]=o))}):function(e,i,o){return t[0]=e,r(t,null,o,n),!n.pop()}}),has:ot(function(e){return function(t){return st(e,t).length>0}}),contains:ot(function(e){return function(t){return(t.textContent||t.innerText||o(t)).indexOf(e)>-1}}),lang:ot(function(e){return X.test(e||"")||st.error("unsupported lang: "+e),e=e.replace(et,tt).toLowerCase(),function(t){var n;do if(n=d?t.getAttribute("xml:lang")||t.getAttribute("lang"):t.lang)return n=n.toLowerCase(),n===e||0===n.indexOf(e+"-");while((t=t.parentNode)&&1===t.nodeType);return!1}}),target:function(t){var n=e.location&&e.location.hash;return n&&n.slice(1)===t.id},root:function(e){return e===f},focus:function(e){return e===p.activeElement&&(!p.hasFocus||p.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:function(e){return e.disabled===!1},disabled:function(e){return e.disabled===!0},checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,e.selected===!0},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeName>"@"||3===e.nodeType||4===e.nodeType)return!1;return!0},parent:function(e){return!i.pseudos.empty(e)},header:function(e){return Q.test(e.nodeName)},input:function(e){return G.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||t.toLowerCase()===e.type)},first:pt(function(){return[0]}),last:pt(function(e,t){return[t-1]}),eq:pt(function(e,t,n){return[0>n?n+t:n]}),even:pt(function(e,t){var n=0;for(;t>n;n+=2)e.push(n);return e}),odd:pt(function(e,t){var n=1;for(;t>n;n+=2)e.push(n);return e}),lt:pt(function(e,t,n){var r=0>n?n+t:n;for(;--r>=0;)e.push(r);return e}),gt:pt(function(e,t,n){var r=0>n?n+t:n;for(;t>++r;)e.push(r);return e})}};for(n in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})i.pseudos[n]=lt(n);for(n in{submit:!0,reset:!0})i.pseudos[n]=ct(n);function ft(e,t){var n,r,o,a,s,u,l,c=E[e+" "];if(c)return t?0:c.slice(0);s=e,u=[],l=i.preFilter;while(s){(!n||(r=$.exec(s)))&&(r&&(s=s.slice(r[0].length)||s),u.push(o=[])),n=!1,(r=I.exec(s))&&(n=r.shift(),o.push({value:n,type:r[0].replace(W," ")}),s=s.slice(n.length));for(a in i.filter)!(r=U[a].exec(s))||l[a]&&!(r=l[a](r))||(n=r.shift(),o.push({value:n,type:a,matches:r}),s=s.slice(n.length));if(!n)break}return t?s.length:s?st.error(e):E(e,u).slice(0)}function dt(e){var t=0,n=e.length,r="";for(;n>t;t++)r+=e[t].value;return r}function ht(e,t,n){var i=t.dir,o=n&&"parentNode"===i,a=C++;return t.first?function(t,n,r){while(t=t[i])if(1===t.nodeType||o)return e(t,n,r)}:function(t,n,s){var u,l,c,p=N+" "+a;if(s){while(t=t[i])if((1===t.nodeType||o)&&e(t,n,s))return!0}else while(t=t[i])if(1===t.nodeType||o)if(c=t[x]||(t[x]={}),(l=c[i])&&l[0]===p){if((u=l[1])===!0||u===r)return u===!0}else if(l=c[i]=[p],l[1]=e(t,n,s)||r,l[1]===!0)return!0}}function gt(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 mt(e,t,n,r,i){var o,a=[],s=0,u=e.length,l=null!=t;for(;u>s;s++)(o=e[s])&&(!n||n(o,r,i))&&(a.push(o),l&&t.push(s));return a}function yt(e,t,n,r,i,o){return r&&!r[x]&&(r=yt(r)),i&&!i[x]&&(i=yt(i,o)),ot(function(o,a,s,u){var l,c,p,f=[],d=[],h=a.length,g=o||xt(t||"*",s.nodeType?[s]:s,[]),m=!e||!o&&t?g:mt(g,f,e,s,u),y=n?i||(o?e:h||r)?[]:a:m;if(n&&n(m,y,s,u),r){l=mt(y,d),r(l,[],s,u),c=l.length;while(c--)(p=l[c])&&(y[d[c]]=!(m[d[c]]=p))}if(o){if(i||e){if(i){l=[],c=y.length;while(c--)(p=y[c])&&l.push(m[c]=p);i(null,y=[],l,u)}c=y.length;while(c--)(p=y[c])&&(l=i?M.call(o,p):f[c])>-1&&(o[l]=!(a[l]=p))}}else y=mt(y===a?y.splice(h,y.length):y),i?i(null,a,y,u):H.apply(a,y)})}function vt(e){var t,n,r,o=e.length,a=i.relative[e[0].type],s=a||i.relative[" "],u=a?1:0,c=ht(function(e){return e===t},s,!0),p=ht(function(e){return M.call(t,e)>-1},s,!0),f=[function(e,n,r){return!a&&(r||n!==l)||((t=n).nodeType?c(e,n,r):p(e,n,r))}];for(;o>u;u++)if(n=i.relative[e[u].type])f=[ht(gt(f),n)];else{if(n=i.filter[e[u].type].apply(null,e[u].matches),n[x]){for(r=++u;o>r;r++)if(i.relative[e[r].type])break;return yt(u>1&>(f),u>1&&dt(e.slice(0,u-1)).replace(W,"$1"),n,r>u&&vt(e.slice(u,r)),o>r&&vt(e=e.slice(r)),o>r&&dt(e))}f.push(n)}return gt(f)}function bt(e,t){var n=0,o=t.length>0,a=e.length>0,s=function(s,u,c,f,d){var h,g,m,y=[],v=0,b="0",x=s&&[],w=null!=d,T=l,C=s||a&&i.find.TAG("*",d&&u.parentNode||u),k=N+=null==T?1:Math.random()||.1;for(w&&(l=u!==p&&u,r=n);null!=(h=C[b]);b++){if(a&&h){g=0;while(m=e[g++])if(m(h,u,c)){f.push(h);break}w&&(N=k,r=++n)}o&&((h=!m&&h)&&v--,s&&x.push(h))}if(v+=b,o&&b!==v){g=0;while(m=t[g++])m(x,y,u,c);if(s){if(v>0)while(b--)x[b]||y[b]||(y[b]=L.call(f));y=mt(y)}H.apply(f,y),w&&!s&&y.length>0&&v+t.length>1&&st.uniqueSort(f)}return w&&(N=k,l=T),x};return o?ot(s):s}s=st.compile=function(e,t){var n,r=[],i=[],o=S[e+" "];if(!o){t||(t=ft(e)),n=t.length;while(n--)o=vt(t[n]),o[x]?r.push(o):i.push(o);o=S(e,bt(i,r))}return o};function xt(e,t,n){var r=0,i=t.length;for(;i>r;r++)st(e,t[r],n);return n}function wt(e,t,n,r){var o,a,u,l,c,p=ft(e);if(!r&&1===p.length){if(a=p[0]=p[0].slice(0),a.length>2&&"ID"===(u=a[0]).type&&9===t.nodeType&&!d&&i.relative[a[1].type]){if(t=i.find.ID(u.matches[0].replace(et,tt),t)[0],!t)return n;e=e.slice(a.shift().value.length)}o=U.needsContext.test(e)?0:a.length;while(o--){if(u=a[o],i.relative[l=u.type])break;if((c=i.find[l])&&(r=c(u.matches[0].replace(et,tt),V.test(a[0].type)&&t.parentNode||t))){if(a.splice(o,1),e=r.length&&dt(a),!e)return H.apply(n,q.call(r,0)),n;break}}}return s(e,p)(r,t,d,n,V.test(e)),n}i.pseudos.nth=i.pseudos.eq;function Tt(){}i.filters=Tt.prototype=i.pseudos,i.setFilters=new Tt,c(),st.attr=b.attr,b.find=st,b.expr=st.selectors,b.expr[":"]=b.expr.pseudos,b.unique=st.uniqueSort,b.text=st.getText,b.isXMLDoc=st.isXML,b.contains=st.contains}(e);var at=/Until$/,st=/^(?:parents|prev(?:Until|All))/,ut=/^.[^:#\[\.,]*$/,lt=b.expr.match.needsContext,ct={children:!0,contents:!0,next:!0,prev:!0};b.fn.extend({find:function(e){var t,n,r,i=this.length;if("string"!=typeof e)return r=this,this.pushStack(b(e).filter(function(){for(t=0;i>t;t++)if(b.contains(r[t],this))return!0}));for(n=[],t=0;i>t;t++)b.find(e,this[t],n);return n=this.pushStack(i>1?b.unique(n):n),n.selector=(this.selector?this.selector+" ":"")+e,n},has:function(e){var t,n=b(e,this),r=n.length;return this.filter(function(){for(t=0;r>t;t++)if(b.contains(this,n[t]))return!0})},not:function(e){return this.pushStack(ft(this,e,!1))},filter:function(e){return this.pushStack(ft(this,e,!0))},is:function(e){return!!e&&("string"==typeof e?lt.test(e)?b(e,this.context).index(this[0])>=0:b.filter(e,this).length>0:this.filter(e).length>0)},closest:function(e,t){var n,r=0,i=this.length,o=[],a=lt.test(e)||"string"!=typeof e?b(e,t||this.context):0;for(;i>r;r++){n=this[r];while(n&&n.ownerDocument&&n!==t&&11!==n.nodeType){if(a?a.index(n)>-1:b.find.matchesSelector(n,e)){o.push(n);break}n=n.parentNode}}return this.pushStack(o.length>1?b.unique(o):o)},index:function(e){return e?"string"==typeof e?b.inArray(this[0],b(e)):b.inArray(e.jquery?e[0]:e,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){var n="string"==typeof e?b(e,t):b.makeArray(e&&e.nodeType?[e]:e),r=b.merge(this.get(),n);return this.pushStack(b.unique(r))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}}),b.fn.andSelf=b.fn.addBack;function pt(e,t){do e=e[t];while(e&&1!==e.nodeType);return e}b.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return b.dir(e,"parentNode")},parentsUntil:function(e,t,n){return b.dir(e,"parentNode",n)},next:function(e){return pt(e,"nextSibling")},prev:function(e){return pt(e,"previousSibling")},nextAll:function(e){return b.dir(e,"nextSibling")},prevAll:function(e){return b.dir(e,"previousSibling")},nextUntil:function(e,t,n){return b.dir(e,"nextSibling",n)},prevUntil:function(e,t,n){return b.dir(e,"previousSibling",n)},siblings:function(e){return b.sibling((e.parentNode||{}).firstChild,e)},children:function(e){return b.sibling(e.firstChild)},contents:function(e){return b.nodeName(e,"iframe")?e.contentDocument||e.contentWindow.document:b.merge([],e.childNodes)}},function(e,t){b.fn[e]=function(n,r){var i=b.map(this,t,n);return at.test(e)||(r=n),r&&"string"==typeof r&&(i=b.filter(r,i)),i=this.length>1&&!ct[e]?b.unique(i):i,this.length>1&&st.test(e)&&(i=i.reverse()),this.pushStack(i)}}),b.extend({filter:function(e,t,n){return n&&(e=":not("+e+")"),1===t.length?b.find.matchesSelector(t[0],e)?[t[0]]:[]:b.find.matches(e,t)},dir:function(e,n,r){var i=[],o=e[n];while(o&&9!==o.nodeType&&(r===t||1!==o.nodeType||!b(o).is(r)))1===o.nodeType&&i.push(o),o=o[n];return i},sibling:function(e,t){var n=[];for(;e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n}});function ft(e,t,n){if(t=t||0,b.isFunction(t))return b.grep(e,function(e,r){var i=!!t.call(e,r,e);return i===n});if(t.nodeType)return b.grep(e,function(e){return e===t===n});if("string"==typeof t){var r=b.grep(e,function(e){return 1===e.nodeType});if(ut.test(t))return b.filter(t,r,!n);t=b.filter(t,r)}return b.grep(e,function(e){return b.inArray(e,t)>=0===n})}function dt(e){var t=ht.split("|"),n=e.createDocumentFragment();if(n.createElement)while(t.length)n.createElement(t.pop());return n}var ht="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",gt=/ jQuery\d+="(?:null|\d+)"/g,mt=RegExp("<(?:"+ht+")[\\s/>]","i"),yt=/^\s+/,vt=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,bt=/<([\w:]+)/,xt=/<tbody/i,wt=/<|&#?\w+;/,Tt=/<(?:script|style|link)/i,Nt=/^(?:checkbox|radio)$/i,Ct=/checked\s*(?:[^=]|=\s*.checked.)/i,kt=/^$|\/(?:java|ecma)script/i,Et=/^true\/(.*)/,St=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,At={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],area:[1,"<map>","</map>"],param:[1,"<object>","</object>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:b.support.htmlSerialize?[0,"",""]:[1,"X<div>","</div>"]},jt=dt(o),Dt=jt.appendChild(o.createElement("div"));At.optgroup=At.option,At.tbody=At.tfoot=At.colgroup=At.caption=At.thead,At.th=At.td,b.fn.extend({text:function(e){return b.access(this,function(e){return e===t?b.text(this):this.empty().append((this[0]&&this[0].ownerDocument||o).createTextNode(e))},null,e,arguments.length)},wrapAll:function(e){if(b.isFunction(e))return this.each(function(t){b(this).wrapAll(e.call(this,t))});if(this[0]){var t=b(e,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstChild&&1===e.firstChild.nodeType)e=e.firstChild;return e}).append(this)}return this},wrapInner:function(e){return b.isFunction(e)?this.each(function(t){b(this).wrapInner(e.call(this,t))}):this.each(function(){var t=b(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=b.isFunction(e);return this.each(function(n){b(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(){return this.parent().each(function(){b.nodeName(this,"body")||b(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(e){(1===this.nodeType||11===this.nodeType||9===this.nodeType)&&this.appendChild(e)})},prepend:function(){return this.domManip(arguments,!0,function(e){(1===this.nodeType||11===this.nodeType||9===this.nodeType)&&this.insertBefore(e,this.firstChild)})},before:function(){return this.domManip(arguments,!1,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return this.domManip(arguments,!1,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},remove:function(e,t){var n,r=0;for(;null!=(n=this[r]);r++)(!e||b.filter(e,[n]).length>0)&&(t||1!==n.nodeType||b.cleanData(Ot(n)),n.parentNode&&(t&&b.contains(n.ownerDocument,n)&&Mt(Ot(n,"script")),n.parentNode.removeChild(n)));return this},empty:function(){var e,t=0;for(;null!=(e=this[t]);t++){1===e.nodeType&&b.cleanData(Ot(e,!1));while(e.firstChild)e.removeChild(e.firstChild);e.options&&b.nodeName(e,"select")&&(e.options.length=0)}return this},clone:function(e,t){return e=null==e?!1:e,t=null==t?e:t,this.map(function(){return b.clone(this,e,t)})},html:function(e){return b.access(this,function(e){var n=this[0]||{},r=0,i=this.length;if(e===t)return 1===n.nodeType?n.innerHTML.replace(gt,""):t;if(!("string"!=typeof e||Tt.test(e)||!b.support.htmlSerialize&&mt.test(e)||!b.support.leadingWhitespace&&yt.test(e)||At[(bt.exec(e)||["",""])[1].toLowerCase()])){e=e.replace(vt,"<$1></$2>");try{for(;i>r;r++)n=this[r]||{},1===n.nodeType&&(b.cleanData(Ot(n,!1)),n.innerHTML=e);n=0}catch(o){}}n&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(e){var t=b.isFunction(e);return t||"string"==typeof e||(e=b(e).not(this).detach()),this.domManip([e],!0,function(e){var t=this.nextSibling,n=this.parentNode;n&&(b(this).remove(),n.insertBefore(e,t))})},detach:function(e){return this.remove(e,!0)},domManip:function(e,n,r){e=f.apply([],e);var i,o,a,s,u,l,c=0,p=this.length,d=this,h=p-1,g=e[0],m=b.isFunction(g);if(m||!(1>=p||"string"!=typeof g||b.support.checkClone)&&Ct.test(g))return this.each(function(i){var o=d.eq(i);m&&(e[0]=g.call(this,i,n?o.html():t)),o.domManip(e,n,r)});if(p&&(l=b.buildFragment(e,this[0].ownerDocument,!1,this),i=l.firstChild,1===l.childNodes.length&&(l=i),i)){for(n=n&&b.nodeName(i,"tr"),s=b.map(Ot(l,"script"),Ht),a=s.length;p>c;c++)o=l,c!==h&&(o=b.clone(o,!0,!0),a&&b.merge(s,Ot(o,"script"))),r.call(n&&b.nodeName(this[c],"table")?Lt(this[c],"tbody"):this[c],o,c);if(a)for(u=s[s.length-1].ownerDocument,b.map(s,qt),c=0;a>c;c++)o=s[c],kt.test(o.type||"")&&!b._data(o,"globalEval")&&b.contains(u,o)&&(o.src?b.ajax({url:o.src,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0}):b.globalEval((o.text||o.textContent||o.innerHTML||"").replace(St,"")));l=i=null}return this}});function Lt(e,t){return e.getElementsByTagName(t)[0]||e.appendChild(e.ownerDocument.createElement(t))}function Ht(e){var t=e.getAttributeNode("type");return e.type=(t&&t.specified)+"/"+e.type,e}function qt(e){var t=Et.exec(e.type);return t?e.type=t[1]:e.removeAttribute("type"),e}function Mt(e,t){var n,r=0;for(;null!=(n=e[r]);r++)b._data(n,"globalEval",!t||b._data(t[r],"globalEval"))}function _t(e,t){if(1===t.nodeType&&b.hasData(e)){var n,r,i,o=b._data(e),a=b._data(t,o),s=o.events;if(s){delete a.handle,a.events={};for(n in s)for(r=0,i=s[n].length;i>r;r++)b.event.add(t,n,s[n][r])}a.data&&(a.data=b.extend({},a.data))}}function Ft(e,t){var n,r,i;if(1===t.nodeType){if(n=t.nodeName.toLowerCase(),!b.support.noCloneEvent&&t[b.expando]){i=b._data(t);for(r in i.events)b.removeEvent(t,r,i.handle);t.removeAttribute(b.expando)}"script"===n&&t.text!==e.text?(Ht(t).text=e.text,qt(t)):"object"===n?(t.parentNode&&(t.outerHTML=e.outerHTML),b.support.html5Clone&&e.innerHTML&&!b.trim(t.innerHTML)&&(t.innerHTML=e.innerHTML)):"input"===n&&Nt.test(e.type)?(t.defaultChecked=t.checked=e.checked,t.value!==e.value&&(t.value=e.value)):"option"===n?t.defaultSelected=t.selected=e.defaultSelected:("input"===n||"textarea"===n)&&(t.defaultValue=e.defaultValue)}}b.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(e,t){b.fn[e]=function(e){var n,r=0,i=[],o=b(e),a=o.length-1;for(;a>=r;r++)n=r===a?this:this.clone(!0),b(o[r])[t](n),d.apply(i,n.get());return this.pushStack(i)}});function Ot(e,n){var r,o,a=0,s=typeof e.getElementsByTagName!==i?e.getElementsByTagName(n||"*"):typeof e.querySelectorAll!==i?e.querySelectorAll(n||"*"):t;if(!s)for(s=[],r=e.childNodes||e;null!=(o=r[a]);a++)!n||b.nodeName(o,n)?s.push(o):b.merge(s,Ot(o,n));return n===t||n&&b.nodeName(e,n)?b.merge([e],s):s}function Bt(e){Nt.test(e.type)&&(e.defaultChecked=e.checked)}b.extend({clone:function(e,t,n){var r,i,o,a,s,u=b.contains(e.ownerDocument,e);if(b.support.html5Clone||b.isXMLDoc(e)||!mt.test("<"+e.nodeName+">")?o=e.cloneNode(!0):(Dt.innerHTML=e.outerHTML,Dt.removeChild(o=Dt.firstChild)),!(b.support.noCloneEvent&&b.support.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||b.isXMLDoc(e)))for(r=Ot(o),s=Ot(e),a=0;null!=(i=s[a]);++a)r[a]&&Ft(i,r[a]);if(t)if(n)for(s=s||Ot(e),r=r||Ot(o),a=0;null!=(i=s[a]);a++)_t(i,r[a]);else _t(e,o);return r=Ot(o,"script"),r.length>0&&Mt(r,!u&&Ot(e,"script")),r=s=i=null,o},buildFragment:function(e,t,n,r){var i,o,a,s,u,l,c,p=e.length,f=dt(t),d=[],h=0;for(;p>h;h++)if(o=e[h],o||0===o)if("object"===b.type(o))b.merge(d,o.nodeType?[o]:o);else if(wt.test(o)){s=s||f.appendChild(t.createElement("div")),u=(bt.exec(o)||["",""])[1].toLowerCase(),c=At[u]||At._default,s.innerHTML=c[1]+o.replace(vt,"<$1></$2>")+c[2],i=c[0];while(i--)s=s.lastChild;if(!b.support.leadingWhitespace&&yt.test(o)&&d.push(t.createTextNode(yt.exec(o)[0])),!b.support.tbody){o="table"!==u||xt.test(o)?"<table>"!==c[1]||xt.test(o)?0:s:s.firstChild,i=o&&o.childNodes.length;while(i--)b.nodeName(l=o.childNodes[i],"tbody")&&!l.childNodes.length&&o.removeChild(l) +}b.merge(d,s.childNodes),s.textContent="";while(s.firstChild)s.removeChild(s.firstChild);s=f.lastChild}else d.push(t.createTextNode(o));s&&f.removeChild(s),b.support.appendChecked||b.grep(Ot(d,"input"),Bt),h=0;while(o=d[h++])if((!r||-1===b.inArray(o,r))&&(a=b.contains(o.ownerDocument,o),s=Ot(f.appendChild(o),"script"),a&&Mt(s),n)){i=0;while(o=s[i++])kt.test(o.type||"")&&n.push(o)}return s=null,f},cleanData:function(e,t){var n,r,o,a,s=0,u=b.expando,l=b.cache,p=b.support.deleteExpando,f=b.event.special;for(;null!=(n=e[s]);s++)if((t||b.acceptData(n))&&(o=n[u],a=o&&l[o])){if(a.events)for(r in a.events)f[r]?b.event.remove(n,r):b.removeEvent(n,r,a.handle);l[o]&&(delete l[o],p?delete n[u]:typeof n.removeAttribute!==i?n.removeAttribute(u):n[u]=null,c.push(o))}}});var Pt,Rt,Wt,$t=/alpha\([^)]*\)/i,It=/opacity\s*=\s*([^)]*)/,zt=/^(top|right|bottom|left)$/,Xt=/^(none|table(?!-c[ea]).+)/,Ut=/^margin/,Vt=RegExp("^("+x+")(.*)$","i"),Yt=RegExp("^("+x+")(?!px)[a-z%]+$","i"),Jt=RegExp("^([+-])=("+x+")","i"),Gt={BODY:"block"},Qt={position:"absolute",visibility:"hidden",display:"block"},Kt={letterSpacing:0,fontWeight:400},Zt=["Top","Right","Bottom","Left"],en=["Webkit","O","Moz","ms"];function tn(e,t){if(t in e)return t;var n=t.charAt(0).toUpperCase()+t.slice(1),r=t,i=en.length;while(i--)if(t=en[i]+n,t in e)return t;return r}function nn(e,t){return e=t||e,"none"===b.css(e,"display")||!b.contains(e.ownerDocument,e)}function rn(e,t){var n,r,i,o=[],a=0,s=e.length;for(;s>a;a++)r=e[a],r.style&&(o[a]=b._data(r,"olddisplay"),n=r.style.display,t?(o[a]||"none"!==n||(r.style.display=""),""===r.style.display&&nn(r)&&(o[a]=b._data(r,"olddisplay",un(r.nodeName)))):o[a]||(i=nn(r),(n&&"none"!==n||!i)&&b._data(r,"olddisplay",i?n:b.css(r,"display"))));for(a=0;s>a;a++)r=e[a],r.style&&(t&&"none"!==r.style.display&&""!==r.style.display||(r.style.display=t?o[a]||"":"none"));return e}b.fn.extend({css:function(e,n){return b.access(this,function(e,n,r){var i,o,a={},s=0;if(b.isArray(n)){for(o=Rt(e),i=n.length;i>s;s++)a[n[s]]=b.css(e,n[s],!1,o);return a}return r!==t?b.style(e,n,r):b.css(e,n)},e,n,arguments.length>1)},show:function(){return rn(this,!0)},hide:function(){return rn(this)},toggle:function(e){var t="boolean"==typeof e;return this.each(function(){(t?e:nn(this))?b(this).show():b(this).hide()})}}),b.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Wt(e,"opacity");return""===n?"1":n}}}},cssNumber:{columnCount:!0,fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":b.support.cssFloat?"cssFloat":"styleFloat"},style:function(e,n,r,i){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var o,a,s,u=b.camelCase(n),l=e.style;if(n=b.cssProps[u]||(b.cssProps[u]=tn(l,u)),s=b.cssHooks[n]||b.cssHooks[u],r===t)return s&&"get"in s&&(o=s.get(e,!1,i))!==t?o:l[n];if(a=typeof r,"string"===a&&(o=Jt.exec(r))&&(r=(o[1]+1)*o[2]+parseFloat(b.css(e,n)),a="number"),!(null==r||"number"===a&&isNaN(r)||("number"!==a||b.cssNumber[u]||(r+="px"),b.support.clearCloneStyle||""!==r||0!==n.indexOf("background")||(l[n]="inherit"),s&&"set"in s&&(r=s.set(e,r,i))===t)))try{l[n]=r}catch(c){}}},css:function(e,n,r,i){var o,a,s,u=b.camelCase(n);return n=b.cssProps[u]||(b.cssProps[u]=tn(e.style,u)),s=b.cssHooks[n]||b.cssHooks[u],s&&"get"in s&&(a=s.get(e,!0,r)),a===t&&(a=Wt(e,n,i)),"normal"===a&&n in Kt&&(a=Kt[n]),""===r||r?(o=parseFloat(a),r===!0||b.isNumeric(o)?o||0:a):a},swap:function(e,t,n,r){var i,o,a={};for(o in t)a[o]=e.style[o],e.style[o]=t[o];i=n.apply(e,r||[]);for(o in t)e.style[o]=a[o];return i}}),e.getComputedStyle?(Rt=function(t){return e.getComputedStyle(t,null)},Wt=function(e,n,r){var i,o,a,s=r||Rt(e),u=s?s.getPropertyValue(n)||s[n]:t,l=e.style;return s&&(""!==u||b.contains(e.ownerDocument,e)||(u=b.style(e,n)),Yt.test(u)&&Ut.test(n)&&(i=l.width,o=l.minWidth,a=l.maxWidth,l.minWidth=l.maxWidth=l.width=u,u=s.width,l.width=i,l.minWidth=o,l.maxWidth=a)),u}):o.documentElement.currentStyle&&(Rt=function(e){return e.currentStyle},Wt=function(e,n,r){var i,o,a,s=r||Rt(e),u=s?s[n]:t,l=e.style;return null==u&&l&&l[n]&&(u=l[n]),Yt.test(u)&&!zt.test(n)&&(i=l.left,o=e.runtimeStyle,a=o&&o.left,a&&(o.left=e.currentStyle.left),l.left="fontSize"===n?"1em":u,u=l.pixelLeft+"px",l.left=i,a&&(o.left=a)),""===u?"auto":u});function on(e,t,n){var r=Vt.exec(t);return r?Math.max(0,r[1]-(n||0))+(r[2]||"px"):t}function an(e,t,n,r,i){var o=n===(r?"border":"content")?4:"width"===t?1:0,a=0;for(;4>o;o+=2)"margin"===n&&(a+=b.css(e,n+Zt[o],!0,i)),r?("content"===n&&(a-=b.css(e,"padding"+Zt[o],!0,i)),"margin"!==n&&(a-=b.css(e,"border"+Zt[o]+"Width",!0,i))):(a+=b.css(e,"padding"+Zt[o],!0,i),"padding"!==n&&(a+=b.css(e,"border"+Zt[o]+"Width",!0,i)));return a}function sn(e,t,n){var r=!0,i="width"===t?e.offsetWidth:e.offsetHeight,o=Rt(e),a=b.support.boxSizing&&"border-box"===b.css(e,"boxSizing",!1,o);if(0>=i||null==i){if(i=Wt(e,t,o),(0>i||null==i)&&(i=e.style[t]),Yt.test(i))return i;r=a&&(b.support.boxSizingReliable||i===e.style[t]),i=parseFloat(i)||0}return i+an(e,t,n||(a?"border":"content"),r,o)+"px"}function un(e){var t=o,n=Gt[e];return n||(n=ln(e,t),"none"!==n&&n||(Pt=(Pt||b("<iframe frameborder='0' width='0' height='0'/>").css("cssText","display:block !important")).appendTo(t.documentElement),t=(Pt[0].contentWindow||Pt[0].contentDocument).document,t.write("<!doctype html><html><body>"),t.close(),n=ln(e,t),Pt.detach()),Gt[e]=n),n}function ln(e,t){var n=b(t.createElement(e)).appendTo(t.body),r=b.css(n[0],"display");return n.remove(),r}b.each(["height","width"],function(e,n){b.cssHooks[n]={get:function(e,r,i){return r?0===e.offsetWidth&&Xt.test(b.css(e,"display"))?b.swap(e,Qt,function(){return sn(e,n,i)}):sn(e,n,i):t},set:function(e,t,r){var i=r&&Rt(e);return on(e,t,r?an(e,n,r,b.support.boxSizing&&"border-box"===b.css(e,"boxSizing",!1,i),i):0)}}}),b.support.opacity||(b.cssHooks.opacity={get:function(e,t){return It.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=b.isNumeric(t)?"alpha(opacity="+100*t+")":"",o=r&&r.filter||n.filter||"";n.zoom=1,(t>=1||""===t)&&""===b.trim(o.replace($t,""))&&n.removeAttribute&&(n.removeAttribute("filter"),""===t||r&&!r.filter)||(n.filter=$t.test(o)?o.replace($t,i):o+" "+i)}}),b(function(){b.support.reliableMarginRight||(b.cssHooks.marginRight={get:function(e,n){return n?b.swap(e,{display:"inline-block"},Wt,[e,"marginRight"]):t}}),!b.support.pixelPosition&&b.fn.position&&b.each(["top","left"],function(e,n){b.cssHooks[n]={get:function(e,r){return r?(r=Wt(e,n),Yt.test(r)?b(e).position()[n]+"px":r):t}}})}),b.expr&&b.expr.filters&&(b.expr.filters.hidden=function(e){return 0>=e.offsetWidth&&0>=e.offsetHeight||!b.support.reliableHiddenOffsets&&"none"===(e.style&&e.style.display||b.css(e,"display"))},b.expr.filters.visible=function(e){return!b.expr.filters.hidden(e)}),b.each({margin:"",padding:"",border:"Width"},function(e,t){b.cssHooks[e+t]={expand:function(n){var r=0,i={},o="string"==typeof n?n.split(" "):[n];for(;4>r;r++)i[e+Zt[r]+t]=o[r]||o[r-2]||o[0];return i}},Ut.test(e)||(b.cssHooks[e+t].set=on)});var cn=/%20/g,pn=/\[\]$/,fn=/\r?\n/g,dn=/^(?:submit|button|image|reset|file)$/i,hn=/^(?:input|select|textarea|keygen)/i;b.fn.extend({serialize:function(){return b.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var e=b.prop(this,"elements");return e?b.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!b(this).is(":disabled")&&hn.test(this.nodeName)&&!dn.test(e)&&(this.checked||!Nt.test(e))}).map(function(e,t){var n=b(this).val();return null==n?null:b.isArray(n)?b.map(n,function(e){return{name:t.name,value:e.replace(fn,"\r\n")}}):{name:t.name,value:n.replace(fn,"\r\n")}}).get()}}),b.param=function(e,n){var r,i=[],o=function(e,t){t=b.isFunction(t)?t():null==t?"":t,i[i.length]=encodeURIComponent(e)+"="+encodeURIComponent(t)};if(n===t&&(n=b.ajaxSettings&&b.ajaxSettings.traditional),b.isArray(e)||e.jquery&&!b.isPlainObject(e))b.each(e,function(){o(this.name,this.value)});else for(r in e)gn(r,e[r],n,o);return i.join("&").replace(cn,"+")};function gn(e,t,n,r){var i;if(b.isArray(t))b.each(t,function(t,i){n||pn.test(e)?r(e,i):gn(e+"["+("object"==typeof i?t:"")+"]",i,n,r)});else if(n||"object"!==b.type(t))r(e,t);else for(i in t)gn(e+"["+i+"]",t[i],n,r)}b.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(e,t){b.fn[t]=function(e,n){return arguments.length>0?this.on(t,null,e,n):this.trigger(t)}}),b.fn.hover=function(e,t){return this.mouseenter(e).mouseleave(t||e)};var mn,yn,vn=b.now(),bn=/\?/,xn=/#.*$/,wn=/([?&])_=[^&]*/,Tn=/^(.*?):[ \t]*([^\r\n]*)\r?$/gm,Nn=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Cn=/^(?:GET|HEAD)$/,kn=/^\/\//,En=/^([\w.+-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,Sn=b.fn.load,An={},jn={},Dn="*/".concat("*");try{yn=a.href}catch(Ln){yn=o.createElement("a"),yn.href="",yn=yn.href}mn=En.exec(yn.toLowerCase())||[];function Hn(e){return function(t,n){"string"!=typeof t&&(n=t,t="*");var r,i=0,o=t.toLowerCase().match(w)||[];if(b.isFunction(n))while(r=o[i++])"+"===r[0]?(r=r.slice(1)||"*",(e[r]=e[r]||[]).unshift(n)):(e[r]=e[r]||[]).push(n)}}function qn(e,n,r,i){var o={},a=e===jn;function s(u){var l;return o[u]=!0,b.each(e[u]||[],function(e,u){var c=u(n,r,i);return"string"!=typeof c||a||o[c]?a?!(l=c):t:(n.dataTypes.unshift(c),s(c),!1)}),l}return s(n.dataTypes[0])||!o["*"]&&s("*")}function Mn(e,n){var r,i,o=b.ajaxSettings.flatOptions||{};for(i in n)n[i]!==t&&((o[i]?e:r||(r={}))[i]=n[i]);return r&&b.extend(!0,e,r),e}b.fn.load=function(e,n,r){if("string"!=typeof e&&Sn)return Sn.apply(this,arguments);var i,o,a,s=this,u=e.indexOf(" ");return u>=0&&(i=e.slice(u,e.length),e=e.slice(0,u)),b.isFunction(n)?(r=n,n=t):n&&"object"==typeof n&&(a="POST"),s.length>0&&b.ajax({url:e,type:a,dataType:"html",data:n}).done(function(e){o=arguments,s.html(i?b("<div>").append(b.parseHTML(e)).find(i):e)}).complete(r&&function(e,t){s.each(r,o||[e.responseText,t,e])}),this},b.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){b.fn[t]=function(e){return this.on(t,e)}}),b.each(["get","post"],function(e,n){b[n]=function(e,r,i,o){return b.isFunction(r)&&(o=o||i,i=r,r=t),b.ajax({url:e,type:n,dataType:o,data:r,success:i})}}),b.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:yn,type:"GET",isLocal:Nn.test(mn[1]),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":Dn,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":e.String,"text html":!0,"text json":b.parseJSON,"text xml":b.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?Mn(Mn(e,b.ajaxSettings),t):Mn(b.ajaxSettings,e)},ajaxPrefilter:Hn(An),ajaxTransport:Hn(jn),ajax:function(e,n){"object"==typeof e&&(n=e,e=t),n=n||{};var r,i,o,a,s,u,l,c,p=b.ajaxSetup({},n),f=p.context||p,d=p.context&&(f.nodeType||f.jquery)?b(f):b.event,h=b.Deferred(),g=b.Callbacks("once memory"),m=p.statusCode||{},y={},v={},x=0,T="canceled",N={readyState:0,getResponseHeader:function(e){var t;if(2===x){if(!c){c={};while(t=Tn.exec(a))c[t[1].toLowerCase()]=t[2]}t=c[e.toLowerCase()]}return null==t?null:t},getAllResponseHeaders:function(){return 2===x?a:null},setRequestHeader:function(e,t){var n=e.toLowerCase();return x||(e=v[n]=v[n]||e,y[e]=t),this},overrideMimeType:function(e){return x||(p.mimeType=e),this},statusCode:function(e){var t;if(e)if(2>x)for(t in e)m[t]=[m[t],e[t]];else N.always(e[N.status]);return this},abort:function(e){var t=e||T;return l&&l.abort(t),k(0,t),this}};if(h.promise(N).complete=g.add,N.success=N.done,N.error=N.fail,p.url=((e||p.url||yn)+"").replace(xn,"").replace(kn,mn[1]+"//"),p.type=n.method||n.type||p.method||p.type,p.dataTypes=b.trim(p.dataType||"*").toLowerCase().match(w)||[""],null==p.crossDomain&&(r=En.exec(p.url.toLowerCase()),p.crossDomain=!(!r||r[1]===mn[1]&&r[2]===mn[2]&&(r[3]||("http:"===r[1]?80:443))==(mn[3]||("http:"===mn[1]?80:443)))),p.data&&p.processData&&"string"!=typeof p.data&&(p.data=b.param(p.data,p.traditional)),qn(An,p,n,N),2===x)return N;u=p.global,u&&0===b.active++&&b.event.trigger("ajaxStart"),p.type=p.type.toUpperCase(),p.hasContent=!Cn.test(p.type),o=p.url,p.hasContent||(p.data&&(o=p.url+=(bn.test(o)?"&":"?")+p.data,delete p.data),p.cache===!1&&(p.url=wn.test(o)?o.replace(wn,"$1_="+vn++):o+(bn.test(o)?"&":"?")+"_="+vn++)),p.ifModified&&(b.lastModified[o]&&N.setRequestHeader("If-Modified-Since",b.lastModified[o]),b.etag[o]&&N.setRequestHeader("If-None-Match",b.etag[o])),(p.data&&p.hasContent&&p.contentType!==!1||n.contentType)&&N.setRequestHeader("Content-Type",p.contentType),N.setRequestHeader("Accept",p.dataTypes[0]&&p.accepts[p.dataTypes[0]]?p.accepts[p.dataTypes[0]]+("*"!==p.dataTypes[0]?", "+Dn+"; q=0.01":""):p.accepts["*"]);for(i in p.headers)N.setRequestHeader(i,p.headers[i]);if(p.beforeSend&&(p.beforeSend.call(f,N,p)===!1||2===x))return N.abort();T="abort";for(i in{success:1,error:1,complete:1})N[i](p[i]);if(l=qn(jn,p,n,N)){N.readyState=1,u&&d.trigger("ajaxSend",[N,p]),p.async&&p.timeout>0&&(s=setTimeout(function(){N.abort("timeout")},p.timeout));try{x=1,l.send(y,k)}catch(C){if(!(2>x))throw C;k(-1,C)}}else k(-1,"No Transport");function k(e,n,r,i){var c,y,v,w,T,C=n;2!==x&&(x=2,s&&clearTimeout(s),l=t,a=i||"",N.readyState=e>0?4:0,r&&(w=_n(p,N,r)),e>=200&&300>e||304===e?(p.ifModified&&(T=N.getResponseHeader("Last-Modified"),T&&(b.lastModified[o]=T),T=N.getResponseHeader("etag"),T&&(b.etag[o]=T)),204===e?(c=!0,C="nocontent"):304===e?(c=!0,C="notmodified"):(c=Fn(p,w),C=c.state,y=c.data,v=c.error,c=!v)):(v=C,(e||!C)&&(C="error",0>e&&(e=0))),N.status=e,N.statusText=(n||C)+"",c?h.resolveWith(f,[y,C,N]):h.rejectWith(f,[N,C,v]),N.statusCode(m),m=t,u&&d.trigger(c?"ajaxSuccess":"ajaxError",[N,p,c?y:v]),g.fireWith(f,[N,C]),u&&(d.trigger("ajaxComplete",[N,p]),--b.active||b.event.trigger("ajaxStop")))}return N},getScript:function(e,n){return b.get(e,t,n,"script")},getJSON:function(e,t,n){return b.get(e,t,n,"json")}});function _n(e,n,r){var i,o,a,s,u=e.contents,l=e.dataTypes,c=e.responseFields;for(s in c)s in r&&(n[c[s]]=r[s]);while("*"===l[0])l.shift(),o===t&&(o=e.mimeType||n.getResponseHeader("Content-Type"));if(o)for(s in u)if(u[s]&&u[s].test(o)){l.unshift(s);break}if(l[0]in r)a=l[0];else{for(s in r){if(!l[0]||e.converters[s+" "+l[0]]){a=s;break}i||(i=s)}a=a||i}return a?(a!==l[0]&&l.unshift(a),r[a]):t}function Fn(e,t){var n,r,i,o,a={},s=0,u=e.dataTypes.slice(),l=u[0];if(e.dataFilter&&(t=e.dataFilter(t,e.dataType)),u[1])for(i in e.converters)a[i.toLowerCase()]=e.converters[i];for(;r=u[++s];)if("*"!==r){if("*"!==l&&l!==r){if(i=a[l+" "+r]||a["* "+r],!i)for(n in a)if(o=n.split(" "),o[1]===r&&(i=a[l+" "+o[0]]||a["* "+o[0]])){i===!0?i=a[n]:a[n]!==!0&&(r=o[0],u.splice(s--,0,r));break}if(i!==!0)if(i&&e["throws"])t=i(t);else try{t=i(t)}catch(c){return{state:"parsererror",error:i?c:"No conversion from "+l+" to "+r}}}l=r}return{state:"success",data:t}}b.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/(?:java|ecma)script/},converters:{"text script":function(e){return b.globalEval(e),e}}}),b.ajaxPrefilter("script",function(e){e.cache===t&&(e.cache=!1),e.crossDomain&&(e.type="GET",e.global=!1)}),b.ajaxTransport("script",function(e){if(e.crossDomain){var n,r=o.head||b("head")[0]||o.documentElement;return{send:function(t,i){n=o.createElement("script"),n.async=!0,e.scriptCharset&&(n.charset=e.scriptCharset),n.src=e.url,n.onload=n.onreadystatechange=function(e,t){(t||!n.readyState||/loaded|complete/.test(n.readyState))&&(n.onload=n.onreadystatechange=null,n.parentNode&&n.parentNode.removeChild(n),n=null,t||i(200,"success"))},r.insertBefore(n,r.firstChild)},abort:function(){n&&n.onload(t,!0)}}}});var On=[],Bn=/(=)\?(?=&|$)|\?\?/;b.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=On.pop()||b.expando+"_"+vn++;return this[e]=!0,e}}),b.ajaxPrefilter("json jsonp",function(n,r,i){var o,a,s,u=n.jsonp!==!1&&(Bn.test(n.url)?"url":"string"==typeof n.data&&!(n.contentType||"").indexOf("application/x-www-form-urlencoded")&&Bn.test(n.data)&&"data");return u||"jsonp"===n.dataTypes[0]?(o=n.jsonpCallback=b.isFunction(n.jsonpCallback)?n.jsonpCallback():n.jsonpCallback,u?n[u]=n[u].replace(Bn,"$1"+o):n.jsonp!==!1&&(n.url+=(bn.test(n.url)?"&":"?")+n.jsonp+"="+o),n.converters["script json"]=function(){return s||b.error(o+" was not called"),s[0]},n.dataTypes[0]="json",a=e[o],e[o]=function(){s=arguments},i.always(function(){e[o]=a,n[o]&&(n.jsonpCallback=r.jsonpCallback,On.push(o)),s&&b.isFunction(a)&&a(s[0]),s=a=t}),"script"):t});var Pn,Rn,Wn=0,$n=e.ActiveXObject&&function(){var e;for(e in Pn)Pn[e](t,!0)};function In(){try{return new e.XMLHttpRequest}catch(t){}}function zn(){try{return new e.ActiveXObject("Microsoft.XMLHTTP")}catch(t){}}b.ajaxSettings.xhr=e.ActiveXObject?function(){return!this.isLocal&&In()||zn()}:In,Rn=b.ajaxSettings.xhr(),b.support.cors=!!Rn&&"withCredentials"in Rn,Rn=b.support.ajax=!!Rn,Rn&&b.ajaxTransport(function(n){if(!n.crossDomain||b.support.cors){var r;return{send:function(i,o){var a,s,u=n.xhr();if(n.username?u.open(n.type,n.url,n.async,n.username,n.password):u.open(n.type,n.url,n.async),n.xhrFields)for(s in n.xhrFields)u[s]=n.xhrFields[s];n.mimeType&&u.overrideMimeType&&u.overrideMimeType(n.mimeType),n.crossDomain||i["X-Requested-With"]||(i["X-Requested-With"]="XMLHttpRequest");try{for(s in i)u.setRequestHeader(s,i[s])}catch(l){}u.send(n.hasContent&&n.data||null),r=function(e,i){var s,l,c,p;try{if(r&&(i||4===u.readyState))if(r=t,a&&(u.onreadystatechange=b.noop,$n&&delete Pn[a]),i)4!==u.readyState&&u.abort();else{p={},s=u.status,l=u.getAllResponseHeaders(),"string"==typeof u.responseText&&(p.text=u.responseText);try{c=u.statusText}catch(f){c=""}s||!n.isLocal||n.crossDomain?1223===s&&(s=204):s=p.text?200:404}}catch(d){i||o(-1,d)}p&&o(s,c,p,l)},n.async?4===u.readyState?setTimeout(r):(a=++Wn,$n&&(Pn||(Pn={},b(e).unload($n)),Pn[a]=r),u.onreadystatechange=r):r()},abort:function(){r&&r(t,!0)}}}});var Xn,Un,Vn=/^(?:toggle|show|hide)$/,Yn=RegExp("^(?:([+-])=|)("+x+")([a-z%]*)$","i"),Jn=/queueHooks$/,Gn=[nr],Qn={"*":[function(e,t){var n,r,i=this.createTween(e,t),o=Yn.exec(t),a=i.cur(),s=+a||0,u=1,l=20;if(o){if(n=+o[2],r=o[3]||(b.cssNumber[e]?"":"px"),"px"!==r&&s){s=b.css(i.elem,e,!0)||n||1;do u=u||".5",s/=u,b.style(i.elem,e,s+r);while(u!==(u=i.cur()/a)&&1!==u&&--l)}i.unit=r,i.start=s,i.end=o[1]?s+(o[1]+1)*n:n}return i}]};function Kn(){return setTimeout(function(){Xn=t}),Xn=b.now()}function Zn(e,t){b.each(t,function(t,n){var r=(Qn[t]||[]).concat(Qn["*"]),i=0,o=r.length;for(;o>i;i++)if(r[i].call(e,t,n))return})}function er(e,t,n){var r,i,o=0,a=Gn.length,s=b.Deferred().always(function(){delete u.elem}),u=function(){if(i)return!1;var t=Xn||Kn(),n=Math.max(0,l.startTime+l.duration-t),r=n/l.duration||0,o=1-r,a=0,u=l.tweens.length;for(;u>a;a++)l.tweens[a].run(o);return s.notifyWith(e,[l,o,n]),1>o&&u?n:(s.resolveWith(e,[l]),!1)},l=s.promise({elem:e,props:b.extend({},t),opts:b.extend(!0,{specialEasing:{}},n),originalProperties:t,originalOptions:n,startTime:Xn||Kn(),duration:n.duration,tweens:[],createTween:function(t,n){var r=b.Tween(e,l.opts,t,n,l.opts.specialEasing[t]||l.opts.easing);return l.tweens.push(r),r},stop:function(t){var n=0,r=t?l.tweens.length:0;if(i)return this;for(i=!0;r>n;n++)l.tweens[n].run(1);return t?s.resolveWith(e,[l,t]):s.rejectWith(e,[l,t]),this}}),c=l.props;for(tr(c,l.opts.specialEasing);a>o;o++)if(r=Gn[o].call(l,e,c,l.opts))return r;return Zn(l,c),b.isFunction(l.opts.start)&&l.opts.start.call(e,l),b.fx.timer(b.extend(u,{elem:e,anim:l,queue:l.opts.queue})),l.progress(l.opts.progress).done(l.opts.done,l.opts.complete).fail(l.opts.fail).always(l.opts.always)}function tr(e,t){var n,r,i,o,a;for(i in e)if(r=b.camelCase(i),o=t[r],n=e[i],b.isArray(n)&&(o=n[1],n=e[i]=n[0]),i!==r&&(e[r]=n,delete e[i]),a=b.cssHooks[r],a&&"expand"in a){n=a.expand(n),delete e[r];for(i in n)i in e||(e[i]=n[i],t[i]=o)}else t[r]=o}b.Animation=b.extend(er,{tweener:function(e,t){b.isFunction(e)?(t=e,e=["*"]):e=e.split(" ");var n,r=0,i=e.length;for(;i>r;r++)n=e[r],Qn[n]=Qn[n]||[],Qn[n].unshift(t)},prefilter:function(e,t){t?Gn.unshift(e):Gn.push(e)}});function nr(e,t,n){var r,i,o,a,s,u,l,c,p,f=this,d=e.style,h={},g=[],m=e.nodeType&&nn(e);n.queue||(c=b._queueHooks(e,"fx"),null==c.unqueued&&(c.unqueued=0,p=c.empty.fire,c.empty.fire=function(){c.unqueued||p()}),c.unqueued++,f.always(function(){f.always(function(){c.unqueued--,b.queue(e,"fx").length||c.empty.fire()})})),1===e.nodeType&&("height"in t||"width"in t)&&(n.overflow=[d.overflow,d.overflowX,d.overflowY],"inline"===b.css(e,"display")&&"none"===b.css(e,"float")&&(b.support.inlineBlockNeedsLayout&&"inline"!==un(e.nodeName)?d.zoom=1:d.display="inline-block")),n.overflow&&(d.overflow="hidden",b.support.shrinkWrapBlocks||f.always(function(){d.overflow=n.overflow[0],d.overflowX=n.overflow[1],d.overflowY=n.overflow[2]}));for(i in t)if(a=t[i],Vn.exec(a)){if(delete t[i],u=u||"toggle"===a,a===(m?"hide":"show"))continue;g.push(i)}if(o=g.length){s=b._data(e,"fxshow")||b._data(e,"fxshow",{}),"hidden"in s&&(m=s.hidden),u&&(s.hidden=!m),m?b(e).show():f.done(function(){b(e).hide()}),f.done(function(){var t;b._removeData(e,"fxshow");for(t in h)b.style(e,t,h[t])});for(i=0;o>i;i++)r=g[i],l=f.createTween(r,m?s[r]:0),h[r]=s[r]||b.style(e,r),r in s||(s[r]=l.start,m&&(l.end=l.start,l.start="width"===r||"height"===r?1:0))}}function rr(e,t,n,r,i){return new rr.prototype.init(e,t,n,r,i)}b.Tween=rr,rr.prototype={constructor:rr,init:function(e,t,n,r,i,o){this.elem=e,this.prop=n,this.easing=i||"swing",this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=o||(b.cssNumber[n]?"":"px")},cur:function(){var e=rr.propHooks[this.prop];return e&&e.get?e.get(this):rr.propHooks._default.get(this)},run:function(e){var t,n=rr.propHooks[this.prop];return this.pos=t=this.options.duration?b.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):rr.propHooks._default.set(this),this}},rr.prototype.init.prototype=rr.prototype,rr.propHooks={_default:{get:function(e){var t;return null==e.elem[e.prop]||e.elem.style&&null!=e.elem.style[e.prop]?(t=b.css(e.elem,e.prop,""),t&&"auto"!==t?t:0):e.elem[e.prop]},set:function(e){b.fx.step[e.prop]?b.fx.step[e.prop](e):e.elem.style&&(null!=e.elem.style[b.cssProps[e.prop]]||b.cssHooks[e.prop])?b.style(e.elem,e.prop,e.now+e.unit):e.elem[e.prop]=e.now}}},rr.propHooks.scrollTop=rr.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},b.each(["toggle","show","hide"],function(e,t){var n=b.fn[t];b.fn[t]=function(e,r,i){return null==e||"boolean"==typeof e?n.apply(this,arguments):this.animate(ir(t,!0),e,r,i)}}),b.fn.extend({fadeTo:function(e,t,n,r){return this.filter(nn).css("opacity",0).show().end().animate({opacity:t},e,n,r)},animate:function(e,t,n,r){var i=b.isEmptyObject(e),o=b.speed(t,n,r),a=function(){var t=er(this,b.extend({},e),o);a.finish=function(){t.stop(!0)},(i||b._data(this,"finish"))&&t.stop(!0)};return a.finish=a,i||o.queue===!1?this.each(a):this.queue(o.queue,a)},stop:function(e,n,r){var i=function(e){var t=e.stop;delete e.stop,t(r)};return"string"!=typeof e&&(r=n,n=e,e=t),n&&e!==!1&&this.queue(e||"fx",[]),this.each(function(){var t=!0,n=null!=e&&e+"queueHooks",o=b.timers,a=b._data(this);if(n)a[n]&&a[n].stop&&i(a[n]);else for(n in a)a[n]&&a[n].stop&&Jn.test(n)&&i(a[n]);for(n=o.length;n--;)o[n].elem!==this||null!=e&&o[n].queue!==e||(o[n].anim.stop(r),t=!1,o.splice(n,1));(t||!r)&&b.dequeue(this,e)})},finish:function(e){return e!==!1&&(e=e||"fx"),this.each(function(){var t,n=b._data(this),r=n[e+"queue"],i=n[e+"queueHooks"],o=b.timers,a=r?r.length:0;for(n.finish=!0,b.queue(this,e,[]),i&&i.cur&&i.cur.finish&&i.cur.finish.call(this),t=o.length;t--;)o[t].elem===this&&o[t].queue===e&&(o[t].anim.stop(!0),o.splice(t,1));for(t=0;a>t;t++)r[t]&&r[t].finish&&r[t].finish.call(this);delete n.finish})}});function ir(e,t){var n,r={height:e},i=0;for(t=t?1:0;4>i;i+=2-t)n=Zt[i],r["margin"+n]=r["padding"+n]=e;return t&&(r.opacity=r.width=e),r}b.each({slideDown:ir("show"),slideUp:ir("hide"),slideToggle:ir("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(e,t){b.fn[e]=function(e,n,r){return this.animate(t,e,n,r)}}),b.speed=function(e,t,n){var r=e&&"object"==typeof e?b.extend({},e):{complete:n||!n&&t||b.isFunction(e)&&e,duration:e,easing:n&&t||t&&!b.isFunction(t)&&t};return r.duration=b.fx.off?0:"number"==typeof r.duration?r.duration:r.duration in b.fx.speeds?b.fx.speeds[r.duration]:b.fx.speeds._default,(null==r.queue||r.queue===!0)&&(r.queue="fx"),r.old=r.complete,r.complete=function(){b.isFunction(r.old)&&r.old.call(this),r.queue&&b.dequeue(this,r.queue)},r},b.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2}},b.timers=[],b.fx=rr.prototype.init,b.fx.tick=function(){var e,n=b.timers,r=0;for(Xn=b.now();n.length>r;r++)e=n[r],e()||n[r]!==e||n.splice(r--,1);n.length||b.fx.stop(),Xn=t},b.fx.timer=function(e){e()&&b.timers.push(e)&&b.fx.start()},b.fx.interval=13,b.fx.start=function(){Un||(Un=setInterval(b.fx.tick,b.fx.interval))},b.fx.stop=function(){clearInterval(Un),Un=null},b.fx.speeds={slow:600,fast:200,_default:400},b.fx.step={},b.expr&&b.expr.filters&&(b.expr.filters.animated=function(e){return b.grep(b.timers,function(t){return e===t.elem}).length}),b.fn.offset=function(e){if(arguments.length)return e===t?this:this.each(function(t){b.offset.setOffset(this,e,t)});var n,r,o={top:0,left:0},a=this[0],s=a&&a.ownerDocument;if(s)return n=s.documentElement,b.contains(n,a)?(typeof a.getBoundingClientRect!==i&&(o=a.getBoundingClientRect()),r=or(s),{top:o.top+(r.pageYOffset||n.scrollTop)-(n.clientTop||0),left:o.left+(r.pageXOffset||n.scrollLeft)-(n.clientLeft||0)}):o},b.offset={setOffset:function(e,t,n){var r=b.css(e,"position");"static"===r&&(e.style.position="relative");var i=b(e),o=i.offset(),a=b.css(e,"top"),s=b.css(e,"left"),u=("absolute"===r||"fixed"===r)&&b.inArray("auto",[a,s])>-1,l={},c={},p,f;u?(c=i.position(),p=c.top,f=c.left):(p=parseFloat(a)||0,f=parseFloat(s)||0),b.isFunction(t)&&(t=t.call(e,n,o)),null!=t.top&&(l.top=t.top-o.top+p),null!=t.left&&(l.left=t.left-o.left+f),"using"in t?t.using.call(e,l):i.css(l)}},b.fn.extend({position:function(){if(this[0]){var e,t,n={top:0,left:0},r=this[0];return"fixed"===b.css(r,"position")?t=r.getBoundingClientRect():(e=this.offsetParent(),t=this.offset(),b.nodeName(e[0],"html")||(n=e.offset()),n.top+=b.css(e[0],"borderTopWidth",!0),n.left+=b.css(e[0],"borderLeftWidth",!0)),{top:t.top-n.top-b.css(r,"marginTop",!0),left:t.left-n.left-b.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent||o.documentElement;while(e&&!b.nodeName(e,"html")&&"static"===b.css(e,"position"))e=e.offsetParent;return e||o.documentElement})}}),b.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(e,n){var r=/Y/.test(n);b.fn[e]=function(i){return b.access(this,function(e,i,o){var a=or(e);return o===t?a?n in a?a[n]:a.document.documentElement[i]:e[i]:(a?a.scrollTo(r?b(a).scrollLeft():o,r?o:b(a).scrollTop()):e[i]=o,t)},e,i,arguments.length,null)}});function or(e){return b.isWindow(e)?e:9===e.nodeType?e.defaultView||e.parentWindow:!1}b.each({Height:"height",Width:"width"},function(e,n){b.each({padding:"inner"+e,content:n,"":"outer"+e},function(r,i){b.fn[i]=function(i,o){var a=arguments.length&&(r||"boolean"!=typeof i),s=r||(i===!0||o===!0?"margin":"border");return b.access(this,function(n,r,i){var o;return b.isWindow(n)?n.document.documentElement["client"+e]:9===n.nodeType?(o=n.documentElement,Math.max(n.body["scroll"+e],o["scroll"+e],n.body["offset"+e],o["offset"+e],o["client"+e])):i===t?b.css(n,r,s):b.style(n,r,i,s)},n,a?i:t,a,null)}})}),e.jQuery=e.$=b,"function"==typeof define&&define.amd&&define.amd.jQuery&&define("jquery",[],function(){return b})})(window); \ No newline at end of file -- cgit v1.2.3 From e20faad8330af3e6f2edbd6e8dc3f70c05305492 Mon Sep 17 00:00:00 2001 From: Victor Westmann <victor.westmann@gmail.com> Date: Sun, 24 Mar 2013 10:28:51 +0100 Subject: Brazilian Portuguese language update --- inc/lang/pt-br/lang.php | 4 ++++ lib/plugins/acl/lang/pt-br/lang.php | 1 + lib/plugins/authad/lang/pt-br/settings.php | 16 ++++++++++++++++ lib/plugins/authldap/lang/pt-br/settings.php | 19 +++++++++++++++++++ lib/plugins/authmysql/lang/pt-br/settings.php | 18 ++++++++++++++++++ lib/plugins/authpgsql/lang/pt-br/settings.php | 25 +++++++++++++++++++++++++ lib/plugins/config/lang/pt-br/lang.php | 1 + lib/plugins/plugin/lang/pt-br/lang.php | 1 + lib/plugins/popularity/lang/pt-br/lang.php | 1 + lib/plugins/revert/lang/pt-br/lang.php | 1 + lib/plugins/usermanager/lang/pt-br/lang.php | 1 + 11 files changed, 88 insertions(+) create mode 100644 lib/plugins/authad/lang/pt-br/settings.php create mode 100644 lib/plugins/authldap/lang/pt-br/settings.php create mode 100644 lib/plugins/authmysql/lang/pt-br/settings.php create mode 100644 lib/plugins/authpgsql/lang/pt-br/settings.php diff --git a/inc/lang/pt-br/lang.php b/inc/lang/pt-br/lang.php index 992fae48a..a92afc0a0 100644 --- a/inc/lang/pt-br/lang.php +++ b/inc/lang/pt-br/lang.php @@ -19,6 +19,7 @@ * @author Isaias Masiero Filho <masiero@masiero.org> * @author Frederico Guimarães <frederico@teia.bio.br> * @author Balaco Baco <balacobaco@imap.cc> + * @author Victor Westmann <victor.westmann@gmail.com> */ $lang['encoding'] = 'utf-8'; $lang['direction'] = 'ltr'; @@ -299,6 +300,9 @@ $lang['i_pol1'] = 'Wiki público (leitura por todos, escrita e en $lang['i_pol2'] = 'Wiki fechado (leitura, escrita e envio de arquivos somente por usuários registrados)'; $lang['i_retry'] = 'Tentar novamente'; $lang['i_license'] = 'Por favor escolha a licença que voce deseja utilizar para seu conteúdo:'; +$lang['i_license_none'] = 'Não mostrar nenhuma informação da licença'; +$lang['i_pop_field'] = 'Por favor, nos ajude a melhorar sua experiência com DokuWiki:'; +$lang['i_pop_label'] = 'Uma vez por mês, enviar anonimamente informações de uso de dados para os desenvolvedores DokuWiki'; $lang['recent_global'] = 'Você está observando as alterações dentro do espaço de nomes <b>%s</b>. Também é possível ver as <a href="%s">modificações recentes no wiki inteiro</a>.'; $lang['years'] = '%d anos atrás'; $lang['months'] = '%d meses atrás'; diff --git a/lib/plugins/acl/lang/pt-br/lang.php b/lib/plugins/acl/lang/pt-br/lang.php index a0c997600..c49b430f8 100644 --- a/lib/plugins/acl/lang/pt-br/lang.php +++ b/lib/plugins/acl/lang/pt-br/lang.php @@ -19,6 +19,7 @@ * @author Sergio Motta sergio@cisne.com.br * @author Isaias Masiero Filho <masiero@masiero.org> * @author Balaco Baco <balacobaco@imap.cc> + * @author Victor Westmann <victor.westmann@gmail.com> */ $lang['admin_acl'] = 'Administração da Lista de Controles de Acesso'; $lang['acl_group'] = 'Grupo'; diff --git a/lib/plugins/authad/lang/pt-br/settings.php b/lib/plugins/authad/lang/pt-br/settings.php new file mode 100644 index 000000000..b8b1efd42 --- /dev/null +++ b/lib/plugins/authad/lang/pt-br/settings.php @@ -0,0 +1,16 @@ +<?php +/** + * Brazilian Portuguese language file + * + * @author Victor Westmann <victor.westmann@gmail.com> + */ +$lang['account_suffix'] = 'Sufixo de sua conta. Eg. <code>@meu.domínio.org</code>'; +$lang['base_dn'] = 'Sua base DN. Eg. <code>DC=meu,DC=domínio,DC=org</code>'; +$lang['domain_controllers'] = 'Uma lista de controles de domínios separada por vírgulas. Eg. <code>srv1.domínio.org,srv2.domínio.org</code>'; +$lang['ad_password'] = 'A senha do usuário acima.'; +$lang['sso'] = 'Usar Single-Sign-On através do Kerberos ou NTLM?'; +$lang['use_ssl'] = 'Usar conexão SSL? Se usar, não habilitar TLS abaixo.'; +$lang['use_tls'] = 'Usar conexão TLS? se usar, não habilitar SSL acima.'; +$lang['debug'] = 'Mostrar saída adicional de depuração em mensagens de erros?'; +$lang['expirywarn'] = 'Dias com antecedência para avisar o usuário de uma senha que vai expirar. 0 para desabilitar.'; +$lang['additional'] = 'Uma lista separada de vírgulas de atributos adicionais AD para pegar dados de usuários. Usados por alguns plugins.'; diff --git a/lib/plugins/authldap/lang/pt-br/settings.php b/lib/plugins/authldap/lang/pt-br/settings.php new file mode 100644 index 000000000..daf9efd00 --- /dev/null +++ b/lib/plugins/authldap/lang/pt-br/settings.php @@ -0,0 +1,19 @@ +<?php +/** + * Brazilian Portuguese language file + * + * @author Victor Westmann <victor.westmann@gmail.com> + */ +$lang['server'] = 'Seu servidor LDAP. Ou hostname (<code>localhost</code>) ou uma URL completa (<code>ldap://server.tld:389</code>)'; +$lang['port'] = 'Porta LDAP do servidor se nenhuma URL completa tiver sido fornecida acima'; +$lang['usertree'] = 'Onde encontrar as contas de usuários. Eg. <code>ou=Pessoas, dc=servidor, dc=tld</code>'; +$lang['grouptree'] = 'Onde encontrar os grupos de usuários. Eg. <code>ou=Pessoas, dc=servidor, dc=tld</code>'; +$lang['version'] = 'A versão do protocolo para usar. Você talvez deva definir isto para <code>3</code>'; +$lang['starttls'] = 'Usar conexões TLS?'; +$lang['referrals'] = 'Permitir referências serem seguidas?'; +$lang['binddn'] = 'DN de um vínculo opcional de usuário se vínculo anônimo não for suficiente. Eg. <code>cn=admin, dc=my, dc=home</code>'; +$lang['bindpw'] = 'Senha do usuário acima'; +$lang['userscope'] = 'Limitar escopo da busca para busca de usuário'; +$lang['groupscope'] = 'Limitar escopo da busca para busca de grupo'; +$lang['groupkey'] = 'Membro de grupo vem de qualquer atributo do usuário (ao invés de grupos padrões AD) e.g. departamento de grupo ou número de telefone'; +$lang['debug'] = 'Mostrar informações adicionais de depuração em erros'; diff --git a/lib/plugins/authmysql/lang/pt-br/settings.php b/lib/plugins/authmysql/lang/pt-br/settings.php new file mode 100644 index 000000000..59976ed65 --- /dev/null +++ b/lib/plugins/authmysql/lang/pt-br/settings.php @@ -0,0 +1,18 @@ +<?php +/** + * Brazilian Portuguese language file + * + * @author Victor Westmann <victor.westmann@gmail.com> + */ +$lang['server'] = 'Seu servidor MySQL'; +$lang['user'] = 'usuário MySQL'; +$lang['password'] = 'Senha do usuário acima'; +$lang['database'] = 'Base de dados para usar'; +$lang['charset'] = 'Codificação de caracter usado na base de dados'; +$lang['debug'] = 'Mostrar informações adicionais de depuração'; +$lang['forwardClearPass'] = 'Passar senhas de usuários como texto puro para comandos SQL abaixo, ao invés de usar opção passcrypt'; +$lang['TablesToLock'] = 'Lista separada por vírgulas para tabelas que devem estar travadas em operações de escrita'; +$lang['checkPass'] = 'Comandos SQL para verificar senhas'; +$lang['debug_o_0'] = 'nenhum'; +$lang['debug_o_1'] = 'apenas em erros'; +$lang['debug_o_2'] = 'todas as queries SQL'; diff --git a/lib/plugins/authpgsql/lang/pt-br/settings.php b/lib/plugins/authpgsql/lang/pt-br/settings.php new file mode 100644 index 000000000..714f01163 --- /dev/null +++ b/lib/plugins/authpgsql/lang/pt-br/settings.php @@ -0,0 +1,25 @@ +<?php +/** + * Brazilian Portuguese language file + * + * @author Victor Westmann <victor.westmann@gmail.com> + */ +$lang['server'] = 'Seu servidor PostgreSQL'; +$lang['port'] = 'Sua porta do servidor PostgreSQL'; +$lang['user'] = 'Nome de usuário PostgreSQL'; +$lang['password'] = 'Senha do usuário acima'; +$lang['database'] = 'Base de dados para usar'; +$lang['getUsers'] = 'Comando SQL para listar todos os usuários'; +$lang['FilterLogin'] = 'Cláusula SQL para filtrar usuários pelo nome de login'; +$lang['FilterName'] = 'Cláusula SQL para filtrar usuários pelo nome completo'; +$lang['FilterEmail'] = 'Cláusula SQL para filtrar usuários pelo endereço de email'; +$lang['FilterGroup'] = 'Cláusula SQL para filtrar usuários pelo grupo que pertencem'; +$lang['SortOrder'] = 'Comando SQL para adicionar novo grupo'; +$lang['addUser'] = 'Comando SQL para adicionar novo usuário'; +$lang['addGroup'] = 'Comando SQL para adicionar novo grupo'; +$lang['addUserGroup'] = 'Comando SQL para adicionar um usuário a um grupo existente'; +$lang['delGroup'] = 'Comando SQL para remover um grupo'; +$lang['getUserID'] = 'Comando SQL para obter chave primária de usuário'; +$lang['delUser'] = 'Comando SQL para apagar usuário'; +$lang['delUserRefs'] = 'Comando SQL para remover um usuário de todos os grupos'; +$lang['updateUser'] = 'Comando SQL para atualizar perfil de usuário'; diff --git a/lib/plugins/config/lang/pt-br/lang.php b/lib/plugins/config/lang/pt-br/lang.php index 7151713d8..85218439a 100644 --- a/lib/plugins/config/lang/pt-br/lang.php +++ b/lib/plugins/config/lang/pt-br/lang.php @@ -16,6 +16,7 @@ * @author Sergio Motta sergio@cisne.com.br * @author Isaias Masiero Filho <masiero@masiero.org> * @author Balaco Baco <balacobaco@imap.cc> + * @author Victor Westmann <victor.westmann@gmail.com> */ $lang['menu'] = 'Configurações do DokuWiki'; $lang['error'] = 'As configurações não foram atualizadas devido a um valor inválido. Por favor, reveja suas alterações e reenvie-as.<br />O(s) valor(es) incorreto(s) serão exibidos contornados por uma borda vermelha.'; diff --git a/lib/plugins/plugin/lang/pt-br/lang.php b/lib/plugins/plugin/lang/pt-br/lang.php index 26e73f4fc..437b6ca57 100644 --- a/lib/plugins/plugin/lang/pt-br/lang.php +++ b/lib/plugins/plugin/lang/pt-br/lang.php @@ -16,6 +16,7 @@ * @author Sergio Motta sergio@cisne.com.br * @author Isaias Masiero Filho <masiero@masiero.org> * @author Balaco Baco <balacobaco@imap.cc> + * @author Victor Westmann <victor.westmann@gmail.com> */ $lang['menu'] = 'Gerenciar Plug-ins'; $lang['download'] = 'Baixar e instalar um novo plug-in'; diff --git a/lib/plugins/popularity/lang/pt-br/lang.php b/lib/plugins/popularity/lang/pt-br/lang.php index 44d811d81..c2ec36145 100644 --- a/lib/plugins/popularity/lang/pt-br/lang.php +++ b/lib/plugins/popularity/lang/pt-br/lang.php @@ -15,6 +15,7 @@ * @author Sergio Motta sergio@cisne.com.br * @author Isaias Masiero Filho <masiero@masiero.org> * @author Balaco Baco <balacobaco@imap.cc> + * @author Victor Westmann <victor.westmann@gmail.com> */ $lang['name'] = 'Retorno de popularidade (pode demorar um pouco para carregar)'; $lang['submit'] = 'Enviar dados'; diff --git a/lib/plugins/revert/lang/pt-br/lang.php b/lib/plugins/revert/lang/pt-br/lang.php index c4a2f742b..b74e0408f 100644 --- a/lib/plugins/revert/lang/pt-br/lang.php +++ b/lib/plugins/revert/lang/pt-br/lang.php @@ -16,6 +16,7 @@ * @author Sergio Motta sergio@cisne.com.br * @author Isaias Masiero Filho <masiero@masiero.org> * @author Balaco Baco <balacobaco@imap.cc> + * @author Victor Westmann <victor.westmann@gmail.com> */ $lang['menu'] = 'Gerenciador de reversões'; $lang['filter'] = 'Procura por páginas com spam'; diff --git a/lib/plugins/usermanager/lang/pt-br/lang.php b/lib/plugins/usermanager/lang/pt-br/lang.php index 285231f35..637be8860 100644 --- a/lib/plugins/usermanager/lang/pt-br/lang.php +++ b/lib/plugins/usermanager/lang/pt-br/lang.php @@ -16,6 +16,7 @@ * @author Sergio Motta sergio@cisne.com.br * @author Isaias Masiero Filho <masiero@masiero.org> * @author Balaco Baco <balacobaco@imap.cc> + * @author Victor Westmann <victor.westmann@gmail.com> */ $lang['menu'] = 'Gerenciamento de Usuários'; $lang['noauth'] = '(o gerenciamento de usuários não está disponível)'; -- cgit v1.2.3 From 14bc69e3e1db81c4d329a140cb0e095f0dcf9b5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EB=AA=85=EC=A7=84?= <aranet100@gmail.com> Date: Sun, 24 Mar 2013 10:30:58 +0100 Subject: Korean language update --- inc/lang/ko/backlinks.txt | 2 +- inc/lang/ko/conflict.txt | 6 +- inc/lang/ko/denied.txt | 2 +- inc/lang/ko/diff.txt | 2 +- inc/lang/ko/draft.txt | 2 +- inc/lang/ko/editrev.txt | 2 +- inc/lang/ko/install.html | 6 +- inc/lang/ko/lang.php | 115 ++++++++++++++------------- inc/lang/ko/locked.txt | 2 +- inc/lang/ko/mailtext.txt | 4 +- inc/lang/ko/norev.txt | 4 +- inc/lang/ko/preview.txt | 2 +- inc/lang/ko/pwconfirm.txt | 2 +- inc/lang/ko/read.txt | 3 +- inc/lang/ko/recent.txt | 2 +- inc/lang/ko/resendpwd.txt | 4 +- inc/lang/ko/revisions.txt | 4 +- inc/lang/ko/searchpage.txt | 2 +- inc/lang/ko/showrev.txt | 4 +- inc/lang/ko/stopwords.txt | 2 +- inc/lang/ko/subscr_digest.txt | 6 +- inc/lang/ko/subscr_list.txt | 2 +- inc/lang/ko/subscr_single.txt | 6 +- inc/lang/ko/updateprofile.txt | 2 +- inc/lang/ko/uploadmail.txt | 2 +- lib/plugins/acl/lang/ko/help.txt | 11 +-- lib/plugins/acl/lang/ko/lang.php | 11 ++- lib/plugins/authad/lang/ko/settings.php | 14 ++++ lib/plugins/authldap/lang/ko/settings.php | 10 +++ lib/plugins/authmysql/lang/ko/settings.php | 41 ++++++++++ lib/plugins/authpgsql/lang/ko/settings.php | 37 +++++++++ lib/plugins/config/lang/ko/lang.php | 23 +++--- lib/plugins/plugin/lang/ko/lang.php | 13 ++- lib/plugins/popularity/lang/ko/intro.txt | 4 +- lib/plugins/popularity/lang/ko/lang.php | 11 ++- lib/plugins/popularity/lang/ko/submitted.txt | 2 +- lib/plugins/revert/lang/ko/intro.txt | 4 +- lib/plugins/revert/lang/ko/lang.php | 21 +++-- lib/plugins/usermanager/lang/ko/lang.php | 29 ++++--- 39 files changed, 258 insertions(+), 163 deletions(-) create mode 100644 lib/plugins/authad/lang/ko/settings.php create mode 100644 lib/plugins/authldap/lang/ko/settings.php create mode 100644 lib/plugins/authmysql/lang/ko/settings.php create mode 100644 lib/plugins/authpgsql/lang/ko/settings.php diff --git a/inc/lang/ko/backlinks.txt b/inc/lang/ko/backlinks.txt index ce77ca5a7..85fdfa3da 100644 --- a/inc/lang/ko/backlinks.txt +++ b/inc/lang/ko/backlinks.txt @@ -1,3 +1,3 @@ -====== 가리키는 링크 ====== +====== 백링크 ====== 현재 문서를 가리키는 링크가 있는 문서 목록입니다. diff --git a/inc/lang/ko/conflict.txt b/inc/lang/ko/conflict.txt index 43988a62b..9b7764d46 100644 --- a/inc/lang/ko/conflict.txt +++ b/inc/lang/ko/conflict.txt @@ -1,5 +1,5 @@ -====== 새 버전 있음 ====== +====== 새 판 있음 ====== -편집한 문서의 새 버전이 있습니다. 당신이 편집하고 있는 동안 다른 사람이 같은 파일을 편집하였을 경우 이런 일이 생길 수 있습니다. +편집한 문서의 새 판이 있습니다. 당신이 편집하고 있는 동안 다른 사람이 같은 파일을 편집하였을 경우 이런 일이 생길 수 있습니다. -아래의 차이를 철저하게 검토하고 어떤 버전을 저장하실지 결정하십시오. **저장**을 선택하면, 당신의 버전이 저장됩니다. **취소**를 선택하면 현재 버전이 유지됩니다. \ No newline at end of file +아래의 차이를 철저하게 검토하고 어떤 판을 저장하실지 결정하세요. **저장**을 선택하면 당신의 판이 저장됩니다. **취소**를 선택하면 현재 판이 유지됩니다. \ No newline at end of file diff --git a/inc/lang/ko/denied.txt b/inc/lang/ko/denied.txt index f384a0a8c..89d417f7b 100644 --- a/inc/lang/ko/denied.txt +++ b/inc/lang/ko/denied.txt @@ -1,3 +1,3 @@ ====== 권한 거절 ====== -계속할 수 있는 권한이 없습니다. 로그인하십시오. \ No newline at end of file +계속할 수 있는 권한이 없습니다. 로그인하세요. \ No newline at end of file diff --git a/inc/lang/ko/diff.txt b/inc/lang/ko/diff.txt index 76b488d90..8237342f7 100644 --- a/inc/lang/ko/diff.txt +++ b/inc/lang/ko/diff.txt @@ -1,3 +1,3 @@ ====== 차이 ====== -이 문서의 선택한 이전 버전과 현재 버전 사이의 차이를 보여줍니다. \ No newline at end of file +이 문서의 선택한 이전 판과 현재 판 사이의 차이를 보여줍니다. \ No newline at end of file diff --git a/inc/lang/ko/draft.txt b/inc/lang/ko/draft.txt index 861834e5d..f7787f981 100644 --- a/inc/lang/ko/draft.txt +++ b/inc/lang/ko/draft.txt @@ -2,4 +2,4 @@ 이 문서의 마지막 편집 세션은 정상적으로 끝나지 않았습니다. DokuWiki는 작업 도중 자동으로 저장된 문서 초안을 사용하여 편집을 계속 할 수 있습니다. 마지막 세션 동안 저장된 문서 초안을 아래에서 볼 수 있습니다. -비정상적으로 끝난 편집 세션을 **복구**할지 여부를 결정하고, 자동으로 저장되었던 초안을 **삭제**하거나 편집 과정을 **취소**하기 바랍니다. \ No newline at end of file +비정상적으로 끝난 편집 세션을 **되돌릴**지 여부를 결정하고, 자동으로 저장되었던 초안을 **삭제**하거나 편집 과정을 **취소**하세요. \ No newline at end of file diff --git a/inc/lang/ko/editrev.txt b/inc/lang/ko/editrev.txt index 136eef733..911ea5f1b 100644 --- a/inc/lang/ko/editrev.txt +++ b/inc/lang/ko/editrev.txt @@ -1,2 +1,2 @@ -**문서의 이전 버전을 선택하였습니다!** 저장할 경우 이 데이터로 새 버전을 만듭니다. +**문서의 이전 판을 선택했습니다!** 저장할 경우 이 데이터로 새 판을 만듭니다. ---- \ No newline at end of file diff --git a/inc/lang/ko/install.html b/inc/lang/ko/install.html index aeeac870f..a87bb6382 100644 --- a/inc/lang/ko/install.html +++ b/inc/lang/ko/install.html @@ -1,14 +1,14 @@ <p>이 페이지는 <a href="http://dokuwiki.org">Dokuwiki</a> 설치와 환경 설정을 도와줍니다. 설치 과정에 대한 더 자세한 정보는 <a href="http://dokuwiki.org/ko:install">(한국어) 설치 문서</a>와 -<a href="http://dokuwiki.org/install">(영어) 설치 문서</a>를 참고하기 바랍니다.</p> +<a href="http://dokuwiki.org/install">(영어) 설치 문서</a>를 참고하시기 바랍니다.</p> -<p>DokuWiki는 위키 문서와 문서와 관련된 정보(예를 들어 그림, 검색 색인, 이전 버전 문서)를 저장하기 위해 일반적인 텍스트 파일을 사용합니다. 정상적으로 DokuWiki를 사용하려면 이 파일을 담고 있는 디렉토리에 대한 쓰기 권한을 가지고 있어야 합니다. +<p>DokuWiki는 위키 문서와 문서와 관련된 정보(예를 들어 그림, 검색 색인, 이전 판 문서)를 저장하기 위해 일반적인 텍스트 파일을 사용합니다. 정상적으로 DokuWiki를 사용하려면 이 파일을 담고 있는 디렉토리에 대한 쓰기 권한을 가지고 있어야 합니다. 현재 설치 과정 중에는 디렉토리 권한 설정이 불가능합니다. 보통 직접 쉘 명령어를 사용하거나, 호스팅을 사용한다면 FTP나 호스팅 제어판(예를 들어 CPanel)을 사용해서 설정해야 합니다.</p> <p>현재 설치 과정중에 관리자로 로그인 후 DokuWiki의 관리 메뉴(플러그인 설치, 사용자 관리, 위키 문서 접근 권한 관리, 옵션 설정)를 가능하게 <acronym title="접근 제어 목록">ACL</acronym>에 대한 환경 설정을 수행합니다. DokuWiki가 동작하는데 필요한 사항은 아니지만, 어쨌든 더 쉽게 관리자가 관리할 수 있도록 해줍니다.</p> -<p>숙련된 사용자나 특별한 설치 과정이 필요한 경우에 다음 링크를 참고하기 바랍니다: +<p>숙련된 사용자나 특별한 설치 과정이 필요한 경우에 다음 링크를 참고하시기 바랍니다: <a href="http://dokuwiki.org/ko:install">설치 과정 (한국어)</a> 과 <a href="http://dokuwiki.org/ko:config">환경 설정 (한국어),</a> <a href="http://dokuwiki.org/install">설치 과정 (영어)</a> diff --git a/inc/lang/ko/lang.php b/inc/lang/ko/lang.php index e5b21aef8..dd3d6747b 100644 --- a/inc/lang/ko/lang.php +++ b/inc/lang/ko/lang.php @@ -1,8 +1,8 @@ <?php /** - * korean language file + * Korean language file * - * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) + * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) * @author Hyun Kim <lawfully@gmail.com> * @author jk Lee * @author dongnak@gmail.com @@ -28,7 +28,7 @@ $lang['btn_preview'] = '미리 보기'; $lang['btn_top'] = '맨 위로'; $lang['btn_newer'] = '<< 최근'; $lang['btn_older'] = '이전 >>'; -$lang['btn_revs'] = '이전 버전'; +$lang['btn_revs'] = '이전 판'; $lang['btn_recent'] = '최근 바뀜'; $lang['btn_upload'] = '올리기'; $lang['btn_cancel'] = '취소'; @@ -40,16 +40,16 @@ $lang['btn_admin'] = '관리'; $lang['btn_update'] = '바꾸기'; $lang['btn_delete'] = '삭제'; $lang['btn_back'] = '뒤로'; -$lang['btn_backlink'] = '가리키는 링크'; +$lang['btn_backlink'] = '백링크'; $lang['btn_backtomedia'] = '미디어 파일 선택으로 돌아가기'; $lang['btn_subscribe'] = '구독 관리'; $lang['btn_profile'] = '개인 정보 바꾸기'; $lang['btn_reset'] = '초기화'; $lang['btn_resendpwd'] = '새 비밀번호 설정'; $lang['btn_draft'] = '문서 초안 편집'; -$lang['btn_recover'] = '문서 초안 복구'; +$lang['btn_recover'] = '문서 초안 되돌리기'; $lang['btn_draftdel'] = '문서 초안 삭제'; -$lang['btn_revert'] = '복원'; +$lang['btn_revert'] = '되돌리기'; $lang['btn_register'] = '등록'; $lang['btn_apply'] = '적용'; $lang['btn_media'] = '미디어 관리'; @@ -63,7 +63,7 @@ $lang['remember'] = '기억하기'; $lang['fullname'] = '실제 이름'; $lang['email'] = '이메일'; $lang['profile'] = '개인 정보'; -$lang['badlogin'] = '잘못된 사용자 이름이거나 비밀번호입니다.'; +$lang['badlogin'] = '사용자 이름이거나 비밀번호가 잘못되었습니다.'; $lang['minoredit'] = '사소한 바뀜'; $lang['draftdate'] = '문서 초안 자동 저장 시간'; $lang['nosecedit'] = '한동안 문서가 바뀌어 세션 정보의 유효 시간이 지나 문서 전부를 다시 읽습니다.'; @@ -71,21 +71,21 @@ $lang['regmissing'] = '모든 항목을 입력해야 합니다.'; $lang['reguexists'] = '같은 이름을 사용하는 사용자가 있습니다.'; $lang['regsuccess'] = '사용자를 만들었으며 비밀번호는 이메일로 보냈습니다.'; $lang['regsuccess2'] = '사용자를 만들었습니다.'; -$lang['regmailfail'] = '비밀번호를 이메일로 전송할 때 오류가 발생했습니다. 관리자에게 문의하기 바랍니다!'; -$lang['regbadmail'] = '이메일 주소가 잘못됐습니다 - 오류라고 생각하면 관리자에게 문의하기 바랍니다.'; -$lang['regbadpass'] = '새 비밀번호가 일치하지 않습니다. 다시 입력하기 바랍니다.'; +$lang['regmailfail'] = '비밀번호를 이메일로 보낼 때 오류가 발생했습니다. 관리자에게 문의하시기 바랍니다!'; +$lang['regbadmail'] = '이메일 주소가 잘못됐습니다 - 오류라고 생각하면 관리자에게 문의하시기 바랍니다.'; +$lang['regbadpass'] = '새 비밀번호가 일치하지 않습니다. 다시 입력하세요.'; $lang['regpwmail'] = 'DokuWiki 비밀번호'; $lang['reghere'] = '계정이 없나요? 계정을 등록할 수 있습니다'; $lang['profna'] = '이 위키는 개인 정보 수정을 허용하지 않습니다'; -$lang['profnochange'] = '바뀐 사항이 없습니다.'; +$lang['profnochange'] = '바뀜이 없습니다.'; $lang['profnoempty'] = '이름이나 이메일 주소가 비었습니다.'; $lang['profchanged'] = '개인 정보가 성공적으로 바뀌었습니다.'; -$lang['pwdforget'] = '비밀번호를 잊으셨나요? 새로 발급받을 수 있습니다'; -$lang['resendna'] = '이 위키는 비밀번호 재발급을 지원하지 않습니다.'; -$lang['resendpwd'] = '다음으로 새 비밀번호 전송'; +$lang['pwdforget'] = '비밀번호를 잊으셨나요? 비밀번호를 재설정할 수 있습니다'; +$lang['resendna'] = '이 위키는 비밀번호 재설정을 지원하지 않습니다.'; +$lang['resendpwd'] = '다음으로 새 비밀번호 보내기'; $lang['resendpwdmissing'] = '모든 비밀번호를 입력해야 합니다.'; $lang['resendpwdnouser'] = '등록된 사용자가 아닙니다.'; -$lang['resendpwdbadauth'] = '인증 코드가 잘못됐습니다. 잘못된 링크인지 확인 바랍니다.'; +$lang['resendpwdbadauth'] = '인증 코드가 잘못됐습니다. 잘못된 링크인지 확인하시기 바랍니다.'; $lang['resendpwdconfirm'] = '확인 링크를 이메일로 보냈습니다.'; $lang['resendpwdsuccess'] = '새로운 비밀번호를 이메일로 보냈습니다.'; $lang['license'] = '별도로 라이선스를 알리지 않을 경우, 이 위키의 내용은 다음의 라이선스에 따릅니다:'; @@ -94,14 +94,14 @@ $lang['searchmedia'] = '파일 이름 찾기:'; $lang['searchmedia_in'] = '%s에서 찾기'; $lang['txt_upload'] = '올릴 파일 선택'; $lang['txt_filename'] = '올릴 파일 이름 입력 (선택 사항)'; -$lang['txt_overwrt'] = '이전 파일을 새로운 파일로 덮어쓰기'; -$lang['maxuploadsize'] = '최대 올리기 용량. 파일당 %s'; +$lang['txt_overwrt'] = '기존 파일에 덮어쓰기'; +$lang['maxuploadsize'] = '최대 올리기 용량입니다. 파일당 %s입니다.'; $lang['lockedby'] = '현재 잠겨진 사용자'; $lang['lockexpire'] = '잠금 해제 시간'; -$lang['js']['willexpire'] = '잠시 후 편집 잠금이 해제됩니다.\n편집 충돌을 피하려면 미리 보기를 눌러 잠금 시간을 다시 설정하기 바랍니다.'; +$lang['js']['willexpire'] = '잠시 후 편집 잠금이 해제됩니다.\n편집 충돌을 피하려면 미리 보기를 눌러 잠금 시간을 다시 설정하세요.'; $lang['js']['notsavedyet'] = '저장하지 않은 바뀜이 지워집니다.'; $lang['js']['searchmedia'] = '파일 찾기'; -$lang['js']['keepopen'] = '선택할 때 창을 열어놓기'; +$lang['js']['keepopen'] = '선택할 때 창을 열어 놓기'; $lang['js']['hidedetails'] = '자세한 정보 숨기기'; $lang['js']['mediatitle'] = '링크 설정'; $lang['js']['mediadisplay'] = '링크 형태'; @@ -128,7 +128,7 @@ $lang['js']['nosmblinks'] = '윈도우 공유 파일과의 연결은 마이 $lang['js']['linkwiz'] = '링크 마법사'; $lang['js']['linkto'] = '다음으로 연결:'; $lang['js']['del_confirm'] = '정말 선택된 항목을 삭제하겠습니까?'; -$lang['js']['restore_confirm'] = '정말 이 버전으로 되돌리겠습니까?'; +$lang['js']['restore_confirm'] = '정말 이 판으로 되돌리겠습니까?'; $lang['js']['media_diff'] = '차이 보기:'; $lang['js']['media_diff_both'] = '나란히 보기'; $lang['js']['media_diff_opacity'] = '겹쳐 보기'; @@ -138,26 +138,26 @@ $lang['js']['media_upload_btn'] = '올리기'; $lang['js']['media_done_btn'] = '완료'; $lang['js']['media_drop'] = '올릴 파일을 끌어넣으세요'; $lang['js']['media_cancel'] = '삭제'; -$lang['js']['media_overwrt'] = '이미 있는 파일 덮어쓰기'; -$lang['rssfailed'] = '이 피드를 가져오는 동안 오류 발생:'; +$lang['js']['media_overwrt'] = '기존 파일에 덮어쓰기'; +$lang['rssfailed'] = '이 피드를 가져오는 동안 오류가 발생했습니다:'; $lang['nothingfound'] = '아무 것도 없습니다.'; $lang['mediaselect'] = '미디어 파일 선택'; $lang['fileupload'] = '미디어 파일 올리기'; $lang['uploadsucc'] = '올리기 성공'; -$lang['uploadfail'] = '올리기 실패. 잘못된 권한 때문일지도 모릅니다.'; -$lang['uploadwrong'] = '올리기 거부. 금지된 확장자입니다!'; +$lang['uploadfail'] = '올리기를 실패했습니다. 잘못된 권한 때문일지도 모릅니다.'; +$lang['uploadwrong'] = '올리기를 거부했습니다. 금지된 확장자입니다!'; $lang['uploadexist'] = '파일이 이미 존재합니다.'; $lang['uploadbadcontent'] = '올린 파일이 %s 파일 확장자와 일치하지 않습니다.'; $lang['uploadspam'] = '스팸 차단 목록이 올리기를 취소했습니다.'; $lang['uploadxss'] = '악성 코드의 가능성이 있어 올리기를 취소했습니다.'; $lang['uploadsize'] = '올린 파일이 너무 큽니다. (최대 %s)'; $lang['deletesucc'] = '"%s" 파일이 삭제되었습니다.'; -$lang['deletefail'] = '"%s" 파일을 삭제할 수 없습니다 - 삭제 권한이 있는지 확인하기 바랍니다.'; +$lang['deletefail'] = '"%s" 파일을 삭제할 수 없습니다 - 삭제 권한이 있는지 확인하세요.'; $lang['mediainuse'] = '"%s" 파일을 삭제할 수 없습니다 - 아직 사용 중입니다.'; $lang['namespaces'] = '이름공간'; $lang['mediafiles'] = '사용 가능한 파일 목록'; $lang['accessdenied'] = '이 문서를 볼 권한이 없습니다.'; -$lang['mediausage'] = '이 파일을 참고하려면 다음 문법을 사용하기 바랍니다:'; +$lang['mediausage'] = '이 파일을 참고하려면 다음 문법을 사용하세요:'; $lang['mediaview'] = '원본 파일 보기'; $lang['mediaroot'] = '루트 (root)'; $lang['mediaupload'] = '파일을 현재 이름공간으로 올립니다. 하위 이름공간으로 만들려면 선택한 파일 이름 앞에 콜론(:)으로 구분되는 이름을 붙이면 됩니다. 파일을 드래그 앤 드롭하여 선택할 수 있습니다.'; @@ -169,22 +169,22 @@ $lang['hits'] = '조회 수'; $lang['quickhits'] = '일치하는 문서 이름'; $lang['toc'] = '목차'; $lang['current'] = '현재'; -$lang['yours'] = '버전'; -$lang['diff'] = '현재 버전과의 차이 보기'; -$lang['diff2'] = '선택한 버전 간 차이 보기'; -$lang['difflink'] = '차이 보기로 연결'; -$lang['diff_type'] = '버전간 차이 보기:'; +$lang['yours'] = '판'; +$lang['diff'] = '현재 판과의 차이 보기'; +$lang['diff2'] = '선택한 판 간 차이 보기'; +$lang['difflink'] = '차이 보기로 링크'; +$lang['diff_type'] = '차이 보기:'; $lang['diff_inline'] = '인라인 방식'; $lang['diff_side'] = '다중 창 방식'; $lang['line'] = '줄'; $lang['breadcrumb'] = '추적'; $lang['youarehere'] = '현재 위치'; -$lang['lastmod'] = '마지막 수정'; +$lang['lastmod'] = '마지막으로 수정함'; $lang['by'] = '작성자'; -$lang['deleted'] = '삭제'; +$lang['deleted'] = '삭제함'; $lang['created'] = '새로 만듦'; -$lang['restored'] = '이전 버전 복구 (%s)'; -$lang['external_edit'] = '외부 편집기'; +$lang['restored'] = '이전 판으로 되돌림 (%s)'; +$lang['external_edit'] = '바깥 편집기'; $lang['summary'] = '편집 요약'; $lang['noflash'] = '이 콘텐츠를 표시하기 위해서 <a href="http://www.adobe.com/products/flashplayer/">Adobe Flash 플러그인</a>이 필요합니다.'; $lang['download'] = '조각 다운로드'; @@ -246,48 +246,51 @@ $lang['img_keywords'] = '키워드'; $lang['img_width'] = '너비'; $lang['img_height'] = '높이'; $lang['img_manager'] = '미디어 관리자에서 보기'; -$lang['subscr_subscribe_success'] = '%s을(를) 구독 목록 %s에 추가하였습니다'; -$lang['subscr_subscribe_error'] = '%s을(를) 구독 목록 %s에 추가하는데 실패했습니다'; +$lang['subscr_subscribe_success'] = '%s을(를) %s 구독 목록에 추가하였습니다'; +$lang['subscr_subscribe_error'] = '%s을(를) %s 구독 목록에 추가하는데 실패했습니다'; $lang['subscr_subscribe_noaddress'] = '등록된 주소가 없기 때문에 구독 목록에 등록되지 않았습니다'; -$lang['subscr_unsubscribe_success'] = '%s을(를) 구독 목록 %s에서 삭제하였습니다'; -$lang['subscr_unsubscribe_error'] = '%s을(를) 구독 목록 %s에서 삭제하는데 실패했습니다'; +$lang['subscr_unsubscribe_success'] = '%s을(를) %s 구독 목록에서 삭제하였습니다'; +$lang['subscr_unsubscribe_error'] = '%s을(를) %s 구독 목록에서 삭제하는데 실패했습니다'; $lang['subscr_already_subscribed'] = '%s은(는) 이미 %s에 구독되고 있습니다'; $lang['subscr_not_subscribed'] = '%s은(는) 이미 %s에 구독되어 있지 않습니다'; -$lang['subscr_m_not_subscribed'] = '현재의 문서나 이름공간에 구독 등록이 되어있지 않습니다.'; +$lang['subscr_m_not_subscribed'] = '현재의 문서나 이름공간에 구독 등록이 되어 있지 않습니다.'; $lang['subscr_m_new_header'] = '구독 추가'; -$lang['subscr_m_current_header'] = '현재 구독 중인 것'; +$lang['subscr_m_current_header'] = '현재 구독 중인 문서'; $lang['subscr_m_unsubscribe'] = '구독 취소'; $lang['subscr_m_subscribe'] = '구독'; $lang['subscr_m_receive'] = '받기'; $lang['subscr_style_every'] = '모든 바뀜을 이메일로 받기'; $lang['subscr_style_digest'] = '각 문서의 바뀜을 요약 (매 %.2f일 마다)'; $lang['subscr_style_list'] = '마지막 이메일 이후 바뀐 문서의 목록 (매 %.2f일 마다)'; -$lang['authmodfailed'] = '잘못된 사용자 인증 설정입니다. 관리자에게 문의하기 바랍니다.'; -$lang['authtempfail'] = '사용자 인증이 일시적으로 불가능합니다. 만일 계속해서 문제가 발생하면 관리자에게 문의하기 바랍니다.'; -$lang['authpwdexpire'] = '현재 비밀번호를 설정한지 %d일이 지났습니다. 새로 설정해주시기 바랍니다.'; +$lang['authmodfailed'] = '잘못된 사용자 인증 설정입니다. 관리자에게 문의하시기 바랍니다.'; +$lang['authtempfail'] = '사용자 인증이 일시적으로 불가능합니다. 만일 계속해서 문제가 발생하면 관리자에게 문의하시기 바랍니다.'; +$lang['authpwdexpire'] = '비밀번호를 바꾼지 %d일이 지났습니다. 비민번호를 곧 바꿔야 합니다.'; $lang['i_chooselang'] = '사용할 언어를 선택하세요'; $lang['i_installer'] = 'DokuWiki 설치'; $lang['i_wikiname'] = '위키 이름'; $lang['i_enableacl'] = 'ACL 기능 사용 (권장)'; $lang['i_superuser'] = '슈퍼 유저'; -$lang['i_problems'] = '설치 중 아래와 같은 문제가 발생했습니다. 문제를 해결한 후 설치를 계속하기 바랍니다.'; +$lang['i_problems'] = '설치하는 동안 아래와 같은 문제가 발생했습니다. 문제를 해결한 후 설치를 계속하세요.'; $lang['i_modified'] = '보안 상의 이유로 이 스크립트는 수정되지 않은 새 Dokuwiki 설치에서만 동작됩니다. -다운로드한 압축 패키지를 다시 설치하거나 <a href="http://dokuwiki.org/install">DokuWiki 설치 과정</a>을 참고해서 설치하기 바랍니다.'; +다운로드한 압축 패키지를 다시 설치하거나 <a href="http://dokuwiki.org/install">DokuWiki 설치 과정</a>을 참고해서 설치하세요.'; $lang['i_funcna'] = '<code>%s</code> PHP 함수의 사용이 불가능합니다. 호스트 제공자가 어떤 이유에서인지 막아 놓았을지 모릅니다.'; $lang['i_phpver'] = 'PHP <code>%s</code> 버전은 필요한 <code>%s</code> 버전보다 오래되었습니다. PHP를 업그레이드할 필요가 있습니다.'; $lang['i_permfail'] = 'DokuWiki는 <code>%s</code>에 쓰기 가능 권한이 없습니다. 먼저 이 디렉토리에 쓰기 권한이 설정되어야 합니다!'; -$lang['i_confexists'] = '<code>%s</code>(은)는 이미 존재합니다.'; -$lang['i_writeerr'] = '<code>%s</code>(을)를 만들 수 없습니다. 먼저 디렉토리/파일 권한을 확인하고 파일을 수동으로 만들기 바랍니다.'; -$lang['i_badhash'] = 'dokuwiki.php를 인식할 수 없거나 원본 파일이 아닙니다. (해시=<code>%s</code>)'; -$lang['i_badval'] = '<code>%s</code> - 유효하지 않거나 빈 값입니다.'; +$lang['i_confexists'] = '<code>%s</code>(은)는 이미 존재합니다'; +$lang['i_writeerr'] = '<code>%s</code>(을)를 만들 수 없습니다. 먼저 디렉토리/파일 권한을 확인하고 파일을 수동으로 만드세요.'; +$lang['i_badhash'] = 'dokuwiki.php를 인식할 수 없거나 원본 파일이 아닙니다 (해시=<code>%s</code>)'; +$lang['i_badval'] = '<code>%s</code> - 유효하지 않거나 빈 값입니다'; $lang['i_success'] = '환경 설정이 성공적으로 끝났습니다. 지금 install.php를 지워도 상관없습니다. <a href="doku.php?id=wiki:welcome">새 DokuWiki</a>로 들어갑니다.'; -$lang['i_failure'] = '환경 설정 파일에 쓰는 도중에 오류가 발생했습니다. <a href="doku.php?id=wiki:welcome">새 DokuWiki</a>를 사용하기 전에 수동으로 문제를 해결할 필요가 있습니다.'; +$lang['i_failure'] = '환경 설정 파일에 쓰는 도중에 오류가 발생했습니다. <a href="doku.php?id=wiki:welcome">새 DokuWiki</a>를 사용하기 전에 수동으로 문제를 해결해야 합니다.'; $lang['i_policy'] = '초기 ACL 정책'; -$lang['i_pol0'] = '열린 위키 (누구나 읽기, 쓰기, 올리기가 가능합니다.)'; -$lang['i_pol1'] = '공개 위키 (누구나 읽을 수 있지만, 등록된 사용자만 쓰기와 올리기가 가능합니다.)'; -$lang['i_pol2'] = '닫힌 위키 (등록된 사용자만 읽기, 쓰기, 업로드가 가능합니다.)'; +$lang['i_pol0'] = '열린 위키 (누구나 읽기, 쓰기, 올리기가 가능합니다)'; +$lang['i_pol1'] = '공개 위키 (누구나 읽을 수 있지만, 등록된 사용자만 쓰기와 올리기가 가능합니다)'; +$lang['i_pol2'] = '닫힌 위키 (등록된 사용자만 읽기, 쓰기, 올리기가 가능합니다)'; $lang['i_retry'] = '다시 시도'; $lang['i_license'] = '내용을 배포하기 위한 라이선스를 선택하세요:'; +$lang['i_license_none'] = '라이선스 정보를 보여주지 않습니다'; +$lang['i_pop_field'] = 'DokuWiki 경험을 개선하는 데 도움을 주세요:'; +$lang['i_pop_label'] = '한 달에 한 번씩, DokuWiki 개발자에게 익명의 사용 데이터를 보냅니다'; $lang['recent_global'] = '<b>%s</b> 이름공간을 구독 중입니다. <a href="%s">전체 위키의 최근 바뀜도 볼 수</a> 있습니다.'; $lang['years'] = '%d년 전'; $lang['months'] = '%d개월 전'; @@ -318,5 +321,5 @@ $lang['media_history'] = '%s 바뀜 내역'; $lang['media_meta_edited'] = '메타데이터가 수정됨'; $lang['media_perm_read'] = '이 파일을 읽을 권한이 없습니다.'; $lang['media_perm_upload'] = '파일을 올릴 권한이 없습니다.'; -$lang['media_update'] = '새 버전 올리기'; -$lang['media_restore'] = '이 버전으로 되돌리기'; +$lang['media_update'] = '새 판 올리기'; +$lang['media_restore'] = '이 판으로 되돌리기'; diff --git a/inc/lang/ko/locked.txt b/inc/lang/ko/locked.txt index 176a792d6..f4070d4bc 100644 --- a/inc/lang/ko/locked.txt +++ b/inc/lang/ko/locked.txt @@ -1,3 +1,3 @@ ====== 문서 잠금 ====== -다른 사용자가 이 문서를 편집하기 위해 잠금을 실행하였습니다. 해당 사용자가 편집을 끝내거나 잠금이 해제될 때까지 기다리십시오. \ No newline at end of file +다른 사용자가 이 문서를 편집하기 위해 잠금을 실행하였습니다. 해당 사용자가 편집을 끝내거나 잠금이 해제될 때까지 기다리세요. \ No newline at end of file diff --git a/inc/lang/ko/mailtext.txt b/inc/lang/ko/mailtext.txt index 01bada9ba..8fb6fd446 100644 --- a/inc/lang/ko/mailtext.txt +++ b/inc/lang/ko/mailtext.txt @@ -4,8 +4,8 @@ DokuWiki 문서가 추가 또는 바뀌었습니다. 자세한 정보는 다음 브라우저 : @BROWSER@ IP 주소 : @IPADDRESS@ 호스트 이름 : @HOSTNAME@ -이전 버전 : @OLDPAGE@ -새 버전 : @NEWPAGE@ +이전 판 : @OLDPAGE@ +새 판 : @NEWPAGE@ 편집 요약 : @SUMMARY@ 사용자 : @USER@ diff --git a/inc/lang/ko/norev.txt b/inc/lang/ko/norev.txt index 6758ce4ec..3e203b235 100644 --- a/inc/lang/ko/norev.txt +++ b/inc/lang/ko/norev.txt @@ -1,3 +1,3 @@ -====== 지정한 버전 없음 ====== +====== 지정한 판 없음 ====== -지정한 버전이 존재하지 않습니다. **이전 버전** 버튼을 사용하여 이 문서의 이전 버전 목록을 보세요. \ No newline at end of file +지정한 판이 존재하지 않습니다. **이전 판** 버튼을 사용하여 이 문서의 이전 판 목록을 보세요. \ No newline at end of file diff --git a/inc/lang/ko/preview.txt b/inc/lang/ko/preview.txt index 1b7710e2f..eed2b21f5 100644 --- a/inc/lang/ko/preview.txt +++ b/inc/lang/ko/preview.txt @@ -1,3 +1,3 @@ ====== 미리 보기 ====== -입력한 내용이 어떻게 보일지 미리 보여줍니다. 아직 **저장되지 않았다**는 점을 기억해두십시오! \ No newline at end of file +입력한 내용이 어떻게 보일지 미리 보여줍니다. 아직 **저장되지 않았다**는 점을 기억해두세요! \ No newline at end of file diff --git a/inc/lang/ko/pwconfirm.txt b/inc/lang/ko/pwconfirm.txt index 1920f4a20..6e447a021 100644 --- a/inc/lang/ko/pwconfirm.txt +++ b/inc/lang/ko/pwconfirm.txt @@ -5,7 +5,7 @@ 새로운 비밀번호 요청한 적이 없다면 이 이메일을 무시해버리세요. -정말로 당신이 그러한 요청을 했는지 다음 링크에서 확인하기 바랍니다. +정말로 당신이 요청을 했는지 다음 링크에서 확인하세요. @CONFIRM@ diff --git a/inc/lang/ko/read.txt b/inc/lang/ko/read.txt index 9b2ec822f..c510b598e 100644 --- a/inc/lang/ko/read.txt +++ b/inc/lang/ko/read.txt @@ -1,2 +1 @@ -이 문서는 읽기 전용입니다. 내용을 볼 수는 있지만, 수정할 수는 없습니다. 문제가 있다고 생각하면 관리자에게 문의하십시오. - +이 문서는 읽기 전용입니다. 내용을 볼 수는 있지만 수정할 수는 없습니다. 문제가 있다고 생각하면 관리자에게 문의하세요. \ No newline at end of file diff --git a/inc/lang/ko/recent.txt b/inc/lang/ko/recent.txt index f2ffb8c6f..b1dae2463 100644 --- a/inc/lang/ko/recent.txt +++ b/inc/lang/ko/recent.txt @@ -1,3 +1,3 @@ ====== 최근 바뀜 ====== -아래의 문서는 최근에 바뀐 것입니다. \ No newline at end of file +아래의 문서는 최근에 바뀌었습니다. \ No newline at end of file diff --git a/inc/lang/ko/resendpwd.txt b/inc/lang/ko/resendpwd.txt index 0ad46eb1e..faee2072c 100644 --- a/inc/lang/ko/resendpwd.txt +++ b/inc/lang/ko/resendpwd.txt @@ -1,3 +1,3 @@ -====== 새로운 비밀번호 전송 ====== +====== 새 비밀번호 보내기 ====== -이 위키 계정에 대한 새 비밀번호를 요구하기 위해 아래 양식에서 사용자 이름을 입력하세요. 확인 링크는 새로 등록한 이메일 주소로 발송됩니다. \ No newline at end of file +이 위키 계정에 대한 새 비밀번호를 요구하기 위해 아래 양식에서 사용자 이름을 입력하세요. 확인 링크는 새로 등록한 이메일 주소로 보냅니다. \ No newline at end of file diff --git a/inc/lang/ko/revisions.txt b/inc/lang/ko/revisions.txt index 64733d86d..f499e2f72 100644 --- a/inc/lang/ko/revisions.txt +++ b/inc/lang/ko/revisions.txt @@ -1,3 +1,3 @@ -====== 이전 버전 ====== +====== 이전 판 ====== -이 문서의 이전 버전은 다음과 같습니다. 이전 버전으로 돌아가려면, 아래에서 선택한 다음 **문서 편집**을 클릭하고 나서 저장하세요. \ No newline at end of file +이 문서의 이전 판은 다음과 같습니다. 이전 판으로 되돌리려면, 아래에서 선택한 다음 **문서 편집**을 클릭하고 나서 저장하세요. \ No newline at end of file diff --git a/inc/lang/ko/searchpage.txt b/inc/lang/ko/searchpage.txt index 2e8502b13..8cc003950 100644 --- a/inc/lang/ko/searchpage.txt +++ b/inc/lang/ko/searchpage.txt @@ -1,5 +1,5 @@ ====== 찾기 ====== -아래에서 찾기 결과를 볼 수 있습니다. 만일 원하는 것을 찾지 못하였다면, **문서 만들기**나 **문서 편집** 버튼을 사용하여 쿼리 내용과 같은 이름의 문서를 만들거나 편집할 수 있습니다. +아래에서 찾기 결과를 볼 수 있습니다. 만일 원하는 문서를 찾지 못하였다면, **문서 만들기**나 **문서 편집** 버튼을 사용하여 쿼리 내용과 같은 이름의 문서를 만들거나 편집할 수 있습니다. ===== 결과 ===== \ No newline at end of file diff --git a/inc/lang/ko/showrev.txt b/inc/lang/ko/showrev.txt index f6930044b..91be367f5 100644 --- a/inc/lang/ko/showrev.txt +++ b/inc/lang/ko/showrev.txt @@ -1,2 +1,2 @@ -**문서의 이전 버전입니다!** ----- +**문서의 이전 판입니다!** +---- \ No newline at end of file diff --git a/inc/lang/ko/stopwords.txt b/inc/lang/ko/stopwords.txt index 4b5551ce5..c0dc2a79b 100644 --- a/inc/lang/ko/stopwords.txt +++ b/inc/lang/ko/stopwords.txt @@ -1,5 +1,5 @@ # 색인이 만들어지지 않는 단어 목록입니다. (한줄에 한 단어) -# 이 파일을 편집한다면 UNIX 줄 종료 문자를 사용해야합니다.(단일 개행 문자) +# 이 파일을 편집한다면 UNIX 줄 종료 문자를 사용해야 합니다.(단일 개행 문자) # 3문자 이하 단어는 자동으로 무시되므로 3문자보다 짧은 단어는 포함시킬 필요가 없습니다. # http://www.ranks.nl/stopwords/을 기준으로 만들어진 목록입니다. about diff --git a/inc/lang/ko/subscr_digest.txt b/inc/lang/ko/subscr_digest.txt index 13459428f..b67cc9bbc 100644 --- a/inc/lang/ko/subscr_digest.txt +++ b/inc/lang/ko/subscr_digest.txt @@ -1,14 +1,14 @@ 안녕하세요! @TITLE@ 위키의 @PAGE@ 문서가 바뀌었습니다. -바뀐 점은 다음과 같습니다: +바뀜은 다음과 같습니다: -------------------------------------------------------- @DIFF@ -------------------------------------------------------- -이전 버전 : @OLDPAGE@ -새 버전 : @NEWPAGE@ +이전 판 : @OLDPAGE@ +새 판 : @NEWPAGE@ 이 문서의 알림을 취소하려면, @DOKUWIKIURL@에 로그인한 뒤 diff --git a/inc/lang/ko/subscr_list.txt b/inc/lang/ko/subscr_list.txt index 68adf0de9..03ca86d2a 100644 --- a/inc/lang/ko/subscr_list.txt +++ b/inc/lang/ko/subscr_list.txt @@ -1,7 +1,7 @@ 안녕하세요! @TITLE@ 위키의 @PAGE@ 문서가 바뀌었습니다. -바뀐 점은 다음과 같습니다: +문서의 바뀜은 다음과 같습니다: -------------------------------------------------------- @DIFF@ diff --git a/inc/lang/ko/subscr_single.txt b/inc/lang/ko/subscr_single.txt index 2679db393..5f8b43b98 100644 --- a/inc/lang/ko/subscr_single.txt +++ b/inc/lang/ko/subscr_single.txt @@ -1,7 +1,7 @@ 안녕하세요! @TITLE@ 위키의 @PAGE@ 문서가 바뀌었습니다. -바뀐 점은 다음과 같습니다: +바뀜은 다음과 같습니다: -------------------------------------------------------- @DIFF@ @@ -10,8 +10,8 @@ 날짜 : @DATE@ 사용자 : @USER@ 편집 요약 : @SUMMARY@ -이전 버전 : @OLDPAGE@ -새 버전 : @NEWPAGE@ +이전 판 : @OLDPAGE@ +새 판 : @NEWPAGE@ 이 문서의 알림을 취소하려면, @DOKUWIKIURL@에 로그인한 뒤 @SUBSCRIBE@ 문서를 방문하여 문서나 이름공간의 구독을 취소하세요. diff --git a/inc/lang/ko/updateprofile.txt b/inc/lang/ko/updateprofile.txt index 379981cb3..80545e9bf 100644 --- a/inc/lang/ko/updateprofile.txt +++ b/inc/lang/ko/updateprofile.txt @@ -1,3 +1,3 @@ ====== 개인 정보 바꾸기 ====== -바꾸고 싶은 항목을 입력하기 바랍니다. 사용자 이름은 바꿀 수 없습니다. \ No newline at end of file +바꾸고 싶은 항목을 입력하세요. 사용자 이름은 바꿀 수 없습니다. \ No newline at end of file diff --git a/inc/lang/ko/uploadmail.txt b/inc/lang/ko/uploadmail.txt index 675c0bd3f..8e0a4d70b 100644 --- a/inc/lang/ko/uploadmail.txt +++ b/inc/lang/ko/uploadmail.txt @@ -1,7 +1,7 @@ DokuWiki가 파일을 올렸습니다. 자세한 정보는 다음과 같습니다: 파일 : @MEDIA@ -이전 버전 : @OLD@ +이전 판 : @OLD@ 날짜 : @DATE@ 브라우저 : @BROWSER@ IP 주소 : @IPADDRESS@ diff --git a/lib/plugins/acl/lang/ko/help.txt b/lib/plugins/acl/lang/ko/help.txt index 6a15b7a2e..0386b5990 100644 --- a/lib/plugins/acl/lang/ko/help.txt +++ b/lib/plugins/acl/lang/ko/help.txt @@ -1,11 +1,8 @@ === 빠른 도움말: === 현재 문서에서 위키 이름공간과 문서에 대한 접근 권한을 추가하거나 삭제할 수 있습니다. +* 왼쪽 영역에는 선택 가능한 이름공간과 문서 목록을 보여줍니다. +* 위쪽 입력 양식에서 선택된 사용자와 그룹의 접근 권한을 보거나 바꿀 수 있습니다. +* 아래 테이블에서 현재 설정된 모든 접근 제어 규칙을 볼 수 있으며, 즉시 여러 규칙을 삭제하거나 바꿀 수 있습니다. -왼쪽 영역에는 선택 가능한 이름공간과 문서 목록을 보여줍니다. - -위쪽 입력 양식에서 선택된 사용자와 그룹의 접근 권한을 보거나 바꿀 수 있습니다. - -아래 테이블에서 현재 설정된 모든 접근 제어 규칙을 볼 수 있으며, 즉시 여러 규칙을 삭제하거나 바꿀 수 있습니다. - -DokuWiki에서 접근 제어가 어떻게 동작되는지 알아보려면 [[doku>acl|ACL 공식 문서]]를 읽어보기 바랍니다. \ No newline at end of file +DokuWiki에서 접근 제어가 어떻게 동작되는지 알아보려면 [[doku>acl|ACL 공식 문서]]를 읽어보시기 바랍니다. \ No newline at end of file diff --git a/lib/plugins/acl/lang/ko/lang.php b/lib/plugins/acl/lang/ko/lang.php index 5d2662ef8..5cec4b8fd 100644 --- a/lib/plugins/acl/lang/ko/lang.php +++ b/lib/plugins/acl/lang/ko/lang.php @@ -1,16 +1,15 @@ <?php /** - * korean language file + * Korean language file * - * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) + * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) * @author Andreas Gohr <andi@splitbrain.org> * @author Anika Henke <anika@selfthinker.org> * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net> * @author jk Lee * @author dongnak@gmail.com * @author Song Younghwan <purluno@gmail.com> - * @author SONG Younghwan <purluno@gmail.com> - * @author Seung-Chul Yoo <dryoo@live.com> + * @author Seung-Chul Yoo <dryoo@live.com> * @author erial2@gmail.com * @author Myeongjin <aranet100@gmail.com> */ @@ -25,8 +24,8 @@ $lang['p_user_id'] = '<b class="acluser">%s</b> 사용자는 현재 $lang['p_user_ns'] = '<b class="acluser">%s</b> 사용자는 현재 <b class="aclns">%s</b>: <i>%s</i> 이름공간 접근이 가능합니다.'; $lang['p_group_id'] = '<b class="aclgroup">%s</b> 그룹 구성원은 현재 <b class="aclpage">%s</b>: <i>%s</i> 문서 접근이 가능합니다.'; $lang['p_group_ns'] = '<b class="aclgroup">%s</b> 그룹 구성원은 현재 <b class="aclns">%s</b>: <i>%s</i> 이름공간 접근이 가능합니다.'; -$lang['p_choose_id'] = '<b class="aclpage">%s</b> 문서 접근 권한을 보거나 바꾸려면 <b>사용자</b>나 <b>그룹</b>을 위 양식에 입력하기 바랍니다.'; -$lang['p_choose_ns'] = '<b class="aclns">%s</b> 이름공간 접근 권한을 보거나 바꾸려면 <b>사용자</b>나 <b>그룹</b>을 위 양식에 입력하기 바랍니다.'; +$lang['p_choose_id'] = '<b class="aclpage">%s</b> 문서 접근 권한을 보거나 바꾸려면 <b>사용자</b>나 <b>그룹</b>을 위 양식에 입력하세요.'; +$lang['p_choose_ns'] = '<b class="aclns">%s</b> 이름공간 접근 권한을 보거나 바꾸려면 <b>사용자</b>나 <b>그룹</b>을 위 양식에 입력하세요.'; $lang['p_inherited'] = '참고: 권한이 명시적으로 설정되지 않았으므로 다른 그룹이나 상위 이름공간으로부터 가져왔습니다.'; $lang['p_isadmin'] = '참고: 슈퍼유저로 설정되어 있으므로 선택된 그룹이나 사용자는 언제나 모든 접근 권한을 가집니다.'; $lang['p_include'] = '더 높은 접근 권한은 하위를 포함합니다. 문서가 아닌 이름공간에는 만들기, 올리기, 삭제 권한만 적용됩니다.'; diff --git a/lib/plugins/authad/lang/ko/settings.php b/lib/plugins/authad/lang/ko/settings.php new file mode 100644 index 000000000..31071e9a3 --- /dev/null +++ b/lib/plugins/authad/lang/ko/settings.php @@ -0,0 +1,14 @@ +<?php +/** + * Korean language file + * + * @author Myeongjin <aranet100@gmail.com> + */ +$lang['account_suffix'] = '계정 접미어. 예를 들어 <code>@my.domain.org</code>'; +$lang['base_dn'] = '기본 DN. 예를 들어 <code>DC=my,DC=domain,DC=org</code>'; +$lang['domain_controllers'] = '도메인 컨트롤러의 쉼표로 구분한 목록입니다. 예를 들어 <code>srv1.domain.org,srv2.domain.org</code>'; +$lang['ad_password'] = '위 사용자의 비밀번호입니다.'; +$lang['sso'] = 'Kerberos나 NTLM을 통해 Single-Sign-On을 사용해야 합니까?'; +$lang['use_ssl'] = 'SSL 연결을 사용합니까? 사용한다면 아래 TLS을 활성화하지 마세요.'; +$lang['use_tls'] = 'TLS 연결을 사용합니까? 사용한다면 위 SSL을 활성화하지 마세요.'; +$lang['debug'] = '오류에 대한 추가적인 디버그 정보를 보이겠습니까?'; diff --git a/lib/plugins/authldap/lang/ko/settings.php b/lib/plugins/authldap/lang/ko/settings.php new file mode 100644 index 000000000..6c80414d3 --- /dev/null +++ b/lib/plugins/authldap/lang/ko/settings.php @@ -0,0 +1,10 @@ +<?php +/** + * Korean language file + * + * @author Myeongjin <aranet100@gmail.com> + */ +$lang['server'] = 'LDAP 서버. 호스트 이름(<code>localhost</code>)이나 전체 자격 URL(<code>ldap://server.tld:389</code>) 중 하나'; +$lang['port'] = '위에 주어진 전체 URL이 없을 때의 LDAP 서버 포트'; +$lang['starttls'] = 'TLS 연결을 사용하겠습니까?'; +$lang['debug'] = '오류에 대한 추가적인 디버그 정보를 보이기'; diff --git a/lib/plugins/authmysql/lang/ko/settings.php b/lib/plugins/authmysql/lang/ko/settings.php new file mode 100644 index 000000000..c5518b8cc --- /dev/null +++ b/lib/plugins/authmysql/lang/ko/settings.php @@ -0,0 +1,41 @@ +<?php +/** + * Korean language file + * + * @author Myeongjin <aranet100@gmail.com> + */ +$lang['server'] = 'MySQL 서버'; +$lang['user'] = 'MySQL 사용자 이름'; +$lang['password'] = '위 사용자의 비밀번호'; +$lang['database'] = '사용할 데이터베이스'; +$lang['charset'] = '데이터베이스에 사용하는 문자 집합'; +$lang['debug'] = '추가적인 디버그 정보 보이기'; +$lang['forwardClearPass'] = 'passcrypt 옵션을 사용하는 대신 아래 SQL 문에 일반 텍스트로 사용자 비밀번호를 전달'; +$lang['TablesToLock'] = '쓰기 작업에 잠궈야 하는 테이블의 쉼표로 구분한 목록'; +$lang['checkPass'] = '비밀번호를 확인하기 위한 SQL 문'; +$lang['getUserInfo'] = '사용자 정보를 가져오기 위한 SQL 문'; +$lang['getGroups'] = '사용자의 그룹 구성원을 가져오기 위한 SQL 문'; +$lang['getUsers'] = '모든 사용자를 나타낼 SQL 문'; +$lang['FilterLogin'] = '로그인 이름 별로 사용자를 필터하기 위한 SQL 조항'; +$lang['FilterName'] = '전체 이름 별로 사용자를 필터하기 위한 SQL 조항'; +$lang['FilterEmail'] = '이메일 주소 별로 사용자를 필터하기 위한 SQL 조항'; +$lang['FilterGroup'] = '그룹 구성원 별로 사용자를 필터하기 위한 SQL 조항'; +$lang['SortOrder'] = '사용자를 정렬할 SQL 조항'; +$lang['addUser'] = '새 사용자를 추가할 SQL 문'; +$lang['addGroup'] = '새 그룹을 추가할 SQL 문'; +$lang['addUserGroup'] = '기존 그룹에 사용자를 추가할 SQL 문'; +$lang['delGroup'] = '그룹을 제거할 SQL 문'; +$lang['getUserID'] = '사용자의 기본 키를 얻을 SQL 문'; +$lang['delUser'] = '사용자를 삭제할 SQL 문'; +$lang['delUserRefs'] = '모든 그룹에서 사용자를 제거할 SQL 문'; +$lang['updateUser'] = '사용자 프로필을 업데이트할 SQL 문'; +$lang['UpdateLogin'] = '사용자의 로그인 이름을 업데이트하기 위한 Update 조항'; +$lang['UpdatePass'] = '사용자의 비밀번호를 업데이트하기 위한 Update 조항'; +$lang['UpdateEmail'] = '사용자의 이메일 주소를 업데이트하기 위한 Update 조항'; +$lang['UpdateName'] = '사용자의 전체 이름을 업데이트하기 위한 Update 조항'; +$lang['UpdateTarget'] = '업데이트할 때 사용자를 식별할 Limit 조항'; +$lang['delUserGroup'] = '주어진 그룹에서 사용자를 제거할 SQL 문'; +$lang['getGroupID'] = '주어진 그룹의 기본 키를 얻을 SQL 문'; +$lang['debug_o_0'] = '없음'; +$lang['debug_o_1'] = '오류에만'; +$lang['debug_o_2'] = '모든 SQL 쿼리'; diff --git a/lib/plugins/authpgsql/lang/ko/settings.php b/lib/plugins/authpgsql/lang/ko/settings.php new file mode 100644 index 000000000..d21e81cd6 --- /dev/null +++ b/lib/plugins/authpgsql/lang/ko/settings.php @@ -0,0 +1,37 @@ +<?php +/** + * Korean language file + * + * @author Myeongjin <aranet100@gmail.com> + */ +$lang['server'] = 'PostgreSQL 서버'; +$lang['port'] = 'PostgreSQL 서버의 포트'; +$lang['user'] = 'PostgreSQL 사용자 이름'; +$lang['password'] = '위 사용자의 비밀번호'; +$lang['database'] = '사용할 데이터베이스'; +$lang['debug'] = '추가적인 디버그 정보 보이기'; +$lang['forwardClearPass'] = 'passcrypt 옵션을 사용하는 대신 아래 SQL 문에 일반 텍스트로 사용자 비밀번호를 전달'; +$lang['checkPass'] = '비밀번호를 확인하기 위한 SQL 문'; +$lang['getUserInfo'] = '사용자 정보를 가져오기 위한 SQL 문'; +$lang['getGroups'] = '사용자의 그룹 구성원을 가져오기 위한 SQL 문'; +$lang['getUsers'] = '모든 사용자를 나타낼 SQL 문'; +$lang['FilterLogin'] = '로그인 이름 별로 사용자를 필터하기 위한 SQL 조항'; +$lang['FilterName'] = '전체 이름 별로 사용자를 필터하기 위한 SQL 조항'; +$lang['FilterEmail'] = '이메일 주소 별로 사용자를 필터하기 위한 SQL 조항'; +$lang['FilterGroup'] = '그룹 구성원 별로 사용자를 필터하기 위한 SQL 조항'; +$lang['SortOrder'] = '사용자를 정렬할 SQL 조항'; +$lang['addUser'] = '새 사용자를 추가할 SQL 문'; +$lang['addGroup'] = '새 그룹을 추가할 SQL 문'; +$lang['addUserGroup'] = '기존 그룹에 사용자를 추가할 SQL 문'; +$lang['delGroup'] = '그룹을 제거할 SQL 문'; +$lang['getUserID'] = '사용자의 기본 키를 얻을 SQL 문'; +$lang['delUser'] = '사용자를 삭제할 SQL 문'; +$lang['delUserRefs'] = '모든 그룹에서 사용자를 제거할 SQL 문'; +$lang['updateUser'] = '사용자 프로필을 업데이트할 SQL 문'; +$lang['UpdateLogin'] = '사용자의 로그인 이름을 업데이트하기 위한 Update 조항'; +$lang['UpdatePass'] = '사용자의 비밀번호를 업데이트하기 위한 Update 조항'; +$lang['UpdateEmail'] = '사용자의 이메일 주소를 업데이트하기 위한 Update 조항'; +$lang['UpdateName'] = '사용자의 전체 이름을 업데이트하기 위한 Update 조항'; +$lang['UpdateTarget'] = '업데이트할 때 사용자를 식별할 Limit 조항'; +$lang['delUserGroup'] = '주어진 그룹에서 사용자를 제거할 SQL 문'; +$lang['getGroupID'] = '주어진 그룹의 기본 키를 얻을 SQL 문'; diff --git a/lib/plugins/config/lang/ko/lang.php b/lib/plugins/config/lang/ko/lang.php index cd2cc6d6c..7737af70f 100644 --- a/lib/plugins/config/lang/ko/lang.php +++ b/lib/plugins/config/lang/ko/lang.php @@ -1,13 +1,12 @@ <?php /** - * korean language file + * Korean language file * - * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) + * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) * @author jk Lee * @author dongnak@gmail.com * @author Song Younghwan <purluno@gmail.com> - * @author SONG Younghwan <purluno@gmail.com> - * @author Seung-Chul Yoo <dryoo@live.com> + * @author Seung-Chul Yoo <dryoo@live.com> * @author erial2@gmail.com * @author Myeongjin <aranet100@gmail.com> */ @@ -15,9 +14,9 @@ $lang['menu'] = '환경 설정'; $lang['error'] = '잘못된 값 때문에 설정을 바꿀 수 없습니다. 수정한 값을 검토하고 확인을 누르세요. <br />잘못된 값은 빨간 선으로 둘러싸여 있습니다.'; $lang['updated'] = '설정이 성공적으로 바뀌었습니다.'; -$lang['nochoice'] = '(다른 선택이 불가능합니다.)'; +$lang['nochoice'] = '(다른 선택이 불가능합니다)'; $lang['locked'] = '환경 설정 파일을 수정할 수 없습니다. 의도한 행동이 아니라면,<br /> -파일 이름과 권한이 맞는지 확인하기 바랍니다. '; +파일 이름과 권한이 맞는지 확인하세요.'; $lang['danger'] = '위험: 이 옵션을 잘못 수정하면 환경설정 메뉴를 사용할 수 없을 수도 있습니다.'; $lang['warning'] = '경고: 이 옵션을 잘못 수정하면 잘못 동작할 수 있습니다.'; $lang['security'] = '보안 경고: 이 옵션은 보안에 위험이 있을 수 있습니다.'; @@ -47,7 +46,7 @@ $lang['start'] = '각 이름공간에서 사용할 시작 문서 $lang['lang'] = '인터페이스 언어'; $lang['template'] = '템플릿 (위키 디자인)'; $lang['tagline'] = '태그 라인 (템플릿이 지원할 때에 한함)'; -$lang['sidebar'] = '사이드바 문서 이름 (템플릿이 지원할 때에 한함). 비워두면 사이드바를 비활성화'; +$lang['sidebar'] = '사이드바 문서 이름 (템플릿이 지원할 때에 한함), 비워두면 사이드바를 비활성화'; $lang['license'] = '콘텐츠에 어떤 라이선스를 적용하겠습니까?'; $lang['savedir'] = '데이타 저장 디렉토리'; $lang['basedir'] = '서버 경로 (예를 들어 <code>/dokuwiki/</code>). 자동 감지를 하려면 비우세요.'; @@ -59,7 +58,7 @@ $lang['allowdebug'] = '디버그 허용 <b>필요하지 않으면 금 $lang['recent'] = '최근 바뀐 문서당 항목 수'; $lang['recent_days'] = '최근 바뀐 문서 기준 시간 (날짜)'; $lang['breadcrumbs'] = '위치 "추적" 수. 0으로 설정하면 비활성화합니다.'; -$lang['youarehere'] = '계층형 위치 추적 (다음 위의 옵션을 비활성화하고 싶습니다)'; +$lang['youarehere'] = '계층형 위치 추적 (다음 위의 옵션을 비활성화하게 됩니다)'; $lang['fullpath'] = '문서 하단에 전체 경로 보여주기'; $lang['typography'] = '기호 대체'; $lang['dformat'] = '날짜 형식 (PHP <a href="http://www.php.net/strftime">strftime</a> 기능 참고)'; @@ -108,7 +107,7 @@ $lang['target____interwiki'] = '인터위키 링크에 대한 타겟 창'; $lang['target____extern'] = '바깥 링크에 대한 타겟 창'; $lang['target____media'] = '미디어 링크에 대한 타겟 창'; $lang['target____windows'] = '창 링크에 대한 타겟 창'; -$lang['mediarevisions'] = '미디어 버전 관리를 사용하겠습니까?'; +$lang['mediarevisions'] = '미디어 판 관리를 사용하겠습니까?'; $lang['refcheck'] = '미디어 파일을 삭제하기 전에 사용하고 있는지 검사'; $lang['refshow'] = '위의 설정이 활성화되었을 때 보여줄 미디어 참고 수'; $lang['gdlib'] = 'GD 라이브러리 버전'; @@ -121,7 +120,7 @@ $lang['notify'] = '항상 이 이메일 주소로 바뀜 알림 $lang['registernotify'] = '항상 새 사용자한테 이 이메일 주소로 정보를 보냄'; $lang['mailfrom'] = '자동으로 보내지는 메일 발신자'; $lang['mailprefix'] = '자동으로 보내지는 메일의 제목 말머리 내용. 비웠을 경우 위키 제목 사용'; -$lang['htmlmail'] = '용량은 조금 더 크지만 보기 좋은 HTML 태그가 포함된 메일을 발송합니다. 텍스트만의 메일을 보내고자하면 비활성화하세요.'; +$lang['htmlmail'] = '용량은 조금 더 크지만 보기 좋은 HTML 태그가 포함된 메일을 보냅니다. 텍스트만의 메일을 보내고자하면 비활성화하세요.'; $lang['sitemap'] = '구글 사이트맵 생성 (날짜). 0일 경우 비활성화'; $lang['rss_type'] = 'XML 피드 타입'; $lang['rss_linkto'] = 'XML 피드 링크 정보'; @@ -141,12 +140,12 @@ $lang['gzip_output'] = 'xhml 내용 gzip 압축 사용'; $lang['compress'] = '최적화된 CSS, 자바스크립트 출력'; $lang['cssdatauri'] = '그림이 렌더링될 최대 용량 크기를 CSS에 규정해야 HTTP 요청 헤더 오버헤드 크기를 감소시킬 수 있습니다. 이 기술은 IE 7 이하에서는 작동하지 않습니다! <code>400</code>에서 <code>600</code> 정도면 좋은 효율을 가져옵니다. <code>0</code>로 지정할 경우 비활성화 됩니다.'; $lang['send404'] = '존재하지 않는 페이지에 대해 "HTTP 404/Page Not Found" 응답'; -$lang['broken_iua'] = '설치된 시스템에서 ignore_user_abort 기능에 문제가 있습니까? 문제가 있다면 색인이 정상적으로 동작하지 않습니다. 이 기능이 IIS+PHP/CGI에서 문제가 있는 것으로 알려졌습니다. 자세한 정보는 <a href="http://bugs.dokuwiki.org/?do=details&task_id=852">버그 852</a>를 참고하기 바랍니다.'; +$lang['broken_iua'] = '설치된 시스템에서 ignore_user_abort 기능에 문제가 있습니까? 문제가 있다면 색인이 정상적으로 동작하지 않습니다. 이 기능이 IIS+PHP/CGI에서 문제가 있는 것으로 알려졌습니다. 자세한 정보는 <a href="http://bugs.dokuwiki.org/?do=details&task_id=852">버그 852</a>를 참고하시기 바랍니다.'; $lang['xsendfile'] = '웹 서버가 정적 파일을 제공하도록 X-Sendfile 헤더를 사용하겠습니까? 웹 서버가 이 기능을 지원해야 합니다.'; $lang['renderer_xhtml'] = '주 (xhtml) 위키 출력 처리기'; $lang['renderer__core'] = '%s (DokuWiki 내부 기능)'; $lang['renderer__plugin'] = '%s (플러그인)'; -$lang['dnslookups'] = '이 옵션을 활성화하면 도쿠위키가 문서를 수정하는 사용자의 호스트 네임과 원격 IP 주소를 확인합니다. 서버가 느리거나, DNS를 운영하지 않거나 이 기능을 원치 않으면 비활성화 시켜주세요.'; +$lang['dnslookups'] = '이 옵션을 활성화하면 DokuWiki가 문서를 수정하는 사용자의 호스트 네임과 원격 IP 주소를 확인합니다. 서버가 느리거나, DNS를 운영하지 않거나 이 기능을 원치 않으면 비활성화 시켜주세요.'; $lang['proxy____host'] = '프록시 서버 이름'; $lang['proxy____port'] = '프록시 서버 포트'; $lang['proxy____user'] = '프록시 사용자 이름'; diff --git a/lib/plugins/plugin/lang/ko/lang.php b/lib/plugins/plugin/lang/ko/lang.php index 4fc6fd1d9..7ca021ac4 100644 --- a/lib/plugins/plugin/lang/ko/lang.php +++ b/lib/plugins/plugin/lang/ko/lang.php @@ -1,13 +1,12 @@ <?php /** - * korean language file + * Korean language file * - * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) + * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) * @author jk Lee * @author dongnak@gmail.com * @author Song Younghwan <purluno@gmail.com> - * @author SONG Younghwan <purluno@gmail.com> - * @author Seung-Chul Yoo <dryoo@live.com> + * @author Seung-Chul Yoo <dryoo@live.com> * @author erial2@gmail.com * @author Myeongjin <aranet100@gmail.com> */ @@ -48,11 +47,11 @@ $lang['error'] = '알 수 없는 문제가 발생했습니다.'; $lang['error_download'] = '플러그인 파일을 다운로드 할 수 없습니다: %s'; $lang['error_badurl'] = '잘못된 URL 같습니다 - URL에서 파일 이름을 알 수 없습니다.'; $lang['error_dircreate'] = '다운로드를 받기 위한 임시 디렉토리를 만들 수 없습니다.'; -$lang['error_decompress'] = '플러그인 관리자가 다운로드 받은 파일을 압축을 풀 수 없습니다. 잘못 다운로드 받았을 수도 있으니 다시 한번 시도해보기 바랍니다. 또는 압축 포맷을 알 수 없는 경우에는 다운로드한 후 수동으로 직접 설치하기 바랍니다.'; +$lang['error_decompress'] = '플러그인 관리자가 다운로드 받은 파일을 압축을 풀 수 없습니다. 잘못 다운로드 받았을 수도 있으니 다시 한번 시도하거나 압축 포맷을 알 수 없는 경우에는 다운로드한 후 수동으로 직접 설치하세요.'; $lang['error_copy'] = '플러그인을 설치하는 동안 파일 복사하는 데 오류가 발생했습니다. <em>%s</em>: 디스크가 꽉 찼거나 파일 접근 권한이 잘못된 경우입니다. 플러그인 설치가 부분적으로만 이루어졌을 것입니다. 설치가 불완전합니다.'; $lang['error_delete'] = '<em>%s</em> 플러그인을 삭제하는 동안 오류가 발생했습니다. 대부분의 경우 불완전한 파일이거나 디렉토리 접근 권한이 잘못된 경우입니다.'; $lang['enabled'] = '%s 플러그인을 활성화했습니다.'; -$lang['notenabled'] = '%s 플러그인을 활성화할 수 없습니다. 파일 권한을 확인하십시오.'; +$lang['notenabled'] = '%s 플러그인을 활성화할 수 없습니다. 파일 권한을 확인하세요.'; $lang['disabled'] = '%s 플러그인을 비활성화했습니다.'; -$lang['notdisabled'] = '%s 플러그인을 비활성화할 수 없습니다. 파일 권한을 확인하십시오.'; +$lang['notdisabled'] = '%s 플러그인을 비활성화할 수 없습니다. 파일 권한을 확인하하세요.'; $lang['packageinstalled'] = '플러그인 패키지(플러그인 %d개: %s)가 성공적으로 설치되었습니다.'; diff --git a/lib/plugins/popularity/lang/ko/intro.txt b/lib/plugins/popularity/lang/ko/intro.txt index b9e66094e..2513b77b4 100644 --- a/lib/plugins/popularity/lang/ko/intro.txt +++ b/lib/plugins/popularity/lang/ko/intro.txt @@ -4,6 +4,6 @@ 설치된 위키가 커짐에 따라서 이 과정을 반복할 필요가 있습니다. 반복된 데이타는 익명 ID로 구별되어집니다. -전송 데이타는 설치 DokuWiki 버전, 문서와 파일 수, 크기, 설치 플러그인, 설치 PHP 정보등을 포함하고 있습니다. +보내려는 데이터는 설치 DokuWiki 버전, 문서와 파일 수, 크기, 설치 플러그인, 설치 PHP 정보등을 포함하고 있습니다. -실제 보내질 자료는 아래와 같습니다. 정보를 보내려면 "자료 보내기" 버튼을 클릭합니다. \ No newline at end of file +실제 보내질 자료는 아래와 같습니다. 정보를 보내려면 "자료 보내기" 버튼을 클릭하세요. \ No newline at end of file diff --git a/lib/plugins/popularity/lang/ko/lang.php b/lib/plugins/popularity/lang/ko/lang.php index 5e6966402..c881b5a5a 100644 --- a/lib/plugins/popularity/lang/ko/lang.php +++ b/lib/plugins/popularity/lang/ko/lang.php @@ -2,18 +2,17 @@ /** * Korean language file * - * @author jk lee + * @author jk Lee * @author dongnak@gmail.com * @author Song Younghwan <purluno@gmail.com> - * @author SONG Younghwan <purluno@gmail.com> - * @author Seung-Chul Yoo <dryoo@live.com> + * @author Seung-Chul Yoo <dryoo@live.com> * @author erial2@gmail.com * @author Myeongjin <aranet100@gmail.com> */ $lang['name'] = '인기도 조사 (불러오는데 시간이 걸릴 수 있습니다.)'; $lang['submit'] = '자료 보내기'; $lang['autosubmit'] = '자료를 자동으로 매달 한번씩 보내기'; -$lang['submissionFailed'] = '다음과 같은 이유로 자료 전송에 실패했습니다:'; +$lang['submissionFailed'] = '다음과 같은 이유로 자료 보내기에 실패했습니다:'; $lang['submitDirectly'] = '아래의 양식에 맞춰 수동으로 작성된 자료를 보낼 수 있습니다'; -$lang['autosubmitError'] = '다음과 같은 이유로 자동 자료 전송에 실패했습니다:'; -$lang['lastSent'] = '자료가 전송되었습니다'; +$lang['autosubmitError'] = '다음과 같은 이유로 자동 자료 보내기에 실패했습니다:'; +$lang['lastSent'] = '자료를 보냈습니다'; diff --git a/lib/plugins/popularity/lang/ko/submitted.txt b/lib/plugins/popularity/lang/ko/submitted.txt index 12f0efe45..37cfbd8f2 100644 --- a/lib/plugins/popularity/lang/ko/submitted.txt +++ b/lib/plugins/popularity/lang/ko/submitted.txt @@ -1,3 +1,3 @@ ====== 인기도 조사 ====== -자료 전송이 성공적으로 완료되었습니다. \ No newline at end of file +자료를 성공적으로 보냈습니다. \ No newline at end of file diff --git a/lib/plugins/revert/lang/ko/intro.txt b/lib/plugins/revert/lang/ko/intro.txt index 30813fe49..548890ecd 100644 --- a/lib/plugins/revert/lang/ko/intro.txt +++ b/lib/plugins/revert/lang/ko/intro.txt @@ -1,3 +1,3 @@ -====== 복구 관리자 ====== +====== 되돌리기 관리자 ====== -스팸 공격으로 부터 자동으로 복구하는데 이 페이지가 도움이 될 수 있습니다. 스팸 공격받은 문서 목록을 찾으려면 문자열을 입력하기 바랍니다 (예를 들어 스팸 URL), 그 후 찾은 문서가 스팸 공격을 받았는지 확인하고 복구합니다. +스팸 공격으로부터 자동으로 되돌리는데 이 페이지가 도움이 될 수 있습니다. 스팸 공격받은 문서 목록을 찾으려면 문자열을 입력하고(예를 들어 스팸 URL) 나서 찾은 문서가 스팸 공격을 받았는지 확인하고 되돌리세요. diff --git a/lib/plugins/revert/lang/ko/lang.php b/lib/plugins/revert/lang/ko/lang.php index 90cba9bce..d36726279 100644 --- a/lib/plugins/revert/lang/ko/lang.php +++ b/lib/plugins/revert/lang/ko/lang.php @@ -2,20 +2,19 @@ /** * Korean language file * - * @author jk lee + * @author jk Lee * @author dongnak@gmail.com * @author Song Younghwan <purluno@gmail.com> - * @author SONG Younghwan <purluno@gmail.com> - * @author Seung-Chul Yoo <dryoo@live.com> + * @author Seung-Chul Yoo <dryoo@live.com> * @author erial2@gmail.com * @author Myeongjin <aranet100@gmail.com> */ -$lang['menu'] = '복구 관리자'; +$lang['menu'] = '되돌리기 관리자'; $lang['filter'] = '스팸 문서 찾기'; -$lang['revert'] = '선택한 문서 복구'; -$lang['reverted'] = '%s 버전을 %s 버전으로 복구'; -$lang['removed'] = '%s 삭제'; -$lang['revstart'] = '복구 작업을 시작합니다. 오랜 시간이 걸릴 수 있습니다. 완료되기 전에 스크립트 시간 초과가 발생한다면 더 작은 작업으로 나누어서 복구하기 바랍니다.'; -$lang['revstop'] = '복구 작업이 성공적으로 끝났습니다.'; -$lang['note1'] = '참고: 대소문자 구별하여 찾습니다.'; -$lang['note2'] = '참고: 이 문서는 <i>%s</i> 스팸 단어를 포함하지 않은 최근 이전 버전으로 복구됩니다. '; +$lang['revert'] = '선택한 문서 되돌리기'; +$lang['reverted'] = '%s 판을 %s 판으로 되돌림'; +$lang['removed'] = '%s 삭제함'; +$lang['revstart'] = '되돌리기 작업을 시작합니다. 오랜 시간이 걸릴 수 있습니다. 완료되기 전에 스크립트 시간 초과가 발생한다면 더 작은 작업으로 나누어서 되돌리시기 바랍니다.'; +$lang['revstop'] = '되돌리기 작업이 성공적으로 끝났습니다.'; +$lang['note1'] = '참고: 대소문자를 구별하여 찾습니다'; +$lang['note2'] = '참고: 이 문서는 <i>%s</i> 스팸 단어를 포함하지 않은 최근 이전 판으로 되돌립니다. '; diff --git a/lib/plugins/usermanager/lang/ko/lang.php b/lib/plugins/usermanager/lang/ko/lang.php index 58f9bf14a..f8c400d19 100644 --- a/lib/plugins/usermanager/lang/ko/lang.php +++ b/lib/plugins/usermanager/lang/ko/lang.php @@ -1,19 +1,18 @@ <?php /** - * korean language file + * Korean language file * * @author jk Lee * @author dongnak@gmail.com * @author Song Younghwan <purluno@gmail.com> - * @author SONG Younghwan <purluno@gmail.com> - * @author Seung-Chul Yoo <dryoo@live.com> + * @author Seung-Chul Yoo <dryoo@live.com> * @author erial2@gmail.com * @author Myeongjin <aranet100@gmail.com> */ $lang['menu'] = '사용자 관리자'; -$lang['noauth'] = '(사용자 인증이 불가능합니다.)'; -$lang['nosupport'] = '(사용자 관리가 지원되지 않습니다.)'; -$lang['badauth'] = '잘못된 인증 메카니즘'; +$lang['noauth'] = '(사용자 인증이 불가능합니다)'; +$lang['nosupport'] = '(사용자 관리가 지원되지 않습니다)'; +$lang['badauth'] = '인증 메카니즘이 잘못되었습니다'; $lang['user_id'] = '사용자'; $lang['user_pass'] = '비밀번호'; $lang['user_name'] = '실제 이름'; @@ -31,13 +30,13 @@ $lang['search'] = '찾기'; $lang['search_prompt'] = '찾기 실행'; $lang['clear'] = '찾기 필터 초기화'; $lang['filter'] = '필터'; -$lang['summary'] = '찾은 사용자 %3$d 중 %1$d-%2$d 보기. 전체 사용자 %4$d명.'; -$lang['nonefound'] = '찾은 사용자가 없습니다. 전체 사용자 %d명.'; +$lang['summary'] = '찾은 사용자 %3$d 중 %1$d-%2$d을(를) 봅니다. 전체 사용자는 %4$d명입니다.'; +$lang['nonefound'] = '찾은 사용자가 없습니다. 전체 사용자는 %d명입니다.'; $lang['delete_ok'] = '사용자 %d명이 삭제되었습니다'; $lang['delete_fail'] = '사용자 %d명의 삭제가 실패했습니다.'; -$lang['update_ok'] = '사용자 정보를 성공적으로 바꾸었습니다.'; -$lang['update_fail'] = '사용자 정보를 바꾸는 데 실패했습니다.'; -$lang['update_exists'] = '사용자 이름을 바꾸기는 데 실패했습니다. 사용자 이름(%s)이 이미 존재합니다. (다른 항목의 바뀜은 적용됩니다.)'; +$lang['update_ok'] = '사용자 정보를 성공적으로 바꾸었습니다'; +$lang['update_fail'] = '사용자 정보를 바꾸는 데 실패했습니다'; +$lang['update_exists'] = '사용자 이름을 바꾸는 데 실패했습니다. 사용자 이름(%s)이 이미 존재합니다. (다른 항목의 바뀜은 적용됩니다.)'; $lang['start'] = '시작'; $lang['prev'] = '이전'; $lang['next'] = '다음'; @@ -47,7 +46,7 @@ $lang['user_notify'] = '사용자에게 알림'; $lang['note_notify'] = '사용자에게 새로운 비밀번호를 준 경우에만 알림 이메일이 보내집니다.'; $lang['note_group'] = '새로운 사용자는 어떤 그룹도 설정하지 않은 경우에 기본 그룹(%s)에 추가됩니다.'; $lang['note_pass'] = '사용자 통지가 지정되어 있을 때 필드에 아무 값도 입력하지 않으면 비밀번호가 자동으로 만들어집니다.'; -$lang['add_ok'] = '사용자가 성공적으로 추가되었습니다.'; -$lang['add_fail'] = '사용자 추가가 실패했습니다.'; -$lang['notify_ok'] = '알림 이메일이 성공적으로 발송되었습니다. '; -$lang['notify_fail'] = '알림 이메일 발송이 실패했습니다.'; +$lang['add_ok'] = '사용자를 성공적으로 추가했습니다'; +$lang['add_fail'] = '사용자 추가를 실패했습니다'; +$lang['notify_ok'] = '알림 이메일을 성공적으로 보냈습니다'; +$lang['notify_fail'] = '알림 이메일을 보낼 수 없습니다'; -- cgit v1.2.3 From f2b500f5e7be771601ea1b1bc110337883d7caf2 Mon Sep 17 00:00:00 2001 From: Frank Loizzi <catchall@bacal.de> Date: Sun, 24 Mar 2013 10:32:26 +0100 Subject: German (informal) language update --- inc/lang/de-informal/lang.php | 4 + lib/plugins/acl/lang/de-informal/lang.php | 1 + lib/plugins/authad/lang/de-informal/settings.php | 18 ++++ lib/plugins/authldap/lang/de-informal/settings.php | 6 ++ .../authmysql/lang/de-informal/settings.php | 6 ++ .../authpgsql/lang/de-informal/settings.php | 6 ++ lib/plugins/config/lang/de-informal/lang.php | 103 +++++++++++---------- lib/plugins/plugin/lang/de-informal/lang.php | 1 + lib/plugins/popularity/lang/de-informal/lang.php | 1 + lib/plugins/revert/lang/de-informal/lang.php | 1 + lib/plugins/usermanager/lang/de-informal/lang.php | 1 + 11 files changed, 97 insertions(+), 51 deletions(-) create mode 100644 lib/plugins/authad/lang/de-informal/settings.php create mode 100644 lib/plugins/authldap/lang/de-informal/settings.php create mode 100644 lib/plugins/authmysql/lang/de-informal/settings.php create mode 100644 lib/plugins/authpgsql/lang/de-informal/settings.php diff --git a/inc/lang/de-informal/lang.php b/inc/lang/de-informal/lang.php index 3b19f749d..8a954c0e8 100644 --- a/inc/lang/de-informal/lang.php +++ b/inc/lang/de-informal/lang.php @@ -19,6 +19,7 @@ * @author Matthias Schulte <dokuwiki@lupo49.de> * @author Christian Wichmann <nospam@zone0.de> * @author Pierre Corell <info@joomla-praxis.de> + * @author Frank Loizzi <contact@software.bacal.de> */ $lang['encoding'] = 'utf-8'; $lang['direction'] = 'ltr'; @@ -296,6 +297,9 @@ $lang['i_pol1'] = 'Öffentliches Wiki (Lesen für alle, Schreiben $lang['i_pol2'] = 'Geschlossenes Wiki (Lesen, Schreiben und Hochladen nur für registrierte Nutzer)'; $lang['i_retry'] = 'Wiederholen'; $lang['i_license'] = 'Bitte wähle die Lizenz aus unter der die Wiki-Inhalte veröffentlicht werden sollen:'; +$lang['i_license_none'] = 'Keine Lizenzinformationen anzeigen'; +$lang['i_pop_field'] = 'Bitte helfe uns, die DokuWiki-Erfahrung zu verbessern'; +$lang['i_pop_label'] = 'Sende einmal im Monat anonyme Nutzungsdaten an die DokuWiki Entwickler'; $lang['recent_global'] = 'Im Moment siehst du die Änderungen im Namensraum <b>%s</b>. Du kannst auch <a href="%s">die Änderungen im gesamten Wiki sehen</a>.'; $lang['years'] = 'vor %d Jahren'; $lang['months'] = 'vor %d Monaten'; diff --git a/lib/plugins/acl/lang/de-informal/lang.php b/lib/plugins/acl/lang/de-informal/lang.php index 05f7df037..8b1416137 100644 --- a/lib/plugins/acl/lang/de-informal/lang.php +++ b/lib/plugins/acl/lang/de-informal/lang.php @@ -8,6 +8,7 @@ * @author Matthias Schulte <dokuwiki@lupo49.de> * @author Christian Wichmann <nospam@zone0.de> * @author Pierre Corell <info@joomla-praxis.de> + * @author Frank Loizzi <contact@software.bacal.de> */ $lang['admin_acl'] = 'Zugangsverwaltung'; $lang['acl_group'] = 'Gruppe'; diff --git a/lib/plugins/authad/lang/de-informal/settings.php b/lib/plugins/authad/lang/de-informal/settings.php new file mode 100644 index 000000000..da33a2e98 --- /dev/null +++ b/lib/plugins/authad/lang/de-informal/settings.php @@ -0,0 +1,18 @@ +<?php +/** + * German (informal) language file + * + * @author Frank Loizzi <contact@software.bacal.de> + */ +$lang['account_suffix'] = 'Ihre Kontoendung. Z.B. <code>@my.domain.org</code>'; +$lang['base_dn'] = 'Ihre base DN. Z.B. <code>DC=my,DC=domain,DC=org</code>'; +$lang['domain_controllers'] = 'Eine kommaseparierte Liste von Domänenkontrollern. Z.B. <code>srv1.domain.org,srv2.domain.org</code>'; +$lang['ad_username'] = 'Ein priviligierter Active Directory Benutzer mit Zugriff zu allen anderen Benutzerdaten. Optional aber benötigt für einige Aktionen wie das Senden von Mitglieder E-Mails.'; +$lang['ad_password'] = 'Das Passwort des obigen Benutzers.'; +$lang['sso'] = 'Soll Single-Sign-On via Kerberos oder NTLM benutzt werden?'; +$lang['real_primarygroup'] = 'Soll die echte primäre Gruppe aufgelöst werden anstelle der Annahme "Domain Users" (langsamer)'; +$lang['use_ssl'] = 'SSL-Verbindung benutzen? Falls ja, TLS unterhalb nicht aktivieren.'; +$lang['use_tls'] = 'TLS-Verbindung benutzen? Falls ja, SSL oberhalb nicht aktivieren.'; +$lang['debug'] = 'Zusätzliche Debug-Informationen bei Fehlern anzeigen?'; +$lang['expirywarn'] = 'Tage im Voraus um Benutzer über ablaufende Passwörter zu informieren. 0 zum Ausschalten.'; +$lang['additional'] = 'Eine kommaseparierte Liste von zusätzlichen AD Attributen von den Benutzdedaten abrufen. Wird von einigen Plugins benutzt.'; diff --git a/lib/plugins/authldap/lang/de-informal/settings.php b/lib/plugins/authldap/lang/de-informal/settings.php new file mode 100644 index 000000000..e7b3d2673 --- /dev/null +++ b/lib/plugins/authldap/lang/de-informal/settings.php @@ -0,0 +1,6 @@ +<?php +/** + * German (informal) language file + * + * @author Frank Loizzi <contact@software.bacal.de> + */ diff --git a/lib/plugins/authmysql/lang/de-informal/settings.php b/lib/plugins/authmysql/lang/de-informal/settings.php new file mode 100644 index 000000000..e7b3d2673 --- /dev/null +++ b/lib/plugins/authmysql/lang/de-informal/settings.php @@ -0,0 +1,6 @@ +<?php +/** + * German (informal) language file + * + * @author Frank Loizzi <contact@software.bacal.de> + */ diff --git a/lib/plugins/authpgsql/lang/de-informal/settings.php b/lib/plugins/authpgsql/lang/de-informal/settings.php new file mode 100644 index 000000000..e7b3d2673 --- /dev/null +++ b/lib/plugins/authpgsql/lang/de-informal/settings.php @@ -0,0 +1,6 @@ +<?php +/** + * German (informal) language file + * + * @author Frank Loizzi <contact@software.bacal.de> + */ diff --git a/lib/plugins/config/lang/de-informal/lang.php b/lib/plugins/config/lang/de-informal/lang.php index d86c2d809..58a78fe47 100644 --- a/lib/plugins/config/lang/de-informal/lang.php +++ b/lib/plugins/config/lang/de-informal/lang.php @@ -8,6 +8,7 @@ * @author Matthias Schulte <dokuwiki@lupo49.de> * @author Christian Wichmann <nospam@zone0.de> * @author Pierre Corell <info@joomla-praxis.de> + * @author Frank Loizzi <contact@software.bacal.de> */ $lang['menu'] = 'Einstellungen'; $lang['error'] = 'Einstellungen wurden nicht aktualisiert auf Grund eines ungültigen Wertes. Bitte überprüfe deine Änderungen und versuche es erneut.<br />Die/der ungültige(n) Wert(e) werden durch eine rote Umrandung hervorgehoben.'; @@ -38,28 +39,29 @@ $lang['_template_sufix'] = 'Vorlageneinstellungen'; $lang['_msg_setting_undefined'] = 'Keine Konfigurationsmetadaten.'; $lang['_msg_setting_no_class'] = 'Keine Konfigurationsklasse.'; $lang['_msg_setting_no_default'] = 'Kein Standardwert.'; -$lang['fmode'] = 'Zugriffsrechte bei Dateierstellung'; -$lang['dmode'] = 'Zugriffsrechte bei Verzeichniserstellung'; -$lang['lang'] = 'Sprache'; -$lang['basedir'] = 'Installationsverzeichnis'; -$lang['baseurl'] = 'Installationspfad (URL)'; -$lang['savedir'] = 'Ordner zum Speichern von Daten'; -$lang['cookiedir'] = 'Cookie Pfad. Leer lassen, um die Standard-Url zu belassen.'; -$lang['start'] = 'Name der Startseite'; $lang['title'] = 'Wiki Titel'; +$lang['start'] = 'Name der Startseite'; +$lang['lang'] = 'Sprache'; $lang['template'] = 'Vorlage'; $lang['tagline'] = 'Tag-Linie (nur, wenn vom Template unterstützt)'; $lang['sidebar'] = 'Name der Sidebar-Seite (nur, wenn vom Template unterstützt)), ein leeres Feld deaktiviert die Sidebar'; $lang['license'] = 'Unter welcher Lizenz sollte Ihr Inhalt veröffentlicht werden?'; -$lang['fullpath'] = 'Zeige vollen Pfad der Datei in Fußzeile an'; +$lang['savedir'] = 'Ordner zum Speichern von Daten'; +$lang['basedir'] = 'Installationsverzeichnis'; +$lang['baseurl'] = 'Installationspfad (URL)'; +$lang['cookiedir'] = 'Cookie Pfad. Leer lassen, um die Standard-Url zu belassen.'; +$lang['dmode'] = 'Zugriffsrechte bei Verzeichniserstellung'; +$lang['fmode'] = 'Zugriffsrechte bei Dateierstellung'; +$lang['allowdebug'] = 'Debug-Ausgaben erlauben <b>Abschalten wenn nicht benötigt!</b>'; $lang['recent'] = 'letzte Änderungen'; +$lang['recent_days'] = 'Wie viele Änderungen sollen vorgehalten werden? (Tage)'; $lang['breadcrumbs'] = 'Anzahl der Einträge im "Krümelpfad"'; $lang['youarehere'] = 'Hierarchische Pfadnavigation verwenden'; +$lang['fullpath'] = 'Zeige vollen Pfad der Datei in Fußzeile an'; $lang['typography'] = 'Mach drucktechnische Ersetzungen'; -$lang['htmlok'] = 'Erlaube eingebettetes HTML'; -$lang['phpok'] = 'Erlaube eingebettetes PHP'; $lang['dformat'] = 'Datumsformat (siehe PHPs <a href="http://www.php.net/strftime">strftime</a> Funktion)'; $lang['signature'] = 'Signatur'; +$lang['showuseras'] = 'Was angezeigt werden soll, wenn der Benutzer, der zuletzt eine Seite bearbeitet hat, angezeigt wird'; $lang['toptoclevel'] = 'Inhaltsverzeichnis bei dieser Überschriftengröße beginnen'; $lang['tocminheads'] = 'Mindestanzahl der Überschriften die entscheidet, ob ein Inhaltsverzeichnis erscheinen soll'; $lang['maxtoclevel'] = 'Maximale Überschriftsgröße für Inhaltsverzeichnis'; @@ -67,16 +69,8 @@ $lang['maxseclevel'] = 'Abschnitte bis zu dieser Stufe einzeln editier $lang['camelcase'] = 'CamelCase-Verlinkungen verwenden'; $lang['deaccent'] = 'Seitennamen bereinigen'; $lang['useheading'] = 'Erste Überschrift als Seitennamen verwenden'; -$lang['refcheck'] = 'Auf Verwendung beim Löschen von Media-Dateien testen'; -$lang['refshow'] = 'Wie viele Verwendungsorte der Media-Datei zeigen'; -$lang['allowdebug'] = 'Debug-Ausgaben erlauben <b>Abschalten wenn nicht benötigt!</b>'; -$lang['mediarevisions'] = 'Media-Revisionen (ältere Versionen) aktivieren?'; -$lang['usewordblock'] = 'Blockiere Spam basierend auf der Wortliste'; -$lang['indexdelay'] = 'Zeit bevor Suchmaschinenindexierung erlaubt ist'; -$lang['relnofollow'] = 'rel="nofollow" verwenden'; -$lang['mailguard'] = 'E-Mail-Adressen schützen'; -$lang['iexssprotect'] = 'Hochgeladene Dateien auf bösartigen JavaScript- und HTML-Code untersuchen'; -$lang['showuseras'] = 'Was angezeigt werden soll, wenn der Benutzer, der zuletzt eine Seite bearbeitet hat, angezeigt wird'; +$lang['sneaky_index'] = 'Standardmäßig zeigt DokuWiki alle Namensräume in der Indexansicht an. Bei Aktivierung dieser Einstellung werden alle Namensräume versteckt, in welchen der Benutzer keine Leserechte hat. Dies könnte dazu führen, dass lesbare Unternamensräume versteckt werden. Dies kann die Indexansicht bei bestimmten Zugangskontrolleinstellungen unbenutzbar machen.'; +$lang['hidepages'] = 'Seiten verstecken (Regulärer Ausdruck)'; $lang['useacl'] = 'Benutze Zugangskontrollliste'; $lang['autopasswd'] = 'Automatisch erzeugte Passwörter'; $lang['authtype'] = 'Authentifizierungsmethode'; @@ -85,62 +79,69 @@ $lang['defaultgroup'] = 'Standardgruppe'; $lang['superuser'] = 'Administrator - Eine Gruppe oder Nutzer mit vollem Zugriff auf alle Seiten und Administrationswerkzeuge.'; $lang['manager'] = 'Manager - Eine Gruppe oder Nutzer mit Zugriff auf einige Administrationswerkzeuge.'; $lang['profileconfirm'] = 'Änderungen am Benutzerprofil mit Passwort bestätigen'; +$lang['rememberme'] = 'Permanente Login-Cookies erlauben (Auf diesem Computer eingeloggt bleiben)'; $lang['disableactions'] = 'Deaktiviere DokuWiki\'s Zugriffe'; $lang['disableactions_check'] = 'Check'; $lang['disableactions_subscription'] = 'Bestellen/Abbestellen'; $lang['disableactions_wikicode'] = 'Zeige Quelle/Exportiere Rohdaten'; $lang['disableactions_other'] = 'Weitere Aktionen (durch Komma getrennt)'; -$lang['sneaky_index'] = 'Standardmäßig zeigt DokuWiki alle Namensräume in der Indexansicht an. Bei Aktivierung dieser Einstellung werden alle Namensräume versteckt, in welchen der Benutzer keine Leserechte hat. Dies könnte dazu führen, dass lesbare Unternamensräume versteckt werden. Dies kann die Indexansicht bei bestimmten Zugangskontrolleinstellungen unbenutzbar machen.'; $lang['auth_security_timeout'] = 'Zeitüberschreitung bei der Authentifizierung (Sekunden)'; $lang['securecookie'] = 'Sollen Cookies, die via HTTPS gesetzt wurden nur per HTTPS versendet werden? Deaktiviere diese Option, wenn nur der Login deines Wikis mit SSL gesichert ist, aber das Betrachten des Wikis ungesichert geschieht.'; $lang['remote'] = 'Aktiviert den externen API-Zugang. Diese Option erlaubt es externen Anwendungen von außen auf die XML-RPC-Schnittstelle oder anderweitigen Schnittstellen zuzugreifen.'; $lang['remoteuser'] = 'Zugriff auf die externen Schnittstellen durch kommaseparierte Angabe von Benutzern oder Gruppen einschränken. Ein leeres Feld erlaubt Zugriff für jeden.'; -$lang['updatecheck'] = 'Automatisch auf Updates und Sicherheitswarnungen prüfen? DokuWiki muss sich dafür mit update.dokuwiki.org verbinden.'; -$lang['userewrite'] = 'Benutze schöne URLs'; -$lang['useslash'] = 'Benutze Schrägstrich als Namensraumtrenner in URLs'; +$lang['usewordblock'] = 'Blockiere Spam basierend auf der Wortliste'; +$lang['relnofollow'] = 'rel="nofollow" verwenden'; +$lang['indexdelay'] = 'Zeit bevor Suchmaschinenindexierung erlaubt ist'; +$lang['mailguard'] = 'E-Mail-Adressen schützen'; +$lang['iexssprotect'] = 'Hochgeladene Dateien auf bösartigen JavaScript- und HTML-Code untersuchen'; $lang['usedraft'] = 'Speichere automatisch Entwürfe während der Bearbeitung'; -$lang['sepchar'] = 'Worttrenner für Seitennamen in URLs'; -$lang['canonical'] = 'Immer Links mit vollständigen URLs erzeugen'; -$lang['fnencode'] = 'Methode um nicht-ASCII Dateinamen zu kodieren.'; -$lang['autoplural'] = 'Bei Links automatisch nach vorhandenen Pluralformen suchen'; -$lang['compression'] = 'Komprimierungsmethode für alte Seitenrevisionen'; -$lang['cachetime'] = 'Maximale Cachespeicherung (Sekunden)'; +$lang['htmlok'] = 'Erlaube eingebettetes HTML'; +$lang['phpok'] = 'Erlaube eingebettetes PHP'; $lang['locktime'] = 'Maximales Alter für Seitensperren (Sekunden)'; +$lang['cachetime'] = 'Maximale Cachespeicherung (Sekunden)'; +$lang['target____wiki'] = 'Zielfenstername für interne Links'; +$lang['target____interwiki'] = 'Zielfenstername für InterWiki-Links'; +$lang['target____extern'] = 'Zielfenstername für externe Links'; +$lang['target____media'] = 'Zielfenstername für Medienlinks'; +$lang['target____windows'] = 'Zielfenstername für Windows-Freigaben-Links'; +$lang['mediarevisions'] = 'Media-Revisionen (ältere Versionen) aktivieren?'; +$lang['refcheck'] = 'Auf Verwendung beim Löschen von Media-Dateien testen'; +$lang['refshow'] = 'Wie viele Verwendungsorte der Media-Datei zeigen'; +$lang['gdlib'] = 'GD Lib Version'; +$lang['im_convert'] = 'Pfad zu ImageMagicks-Konvertierwerkzeug'; +$lang['jpg_quality'] = 'JPEG Kompressionsqualität (0-100)'; $lang['fetchsize'] = 'Maximale Größe (in Bytes), die fetch.php von extern herunterladen darf'; +$lang['subscribers'] = 'E-Mail-Abos zulassen'; +$lang['subscribe_time'] = 'Zeit nach der Zusammenfassungs- und Änderungslisten-E-Mails verschickt werden; Dieser Wert sollte kleiner als die in recent_days konfigurierte Zeit sein.'; $lang['notify'] = 'Sende Änderungsbenachrichtigungen an diese E-Mail-Adresse.'; $lang['registernotify'] = 'Sende Information bei neu registrierten Benutzern an diese E-Mail-Adresse.'; $lang['mailfrom'] = 'Absenderadresse für automatisch erzeugte E-Mails'; $lang['mailprefix'] = 'Präfix für E-Mail-Betreff beim automatischen Versand von Benachrichtigungen'; $lang['htmlmail'] = 'Versendet optisch angenehmere, aber größere E-Mails im HTML-Format (multipart). Deaktivieren, um Text-Mails zu versenden.'; +$lang['sitemap'] = 'Erzeuge Google Sitemaps (Tage)'; +$lang['rss_type'] = 'XML-Feed-Format'; +$lang['rss_linkto'] = 'XML-Feed verlinken auf'; +$lang['rss_content'] = 'Was soll in XML-Feedinhalten angezeigt werden?'; +$lang['rss_update'] = 'Aktualisierungsintervall für XML-Feeds (Sekunden)'; +$lang['rss_show_summary'] = 'Bearbeitungs-Zusammenfassung im XML-Feed anzeigen'; +$lang['rss_media'] = 'Welche Änderungen sollen im XML-Feed angezeigt werden?'; +$lang['updatecheck'] = 'Automatisch auf Updates und Sicherheitswarnungen prüfen? DokuWiki muss sich dafür mit update.dokuwiki.org verbinden.'; +$lang['userewrite'] = 'Benutze schöne URLs'; +$lang['useslash'] = 'Benutze Schrägstrich als Namensraumtrenner in URLs'; +$lang['sepchar'] = 'Worttrenner für Seitennamen in URLs'; +$lang['canonical'] = 'Immer Links mit vollständigen URLs erzeugen'; +$lang['fnencode'] = 'Methode um nicht-ASCII Dateinamen zu kodieren.'; +$lang['autoplural'] = 'Bei Links automatisch nach vorhandenen Pluralformen suchen'; +$lang['compression'] = 'Komprimierungsmethode für alte Seitenrevisionen'; $lang['gzip_output'] = 'Seiten mit gzip komprimiert ausliefern'; -$lang['gdlib'] = 'GD Lib Version'; -$lang['im_convert'] = 'Pfad zu ImageMagicks-Konvertierwerkzeug'; -$lang['jpg_quality'] = 'JPEG Kompressionsqualität (0-100)'; -$lang['subscribers'] = 'E-Mail-Abos zulassen'; -$lang['subscribe_time'] = 'Zeit nach der Zusammenfassungs- und Änderungslisten-E-Mails verschickt werden; Dieser Wert sollte kleiner als die in recent_days konfigurierte Zeit sein.'; $lang['compress'] = 'JavaScript und Stylesheets komprimieren'; $lang['cssdatauri'] = 'Größe in Bytes, bis zu der Bilder in css-Dateien referenziert werden können, um HTTP-Anfragen zu minimieren. Diese Technik funktioniert nicht im IE 7 und älter! <code>400</code> bis <code>600</code> Bytes sind gute Werte. Setze <code>0</code> für inaktive Funktion.'; -$lang['hidepages'] = 'Seiten verstecken (Regulärer Ausdruck)'; $lang['send404'] = 'Sende "HTTP 404/Seite nicht gefunden" für nicht existierende Seiten'; -$lang['sitemap'] = 'Erzeuge Google Sitemaps (Tage)'; $lang['broken_iua'] = 'Falls die Funktion ignore_user_abort auf deinem System nicht funktioniert, könnte der Such-Index nicht funktionieren. IIS+PHP/CGI ist bekannt dafür. Siehe auch <a href="http://bugs.splitbrain.org/?do=details&task_id=852">Bug 852</a>.'; $lang['xsendfile'] = 'Den X-Sendfile-Header nutzen, um Dateien direkt vom Webserver ausliefern zu lassen? Dein Webserver muss dies unterstützen!'; $lang['renderer_xhtml'] = 'Standard-Renderer für die normale (XHTML) Wiki-Ausgabe.'; $lang['renderer__core'] = '%s (DokuWiki Kern)'; $lang['renderer__plugin'] = '%s (Erweiterung)'; -$lang['rememberme'] = 'Permanente Login-Cookies erlauben (Auf diesem Computer eingeloggt bleiben)'; -$lang['rss_type'] = 'XML-Feed-Format'; -$lang['rss_linkto'] = 'XML-Feed verlinken auf'; -$lang['rss_content'] = 'Was soll in XML-Feedinhalten angezeigt werden?'; -$lang['rss_update'] = 'Aktualisierungsintervall für XML-Feeds (Sekunden)'; -$lang['recent_days'] = 'Wie viele Änderungen sollen vorgehalten werden? (Tage)'; -$lang['rss_show_summary'] = 'Bearbeitungs-Zusammenfassung im XML-Feed anzeigen'; -$lang['rss_media'] = 'Welche Änderungen sollen im XML-Feed angezeigt werden?'; -$lang['target____wiki'] = 'Zielfenstername für interne Links'; -$lang['target____interwiki'] = 'Zielfenstername für InterWiki-Links'; -$lang['target____extern'] = 'Zielfenstername für externe Links'; -$lang['target____media'] = 'Zielfenstername für Medienlinks'; -$lang['target____windows'] = 'Zielfenstername für Windows-Freigaben-Links'; $lang['dnslookups'] = 'DokuWiki löst die IP-Adressen von Benutzern zu deren Hostnamen auf. Wenn du einen langsamen, unbrauchbaren DNS-Server verwendest oder die Funktion nicht benötigst, dann sollte diese Option deaktivert sein.'; $lang['proxy____host'] = 'Proxyadresse'; $lang['proxy____port'] = 'Proxyport'; diff --git a/lib/plugins/plugin/lang/de-informal/lang.php b/lib/plugins/plugin/lang/de-informal/lang.php index abcdf2c83..a082218d8 100644 --- a/lib/plugins/plugin/lang/de-informal/lang.php +++ b/lib/plugins/plugin/lang/de-informal/lang.php @@ -8,6 +8,7 @@ * @author Matthias Schulte <post@lupo49.de> * @author Christian Wichmann <nospam@zone0.de> * @author Pierre Corell <info@joomla-praxis.de> + * @author Frank Loizzi <contact@software.bacal.de> */ $lang['menu'] = 'Plugins verwalten'; $lang['download'] = 'Herunterladen und installieren einer neuen Erweiterung'; diff --git a/lib/plugins/popularity/lang/de-informal/lang.php b/lib/plugins/popularity/lang/de-informal/lang.php index 40e6c4343..513a1b6e1 100644 --- a/lib/plugins/popularity/lang/de-informal/lang.php +++ b/lib/plugins/popularity/lang/de-informal/lang.php @@ -8,6 +8,7 @@ * @author Matthias Schulte <post@lupo49.de> * @author Christian Wichmann <nospam@zone0.de> * @author Pierre Corell <info@joomla-praxis.de> + * @author Frank Loizzi <contact@software.bacal.de> */ $lang['name'] = 'Popularitätsrückmeldung (kann eine Weile dauern, bis es fertig geladen wurde)'; $lang['submit'] = 'Sende Daten'; diff --git a/lib/plugins/revert/lang/de-informal/lang.php b/lib/plugins/revert/lang/de-informal/lang.php index c199bb55b..3a96429c7 100644 --- a/lib/plugins/revert/lang/de-informal/lang.php +++ b/lib/plugins/revert/lang/de-informal/lang.php @@ -8,6 +8,7 @@ * @author Matthias Schulte <post@lupo49.de> * @author Christian Wichmann <nospam@zone0.de> * @author Pierre Corell <info@joomla-praxis.de> + * @author Frank Loizzi <contact@software.bacal.de> */ $lang['menu'] = 'Zurückstellungsmanager'; $lang['filter'] = 'Durchsuche als Spam markierte Seiten'; diff --git a/lib/plugins/usermanager/lang/de-informal/lang.php b/lib/plugins/usermanager/lang/de-informal/lang.php index e53781c77..07390854f 100644 --- a/lib/plugins/usermanager/lang/de-informal/lang.php +++ b/lib/plugins/usermanager/lang/de-informal/lang.php @@ -8,6 +8,7 @@ * @author Matthias Schulte <dokuwiki@lupo49.de> * @author Christian Wichmann <nospam@zone0.de> * @author Pierre Corell <info@joomla-praxis.de> + * @author Frank Loizzi <contact@software.bacal.de> */ $lang['menu'] = 'Benutzerverwaltung'; $lang['noauth'] = '(Benutzeranmeldung ist nicht verfügbar)'; -- cgit v1.2.3 From 33b8a94705bfbd34fbee5ed24982374e166a80d0 Mon Sep 17 00:00:00 2001 From: Andreas Gohr <andi@splitbrain.org> Date: Sun, 24 Mar 2013 13:09:30 +0100 Subject: stream select parameters need to be reset for each call --- _test/tests/inc/httpclient_http.test.php | 11 +++++++++++ inc/HTTPClient.php | 29 +++++++++++++---------------- 2 files changed, 24 insertions(+), 16 deletions(-) diff --git a/_test/tests/inc/httpclient_http.test.php b/_test/tests/inc/httpclient_http.test.php index 252eb6b65..387eb53aa 100644 --- a/_test/tests/inc/httpclient_http.test.php +++ b/_test/tests/inc/httpclient_http.test.php @@ -204,5 +204,16 @@ class httpclient_http_test extends DokuWikiTest { $this->assertFalse($data === false, 'HTTP response'); $this->assertEquals(2550,strlen($data)); } + + /** + * This address caused trouble with stream_select() + * + * @group internet + */ + function test_wikimatrix(){ + $http = new HTTPClient(); + $data = $http->get('http://www.wikimatrix.org/cfeed/dokuwiki/-/-'); + $this->assertTrue($data !== false, $http->error); + } } //Setup VIM: ex: et ts=4 : diff --git a/inc/HTTPClient.php b/inc/HTTPClient.php index 772b580b2..6d9855e12 100644 --- a/inc/HTTPClient.php +++ b/inc/HTTPClient.php @@ -570,11 +570,6 @@ class HTTPClient { * @author Tom N Harris <tnharris@whoopdedo.org> */ function _sendData($socket, $data, $message) { - // select parameters - $sel_r = null; - $sel_w = array($socket); - $sel_e = null; - // send request $towrite = strlen($data); $written = 0; @@ -586,6 +581,10 @@ class HTTPClient { if(feof($socket)) throw new HTTPClientException("Socket disconnected while writing $message"); + // select parameters + $sel_r = null; + $sel_w = array($socket); + $sel_e = null; // wait for stream ready or timeout (1sec) if(@stream_select($sel_r,$sel_w,$sel_e,1) === false){ usleep(1000); @@ -615,11 +614,6 @@ class HTTPClient { * @author Tom N Harris <tnharris@whoopdedo.org> */ function _readData($socket, $nbytes, $message, $ignore_eof = false) { - // select parameters - $sel_r = array($socket); - $sel_w = null; - $sel_e = null; - $r_data = ''; // Does not return immediately so timeout and eof can be checked if ($nbytes < 0) $nbytes = 0; @@ -637,6 +631,10 @@ class HTTPClient { } if ($to_read > 0) { + // select parameters + $sel_r = array($socket); + $sel_w = null; + $sel_e = null; // wait for stream ready or timeout (1sec) if(@stream_select($sel_r,$sel_w,$sel_e,1) === false){ usleep(1000); @@ -665,21 +663,20 @@ class HTTPClient { * @author Tom N Harris <tnharris@whoopdedo.org> */ function _readLine($socket, $message) { - // select parameters - $sel_r = array($socket); - $sel_w = null; - $sel_e = null; - $r_data = ''; do { $time_used = $this->_time() - $this->start; if ($time_used > $this->timeout) throw new HTTPClientException( - sprintf('Timeout while reading %s (%.3fs)', $message, $time_used), + sprintf('Timeout while reading %s (%.3fs) >%s<', $message, $time_used, $r_data), -100); if(feof($socket)) throw new HTTPClientException("Premature End of File (socket) while reading $message"); + // select parameters + $sel_r = array($socket); + $sel_w = null; + $sel_e = null; // wait for stream ready or timeout (1sec) if(@stream_select($sel_r,$sel_w,$sel_e,1) === false){ usleep(1000); -- cgit v1.2.3 From 8f989436768f021725a023c5ae7efae150586d0c Mon Sep 17 00:00:00 2001 From: Andreas Gohr <andi@splitbrain.org> Date: Sun, 24 Mar 2013 13:09:56 +0100 Subject: don't send empty cookie header --- inc/HTTPClient.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inc/HTTPClient.php b/inc/HTTPClient.php index 6d9855e12..0d7b80cf8 100644 --- a/inc/HTTPClient.php +++ b/inc/HTTPClient.php @@ -796,7 +796,7 @@ class HTTPClient { $headers .= "$key=$val; "; } $headers = substr($headers, 0, -2); - if ($headers !== '') $headers = "Cookie: $headers".HTTP_NL; + if ($headers) $headers = "Cookie: $headers".HTTP_NL; return $headers; } -- cgit v1.2.3 From 939baf40725d16e0cd929a9dadbf12ae6b0412c6 Mon Sep 17 00:00:00 2001 From: senorandy <senorandy@hotmail.co.uk> Date: Tue, 26 Mar 2013 10:14:44 +0100 Subject: Update default.php Wihtout this, unable to fetch any AD info.. also allows SSO. --- lib/plugins/authad/conf/default.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/plugins/authad/conf/default.php b/lib/plugins/authad/conf/default.php index 05d6c328e..9274db209 100644 --- a/lib/plugins/authad/conf/default.php +++ b/lib/plugins/authad/conf/default.php @@ -4,11 +4,11 @@ $conf['account_suffix'] = ''; $conf['base_dn'] = ''; $conf['domain_controllers'] = ''; $conf['sso'] = 0; -$conf['ad_username'] = ''; -$conf['ad_password'] = ''; +$conf['admin_username'] = ''; +$conf['admin_password'] = ''; $conf['real_primarygroup'] = 0; $conf['use_ssl'] = 0; $conf['use_tls'] = 0; $conf['debug'] = 0; $conf['expirywarn'] = 0; -$conf['additional'] = ''; \ No newline at end of file +$conf['additional'] = ''; -- cgit v1.2.3 From 0bb7340a11736568d7b537dfca36e52d5032c193 Mon Sep 17 00:00:00 2001 From: senorandy <senorandy@hotmail.co.uk> Date: Tue, 26 Mar 2013 10:15:31 +0100 Subject: Update metadata.php Without this unable to access AD info. Also allows SSO. --- lib/plugins/authad/conf/metadata.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/plugins/authad/conf/metadata.php b/lib/plugins/authad/conf/metadata.php index dc251a108..fbc3f163c 100644 --- a/lib/plugins/authad/conf/metadata.php +++ b/lib/plugins/authad/conf/metadata.php @@ -4,11 +4,11 @@ $meta['account_suffix'] = array('string'); $meta['base_dn'] = array('string'); $meta['domain_controllers'] = array('string'); $meta['sso'] = array('onoff'); -$meta['ad_username'] = array('string'); -$meta['ad_password'] = array('password'); +$meta['admin_username'] = array('string'); +$meta['admin_password'] = array('password'); $meta['real_primarygroup'] = array('onoff'); $meta['use_ssl'] = array('onoff'); $meta['use_tls'] = array('onoff'); $meta['debug'] = array('onoff'); $meta['expirywarn'] = array('numeric', '_min'=>0); -$meta['additional'] = array('string'); \ No newline at end of file +$meta['additional'] = array('string'); -- cgit v1.2.3 From 3bca6c65969446444ec4e8945d670c815b6ba066 Mon Sep 17 00:00:00 2001 From: senorandy <senorandy@hotmail.co.uk> Date: Tue, 26 Mar 2013 10:16:05 +0100 Subject: Update settings.php --- lib/plugins/authad/lang/en/settings.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/plugins/authad/lang/en/settings.php b/lib/plugins/authad/lang/en/settings.php index 41176847a..7728d5ac4 100644 --- a/lib/plugins/authad/lang/en/settings.php +++ b/lib/plugins/authad/lang/en/settings.php @@ -3,12 +3,12 @@ $lang['account_suffix'] = 'Your account suffix. Eg. <code>@my.domain.org</code>'; $lang['base_dn'] = 'Your base DN. Eg. <code>DC=my,DC=domain,DC=org</code>'; $lang['domain_controllers'] = 'A comma separated list of Domain controllers. Eg. <code>srv1.domain.org,srv2.domain.org</code>'; -$lang['ad_username'] = 'A privileged Active Directory user with access to all other user\'s data. Optional, but needed for certain actions like sending subscription mails.'; -$lang['ad_password'] = 'The password of the above user.'; +$lang['admin_username'] = 'A privileged Active Directory user with access to all other user\'s data. Optional, but needed for certain actions like sending subscription mails.'; +$lang['admin_password'] = 'The password of the above user.'; $lang['sso'] = 'Should Single-Sign-On via Kerberos or NTLM be used?'; $lang['real_primarygroup'] = 'Should the real primary group be resolved instead of assuming "Domain Users" (slower)'; $lang['use_ssl'] = 'Use SSL connection? If used, do not enable TLS below.'; $lang['use_tls'] = 'Use TLS connection? If used, do not enable SSL above.'; $lang['debug'] = 'Display additional debugging output on errors?'; $lang['expirywarn'] = 'Days in advance to warn user about expiring password. 0 to disable.'; -$lang['additional'] = 'A comma separated list of additional AD attributes to fetch from user data. Used by some plugins.'; \ No newline at end of file +$lang['additional'] = 'A comma separated list of additional AD attributes to fetch from user data. Used by some plugins.'; -- cgit v1.2.3 From bad7fb67d7e2a6939d7e6de1779100970d41b600 Mon Sep 17 00:00:00 2001 From: Michael Hamann <michael@content-space.de> Date: Sat, 30 Mar 2013 23:31:41 +0100 Subject: Add missing jQuery-UI image and update update script For just one image another syntax was used, this fixes the update script to also fetch this image. --- .../jquery/jquery-ui-theme/images/animated-overlay.gif | Bin 0 -> 1738 bytes lib/scripts/jquery/update.sh | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 lib/scripts/jquery/jquery-ui-theme/images/animated-overlay.gif diff --git a/lib/scripts/jquery/jquery-ui-theme/images/animated-overlay.gif b/lib/scripts/jquery/jquery-ui-theme/images/animated-overlay.gif new file mode 100644 index 000000000..d441f75eb Binary files /dev/null and b/lib/scripts/jquery/jquery-ui-theme/images/animated-overlay.gif differ diff --git a/lib/scripts/jquery/update.sh b/lib/scripts/jquery/update.sh index 3bc2c761e..749b0f4e2 100755 --- a/lib/scripts/jquery/update.sh +++ b/lib/scripts/jquery/update.sh @@ -19,7 +19,7 @@ wget -nv https://ajax.googleapis.com/ajax/libs/jqueryui/1/jquery-ui.js -O jq # load the smoothness theme mkdir -p jquery-ui-theme/images wget -nv -qO- https://ajax.googleapis.com/ajax/libs/jqueryui/1/themes/smoothness/jquery-ui.css | sed "s/font-family:[^;]*;//" > jquery-ui-theme/smoothness.css -images=`gawk 'match($0, /url\((images\/[^\)]+)\)/, m) { print m[1] }' jquery-ui-theme/smoothness.css` +images=`gawk 'match($0, /url\("?(images\/[^\)"]+)"?\)/, m) { print m[1] }' jquery-ui-theme/smoothness.css` for img in $images do wget -nv https://ajax.googleapis.com/ajax/libs/jqueryui/1/themes/smoothness/$img -O jquery-ui-theme/$img -- cgit v1.2.3 From f6af1fe63a13b2734d1b69817ec800c51e6def9c Mon Sep 17 00:00:00 2001 From: lupo49 <dokuwiki@lupo49.de> Date: Sun, 31 Mar 2013 20:40:03 +0200 Subject: de/de-informal: language updates for the core, authldap, authmysql, authpgsql --- lib/plugins/authad/lang/de-informal/settings.php | 11 +++--- lib/plugins/authad/lang/de/settings.php | 19 ++++++++++ lib/plugins/authldap/lang/de-informal/settings.php | 20 +++++++++-- lib/plugins/authldap/lang/de/settings.php | 22 ++++++++++++ lib/plugins/authmysql/auth.php | 18 ++++++++-- .../authmysql/lang/de-informal/settings.php | 40 +++++++++++++++++++-- lib/plugins/authmysql/lang/de/settings.php | 42 ++++++++++++++++++++++ .../authpgsql/lang/de-informal/settings.php | 36 +++++++++++++++++-- lib/plugins/authpgsql/lang/de/settings.php | 38 ++++++++++++++++++++ 9 files changed, 233 insertions(+), 13 deletions(-) create mode 100644 lib/plugins/authad/lang/de/settings.php create mode 100644 lib/plugins/authldap/lang/de/settings.php create mode 100644 lib/plugins/authmysql/lang/de/settings.php create mode 100644 lib/plugins/authpgsql/lang/de/settings.php diff --git a/lib/plugins/authad/lang/de-informal/settings.php b/lib/plugins/authad/lang/de-informal/settings.php index da33a2e98..f6ba679ff 100644 --- a/lib/plugins/authad/lang/de-informal/settings.php +++ b/lib/plugins/authad/lang/de-informal/settings.php @@ -3,11 +3,12 @@ * German (informal) language file * * @author Frank Loizzi <contact@software.bacal.de> + * @author Matthias Schulte <dokuwiki@lupo49.de> */ -$lang['account_suffix'] = 'Ihre Kontoendung. Z.B. <code>@my.domain.org</code>'; -$lang['base_dn'] = 'Ihre base DN. Z.B. <code>DC=my,DC=domain,DC=org</code>'; -$lang['domain_controllers'] = 'Eine kommaseparierte Liste von Domänenkontrollern. Z.B. <code>srv1.domain.org,srv2.domain.org</code>'; -$lang['ad_username'] = 'Ein priviligierter Active Directory Benutzer mit Zugriff zu allen anderen Benutzerdaten. Optional aber benötigt für einige Aktionen wie das Senden von Mitglieder E-Mails.'; +$lang['account_suffix'] = 'Dein Account-Suffix. Z.B. <code>@my.domain.org</code>'; +$lang['base_dn'] = 'Dein Base-DN. Z.B. <code>DC=my,DC=domain,DC=org</code>'; +$lang['domain_controllers'] = 'Eine Komma-separierte Liste von Domänen-Controllern. Z.B. <code>srv1.domain.org,srv2.domain.org</code>'; +$lang['ad_username'] = 'Ein privilegierter Active Directory-Benutzer mit Zugriff zu allen anderen Benutzerdaten. Optional, aber wird benötigt für Aktionen wie z. B. dass Senden von Benachrichtigungs-Mails.'; $lang['ad_password'] = 'Das Passwort des obigen Benutzers.'; $lang['sso'] = 'Soll Single-Sign-On via Kerberos oder NTLM benutzt werden?'; $lang['real_primarygroup'] = 'Soll die echte primäre Gruppe aufgelöst werden anstelle der Annahme "Domain Users" (langsamer)'; @@ -15,4 +16,4 @@ $lang['use_ssl'] = 'SSL-Verbindung benutzen? Falls ja, TLS unterha $lang['use_tls'] = 'TLS-Verbindung benutzen? Falls ja, SSL oberhalb nicht aktivieren.'; $lang['debug'] = 'Zusätzliche Debug-Informationen bei Fehlern anzeigen?'; $lang['expirywarn'] = 'Tage im Voraus um Benutzer über ablaufende Passwörter zu informieren. 0 zum Ausschalten.'; -$lang['additional'] = 'Eine kommaseparierte Liste von zusätzlichen AD Attributen von den Benutzdedaten abrufen. Wird von einigen Plugins benutzt.'; +$lang['additional'] = 'Eine Komma-separierte Liste von zusätzlichen AD-Attributen, die von den Benutzerobjekten abgefragt werden. Wird von einigen Plugins benutzt.'; diff --git a/lib/plugins/authad/lang/de/settings.php b/lib/plugins/authad/lang/de/settings.php new file mode 100644 index 000000000..38bccbf24 --- /dev/null +++ b/lib/plugins/authad/lang/de/settings.php @@ -0,0 +1,19 @@ +<?php +/** + * German (informal) language file + * + * @author Frank Loizzi <contact@software.bacal.de> + * @author Matthias Schulte <dokuwiki@lupo49.de> + */ +$lang['account_suffix'] = 'Ihr Account-Suffix. Z.B. <code>@my.domain.org</code>'; +$lang['base_dn'] = 'Ihre Base-DN. Z.B. <code>DC=my,DC=domain,DC=org</code>'; +$lang['domain_controllers'] = 'Eine Komma-separierte Liste von Domänen-Controllern. Z.B. <code>srv1.domain.org,srv2.domain.org</code>'; +$lang['ad_username'] = 'Ein priviligierter Active Directory-Benutzer mit Zugriff zu allen anderen Benutzerdaten. Optional, aber wird benötigt für Aktionen wie z. B. dass Senden von Benachrichtigungs-Mails.'; +$lang['ad_password'] = 'Das Passwort des obigen Benutzers.'; +$lang['sso'] = 'Soll Single-Sign-On via Kerberos oder NTLM benutzt werden?'; +$lang['real_primarygroup'] = 'Soll die echte primäre Gruppe aufgelöst werden anstelle der Annahme "Domain Users" (langsamer)'; +$lang['use_ssl'] = 'SSL-Verbindung benutzen? Falls ja, TLS unterhalb nicht aktivieren.'; +$lang['use_tls'] = 'TLS-Verbindung benutzen? Falls ja, SSL oberhalb nicht aktivieren.'; +$lang['debug'] = 'Zusätzliche Debug-Informationen bei Fehlern anzeigen?'; +$lang['expirywarn'] = 'Tage im Voraus um Benutzer über ablaufende Passwörter zu informieren. 0 zum Ausschalten.'; +$lang['additional'] = 'Eine Komma-separierte Liste von zusätzlichen AD-Attributen, die von den Benutzerobjekten abgefragt werden. Wird von einigen Plugins benutzt.'; diff --git a/lib/plugins/authldap/lang/de-informal/settings.php b/lib/plugins/authldap/lang/de-informal/settings.php index e7b3d2673..fa0fc1521 100644 --- a/lib/plugins/authldap/lang/de-informal/settings.php +++ b/lib/plugins/authldap/lang/de-informal/settings.php @@ -1,6 +1,22 @@ <?php /** - * German (informal) language file + * German informal language file * - * @author Frank Loizzi <contact@software.bacal.de> + * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) + * @author Matthias Schulte <dokuwiki@lupo49.de> */ +$lang['server'] = 'Adresse zum LDAP-Server. Entweder als Hostname (<code>localhost</code>) oder als FQDN (<code>ldap://server.tld:389</code>).'; +$lang['port'] = 'Port des LDAP-Servers, falls kein Port angegeben wurde.'; +$lang['usertree'] = 'Zweig, in dem die die Benutzeraccounts gespeichert sind. Zum Beispiel: <code>ou=People, dc=server, dc=tld</code>.'; +$lang['grouptree'] = 'Zweig, in dem die Benutzergruppen gespeichert sind. Zum Beispiel: <code>ou=Group, dc=server, dc=tld</code>.'; +$lang['userfilter'] = 'LDAP-Filter, um die Benutzeraccounts zu suchen. Zum Beispiel: <code>(&(uid=%{user})(objectClass=posixAccount))</code>.'; +$lang['groupfilter'] = 'LDAP-Filter, um die Benutzergruppen zu suchen. Zum Beispiel: <code>(&(objectClass=posixGroup)(|(gidNumber=%{gid})(memberUID=%{user})))</code>.'; +$lang['version'] = 'Zu verwendende Protokollversion von LDAP.'; +$lang['starttls'] = 'Verbindung über TLS aufbauen?'; +$lang['referrals'] = 'Weiterverfolgen von LDAP-Referrals (Verweise)?'; +$lang['binddn'] = 'DN eines optionalen Benutzers, wenn der anonyme Zugriff nicht ausreichend ist. Zum Beispiel: <code>cn=admin, dc=my, dc=home</code>.'; +$lang['bindpw'] = 'Passwort des angegebenen Benutzers.'; +$lang['userscope'] = 'Die Suchweite nach Benutzeraccounts.'; +$lang['groupscope'] = 'Die Suchweite nach Benutzergruppen.'; +$lang['groupkey'] = 'Gruppieren der Benutzeraccounts anhand eines beliebigen Benutzerattributes z. B. Telefonnummer oder Abteilung, anstelle der Standard-Gruppen).'; +$lang['debug'] = 'Debug-Informationen beim Auftreten von Fehlern anzeigen?'; diff --git a/lib/plugins/authldap/lang/de/settings.php b/lib/plugins/authldap/lang/de/settings.php new file mode 100644 index 000000000..b237201d8 --- /dev/null +++ b/lib/plugins/authldap/lang/de/settings.php @@ -0,0 +1,22 @@ +<?php +/** + * German language file + * + * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) + * @author Matthias Schulte <dokuwiki@lupo49.de> + */ +$lang['server'] = 'Adresse zum LDAP-Server. Entweder als Hostname (<code>localhost</code>) oder als FQDN (<code>ldap://server.tld:389</code>).'; +$lang['port'] = 'Port des LDAP-Servers, falls kein Port angegeben wurde.'; +$lang['usertree'] = 'Zweig, in dem die die Benutzeraccounts gespeichert sind. Zum Beispiel: <code>ou=People, dc=server, dc=tld</code>.'; +$lang['grouptree'] = 'Zweig, in dem die Benutzergruppen gespeichert sind. Zum Beispiel: <code>ou=Group, dc=server, dc=tld</code>.'; +$lang['userfilter'] = 'LDAP-Filter, um die Benutzeraccounts zu suchen. Zum Beispiel: <code>(&(uid=%{user})(objectClass=posixAccount))</code>.'; +$lang['groupfilter'] = 'LDAP-Filter, um die Benutzergruppen zu suchen. Zum Beispiel: <code>(&(objectClass=posixGroup)(|(gidNumber=%{gid})(memberUID=%{user})))</code>.'; +$lang['version'] = 'Zu verwendende Protokollversion von LDAP.'; +$lang['starttls'] = 'Verbindung über TLS aufbauen?'; +$lang['referrals'] = 'Weiterverfolgen von LDAP-Referrals (Verweise)?'; +$lang['binddn'] = 'DN eines optionalen Benutzers, wenn der anonyme Zugriff nicht ausreichend ist. Zum Beispiel: <code>cn=admin, dc=my, dc=home</code>.'; +$lang['bindpw'] = 'Passwort des angegebenen Benutzers.'; +$lang['userscope'] = 'Die Suchweite nach Benutzeraccounts.'; +$lang['groupscope'] = 'Die Suchweite nach Benutzergruppen.'; +$lang['groupkey'] = 'Gruppieren der Benutzeraccounts anhand eines beliebigen Benutzerattributes z. B. Telefonnummer oder Abteilung, anstelle der Standard-Gruppen).'; +$lang['debug'] = 'Debug-Informationen beim Auftreten von Fehlern anzeigen?'; diff --git a/lib/plugins/authmysql/auth.php b/lib/plugins/authmysql/auth.php index 7d303726b..5f6e86c71 100644 --- a/lib/plugins/authmysql/auth.php +++ b/lib/plugins/authmysql/auth.php @@ -97,6 +97,15 @@ class auth_plugin_authmysql extends DokuWiki_Auth_Plugin { ), false ); $this->cando['getUserCount'] = $this->_chkcnf(array('getUsers'), false); + + if($this->getConf('debug') >= 2) { + $candoDebug = ''; + foreach($this->cando as $cd => $value) { + if($value) { $value = 'yes'; } else { $value = 'no'; } + $candoDebug .= $cd . ": " . $value . " | "; + } + $this->_debug("authmysql cando: " . $candoDebug, 0, __LINE__, __FILE__); + } } /** @@ -816,6 +825,10 @@ class auth_plugin_authmysql extends DokuWiki_Auth_Plugin { * @return int|bool insert id or 0, false on error */ protected function _modifyDB($query) { + if($this->getConf('debug') >= 2) { + msg('MySQL query: '.hsc($query), 0, __LINE__, __FILE__); + } + if($this->dbcon) { $result = @mysql_query($query, $this->dbcon); if($result) { @@ -848,11 +861,12 @@ class auth_plugin_authmysql extends DokuWiki_Auth_Plugin { */ protected function _lockTables($mode) { if($this->dbcon) { - if(is_array($this->getConf('TablesToLock'))) { + $ttl = $this->getConf('TablesToLock'); + if(is_array($ttl) && !empty($ttl)) { if($mode == "READ" || $mode == "WRITE") { $sql = "LOCK TABLES "; $cnt = 0; - foreach($this->getConf('TablesToLock') as $table) { + foreach($ttl as $table) { if($cnt++ != 0) $sql .= ", "; $sql .= "$table $mode"; } diff --git a/lib/plugins/authmysql/lang/de-informal/settings.php b/lib/plugins/authmysql/lang/de-informal/settings.php index e7b3d2673..0c9bc85fe 100644 --- a/lib/plugins/authmysql/lang/de-informal/settings.php +++ b/lib/plugins/authmysql/lang/de-informal/settings.php @@ -1,6 +1,42 @@ <?php /** - * German (informal) language file + * German informal language file * - * @author Frank Loizzi <contact@software.bacal.de> + * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) + * @author Matthias Schulte <dokuwiki@lupo49.de> */ +$lang['server'] = 'MySQL-Server'; +$lang['user'] = 'Benutzername für den Zugriff auf den MySQL-Server.'; +$lang['password'] = 'Passwort des angegebenen Benutzers.'; +$lang['database'] = 'Zu verwendende Datenbank.'; +$lang['charset'] = 'Verwendetes Character-Set in der Datenbank.'; +$lang['debug'] = 'Debug-Informationen anzeigen?'; +$lang['forwardClearPass'] = 'Passwort der DokuWiki-Benutzer im Klartext an die Datenbank übergeben? (Im Normalfall wird die passcrypt-Option angewendet.)'; +$lang['TablesToLock'] = 'Eine Komma-separierte Liste von Tabellen, die vor Schreiboperationen gesperrt werden müssen.'; +$lang['checkPass'] = 'SQL-Kommando zum Überprüfen von Passwörtern.'; +$lang['getUserInfo'] = 'SQL-Kommando um Benutzerinformationen auszulesen.'; +$lang['getGroups'] = 'SQL-Kommando um Gruppen eines Benutzers auszulesen.'; +$lang['getUsers'] = 'SQL-Kommando um alle Benutzer auszulesen.'; +$lang['FilterLogin'] = 'SQL-Bedingung um Benutzer anhand ihres Anmeldenamens zu filtern.'; +$lang['FilterName'] = 'SQL-Bedingung um Benutzer anhand ihres Namens zu filtern.'; +$lang['FilterEmail'] = 'SQL-Bedingung um Benutzer anhand ihrer E-Mail-Adresse zu filtern.'; +$lang['FilterGroup'] = 'SQL-Bedingung um Benutzer anhand ihrer Gruppenzugehörigkeit zu filtern.'; +$lang['SortOrder'] = 'SQL-Bedingung um anhand der die Benutzerliste sortiert wird.'; +$lang['addUser'] = 'SQL-Kommando um einen neuen Benutzer anzulegen.'; +$lang['addGroup'] = 'SQL-Kommando um eine neue Gruppe anzulegen.'; +$lang['addUserGroup'] = 'SQL-Kommando um einen Benutzer zu einer Gruppe hinzuzufügen.'; +$lang['delGroup'] = 'SQL-Kommando um eine Gruppe zu löschen.'; +$lang['getUserID'] = 'SQL-Kommando um den Primärschlüssel des Benutzers auszulesen.'; +$lang['delUser'] = 'SQL-Kommando um einen Benutzer zu löschen.'; +$lang['delUserRefs'] = 'SQL-Kommando um einen Benutzer aus allen Gruppen zu entfernen.'; +$lang['updateUser'] = 'SQL-Kommando um das Profil eines Benutzers zu aktualisieren.'; +$lang['UpdateLogin'] = 'SQL-Bedingung um den Anmeldenamen eines Benutzers zu ändern.'; +$lang['UpdatePass'] = 'SQL-Bedingung um das Passwort eines Benutzers zu ändern.'; +$lang['UpdateEmail'] = 'SQL-Bedingung um die E-Mail-Adresse eines Benutzers zu ändern.'; +$lang['UpdateName'] = 'SQL-Bedingung um den Namen eines Benutzers zu ändern.'; +$lang['UpdateTarget'] = 'SQL-Bedingung zur eindeutigen Identifikation des Benutzers.'; +$lang['delUserGroup'] = 'SQL-Kommando um einen Benutzer aus einer angegeben Gruppe zu entfernen.'; +$lang['getGroupID'] = 'SQL-Kommando um den Primärschlüssel einer Gruppe auszulesen.'; +$lang['debug_o_0'] = 'Keine.'; +$lang['debug_o_1'] = 'Nur Fehler.'; +$lang['debug_o_2'] = 'Alle SQL-Abfragen.'; diff --git a/lib/plugins/authmysql/lang/de/settings.php b/lib/plugins/authmysql/lang/de/settings.php new file mode 100644 index 000000000..97ba06a9d --- /dev/null +++ b/lib/plugins/authmysql/lang/de/settings.php @@ -0,0 +1,42 @@ +<?php +/** + * German language file + * + * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) + * @author Matthias Schulte <dokuwiki@lupo49.de> + */ +$lang['server'] = 'MySQL-Server'; +$lang['user'] = 'Benutzername für den Zugriff auf den MySQL-Server.'; +$lang['password'] = 'Passwort des angegebenen Benutzers.'; +$lang['database'] = 'Zu verwendende Datenbank.'; +$lang['charset'] = 'Verwendetes Character-Set in der Datenbank.'; +$lang['debug'] = 'Debug-Informationen anzeigen?'; +$lang['forwardClearPass'] = 'Passwort der DokuWiki-Benutzer im Klartext an die Datenbank übergeben? (Im Normalfall wird die passcrypt-Option angewendet.)'; +$lang['TablesToLock'] = 'Eine Komma-separierte Liste von Tabellen, die vor Schreiboperationen gesperrt werden müssen.'; +$lang['checkPass'] = 'SQL-Kommando zum Überprüfen von Passwörtern.'; +$lang['getUserInfo'] = 'SQL-Kommando um Benutzerinformationen auszulesen.'; +$lang['getGroups'] = 'SQL-Kommando um Gruppen eines Benutzers auszulesen.'; +$lang['getUsers'] = 'SQL-Kommando um alle Benutzer auszulesen.'; +$lang['FilterLogin'] = 'SQL-Bedingung um Benutzer anhand ihres Anmeldenamens zu filtern.'; +$lang['FilterName'] = 'SQL-Bedingung um Benutzer anhand ihres Namens zu filtern.'; +$lang['FilterEmail'] = 'SQL-Bedingung um Benutzer anhand ihrer E-Mail-Adresse zu filtern.'; +$lang['FilterGroup'] = 'SQL-Bedingung um Benutzer anhand ihrer Gruppenzugehörigkeit zu filtern.'; +$lang['SortOrder'] = 'SQL-Bedingung um anhand der die Benutzerliste sortiert wird.'; +$lang['addUser'] = 'SQL-Kommando um einen neuen Benutzer anzulegen.'; +$lang['addGroup'] = 'SQL-Kommando um eine neue Gruppe anzulegen.'; +$lang['addUserGroup'] = 'SQL-Kommando um einen Benutzer zu einer Gruppe hinzuzufügen.'; +$lang['delGroup'] = 'SQL-Kommando um eine Gruppe zu löschen.'; +$lang['getUserID'] = 'SQL-Kommando um den Primärschlüssel des Benutzers auszulesen.'; +$lang['delUser'] = 'SQL-Kommando um einen Benutzer zu löschen.'; +$lang['delUserRefs'] = 'SQL-Kommando um einen Benutzer aus allen Gruppen zu entfernen.'; +$lang['updateUser'] = 'SQL-Kommando um das Profil eines Benutzers zu aktualisieren.'; +$lang['UpdateLogin'] = 'SQL-Bedingung um den Anmeldenamen eines Benutzers zu ändern.'; +$lang['UpdatePass'] = 'SQL-Bedingung um das Passwort eines Benutzers zu ändern.'; +$lang['UpdateEmail'] = 'SQL-Bedingung um die E-Mail-Adresse eines Benutzers zu ändern.'; +$lang['UpdateName'] = 'SQL-Bedingung um den Namen eines Benutzers zu ändern.'; +$lang['UpdateTarget'] = 'SQL-Bedingung zur eindeutigen Identifikation des Benutzers.'; +$lang['delUserGroup'] = 'SQL-Kommando um einen Benutzer aus einer angegeben Gruppe zu entfernen.'; +$lang['getGroupID'] = 'SQL-Kommando um den Primärschlüssel einer Gruppe auszulesen.'; +$lang['debug_o_0'] = 'Keine.'; +$lang['debug_o_1'] = 'Nur Fehler.'; +$lang['debug_o_2'] = 'Alle SQL-Abfragen.'; diff --git a/lib/plugins/authpgsql/lang/de-informal/settings.php b/lib/plugins/authpgsql/lang/de-informal/settings.php index e7b3d2673..4c80245d6 100644 --- a/lib/plugins/authpgsql/lang/de-informal/settings.php +++ b/lib/plugins/authpgsql/lang/de-informal/settings.php @@ -1,6 +1,38 @@ <?php /** - * German (informal) language file + * German language file * - * @author Frank Loizzi <contact@software.bacal.de> + * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) + * @author Matthias Schulte <dokuwiki@lupo49.de> */ +$lang['server'] = 'PostgreSQL-Server'; +$lang['port'] = 'Port des PostgreSQL-Servers.'; +$lang['user'] = 'Benutzername für den Zugriff auf den PostgreSQL-Server.'; +$lang['password'] = 'Passwort des angegebenen Benutzers.'; +$lang['database'] = 'Zu verwendende Datenbank.'; +$lang['debug'] = 'Debug-Informationen anzeigen?'; +$lang['forwardClearPass'] = 'Passwort der DokuWiki-Benutzer im Klartext an die Datenbank übergeben? (Im Normalfall wird die passcrypt-Option angewendet.)'; +$lang['checkPass'] = 'SQL-Kommando zum Überprüfen von Passwörtern.'; +$lang['getUserInfo'] = 'SQL-Kommando um Benutzerinformationen auszulesen.'; +$lang['getGroups'] = 'SQL-Kommando um Gruppen eines Benutzers auszulesen.'; +$lang['getUsers'] = 'SQL-Kommando um alle Benutzer auszulesen.'; +$lang['FilterLogin'] = 'SQL-Bedingung um Benutzer anhand ihres Anmeldenamens zu filtern.'; +$lang['FilterName'] = 'SQL-Bedingung um Benutzer anhand ihres Namens zu filtern.'; +$lang['FilterEmail'] = 'SQL-Bedingung um Benutzer anhand ihrer E-Mail-Adresse zu filtern.'; +$lang['FilterGroup'] = 'SQL-Bedingung um Benutzer anhand ihrer Gruppenzugehörigkeit zu filtern.'; +$lang['SortOrder'] = 'SQL-Bedingung um anhand der die Benutzerliste sortiert wird.'; +$lang['addUser'] = 'SQL-Kommando um einen neuen Benutzer anzulegen.'; +$lang['addGroup'] = 'SQL-Kommando um eine neue Gruppe anzulegen.'; +$lang['addUserGroup'] = 'SQL-Kommando um einen Benutzer zu einer Gruppe hinzuzufügen.'; +$lang['delGroup'] = 'SQL-Kommando um eine Gruppe zu löschen.'; +$lang['getUserID'] = 'SQL-Kommando um den Primärschlüssel des Benutzers auszulesen.'; +$lang['delUser'] = 'SQL-Kommando um einen Benutzer zu löschen.'; +$lang['delUserRefs'] = 'SQL-Kommando um einen Benutzer aus allen Gruppen zu entfernen.'; +$lang['updateUser'] = 'SQL-Kommando um das Profil eines Benutzers zu aktualisieren.'; +$lang['UpdateLogin'] = 'SQL-Bedingung um den Anmeldenamen eines Benutzers zu ändern.'; +$lang['UpdatePass'] = 'SQL-Bedingung um das Passwort eines Benutzers zu ändern.'; +$lang['UpdateEmail'] = 'SQL-Bedingung um die E-Mail-Adresse eines Benutzers zu ändern.'; +$lang['UpdateName'] = 'SQL-Bedingung um den Namen eines Benutzers zu ändern.'; +$lang['UpdateTarget'] = 'SQL-Bedingung zur eindeutigen Identifikation des Benutzers.'; +$lang['delUserGroup'] = 'SQL-Kommando um einen Benutzer aus einer angegeben Gruppe zu entfernen.'; +$lang['getGroupID'] = 'SQL-Kommando um den Primärschlüssel einer Gruppe auszulesen.'; diff --git a/lib/plugins/authpgsql/lang/de/settings.php b/lib/plugins/authpgsql/lang/de/settings.php new file mode 100644 index 000000000..4c80245d6 --- /dev/null +++ b/lib/plugins/authpgsql/lang/de/settings.php @@ -0,0 +1,38 @@ +<?php +/** + * German language file + * + * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) + * @author Matthias Schulte <dokuwiki@lupo49.de> + */ +$lang['server'] = 'PostgreSQL-Server'; +$lang['port'] = 'Port des PostgreSQL-Servers.'; +$lang['user'] = 'Benutzername für den Zugriff auf den PostgreSQL-Server.'; +$lang['password'] = 'Passwort des angegebenen Benutzers.'; +$lang['database'] = 'Zu verwendende Datenbank.'; +$lang['debug'] = 'Debug-Informationen anzeigen?'; +$lang['forwardClearPass'] = 'Passwort der DokuWiki-Benutzer im Klartext an die Datenbank übergeben? (Im Normalfall wird die passcrypt-Option angewendet.)'; +$lang['checkPass'] = 'SQL-Kommando zum Überprüfen von Passwörtern.'; +$lang['getUserInfo'] = 'SQL-Kommando um Benutzerinformationen auszulesen.'; +$lang['getGroups'] = 'SQL-Kommando um Gruppen eines Benutzers auszulesen.'; +$lang['getUsers'] = 'SQL-Kommando um alle Benutzer auszulesen.'; +$lang['FilterLogin'] = 'SQL-Bedingung um Benutzer anhand ihres Anmeldenamens zu filtern.'; +$lang['FilterName'] = 'SQL-Bedingung um Benutzer anhand ihres Namens zu filtern.'; +$lang['FilterEmail'] = 'SQL-Bedingung um Benutzer anhand ihrer E-Mail-Adresse zu filtern.'; +$lang['FilterGroup'] = 'SQL-Bedingung um Benutzer anhand ihrer Gruppenzugehörigkeit zu filtern.'; +$lang['SortOrder'] = 'SQL-Bedingung um anhand der die Benutzerliste sortiert wird.'; +$lang['addUser'] = 'SQL-Kommando um einen neuen Benutzer anzulegen.'; +$lang['addGroup'] = 'SQL-Kommando um eine neue Gruppe anzulegen.'; +$lang['addUserGroup'] = 'SQL-Kommando um einen Benutzer zu einer Gruppe hinzuzufügen.'; +$lang['delGroup'] = 'SQL-Kommando um eine Gruppe zu löschen.'; +$lang['getUserID'] = 'SQL-Kommando um den Primärschlüssel des Benutzers auszulesen.'; +$lang['delUser'] = 'SQL-Kommando um einen Benutzer zu löschen.'; +$lang['delUserRefs'] = 'SQL-Kommando um einen Benutzer aus allen Gruppen zu entfernen.'; +$lang['updateUser'] = 'SQL-Kommando um das Profil eines Benutzers zu aktualisieren.'; +$lang['UpdateLogin'] = 'SQL-Bedingung um den Anmeldenamen eines Benutzers zu ändern.'; +$lang['UpdatePass'] = 'SQL-Bedingung um das Passwort eines Benutzers zu ändern.'; +$lang['UpdateEmail'] = 'SQL-Bedingung um die E-Mail-Adresse eines Benutzers zu ändern.'; +$lang['UpdateName'] = 'SQL-Bedingung um den Namen eines Benutzers zu ändern.'; +$lang['UpdateTarget'] = 'SQL-Bedingung zur eindeutigen Identifikation des Benutzers.'; +$lang['delUserGroup'] = 'SQL-Kommando um einen Benutzer aus einer angegeben Gruppe zu entfernen.'; +$lang['getGroupID'] = 'SQL-Kommando um den Primärschlüssel einer Gruppe auszulesen.'; -- cgit v1.2.3 From 83fd0ad628216c2bea2997cd6c5c1b703ac08ac3 Mon Sep 17 00:00:00 2001 From: lupo49 <dokuwiki@lupo49.de> Date: Sun, 31 Mar 2013 20:41:30 +0200 Subject: de/de-informal: config plugin - Clean up the TOC in the configuration page / No need to add "Konfiguration" or "Plugin" to every element if the heading tells you that. --- lib/plugins/config/lang/de-informal/lang.php | 44 ++++++++++++++-------------- lib/plugins/config/lang/de/lang.php | 42 +++++++++++++------------- 2 files changed, 42 insertions(+), 44 deletions(-) diff --git a/lib/plugins/config/lang/de-informal/lang.php b/lib/plugins/config/lang/de-informal/lang.php index 58a78fe47..72823c0de 100644 --- a/lib/plugins/config/lang/de-informal/lang.php +++ b/lib/plugins/config/lang/de-informal/lang.php @@ -10,31 +10,31 @@ * @author Pierre Corell <info@joomla-praxis.de> * @author Frank Loizzi <contact@software.bacal.de> */ -$lang['menu'] = 'Einstellungen'; -$lang['error'] = 'Einstellungen wurden nicht aktualisiert auf Grund eines ungültigen Wertes. Bitte überprüfe deine Änderungen und versuche es erneut.<br />Die/der ungültige(n) Wert(e) werden durch eine rote Umrandung hervorgehoben.'; -$lang['updated'] = 'Einstellungen erfolgreich aktualisiert.'; +$lang['menu'] = 'Konfiguration'; +$lang['error'] = 'Konfiguration wurde nicht aktualisiert auf Grund eines ungültigen Wertes. Bitte überprüfe deine Änderungen und versuche es erneut.<br />Die/der ungültige(n) Wert(e) werden durch eine rote Umrandung hervorgehoben.'; +$lang['updated'] = 'Konfiguration erfolgreich aktualisiert.'; $lang['nochoice'] = '(keine andere Option möglich)'; -$lang['locked'] = 'Die Einstellungsdatei kann nicht aktualisiert werden. Wenn dies unbeabsichtigt ist stelle sicher, dass der Name und die Zugriffsrechte der Einstellungsdatei richtig sind.'; +$lang['locked'] = 'Die Konfigurationsdatei kann nicht aktualisiert werden. Wenn dies unbeabsichtigt ist stelle sicher, dass der Name und die Zugriffsrechte der Konfigurationsdatei richtig sind.'; $lang['danger'] = '**Achtung**: Eine Änderung dieser Einstellung kann dein Wiki und das Einstellungsmenü unerreichbar machen.'; $lang['warning'] = 'Achtung: Eine Änderungen dieser Option kann zu unbeabsichtigtem Verhalten führen.'; $lang['security'] = 'Sicherheitswarnung: Eine Änderungen dieser Option können ein Sicherheitsrisiko bedeuten.'; -$lang['_configuration_manager'] = 'Einstellungen'; -$lang['_header_dokuwiki'] = 'DokuWiki-Einstellungen'; -$lang['_header_plugin'] = 'Plugin-Einstellungen'; -$lang['_header_template'] = 'Vorlageneinstellungen'; -$lang['_header_undefined'] = 'unbestimmte Einstellungen'; -$lang['_basic'] = 'Grundeinstellungen'; -$lang['_display'] = 'Darstellungs-Einstellungen'; -$lang['_authentication'] = 'Bestätigungseinstellungen'; -$lang['_anti_spam'] = 'Anti-Spam-Einstellungen'; -$lang['_editing'] = 'Bearbeitungseinstellungen'; -$lang['_links'] = 'Link-Einstellungen'; -$lang['_media'] = 'Media-Einstellungen'; -$lang['_notifications'] = 'Benachrichtigungs-Konfiguration'; -$lang['_syndication'] = 'Syndication-Konfiguration (RSS)'; -$lang['_advanced'] = 'erweiterte Einstellungen'; -$lang['_network'] = 'Netzwerk-Einstellungen'; -$lang['_plugin_sufix'] = 'Plugin-Einstellungen'; +$lang['_configuration_manager'] = 'Konfiguration'; +$lang['_header_dokuwiki'] = 'DokuWiki-Konfiguration'; +$lang['_header_plugin'] = 'Plugin-Konfiguration'; +$lang['_header_template'] = 'Vorlagen'; +$lang['_header_undefined'] = 'Unbekannte Werte'; +$lang['_basic'] = 'Grundkonfiguration'; +$lang['_display'] = 'Darstellung'; +$lang['_authentication'] = 'Authentifizierung'; +$lang['_anti_spam'] = 'Anti-Spam'; +$lang['_editing'] = 'Bearbeitung'; +$lang['_links'] = 'Links'; +$lang['_media'] = 'Medien'; +$lang['_notifications'] = 'Benachrichtigungen'; +$lang['_syndication'] = 'Syndication (RSS)'; +$lang['_advanced'] = 'Erweiterte Konfiguration'; +$lang['_network'] = 'Netzwerk'; +$lang['_plugin_sufix'] = ''; $lang['_template_sufix'] = 'Vorlageneinstellungen'; $lang['_msg_setting_undefined'] = 'Keine Konfigurationsmetadaten.'; $lang['_msg_setting_no_class'] = 'Keine Konfigurationsklasse.'; @@ -190,7 +190,7 @@ $lang['xsendfile_o_2'] = 'Standard X-Sendfile-Header'; $lang['xsendfile_o_3'] = 'Proprietärer Nginx X-Accel-Redirect-Header'; $lang['showuseras_o_loginname'] = 'Login-Name'; $lang['showuseras_o_username'] = 'Voller Name des Nutzers'; -$lang['showuseras_o_email'] = 'E-Mail-Adresse des Benutzers (je nach Mailguard-Einstellung verschleiert)'; +$lang['showuseras_o_email'] = 'E-Mail-Adresse des Benutzers (Beachte "mailguard"-Einstellung)'; $lang['showuseras_o_email_link'] = 'E-Mail-Adresse des Benutzers als mailto:-Link'; $lang['useheading_o_0'] = 'Niemals'; $lang['useheading_o_navigation'] = 'Nur Navigation'; diff --git a/lib/plugins/config/lang/de/lang.php b/lib/plugins/config/lang/de/lang.php index bcbc061a3..063ee40ad 100644 --- a/lib/plugins/config/lang/de/lang.php +++ b/lib/plugins/config/lang/de/lang.php @@ -19,38 +19,36 @@ * @author Matthias Schulte <dokuwiki@lupo49.de> */ $lang['menu'] = 'Konfiguration'; -$lang['error'] = 'Die Einstellungen wurden wegen einer fehlerhaften Eingabe nicht gespeichert. -<br />Bitte überprüfen sie die rot umrandeten Eingaben und speichern Sie erneut.'; +$lang['error'] = 'Die Einstellungen wurden wegen einer fehlerhaften Eingabe nicht gespeichert.<br /> Bitte überprüfen sie die rot umrandeten Eingaben und speichern Sie erneut.'; $lang['updated'] = 'Einstellungen erfolgreich gespeichert.'; $lang['nochoice'] = '(keine Auswahlmöglichkeiten vorhanden)'; -$lang['locked'] = 'Die Konfigurationsdatei kann nicht geändert werden, wenn dies unbeabsichtigt ist - <br />überprüfen Sie, dass die Dateiberechtigungen korrekt gesetzt sind.'; +$lang['locked'] = 'Die Konfigurationsdatei kann nicht geändert werden. Wenn dies unbeabsichtigt ist, <br />überprüfen Sie, ob die Dateiberechtigungen korrekt gesetzt sind.'; $lang['danger'] = 'Vorsicht: Die Änderung dieser Option könnte Ihr Wiki und das Konfigurationsmenü unzugänglich machen.'; $lang['warning'] = 'Hinweis: Die Änderung dieser Option könnte unbeabsichtigtes Verhalten hervorrufen.'; $lang['security'] = 'Sicherheitswarnung: Die Änderung dieser Option könnte ein Sicherheitsrisiko darstellen.'; $lang['_configuration_manager'] = 'Konfiguration'; $lang['_header_dokuwiki'] = 'DokuWiki-Konfiguration'; $lang['_header_plugin'] = 'Plugin-Konfiguration'; -$lang['_header_template'] = 'Template-Konfiguration'; -$lang['_header_undefined'] = 'Unbekannte Einstellungen'; -$lang['_basic'] = 'Grund-Konfiguration'; -$lang['_display'] = 'Anzeige-Konfiguration'; -$lang['_authentication'] = 'Authentifizierungs-Konfiguration'; -$lang['_anti_spam'] = 'Anti-Spam-Konfiguration'; -$lang['_editing'] = 'Bearbeitungs-Konfiguration'; -$lang['_links'] = 'Link-Konfiguration'; -$lang['_media'] = 'Medien-Konfiguration'; -$lang['_notifications'] = 'Benachrichtigungs-Konfiguration'; -$lang['_syndication'] = 'Syndication-Konfiguration (RSS)'; +$lang['_header_template'] = 'Vorlagen'; +$lang['_header_undefined'] = 'Unbekannte Werte'; +$lang['_basic'] = 'Grundkonfiguration'; +$lang['_display'] = 'Darstellung'; +$lang['_authentication'] = 'Authentifizierung'; +$lang['_anti_spam'] = 'Anti-Spam'; +$lang['_editing'] = 'Bearbeitung'; +$lang['_links'] = 'Links'; +$lang['_media'] = 'Medien'; +$lang['_notifications'] = 'Benachrichtigungen'; +$lang['_syndication'] = 'Syndication (RSS)'; $lang['_advanced'] = 'Erweiterte Konfiguration'; -$lang['_network'] = 'Netzwerk-Konfiguration'; -$lang['_plugin_sufix'] = 'Plugin-Konfiguration'; -$lang['_template_sufix'] = 'Template-Konfiguration'; +$lang['_network'] = 'Netzwerk'; +$lang['_plugin_sufix'] = ''; +$lang['_template_sufix'] = 'Vorlagen-Konfiguration'; $lang['_msg_setting_undefined'] = 'Keine Konfigurationsmetadaten.'; $lang['_msg_setting_no_class'] = 'Keine Konfigurationsklasse.'; $lang['_msg_setting_no_default'] = 'Kein Standardwert.'; -$lang['fmode'] = 'Rechte für neue Dateien'; -$lang['dmode'] = 'Rechte für neue Verzeichnisse'; +$lang['fmode'] = 'Berechtigungen für neue Dateien'; +$lang['dmode'] = 'Berechtigungen für neue Verzeichnisse'; $lang['lang'] = 'Sprache'; $lang['basedir'] = 'Installationsverzeichnis'; $lang['baseurl'] = 'Installationspfad (URL)'; @@ -198,9 +196,9 @@ $lang['xsendfile_o_0'] = 'nicht benutzen'; $lang['xsendfile_o_1'] = 'Proprietärer lighttpd-Header (vor Release 1.5)'; $lang['xsendfile_o_2'] = 'Standard X-Sendfile-Header'; $lang['xsendfile_o_3'] = 'Proprietärer Nginx X-Accel-Redirect-Header'; -$lang['showuseras_o_loginname'] = 'Loginname'; +$lang['showuseras_o_loginname'] = 'Login-Name'; $lang['showuseras_o_username'] = 'Vollständiger Name des Benutzers'; -$lang['showuseras_o_email'] = 'E-Mail-Adresse des Benutzers (je nach Mailguard-Einstellung verschleiert)'; +$lang['showuseras_o_email'] = 'E-Mail-Adresse des Benutzers (Beachte "mailguard"-Einstellung)'; $lang['showuseras_o_email_link'] = 'E-Mail-Adresse des Benutzers als mailto:-Link'; $lang['useheading_o_0'] = 'Nie'; $lang['useheading_o_navigation'] = 'Nur Navigation'; -- cgit v1.2.3 From ab38a3220676a13042d13f3784fc517c5f6f66e4 Mon Sep 17 00:00:00 2001 From: lupo49 <dokuwiki@lupo49.de> Date: Sun, 31 Mar 2013 20:44:06 +0200 Subject: install.php: Added pack() to required DokuWiki PHP functions (FS#2761) --- install.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install.php b/install.php index 330a47d52..33f3406a3 100644 --- a/install.php +++ b/install.php @@ -529,7 +529,7 @@ function check_functions(){ 'ob_start opendir parse_ini_file readfile realpath '. 'rename rmdir serialize session_start unlink usleep '. 'preg_replace file_get_contents htmlspecialchars_decode '. - 'spl_autoload_register stream_select fsockopen'); + 'spl_autoload_register stream_select fsockopen pack'); if (!function_exists('mb_substr')) { $funcs[] = 'utf8_encode'; -- cgit v1.2.3 From d3bae4781025502fdfb729854e39f8b2072b8a37 Mon Sep 17 00:00:00 2001 From: Christopher Smith <chris@jalakai.co.uk> Date: Mon, 1 Apr 2013 16:55:40 +0100 Subject: add capability to restrict recipients of dokuwiki 'msg' alerts. This is useful where message is added to the queue before authentication is initialized --- inc/html.php | 8 +++++--- inc/infoutils.php | 37 +++++++++++++++++++++++++++++++++++-- 2 files changed, 40 insertions(+), 5 deletions(-) diff --git a/inc/html.php b/inc/html.php index 59415f7da..09d1387bd 100644 --- a/inc/html.php +++ b/inc/html.php @@ -1297,9 +1297,11 @@ function html_msgarea(){ foreach($MSG as $msg){ $hash = md5($msg['msg']); if(isset($shown[$hash])) continue; // skip double messages - print '<div class="'.$msg['lvl'].'">'; - print $msg['msg']; - print '</div>'; + if(info_msg_canshow($msg)){ + print '<div class="'.$msg['lvl'].'">'; + print $msg['msg']; + print '</div>'; + } $shown[$hash] = 1; } diff --git a/inc/infoutils.php b/inc/infoutils.php index 92607e4fa..3d1326624 100644 --- a/inc/infoutils.php +++ b/inc/infoutils.php @@ -269,7 +269,13 @@ function check(){ * @author Andreas Gohr <andi@splitbrain.org> * @see html_msgarea */ -function msg($message,$lvl=0,$line='',$file=''){ + +define('MSG_PUBLIC', 0); +define('MSG_USERS_ONLY', 1); +define('MSG_MANAGERS_ONLY',2); +define('MSG_ADMINS_ONLY',4); + +function msg($message,$lvl=0,$line='',$file='',$show=MSG_PUBLIC){ global $MSG, $MSG_shown; $errors[-1] = 'error'; $errors[0] = 'info'; @@ -279,7 +285,7 @@ function msg($message,$lvl=0,$line='',$file=''){ if($line || $file) $message.=' ['.utf8_basename($file).':'.$line.']'; if(!isset($MSG)) $MSG = array(); - $MSG[]=array('lvl' => $errors[$lvl], 'msg' => $message); + $MSG[]=array('lvl' => $errors[$lvl], 'msg' => $message, 'show' => $show); if(isset($MSG_shown) || headers_sent()){ if(function_exists('html_msgarea')){ html_msgarea(); @@ -290,6 +296,33 @@ function msg($message,$lvl=0,$line='',$file=''){ } } +function info_msg_canshow($msg){ + global $INFO, $auth; + + // is the message public? - everyone and anyone can see it + if (empty($msg['show'])) return true; + + // restricted msg, but no authentication + if (empty($auth)) return false; + + switch ($msg['show']){ + case MSG_USERS_ONLY: + return !empty($INFO['userinfo']); + + case MSG_MANAGERS_ONLY: + return $INFO['ismanager']; + + case MSG_ADMINS_ONLY: + return $INFO['isadmin']; + + default: + trigger_error('invalid msg show restriction. msg="'.$msg['msg'].'" show='.$msg['show'].'"', E_USER_WARNING); + return $INFO['isadmin']; + } + + return false; +} + /** * print debug messages * -- cgit v1.2.3 From 0b2e0a720d550ed8e96ffcdc62cbbffe78d27c21 Mon Sep 17 00:00:00 2001 From: Christopher Smith <chris@jalakai.co.uk> Date: Mon, 1 Apr 2013 17:03:25 +0100 Subject: restrict 'authtype deprecated' alert to superusers only --- inc/auth.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inc/auth.php b/inc/auth.php index 0713ca6af..9f180fc94 100644 --- a/inc/auth.php +++ b/inc/auth.php @@ -55,7 +55,7 @@ function auth_setup() { // matches old auth backends (pre-Weatherwax) $auth = $plugin_controller->load('auth', $plugin); msg('Your authtype setting is deprecated. You must set $conf[\'authconfig\'] = ' . "auth" . $conf['authtype'] - . ' in your config (see <a href="https://www.dokuwiki.org/auth">Authentication Backends</a>)',-1); + . ' in your config (see <a href="https://www.dokuwiki.org/auth">Authentication Backends</a>)',-1,'','',MSG_ADMINS_ONLY); } } -- cgit v1.2.3 From 64cafb1fc08f57bf3d9960139f3fa30034432be9 Mon Sep 17 00:00:00 2001 From: Christopher Smith <chris@jalakai.co.uk> Date: Mon, 1 Apr 2013 20:47:21 +0100 Subject: for completeness (& defensive coding), test ['show'] against MSG_PUBLIC in case its redefined to a non-zero value --- inc/infoutils.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inc/infoutils.php b/inc/infoutils.php index 3d1326624..da230da37 100644 --- a/inc/infoutils.php +++ b/inc/infoutils.php @@ -300,7 +300,7 @@ function info_msg_canshow($msg){ global $INFO, $auth; // is the message public? - everyone and anyone can see it - if (empty($msg['show'])) return true; + if (empty($msg['show']) || ($msg['show'] == MSG_PUBLIC)) return true; // restricted msg, but no authentication if (empty($auth)) return false; -- cgit v1.2.3 From 3b5b1d9d6524d89f50b1825e8067cc28133358f8 Mon Sep 17 00:00:00 2001 From: Anika Henke <anika@selfthinker.org> Date: Wed, 3 Apr 2013 00:15:45 +0100 Subject: fixed info/error messages in RTL languages --- lib/styles/screen.css | 9 +++++++++ lib/tpl/dokuwiki/css/print.css | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/lib/styles/screen.css b/lib/styles/screen.css index 241904d7c..2d84f65eb 100644 --- a/lib/styles/screen.css +++ b/lib/styles/screen.css @@ -20,6 +20,15 @@ div.notify { border-radius: 5px; } +[dir=rtl] div.error, +[dir=rtl] div.info, +[dir=rtl] div.success, +[dir=rtl] div.notify { + background-position: 99% 50%; + padding-left: .4em; + padding-right: 32px; +} + div.error { background-color: #fcc; background-image: url(../images/error.png); diff --git a/lib/tpl/dokuwiki/css/print.css b/lib/tpl/dokuwiki/css/print.css index e0eaab848..86e686b69 100644 --- a/lib/tpl/dokuwiki/css/print.css +++ b/lib/tpl/dokuwiki/css/print.css @@ -106,7 +106,7 @@ blockquote { border: solid #ccc; border-width: 0 0 0 2pt; } -[dir=rtl] .dokuwiki blockquote { +[dir=rtl] blockquote { border-width: 0 2pt 0 0; } -- cgit v1.2.3 From 8ee0487708ea528ade7e43e3688cfd14cf6a7582 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EB=AA=85=EC=A7=84?= <aranet100@gmail.com> Date: Thu, 4 Apr 2013 20:43:19 +0200 Subject: Korean language update --- inc/lang/ko/adminplugins.txt | 2 +- inc/lang/ko/backlinks.txt | 2 +- inc/lang/ko/edit.txt | 2 +- inc/lang/ko/index.txt | 2 +- inc/lang/ko/install.html | 4 ++-- inc/lang/ko/lang.php | 36 ++++++++++++++--------------- inc/lang/ko/newpage.txt | 2 +- inc/lang/ko/recent.txt | 2 +- inc/lang/ko/registermail.txt | 2 +- lib/plugins/authad/lang/ko/settings.php | 8 +++++-- lib/plugins/authldap/lang/ko/settings.php | 11 +++++++++ lib/plugins/config/lang/ko/intro.txt | 2 +- lib/plugins/config/lang/ko/lang.php | 20 ++++++++-------- lib/plugins/plugin/lang/ko/admin_plugin.txt | 4 +--- lib/plugins/plugin/lang/ko/lang.php | 8 +++---- lib/plugins/popularity/lang/ko/lang.php | 4 ++-- lib/plugins/revert/lang/ko/intro.txt | 2 +- lib/plugins/usermanager/lang/ko/add.txt | 2 +- lib/plugins/usermanager/lang/ko/delete.txt | 2 +- lib/plugins/usermanager/lang/ko/edit.txt | 2 +- lib/plugins/usermanager/lang/ko/intro.txt | 2 +- lib/plugins/usermanager/lang/ko/list.txt | 2 +- 22 files changed, 68 insertions(+), 55 deletions(-) diff --git a/inc/lang/ko/adminplugins.txt b/inc/lang/ko/adminplugins.txt index 5312cf357..2c436d6f8 100644 --- a/inc/lang/ko/adminplugins.txt +++ b/inc/lang/ko/adminplugins.txt @@ -1 +1 @@ -===== 부가적인 플러그인 ===== \ No newline at end of file +===== 추가적인 플러그인 ===== \ No newline at end of file diff --git a/inc/lang/ko/backlinks.txt b/inc/lang/ko/backlinks.txt index 85fdfa3da..6a6ad48a4 100644 --- a/inc/lang/ko/backlinks.txt +++ b/inc/lang/ko/backlinks.txt @@ -1,3 +1,3 @@ ====== 백링크 ====== -현재 문서를 가리키는 링크가 있는 문서 목록입니다. +현재 문서를 가리키는 링크가 있는 문서 목록입니다. \ No newline at end of file diff --git a/inc/lang/ko/edit.txt b/inc/lang/ko/edit.txt index f52326a33..97927b7fe 100644 --- a/inc/lang/ko/edit.txt +++ b/inc/lang/ko/edit.txt @@ -1 +1 @@ -문서를 편집하고 **저장**을 누르세요. 위키 구문은 [[wiki:syntax]] 또는 [[wiki:ko_syntax|(한국어) 구문]]을 참고하세요. 이 문서를 **더 좋게 만들 자신이 있을 때**에만 편집하세요. 연습을 하고 싶다면 먼저 [[playground:playground|연습장]]에 가서 연습하세요. +문서를 편집하고 **저장**을 누르세요. 위키 구문은 [[wiki:syntax]] 또는 [[wiki:ko_syntax|(한국어) 구문]]을 참고하세요. 이 문서를 **더 좋게 만들 자신이 있을 때**에만 편집하세요. 연습을 하고 싶다면 먼저 [[playground:playground|연습장]]에 가서 연습하세요. \ No newline at end of file diff --git a/inc/lang/ko/index.txt b/inc/lang/ko/index.txt index 24eb9450c..058f04254 100644 --- a/inc/lang/ko/index.txt +++ b/inc/lang/ko/index.txt @@ -1,3 +1,3 @@ ====== 사이트맵 ====== -이 페이지는 [[doku>namespaces|이름공간]]에서 정렬한 모든 문서의 목록입니다. \ No newline at end of file +[[doku>namespaces|이름공간]]에서 정렬한 모든 문서의 목록입니다. \ No newline at end of file diff --git a/inc/lang/ko/install.html b/inc/lang/ko/install.html index a87bb6382..a9961b47e 100644 --- a/inc/lang/ko/install.html +++ b/inc/lang/ko/install.html @@ -3,7 +3,7 @@ <a href="http://dokuwiki.org/install">(영어) 설치 문서</a>를 참고하시기 바랍니다.</p> <p>DokuWiki는 위키 문서와 문서와 관련된 정보(예를 들어 그림, 검색 색인, 이전 판 문서)를 저장하기 위해 일반적인 텍스트 파일을 사용합니다. 정상적으로 DokuWiki를 사용하려면 이 파일을 담고 있는 디렉토리에 대한 쓰기 권한을 가지고 있어야 합니다. -현재 설치 과정 중에는 디렉토리 권한 설정이 불가능합니다. 보통 직접 쉘 명령어를 사용하거나, 호스팅을 사용한다면 FTP나 호스팅 제어판(예를 들어 CPanel)을 사용해서 설정해야 합니다.</p> +현재 설치 과정 중에는 디렉토리 권한 설정이 불가능합니다. 보통 직접 셸 명령어를 사용하거나, 호스팅을 사용한다면 FTP나 호스팅 제어판(예를 들어 CPanel)을 사용해서 설정해야 합니다.</p> <p>현재 설치 과정중에 관리자로 로그인 후 DokuWiki의 관리 메뉴(플러그인 설치, 사용자 관리, 위키 문서 접근 권한 관리, 옵션 설정)를 가능하게 <acronym title="접근 제어 목록">ACL</acronym>에 대한 환경 설정을 수행합니다. DokuWiki가 동작하는데 필요한 사항은 아니지만, 어쨌든 더 쉽게 관리자가 관리할 수 있도록 해줍니다.</p> @@ -12,4 +12,4 @@ DokuWiki가 동작하는데 필요한 사항은 아니지만, 어쨌든 더 쉽 <a href="http://dokuwiki.org/ko:install">설치 과정 (한국어)</a> 과 <a href="http://dokuwiki.org/ko:config">환경 설정 (한국어),</a> <a href="http://dokuwiki.org/install">설치 과정 (영어)</a> -과 <a href="http://dokuwiki.org/config">환경 설정 (영어)</a></p> +과 <a href="http://dokuwiki.org/config">환경 설정 (영어)</a></p> \ No newline at end of file diff --git a/inc/lang/ko/lang.php b/inc/lang/ko/lang.php index dd3d6747b..93f8611d6 100644 --- a/inc/lang/ko/lang.php +++ b/inc/lang/ko/lang.php @@ -72,11 +72,11 @@ $lang['reguexists'] = '같은 이름을 사용하는 사용자가 있 $lang['regsuccess'] = '사용자를 만들었으며 비밀번호는 이메일로 보냈습니다.'; $lang['regsuccess2'] = '사용자를 만들었습니다.'; $lang['regmailfail'] = '비밀번호를 이메일로 보낼 때 오류가 발생했습니다. 관리자에게 문의하시기 바랍니다!'; -$lang['regbadmail'] = '이메일 주소가 잘못됐습니다 - 오류라고 생각하면 관리자에게 문의하시기 바랍니다.'; +$lang['regbadmail'] = '이메일 주소가 잘못됐습니다 - 오류라고 생각하면 관리자에게 문의하시기 바랍니다'; $lang['regbadpass'] = '새 비밀번호가 일치하지 않습니다. 다시 입력하세요.'; $lang['regpwmail'] = 'DokuWiki 비밀번호'; $lang['reghere'] = '계정이 없나요? 계정을 등록할 수 있습니다'; -$lang['profna'] = '이 위키는 개인 정보 수정을 허용하지 않습니다'; +$lang['profna'] = '이 위키는 개인 정보 수정을 할 수 없습니다'; $lang['profnochange'] = '바뀜이 없습니다.'; $lang['profnoempty'] = '이름이나 이메일 주소가 비었습니다.'; $lang['profchanged'] = '개인 정보가 성공적으로 바뀌었습니다.'; @@ -145,7 +145,7 @@ $lang['mediaselect'] = '미디어 파일 선택'; $lang['fileupload'] = '미디어 파일 올리기'; $lang['uploadsucc'] = '올리기 성공'; $lang['uploadfail'] = '올리기를 실패했습니다. 잘못된 권한 때문일지도 모릅니다.'; -$lang['uploadwrong'] = '올리기를 거부했습니다. 금지된 확장자입니다!'; +$lang['uploadwrong'] = '올리기를 거부했습니다. 금지된 파일 확장자입니다!'; $lang['uploadexist'] = '파일이 이미 존재합니다.'; $lang['uploadbadcontent'] = '올린 파일이 %s 파일 확장자와 일치하지 않습니다.'; $lang['uploadspam'] = '스팸 차단 목록이 올리기를 취소했습니다.'; @@ -160,7 +160,7 @@ $lang['accessdenied'] = '이 문서를 볼 권한이 없습니다.'; $lang['mediausage'] = '이 파일을 참고하려면 다음 문법을 사용하세요:'; $lang['mediaview'] = '원본 파일 보기'; $lang['mediaroot'] = '루트 (root)'; -$lang['mediaupload'] = '파일을 현재 이름공간으로 올립니다. 하위 이름공간으로 만들려면 선택한 파일 이름 앞에 콜론(:)으로 구분되는 이름을 붙이면 됩니다. 파일을 드래그 앤 드롭하여 선택할 수 있습니다.'; +$lang['mediaupload'] = '파일을 현재 이름공간으로 올립니다. 하위 이름공간으로 만들려면 선택한 파일 이름 앞에 쌍점(:)으로 구분되는 이름을 붙이면 됩니다. 파일을 드래그 앤 드롭하여 선택할 수 있습니다.'; $lang['mediaextchange'] = '파일 확장자가 .%s에서 .%s(으)로 바뀌었습니다!'; $lang['reference'] = '참고'; $lang['ref_inuse'] = '다음 문서에서 아직 사용 중이므로 파일을 삭제할 수 없습니다:'; @@ -171,7 +171,7 @@ $lang['toc'] = '목차'; $lang['current'] = '현재'; $lang['yours'] = '판'; $lang['diff'] = '현재 판과의 차이 보기'; -$lang['diff2'] = '선택한 판 간 차이 보기'; +$lang['diff2'] = '선택한 판 사이의 차이 보기'; $lang['difflink'] = '차이 보기로 링크'; $lang['diff_type'] = '차이 보기:'; $lang['diff_inline'] = '인라인 방식'; @@ -194,15 +194,15 @@ $lang['site_tools'] = '사이트 도구'; $lang['page_tools'] = '문서 도구'; $lang['skip_to_content'] = '콘텐츠 넘기기'; $lang['sidebar'] = '사이드바'; -$lang['mail_newpage'] = '문서 추가:'; +$lang['mail_newpage'] = '문서 추가함:'; $lang['mail_changed'] = '문서 바뀜:'; $lang['mail_subscribe_list'] = '이름공간에서 바뀐 문서:'; -$lang['mail_new_user'] = '새로운 사용자:'; -$lang['mail_upload'] = '파일 첨부:'; +$lang['mail_new_user'] = '새 사용자:'; +$lang['mail_upload'] = '파일 올림:'; $lang['changes_type'] = '차이 보기'; $lang['pages_changes'] = '문서'; $lang['media_changes'] = '미디어 파일'; -$lang['both_changes'] = '미디어 파일과 문서 모두'; +$lang['both_changes'] = '문서와 미디어 파일 모두'; $lang['qb_bold'] = '굵은 글씨'; $lang['qb_italic'] = '기울인 글씨'; $lang['qb_underl'] = '밑줄 그어진 글씨'; @@ -246,14 +246,14 @@ $lang['img_keywords'] = '키워드'; $lang['img_width'] = '너비'; $lang['img_height'] = '높이'; $lang['img_manager'] = '미디어 관리자에서 보기'; -$lang['subscr_subscribe_success'] = '%s을(를) %s 구독 목록에 추가하였습니다'; -$lang['subscr_subscribe_error'] = '%s을(를) %s 구독 목록에 추가하는데 실패했습니다'; -$lang['subscr_subscribe_noaddress'] = '등록된 주소가 없기 때문에 구독 목록에 등록되지 않았습니다'; -$lang['subscr_unsubscribe_success'] = '%s을(를) %s 구독 목록에서 삭제하였습니다'; -$lang['subscr_unsubscribe_error'] = '%s을(를) %s 구독 목록에서 삭제하는데 실패했습니다'; -$lang['subscr_already_subscribed'] = '%s은(는) 이미 %s에 구독되고 있습니다'; -$lang['subscr_not_subscribed'] = '%s은(는) 이미 %s에 구독되어 있지 않습니다'; -$lang['subscr_m_not_subscribed'] = '현재의 문서나 이름공간에 구독 등록이 되어 있지 않습니다.'; +$lang['subscr_subscribe_success'] = '%s 사용자가 %s 구독 목록에 추가하였습니다'; +$lang['subscr_subscribe_error'] = '%s 사용자가 %s 구독 목록에 추가하는데 실패했습니다'; +$lang['subscr_subscribe_noaddress'] = '로그인으로 연결된 주소가 없기 때문에 구독 목록에 추가할 수 없습니다'; +$lang['subscr_unsubscribe_success'] = '%s 사용자가 %s 구독 목록에서 삭제하였습니다'; +$lang['subscr_unsubscribe_error'] = '%s 사용자가 %s 구독 목록에서 삭제하는데 실패했습니다'; +$lang['subscr_already_subscribed'] = '%s 사용자가 이미 %s에 구독하고 있습니다'; +$lang['subscr_not_subscribed'] = '%s 사용자가 %s에 구독하고 있지 않습니다'; +$lang['subscr_m_not_subscribed'] = '현재의 문서나 이름공간에 구독하고 있지 않습니다.'; $lang['subscr_m_new_header'] = '구독 추가'; $lang['subscr_m_current_header'] = '현재 구독 중인 문서'; $lang['subscr_m_unsubscribe'] = '구독 취소'; @@ -279,7 +279,7 @@ $lang['i_permfail'] = 'DokuWiki는 <code>%s</code>에 쓰기 가능 $lang['i_confexists'] = '<code>%s</code>(은)는 이미 존재합니다'; $lang['i_writeerr'] = '<code>%s</code>(을)를 만들 수 없습니다. 먼저 디렉토리/파일 권한을 확인하고 파일을 수동으로 만드세요.'; $lang['i_badhash'] = 'dokuwiki.php를 인식할 수 없거나 원본 파일이 아닙니다 (해시=<code>%s</code>)'; -$lang['i_badval'] = '<code>%s</code> - 유효하지 않거나 빈 값입니다'; +$lang['i_badval'] = '<code>%s</code> - 올바르지 않거나 빈 값입니다'; $lang['i_success'] = '환경 설정이 성공적으로 끝났습니다. 지금 install.php를 지워도 상관없습니다. <a href="doku.php?id=wiki:welcome">새 DokuWiki</a>로 들어갑니다.'; $lang['i_failure'] = '환경 설정 파일에 쓰는 도중에 오류가 발생했습니다. <a href="doku.php?id=wiki:welcome">새 DokuWiki</a>를 사용하기 전에 수동으로 문제를 해결해야 합니다.'; $lang['i_policy'] = '초기 ACL 정책'; diff --git a/inc/lang/ko/newpage.txt b/inc/lang/ko/newpage.txt index 87ac969d2..8db34f9cf 100644 --- a/inc/lang/ko/newpage.txt +++ b/inc/lang/ko/newpage.txt @@ -1,3 +1,3 @@ ====== 이 주제는 아직 없습니다 ====== -아직 없는 주제에 대한 링크를 따라왔습니다. **문서 만들기** 버튼을 이용하여 새로 만들 수 있습니다. \ No newline at end of file +아직 없는 주제에 대한 링크를 따라왔습니다. **문서 만들기** 버튼을 클릭하여 새로 만들 수 있습니다. \ No newline at end of file diff --git a/inc/lang/ko/recent.txt b/inc/lang/ko/recent.txt index b1dae2463..4dd19640c 100644 --- a/inc/lang/ko/recent.txt +++ b/inc/lang/ko/recent.txt @@ -1,3 +1,3 @@ ====== 최근 바뀜 ====== -아래의 문서는 최근에 바뀌었습니다. \ No newline at end of file +다음 문서는 최근에 바뀌었습니다. \ No newline at end of file diff --git a/inc/lang/ko/registermail.txt b/inc/lang/ko/registermail.txt index d06f93047..4707dfa13 100644 --- a/inc/lang/ko/registermail.txt +++ b/inc/lang/ko/registermail.txt @@ -10,4 +10,4 @@ IP 주소 : @IPADDRESS@ 호스트 이름 : @HOSTNAME@ -- -@DOKUWIKIURL@의 DokuWiki가 자동으로 만들어낸 메일입니다. +@DOKUWIKIURL@의 DokuWiki가 자동으로 만들어낸 메일입니다. \ No newline at end of file diff --git a/lib/plugins/authad/lang/ko/settings.php b/lib/plugins/authad/lang/ko/settings.php index 31071e9a3..6134bd657 100644 --- a/lib/plugins/authad/lang/ko/settings.php +++ b/lib/plugins/authad/lang/ko/settings.php @@ -6,9 +6,13 @@ */ $lang['account_suffix'] = '계정 접미어. 예를 들어 <code>@my.domain.org</code>'; $lang['base_dn'] = '기본 DN. 예를 들어 <code>DC=my,DC=domain,DC=org</code>'; -$lang['domain_controllers'] = '도메인 컨트롤러의 쉼표로 구분한 목록입니다. 예를 들어 <code>srv1.domain.org,srv2.domain.org</code>'; -$lang['ad_password'] = '위 사용자의 비밀번호입니다.'; +$lang['domain_controllers'] = '도메인 컨트롤러의 쉼표로 구분한 목록. 예를 들어 <code>srv1.domain.org,srv2.domain.org</code>'; +$lang['ad_username'] = '다른 모든 사용자의 데이터에 접근할 수 있는 권한이 있는 Active Directory 사용자. 선택적이지만 구독 메일을 보내는 등의 특정 작업에 필요합니다.'; +$lang['ad_password'] = '위 사용자의 비밀번호.'; $lang['sso'] = 'Kerberos나 NTLM을 통해 Single-Sign-On을 사용해야 합니까?'; +$lang['real_primarygroup'] = '실제 기본 그룹은 "도메인 사용자"를 가정하는 대신 해결될 것입니다 (느림)'; $lang['use_ssl'] = 'SSL 연결을 사용합니까? 사용한다면 아래 TLS을 활성화하지 마세요.'; $lang['use_tls'] = 'TLS 연결을 사용합니까? 사용한다면 위 SSL을 활성화하지 마세요.'; $lang['debug'] = '오류에 대한 추가적인 디버그 정보를 보이겠습니까?'; +$lang['expirywarn'] = '미리 비밀번호 만료를 사용자에게 경고할 날짜. 0일 경우 비활성화합니다.'; +$lang['additional'] = '사용자 데이터에서 가져올 추가적인 AD 속성의 쉼표로 구분한 목록. 일부 플러그인이 사용합니다.'; diff --git a/lib/plugins/authldap/lang/ko/settings.php b/lib/plugins/authldap/lang/ko/settings.php index 6c80414d3..7f7efe8d0 100644 --- a/lib/plugins/authldap/lang/ko/settings.php +++ b/lib/plugins/authldap/lang/ko/settings.php @@ -6,5 +6,16 @@ */ $lang['server'] = 'LDAP 서버. 호스트 이름(<code>localhost</code>)이나 전체 자격 URL(<code>ldap://server.tld:389</code>) 중 하나'; $lang['port'] = '위에 주어진 전체 URL이 없을 때의 LDAP 서버 포트'; +$lang['usertree'] = '사용자 계정을 찾을 장소. 예를 들어 <code>ou=People, dc=server, dc=tld</code>'; +$lang['grouptree'] = '사용자 그룹을 찾을 장소. 예를 들어 <code>ou=Group, dc=server, dc=tld</code>'; +$lang['userfilter'] = '사용자 계정을 찾을 LDAP 필터. 예를 들어 <code>(&(uid=%{user})(objectClass=posixAccount))</code>'; +$lang['groupfilter'] = '그룹을 찾을 LDAP 필터. 예를 들어 <code>(&(objectClass=posixGroup)(|(gidNumber=%{gid})(memberUID=%{user})))</code>'; +$lang['version'] = '사용할 프로토콜 버전. <code>3</code>으로 설정해야 할 수도 있습니다'; $lang['starttls'] = 'TLS 연결을 사용하겠습니까?'; +$lang['referrals'] = '참고(referrals)를 허용하겠습니까? '; +$lang['binddn'] = '익명 바인드가 충분하지 않으면 선택적인 바인드 사용자의 DN. 예를 들어 <code>cn=admin, dc=my, dc=home</code>'; +$lang['bindpw'] = '위 사용자의 비밀번호'; +$lang['userscope'] = '사용자 찾기에 대한 찾기 범위 제한'; +$lang['groupscope'] = '그룹 찾기에 대한 찾기 범위 제한'; +$lang['groupkey'] = '(표준 AD 그룹 대신) 사용자 속성에서 그룹 구성원. 예를 들어 부서나 전화에서 그룹'; $lang['debug'] = '오류에 대한 추가적인 디버그 정보를 보이기'; diff --git a/lib/plugins/config/lang/ko/intro.txt b/lib/plugins/config/lang/ko/intro.txt index 5ef34df64..a2dc7b6f6 100644 --- a/lib/plugins/config/lang/ko/intro.txt +++ b/lib/plugins/config/lang/ko/intro.txt @@ -4,4 +4,4 @@ DokuWiki 설치할 때 설정을 바꾸기 위해 사용하는 페이지입니 플러그인에 대한 자세한 정보가 필요하다면 [[doku>plugin:config|플러그인 설정]] 문서를 참고하세요. 빨간 배경색으로 보이는 설정은 이 플러그인에서 바꾸지 못하도록 되어있습니다. 파란 배경색으로 보이는 설정은 기본 설정값을 가지고 있습니다. 하얀 배경색으로 보이는 설정은 특별한 설치를 위해 설정되어 있습니다. 파란색과 하얀색 배경으로 된 설정은 수정이 가능합니다. -이 페이지를 끝내기 전에 **저장** 버튼을 누르지 않으면 설정값은 적용되지 않습니다. +이 페이지를 떠나기 전에 **저장** 버튼을 누르지 않으면 바뀐 값은 적용되지 않습니다. \ No newline at end of file diff --git a/lib/plugins/config/lang/ko/lang.php b/lib/plugins/config/lang/ko/lang.php index 7737af70f..f69af2df6 100644 --- a/lib/plugins/config/lang/ko/lang.php +++ b/lib/plugins/config/lang/ko/lang.php @@ -54,9 +54,9 @@ $lang['baseurl'] = '서버 URL (예를 들어 <code>http://www.you $lang['cookiedir'] = '쿠키 위치. 비워두면 기본 URL 위치로 지정됩니다.'; $lang['dmode'] = '디렉토리 만들기 모드'; $lang['fmode'] = '파일 만들기 모드'; -$lang['allowdebug'] = '디버그 허용 <b>필요하지 않으면 금지!</b>'; +$lang['allowdebug'] = '디버그 허용 <b>필요하지 않으면 비활성화할 것!</b>'; $lang['recent'] = '최근 바뀐 문서당 항목 수'; -$lang['recent_days'] = '최근 바뀐 문서 기준 시간 (날짜)'; +$lang['recent_days'] = '최근 바뀐 문서 기준 시간 (일)'; $lang['breadcrumbs'] = '위치 "추적" 수. 0으로 설정하면 비활성화합니다.'; $lang['youarehere'] = '계층형 위치 추적 (다음 위의 옵션을 비활성화하게 됩니다)'; $lang['fullpath'] = '문서 하단에 전체 경로 보여주기'; @@ -85,8 +85,8 @@ $lang['profileconfirm'] = '개인 정보를 바꿀 때 비밀번호 다 $lang['rememberme'] = '항상 로그인 정보 저장 허용 (기억하기)'; $lang['disableactions'] = 'DokuWiki 활동 비활성화'; $lang['disableactions_check'] = '검사'; -$lang['disableactions_subscription'] = '구독 신청/해지'; -$lang['disableactions_wikicode'] = '내용 보기/원본 내보대기'; +$lang['disableactions_subscription'] = '구독 신청/구독 취소'; +$lang['disableactions_wikicode'] = '내용 보기/원본 내보내기'; $lang['disableactions_other'] = '다른 활동 (쉼표로 구분)'; $lang['auth_security_timeout'] = '인증 보안 초과 시간 (초)'; $lang['securecookie'] = 'HTTPS로 보내진 쿠키는 HTTPS에만 적용 할까요? 위키의 로그인 페이지만 SSL로 암호화하고 위키 문서는 그렇지 않은 경우 비활성화 합니다.'; @@ -121,10 +121,10 @@ $lang['registernotify'] = '항상 새 사용자한테 이 이메일 주 $lang['mailfrom'] = '자동으로 보내지는 메일 발신자'; $lang['mailprefix'] = '자동으로 보내지는 메일의 제목 말머리 내용. 비웠을 경우 위키 제목 사용'; $lang['htmlmail'] = '용량은 조금 더 크지만 보기 좋은 HTML 태그가 포함된 메일을 보냅니다. 텍스트만의 메일을 보내고자하면 비활성화하세요.'; -$lang['sitemap'] = '구글 사이트맵 생성 (날짜). 0일 경우 비활성화'; +$lang['sitemap'] = '구글 사이트맵 생성 날짜 빈도. 0일 경우 비활성화합니다'; $lang['rss_type'] = 'XML 피드 타입'; $lang['rss_linkto'] = 'XML 피드 링크 정보'; -$lang['rss_content'] = 'XML 피드 항목에 표시되는 내용은?'; +$lang['rss_content'] = 'XML 피드 항목에 표시되는 내용은 무엇입니까?'; $lang['rss_update'] = 'XML 피드 업데이트 주기 (초)'; $lang['rss_show_summary'] = 'XML 피드 제목에서 요약 보여주기'; $lang['rss_media'] = '어떤 규격으로 XML 피드를 받아보시겠습니까?'; @@ -145,7 +145,7 @@ $lang['xsendfile'] = '웹 서버가 정적 파일을 제공하도록 $lang['renderer_xhtml'] = '주 (xhtml) 위키 출력 처리기'; $lang['renderer__core'] = '%s (DokuWiki 내부 기능)'; $lang['renderer__plugin'] = '%s (플러그인)'; -$lang['dnslookups'] = '이 옵션을 활성화하면 DokuWiki가 문서를 수정하는 사용자의 호스트 네임과 원격 IP 주소를 확인합니다. 서버가 느리거나, DNS를 운영하지 않거나 이 기능을 원치 않으면 비활성화 시켜주세요.'; +$lang['dnslookups'] = '이 옵션을 활성화하면 DokuWiki가 문서를 수정하는 사용자의 호스트 네임과 원격 IP 주소를 확인합니다. 서버가 느리거나, DNS를 운영하지 않거나 이 기능을 원치 않으면 비활성화하세요'; $lang['proxy____host'] = '프록시 서버 이름'; $lang['proxy____port'] = '프록시 서버 포트'; $lang['proxy____user'] = '프록시 사용자 이름'; @@ -165,7 +165,7 @@ $lang['typography_o_2'] = '모든 가능한 인용 부호 (동작 안될 $lang['userewrite_o_0'] = '사용 안함'; $lang['userewrite_o_1'] = '.htaccess'; $lang['userewrite_o_2'] = 'DokuWiki 내부 기능'; -$lang['deaccent_o_0'] = '사용 안함'; +$lang['deaccent_o_0'] = '끄기'; $lang['deaccent_o_1'] = '악센트 제거'; $lang['deaccent_o_2'] = '라틴문자화'; $lang['gdlib_o_0'] = 'GD 라이브러리 사용 불가'; @@ -192,8 +192,8 @@ $lang['xsendfile_o_1'] = '비공개 lighttpd 헤더 (1.5 이전 버전)' $lang['xsendfile_o_2'] = '표준 X-Sendfile 헤더'; $lang['xsendfile_o_3'] = '비공개 Nginx X-Accel-Redirect 헤더'; $lang['showuseras_o_loginname'] = '로그인 이름'; -$lang['showuseras_o_username'] = '사용자 이름'; -$lang['showuseras_o_email'] = '사용자 이메일 주소 (메일 주소 보호 설정에 따라 안보일 수 있음)'; +$lang['showuseras_o_username'] = '사용자의 전체 이름'; +$lang['showuseras_o_email'] = '사용자의 이메일 주소 (메일 주소 보호 설정에 따라 안보일 수 있음)'; $lang['showuseras_o_email_link'] = 'mailto: link로 표현될 사용자 이메일 주소'; $lang['useheading_o_0'] = '아니오'; $lang['useheading_o_navigation'] = '둘러보기에만'; diff --git a/lib/plugins/plugin/lang/ko/admin_plugin.txt b/lib/plugins/plugin/lang/ko/admin_plugin.txt index b553d622b..7cbd08f7a 100644 --- a/lib/plugins/plugin/lang/ko/admin_plugin.txt +++ b/lib/plugins/plugin/lang/ko/admin_plugin.txt @@ -1,5 +1,3 @@ ====== 플러그인 관리 ====== -이 페이지에서 Dokuwiki [[doku>plugins|플러그인]]에 관련된 모든 관리 작업을 합니다. 플러그인을 다운로드하거나 설치하기 위해서는 웹 서버가 플러그인 디렉토리에 대해 쓰기 권한을 가지고 있어야 합니다. - - +이 페이지에서 Dokuwiki [[doku>plugins|플러그인]]에 관련된 모든 관리 작업을 합니다. 플러그인을 다운로드하거나 설치하기 위해서는 웹 서버가 플러그인 디렉토리에 대해 쓰기 권한을 가지고 있어야 합니다. \ No newline at end of file diff --git a/lib/plugins/plugin/lang/ko/lang.php b/lib/plugins/plugin/lang/ko/lang.php index 7ca021ac4..447fe667b 100644 --- a/lib/plugins/plugin/lang/ko/lang.php +++ b/lib/plugins/plugin/lang/ko/lang.php @@ -31,7 +31,7 @@ $lang['update_none'] = '업데이트를 찾을 수 없습니다.'; $lang['deleting'] = '삭제 중 ...'; $lang['deleted'] = '%s 플러그인이 삭제되었습니다.'; $lang['downloading'] = '다운로드 중 ...'; -$lang['downloaded'] = '%s 플러그인이 성공적으로 설치되었습니다.'; +$lang['downloaded'] = '%s 플러그인이 성공적으로 설치되었습니다'; $lang['downloads'] = '다음 플러그인이 성공적으로 설치되었습니다:'; $lang['download_none'] = '플러그인이 없거나 다운로드 또는 설치 중에 알 수 없는 문제가 발생했습니다.'; $lang['plugin'] = '플러그인:'; @@ -45,11 +45,11 @@ $lang['author'] = '만든이:'; $lang['www'] = '웹:'; $lang['error'] = '알 수 없는 문제가 발생했습니다.'; $lang['error_download'] = '플러그인 파일을 다운로드 할 수 없습니다: %s'; -$lang['error_badurl'] = '잘못된 URL 같습니다 - URL에서 파일 이름을 알 수 없습니다.'; -$lang['error_dircreate'] = '다운로드를 받기 위한 임시 디렉토리를 만들 수 없습니다.'; +$lang['error_badurl'] = '잘못된 URL 같습니다 - URL에서 파일 이름을 알 수 없습니다'; +$lang['error_dircreate'] = '다운로드를 받기 위한 임시 디렉토리를 만들 수 없습니다'; $lang['error_decompress'] = '플러그인 관리자가 다운로드 받은 파일을 압축을 풀 수 없습니다. 잘못 다운로드 받았을 수도 있으니 다시 한번 시도하거나 압축 포맷을 알 수 없는 경우에는 다운로드한 후 수동으로 직접 설치하세요.'; $lang['error_copy'] = '플러그인을 설치하는 동안 파일 복사하는 데 오류가 발생했습니다. <em>%s</em>: 디스크가 꽉 찼거나 파일 접근 권한이 잘못된 경우입니다. 플러그인 설치가 부분적으로만 이루어졌을 것입니다. 설치가 불완전합니다.'; -$lang['error_delete'] = '<em>%s</em> 플러그인을 삭제하는 동안 오류가 발생했습니다. 대부분의 경우 불완전한 파일이거나 디렉토리 접근 권한이 잘못된 경우입니다.'; +$lang['error_delete'] = '<em>%s</em> 플러그인을 삭제하는 동안 오류가 발생했습니다. 대부분의 경우 불완전한 파일이거나 디렉토리 접근 권한이 잘못된 경우입니다'; $lang['enabled'] = '%s 플러그인을 활성화했습니다.'; $lang['notenabled'] = '%s 플러그인을 활성화할 수 없습니다. 파일 권한을 확인하세요.'; $lang['disabled'] = '%s 플러그인을 비활성화했습니다.'; diff --git a/lib/plugins/popularity/lang/ko/lang.php b/lib/plugins/popularity/lang/ko/lang.php index c881b5a5a..3463f4f8e 100644 --- a/lib/plugins/popularity/lang/ko/lang.php +++ b/lib/plugins/popularity/lang/ko/lang.php @@ -9,10 +9,10 @@ * @author erial2@gmail.com * @author Myeongjin <aranet100@gmail.com> */ -$lang['name'] = '인기도 조사 (불러오는데 시간이 걸릴 수 있습니다.)'; +$lang['name'] = '인기도 조사 (불러오는 데 시간이 걸릴 수 있습니다)'; $lang['submit'] = '자료 보내기'; $lang['autosubmit'] = '자료를 자동으로 매달 한번씩 보내기'; $lang['submissionFailed'] = '다음과 같은 이유로 자료 보내기에 실패했습니다:'; -$lang['submitDirectly'] = '아래의 양식에 맞춰 수동으로 작성된 자료를 보낼 수 있습니다'; +$lang['submitDirectly'] = '아래의 양식에 맞춰 수동으로 작성된 자료를 보낼 수 있습니다.'; $lang['autosubmitError'] = '다음과 같은 이유로 자동 자료 보내기에 실패했습니다:'; $lang['lastSent'] = '자료를 보냈습니다'; diff --git a/lib/plugins/revert/lang/ko/intro.txt b/lib/plugins/revert/lang/ko/intro.txt index 548890ecd..7aa618ba6 100644 --- a/lib/plugins/revert/lang/ko/intro.txt +++ b/lib/plugins/revert/lang/ko/intro.txt @@ -1,3 +1,3 @@ ====== 되돌리기 관리자 ====== -스팸 공격으로부터 자동으로 되돌리는데 이 페이지가 도움이 될 수 있습니다. 스팸 공격받은 문서 목록을 찾으려면 문자열을 입력하고(예를 들어 스팸 URL) 나서 찾은 문서가 스팸 공격을 받았는지 확인하고 되돌리세요. +스팸 공격으로부터 자동으로 되돌리는데 이 페이지가 도움이 될 수 있습니다. 스팸 공격받은 문서 목록을 찾으려면 문자열을 입력하고(예를 들어 스팸 URL) 나서 찾은 문서가 스팸 공격을 받았는지 확인하고 되돌리세요. \ No newline at end of file diff --git a/lib/plugins/usermanager/lang/ko/add.txt b/lib/plugins/usermanager/lang/ko/add.txt index 578ba5636..845d8090a 100644 --- a/lib/plugins/usermanager/lang/ko/add.txt +++ b/lib/plugins/usermanager/lang/ko/add.txt @@ -1 +1 @@ -===== 사용자 추가 ===== +===== 사용자 추가 ===== \ No newline at end of file diff --git a/lib/plugins/usermanager/lang/ko/delete.txt b/lib/plugins/usermanager/lang/ko/delete.txt index 1e9c0ba73..52b8209a1 100644 --- a/lib/plugins/usermanager/lang/ko/delete.txt +++ b/lib/plugins/usermanager/lang/ko/delete.txt @@ -1 +1 @@ -===== 사용자 삭제 ===== +===== 사용자 삭제 ===== \ No newline at end of file diff --git a/lib/plugins/usermanager/lang/ko/edit.txt b/lib/plugins/usermanager/lang/ko/edit.txt index ebb5bb002..a938c5b2e 100644 --- a/lib/plugins/usermanager/lang/ko/edit.txt +++ b/lib/plugins/usermanager/lang/ko/edit.txt @@ -1 +1 @@ -===== 사용자 정보 편집 ===== +===== 사용자 정보 편집 ===== \ No newline at end of file diff --git a/lib/plugins/usermanager/lang/ko/intro.txt b/lib/plugins/usermanager/lang/ko/intro.txt index 8c8bfa5b9..d75680c71 100644 --- a/lib/plugins/usermanager/lang/ko/intro.txt +++ b/lib/plugins/usermanager/lang/ko/intro.txt @@ -1 +1 @@ -====== 사용자 관리 ====== +====== 사용자 관리 ====== \ No newline at end of file diff --git a/lib/plugins/usermanager/lang/ko/list.txt b/lib/plugins/usermanager/lang/ko/list.txt index 93fa3d6f2..2a1b45bfb 100644 --- a/lib/plugins/usermanager/lang/ko/list.txt +++ b/lib/plugins/usermanager/lang/ko/list.txt @@ -1 +1 @@ -===== 사용자 목록 ===== +===== 사용자 목록 ===== \ No newline at end of file -- cgit v1.2.3 From e0c4e620222bfa7d72897f0ab783cd1d30ef1d66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EB=AA=85=EC=A7=84?= <aranet100@gmail.com> Date: Thu, 4 Apr 2013 20:44:23 +0200 Subject: Chinese language update --- lib/plugins/authldap/lang/zh/settings.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/plugins/authldap/lang/zh/settings.php b/lib/plugins/authldap/lang/zh/settings.php index 2dfbeb464..3f38deae9 100644 --- a/lib/plugins/authldap/lang/zh/settings.php +++ b/lib/plugins/authldap/lang/zh/settings.php @@ -13,7 +13,7 @@ $lang['groupfilter'] = '用于搜索组的 LDAP 筛选器。例如 <co $lang['version'] = '使用的协议版本。您或许需要设置为 <code>3</code>'; $lang['starttls'] = '使用 TLS 连接?'; $lang['referrals'] = '是否允许引用 (referrals)?'; -$lang['binddn'] = '一个可选的绑定用户的 DN (如果匿名绑定不满足要求)。例如 Eg. <code>cn=admin, dc=my, dc=home</code>'; +$lang['binddn'] = '一个可选的绑定用户的 DN (如果匿名绑定不满足要求)。例如 <code>cn=admin, dc=my, dc=home</code>'; $lang['bindpw'] = '上述用户的密码'; $lang['userscope'] = '限制用户搜索的范围'; $lang['groupscope'] = '限制组搜索的范围'; -- cgit v1.2.3 From ba04585eb6f5ff34f7bd452c14dad1e536693038 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aivars=20Mi=C5=A1ka?= <allefm@gmail.com> Date: Thu, 4 Apr 2013 20:46:28 +0200 Subject: Latvian language update --- inc/lang/lv/lang.php | 4 ++++ lib/plugins/authad/lang/lv/settings.php | 6 ++++++ lib/plugins/authldap/lang/lv/settings.php | 6 ++++++ lib/plugins/authmysql/lang/lv/settings.php | 6 ++++++ lib/plugins/authpgsql/lang/lv/settings.php | 6 ++++++ lib/plugins/config/lang/lv/lang.php | 1 + 6 files changed, 29 insertions(+) create mode 100644 lib/plugins/authad/lang/lv/settings.php create mode 100644 lib/plugins/authldap/lang/lv/settings.php create mode 100644 lib/plugins/authmysql/lang/lv/settings.php create mode 100644 lib/plugins/authpgsql/lang/lv/settings.php diff --git a/inc/lang/lv/lang.php b/inc/lang/lv/lang.php index 2027b87ba..4d2b5d23c 100644 --- a/inc/lang/lv/lang.php +++ b/inc/lang/lv/lang.php @@ -128,6 +128,7 @@ $lang['js']['restore_confirm'] = 'Tiešām atjaunot šo versiju'; $lang['js']['media_diff'] = 'Skatīt atšķirību'; $lang['js']['media_diff_both'] = 'Blakus'; $lang['js']['media_diff_opacity'] = 'Pārklāti'; +$lang['js']['media_diff_portions'] = 'Pa daļām'; $lang['js']['media_select'] = 'Norādīt failus...'; $lang['js']['media_upload_btn'] = 'Augšuplādēt'; $lang['js']['media_done_btn'] = 'Gatavs'; @@ -283,6 +284,9 @@ $lang['i_pol1'] = 'Publisks Wiki (lasa ikviens, raksta un augšup $lang['i_pol2'] = 'Slēgts Wiki (raksta, lasa un augšupielādē tikai reģistrēti lietotāji)'; $lang['i_retry'] = 'Atkārtot'; $lang['i_license'] = 'Ar kādu licenci saturs tiks publicēts:'; +$lang['i_license_none'] = 'Nerādīt nekādu licences informāciju'; +$lang['i_pop_field'] = 'Lūdzu palīdziet uzlabot DokuWiki'; +$lang['i_pop_label'] = 'Rezi mēnesī nosūtīt DokuWiki izstrādātājiem anonīmus lietošanas datus.'; $lang['recent_global'] = 'Tu skati izmaiņas nodaļā <b>%s</b>. Ir iespējams <a href="%s">skatīt jaunākos grozījums visā viki</a>. '; $lang['years'] = 'pirms %d gadiem'; $lang['months'] = 'pirms %d mēnešiem'; diff --git a/lib/plugins/authad/lang/lv/settings.php b/lib/plugins/authad/lang/lv/settings.php new file mode 100644 index 000000000..ced5dabf8 --- /dev/null +++ b/lib/plugins/authad/lang/lv/settings.php @@ -0,0 +1,6 @@ +<?php +/** + * Latvian, Lettish language file + * + * @author Aivars Miška <allefm@gmail.com> + */ diff --git a/lib/plugins/authldap/lang/lv/settings.php b/lib/plugins/authldap/lang/lv/settings.php new file mode 100644 index 000000000..ced5dabf8 --- /dev/null +++ b/lib/plugins/authldap/lang/lv/settings.php @@ -0,0 +1,6 @@ +<?php +/** + * Latvian, Lettish language file + * + * @author Aivars Miška <allefm@gmail.com> + */ diff --git a/lib/plugins/authmysql/lang/lv/settings.php b/lib/plugins/authmysql/lang/lv/settings.php new file mode 100644 index 000000000..ced5dabf8 --- /dev/null +++ b/lib/plugins/authmysql/lang/lv/settings.php @@ -0,0 +1,6 @@ +<?php +/** + * Latvian, Lettish language file + * + * @author Aivars Miška <allefm@gmail.com> + */ diff --git a/lib/plugins/authpgsql/lang/lv/settings.php b/lib/plugins/authpgsql/lang/lv/settings.php new file mode 100644 index 000000000..ced5dabf8 --- /dev/null +++ b/lib/plugins/authpgsql/lang/lv/settings.php @@ -0,0 +1,6 @@ +<?php +/** + * Latvian, Lettish language file + * + * @author Aivars Miška <allefm@gmail.com> + */ diff --git a/lib/plugins/config/lang/lv/lang.php b/lib/plugins/config/lang/lv/lang.php index 50031d5e5..3adfd1871 100644 --- a/lib/plugins/config/lang/lv/lang.php +++ b/lib/plugins/config/lang/lv/lang.php @@ -26,6 +26,7 @@ $lang['_anti_spam'] = 'Pretspama iestatījumi'; $lang['_editing'] = 'Labošanas iestatījumi'; $lang['_links'] = 'Saišu iestatījumi'; $lang['_media'] = 'Mēdiju iestatījumi'; +$lang['_notifications'] = 'Brīdinājumu iestatījumi'; $lang['_advanced'] = 'Smalkāka iestatīšana'; $lang['_network'] = 'Tīkla iestatījumi'; $lang['_plugin_sufix'] = 'moduļa iestatījumi'; -- cgit v1.2.3 From f9cfe5598c5d3e6dfec2c783e228482375339db3 Mon Sep 17 00:00:00 2001 From: Victor Westmann <victor.westmann@gmail.com> Date: Thu, 4 Apr 2013 20:47:44 +0200 Subject: Brazilian Portuguese language update --- lib/plugins/authmysql/lang/pt-br/settings.php | 12 ++++++++++++ lib/plugins/authpgsql/lang/pt-br/settings.php | 6 ++++++ 2 files changed, 18 insertions(+) diff --git a/lib/plugins/authmysql/lang/pt-br/settings.php b/lib/plugins/authmysql/lang/pt-br/settings.php index 59976ed65..c37690314 100644 --- a/lib/plugins/authmysql/lang/pt-br/settings.php +++ b/lib/plugins/authmysql/lang/pt-br/settings.php @@ -13,6 +13,18 @@ $lang['debug'] = 'Mostrar informações adicionais de depuraçã $lang['forwardClearPass'] = 'Passar senhas de usuários como texto puro para comandos SQL abaixo, ao invés de usar opção passcrypt'; $lang['TablesToLock'] = 'Lista separada por vírgulas para tabelas que devem estar travadas em operações de escrita'; $lang['checkPass'] = 'Comandos SQL para verificar senhas'; +$lang['getUserInfo'] = 'Comando SQL para obter informações de usuário'; +$lang['getGroups'] = 'Comando SQL para obter as credenciais de grupo de um usuário'; +$lang['getUsers'] = 'Comando SQL para listar todos os usuários'; +$lang['FilterLogin'] = 'Comando SQL para filtrar usuários pelo login'; +$lang['addGroup'] = 'Comando SQL para adicionar um novo grupo'; +$lang['addUserGroup'] = 'Comando SQL para adicionar um usuário a um determinado grupo'; +$lang['delGroup'] = 'Comando SQL para remover um grupo'; +$lang['delUser'] = 'Comando SQL para apagar um usuário'; +$lang['delUserRefs'] = 'Comando SQL para apagar um usuário de todos os grupos'; +$lang['updateUser'] = 'Comando SQL para atualizar perfil de usuário'; +$lang['delUserGroup'] = 'Comando SQL para remover um usuário de um grupo determinado'; +$lang['getGroupID'] = 'Comando SQL para obter a chave primária de um grupo determinado'; $lang['debug_o_0'] = 'nenhum'; $lang['debug_o_1'] = 'apenas em erros'; $lang['debug_o_2'] = 'todas as queries SQL'; diff --git a/lib/plugins/authpgsql/lang/pt-br/settings.php b/lib/plugins/authpgsql/lang/pt-br/settings.php index 714f01163..fea309496 100644 --- a/lib/plugins/authpgsql/lang/pt-br/settings.php +++ b/lib/plugins/authpgsql/lang/pt-br/settings.php @@ -9,6 +9,10 @@ $lang['port'] = 'Sua porta do servidor PostgreSQL'; $lang['user'] = 'Nome de usuário PostgreSQL'; $lang['password'] = 'Senha do usuário acima'; $lang['database'] = 'Base de dados para usar'; +$lang['debug'] = 'Mostrar informações adicionais de depuração'; +$lang['checkPass'] = 'Comando SQL para verificar senhas'; +$lang['getUserInfo'] = 'Comando SQL para obter informações do usuário'; +$lang['getGroups'] = 'Comando SQL para obter as credenciais de um usuário de um determinado grupo'; $lang['getUsers'] = 'Comando SQL para listar todos os usuários'; $lang['FilterLogin'] = 'Cláusula SQL para filtrar usuários pelo nome de login'; $lang['FilterName'] = 'Cláusula SQL para filtrar usuários pelo nome completo'; @@ -23,3 +27,5 @@ $lang['getUserID'] = 'Comando SQL para obter chave primária de usu $lang['delUser'] = 'Comando SQL para apagar usuário'; $lang['delUserRefs'] = 'Comando SQL para remover um usuário de todos os grupos'; $lang['updateUser'] = 'Comando SQL para atualizar perfil de usuário'; +$lang['delUserGroup'] = 'Comando SQL para remover um usuário de um determinado grupo'; +$lang['getGroupID'] = 'Comando SQL para obter a chave primária de um determinado grupo'; -- cgit v1.2.3 From 02ea0357f6a255b0f65c967112e6a6d9ec1fa116 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Koot?= <meneer@tken.net> Date: Thu, 4 Apr 2013 20:48:39 +0200 Subject: Dutch language update --- inc/lang/nl/lang.php | 3 +++ inc/lang/nl/password.txt | 2 +- lib/plugins/authad/lang/nl/settings.php | 17 +++++++++++++ lib/plugins/authldap/lang/nl/settings.php | 20 +++++++++++++++ lib/plugins/authmysql/lang/nl/settings.php | 40 ++++++++++++++++++++++++++++++ lib/plugins/authpgsql/lang/nl/settings.php | 36 +++++++++++++++++++++++++++ lib/plugins/config/lang/nl/lang.php | 2 +- lib/plugins/usermanager/lang/nl/lang.php | 2 +- 8 files changed, 119 insertions(+), 3 deletions(-) create mode 100644 lib/plugins/authad/lang/nl/settings.php create mode 100644 lib/plugins/authldap/lang/nl/settings.php create mode 100644 lib/plugins/authmysql/lang/nl/settings.php create mode 100644 lib/plugins/authpgsql/lang/nl/settings.php diff --git a/inc/lang/nl/lang.php b/inc/lang/nl/lang.php index f6192a99b..6c416ca74 100644 --- a/inc/lang/nl/lang.php +++ b/inc/lang/nl/lang.php @@ -296,6 +296,9 @@ $lang['i_pol1'] = 'Publieke wiki (lezen voor iedereen, schrijven $lang['i_pol2'] = 'Besloten wiki (lezen, schrijven en uploaden alleen voor geregistreerde gebruikers)'; $lang['i_retry'] = 'Opnieuw'; $lang['i_license'] = 'Kies a.u.b. een licentie die u voor uw inhoud wilt gebruiken:'; +$lang['i_license_none'] = 'Toon geen licentie informatie'; +$lang['i_pop_field'] = 'Help ons om je DokuWiki ervaring te verbeteren'; +$lang['i_pop_label'] = 'Stuur eens per maand geanonimiseerde gebruiksstatistieken naar de Dokuwiki ontwikkelaars'; $lang['recent_global'] = 'Je bekijkt momenteel de wijzigingen binnen de <b>%s</b> namespace. Je kunt ook de <a href="%s">recente wijzigingen van de hele wiki</a> bekijken.'; $lang['years'] = '%d jaar geleden'; $lang['months'] = '%d maand geleden'; diff --git a/inc/lang/nl/password.txt b/inc/lang/nl/password.txt index 294dcbd1a..5041322db 100644 --- a/inc/lang/nl/password.txt +++ b/inc/lang/nl/password.txt @@ -1,6 +1,6 @@ Beste @FULLNAME@! -Hier is je gebruikersinformatie for @TITLE@ op @DOKUWIKIURL@ +Hier is je gebruikersinformatie voor @TITLE@ op @DOKUWIKIURL@ Gebruikersnaam: @LOGIN@ Wachtwoord : @PASSWORD@ diff --git a/lib/plugins/authad/lang/nl/settings.php b/lib/plugins/authad/lang/nl/settings.php new file mode 100644 index 000000000..e73cac75d --- /dev/null +++ b/lib/plugins/authad/lang/nl/settings.php @@ -0,0 +1,17 @@ +<?php +/** + * Dutch language file + * + */ +$lang['account_suffix'] = 'Je account domeinnaam. Bijv <code>@mijn.domein.org</code>'; +$lang['base_dn'] = 'Je basis DN. Bijv. <code>DC=mijn,DC=domein,DC=org</code>'; +$lang['domain_controllers'] = 'Eeen commagesepareerde lijst van domeinservers. Bijv. <code>srv1.domein.org,srv2.domein.org</code>'; +$lang['ad_username'] = 'Een geprivilegeerde Active Directory gebruiker die bij alle gebruikersgegevens kan komen. Optioneel, maar kan nodig zijn voor bepaalde acties, zoals het versturen van abonnementsmailtjes.'; +$lang['ad_password'] = 'Het wachtwoord van bovernvermelde gebruiker.'; +$lang['sso'] = 'Wordt voor Single-Sign-on Kerberos of NTLM gebruikt?'; +$lang['real_primarygroup'] = 'Moet de echte primaire groep worden opgezocht in plaats van het aannemen van "Domeingebruikers" (langzamer)'; +$lang['use_ssl'] = 'SSL verbinding gebruiken? Zo ja, gebruik dan TLS hieronder niet.'; +$lang['use_tls'] = 'TLS verbinding gebruiken? Zo ja, activeer dan niet de SSL verbinding hierboven.'; +$lang['debug'] = 'Aanvullende debug informatie tonen bij fouten?'; +$lang['expirywarn'] = 'Waarschuwingstermijn voor vervallen wachtwoord. 0 om te deactiveren.'; +$lang['additional'] = 'Commagesepareerde lijst van aanvullend uit AD op te halen attributen. Gebruikt door sommige plugins.'; diff --git a/lib/plugins/authldap/lang/nl/settings.php b/lib/plugins/authldap/lang/nl/settings.php new file mode 100644 index 000000000..274c3b7fc --- /dev/null +++ b/lib/plugins/authldap/lang/nl/settings.php @@ -0,0 +1,20 @@ +<?php +/** + * Dutch language file + * + */ +$lang['server'] = 'Je LDAP server. Ofwel servernaam (<code>localhost</code>) of volledige URL (<code>ldap://server.tld:389</code>)'; +$lang['port'] = 'LDAP server poort als hiervoor geen volledige URL is opgegeven'; +$lang['usertree'] = 'Locatie van de gebruikersaccounts. Bijv. <code>ou=Personen,dc=server,dc=tld</code>'; +$lang['grouptree'] = 'Locatie van de gebruikersgroepen. Bijv. <code>ou=Group,dc=server,dc=tld</code>'; +$lang['userfilter'] = 'LDAP gebruikersfilter. Bijv. <code>(&(uid=%{user})(objectClass=posixAccount))</code>'; +$lang['groupfilter'] = 'LDAP groepsfilter. Bijv. <code>(&(objectClass=posixGroup)(|(gidNumber=%{gid})(memberUID=%{user})))</code>'; +$lang['version'] = 'Te gebruiken protocolversie. Je zou het moeten kunnen instellen op <code>3</code>'; +$lang['starttls'] = 'Gebruiken TLS verbindingen'; +$lang['referrals'] = 'Moeten verwijzingen worden gevolg'; +$lang['binddn'] = 'DN van een optionele bind gebruiker als anonieme bind niet genoeg is. Bijv. <code>cn=beheer, dc=mijn, dc=thuis</code>'; +$lang['bindpw'] = 'Wachtwoord van bovenstaande gebruiker'; +$lang['userscope'] = 'Beperken scope van zoekfuncties voor gebruikers'; +$lang['groupscope'] = 'Beperken scope van zoekfuncties voor groepen'; +$lang['groupkey'] = 'Groepslidmaatschap van enig gebruikersattribuut (in plaats van standaard AD groepen), bijv. groep van afdeling of telefoonnummer'; +$lang['debug'] = 'Tonen van aanvullende debuginformatie bij fouten'; diff --git a/lib/plugins/authmysql/lang/nl/settings.php b/lib/plugins/authmysql/lang/nl/settings.php new file mode 100644 index 000000000..dc85b7eee --- /dev/null +++ b/lib/plugins/authmysql/lang/nl/settings.php @@ -0,0 +1,40 @@ +<?php +/** + * Dutch language file + * + */ +$lang['server'] = 'Je MySQL server'; +$lang['user'] = 'MySql gebruikersnaam'; +$lang['password'] = 'Wachtwoord van bovenstaande gebruiker'; +$lang['database'] = 'Te gebruiken database'; +$lang['charset'] = 'Tekenset voor database'; +$lang['debug'] = 'Tonen aanvullende debuginformatie'; +$lang['forwardClearPass'] = 'Wachtwoorden als leesbare tekst in SQL commando\'s opnemen in plaats van versleutelde tekens'; +$lang['TablesToLock'] = 'Commagesepareerde lijst van tabellen die gelocked moeten worden bij schrijfacties'; +$lang['checkPass'] = 'SQL commando voor verifiëren van wachtwoorden'; +$lang['getUserInfo'] = 'SQL commando voor ophalen gebruikersinformatie'; +$lang['getGroups'] = 'SQL commando voor ophalen groepslidmaatschappen'; +$lang['getUsers'] = 'SQL commando voor tonen alle gebruikers'; +$lang['FilterLogin'] = 'SQL clausule voor filteren gebruikers op inlognaam'; +$lang['FilterName'] = 'SQL clausule voor filteren gebruikers op volledige naam'; +$lang['FilterEmail'] = 'SQL clausule voor filteren gebruikers op e-mailadres'; +$lang['FilterGroup'] = 'SQL clausule voor filteren gebruikers op groepslidmaatschap'; +$lang['SortOrder'] = 'SQL clausule voor sorteren gebruikers'; +$lang['addUser'] = 'SQL commando om een gebruiker toe te voegen'; +$lang['addGroup'] = 'SQL commando om een groep toe te voegen'; +$lang['addUserGroup'] = 'SQL commando om een gebruiker aan een groep toe te voegen'; +$lang['delGroup'] = 'SQL commando om een groep te verwijderen'; +$lang['getUserID'] = 'SQL commando om de de primaire sleutel van een gebruiker op te halen'; +$lang['delUser'] = 'SQL commando om een gebruiker te verwijderen'; +$lang['delUserRefs'] = 'SQL commando om een gebruiker uit alle groepen te verwijderen'; +$lang['updateUser'] = 'SQL commando om een gebruikersprofiel bij te werken'; +$lang['UpdateLogin'] = 'Bijwerkcommando om een inlognaam bij te werken'; +$lang['UpdatePass'] = 'Bijwerkcommando om een wachtwoord bij te werken'; +$lang['UpdateEmail'] = 'Bijwerkcommando om een e-mailadres bij te werken'; +$lang['UpdateName'] = 'Bijwerkcommando om een volledige naam te werken'; +$lang['UpdateTarget'] = 'Beperkingsclausule om gebruiker te identificeren voor bijwerken'; +$lang['delUserGroup'] = 'SQL commando om een gebruiker uit een bepaalde te verwijderen'; +$lang['getGroupID'] = 'SQL commando om de primaire sletel van een bepaalde groep op te halen'; +$lang['debug_o_0'] = 'geen'; +$lang['debug_o_1'] = 'alleen bij fouten'; +$lang['debug_o_2'] = 'alle SQL queries'; diff --git a/lib/plugins/authpgsql/lang/nl/settings.php b/lib/plugins/authpgsql/lang/nl/settings.php new file mode 100644 index 000000000..4e6c007c6 --- /dev/null +++ b/lib/plugins/authpgsql/lang/nl/settings.php @@ -0,0 +1,36 @@ +<?php +/** + * Dutch language file + * + */ +$lang['server'] = 'Je PostgrSQL server'; +$lang['port'] = 'Je PostgreSQL server poort'; +$lang['user'] = 'PostgrSQL gebruikersnaam'; +$lang['password'] = 'Wachtwoord voor bovenstaande gebruiker'; +$lang['database'] = 'Te gebruiken database'; +$lang['debug'] = 'Tonen aanvullende debuginformatie'; +$lang['forwardClearPass'] = 'Wachtwoorden als leesbare tekst in SQL commando\'s opnemen in plaats van versleutelde tekens'; +$lang['checkPass'] = 'SQL commando voor verifiëren wachtwoorden'; +$lang['getUserInfo'] = 'SQL commando voor ophalen gebruikersinformatie'; +$lang['getGroups'] = 'SQL commando voor ophalen groepslidmaatschappen van gebruikers'; +$lang['getUsers'] = 'SQL commando voor tonen alle gebruikers'; +$lang['FilterLogin'] = 'SQL commando voor filteren gebruikers op inlognaam'; +$lang['FilterName'] = 'SQL commando voor filteren gebruikers op volledige naam'; +$lang['FilterEmail'] = 'SQL commando voor filteren gebruikers op e-mailadres'; +$lang['FilterGroup'] = 'SQL commando voor filteren gebruikers op groepslidmaatschap'; +$lang['SortOrder'] = 'SQL commando voor sorteren gebruikers'; +$lang['addUser'] = 'SQL commando voor toevoegen nieuwe gebruiker'; +$lang['addGroup'] = 'SQL commando voor toevoegen nieuwe groep'; +$lang['addUserGroup'] = 'SQL commando voor toevoegen gebruiker aan bestaande groep'; +$lang['delGroup'] = 'SQL commando voor verwijderen groep'; +$lang['getUserID'] = 'SQL commando om de primaire sleutel van een gebruiker op te halen'; +$lang['delUser'] = 'SQL commando voor verwijderen gebruiker'; +$lang['delUserRefs'] = 'SQL commando om een gebruiker uit alle groepen te verwijderen'; +$lang['updateUser'] = 'SQL commando om een gebruikersprofiel bij te werken'; +$lang['UpdateLogin'] = 'SQL commando om een inlognaam bij te werken'; +$lang['UpdatePass'] = 'SQL commando om een wachtwoord bij te werken'; +$lang['UpdateEmail'] = 'SQL commando om een e-mailadres bij te werken'; +$lang['UpdateName'] = 'SQL commando om een volledige naam bij te werken'; +$lang['UpdateTarget'] = 'Beperkingsclausule om gebruiker te identificeren voor bijwerken'; +$lang['delUserGroup'] = 'SQL commando om een gebruiker uit een bepaalde groep te verwijderen'; +$lang['getGroupID'] = 'SQL commando om de primaire sleutel van een bepaalde groep op te halen'; diff --git a/lib/plugins/config/lang/nl/lang.php b/lib/plugins/config/lang/nl/lang.php index 85dc2c4c7..26ea3d8c1 100644 --- a/lib/plugins/config/lang/nl/lang.php +++ b/lib/plugins/config/lang/nl/lang.php @@ -63,7 +63,7 @@ $lang['allowdebug'] = 'Debug toestaan <b>uitzetten indien niet noodza $lang['recent'] = 'Het aantal regels in Recente wijzigingen'; $lang['recent_days'] = 'Hoeveel recente wijzigingen bewaren (dagen)'; $lang['breadcrumbs'] = 'Aantal broodkruimels. Zet dit op 0 om uit te schakelen.'; -$lang['youarehere'] = 'Gebruik hierarchische broodkruimels (waarschijnlijk wil je dan de optie hierboven uitschakelen)'; +$lang['youarehere'] = 'Gebruik hiërarchische broodkruimels (waarschijnlijk wil je dan de optie hierboven uitschakelen)'; $lang['fullpath'] = 'Volledig pad van pagina\'s in de footer weergeven'; $lang['typography'] = 'Breng typografische wijzigingen aan'; $lang['dformat'] = 'Datum formaat (zie de PHP <a href="http://www.php.net/strftime">strftime</a> functie)'; diff --git a/lib/plugins/usermanager/lang/nl/lang.php b/lib/plugins/usermanager/lang/nl/lang.php index 8f30ce3ea..e960e9a14 100644 --- a/lib/plugins/usermanager/lang/nl/lang.php +++ b/lib/plugins/usermanager/lang/nl/lang.php @@ -17,7 +17,7 @@ */ $lang['menu'] = 'Gebruikersmanager'; $lang['noauth'] = '(gebruikersauthenticatie niet beschikbaar)'; -$lang['nosupport'] = '(gebruikersmanagement niet ondersteund)'; +$lang['nosupport'] = '(gebruikersbeheer niet ondersteund)'; $lang['badauth'] = 'ongeldige authenticatiemethode'; $lang['user_id'] = 'Gebruiker'; $lang['user_pass'] = 'Wachtwoord'; -- cgit v1.2.3 From 28e3011634adb583576c1a3a0d2d400dda108356 Mon Sep 17 00:00:00 2001 From: Anika Henke <anika@selfthinker.org> Date: Fri, 5 Apr 2013 02:10:20 +0100 Subject: fixed rfc interwiki url --- conf/interwiki.conf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/conf/interwiki.conf b/conf/interwiki.conf index 28d603de2..aba475a0e 100644 --- a/conf/interwiki.conf +++ b/conf/interwiki.conf @@ -5,7 +5,7 @@ # no further encoding is done # If no placeholder is defined the urlencoded name is appended to the URL -# To prevent losing your added InterWiki shortcuts after an upgrade, +# To prevent losing your added InterWiki shortcuts after an upgrade, # you should add new ones to interwiki.local.conf wp http://en.wikipedia.org/wiki/{NAME} @@ -17,7 +17,7 @@ wpjp http://ja.wikipedia.org/wiki/{NAME} wpmeta http://meta.wikipedia.org/wiki/{NAME} doku http://www.dokuwiki.org/ dokubug http://bugs.dokuwiki.org/index.php?do=details&task_id= -rfc http://www.cs.ccu.edu.tw/~chm91u/rfc2html.php?in= +rfc http://tools.ietf.org/html/rfc man http://man.cx/ amazon http://www.amazon.com/exec/obidos/ASIN/{URL}/splitbrain-20/ amazon.de http://www.amazon.de/exec/obidos/ASIN/{URL}/splitbrain-21/ -- cgit v1.2.3 From f755f9abc6fe099a6bee2bdd4acda44baca5ea7a Mon Sep 17 00:00:00 2001 From: Christopher Smith <chris@jalakai.co.uk> Date: Sun, 7 Apr 2013 19:40:27 +0100 Subject: change nomenclature from 'show' to 'allow' (fn from canshow to allowed) --- inc/html.php | 2 +- inc/infoutils.php | 23 ++++++++++++++++------- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/inc/html.php b/inc/html.php index 09d1387bd..fb39fcb3c 100644 --- a/inc/html.php +++ b/inc/html.php @@ -1297,7 +1297,7 @@ function html_msgarea(){ foreach($MSG as $msg){ $hash = md5($msg['msg']); if(isset($shown[$hash])) continue; // skip double messages - if(info_msg_canshow($msg)){ + if(info_msg_allowed($msg)){ print '<div class="'.$msg['lvl'].'">'; print $msg['msg']; print '</div>'; diff --git a/inc/infoutils.php b/inc/infoutils.php index da230da37..9fe5ee689 100644 --- a/inc/infoutils.php +++ b/inc/infoutils.php @@ -275,7 +275,7 @@ define('MSG_USERS_ONLY', 1); define('MSG_MANAGERS_ONLY',2); define('MSG_ADMINS_ONLY',4); -function msg($message,$lvl=0,$line='',$file='',$show=MSG_PUBLIC){ +function msg($message,$lvl=0,$line='',$file='',$allow=MSG_PUBLIC){ global $MSG, $MSG_shown; $errors[-1] = 'error'; $errors[0] = 'info'; @@ -285,7 +285,7 @@ function msg($message,$lvl=0,$line='',$file='',$show=MSG_PUBLIC){ if($line || $file) $message.=' ['.utf8_basename($file).':'.$line.']'; if(!isset($MSG)) $MSG = array(); - $MSG[]=array('lvl' => $errors[$lvl], 'msg' => $message, 'show' => $show); + $MSG[]=array('lvl' => $errors[$lvl], 'msg' => $message, 'allow' => $allow); if(isset($MSG_shown) || headers_sent()){ if(function_exists('html_msgarea')){ html_msgarea(); @@ -295,17 +295,26 @@ function msg($message,$lvl=0,$line='',$file='',$show=MSG_PUBLIC){ unset($GLOBALS['MSG']); } } - -function info_msg_canshow($msg){ +/** + * Determine whether the current user is allowed to view the message + * in the $msg data structure + * + * @param $msg array dokuwiki msg structure + * msg => string, the message + * lvl => int, level of the message (see msg() function) + * allow => int, flag used to determine who is allowed to see the message + * see MSG_* constants + */ +function info_msg_allowed($msg){ global $INFO, $auth; // is the message public? - everyone and anyone can see it - if (empty($msg['show']) || ($msg['show'] == MSG_PUBLIC)) return true; + if (empty($msg['allow']) || ($msg['allow'] == MSG_PUBLIC)) return true; // restricted msg, but no authentication if (empty($auth)) return false; - switch ($msg['show']){ + switch ($msg['allow']){ case MSG_USERS_ONLY: return !empty($INFO['userinfo']); @@ -316,7 +325,7 @@ function info_msg_canshow($msg){ return $INFO['isadmin']; default: - trigger_error('invalid msg show restriction. msg="'.$msg['msg'].'" show='.$msg['show'].'"', E_USER_WARNING); + trigger_error('invalid msg allow restriction. msg="'.$msg['msg'].'" allow='.$msg['allow'].'"', E_USER_WARNING); return $INFO['isadmin']; } -- cgit v1.2.3 From 25cfdf73de200b6ae57a47960bc3100e4aba3c7b Mon Sep 17 00:00:00 2001 From: Michael Hamann <michael@content-space.de> Date: Mon, 8 Apr 2013 12:21:28 +0200 Subject: indexer.php: disable the GIF output only with debug parameter and allowdebug Before this fix the debug parameter always prevent the GIF from being sent even though no actual debug information was returned unless the allowdebug configuration option was set. Now the GIF is only disabled if debugging is actually allowed. --- lib/exe/indexer.php | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/lib/exe/indexer.php b/lib/exe/indexer.php index 27576f76d..57bee8925 100644 --- a/lib/exe/indexer.php +++ b/lib/exe/indexer.php @@ -16,15 +16,16 @@ if(!defined('NL')) define('NL',"\n"); // check if user abort worked, if yes send output early $defer = !@ignore_user_abort() || $conf['broken_iua']; -if(!$defer){ +$output = $INPUT->has('debug') && $conf['allowdebug']; +if(!$defer && !$output){ sendGIF(); // send gif } $ID = cleanID($INPUT->str('id')); // Catch any possible output (e.g. errors) -$output = $INPUT->has('debug') && $conf['allowdebug']; if(!$output) ob_start(); +else header('Content-Type: text/plain'); // run one of the jobs $tmp = array(); // No event data @@ -192,11 +193,6 @@ function sendDigest() { * @author Harry Fuecks <fuecks@gmail.com> */ function sendGIF(){ - global $INPUT; - if($INPUT->has('debug')){ - header('Content-Type: text/plain'); - return; - } $img = base64_decode('R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAEALAAAAAABAAEAAAIBTAA7'); header('Content-Type: image/gif'); header('Content-Length: '.strlen($img)); -- cgit v1.2.3 From df9752e9c1bfd3eaff132b15817baa1c6e989506 Mon Sep 17 00:00:00 2001 From: Christopher Smith <chris@jalakai.co.uk> Date: Wed, 10 Apr 2013 18:01:04 +0100 Subject: add comment to Unified Diff Formatter making it clear the output is unsafe for use in HTML as is --- inc/DifferenceEngine.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/inc/DifferenceEngine.php b/inc/DifferenceEngine.php index e0fbf8e03..783d6bea5 100644 --- a/inc/DifferenceEngine.php +++ b/inc/DifferenceEngine.php @@ -1004,6 +1004,8 @@ class InlineWordLevelDiff extends MappedDiff { * "Unified" diff formatter. * * This class formats the diff in classic "unified diff" format. + * + * NOTE: output is plain text and unsafe for use in HTML without escaping. */ class UnifiedDiffFormatter extends DiffFormatter { -- cgit v1.2.3 From a494ed3306f1a5e6082a1ffb7e17925a524ea711 Mon Sep 17 00:00:00 2001 From: Christopher Smith <chris@jalakai.co.uk> Date: Wed, 10 Apr 2013 18:36:35 +0100 Subject: FS#2738, fix double encoding of html entities in RSS feeds (updates feed.php for changes to Diff class introduced in PR#179) --- feed.php | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/feed.php b/feed.php index 7803982b8..73fa0e05f 100644 --- a/feed.php +++ b/feed.php @@ -322,14 +322,15 @@ function rss_buildItems(&$rss, &$data, $opt) { $rev = $revs[0]; if($rev) { - $df = new Diff(explode("\n", htmlspecialchars(rawWiki($id, $rev))), - explode("\n", htmlspecialchars(rawWiki($id, '')))); + $df = new Diff(explode("\n", rawWiki($id, $rev)), + explode("\n", rawWiki($id, ''))); } else { $df = new Diff(array(''), - explode("\n", htmlspecialchars(rawWiki($id, '')))); + explode("\n", rawWiki($id, ''))); } if($opt['item_content'] == 'htmldiff') { + // note: no need to escape diff output, TableDiffFormatter provides 'safe' html $tdf = new TableDiffFormatter(); $content = '<table>'; $content .= '<tr><th colspan="2" width="50%">'.$rev.'</th>'; @@ -337,8 +338,9 @@ function rss_buildItems(&$rss, &$data, $opt) { $content .= $tdf->format($df); $content .= '</table>'; } else { + // note: diff output must be escaped, UnifiedDiffFormatter provides plain text $udf = new UnifiedDiffFormatter(); - $content = "<pre>\n".$udf->format($df)."\n</pre>"; + $content = "<pre>\n".hsc($udf->format($df))."\n</pre>"; } } break; -- cgit v1.2.3 From f755f63a3beef948a8d179c0e0860041f4f86db5 Mon Sep 17 00:00:00 2001 From: Christopher Smith <chris@jalakai.co.uk> Date: Wed, 10 Apr 2013 18:42:20 +0100 Subject: FS#2748, fix double encoding of html entities in subscription email diffs (updates subscription.php for changes to Diff class introduced in PR#179) --- inc/subscription.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/inc/subscription.php b/inc/subscription.php index 2989de032..4248e4b11 100644 --- a/inc/subscription.php +++ b/inc/subscription.php @@ -408,8 +408,8 @@ class Subscription { $tdiff = $dformat->format($df); $DIFF_INLINESTYLES = true; - $df = new Diff(explode("\n", hsc($old_content)), - explode("\n", hsc($new_content))); + $df = new Diff(explode("\n", $old_content), + explode("\n", $new_content)); $dformat = new InlineDiffFormatter(); $hdiff = $dformat->format($df); $hdiff = '<table>'.$hdiff.'</table>'; -- cgit v1.2.3 From ba09710ad34bb383ae3526e84490a3d545f78866 Mon Sep 17 00:00:00 2001 From: Martin Terber <mterber@gmx.net> Date: Mon, 15 Apr 2013 21:55:41 +0200 Subject: German language update --- inc/lang/de/lang.php | 4 + lib/plugins/acl/lang/de/lang.php | 1 + lib/plugins/authad/lang/de/settings.php | 17 +--- lib/plugins/authldap/lang/de/settings.php | 18 +--- lib/plugins/authmysql/lang/de/settings.php | 38 +------- lib/plugins/authpgsql/lang/de/settings.php | 34 +------ lib/plugins/config/lang/de/lang.php | 141 +++++++++++++++-------------- lib/plugins/plugin/lang/de/lang.php | 1 + lib/plugins/popularity/lang/de/lang.php | 1 + lib/plugins/revert/lang/de/lang.php | 1 + lib/plugins/usermanager/lang/de/lang.php | 1 + 11 files changed, 86 insertions(+), 171 deletions(-) diff --git a/inc/lang/de/lang.php b/inc/lang/de/lang.php index 160ea53e8..1a9cb7d90 100644 --- a/inc/lang/de/lang.php +++ b/inc/lang/de/lang.php @@ -21,6 +21,7 @@ * @author Matthias Schulte <mailinglist@lupo49.de> * @author Paul Lachewsky <kaeptn.haddock@gmail.com> * @author Pierre Corell <info@joomla-praxis.de> + * @author Mateng Schimmerlos <mateng@firemail.de>) */ $lang['encoding'] = 'utf-8'; $lang['direction'] = 'ltr'; @@ -298,6 +299,9 @@ $lang['i_pol1'] = 'Öffentliches Wiki (Lesen für alle, Schreiben $lang['i_pol2'] = 'Geschlossenes Wiki (Lesen, Schreiben und Hochladen nur für registrierte Nutzer)'; $lang['i_retry'] = 'Wiederholen'; $lang['i_license'] = 'Bitte wählen Sie die Lizenz, unter die Sie Ihre Inhalte stellen möchten:'; +$lang['i_license_none'] = 'Lizensierungsinformation nicht anzeigen'; +$lang['i_pop_field'] = 'Bitte Helfen Sie mit, DokuWiki zu verbessern:'; +$lang['i_pop_label'] = 'Einmal monatlich anonymisierte Nutzungsdaten an das DokuWiki-Entwicklerteam senden'; $lang['recent_global'] = 'Im Moment sehen Sie die Änderungen im Namensraum <b>%s</b>. Sie können auch <a href="%s">die Änderungen im gesamten Wiki sehen</a>.'; $lang['years'] = 'vor %d Jahren'; $lang['months'] = 'vor %d Monaten'; diff --git a/lib/plugins/acl/lang/de/lang.php b/lib/plugins/acl/lang/de/lang.php index eb23636c4..e2ac98cd7 100644 --- a/lib/plugins/acl/lang/de/lang.php +++ b/lib/plugins/acl/lang/de/lang.php @@ -21,6 +21,7 @@ * @author Christian Wichmann <nospam@zone0.de> * @author Paul Lachewsky <kaeptn.haddock@gmail.com> * @author Pierre Corell <info@joomla-praxis.de> + * @author Mateng Schimmerlos <mateng@firemail.de>) */ $lang['admin_acl'] = 'Zugangsverwaltung'; $lang['acl_group'] = 'Gruppe'; diff --git a/lib/plugins/authad/lang/de/settings.php b/lib/plugins/authad/lang/de/settings.php index 38bccbf24..a1a99b6d6 100644 --- a/lib/plugins/authad/lang/de/settings.php +++ b/lib/plugins/authad/lang/de/settings.php @@ -1,19 +1,6 @@ <?php /** - * German (informal) language file + * German language file * - * @author Frank Loizzi <contact@software.bacal.de> - * @author Matthias Schulte <dokuwiki@lupo49.de> + * @author Mateng Schimmerlos <mateng@firemail.de>) */ -$lang['account_suffix'] = 'Ihr Account-Suffix. Z.B. <code>@my.domain.org</code>'; -$lang['base_dn'] = 'Ihre Base-DN. Z.B. <code>DC=my,DC=domain,DC=org</code>'; -$lang['domain_controllers'] = 'Eine Komma-separierte Liste von Domänen-Controllern. Z.B. <code>srv1.domain.org,srv2.domain.org</code>'; -$lang['ad_username'] = 'Ein priviligierter Active Directory-Benutzer mit Zugriff zu allen anderen Benutzerdaten. Optional, aber wird benötigt für Aktionen wie z. B. dass Senden von Benachrichtigungs-Mails.'; -$lang['ad_password'] = 'Das Passwort des obigen Benutzers.'; -$lang['sso'] = 'Soll Single-Sign-On via Kerberos oder NTLM benutzt werden?'; -$lang['real_primarygroup'] = 'Soll die echte primäre Gruppe aufgelöst werden anstelle der Annahme "Domain Users" (langsamer)'; -$lang['use_ssl'] = 'SSL-Verbindung benutzen? Falls ja, TLS unterhalb nicht aktivieren.'; -$lang['use_tls'] = 'TLS-Verbindung benutzen? Falls ja, SSL oberhalb nicht aktivieren.'; -$lang['debug'] = 'Zusätzliche Debug-Informationen bei Fehlern anzeigen?'; -$lang['expirywarn'] = 'Tage im Voraus um Benutzer über ablaufende Passwörter zu informieren. 0 zum Ausschalten.'; -$lang['additional'] = 'Eine Komma-separierte Liste von zusätzlichen AD-Attributen, die von den Benutzerobjekten abgefragt werden. Wird von einigen Plugins benutzt.'; diff --git a/lib/plugins/authldap/lang/de/settings.php b/lib/plugins/authldap/lang/de/settings.php index b237201d8..a1a99b6d6 100644 --- a/lib/plugins/authldap/lang/de/settings.php +++ b/lib/plugins/authldap/lang/de/settings.php @@ -2,21 +2,5 @@ /** * German language file * - * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) - * @author Matthias Schulte <dokuwiki@lupo49.de> + * @author Mateng Schimmerlos <mateng@firemail.de>) */ -$lang['server'] = 'Adresse zum LDAP-Server. Entweder als Hostname (<code>localhost</code>) oder als FQDN (<code>ldap://server.tld:389</code>).'; -$lang['port'] = 'Port des LDAP-Servers, falls kein Port angegeben wurde.'; -$lang['usertree'] = 'Zweig, in dem die die Benutzeraccounts gespeichert sind. Zum Beispiel: <code>ou=People, dc=server, dc=tld</code>.'; -$lang['grouptree'] = 'Zweig, in dem die Benutzergruppen gespeichert sind. Zum Beispiel: <code>ou=Group, dc=server, dc=tld</code>.'; -$lang['userfilter'] = 'LDAP-Filter, um die Benutzeraccounts zu suchen. Zum Beispiel: <code>(&(uid=%{user})(objectClass=posixAccount))</code>.'; -$lang['groupfilter'] = 'LDAP-Filter, um die Benutzergruppen zu suchen. Zum Beispiel: <code>(&(objectClass=posixGroup)(|(gidNumber=%{gid})(memberUID=%{user})))</code>.'; -$lang['version'] = 'Zu verwendende Protokollversion von LDAP.'; -$lang['starttls'] = 'Verbindung über TLS aufbauen?'; -$lang['referrals'] = 'Weiterverfolgen von LDAP-Referrals (Verweise)?'; -$lang['binddn'] = 'DN eines optionalen Benutzers, wenn der anonyme Zugriff nicht ausreichend ist. Zum Beispiel: <code>cn=admin, dc=my, dc=home</code>.'; -$lang['bindpw'] = 'Passwort des angegebenen Benutzers.'; -$lang['userscope'] = 'Die Suchweite nach Benutzeraccounts.'; -$lang['groupscope'] = 'Die Suchweite nach Benutzergruppen.'; -$lang['groupkey'] = 'Gruppieren der Benutzeraccounts anhand eines beliebigen Benutzerattributes z. B. Telefonnummer oder Abteilung, anstelle der Standard-Gruppen).'; -$lang['debug'] = 'Debug-Informationen beim Auftreten von Fehlern anzeigen?'; diff --git a/lib/plugins/authmysql/lang/de/settings.php b/lib/plugins/authmysql/lang/de/settings.php index 97ba06a9d..a1a99b6d6 100644 --- a/lib/plugins/authmysql/lang/de/settings.php +++ b/lib/plugins/authmysql/lang/de/settings.php @@ -2,41 +2,5 @@ /** * German language file * - * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) - * @author Matthias Schulte <dokuwiki@lupo49.de> + * @author Mateng Schimmerlos <mateng@firemail.de>) */ -$lang['server'] = 'MySQL-Server'; -$lang['user'] = 'Benutzername für den Zugriff auf den MySQL-Server.'; -$lang['password'] = 'Passwort des angegebenen Benutzers.'; -$lang['database'] = 'Zu verwendende Datenbank.'; -$lang['charset'] = 'Verwendetes Character-Set in der Datenbank.'; -$lang['debug'] = 'Debug-Informationen anzeigen?'; -$lang['forwardClearPass'] = 'Passwort der DokuWiki-Benutzer im Klartext an die Datenbank übergeben? (Im Normalfall wird die passcrypt-Option angewendet.)'; -$lang['TablesToLock'] = 'Eine Komma-separierte Liste von Tabellen, die vor Schreiboperationen gesperrt werden müssen.'; -$lang['checkPass'] = 'SQL-Kommando zum Überprüfen von Passwörtern.'; -$lang['getUserInfo'] = 'SQL-Kommando um Benutzerinformationen auszulesen.'; -$lang['getGroups'] = 'SQL-Kommando um Gruppen eines Benutzers auszulesen.'; -$lang['getUsers'] = 'SQL-Kommando um alle Benutzer auszulesen.'; -$lang['FilterLogin'] = 'SQL-Bedingung um Benutzer anhand ihres Anmeldenamens zu filtern.'; -$lang['FilterName'] = 'SQL-Bedingung um Benutzer anhand ihres Namens zu filtern.'; -$lang['FilterEmail'] = 'SQL-Bedingung um Benutzer anhand ihrer E-Mail-Adresse zu filtern.'; -$lang['FilterGroup'] = 'SQL-Bedingung um Benutzer anhand ihrer Gruppenzugehörigkeit zu filtern.'; -$lang['SortOrder'] = 'SQL-Bedingung um anhand der die Benutzerliste sortiert wird.'; -$lang['addUser'] = 'SQL-Kommando um einen neuen Benutzer anzulegen.'; -$lang['addGroup'] = 'SQL-Kommando um eine neue Gruppe anzulegen.'; -$lang['addUserGroup'] = 'SQL-Kommando um einen Benutzer zu einer Gruppe hinzuzufügen.'; -$lang['delGroup'] = 'SQL-Kommando um eine Gruppe zu löschen.'; -$lang['getUserID'] = 'SQL-Kommando um den Primärschlüssel des Benutzers auszulesen.'; -$lang['delUser'] = 'SQL-Kommando um einen Benutzer zu löschen.'; -$lang['delUserRefs'] = 'SQL-Kommando um einen Benutzer aus allen Gruppen zu entfernen.'; -$lang['updateUser'] = 'SQL-Kommando um das Profil eines Benutzers zu aktualisieren.'; -$lang['UpdateLogin'] = 'SQL-Bedingung um den Anmeldenamen eines Benutzers zu ändern.'; -$lang['UpdatePass'] = 'SQL-Bedingung um das Passwort eines Benutzers zu ändern.'; -$lang['UpdateEmail'] = 'SQL-Bedingung um die E-Mail-Adresse eines Benutzers zu ändern.'; -$lang['UpdateName'] = 'SQL-Bedingung um den Namen eines Benutzers zu ändern.'; -$lang['UpdateTarget'] = 'SQL-Bedingung zur eindeutigen Identifikation des Benutzers.'; -$lang['delUserGroup'] = 'SQL-Kommando um einen Benutzer aus einer angegeben Gruppe zu entfernen.'; -$lang['getGroupID'] = 'SQL-Kommando um den Primärschlüssel einer Gruppe auszulesen.'; -$lang['debug_o_0'] = 'Keine.'; -$lang['debug_o_1'] = 'Nur Fehler.'; -$lang['debug_o_2'] = 'Alle SQL-Abfragen.'; diff --git a/lib/plugins/authpgsql/lang/de/settings.php b/lib/plugins/authpgsql/lang/de/settings.php index 4c80245d6..a1a99b6d6 100644 --- a/lib/plugins/authpgsql/lang/de/settings.php +++ b/lib/plugins/authpgsql/lang/de/settings.php @@ -2,37 +2,5 @@ /** * German language file * - * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) - * @author Matthias Schulte <dokuwiki@lupo49.de> + * @author Mateng Schimmerlos <mateng@firemail.de>) */ -$lang['server'] = 'PostgreSQL-Server'; -$lang['port'] = 'Port des PostgreSQL-Servers.'; -$lang['user'] = 'Benutzername für den Zugriff auf den PostgreSQL-Server.'; -$lang['password'] = 'Passwort des angegebenen Benutzers.'; -$lang['database'] = 'Zu verwendende Datenbank.'; -$lang['debug'] = 'Debug-Informationen anzeigen?'; -$lang['forwardClearPass'] = 'Passwort der DokuWiki-Benutzer im Klartext an die Datenbank übergeben? (Im Normalfall wird die passcrypt-Option angewendet.)'; -$lang['checkPass'] = 'SQL-Kommando zum Überprüfen von Passwörtern.'; -$lang['getUserInfo'] = 'SQL-Kommando um Benutzerinformationen auszulesen.'; -$lang['getGroups'] = 'SQL-Kommando um Gruppen eines Benutzers auszulesen.'; -$lang['getUsers'] = 'SQL-Kommando um alle Benutzer auszulesen.'; -$lang['FilterLogin'] = 'SQL-Bedingung um Benutzer anhand ihres Anmeldenamens zu filtern.'; -$lang['FilterName'] = 'SQL-Bedingung um Benutzer anhand ihres Namens zu filtern.'; -$lang['FilterEmail'] = 'SQL-Bedingung um Benutzer anhand ihrer E-Mail-Adresse zu filtern.'; -$lang['FilterGroup'] = 'SQL-Bedingung um Benutzer anhand ihrer Gruppenzugehörigkeit zu filtern.'; -$lang['SortOrder'] = 'SQL-Bedingung um anhand der die Benutzerliste sortiert wird.'; -$lang['addUser'] = 'SQL-Kommando um einen neuen Benutzer anzulegen.'; -$lang['addGroup'] = 'SQL-Kommando um eine neue Gruppe anzulegen.'; -$lang['addUserGroup'] = 'SQL-Kommando um einen Benutzer zu einer Gruppe hinzuzufügen.'; -$lang['delGroup'] = 'SQL-Kommando um eine Gruppe zu löschen.'; -$lang['getUserID'] = 'SQL-Kommando um den Primärschlüssel des Benutzers auszulesen.'; -$lang['delUser'] = 'SQL-Kommando um einen Benutzer zu löschen.'; -$lang['delUserRefs'] = 'SQL-Kommando um einen Benutzer aus allen Gruppen zu entfernen.'; -$lang['updateUser'] = 'SQL-Kommando um das Profil eines Benutzers zu aktualisieren.'; -$lang['UpdateLogin'] = 'SQL-Bedingung um den Anmeldenamen eines Benutzers zu ändern.'; -$lang['UpdatePass'] = 'SQL-Bedingung um das Passwort eines Benutzers zu ändern.'; -$lang['UpdateEmail'] = 'SQL-Bedingung um die E-Mail-Adresse eines Benutzers zu ändern.'; -$lang['UpdateName'] = 'SQL-Bedingung um den Namen eines Benutzers zu ändern.'; -$lang['UpdateTarget'] = 'SQL-Bedingung zur eindeutigen Identifikation des Benutzers.'; -$lang['delUserGroup'] = 'SQL-Kommando um einen Benutzer aus einer angegeben Gruppe zu entfernen.'; -$lang['getGroupID'] = 'SQL-Kommando um den Primärschlüssel einer Gruppe auszulesen.'; diff --git a/lib/plugins/config/lang/de/lang.php b/lib/plugins/config/lang/de/lang.php index 063ee40ad..d72056236 100644 --- a/lib/plugins/config/lang/de/lang.php +++ b/lib/plugins/config/lang/de/lang.php @@ -17,58 +17,62 @@ * @author Paul Lachewsky <kaeptn.haddock@gmail.com> * @author Pierre Corell <info@joomla-praxis.de> * @author Matthias Schulte <dokuwiki@lupo49.de> + * @author Mateng Schimmerlos <mateng@firemail.de>) */ $lang['menu'] = 'Konfiguration'; -$lang['error'] = 'Die Einstellungen wurden wegen einer fehlerhaften Eingabe nicht gespeichert.<br /> Bitte überprüfen sie die rot umrandeten Eingaben und speichern Sie erneut.'; +$lang['error'] = 'Die Einstellungen wurden wegen einer fehlerhaften Eingabe nicht gespeichert. +<br />Bitte überprüfen sie die rot umrandeten Eingaben und speichern Sie erneut.'; $lang['updated'] = 'Einstellungen erfolgreich gespeichert.'; $lang['nochoice'] = '(keine Auswahlmöglichkeiten vorhanden)'; -$lang['locked'] = 'Die Konfigurationsdatei kann nicht geändert werden. Wenn dies unbeabsichtigt ist, <br />überprüfen Sie, ob die Dateiberechtigungen korrekt gesetzt sind.'; +$lang['locked'] = 'Die Konfigurationsdatei kann nicht geändert werden, wenn dies unbeabsichtigt ist + <br />überprüfen Sie, dass die Dateiberechtigungen korrekt gesetzt sind.'; $lang['danger'] = 'Vorsicht: Die Änderung dieser Option könnte Ihr Wiki und das Konfigurationsmenü unzugänglich machen.'; $lang['warning'] = 'Hinweis: Die Änderung dieser Option könnte unbeabsichtigtes Verhalten hervorrufen.'; $lang['security'] = 'Sicherheitswarnung: Die Änderung dieser Option könnte ein Sicherheitsrisiko darstellen.'; $lang['_configuration_manager'] = 'Konfiguration'; $lang['_header_dokuwiki'] = 'DokuWiki-Konfiguration'; $lang['_header_plugin'] = 'Plugin-Konfiguration'; -$lang['_header_template'] = 'Vorlagen'; -$lang['_header_undefined'] = 'Unbekannte Werte'; -$lang['_basic'] = 'Grundkonfiguration'; -$lang['_display'] = 'Darstellung'; -$lang['_authentication'] = 'Authentifizierung'; -$lang['_anti_spam'] = 'Anti-Spam'; -$lang['_editing'] = 'Bearbeitung'; -$lang['_links'] = 'Links'; -$lang['_media'] = 'Medien'; -$lang['_notifications'] = 'Benachrichtigungen'; -$lang['_syndication'] = 'Syndication (RSS)'; +$lang['_header_template'] = 'Template-Konfiguration'; +$lang['_header_undefined'] = 'Unbekannte Einstellungen'; +$lang['_basic'] = 'Grund-Konfiguration'; +$lang['_display'] = 'Anzeige-Konfiguration'; +$lang['_authentication'] = 'Authentifizierungs-Konfiguration'; +$lang['_anti_spam'] = 'Anti-Spam-Konfiguration'; +$lang['_editing'] = 'Bearbeitungs-Konfiguration'; +$lang['_links'] = 'Link-Konfiguration'; +$lang['_media'] = 'Medien-Konfiguration'; +$lang['_notifications'] = 'Benachrichtigungs-Konfiguration'; +$lang['_syndication'] = 'Syndication-Konfiguration (RSS)'; $lang['_advanced'] = 'Erweiterte Konfiguration'; -$lang['_network'] = 'Netzwerk'; -$lang['_plugin_sufix'] = ''; -$lang['_template_sufix'] = 'Vorlagen-Konfiguration'; +$lang['_network'] = 'Netzwerk-Konfiguration'; +$lang['_plugin_sufix'] = 'Plugin-Konfiguration'; +$lang['_template_sufix'] = 'Template-Konfiguration'; $lang['_msg_setting_undefined'] = 'Keine Konfigurationsmetadaten.'; $lang['_msg_setting_no_class'] = 'Keine Konfigurationsklasse.'; $lang['_msg_setting_no_default'] = 'Kein Standardwert.'; -$lang['fmode'] = 'Berechtigungen für neue Dateien'; -$lang['dmode'] = 'Berechtigungen für neue Verzeichnisse'; -$lang['lang'] = 'Sprache'; -$lang['basedir'] = 'Installationsverzeichnis'; -$lang['baseurl'] = 'Installationspfad (URL)'; -$lang['savedir'] = 'Speicherverzeichnis'; -$lang['cookiedir'] = 'Cookiepfad. Frei lassen, um den gleichen Pfad wie "baseurl" zu benutzen.'; -$lang['start'] = 'Startseitenname'; $lang['title'] = 'Titel des Wikis'; +$lang['start'] = 'Startseitenname'; +$lang['lang'] = 'Sprache'; $lang['template'] = 'Designvorlage (Template)'; $lang['tagline'] = 'Tag-Linie (nur, wenn vom Template unterstützt)'; $lang['sidebar'] = 'Name der Sidebar-Seite (nur, wenn vom Template unterstützt)), ein leeres Feld deaktiviert die Sidebar'; $lang['license'] = 'Unter welcher Lizenz sollen Ihre Inhalte veröffentlicht werden?'; -$lang['fullpath'] = 'Den kompletten Dateipfad im Footer anzeigen'; +$lang['savedir'] = 'Speicherverzeichnis'; +$lang['basedir'] = 'Installationsverzeichnis'; +$lang['baseurl'] = 'Installationspfad (URL)'; +$lang['cookiedir'] = 'Cookiepfad. Frei lassen, um den gleichen Pfad wie "baseurl" zu benutzen.'; +$lang['dmode'] = 'Rechte für neue Verzeichnisse'; +$lang['fmode'] = 'Rechte für neue Dateien'; +$lang['allowdebug'] = 'Debug-Ausgaben erlauben <b>Abschalten wenn nicht benötigt!</b>'; $lang['recent'] = 'Anzahl der Einträge in der Änderungsliste'; +$lang['recent_days'] = 'Wieviele letzte Änderungen sollen einsehbar bleiben? (Tage)'; $lang['breadcrumbs'] = 'Anzahl der Einträge im "Krümelpfad"'; $lang['youarehere'] = 'Hierarchische Pfadnavigation verwenden'; +$lang['fullpath'] = 'Den kompletten Dateipfad im Footer anzeigen'; $lang['typography'] = 'Typographische Ersetzungen'; -$lang['htmlok'] = 'HTML erlauben'; -$lang['phpok'] = 'PHP erlauben'; $lang['dformat'] = 'Datumsformat (Siehe PHP <a href="http://www.php.net/strftime">strftime</a> Funktion)'; $lang['signature'] = 'Signatur'; +$lang['showuseras'] = 'Was angezeigt werden soll, wenn der Benutzer, der zuletzt eine Seite bearbeitet hat, angezeigt wird'; $lang['toptoclevel'] = 'Inhaltsverzeichnis bei dieser Überschriftengröße beginnen'; $lang['tocminheads'] = 'Mindestanzahl der Überschriften die entscheidet, ob ein Inhaltsverzeichnis erscheinen soll'; $lang['maxtoclevel'] = 'Maximale Überschriftsgröße für Inhaltsverzeichnis'; @@ -76,16 +80,8 @@ $lang['maxseclevel'] = 'Abschnitte bis zu dieser Stufe einzeln editier $lang['camelcase'] = 'CamelCase-Verlinkungen verwenden'; $lang['deaccent'] = 'Seitennamen bereinigen'; $lang['useheading'] = 'Erste Überschrift als Seitennamen verwenden'; -$lang['refcheck'] = 'Auf Verwendung beim Löschen von Media-Dateien testen'; -$lang['refshow'] = 'Wiev iele Verwendungsorte der Media-Datei zeigen'; -$lang['allowdebug'] = 'Debug-Ausgaben erlauben <b>Abschalten wenn nicht benötigt!</b>'; -$lang['mediarevisions'] = 'Media-Revisionen (ältere Versionen) aktivieren?'; -$lang['usewordblock'] = 'Spam-Blocking benutzen'; -$lang['indexdelay'] = 'Zeit bevor Suchmaschinenindexierung erlaubt ist'; -$lang['relnofollow'] = 'rel="nofollow" verwenden'; -$lang['mailguard'] = 'E-Mail-Adressen schützen'; -$lang['iexssprotect'] = 'Hochgeladene Dateien auf bösartigen JavaScript- und HTML-Code untersuchen'; -$lang['showuseras'] = 'Was angezeigt werden soll, wenn der Benutzer, der zuletzt eine Seite bearbeitet hat, angezeigt wird'; +$lang['sneaky_index'] = 'Standardmäßig zeigt DokuWiki alle Namensräume in der Übersicht. Wenn diese Option aktiviert wird, werden alle Namensräume, für die der Benutzer keine Lese-Rechte hat, nicht angezeigt. Dies kann unter Umständen dazu führen, das lesbare Unter-Namensräume nicht angezeigt werden und macht die Übersicht evtl. unbrauchbar in Kombination mit bestimmten ACL Einstellungen.'; +$lang['hidepages'] = 'Seiten verstecken (Regulärer Ausdruck)'; $lang['useacl'] = 'Zugangskontrolle verwenden'; $lang['autopasswd'] = 'Passwort automatisch generieren'; $lang['authtype'] = 'Authentifizierungsmechanismus'; @@ -94,62 +90,69 @@ $lang['defaultgroup'] = 'Standardgruppe'; $lang['superuser'] = 'Administrator - Eine Gruppe oder Nutzer mit vollem Zugriff auf alle Seiten und Administrationswerkzeuge.'; $lang['manager'] = 'Manager - Eine Gruppe oder Nutzer mit Zugriff auf einige Administrationswerkzeuge.'; $lang['profileconfirm'] = 'Profiländerung nur nach Passwortbestätigung'; +$lang['rememberme'] = 'Permanente Login-Cookies erlauben (Auf diesem Computer eingeloggt bleiben)'; $lang['disableactions'] = 'DokuWiki-Aktionen deaktivieren'; $lang['disableactions_check'] = 'Check'; $lang['disableactions_subscription'] = 'Seiten-Abonnements'; $lang['disableactions_wikicode'] = 'Quelltext betrachten/exportieren'; $lang['disableactions_other'] = 'Andere Aktionen (durch Komma getrennt)'; -$lang['sneaky_index'] = 'Standardmäßig zeigt DokuWiki alle Namensräume in der Übersicht. Wenn diese Option aktiviert wird, werden alle Namensräume, für die der Benutzer keine Lese-Rechte hat, nicht angezeigt. Dies kann unter Umständen dazu führen, das lesbare Unter-Namensräume nicht angezeigt werden und macht die Übersicht evtl. unbrauchbar in Kombination mit bestimmten ACL Einstellungen.'; $lang['auth_security_timeout'] = 'Authentifikations-Timeout (Sekunden)'; $lang['securecookie'] = 'Sollen Cookies, die via HTTPS gesetzt wurden nur per HTTPS versendet werden? Deaktivieren Sie diese Option, wenn nur der Login Ihres Wikis mit SSL gesichert ist, aber das Betrachten des Wikis ungesichert geschieht.'; $lang['remote'] = 'Aktiviert den externen API-Zugang. Diese Option erlaubt es externen Anwendungen von außen auf die XML-RPC-Schnittstelle oder anderweitigen Schnittstellen zuzugreifen.'; $lang['remoteuser'] = 'Zugriff auf die externen Schnittstellen durch kommaseparierte Angabe von Benutzern oder Gruppen einschränken. Ein leeres Feld erlaubt Zugriff für jeden.'; -$lang['updatecheck'] = 'Automatisch auf Updates und Sicherheitswarnungen prüfen? DokuWiki muss sich dafür mit update.dokuwiki.org verbinden.'; -$lang['userewrite'] = 'URL rewriting'; -$lang['useslash'] = 'Schrägstrich (/) als Namensraumtrenner in URLs verwenden'; +$lang['usewordblock'] = 'Spam-Blocking benutzen'; +$lang['relnofollow'] = 'rel="nofollow" verwenden'; +$lang['indexdelay'] = 'Zeit bevor Suchmaschinenindexierung erlaubt ist'; +$lang['mailguard'] = 'E-Mail-Adressen schützen'; +$lang['iexssprotect'] = 'Hochgeladene Dateien auf bösartigen JavaScript- und HTML-Code untersuchen'; $lang['usedraft'] = 'Während des Bearbeitens automatisch Zwischenentwürfe speichern'; -$lang['sepchar'] = 'Worttrenner für Seitennamen in URLs'; -$lang['canonical'] = 'Immer Links mit vollständigen URLs erzeugen'; -$lang['fnencode'] = 'Methode um nicht-ASCII Dateinamen zu kodieren.'; -$lang['autoplural'] = 'Bei Links automatisch nach vorhandenen Pluralformen suchen'; -$lang['compression'] = 'Komprimierungsmethode für alte Seitenrevisionen'; -$lang['cachetime'] = 'Maximale Cachespeicherung (Sekunden)'; +$lang['htmlok'] = 'HTML erlauben'; +$lang['phpok'] = 'PHP erlauben'; $lang['locktime'] = 'Maximales Alter für Seitensperren (Sekunden)'; +$lang['cachetime'] = 'Maximale Cachespeicherung (Sekunden)'; +$lang['target____wiki'] = 'Zielfenster für interne Links (target Attribut)'; +$lang['target____interwiki'] = 'Zielfenster für InterWiki-Links (target Attribut)'; +$lang['target____extern'] = 'Zielfenster für Externe Links (target Attribut)'; +$lang['target____media'] = 'Zielfenster für (Bild-)Dateien (target Attribut)'; +$lang['target____windows'] = 'Zielfenster für Windows Freigaben (target Attribut)'; +$lang['mediarevisions'] = 'Media-Revisionen (ältere Versionen) aktivieren?'; +$lang['refcheck'] = 'Auf Verwendung beim Löschen von Media-Dateien testen'; +$lang['refshow'] = 'Wiev iele Verwendungsorte der Media-Datei zeigen'; +$lang['gdlib'] = 'GD Lib Version'; +$lang['im_convert'] = 'Pfad zu ImageMagicks-Konvertierwerkzeug'; +$lang['jpg_quality'] = 'JPEG Kompressionsqualität (0-100)'; $lang['fetchsize'] = 'Maximale Größe (in Bytes), die fetch.php von extern herunterladen darf'; +$lang['subscribers'] = 'E-Mail-Abos zulassen'; +$lang['subscribe_time'] = 'Zeit nach der Zusammenfassungs- und Änderungslisten-E-Mails verschickt werden; Dieser Wert sollte kleiner als die in recent_days konfigurierte Zeit sein.'; $lang['notify'] = 'Änderungsmitteilungen an diese E-Mail-Adresse versenden'; $lang['registernotify'] = 'Information über neu registrierte Nutzer an diese E-Mail-Adresse senden'; $lang['mailfrom'] = 'Absender-E-Mail-Adresse für automatische Mails'; $lang['mailprefix'] = 'Präfix für E-Mail-Betreff beim automatischen Versand von Benachrichtigungen'; $lang['htmlmail'] = 'Versendet optisch angenehmere, aber größere E-Mails im HTML-Format (multipart). Deaktivieren, um Text-Mails zu versenden.'; +$lang['sitemap'] = 'Google Sitemap erzeugen (Tage)'; +$lang['rss_type'] = 'XML-Feed-Format'; +$lang['rss_linkto'] = 'XML-Feed verlinken auf'; +$lang['rss_content'] = 'Welche Inhalte sollen im XML-Feed dargestellt werden?'; +$lang['rss_update'] = 'XML-Feed Aktualisierungsintervall (Sekunden)'; +$lang['rss_show_summary'] = 'Bearbeitungs-Zusammenfassung im XML-Feed anzeigen'; +$lang['rss_media'] = 'Welche Änderungen sollen im XML-Feed angezeigt werden?'; +$lang['updatecheck'] = 'Automatisch auf Updates und Sicherheitswarnungen prüfen? DokuWiki muss sich dafür mit update.dokuwiki.org verbinden.'; +$lang['userewrite'] = 'URL rewriting'; +$lang['useslash'] = 'Schrägstrich (/) als Namensraumtrenner in URLs verwenden'; +$lang['sepchar'] = 'Worttrenner für Seitennamen in URLs'; +$lang['canonical'] = 'Immer Links mit vollständigen URLs erzeugen'; +$lang['fnencode'] = 'Methode um nicht-ASCII Dateinamen zu kodieren.'; +$lang['autoplural'] = 'Bei Links automatisch nach vorhandenen Pluralformen suchen'; +$lang['compression'] = 'Komprimierungsmethode für alte Seitenrevisionen'; $lang['gzip_output'] = 'Seiten mit gzip komprimiert ausliefern'; -$lang['gdlib'] = 'GD Lib Version'; -$lang['im_convert'] = 'Pfad zu ImageMagicks-Konvertierwerkzeug'; -$lang['jpg_quality'] = 'JPEG Kompressionsqualität (0-100)'; -$lang['subscribers'] = 'E-Mail-Abos zulassen'; -$lang['subscribe_time'] = 'Zeit nach der Zusammenfassungs- und Änderungslisten-E-Mails verschickt werden; Dieser Wert sollte kleiner als die in recent_days konfigurierte Zeit sein.'; $lang['compress'] = 'JavaScript und Stylesheets komprimieren'; $lang['cssdatauri'] = 'Größe in Bytes, bis zu der Bilder in css-Dateien referenziert werden können, um HTTP-Anfragen zu minimieren. Diese Technik funktioniert nicht im IE 7 und älter! Empfohlene Einstellung: <code>400</code> to <code>600</code> Bytes. Setzen Sie die Einstellung auf <code>0</code> um die Funktion zu deaktivieren.'; -$lang['hidepages'] = 'Seiten verstecken (Regulärer Ausdruck)'; $lang['send404'] = 'Bei nicht vorhandenen Seiten mit 404 Fehlercode antworten'; -$lang['sitemap'] = 'Google Sitemap erzeugen (Tage)'; $lang['broken_iua'] = 'Falls die Funktion ignore_user_abort auf Ihrem System nicht funktioniert, könnte der Such-Index nicht funktionieren. IIS+PHP/CGI ist bekannt dafür. Siehe auch <a href="http://bugs.splitbrain.org/?do=details&task_id=852">Bug 852</a>.'; $lang['xsendfile'] = 'Den X-Sendfile-Header nutzen, um Dateien direkt vom Webserver ausliefern zu lassen? Ihr Webserver muss dies unterstützen!'; $lang['renderer_xhtml'] = 'Standard-Renderer für die normale (XHTML) Wiki-Ausgabe.'; $lang['renderer__core'] = '%s (DokuWiki Kern)'; $lang['renderer__plugin'] = '%s (Plugin)'; -$lang['rememberme'] = 'Permanente Login-Cookies erlauben (Auf diesem Computer eingeloggt bleiben)'; -$lang['rss_type'] = 'XML-Feed-Format'; -$lang['rss_linkto'] = 'XML-Feed verlinken auf'; -$lang['rss_content'] = 'Welche Inhalte sollen im XML-Feed dargestellt werden?'; -$lang['rss_update'] = 'XML-Feed Aktualisierungsintervall (Sekunden)'; -$lang['recent_days'] = 'Wieviele letzte Änderungen sollen einsehbar bleiben? (Tage)'; -$lang['rss_show_summary'] = 'Bearbeitungs-Zusammenfassung im XML-Feed anzeigen'; -$lang['rss_media'] = 'Welche Änderungen sollen im XML-Feed angezeigt werden?'; -$lang['target____wiki'] = 'Zielfenster für interne Links (target Attribut)'; -$lang['target____interwiki'] = 'Zielfenster für InterWiki-Links (target Attribut)'; -$lang['target____extern'] = 'Zielfenster für Externe Links (target Attribut)'; -$lang['target____media'] = 'Zielfenster für (Bild-)Dateien (target Attribut)'; -$lang['target____windows'] = 'Zielfenster für Windows Freigaben (target Attribut)'; $lang['dnslookups'] = 'DokuWiki löst die IP-Adressen von Benutzern zu deren Hostnamen auf. Wenn du einen langsamen, unbrauchbaren DNS-Server verwendest oder die Funktion nicht benötigst, dann sollte diese Option deaktivert sein.'; $lang['proxy____host'] = 'Proxy-Server'; $lang['proxy____port'] = 'Proxy-Port'; @@ -196,9 +199,9 @@ $lang['xsendfile_o_0'] = 'nicht benutzen'; $lang['xsendfile_o_1'] = 'Proprietärer lighttpd-Header (vor Release 1.5)'; $lang['xsendfile_o_2'] = 'Standard X-Sendfile-Header'; $lang['xsendfile_o_3'] = 'Proprietärer Nginx X-Accel-Redirect-Header'; -$lang['showuseras_o_loginname'] = 'Login-Name'; +$lang['showuseras_o_loginname'] = 'Loginname'; $lang['showuseras_o_username'] = 'Vollständiger Name des Benutzers'; -$lang['showuseras_o_email'] = 'E-Mail-Adresse des Benutzers (Beachte "mailguard"-Einstellung)'; +$lang['showuseras_o_email'] = 'E-Mail-Adresse des Benutzers (je nach Mailguard-Einstellung verschleiert)'; $lang['showuseras_o_email_link'] = 'E-Mail-Adresse des Benutzers als mailto:-Link'; $lang['useheading_o_0'] = 'Nie'; $lang['useheading_o_navigation'] = 'Nur Navigation'; diff --git a/lib/plugins/plugin/lang/de/lang.php b/lib/plugins/plugin/lang/de/lang.php index 9f26a2933..0c560537f 100644 --- a/lib/plugins/plugin/lang/de/lang.php +++ b/lib/plugins/plugin/lang/de/lang.php @@ -18,6 +18,7 @@ * @author Christian Wichmann <nospam@zone0.de> * @author Paul Lachewsky <kaeptn.haddock@gmail.com> * @author Pierre Corell <info@joomla-praxis.de> + * @author Mateng Schimmerlos <mateng@firemail.de>) */ $lang['menu'] = 'Plugins verwalten'; $lang['download'] = 'Neues Plugin herunterladen und installieren'; diff --git a/lib/plugins/popularity/lang/de/lang.php b/lib/plugins/popularity/lang/de/lang.php index 42bdc14d5..4c1ba1391 100644 --- a/lib/plugins/popularity/lang/de/lang.php +++ b/lib/plugins/popularity/lang/de/lang.php @@ -15,6 +15,7 @@ * @author Christian Wichmann <nospam@zone0.de> * @author Paul Lachewsky <kaeptn.haddock@gmail.com> * @author Pierre Corell <info@joomla-praxis.de> + * @author Mateng Schimmerlos <mateng@firemail.de>) */ $lang['name'] = 'Popularitäts-Feedback (Eventuell längere Ladezeit)'; $lang['submit'] = 'Daten senden'; diff --git a/lib/plugins/revert/lang/de/lang.php b/lib/plugins/revert/lang/de/lang.php index b430ce876..39acd3c37 100644 --- a/lib/plugins/revert/lang/de/lang.php +++ b/lib/plugins/revert/lang/de/lang.php @@ -16,6 +16,7 @@ * @author Christian Wichmann <nospam@zone0.de> * @author Paul Lachewsky <kaeptn.haddock@gmail.com> * @author Pierre Corell <info@joomla-praxis.de> + * @author Mateng Schimmerlos <mateng@firemail.de>) */ $lang['menu'] = 'Seiten wieder herstellen'; $lang['filter'] = 'Nach betroffenen Seiten suchen'; diff --git a/lib/plugins/usermanager/lang/de/lang.php b/lib/plugins/usermanager/lang/de/lang.php index 0dd90cc68..cfe528823 100644 --- a/lib/plugins/usermanager/lang/de/lang.php +++ b/lib/plugins/usermanager/lang/de/lang.php @@ -17,6 +17,7 @@ * @author Paul Lachewsky <kaeptn.haddock@gmail.com> * @author Pierre Corell <info@joomla-praxis.de> * @author Matthias Schulte <dokuwiki@lupo49.de> + * @author Mateng Schimmerlos <mateng@firemail.de>) */ $lang['menu'] = 'Benutzerverwaltung'; $lang['noauth'] = '(Authentifizierungssystem nicht verfügbar)'; -- cgit v1.2.3 From 4931ae526572ef290d7337eca9a37786c7108f59 Mon Sep 17 00:00:00 2001 From: Otto Vainio <otto@valjakko.net> Date: Mon, 15 Apr 2013 21:56:46 +0200 Subject: Finnish language update --- inc/lang/fi/lang.php | 3 +++ lib/plugins/authad/lang/fi/settings.php | 6 ++++++ lib/plugins/authldap/lang/fi/settings.php | 6 ++++++ lib/plugins/authmysql/lang/fi/settings.php | 6 ++++++ lib/plugins/authpgsql/lang/fi/settings.php | 6 ++++++ lib/plugins/config/lang/fi/lang.php | 6 ++++++ 6 files changed, 33 insertions(+) create mode 100644 lib/plugins/authad/lang/fi/settings.php create mode 100644 lib/plugins/authldap/lang/fi/settings.php create mode 100644 lib/plugins/authmysql/lang/fi/settings.php create mode 100644 lib/plugins/authpgsql/lang/fi/settings.php diff --git a/inc/lang/fi/lang.php b/inc/lang/fi/lang.php index 59e4dc6cb..b66558d26 100644 --- a/inc/lang/fi/lang.php +++ b/inc/lang/fi/lang.php @@ -287,6 +287,9 @@ $lang['i_pol1'] = 'Julkinen Wiki (luku kaikilla, kirjoitus ja tie $lang['i_pol2'] = 'Suljettu Wiki (luku, kirjoitus ja tiedostojen lähetys vain rekisteröityneillä käyttäjillä)'; $lang['i_retry'] = 'Yritä uudelleen'; $lang['i_license'] = 'Valitse lisenssi, jonka alle haluat sisältösi laittaa:'; +$lang['i_license_none'] = 'Älä näytä mitään lisenssitietoja'; +$lang['i_pop_field'] = 'Auta parantamaan DokuWikiä'; +$lang['i_pop_label'] = 'Lähetä kerran kuussa nimetöntä käyttäjätietoa DokuWikin kehittäjille'; $lang['recent_global'] = 'Seuraat tällä hetkellä muutoksia nimiavaruuden <b>%s</b> sisällä. Voit myös <a href="%s">katsoa muutoksia koko wikissä</a>'; $lang['years'] = '%d vuotta sitten'; $lang['months'] = '%d kuukautta sitten'; diff --git a/lib/plugins/authad/lang/fi/settings.php b/lib/plugins/authad/lang/fi/settings.php new file mode 100644 index 000000000..d3aa13e07 --- /dev/null +++ b/lib/plugins/authad/lang/fi/settings.php @@ -0,0 +1,6 @@ +<?php +/** + * Finnish language file + * + * @author Otto Vainio <otto@valjakko.net> + */ diff --git a/lib/plugins/authldap/lang/fi/settings.php b/lib/plugins/authldap/lang/fi/settings.php new file mode 100644 index 000000000..d3aa13e07 --- /dev/null +++ b/lib/plugins/authldap/lang/fi/settings.php @@ -0,0 +1,6 @@ +<?php +/** + * Finnish language file + * + * @author Otto Vainio <otto@valjakko.net> + */ diff --git a/lib/plugins/authmysql/lang/fi/settings.php b/lib/plugins/authmysql/lang/fi/settings.php new file mode 100644 index 000000000..d3aa13e07 --- /dev/null +++ b/lib/plugins/authmysql/lang/fi/settings.php @@ -0,0 +1,6 @@ +<?php +/** + * Finnish language file + * + * @author Otto Vainio <otto@valjakko.net> + */ diff --git a/lib/plugins/authpgsql/lang/fi/settings.php b/lib/plugins/authpgsql/lang/fi/settings.php new file mode 100644 index 000000000..d3aa13e07 --- /dev/null +++ b/lib/plugins/authpgsql/lang/fi/settings.php @@ -0,0 +1,6 @@ +<?php +/** + * Finnish language file + * + * @author Otto Vainio <otto@valjakko.net> + */ diff --git a/lib/plugins/config/lang/fi/lang.php b/lib/plugins/config/lang/fi/lang.php index f3c57d10e..990852f99 100644 --- a/lib/plugins/config/lang/fi/lang.php +++ b/lib/plugins/config/lang/fi/lang.php @@ -30,6 +30,7 @@ $lang['_editing'] = 'Sivumuokkauksen asetukset'; $lang['_links'] = 'Linkkien asetukset'; $lang['_media'] = 'Media-asetukset'; $lang['_notifications'] = 'Ilmoitus-asetukset'; +$lang['_syndication'] = 'Syöteasetukset'; $lang['_advanced'] = 'Lisäasetukset'; $lang['_network'] = 'Verkkoasetukset'; $lang['_plugin_sufix'] = 'liitännäisen asetukset'; @@ -85,6 +86,8 @@ $lang['disableactions_wikicode'] = 'Näytä lähdekoodi/Vie raakana'; $lang['disableactions_other'] = 'Muut toiminnot (pilkulla erotettuna)'; $lang['auth_security_timeout'] = 'Autentikoinnin aikakatkaisu (sekunteja)'; $lang['securecookie'] = 'Lähetetäänkö HTTPS:n kautta asetetut evästetiedot HTTPS-yhteydellä? Kytke pois, jos vain wikisi kirjautuminen on suojattu SSL:n avulla, mutta muuten wikiä käytetään ilman suojausta.'; +$lang['remote'] = 'Kytke "remote API" käyttöön. Tämä sallii muiden sovellusten päästä wikiin XML-RPC:n avulla'; +$lang['remoteuser'] = 'Salli "remote API" pääsy vain pilkulla erotetuille ryhmille tai käyttäjille tässä. Jätä tyhjäksi, jos haluat sallia käytön kaikille.'; $lang['usewordblock'] = 'Estä spam sanalistan avulla'; $lang['relnofollow'] = 'Käytä rel="nofollow" ulkoisille linkeille'; $lang['indexdelay'] = 'Aikaraja indeksoinnille (sek)'; @@ -113,12 +116,14 @@ $lang['notify'] = 'Lähetä muutosilmoitukset tähän osoitteesee $lang['registernotify'] = 'Lähetä ilmoitus uusista rekisteröitymisistä tähän osoitteeseen'; $lang['mailfrom'] = 'Sähköpostiosoite automaattisia postituksia varten'; $lang['mailprefix'] = 'Etuliite automaattisesti lähetettyihin dähköposteihin'; +$lang['htmlmail'] = 'Lähetä paremman näköisiä, mutta isompia HTML multipart sähköposteja. Ota pois päältä, jos haluat vain tekstimuotoisia posteja.'; $lang['sitemap'] = 'Luo Google sitemap (päiviä)'; $lang['rss_type'] = 'XML-syötteen tyyppi'; $lang['rss_linkto'] = 'XML-syöte kytkeytyy'; $lang['rss_content'] = 'Mitä XML-syöte näyttää?'; $lang['rss_update'] = 'XML-syötteen päivitystahti (sek)'; $lang['rss_show_summary'] = 'XML-syöte näyttää yhteenvedon otsikossa'; +$lang['rss_media'] = 'Millaiset muutokset pitäisi olla mukana XML-syötteessä.'; $lang['updatecheck'] = 'Tarkista päivityksiä ja turvavaroituksia? Tätä varten DokuWikin pitää ottaa yhteys update.dokuwiki.orgiin.'; $lang['userewrite'] = 'Käytä siivottuja URLeja'; $lang['useslash'] = 'Käytä kauttaviivaa nimiavaruuksien erottimena URL-osoitteissa'; @@ -137,6 +142,7 @@ $lang['xsendfile'] = 'Käytä X-Sendfile otsikkoa, kun web-palvelin $lang['renderer_xhtml'] = 'Renderöinti, jota käytetään wikin pääasialliseen (xhtml) tulostukseen'; $lang['renderer__core'] = '%s (dokuwiki core)'; $lang['renderer__plugin'] = '%s (liitännäinen)'; +$lang['dnslookups'] = 'DokuWiki tarkistaa sivun päivittäjän koneen IP-osoitteen isäntänimen. Kytke pois, jos käytät hidasta tai toimimatonta DNS-palvelinta, tai et halua tätä ominaisuutta.'; $lang['proxy____host'] = 'Proxy-palvelimen nimi'; $lang['proxy____port'] = 'Proxy portti'; $lang['proxy____user'] = 'Proxy käyttäjän nimi'; -- cgit v1.2.3 From 0fb6b47f24d6914847f97a98b1598e9af7dab99b Mon Sep 17 00:00:00 2001 From: Victor Westmann <victor.westmann@gmail.com> Date: Mon, 15 Apr 2013 21:59:37 +0200 Subject: Brazilian Portuguese language update --- lib/plugins/authmysql/lang/pt-br/settings.php | 11 +++++++++++ lib/plugins/authpgsql/lang/pt-br/settings.php | 6 ++++++ 2 files changed, 17 insertions(+) diff --git a/lib/plugins/authmysql/lang/pt-br/settings.php b/lib/plugins/authmysql/lang/pt-br/settings.php index c37690314..5febedd13 100644 --- a/lib/plugins/authmysql/lang/pt-br/settings.php +++ b/lib/plugins/authmysql/lang/pt-br/settings.php @@ -17,12 +17,23 @@ $lang['getUserInfo'] = 'Comando SQL para obter informações de usuár $lang['getGroups'] = 'Comando SQL para obter as credenciais de grupo de um usuário'; $lang['getUsers'] = 'Comando SQL para listar todos os usuários'; $lang['FilterLogin'] = 'Comando SQL para filtrar usuários pelo login'; +$lang['FilterName'] = 'Cláusula SQL para filtrar usuários por nome completo'; +$lang['FilterEmail'] = 'Cláusula SQL para filtrar usuários por endereço de email'; +$lang['FilterGroup'] = 'Cláusula SQL para filtrar usuários por membros de grupos'; +$lang['SortOrder'] = 'Cláusula SQL para ordenar usuários'; +$lang['addUser'] = 'Comando SQL para adicionar um novo usuário'; $lang['addGroup'] = 'Comando SQL para adicionar um novo grupo'; $lang['addUserGroup'] = 'Comando SQL para adicionar um usuário a um determinado grupo'; $lang['delGroup'] = 'Comando SQL para remover um grupo'; +$lang['getUserID'] = 'Comando SQL para obter a chave primária de um usuário'; $lang['delUser'] = 'Comando SQL para apagar um usuário'; $lang['delUserRefs'] = 'Comando SQL para apagar um usuário de todos os grupos'; $lang['updateUser'] = 'Comando SQL para atualizar perfil de usuário'; +$lang['UpdateLogin'] = 'Comando SQL para atualizar o login de um usuário'; +$lang['UpdatePass'] = 'Cláusula de atualização para atualizar senha de usuário'; +$lang['UpdateEmail'] = 'Cláusula de atualização para atualizar email do usuário'; +$lang['UpdateName'] = 'Cláusula de atualização para atualizar nome completo do usuário'; +$lang['UpdateTarget'] = 'Limitar cláusula para identificar usuário quando estiver atualizando'; $lang['delUserGroup'] = 'Comando SQL para remover um usuário de um grupo determinado'; $lang['getGroupID'] = 'Comando SQL para obter a chave primária de um grupo determinado'; $lang['debug_o_0'] = 'nenhum'; diff --git a/lib/plugins/authpgsql/lang/pt-br/settings.php b/lib/plugins/authpgsql/lang/pt-br/settings.php index fea309496..d91e9c8e5 100644 --- a/lib/plugins/authpgsql/lang/pt-br/settings.php +++ b/lib/plugins/authpgsql/lang/pt-br/settings.php @@ -10,6 +10,7 @@ $lang['user'] = 'Nome de usuário PostgreSQL'; $lang['password'] = 'Senha do usuário acima'; $lang['database'] = 'Base de dados para usar'; $lang['debug'] = 'Mostrar informações adicionais de depuração'; +$lang['forwardClearPass'] = 'Transmitir senhas de usuário como texto puro para comandos SQL abaixo, ao invés de usar a opção passcrypt'; $lang['checkPass'] = 'Comando SQL para verificar senhas'; $lang['getUserInfo'] = 'Comando SQL para obter informações do usuário'; $lang['getGroups'] = 'Comando SQL para obter as credenciais de um usuário de um determinado grupo'; @@ -27,5 +28,10 @@ $lang['getUserID'] = 'Comando SQL para obter chave primária de usu $lang['delUser'] = 'Comando SQL para apagar usuário'; $lang['delUserRefs'] = 'Comando SQL para remover um usuário de todos os grupos'; $lang['updateUser'] = 'Comando SQL para atualizar perfil de usuário'; +$lang['UpdateLogin'] = 'Atualizar cláusula para atualizar o login do usuário'; +$lang['UpdatePass'] = 'Atualizar cláusula para atualizar a senha do usuário'; +$lang['UpdateEmail'] = 'Atualizar cláusula para atualizar o endereço de email'; +$lang['UpdateName'] = 'Atualizar cláusula para atualizar o nome completo do usuário'; +$lang['UpdateTarget'] = 'Limitar cláusula para identificar quando um usuário estiver atualizando'; $lang['delUserGroup'] = 'Comando SQL para remover um usuário de um determinado grupo'; $lang['getGroupID'] = 'Comando SQL para obter a chave primária de um determinado grupo'; -- cgit v1.2.3 From a426a6cd90e703479b2f5a57d16b97d5ded495af Mon Sep 17 00:00:00 2001 From: Andreas Gohr <andi@splitbrain.org> Date: Fri, 19 Apr 2013 09:28:22 +0200 Subject: LDAP: do not bind anonymously if superuser is set FS#2607 --- lib/plugins/authldap/auth.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/plugins/authldap/auth.php b/lib/plugins/authldap/auth.php index 6e7bde1f0..b49aa4792 100644 --- a/lib/plugins/authldap/auth.php +++ b/lib/plugins/authldap/auth.php @@ -465,7 +465,13 @@ class auth_plugin_authldap extends DokuWiki_Auth_Plugin { if(defined('LDAP_OPT_NETWORK_TIMEOUT')) { ldap_set_option($this->con, LDAP_OPT_NETWORK_TIMEOUT, 1); } - $bound = @ldap_bind($this->con); + + if($this->getConf('binddn') && $this->getConf('bindpw')) { + $bound = @ldap_bind($this->con, $this->getConf('binddn'), $this->getConf('bindpw')); + $this->bound = 2; + } else { + $bound = @ldap_bind($this->con); + } if($bound) { break; } -- cgit v1.2.3 From c5270434ae13b347d8357f578d10543804b17a3a Mon Sep 17 00:00:00 2001 From: Andreas Gohr <andi@splitbrain.org> Date: Fri, 19 Apr 2013 09:35:02 +0200 Subject: browser-based logo resizing in install.php FS#2763 server side resizing now needs a security hash which we can' provide in the installer, yet. --- install.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/install.php b/install.php index 33f3406a3..53ef4a175 100644 --- a/install.php +++ b/install.php @@ -97,8 +97,8 @@ header('Content-Type: text/html; charset=utf-8'); </head> <body style=""> <h1 style="float:left"> - <img src="lib/exe/fetch.php?media=wiki:dokuwiki-128.png&w=64" - style="vertical-align: middle;" alt="" /> + <img src="lib/exe/fetch.php?media=wiki:dokuwiki-128.png" + style="vertical-align: middle;" alt="" height="64" width="64" /> <?php echo $lang['i_installer']?> </h1> <div style="float:right; margin: 1em;"> -- cgit v1.2.3 From 3002d731a466d09ce747cfbbe930444ee584f118 Mon Sep 17 00:00:00 2001 From: Andreas Gohr <andi@splitbrain.org> Date: Fri, 19 Apr 2013 10:25:36 +0200 Subject: adjusted authad language files for config option change --- lib/plugins/authad/auth.php | 4 ++-- lib/plugins/authad/lang/bg/settings.php | 4 ++-- lib/plugins/authad/lang/de-informal/settings.php | 4 ++-- lib/plugins/authad/lang/de/settings.php | 17 +++++++++++++++-- lib/plugins/authad/lang/en/settings.php | 4 ++-- lib/plugins/authad/lang/eo/settings.php | 4 ++-- lib/plugins/authad/lang/fr/settings.php | 4 ++-- lib/plugins/authad/lang/ko/settings.php | 4 ++-- lib/plugins/authad/lang/nl/settings.php | 4 ++-- lib/plugins/authad/lang/pt-br/settings.php | 2 +- lib/plugins/authad/lang/zh-tw/settings.php | 4 ++-- lib/plugins/authad/lang/zh/settings.php | 4 ++-- 12 files changed, 36 insertions(+), 23 deletions(-) diff --git a/lib/plugins/authad/auth.php b/lib/plugins/authad/auth.php index 6c49eafbb..f7f350c3f 100644 --- a/lib/plugins/authad/auth.php +++ b/lib/plugins/authad/auth.php @@ -21,8 +21,8 @@ require_once(DOKU_PLUGIN.'authad/adLDAP/adLDAP.php'); * * //optional: * $conf['plugin']['authad']['sso'] = 1; - * $conf['plugin']['authad']['ad_username'] = 'root'; - * $conf['plugin']['authad']['ad_password'] = 'pass'; + * $conf['plugin']['authad']['admin_username'] = 'root'; + * $conf['plugin']['authad']['admin_password'] = 'pass'; * $conf['plugin']['authad']['real_primarygroup'] = 1; * $conf['plugin']['authad']['use_ssl'] = 1; * $conf['plugin']['authad']['use_tls'] = 1; diff --git a/lib/plugins/authad/lang/bg/settings.php b/lib/plugins/authad/lang/bg/settings.php index d63331078..877810c4e 100644 --- a/lib/plugins/authad/lang/bg/settings.php +++ b/lib/plugins/authad/lang/bg/settings.php @@ -7,8 +7,8 @@ $lang['account_suffix'] = 'Наставка на акаунта Ви. Например <code>@някакъв.домейн.org</code>'; $lang['base_dn'] = 'Вашият основен DN. Например <code>DC=моят,DC=домейн,DC=org</code>'; $lang['domain_controllers'] = 'Domain controller списък, разделете сървърите със запетая. Например <code>сървър1.домейн.org,сървър2.домейн.org</code>'; -$lang['ad_username'] = 'Привилегирован Active Directory потребител с достъп до данните на останалите потребители. Не е задължително, но е необходимо за някои функционалности като изпращането на имейл за абонаменти.'; -$lang['ad_password'] = 'Паролата на горния потребител.'; +$lang['admin_username'] = 'Привилегирован Active Directory потребител с достъп до данните на останалите потребители. Не е задължително, но е необходимо за някои функционалности като изпращането на имейл за абонаменти.'; +$lang['admin_password'] = 'Паролата на горния потребител.'; $lang['sso'] = 'Да се ползва ли еднократно вписване чрез Kerberos или NTLM?'; $lang['real_primarygroup'] = 'Да се извлича ли истинската група вместо да се предполага "Domain Users" (по-бавно)'; $lang['use_ssl'] = 'Ползване на SSL свързаност? Не отбелязвайте TLS (по-долу) ако включите опцията.'; diff --git a/lib/plugins/authad/lang/de-informal/settings.php b/lib/plugins/authad/lang/de-informal/settings.php index f6ba679ff..4d0b93e5d 100644 --- a/lib/plugins/authad/lang/de-informal/settings.php +++ b/lib/plugins/authad/lang/de-informal/settings.php @@ -8,8 +8,8 @@ $lang['account_suffix'] = 'Dein Account-Suffix. Z.B. <code>@my.domain.org</code>'; $lang['base_dn'] = 'Dein Base-DN. Z.B. <code>DC=my,DC=domain,DC=org</code>'; $lang['domain_controllers'] = 'Eine Komma-separierte Liste von Domänen-Controllern. Z.B. <code>srv1.domain.org,srv2.domain.org</code>'; -$lang['ad_username'] = 'Ein privilegierter Active Directory-Benutzer mit Zugriff zu allen anderen Benutzerdaten. Optional, aber wird benötigt für Aktionen wie z. B. dass Senden von Benachrichtigungs-Mails.'; -$lang['ad_password'] = 'Das Passwort des obigen Benutzers.'; +$lang['admin_username'] = 'Ein privilegierter Active Directory-Benutzer mit Zugriff zu allen anderen Benutzerdaten. Optional, aber wird benötigt für Aktionen wie z. B. dass Senden von Benachrichtigungs-Mails.'; +$lang['admin_password'] = 'Das Passwort des obigen Benutzers.'; $lang['sso'] = 'Soll Single-Sign-On via Kerberos oder NTLM benutzt werden?'; $lang['real_primarygroup'] = 'Soll die echte primäre Gruppe aufgelöst werden anstelle der Annahme "Domain Users" (langsamer)'; $lang['use_ssl'] = 'SSL-Verbindung benutzen? Falls ja, TLS unterhalb nicht aktivieren.'; diff --git a/lib/plugins/authad/lang/de/settings.php b/lib/plugins/authad/lang/de/settings.php index a1a99b6d6..acfa7e574 100644 --- a/lib/plugins/authad/lang/de/settings.php +++ b/lib/plugins/authad/lang/de/settings.php @@ -1,6 +1,19 @@ <?php /** - * German language file + * German (informal) language file * - * @author Mateng Schimmerlos <mateng@firemail.de>) + * @author Frank Loizzi <contact@software.bacal.de> + * @author Matthias Schulte <dokuwiki@lupo49.de> */ +$lang['account_suffix'] = 'Ihr Account-Suffix. Z.B. <code>@my.domain.org</code>'; +$lang['base_dn'] = 'Ihr Base-DN. z.B. <code>DC=my,DC=domain,DC=org</code>'; +$lang['domain_controllers'] = 'Eine Komma-separierte Liste von Domänen-Controllern. Z.B. <code>srv1.domain.org,srv2.domain.org</code>'; +$lang['admin_username'] = 'Ein privilegierter Active Directory-Benutzer mit Zugriff zu allen anderen Benutzerdaten. Optional, aber wird benötigt für Aktionen wie z. B. dass Senden von Benachrichtigungs-Mails.'; +$lang['admin_password'] = 'Das Passwort des obigen Benutzers.'; +$lang['sso'] = 'Soll Single-Sign-On via Kerberos oder NTLM benutzt werden?'; +$lang['real_primarygroup'] = 'Soll die echte primäre Gruppe aufgelöst werden anstelle der Annahme "Domain Users" (langsamer)'; +$lang['use_ssl'] = 'SSL-Verbindung benutzen? Falls ja, TLS unterhalb nicht aktivieren.'; +$lang['use_tls'] = 'TLS-Verbindung benutzen? Falls ja, SSL oberhalb nicht aktivieren.'; +$lang['debug'] = 'Zusätzliche Debug-Informationen bei Fehlern anzeigen?'; +$lang['expirywarn'] = 'Tage im Voraus um Benutzer über ablaufende Passwörter zu informieren. 0 zum Ausschalten.'; +$lang['additional'] = 'Eine Komma-separierte Liste von zusätzlichen AD-Attributen, die von den Benutzerobjekten abgefragt werden. Wird von einigen Plugins benutzt.'; diff --git a/lib/plugins/authad/lang/en/settings.php b/lib/plugins/authad/lang/en/settings.php index 7728d5ac4..aff49550b 100644 --- a/lib/plugins/authad/lang/en/settings.php +++ b/lib/plugins/authad/lang/en/settings.php @@ -3,8 +3,8 @@ $lang['account_suffix'] = 'Your account suffix. Eg. <code>@my.domain.org</code>'; $lang['base_dn'] = 'Your base DN. Eg. <code>DC=my,DC=domain,DC=org</code>'; $lang['domain_controllers'] = 'A comma separated list of Domain controllers. Eg. <code>srv1.domain.org,srv2.domain.org</code>'; -$lang['admin_username'] = 'A privileged Active Directory user with access to all other user\'s data. Optional, but needed for certain actions like sending subscription mails.'; -$lang['admin_password'] = 'The password of the above user.'; +$lang['admin_username'] = 'A privileged Active Directory user with access to all other user\'s data. Optional, but needed for certain actions like sending subscription mails.'; +$lang['admin_password'] = 'The password of the above user.'; $lang['sso'] = 'Should Single-Sign-On via Kerberos or NTLM be used?'; $lang['real_primarygroup'] = 'Should the real primary group be resolved instead of assuming "Domain Users" (slower)'; $lang['use_ssl'] = 'Use SSL connection? If used, do not enable TLS below.'; diff --git a/lib/plugins/authad/lang/eo/settings.php b/lib/plugins/authad/lang/eo/settings.php index 85a6abd98..8bd34b439 100644 --- a/lib/plugins/authad/lang/eo/settings.php +++ b/lib/plugins/authad/lang/eo/settings.php @@ -6,8 +6,8 @@ $lang['account_suffix'] = 'Via konto-aldonaĵo, ekz. <code>@mia.domajno.lando</code>'; $lang['base_dn'] = 'Via baza DN, ekz. <code>DC=mia,DC=domajno,DC=lando</code>'; $lang['domain_controllers'] = 'Komodisigita listo de domajno-serviloj, ekz. <code>srv1.domajno.lando,srv2.domajno.lando</code>'; -$lang['ad_username'] = 'Privilegiita Aktiv-Dosieruja uzanto kun aliro al ĉiuj uzantaj datumoj. Libervole, sed necesa por iuj agadoj kiel sendi abonan retpoŝton.'; -$lang['ad_password'] = 'La pasvorto de tiu uzanto.'; +$lang['admin_username'] = 'Privilegiita Aktiv-Dosieruja uzanto kun aliro al ĉiuj uzantaj datumoj. Libervole, sed necesa por iuj agadoj kiel sendi abonan retpoŝton.'; +$lang['admin_password'] = 'La pasvorto de tiu uzanto.'; $lang['sso'] = 'Ĉu uzi Sola Aliro tra Kerberos aŭ NTLM?'; $lang['real_primarygroup'] = 'Ĉu trovi la veran ĉefan grupon anstataŭ supozi "Domajnuzantoj" (pli malrapida)?'; $lang['use_ssl'] = 'Ĉu uzi SSL-konekton? Se jes, ne aktivigu TLS sube.'; diff --git a/lib/plugins/authad/lang/fr/settings.php b/lib/plugins/authad/lang/fr/settings.php index efbca89f9..5480a3d44 100644 --- a/lib/plugins/authad/lang/fr/settings.php +++ b/lib/plugins/authad/lang/fr/settings.php @@ -7,8 +7,8 @@ $lang['account_suffix'] = 'Le suffixe de votre compte. Ex.: <code>@mon.domaine.org</code>'; $lang['base_dn'] = 'Votre nom de domaine de base. <code>DC=mon,DC=domaine,DC=org</code>'; $lang['domain_controllers'] = 'Une liste de contrôleurs de domaine séparés par des virgules. Ex.: <code>srv1.domaine.org,srv2.domaine.org</code>'; -$lang['ad_username'] = 'Un utilisateur Active Directory avec accès aux données de tous les autres utilisateurs. Facultatif, mais nécessaire pour certaines actions telles que l\'envoi de courriels d\'abonnement.'; -$lang['ad_password'] = 'Le mot de passe de l\'utilisateur ci-dessus.'; +$lang['admin_username'] = 'Un utilisateur Active Directory avec accès aux données de tous les autres utilisateurs. Facultatif, mais nécessaire pour certaines actions telles que l\'envoi de courriels d\'abonnement.'; +$lang['admin_password'] = 'Le mot de passe de l\'utilisateur ci-dessus.'; $lang['sso'] = 'Est-ce que la connexion unique (Single-Sign-On) par Kerberos ou NTLM doit être utilisée?'; $lang['real_primarygroup'] = 'Est-ce que le véritable groupe principal doit être résolu au lieu de présumer "Domain Users" (plus lent)?'; $lang['use_ssl'] = 'Utiliser une connexion SSL? Si utilisée, n\'activez pas TLS ci-dessous.'; diff --git a/lib/plugins/authad/lang/ko/settings.php b/lib/plugins/authad/lang/ko/settings.php index 6134bd657..f2bf52681 100644 --- a/lib/plugins/authad/lang/ko/settings.php +++ b/lib/plugins/authad/lang/ko/settings.php @@ -7,8 +7,8 @@ $lang['account_suffix'] = '계정 접미어. 예를 들어 <code>@my.domain.org</code>'; $lang['base_dn'] = '기본 DN. 예를 들어 <code>DC=my,DC=domain,DC=org</code>'; $lang['domain_controllers'] = '도메인 컨트롤러의 쉼표로 구분한 목록. 예를 들어 <code>srv1.domain.org,srv2.domain.org</code>'; -$lang['ad_username'] = '다른 모든 사용자의 데이터에 접근할 수 있는 권한이 있는 Active Directory 사용자. 선택적이지만 구독 메일을 보내는 등의 특정 작업에 필요합니다.'; -$lang['ad_password'] = '위 사용자의 비밀번호.'; +$lang['admin_username'] = '다른 모든 사용자의 데이터에 접근할 수 있는 권한이 있는 Active Directory 사용자. 선택적이지만 구독 메일을 보내는 등의 특정 작업에 필요합니다.'; +$lang['admin_password'] = '위 사용자의 비밀번호.'; $lang['sso'] = 'Kerberos나 NTLM을 통해 Single-Sign-On을 사용해야 합니까?'; $lang['real_primarygroup'] = '실제 기본 그룹은 "도메인 사용자"를 가정하는 대신 해결될 것입니다 (느림)'; $lang['use_ssl'] = 'SSL 연결을 사용합니까? 사용한다면 아래 TLS을 활성화하지 마세요.'; diff --git a/lib/plugins/authad/lang/nl/settings.php b/lib/plugins/authad/lang/nl/settings.php index e73cac75d..933566d18 100644 --- a/lib/plugins/authad/lang/nl/settings.php +++ b/lib/plugins/authad/lang/nl/settings.php @@ -6,8 +6,8 @@ $lang['account_suffix'] = 'Je account domeinnaam. Bijv <code>@mijn.domein.org</code>'; $lang['base_dn'] = 'Je basis DN. Bijv. <code>DC=mijn,DC=domein,DC=org</code>'; $lang['domain_controllers'] = 'Eeen commagesepareerde lijst van domeinservers. Bijv. <code>srv1.domein.org,srv2.domein.org</code>'; -$lang['ad_username'] = 'Een geprivilegeerde Active Directory gebruiker die bij alle gebruikersgegevens kan komen. Optioneel, maar kan nodig zijn voor bepaalde acties, zoals het versturen van abonnementsmailtjes.'; -$lang['ad_password'] = 'Het wachtwoord van bovernvermelde gebruiker.'; +$lang['admin_username'] = 'Een geprivilegeerde Active Directory gebruiker die bij alle gebruikersgegevens kan komen. Optioneel, maar kan nodig zijn voor bepaalde acties, zoals het versturen van abonnementsmailtjes.'; +$lang['admin_password'] = 'Het wachtwoord van bovernvermelde gebruiker.'; $lang['sso'] = 'Wordt voor Single-Sign-on Kerberos of NTLM gebruikt?'; $lang['real_primarygroup'] = 'Moet de echte primaire groep worden opgezocht in plaats van het aannemen van "Domeingebruikers" (langzamer)'; $lang['use_ssl'] = 'SSL verbinding gebruiken? Zo ja, gebruik dan TLS hieronder niet.'; diff --git a/lib/plugins/authad/lang/pt-br/settings.php b/lib/plugins/authad/lang/pt-br/settings.php index b8b1efd42..29f8db4ad 100644 --- a/lib/plugins/authad/lang/pt-br/settings.php +++ b/lib/plugins/authad/lang/pt-br/settings.php @@ -7,7 +7,7 @@ $lang['account_suffix'] = 'Sufixo de sua conta. Eg. <code>@meu.domínio.org</code>'; $lang['base_dn'] = 'Sua base DN. Eg. <code>DC=meu,DC=domínio,DC=org</code>'; $lang['domain_controllers'] = 'Uma lista de controles de domínios separada por vírgulas. Eg. <code>srv1.domínio.org,srv2.domínio.org</code>'; -$lang['ad_password'] = 'A senha do usuário acima.'; +$lang['admin_password'] = 'A senha do usuário acima.'; $lang['sso'] = 'Usar Single-Sign-On através do Kerberos ou NTLM?'; $lang['use_ssl'] = 'Usar conexão SSL? Se usar, não habilitar TLS abaixo.'; $lang['use_tls'] = 'Usar conexão TLS? se usar, não habilitar SSL acima.'; diff --git a/lib/plugins/authad/lang/zh-tw/settings.php b/lib/plugins/authad/lang/zh-tw/settings.php index e38a2c007..c46e5f96f 100644 --- a/lib/plugins/authad/lang/zh-tw/settings.php +++ b/lib/plugins/authad/lang/zh-tw/settings.php @@ -7,8 +7,8 @@ $lang['account_suffix'] = '您的帳號後綴。如: <code>@my.domain.org</code>'; $lang['base_dn'] = '您的基本識別名。如: <code>DC=my,DC=domain,DC=org</code>'; $lang['domain_controllers'] = '以逗號分隔的域名控制器列表。如: <code>srv1.domain.org,srv2.domain.org</code>'; -$lang['ad_username'] = 'Active Directory 的特權使用者,可以查看所有使用者的數據。(非必要,但對發送訂閱郵件等活動來說,這是必須的。)'; -$lang['ad_password'] = '上述使用者的密碼。'; +$lang['admin_username'] = 'Active Directory 的特權使用者,可以查看所有使用者的數據。(非必要,但對發送訂閱郵件等活動來說,這是必須的。)'; +$lang['admin_password'] = '上述使用者的密碼。'; $lang['sso'] = '是否使用 Kerberos 或 NTLM 的單一登入系統 (Single-Sign-On)?'; $lang['real_primarygroup'] = '是否視作真正的主要群組,而不是假設為網域使用者 (比較慢)'; $lang['use_ssl'] = '使用 SSL 連接嗎?如果要使用,請不要啟用下方的 TLS。'; diff --git a/lib/plugins/authad/lang/zh/settings.php b/lib/plugins/authad/lang/zh/settings.php index 9fd3c4e35..0ad8d4e4f 100644 --- a/lib/plugins/authad/lang/zh/settings.php +++ b/lib/plugins/authad/lang/zh/settings.php @@ -7,8 +7,8 @@ $lang['account_suffix'] = '您的账户后缀。例如 <code>@my.domain.org</code>'; $lang['base_dn'] = '您的基本分辨名。例如 <code>DC=my,DC=domain,DC=org</code>'; $lang['domain_controllers'] = '逗号分隔的域名控制器列表。例如 <code>srv1.domain.org,srv2.domain.org</code>'; -$lang['ad_username'] = '一个活动目录的特权用户,可以查看其他所有用户的数据。可选,但对某些活动例如发送订阅邮件是必须的。'; -$lang['ad_password'] = '上述用户的密码。'; +$lang['admin_username'] = '一个活动目录的特权用户,可以查看其他所有用户的数据。可选,但对某些活动例如发送订阅邮件是必须的。'; +$lang['admin_password'] = '上述用户的密码。'; $lang['sso'] = '是否使用经由 Kerberos 和 NTLM 的 Single-Sign-On?'; $lang['real_primarygroup'] = ' 是否解析真实的主要组,而不是假设为“域用户” (较慢)'; $lang['use_ssl'] = '使用 SSL 连接?如果是,不要激活下面的 TLS。'; -- cgit v1.2.3 From 2d3f0c1657bcc4c97b1629fae08661213d973d56 Mon Sep 17 00:00:00 2001 From: Andreas Gohr <andi@splitbrain.org> Date: Fri, 19 Apr 2013 11:42:41 +0200 Subject: strip specials from file name in codeblock downloads FS#2757 --- inc/parser/code.php | 1 + 1 file changed, 1 insertion(+) diff --git a/inc/parser/code.php b/inc/parser/code.php index 43d8d703f..6e159b041 100644 --- a/inc/parser/code.php +++ b/inc/parser/code.php @@ -20,6 +20,7 @@ class Doku_Renderer_code extends Doku_Renderer { if(!$language) $language = 'txt'; if(!$filename) $filename = 'snippet.'.$language; $filename = utf8_basename($filename); + $filename = utf8_stripspecials($filename, '_'); if($this->_codeblock == $INPUT->str('codeblock')){ header("Content-Type: text/plain; charset=utf-8"); -- cgit v1.2.3 From 8e06db6889203ff5a40f4f121ba46c898564f628 Mon Sep 17 00:00:00 2001 From: Andreas Gohr <andi@splitbrain.org> Date: Fri, 19 Apr 2013 11:48:56 +0200 Subject: removed Satisfy All directive FS#2750 --- .htaccess.dist | 1 - conf/.htaccess | 1 - data/.htaccess | 1 - inc/.htaccess | 1 - inc/lang/.htaccess | 1 - 5 files changed, 5 deletions(-) diff --git a/.htaccess.dist b/.htaccess.dist index c90abdc80..5724a6e04 100644 --- a/.htaccess.dist +++ b/.htaccess.dist @@ -8,7 +8,6 @@ <Files ~ "^([\._]ht|README$|VERSION$|COPYING$)"> Order allow,deny Deny from all - Satisfy All </Files> ## Uncomment these rules if you want to have nice URLs using diff --git a/conf/.htaccess b/conf/.htaccess index f5dda6086..bcc3ea0bd 100644 --- a/conf/.htaccess +++ b/conf/.htaccess @@ -1,4 +1,3 @@ ## no access to the conf directory order allow,deny deny from all -Satisfy All diff --git a/data/.htaccess b/data/.htaccess index 2cbb757e7..281d5c33d 100644 --- a/data/.htaccess +++ b/data/.htaccess @@ -1,3 +1,2 @@ order allow,deny deny from all -Satisfy All diff --git a/inc/.htaccess b/inc/.htaccess index 68ae43e72..2d9c357ff 100644 --- a/inc/.htaccess +++ b/inc/.htaccess @@ -1,4 +1,3 @@ ## no access to the inc directory order allow,deny deny from all -Satisfy All diff --git a/inc/lang/.htaccess b/inc/lang/.htaccess index 572f5156f..2d69be754 100644 --- a/inc/lang/.htaccess +++ b/inc/lang/.htaccess @@ -1,4 +1,3 @@ ## no access to the lang directory order allow,deny deny from all -Satisfy All -- cgit v1.2.3 From bba10e63fd89accbcf180b64adbd26e32ffb1810 Mon Sep 17 00:00:00 2001 From: lupo49 <dokuwiki@lupo49.de> Date: Sun, 21 Apr 2013 21:24:28 +0200 Subject: Revert "German language update" This reverts commit ba09710ad34bb383ae3526e84490a3d545f78866. Conflicts: lib/plugins/authad/lang/de/settings.php --- inc/lang/de/lang.php | 4 - lib/plugins/acl/lang/de/lang.php | 1 - lib/plugins/authad/lang/de/settings.php | 10 +- lib/plugins/authldap/lang/de/settings.php | 18 +++- lib/plugins/authmysql/lang/de/settings.php | 38 +++++++- lib/plugins/authpgsql/lang/de/settings.php | 34 ++++++- lib/plugins/config/lang/de/lang.php | 141 ++++++++++++++--------------- lib/plugins/plugin/lang/de/lang.php | 1 - lib/plugins/popularity/lang/de/lang.php | 1 - lib/plugins/revert/lang/de/lang.php | 1 - lib/plugins/usermanager/lang/de/lang.php | 1 - 11 files changed, 161 insertions(+), 89 deletions(-) diff --git a/inc/lang/de/lang.php b/inc/lang/de/lang.php index 1a9cb7d90..160ea53e8 100644 --- a/inc/lang/de/lang.php +++ b/inc/lang/de/lang.php @@ -21,7 +21,6 @@ * @author Matthias Schulte <mailinglist@lupo49.de> * @author Paul Lachewsky <kaeptn.haddock@gmail.com> * @author Pierre Corell <info@joomla-praxis.de> - * @author Mateng Schimmerlos <mateng@firemail.de>) */ $lang['encoding'] = 'utf-8'; $lang['direction'] = 'ltr'; @@ -299,9 +298,6 @@ $lang['i_pol1'] = 'Öffentliches Wiki (Lesen für alle, Schreiben $lang['i_pol2'] = 'Geschlossenes Wiki (Lesen, Schreiben und Hochladen nur für registrierte Nutzer)'; $lang['i_retry'] = 'Wiederholen'; $lang['i_license'] = 'Bitte wählen Sie die Lizenz, unter die Sie Ihre Inhalte stellen möchten:'; -$lang['i_license_none'] = 'Lizensierungsinformation nicht anzeigen'; -$lang['i_pop_field'] = 'Bitte Helfen Sie mit, DokuWiki zu verbessern:'; -$lang['i_pop_label'] = 'Einmal monatlich anonymisierte Nutzungsdaten an das DokuWiki-Entwicklerteam senden'; $lang['recent_global'] = 'Im Moment sehen Sie die Änderungen im Namensraum <b>%s</b>. Sie können auch <a href="%s">die Änderungen im gesamten Wiki sehen</a>.'; $lang['years'] = 'vor %d Jahren'; $lang['months'] = 'vor %d Monaten'; diff --git a/lib/plugins/acl/lang/de/lang.php b/lib/plugins/acl/lang/de/lang.php index e2ac98cd7..eb23636c4 100644 --- a/lib/plugins/acl/lang/de/lang.php +++ b/lib/plugins/acl/lang/de/lang.php @@ -21,7 +21,6 @@ * @author Christian Wichmann <nospam@zone0.de> * @author Paul Lachewsky <kaeptn.haddock@gmail.com> * @author Pierre Corell <info@joomla-praxis.de> - * @author Mateng Schimmerlos <mateng@firemail.de>) */ $lang['admin_acl'] = 'Zugangsverwaltung'; $lang['acl_group'] = 'Gruppe'; diff --git a/lib/plugins/authad/lang/de/settings.php b/lib/plugins/authad/lang/de/settings.php index acfa7e574..650f9f362 100644 --- a/lib/plugins/authad/lang/de/settings.php +++ b/lib/plugins/authad/lang/de/settings.php @@ -5,11 +5,11 @@ * @author Frank Loizzi <contact@software.bacal.de> * @author Matthias Schulte <dokuwiki@lupo49.de> */ -$lang['account_suffix'] = 'Ihr Account-Suffix. Z.B. <code>@my.domain.org</code>'; -$lang['base_dn'] = 'Ihr Base-DN. z.B. <code>DC=my,DC=domain,DC=org</code>'; -$lang['domain_controllers'] = 'Eine Komma-separierte Liste von Domänen-Controllern. Z.B. <code>srv1.domain.org,srv2.domain.org</code>'; -$lang['admin_username'] = 'Ein privilegierter Active Directory-Benutzer mit Zugriff zu allen anderen Benutzerdaten. Optional, aber wird benötigt für Aktionen wie z. B. dass Senden von Benachrichtigungs-Mails.'; -$lang['admin_password'] = 'Das Passwort des obigen Benutzers.'; +$lang['account_suffix'] = 'Ihr Account-Suffix. Z. B. <code>@my.domain.org</code>'; +$lang['base_dn'] = 'Ihr Base-DN. Z. B. <code>DC=my,DC=domain,DC=org</code>'; +$lang['domain_controllers'] = 'Eine Komma-separierte Liste von Domänen-Controllern. Z. B. <code>srv1.domain.org,srv2.domain.org</code>'; +$lang['ad_username'] = 'Ein priviligierter Active Directory-Benutzer mit Zugriff zu allen anderen Benutzerdaten. Optional, aber wird benötigt für Aktionen wie z. B. dass Senden von Benachrichtigungs-Mails.'; +$lang['ad_password'] = 'Das Passwort des obigen Benutzers.'; $lang['sso'] = 'Soll Single-Sign-On via Kerberos oder NTLM benutzt werden?'; $lang['real_primarygroup'] = 'Soll die echte primäre Gruppe aufgelöst werden anstelle der Annahme "Domain Users" (langsamer)'; $lang['use_ssl'] = 'SSL-Verbindung benutzen? Falls ja, TLS unterhalb nicht aktivieren.'; diff --git a/lib/plugins/authldap/lang/de/settings.php b/lib/plugins/authldap/lang/de/settings.php index a1a99b6d6..b237201d8 100644 --- a/lib/plugins/authldap/lang/de/settings.php +++ b/lib/plugins/authldap/lang/de/settings.php @@ -2,5 +2,21 @@ /** * German language file * - * @author Mateng Schimmerlos <mateng@firemail.de>) + * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) + * @author Matthias Schulte <dokuwiki@lupo49.de> */ +$lang['server'] = 'Adresse zum LDAP-Server. Entweder als Hostname (<code>localhost</code>) oder als FQDN (<code>ldap://server.tld:389</code>).'; +$lang['port'] = 'Port des LDAP-Servers, falls kein Port angegeben wurde.'; +$lang['usertree'] = 'Zweig, in dem die die Benutzeraccounts gespeichert sind. Zum Beispiel: <code>ou=People, dc=server, dc=tld</code>.'; +$lang['grouptree'] = 'Zweig, in dem die Benutzergruppen gespeichert sind. Zum Beispiel: <code>ou=Group, dc=server, dc=tld</code>.'; +$lang['userfilter'] = 'LDAP-Filter, um die Benutzeraccounts zu suchen. Zum Beispiel: <code>(&(uid=%{user})(objectClass=posixAccount))</code>.'; +$lang['groupfilter'] = 'LDAP-Filter, um die Benutzergruppen zu suchen. Zum Beispiel: <code>(&(objectClass=posixGroup)(|(gidNumber=%{gid})(memberUID=%{user})))</code>.'; +$lang['version'] = 'Zu verwendende Protokollversion von LDAP.'; +$lang['starttls'] = 'Verbindung über TLS aufbauen?'; +$lang['referrals'] = 'Weiterverfolgen von LDAP-Referrals (Verweise)?'; +$lang['binddn'] = 'DN eines optionalen Benutzers, wenn der anonyme Zugriff nicht ausreichend ist. Zum Beispiel: <code>cn=admin, dc=my, dc=home</code>.'; +$lang['bindpw'] = 'Passwort des angegebenen Benutzers.'; +$lang['userscope'] = 'Die Suchweite nach Benutzeraccounts.'; +$lang['groupscope'] = 'Die Suchweite nach Benutzergruppen.'; +$lang['groupkey'] = 'Gruppieren der Benutzeraccounts anhand eines beliebigen Benutzerattributes z. B. Telefonnummer oder Abteilung, anstelle der Standard-Gruppen).'; +$lang['debug'] = 'Debug-Informationen beim Auftreten von Fehlern anzeigen?'; diff --git a/lib/plugins/authmysql/lang/de/settings.php b/lib/plugins/authmysql/lang/de/settings.php index a1a99b6d6..97ba06a9d 100644 --- a/lib/plugins/authmysql/lang/de/settings.php +++ b/lib/plugins/authmysql/lang/de/settings.php @@ -2,5 +2,41 @@ /** * German language file * - * @author Mateng Schimmerlos <mateng@firemail.de>) + * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) + * @author Matthias Schulte <dokuwiki@lupo49.de> */ +$lang['server'] = 'MySQL-Server'; +$lang['user'] = 'Benutzername für den Zugriff auf den MySQL-Server.'; +$lang['password'] = 'Passwort des angegebenen Benutzers.'; +$lang['database'] = 'Zu verwendende Datenbank.'; +$lang['charset'] = 'Verwendetes Character-Set in der Datenbank.'; +$lang['debug'] = 'Debug-Informationen anzeigen?'; +$lang['forwardClearPass'] = 'Passwort der DokuWiki-Benutzer im Klartext an die Datenbank übergeben? (Im Normalfall wird die passcrypt-Option angewendet.)'; +$lang['TablesToLock'] = 'Eine Komma-separierte Liste von Tabellen, die vor Schreiboperationen gesperrt werden müssen.'; +$lang['checkPass'] = 'SQL-Kommando zum Überprüfen von Passwörtern.'; +$lang['getUserInfo'] = 'SQL-Kommando um Benutzerinformationen auszulesen.'; +$lang['getGroups'] = 'SQL-Kommando um Gruppen eines Benutzers auszulesen.'; +$lang['getUsers'] = 'SQL-Kommando um alle Benutzer auszulesen.'; +$lang['FilterLogin'] = 'SQL-Bedingung um Benutzer anhand ihres Anmeldenamens zu filtern.'; +$lang['FilterName'] = 'SQL-Bedingung um Benutzer anhand ihres Namens zu filtern.'; +$lang['FilterEmail'] = 'SQL-Bedingung um Benutzer anhand ihrer E-Mail-Adresse zu filtern.'; +$lang['FilterGroup'] = 'SQL-Bedingung um Benutzer anhand ihrer Gruppenzugehörigkeit zu filtern.'; +$lang['SortOrder'] = 'SQL-Bedingung um anhand der die Benutzerliste sortiert wird.'; +$lang['addUser'] = 'SQL-Kommando um einen neuen Benutzer anzulegen.'; +$lang['addGroup'] = 'SQL-Kommando um eine neue Gruppe anzulegen.'; +$lang['addUserGroup'] = 'SQL-Kommando um einen Benutzer zu einer Gruppe hinzuzufügen.'; +$lang['delGroup'] = 'SQL-Kommando um eine Gruppe zu löschen.'; +$lang['getUserID'] = 'SQL-Kommando um den Primärschlüssel des Benutzers auszulesen.'; +$lang['delUser'] = 'SQL-Kommando um einen Benutzer zu löschen.'; +$lang['delUserRefs'] = 'SQL-Kommando um einen Benutzer aus allen Gruppen zu entfernen.'; +$lang['updateUser'] = 'SQL-Kommando um das Profil eines Benutzers zu aktualisieren.'; +$lang['UpdateLogin'] = 'SQL-Bedingung um den Anmeldenamen eines Benutzers zu ändern.'; +$lang['UpdatePass'] = 'SQL-Bedingung um das Passwort eines Benutzers zu ändern.'; +$lang['UpdateEmail'] = 'SQL-Bedingung um die E-Mail-Adresse eines Benutzers zu ändern.'; +$lang['UpdateName'] = 'SQL-Bedingung um den Namen eines Benutzers zu ändern.'; +$lang['UpdateTarget'] = 'SQL-Bedingung zur eindeutigen Identifikation des Benutzers.'; +$lang['delUserGroup'] = 'SQL-Kommando um einen Benutzer aus einer angegeben Gruppe zu entfernen.'; +$lang['getGroupID'] = 'SQL-Kommando um den Primärschlüssel einer Gruppe auszulesen.'; +$lang['debug_o_0'] = 'Keine.'; +$lang['debug_o_1'] = 'Nur Fehler.'; +$lang['debug_o_2'] = 'Alle SQL-Abfragen.'; diff --git a/lib/plugins/authpgsql/lang/de/settings.php b/lib/plugins/authpgsql/lang/de/settings.php index a1a99b6d6..4c80245d6 100644 --- a/lib/plugins/authpgsql/lang/de/settings.php +++ b/lib/plugins/authpgsql/lang/de/settings.php @@ -2,5 +2,37 @@ /** * German language file * - * @author Mateng Schimmerlos <mateng@firemail.de>) + * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) + * @author Matthias Schulte <dokuwiki@lupo49.de> */ +$lang['server'] = 'PostgreSQL-Server'; +$lang['port'] = 'Port des PostgreSQL-Servers.'; +$lang['user'] = 'Benutzername für den Zugriff auf den PostgreSQL-Server.'; +$lang['password'] = 'Passwort des angegebenen Benutzers.'; +$lang['database'] = 'Zu verwendende Datenbank.'; +$lang['debug'] = 'Debug-Informationen anzeigen?'; +$lang['forwardClearPass'] = 'Passwort der DokuWiki-Benutzer im Klartext an die Datenbank übergeben? (Im Normalfall wird die passcrypt-Option angewendet.)'; +$lang['checkPass'] = 'SQL-Kommando zum Überprüfen von Passwörtern.'; +$lang['getUserInfo'] = 'SQL-Kommando um Benutzerinformationen auszulesen.'; +$lang['getGroups'] = 'SQL-Kommando um Gruppen eines Benutzers auszulesen.'; +$lang['getUsers'] = 'SQL-Kommando um alle Benutzer auszulesen.'; +$lang['FilterLogin'] = 'SQL-Bedingung um Benutzer anhand ihres Anmeldenamens zu filtern.'; +$lang['FilterName'] = 'SQL-Bedingung um Benutzer anhand ihres Namens zu filtern.'; +$lang['FilterEmail'] = 'SQL-Bedingung um Benutzer anhand ihrer E-Mail-Adresse zu filtern.'; +$lang['FilterGroup'] = 'SQL-Bedingung um Benutzer anhand ihrer Gruppenzugehörigkeit zu filtern.'; +$lang['SortOrder'] = 'SQL-Bedingung um anhand der die Benutzerliste sortiert wird.'; +$lang['addUser'] = 'SQL-Kommando um einen neuen Benutzer anzulegen.'; +$lang['addGroup'] = 'SQL-Kommando um eine neue Gruppe anzulegen.'; +$lang['addUserGroup'] = 'SQL-Kommando um einen Benutzer zu einer Gruppe hinzuzufügen.'; +$lang['delGroup'] = 'SQL-Kommando um eine Gruppe zu löschen.'; +$lang['getUserID'] = 'SQL-Kommando um den Primärschlüssel des Benutzers auszulesen.'; +$lang['delUser'] = 'SQL-Kommando um einen Benutzer zu löschen.'; +$lang['delUserRefs'] = 'SQL-Kommando um einen Benutzer aus allen Gruppen zu entfernen.'; +$lang['updateUser'] = 'SQL-Kommando um das Profil eines Benutzers zu aktualisieren.'; +$lang['UpdateLogin'] = 'SQL-Bedingung um den Anmeldenamen eines Benutzers zu ändern.'; +$lang['UpdatePass'] = 'SQL-Bedingung um das Passwort eines Benutzers zu ändern.'; +$lang['UpdateEmail'] = 'SQL-Bedingung um die E-Mail-Adresse eines Benutzers zu ändern.'; +$lang['UpdateName'] = 'SQL-Bedingung um den Namen eines Benutzers zu ändern.'; +$lang['UpdateTarget'] = 'SQL-Bedingung zur eindeutigen Identifikation des Benutzers.'; +$lang['delUserGroup'] = 'SQL-Kommando um einen Benutzer aus einer angegeben Gruppe zu entfernen.'; +$lang['getGroupID'] = 'SQL-Kommando um den Primärschlüssel einer Gruppe auszulesen.'; diff --git a/lib/plugins/config/lang/de/lang.php b/lib/plugins/config/lang/de/lang.php index d72056236..063ee40ad 100644 --- a/lib/plugins/config/lang/de/lang.php +++ b/lib/plugins/config/lang/de/lang.php @@ -17,62 +17,58 @@ * @author Paul Lachewsky <kaeptn.haddock@gmail.com> * @author Pierre Corell <info@joomla-praxis.de> * @author Matthias Schulte <dokuwiki@lupo49.de> - * @author Mateng Schimmerlos <mateng@firemail.de>) */ $lang['menu'] = 'Konfiguration'; -$lang['error'] = 'Die Einstellungen wurden wegen einer fehlerhaften Eingabe nicht gespeichert. -<br />Bitte überprüfen sie die rot umrandeten Eingaben und speichern Sie erneut.'; +$lang['error'] = 'Die Einstellungen wurden wegen einer fehlerhaften Eingabe nicht gespeichert.<br /> Bitte überprüfen sie die rot umrandeten Eingaben und speichern Sie erneut.'; $lang['updated'] = 'Einstellungen erfolgreich gespeichert.'; $lang['nochoice'] = '(keine Auswahlmöglichkeiten vorhanden)'; -$lang['locked'] = 'Die Konfigurationsdatei kann nicht geändert werden, wenn dies unbeabsichtigt ist - <br />überprüfen Sie, dass die Dateiberechtigungen korrekt gesetzt sind.'; +$lang['locked'] = 'Die Konfigurationsdatei kann nicht geändert werden. Wenn dies unbeabsichtigt ist, <br />überprüfen Sie, ob die Dateiberechtigungen korrekt gesetzt sind.'; $lang['danger'] = 'Vorsicht: Die Änderung dieser Option könnte Ihr Wiki und das Konfigurationsmenü unzugänglich machen.'; $lang['warning'] = 'Hinweis: Die Änderung dieser Option könnte unbeabsichtigtes Verhalten hervorrufen.'; $lang['security'] = 'Sicherheitswarnung: Die Änderung dieser Option könnte ein Sicherheitsrisiko darstellen.'; $lang['_configuration_manager'] = 'Konfiguration'; $lang['_header_dokuwiki'] = 'DokuWiki-Konfiguration'; $lang['_header_plugin'] = 'Plugin-Konfiguration'; -$lang['_header_template'] = 'Template-Konfiguration'; -$lang['_header_undefined'] = 'Unbekannte Einstellungen'; -$lang['_basic'] = 'Grund-Konfiguration'; -$lang['_display'] = 'Anzeige-Konfiguration'; -$lang['_authentication'] = 'Authentifizierungs-Konfiguration'; -$lang['_anti_spam'] = 'Anti-Spam-Konfiguration'; -$lang['_editing'] = 'Bearbeitungs-Konfiguration'; -$lang['_links'] = 'Link-Konfiguration'; -$lang['_media'] = 'Medien-Konfiguration'; -$lang['_notifications'] = 'Benachrichtigungs-Konfiguration'; -$lang['_syndication'] = 'Syndication-Konfiguration (RSS)'; +$lang['_header_template'] = 'Vorlagen'; +$lang['_header_undefined'] = 'Unbekannte Werte'; +$lang['_basic'] = 'Grundkonfiguration'; +$lang['_display'] = 'Darstellung'; +$lang['_authentication'] = 'Authentifizierung'; +$lang['_anti_spam'] = 'Anti-Spam'; +$lang['_editing'] = 'Bearbeitung'; +$lang['_links'] = 'Links'; +$lang['_media'] = 'Medien'; +$lang['_notifications'] = 'Benachrichtigungen'; +$lang['_syndication'] = 'Syndication (RSS)'; $lang['_advanced'] = 'Erweiterte Konfiguration'; -$lang['_network'] = 'Netzwerk-Konfiguration'; -$lang['_plugin_sufix'] = 'Plugin-Konfiguration'; -$lang['_template_sufix'] = 'Template-Konfiguration'; +$lang['_network'] = 'Netzwerk'; +$lang['_plugin_sufix'] = ''; +$lang['_template_sufix'] = 'Vorlagen-Konfiguration'; $lang['_msg_setting_undefined'] = 'Keine Konfigurationsmetadaten.'; $lang['_msg_setting_no_class'] = 'Keine Konfigurationsklasse.'; $lang['_msg_setting_no_default'] = 'Kein Standardwert.'; -$lang['title'] = 'Titel des Wikis'; -$lang['start'] = 'Startseitenname'; +$lang['fmode'] = 'Berechtigungen für neue Dateien'; +$lang['dmode'] = 'Berechtigungen für neue Verzeichnisse'; $lang['lang'] = 'Sprache'; +$lang['basedir'] = 'Installationsverzeichnis'; +$lang['baseurl'] = 'Installationspfad (URL)'; +$lang['savedir'] = 'Speicherverzeichnis'; +$lang['cookiedir'] = 'Cookiepfad. Frei lassen, um den gleichen Pfad wie "baseurl" zu benutzen.'; +$lang['start'] = 'Startseitenname'; +$lang['title'] = 'Titel des Wikis'; $lang['template'] = 'Designvorlage (Template)'; $lang['tagline'] = 'Tag-Linie (nur, wenn vom Template unterstützt)'; $lang['sidebar'] = 'Name der Sidebar-Seite (nur, wenn vom Template unterstützt)), ein leeres Feld deaktiviert die Sidebar'; $lang['license'] = 'Unter welcher Lizenz sollen Ihre Inhalte veröffentlicht werden?'; -$lang['savedir'] = 'Speicherverzeichnis'; -$lang['basedir'] = 'Installationsverzeichnis'; -$lang['baseurl'] = 'Installationspfad (URL)'; -$lang['cookiedir'] = 'Cookiepfad. Frei lassen, um den gleichen Pfad wie "baseurl" zu benutzen.'; -$lang['dmode'] = 'Rechte für neue Verzeichnisse'; -$lang['fmode'] = 'Rechte für neue Dateien'; -$lang['allowdebug'] = 'Debug-Ausgaben erlauben <b>Abschalten wenn nicht benötigt!</b>'; +$lang['fullpath'] = 'Den kompletten Dateipfad im Footer anzeigen'; $lang['recent'] = 'Anzahl der Einträge in der Änderungsliste'; -$lang['recent_days'] = 'Wieviele letzte Änderungen sollen einsehbar bleiben? (Tage)'; $lang['breadcrumbs'] = 'Anzahl der Einträge im "Krümelpfad"'; $lang['youarehere'] = 'Hierarchische Pfadnavigation verwenden'; -$lang['fullpath'] = 'Den kompletten Dateipfad im Footer anzeigen'; $lang['typography'] = 'Typographische Ersetzungen'; +$lang['htmlok'] = 'HTML erlauben'; +$lang['phpok'] = 'PHP erlauben'; $lang['dformat'] = 'Datumsformat (Siehe PHP <a href="http://www.php.net/strftime">strftime</a> Funktion)'; $lang['signature'] = 'Signatur'; -$lang['showuseras'] = 'Was angezeigt werden soll, wenn der Benutzer, der zuletzt eine Seite bearbeitet hat, angezeigt wird'; $lang['toptoclevel'] = 'Inhaltsverzeichnis bei dieser Überschriftengröße beginnen'; $lang['tocminheads'] = 'Mindestanzahl der Überschriften die entscheidet, ob ein Inhaltsverzeichnis erscheinen soll'; $lang['maxtoclevel'] = 'Maximale Überschriftsgröße für Inhaltsverzeichnis'; @@ -80,8 +76,16 @@ $lang['maxseclevel'] = 'Abschnitte bis zu dieser Stufe einzeln editier $lang['camelcase'] = 'CamelCase-Verlinkungen verwenden'; $lang['deaccent'] = 'Seitennamen bereinigen'; $lang['useheading'] = 'Erste Überschrift als Seitennamen verwenden'; -$lang['sneaky_index'] = 'Standardmäßig zeigt DokuWiki alle Namensräume in der Übersicht. Wenn diese Option aktiviert wird, werden alle Namensräume, für die der Benutzer keine Lese-Rechte hat, nicht angezeigt. Dies kann unter Umständen dazu führen, das lesbare Unter-Namensräume nicht angezeigt werden und macht die Übersicht evtl. unbrauchbar in Kombination mit bestimmten ACL Einstellungen.'; -$lang['hidepages'] = 'Seiten verstecken (Regulärer Ausdruck)'; +$lang['refcheck'] = 'Auf Verwendung beim Löschen von Media-Dateien testen'; +$lang['refshow'] = 'Wiev iele Verwendungsorte der Media-Datei zeigen'; +$lang['allowdebug'] = 'Debug-Ausgaben erlauben <b>Abschalten wenn nicht benötigt!</b>'; +$lang['mediarevisions'] = 'Media-Revisionen (ältere Versionen) aktivieren?'; +$lang['usewordblock'] = 'Spam-Blocking benutzen'; +$lang['indexdelay'] = 'Zeit bevor Suchmaschinenindexierung erlaubt ist'; +$lang['relnofollow'] = 'rel="nofollow" verwenden'; +$lang['mailguard'] = 'E-Mail-Adressen schützen'; +$lang['iexssprotect'] = 'Hochgeladene Dateien auf bösartigen JavaScript- und HTML-Code untersuchen'; +$lang['showuseras'] = 'Was angezeigt werden soll, wenn der Benutzer, der zuletzt eine Seite bearbeitet hat, angezeigt wird'; $lang['useacl'] = 'Zugangskontrolle verwenden'; $lang['autopasswd'] = 'Passwort automatisch generieren'; $lang['authtype'] = 'Authentifizierungsmechanismus'; @@ -90,69 +94,62 @@ $lang['defaultgroup'] = 'Standardgruppe'; $lang['superuser'] = 'Administrator - Eine Gruppe oder Nutzer mit vollem Zugriff auf alle Seiten und Administrationswerkzeuge.'; $lang['manager'] = 'Manager - Eine Gruppe oder Nutzer mit Zugriff auf einige Administrationswerkzeuge.'; $lang['profileconfirm'] = 'Profiländerung nur nach Passwortbestätigung'; -$lang['rememberme'] = 'Permanente Login-Cookies erlauben (Auf diesem Computer eingeloggt bleiben)'; $lang['disableactions'] = 'DokuWiki-Aktionen deaktivieren'; $lang['disableactions_check'] = 'Check'; $lang['disableactions_subscription'] = 'Seiten-Abonnements'; $lang['disableactions_wikicode'] = 'Quelltext betrachten/exportieren'; $lang['disableactions_other'] = 'Andere Aktionen (durch Komma getrennt)'; +$lang['sneaky_index'] = 'Standardmäßig zeigt DokuWiki alle Namensräume in der Übersicht. Wenn diese Option aktiviert wird, werden alle Namensräume, für die der Benutzer keine Lese-Rechte hat, nicht angezeigt. Dies kann unter Umständen dazu führen, das lesbare Unter-Namensräume nicht angezeigt werden und macht die Übersicht evtl. unbrauchbar in Kombination mit bestimmten ACL Einstellungen.'; $lang['auth_security_timeout'] = 'Authentifikations-Timeout (Sekunden)'; $lang['securecookie'] = 'Sollen Cookies, die via HTTPS gesetzt wurden nur per HTTPS versendet werden? Deaktivieren Sie diese Option, wenn nur der Login Ihres Wikis mit SSL gesichert ist, aber das Betrachten des Wikis ungesichert geschieht.'; $lang['remote'] = 'Aktiviert den externen API-Zugang. Diese Option erlaubt es externen Anwendungen von außen auf die XML-RPC-Schnittstelle oder anderweitigen Schnittstellen zuzugreifen.'; $lang['remoteuser'] = 'Zugriff auf die externen Schnittstellen durch kommaseparierte Angabe von Benutzern oder Gruppen einschränken. Ein leeres Feld erlaubt Zugriff für jeden.'; -$lang['usewordblock'] = 'Spam-Blocking benutzen'; -$lang['relnofollow'] = 'rel="nofollow" verwenden'; -$lang['indexdelay'] = 'Zeit bevor Suchmaschinenindexierung erlaubt ist'; -$lang['mailguard'] = 'E-Mail-Adressen schützen'; -$lang['iexssprotect'] = 'Hochgeladene Dateien auf bösartigen JavaScript- und HTML-Code untersuchen'; -$lang['usedraft'] = 'Während des Bearbeitens automatisch Zwischenentwürfe speichern'; -$lang['htmlok'] = 'HTML erlauben'; -$lang['phpok'] = 'PHP erlauben'; -$lang['locktime'] = 'Maximales Alter für Seitensperren (Sekunden)'; -$lang['cachetime'] = 'Maximale Cachespeicherung (Sekunden)'; -$lang['target____wiki'] = 'Zielfenster für interne Links (target Attribut)'; -$lang['target____interwiki'] = 'Zielfenster für InterWiki-Links (target Attribut)'; -$lang['target____extern'] = 'Zielfenster für Externe Links (target Attribut)'; -$lang['target____media'] = 'Zielfenster für (Bild-)Dateien (target Attribut)'; -$lang['target____windows'] = 'Zielfenster für Windows Freigaben (target Attribut)'; -$lang['mediarevisions'] = 'Media-Revisionen (ältere Versionen) aktivieren?'; -$lang['refcheck'] = 'Auf Verwendung beim Löschen von Media-Dateien testen'; -$lang['refshow'] = 'Wiev iele Verwendungsorte der Media-Datei zeigen'; -$lang['gdlib'] = 'GD Lib Version'; -$lang['im_convert'] = 'Pfad zu ImageMagicks-Konvertierwerkzeug'; -$lang['jpg_quality'] = 'JPEG Kompressionsqualität (0-100)'; -$lang['fetchsize'] = 'Maximale Größe (in Bytes), die fetch.php von extern herunterladen darf'; -$lang['subscribers'] = 'E-Mail-Abos zulassen'; -$lang['subscribe_time'] = 'Zeit nach der Zusammenfassungs- und Änderungslisten-E-Mails verschickt werden; Dieser Wert sollte kleiner als die in recent_days konfigurierte Zeit sein.'; -$lang['notify'] = 'Änderungsmitteilungen an diese E-Mail-Adresse versenden'; -$lang['registernotify'] = 'Information über neu registrierte Nutzer an diese E-Mail-Adresse senden'; -$lang['mailfrom'] = 'Absender-E-Mail-Adresse für automatische Mails'; -$lang['mailprefix'] = 'Präfix für E-Mail-Betreff beim automatischen Versand von Benachrichtigungen'; -$lang['htmlmail'] = 'Versendet optisch angenehmere, aber größere E-Mails im HTML-Format (multipart). Deaktivieren, um Text-Mails zu versenden.'; -$lang['sitemap'] = 'Google Sitemap erzeugen (Tage)'; -$lang['rss_type'] = 'XML-Feed-Format'; -$lang['rss_linkto'] = 'XML-Feed verlinken auf'; -$lang['rss_content'] = 'Welche Inhalte sollen im XML-Feed dargestellt werden?'; -$lang['rss_update'] = 'XML-Feed Aktualisierungsintervall (Sekunden)'; -$lang['rss_show_summary'] = 'Bearbeitungs-Zusammenfassung im XML-Feed anzeigen'; -$lang['rss_media'] = 'Welche Änderungen sollen im XML-Feed angezeigt werden?'; $lang['updatecheck'] = 'Automatisch auf Updates und Sicherheitswarnungen prüfen? DokuWiki muss sich dafür mit update.dokuwiki.org verbinden.'; $lang['userewrite'] = 'URL rewriting'; $lang['useslash'] = 'Schrägstrich (/) als Namensraumtrenner in URLs verwenden'; +$lang['usedraft'] = 'Während des Bearbeitens automatisch Zwischenentwürfe speichern'; $lang['sepchar'] = 'Worttrenner für Seitennamen in URLs'; $lang['canonical'] = 'Immer Links mit vollständigen URLs erzeugen'; $lang['fnencode'] = 'Methode um nicht-ASCII Dateinamen zu kodieren.'; $lang['autoplural'] = 'Bei Links automatisch nach vorhandenen Pluralformen suchen'; $lang['compression'] = 'Komprimierungsmethode für alte Seitenrevisionen'; +$lang['cachetime'] = 'Maximale Cachespeicherung (Sekunden)'; +$lang['locktime'] = 'Maximales Alter für Seitensperren (Sekunden)'; +$lang['fetchsize'] = 'Maximale Größe (in Bytes), die fetch.php von extern herunterladen darf'; +$lang['notify'] = 'Änderungsmitteilungen an diese E-Mail-Adresse versenden'; +$lang['registernotify'] = 'Information über neu registrierte Nutzer an diese E-Mail-Adresse senden'; +$lang['mailfrom'] = 'Absender-E-Mail-Adresse für automatische Mails'; +$lang['mailprefix'] = 'Präfix für E-Mail-Betreff beim automatischen Versand von Benachrichtigungen'; +$lang['htmlmail'] = 'Versendet optisch angenehmere, aber größere E-Mails im HTML-Format (multipart). Deaktivieren, um Text-Mails zu versenden.'; $lang['gzip_output'] = 'Seiten mit gzip komprimiert ausliefern'; +$lang['gdlib'] = 'GD Lib Version'; +$lang['im_convert'] = 'Pfad zu ImageMagicks-Konvertierwerkzeug'; +$lang['jpg_quality'] = 'JPEG Kompressionsqualität (0-100)'; +$lang['subscribers'] = 'E-Mail-Abos zulassen'; +$lang['subscribe_time'] = 'Zeit nach der Zusammenfassungs- und Änderungslisten-E-Mails verschickt werden; Dieser Wert sollte kleiner als die in recent_days konfigurierte Zeit sein.'; $lang['compress'] = 'JavaScript und Stylesheets komprimieren'; $lang['cssdatauri'] = 'Größe in Bytes, bis zu der Bilder in css-Dateien referenziert werden können, um HTTP-Anfragen zu minimieren. Diese Technik funktioniert nicht im IE 7 und älter! Empfohlene Einstellung: <code>400</code> to <code>600</code> Bytes. Setzen Sie die Einstellung auf <code>0</code> um die Funktion zu deaktivieren.'; +$lang['hidepages'] = 'Seiten verstecken (Regulärer Ausdruck)'; $lang['send404'] = 'Bei nicht vorhandenen Seiten mit 404 Fehlercode antworten'; +$lang['sitemap'] = 'Google Sitemap erzeugen (Tage)'; $lang['broken_iua'] = 'Falls die Funktion ignore_user_abort auf Ihrem System nicht funktioniert, könnte der Such-Index nicht funktionieren. IIS+PHP/CGI ist bekannt dafür. Siehe auch <a href="http://bugs.splitbrain.org/?do=details&task_id=852">Bug 852</a>.'; $lang['xsendfile'] = 'Den X-Sendfile-Header nutzen, um Dateien direkt vom Webserver ausliefern zu lassen? Ihr Webserver muss dies unterstützen!'; $lang['renderer_xhtml'] = 'Standard-Renderer für die normale (XHTML) Wiki-Ausgabe.'; $lang['renderer__core'] = '%s (DokuWiki Kern)'; $lang['renderer__plugin'] = '%s (Plugin)'; +$lang['rememberme'] = 'Permanente Login-Cookies erlauben (Auf diesem Computer eingeloggt bleiben)'; +$lang['rss_type'] = 'XML-Feed-Format'; +$lang['rss_linkto'] = 'XML-Feed verlinken auf'; +$lang['rss_content'] = 'Welche Inhalte sollen im XML-Feed dargestellt werden?'; +$lang['rss_update'] = 'XML-Feed Aktualisierungsintervall (Sekunden)'; +$lang['recent_days'] = 'Wieviele letzte Änderungen sollen einsehbar bleiben? (Tage)'; +$lang['rss_show_summary'] = 'Bearbeitungs-Zusammenfassung im XML-Feed anzeigen'; +$lang['rss_media'] = 'Welche Änderungen sollen im XML-Feed angezeigt werden?'; +$lang['target____wiki'] = 'Zielfenster für interne Links (target Attribut)'; +$lang['target____interwiki'] = 'Zielfenster für InterWiki-Links (target Attribut)'; +$lang['target____extern'] = 'Zielfenster für Externe Links (target Attribut)'; +$lang['target____media'] = 'Zielfenster für (Bild-)Dateien (target Attribut)'; +$lang['target____windows'] = 'Zielfenster für Windows Freigaben (target Attribut)'; $lang['dnslookups'] = 'DokuWiki löst die IP-Adressen von Benutzern zu deren Hostnamen auf. Wenn du einen langsamen, unbrauchbaren DNS-Server verwendest oder die Funktion nicht benötigst, dann sollte diese Option deaktivert sein.'; $lang['proxy____host'] = 'Proxy-Server'; $lang['proxy____port'] = 'Proxy-Port'; @@ -199,9 +196,9 @@ $lang['xsendfile_o_0'] = 'nicht benutzen'; $lang['xsendfile_o_1'] = 'Proprietärer lighttpd-Header (vor Release 1.5)'; $lang['xsendfile_o_2'] = 'Standard X-Sendfile-Header'; $lang['xsendfile_o_3'] = 'Proprietärer Nginx X-Accel-Redirect-Header'; -$lang['showuseras_o_loginname'] = 'Loginname'; +$lang['showuseras_o_loginname'] = 'Login-Name'; $lang['showuseras_o_username'] = 'Vollständiger Name des Benutzers'; -$lang['showuseras_o_email'] = 'E-Mail-Adresse des Benutzers (je nach Mailguard-Einstellung verschleiert)'; +$lang['showuseras_o_email'] = 'E-Mail-Adresse des Benutzers (Beachte "mailguard"-Einstellung)'; $lang['showuseras_o_email_link'] = 'E-Mail-Adresse des Benutzers als mailto:-Link'; $lang['useheading_o_0'] = 'Nie'; $lang['useheading_o_navigation'] = 'Nur Navigation'; diff --git a/lib/plugins/plugin/lang/de/lang.php b/lib/plugins/plugin/lang/de/lang.php index 0c560537f..9f26a2933 100644 --- a/lib/plugins/plugin/lang/de/lang.php +++ b/lib/plugins/plugin/lang/de/lang.php @@ -18,7 +18,6 @@ * @author Christian Wichmann <nospam@zone0.de> * @author Paul Lachewsky <kaeptn.haddock@gmail.com> * @author Pierre Corell <info@joomla-praxis.de> - * @author Mateng Schimmerlos <mateng@firemail.de>) */ $lang['menu'] = 'Plugins verwalten'; $lang['download'] = 'Neues Plugin herunterladen und installieren'; diff --git a/lib/plugins/popularity/lang/de/lang.php b/lib/plugins/popularity/lang/de/lang.php index 4c1ba1391..42bdc14d5 100644 --- a/lib/plugins/popularity/lang/de/lang.php +++ b/lib/plugins/popularity/lang/de/lang.php @@ -15,7 +15,6 @@ * @author Christian Wichmann <nospam@zone0.de> * @author Paul Lachewsky <kaeptn.haddock@gmail.com> * @author Pierre Corell <info@joomla-praxis.de> - * @author Mateng Schimmerlos <mateng@firemail.de>) */ $lang['name'] = 'Popularitäts-Feedback (Eventuell längere Ladezeit)'; $lang['submit'] = 'Daten senden'; diff --git a/lib/plugins/revert/lang/de/lang.php b/lib/plugins/revert/lang/de/lang.php index 39acd3c37..b430ce876 100644 --- a/lib/plugins/revert/lang/de/lang.php +++ b/lib/plugins/revert/lang/de/lang.php @@ -16,7 +16,6 @@ * @author Christian Wichmann <nospam@zone0.de> * @author Paul Lachewsky <kaeptn.haddock@gmail.com> * @author Pierre Corell <info@joomla-praxis.de> - * @author Mateng Schimmerlos <mateng@firemail.de>) */ $lang['menu'] = 'Seiten wieder herstellen'; $lang['filter'] = 'Nach betroffenen Seiten suchen'; diff --git a/lib/plugins/usermanager/lang/de/lang.php b/lib/plugins/usermanager/lang/de/lang.php index cfe528823..0dd90cc68 100644 --- a/lib/plugins/usermanager/lang/de/lang.php +++ b/lib/plugins/usermanager/lang/de/lang.php @@ -17,7 +17,6 @@ * @author Paul Lachewsky <kaeptn.haddock@gmail.com> * @author Pierre Corell <info@joomla-praxis.de> * @author Matthias Schulte <dokuwiki@lupo49.de> - * @author Mateng Schimmerlos <mateng@firemail.de>) */ $lang['menu'] = 'Benutzerverwaltung'; $lang['noauth'] = '(Authentifizierungssystem nicht verfügbar)'; -- cgit v1.2.3 From 1b228d28eda480cd189c68eadd1172c9409c6ef7 Mon Sep 17 00:00:00 2001 From: Klap-in <klapinklapin@gmail.com> Date: Sun, 21 Apr 2013 21:24:33 +0200 Subject: Rename ad_username to admin_username canDo getUsers to false when unavailable --- lib/plugins/authad/auth.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/plugins/authad/auth.php b/lib/plugins/authad/auth.php index f7f350c3f..5985cd18f 100644 --- a/lib/plugins/authad/auth.php +++ b/lib/plugins/authad/auth.php @@ -469,10 +469,10 @@ class auth_plugin_authad extends DokuWiki_Auth_Plugin { $this->cando['modPass'] = false; } - if(isset($opts['ad_username']) && isset($opts['ad_password'])) { + if(isset($opts['admin_username']) && isset($opts['admin_password'])) { $this->cando['getUsers'] = true; } else { - $this->cando['getUsers'] = true; + $this->cando['getUsers'] = false; } return $opts; -- cgit v1.2.3 From 4c1219f3b8d93b4dd5d55b4246cd44bb5828fbc9 Mon Sep 17 00:00:00 2001 From: Mateng Schimmerlos <mateng@firemail.de> Date: Sun, 21 Apr 2013 21:31:49 +0200 Subject: de/de-informal: Re-apply the updates of ba09710ad34bb383ae3526e84490a3d545f78866 --- inc/lang/de/lang.php | 4 ++++ lib/plugins/config/lang/de-informal/lang.php | 3 ++- lib/plugins/config/lang/de/lang.php | 3 ++- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/inc/lang/de/lang.php b/inc/lang/de/lang.php index 160ea53e8..af6f32bf4 100644 --- a/inc/lang/de/lang.php +++ b/inc/lang/de/lang.php @@ -21,6 +21,7 @@ * @author Matthias Schulte <mailinglist@lupo49.de> * @author Paul Lachewsky <kaeptn.haddock@gmail.com> * @author Pierre Corell <info@joomla-praxis.de> + * @author Mateng Schimmerlos <mateng@firemail.de> */ $lang['encoding'] = 'utf-8'; $lang['direction'] = 'ltr'; @@ -298,6 +299,9 @@ $lang['i_pol1'] = 'Öffentliches Wiki (Lesen für alle, Schreiben $lang['i_pol2'] = 'Geschlossenes Wiki (Lesen, Schreiben und Hochladen nur für registrierte Nutzer)'; $lang['i_retry'] = 'Wiederholen'; $lang['i_license'] = 'Bitte wählen Sie die Lizenz, unter die Sie Ihre Inhalte stellen möchten:'; +$lang['i_license_none'] = 'Lizensierungsinformation nicht anzeigen'; +$lang['i_pop_field'] = 'Bitte helfen Sie mit, DokuWiki zu verbessern:'; +$lang['i_pop_label'] = 'Einmal monatlich anonymisierte Nutzungsdaten an das DokuWiki-Entwicklerteam senden'; $lang['recent_global'] = 'Im Moment sehen Sie die Änderungen im Namensraum <b>%s</b>. Sie können auch <a href="%s">die Änderungen im gesamten Wiki sehen</a>.'; $lang['years'] = 'vor %d Jahren'; $lang['months'] = 'vor %d Monaten'; diff --git a/lib/plugins/config/lang/de-informal/lang.php b/lib/plugins/config/lang/de-informal/lang.php index 72823c0de..dcf970726 100644 --- a/lib/plugins/config/lang/de-informal/lang.php +++ b/lib/plugins/config/lang/de-informal/lang.php @@ -9,6 +9,7 @@ * @author Christian Wichmann <nospam@zone0.de> * @author Pierre Corell <info@joomla-praxis.de> * @author Frank Loizzi <contact@software.bacal.de> + * @author Mateng Schimmerlos <mateng@firemail.de> */ $lang['menu'] = 'Konfiguration'; $lang['error'] = 'Konfiguration wurde nicht aktualisiert auf Grund eines ungültigen Wertes. Bitte überprüfe deine Änderungen und versuche es erneut.<br />Die/der ungültige(n) Wert(e) werden durch eine rote Umrandung hervorgehoben.'; @@ -190,7 +191,7 @@ $lang['xsendfile_o_2'] = 'Standard X-Sendfile-Header'; $lang['xsendfile_o_3'] = 'Proprietärer Nginx X-Accel-Redirect-Header'; $lang['showuseras_o_loginname'] = 'Login-Name'; $lang['showuseras_o_username'] = 'Voller Name des Nutzers'; -$lang['showuseras_o_email'] = 'E-Mail-Adresse des Benutzers (Beachte "mailguard"-Einstellung)'; +$lang['showuseras_o_email'] = 'E-Mail-Adresse des Benutzers (je nach Mailguard-Einstellung verschleiert)'; $lang['showuseras_o_email_link'] = 'E-Mail-Adresse des Benutzers als mailto:-Link'; $lang['useheading_o_0'] = 'Niemals'; $lang['useheading_o_navigation'] = 'Nur Navigation'; diff --git a/lib/plugins/config/lang/de/lang.php b/lib/plugins/config/lang/de/lang.php index 063ee40ad..b50a99cda 100644 --- a/lib/plugins/config/lang/de/lang.php +++ b/lib/plugins/config/lang/de/lang.php @@ -17,6 +17,7 @@ * @author Paul Lachewsky <kaeptn.haddock@gmail.com> * @author Pierre Corell <info@joomla-praxis.de> * @author Matthias Schulte <dokuwiki@lupo49.de> + * @author Mateng Schimmerlos <mateng@firemail.de> */ $lang['menu'] = 'Konfiguration'; $lang['error'] = 'Die Einstellungen wurden wegen einer fehlerhaften Eingabe nicht gespeichert.<br /> Bitte überprüfen sie die rot umrandeten Eingaben und speichern Sie erneut.'; @@ -198,7 +199,7 @@ $lang['xsendfile_o_2'] = 'Standard X-Sendfile-Header'; $lang['xsendfile_o_3'] = 'Proprietärer Nginx X-Accel-Redirect-Header'; $lang['showuseras_o_loginname'] = 'Login-Name'; $lang['showuseras_o_username'] = 'Vollständiger Name des Benutzers'; -$lang['showuseras_o_email'] = 'E-Mail-Adresse des Benutzers (Beachte "mailguard"-Einstellung)'; +$lang['showuseras_o_email'] = 'E-Mail-Adresse des Benutzers (je nach Mailguard-Einstellung verschleiert)'; $lang['showuseras_o_email_link'] = 'E-Mail-Adresse des Benutzers als mailto:-Link'; $lang['useheading_o_0'] = 'Nie'; $lang['useheading_o_navigation'] = 'Nur Navigation'; -- cgit v1.2.3 From bb7b8a518eac7d3c3dc2b465600047bd10b3f82a Mon Sep 17 00:00:00 2001 From: lupo49 <dokuwiki@lupo49.de> Date: Sun, 21 Apr 2013 21:39:06 +0200 Subject: de/de-informal: Re-add TOC suffixes (Will be removed after the release again) --- lib/plugins/config/lang/de-informal/lang.php | 26 +++++++++++++------------- lib/plugins/config/lang/de/lang.php | 24 ++++++++++++------------ 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/lib/plugins/config/lang/de-informal/lang.php b/lib/plugins/config/lang/de-informal/lang.php index dcf970726..5cc7b0add 100644 --- a/lib/plugins/config/lang/de-informal/lang.php +++ b/lib/plugins/config/lang/de-informal/lang.php @@ -22,21 +22,21 @@ $lang['security'] = 'Sicherheitswarnung: Eine Änderungen dieser Op $lang['_configuration_manager'] = 'Konfiguration'; $lang['_header_dokuwiki'] = 'DokuWiki-Konfiguration'; $lang['_header_plugin'] = 'Plugin-Konfiguration'; -$lang['_header_template'] = 'Vorlagen'; +$lang['_header_template'] = 'Vorlagen-Konfiguration'; $lang['_header_undefined'] = 'Unbekannte Werte'; -$lang['_basic'] = 'Grundkonfiguration'; -$lang['_display'] = 'Darstellung'; -$lang['_authentication'] = 'Authentifizierung'; -$lang['_anti_spam'] = 'Anti-Spam'; -$lang['_editing'] = 'Bearbeitung'; -$lang['_links'] = 'Links'; -$lang['_media'] = 'Medien'; -$lang['_notifications'] = 'Benachrichtigungen'; -$lang['_syndication'] = 'Syndication (RSS)'; +$lang['_basic'] = 'Grund-Konfiguration'; +$lang['_display'] = 'Darstellungs-Konfiguration'; +$lang['_authentication'] = 'Authentifizierung-Konfiguration'; +$lang['_anti_spam'] = 'Anti-Spam-Konfiguration'; +$lang['_editing'] = 'Bearbeitungs-Konfiguration'; +$lang['_links'] = 'Links-Konfiguration'; +$lang['_media'] = 'Medien-Konfiguration'; +$lang['_notifications'] = 'Benachrichtigungs-Konfiguration'; +$lang['_syndication'] = 'Syndication-Konfiguration (RSS)'; $lang['_advanced'] = 'Erweiterte Konfiguration'; -$lang['_network'] = 'Netzwerk'; -$lang['_plugin_sufix'] = ''; -$lang['_template_sufix'] = 'Vorlageneinstellungen'; +$lang['_network'] = 'Netzwerk-Konfiguration'; +$lang['_plugin_sufix'] = 'Plugin-Konfiguration'; +$lang['_template_sufix'] = 'Vorlagen-Konfiguration'; $lang['_msg_setting_undefined'] = 'Keine Konfigurationsmetadaten.'; $lang['_msg_setting_no_class'] = 'Keine Konfigurationsklasse.'; $lang['_msg_setting_no_default'] = 'Kein Standardwert.'; diff --git a/lib/plugins/config/lang/de/lang.php b/lib/plugins/config/lang/de/lang.php index b50a99cda..c550caa39 100644 --- a/lib/plugins/config/lang/de/lang.php +++ b/lib/plugins/config/lang/de/lang.php @@ -30,20 +30,20 @@ $lang['security'] = 'Sicherheitswarnung: Die Änderung dieser Optio $lang['_configuration_manager'] = 'Konfiguration'; $lang['_header_dokuwiki'] = 'DokuWiki-Konfiguration'; $lang['_header_plugin'] = 'Plugin-Konfiguration'; -$lang['_header_template'] = 'Vorlagen'; +$lang['_header_template'] = 'Vorlagen-Konfiguration'; $lang['_header_undefined'] = 'Unbekannte Werte'; -$lang['_basic'] = 'Grundkonfiguration'; -$lang['_display'] = 'Darstellung'; -$lang['_authentication'] = 'Authentifizierung'; -$lang['_anti_spam'] = 'Anti-Spam'; -$lang['_editing'] = 'Bearbeitung'; -$lang['_links'] = 'Links'; -$lang['_media'] = 'Medien'; -$lang['_notifications'] = 'Benachrichtigungen'; -$lang['_syndication'] = 'Syndication (RSS)'; +$lang['_basic'] = 'Grund-Konfiguration'; +$lang['_display'] = 'Darstellungs-Konfiguration'; +$lang['_authentication'] = 'Authentifizierungs-Konfiguration'; +$lang['_anti_spam'] = 'Anti-Spam-Konfiguration'; +$lang['_editing'] = 'Bearbeitungs-Konfiguration'; +$lang['_links'] = 'Links-Konfiguration'; +$lang['_media'] = 'Medien-Konfiguration'; +$lang['_notifications'] = 'Benachrichtigungs-Konfiguration'; +$lang['_syndication'] = 'Syndication-Konfiguration (RSS)'; $lang['_advanced'] = 'Erweiterte Konfiguration'; -$lang['_network'] = 'Netzwerk'; -$lang['_plugin_sufix'] = ''; +$lang['_network'] = 'Netzwerk-Konfiguration'; +$lang['_plugin_sufix'] = 'Plugin-Konfiguration'; $lang['_template_sufix'] = 'Vorlagen-Konfiguration'; $lang['_msg_setting_undefined'] = 'Keine Konfigurationsmetadaten.'; $lang['_msg_setting_no_class'] = 'Keine Konfigurationsklasse.'; -- cgit v1.2.3 From 2de592cb4bbca69698b25fb0b11f0f73df46e395 Mon Sep 17 00:00:00 2001 From: lupo49 <dokuwiki@lupo49.de> Date: Sun, 21 Apr 2013 21:42:58 +0200 Subject: de/de-informal: Change "Vorlage" to "Template" --- lib/plugins/config/lang/de-informal/lang.php | 4 ++-- lib/plugins/config/lang/de/lang.php | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/plugins/config/lang/de-informal/lang.php b/lib/plugins/config/lang/de-informal/lang.php index 5cc7b0add..ac61e4c85 100644 --- a/lib/plugins/config/lang/de-informal/lang.php +++ b/lib/plugins/config/lang/de-informal/lang.php @@ -22,7 +22,7 @@ $lang['security'] = 'Sicherheitswarnung: Eine Änderungen dieser Op $lang['_configuration_manager'] = 'Konfiguration'; $lang['_header_dokuwiki'] = 'DokuWiki-Konfiguration'; $lang['_header_plugin'] = 'Plugin-Konfiguration'; -$lang['_header_template'] = 'Vorlagen-Konfiguration'; +$lang['_header_template'] = 'Template-Konfiguration'; $lang['_header_undefined'] = 'Unbekannte Werte'; $lang['_basic'] = 'Grund-Konfiguration'; $lang['_display'] = 'Darstellungs-Konfiguration'; @@ -36,7 +36,7 @@ $lang['_syndication'] = 'Syndication-Konfiguration (RSS)'; $lang['_advanced'] = 'Erweiterte Konfiguration'; $lang['_network'] = 'Netzwerk-Konfiguration'; $lang['_plugin_sufix'] = 'Plugin-Konfiguration'; -$lang['_template_sufix'] = 'Vorlagen-Konfiguration'; +$lang['_template_sufix'] = 'Template-Konfiguration'; $lang['_msg_setting_undefined'] = 'Keine Konfigurationsmetadaten.'; $lang['_msg_setting_no_class'] = 'Keine Konfigurationsklasse.'; $lang['_msg_setting_no_default'] = 'Kein Standardwert.'; diff --git a/lib/plugins/config/lang/de/lang.php b/lib/plugins/config/lang/de/lang.php index c550caa39..dd29f8038 100644 --- a/lib/plugins/config/lang/de/lang.php +++ b/lib/plugins/config/lang/de/lang.php @@ -30,7 +30,7 @@ $lang['security'] = 'Sicherheitswarnung: Die Änderung dieser Optio $lang['_configuration_manager'] = 'Konfiguration'; $lang['_header_dokuwiki'] = 'DokuWiki-Konfiguration'; $lang['_header_plugin'] = 'Plugin-Konfiguration'; -$lang['_header_template'] = 'Vorlagen-Konfiguration'; +$lang['_header_template'] = 'Template-Konfiguration'; $lang['_header_undefined'] = 'Unbekannte Werte'; $lang['_basic'] = 'Grund-Konfiguration'; $lang['_display'] = 'Darstellungs-Konfiguration'; @@ -44,7 +44,7 @@ $lang['_syndication'] = 'Syndication-Konfiguration (RSS)'; $lang['_advanced'] = 'Erweiterte Konfiguration'; $lang['_network'] = 'Netzwerk-Konfiguration'; $lang['_plugin_sufix'] = 'Plugin-Konfiguration'; -$lang['_template_sufix'] = 'Vorlagen-Konfiguration'; +$lang['_template_sufix'] = 'Template-Konfiguration'; $lang['_msg_setting_undefined'] = 'Keine Konfigurationsmetadaten.'; $lang['_msg_setting_no_class'] = 'Keine Konfigurationsklasse.'; $lang['_msg_setting_no_default'] = 'Kein Standardwert.'; -- cgit v1.2.3 From eb12065057595644fb1dcd333930e0653c024049 Mon Sep 17 00:00:00 2001 From: Klap-in <klapinklapin@gmail.com> Date: Mon, 22 Apr 2013 20:46:05 +0200 Subject: fix ids in de lang of authAD --- lib/plugins/authad/lang/de/settings.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/plugins/authad/lang/de/settings.php b/lib/plugins/authad/lang/de/settings.php index 650f9f362..f4e86dedd 100644 --- a/lib/plugins/authad/lang/de/settings.php +++ b/lib/plugins/authad/lang/de/settings.php @@ -8,8 +8,8 @@ $lang['account_suffix'] = 'Ihr Account-Suffix. Z. B. <code>@my.domain.org</code>'; $lang['base_dn'] = 'Ihr Base-DN. Z. B. <code>DC=my,DC=domain,DC=org</code>'; $lang['domain_controllers'] = 'Eine Komma-separierte Liste von Domänen-Controllern. Z. B. <code>srv1.domain.org,srv2.domain.org</code>'; -$lang['ad_username'] = 'Ein priviligierter Active Directory-Benutzer mit Zugriff zu allen anderen Benutzerdaten. Optional, aber wird benötigt für Aktionen wie z. B. dass Senden von Benachrichtigungs-Mails.'; -$lang['ad_password'] = 'Das Passwort des obigen Benutzers.'; +$lang['admin_username'] = 'Ein priviligierter Active Directory-Benutzer mit Zugriff zu allen anderen Benutzerdaten. Optional, aber wird benötigt für Aktionen wie z. B. dass Senden von Benachrichtigungs-Mails.'; +$lang['admin_password'] = 'Das Passwort des obigen Benutzers.'; $lang['sso'] = 'Soll Single-Sign-On via Kerberos oder NTLM benutzt werden?'; $lang['real_primarygroup'] = 'Soll die echte primäre Gruppe aufgelöst werden anstelle der Annahme "Domain Users" (langsamer)'; $lang['use_ssl'] = 'SSL-Verbindung benutzen? Falls ja, TLS unterhalb nicht aktivieren.'; -- cgit v1.2.3 From 5f6a84c5e12312db9b5bebf876989faf4aa8eb7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EB=AA=85=EC=A7=84?= <aranet100@gmail.com> Date: Mon, 22 Apr 2013 21:49:37 +0200 Subject: Korean language update --- inc/lang/ko/lang.php | 10 +++++----- inc/lang/ko/locked.txt | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/inc/lang/ko/lang.php b/inc/lang/ko/lang.php index 93f8611d6..76d6a535d 100644 --- a/inc/lang/ko/lang.php +++ b/inc/lang/ko/lang.php @@ -246,10 +246,10 @@ $lang['img_keywords'] = '키워드'; $lang['img_width'] = '너비'; $lang['img_height'] = '높이'; $lang['img_manager'] = '미디어 관리자에서 보기'; -$lang['subscr_subscribe_success'] = '%s 사용자가 %s 구독 목록에 추가하였습니다'; +$lang['subscr_subscribe_success'] = '%s 사용자가 %s 구독 목록에 추가했습니다'; $lang['subscr_subscribe_error'] = '%s 사용자가 %s 구독 목록에 추가하는데 실패했습니다'; $lang['subscr_subscribe_noaddress'] = '로그인으로 연결된 주소가 없기 때문에 구독 목록에 추가할 수 없습니다'; -$lang['subscr_unsubscribe_success'] = '%s 사용자가 %s 구독 목록에서 삭제하였습니다'; +$lang['subscr_unsubscribe_success'] = '%s 사용자가 %s 구독 목록에서 삭제했습니다'; $lang['subscr_unsubscribe_error'] = '%s 사용자가 %s 구독 목록에서 삭제하는데 실패했습니다'; $lang['subscr_already_subscribed'] = '%s 사용자가 이미 %s에 구독하고 있습니다'; $lang['subscr_not_subscribed'] = '%s 사용자가 %s에 구독하고 있지 않습니다'; @@ -299,7 +299,7 @@ $lang['days'] = '%d일 전'; $lang['hours'] = '%d시간 전'; $lang['minutes'] = '%d분 전'; $lang['seconds'] = '%d초 전'; -$lang['wordblock'] = '스팸 문구를 포함하고 있어서 저장하지 않았습니다.'; +$lang['wordblock'] = '차단 문구(스팸 문구)를 포함하고 있어서 저장하지 않았습니다.'; $lang['media_uploadtab'] = '올리기'; $lang['media_searchtab'] = '찾기'; $lang['media_file'] = '파일'; @@ -311,11 +311,11 @@ $lang['media_list_rows'] = '목록'; $lang['media_sort_name'] = '이름'; $lang['media_sort_date'] = '날짜'; $lang['media_namespaces'] = '이름공간 선택'; -$lang['media_files'] = '%s의 파일'; +$lang['media_files'] = '%s에 있는 파일'; $lang['media_upload'] = '%s에 올리기'; $lang['media_search'] = '%s 찾기'; $lang['media_view'] = '%s'; -$lang['media_viewold'] = '%s의 %s'; +$lang['media_viewold'] = '%s (%s에 있음)'; $lang['media_edit'] = '%s 편집'; $lang['media_history'] = '%s 바뀜 내역'; $lang['media_meta_edited'] = '메타데이터가 수정됨'; diff --git a/inc/lang/ko/locked.txt b/inc/lang/ko/locked.txt index f4070d4bc..8e2eab9f9 100644 --- a/inc/lang/ko/locked.txt +++ b/inc/lang/ko/locked.txt @@ -1,3 +1,3 @@ ====== 문서 잠금 ====== -다른 사용자가 이 문서를 편집하기 위해 잠금을 실행하였습니다. 해당 사용자가 편집을 끝내거나 잠금이 해제될 때까지 기다리세요. \ No newline at end of file +다른 사용자가 이 문서를 편집하기 위해 잠금을 실행했습니다. 해당 사용자가 편집을 끝내거나 잠금이 해제될 때까지 기다리세요. \ No newline at end of file -- cgit v1.2.3 From 87945c0e9622dca02b441749b7ed54cc67801475 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EB=AA=85=EC=A7=84?= <aranet100@gmail.com> Date: Mon, 22 Apr 2013 21:50:17 +0200 Subject: Japanese language update --- inc/lang/ja/lang.php | 2 +- lib/plugins/authad/lang/ja/settings.php | 5 +++++ lib/plugins/authldap/lang/ja/settings.php | 5 +++++ lib/plugins/authmysql/lang/ja/settings.php | 5 +++++ lib/plugins/authpgsql/lang/ja/settings.php | 5 +++++ 5 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 lib/plugins/authad/lang/ja/settings.php create mode 100644 lib/plugins/authldap/lang/ja/settings.php create mode 100644 lib/plugins/authmysql/lang/ja/settings.php create mode 100644 lib/plugins/authpgsql/lang/ja/settings.php diff --git a/inc/lang/ja/lang.php b/inc/lang/ja/lang.php index 7997889e4..d8d0864ae 100644 --- a/inc/lang/ja/lang.php +++ b/inc/lang/ja/lang.php @@ -310,7 +310,7 @@ $lang['media_files'] = '%s 内のファイル'; $lang['media_upload'] = '%s にアップロード'; $lang['media_search'] = '%s 内で検索'; $lang['media_view'] = '%s'; -$lang['media_viewold'] = '%s at %s'; +$lang['media_viewold'] = '%s(%sである)'; $lang['media_edit'] = '%s を編集'; $lang['media_history'] = '%s の履歴'; $lang['media_meta_edited'] = 'メタデータが編集されました'; diff --git a/lib/plugins/authad/lang/ja/settings.php b/lib/plugins/authad/lang/ja/settings.php new file mode 100644 index 000000000..576f0eeb5 --- /dev/null +++ b/lib/plugins/authad/lang/ja/settings.php @@ -0,0 +1,5 @@ +<?php +/** + * Japanese language file + * + */ diff --git a/lib/plugins/authldap/lang/ja/settings.php b/lib/plugins/authldap/lang/ja/settings.php new file mode 100644 index 000000000..576f0eeb5 --- /dev/null +++ b/lib/plugins/authldap/lang/ja/settings.php @@ -0,0 +1,5 @@ +<?php +/** + * Japanese language file + * + */ diff --git a/lib/plugins/authmysql/lang/ja/settings.php b/lib/plugins/authmysql/lang/ja/settings.php new file mode 100644 index 000000000..576f0eeb5 --- /dev/null +++ b/lib/plugins/authmysql/lang/ja/settings.php @@ -0,0 +1,5 @@ +<?php +/** + * Japanese language file + * + */ diff --git a/lib/plugins/authpgsql/lang/ja/settings.php b/lib/plugins/authpgsql/lang/ja/settings.php new file mode 100644 index 000000000..576f0eeb5 --- /dev/null +++ b/lib/plugins/authpgsql/lang/ja/settings.php @@ -0,0 +1,5 @@ +<?php +/** + * Japanese language file + * + */ -- cgit v1.2.3 From 1e52e72a2e603634696a9f6db2fae3daf1d821fa Mon Sep 17 00:00:00 2001 From: Andreas Gohr <andi@splitbrain.org> Date: Mon, 22 Apr 2013 22:03:13 +0200 Subject: fix expiry check for adLDAP version FS#2759 --- lib/plugins/authad/auth.php | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/lib/plugins/authad/auth.php b/lib/plugins/authad/auth.php index 5985cd18f..95a25c5af 100644 --- a/lib/plugins/authad/auth.php +++ b/lib/plugins/authad/auth.php @@ -218,22 +218,24 @@ class auth_plugin_authad extends DokuWiki_Auth_Plugin { // check expiry time if($info['expires'] && $this->conf['expirywarn']){ - $timeleft = $adldap->user()->passwordExpiry($user); // returns unixtime - $timeleft = round($timeleft/(24*60*60)); - $info['expiresin'] = $timeleft; - - // if this is the current user, warn him (once per request only) - if(($_SERVER['REMOTE_USER'] == $user) && - ($timeleft <= $this->conf['expirywarn']) && - !$this->msgshown - ) { - $msg = sprintf($lang['authpwdexpire'], $timeleft); - if($this->canDo('modPass')) { - $url = wl($ID, array('do'=> 'profile')); - $msg .= ' <a href="'.$url.'">'.$lang['btn_profile'].'</a>'; + $expiry = $adldap->user()->passwordExpiry($user); + if(is_array($expiry)){ + $info['expiresat'] = $expiry['expiryts']; + $info['expiresin'] = round(($info['expiresat'] - time())/(24*60*60)); + + // if this is the current user, warn him (once per request only) + if(($_SERVER['REMOTE_USER'] == $user) && + ($info['expiresin'] <= $this->conf['expirywarn']) && + !$this->msgshown + ) { + $msg = sprintf($lang['authpwdexpire'], $info['expiresin']); + if($this->canDo('modPass')) { + $url = wl($ID, array('do'=> 'profile')); + $msg .= ' <a href="'.$url.'">'.$lang['btn_profile'].'</a>'; + } + msg($msg); + $this->msgshown = true; } - msg($msg); - $this->msgshown = true; } } -- cgit v1.2.3 From 14642325892b50c3a95bead35efca7c5a6f16dc7 Mon Sep 17 00:00:00 2001 From: Andreas Gohr <gohr@cosmocode.de> Date: Thu, 25 Apr 2013 15:57:55 +0200 Subject: authad: don't request empty fields --- lib/plugins/authad/auth.php | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/plugins/authad/auth.php b/lib/plugins/authad/auth.php index 95a25c5af..d6455c751 100644 --- a/lib/plugins/authad/auth.php +++ b/lib/plugins/authad/auth.php @@ -172,6 +172,7 @@ class auth_plugin_authad extends DokuWiki_Auth_Plugin { // add additional fields to read $fields = array_merge($fields, $this->conf['additional']); $fields = array_unique($fields); + $fields = array_filter($fields); //get info for given user $result = $adldap->user()->info($this->_userName($user), $fields); -- cgit v1.2.3 From 8257d713a47c1819c2c33ddd2b868eea62d9f6fc Mon Sep 17 00:00:00 2001 From: Andreas Gohr <gohr@cosmocode.de> Date: Thu, 25 Apr 2013 16:05:53 +0200 Subject: authad: added compatibility for old option names adLDAP renamed the ad_username and ad_password to admin_username admin_password recently. this makes our backend recognize the old settings --- lib/plugins/authad/auth.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/plugins/authad/auth.php b/lib/plugins/authad/auth.php index d6455c751..5d5f532b6 100644 --- a/lib/plugins/authad/auth.php +++ b/lib/plugins/authad/auth.php @@ -465,6 +465,10 @@ class auth_plugin_authad extends DokuWiki_Auth_Plugin { $opts['domain_controllers'] = array_map('trim', $opts['domain_controllers']); $opts['domain_controllers'] = array_filter($opts['domain_controllers']); + // compatibility with old option name + if(empty($opts['admin_username']) && !empty($opts['ad_username'])) $opts['admin_username'] = $opts['ad_username']; + if(empty($opts['admin_password']) && !empty($opts['ad_password'])) $opts['admin_password'] = $opts['ad_password']; + // we can change the password if SSL is set if($opts['use_ssl'] || $opts['use_tls']) { $this->cando['modPass'] = true; @@ -472,7 +476,7 @@ class auth_plugin_authad extends DokuWiki_Auth_Plugin { $this->cando['modPass'] = false; } - if(isset($opts['admin_username']) && isset($opts['admin_password'])) { + if(!empty($opts['admin_username']) && !empty($opts['admin_password'])) { $this->cando['getUsers'] = true; } else { $this->cando['getUsers'] = false; -- cgit v1.2.3 From a154806fb54c04841a42641bf5d66716d89c1554 Mon Sep 17 00:00:00 2001 From: Andreas Gohr <gohr@cosmocode.de> Date: Thu, 25 Apr 2013 16:43:54 +0200 Subject: authad: capabilities depend on userdomain specific config --- inc/html.php | 2 ++ lib/plugins/authad/auth.php | 13 +++++++++++++ 2 files changed, 15 insertions(+) diff --git a/inc/html.php b/inc/html.php index fb39fcb3c..3bef75eab 100644 --- a/inc/html.php +++ b/inc/html.php @@ -1352,6 +1352,8 @@ function html_updateprofile(){ /** @var auth_basic $auth */ global $auth; + var_dump($auth); + print p_locale_xhtml('updateprofile'); $fullname = $INPUT->post->str('fullname', $INFO['userinfo']['name'], true); diff --git a/lib/plugins/authad/auth.php b/lib/plugins/authad/auth.php index 5d5f532b6..b6b5dd268 100644 --- a/lib/plugins/authad/auth.php +++ b/lib/plugins/authad/auth.php @@ -110,6 +110,19 @@ class auth_plugin_authad extends DokuWiki_Auth_Plugin { $this->cando['modMail'] = true; } + /** + * Load domain config on capability check + * + * @param string $cap + * @return bool + */ + public function canDo($cap) { + //capabilities depend on config, which may change depending on domain + $domain = $this->_userDomain($_SERVER['REMOTE_USER']); + $this->_loadServerConfig($domain); + return parent::canDo($cap); + } + /** * Check user+password [required auth function] * -- cgit v1.2.3 From c366e16a83b0dcd4ad853358daf8cf6ecd8b3cd6 Mon Sep 17 00:00:00 2001 From: Andreas Gohr <gohr@cosmocode.de> Date: Thu, 25 Apr 2013 17:03:19 +0200 Subject: removed debug statement thanks @Klap-in --- inc/html.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/inc/html.php b/inc/html.php index 3bef75eab..fb39fcb3c 100644 --- a/inc/html.php +++ b/inc/html.php @@ -1352,8 +1352,6 @@ function html_updateprofile(){ /** @var auth_basic $auth */ global $auth; - var_dump($auth); - print p_locale_xhtml('updateprofile'); $fullname = $INPUT->post->str('fullname', $INFO['userinfo']['name'], true); -- cgit v1.2.3 From 28cac1091e0363924084330e38c0a35e1cdc06b6 Mon Sep 17 00:00:00 2001 From: Satoshi Sahara <sahara.satoshi@gmail.com> Date: Fri, 26 Apr 2013 14:31:42 +0200 Subject: Japanese language update --- lib/plugins/usermanager/lang/ja/lang.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/plugins/usermanager/lang/ja/lang.php b/lib/plugins/usermanager/lang/ja/lang.php index b5fd556dc..f9ad0814c 100644 --- a/lib/plugins/usermanager/lang/ja/lang.php +++ b/lib/plugins/usermanager/lang/ja/lang.php @@ -7,6 +7,7 @@ * @author Daniel Dupriest <kououken@gmail.com> * @author Kazutaka Miyasaka <kazmiya@gmail.com> * @author Taisuke Shimamoto <dentostar@gmail.com> + * @author Satoshi Sahara <sahara.satoshi@gmail.com> */ $lang['menu'] = 'ユーザー管理'; $lang['noauth'] = '(ユーザー認証が無効です)'; @@ -43,7 +44,7 @@ $lang['last'] = '最後'; $lang['edit_usermissing'] = '選択したユーザーは見つかりません。削除もしくは変更された可能性があります。'; $lang['user_notify'] = '通知するユーザー'; $lang['note_notify'] = 'ユーザーが新しいパスワードを設定した場合のみ、通知メールが送信されます。'; -$lang['note_group'] = 'グループを指定しない場合は、既定のグループ(%s)に登録されいます。'; +$lang['note_group'] = 'グループを指定しない場合は、既定のグループ(%s)に登録されます。'; $lang['note_pass'] = 'パスワードを空欄とした場合は、パスワードを自動的に生成します。この場合、ユーザーへの通知が有効となります。'; $lang['add_ok'] = 'ユーザーを登録しました'; $lang['add_fail'] = 'ユーザーの登録に失敗しました'; -- cgit v1.2.3 From 9199f1a464f80d9c6b8a996a508ba051e3223eac Mon Sep 17 00:00:00 2001 From: "Ivan I. Udovichenko" <sendtome@mymailbox.pp.ua> Date: Fri, 26 Apr 2013 14:32:47 +0200 Subject: Russian language update --- inc/lang/ru/lang.php | 6 +++++ lib/plugins/acl/lang/ru/lang.php | 1 + lib/plugins/authad/lang/ru/settings.php | 6 +++++ lib/plugins/authldap/lang/ru/settings.php | 6 +++++ lib/plugins/authmysql/lang/ru/settings.php | 41 ++++++++++++++++++++++++++++++ lib/plugins/authpgsql/lang/ru/settings.php | 6 +++++ lib/plugins/config/lang/ru/lang.php | 1 + lib/plugins/plugin/lang/ru/lang.php | 1 + lib/plugins/popularity/lang/ru/lang.php | 1 + lib/plugins/revert/lang/ru/lang.php | 1 + lib/plugins/usermanager/lang/ru/lang.php | 1 + 11 files changed, 71 insertions(+) create mode 100644 lib/plugins/authad/lang/ru/settings.php create mode 100644 lib/plugins/authldap/lang/ru/settings.php create mode 100644 lib/plugins/authmysql/lang/ru/settings.php create mode 100644 lib/plugins/authpgsql/lang/ru/settings.php diff --git a/inc/lang/ru/lang.php b/inc/lang/ru/lang.php index 52e0ef3d6..6709ebc59 100644 --- a/inc/lang/ru/lang.php +++ b/inc/lang/ru/lang.php @@ -20,6 +20,7 @@ * @author Ladyko Andrey <fylh@succexy.spb.ru> * @author Eugene <windy.wanderer@gmail.com> * @author Johnny Utah <pcpa@cyberpunk.su> + * @author Ivan I. Udovichenko (sendtome@mymailbox.pp.ua) */ $lang['encoding'] = ' utf-8'; $lang['direction'] = 'ltr'; @@ -270,6 +271,8 @@ $lang['subscr_m_unsubscribe'] = 'Отменить подписку'; $lang['subscr_m_subscribe'] = 'Подписаться'; $lang['subscr_m_receive'] = 'Получить'; $lang['subscr_style_every'] = 'уведомлять о каждом изменении'; +$lang['subscr_style_digest'] = 'информационное электронное письмо со списком изменений для каждоый страницы (каждые %.2f дней)'; +$lang['subscr_style_list'] = 'список изменённых страниц со времени последнего отправленного электронного письма (каждые %.2f дней)'; $lang['authmodfailed'] = 'Неправильная конфигурация аутентификации пользователя. Пожалуйста, сообщите об этом своему администратору вики.'; $lang['authtempfail'] = 'Аутентификация пользователей временно недоступна. Если проблема продолжается какое-то время, пожалуйста, сообщите об этом своему администратору вики.'; $lang['authpwdexpire'] = 'Действие вашего пароля истекает через %d дней. Вы должны изменить его как можно скорее'; @@ -298,6 +301,9 @@ $lang['i_pol1'] = 'Общедоступная вики (чтен $lang['i_pol2'] = 'Закрытая вики (чтение, запись и загрузка файлов только для зарегистрированных пользователей)'; $lang['i_retry'] = 'Повторить попытку'; $lang['i_license'] = 'Пожалуйста, выберите тип лицензии для своей вики:'; +$lang['i_license_none'] = 'Не отображать информацию о лицензионных операциях'; +$lang['i_pop_field'] = 'Пожалуйста, помогите нам улучшить DokuWiki:'; +$lang['i_pop_label'] = 'Отправлять раз в месяц анонимную пользовательскую информацию разработчикам DokuWiki'; $lang['recent_global'] = 'Вы просматриваете изменения в пространстве имён <b>%s</b>. Вы можете также <a href="%s">просмотреть недавние изменения во всей вики</a>.'; $lang['years'] = '%d лет назад'; $lang['months'] = '%d месяц(ев) назад'; diff --git a/lib/plugins/acl/lang/ru/lang.php b/lib/plugins/acl/lang/ru/lang.php index 15ba78ef6..2501c00e2 100644 --- a/lib/plugins/acl/lang/ru/lang.php +++ b/lib/plugins/acl/lang/ru/lang.php @@ -16,6 +16,7 @@ * @author Ladyko Andrey <fylh@succexy.spb.ru> * @author Eugene <windy.wanderer@gmail.com> * @author Johnny Utah <pcpa@cyberpunk.su> + * @author Ivan I. Udovichenko (sendtome@mymailbox.pp.ua) */ $lang['admin_acl'] = 'Управление списками контроля доступа'; $lang['acl_group'] = 'Группа'; diff --git a/lib/plugins/authad/lang/ru/settings.php b/lib/plugins/authad/lang/ru/settings.php new file mode 100644 index 000000000..4c394080e --- /dev/null +++ b/lib/plugins/authad/lang/ru/settings.php @@ -0,0 +1,6 @@ +<?php +/** + * Russian language file + * + * @author Ivan I. Udovichenko (sendtome@mymailbox.pp.ua) + */ diff --git a/lib/plugins/authldap/lang/ru/settings.php b/lib/plugins/authldap/lang/ru/settings.php new file mode 100644 index 000000000..4c394080e --- /dev/null +++ b/lib/plugins/authldap/lang/ru/settings.php @@ -0,0 +1,6 @@ +<?php +/** + * Russian language file + * + * @author Ivan I. Udovichenko (sendtome@mymailbox.pp.ua) + */ diff --git a/lib/plugins/authmysql/lang/ru/settings.php b/lib/plugins/authmysql/lang/ru/settings.php new file mode 100644 index 000000000..066598331 --- /dev/null +++ b/lib/plugins/authmysql/lang/ru/settings.php @@ -0,0 +1,41 @@ +<?php +/** + * Russian language file + * + * @author Ivan I. Udovichenko (sendtome@mymailbox.pp.ua) + */ +$lang['server'] = 'Ваш MySQL-сервер'; +$lang['user'] = 'Имя пользователя MySQL'; +$lang['password'] = 'Пароль пользователя MySQL'; +$lang['database'] = 'Имя базы данных'; +$lang['charset'] = 'Используемый набор символов в базе данных'; +$lang['debug'] = 'Отображение дополнительной отладочной информации'; +$lang['forwardClearPass'] = 'Передача пароля пользователя открытым текстом, вместо зашифрованной формы в используемом выражении SQL'; +$lang['TablesToLock'] = 'Имена таблиц (через запятую), которые необходимо ограничение для записи'; +$lang['checkPass'] = 'Выражение SQL, осуществляющее проверку пароля'; +$lang['getUserInfo'] = 'Выражение SQL, осуществляющее извлечение информации о пользователе'; +$lang['getGroups'] = 'Выражение SQL, осуществляющее извлечение информации о членстве пользователе в группах'; +$lang['getUsers'] = 'Выражение SQL, осуществляющее извлечение полного списка пользователей'; +$lang['FilterLogin'] = 'Выражение SQL, осуществляющее фильтрацию пользователей по пользовательскому имени'; +$lang['FilterName'] = 'Выражение SQL, осуществляющее фильтрацию пользователей по полному имени'; +$lang['FilterEmail'] = 'Выражение SQL, осуществляющее фильтрацию пользователей по адресу электронной почты'; +$lang['FilterGroup'] = 'Выражение SQL, осуществляющее фильтрацию пользователей согласно членству в группе'; +$lang['SortOrder'] = 'Выражение SQL, осуществляющее сортировку пользователей'; +$lang['addUser'] = 'Выражение SQL, осуществляющее добавление нового опльзователя'; +$lang['addGroup'] = 'Выражение SQL, осуществляющее добавление новой группы'; +$lang['addUserGroup'] = 'Выражение SQL, осуществляющее добавление пользователя в существующую группу'; +$lang['delGroup'] = 'Выражение SQL, осуществляющее удаление группы'; +$lang['getUserID'] = 'Выражение SQL, обеспечивающее получение первичного ключа пользователя'; +$lang['delUser'] = 'Выражение SQL, осуществляющее удаление пользователя'; +$lang['delUserRefs'] = 'Выражение SQL, осуществляющее удаление пользователя из всех групп'; +$lang['updateUser'] = 'Выражение SQL, осуществляющее обновление профиля пользователя'; +$lang['UpdateLogin'] = 'Условие для обновления имени пользователя'; +$lang['UpdatePass'] = 'Условие для обновления пароля пользователя'; +$lang['UpdateEmail'] = 'Условие для обновления адреса электронной почты пользователя'; +$lang['UpdateName'] = 'Условие для обновления полного имени пользователя'; +$lang['UpdateTarget'] = 'Условие для идентификации пользователя при обновлении'; +$lang['delUserGroup'] = 'Выражение SQL, осуществляющее удаление пользователя из указанной группы'; +$lang['getGroupID'] = 'Выражение SQL, обеспечивающее получение первичного ключа указанной группы'; +$lang['debug_o_0'] = 'ни один из вариантов'; +$lang['debug_o_1'] = 'только при возникновении ошибок'; +$lang['debug_o_2'] = 'все SQL-запросы'; diff --git a/lib/plugins/authpgsql/lang/ru/settings.php b/lib/plugins/authpgsql/lang/ru/settings.php new file mode 100644 index 000000000..4c394080e --- /dev/null +++ b/lib/plugins/authpgsql/lang/ru/settings.php @@ -0,0 +1,6 @@ +<?php +/** + * Russian language file + * + * @author Ivan I. Udovichenko (sendtome@mymailbox.pp.ua) + */ diff --git a/lib/plugins/config/lang/ru/lang.php b/lib/plugins/config/lang/ru/lang.php index 36e04686d..42cbbd35a 100644 --- a/lib/plugins/config/lang/ru/lang.php +++ b/lib/plugins/config/lang/ru/lang.php @@ -17,6 +17,7 @@ * @author Ladyko Andrey <fylh@succexy.spb.ru> * @author Eugene <windy.wanderer@gmail.com> * @author Johnny Utah <pcpa@cyberpunk.su> + * @author Ivan I. Udovichenko (sendtome@mymailbox.pp.ua) */ $lang['menu'] = 'Настройки вики'; $lang['error'] = 'Настройки не были сохранены из-за ошибки в одном из значений. Пожалуйста, проверьте свои изменения и попробуйте ещё раз.<br />Неправильные значения будут обведены красной рамкой.'; diff --git a/lib/plugins/plugin/lang/ru/lang.php b/lib/plugins/plugin/lang/ru/lang.php index f011c9954..7b9579e96 100644 --- a/lib/plugins/plugin/lang/ru/lang.php +++ b/lib/plugins/plugin/lang/ru/lang.php @@ -17,6 +17,7 @@ * @author Ladyko Andrey <fylh@succexy.spb.ru> * @author Eugene <windy.wanderer@gmail.com> * @author Johnny Utah <pcpa@cyberpunk.su> + * @author Ivan I. Udovichenko (sendtome@mymailbox.pp.ua) */ $lang['menu'] = 'Управление плагинами'; $lang['download'] = 'Скачать и установить новый плагин'; diff --git a/lib/plugins/popularity/lang/ru/lang.php b/lib/plugins/popularity/lang/ru/lang.php index 0e29c795d..a7f33156f 100644 --- a/lib/plugins/popularity/lang/ru/lang.php +++ b/lib/plugins/popularity/lang/ru/lang.php @@ -14,6 +14,7 @@ * @author Ladyko Andrey <fylh@succexy.spb.ru> * @author Eugene <windy.wanderer@gmail.com> * @author Johnny Utah <pcpa@cyberpunk.su> + * @author Ivan I. Udovichenko (sendtome@mymailbox.pp.ua) */ $lang['name'] = 'Сбор информации о популярности (для загрузки может потребоваться некоторое время)'; $lang['submit'] = 'Отправить данные'; diff --git a/lib/plugins/revert/lang/ru/lang.php b/lib/plugins/revert/lang/ru/lang.php index 4abe37e6a..817bd1064 100644 --- a/lib/plugins/revert/lang/ru/lang.php +++ b/lib/plugins/revert/lang/ru/lang.php @@ -15,6 +15,7 @@ * @author Ladyko Andrey <fylh@succexy.spb.ru> * @author Eugene <windy.wanderer@gmail.com> * @author Johnny Utah <pcpa@cyberpunk.su> + * @author Ivan I. Udovichenko (sendtome@mymailbox.pp.ua) */ $lang['menu'] = 'Менеджер откаток'; $lang['filter'] = 'Поиск спам-страниц'; diff --git a/lib/plugins/usermanager/lang/ru/lang.php b/lib/plugins/usermanager/lang/ru/lang.php index eb9f26be6..29cee6576 100644 --- a/lib/plugins/usermanager/lang/ru/lang.php +++ b/lib/plugins/usermanager/lang/ru/lang.php @@ -17,6 +17,7 @@ * @author Ladyko Andrey <fylh@succexy.spb.ru> * @author Eugene <windy.wanderer@gmail.com> * @author Johnny Utah <pcpa@cyberpunk.su> + * @author Ivan I. Udovichenko (sendtome@mymailbox.pp.ua) */ $lang['menu'] = 'Управление пользователями'; $lang['noauth'] = '(авторизация пользователей недоступна)'; -- cgit v1.2.3 From 4bc058637bdcf381c07dfb96502b96afa71df76a Mon Sep 17 00:00:00 2001 From: Anika Henke <anika@selfthinker.org> Date: Fri, 3 May 2013 01:04:59 +0100 Subject: fixed missing css placeholders for page container --- lib/tpl/dokuwiki/css/design.css | 6 +++--- lib/tpl/dokuwiki/css/mobile.css | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/tpl/dokuwiki/css/design.css b/lib/tpl/dokuwiki/css/design.css index 2eb357a59..457414839 100644 --- a/lib/tpl/dokuwiki/css/design.css +++ b/lib/tpl/dokuwiki/css/design.css @@ -341,15 +341,15 @@ padding: .1em .35em; border-top-left-radius: 2px; border-top-right-radius: 2px; - box-shadow: 0 0 .5em #999; + box-shadow: 0 0 .5em __text_alt__; display: block; } .dokuwiki div.page { background: __background__; color: inherit; - border: 1px solid #eee; - box-shadow: 0 0 .5em #999; + border: 1px solid __background_alt__; + box-shadow: 0 0 .5em __text_alt__; border-radius: 2px; padding: 1.556em 2em 2em; margin-bottom: .5em; diff --git a/lib/tpl/dokuwiki/css/mobile.css b/lib/tpl/dokuwiki/css/mobile.css index e1d4dda72..71f80599d 100644 --- a/lib/tpl/dokuwiki/css/mobile.css +++ b/lib/tpl/dokuwiki/css/mobile.css @@ -32,7 +32,7 @@ background: __background__; color: inherit; border: 1px solid #eee; - box-shadow: 0 0 .5em #999; + box-shadow: 0 0 .5em __text_alt__; border-radius: 2px; padding: 1em; margin-bottom: .5em; -- cgit v1.2.3 From e63eccff3ef8998a3dac6034132970be5dad0069 Mon Sep 17 00:00:00 2001 From: Andreas Gohr <andi@splitbrain.org> Date: Fri, 3 May 2013 12:11:34 +0200 Subject: use correct endpoint in tpl_actiondropdown FS#2760 --- inc/template.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inc/template.php b/inc/template.php index 415b56de7..a87650b84 100644 --- a/inc/template.php +++ b/inc/template.php @@ -1373,7 +1373,7 @@ function tpl_actiondropdown($empty = '', $button = '>') { global $REV; global $lang; - echo '<form action="'.DOKU_SCRIPT.'" method="get" accept-charset="utf-8">'; + echo '<form action="'.script().'" method="get" accept-charset="utf-8">'; echo '<div class="no">'; echo '<input type="hidden" name="id" value="'.$ID.'" />'; if($REV) echo '<input type="hidden" name="rev" value="'.$REV.'" />'; -- cgit v1.2.3 From 46ac8ef9ac8c7465449cd3d33c21148c75241ac8 Mon Sep 17 00:00:00 2001 From: Andreas Gohr <andi@splitbrain.org> Date: Fri, 3 May 2013 17:52:48 +0200 Subject: Tar: avoid lone zero blocks when adding 0 byte files --- inc/Tar.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inc/Tar.class.php b/inc/Tar.class.php index 20f397395..10e82109b 100644 --- a/inc/Tar.class.php +++ b/inc/Tar.class.php @@ -295,7 +295,7 @@ class Tar { filemtime($file) ); - while(!feof($fp)) { + if(filesize($file)) while(!feof($fp)) { $packed = pack("a512", fread($fp, 512)); $this->writebytes($packed); } -- cgit v1.2.3 From 6db7468b987c4b5f9bcfdd7e98ceb1883c49a364 Mon Sep 17 00:00:00 2001 From: Andreas Gohr <andi@splitbrain.org> Date: Sun, 5 May 2013 14:38:10 +0200 Subject: make sure loaded text has the right encoding When pages contain non-UTF8 chars (eg. when posted through a script or when edited on the filesystem, parts of DokuWiki can break resulting in missing page content. This fixes these problems by forcing the content to UTF-8 on load. This will result in bad characters for input that is not latin1 but contents will at least be visible. --- inc/common.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/inc/common.php b/inc/common.php index 27f90b53b..110350951 100644 --- a/inc/common.php +++ b/inc/common.php @@ -781,11 +781,19 @@ function unlock($id) { /** * convert line ending to unix format * + * also makes sure the given text is valid UTF-8 + * * @see formText() for 2crlf conversion * @author Andreas Gohr <andi@splitbrain.org> */ function cleanText($text) { $text = preg_replace("/(\015\012)|(\015)/", "\012", $text); + + // if the text is not valid UTF-8 we simply assume latin1 + // this won't break any worse than it breaks with the wrong encoding + // but might actually fix the problem in many cases + if(!utf8_check($text)) $text = utf8_encode($text); + return $text; } -- cgit v1.2.3 From 3e967eac778be30e35501150970fed880513c841 Mon Sep 17 00:00:00 2001 From: Andreas Gohr <andi@splitbrain.org> Date: Sun, 5 May 2013 19:52:33 +0200 Subject: removed superfluous parameter FS#2773 --- feed.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feed.php b/feed.php index 73fa0e05f..8d1dcea6a 100644 --- a/feed.php +++ b/feed.php @@ -242,7 +242,7 @@ function rss_buildItems(&$rss, &$data, $opt) { ), '&', true ); } else { - $item->link = wl($id, 'rev='.$date, true, '&', true); + $item->link = wl($id, 'rev='.$date, true, '&'); } break; case 'rev': -- cgit v1.2.3 From 63e0b28d73c4be5de6f734211d5c09992d1b7541 Mon Sep 17 00:00:00 2001 From: Andreas Gohr <andi@splitbrain.org> Date: Sun, 5 May 2013 19:54:52 +0200 Subject: fixed exception call FS#2772 --- inc/RemoteAPICore.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inc/RemoteAPICore.php b/inc/RemoteAPICore.php index 81b211ec8..4c940b39e 100644 --- a/inc/RemoteAPICore.php +++ b/inc/RemoteAPICore.php @@ -372,7 +372,7 @@ class RemoteAPICore { $file = wikiFN($id,$rev); $time = @filemtime($file); if(!$time){ - throw new RemoteException(10, 'The requested page does not exist', 121); + throw new RemoteException('The requested page does not exist', 121); } $info = getRevisionInfo($id, $time, 1024); -- cgit v1.2.3 From ead122f7cf2bcfdcecfa1a433014cc0d55ade898 Mon Sep 17 00:00:00 2001 From: Andreas Gohr <andi@splitbrain.org> Date: Sun, 5 May 2013 19:59:29 +0200 Subject: don't pass unused variable in doku.php FS#2774 --- doku.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doku.php b/doku.php index 46c64c535..c058bb64a 100644 --- a/doku.php +++ b/doku.php @@ -80,8 +80,8 @@ trigger_event('DOKUWIKI_STARTED', $tmp); //close session session_write_close(); -//do the work -act_dispatch($ACT); +//do the work (picks up what to do from global env) +act_dispatch(); $tmp = array(); // No event data trigger_event('DOKUWIKI_DONE', $tmp); -- cgit v1.2.3 From b055d7074c8f9415798be4f2fce8dfdea30d4f68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miroslav=20Ku=C4=8Dera?= <mkucera66@seznam.cz> Date: Sun, 5 May 2013 20:03:01 +0200 Subject: Czech language update --- inc/lang/cs/lang.php | 1 + lib/plugins/acl/lang/cs/lang.php | 1 + lib/plugins/authad/lang/cs/settings.php | 18 +++++++++++++ lib/plugins/authldap/lang/cs/settings.php | 21 +++++++++++++++ lib/plugins/authmysql/lang/cs/settings.php | 41 ++++++++++++++++++++++++++++++ lib/plugins/authpgsql/lang/cs/settings.php | 37 +++++++++++++++++++++++++++ lib/plugins/config/lang/cs/lang.php | 1 + lib/plugins/plugin/lang/cs/lang.php | 1 + lib/plugins/popularity/lang/cs/lang.php | 1 + lib/plugins/revert/lang/cs/lang.php | 1 + lib/plugins/usermanager/lang/cs/lang.php | 1 + 11 files changed, 124 insertions(+) create mode 100644 lib/plugins/authad/lang/cs/settings.php create mode 100644 lib/plugins/authldap/lang/cs/settings.php create mode 100644 lib/plugins/authmysql/lang/cs/settings.php create mode 100644 lib/plugins/authpgsql/lang/cs/settings.php diff --git a/inc/lang/cs/lang.php b/inc/lang/cs/lang.php index f0b8f3ba4..c01b72a1b 100644 --- a/inc/lang/cs/lang.php +++ b/inc/lang/cs/lang.php @@ -13,6 +13,7 @@ * @author zbynek.krivka@seznam.cz * @author Bohumir Zamecnik <bohumir.zamecnik@gmail.com> * @author Jakub A. Těšínský (j@kub.cz) + * @author mkucera66@seznam.cz */ $lang['encoding'] = 'utf-8'; $lang['direction'] = 'ltr'; diff --git a/lib/plugins/acl/lang/cs/lang.php b/lib/plugins/acl/lang/cs/lang.php index feb160a02..a4e59287a 100644 --- a/lib/plugins/acl/lang/cs/lang.php +++ b/lib/plugins/acl/lang/cs/lang.php @@ -12,6 +12,7 @@ * @author zbynek.krivka@seznam.cz * @author Bohumir Zamecnik <bohumir.zamecnik@gmail.com> * @author Jakub A. Těšínský (j@kub.cz) + * @author mkucera66@seznam.cz */ $lang['admin_acl'] = 'Správa přístupových práv'; $lang['acl_group'] = 'Skupina'; diff --git a/lib/plugins/authad/lang/cs/settings.php b/lib/plugins/authad/lang/cs/settings.php new file mode 100644 index 000000000..71f83afda --- /dev/null +++ b/lib/plugins/authad/lang/cs/settings.php @@ -0,0 +1,18 @@ +<?php +/** + * Czech language file + * + * @author mkucera66@seznam.cz + */ +$lang['account_suffix'] = 'Přípona vašeho účtu, tj. <code>@moje.domena.org</code>'; +$lang['base_dn'] = 'Vaše doménové jméno DN. tj. <code>DC=moje,DC=domena,DC=org</code>'; +$lang['domain_controllers'] = 'Čárkou oddělenových kontrol=rů, tj. <code>srv1.domena.org,srv2.domena.org</code>'; +$lang['admin_username'] = 'Privilegovaný uživatel Active Directory s přístupem ke všem datům. Volitelně, ale nutné pro určité akce typu zasílání mailů.'; +$lang['admin_password'] = 'Heslo uživatele výše'; +$lang['sso'] = 'Chcete přihlašování Single-Sign-On pomocí jádra Kerberos nebo NTLM ( autentizační protokol obvyklý ve Windows)?'; +$lang['real_primarygroup'] = 'Má být zjištěna primární skupina namísto vyhodnocení hodnoty "doménoví uživatelé" (pomalejší)'; +$lang['use_ssl'] = 'Použít spojení SSL? Pokud ano, nevyužívejte TLS níže.'; +$lang['use_tls'] = 'Použít spojení TLS? Pokud ano, nevyužívejte SSL výše.'; +$lang['debug'] = 'Zobrazit dodatečné debugovací výstupy při chybách?'; +$lang['expirywarn'] = 'Dny mezi varováním o vyprčšení hesla uživatele a jeho vypršením. 0 znaší vypnuto.'; +$lang['additional'] = 'Čárkou oddělený seznam dodatečných atributů získávaných z uživatelských dat. Využito některými pluginy.'; diff --git a/lib/plugins/authldap/lang/cs/settings.php b/lib/plugins/authldap/lang/cs/settings.php new file mode 100644 index 000000000..783d2a3ae --- /dev/null +++ b/lib/plugins/authldap/lang/cs/settings.php @@ -0,0 +1,21 @@ +<?php +/** + * Czech language file + * + * @author mkucera66@seznam.cz + */ +$lang['server'] = 'Váš server LDAP. Buď jméno hosta (<code>localhost</code>) nebo plně kvalifikovaný popis URL (<code>ldap://server.tld:389</code>)'; +$lang['port'] = 'Port serveru LDAP. Pokud není, bude využito URL výše'; +$lang['usertree'] = 'Kde najít uživatelské účty, tj. <code>ou=Lide, dc=server, dc=tld</code>'; +$lang['grouptree'] = 'Kde najít uživatelské skupiny, tj. <code>ou=Skupina, dc=server, dc=tld</code>'; +$lang['userfilter'] = 'Filter LDAPu pro vyhledávání uživatelských účtů, tj. <code>(&(uid=%{user})(objectClass=posixAccount))</code>'; +$lang['groupfilter'] = 'Filter LDAPu pro vyhledávání uživatelských skupin, tj. <code>(&(uid=%{user})(objectClass=posixAccount))</code>'; +$lang['version'] = 'Verze použitého protokolu. Můžete potřebovat jej nastavit na <code>3</code>'; +$lang['starttls'] = 'Využít spojení TLS?'; +$lang['referrals'] = 'Přeposílat odkazy?'; +$lang['binddn'] = 'Doménový název DN volitelně připojeného uživatele, pokus anonymní připojení není vyhovující, tj. <code>cn=admin, dc=muj, dc=domov</code>'; +$lang['bindpw'] = 'Heslo uživatele výše'; +$lang['userscope'] = 'Omezení rozsahu vyhledávání uživatele'; +$lang['groupscope'] = 'Omezení rozsahu vyhledávání skupiny'; +$lang['groupkey'] = 'Atribut šlenství uživatele ve skupinách (namísto standardních AD skupin), tj. skupina z oddělení nebo telefonní číslo'; +$lang['debug'] = 'Zobrazit dodatečné debugovací informace'; diff --git a/lib/plugins/authmysql/lang/cs/settings.php b/lib/plugins/authmysql/lang/cs/settings.php new file mode 100644 index 000000000..7fedefbbb --- /dev/null +++ b/lib/plugins/authmysql/lang/cs/settings.php @@ -0,0 +1,41 @@ +<?php +/** + * Czech language file + * + * @author mkucera66@seznam.cz + */ +$lang['server'] = 'Váš server MySQL'; +$lang['user'] = 'Uživatelské jméno pro MySQL'; +$lang['password'] = 'Heslo tohoto uživatele'; +$lang['database'] = 'Použtá databáze'; +$lang['charset'] = 'znaková sada použitá v databázi'; +$lang['debug'] = 'Zobrazit dodatečné debugovací informace'; +$lang['forwardClearPass'] = 'Posílat uživatelské heslo jako čistý text do příkazů SQL namísto využití volby passcrypt.'; +$lang['TablesToLock'] = 'Čárkou oddělený seznam tabulek, které mohou být zamčené během operací zápisu'; +$lang['checkPass'] = 'Příkaz SQL pro kontrolu hesel'; +$lang['getUserInfo'] = 'Příkaz SQL pro získání informací o uživateli'; +$lang['getGroups'] = 'Příkaz SQL pro získání uživatelovy skupiny'; +$lang['getUsers'] = 'Příkaz SQL pro seznam všech uživatelů'; +$lang['FilterLogin'] = 'Příkaz SQL pro filtrování uživatelů podle přihlašovacího jména'; +$lang['FilterName'] = 'Příkaz SQL pro filtrování uživatelů podle celého jména'; +$lang['FilterEmail'] = 'Příkaz SQL pro filtrování uživatelů podle adres emailů'; +$lang['FilterGroup'] = 'Příkaz SQL pro filtrování uživatelů podle členství ve skupinách'; +$lang['SortOrder'] = 'Příkaz SQL pro řazení uživatelů'; +$lang['addUser'] = 'Příkaz SQL pro přidání nového uživatele'; +$lang['addGroup'] = 'Příkaz SQL pro přidání nové skupiny'; +$lang['addUserGroup'] = 'Příkaz SQL pro přidání uživatele do existující skupiny'; +$lang['delGroup'] = 'Příkaz SQL pro vymazání skupiny'; +$lang['getUserID'] = 'Příkaz SQL pro získání primárního klíče uživatele'; +$lang['delUser'] = 'Příkaz SQL pro vymazání uživatele'; +$lang['delUserRefs'] = 'Příkaz SQL pro odstranění členství uživatele se všech skupin'; +$lang['updateUser'] = 'Příkaz SQL pro aktualizaci uživatelského profilu'; +$lang['UpdateLogin'] = 'Klauzule pro aktualizaci přihlačovacího jména uživatele'; +$lang['UpdatePass'] = 'Klauzule pro aktualizaci hesla uživatele'; +$lang['UpdateEmail'] = 'Klauzule pro aktualizaci emailové adresy uživatele'; +$lang['UpdateName'] = 'Klauzule pro aktualizaci celého jména uživatele'; +$lang['UpdateTarget'] = 'Omezující klauzule pro identifikaci uživatele při aktualizaci'; +$lang['delUserGroup'] = 'Příkaz SQL pro zrušení členství uživatele v dané skupině'; +$lang['getGroupID'] = 'Příkaz SQL pro získání primárního klíče skupiny'; +$lang['debug_o_0'] = 'nic'; +$lang['debug_o_1'] = 'pouze při chybách'; +$lang['debug_o_2'] = 'všechny dotazy SQL'; diff --git a/lib/plugins/authpgsql/lang/cs/settings.php b/lib/plugins/authpgsql/lang/cs/settings.php new file mode 100644 index 000000000..06abe86f4 --- /dev/null +++ b/lib/plugins/authpgsql/lang/cs/settings.php @@ -0,0 +1,37 @@ +<?php +/** + * Czech language file + * + * @author mkucera66@seznam.cz + */ +$lang['server'] = 'Váš server PostgreSQL'; +$lang['port'] = 'Port vašeho serveru PostgreSQL'; +$lang['user'] = 'Uživatelské jméno pro PostgreSQL'; +$lang['password'] = 'Heslo tohoto uživatele'; +$lang['database'] = 'Použtá databáze'; +$lang['debug'] = 'Zobrazit dodatečné debugovací informace'; +$lang['forwardClearPass'] = 'Posílat uživatelské heslo jako čistý text do příkazů SQL namísto využití volby passcrypt.'; +$lang['checkPass'] = 'Příkaz SQL pro kontrolu hesel'; +$lang['getUserInfo'] = 'Příkaz SQL pro získání informací o uživateli'; +$lang['getGroups'] = 'Příkaz SQL pro získání členství uživatele ve skupinách'; +$lang['getUsers'] = 'Příkaz SQL pro seznam všech uživatelů'; +$lang['FilterLogin'] = 'Příkaz SQL pro filtrování uživatelů podle přihlašovacího jména'; +$lang['FilterName'] = 'Příkaz SQL pro filtrování uživatelů podle celého jména'; +$lang['FilterEmail'] = 'Příkaz SQL pro filtrování uživatelů podle adres emailů'; +$lang['FilterGroup'] = 'Příkaz SQL pro filtrování uživatelů podle členství ve skupinách'; +$lang['SortOrder'] = 'Příkaz SQL pro řazení uživatelů'; +$lang['addUser'] = 'Příkaz SQL pro řazení uživatelů'; +$lang['addGroup'] = 'Příkaz SQL pro přidání nové skupiny'; +$lang['addUserGroup'] = 'Příkaz SQL pro přidání uživatele do existující skupiny'; +$lang['delGroup'] = 'Příkaz SQL pro vymazání skupiny'; +$lang['getUserID'] = 'Příkaz SQL pro získání primárního klíče uživatele'; +$lang['delUser'] = 'Příkaz SQL pro vymazání uživatele'; +$lang['delUserRefs'] = 'Příkaz SQL pro odstranění členství uživatele se všech skupin'; +$lang['updateUser'] = 'Příkaz SQL pro aktualizaci uživatelského profilu'; +$lang['UpdateLogin'] = 'Klauzule pro aktualizaci přihlačovacího jména uživatele'; +$lang['UpdatePass'] = 'Klauzule pro aktualizaci hesla uživatele'; +$lang['UpdateEmail'] = 'Klauzule pro aktualizaci emailové adresy uživatele'; +$lang['UpdateName'] = 'Klauzule pro aktualizaci celého jména uživatele'; +$lang['UpdateTarget'] = 'Omezující klauzule pro identifikaci uživatele při aktualizaci'; +$lang['delUserGroup'] = 'Příkaz SQL pro zrušení členství uživatele v dané skupině'; +$lang['getGroupID'] = 'Příkaz SQL pro získání primárního klíče skupiny'; diff --git a/lib/plugins/config/lang/cs/lang.php b/lib/plugins/config/lang/cs/lang.php index 383afebb4..d35ebec9b 100644 --- a/lib/plugins/config/lang/cs/lang.php +++ b/lib/plugins/config/lang/cs/lang.php @@ -12,6 +12,7 @@ * @author zbynek.krivka@seznam.cz * @author Bohumir Zamecnik <bohumir.zamecnik@gmail.com> * @author Jakub A. Těšínský (j@kub.cz) + * @author mkucera66@seznam.cz */ $lang['menu'] = 'Správa nastavení'; $lang['error'] = 'Nastavení nebyla změněna kvůli alespoň jedné neplatné položce, diff --git a/lib/plugins/plugin/lang/cs/lang.php b/lib/plugins/plugin/lang/cs/lang.php index 20a015cd4..98fae12c7 100644 --- a/lib/plugins/plugin/lang/cs/lang.php +++ b/lib/plugins/plugin/lang/cs/lang.php @@ -13,6 +13,7 @@ * @author zbynek.krivka@seznam.cz * @author Bohumir Zamecnik <bohumir.zamecnik@gmail.com> * @author Jakub A. Těšínský (j@kub.cz) + * @author mkucera66@seznam.cz */ $lang['menu'] = 'Správa pluginů'; $lang['download'] = 'Stáhnout a instalovat plugin'; diff --git a/lib/plugins/popularity/lang/cs/lang.php b/lib/plugins/popularity/lang/cs/lang.php index 0b0dbae7f..ee090a131 100644 --- a/lib/plugins/popularity/lang/cs/lang.php +++ b/lib/plugins/popularity/lang/cs/lang.php @@ -10,6 +10,7 @@ * @author zbynek.krivka@seznam.cz * @author Bohumir Zamecnik <bohumir.zamecnik@gmail.com> * @author Jakub A. Těšínský (j@kub.cz) + * @author mkucera66@seznam.cz */ $lang['name'] = 'Průzkum používání (může chviličku trvat, než se natáhne)'; $lang['submit'] = 'Odeslat data'; diff --git a/lib/plugins/revert/lang/cs/lang.php b/lib/plugins/revert/lang/cs/lang.php index dd8d7845c..eef3295ba 100644 --- a/lib/plugins/revert/lang/cs/lang.php +++ b/lib/plugins/revert/lang/cs/lang.php @@ -13,6 +13,7 @@ * @author zbynek.krivka@seznam.cz * @author Bohumir Zamecnik <bohumir.zamecnik@gmail.com> * @author Jakub A. Těšínský (j@kub.cz) + * @author mkucera66@seznam.cz */ $lang['menu'] = 'Obnova zaspamovaných stránek'; $lang['filter'] = 'Hledat zaspamované stránky'; diff --git a/lib/plugins/usermanager/lang/cs/lang.php b/lib/plugins/usermanager/lang/cs/lang.php index 6de408e14..9fc3a5e75 100644 --- a/lib/plugins/usermanager/lang/cs/lang.php +++ b/lib/plugins/usermanager/lang/cs/lang.php @@ -12,6 +12,7 @@ * @author zbynek.krivka@seznam.cz * @author Bohumir Zamecnik <bohumir.zamecnik@gmail.com> * @author Jakub A. Těšínský (j@kub.cz) + * @author mkucera66@seznam.cz */ $lang['menu'] = 'Správa uživatelů'; $lang['noauth'] = '(autentizace uživatelů není k dispozici)'; -- cgit v1.2.3 From 8fb341d2133fef951e0a7bb959440b93d5ca2e4a Mon Sep 17 00:00:00 2001 From: Satoshi Sahara <sahara.satoshi@gmail.com> Date: Sun, 5 May 2013 20:04:04 +0200 Subject: Japanese language update --- inc/lang/ja/lang.php | 16 +++++++------ inc/lang/ja/mailwrap.html | 13 +++++++++++ lib/plugins/acl/lang/ja/lang.php | 1 + lib/plugins/authad/lang/ja/settings.php | 1 + lib/plugins/authldap/lang/ja/settings.php | 1 + lib/plugins/authmysql/lang/ja/settings.php | 36 ++++++++++++++++++++++++++++++ lib/plugins/authpgsql/lang/ja/settings.php | 32 ++++++++++++++++++++++++++ lib/plugins/config/lang/ja/lang.php | 7 ++++-- lib/plugins/plugin/lang/ja/lang.php | 1 + lib/plugins/popularity/lang/ja/lang.php | 1 + lib/plugins/revert/lang/ja/lang.php | 1 + lib/plugins/usermanager/lang/ja/lang.php | 8 +++---- 12 files changed, 105 insertions(+), 13 deletions(-) create mode 100644 inc/lang/ja/mailwrap.html diff --git a/inc/lang/ja/lang.php b/inc/lang/ja/lang.php index d8d0864ae..34ff5b21d 100644 --- a/inc/lang/ja/lang.php +++ b/inc/lang/ja/lang.php @@ -8,6 +8,7 @@ * @author Daniel Dupriest <kououken@gmail.com> * @author Kazutaka Miyasaka <kazmiya@gmail.com> * @author Taisuke Shimamoto <dentostar@gmail.com> + * @author Satoshi Sahara <sahara.satoshi@gmail.com> */ $lang['encoding'] = 'utf-8'; $lang['direction'] = 'ltr'; @@ -93,7 +94,8 @@ $lang['searchmedia_in'] = '%s 内を検索'; $lang['txt_upload'] = 'アップロードするファイルを選んでください。'; $lang['txt_filename'] = '名前を変更してアップロード(オプション)'; $lang['txt_overwrt'] = '既存のファイルを上書き'; -$lang['lockedby'] = 'この文書は次のユーザによってロックされています'; +$lang['maxuploadsize'] = 'アップロード上限サイズ %s /ファイル'; +$lang['lockedby'] = 'この文書は次のユーザーによってロックされています'; $lang['lockexpire'] = 'ロック期限:'; $lang['js']['willexpire'] = '編集中の文書はロック期限を過ぎようとしています。このままロックする場合は、一度文書の確認を行って期限をリセットしてください。'; $lang['js']['notsavedyet'] = '変更は保存されません。このまま処理を続けてよろしいですか?'; @@ -121,8 +123,7 @@ $lang['js']['medialeft'] = 'イメージを左に寄せる'; $lang['js']['mediaright'] = 'イメージを右に寄せる'; $lang['js']['mediacenter'] = 'イメージを中央に寄せる'; $lang['js']['medianoalign'] = '位置を設定しない'; -$lang['js']['nosmblinks'] = 'ウィンドウズの共有フォルダへリンクは Microsoft Internet Explorer でのみ可能となります。 -当然、カットアンドペーストが使用できます。'; +$lang['js']['nosmblinks'] = 'ウィンドウズの共有フォルダへリンクは Microsoft Internet Explorer でしか機能しませんが、リンクをコピーして貼り付けることは可能です。'; $lang['js']['linkwiz'] = 'リンクウィザード'; $lang['js']['linkto'] = 'リンク先:'; $lang['js']['del_confirm'] = '選択した項目を本当に削除しますか?'; @@ -181,7 +182,7 @@ $lang['lastmod'] = '最終更新'; $lang['by'] = 'by'; $lang['deleted'] = '削除'; $lang['created'] = '作成'; -$lang['restored'] = '以前のバージョンを復元 (%s)'; +$lang['restored'] = '以前のリビジョンを復元 (%s)'; $lang['external_edit'] = '外部編集'; $lang['summary'] = '編集の概要'; $lang['noflash'] = 'この内容を表示するためには <a href="http://www.adobe.com/products/flashplayer/">Adobe Flash Plugin</a> が必要です。'; @@ -191,6 +192,7 @@ $lang['user_tools'] = 'ユーザ用ツール'; $lang['site_tools'] = 'サイト用ツール'; $lang['page_tools'] = 'ページ用ツール'; $lang['skip_to_content'] = '内容へ移動'; +$lang['sidebar'] = 'サイドバー'; $lang['mail_newpage'] = '文書の追加:'; $lang['mail_changed'] = '文書の変更:'; $lang['mail_subscribe_list'] = '名前空間内でページが変更:'; @@ -271,7 +273,7 @@ $lang['i_problems'] = '問題が発見されました。以下に示 $lang['i_modified'] = 'セキュリティの理由から、新規もしくはカスタマイズしていない DokuWiki に対してのみ、このスクリプトは有効です。 ダウンロードしたパッケージを再解凍して使用するか、 <a href="http://dokuwiki.org/install">Dokuwiki インストールガイド</a>を参考にしてインストールしてください。'; -$lang['i_funcna'] = 'PHPの関数 <code>%s</code> が使用できません。ホスティング会社が何らかの理由で無効にしている恐れがあります。'; +$lang['i_funcna'] = 'PHPの関数 <code>%s</code> が使用できません。ホスティング会社が何らかの理由で無効にしている可能性があります。'; $lang['i_phpver'] = 'PHPのバージョン <code>%s</code> が必要なバージョン <code>%s</code> より以前のものです。PHPのアップグレードが必要です。'; $lang['i_permfail'] = '<code>%s</code> に書き込みできません。このディレクトリの権限を確認して下さい。'; $lang['i_confexists'] = '<code>%s</code> は既に存在します'; @@ -286,7 +288,7 @@ $lang['i_pol1'] = 'パブリック Wiki(閲覧は全ての人 $lang['i_pol2'] = 'クローズド Wiki (登録ユーザーにのみ使用を許可)'; $lang['i_retry'] = '再試行'; $lang['i_license'] = 'あなたが作成したコンテンツが属するライセンスを選択してください:'; -$lang['recent_global'] = '現在、<b>%s</b> 名前空間内の変更点を閲覧中です。<a href="%s">Wiki全体の最近の変更点を確認する</a>ことも可能です。'; +$lang['recent_global'] = '現在、<b>%s</b> 名前空間内の変更点を閲覧中です。<a href="%s">Wiki全体の最近の変更点の確認</a>もできます。'; $lang['years'] = '%d年前'; $lang['months'] = '%dカ月前'; $lang['weeks'] = '%d週間前'; @@ -310,7 +312,7 @@ $lang['media_files'] = '%s 内のファイル'; $lang['media_upload'] = '%s にアップロード'; $lang['media_search'] = '%s 内で検索'; $lang['media_view'] = '%s'; -$lang['media_viewold'] = '%s(%sである)'; +$lang['media_viewold'] = '%s at %s'; $lang['media_edit'] = '%s を編集'; $lang['media_history'] = '%s の履歴'; $lang['media_meta_edited'] = 'メタデータが編集されました'; diff --git a/inc/lang/ja/mailwrap.html b/inc/lang/ja/mailwrap.html new file mode 100644 index 000000000..a9dd41480 --- /dev/null +++ b/inc/lang/ja/mailwrap.html @@ -0,0 +1,13 @@ +<html> +<head> +<title>@TITLE@ + + + + +@HTMLBODY@ + +

        +このメールは次の DokuWiki によって生成されました:
        @DOKUWIKIURL@.
        + + \ No newline at end of file diff --git a/lib/plugins/acl/lang/ja/lang.php b/lib/plugins/acl/lang/ja/lang.php index 5bebb58a9..0dd4d09c6 100644 --- a/lib/plugins/acl/lang/ja/lang.php +++ b/lib/plugins/acl/lang/ja/lang.php @@ -9,6 +9,7 @@ * @author Daniel Dupriest * @author Kazutaka Miyasaka * @author Taisuke Shimamoto + * @author Satoshi Sahara */ $lang['admin_acl'] = 'アクセスコントロール管理'; $lang['acl_group'] = 'グループ'; diff --git a/lib/plugins/authad/lang/ja/settings.php b/lib/plugins/authad/lang/ja/settings.php index 576f0eeb5..fdc6fc434 100644 --- a/lib/plugins/authad/lang/ja/settings.php +++ b/lib/plugins/authad/lang/ja/settings.php @@ -2,4 +2,5 @@ /** * Japanese language file * + * @author Satoshi Sahara */ diff --git a/lib/plugins/authldap/lang/ja/settings.php b/lib/plugins/authldap/lang/ja/settings.php index 576f0eeb5..fdc6fc434 100644 --- a/lib/plugins/authldap/lang/ja/settings.php +++ b/lib/plugins/authldap/lang/ja/settings.php @@ -2,4 +2,5 @@ /** * Japanese language file * + * @author Satoshi Sahara */ diff --git a/lib/plugins/authmysql/lang/ja/settings.php b/lib/plugins/authmysql/lang/ja/settings.php index 576f0eeb5..45f938fec 100644 --- a/lib/plugins/authmysql/lang/ja/settings.php +++ b/lib/plugins/authmysql/lang/ja/settings.php @@ -2,4 +2,40 @@ /** * Japanese language file * + * @author Satoshi Sahara */ +$lang['server'] = 'MySQL のホスト名'; +$lang['user'] = 'MySQL 接続用ユーザー名'; +$lang['password'] = 'MySQL 接続用ユーザーのパスワード'; +$lang['database'] = '使用するデータベース名'; +$lang['charset'] = 'データベースの文字コード'; +$lang['debug'] = 'デバック情報を表示する'; +$lang['forwardClearPass'] = '以下で定義する SQL ステートメントにおいて, パスワード変数 %{pass} を平文とする(DokiWiki側で暗号化しない)'; +$lang['TablesToLock'] = '書き込み時にロックするテーブル(コンマ区切りで列挙)'; +$lang['checkPass'] = 'パスワードの照合に用いる SQL ステートメント'; +$lang['getUserInfo'] = 'ユーザー情報の取得に用いる SQL ステートメント'; +$lang['getGroups'] = 'ユーザーが所属する全てのグループの取得に用いる SQL ステートメント'; +$lang['getUsers'] = 'ユーザーリストを取得する SQL ステートメント'; +$lang['FilterLogin'] = 'ユーザーリストをログイン名で絞り込む SQL 句'; +$lang['FilterName'] = 'ユーザーリストをフルネームで絞り込む SQL 句'; +$lang['FilterEmail'] = 'ユーザーリストをメールアドレスで絞り込む SQL 句'; +$lang['FilterGroup'] = 'ユーザーリストを所属グループで絞り込む SQL 句'; +$lang['SortOrder'] = 'ユーザーリストのソート方法を指定する SQL 句'; +$lang['addUser'] = '新規ユーザーを追加する SQL ステートメント'; +$lang['addGroup'] = '新規グループを追加する SQL ステートメント'; +$lang['addUserGroup'] = 'ユーザーをグループに配属する SQL ステートメント'; +$lang['delGroup'] = 'グループを削除する SQL ステートメント'; +$lang['getUserID'] = 'ユーザーIDの取得に用いる SQL ステートメント'; +$lang['delUser'] = 'ユーザーを削除する SQL ステートメント'; +$lang['delUserRefs'] = 'ユーザーのグループ所属を全て取り消す SQL ステートメント'; +$lang['updateUser'] = 'ユーザー情報を変更する SQL ステートメント'; +$lang['UpdateLogin'] = '変更後のログイン名を指定する SQL 句'; +$lang['UpdatePass'] = '変更後のパスワードを指定する SQL 句'; +$lang['UpdateEmail'] = '変更後のメールアドレスを指定する SQL 句'; +$lang['UpdateName'] = '変更後のフルネームを指定する SQL 句'; +$lang['UpdateTarget'] = '変更対象のユーザを特定するための SQL 句'; +$lang['delUserGroup'] = 'ユーザーをグループから除名する SQL ステートメント'; +$lang['getGroupID'] = 'グループIDの取得に用いる SQL ステートメント'; +$lang['debug_o_0'] = '表示しない'; +$lang['debug_o_1'] = 'エラー発生時のみ表示'; +$lang['debug_o_2'] = '全ての SQLクエリで表示'; diff --git a/lib/plugins/authpgsql/lang/ja/settings.php b/lib/plugins/authpgsql/lang/ja/settings.php index 576f0eeb5..4883caa4c 100644 --- a/lib/plugins/authpgsql/lang/ja/settings.php +++ b/lib/plugins/authpgsql/lang/ja/settings.php @@ -2,4 +2,36 @@ /** * Japanese language file * + * @author Satoshi Sahara */ +$lang['server'] = 'PostgreSQL のサーバー名'; +$lang['port'] = 'PostgreSQL サーバーのポート番号'; +$lang['user'] = 'PostgreSQL 接続用ユーザー名'; +$lang['password'] = 'PostgreSQL 接続用ユーザーのパスワード'; +$lang['database'] = '使用するデータベース名'; +$lang['debug'] = 'デバック情報を表示する'; +$lang['forwardClearPass'] = '以下で定義する SQL ステートメントにおいて, パスワード変数 %{pass} を平文とする(DokiWiki側で暗号化しない)'; +$lang['checkPass'] = 'パスワードの照合に用いる SQL ステートメント'; +$lang['getUserInfo'] = 'ユーザー情報の取得に用いる SQL ステートメント'; +$lang['getGroups'] = 'ユーザーが所属する全てのグループの取得に用いる SQL ステートメント'; +$lang['getUsers'] = 'ユーザーリストを取得する SQL ステートメント'; +$lang['FilterLogin'] = 'ユーザーリストをログイン名で絞り込む SQL 句'; +$lang['FilterName'] = 'ユーザーリストをフルネームで絞り込む SQL 句'; +$lang['FilterEmail'] = 'ユーザーリストをメールアドレスで絞り込む SQL 句'; +$lang['FilterGroup'] = 'ユーザーリストを所属グループで絞り込む SQL 句'; +$lang['SortOrder'] = 'ユーザーリストのソート方法を指定する SQL 句'; +$lang['addUser'] = '新規ユーザーを追加する SQL ステートメント'; +$lang['addGroup'] = '新規グループを追加する SQL ステートメント'; +$lang['addUserGroup'] = 'ユーザーをグループに配属する SQL ステートメント'; +$lang['delGroup'] = 'グループを削除する SQL ステートメント'; +$lang['getUserID'] = 'ユーザーIDの取得に用いる SQL ステートメン'; +$lang['delUser'] = 'ユーザーを削除する SQL ステートメント'; +$lang['delUserRefs'] = 'ユーザーのグループ所属を全て取り消す SQL ステートメント'; +$lang['updateUser'] = 'ユーザー情報を変更する SQL ステートメント'; +$lang['UpdateLogin'] = '変更後のログイン名を指定する SQL 句'; +$lang['UpdatePass'] = '変更後のパスワードを指定する SQL 句'; +$lang['UpdateEmail'] = '変更後のメールアドレスを指定する SQL 句'; +$lang['UpdateName'] = '変更後のフルネームを指定する SQL 句'; +$lang['UpdateTarget'] = '変更対象のユーザを特定するための SQL 句'; +$lang['delUserGroup'] = 'ユーザーをグループから除名する SQL ステートメント'; +$lang['getGroupID'] = 'グループIDの取得に用いる SQL ステートメント'; diff --git a/lib/plugins/config/lang/ja/lang.php b/lib/plugins/config/lang/ja/lang.php index a89123f8c..807436cca 100644 --- a/lib/plugins/config/lang/ja/lang.php +++ b/lib/plugins/config/lang/ja/lang.php @@ -9,6 +9,7 @@ * @author Daniel Dupriest * @author Kazutaka Miyasaka * @author Taisuke Shimamoto + * @author Satoshi Sahara */ $lang['menu'] = 'サイト設定'; $lang['error'] = '不正な値が存在するため、設定は更新されませんでした。入力値を確認してから、再度更新してください。 @@ -72,7 +73,7 @@ $lang['camelcase'] = 'キャメルケースリンク'; $lang['deaccent'] = 'ページ名アクセント'; $lang['useheading'] = '最初の見出しをページ名とする'; $lang['sneaky_index'] = 'デフォルトでは索引にすべての名前空間を表示しますが、この機能はユーザーに閲覧権限のない名前空間を非表示にします。ただし、閲覧が可能な副名前空間まで表示されなくなるため、ACLの設定が適正でない場合は索引機能が使えなくなる場合があります。'; -$lang['hidepages'] = '非公開ページ(Regex)'; +$lang['hidepages'] = '検索、サイトマップ、その他の自動インデックスの結果に表示しないページ(Regex)'; $lang['useacl'] = 'アクセス管理を行う(ACL)'; $lang['autopasswd'] = 'パスワードの自動生成(ACL)'; $lang['authtype'] = '認証方法(ACL)'; @@ -119,6 +120,7 @@ $lang['notify'] = '変更を通知するメールアドレス'; $lang['registernotify'] = '新規ユーザー登録を通知するメールアドレス'; $lang['mailfrom'] = 'メール送信時の送信元アドレス'; $lang['mailprefix'] = '自動メールの題名に使用する接頭語'; +$lang['htmlmail'] = 'メールをテキスト形式ではなく、HTML形式で送信する。'; $lang['sitemap'] = 'Googleサイトマップ作成頻度(日数)'; $lang['rss_type'] = 'RSSフィード形式'; $lang['rss_linkto'] = 'RSS内リンク先'; @@ -143,6 +145,7 @@ $lang['xsendfile'] = 'ウェブサーバーが静的ファイルを $lang['renderer_xhtml'] = 'Wikiの出力(xhtml)にレンダラーを使用する'; $lang['renderer__core'] = '%s (Dokuwikiコア)'; $lang['renderer__plugin'] = '%s (プラグイン)'; +$lang['dnslookups'] = 'ページを編集しているユーザーのIPアドレスからホスト名を逆引きする。利用できるDNSサーバーがない、あるいはこの機能が不要な場合にはオフにします。'; $lang['proxy____host'] = 'プロキシ - サーバー名'; $lang['proxy____port'] = 'プロキシ - ポート'; $lang['proxy____user'] = 'プロキシ - ユーザー名'; @@ -156,7 +159,7 @@ $lang['ftp____user'] = 'FTP ユーザー名(セーフモード対策 $lang['ftp____pass'] = 'FTP パスワード(セーフモード対策)'; $lang['ftp____root'] = 'FTP ルートディレクトリ(セーフモード対策)'; $lang['license_o_'] = '選択されていません'; -$lang['typography_o_0'] = '無し'; +$lang['typography_o_0'] = '変換しない'; $lang['typography_o_1'] = '二重引用符(ダブルクオート)のみ'; $lang['typography_o_2'] = 'すべての引用符(動作しない場合があります)'; $lang['userewrite_o_0'] = '使用しない'; diff --git a/lib/plugins/plugin/lang/ja/lang.php b/lib/plugins/plugin/lang/ja/lang.php index d366806c3..73f295157 100644 --- a/lib/plugins/plugin/lang/ja/lang.php +++ b/lib/plugins/plugin/lang/ja/lang.php @@ -9,6 +9,7 @@ * @author Daniel Dupriest * @author Kazutaka Miyasaka * @author Taisuke Shimamoto + * @author Satoshi Sahara */ $lang['menu'] = 'プラグイン管理'; $lang['download'] = 'プラグインのダウンロードとインストール'; diff --git a/lib/plugins/popularity/lang/ja/lang.php b/lib/plugins/popularity/lang/ja/lang.php index f5e280db5..774785511 100644 --- a/lib/plugins/popularity/lang/ja/lang.php +++ b/lib/plugins/popularity/lang/ja/lang.php @@ -7,6 +7,7 @@ * @author Kazutaka Miyasaka * @author Yuji Takenaka * @author Taisuke Shimamoto + * @author Satoshi Sahara */ $lang['name'] = '利用状況調査(ロードに少し時間が掛かります)'; $lang['submit'] = 'データ送信'; diff --git a/lib/plugins/revert/lang/ja/lang.php b/lib/plugins/revert/lang/ja/lang.php index bb5a9c150..7ef850ea7 100644 --- a/lib/plugins/revert/lang/ja/lang.php +++ b/lib/plugins/revert/lang/ja/lang.php @@ -6,6 +6,7 @@ * @author Daniel Dupriest * @author Kazutaka Miyasaka * @author Taisuke Shimamoto + * @author Satoshi Sahara */ $lang['menu'] = '復元管理'; $lang['filter'] = 'スパムを受けたページを検索'; diff --git a/lib/plugins/usermanager/lang/ja/lang.php b/lib/plugins/usermanager/lang/ja/lang.php index f9ad0814c..1510d1eb0 100644 --- a/lib/plugins/usermanager/lang/ja/lang.php +++ b/lib/plugins/usermanager/lang/ja/lang.php @@ -42,10 +42,10 @@ $lang['prev'] = '前へ'; $lang['next'] = '次へ'; $lang['last'] = '最後'; $lang['edit_usermissing'] = '選択したユーザーは見つかりません。削除もしくは変更された可能性があります。'; -$lang['user_notify'] = '通知するユーザー'; -$lang['note_notify'] = 'ユーザーが新しいパスワードを設定した場合のみ、通知メールが送信されます。'; -$lang['note_group'] = 'グループを指定しない場合は、既定のグループ(%s)に登録されます。'; -$lang['note_pass'] = 'パスワードを空欄とした場合は、パスワードを自動的に生成します。この場合、ユーザーへの通知が有効となります。'; +$lang['user_notify'] = 'ユーザーに通知する'; +$lang['note_notify'] = '通知メールは、ユーザーに新たなパスワードが設定された場合のみ送信されます。'; +$lang['note_group'] = 'グループを指定しない場合は、既定のグループ(%s)に配属されます。'; +$lang['note_pass'] = 'パスワードを空欄とした場合は、(”ユーザーに通知する”がチェックされていなくとも)自動生成したパスワードの通知がユーザー宛てに送信されます。'; $lang['add_ok'] = 'ユーザーを登録しました'; $lang['add_fail'] = 'ユーザーの登録に失敗しました'; $lang['notify_ok'] = '通知メールを送信しました'; -- cgit v1.2.3 From 9e64ca0debc28da382754236a849287cd6da737c Mon Sep 17 00:00:00 2001 From: Michael Hamann Date: Sun, 5 May 2013 21:08:45 +0200 Subject: Indexer: Fix wrong suffix parameter The suffix parameter is only for the word length in the word index and not for the metadata index. --- inc/indexer.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/inc/indexer.php b/inc/indexer.php index e518907d7..fdb147334 100644 --- a/inc/indexer.php +++ b/inc/indexer.php @@ -405,10 +405,10 @@ class Doku_Indexer { unset ($metavalues); // okay, now we have two entries for the same value. we need to merge them. - $indexline = $this->getIndexKey($key, '_i', $oldid); + $indexline = $this->getIndexKey($key.'_i', '', $oldid); if ($indexline != '') { - $newindexline = $this->getIndexKey($key, '_i', $newid); - $pagekeys = $this->getIndex($key, '_p'); + $newindexline = $this->getIndexKey($key.'_i', '', $newid); + $pagekeys = $this->getIndex($key.'_p', ''); $parts = explode(':', $indexline); foreach ($parts as $part) { list($id, $count) = explode('*', $part); @@ -423,14 +423,14 @@ class Doku_Indexer { } $pagekeys[$id] = implode(':', $keyline); } - $this->saveIndex($key, '_p', $pagekeys); + $this->saveIndex($key.'_p', '', $pagekeys); unset($pagekeys); - $this->saveIndexKey($key, '_i', $oldid, ''); - $this->saveIndexKey($key, '_i', $newid, $newindexline); + $this->saveIndexKey($key.'_i', '', $oldid, ''); + $this->saveIndexKey($key.'_i', '', $newid, $newindexline); } } else { $metavalues[$oldid] = $newvalue; - if (!$this->saveIndex($key, '_w', $metavalues)) { + if (!$this->saveIndex($key.'_w', '', $metavalues)) { $this->unlock(); return false; } -- cgit v1.2.3 From b1720e5c647585ac14f86e6080b54c932cac9bee Mon Sep 17 00:00:00 2001 From: Michael Hamann Date: Sun, 5 May 2013 21:09:40 +0200 Subject: Indexer: Remove broken and dead readdircache code FS#2771 The code that is removed in this commit has either never been used (listIndexLenghts) or was completely broken (cacheIndexDir) and was introduced in the indexer rewrite in 2010. The idea of the rewrite was to update the readdir cache after every index change instead of on demand. What the code actually did was removing every updated index from the cache as it used a wrong if condition. Simply fixing the condition wouldn't fix the problem as then only updated indexes would be added to the cache and furthermore the rewrite simply ignored the readdircache setting. For now the safest solution seems to be removing the code. It could be added again in a changed form in a future version. --- inc/indexer.php | 78 +-------------------------------------------------------- 1 file changed, 1 insertion(+), 77 deletions(-) diff --git a/inc/indexer.php b/inc/indexer.php index fdb147334..2f3ab25dc 100644 --- a/inc/indexer.php +++ b/inc/indexer.php @@ -1073,8 +1073,6 @@ class Doku_Indexer { if (isset($conf['fperm'])) chmod($fn.'.tmp', $conf['fperm']); io_rename($fn.'.tmp', $fn.'.idx'); - if ($suffix !== '') - $this->cacheIndexDir($idx, $suffix, empty($lines)); return true; } @@ -1140,8 +1138,6 @@ class Doku_Indexer { if (isset($conf['fperm'])) chmod($fn.'.tmp', $conf['fperm']); io_rename($fn.'.tmp', $fn.'.idx'); - if ($suffix !== '') - $this->cacheIndexDir($idx, $suffix); return true; } @@ -1168,40 +1164,6 @@ class Doku_Indexer { return $id; } - /** - * @param string $idx The index file which should be added to the key. - * @param string $suffix The suffix of the file - * @param bool $delete Unused - */ - protected function cacheIndexDir($idx, $suffix, $delete=false) { - global $conf; - if ($idx == 'i') - $cachename = $conf['indexdir'].'/lengths'; - else - $cachename = $conf['indexdir'].'/'.$idx.'lengths'; - $lengths = @file($cachename.'.idx', FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); - if ($lengths === false) $lengths = array(); - $old = array_search((string)$suffix, $lengths); - if (empty($lines)) { - if ($old === false) return; - unset($lengths[$old]); - } else { - if ($old !== false) return; - $lengths[] = $suffix; - sort($lengths); - } - $fh = @fopen($cachename.'.tmp', 'w'); - if (!$fh) { - trigger_error("Failed to write index cache", E_USER_ERROR); - return; - } - @fwrite($fh, implode("\n", $lengths)); - @fclose($fh); - if (isset($conf['fperm'])) - chmod($cachename.'.tmp', $conf['fperm']); - io_rename($cachename.'.tmp', $cachename.'.idx'); - } - /** * Get the list of lengths indexed in the wiki. * @@ -1211,45 +1173,7 @@ class Doku_Indexer { * @author YoBoY */ protected function listIndexLengths() { - global $conf; - $cachename = $conf['indexdir'].'/lengths'; - clearstatcache(); - if (@file_exists($cachename.'.idx')) { - $lengths = @file($cachename.'.idx', FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); - if ($lengths !== false) { - $idx = array(); - foreach ($lengths as $length) - $idx[] = (int)$length; - return $idx; - } - } - - $dir = @opendir($conf['indexdir']); - if ($dir === false) - return array(); - $lengths[] = array(); - while (($f = readdir($dir)) !== false) { - if (substr($f, 0, 1) == 'i' && substr($f, -4) == '.idx') { - $i = substr($f, 1, -4); - if (is_numeric($i)) - $lengths[] = (int)$i; - } - } - closedir($dir); - sort($lengths); - // save this in a file - $fh = @fopen($cachename.'.tmp', 'w'); - if (!$fh) { - trigger_error("Failed to write index cache", E_USER_ERROR); - return $lengths; - } - @fwrite($fh, implode("\n", $lengths)); - @fclose($fh); - if (isset($conf['fperm'])) - chmod($cachename.'.tmp', $conf['fperm']); - io_rename($cachename.'.tmp', $cachename.'.idx'); - - return $lengths; + return idx_listIndexLengths(); } /** -- cgit v1.2.3 From a3d0aa224c509ed311955813d6eb459d1dc141c8 Mon Sep 17 00:00:00 2001 From: Christopher Smith Date: Mon, 6 May 2013 01:03:17 +0100 Subject: add some tests for ml() --- _test/tests/inc/common_ml.test.php | 77 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 _test/tests/inc/common_ml.test.php diff --git a/_test/tests/inc/common_ml.test.php b/_test/tests/inc/common_ml.test.php new file mode 100644 index 000000000..ac4158540 --- /dev/null +++ b/_test/tests/inc/common_ml.test.php @@ -0,0 +1,77 @@ +assertEquals(DOKU_BASE . $this->script . '?media=' , ml()); + } + + function test_ml_args_array() { + global $conf; + $conf['useslash'] = 0; + $conf['userewrite'] = 0; + + $args = array('a' => 'b', 'c' => 'd', 'q' => '&ä'); + + $expect = DOKU_BASE . $this->script . '?a=b&c=d&q=%26%C3%A4&media=some:'; + $this->assertEquals($expect, ml('some:', $args)); + } + + function test_ml_args_string() { + global $conf; + $conf['useslash'] = 0; + $conf['userewrite'] = 0; + + $args = 'a=b&c=d'; + + $expect = DOKU_BASE . $this->script . '?a=b&c=d&media=some:'; + $this->assertEquals($expect, ml('some:', $args)); + } + + function test_ml_args_comma_string() { + global $conf; + $conf['useslash'] = 0; + $conf['userewrite'] = 0; + + $args = 'a=b,c=d'; + + $expect = DOKU_BASE . $this->script . '?a=b&c=d&media=some:'; + $this->assertEquals($expect, ml('some:', $args)); + } + + + function test_ml_imgresize_array() { + global $conf; + $conf['useslash'] = 0; + $conf['userewrite'] = 0; + + $id = 'some:'; + $w = 80; + $args = array('w' => $w); + $tok = media_get_token($id,$w,0); + + $expect = DOKU_BASE . $this->script . '?w='.$w.'&tok='.$tok.'&media='.$id; + $this->assertEquals($expect, ml($id, $args)); + } + + function test_ml_imgresize_string() { + global $conf; + $conf['useslash'] = 0; + $conf['userewrite'] = 0; + + $id = 'some:'; + $w = 80; + $args = 'w='.$w; + $tok = media_get_token($id,$w,0); + + $expect = DOKU_BASE . $this->script . '?w='.$w.'&tok='.$tok.'&media='.$id; + $this->assertEquals($expect, ml($id, $args)); + } +} \ No newline at end of file -- cgit v1.2.3 From 5e7db1e21093dbb999f1d1cee487a791af3650eb Mon Sep 17 00:00:00 2001 From: Christopher Smith Date: Mon, 6 May 2013 01:06:16 +0100 Subject: ensure security token is included in media url when resize parameter is passed in string form, e.g. 'w=80' --- inc/common.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/inc/common.php b/inc/common.php index 110350951..4d939ac77 100644 --- a/inc/common.php +++ b/inc/common.php @@ -447,6 +447,14 @@ function ml($id = '', $more = '', $direct = true, $sep = '&', $abs = false) if(isset($more['id']) && $direct) unset($more['id']); $more = buildURLparams($more, $sep); } else { + $matches = array(); + if (preg_match_all('/\b(w|h)=(\d*)\b/',$more,$matches,PREG_SET_ORDER)){ + $resize = array('w'=>0, 'h'=>0); + foreach ($matches as $match){ + $resize[$match[1]] = $match[2]; + } + $more .= $sep.'tok='.media_get_token($id,$resize['w'],$resize['h']); + } $more = str_replace('cache=cache', '', $more); //skip default $more = str_replace(',,', ',', $more); $more = str_replace(',', $sep, $more); -- cgit v1.2.3 From c3ff531efb93a30dc680ead0baac2a0d628827e4 Mon Sep 17 00:00:00 2001 From: Andreas Gohr Date: Mon, 6 May 2013 09:22:06 +0200 Subject: fixed test name --- _test/tests/inc/common_ml.test.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/_test/tests/inc/common_ml.test.php b/_test/tests/inc/common_ml.test.php index ac4158540..0abfde37a 100644 --- a/_test/tests/inc/common_ml.test.php +++ b/_test/tests/inc/common_ml.test.php @@ -1,6 +1,6 @@ script . '?w='.$w.'&tok='.$tok.'&media='.$id; $this->assertEquals($expect, ml($id, $args)); } -} \ No newline at end of file +} -- cgit v1.2.3 From 0e748a96cda77fa0131fc0b9601de54a41592ca7 Mon Sep 17 00:00:00 2001 From: Anika Henke Date: Mon, 6 May 2013 12:25:27 +0100 Subject: updated dates in templates' and plugins' info.txt files --- lib/plugins/acl/plugin.info.txt | 2 +- lib/plugins/authad/plugin.info.txt | 2 +- lib/plugins/authldap/plugin.info.txt | 2 +- lib/plugins/authmysql/plugin.info.txt | 2 +- lib/plugins/authpgsql/plugin.info.txt | 2 +- lib/plugins/authplain/plugin.info.txt | 2 +- lib/plugins/config/plugin.info.txt | 2 +- lib/plugins/plugin/plugin.info.txt | 2 +- lib/plugins/popularity/plugin.info.txt | 2 +- lib/plugins/revert/plugin.info.txt | 2 +- lib/plugins/safefnrecode/plugin.info.txt | 2 +- lib/plugins/testing/plugin.info.txt | 2 +- lib/plugins/usermanager/plugin.info.txt | 2 +- lib/tpl/default/template.info.txt | 2 +- lib/tpl/dokuwiki/template.info.txt | 2 +- 15 files changed, 15 insertions(+), 15 deletions(-) diff --git a/lib/plugins/acl/plugin.info.txt b/lib/plugins/acl/plugin.info.txt index 42babd71c..029dc82e7 100644 --- a/lib/plugins/acl/plugin.info.txt +++ b/lib/plugins/acl/plugin.info.txt @@ -1,7 +1,7 @@ base acl author Andreas Gohr email andi@splitbrain.org -date 2012-09-06 +date 2013-02-17 name ACL Manager desc Manage Page Access Control Lists url http://dokuwiki.org/plugin:acl diff --git a/lib/plugins/authad/plugin.info.txt b/lib/plugins/authad/plugin.info.txt index f02b5118c..996813bc5 100644 --- a/lib/plugins/authad/plugin.info.txt +++ b/lib/plugins/authad/plugin.info.txt @@ -1,7 +1,7 @@ base authad author Andreas Gohr email andi@splitbrain.org -date 2012-11-09 +date 2013-04-25 name Active Directory auth plugin desc Provides authentication against a Microsoft Active Directory url http://www.dokuwiki.org/plugin:authad diff --git a/lib/plugins/authldap/plugin.info.txt b/lib/plugins/authldap/plugin.info.txt index 2af8cf00a..94809a75b 100644 --- a/lib/plugins/authldap/plugin.info.txt +++ b/lib/plugins/authldap/plugin.info.txt @@ -1,7 +1,7 @@ base authldap author Andreas Gohr email andi@splitbrain.org -date 2012-10-06 +date 2013-04-19 name ldap auth plugin desc Provides authentication against am LDAP server url http://www.dokuwiki.org/plugin:authldap diff --git a/lib/plugins/authmysql/plugin.info.txt b/lib/plugins/authmysql/plugin.info.txt index c1e118427..16fe27e74 100644 --- a/lib/plugins/authmysql/plugin.info.txt +++ b/lib/plugins/authmysql/plugin.info.txt @@ -1,7 +1,7 @@ base authmysql author Andreas Gohr email andi@splitbrain.org -date 2012-10-06 +date 2013-02-16 name mysql auth plugin desc Provides authentication against a MySQL Server url http://www.dokuwiki.org/plugin:authmysql diff --git a/lib/plugins/authpgsql/plugin.info.txt b/lib/plugins/authpgsql/plugin.info.txt index ad71771b4..af33cec3e 100644 --- a/lib/plugins/authpgsql/plugin.info.txt +++ b/lib/plugins/authpgsql/plugin.info.txt @@ -1,7 +1,7 @@ base authpgsql author Andreas Gohr email andi@splitbrain.org -date 2012-10-06 +date 2013-02-16 name PostgreSQL auth plugin desc Provides authentication against a PostgreSQL database url http://www.dokuwiki.org/plugin:authpgsql diff --git a/lib/plugins/authplain/plugin.info.txt b/lib/plugins/authplain/plugin.info.txt index cde38eaac..8d9d3a82d 100644 --- a/lib/plugins/authplain/plugin.info.txt +++ b/lib/plugins/authplain/plugin.info.txt @@ -1,7 +1,7 @@ base authplain author Andreas Gohr email andi@splitbrain.org -date 2012-10-06 +date 2012-11-09 name auth plugin desc Provides authentication against local password storage url http://www.dokuwiki.org/plugin:authplain diff --git a/lib/plugins/config/plugin.info.txt b/lib/plugins/config/plugin.info.txt index 1f9968154..510be3be4 100644 --- a/lib/plugins/config/plugin.info.txt +++ b/lib/plugins/config/plugin.info.txt @@ -1,7 +1,7 @@ base config author Christopher Smith email chris@jalakai.co.uk -date 2012-09-08 +date 2013-02-24 name Configuration Manager desc Manage Dokuwiki's Configuration Settings url http://dokuwiki.org/plugin:config diff --git a/lib/plugins/plugin/plugin.info.txt b/lib/plugins/plugin/plugin.info.txt index c2f72d998..cdf866842 100644 --- a/lib/plugins/plugin/plugin.info.txt +++ b/lib/plugins/plugin/plugin.info.txt @@ -1,7 +1,7 @@ base plugin author Christopher Smith email chris@jalakai.co.uk -date 2012-09-08 +date 2013-02-20 name Plugin Manager plugin desc Manage and install plugins url http://www.dokuwiki.org/plugin:plugin diff --git a/lib/plugins/popularity/plugin.info.txt b/lib/plugins/popularity/plugin.info.txt index 2f1451c4a..17f3110c4 100644 --- a/lib/plugins/popularity/plugin.info.txt +++ b/lib/plugins/popularity/plugin.info.txt @@ -1,7 +1,7 @@ base popularity author Andreas Gohr email andi@splitbrain.org -date 2012-10-07 +date 2012-11-29 name Popularity Feedback Plugin desc Send anonymous data about your wiki to the developers. url http://www.dokuwiki.org/plugin:popularity diff --git a/lib/plugins/revert/plugin.info.txt b/lib/plugins/revert/plugin.info.txt index 205fe9177..984a531b3 100644 --- a/lib/plugins/revert/plugin.info.txt +++ b/lib/plugins/revert/plugin.info.txt @@ -1,7 +1,7 @@ base revert author Andreas Gohr email andi@splitbrain.org -date 2012-08-05 +date 2013-03-09 name Revert Manager desc Allows you to mass revert recent edits url http://dokuwiki.org/plugin:revert diff --git a/lib/plugins/safefnrecode/plugin.info.txt b/lib/plugins/safefnrecode/plugin.info.txt index 2b42399b0..3c6249d73 100644 --- a/lib/plugins/safefnrecode/plugin.info.txt +++ b/lib/plugins/safefnrecode/plugin.info.txt @@ -1,7 +1,7 @@ base safefnrecode author Andreas Gohr email andi@splitbrain.org -date 2011-04-06 +date 2012-07-28 name safefnrecode plugin desc Changes existing page and foldernames for the change in the safe filename encoding url http://www.dokuwiki.org/plugin:safefnrecode diff --git a/lib/plugins/testing/plugin.info.txt b/lib/plugins/testing/plugin.info.txt index c78c07739..64ab0b62e 100644 --- a/lib/plugins/testing/plugin.info.txt +++ b/lib/plugins/testing/plugin.info.txt @@ -1,7 +1,7 @@ base testing author Tobias Sarnowski email tobias@trustedco.de -date 2012-04-26 +date 2012-07-28 name Testing Plugin desc Used to test the test framework. Should always be disabled. url http://www.dokuwiki.org/plugin:testing diff --git a/lib/plugins/usermanager/plugin.info.txt b/lib/plugins/usermanager/plugin.info.txt index f4495bb19..1f8c2282b 100644 --- a/lib/plugins/usermanager/plugin.info.txt +++ b/lib/plugins/usermanager/plugin.info.txt @@ -1,7 +1,7 @@ base usermanager author Chris Smith email chris@jalakai.co.uk -date 2012-09-08 +date 2013-02-20 name User Manager desc Manage users url http://dokuwiki.org/plugin:usermanager diff --git a/lib/tpl/default/template.info.txt b/lib/tpl/default/template.info.txt index a77289e58..e0dbf54ba 100644 --- a/lib/tpl/default/template.info.txt +++ b/lib/tpl/default/template.info.txt @@ -1,7 +1,7 @@ base default author Andreas Gohr email andi@splitbrain.org -date 2012-09-08 +date 2013-02-16 name DokuWiki Default Template desc DokuWiki's default template until 2012 url http://www.dokuwiki.org/template:default diff --git a/lib/tpl/dokuwiki/template.info.txt b/lib/tpl/dokuwiki/template.info.txt index d32e94d39..9d062655d 100644 --- a/lib/tpl/dokuwiki/template.info.txt +++ b/lib/tpl/dokuwiki/template.info.txt @@ -1,7 +1,7 @@ base dokuwiki author Anika Henke email anika@selfthinker.org -date 2012-10-26 +date 2013-05-02 name DokuWiki Template desc DokuWiki's default template since 2012 url http://www.dokuwiki.org/template:dokuwiki -- cgit v1.2.3 From 0aa90d9aa7210ab4df4b96f23a9fc8045e572131 Mon Sep 17 00:00:00 2001 From: Andreas Gohr Date: Thu, 9 May 2013 14:53:36 +0200 Subject: tar library: another fix for lone zero blocks --- _test/tests/inc/tar.test.php | 44 ++++++++++++++++++++++++++++++++++++++++++++ inc/Tar.class.php | 9 ++++++--- 2 files changed, 50 insertions(+), 3 deletions(-) diff --git a/_test/tests/inc/tar.test.php b/_test/tests/inc/tar.test.php index e8805a75d..90bc2e49e 100644 --- a/_test/tests/inc/tar.test.php +++ b/_test/tests/inc/tar.test.php @@ -316,4 +316,48 @@ class Tar_TestCase extends DokuWikiTest { TestUtils::rdelete($out); } + + /** + * A single zero file should be just a header block + the footer + */ + public function test_zerofile(){ + $dir = dirname(__FILE__).'/tar'; + $tar = new Tar(); + $tar->create(); + $tar->addFile("$dir/zero.txt", 'zero.txt'); + $file = $tar->getArchive(Tar::COMPRESS_NONE); + + $this->assertEquals(512*3, strlen($file)); // 1 header block + 2 footer blocks + } + + public function test_zerodata(){ + $tar = new Tar(); + $tar->create(); + $tar->addData('zero.txt',''); + $file = $tar->getArchive(Tar::COMPRESS_NONE); + + $this->assertEquals(512*3, strlen($file)); // 1 header block + 2 footer blocks + } + + /** + * A file of exactly one block should be just a header block + data block + the footer + */ + public function test_blockfile(){ + $dir = dirname(__FILE__).'/tar'; + $tar = new Tar(); + $tar->create(); + $tar->addFile("$dir/block.txt", 'block.txt'); + $file = $tar->getArchive(Tar::COMPRESS_NONE); + + $this->assertEquals(512*4, strlen($file)); // 1 header block + data block + 2 footer blocks + } + + public function test_blockdata(){ + $tar = new Tar(); + $tar->create(); + $tar->addData('block.txt', str_pad('', 512, 'x')); + $file = $tar->getArchive(Tar::COMPRESS_NONE); + + $this->assertEquals(512*4, strlen($file)); // 1 header block + data block + 2 footer blocks + } } \ No newline at end of file diff --git a/inc/Tar.class.php b/inc/Tar.class.php index 10e82109b..d1a38ea0e 100644 --- a/inc/Tar.class.php +++ b/inc/Tar.class.php @@ -262,7 +262,7 @@ class Tar { if(!$this->fh) throw new TarIOException('Could not open file for writing: '.$this->file); } - $this->writeaccess = false; + $this->writeaccess = true; $this->closed = false; } @@ -295,8 +295,11 @@ class Tar { filemtime($file) ); - if(filesize($file)) while(!feof($fp)) { - $packed = pack("a512", fread($fp, 512)); + while(!feof($fp)) { + $data = fread($fp, 512); + if($data === false) break; + if($data === '') break; + $packed = pack("a512", $data); $this->writebytes($packed); } fclose($fp); -- cgit v1.2.3 From a27d8c740b9130905209f802a85643fd97e78996 Mon Sep 17 00:00:00 2001 From: Andreas Gohr Date: Thu, 9 May 2013 15:07:31 +0200 Subject: added missing test case files --- _test/tests/inc/tar/block.txt | 1 + _test/tests/inc/tar/zero.txt | 0 2 files changed, 1 insertion(+) create mode 100644 _test/tests/inc/tar/block.txt create mode 100644 _test/tests/inc/tar/zero.txt diff --git a/_test/tests/inc/tar/block.txt b/_test/tests/inc/tar/block.txt new file mode 100644 index 000000000..9b2f53080 --- /dev/null +++ b/_test/tests/inc/tar/block.txt @@ -0,0 +1 @@ +xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx \ No newline at end of file diff --git a/_test/tests/inc/tar/zero.txt b/_test/tests/inc/tar/zero.txt new file mode 100644 index 000000000..e69de29bb -- cgit v1.2.3 From 2a5a1456564635ddbca06edbc902e7f820d2a97b Mon Sep 17 00:00:00 2001 From: Guy Brand Date: Fri, 10 May 2013 14:34:29 +0200 Subject: Release preparation --- data/deleted.files | 3 +++ doku.php | 2 +- install.php | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/data/deleted.files b/data/deleted.files index 4b9657da2..664086c25 100644 --- a/data/deleted.files +++ b/data/deleted.files @@ -4,6 +4,9 @@ # A copy of this list is maintained at # http://www.dokuwiki.org/install:upgrade#files_to_remove +# removed in 2013-05-10 +lib/plugins/info/lang/sl/lang.php + # removed in 2013-04-06 inc/adLDAP.php inc/auth/ad.class.php diff --git a/doku.php b/doku.php index c058bb64a..9aeb30013 100644 --- a/doku.php +++ b/doku.php @@ -9,7 +9,7 @@ */ // update message version -$updateVersion = 39; +$updateVersion = 40; // xdebug_start_profiling(); diff --git a/install.php b/install.php index 53ef4a175..24f06608d 100644 --- a/install.php +++ b/install.php @@ -55,7 +55,7 @@ $dokuwiki_hash = array( '2011-11-10' => 'b46ff19a7587966ac4df61cbab1b8b31', '2012-01-25' => '72c083c73608fc43c586901fd5dabb74', '2012-09-10' => 'eb0b3fc90056fbc12bac6f49f7764df3', - '2013-04-06' => '7b62b75245f57f122d3e0f8ed7989623', + '2013-05-10' => '7b62b75245f57f122d3e0f8ed7989623', ); -- cgit v1.2.3 From 37764cbb34237da3c96bab21102e44ffe2715cd9 Mon Sep 17 00:00:00 2001 From: Dominik Eckelmann Date: Wed, 15 May 2013 10:06:23 +0200 Subject: fixed space of list points beside a floating image --- lib/tpl/dokuwiki/css/basic.css | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/tpl/dokuwiki/css/basic.css b/lib/tpl/dokuwiki/css/basic.css index a0a60d295..f7addc321 100644 --- a/lib/tpl/dokuwiki/css/basic.css +++ b/lib/tpl/dokuwiki/css/basic.css @@ -111,7 +111,7 @@ div { ul, ol { - padding: 0 0 0 1.5em; + padding: 0 0 0 0.5em; } [dir=rtl] ul, [dir=rtl] ol { @@ -146,8 +146,8 @@ li li { font-size: 100%; } -ul { list-style: square outside; } -ol { list-style: decimal outside; } +ul { list-style: square inside; } +ol { list-style: decimal inside; } ol ol { list-style-type: lower-alpha; } ol ol ol { list-style-type: upper-roman; } ol ol ol ol { list-style-type: upper-alpha; } -- cgit v1.2.3 From 712b791cc1f86484279cd54b41dfc14d0ded6fff Mon Sep 17 00:00:00 2001 From: Dominik Eckelmann Date: Wed, 15 May 2013 12:04:02 +0200 Subject: Revert "fixed space of list points beside a floating image" This reverts commit 37764cbb34237da3c96bab21102e44ffe2715cd9. --- lib/tpl/dokuwiki/css/basic.css | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/tpl/dokuwiki/css/basic.css b/lib/tpl/dokuwiki/css/basic.css index f7addc321..a0a60d295 100644 --- a/lib/tpl/dokuwiki/css/basic.css +++ b/lib/tpl/dokuwiki/css/basic.css @@ -111,7 +111,7 @@ div { ul, ol { - padding: 0 0 0 0.5em; + padding: 0 0 0 1.5em; } [dir=rtl] ul, [dir=rtl] ol { @@ -146,8 +146,8 @@ li li { font-size: 100%; } -ul { list-style: square inside; } -ol { list-style: decimal inside; } +ul { list-style: square outside; } +ol { list-style: decimal outside; } ol ol { list-style-type: lower-alpha; } ol ol ol { list-style-type: upper-roman; } ol ol ol ol { list-style-type: upper-alpha; } -- cgit v1.2.3 From 98e31f853f43d94c5bd1d3ab79388c44ce29ce0a Mon Sep 17 00:00:00 2001 From: Klap-in Date: Wed, 15 May 2013 16:51:44 +0200 Subject: Fix wrong config key in deprecated auth message --- inc/auth.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/inc/auth.php b/inc/auth.php index 9f180fc94..3f1f7925b 100644 --- a/inc/auth.php +++ b/inc/auth.php @@ -54,8 +54,8 @@ function auth_setup() { } elseif ('auth' . $conf['authtype'] === $plugin) { // matches old auth backends (pre-Weatherwax) $auth = $plugin_controller->load('auth', $plugin); - msg('Your authtype setting is deprecated. You must set $conf[\'authconfig\'] = ' . "auth" . $conf['authtype'] - . ' in your config (see Authentication Backends)',-1,'','',MSG_ADMINS_ONLY); + msg('Your authtype setting is deprecated. You must set $conf[\'authtype\'] = ' . "auth" . $conf['authtype'] + . ' in your configuration (see Authentication Backends)',-1,'','',MSG_ADMINS_ONLY); } } -- cgit v1.2.3 From bfd197d22f32f74940afadf1e308828773dbde18 Mon Sep 17 00:00:00 2001 From: hArpanet Date: Mon, 20 May 2013 20:12:52 +0200 Subject: Added comment to DiffFormatter _escape() method Clarify use of _escape() method in base class. --- inc/DifferenceEngine.php | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/inc/DifferenceEngine.php b/inc/DifferenceEngine.php index 783d6bea5..07df7a4be 100644 --- a/inc/DifferenceEngine.php +++ b/inc/DifferenceEngine.php @@ -817,7 +817,16 @@ class DiffFormatter { $this->_added($closing); } - function _escape($str){ + /** + * Escape string + * + * Override this method within other formatters if escaping required. + * Base class requires $str to be returned WITHOUT escaping. + * + * @param $str string Text string to escape + * @return string The escaped string. + */ + function _escape($str){ return $str; } } -- cgit v1.2.3 From 826d276602b191ee09d3450f7a8f9476c0e787b1 Mon Sep 17 00:00:00 2001 From: Klap-in Date: Tue, 21 May 2013 12:06:16 +0200 Subject: Clean internal ids in ml(), that it matches with fetch.php The resize token was broken because fetch.php cleans the id before the token calculation, while ml() uses the raw id --- _test/tests/inc/common_ml.test.php | 52 ++++++++++++++++++++++++++++++++------ inc/common.php | 7 ++++- 2 files changed, 50 insertions(+), 9 deletions(-) diff --git a/_test/tests/inc/common_ml.test.php b/_test/tests/inc/common_ml.test.php index 0abfde37a..9f3d87598 100644 --- a/_test/tests/inc/common_ml.test.php +++ b/_test/tests/inc/common_ml.test.php @@ -20,8 +20,8 @@ class common_ml_test extends DokuWikiTest { $args = array('a' => 'b', 'c' => 'd', 'q' => '&ä'); - $expect = DOKU_BASE . $this->script . '?a=b&c=d&q=%26%C3%A4&media=some:'; - $this->assertEquals($expect, ml('some:', $args)); + $expect = DOKU_BASE . $this->script . '?a=b&c=d&q=%26%C3%A4&media=some:img.jpg'; + $this->assertEquals($expect, ml('some:img.jpg', $args)); } function test_ml_args_string() { @@ -31,8 +31,8 @@ class common_ml_test extends DokuWikiTest { $args = 'a=b&c=d'; - $expect = DOKU_BASE . $this->script . '?a=b&c=d&media=some:'; - $this->assertEquals($expect, ml('some:', $args)); + $expect = DOKU_BASE . $this->script . '?a=b&c=d&media=some:img.png'; + $this->assertEquals($expect, ml('some:img.png', $args)); } function test_ml_args_comma_string() { @@ -42,8 +42,8 @@ class common_ml_test extends DokuWikiTest { $args = 'a=b,c=d'; - $expect = DOKU_BASE . $this->script . '?a=b&c=d&media=some:'; - $this->assertEquals($expect, ml('some:', $args)); + $expect = DOKU_BASE . $this->script . '?a=b&c=d&media=some:img.gif'; + $this->assertEquals($expect, ml('some:img.gif', $args)); } @@ -52,7 +52,7 @@ class common_ml_test extends DokuWikiTest { $conf['useslash'] = 0; $conf['userewrite'] = 0; - $id = 'some:'; + $id = 'some:img.png'; $w = 80; $args = array('w' => $w); $tok = media_get_token($id,$w,0); @@ -66,7 +66,7 @@ class common_ml_test extends DokuWikiTest { $conf['useslash'] = 0; $conf['userewrite'] = 0; - $id = 'some:'; + $id = 'some:img.png'; $w = 80; $args = 'w='.$w; $tok = media_get_token($id,$w,0); @@ -74,4 +74,40 @@ class common_ml_test extends DokuWikiTest { $expect = DOKU_BASE . $this->script . '?w='.$w.'&tok='.$tok.'&media='.$id; $this->assertEquals($expect, ml($id, $args)); } + + function test_ml_imgresize_array_rootid() { + global $conf; + $conf['useslash'] = 0; + $conf['userewrite'] = 0; + + $id = ':wiki:dokuwiki-128.png'; + $cleanid = 'wiki:dokuwiki-128.png'; + $w = 80; + $args = array('w' => $w); + $tok = media_get_token($cleanid, $w, 0); + + $expect = DOKU_BASE.$this->script.'?w='.$w.'&tok='.$tok.'&media='.$cleanid; + $this->assertEquals($expect, ml($id, $args)); + } + + function test_ml_imgresize_array_external() { + global $conf; + $conf['useslash'] = 0; + $conf['userewrite'] = 0; + + $ids = array( + 'https://example.com/lib/tpl/dokuwiki/images/logo.png', + 'http://example.com/lib/tpl/dokuwiki/images/logo.png', + 'ftp://example.com/lib/tpl/dokuwiki/images/logo.png' + ); + $w = 80; + $args = array('w' => $w); + + foreach($ids as $id) { + $tok = media_get_token($id, $w, 0); + + $expect = DOKU_BASE.$this->script.'?hash='.substr(md5(auth_cookiesalt().$id), 0, 6).'&w='.$w.'&tok='.$tok.'&media='.rawurlencode($id); + $this->assertEquals($expect, ml($id, $args)); + } + } } diff --git a/inc/common.php b/inc/common.php index 4d939ac77..03236f7d4 100644 --- a/inc/common.php +++ b/inc/common.php @@ -435,6 +435,11 @@ function exportlink($id = '', $format = 'raw', $more = '', $abs = false, $sep = */ function ml($id = '', $more = '', $direct = true, $sep = '&', $abs = false) { global $conf; + $isexternalimage = preg_match('#^(https?|ftp)://#i', $id); + if(!$isexternalimage) { + $id = cleanID($id); + } + if(is_array($more)) { // add token for resized images if($more['w'] || $more['h']){ @@ -467,7 +472,7 @@ function ml($id = '', $more = '', $direct = true, $sep = '&', $abs = false) } // external URLs are always direct without rewriting - if(preg_match('#^(https?|ftp)://#i', $id)) { + if($isexternalimage) { $xlink .= 'lib/exe/fetch.php'; // add hash: $xlink .= '?hash='.substr(md5(auth_cookiesalt().$id), 0, 6); -- cgit v1.2.3 From dcb2204bf0a8e3e25bf4ff8352a71160e846266b Mon Sep 17 00:00:00 2001 From: Klap-in Date: Tue, 21 May 2013 12:24:40 +0200 Subject: Add some tests about handling of semicolons Informative as sample implementation too --- _test/tests/inc/pageutils_clean_id.test.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/_test/tests/inc/pageutils_clean_id.test.php b/_test/tests/inc/pageutils_clean_id.test.php index 9c5781b24..478fd2bc4 100644 --- a/_test/tests/inc/pageutils_clean_id.test.php +++ b/_test/tests/inc/pageutils_clean_id.test.php @@ -43,6 +43,10 @@ class init_clean_id_test extends DokuWikiTest { $tests[] = array('ns._#!ns:page','false','ns._ns:page'); $tests[] = array('ns_:page',false,'ns:page'); $tests[] = array('page...page','false','page...page'); + $tests[] = array(':page',false,'page'); + $tests[] = array(':ns:page',false,'ns:page'); + $tests[] = array('page:',false,'page'); + $tests[] = array('ns:page:',false,'ns:page'); $conf['useslash'] = 0; $tests[] = array('page/page',false,'page_page'); -- cgit v1.2.3 From 0a2029172f535e4dfa258b8fe96e457c865cf18d Mon Sep 17 00:00:00 2001 From: Klap-in Date: Tue, 21 May 2013 12:36:45 +0200 Subject: Support handle of images from ftp. ml() can built url to these images, either fetch didn't accept them. --- inc/fetch.functions.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inc/fetch.functions.php b/inc/fetch.functions.php index 5801e96fa..b85a1284f 100644 --- a/inc/fetch.functions.php +++ b/inc/fetch.functions.php @@ -97,7 +97,7 @@ function checkFileStatus(&$media, &$file, $rev = '', $width=0, $height=0) { global $MIME, $EXT, $CACHE, $INPUT; //media to local file - if(preg_match('#^(https?)://#i', $media)) { + if(preg_match('#^(https?|ftp)://#i', $media)) { //check hash if(substr(md5(auth_cookiesalt().$media), 0, 6) !== $INPUT->str('hash')) { return array(412, 'Precondition Failed'); -- cgit v1.2.3 From f481fb8c448406f875dbf08e2aaa94a59e3b0f93 Mon Sep 17 00:00:00 2001 From: Klap-in Date: Tue, 21 May 2013 12:41:02 +0200 Subject: Update phpdocs of checkFileStatus --- inc/fetch.functions.php | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/inc/fetch.functions.php b/inc/fetch.functions.php index b85a1284f..56ca75465 100644 --- a/inc/fetch.functions.php +++ b/inc/fetch.functions.php @@ -89,9 +89,12 @@ function sendFile($file, $mime, $dl, $cache, $public = false) { * WRITE: MEDIA, FILE, array( STATUS, STATUSMESSAGE ) * * @author Gerry Weissbach - * @param $media reference to the media id - * @param $file reference to the file variable - * @returns array(STATUS, STATUSMESSAGE) + * @param string $media reference to the media id + * @param string $file reference to the file variable + * @param string $rev + * @param int $width + * @param int $height + * @return array(STATUS, STATUSMESSAGE) */ function checkFileStatus(&$media, &$file, $rev = '', $width=0, $height=0) { global $MIME, $EXT, $CACHE, $INPUT; -- cgit v1.2.3 From d54f79638bcd4567f3d20469bfb7ab95c1fe8d24 Mon Sep 17 00:00:00 2001 From: Klap-in Date: Tue, 21 May 2013 22:47:49 +0200 Subject: Added media_isexternal() --- inc/media.php | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/inc/media.php b/inc/media.php index e29a47631..f3b1a0af5 100644 --- a/inc/media.php +++ b/inc/media.php @@ -82,6 +82,18 @@ function media_metasave($id,$auth,$data){ } } +/** + * check if a media is external source + * + * @author Gerrit Uitslag + * @param string $id the media ID or URL + * @return bool + */ +function media_isexternal($id){ + if (preg_match('#^(https?|ftp)://#i', $id)) return true; + return false; +} + /** * Check if a media item is public (eg, external URL or readable by @ALL) * @@ -90,7 +102,7 @@ function media_metasave($id,$auth,$data){ * @return bool */ function media_ispublic($id){ - if(preg_match('/^https?:\/\//i',$id)) return true; + if(media_isexternal($id)) return true; $id = cleanID($id); if(auth_aclcheck(getNS($id).':*', '', array()) >= AUTH_READ) return true; return false; -- cgit v1.2.3 From 5287f99cf079142a71032cbbfaffbd32a5bd6f3d Mon Sep 17 00:00:00 2001 From: Klap-in Date: Tue, 21 May 2013 22:51:07 +0200 Subject: tests for media_isexternal --- _test/tests/inc/media_isexternal.test.php | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 _test/tests/inc/media_isexternal.test.php diff --git a/_test/tests/inc/media_isexternal.test.php b/_test/tests/inc/media_isexternal.test.php new file mode 100644 index 000000000..cf5f793e4 --- /dev/null +++ b/_test/tests/inc/media_isexternal.test.php @@ -0,0 +1,22 @@ +assertTrue(media_isexternal('http://www.example.com/foo.png')); + $this->assertTrue(media_isexternal('https://www.example.com/foo.png')); + $this->assertTrue(media_isexternal('ftp://www.example.com/foo.png')); + $this->assertTrue(media_isexternal('hTTp://www.example.com/foo.png')); + $this->assertTrue(media_isexternal('hTTps://www.example.com/foo.png')); + $this->assertTrue(media_isexternal('Ftp://www.example.com/foo.png')); + } + + public function test_internal(){ + $this->assertFalse(media_isexternal('wiki:logo.png')); + $this->assertFalse(media_isexternal('private:logo.png')); + $this->assertFalse(media_isexternal('ftp:private:logo.png')); + + } + +} \ No newline at end of file -- cgit v1.2.3 From 3e7e6067571e660cd835164c22d0973aa6343408 Mon Sep 17 00:00:00 2001 From: Klap-in Date: Tue, 21 May 2013 22:52:10 +0200 Subject: apply media_isexternal --- inc/Mailer.class.php | 2 +- inc/fetch.functions.php | 2 +- inc/fulltext.php | 2 +- inc/parser/handler.php | 2 +- inc/parser/metadata.php | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/inc/Mailer.class.php b/inc/Mailer.class.php index f87d7dd84..cb5f22f54 100644 --- a/inc/Mailer.class.php +++ b/inc/Mailer.class.php @@ -192,7 +192,7 @@ class Mailer { // copy over all replacements missing for HTML (autolink URLs) foreach($textrep as $key => $value) { if(isset($htmlrep[$key])) continue; - if(preg_match('/^https?:\/\//i', $value)) { + if(media_isexternal($value)) { $htmlrep[$key] = ''.hsc($value).''; } else { $htmlrep[$key] = hsc($value); diff --git a/inc/fetch.functions.php b/inc/fetch.functions.php index 56ca75465..e78bbf103 100644 --- a/inc/fetch.functions.php +++ b/inc/fetch.functions.php @@ -100,7 +100,7 @@ function checkFileStatus(&$media, &$file, $rev = '', $width=0, $height=0) { global $MIME, $EXT, $CACHE, $INPUT; //media to local file - if(preg_match('#^(https?|ftp)://#i', $media)) { + if(media_isexternal($media)) { //check hash if(substr(md5(auth_cookiesalt().$media), 0, 6) !== $INPUT->str('hash')) { return array(412, 'Precondition Failed'); diff --git a/inc/fulltext.php b/inc/fulltext.php index 7ee386063..2f073acea 100644 --- a/inc/fulltext.php +++ b/inc/fulltext.php @@ -172,7 +172,7 @@ function ft_mediause($id,$max){ preg_match_all('/\{\{([^|}]*'.$pcre.'[^|}]*)(|[^}]+)?\}\}/i',rawWiki($doc),$matches); foreach($matches[1] as $img){ $img = trim($img); - if(preg_match('/^https?:\/\//i',$img)) continue; // skip external images + if(media_isexternal($img)) continue; // skip external images list($img) = explode('?',$img); // remove any parameters resolve_mediaid($ns,$img,$exists); // resolve the possibly relative img diff --git a/inc/parser/handler.php b/inc/parser/handler.php index 55b715ad9..1cf32aaed 100644 --- a/inc/parser/handler.php +++ b/inc/parser/handler.php @@ -680,7 +680,7 @@ function Doku_Handler_Parse_Media($match) { } // Check whether this is a local or remote image - if ( preg_match('#^(https?|ftp)#i',$src) ) { + if ( media_isexternal($src) ) { $call = 'externalmedia'; } else { $call = 'internalmedia'; diff --git a/inc/parser/metadata.php b/inc/parser/metadata.php index 8638ffa6a..e17b82f8b 100644 --- a/inc/parser/metadata.php +++ b/inc/parser/metadata.php @@ -432,7 +432,7 @@ class Doku_Renderer_metadata extends Doku_Renderer { global $ID; list($src,$hash) = explode('#',$src,2); - if(!preg_match('/^https?:\/\//i',$src)){ + if(!media_isexternal($src)){ resolve_mediaid(getNS($ID),$src, $exists); } if(preg_match('/.(jpe?g|gif|png)$/i',$src)){ -- cgit v1.2.3 From 6b519690e45cefe83fbef5691e372c6078c3fb9b Mon Sep 17 00:00:00 2001 From: Anika Henke Date: Mon, 27 May 2013 16:26:40 +0100 Subject: fixed broken default config options (FS#2789) --- lib/plugins/authldap/conf/default.php | 2 +- lib/plugins/authmysql/conf/default.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/plugins/authldap/conf/default.php b/lib/plugins/authldap/conf/default.php index d07f9c82e..d530d59c9 100644 --- a/lib/plugins/authldap/conf/default.php +++ b/lib/plugins/authldap/conf/default.php @@ -16,4 +16,4 @@ $conf['bindpw'] = ''; $conf['userscope'] = 'sub'; $conf['groupscope'] = 'sub'; $conf['groupkey'] = 'cn'; -$conf['debug'] = array('onoff'); \ No newline at end of file +$conf['debug'] = 0; \ No newline at end of file diff --git a/lib/plugins/authmysql/conf/default.php b/lib/plugins/authmysql/conf/default.php index 647f3d96c..427bea273 100644 --- a/lib/plugins/authmysql/conf/default.php +++ b/lib/plugins/authmysql/conf/default.php @@ -7,7 +7,7 @@ $conf['password'] = ''; $conf['database'] = ''; $conf['debug'] = 0; $conf['forwardClearPass'] = 0; -$conf['TablesToLock'] = ''; +$conf['TablesToLock'] = array(); $conf['checkPass'] = ''; $conf['getUserInfo'] = ''; $conf['getGroups'] = ''; -- cgit v1.2.3 From a91f1103e66d9f28375fc94de05ebbcde454950d Mon Sep 17 00:00:00 2001 From: Anika Henke Date: Mon, 27 May 2013 16:39:54 +0100 Subject: fixed wrong use of quotes in authtype warning message --- inc/auth.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inc/auth.php b/inc/auth.php index 3f1f7925b..af9f35b38 100644 --- a/inc/auth.php +++ b/inc/auth.php @@ -54,7 +54,7 @@ function auth_setup() { } elseif ('auth' . $conf['authtype'] === $plugin) { // matches old auth backends (pre-Weatherwax) $auth = $plugin_controller->load('auth', $plugin); - msg('Your authtype setting is deprecated. You must set $conf[\'authtype\'] = ' . "auth" . $conf['authtype'] + msg('Your authtype setting is deprecated. You must set $conf[\'authtype\'] = "auth' . $conf['authtype'] . '"' . ' in your configuration (see Authentication Backends)',-1,'','',MSG_ADMINS_ONLY); } } -- cgit v1.2.3 From 01fb97e278338569ebf861059b81adff5f4a55c6 Mon Sep 17 00:00:00 2001 From: Anika Henke Date: Mon, 27 May 2013 17:01:43 +0100 Subject: fixed references from old mysql authtype to new mysql plugin in mysql.conf example --- conf/mysql.conf.php.example | 140 ++++++++++++++++++++--------------------- lib/plugins/authmysql/auth.php | 2 +- 2 files changed, 71 insertions(+), 71 deletions(-) diff --git a/conf/mysql.conf.php.example b/conf/mysql.conf.php.example index 94bc14e1f..c67e77c45 100644 --- a/conf/mysql.conf.php.example +++ b/conf/mysql.conf.php.example @@ -1,6 +1,6 @@ Date: Thu, 30 May 2013 16:49:58 +0200 Subject: added HMAC support to PassHash class FS#2794 --- _test/tests/inc/PassHash.test.php | 22 ++++++++++++++++++ inc/PassHash.class.php | 47 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+) create mode 100644 _test/tests/inc/PassHash.test.php diff --git a/_test/tests/inc/PassHash.test.php b/_test/tests/inc/PassHash.test.php new file mode 100644 index 000000000..b6cb07090 --- /dev/null +++ b/_test/tests/inc/PassHash.test.php @@ -0,0 +1,22 @@ +assertEquals('df08aef118f36b32e29d2f47cda649b6', PassHash::hmac('md5','data','secret')); + $this->assertEquals('9818e3306ba5ac267b5f2679fe4abd37e6cd7b54', PassHash::hmac('sha1','data','secret')); + + // known hashes from https://en.wikipedia.org/wiki/Hash-based_message_authentication_code + $this->assertEquals('74e6f7298a9c2d168935f58c001bad88', PassHash::hmac('md5','','')); + $this->assertEquals('fbdb1d1b18aa6c08324b7d64b71fb76370690e1d', PassHash::hmac('sha1','','')); + $this->assertEquals('80070713463e7749b90c2dc24911e275', PassHash::hmac('md5','The quick brown fox jumps over the lazy dog','key')); + $this->assertEquals('de7c9b85b8b78aa6bc8a7a36f70a90701c9db4d9', PassHash::hmac('sha1','The quick brown fox jumps over the lazy dog','key')); + + } +} \ No newline at end of file diff --git a/inc/PassHash.class.php b/inc/PassHash.class.php index 080fb4778..61bd74939 100644 --- a/inc/PassHash.class.php +++ b/inc/PassHash.class.php @@ -494,4 +494,51 @@ class PassHash { $this->init_salt($salt, 8, false); return ':B:'.$salt.':'.md5($salt.'-'.md5($clear)); } + + /** + * Wraps around native hash_hmac() or reimplents it + * + * This is not directly used as password hashing method, and thus isn't callable via the + * verify_hash() method. It should be used to create signatures and might be used in other + * password hashing methods. + * + * @see hash_hmac() + * @author KC Cloyd + * @link http://www.php.net/manual/en/function.hash-hmac.php#93440 + * + * @param string $algo Name of selected hashing algorithm (i.e. "md5", "sha256", "haval160,4", + * etc..) See hash_algos() for a list of supported algorithms. + * @param string $data Message to be hashed. + * @param string $key Shared secret key used for generating the HMAC variant of the message digest. + * @param bool $raw_output When set to TRUE, outputs raw binary data. FALSE outputs lowercase hexits. + * + * @return string + */ + public static function hmac($algo, $data, $key, $raw_output = false) { + // use native function if available and not in unit test + if(function_exists('hash_hmac') && !defined('SIMPLE_TEST')){ + return hash_hmac($algo, $data, $key, $raw_output); + } + + $algo = strtolower($algo); + $pack = 'H' . strlen($algo('test')); + $size = 64; + $opad = str_repeat(chr(0x5C), $size); + $ipad = str_repeat(chr(0x36), $size); + + if(strlen($key) > $size) { + $key = str_pad(pack($pack, $algo($key)), $size, chr(0x00)); + } else { + $key = str_pad($key, $size, chr(0x00)); + } + + for($i = 0; $i < strlen($key) - 1; $i++) { + $opad[$i] = $opad[$i] ^ $key[$i]; + $ipad[$i] = $ipad[$i] ^ $key[$i]; + } + + $output = $algo($opad . pack($pack, $algo($ipad . $data))); + + return ($raw_output) ? pack($pack, $output) : $output; + } } -- cgit v1.2.3 From 3c124064ad6f670d52c3678335caa57892408362 Mon Sep 17 00:00:00 2001 From: Andreas Gohr Date: Thu, 30 May 2013 16:56:34 +0200 Subject: use HMAC in media_token FS#2794 --- inc/media.php | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/inc/media.php b/inc/media.php index e29a47631..18148a446 100644 --- a/inc/media.php +++ b/inc/media.php @@ -1879,20 +1879,21 @@ function media_crop_image($file, $ext, $w, $h=0){ * cropped images have been internally generated - and prevent external * DDOS attacks via fetch * + * @author Christopher Smith + * * @param string $id id of the image * @param int $w resize/crop width * @param int $h resize/crop height - * - * @author Christopher Smith + * @return string */ function media_get_token($id,$w,$h){ // token is only required for modified images if ($w || $h) { - $token = auth_cookiesalt().$id; + $token = $id; if ($w) $token .= '.'.$w; if ($h) $token .= '.'.$h; - return substr(md5($token),0,6); + return substr(PassHash::hmac('md5', $token, auth_cookiesalt()),0,6); } return ''; -- cgit v1.2.3 From cdcd66dfc2bcf16e481d10bfa2d3ff1b4d433f99 Mon Sep 17 00:00:00 2001 From: Andreas Gohr Date: Fri, 31 May 2013 09:22:45 +0200 Subject: use hmac for external ressource hash FS#2794 --- inc/common.php | 2 +- inc/fetch.functions.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/inc/common.php b/inc/common.php index 4d939ac77..e096d8b30 100644 --- a/inc/common.php +++ b/inc/common.php @@ -470,7 +470,7 @@ function ml($id = '', $more = '', $direct = true, $sep = '&', $abs = false) if(preg_match('#^(https?|ftp)://#i', $id)) { $xlink .= 'lib/exe/fetch.php'; // add hash: - $xlink .= '?hash='.substr(md5(auth_cookiesalt().$id), 0, 6); + $xlink .= '?hash='.substr(PassHash::hmac('md5', $id, auth_cookiesalt()), 0, 6); if($more) { $xlink .= $sep.$more; $xlink .= $sep.'media='.rawurlencode($id); diff --git a/inc/fetch.functions.php b/inc/fetch.functions.php index 5801e96fa..ea524a37a 100644 --- a/inc/fetch.functions.php +++ b/inc/fetch.functions.php @@ -99,7 +99,7 @@ function checkFileStatus(&$media, &$file, $rev = '', $width=0, $height=0) { //media to local file if(preg_match('#^(https?)://#i', $media)) { //check hash - if(substr(md5(auth_cookiesalt().$media), 0, 6) !== $INPUT->str('hash')) { + if(substr(PassHash::hmac('md5', $media, auth_cookiesalt()), 0, 6) !== $INPUT->str('hash')) { return array(412, 'Precondition Failed'); } //handle external images -- cgit v1.2.3 From a132f948f22ae344760ee3da82f9f92cf0f18b7b Mon Sep 17 00:00:00 2001 From: Andreas Gohr Date: Fri, 31 May 2013 09:25:43 +0200 Subject: use HMAC for CSRF security tokens FS#2794 --- inc/common.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inc/common.php b/inc/common.php index e096d8b30..55c5b5ac4 100644 --- a/inc/common.php +++ b/inc/common.php @@ -56,7 +56,7 @@ function stripctl($string) { * @return string */ function getSecurityToken() { - return md5(auth_cookiesalt().session_id().$_SERVER['REMOTE_USER']); + return PassHash::hmac('md5', session_id().$_SERVER['REMOTE_USER'], auth_cookiesalt()); } /** -- cgit v1.2.3 From 8fcfc7abfd65ccd920753bee341c6bfdebcecd99 Mon Sep 17 00:00:00 2001 From: Andreas Gohr Date: Fri, 31 May 2013 09:29:08 +0200 Subject: use HMAC in password reset token FS#2794 --- inc/auth.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inc/auth.php b/inc/auth.php index af9f35b38..dac67bcb7 100644 --- a/inc/auth.php +++ b/inc/auth.php @@ -993,7 +993,7 @@ function act_resendpwd() { } // generate auth token - $token = md5(auth_cookiesalt().$user); //secret but user based + $token = PassHash::hmac('md5', $user, auth_cookiesalt()); //secret but user based $tfile = $conf['cachedir'].'/'.$token{0}.'/'.$token.'.pwauth'; $url = wl('', array('do'=> 'resendpwd', 'pwauth'=> $token), true, '&'); -- cgit v1.2.3 From 183a7b8845875e4a6b67e466cfff9f5163da3f17 Mon Sep 17 00:00:00 2001 From: Andreas Gohr Date: Fri, 31 May 2013 14:43:31 +0200 Subject: make password reset token completely random No need for HMAC here because there's no length attack vector here. We only care for the existance of the file and each reset request is completely (random) independent from each other. --- inc/auth.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inc/auth.php b/inc/auth.php index dac67bcb7..1f8489f03 100644 --- a/inc/auth.php +++ b/inc/auth.php @@ -993,7 +993,7 @@ function act_resendpwd() { } // generate auth token - $token = PassHash::hmac('md5', $user, auth_cookiesalt()); //secret but user based + $token = md5(uniqid(mt_rand(), true)); // random secret $tfile = $conf['cachedir'].'/'.$token{0}.'/'.$token.'.pwauth'; $url = wl('', array('do'=> 'resendpwd', 'pwauth'=> $token), true, '&'); -- cgit v1.2.3 From b9cf8ad44bcbbbded9d6e991f96b0d5f36310a9b Mon Sep 17 00:00:00 2001 From: Anika Henke Date: Sat, 1 Jun 2013 23:36:28 +0100 Subject: moved X-UA-Compatible from meta tag to be sent by http header instead --- lib/tpl/dokuwiki/detail.php | 2 +- lib/tpl/dokuwiki/main.php | 2 +- lib/tpl/dokuwiki/mediamanager.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/tpl/dokuwiki/detail.php b/lib/tpl/dokuwiki/detail.php index a8c5fef8a..d2ed530a3 100644 --- a/lib/tpl/dokuwiki/detail.php +++ b/lib/tpl/dokuwiki/detail.php @@ -9,12 +9,12 @@ // must be run from within DokuWiki if (!defined('DOKU_INC')) die(); +header('X-UA-Compatible: IE=edge,chrome=1'); ?> - <?php echo hsc(tpl_img_getTag('IPTC.Headline',$IMG))?> [<?php echo strip_tags($conf['title'])?>] diff --git a/lib/tpl/dokuwiki/main.php b/lib/tpl/dokuwiki/main.php index 963750a1c..43a0c0da7 100644 --- a/lib/tpl/dokuwiki/main.php +++ b/lib/tpl/dokuwiki/main.php @@ -9,6 +9,7 @@ */ if (!defined('DOKU_INC')) die(); /* must be run from within DokuWiki */ +header('X-UA-Compatible: IE=edge,chrome=1'); $hasSidebar = page_findnearest($conf['sidebar']); $showSidebar = $hasSidebar && ($ACT=='show'); @@ -16,7 +17,6 @@ $showSidebar = $hasSidebar && ($ACT=='show'); <html lang="<?php echo $conf['lang'] ?>" dir="<?php echo $lang['direction'] ?>" class="no-js"> <head> <meta charset="utf-8" /> - <!--[if IE]><meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" /><![endif]--> <title><?php tpl_pagetitle() ?> [<?php echo strip_tags($conf['title']) ?>] diff --git a/lib/tpl/dokuwiki/mediamanager.php b/lib/tpl/dokuwiki/mediamanager.php index 23c9cee79..dadf2b10f 100644 --- a/lib/tpl/dokuwiki/mediamanager.php +++ b/lib/tpl/dokuwiki/mediamanager.php @@ -7,12 +7,12 @@ */ // must be run from within DokuWiki if (!defined('DOKU_INC')) die(); +header('X-UA-Compatible: IE=edge,chrome=1'); ?> - <?php echo hsc($lang['mediaselect'])?> [<?php echo strip_tags($conf['title'])?>] -- cgit v1.2.3 From 21c9604e66bcb42ab5267e9873738a6e22250103 Mon Sep 17 00:00:00 2001 From: Andreas Gohr <andi@splitbrain.org> Date: Sun, 2 Jun 2013 21:48:31 +0200 Subject: we now require PHP 5.2.0 at least --- inc/infoutils.php | 4 ++-- install.php | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/inc/infoutils.php b/inc/infoutils.php index 9fe5ee689..71e642995 100644 --- a/inc/infoutils.php +++ b/inc/infoutils.php @@ -107,8 +107,8 @@ function check(){ msg('DokuWiki version: '.getVersion(),1); } - if(version_compare(phpversion(),'5.1.2','<')){ - msg('Your PHP version is too old ('.phpversion().' vs. 5.1.2+ needed)',-1); + if(version_compare(phpversion(),'5.2.0','<')){ + msg('Your PHP version is too old ('.phpversion().' vs. 5.2.0+ needed)',-1); }else{ msg('PHP version '.phpversion(),1); } diff --git a/install.php b/install.php index 24f06608d..ab0fad121 100644 --- a/install.php +++ b/install.php @@ -518,8 +518,8 @@ function check_functions(){ global $lang; $ok = true; - if(version_compare(phpversion(),'5.1.2','<')){ - $error[] = sprintf($lang['i_phpver'],phpversion(),'5.1.2'); + if(version_compare(phpversion(),'5.2.0','<')){ + $error[] = sprintf($lang['i_phpver'],phpversion(),'5.2.0'); $ok = false; } -- cgit v1.2.3 From 7482f2d6e43ea5768b2de40d89c7e7ea836a60df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EB=AA=85=EC=A7=84?= <aranet100@gmail.com> Date: Fri, 7 Jun 2013 11:30:39 +0200 Subject: Korean language update --- inc/lang/ko/draft.txt | 2 +- inc/lang/ko/lang.php | 10 +++++----- inc/lang/ko/login.txt | 2 +- inc/lang/ko/newpage.txt | 2 +- inc/lang/ko/norev.txt | 2 +- inc/lang/ko/read.txt | 2 +- inc/lang/ko/searchpage.txt | 2 +- inc/lang/ko/subscr_digest.txt | 2 +- inc/lang/ko/subscr_list.txt | 2 +- inc/lang/ko/subscr_single.txt | 2 +- lib/plugins/acl/lang/ko/lang.php | 2 +- lib/plugins/config/lang/ko/intro.txt | 2 +- lib/plugins/config/lang/ko/lang.php | 22 +++++++++++----------- lib/plugins/popularity/lang/ko/intro.txt | 2 +- lib/plugins/revert/lang/ko/lang.php | 2 +- lib/plugins/usermanager/lang/ko/lang.php | 4 ++-- 16 files changed, 31 insertions(+), 31 deletions(-) diff --git a/inc/lang/ko/draft.txt b/inc/lang/ko/draft.txt index f7787f981..b655d7c92 100644 --- a/inc/lang/ko/draft.txt +++ b/inc/lang/ko/draft.txt @@ -1,5 +1,5 @@ ====== 문서 초안 있음 ====== -이 문서의 마지막 편집 세션은 정상적으로 끝나지 않았습니다. DokuWiki는 작업 도중 자동으로 저장된 문서 초안을 사용하여 편집을 계속 할 수 있습니다. 마지막 세션 동안 저장된 문서 초안을 아래에서 볼 수 있습니다. +이 문서의 마지막 편집 세션은 정상적으로 끝나지 않았습니다. DokuWiki는 작업 도중 자동으로 저장된 문서 초안을 사용해 편집을 계속 할 수 있습니다. 마지막 세션 동안 저장된 문서 초안을 아래에서 볼 수 있습니다. 비정상적으로 끝난 편집 세션을 **되돌릴**지 여부를 결정하고, 자동으로 저장되었던 초안을 **삭제**하거나 편집 과정을 **취소**하세요. \ No newline at end of file diff --git a/inc/lang/ko/lang.php b/inc/lang/ko/lang.php index 76d6a535d..76684659c 100644 --- a/inc/lang/ko/lang.php +++ b/inc/lang/ko/lang.php @@ -160,7 +160,7 @@ $lang['accessdenied'] = '이 문서를 볼 권한이 없습니다.'; $lang['mediausage'] = '이 파일을 참고하려면 다음 문법을 사용하세요:'; $lang['mediaview'] = '원본 파일 보기'; $lang['mediaroot'] = '루트 (root)'; -$lang['mediaupload'] = '파일을 현재 이름공간으로 올립니다. 하위 이름공간으로 만들려면 선택한 파일 이름 앞에 쌍점(:)으로 구분되는 이름을 붙이면 됩니다. 파일을 드래그 앤 드롭하여 선택할 수 있습니다.'; +$lang['mediaupload'] = '파일을 현재 이름공간으로 올립니다. 하위 이름공간으로 만들려면 선택한 파일 이름 앞에 쌍점(:)으로 구분되는 이름을 붙이면 됩니다. 파일을 드래그 앤 드롭해 선택할 수 있습니다.'; $lang['mediaextchange'] = '파일 확장자가 .%s에서 .%s(으)로 바뀌었습니다!'; $lang['reference'] = '참고'; $lang['ref_inuse'] = '다음 문서에서 아직 사용 중이므로 파일을 삭제할 수 없습니다:'; @@ -218,7 +218,7 @@ $lang['qb_hs'] = '문단 제목 선택'; $lang['qb_hplus'] = '상위 문단 제목'; $lang['qb_hminus'] = '하위 문단 제목'; $lang['qb_hequal'] = '동급 문단 제목'; -$lang['qb_link'] = '내부 링크'; +$lang['qb_link'] = '안쪽 링크'; $lang['qb_extlink'] = '바깥 링크'; $lang['qb_hr'] = '가로줄'; $lang['qb_ol'] = '순서 있는 목록'; @@ -231,7 +231,7 @@ $lang['upperns'] = '상위 이름공간으로 이동'; $lang['admin_register'] = '새 사용자 추가'; $lang['metaedit'] = '메타 데이터 편집'; $lang['metasaveerr'] = '메타 데이터 쓰기 실패'; -$lang['metasaveok'] = '메타 데이타 저장됨'; +$lang['metasaveok'] = '메타 데이터 저장됨'; $lang['img_backto'] = '뒤로'; $lang['img_title'] = '이름'; $lang['img_caption'] = '설명'; @@ -304,7 +304,7 @@ $lang['media_uploadtab'] = '올리기'; $lang['media_searchtab'] = '찾기'; $lang['media_file'] = '파일'; $lang['media_viewtab'] = '보기'; -$lang['media_edittab'] = '수정'; +$lang['media_edittab'] = '편집'; $lang['media_historytab'] = '역사'; $lang['media_list_thumbs'] = '섬네일'; $lang['media_list_rows'] = '목록'; @@ -318,7 +318,7 @@ $lang['media_view'] = '%s'; $lang['media_viewold'] = '%s (%s에 있음)'; $lang['media_edit'] = '%s 편집'; $lang['media_history'] = '%s 바뀜 내역'; -$lang['media_meta_edited'] = '메타데이터가 수정됨'; +$lang['media_meta_edited'] = '메타 데이터 편집됨'; $lang['media_perm_read'] = '이 파일을 읽을 권한이 없습니다.'; $lang['media_perm_upload'] = '파일을 올릴 권한이 없습니다.'; $lang['media_update'] = '새 판 올리기'; diff --git a/inc/lang/ko/login.txt b/inc/lang/ko/login.txt index 160b899d3..f8af4100f 100644 --- a/inc/lang/ko/login.txt +++ b/inc/lang/ko/login.txt @@ -1,3 +1,3 @@ ====== 로그인 ====== -로그인하지 않았습니다! 아래에서 로그인하세요. 로그인하려면 쿠키를 받도록 설정하여야 합니다. \ No newline at end of file +로그인하지 않았습니다! 아래에서 로그인하세요. 로그인하려면 쿠키를 활성화해야 합니다. \ No newline at end of file diff --git a/inc/lang/ko/newpage.txt b/inc/lang/ko/newpage.txt index 8db34f9cf..fa7864610 100644 --- a/inc/lang/ko/newpage.txt +++ b/inc/lang/ko/newpage.txt @@ -1,3 +1,3 @@ ====== 이 주제는 아직 없습니다 ====== -아직 없는 주제에 대한 링크를 따라왔습니다. **문서 만들기** 버튼을 클릭하여 새로 만들 수 있습니다. \ No newline at end of file +아직 없는 주제에 대한 링크를 따라왔습니다. **문서 만들기** 버튼을 클릭해 새로 만들 수 있습니다. \ No newline at end of file diff --git a/inc/lang/ko/norev.txt b/inc/lang/ko/norev.txt index 3e203b235..246f3e4f6 100644 --- a/inc/lang/ko/norev.txt +++ b/inc/lang/ko/norev.txt @@ -1,3 +1,3 @@ ====== 지정한 판 없음 ====== -지정한 판이 존재하지 않습니다. **이전 판** 버튼을 사용하여 이 문서의 이전 판 목록을 보세요. \ No newline at end of file +지정한 판이 존재하지 않습니다. **이전 판** 버튼을 사용해 이 문서의 이전 판 목록을 보세요. \ No newline at end of file diff --git a/inc/lang/ko/read.txt b/inc/lang/ko/read.txt index c510b598e..8f080fcb1 100644 --- a/inc/lang/ko/read.txt +++ b/inc/lang/ko/read.txt @@ -1 +1 @@ -이 문서는 읽기 전용입니다. 내용을 볼 수는 있지만 수정할 수는 없습니다. 문제가 있다고 생각하면 관리자에게 문의하세요. \ No newline at end of file +이 문서는 읽기 전용입니다. 내용을 볼 수는 있지만 바꿀 수는 없습니다. 문제가 있다고 생각하면 관리자에게 문의하세요. \ No newline at end of file diff --git a/inc/lang/ko/searchpage.txt b/inc/lang/ko/searchpage.txt index 8cc003950..d3b37ec7c 100644 --- a/inc/lang/ko/searchpage.txt +++ b/inc/lang/ko/searchpage.txt @@ -1,5 +1,5 @@ ====== 찾기 ====== -아래에서 찾기 결과를 볼 수 있습니다. 만일 원하는 문서를 찾지 못하였다면, **문서 만들기**나 **문서 편집** 버튼을 사용하여 쿼리 내용과 같은 이름의 문서를 만들거나 편집할 수 있습니다. +아래에서 찾기 결과를 볼 수 있습니다. 만일 원하는 문서를 찾지 못하였다면, **문서 만들기**나 **문서 편집** 버튼을 사용해 쿼리 내용과 같은 이름의 문서를 만들거나 편집할 수 있습니다. ===== 결과 ===== \ No newline at end of file diff --git a/inc/lang/ko/subscr_digest.txt b/inc/lang/ko/subscr_digest.txt index b67cc9bbc..6db7b963c 100644 --- a/inc/lang/ko/subscr_digest.txt +++ b/inc/lang/ko/subscr_digest.txt @@ -12,7 +12,7 @@ 이 문서의 알림을 취소하려면, @DOKUWIKIURL@에 로그인한 뒤 -@SUBSCRIBE@ 문서를 방문하여 문서나 이름공간의 구독을 취소하세요. +@SUBSCRIBE@ 문서를 방문해 문서나 이름공간의 구독을 취소하세요. -- @DOKUWIKIURL@의 DokuWiki가 자동으로 만들어낸 메일입니다. \ No newline at end of file diff --git a/inc/lang/ko/subscr_list.txt b/inc/lang/ko/subscr_list.txt index 03ca86d2a..c13e0097a 100644 --- a/inc/lang/ko/subscr_list.txt +++ b/inc/lang/ko/subscr_list.txt @@ -8,7 +8,7 @@ -------------------------------------------------------- 이 문서의 알림을 취소하려면, @DOKUWIKIURL@에 로그인한 뒤 -@SUBSCRIBE@ 문서를 방문하여 문서나 이름공간의 구독을 취소하세요. +@SUBSCRIBE@ 문서를 방문해 문서나 이름공간의 구독을 취소하세요. -- @DOKUWIKIURL@의 DokuWiki가 자동으로 만들어낸 메일입니다. \ No newline at end of file diff --git a/inc/lang/ko/subscr_single.txt b/inc/lang/ko/subscr_single.txt index 5f8b43b98..d4e38e044 100644 --- a/inc/lang/ko/subscr_single.txt +++ b/inc/lang/ko/subscr_single.txt @@ -14,7 +14,7 @@ 새 판 : @NEWPAGE@ 이 문서의 알림을 취소하려면, @DOKUWIKIURL@에 로그인한 뒤 -@SUBSCRIBE@ 문서를 방문하여 문서나 이름공간의 구독을 취소하세요. +@SUBSCRIBE@ 문서를 방문해 문서나 이름공간의 구독을 취소하세요. -- @DOKUWIKIURL@의 DokuWiki가 자동으로 만들어낸 메일입니다. \ No newline at end of file diff --git a/lib/plugins/acl/lang/ko/lang.php b/lib/plugins/acl/lang/ko/lang.php index 5cec4b8fd..7c1e9a43d 100644 --- a/lib/plugins/acl/lang/ko/lang.php +++ b/lib/plugins/acl/lang/ko/lang.php @@ -40,4 +40,4 @@ $lang['acl_perm4'] = '만들기'; $lang['acl_perm8'] = '올리기'; $lang['acl_perm16'] = '삭제'; $lang['acl_new'] = '새 항목 추가'; -$lang['acl_mod'] = '선택 항목 수정'; +$lang['acl_mod'] = '항목 수정'; diff --git a/lib/plugins/config/lang/ko/intro.txt b/lib/plugins/config/lang/ko/intro.txt index a2dc7b6f6..b9eb763a4 100644 --- a/lib/plugins/config/lang/ko/intro.txt +++ b/lib/plugins/config/lang/ko/intro.txt @@ -2,6 +2,6 @@ DokuWiki 설치할 때 설정을 바꾸기 위해 사용하는 페이지입니다. 각 설정에 대한 자세한 도움말이 필요하다면 [[doku>ko:config|설정 문서 (한국어)]]와 [[doku>config|설정 문서 (영어)]]를 참고하세요. -플러그인에 대한 자세한 정보가 필요하다면 [[doku>plugin:config|플러그인 설정]] 문서를 참고하세요. 빨간 배경색으로 보이는 설정은 이 플러그인에서 바꾸지 못하도록 되어있습니다. 파란 배경색으로 보이는 설정은 기본 설정값을 가지고 있습니다. 하얀 배경색으로 보이는 설정은 특별한 설치를 위해 설정되어 있습니다. 파란색과 하얀색 배경으로 된 설정은 수정이 가능합니다. +플러그인에 대한 자세한 정보가 필요하다면 [[doku>plugin:config|플러그인 설정]] 문서를 참고하세요. 빨간 배경색으로 보이는 설정은 이 플러그인에서 바꾸지 못하도록 되어있습니다. 파란 배경색으로 보이는 설정은 기본 설정값을 가지고 있습니다. 하얀 배경색으로 보이는 설정은 특별한 설치를 위해 설정되어 있습니다. 파란색과 하얀색 배경으로 된 설정은 바꿀 수 있습니다. 이 페이지를 떠나기 전에 **저장** 버튼을 누르지 않으면 바뀐 값은 적용되지 않습니다. \ No newline at end of file diff --git a/lib/plugins/config/lang/ko/lang.php b/lib/plugins/config/lang/ko/lang.php index f69af2df6..da155bcef 100644 --- a/lib/plugins/config/lang/ko/lang.php +++ b/lib/plugins/config/lang/ko/lang.php @@ -11,14 +11,14 @@ * @author Myeongjin <aranet100@gmail.com> */ $lang['menu'] = '환경 설정'; -$lang['error'] = '잘못된 값 때문에 설정을 바꿀 수 없습니다. 수정한 값을 검토하고 확인을 누르세요. +$lang['error'] = '잘못된 값 때문에 설정을 바꿀 수 없습니다. 바뀜을 검토하고 확인을 누르세요. <br />잘못된 값은 빨간 선으로 둘러싸여 있습니다.'; $lang['updated'] = '설정이 성공적으로 바뀌었습니다.'; $lang['nochoice'] = '(다른 선택이 불가능합니다)'; -$lang['locked'] = '환경 설정 파일을 수정할 수 없습니다. 의도한 행동이 아니라면,<br /> +$lang['locked'] = '환경 설정 파일을 바꿀 수 없습니다. 의도한 행동이 아니라면,<br /> 파일 이름과 권한이 맞는지 확인하세요.'; -$lang['danger'] = '위험: 이 옵션을 잘못 수정하면 환경설정 메뉴를 사용할 수 없을 수도 있습니다.'; -$lang['warning'] = '경고: 이 옵션을 잘못 수정하면 잘못 동작할 수 있습니다.'; +$lang['danger'] = '위험: 이 옵션을 잘못 바꾸면 환경 설정 메뉴를 사용할 수 없을 수도 있습니다.'; +$lang['warning'] = '경고: 이 옵션을 잘못 바꾸면 잘못 동작할 수 있습니다.'; $lang['security'] = '보안 경고: 이 옵션은 보안에 위험이 있을 수 있습니다.'; $lang['_configuration_manager'] = '환경 설정 관리자'; $lang['_header_dokuwiki'] = 'DokuWiki 설정'; @@ -48,13 +48,13 @@ $lang['template'] = '템플릿 (위키 디자인)'; $lang['tagline'] = '태그 라인 (템플릿이 지원할 때에 한함)'; $lang['sidebar'] = '사이드바 문서 이름 (템플릿이 지원할 때에 한함), 비워두면 사이드바를 비활성화'; $lang['license'] = '콘텐츠에 어떤 라이선스를 적용하겠습니까?'; -$lang['savedir'] = '데이타 저장 디렉토리'; +$lang['savedir'] = '데이터 저장 디렉토리'; $lang['basedir'] = '서버 경로 (예를 들어 <code>/dokuwiki/</code>). 자동 감지를 하려면 비우세요.'; $lang['baseurl'] = '서버 URL (예를 들어 <code>http://www.yourserver.com</code>). 자동 감지를 하려면 비우세요.'; $lang['cookiedir'] = '쿠키 위치. 비워두면 기본 URL 위치로 지정됩니다.'; $lang['dmode'] = '디렉토리 만들기 모드'; $lang['fmode'] = '파일 만들기 모드'; -$lang['allowdebug'] = '디버그 허용 <b>필요하지 않으면 비활성화할 것!</b>'; +$lang['allowdebug'] = '디버그 허용 <b>필요하지 않으면 비활성화하세요!</b>'; $lang['recent'] = '최근 바뀐 문서당 항목 수'; $lang['recent_days'] = '최근 바뀐 문서 기준 시간 (일)'; $lang['breadcrumbs'] = '위치 "추적" 수. 0으로 설정하면 비활성화합니다.'; @@ -63,7 +63,7 @@ $lang['fullpath'] = '문서 하단에 전체 경로 보여주기'; $lang['typography'] = '기호 대체'; $lang['dformat'] = '날짜 형식 (PHP <a href="http://www.php.net/strftime">strftime</a> 기능 참고)'; $lang['signature'] = '편집기에서 서명 버튼을 누를 때 삽입할 내용'; -$lang['showuseras'] = '마지막에 문서를 수정한 사용자를 보여줄지 여부'; +$lang['showuseras'] = '마지막에 문서를 편집한 사용자를 보여줄지 여부'; $lang['toptoclevel'] = '목차 최상위 항목'; $lang['tocminheads'] = '목차 표시 여부를 결정할 최소한의 문단 제목 항목의 수'; $lang['maxtoclevel'] = '목차 최대 단계'; @@ -102,7 +102,7 @@ $lang['htmlok'] = 'HTML 내장 허용'; $lang['phpok'] = 'PHP 내장 허용'; $lang['locktime'] = '최대 파일 잠금 시간(초)'; $lang['cachetime'] = '최대 캐시 생존 시간 (초)'; -$lang['target____wiki'] = '내부 링크에 대한 타겟 창'; +$lang['target____wiki'] = '안쪽 링크에 대한 타겟 창'; $lang['target____interwiki'] = '인터위키 링크에 대한 타겟 창'; $lang['target____extern'] = '바깥 링크에 대한 타겟 창'; $lang['target____media'] = '미디어 링크에 대한 타겟 창'; @@ -133,7 +133,7 @@ $lang['userewrite'] = '멋진 URL 사용'; $lang['useslash'] = 'URL에서 이름 구분자로 슬래시 문자 사용'; $lang['sepchar'] = '문서 이름 단어 구분자'; $lang['canonical'] = '완전한 canonical URL 사용'; -$lang['fnencode'] = '아스키가 아닌 파일 이름을 인코딩 하는 방법.'; +$lang['fnencode'] = 'ASCII가 아닌 파일 이름을 인코딩 하는 방법.'; $lang['autoplural'] = '링크 연결시 복수 양식 검사'; $lang['compression'] = '첨부 파일 압축 방법 선택'; $lang['gzip_output'] = 'xhml 내용 gzip 압축 사용'; @@ -143,9 +143,9 @@ $lang['send404'] = '존재하지 않는 페이지에 대해 "HTTP $lang['broken_iua'] = '설치된 시스템에서 ignore_user_abort 기능에 문제가 있습니까? 문제가 있다면 색인이 정상적으로 동작하지 않습니다. 이 기능이 IIS+PHP/CGI에서 문제가 있는 것으로 알려졌습니다. 자세한 정보는 <a href="http://bugs.dokuwiki.org/?do=details&task_id=852">버그 852</a>를 참고하시기 바랍니다.'; $lang['xsendfile'] = '웹 서버가 정적 파일을 제공하도록 X-Sendfile 헤더를 사용하겠습니까? 웹 서버가 이 기능을 지원해야 합니다.'; $lang['renderer_xhtml'] = '주 (xhtml) 위키 출력 처리기'; -$lang['renderer__core'] = '%s (DokuWiki 내부 기능)'; +$lang['renderer__core'] = '%s (DokuWiki 내부)'; $lang['renderer__plugin'] = '%s (플러그인)'; -$lang['dnslookups'] = '이 옵션을 활성화하면 DokuWiki가 문서를 수정하는 사용자의 호스트 네임과 원격 IP 주소를 확인합니다. 서버가 느리거나, DNS를 운영하지 않거나 이 기능을 원치 않으면 비활성화하세요'; +$lang['dnslookups'] = '이 옵션을 활성화하면 DokuWiki가 문서를 편집하는 사용자의 호스트 네임과 원격 IP 주소를 확인합니다. 서버가 느리거나, DNS를 운영하지 않거나 이 기능을 원치 않으면 비활성화하세요'; $lang['proxy____host'] = '프록시 서버 이름'; $lang['proxy____port'] = '프록시 서버 포트'; $lang['proxy____user'] = '프록시 사용자 이름'; diff --git a/lib/plugins/popularity/lang/ko/intro.txt b/lib/plugins/popularity/lang/ko/intro.txt index 2513b77b4..c75c57ba5 100644 --- a/lib/plugins/popularity/lang/ko/intro.txt +++ b/lib/plugins/popularity/lang/ko/intro.txt @@ -2,7 +2,7 @@ 설치된 위키의 익명 정보를 DokuWiki 개발자에게 보냅니다. 이 [[doku>popularity|도구]]는 DokuWiki가 실제 사용자에게 어떻게 사용되는지 DokuWiki 개발자에게 알려줌으로써 이 후 개발 시 참고가 됩니다. -설치된 위키가 커짐에 따라서 이 과정을 반복할 필요가 있습니다. 반복된 데이타는 익명 ID로 구별되어집니다. +설치된 위키가 커짐에 따라서 이 과정을 반복할 필요가 있습니다. 반복된 데이터는 익명 ID로 구별되어집니다. 보내려는 데이터는 설치 DokuWiki 버전, 문서와 파일 수, 크기, 설치 플러그인, 설치 PHP 정보등을 포함하고 있습니다. diff --git a/lib/plugins/revert/lang/ko/lang.php b/lib/plugins/revert/lang/ko/lang.php index d36726279..f944361b8 100644 --- a/lib/plugins/revert/lang/ko/lang.php +++ b/lib/plugins/revert/lang/ko/lang.php @@ -16,5 +16,5 @@ $lang['reverted'] = '%s 판을 %s 판으로 되돌림'; $lang['removed'] = '%s 삭제함'; $lang['revstart'] = '되돌리기 작업을 시작합니다. 오랜 시간이 걸릴 수 있습니다. 완료되기 전에 스크립트 시간 초과가 발생한다면 더 작은 작업으로 나누어서 되돌리시기 바랍니다.'; $lang['revstop'] = '되돌리기 작업이 성공적으로 끝났습니다.'; -$lang['note1'] = '참고: 대소문자를 구별하여 찾습니다'; +$lang['note1'] = '참고: 대소문자를 구별해 찾습니다'; $lang['note2'] = '참고: 이 문서는 <i>%s</i> 스팸 단어를 포함하지 않은 최근 이전 판으로 되돌립니다. '; diff --git a/lib/plugins/usermanager/lang/ko/lang.php b/lib/plugins/usermanager/lang/ko/lang.php index f8c400d19..57bfbc4a2 100644 --- a/lib/plugins/usermanager/lang/ko/lang.php +++ b/lib/plugins/usermanager/lang/ko/lang.php @@ -23,8 +23,8 @@ $lang['value'] = '값'; $lang['add'] = '추가'; $lang['delete'] = '삭제'; $lang['delete_selected'] = '선택 삭제'; -$lang['edit'] = '수정'; -$lang['edit_prompt'] = '이 사용자 수정'; +$lang['edit'] = '편집'; +$lang['edit_prompt'] = '이 사용자 편집'; $lang['modify'] = '바뀜 저장'; $lang['search'] = '찾기'; $lang['search_prompt'] = '찾기 실행'; -- cgit v1.2.3 From 12d195ab7189878b41dc4d211befafc79ae402a6 Mon Sep 17 00:00:00 2001 From: Andreas Gohr <andi@splitbrain.org> Date: Fri, 7 Jun 2013 12:48:07 +0200 Subject: treat empty AD credentials as NULL values FS#2781 --- lib/plugins/authad/auth.php | 5 +++++ lib/plugins/authad/conf/default.php | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/plugins/authad/auth.php b/lib/plugins/authad/auth.php index b6b5dd268..fcbd2eeef 100644 --- a/lib/plugins/authad/auth.php +++ b/lib/plugins/authad/auth.php @@ -489,6 +489,11 @@ class auth_plugin_authad extends DokuWiki_Auth_Plugin { $this->cando['modPass'] = false; } + // adLDAP expects empty user/pass as NULL, we're less strict FS#2781 + if(empty($opts['admin_username'])) $opts['admin_username'] = null; + if(empty($opts['admin_password'])) $opts['admin_password'] = null; + + // user listing needs admin priviledges if(!empty($opts['admin_username']) && !empty($opts['admin_password'])) { $this->cando['getUsers'] = true; } else { diff --git a/lib/plugins/authad/conf/default.php b/lib/plugins/authad/conf/default.php index 9274db209..f71202cfc 100644 --- a/lib/plugins/authad/conf/default.php +++ b/lib/plugins/authad/conf/default.php @@ -4,8 +4,8 @@ $conf['account_suffix'] = ''; $conf['base_dn'] = ''; $conf['domain_controllers'] = ''; $conf['sso'] = 0; -$conf['admin_username'] = ''; -$conf['admin_password'] = ''; +$conf['admin_username'] = ''; +$conf['admin_password'] = ''; $conf['real_primarygroup'] = 0; $conf['use_ssl'] = 0; $conf['use_tls'] = 0; -- cgit v1.2.3 From e7fbe18945e8d94fd400fd66f36e67174951f290 Mon Sep 17 00:00:00 2001 From: Andreas Gohr <andi@splitbrain.org> Date: Fri, 7 Jun 2013 13:23:40 +0200 Subject: fix ldap deref option FS2798 Do not pass timelimit and deref settings to ldap_search. These values should be set globally via ldap_set_option() instead (as we do for deref). --- lib/plugins/authldap/auth.php | 8 ++++---- lib/plugins/authldap/conf/default.php | 1 + lib/plugins/authldap/conf/metadata.php | 1 + lib/plugins/authldap/lang/en/settings.php | 9 ++++++++- 4 files changed, 14 insertions(+), 5 deletions(-) diff --git a/lib/plugins/authldap/auth.php b/lib/plugins/authldap/auth.php index b49aa4792..e43c3f828 100644 --- a/lib/plugins/authldap/auth.php +++ b/lib/plugins/authldap/auth.php @@ -502,23 +502,23 @@ class auth_plugin_authldap extends DokuWiki_Auth_Plugin { * @return resource */ protected function _ldapsearch($link_identifier, $base_dn, $filter, $scope = 'sub', $attributes = null, - $attrsonly = 0, $sizelimit = 0, $timelimit = 0, $deref = LDAP_DEREF_NEVER) { + $attrsonly = 0, $sizelimit = 0) { if(is_null($attributes)) $attributes = array(); if($scope == 'base') { return @ldap_read( $link_identifier, $base_dn, $filter, $attributes, - $attrsonly, $sizelimit, $timelimit, $deref + $attrsonly, $sizelimit ); } elseif($scope == 'one') { return @ldap_list( $link_identifier, $base_dn, $filter, $attributes, - $attrsonly, $sizelimit, $timelimit, $deref + $attrsonly, $sizelimit ); } else { return @ldap_search( $link_identifier, $base_dn, $filter, $attributes, - $attrsonly, $sizelimit, $timelimit, $deref + $attrsonly, $sizelimit ); } } diff --git a/lib/plugins/authldap/conf/default.php b/lib/plugins/authldap/conf/default.php index d530d59c9..2c295eeeb 100644 --- a/lib/plugins/authldap/conf/default.php +++ b/lib/plugins/authldap/conf/default.php @@ -9,6 +9,7 @@ $conf['groupfilter'] = ''; $conf['version'] = 2; $conf['starttls'] = 0; $conf['referrals'] = 0; +$conf['deref'] = 0; $conf['binddn'] = ''; $conf['bindpw'] = ''; //$conf['mapping']['name'] unsupported in config manager diff --git a/lib/plugins/authldap/conf/metadata.php b/lib/plugins/authldap/conf/metadata.php index fc5b2e63c..a3256628c 100644 --- a/lib/plugins/authldap/conf/metadata.php +++ b/lib/plugins/authldap/conf/metadata.php @@ -8,6 +8,7 @@ $meta['groupfilter'] = array('string'); $meta['version'] = array('numeric'); $meta['starttls'] = array('onoff'); $meta['referrals'] = array('onoff'); +$meta['deref'] = array('multichoice','_choices' => array(0,1,2,3)); $meta['binddn'] = array('string'); $meta['bindpw'] = array('password'); //$meta['mapping']['name'] unsupported in config manager diff --git a/lib/plugins/authldap/lang/en/settings.php b/lib/plugins/authldap/lang/en/settings.php index ddedf8ae3..e3f385f99 100644 --- a/lib/plugins/authldap/lang/en/settings.php +++ b/lib/plugins/authldap/lang/en/settings.php @@ -8,9 +8,16 @@ $lang['groupfilter'] = 'LDAP filter to search for groups. Eg. <code>(&(objec $lang['version'] = 'The protocol version to use. You may need to set this to <code>3</code>'; $lang['starttls'] = 'Use TLS connections?'; $lang['referrals'] = 'Shall referrals be followed?'; +$lang['deref'] = 'How to dereference aliases?'; $lang['binddn'] = 'DN of an optional bind user if anonymous bind is not sufficient. Eg. <code>cn=admin, dc=my, dc=home</code>'; $lang['bindpw'] = 'Password of above user'; $lang['userscope'] = 'Limit search scope for user search'; $lang['groupscope'] = 'Limit search scope for group search'; -$lang['groupkey'] = 'Group member ship from any user attribute (instead of standard AD groups) e.g. group from department or telephone number'; +$lang['groupkey'] = 'Group membership from any user attribute (instead of standard AD groups) e.g. group from department or telephone number'; $lang['debug'] = 'Display additional debug information on errors'; + + +$lang['deref_o_0'] = 'LDAP_DEREF_NEVER'; +$lang['deref_o_1'] = 'LDAP_DEREF_SEARCHING'; +$lang['deref_o_2'] = 'LDAP_DEREF_FINDING'; +$lang['deref_o_3'] = 'LDAP_DEREF_ALWAYS'; \ No newline at end of file -- cgit v1.2.3 From 04e4890db370bdb57201f76581fe3dc0a3adb614 Mon Sep 17 00:00:00 2001 From: Andreas Gohr <andi@splitbrain.org> Date: Fri, 7 Jun 2013 13:50:46 +0200 Subject: fix problem when ldap returns no groups FS#2788 --- lib/plugins/authldap/auth.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/plugins/authldap/auth.php b/lib/plugins/authldap/auth.php index e43c3f828..6a967a6d4 100644 --- a/lib/plugins/authldap/auth.php +++ b/lib/plugins/authldap/auth.php @@ -248,7 +248,7 @@ class auth_plugin_authldap extends DokuWiki_Auth_Plugin { } // always add the default group to the list of groups - if(!in_array($conf['defaultgroup'], $info['grps'])) { + if(!$info['grps'] or !in_array($conf['defaultgroup'], $info['grps'])) { $info['grps'][] = $conf['defaultgroup']; } return $info; -- cgit v1.2.3 From 8a285f7fa7f09ae969e12cf4b7bda0f5123bb0fb Mon Sep 17 00:00:00 2001 From: Andreas Gohr <andi@splitbrain.org> Date: Sun, 9 Jun 2013 02:29:27 +0200 Subject: AUTH_PASSWORD_GENERATE event added This is needed to replace the password generator by a plugin implementation. Related to PR #166 and FS#2147 --- inc/auth.php | 45 +++++++++++++++++++++++++-------------- lib/plugins/usermanager/admin.php | 4 ++-- 2 files changed, 31 insertions(+), 18 deletions(-) diff --git a/inc/auth.php b/inc/auth.php index 1f8489f03..82a6b46cd 100644 --- a/inc/auth.php +++ b/inc/auth.php @@ -678,27 +678,40 @@ function auth_nameencode($name, $skip_group = false) { /** * Create a pronouncable password * + * The $foruser variable might be used by plugins to run additional password + * policy checks, but is not used by the default implementation + * * @author Andreas Gohr <andi@splitbrain.org> * @link http://www.phpbuilder.com/annotate/message.php3?id=1014451 + * @triggers AUTH_PASSWORD_GENERATE * + * @param string $foruser username for which the password is generated * @return string pronouncable password */ -function auth_pwgen() { - $pw = ''; - $c = 'bcdfghjklmnprstvwz'; //consonants except hard to speak ones - $v = 'aeiou'; //vowels - $a = $c.$v; //both - - //use two syllables... - for($i = 0; $i < 2; $i++) { - $pw .= $c[rand(0, strlen($c) - 1)]; - $pw .= $v[rand(0, strlen($v) - 1)]; - $pw .= $a[rand(0, strlen($a) - 1)]; +function auth_pwgen($foruser='') { + $data = array( + 'password' = '', + 'foruser' = $foruser + ); + + $evt = new Doku_Event('AUTH_PASSWORD_GENERATE', $data); + if($evt->advise_before(true)) { + $c = 'bcdfghjklmnprstvwz'; //consonants except hard to speak ones + $v = 'aeiou'; //vowels + $a = $c.$v; //both + + //use two syllables... + for($i = 0; $i < 2; $i++) { + $data['password'] .= $c[rand(0, strlen($c) - 1)]; + $data['password'] .= $v[rand(0, strlen($v) - 1)]; + $data['password'] .= $a[rand(0, strlen($a) - 1)]; + } + //... and add a nice number + $data['password'] .= rand(10, 99); } - //... and add a nice number - $pw .= rand(10, 99); + $evt->advise_after(); - return $pw; + return $data['password']; } /** @@ -765,7 +778,7 @@ function register() { } if($conf['autopasswd']) { - $pass = auth_pwgen(); // automatically generate password + $pass = auth_pwgen($login); // automatically generate password } elseif(empty($pass) || empty($passchk)) { msg($lang['regmissing'], -1); // complain about missing passwords return false; @@ -958,7 +971,7 @@ function act_resendpwd() { } else { // autogenerate the password and send by mail - $pass = auth_pwgen(); + $pass = auth_pwgen($user); if(!$auth->triggerUserMod('modify', array($user, array('pass' => $pass)))) { msg('error modifying user data', -1); return false; diff --git a/lib/plugins/usermanager/admin.php b/lib/plugins/usermanager/admin.php index 01f4a4cdb..445836a50 100644 --- a/lib/plugins/usermanager/admin.php +++ b/lib/plugins/usermanager/admin.php @@ -355,7 +355,7 @@ class admin_plugin_usermanager extends DokuWiki_Admin_Plugin { if ($this->_auth->canDo('modPass')){ if (empty($pass)){ if($INPUT->has('usernotify')){ - $pass = auth_pwgen(); + $pass = auth_pwgen($user); } else { msg($this->lang['add_fail'], -1); return false; @@ -496,7 +496,7 @@ class admin_plugin_usermanager extends DokuWiki_Admin_Plugin { // generate password if left empty and notification is on if($INPUT->has('usernotify') && empty($newpass)){ - $newpass = auth_pwgen(); + $newpass = auth_pwgen($olduser); } if (!empty($newpass) && $this->_auth->canDo('modPass')) -- cgit v1.2.3 From d628dcf33c131b3ede5c78b4550c2ba23124f432 Mon Sep 17 00:00:00 2001 From: Andreas Gohr <andi@splitbrain.org> Date: Sun, 9 Jun 2013 02:51:19 +0200 Subject: fixed syntax fuckup --- inc/auth.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/inc/auth.php b/inc/auth.php index 82a6b46cd..db6245e20 100644 --- a/inc/auth.php +++ b/inc/auth.php @@ -690,8 +690,8 @@ function auth_nameencode($name, $skip_group = false) { */ function auth_pwgen($foruser='') { $data = array( - 'password' = '', - 'foruser' = $foruser + 'password' => '', + 'foruser' => $foruser ); $evt = new Doku_Event('AUTH_PASSWORD_GENERATE', $data); -- cgit v1.2.3 From 62765857f84626449d6c53b1a46c462a37e5083a Mon Sep 17 00:00:00 2001 From: Klap-in <klapinklapin@gmail.com> Date: Sun, 9 Jun 2013 21:17:20 +0200 Subject: update common_ml test for hash change --- _test/tests/inc/common_ml.test.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/_test/tests/inc/common_ml.test.php b/_test/tests/inc/common_ml.test.php index 9f3d87598..6f3b71db4 100644 --- a/_test/tests/inc/common_ml.test.php +++ b/_test/tests/inc/common_ml.test.php @@ -105,8 +105,9 @@ class common_ml_test extends DokuWikiTest { foreach($ids as $id) { $tok = media_get_token($id, $w, 0); + $hash = substr(PassHash::hmac('md5', $id, auth_cookiesalt()), 0, 6); - $expect = DOKU_BASE.$this->script.'?hash='.substr(md5(auth_cookiesalt().$id), 0, 6).'&w='.$w.'&tok='.$tok.'&media='.rawurlencode($id); + $expect = DOKU_BASE.$this->script.'?hash='.$hash.'&w='.$w.'&tok='.$tok.'&media='.rawurlencode($id); $this->assertEquals($expect, ml($id, $args)); } } -- cgit v1.2.3 From b9ee6a44e7499b5c2e9f117096cedc769ef2e25d Mon Sep 17 00:00:00 2001 From: Klap-in <klapinklapin@gmail.com> Date: Sun, 9 Jun 2013 23:04:52 +0200 Subject: apply media_isexternal in ml() --- inc/common.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inc/common.php b/inc/common.php index 59ceb0c0d..5f045e72d 100644 --- a/inc/common.php +++ b/inc/common.php @@ -435,7 +435,7 @@ function exportlink($id = '', $format = 'raw', $more = '', $abs = false, $sep = */ function ml($id = '', $more = '', $direct = true, $sep = '&', $abs = false) { global $conf; - $isexternalimage = preg_match('#^(https?|ftp)://#i', $id); + $isexternalimage = media_isexternal($id); if(!$isexternalimage) { $id = cleanID($id); } -- cgit v1.2.3 From e0086ca277bafe4f068079a4655a5601914a6f03 Mon Sep 17 00:00:00 2001 From: Andreas Gohr <andi@splitbrain.org> Date: Wed, 12 Jun 2013 21:45:37 +0200 Subject: check for spam in summary as well, added common spam summary --- conf/wordblock.conf | 1 + inc/common.php | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/conf/wordblock.conf b/conf/wordblock.conf index fe451f278..fc939a4d4 100644 --- a/conf/wordblock.conf +++ b/conf/wordblock.conf @@ -30,3 +30,4 @@ https?:\/\/(\S*?)(2-pay-secure|911essay|academia-research|anypapers|applicatione flatsinmumbai\.co\.in https?:\/\/(\S*?)penny-?stock mattressreview\.biz +(just|simply) (my|a) profile (site|webpage|page) diff --git a/inc/common.php b/inc/common.php index 59ceb0c0d..760a9f6dc 100644 --- a/inc/common.php +++ b/inc/common.php @@ -557,12 +557,13 @@ function checkwordblock($text = '') { global $TEXT; global $PRE; global $SUF; + global $SUM; global $conf; global $INFO; if(!$conf['usewordblock']) return false; - if(!$text) $text = "$PRE $TEXT $SUF"; + if(!$text) $text = "$PRE $TEXT $SUF $SUM"; // we prepare the text a tiny bit to prevent spammers circumventing URL checks $text = preg_replace('!(\b)(www\.[\w.:?\-;,]+?\.[\w.:?\-;,]+?[\w/\#~:.?+=&%@\!\-.:?\-;,]+?)([.:?\-;,]*[^\w/\#~:.?+=&%@\!\-.:?\-;,])!i', '\1http://\2 \2\3', $text); -- cgit v1.2.3 From 987c8d26bbfec753f50b50e8f16e0f5579a93e11 Mon Sep 17 00:00:00 2001 From: Andreas Gohr <andi@splitbrain.org> Date: Fri, 14 Jun 2013 14:49:39 +0200 Subject: Increased strength of auto generated passwords a bit If you want better random initialization and more control over the password strength install the passpolicy plugin. --- inc/auth.php | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/inc/auth.php b/inc/auth.php index db6245e20..6107645cd 100644 --- a/inc/auth.php +++ b/inc/auth.php @@ -681,14 +681,14 @@ function auth_nameencode($name, $skip_group = false) { * The $foruser variable might be used by plugins to run additional password * policy checks, but is not used by the default implementation * - * @author Andreas Gohr <andi@splitbrain.org> - * @link http://www.phpbuilder.com/annotate/message.php3?id=1014451 + * @author Andreas Gohr <andi@splitbrain.org> + * @link http://www.phpbuilder.com/annotate/message.php3?id=1014451 * @triggers AUTH_PASSWORD_GENERATE * * @param string $foruser username for which the password is generated * @return string pronouncable password */ -function auth_pwgen($foruser='') { +function auth_pwgen($foruser = '') { $data = array( 'password' => '', 'foruser' => $foruser @@ -696,18 +696,19 @@ function auth_pwgen($foruser='') { $evt = new Doku_Event('AUTH_PASSWORD_GENERATE', $data); if($evt->advise_before(true)) { - $c = 'bcdfghjklmnprstvwz'; //consonants except hard to speak ones - $v = 'aeiou'; //vowels - $a = $c.$v; //both - - //use two syllables... - for($i = 0; $i < 2; $i++) { - $data['password'] .= $c[rand(0, strlen($c) - 1)]; - $data['password'] .= $v[rand(0, strlen($v) - 1)]; - $data['password'] .= $a[rand(0, strlen($a) - 1)]; + $c = 'bcdfghjklmnprstvwz'; //consonants except hard to speak ones + $v = 'aeiou'; //vowels + $a = $c.$v; //both + $s = '!$%&?+*~#-_:.;,'; // specials + + //use thre syllables... + for($i = 0; $i < 3; $i++) { + $data['password'] .= $c[mt_rand(0, strlen($c) - 1)]; + $data['password'] .= $v[mt_rand(0, strlen($v) - 1)]; + $data['password'] .= $a[mt_rand(0, strlen($a) - 1)]; } - //... and add a nice number - $data['password'] .= rand(10, 99); + //... and add a nice number and special + $data['password'] .= mt_rand(10, 99).$s[mt_rand(0, strlen($s) - 1)]; } $evt->advise_after(); -- cgit v1.2.3 From 9d24536dd8ad865dfad2c0259d6b00273e826c12 Mon Sep 17 00:00:00 2001 From: Andreas Gohr <andi@splitbrain.org> Date: Fri, 14 Jun 2013 17:11:37 +0200 Subject: correctly count deleted users in plain auth FS#2800 reloading the user list after the delete action will make sure the count is always correct. --- lib/plugins/authplain/auth.php | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/lib/plugins/authplain/auth.php b/lib/plugins/authplain/auth.php index 3416ede89..8c4ce0dd9 100644 --- a/lib/plugins/authplain/auth.php +++ b/lib/plugins/authplain/auth.php @@ -198,13 +198,9 @@ class auth_plugin_authplain extends DokuWiki_Auth_Plugin { if(empty($deleted)) return 0; $pattern = '/^('.join('|', $deleted).'):/'; + io_deleteFromFile($config_cascade['plainauth.users']['default'], $pattern, true); - if(io_deleteFromFile($config_cascade['plainauth.users']['default'], $pattern, true)) { - foreach($deleted as $user) unset($this->users[$user]); - return count($deleted); - } - - // problem deleting, reload the user list and count the difference + // reload the user list and count the difference $count = count($this->users); $this->_loadUserData(); $count -= count($this->users); -- cgit v1.2.3 From 81ee3b1c4ea669b4278fc1160162c686b82e559c Mon Sep 17 00:00:00 2001 From: Andreas Gohr <andi@splitbrain.org> Date: Sun, 16 Jun 2013 18:09:34 +0200 Subject: Swedish language update --- inc/lang/sv/lang.php | 65 ++++++++++++++++++- inc/lang/sv/mailwrap.html | 13 ++++ inc/lang/sv/resetpwd.txt | 3 + inc/lang/sv/subscr_form.txt | 3 + inc/lang/sv/subscr_single.txt | 23 +++++++ lib/plugins/acl/lang/sv/lang.php | 1 + lib/plugins/authad/lang/sv/settings.php | 11 ++++ lib/plugins/authldap/lang/sv/settings.php | 16 +++++ lib/plugins/authmysql/lang/sv/settings.php | 25 ++++++++ lib/plugins/authpgsql/lang/sv/settings.php | 28 ++++++++ lib/plugins/config/lang/sv/lang.php | 100 ++++++++++++++++------------- lib/plugins/plugin/lang/sv/lang.php | 2 + lib/plugins/popularity/lang/sv/lang.php | 1 + lib/plugins/revert/lang/sv/lang.php | 1 + lib/plugins/usermanager/lang/sv/lang.php | 1 + 15 files changed, 246 insertions(+), 47 deletions(-) create mode 100644 inc/lang/sv/mailwrap.html create mode 100644 inc/lang/sv/resetpwd.txt create mode 100644 inc/lang/sv/subscr_form.txt create mode 100644 inc/lang/sv/subscr_single.txt create mode 100644 lib/plugins/authad/lang/sv/settings.php create mode 100644 lib/plugins/authldap/lang/sv/settings.php create mode 100644 lib/plugins/authmysql/lang/sv/settings.php create mode 100644 lib/plugins/authpgsql/lang/sv/settings.php diff --git a/inc/lang/sv/lang.php b/inc/lang/sv/lang.php index 4c4e060b4..9608784c6 100644 --- a/inc/lang/sv/lang.php +++ b/inc/lang/sv/lang.php @@ -17,6 +17,7 @@ * @author Bogge Bogge <bogge@bogge.com> * @author Peter Åström <eaustreum@gmail.com> * @author mikael@mallander.net + * @author Smorkster Andersson smorkster@gmail.com */ $lang['encoding'] = 'utf-8'; $lang['direction'] = 'ltr'; @@ -52,11 +53,14 @@ $lang['btn_backtomedia'] = 'Tillbaka till val av Mediafil'; $lang['btn_subscribe'] = 'Prenumerera på ändringar'; $lang['btn_profile'] = 'Uppdatera profil'; $lang['btn_reset'] = 'Återställ'; +$lang['btn_resendpwd'] = 'Skapa nytt lösenord'; $lang['btn_draft'] = 'Redigera utkast'; $lang['btn_recover'] = 'Återskapa utkast'; $lang['btn_draftdel'] = 'Radera utkast'; $lang['btn_revert'] = 'Återställ'; $lang['btn_register'] = 'Registrera'; +$lang['btn_apply'] = 'Verkställ'; +$lang['btn_media'] = 'Media Hanteraren'; $lang['loggedinas'] = 'Inloggad som'; $lang['user'] = 'Användarnamn'; $lang['pass'] = 'Lösenord'; @@ -86,6 +90,7 @@ $lang['profnoempty'] = 'Namn och e-postadress måste fyllas i.'; $lang['profchanged'] = 'Användarprofilen uppdaterad.'; $lang['pwdforget'] = 'Glömt ditt lösenord? Ordna ett nytt'; $lang['resendna'] = 'Den här wikin stödjer inte utskick av lösenord.'; +$lang['resendpwd'] = 'Sätt lösenord för'; $lang['resendpwdmissing'] = 'Du måste fylla i alla fält.'; $lang['resendpwdnouser'] = 'Den här användaren hittas inte i databasen.'; $lang['resendpwdbadauth'] = 'Den här verifieringskoden är inte giltig. Kontrollera att du använde hela verifieringslänken.'; @@ -98,9 +103,10 @@ $lang['searchmedia_in'] = 'Sök i %s'; $lang['txt_upload'] = 'Välj fil att ladda upp'; $lang['txt_filename'] = 'Ladda upp som (ej obligatoriskt)'; $lang['txt_overwrt'] = 'Skriv över befintlig fil'; +$lang['maxuploadsize'] = 'Max %s per uppladdad fil.'; $lang['lockedby'] = 'Låst av'; $lang['lockexpire'] = 'Lås upphör att gälla'; -$lang['js']['willexpire'] = 'Ditt redigeringslås för detta dokument kommer snart att upphöra.\nFör att undvika versionskonflikter bör du förhandsgranska ditt dokument för att förlänga redigeringslåset.'; +$lang['js']['willexpire'] = 'Ditt redigeringslås för detta dokument kommer snart att upphöra.\nFör att undvika versionskonflikter bör du förhandsgranska ditt dokument för att förlänga redigeringslåset.'; $lang['js']['notsavedyet'] = 'Det finns ändringar som inte är sparade. Är du säker på att du vill fortsätta?'; $lang['js']['searchmedia'] = 'Sök efter filer'; @@ -112,12 +118,14 @@ $lang['js']['mediaalign'] = 'Justering'; $lang['js']['mediasize'] = 'Bildstorlek'; $lang['js']['mediatarget'] = 'Länköppning'; $lang['js']['mediaclose'] = 'Stäng'; +$lang['js']['mediainsert'] = 'Infoga'; $lang['js']['mediadisplayimg'] = 'Visa bilden.'; $lang['js']['mediadisplaylnk'] = 'Visa endast länken.'; $lang['js']['mediasmall'] = 'Liten storlek'; $lang['js']['mediamedium'] = 'Mellanstor storlek'; $lang['js']['medialarge'] = 'Stor storlek'; $lang['js']['mediaoriginal'] = 'Originalstorlek'; +$lang['js']['medialnk'] = 'Länk till detalj sida'; $lang['js']['mediadirect'] = 'Direktlänk till originalet'; $lang['js']['medianolnk'] = 'Ingen länk'; $lang['js']['medianolink'] = 'Länka inte bilden'; @@ -129,6 +137,15 @@ Du kan fortfarande klippa och klistra in länken om du använder en annan webbl $lang['js']['linkwiz'] = 'Snabbguide Länkar'; $lang['js']['linkto'] = 'Länk till:'; $lang['js']['del_confirm'] = 'Vill du verkligen radera?'; +$lang['js']['restore_confirm'] = 'Återställa denna version?'; +$lang['js']['media_diff'] = 'Se skillnader:'; +$lang['js']['media_diff_both'] = 'Sida vid sida'; +$lang['js']['media_select'] = 'Välj filer...'; +$lang['js']['media_upload_btn'] = 'Ladda upp'; +$lang['js']['media_done_btn'] = 'Färdig'; +$lang['js']['media_drop'] = 'Släpp filer här för att ladda upp'; +$lang['js']['media_cancel'] = 'ta bort'; +$lang['js']['media_overwrt'] = 'Skriv över existerande filer'; $lang['rssfailed'] = 'Ett fel uppstod när detta RSS-flöde skulle hämtas: '; $lang['nothingfound'] = 'Inga filer hittades.'; $lang['mediaselect'] = 'Mediafiler'; @@ -177,10 +194,19 @@ $lang['external_edit'] = 'extern redigering'; $lang['summary'] = 'Redigeringskommentar'; $lang['noflash'] = '<a href="http://www.adobe.com/products/flashplayer/">Adobe Flash Plugin</a> behövs för att visa detta innehåll.'; $lang['download'] = 'Ladda ner kodfragmentet'; +$lang['tools'] = 'Verktyg'; +$lang['user_tools'] = 'Användarverktyg'; +$lang['page_tools'] = 'Sidverktyg'; +$lang['skip_to_content'] = 'hoppa till innehåll'; $lang['mail_newpage'] = 'sida tillagd:'; $lang['mail_changed'] = 'sida ändrad:'; +$lang['mail_subscribe_list'] = 'sidor ändrade i namnrymd:'; $lang['mail_new_user'] = 'Ny användare:'; $lang['mail_upload'] = 'fil uppladdad:'; +$lang['changes_type'] = 'Se ändringar av'; +$lang['pages_changes'] = 'Sidor'; +$lang['media_changes'] = 'Mediafiler'; +$lang['both_changes'] = 'Både sidor och mediafiler'; $lang['qb_bold'] = 'Fet text'; $lang['qb_italic'] = 'Kursiv text'; $lang['qb_underl'] = 'Understruken text'; @@ -221,14 +247,26 @@ $lang['img_copyr'] = 'Copyright'; $lang['img_format'] = 'Format'; $lang['img_camera'] = 'Kamera'; $lang['img_keywords'] = 'Nyckelord'; +$lang['img_width'] = 'Bredd'; +$lang['img_height'] = 'Höjd'; +$lang['img_manager'] = 'Se mediahanteraren'; +$lang['subscr_subscribe_success'] = 'La till %s till prenumerationslista %s'; +$lang['subscr_subscribe_noaddress'] = 'Det finns ingen adress associerad med din inloggning, du kan inte bli tillagd i prenumerationslistan'; +$lang['subscr_unsubscribe_success'] = '% borttagen från prenumerationslistan för %'; +$lang['subscr_unsubscribe_error'] = 'Fel vid borttagning av %s från prenumerationslista %s'; +$lang['subscr_already_subscribed'] = '%s prenumererar redan på %s'; +$lang['subscr_not_subscribed'] = '%s prenumererar inte på %s'; +$lang['subscr_m_not_subscribed'] = 'Du prenumererar inte på denna sida eller namnrymd.'; $lang['subscr_m_new_header'] = 'Lägg till prenumeration'; $lang['subscr_m_current_header'] = 'Nuvarande prenumerationer'; $lang['subscr_m_unsubscribe'] = 'Avsluta prenumeration'; $lang['subscr_m_subscribe'] = 'Prenumerera'; $lang['subscr_m_receive'] = 'Ta emot'; $lang['subscr_style_every'] = 'skicka epost vid varje ändring'; +$lang['subscr_style_list'] = 'lista över ändrade sidor sedan senaste e-post (varje %.2f dag)'; $lang['authmodfailed'] = 'Felaktiga inställningar för användarautentisering. Var vänlig meddela wikiadministratören.'; $lang['authtempfail'] = 'Tillfälligt fel på användarautentisering. Om felet kvarstår, var vänlig meddela wikiadministratören.'; +$lang['authpwdexpire'] = 'Ditt lösenord kommer att bli ogiltigt om %d dagar, du bör ändra det snart.'; $lang['i_chooselang'] = 'Välj språk'; $lang['i_installer'] = 'Installation av DokuWiki'; $lang['i_wikiname'] = 'Wikins namn'; @@ -254,6 +292,10 @@ $lang['i_pol0'] = 'Öppen wiki (alla får läsa, skriva och ladda $lang['i_pol1'] = 'Publik wiki (alla får läsa, registrerade användare för skriva och ladda upp filer)'; $lang['i_pol2'] = 'Sluten wiki (endast registrerade användare får läsa, skriva och ladda upp filer)'; $lang['i_retry'] = 'Försök igen'; +$lang['i_license'] = 'Vänligen välj licens du vill använda för ditt innehåll:'; +$lang['i_license_none'] = 'Visa ingen licensinformation'; +$lang['i_pop_field'] = 'Hjälp oss förbättra DokuWiki upplevelsen:'; +$lang['i_pop_label'] = 'Sänd anonym användarinformation en gång i månaden till DokuWikis utvecklare'; $lang['recent_global'] = 'Du bevakar ändringar i namnrymden <b>%s</b>. Du kan också titta på <a href="%s">senaste ändringar för hela wikin</a>.'; $lang['years'] = '%d år sedan'; $lang['months'] = '%d månader sedan'; @@ -263,3 +305,24 @@ $lang['hours'] = '%d timmar sedan'; $lang['minutes'] = '%d minuter sedan'; $lang['seconds'] = '%d sekunder sedan'; $lang['wordblock'] = 'Din ändring sparades inte för att den innehåller otillåten text (spam).'; +$lang['media_uploadtab'] = 'Ladda upp'; +$lang['media_searchtab'] = 'Sök'; +$lang['media_file'] = 'Fil'; +$lang['media_viewtab'] = 'Visa'; +$lang['media_edittab'] = 'Redigera'; +$lang['media_list_thumbs'] = 'Miniatyrbild'; +$lang['media_list_rows'] = 'Rader'; +$lang['media_sort_name'] = 'Namn'; +$lang['media_sort_date'] = 'Datum'; +$lang['media_namespaces'] = 'Visa namnrymd'; +$lang['media_files'] = 'Filer i %s'; +$lang['media_upload'] = 'Ladda upp till %s'; +$lang['media_search'] = 'Sök i %s'; +$lang['media_view'] = '%s'; +$lang['media_viewold'] = '%s vid %s'; +$lang['media_edit'] = 'Redigera %s'; +$lang['media_meta_edited'] = 'metadata redigerat'; +$lang['media_perm_read'] = 'Du har tyvärr inte tillräckliga behörigheter för att läsa filer.'; +$lang['media_perm_upload'] = 'Du har tyvärr inte tillräckliga behörigheter för att ladda upp filer.'; +$lang['media_update'] = 'Ladda upp ny version'; +$lang['media_restore'] = 'Återställ denna version'; diff --git a/inc/lang/sv/mailwrap.html b/inc/lang/sv/mailwrap.html new file mode 100644 index 000000000..d8ab9ba5b --- /dev/null +++ b/inc/lang/sv/mailwrap.html @@ -0,0 +1,13 @@ +<html> +<head> +<title>@TITLE@ + + + + +@HTMLBODY@ + +

        +Denna e-post har genererats av DokuWiki vid @DOKUWIKIURL@. + + \ No newline at end of file diff --git a/inc/lang/sv/resetpwd.txt b/inc/lang/sv/resetpwd.txt new file mode 100644 index 000000000..a329ce571 --- /dev/null +++ b/inc/lang/sv/resetpwd.txt @@ -0,0 +1,3 @@ +====== Sätt nytt lösenord ====== + +Vänligen skriv ett nytt lösenord för ditt konto på denna wiki. \ No newline at end of file diff --git a/inc/lang/sv/subscr_form.txt b/inc/lang/sv/subscr_form.txt new file mode 100644 index 000000000..bfb8fa3cd --- /dev/null +++ b/inc/lang/sv/subscr_form.txt @@ -0,0 +1,3 @@ +====== Prenumerations hantering ====== + +Denna sida låter dig hantera dina prenumerationer för nuvarande sida och namnrymd. \ No newline at end of file diff --git a/inc/lang/sv/subscr_single.txt b/inc/lang/sv/subscr_single.txt new file mode 100644 index 000000000..dff88343e --- /dev/null +++ b/inc/lang/sv/subscr_single.txt @@ -0,0 +1,23 @@ +Hej! + +Sidan @PAGE@ i wikin @TITLE@ har ändrats. +Detta är ändringarna: + +-------------------------------------------------------- +@DIFF@ +-------------------------------------------------------- + +Datum: @DATE@ +Användare: @USER@ +Ändrings sammanfattning: @SUMMARY@ +Gammal version: @OLDPAGE@ +Ny version: @NEWPAGE@ + +För att avsluta noteringar om sidor, logga in på wikin vid +@DOKUWIKIURL@ gå sedan till +@SUBSCRIBE@ +och avsluta prenumerationen av sida och/eller namnrymd ändringar. + +-- +Denna e-post har genererats av DokuWiki vid +@DOKUWIKIURL@ \ No newline at end of file diff --git a/lib/plugins/acl/lang/sv/lang.php b/lib/plugins/acl/lang/sv/lang.php index 7f963d5e1..388672fc0 100644 --- a/lib/plugins/acl/lang/sv/lang.php +++ b/lib/plugins/acl/lang/sv/lang.php @@ -16,6 +16,7 @@ * @author Peter Åström * @author Håkan Sandell * @author mikael@mallander.net + * @author Smorkster Andersson smorkster@gmail.com */ $lang['admin_acl'] = 'Hantera behörighetslistan (ACL)'; $lang['acl_group'] = 'Grupp'; diff --git a/lib/plugins/authad/lang/sv/settings.php b/lib/plugins/authad/lang/sv/settings.php new file mode 100644 index 000000000..b1eb1cb96 --- /dev/null +++ b/lib/plugins/authad/lang/sv/settings.php @@ -0,0 +1,11 @@ +min.domän.org'; +$lang['admin_password'] = 'Lösenord för användare ovan.'; +$lang['sso'] = 'Ska Single-Sign-On via Kerberos eller NTLM användas?'; +$lang['use_ssl'] = 'Använda SSL anslutning? Om använd, möjliggör inte TLS nedan.'; +$lang['use_tls'] = 'Använda TLS anslutning? Om använd, möjliggör inte SSL ovan.'; diff --git a/lib/plugins/authldap/lang/sv/settings.php b/lib/plugins/authldap/lang/sv/settings.php new file mode 100644 index 000000000..0fdcad147 --- /dev/null +++ b/lib/plugins/authldap/lang/sv/settings.php @@ -0,0 +1,16 @@ +localhost) eller giltig full URL (ldap://server.tld:389)'; +$lang['port'] = 'LDAP server port, om det inte angavs full URL ovan'; +$lang['usertree'] = 'Specificera var användarkonton finns. T.ex. ou=Användare, dc=server, dc=tld'; +$lang['grouptree'] = 'Specificera var grupper finns. T.ex. ou=Grupp, dc=server, dc=tld'; +$lang['userfilter'] = 'LDAP filter för att söka efter användarkonton. T.ex. (&(uid=%{user})(objectClass=posixAccount))'; +$lang['groupfilter'] = 'LDAP filter för att söka efter grupper. T.ex. (&(objectClass=posixGroup)(|(gidNumber=%{gid})(memberUID=%{user})))'; +$lang['version'] = 'Version av protokoll att använda. Du kan behöva sätta detta till 3'; +$lang['bindpw'] = 'Lösenord för användare ovan'; +$lang['groupkey'] = 'Gruppmedlemskap från något användarattribut (istället för standard AD grupp) t.ex. grupp från avdelning eller telefonnummer'; +$lang['debug'] = 'Visa ytterligare felsökningsinformation vid fel'; diff --git a/lib/plugins/authmysql/lang/sv/settings.php b/lib/plugins/authmysql/lang/sv/settings.php new file mode 100644 index 000000000..027c64025 --- /dev/null +++ b/lib/plugins/authmysql/lang/sv/settings.php @@ -0,0 +1,25 @@ + * @author Håkan Sandell * @author mikael@mallander.net + * @author Smorkster Andersson smorkster@gmail.com */ $lang['menu'] = 'Hantera inställningar'; $lang['error'] = 'Inställningarna uppdaterades inte på grund av ett felaktigt värde. Titta igenom dina ändringar och försök sedan spara igen. @@ -39,6 +40,8 @@ $lang['_anti_spam'] = 'Inställningar för anti-spam'; $lang['_editing'] = 'Inställningar för redigering'; $lang['_links'] = 'Inställningar för länkar'; $lang['_media'] = 'Inställningar för medier'; +$lang['_notifications'] = 'Noterings inställningar'; +$lang['_syndication'] = 'Syndikats inställningar'; $lang['_advanced'] = 'Avancerade inställningar'; $lang['_network'] = 'Nätverksinställningar'; $lang['_plugin_sufix'] = '(inställningar för insticksmodul)'; @@ -46,25 +49,27 @@ $lang['_template_sufix'] = '(inställningar för mall)'; $lang['_msg_setting_undefined'] = 'Ingen inställningsmetadata.'; $lang['_msg_setting_no_class'] = 'Ingen inställningsklass.'; $lang['_msg_setting_no_default'] = 'Inget standardvärde.'; -$lang['fmode'] = 'Filskydd för nya filer'; -$lang['dmode'] = 'Filskydd för nya kataloger'; -$lang['lang'] = 'Språk'; -$lang['basedir'] = 'Grundkatalog'; -$lang['baseurl'] = 'Grund-webbadress'; -$lang['savedir'] = 'Katalog för att spara data'; -$lang['start'] = 'Startsidans namn'; $lang['title'] = 'Wikins namn'; +$lang['start'] = 'Startsidans namn'; +$lang['lang'] = 'Språk'; $lang['template'] = 'Mall'; $lang['license'] = 'Under vilken licens skall ditt innehåll publiceras?'; -$lang['fullpath'] = 'Visa fullständig sökväg i sidfoten'; +$lang['savedir'] = 'Katalog för att spara data'; +$lang['basedir'] = 'Grundkatalog'; +$lang['baseurl'] = 'Grund-webbadress'; +$lang['cookiedir'] = 'Cookie sökväg. Lämna blankt för att använda basurl.'; +$lang['dmode'] = 'Filskydd för nya kataloger'; +$lang['fmode'] = 'Filskydd för nya filer'; +$lang['allowdebug'] = 'Tillåt felsökning stäng av om det inte behövs!'; $lang['recent'] = 'Antal poster under "Nyligen ändrat"'; +$lang['recent_days'] = 'Hur många ändringar som ska sparas (dagar)'; $lang['breadcrumbs'] = 'Antal spår'; $lang['youarehere'] = 'Hierarkiska spår'; +$lang['fullpath'] = 'Visa fullständig sökväg i sidfoten'; $lang['typography'] = 'Aktivera typografiska ersättningar'; -$lang['htmlok'] = 'Tillåt inbäddad HTML'; -$lang['phpok'] = 'Tillåt inbäddad PHP'; $lang['dformat'] = 'Datumformat (se PHP:s strftime-funktion)'; $lang['signature'] = 'Signatur'; +$lang['showuseras'] = 'Vad som skall visas när man visar den användare som senast redigerade en sida'; $lang['toptoclevel'] = 'Toppnivå för innehållsförteckning'; $lang['tocminheads'] = 'Minimalt antal rubriker för att avgöra om innehållsförteckning byggs'; $lang['maxtoclevel'] = 'Maximal nivå för innehållsförteckning'; @@ -72,15 +77,8 @@ $lang['maxseclevel'] = 'Maximal nivå för redigering av rubriker'; $lang['camelcase'] = 'Använd CamelCase för länkar'; $lang['deaccent'] = 'Rena sidnamn'; $lang['useheading'] = 'Använda första rubriken som sidnamn'; -$lang['refcheck'] = 'Kontrollera referenser till mediafiler'; -$lang['refshow'] = 'Antal mediareferenser som ska visas'; -$lang['allowdebug'] = 'Tillåt felsökning stäng av om det inte behövs!'; -$lang['usewordblock'] = 'Blockera spam baserat på ordlista'; -$lang['indexdelay'] = 'Tidsfördröjning före indexering (sek)'; -$lang['relnofollow'] = 'Använd rel="nofollow" för externa länkar'; -$lang['mailguard'] = 'Koda e-postadresser'; -$lang['iexssprotect'] = 'Kontrollera om uppladdade filer innehåller eventuellt skadlig JavaScript eller HTML-kod'; -$lang['showuseras'] = 'Vad som skall visas när man visar den användare som senast redigerade en sida'; +$lang['sneaky_index'] = 'Som standard visar DokuWiki alla namnrymder på indexsidan. Genom att aktivera det här valet döljer man namnrymder som användaren inte har behörighet att läsa. Det kan leda till att man döljer åtkomliga undernamnrymder, och gör indexet oanvändbart med vissa ACL-inställningar.'; +$lang['hidepages'] = 'Dölj matchande sidor (reguljära uttryck)'; $lang['useacl'] = 'Använd behörighetslista (ACL)'; $lang['autopasswd'] = 'Autogenerera lösenord'; $lang['authtype'] = 'System för autentisering'; @@ -89,60 +87,69 @@ $lang['defaultgroup'] = 'Förvald grupp'; $lang['superuser'] = 'Huvudadministratör - en grupp eller en användare med full tillgång till alla sidor och funktioner, oavsett behörighetsinställningars'; $lang['manager'] = 'Administratör -- en grupp eller användare med tillgång till vissa administrativa funktioner.'; $lang['profileconfirm'] = 'Bekräfta ändringarna i profilen med lösenordet'; +$lang['rememberme'] = 'Tillåt permanenta inloggningscookies (kom ihåg mig)'; $lang['disableactions'] = 'Stäng av funktioner i DokuWiki'; $lang['disableactions_check'] = 'Kontroll'; $lang['disableactions_subscription'] = 'Prenumerera/Säg upp prenumeration'; $lang['disableactions_wikicode'] = 'Visa källkod/Exportera råtext'; $lang['disableactions_other'] = 'Andra funktioner (kommaseparerade)'; -$lang['sneaky_index'] = 'Som standard visar DokuWiki alla namnrymder på indexsidan. Genom att aktivera det här valet döljer man namnrymder som användaren inte har behörighet att läsa. Det kan leda till att man döljer åtkomliga undernamnrymder, och gör indexet oanvändbart med vissa ACL-inställningar.'; $lang['auth_security_timeout'] = 'Autentisieringssäkerhets timeout (sekunder)'; $lang['securecookie'] = 'Skall cookies som sätts via HTTPS endast skickas via HTTPS från webbläsaren? Avaktivera detta alternativ endast om inloggningen till din wiki är säkrad med SSL men läsning av wikin är osäkrad.'; -$lang['updatecheck'] = 'Kontrollera uppdateringar och säkerhetsvarningar? DokuWiki behöver kontakta update.dokuwiki.org för den här funktionen.'; -$lang['userewrite'] = 'Använd rena webbadresser'; -$lang['useslash'] = 'Använd snedstreck för att separera namnrymder i webbadresser'; +$lang['usewordblock'] = 'Blockera spam baserat på ordlista'; +$lang['relnofollow'] = 'Använd rel="nofollow" för externa länkar'; +$lang['indexdelay'] = 'Tidsfördröjning före indexering (sek)'; +$lang['mailguard'] = 'Koda e-postadresser'; +$lang['iexssprotect'] = 'Kontrollera om uppladdade filer innehåller eventuellt skadlig JavaScript eller HTML-kod'; $lang['usedraft'] = 'Spara utkast automatiskt under redigering'; -$lang['sepchar'] = 'Ersätt blanktecken i webbadresser med'; -$lang['canonical'] = 'Använd fullständiga webbadresser'; -$lang['autoplural'] = 'Leta efter pluralformer av länkar'; -$lang['compression'] = 'Metod för komprimering av gamla versioner'; -$lang['cachetime'] = 'Maximal livslängd för cache (sek)'; +$lang['htmlok'] = 'Tillåt inbäddad HTML'; +$lang['phpok'] = 'Tillåt inbäddad PHP'; $lang['locktime'] = 'Maximal livslängd för fillåsning (sek)'; +$lang['cachetime'] = 'Maximal livslängd för cache (sek)'; +$lang['target____wiki'] = 'Målfönster för interna länkar'; +$lang['target____interwiki'] = 'Målfönster för interwiki-länkar'; +$lang['target____extern'] = 'Målfönster för externa länkar'; +$lang['target____media'] = 'Målfönster för medialänkar'; +$lang['target____windows'] = 'Målfönster för windowslänkar'; +$lang['refcheck'] = 'Kontrollera referenser till mediafiler'; +$lang['refshow'] = 'Antal mediareferenser som ska visas'; +$lang['gdlib'] = 'Version av GD-biblioteket'; +$lang['im_convert'] = 'Sökväg till ImageMagicks konverteringsverktyg'; +$lang['jpg_quality'] = 'Kvalitet för JPG-komprimering (0-100)'; $lang['fetchsize'] = 'Maximal storlek (bytes) som fetch.php får ladda ned externt'; +$lang['subscribers'] = 'Aktivera stöd för prenumeration på ändringar'; $lang['notify'] = 'Skicka meddelande om ändrade sidor till den här e-postadressen'; $lang['registernotify'] = 'Skicka meddelande om nyregistrerade användare till en här e-postadressen'; $lang['mailfrom'] = 'Avsändaradress i automatiska e-postmeddelanden'; $lang['mailprefix'] = 'Prefix i början på ämnesraden vid automatiska e-postmeddelanden'; +$lang['sitemap'] = 'Skapa Google sitemap (dagar)'; +$lang['rss_type'] = 'Typ av XML-flöde'; +$lang['rss_linkto'] = 'XML-flöde pekar på'; +$lang['rss_content'] = 'Vad ska visas för saker i XML-flödet?'; +$lang['rss_update'] = 'Uppdateringsintervall för XML-flöde (sek)'; +$lang['rss_show_summary'] = 'XML-flöde visar sammanfattning i rubriken'; +$lang['rss_media'] = 'Vilka ändringar ska listas i XML flödet?'; +$lang['updatecheck'] = 'Kontrollera uppdateringar och säkerhetsvarningar? DokuWiki behöver kontakta update.dokuwiki.org för den här funktionen.'; +$lang['userewrite'] = 'Använd rena webbadresser'; +$lang['useslash'] = 'Använd snedstreck för att separera namnrymder i webbadresser'; +$lang['sepchar'] = 'Ersätt blanktecken i webbadresser med'; +$lang['canonical'] = 'Använd fullständiga webbadresser'; +$lang['fnencode'] = 'Metod för kodning av icke-ASCII filnamn.'; +$lang['autoplural'] = 'Leta efter pluralformer av länkar'; +$lang['compression'] = 'Metod för komprimering av gamla versioner'; $lang['gzip_output'] = 'Använd gzip Content-Encoding för xhtml'; -$lang['gdlib'] = 'Version av GD-biblioteket'; -$lang['im_convert'] = 'Sökväg till ImageMagicks konverteringsverktyg'; -$lang['jpg_quality'] = 'Kvalitet för JPG-komprimering (0-100)'; -$lang['subscribers'] = 'Aktivera stöd för prenumeration på ändringar'; $lang['compress'] = 'Komprimera CSS och javascript'; -$lang['hidepages'] = 'Dölj matchande sidor (reguljära uttryck)'; $lang['send404'] = 'Skicka "HTTP 404/Page Not Found" för sidor som inte finns'; -$lang['sitemap'] = 'Skapa Google sitemap (dagar)'; $lang['broken_iua'] = 'Är funktionen ignore_user_abort trasig på ditt system? Det kan i så fall leda till att indexering av sökningar inte fungerar. Detta är ett känt problem med IIS+PHP/CGI. Se Bug 852 för mer info.'; $lang['xsendfile'] = 'Använd X-Sendfile huvudet för att låta webservern leverera statiska filer? Din webserver behöver stöd för detta.'; $lang['renderer_xhtml'] = 'Generera för användning i huvudwikipresentation (xhtml)'; $lang['renderer__core'] = '%s (dokuwiki core)'; $lang['renderer__plugin'] = '%s (plugin)'; -$lang['rememberme'] = 'Tillåt permanenta inloggningscookies (kom ihåg mig)'; -$lang['rss_type'] = 'Typ av XML-flöde'; -$lang['rss_linkto'] = 'XML-flöde pekar på'; -$lang['rss_content'] = 'Vad ska visas för saker i XML-flödet?'; -$lang['rss_update'] = 'Uppdateringsintervall för XML-flöde (sek)'; -$lang['recent_days'] = 'Hur många ändringar som ska sparas (dagar)'; -$lang['rss_show_summary'] = 'XML-flöde visar sammanfattning i rubriken'; -$lang['target____wiki'] = 'Målfönster för interna länkar'; -$lang['target____interwiki'] = 'Målfönster för interwiki-länkar'; -$lang['target____extern'] = 'Målfönster för externa länkar'; -$lang['target____media'] = 'Målfönster för medialänkar'; -$lang['target____windows'] = 'Målfönster för windowslänkar'; $lang['proxy____host'] = 'Proxyserver'; $lang['proxy____port'] = 'Proxyport'; $lang['proxy____user'] = 'Användarnamn för proxy'; $lang['proxy____pass'] = 'Lösenord för proxy'; $lang['proxy____ssl'] = 'Använd ssl för anslutning till proxy'; +$lang['proxy____except'] = 'Regular expression för matchning av URL som proxy ska hoppa över.'; $lang['safemodehack'] = 'Aktivera safemode hack'; $lang['ftp____host'] = 'FTP-server för safemode hack'; $lang['ftp____port'] = 'FTP-port för safemode hack'; @@ -190,3 +197,4 @@ $lang['useheading_o_0'] = 'Aldrig'; $lang['useheading_o_navigation'] = 'Endst navigering'; $lang['useheading_o_content'] = 'Endast innehåll i wiki'; $lang['useheading_o_1'] = 'Alltid'; +$lang['readdircache'] = 'Max ålder för readdir cache (sek)'; diff --git a/lib/plugins/plugin/lang/sv/lang.php b/lib/plugins/plugin/lang/sv/lang.php index 5892e42b5..a8578c03c 100644 --- a/lib/plugins/plugin/lang/sv/lang.php +++ b/lib/plugins/plugin/lang/sv/lang.php @@ -16,6 +16,7 @@ * @author Peter Åström * @author Håkan Sandell * @author mikael@mallander.net + * @author Smorkster Andersson smorkster@gmail.com */ $lang['menu'] = 'Hantera insticksmoduler'; $lang['download'] = 'Ladda ned och installera en ny insticksmodul'; @@ -61,3 +62,4 @@ $lang['enabled'] = 'Tilläggsmodulen %s är aktiverad.'; $lang['notenabled'] = 'Tilläggsmodulen %s kunde inte aktiveras, kontrollera filrättigheterna.'; $lang['disabled'] = 'Tiläggsmodulen %s är avaktiverad.'; $lang['notdisabled'] = 'Tilläggsmodulen %s kunde inte avaktiveras, kontrollera filrättigheterna.'; +$lang['packageinstalled'] = 'Tilläggs paket (%d tillägg: %s) har installerats.'; diff --git a/lib/plugins/popularity/lang/sv/lang.php b/lib/plugins/popularity/lang/sv/lang.php index 8be542e7f..90d820ba0 100644 --- a/lib/plugins/popularity/lang/sv/lang.php +++ b/lib/plugins/popularity/lang/sv/lang.php @@ -13,6 +13,7 @@ * @author Peter Åström * @author Håkan Sandell * @author mikael@mallander.net + * @author Smorkster Andersson smorkster@gmail.com */ $lang['name'] = 'Popularitets-feedback (det kan ta en stund att ladda sidan)'; $lang['submit'] = 'Sänd data'; diff --git a/lib/plugins/revert/lang/sv/lang.php b/lib/plugins/revert/lang/sv/lang.php index 29c6702eb..4a727b339 100644 --- a/lib/plugins/revert/lang/sv/lang.php +++ b/lib/plugins/revert/lang/sv/lang.php @@ -15,6 +15,7 @@ * @author Peter Åström * @author Håkan Sandell * @author mikael@mallander.net + * @author Smorkster Andersson smorkster@gmail.com */ $lang['menu'] = 'Hantera återställningar'; $lang['filter'] = 'Sök efter spamsidor'; diff --git a/lib/plugins/usermanager/lang/sv/lang.php b/lib/plugins/usermanager/lang/sv/lang.php index bd747927e..f8b530d90 100644 --- a/lib/plugins/usermanager/lang/sv/lang.php +++ b/lib/plugins/usermanager/lang/sv/lang.php @@ -15,6 +15,7 @@ * @author Peter Åström * @author Håkan Sandell * @author mikael@mallander.net + * @author Smorkster Andersson smorkster@gmail.com */ $lang['menu'] = 'Hantera användare'; $lang['noauth'] = '(användarautentisering ej tillgänlig)'; -- cgit v1.2.3 From c594dd1e99b18f3c73464d7fc17f1759300cffeb Mon Sep 17 00:00:00 2001 From: Andreas Gohr Date: Sun, 16 Jun 2013 20:13:06 +0200 Subject: message increase for hotfix --- doku.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doku.php b/doku.php index 9aeb30013..777a68df8 100644 --- a/doku.php +++ b/doku.php @@ -9,7 +9,7 @@ */ // update message version -$updateVersion = 40; +$updateVersion = 40.1; // xdebug_start_profiling(); -- cgit v1.2.3 From ea2272c40a77ba38305773f8f3e3172bb71e9f49 Mon Sep 17 00:00:00 2001 From: Andreas Gohr Date: Sun, 16 Jun 2013 21:57:42 +0200 Subject: removed tabs --- inc/auth.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/inc/auth.php b/inc/auth.php index 6107645cd..47b29eff7 100644 --- a/inc/auth.php +++ b/inc/auth.php @@ -59,18 +59,18 @@ function auth_setup() { } } - if(!isset($auth) || !$auth){ + if(!isset($auth) || !$auth){ msg($lang['authtempfail'], -1); return false; } if ($auth->success == false) { - // degrade to unauthenticated user - unset($auth); - auth_logoff(); - msg($lang['authtempfail'], -1); + // degrade to unauthenticated user + unset($auth); + auth_logoff(); + msg($lang['authtempfail'], -1); return false; - } + } // do the login either by cookie or provided credentials XXX $INPUT->set('http_credentials', false); -- cgit v1.2.3 From 603a638180749a2925e589bc0c13f19899b6c732 Mon Sep 17 00:00:00 2001 From: Klap-in Date: Tue, 18 Jun 2013 21:18:20 +0200 Subject: add newest plugin types to info plugin --- lib/plugins/info/syntax.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/plugins/info/syntax.php b/lib/plugins/info/syntax.php index 97b28076b..5e7543603 100644 --- a/lib/plugins/info/syntax.php +++ b/lib/plugins/info/syntax.php @@ -81,6 +81,12 @@ class syntax_plugin_info extends DokuWiki_Syntax_Plugin { case 'helperplugins': $this->_plugins_xhtml('helper', $renderer); break; + case 'authplugins': + $this->_plugins_xhtml('auth', $renderer); + break; + case 'remoteplugins': + $this->_plugins_xhtml('remote', $renderer); + break; case 'helpermethods': $this->_helpermethods_xhtml($renderer); break; -- cgit v1.2.3 From 22c5d8b475ffef3674a95847a6f2bcbf759c42e6 Mon Sep 17 00:00:00 2001 From: Anika Henke Date: Fri, 12 Jul 2013 00:08:14 +0100 Subject: fixed picker buttons not showing in IE8 and below --- lib/tpl/dokuwiki/css/basic.css | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/tpl/dokuwiki/css/basic.css b/lib/tpl/dokuwiki/css/basic.css index a0a60d295..ad04f7c41 100644 --- a/lib/tpl/dokuwiki/css/basic.css +++ b/lib/tpl/dokuwiki/css/basic.css @@ -227,7 +227,8 @@ audio { max-width: 100%; } #IE7 img, -#IE8 img { +#IE8 img, +button img { max-width: none; } -- cgit v1.2.3 From b243b168571b08a674d34701cfbb7ac0a03239e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volker=20B=C3=B6dker?= Date: Fri, 12 Jul 2013 17:04:41 +0200 Subject: Informal German language update --- inc/lang/de-informal/lang.php | 1 + lib/plugins/acl/lang/de-informal/lang.php | 1 + lib/plugins/authad/lang/de-informal/settings.php | 1 + lib/plugins/authldap/lang/de-informal/settings.php | 6 ++++++ lib/plugins/authmysql/lang/de-informal/settings.php | 1 + lib/plugins/authpgsql/lang/de-informal/settings.php | 1 + lib/plugins/config/lang/de-informal/lang.php | 1 + lib/plugins/plugin/lang/de-informal/lang.php | 1 + lib/plugins/popularity/lang/de-informal/lang.php | 1 + lib/plugins/revert/lang/de-informal/lang.php | 1 + lib/plugins/usermanager/lang/de-informal/lang.php | 1 + 11 files changed, 16 insertions(+) diff --git a/inc/lang/de-informal/lang.php b/inc/lang/de-informal/lang.php index 8a954c0e8..9a6e6f72c 100644 --- a/inc/lang/de-informal/lang.php +++ b/inc/lang/de-informal/lang.php @@ -20,6 +20,7 @@ * @author Christian Wichmann * @author Pierre Corell * @author Frank Loizzi + * @author Volker Bödker */ $lang['encoding'] = 'utf-8'; $lang['direction'] = 'ltr'; diff --git a/lib/plugins/acl/lang/de-informal/lang.php b/lib/plugins/acl/lang/de-informal/lang.php index 8b1416137..45a993982 100644 --- a/lib/plugins/acl/lang/de-informal/lang.php +++ b/lib/plugins/acl/lang/de-informal/lang.php @@ -9,6 +9,7 @@ * @author Christian Wichmann * @author Pierre Corell * @author Frank Loizzi + * @author Volker Bödker */ $lang['admin_acl'] = 'Zugangsverwaltung'; $lang['acl_group'] = 'Gruppe'; diff --git a/lib/plugins/authad/lang/de-informal/settings.php b/lib/plugins/authad/lang/de-informal/settings.php index 4d0b93e5d..a458617b8 100644 --- a/lib/plugins/authad/lang/de-informal/settings.php +++ b/lib/plugins/authad/lang/de-informal/settings.php @@ -4,6 +4,7 @@ * * @author Frank Loizzi * @author Matthias Schulte + * @author Volker Bödker */ $lang['account_suffix'] = 'Dein Account-Suffix. Z.B. @my.domain.org'; $lang['base_dn'] = 'Dein Base-DN. Z.B. DC=my,DC=domain,DC=org'; diff --git a/lib/plugins/authldap/lang/de-informal/settings.php b/lib/plugins/authldap/lang/de-informal/settings.php index fa0fc1521..15e4d8129 100644 --- a/lib/plugins/authldap/lang/de-informal/settings.php +++ b/lib/plugins/authldap/lang/de-informal/settings.php @@ -4,6 +4,7 @@ * * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) * @author Matthias Schulte + * @author Volker Bödker */ $lang['server'] = 'Adresse zum LDAP-Server. Entweder als Hostname (localhost) oder als FQDN (ldap://server.tld:389).'; $lang['port'] = 'Port des LDAP-Servers, falls kein Port angegeben wurde.'; @@ -14,9 +15,14 @@ $lang['groupfilter'] = 'LDAP-Filter, um die Benutzergruppen zu suchen. $lang['version'] = 'Zu verwendende Protokollversion von LDAP.'; $lang['starttls'] = 'Verbindung über TLS aufbauen?'; $lang['referrals'] = 'Weiterverfolgen von LDAP-Referrals (Verweise)?'; +$lang['deref'] = 'Wie sollen Aliasse derefernziert werden?'; $lang['binddn'] = 'DN eines optionalen Benutzers, wenn der anonyme Zugriff nicht ausreichend ist. Zum Beispiel: cn=admin, dc=my, dc=home.'; $lang['bindpw'] = 'Passwort des angegebenen Benutzers.'; $lang['userscope'] = 'Die Suchweite nach Benutzeraccounts.'; $lang['groupscope'] = 'Die Suchweite nach Benutzergruppen.'; $lang['groupkey'] = 'Gruppieren der Benutzeraccounts anhand eines beliebigen Benutzerattributes z. B. Telefonnummer oder Abteilung, anstelle der Standard-Gruppen).'; $lang['debug'] = 'Debug-Informationen beim Auftreten von Fehlern anzeigen?'; +$lang['deref_o_0'] = 'LDAP_DEREF_NIEMALS'; +$lang['deref_o_1'] = 'LDAP_DEREF_SUCHEN'; +$lang['deref_o_2'] = 'LDAP_DEREF_FINDEN'; +$lang['deref_o_3'] = 'LDAP_DEREF_IMMER'; diff --git a/lib/plugins/authmysql/lang/de-informal/settings.php b/lib/plugins/authmysql/lang/de-informal/settings.php index 0c9bc85fe..540979cf4 100644 --- a/lib/plugins/authmysql/lang/de-informal/settings.php +++ b/lib/plugins/authmysql/lang/de-informal/settings.php @@ -4,6 +4,7 @@ * * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) * @author Matthias Schulte + * @author Volker Bödker */ $lang['server'] = 'MySQL-Server'; $lang['user'] = 'Benutzername für den Zugriff auf den MySQL-Server.'; diff --git a/lib/plugins/authpgsql/lang/de-informal/settings.php b/lib/plugins/authpgsql/lang/de-informal/settings.php index 4c80245d6..d864d14d4 100644 --- a/lib/plugins/authpgsql/lang/de-informal/settings.php +++ b/lib/plugins/authpgsql/lang/de-informal/settings.php @@ -4,6 +4,7 @@ * * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) * @author Matthias Schulte + * @author Volker Bödker */ $lang['server'] = 'PostgreSQL-Server'; $lang['port'] = 'Port des PostgreSQL-Servers.'; diff --git a/lib/plugins/config/lang/de-informal/lang.php b/lib/plugins/config/lang/de-informal/lang.php index ac61e4c85..10fa363dc 100644 --- a/lib/plugins/config/lang/de-informal/lang.php +++ b/lib/plugins/config/lang/de-informal/lang.php @@ -10,6 +10,7 @@ * @author Pierre Corell * @author Frank Loizzi * @author Mateng Schimmerlos + * @author Volker Bödker */ $lang['menu'] = 'Konfiguration'; $lang['error'] = 'Konfiguration wurde nicht aktualisiert auf Grund eines ungültigen Wertes. Bitte überprüfe deine Änderungen und versuche es erneut.
        Die/der ungültige(n) Wert(e) werden durch eine rote Umrandung hervorgehoben.'; diff --git a/lib/plugins/plugin/lang/de-informal/lang.php b/lib/plugins/plugin/lang/de-informal/lang.php index a082218d8..5d1649434 100644 --- a/lib/plugins/plugin/lang/de-informal/lang.php +++ b/lib/plugins/plugin/lang/de-informal/lang.php @@ -9,6 +9,7 @@ * @author Christian Wichmann * @author Pierre Corell * @author Frank Loizzi + * @author Volker Bödker */ $lang['menu'] = 'Plugins verwalten'; $lang['download'] = 'Herunterladen und installieren einer neuen Erweiterung'; diff --git a/lib/plugins/popularity/lang/de-informal/lang.php b/lib/plugins/popularity/lang/de-informal/lang.php index 513a1b6e1..0abf90b0b 100644 --- a/lib/plugins/popularity/lang/de-informal/lang.php +++ b/lib/plugins/popularity/lang/de-informal/lang.php @@ -9,6 +9,7 @@ * @author Christian Wichmann * @author Pierre Corell * @author Frank Loizzi + * @author Volker Bödker */ $lang['name'] = 'Popularitätsrückmeldung (kann eine Weile dauern, bis es fertig geladen wurde)'; $lang['submit'] = 'Sende Daten'; diff --git a/lib/plugins/revert/lang/de-informal/lang.php b/lib/plugins/revert/lang/de-informal/lang.php index 3a96429c7..b702e7727 100644 --- a/lib/plugins/revert/lang/de-informal/lang.php +++ b/lib/plugins/revert/lang/de-informal/lang.php @@ -9,6 +9,7 @@ * @author Christian Wichmann * @author Pierre Corell * @author Frank Loizzi + * @author Volker Bödker */ $lang['menu'] = 'Zurückstellungsmanager'; $lang['filter'] = 'Durchsuche als Spam markierte Seiten'; diff --git a/lib/plugins/usermanager/lang/de-informal/lang.php b/lib/plugins/usermanager/lang/de-informal/lang.php index 07390854f..791cfa74f 100644 --- a/lib/plugins/usermanager/lang/de-informal/lang.php +++ b/lib/plugins/usermanager/lang/de-informal/lang.php @@ -9,6 +9,7 @@ * @author Christian Wichmann * @author Pierre Corell * @author Frank Loizzi + * @author Volker Bödker */ $lang['menu'] = 'Benutzerverwaltung'; $lang['noauth'] = '(Benutzeranmeldung ist nicht verfügbar)'; -- cgit v1.2.3 From dbd5b4caeac5f2f45d05da38f1a54282d972b3ce Mon Sep 17 00:00:00 2001 From: Victor Westmann Date: Fri, 12 Jul 2013 17:06:30 +0200 Subject: Brazilian Portuguese language update --- lib/plugins/authad/lang/pt-br/settings.php | 2 ++ lib/plugins/authldap/lang/pt-br/settings.php | 7 +++++++ 2 files changed, 9 insertions(+) diff --git a/lib/plugins/authad/lang/pt-br/settings.php b/lib/plugins/authad/lang/pt-br/settings.php index 29f8db4ad..308d122dd 100644 --- a/lib/plugins/authad/lang/pt-br/settings.php +++ b/lib/plugins/authad/lang/pt-br/settings.php @@ -7,8 +7,10 @@ $lang['account_suffix'] = 'Sufixo de sua conta. Eg. @meu.domínio.org'; $lang['base_dn'] = 'Sua base DN. Eg. DC=meu,DC=domínio,DC=org'; $lang['domain_controllers'] = 'Uma lista de controles de domínios separada por vírgulas. Eg. srv1.domínio.org,srv2.domínio.org'; +$lang['admin_username'] = 'Um usuário com privilégios do Active Directory com acesso a todos os dados dos outros usuários. Opcional, mas necessário para certas ações como enviar emails de inscrição.'; $lang['admin_password'] = 'A senha do usuário acima.'; $lang['sso'] = 'Usar Single-Sign-On através do Kerberos ou NTLM?'; +$lang['real_primarygroup'] = 'Deverá o grupo real primário ser resolvido ao invés de assumir "Usuários de domínio" (mais lento) '; $lang['use_ssl'] = 'Usar conexão SSL? Se usar, não habilitar TLS abaixo.'; $lang['use_tls'] = 'Usar conexão TLS? se usar, não habilitar SSL acima.'; $lang['debug'] = 'Mostrar saída adicional de depuração em mensagens de erros?'; diff --git a/lib/plugins/authldap/lang/pt-br/settings.php b/lib/plugins/authldap/lang/pt-br/settings.php index daf9efd00..70b68b289 100644 --- a/lib/plugins/authldap/lang/pt-br/settings.php +++ b/lib/plugins/authldap/lang/pt-br/settings.php @@ -8,12 +8,19 @@ $lang['server'] = 'Seu servidor LDAP. Ou hostname (localhos $lang['port'] = 'Porta LDAP do servidor se nenhuma URL completa tiver sido fornecida acima'; $lang['usertree'] = 'Onde encontrar as contas de usuários. Eg. ou=Pessoas, dc=servidor, dc=tld'; $lang['grouptree'] = 'Onde encontrar os grupos de usuários. Eg. ou=Pessoas, dc=servidor, dc=tld'; +$lang['userfilter'] = 'Filtro do LDAP para procurar por contas de usuários. Eg. (&(uid=%{user})(objectClass=posixAccount))'; +$lang['groupfilter'] = 'Filtro do LDAP 0ara procurar por grupos. Eg. (&(objectClass=posixGroup)(|(gidNumber=%{gid})(memberUID=%{user})))'; $lang['version'] = 'A versão do protocolo para usar. Você talvez deva definir isto para 3'; $lang['starttls'] = 'Usar conexões TLS?'; $lang['referrals'] = 'Permitir referências serem seguidas?'; +$lang['deref'] = 'Como respeitar aliases ?'; $lang['binddn'] = 'DN de um vínculo opcional de usuário se vínculo anônimo não for suficiente. Eg. cn=admin, dc=my, dc=home'; $lang['bindpw'] = 'Senha do usuário acima'; $lang['userscope'] = 'Limitar escopo da busca para busca de usuário'; $lang['groupscope'] = 'Limitar escopo da busca para busca de grupo'; $lang['groupkey'] = 'Membro de grupo vem de qualquer atributo do usuário (ao invés de grupos padrões AD) e.g. departamento de grupo ou número de telefone'; $lang['debug'] = 'Mostrar informações adicionais de depuração em erros'; +$lang['deref_o_0'] = 'LDAP_DEREF_NEVER'; +$lang['deref_o_1'] = 'LDAP_DEREF_SEARCHING'; +$lang['deref_o_2'] = 'LDAP_DEREF_FINDING'; +$lang['deref_o_3'] = 'LDAP_DEREF_ALWAYS'; -- cgit v1.2.3 From 89e71fa967a455a3c062b26a00af0e886fbecd86 Mon Sep 17 00:00:00 2001 From: Andreas Gohr Date: Fri, 12 Jul 2013 17:20:45 +0200 Subject: fix function call in feedcreator FS#2805 the _redirect function is not used in DokuWiki anyway --- inc/feedcreator.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inc/feedcreator.class.php b/inc/feedcreator.class.php index ea8cc7b15..670a1bc29 100644 --- a/inc/feedcreator.class.php +++ b/inc/feedcreator.class.php @@ -599,7 +599,7 @@ class FeedCreator extends HtmlDescribable { header("Content-Type: ".$this->contentType."; charset=".$this->encoding."; filename=".utf8_basename($filename)); header("Content-Disposition: inline; filename=".utf8_basename($filename)); - readfile($filename, "r"); + readfile($filename); die(); } -- cgit v1.2.3 From fbd8067eeeb9f424981aad8b283e17f734c738c3 Mon Sep 17 00:00:00 2001 From: Andreas Gohr Date: Fri, 12 Jul 2013 17:29:28 +0200 Subject: updated jquery.cookie.js to 1.3.1 FS#2804 --- lib/scripts/jquery/jquery.cookie.js | 59 ++++++++++++++++++++++++++----------- 1 file changed, 41 insertions(+), 18 deletions(-) diff --git a/lib/scripts/jquery/jquery.cookie.js b/lib/scripts/jquery/jquery.cookie.js index 2d4c05a84..c4f99af00 100644 --- a/lib/scripts/jquery/jquery.cookie.js +++ b/lib/scripts/jquery/jquery.cookie.js @@ -1,13 +1,19 @@ /*! - * jQuery Cookie Plugin v1.3 + * jQuery Cookie Plugin v1.3.1 * https://github.com/carhartl/jquery-cookie * - * Copyright 2011, Klaus Hartl - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://www.opensource.org/licenses/mit-license.php - * http://www.opensource.org/licenses/GPL-2.0 + * Copyright 2013 Klaus Hartl + * Released under the MIT license */ -(function ($, document, undefined) { +(function (factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as anonymous module. + define(['jquery'], factory); + } else { + // Browser globals. + factory(jQuery); + } +}(function ($) { var pluses = /\+/g; @@ -19,16 +25,22 @@ return decodeURIComponent(s.replace(pluses, ' ')); } + function converted(s) { + if (s.indexOf('"') === 0) { + // This is a quoted cookie as according to RFC2068, unescape + s = s.slice(1, -1).replace(/\\"/g, '"').replace(/\\\\/g, '\\'); + } + try { + return config.json ? JSON.parse(s) : s; + } catch(er) {} + } + var config = $.cookie = function (key, value, options) { // write if (value !== undefined) { options = $.extend({}, config.defaults, options); - if (value === null) { - options.expires = -1; - } - if (typeof options.expires === 'number') { var days = options.expires, t = options.expires = new Date(); t.setDate(t.getDate() + days); @@ -37,7 +49,9 @@ value = config.json ? JSON.stringify(value) : String(value); return (document.cookie = [ - encodeURIComponent(key), '=', config.raw ? value : encodeURIComponent(value), + config.raw ? key : encodeURIComponent(key), + '=', + config.raw ? value : encodeURIComponent(value), options.expires ? '; expires=' + options.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE options.path ? '; path=' + options.path : '', options.domain ? '; domain=' + options.domain : '', @@ -48,25 +62,34 @@ // read var decode = config.raw ? raw : decoded; var cookies = document.cookie.split('; '); + var result = key ? undefined : {}; for (var i = 0, l = cookies.length; i < l; i++) { var parts = cookies[i].split('='); - if (decode(parts.shift()) === key) { - var cookie = decode(parts.join('=')); - return config.json ? JSON.parse(cookie) : cookie; + var name = decode(parts.shift()); + var cookie = decode(parts.join('=')); + + if (key && key === name) { + result = converted(cookie); + break; + } + + if (!key) { + result[name] = converted(cookie); } } - return null; + return result; }; config.defaults = {}; $.removeCookie = function (key, options) { - if ($.cookie(key) !== null) { - $.cookie(key, null, options); + if ($.cookie(key) !== undefined) { + // Must not alter options, thus extending a fresh object... + $.cookie(key, '', $.extend({}, options, { expires: -1 })); return true; } return false; }; -})(jQuery, document); +})); -- cgit v1.2.3