diff --git a/_test/bootstrap.php b/_test/bootstrap.php
index 732fef9ed272743411f04c8c1fec2e0d6e3a3e54..3f59db51562801672ad4df8b0b1ea22a3daeb685 100644
--- a/_test/bootstrap.php
+++ b/_test/bootstrap.php
@@ -68,6 +68,13 @@ $default_server_vars = array(
     'REQUEST_TIME' => time(),
 );
 
+// fixup for $_SERVER when run from CLI,
+// some values should be mocked for use by inc/init.php which is called here
+// [ $_SERVER is also mocked in TestRequest::execute() ]
+if (php_sapi_name() == 'cli') {
+  $_SERVER = array_merge($default_server_vars, $_SERVER);
+}
+
 // create temp directories
 mkdir(TMP_DIR);
 
diff --git a/_test/tests/inc/indexer_indexing.test.php b/_test/tests/inc/indexer_indexing.test.php
new file mode 100644
index 0000000000000000000000000000000000000000..628e82e00164ed09f72cfb50919841f0faf180cb
--- /dev/null
+++ b/_test/tests/inc/indexer_indexing.test.php
@@ -0,0 +1,45 @@
+<?php
+/**
+ * Tests the indexing functionality of the indexer
+ *
+ * @author Michael Hamann <michael@content-space.de>
+ */
+class indexer_indexing_test extends DokuWikiTest {
+    public function setUp() {
+        parent::setUp();
+        saveWikiText('testpage', 'Foo bar baz.', 'Test initialization');
+        saveWikiText('notfound', 'Foon barn bazn.', 'Test initialization');
+        idx_addPage('testpage');
+        idx_addPage('notfound');
+    }
+
+    public function test_words() {
+        $indexer = idx_get_indexer();
+        $query = array('baz', 'foo');
+        $this->assertEquals(array('baz' => array('testpage' => 1), 'foo' => array('testpage' => 1)), $indexer->lookup($query));
+    }
+
+    public function test_numerically_identical_words() {
+        $indexer = idx_get_indexer();
+        $indexer->addPageWords('testpage', '0x1 002');
+        $indexer->addPageWords('notfound', '0x2');
+        $query = array('001', '002');
+        $this->assertEquals(array('001' => array(), '002' => array('testpage' => 1)), $indexer->lookup($query));
+    }
+
+    public function test_meta() {
+        $indexer = idx_get_indexer();
+        $indexer->addMetaKeys('testpage', 'testkey', 'testvalue');
+        $indexer->addMetaKeys('notfound', 'testkey', 'notvalue');
+        $query = 'testvalue';
+        $this->assertEquals(array('testpage'), $indexer->lookupKey('testkey', $query));
+    }
+
+    public function test_numerically_identical_meta_values() {
+        $indexer = idx_get_indexer();
+        $indexer->addMetaKeys('testpage', 'numkey', array('0001', '01'));
+        $indexer->addMetaKeys('notfound', 'numkey', array('00001', '000001'));
+        $query = array('001', '01');
+        $this->assertEquals(array('001' => array(), '01' => array('testpage')), $indexer->lookupKey('numkey', $query));
+    }
+}
\ No newline at end of file
diff --git a/inc/html.php b/inc/html.php
index 03e9dc751b538cd3716fbadcc33a7d58169b91a6..a13c9e58c2dabdf0a8709beff209c1e3556fd591 100644
--- a/inc/html.php
+++ b/inc/html.php
@@ -428,7 +428,7 @@ function html_revisions($first=0, $media_id = false){
     global $conf;
     global $lang;
     $id = $ID;
-    /* we need to get one additionally log entry to be able to
+    /* we need to get one additional log entry to be able to
      * decide if this is the last page or is there another one.
      * see html_recent()
      */
diff --git a/inc/indexer.php b/inc/indexer.php
index 8f0ba7ec661c4618fcebd10dcc27e769dff52145..378abb36057f1518bb612be3599832e7a94bbac6 100644
--- a/inc/indexer.php
+++ b/inc/indexer.php
@@ -10,7 +10,7 @@
 if(!defined('DOKU_INC')) die('meh.');
 
 // Version tag used to force rebuild on upgrade
-define('INDEXER_VERSION', 6);
+define('INDEXER_VERSION', 7);
 
 // set the minimum token length to use in the index (note, this doesn't apply to numeric tokens)
 if (!defined('IDX_MINWORDLENGTH')) define('IDX_MINWORDLENGTH',2);
@@ -215,7 +215,7 @@ class Doku_Indexer {
         foreach (array_keys($words) as $wlen) {
             $word_idx = $this->getIndex('w', $wlen);
             foreach ($words[$wlen] as $word => $freq) {
-                $wid = array_search($word, $word_idx);
+                $wid = array_search($word, $word_idx, true);
                 if ($wid === false) {
                     $wid = count($word_idx);
                     $word_idx[] = $word;
@@ -296,7 +296,7 @@ class Doku_Indexer {
             foreach ($values as $val) {
                 $val = (string)$val;
                 if ($val !== "") {
-                    $id = array_search($val, $metawords);
+                    $id = array_search($val, $metawords, true);
                     if ($id === false) {
                         $id = count($metawords);
                         $metawords[$id] = $val;
@@ -352,13 +352,13 @@ class Doku_Indexer {
 
         $pages = $this->getPages();
 
-        $id = array_search($oldpage, $pages);
+        $id = array_search($oldpage, $pages, true);
         if ($id === false) {
             $this->unlock();
             return 'page is not in index';
         }
 
-        $new_id = array_search($newpage, $pages);
+        $new_id = array_search($newpage, $pages, true);
         if ($new_id !== false) {
             // make sure the page is not in the index anymore
             if ($this->deletePageNoLock($newpage) !== true) {
@@ -397,9 +397,9 @@ class Doku_Indexer {
 
         // change the relation references index
         $metavalues = $this->getIndex($key, '_w');
-        $oldid = array_search($oldvalue, $metavalues);
+        $oldid = array_search($oldvalue, $metavalues, true);
         if ($oldid !== false) {
-            $newid = array_search($newvalue, $metavalues);
+            $newid = array_search($newvalue, $metavalues, true);
             if ($newid !== false) {
                 // free memory
                 unset ($metavalues);
@@ -600,7 +600,7 @@ class Doku_Indexer {
 
         foreach ($wordlist as $i => $word) {
             if ((!is_numeric($word) && strlen($word) < IDX_MINWORDLENGTH)
-              || array_search($word, $stopwords) !== false)
+              || array_search($word, $stopwords, true) !== false)
                 unset($wordlist[$i]);
         }
         return array_values($wordlist);
@@ -771,7 +771,7 @@ class Doku_Indexer {
                     foreach(array_keys(preg_grep('/'.$re.'/', $words)) as $i)
                         $value_ids[$i][] = $val;
                 } else {
-                    if (($i = array_search($val, $words)) !== false)
+                    if (($i = array_search($val, $words, true)) !== false)
                         $value_ids[$i][] = $val;
                 }
             }
@@ -874,7 +874,7 @@ class Doku_Indexer {
             // handle exact search
             if (isset($tokenlength[$ixlen])) {
                 foreach ($tokenlength[$ixlen] as $xword) {
-                    $wid = array_search($xword, $word_idx);
+                    $wid = array_search($xword, $word_idx, true);
                     if ($wid !== false) {
                         $wids[$ixlen][] = $wid;
                         foreach ($tokens[$xword] as $w)
@@ -1152,7 +1152,7 @@ class Doku_Indexer {
      */
     protected function addIndexKey($idx, $suffix, $value) {
         $index = $this->getIndex($idx, $suffix);
-        $id = array_search($value, $index);
+        $id = array_search($value, $index, true);
         if ($id === false) {
             $id = count($index);
             $index[$id] = $value;
diff --git a/inc/init.php b/inc/init.php
index 30eb1b2519948cbe1e21714530a420582f9f6651..248d27b9ca6e4e947d97f86bbd03906c655ba005 100644
--- a/inc/init.php
+++ b/inc/init.php
@@ -267,10 +267,10 @@ function init_lang($langCode) {
     $lang = array();
 
     //load the language files
-    require_once(DOKU_INC.'inc/lang/en/lang.php');
+    require(DOKU_INC.'inc/lang/en/lang.php');
     if ($langCode && $langCode != 'en') {
         if (file_exists(DOKU_INC."inc/lang/$langCode/lang.php")) {
-            require_once(DOKU_INC."inc/lang/$langCode/lang.php");
+            require(DOKU_INC."inc/lang/$langCode/lang.php");
         }
     }
 }
diff --git a/inc/lang/zh/lang.php b/inc/lang/zh/lang.php
index a6c95143f6e25ce4a5cefaa725acc21360b525e0..a125e11e73bf329a07d2dbe70b7279d57838e4e1 100644
--- a/inc/lang/zh/lang.php
+++ b/inc/lang/zh/lang.php
@@ -17,6 +17,7 @@
  * @author Shuo-Ting Jian <shoting@gmail.com>
  * @author Rachel <rzhang0802@gmail.com>
  * @author Donald <donaldtcong@gmail.com>
+ * @author Yangyu Huang <yangyu.huang@gmail.com>
  */
 $lang['encoding']              = 'utf-8';
 $lang['direction']             = 'ltr';
@@ -60,6 +61,7 @@ $lang['btn_revert']            = '恢复';
 $lang['btn_register']          = '注册';
 $lang['btn_apply']             = '应用';
 $lang['btn_media']             = '媒体管理器';
+$lang['btn_deleteuser']        = '移除我的账户';
 $lang['loggedinas']            = '登录为';
 $lang['user']                  = '用户名';
 $lang['pass']                  = '密码';
@@ -88,7 +90,11 @@ $lang['profna']                = '本维基不支持修改个人信息';
 $lang['profnochange']          = '没有改动,不进行操作。';
 $lang['profnoempty']           = '不允许使用空的用户名或邮件地址。';
 $lang['profchanged']           = '用户信息更新成功。';
+$lang['profnodelete']          = '这个 wiki 不支持删除用户';
 $lang['profdeleteuser']        = '删除账号';
+$lang['profdeleted']           = '你的用户已经从这个 wiki 中删除';
+$lang['profconfdelete']        = '我希望删除我的账户。<br/>这项操作无法撤销。';
+$lang['profconfdeletemissing'] = '确认框未勾选';
 $lang['pwdforget']             = '忘记密码?立即获取新密码';
 $lang['resendna']              = '本维基不支持二次发送密码。';
 $lang['resendpwd']             = '设置新密码用于';
diff --git a/inc/plugincontroller.class.php b/inc/plugincontroller.class.php
index c825870cd142625481280ce397be4a4d819319de..33d8c92cd89a7cd45c06cc5693ecf963aac11214 100644
--- a/inc/plugincontroller.class.php
+++ b/inc/plugincontroller.class.php
@@ -11,15 +11,15 @@ if(!defined('DOKU_PLUGIN'))  define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/');
 
 class Doku_Plugin_Controller {
 
-    var $list_bytype = array();
-    var $tmp_plugins = array();
-    var $plugin_cascade = array('default'=>array(),'local'=>array(),'protected'=>array());
-    var $last_local_config_file = '';
+    protected $list_bytype = array();
+    protected $tmp_plugins = array();
+    protected $plugin_cascade = array('default'=>array(),'local'=>array(),'protected'=>array());
+    protected $last_local_config_file = '';
 
     /**
      * Populates the master list of plugins
      */
-    function __construct() {
+    public function __construct() {
         $this->loadConfig();
         $this->_populateMasterList();
     }
@@ -34,11 +34,13 @@ class Doku_Plugin_Controller {
      *               false to only return enabled plugins,
      *               true to return both enabled and disabled plugins
      *
-     * @return       array of plugin names
+     * @return       array of
+     *                  - plugin names when $type = ''
+     *                  - or plugin component names when a $type is given
      *
      * @author Andreas Gohr <andi@splitbrain.org>
      */
-    function getList($type='',$all=false){
+    public function getList($type='',$all=false){
 
         // request the complete list
         if (!$type) {
@@ -64,9 +66,9 @@ class Doku_Plugin_Controller {
      * @param  $name     string name of the plugin to load
      * @param  $new      bool   true to return a new instance of the plugin, false to use an already loaded instance
      * @param  $disabled bool   true to load even disabled plugins
-     * @return objectreference  the plugin object or null on failure
+     * @return DokuWiki_Plugin|DokuWiki_Syntax_Plugin|null  the plugin object or null on failure
      */
-    function load($type,$name,$new=false,$disabled=false){
+    public function load($type,$name,$new=false,$disabled=false){
 
         //we keep all loaded plugins available in global scope for reuse
         global $DOKU_PLUGINS;
@@ -108,26 +110,59 @@ class Doku_Plugin_Controller {
         return $DOKU_PLUGINS[$type][$name];
     }
 
-    function isdisabled($plugin) {
+    /**
+     * Whether plugin is disabled
+     *
+     * @param string $plugin name of plugin
+     * @return bool; true disabled, false enabled
+     */
+    public function isdisabled($plugin) {
         return empty($this->tmp_plugins[$plugin]);
     }
 
-    function disable($plugin) {
+    /**
+     * Disable the plugin
+     *
+     * @param string $plugin name of plugin
+     * @return bool; true saving succeed, false saving failed
+     */
+    public function disable($plugin) {
         if(array_key_exists($plugin,$this->plugin_cascade['protected'])) return false;
         $this->tmp_plugins[$plugin] = 0;
         return $this->saveList();
     }
 
-    function enable($plugin) {
+    /**
+     * Enable the plugin
+     *
+     * @param string $plugin name of plugin
+     * @return bool; true saving succeed, false saving failed
+     */
+    public function enable($plugin) {
         if(array_key_exists($plugin,$this->plugin_cascade['protected'])) return false;
         $this->tmp_plugins[$plugin] = 1;
         return $this->saveList();
     }
 
-    function get_directory($plugin) {
+    /**
+     * Returns directory name of plugin
+     *
+     * @param string $plugin name of plugin
+     * @return string name of directory
+     */
+    public function get_directory($plugin) {
         return $plugin;
     }
 
+    /**
+     * Returns cascade of the config files
+     *
+     * @return array with arrays of plugin configs
+     */
+    public function getCascade() {
+        return $this->plugin_cascade;
+    }
+
     protected function _populateMasterList() {
         global $conf;
 
@@ -169,6 +204,13 @@ class Doku_Plugin_Controller {
         }
     }
 
+    /**
+     * Includes the plugin config $files
+     * and returns the entries of the $plugins array set in these files
+     *
+     * @param array $files list of files to include, latter overrides previous
+     * @return array with entries of the $plugins arrays of the included files
+     */
     protected function checkRequire($files) {
         $plugins = array();
         foreach($files as $file) {
@@ -179,14 +221,15 @@ class Doku_Plugin_Controller {
         return $plugins;
     }
 
-    function getCascade() {
-        return $this->plugin_cascade;
-    }
-
     /**
      * Save the current list of plugins
+     *
+     * @param bool $forceSave;
+     *              false to save only when config changed
+     *              true to always save
+     * @return bool; true saving succeed, false saving failed
      */
-    function saveList($forceSave = false) {
+    protected function saveList($forceSave = false) {
         global $conf;
 
         if (empty($this->tmp_plugins)) return false;
@@ -216,9 +259,10 @@ class Doku_Plugin_Controller {
 
     /**
      * Rebuild the set of local plugins
+     *
      * @return array array of plugins to be saved in end($config_cascade['plugins']['local'])
      */
-    function rebuildLocal() {
+    protected function rebuildLocal() {
         //assign to local variable to avoid overwriting
         $backup = $this->tmp_plugins;
         //Can't do anything about protected one so rule them out completely
@@ -238,7 +282,7 @@ class Doku_Plugin_Controller {
      * Build the list of plugins and cascade
      * 
      */
-    function loadConfig() {
+    protected function loadConfig() {
         global $config_cascade;
         foreach(array('default','protected') as $type) {
             if(array_key_exists($type,$config_cascade['plugins']))
@@ -253,7 +297,18 @@ class Doku_Plugin_Controller {
         $this->tmp_plugins = array_merge($this->plugin_cascade['default'],$this->plugin_cascade['local'],$this->plugin_cascade['protected']);
     }
 
-    function _getListByType($type, $enabled) {
+    /**
+     * Returns a list of available plugin components of given type
+     *
+     * @param string $type, plugin_type name;
+     *                      the type of plugin to return,
+     * @param bool   $enabled;
+     *                      true to return enabled plugins,
+     *                      false to return disabled plugins
+     *
+     * @return array of plugin components of requested type
+     */
+    protected function _getListByType($type, $enabled) {
         $master_list = $enabled ? array_keys(array_filter($this->tmp_plugins)) : array_keys(array_filter($this->tmp_plugins,array($this,'negate')));
 
         $plugins = array();
@@ -278,14 +333,29 @@ class Doku_Plugin_Controller {
         return $plugins;
     }
 
-    function _splitName($name) {
+    /**
+     * Split name in a plugin name and a component name
+     *
+     * @param string $name
+     * @return array with
+     *              - plugin name
+     *              - and component name when available, otherwise empty string
+     */
+    protected function _splitName($name) {
         if (array_search($name, array_keys($this->tmp_plugins)) === false) {
             return explode('_',$name,2);
         }
 
         return array($name,'');
     }
-    function negate($input) {
+
+    /**
+     * Returns inverse boolean value of the input
+     *
+     * @param mixed $input
+     * @return bool inversed boolean value of input
+     */
+    protected function negate($input) {
         return !(bool) $input;
     }
 }
diff --git a/inc/pluginutils.php b/inc/pluginutils.php
index 7c37d4f7ffefbff48d2aae99ed87cef67e22b961..894bbefb6c7512effc89cc86a3b62e574326866f 100644
--- a/inc/pluginutils.php
+++ b/inc/pluginutils.php
@@ -14,31 +14,92 @@ if(!defined('DOKU_PLUGIN_NAME_REGEX')) define('DOKU_PLUGIN_NAME_REGEX', '[a-zA-Z
 /**
  * Original plugin functions, remain for backwards compatibility
  */
+
+/**
+ * Return list of available plugins
+ *
+ * @param string $type type of plugins; empty string for all
+ * @param bool $all; true to retrieve all, false to retrieve only enabled plugins
+ * @return array with plugin names or plugin component names
+ */
 function plugin_list($type='',$all=false) {
+    /** @var $plugin_controller Doku_Plugin_Controller */
     global $plugin_controller;
     return $plugin_controller->getList($type,$all);
 }
+
+/**
+ * Returns plugin object
+ * Returns only new instances of a plugin when $new is true or if plugin is not Singleton,
+ * otherwise an already loaded instance.
+ *
+ * @param  $type     string type of plugin to load
+ * @param  $name     string name of the plugin to load
+ * @param  $new      bool   true to return a new instance of the plugin, false to use an already loaded instance
+ * @param  $disabled bool   true to load even disabled plugins
+ * @return DokuWiki_Plugin|DokuWiki_Syntax_Plugin|null  the plugin object or null on failure
+ */
 function plugin_load($type,$name,$new=false,$disabled=false) {
+    /** @var $plugin_controller Doku_Plugin_Controller */
     global $plugin_controller;
     return $plugin_controller->load($type,$name,$new,$disabled);
 }
+
+/**
+ * Whether plugin is disabled
+ *
+ * @param string $plugin name of plugin
+ * @return bool; true disabled, false enabled
+ */
 function plugin_isdisabled($plugin) {
+    /** @var $plugin_controller Doku_Plugin_Controller */
     global $plugin_controller;
     return $plugin_controller->isdisabled($plugin);
 }
+
+/**
+ * Enable the plugin
+ *
+ * @param string $plugin name of plugin
+ * @return bool; true saving succeed, false saving failed
+ */
 function plugin_enable($plugin) {
+    /** @var $plugin_controller Doku_Plugin_Controller */
     global $plugin_controller;
     return $plugin_controller->enable($plugin);
 }
+
+/**
+ * Disable the plugin
+ *
+ * @param string $plugin name of plugin
+ * @return bool; true saving succeed, false saving failed
+ */
 function plugin_disable($plugin) {
+    /** @var $plugin_controller Doku_Plugin_Controller */
     global $plugin_controller;
     return $plugin_controller->disable($plugin);
 }
+
+/**
+ * Returns directory name of plugin
+ *
+ * @param string $plugin name of plugin
+ * @return string name of directory
+ */
 function plugin_directory($plugin) {
+    /** @var $plugin_controller Doku_Plugin_Controller */
     global $plugin_controller;
     return $plugin_controller->get_directory($plugin);
 }
+
+/**
+ * Returns cascade of the config files
+ *
+ * @return array with arrays of plugin configs
+ */
 function plugin_getcascade() {
+    /** @var $plugin_controller Doku_Plugin_Controller */
     global $plugin_controller;
     return $plugin_controller->getCascade();
 }
diff --git a/inc/search.php b/inc/search.php
index 884aa7b237ecfbbbe1d9cfd46b6e4e532bb61161..cd36feeab3593a2474ce5108cfebbd053608508e 100644
--- a/inc/search.php
+++ b/inc/search.php
@@ -9,14 +9,15 @@
 if(!defined('DOKU_INC')) die('meh.');
 
 /**
- * recurse direcory
+ * Recurse directory
  *
  * This function recurses into a given base directory
  * and calls the supplied function for each file and directory
  *
- * @param   array ref $data The results of the search are stored here
+ * @param   array    &$data The results of the search are stored here
  * @param   string    $base Where to start the search
  * @param   callback  $func Callback (function name or array with object,method)
+ * @param   array     $opts option array will be given to the Callback
  * @param   string    $dir  Current directory beyond $base
  * @param   int       $lvl  Recursion Level
  * @param   mixed     $sort 'natural' to use natural order sorting (default); 'date' to sort by filemtime; leave empty to skip sorting.
@@ -68,12 +69,12 @@ function search(&$data,$base,$func,$opts,$dir='',$lvl=1,$sort='natural'){
  * decide if this directory should be traversed (true) or not (false)
  * The function has to accept the following parameters:
  *
- * &$data - Reference to the result data structure
- * $base  - Base usually $conf['datadir']
- * $file  - current file or directory relative to $base
- * $type  - Type either 'd' for directory or 'f' for file
- * $lvl   - Current recursion depht
- * $opts  - option array as given to search()
+ * array &$data  - Reference to the result data structure
+ * string $base  - Base usually $conf['datadir']
+ * string $file  - current file or directory relative to $base
+ * string $type  - Type either 'd' for directory or 'f' for file
+ * int    $lvl   - Current recursion depht
+ * array  $opts  - option array as given to search()
  *
  * return values for files are ignored
  *
@@ -334,6 +335,15 @@ function pathID($path,$keeptxt=false){
  * showhidden bool    show hidden files too
  * firsthead  bool    return first heading for pages
  *
+ * @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 string $type  - Type either 'd' for directory or 'f' for file
+ * @param int    $lvl   - Current recursion depht
+ * @param array  $opts  - option array as given to search()
+ * @return bool if this directory should be traversed (true) or not (false)
+ *              return value is ignored for files
+ *
  * @author Andreas Gohr <gohr@cosmocode.de>
  */
 function search_universal(&$data,$base,$file,$type,$lvl,$opts){
diff --git a/lib/plugins/config/settings/config.metadata.php b/lib/plugins/config/settings/config.metadata.php
index f4c2ed2651a373753d9734a4ee510a1e4d6b3afb..f9dabfeb0018cb58b03814bbd964bb78ff347064 100644
--- a/lib/plugins/config/settings/config.metadata.php
+++ b/lib/plugins/config/settings/config.metadata.php
@@ -48,6 +48,7 @@
  *   'compression' - no additional parameters. checks php installation supports possible compression alternatives
  *   'licence'     - as multichoice, selection constructed from licence strings in language files
  *   'renderer'    - as multichoice, selection constructed from enabled renderer plugins which canRender()
+ *   'authtype'    - as multichoice, selection constructed from the enabled auth plugins
  *
  *  Any setting commented or missing will use 'setting' class - text input, minimal validation, quoted output
  *
diff --git a/lib/plugins/popularity/admin.php b/lib/plugins/popularity/admin.php
index deb8048f4e9c01be83f8601333dd0a6fb8abe2fd..bd2d090e105fb381d0bca28532b896e61081f763 100644
--- a/lib/plugins/popularity/admin.php
+++ b/lib/plugins/popularity/admin.php
@@ -13,7 +13,6 @@ if(!defined('DOKU_INC')) die();
  * need to inherit from this class
  */
 class admin_plugin_popularity extends DokuWiki_Admin_Plugin {
-    var $version;
 
     /**
      * @var helper_plugin_popularity
@@ -23,9 +22,6 @@ class admin_plugin_popularity extends DokuWiki_Admin_Plugin {
 
     function admin_plugin_popularity(){
         $this->helper = $this->loadHelper('popularity', false);
-
-        $pluginInfo = $this->getInfo();
-        $this->version = $pluginInfo['date'];
     }
 
     /**
diff --git a/lib/plugins/popularity/helper.php b/lib/plugins/popularity/helper.php
index 0e38bcb882d5ad2f16127ff944c8ebc80044407f..eacde06d00f7816c3a9de1da8d90f6a1f5b0dd7e 100644
--- a/lib/plugins/popularity/helper.php
+++ b/lib/plugins/popularity/helper.php
@@ -29,8 +29,6 @@ class helper_plugin_popularity extends Dokuwiki_Plugin {
      */
     var $popularityLastSubmitFile;
 
-    var $version;
-
 
     function helper_plugin_popularity(){
         global $conf;
@@ -39,6 +37,11 @@ class helper_plugin_popularity extends Dokuwiki_Plugin {
         $this->popularityLastSubmitFile = $conf['cachedir'].'/lastSubmitTime.txt';
     }
 
+    /**
+     * Return methods of this helper
+     *
+     * @return array with methods description
+     */
     function getMethods(){
         $result = array();
         $result[] = array(
@@ -125,15 +128,17 @@ class helper_plugin_popularity extends Dokuwiki_Plugin {
      */
     function _gather(){
         global $conf;
+        /** @var $auth DokuWiki_Auth_Plugin */
         global $auth;
         $data = array();
         $phptime = ini_get('max_execution_time');
         @set_time_limit(0);
+        $pluginInfo = $this->getInfo();
 
         // version
         $data['anon_id'] = md5(auth_cookiesalt());
         $data['version'] = getVersion();
-        $data['popversion'] = $this->version;
+        $data['popversion'] = $pluginInfo['date'];
         $data['language'] = $conf['lang'];
         $data['now']      = time();
         $data['popauto']  = (int) $this->isAutoSubmitEnabled();
@@ -245,6 +250,17 @@ class helper_plugin_popularity extends Dokuwiki_Plugin {
         return $data;
     }
 
+    /**
+     * Callback to search and count the content of directories in DokuWiki
+     *
+     * @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 string $type  Type either 'd' for directory or 'f' for file
+     * @param int    $lvl   Current recursion depht
+     * @param array  $opts  option array as given to search()
+     * @return bool
+     */
     function _search_count(&$data,$base,$file,$type,$lvl,$opts){
         // traverse
         if($type == 'd'){
diff --git a/lib/plugins/usermanager/lang/zh/lang.php b/lib/plugins/usermanager/lang/zh/lang.php
index 2674983b210338ac5b691c83bea69250c3d6e1d8..06656110f2d238f7a2e3c00450fdad3db1831b8b 100644
--- a/lib/plugins/usermanager/lang/zh/lang.php
+++ b/lib/plugins/usermanager/lang/zh/lang.php
@@ -16,6 +16,7 @@
  * @author lainme993@gmail.com
  * @author Shuo-Ting Jian <shoting@gmail.com>
  * @author Rachel <rzhang0802@gmail.com>
+ * @author Yangyu Huang <yangyu.huang@gmail.com>
  */
 $lang['menu']                  = '用户管理器';
 $lang['noauth']                = '(用户认证不可用)';
@@ -38,6 +39,8 @@ $lang['search']                = '搜索';
 $lang['search_prompt']         = '进行搜索';
 $lang['clear']                 = '重置搜索过滤器';
 $lang['filter']                = '过滤器';
+$lang['export_all']            = '导出所有用户(CSV)';
+$lang['export_filtered']       = '导出已筛选的用户列表(CSV)';
 $lang['import']                = '请输入新用户名';
 $lang['line']                  = '行号';
 $lang['error']                 = '信息错误';
@@ -61,6 +64,10 @@ $lang['add_ok']                = '用户添加成功';
 $lang['add_fail']              = '用户添加失败';
 $lang['notify_ok']             = '通知邮件已发送';
 $lang['notify_fail']           = '通知邮件无法发送';
+$lang['import_userlistcsv']    = '用户列表文件(CSV)';
+$lang['import_header']         = '最近一次导入 - 失败';
+$lang['import_success_count']  = '用户导入:找到了 %d 个用户,%d 个用户被成功导入。';
+$lang['import_failure_count']  = '用户导入:%d 个用户导入失败。下面列出了失败的用户。';
 $lang['import_error_baduserid'] = '用户ID丢失';
 $lang['import_error_badname']  = '名称错误';
 $lang['import_error_badmail']  = '邮件地址错误';