Browse Source

! Pedantry in action. Making sure all new files have 'LF' svn property.
! messageIconChecks_disable should be enable [bug 4095]
! MySQL 4.0.0 allows for multi-table deletes. (ManageBans.php, ManageMaintenance.php, ManagePermissions.php)
! Two very tiny doc changes that were annoying me
+ Allow users to view their login history
+ 1/3 of the way done adding Slammeddime's additional hooks mod
! Always show boxes to add new censored words [bug 4555] (Admin.template.php)
! Robots shouldn't update num views (Display.php)
+ Style the <body> by id
! getMembersOnlineStats() should be cached and allow for no-sorting as an option (BoardIndex.php, Subs-MembersOnline.php, SSI.php)
! It also appears I fixed a bug where = was used instead of == in Subs-MembersOnline.php
+ LiteSpeed = Apache [bug 4538] (Querystring.php, Subs.php, Load.php)

Spuds 13 years ago
parent
commit
8965e86c4d

+ 2 - 4
SSI.php

@@ -475,7 +475,7 @@ function ssi_recentTopics($num_recent = 8, $exclude_boards = null, $include_boar
 		censorText($row['subject']);
 		censorText($row['body']);
 
-		if (empty($modSettings['messageIconChecks_disable']) && !isset($icon_sources[$row['icon']]))
+		if (!empty($modSettings['messageIconChecks_enable']) && !isset($icon_sources[$row['icon']]))
 			$icon_sources[$row['icon']] = file_exists($settings['theme_dir'] . '/images/post/' . $row['icon'] . '.gif') ? 'images_url' : 'default_images_url';
 
 		// Build the array.
@@ -930,8 +930,6 @@ function ssi_whosOnline($output_method = 'echo')
 	require_once($sourcedir . '/Subs-MembersOnline.php');
 	$membersOnlineOptions = array(
 		'show_hidden' => allowedTo('moderate_forum'),
-		'sort' => 'log_time',
-		'reverse_sort' => true,
 	);
 	$return = getMembersOnlineStats($membersOnlineOptions);
 
@@ -1687,7 +1685,7 @@ function ssi_boardNews($board = null, $limit = null, $start = null, $length = nu
 		$row['body'] = parse_bbc($row['body'], $row['smileys_enabled'], $row['id_msg']);
 
 		// Check that this message icon is there...
-		if (empty($modSettings['messageIconChecks_disable']) && !isset($icon_sources[$row['icon']]))
+		if (!empty($modSettings['messageIconChecks_enable']) && !isset($icon_sources[$row['icon']]))
 			$icon_sources[$row['icon']] = file_exists($settings['theme_dir'] . '/images/post/' . $row['icon'] . '.gif') ? 'images_url' : 'default_images_url';
 
 		censorText($row['subject']);

+ 2 - 0
Sources/Admin.php

@@ -962,6 +962,8 @@ function AdminLogs()
 		'pruning' => array('ManageSettings.php', 'ModifyPruningSettings'),
 	);
 
+	call_integration_hook('integrate_manage_logs', array(&$log_functions));
+
 	$sub_action = isset($_REQUEST['sa']) && isset($log_functions[$_REQUEST['sa']]) ? $_REQUEST['sa'] : 'errorlog';
 	// If it's not got a sa set it must have come here for first time, pretend error log should be reversed.
 	if (!isset($_REQUEST['sa']))

+ 32 - 19
Sources/Load.php

@@ -18,8 +18,9 @@ if (!defined('SMF'))
 
 /**
  * Load the $modSettings array.
- * @todo okay question of the day: why a function loading settings is called
- * reloadSettings()
+ * @todo okay question of the day: why a function loading settings is called reloadSettings()
+ * 
+ * @global array $modSettings is a giant array of all of the forum-wide settings and statistics.
  */
 function reloadSettings()
 {
@@ -71,6 +72,9 @@ function reloadSettings()
 	// Preg_replace can handle complex characters only for higher PHP versions.
 	$space_chars = $utf8 ? (@version_compare(PHP_VERSION, '4.3.3') != -1 ? '\x{A0}\x{AD}\x{2000}-\x{200F}\x{201F}\x{202F}\x{3000}\x{FEFF}' : "\xC2\xA0\xC2\xAD\xE2\x80\x80-\xE2\x80\x8F\xE2\x80\x9F\xE2\x80\xAF\xE2\x80\x9F\xE3\x80\x80\xEF\xBB\xBF") : '\x00-\x08\x0B\x0C\x0E-\x19\xA0';
 
+	/**
+	 * @global array An array of anonymous helper functions.
+	 */
 	$smcFunc += array(
 		'entity_fix' => create_function('$string', '
 			$num = substr($string, 0, 1) === \'x\' ? hexdec(substr($string, 1)) : (int) $string;
@@ -198,12 +202,12 @@ function reloadSettings()
  * Load all the important user information.
  * What it does:
  * 	- sets up the $user_info array
-	- assigns $user_info['query_wanna_see_board'] for what boards the user can see.
-	- first checks for cookie or integration validation.
-	- uses the current session if no integration function or cookie is found.
-	- checks password length, if member is activated and the login span isn't over.
-		- if validation fails for the user, $id_member is set to 0.
-		- updates the last visit time when needed.
+ *	- assigns $user_info['query_wanna_see_board'] for what boards the user can see.
+ *	- first checks for cookie or integration validation.
+ *	- uses the current session if no integration function or cookie is found.
+ *	- checks password length, if member is activated and the login span isn't over.
+ *		- if validation fails for the user, $id_member is set to 0.
+ *		- updates the last visit time when needed.
  */
 function loadUserSettings()
 {
@@ -622,7 +626,8 @@ function loadBoard()
 			// If that is the case do an additional check to see if they have any topics waiting to be approved.
 			if ($board_info['num_topics'] == 0 && $modSettings['postmod_active'] && !allowedTo('approve_posts'))
 			{
-				$smcFunc['db_free_result']($request); // Free the previous result
+				// Free the previous result
+				$smcFunc['db_free_result']($request);
 
 				$request = $smcFunc['db_query']('', '
 					SELECT COUNT(id_topic)
@@ -850,9 +855,9 @@ function loadPermissions()
 /**
  * Loads an array of users' data by ID or member_name.
  *
- * @param $users
- * @param $is_name
- * @param string $set = 'normal'
+ * @param mixed $users An array of users by id or name
+ * @param bool $is_name = false $users is by name or by id
+ * @param string $set = 'normal' What kind of data to load (normal, profile, minimal)
  */
 function loadMemberData($users, $is_name = false, $set = 'normal')
 {
@@ -1013,8 +1018,8 @@ function loadMemberData($users, $is_name = false, $set = 'normal')
 /**
  * Loads the user's basic values... meant for template/theme usage.
  *
- * @param $user
- * @param bool $display_custom_fields
+ * @param int $user
+ * @param bool $display_custom_fields = false
  */
 function loadMemberContext($user, $display_custom_fields = false)
 {
@@ -1271,7 +1276,7 @@ function detectBrowser()
  * Load a theme, by ID.
  *
  * @param int $id_theme = 0
- * @parambool $initialize = true
+ * @param bool $initialize = true
  */
 function loadTheme($id_theme = 0, $initialize = true)
 {
@@ -1533,7 +1538,7 @@ function loadTheme($id_theme = 0, $initialize = true)
 	// A bug in some versions of IIS under CGI (older ones) makes cookie setting not work with Location: headers.
 	$context['server']['needs_login_fix'] = $context['server']['is_cgi'] && $context['server']['is_iis'];
 
-	// Detect the browser. This is separated out because it's also used in attachment downloads
+	// Detect the browser. This is separated out because it's also used in attachment downloads.
 	detectBrowser();
 
 	// Set the top level linktree up.
@@ -1729,9 +1734,11 @@ function loadTheme($id_theme = 0, $initialize = true)
  *  - uses the template_include() function to include the file.
  *  - detects a wrong default theme directory and tries to work around it.
  *  - if fatal is true, dies with an error message if the template cannot be found.
+ * 
  * @param string $template_name
  * @param array $style_sheets = array()
  * @param bool $fatal = true
+ * @return bool
  */
 function loadTemplate($template_name, $style_sheets = array(), $fatal = true)
 {
@@ -1821,7 +1828,9 @@ function loadTemplate($template_name, $style_sheets = array(), $fatal = true)
  *  template.
  *  - if ?debug is in the query string, shows administrators a marker after every sub template
  *   for debugging purposes.
- *   @todo get rid of reading $_REQUEST directly
+ * 
+ * @todo get rid of reading $_REQUEST directly
+ * 
  * @param string $sub_template_name
  * @param bool $fatal = false, $fatal = true is for templates that shouldn't get a 'pretty' error screen.
  */
@@ -1856,6 +1865,7 @@ function loadSubTemplate($sub_template_name, $fatal = false)
  * @param string $lang
  * @param bool $fatal = true
  * @param bool $force_reload = false
+ * @return string The language actually loaded.
  */
 function loadLanguage($template_name, $lang = '', $fatal = true, $force_reload = false)
 {
@@ -2023,6 +2033,7 @@ function getBoardParents($id_parent)
  *
  * @param bool $use_cache = true
  * @param bool $favor_utf8 = true
+ * @return array
  */
 function getLanguages($use_cache = true, $favor_utf8 = true)
 {
@@ -2096,8 +2107,10 @@ function getLanguages($use_cache = true, $favor_utf8 = true)
  *  	  show_no_censored is enabled, does not censor - unless force is set.
  *  - it caches the list of censored words to reduce parsing.
  * @todo what is this function doing here?
- * @param $text
- * @param $force
+ * 
+ * @param string &$text
+ * @param bool $force
+ * @return string The censored text
  */
 function &censorText(&$text, $force = false)
 {

+ 15 - 0
Sources/LogInOut.php

@@ -523,6 +523,21 @@ function DoLogin()
 	);
 	$_SESSION['log_time'] = 0;
 
+	// Log this entry, only if we have it enabled.
+	if (!empty($modSettings['loginHistoryDays']))
+		$smcFunc['db_insert']('insert',
+			'{db_prefix}member_logins',
+			array(
+				'id_member' => 'int', 'time' => 'int', 'ip' => 'string', 'ip2' => 'string',
+			),
+			array(
+				$user_info['id'], time(), $user_info['ip'], $user_info['ip2']
+			),
+			array(
+				'id_member', 'time'
+			)
+		);
+
 	// Just log you back out if it's in maintenance mode and you AREN'T an admin.
 	if (empty($maintenance) || allowedTo('admin_forum'))
 		redirectexit('action=login2;sa=check;member=' . $user_info['id'], $context['server']['needs_login_fix']);

+ 8 - 0
Sources/ManageLanguages.php

@@ -43,6 +43,8 @@ function ManageLanguages()
 		'editlang' => 'ModifyLanguage',
 	);
 
+	call_integration_hook('integrate_manage_languages', array(&$config_vars));
+
 	// By default we're managing languages.
 	$_REQUEST['sa'] = isset($_REQUEST['sa']) && isset($subActions[$_REQUEST['sa']]) ? $_REQUEST['sa'] : 'edit';
 	$context['sub_action'] = $_REQUEST['sa'];
@@ -724,6 +726,8 @@ function ModifyLanguageSettings($return_config = false)
 		array('userLanguage', $txt['userLanguage'], 'db', 'check', null, 'userLanguage'),
 	);
 
+	call_integration_hook('integrate_language_settings', array(&$config_vars));
+
 	if ($return_config)
 		return $config_vars;
 
@@ -736,6 +740,9 @@ function ModifyLanguageSettings($return_config = false)
 	if (isset($_REQUEST['save']))
 	{
 		checkSession();
+
+		call_integration_hook('integrate_save_language_settings');
+
 		saveSettings($config_vars);
 		redirectexit('action=admin;area=languages;sa=settings');
 	}
@@ -855,6 +862,7 @@ function ModifyLanguage()
 	if (!empty($_POST['delete_main']) && $context['lang_id'] != 'english')
 	{
 		checkSession();
+		validateToken('admin-mlang');
 
 		/**
 		 * @todo FTP Controls?

+ 6 - 11
Sources/ManageMaintenance.php

@@ -260,24 +260,19 @@ function MaintainEmptyUnimportantLogs()
 
 	// No one's online now.... MUHAHAHAHA :P.
 	$smcFunc['db_query']('', '
-		DELETE FROM {db_prefix}log_online');
+		DELETE FROM ');
 
-	// Dump the banning logs.
+	// @todo why are we truncating some but not all?
+
+	// Clear out the ban, SPAM, and karma logs.
 	$smcFunc['db_query']('', '
-		DELETE FROM {db_prefix}log_banned');
+		DELETE FROM {db_prefix}log_banned, {db_prefix}log_online,
+			{db_prefix}log_floodcontrol, {db_prefix}log_karma');
 
 	// Start id_error back at 0 and dump the error log.
 	$smcFunc['db_query']('truncate_table', '
 		TRUNCATE {db_prefix}log_errors');
 
-	// Clear out the spam log.
-	$smcFunc['db_query']('', '
-		DELETE FROM {db_prefix}log_floodcontrol');
-
-	// Clear out the karma actions.
-	$smcFunc['db_query']('', '
-		DELETE FROM {db_prefix}log_karma');
-
 	// Last but not least, the search logs!
 	$smcFunc['db_query']('truncate_table', '
 		TRUNCATE {db_prefix}log_search_topics');

+ 15 - 0
Sources/ManageMembergroups.php

@@ -40,6 +40,8 @@ function ModifyMembergroups()
 		'settings' => array('ModifyMembergroupsettings', 'admin_forum'),
 	);
 
+	call_integration_hook('integrate_manage_membergroups', array(&$subActions));
+
 	// Default to sub action 'index' or 'settings' depending on permissions.
 	$_REQUEST['sa'] = isset($_REQUEST['sa']) && isset($subActions[$_REQUEST['sa']]) ? $_REQUEST['sa'] : (allowedTo('manage_membergroups') ? 'index' : 'settings');
 
@@ -194,6 +196,8 @@ function MembergroupIndex()
 		),
 	);
 
+	call_integration_hook('integrate_modify_regular_groups', array(&$listOptions));
+
 	require_once($sourcedir . '/Subs-List.php');
 	createList($listOptions);
 
@@ -305,6 +309,8 @@ function MembergroupIndex()
 		),
 	);
 
+	call_integration_hook('integrate_modify_post_groups', array(&$listOptions));
+
 	createList($listOptions);
 }
 
@@ -357,6 +363,8 @@ function AddMembergroup()
 			array('id_group')
 		);
 
+		call_integration_hook('integrate_add_membergroup', array($id_group, $postCountBasedGroup));
+
 		// Update the post groups now, if this is a post group!
 		if (isset($_POST['min_posts']))
 			updateStats('postgroups');
@@ -706,6 +714,8 @@ function EditMembergroup()
 			)
 		);
 
+		call_integration_hook('integrate_save_membergroup', array((int) $_REQUEST['group']));
+
 		// Time to update the boards this membergroup has access to.
 		if ($_REQUEST['group'] == 2 || $_REQUEST['group'] > 3)
 		{
@@ -1036,6 +1046,8 @@ function EditMembergroup()
 		$context['inheritable_groups'][$row['id_group']] = $row['group_name'];
 	$smcFunc['db_free_result']($request);
 
+	call_integration_hook('integrate_view_membergroup');
+
 	$context['sub_template'] = 'edit_group';
 	$context['page_title'] = $txt['membergroups_edit_group'];
 
@@ -1068,9 +1080,12 @@ function ModifyMembergroupsettings()
 			array('permissions', 'manage_membergroups'),
 	);
 
+	call_integration_hook('integrate_modify_membergroup_settings', array(&$config_vars));
+
 	if (isset($_REQUEST['save']))
 	{
 		checkSession();
+		call_integration_hook('integrate_save_membergroup_settings');
 
 		// Yeppers, saving this...
 		saveDBSettings($config_vars);

+ 7 - 0
Sources/ManageNews.php

@@ -41,6 +41,8 @@ function ManageNews()
 		'settings' => array('ModifyNewsSettings', 'admin_forum'),
 	);
 
+	call_integration_hook('integrate_manage_news', array(&$subActions));
+
 	// Default to sub action 'main' or 'settings' depending on permissions.
 	$_REQUEST['sa'] = isset($_REQUEST['sa']) && isset($subActions[$_REQUEST['sa']]) ? $_REQUEST['sa'] : (allowedTo('edit_news') ? 'editnews' : (allowedTo('send_mail') ? 'mailingmembers' : 'settings'));
 
@@ -786,6 +788,8 @@ function ModifyNewsSettings($return_config = false)
 			array('text', 'xmlnews_maxlen', 10),
 	);
 
+	call_integration_hook('integrate_modify_news_settings', array(&$config_vars));
+
 	if ($return_config)
 		return $config_vars;
 
@@ -793,6 +797,7 @@ function ModifyNewsSettings($return_config = false)
 	$context['sub_template'] = 'show_settings';
 
 	// Needed for the inline permission functions, and the settings template.
+	// @todo is this really needed?
 	require_once($sourcedir . '/ManagePermissions.php');
 	require_once($sourcedir . '/ManageServer.php');
 
@@ -811,6 +816,8 @@ function ModifyNewsSettings($return_config = false)
 	{
 		checkSession();
 
+		call_integration_hook('integrate_save_news_settings');
+
 		saveDBSettings($config_vars);
 		redirectexit('action=admin;area=news;sa=settings');
 	}

+ 2 - 16
Sources/ManagePermissions.php

@@ -996,14 +996,7 @@ function GeneralPermissionSettings($return_config = false)
 		if (empty($modSettings['permission_enable_deny']))
 		{
 			$smcFunc['db_query']('', '
-				DELETE FROM {db_prefix}permissions
-				WHERE add_deny = {int:denied}',
-				array(
-					'denied' => 0,
-				)
-			);
-			$smcFunc['db_query']('', '
-				DELETE FROM {db_prefix}board_permissions
+				DELETE FROM {db_prefix}permissions, {db_prefix}board_permissions
 				WHERE add_deny = {int:denied}',
 				array(
 					'denied' => 0,
@@ -1030,14 +1023,7 @@ function GeneralPermissionSettings($return_config = false)
 
 			// Remove'em.
 			$smcFunc['db_query']('', '
-				DELETE FROM {db_prefix}permissions
-				WHERE id_group IN ({array_int:post_group_list})',
-				array(
-					'post_group_list' => $post_groups,
-				)
-			);
-			$smcFunc['db_query']('', '
-				DELETE FROM {db_prefix}board_permissions
+				DELETE FROM {db_prefix}permissions, {db_prefix}board_permissions
 				WHERE id_group IN ({array_int:post_group_list})',
 				array(
 					'post_group_list' => $post_groups,

+ 6 - 0
Sources/ManageSearch.php

@@ -48,6 +48,8 @@ function ManageSearch()
 		'createmsgindex' => 'CreateMessageIndex',
 	);
 
+	call_integration_hook('integrate_manage_search', array(&$subActions));
+
 	// Default the sub-action to 'edit search settings'.
 	$_REQUEST['sa'] = isset($_REQUEST['sa']) && isset($subActions[$_REQUEST['sa']]) ? $_REQUEST['sa'] : 'weights';
 
@@ -100,6 +102,8 @@ function EditSearchSettings($return_config = false)
 			array('int', 'search_floodcontrol_time', 'subtext' => $txt['search_floodcontrol_time_desc']),
 	);
 
+	call_integration_hook('integrate_modify_search_settings', array(&$config_vars));
+
 	// Perhaps the search method wants to add some settings?
 	$modSettings['search_index'] = empty($modSettings['search_index']) ? 'standard' : $modSettings['search_index'];
 	if (file_exists($sourcedir . '/SearchAPI-' . ucwords($modSettings['search_index']) . '.php'))
@@ -125,6 +129,8 @@ function EditSearchSettings($return_config = false)
 	{
 		checkSession();
 
+		call_integration_hook('integrate_save_search_settings');
+
 		saveDBSettings($config_vars);
 		redirectexit('action=admin;area=managesearch;sa=settings;' . $context['session_var'] . '=' . $context['session_id']);
 	}

+ 7 - 0
Sources/ManageSearchEngines.php

@@ -36,6 +36,8 @@ function SearchEngines()
 		'stats' => 'SpiderStats',
 	);
 
+	call_integration_hook('integrate_manage_search_engines', array(&$subActions));
+
 	// Ensure we have a valid subaction.
 	$context['sub_action'] = isset($_REQUEST['sa']) && isset($subActions[$_REQUEST['sa']]) ? $_REQUEST['sa'] : 'stats';
 
@@ -86,6 +88,8 @@ function ManageSearchEngineSettings($return_config = false)
 		}
 		disableFields();';
 
+	call_integration_function('integrate_search_engine_settings', array(&$config_vars));
+
 	if ($return_config)
 		return $config_vars;
 
@@ -120,6 +124,7 @@ function ManageSearchEngineSettings($return_config = false)
 	{
 		checkSession();
 
+		call_integration_function('integrate_save_search_engine_settings');
 		saveDBSettings($config_vars);
 		recacheSpiderNames();
 		redirectexit('action=admin;area=sengines;sa=settings');
@@ -449,6 +454,7 @@ function EditSpider()
 
 /**
  * Do we think the current user is a spider?
+ * 
  * @todo Should this not be... you know... in a different file?
  */
 function SpiderCheck()
@@ -525,6 +531,7 @@ function SpiderCheck()
 
 /**
  * Log the spider presence online.
+ * 
  * @todo Different file?
  */
 function logSpider()

+ 23 - 1
Sources/ManageServer.php

@@ -1,7 +1,7 @@
 <?php
 
 /**
- * This file contains all the functionality required to be able to edit the
+ * Contains all the functionality required to be able to edit the
  * core server settings. This includes anything from which an error may
  * result in the forum destroying itself in a firey fury.
  *
@@ -105,6 +105,8 @@ function ModifySettings()
 		'loads' => 'ModifyLoadBalancingSettings',
 	);
 
+	call_integration_hook('integrate_server_settings', array(&$subActions));
+
 	// By default we're editing the core settings
 	$_REQUEST['sa'] = isset($_REQUEST['sa']) && isset($subActions[$_REQUEST['sa']]) ? $_REQUEST['sa'] : 'general';
 	$context['sub_action'] = $_REQUEST['sa'];
@@ -163,6 +165,8 @@ function ModifyGeneralSettings($return_config = false)
 		array('disableHostnameLookup', $txt['disableHostnameLookup'], 'db', 'check', null, 'disableHostnameLookup'),
 	);
 
+	call_integration_hook('integrate_general_settings', array(&$config_vars));
+
 	if ($return_config)
 		return $config_vars;
 
@@ -173,6 +177,8 @@ function ModifyGeneralSettings($return_config = false)
 	// Saving settings?
 	if (isset($_REQUEST['save']))
 	{
+		call_integration_hook('integrate_save_general_settings');
+
 		saveSettings($config_vars);
 		redirectexit('action=admin;area=serversettings;sa=general;' . $context['session_var'] . '=' . $context['session_id']);
 	}
@@ -221,6 +227,8 @@ function ModifyDatabaseSettings($return_config = false)
 		array('cachedir', $txt['cachedir'], 'file', 'text', 36),
 	);
 
+	call_integration_hook('integrate_database_settings', array(&$config_vars));
+
 	if ($return_config)
 		return $config_vars;
 
@@ -232,6 +240,8 @@ function ModifyDatabaseSettings($return_config = false)
 	// Saving settings?
 	if (isset($_REQUEST['save']))
 	{
+		call_integration_hook('integrate_save_database_settings');
+
 		saveSettings($config_vars);
 		redirectexit('action=admin;area=serversettings;sa=database;' . $context['session_var'] . '=' . $context['session_id']);
 	}
@@ -264,6 +274,8 @@ function ModifyCookieSettings($return_config = false)
 		array('databaseSession_lifetime', $txt['databaseSession_lifetime'], 'db', 'int', false, 'databaseSession_lifetime'),
 	);
 
+	call_integration_hook('integrate_cookie_settings', array(&$config_vars));
+
 	if ($return_config)
 		return $config_vars;
 
@@ -273,6 +285,8 @@ function ModifyCookieSettings($return_config = false)
 	// Saving settings?
 	if (isset($_REQUEST['save']))
 	{
+		call_integration_hook('integrate_save_cookie_settings');
+
 		saveSettings($config_vars);
 
 		// If the cookie name was changed, reset the cookie.
@@ -314,12 +328,16 @@ function ModifyCacheSettings($return_config = false)
 		array('text', 'cache_memcached'),
 	);
 
+	call_integration_hook('integrate_cache_settings', array(&$config_vars));
+
 	if ($return_config)
 		return $config_vars;
 
 	// Saving again?
 	if (isset($_GET['save']))
 	{
+		call_integration_hook('integrate_save_cache_settings');
+
 		saveDBSettings($config_vars);
 
 		// We have to manually force the clearing of the cache otherwise the changed settings might not get noticed.
@@ -410,6 +428,8 @@ function ModifyLoadBalancingSettings($return_config = false)
 		$config_vars[] = array('text', $name, 'value' => $value, 'disabled' => $disabled);
 	}
 
+	call_integration_hook('integrate_loadavg_settings', array(&$config_vars));
+
 	if ($return_config)
 		return $config_vars;
 
@@ -432,6 +452,8 @@ function ModifyLoadBalancingSettings($return_config = false)
 				$_POST[$key] = '2.0';
 		}
 
+		call_integration_hook('integrate_save_loadavg_settings');
+
 		saveDBSettings($config_vars);
 		redirectexit('action=admin;area=serversettings;sa=loads;' . $context['session_var'] . '=' . $context['session_id']);
 	}

+ 2 - 0
Sources/ManageSettings.php

@@ -507,9 +507,11 @@ function ModifyGeneralSecuritySettings($return_config = false)
 			array('check', 'make_email_viewable'),
 		'',
 			array('int', 'failed_login_threshold'),
+			array('int', 'loginHistoryDays'),
 		'',
 			array('check', 'enableErrorLogging'),
 			array('check', 'enableErrorQueryLogging'),
+		'',
 			array('check', 'securityDisable'),
 			array('check', 'securityDisable_moderate'),
 		'',

+ 1 - 1
Sources/MessageIndex.php

@@ -454,7 +454,7 @@ function MessageIndex()
 				$pages = '';
 
 			// We need to check the topic icons exist...
-			if (empty($modSettings['messageIconChecks_disable']))
+			if (!empty($modSettings['messageIconChecks_enable']))
 			{
 				if (!isset($context['icon_sources'][$row['first_icon']]))
 					$context['icon_sources'][$row['first_icon']] = file_exists($settings['theme_dir'] . '/images/post/' . $row['first_icon'] . '.gif') ? 'images_url' : 'default_images_url';

+ 3 - 0
Sources/Post.php

@@ -363,6 +363,8 @@ function Post()
 		$context['post_errors'] = array();
 
 	// See if any new replies have come along.
+	// Huh, $_REQUEST['msg'] is set upon submit, so this doesn't get executed at submit
+	// only at preview
 	if (empty($_REQUEST['msg']) && !empty($topic))
 	{
 		if (empty($options['no_new_reply_warning']) && isset($_REQUEST['last_msg']) && $context['topic_last_message'] > $_REQUEST['last_msg'])
@@ -419,6 +421,7 @@ function Post()
 	}
 
 	// Previewing, modifying, or posting?
+	// Do we have a body, but an error happened.
 	if (isset($_REQUEST['message']) || !empty($context['post_error']))
 	{
 		// Validate inputs.

+ 141 - 0
Sources/Profile-View.php

@@ -826,6 +826,7 @@ function tracking($memID)
 		'activity' => array('trackActivity', $txt['trackActivity']),
 		'ip' => array('TrackIP', $txt['trackIP']),
 		'edits' => array('trackEdits', $txt['trackEdits']),
+		'logins' => array('TrackLogins', $txt['trackLogins']),
 	);
 
 	$context['tracking_area'] = isset($_GET['sa']) && isset($subActions[$_GET['sa']]) ? $_GET['sa'] : 'activity';
@@ -1500,6 +1501,146 @@ function TrackIP($memID = 0)
 	}
 }
 
+/**
+ * Tracks a users logins.
+ * 
+ * @param int $memID = 0 id_member
+ */
+function TrackLogins($memID = 0)
+{
+	global $user_profile, $scripturl, $txt, $user_info, $modSettings, $sourcedir;
+	global $context, $smcFunc;
+
+	// Gonna want this for the list.
+	require_once($sourcedir . '/Subs-List.php');
+
+	if ($memID == 0)
+		$context['base_url'] = $scripturl . '?action=trackip';
+	else
+		$context['base_url'] = $scripturl . '?action=profile;area=tracking;sa=ip;u=' . $memID;
+
+	// Start with the user messages.
+	$listOptions = array(
+		'id' => 'track_logins_list',
+		'title' => $txt['trackLogins'],
+		'no_items_label' => $txt['trackLogins_none_found'],
+		'base_href' => $context['base_url'],
+		'get_items' => array(
+			'function' => 'list_getLogins',
+			'params' => array(
+				'id_member = {int:current_member}',
+				array('current_member' => $memID),
+			),
+		),
+		'get_count' => array(
+			'function' => 'list_getLoginCount',
+			'params' => array(
+				'id_member = {int:current_member}',
+				array('current_member' => $memID),
+			),
+		),
+		'columns' => array(
+			'time' => array(
+				'header' => array(
+					'value' => $txt['date'],
+				),
+				'data' => array(
+					'db' => 'time',
+				),
+			),
+			'ip' => array(
+				'header' => array(
+					'value' => $txt['ip_address'],
+				),
+				'data' => array(
+					'sprintf' => array(
+						'format' => '<a href="' . $context['base_url'] . ';searchip=%1$s">%1$s</a> (<a href="' . $context['base_url'] . ';searchip=%2$s">%2$s</a>) ',
+						'params' => array(
+							'ip' => false,
+							'ip2' => false
+						),
+					),
+				),
+			),
+		),
+		'additional_rows' => array(
+			array(
+				'position' => 'after_title',
+				'value' => $txt['trackLogins_desc'],
+				'class' => 'smalltext',
+				'style' => 'padding: 2ex;',
+			),
+		),
+	);
+
+	// Create the messages list.
+	createList($listOptions);
+
+	$context['sub_template'] = 'show_list';
+	$context['default_list'] = 'track_logins_list';
+}
+
+/**
+ * Callback for trackLogins for counting history.
+ * 
+ * @param string $where
+ * @param array $where_vars
+ * @return string count of messages matching the IP
+ */
+function list_getLoginCount($where, $where_vars = array())
+{
+	global $smcFunc;
+
+	$request = $smcFunc['db_query']('', '
+		SELECT COUNT(*) AS message_count
+		FROM {db_prefix}member_logins
+		WHERE id_member = {int:id_member}',
+		array(
+			'id_member' => $where_vars['current_member'],
+		)
+	);
+	list ($count) = $smcFunc['db_fetch_row']($request);
+	$smcFunc['db_free_result']($request);
+
+	// @todo cast to integer
+	return $count;
+}
+
+/**
+ * Callback for trackLogins data.
+ * 
+ * @param int $start
+ * @param int $items_per_page
+ * @param string $sort
+ * @param string $where
+ * @param array $where_vars
+ * @return array an array of messages
+ */
+function list_getLogins($start, $items_per_page, $sort, $where, $where_vars = array())
+{
+	global $smcFunc, $txt, $scripturl;
+
+	$request = $smcFunc['db_query']('', '
+		SELECT time, ip, ip2
+		FROM {db_prefix}member_logins
+		WHERE {int:id_member}
+		ORDER BY time DESC',
+		array(
+			'id_member' => $where_vars['current_member'],
+		)
+	);
+	$logins = array();
+	while ($row = $smcFunc['db_fetch_assoc']($request))
+		$logins[] = array(
+			'time' => timeformat($row['time']),
+			'ip' => $row['ip'],
+			'ip2' => $row['ip2'],
+		);
+	$smcFunc['db_free_result']($request);
+
+	return $logins;
+}
+
 /**
  * @todo needs a description
  * 

+ 1 - 0
Sources/Profile.php

@@ -133,6 +133,7 @@ function ModifyProfile($post_errors = array())
 						'activity' => array($txt['trackActivity'], 'moderate_forum'),
 						'ip' => array($txt['trackIP'], 'moderate_forum'),
 						'edits' => array($txt['trackEdits'], 'moderate_forum'),
+						'logins' => array($txt['trackLogins'], array('profile_view_own', 'moderate_forum')),
 					),
 					'permission' => array(
 						'own' => 'moderate_forum',

+ 5 - 5
Sources/QueryString.php

@@ -22,7 +22,7 @@ if (!defined('SMF'))
  *
  * What it does:
  * - cleans the request variables (ENV, GET, POST, COOKIE, SERVER) and
- * makes sure the query string was parsed correctly.
+ *	 makes sure the query string was parsed correctly.
  * - handles the URLs passed by the queryless URLs option.
  * - makes sure, regardless of php.ini, everything has slashes.
  * - sets up $board, $topic, and $scripturl and $_REQUEST['start'].
@@ -79,7 +79,7 @@ function cleanRequest()
 		$_SERVER['QUERY_STRING'] = substr($_SERVER['QUERY_STRING'], 0, 5) === 'url=/' ? $_SERVER['REDIRECT_QUERY_STRING'] : $_SERVER['QUERY_STRING'];
 
 		// Replace ';' with '&' and '&something&' with '&something=&'.  (this is done for compatibility...)
-		// !!! smflib
+		// @todo smflib
 		parse_str(preg_replace('/&(\w+)(?=&|$)/', '&$1=', strtr($_SERVER['QUERY_STRING'], array(';?' => '&', ';' => '&', '%00' => '', "\0" => ''))), $_GET);
 
 		// Magic quotes still applies with parse_str - so clean it up.
@@ -125,7 +125,7 @@ function cleanRequest()
 		else
 			$request = $_SERVER['REQUEST_URI'];
 
-		// !!! smflib.
+		// @todo smflib.
 		// Replace 'index.php/a,b,c/d/e,f' with 'a=b,c&d=&e=f' and parse it into $_GET.
 		if (strpos($request, basename($scripturl) . '/') !== false)
 		{
@@ -502,7 +502,7 @@ function ob_sessrewrite($buffer)
 		return $buffer;
 
 	// Do nothing if the session is cookied, or they are a crawler - guests are caught by redirectexit().  This doesn't work below PHP 4.3.0, because it makes the output buffer bigger.
-	// !!! smflib
+	// @todo smflib
 	if (empty($_COOKIE) && SID != '' && empty($context['browser']['possibly_robot']) && @version_compare(PHP_VERSION, '4.3.0') != -1)
 		$buffer = preg_replace('/"' . preg_quote($scripturl, '/') . '(?!\?' . preg_quote(SID, '/') . ')\\??/', '"' . $scripturl . '?' . SID . '&amp;', $buffer);
 	// Debugging templates, are we?
@@ -510,7 +510,7 @@ function ob_sessrewrite($buffer)
 		$buffer = preg_replace('/(?<!<link rel="canonical" href=)"' . preg_quote($scripturl, '/') . '\\??/', '"' . $scripturl . '?debug;', $buffer);
 
 	// This should work even in 4.2.x, just not CGI without cgi.fix_pathinfo.
-	if (!empty($modSettings['queryless_urls']) && (!$context['server']['is_cgi'] || @ini_get('cgi.fix_pathinfo') == 1 || @get_cfg_var('cgi.fix_pathinfo') == 1) && ($context['server']['is_apache'] || $context['server']['is_lighttpd']))
+	if (!empty($modSettings['queryless_urls']) && (!$context['server']['is_cgi'] || @ini_get('cgi.fix_pathinfo') == 1 || @get_cfg_var('cgi.fix_pathinfo') == 1) && ($context['server']['is_apache'] || $context['server']['is_lighttpd'] || $context['server']['is_litespeed']))
 	{
 		// Let's do something special for session ids!
 		if (defined('SID') && SID != '')

+ 1 - 1
Sources/Recent.php

@@ -1208,7 +1208,7 @@ function UnreadTopics()
 			$pages = '';
 
 		// We need to check the topic icons exist... you can never be too sure!
-		if (empty($modSettings['messageIconChecks_disable']))
+		if (!empty($modSettings['messageIconChecks_enable']))
 		{
 			// First icon first... as you'd expect.
 			if (!isset($context['icon_sources'][$row['first_icon']]))

+ 33 - 28
Sources/RepairBoards.php

@@ -1,6 +1,8 @@
 <?php
 
 /**
+ * This is here for the "repair any errors" feature in the admin center.
+ *
  * Simple Machines Forum (SMF)
  *
  * @package SMF
@@ -14,33 +16,14 @@
 if (!defined('SMF'))
 	die('Hacking attempt...');
 
-/*	This is here for the "repair any errors" feature in the admin center.  It
-	uses just two simple functions:
-
-	void RepairBoards()
-		- finds or repairs errors in the database to fix possible problems.
-		- requires the admin_forum permission.
-		- uses the raw_data sub template.
-		- calls createSalvageArea() to create a new board, if necesary.
-		- accessed by ?action=admin;area=repairboards.
-
-	void pauseRepairProcess(array to_fix, string current_step_desc, int max_substep = none, force = false)
-		- show the not_done template to avoid CGI timeouts and similar.
-		- called when 3 or more seconds have passed while searching for errors.
-		- if max_substep is set, $_GET['substep'] / $max_substep is the percent
-		  done this step is.
-
-	array findForumErrors()
-		- checks for errors in steps, until 5 seconds have passed.
-		- keeps track of the errors it did find, so that the actual repair
-		  won't have to recheck everything.
-		- returns the array of errors found.
-
-	void createSalvageArea()
-		- creates a salvage board/category if one doesn't already exist.
-		- uses the forum's default language, and checks based on that name.
-*/
-
+/**
+ * Finds or repairs errors in the database to fix possible problems.
+ * Requires the admin_forum permission.
+ * Calls createSalvageArea() to create a new board, if necesary.
+ * Accessed by ?action=admin;area=repairboards.
+ *
+ * @uses raw_data sub-template.
+ */
 function RepairBoards()
 {
 	global $txt, $scripturl, $db_connection, $context, $sourcedir;
@@ -124,6 +107,17 @@ function RepairBoards()
 	}
 }
 
+/**
+ * Show the not_done template to avoid CGI timeouts and similar.
+ * Called when 3 or more seconds have passed while searching for errors.
+ * If max_substep is set, $_GET['substep'] / $max_substep is the percent
+ * done this step is.
+ *
+ * @param array $to_fix
+ * @param string $current_step_description
+ * @param int $max_substep = none
+ * @param force $force = false
+ */
 function pauseRepairProcess($to_fix, $current_step_description, $max_substep = 0, $force = false)
 {
 	global $context, $txt, $time_start, $db_temp_cache, $db_cache;
@@ -1331,6 +1325,14 @@ function loadForumTests()
 	);
 }
 
+/**
+ * Checks for errors in steps, until 5 seconds have passed.
+ * It keeps track of the errors it did find, so that the actual repair
+ * won't have to recheck everything.
+ *
+ * @param $do_fix
+ * @return array, the errors found.
+ */
 function findForumErrors($do_fix = false)
 {
 	global $context, $txt, $smcFunc, $errorTests, $db_cache, $db_temp_cache;
@@ -1549,7 +1551,10 @@ function findForumErrors($do_fix = false)
 	return $to_fix;
 }
 
-// Create a salvage area for repair purposes.
+/**
+ * Create a salvage area for repair purposes, if one doesn't already exist.
+ * Uses the forum's default language, and checks based on that name.
+ */
 function createSalvageArea()
 {
 	global $txt, $language, $salvageBoardID, $salvageCatID, $smcFunc;

+ 2 - 0
Sources/Reports.php

@@ -102,6 +102,8 @@ function ReportsMain()
 		'staff' => 'StaffReport',
 	);
 
+	call_integration_hook('integrate_report_types');
+
 	$is_first = 0;
 	foreach ($context['report_types'] as $k => $temp)
 		$context['report_types'][$k] = array(

+ 8 - 0
Sources/ScheduledTasks.php

@@ -491,6 +491,14 @@ function scheduled_daily_maintenance()
 			)
 		);
 
+	// Clean up some old login history information.
+	$smcFunc['db_query']('', '
+		DELETE FROM {db_prefix}member_logins
+		WHERE time > {int:oldLogns}',
+		array(
+			'oldLogins' => !empty($modSettings['loginHistoryDays']) ? 60 * 60 * $modSettings['loginHistoryDays'] : 108000,
+	));
+
 	// Log we've done it...
 	return true;
 }

+ 1 - 1
Sources/Search.php

@@ -1945,7 +1945,7 @@ function prepareSearchContext($reset = false)
 	$message['body'] = preg_replace('~^(?:&nbsp;)+$~', '', $message['body']);
 
 	// Sadly, we need to check the icon ain't broke.
-	if (empty($modSettings['messageIconChecks_disable']))
+	if (!empty($modSettings['messageIconChecks_enable']))
 	{
 		if (!isset($context['icon_sources'][$message['first_icon']]))
 			$context['icon_sources'][$message['first_icon']] = file_exists($settings['theme_dir'] . '/images/post/' . $message['first_icon'] . '.gif') ? 'images_url' : 'default_images_url';

+ 1 - 1
Sources/Session.php

@@ -41,7 +41,7 @@ function loadSession()
 		if (preg_match('~^\d{1,3}(\.\d{1,3}){3}$~', $parsed_url['host']) == 0 && preg_match('~(?:[^\.]+\.)?([^\.]{2,}\..+)\z~i', $parsed_url['host'], $parts) == 1)
 			@ini_set('session.cookie_domain', '.' . $parts[1]);
 	}
-	// !!! Set the session cookie path?
+	// @todo Set the session cookie path?
 
 	// If it's already been started... probably best to skip this.
 	if ((@ini_get('session.auto_start') == 1 && !empty($modSettings['databaseSession_enable'])) || session_id() == '')

+ 6 - 0
Sources/Subs-Boards.php

@@ -486,6 +486,8 @@ function modifyBoard($board_id, &$boardOptions)
 	if (!isset($boards[$board_id]) || (isset($boardOptions['target_board']) && !isset($boards[$boardOptions['target_board']])) || (isset($boardOptions['target_category']) && !isset($cat_tree[$boardOptions['target_category']])))
 		fatal_lang_error('no_board');
 
+	call_integration_hook('integrate_modify_board', array($board_id, &$boardOptions));
+
 	// All things that will be updated in the database will be in $boardUpdates.
 	$boardUpdates = array();
 	$boardUpdateParameters = array();
@@ -756,6 +758,8 @@ function createBoard($boardOptions)
 	if (in_array($boardOptions['move_to'], array('child', 'before', 'after')) && !isset($boardOptions['target_board']))
 		trigger_error('createBoard(): Target board is not set', E_USER_ERROR);
 
+	call_integration_hook('integrate_create_board', array(&$boardOptions));
+
 	// Set every optional value to its default value.
 	$boardOptions += array(
 		'posts_count' => true,
@@ -842,6 +846,8 @@ function deleteBoards($boards_to_remove, $moveChildrenTo = null)
 
 	getBoardTree();
 
+	call_integration_hook('integrate_delete_board', array($boards_to_remove, &$moveChildrenTo));
+
 	// If $moveChildrenTo is set to null, include the children in the removal.
 	if ($moveChildrenTo === null)
 	{

+ 7 - 1
Sources/Subs-Categories.php

@@ -31,6 +31,8 @@ function modifyCategory($category_id, $catOptions)
 	$catUpdates = array();
 	$catParameters = array();
 
+	call_integration_hook('integrate_modify_category', array($category_id, &$catOptions));
+
 	// Wanna change the categories position?
 	if (isset($catOptions['move_after']))
 	{
@@ -123,8 +125,10 @@ function createCategory($catOptions)
 {
 	global $smcFunc;
 
+	call_integration_hook('integrate_create_category', array(&$catOptions));
+
 	// Check required values.
-	if (!isset($catOptions['cat_name']) || trim($catOptions['cat_name']) == '')
+	if (!isset($catOptions['cat_name']) || trim($catOptions['cat_name']) === '')
 		trigger_error('createCategory(): A category name is required', E_USER_ERROR);
 
 	// Set default values.
@@ -178,6 +182,8 @@ function deleteCategories($categories, $moveBoardsTo = null)
 
 	getBoardTree();
 
+	call_integration_hook('integrate_delete_category', array($categories, &$moveBoardsTo));
+
 	// With no category set to move the boards to, delete them all.
 	if ($moveBoardsTo === null)
 	{

+ 494 - 494
Sources/Subs-Charset.php

@@ -30,253 +30,253 @@ function utf8_strtolower($string)
 		'M' => 'm',		'N' => 'n',		'O' => 'o',		'P' => 'p',
 		'Q' => 'q',		'R' => 'r',		'S' => 's',		'T' => 't',
 		'U' => 'u',		'V' => 'v',		'W' => 'w',		'X' => 'x',
-		'Y' => 'y',		'Z' => 'z',		'µ' => 'μ',		'À' => 'à',
-		'�' => 'á',		'Â' => 'â',		'Ã' => 'ã',		'Ä' => 'ä',
-		'Å' => 'å',		'Æ' => 'æ',		'Ç' => 'ç',		'È' => 'è',
-		'É' => 'é',		'Ê' => 'ê',		'Ë' => 'ë',		'Ì' => 'ì',
-		'�' => 'í',		'Î' => 'î',		'�' => 'ï',		'�' => 'ð',
-		'Ñ' => 'ñ',		'Ò' => 'ò',		'Ó' => 'ó',		'Ô' => 'ô',
-		'Õ' => 'õ',		'Ö' => 'ö',		'Ø' => 'ø',		'Ù' => 'ù',
-		'Ú' => 'ú',		'Û' => 'û',		'Ü' => 'ü',		'�' => 'ý',
-		'Þ' => 'þ',		'ß' => 'ss',	'Ā' => '�',		'Ă' => 'ă',
-		'Ą' => 'ą',		'Ć' => 'ć',		'Ĉ' => 'ĉ',		'Ċ' => 'ċ',
-		'Č' => '�',		'Ď' => '�',		'�' => 'đ',		'Ē' => 'ē',
-		'Ĕ' => 'ĕ',		'Ė' => 'ė',		'Ę' => 'ę',		'Ě' => 'ě',
-		'Ĝ' => '�',		'Ğ' => 'ğ',		'Ġ' => 'ġ',		'Ģ' => 'ģ',
-		'Ĥ' => 'ĥ',		'Ħ' => 'ħ',		'Ĩ' => 'ĩ',		'Ī' => 'ī',
-		'Ĭ' => 'ĭ',		'Į' => 'į',		'İ' => 'i̇',		'IJ' => 'ij',
-		'Ĵ' => 'ĵ',		'Ķ' => 'ķ',		'Ĺ' => 'ĺ',		'Ļ' => 'ļ',
-		'Ľ' => 'ľ',		'Ŀ' => 'ŀ',		'�' => 'ł',		'Ń' => 'ń',
-		'Ņ' => 'ņ',		'Ň' => 'ň',		'ʼn' => 'ʼn',	'Ŋ' => 'ŋ',
-		'Ō' => '�',		'Ŏ' => '�',		'�' => 'ő',		'Œ' => 'œ',
-		'Ŕ' => 'ŕ',		'Ŗ' => 'ŗ',		'Ř' => 'ř',		'Ś' => 'ś',
-		'Ŝ' => '�',		'Ş' => 'ş',		'Š' => 'š',		'Ţ' => 'ţ',
-		'Ť' => 'ť',		'Ŧ' => 'ŧ',		'Ũ' => 'ũ',		'Ū' => 'ū',
-		'Ŭ' => 'ŭ',		'Ů' => 'ů',		'Ű' => 'ű',		'Ų' => 'ų',
-		'Ŵ' => 'ŵ',		'Ŷ' => 'ŷ',		'Ÿ' => 'ÿ',		'Ź' => 'ź',
-		'Ż' => 'ż',		'Ž' => 'ž',		'ſ' => 's',		'�' => 'ɓ',
-		'Ƃ' => 'ƃ',		'Ƅ' => 'ƅ',		'Ɔ' => 'ɔ',		'Ƈ' => 'ƈ',
-		'Ɖ' => 'ɖ',		'Ɗ' => 'ɗ',		'Ƌ' => 'ƌ',		'Ǝ' => '�',
-		'�' => 'ə',		'�' => 'ɛ',		'Ƒ' => 'ƒ',		'Ɠ' => 'ɠ',
-		'Ɣ' => 'ɣ',		'Ɩ' => 'ɩ',		'Ɨ' => 'ɨ',		'Ƙ' => 'ƙ',
-		'Ɯ' => 'ɯ',		'�' => 'ɲ',		'Ɵ' => 'ɵ',		'Ơ' => 'ơ',
-		'Ƣ' => 'ƣ',		'Ƥ' => 'ƥ',		'Ʀ' => 'ʀ',		'Ƨ' => 'ƨ',
-		'Ʃ' => 'ʃ',		'Ƭ' => 'ƭ',		'Ʈ' => 'ʈ',		'Ư' => 'ư',
-		'Ʊ' => 'ʊ',		'Ʋ' => 'ʋ',		'Ƴ' => 'ƴ',		'Ƶ' => 'ƶ',
-		'Ʒ' => 'ʒ',		'Ƹ' => 'ƹ',		'Ƽ' => 'ƽ',		'DŽ' => 'dž',
-		'Dž' => 'dž',		'LJ' => 'lj',		'Lj' => 'lj',		'NJ' => 'nj',
-		'Nj' => 'nj',		'�' => 'ǎ',		'�' => '�',		'Ǒ' => 'ǒ',
-		'Ǔ' => 'ǔ',		'Ǖ' => 'ǖ',		'Ǘ' => 'ǘ',		'Ǚ' => 'ǚ',
-		'Ǜ' => 'ǜ',		'Ǟ' => 'ǟ',		'Ǡ' => 'ǡ',		'Ǣ' => 'ǣ',
-		'Ǥ' => 'ǥ',		'Ǧ' => 'ǧ',		'Ǩ' => 'ǩ',		'Ǫ' => 'ǫ',
-		'Ǭ' => 'ǭ',		'Ǯ' => 'ǯ',		'ǰ' => 'ǰ',		'DZ' => 'dz',
-		'Dz' => 'dz',		'Ǵ' => 'ǵ',		'Ƕ' => 'ƕ',		'Ƿ' => 'ƿ',
-		'Ǹ' => 'ǹ',		'Ǻ' => 'ǻ',		'Ǽ' => 'ǽ',		'Ǿ' => 'ǿ',
-		'Ȁ' => '�',		'Ȃ' => 'ȃ',		'Ȅ' => 'ȅ',		'Ȇ' => 'ȇ',
-		'Ȉ' => 'ȉ',		'Ȋ' => 'ȋ',		'Ȍ' => '�',		'Ȏ' => '�',
-		'�' => 'ȑ',		'Ȓ' => 'ȓ',		'Ȕ' => 'ȕ',		'Ȗ' => 'ȗ',
-		'Ș' => 'ș',		'Ț' => 'ț',		'Ȝ' => '�',		'Ȟ' => 'ȟ',
-		'Ƞ' => 'ƞ',		'Ȣ' => 'ȣ',		'Ȥ' => 'ȥ',		'Ȧ' => 'ȧ',
-		'Ȩ' => 'ȩ',		'Ȫ' => 'ȫ',		'Ȭ' => 'ȭ',		'Ȯ' => 'ȯ',
-		'Ȱ' => 'ȱ',		'Ȳ' => 'ȳ',		'Ⱥ' => 'ⱥ',		'Ȼ' => 'ȼ',
-		'Ƚ' => 'ƚ',		'Ⱦ' => 'ⱦ',		'�' => 'ɂ',		'Ƀ' => 'ƀ',
-		'Ʉ' => 'ʉ',		'Ʌ' => 'ʌ',		'Ɇ' => 'ɇ',		'Ɉ' => 'ɉ',
-		'Ɋ' => 'ɋ',		'Ɍ' => '�',		'Ɏ' => '�',		'ͅ' => 'ι',
-		'Ά' => 'ά',		'Έ' => 'έ',		'Ή' => 'ή',		'Ί' => 'ί',
-		'Ό' => 'ό',		'Ύ' => '�',		'�' => 'ώ',		'�' => 'ϊ�',
-		'Α' => 'α',		'Β' => 'β',		'Γ' => 'γ',		'Δ' => 'δ',
-		'Ε' => 'ε',		'Ζ' => 'ζ',		'Η' => 'η',		'Θ' => 'θ',
-		'Ι' => 'ι',		'Κ' => 'κ',		'Λ' => 'λ',		'Μ' => 'μ',
-		'�' => 'ν',		'Ξ' => 'ξ',		'Ο' => 'ο',		'Π' => 'π',
-		'Ρ' => '�',		'Σ' => 'σ',		'Τ' => 'τ',		'Υ' => 'υ',
-		'Φ' => 'φ',		'Χ' => 'χ',		'Ψ' => 'ψ',		'Ω' => 'ω',
-		'Ϊ' => 'ϊ',		'Ϋ' => 'ϋ',		'ΰ' => 'ϋ�',	'ς' => 'σ',
-		'�' => 'β',		'ϑ' => 'θ',		'ϕ' => 'φ',		'ϖ' => 'π',
-		'Ϙ' => 'ϙ',		'Ϛ' => 'ϛ',		'Ϝ' => '�',		'Ϟ' => 'ϟ',
-		'Ϡ' => 'ϡ',		'Ϣ' => 'ϣ',		'Ϥ' => 'ϥ',		'Ϧ' => 'ϧ',
-		'Ϩ' => 'ϩ',		'Ϫ' => 'ϫ',		'Ϭ' => 'ϭ',		'Ϯ' => 'ϯ',
-		'ϰ' => 'κ',		'ϱ' => '�',		'ϴ' => 'θ',		'ϵ' => 'ε',
-		'Ϸ' => 'ϸ',		'Ϲ' => 'ϲ',		'Ϻ' => 'ϻ',		'Ͻ' => 'ͻ',
-		'Ͼ' => 'ͼ',		'Ͽ' => 'ͽ',		'Ѐ' => '�',		'�' => 'ё',
-		'Ђ' => 'ђ',		'Ѓ' => 'ѓ',		'Є' => 'є',		'Ѕ' => 'ѕ',
-		'І' => 'і',		'Ї' => 'ї',		'Ј' => 'ј',		'Љ' => 'љ',
-		'Њ' => 'њ',		'Ћ' => 'ћ',		'Ќ' => 'ќ',		'�' => '�',
-		'Ў' => 'ў',		'�' => 'џ',		'�' => 'а',		'Б' => 'б',
-		'В' => 'в',		'Г' => 'г',		'Д' => 'д',		'Е' => 'е',
-		'Ж' => 'ж',		'З' => 'з',		'И' => 'и',		'Й' => 'й',
-		'К' => 'к',		'Л' => 'л',		'М' => 'м',		'�' => 'н',
-		'О' => 'о',		'П' => 'п',		'Р' => 'р',		'С' => '�',
-		'Т' => 'т',		'У' => 'у',		'Ф' => 'ф',		'Х' => 'х',
-		'Ц' => 'ц',		'Ч' => 'ч',		'Ш' => 'ш',		'Щ' => 'щ',
-		'Ъ' => 'ъ',		'Ы' => 'ы',		'Ь' => 'ь',		'Э' => '�',
-		'Ю' => 'ю',		'Я' => '�',		'Ѡ' => 'ѡ',		'Ѣ' => 'ѣ',
-		'Ѥ' => 'ѥ',		'Ѧ' => 'ѧ',		'Ѩ' => 'ѩ',		'Ѫ' => 'ѫ',
-		'Ѭ' => 'ѭ',		'Ѯ' => 'ѯ',		'Ѱ' => 'ѱ',		'Ѳ' => 'ѳ',
-		'Ѵ' => 'ѵ',		'Ѷ' => 'ѷ',		'Ѹ' => 'ѹ',		'Ѻ' => 'ѻ',
-		'Ѽ' => 'ѽ',		'Ѿ' => 'ѿ',		'Ҁ' => '�',		'Ҋ' => 'ҋ',
-		'Ҍ' => '�',		'Ҏ' => '�',		'�' => 'ґ',		'Ғ' => 'ғ',
-		'Ò”' => 'Ò•',		'Ò–' => 'Ò—',		'Ò˜' => 'Ò™',		'Òš' => 'Ò›',
-		'Ҝ' => '�',		'Ҟ' => 'ҟ',		'Ҡ' => 'ҡ',		'Ң' => 'ң',
-		'Ò¤' => 'Ò¥',		'Ò¦' => 'Ò§',		'Ò¨' => 'Ò©',		'Òª' => 'Ò«',
-		'Ò¬' => 'Ò­',		'Ò®' => 'Ò¯',		'Ò°' => 'Ò±',		'Ò²' => 'Ò³',
-		'Ò´' => 'Òµ',		'Ò¶' => 'Ò·',		'Ò¸' => 'Ò¹',		'Òº' => 'Ò»',
-		'Ò¼' => 'Ò½',		'Ò¾' => 'Ò¿',		'Ó€' => 'Ó�',		'Ó�' => 'Ó‚',
-		'Óƒ' => 'Ó„',		'Ó…' => 'Ó†',		'Ó‡' => 'Óˆ',		'Ó‰' => 'ÓŠ',
-		'Ӌ' => 'ӌ',		'�' => 'ӎ',		'�' => 'ӑ',		'Ӓ' => 'ӓ',
-		'Ó”' => 'Ó•',		'Ó–' => 'Ó—',		'Ó˜' => 'Ó™',		'Óš' => 'Ó›',
-		'Ӝ' => '�',		'Ӟ' => 'ӟ',		'Ӡ' => 'ӡ',		'Ӣ' => 'ӣ',
-		'Ó¤' => 'Ó¥',		'Ó¦' => 'Ó§',		'Ó¨' => 'Ó©',		'Óª' => 'Ó«',
-		'Ó¬' => 'Ó­',		'Ó®' => 'Ó¯',		'Ó°' => 'Ó±',		'Ó²' => 'Ó³',
-		'Ó´' => 'Óµ',		'Ó¶' => 'Ó·',		'Ó¸' => 'Ó¹',		'Óº' => 'Ó»',
-		'Ó¼' => 'Ó½',		'Ó¾' => 'Ó¿',		'Ô€' => 'Ô�',		'Ô‚' => 'Ôƒ',
-		'Ô„' => 'Ô…',		'Ô†' => 'Ô‡',		'Ôˆ' => 'Ô‰',		'ÔŠ' => 'Ô‹',
-		'Ԍ' => '�',		'Ԏ' => '�',		'�' => 'ԑ',		'Ԓ' => 'ԓ',
-		'Ô±' => 'Õ¡',		'Ô²' => 'Õ¢',		'Ô³' => 'Õ£',		'Ô´' => 'Õ¤',
-		'Ôµ' => 'Õ¥',		'Ô¶' => 'Õ¦',		'Ô·' => 'Õ§',		'Ô¸' => 'Õ¨',
-		'Ô¹' => 'Õ©',		'Ôº' => 'Õª',		'Ô»' => 'Õ«',		'Ô¼' => 'Õ¬',
-		'Ô½' => 'Õ­',		'Ô¾' => 'Õ®',		'Ô¿' => 'Õ¯',		'Õ€' => 'Õ°',
-		'Õ�' => 'Õ±',		'Õ‚' => 'Õ²',		'Õƒ' => 'Õ³',		'Õ„' => 'Õ´',
-		'Õ…' => 'Õµ',		'Õ†' => 'Õ¶',		'Õ‡' => 'Õ·',		'Õˆ' => 'Õ¸',
-		'Չ' => 'չ',		'Պ' => 'պ',		'Ջ' => 'ջ',		'Ռ' => 'ռ',
-		'Õ�' => 'Õ½',		'ÕŽ' => 'Õ¾',		'Õ�' => 'Õ¿',		'Õ�' => 'Ö€',
-		'Õ‘' => 'Ö�',		'Õ’' => 'Ö‚',		'Õ“' => 'Öƒ',		'Õ”' => 'Ö„',
-		'Õ•' => 'Ö…',		'Õ–' => 'Ö†',		'Ö‡' => 'Õ¥Ö‚',		'á‚ ' => 'â´€',
-		'Ⴁ' => '�',		'Ⴂ' => 'ⴂ',		'Ⴃ' => 'ⴃ',		'Ⴄ' => 'ⴄ',
-		'Ⴅ' => 'ⴅ',		'Ⴆ' => 'ⴆ',		'Ⴇ' => 'ⴇ',		'Ⴈ' => 'ⴈ',
-		'Ⴉ' => 'ⴉ',		'Ⴊ' => 'ⴊ',		'Ⴋ' => 'ⴋ',		'Ⴌ' => 'ⴌ',
-		'Ⴍ' => '�',		'Ⴎ' => 'ⴎ',		'Ⴏ' => '�',		'Ⴐ' => '�',
-		'Ⴑ' => 'ⴑ',		'Ⴒ' => 'ⴒ',		'Ⴓ' => 'ⴓ',		'Ⴔ' => 'ⴔ',
-		'Ⴕ' => 'ⴕ',		'Ⴖ' => 'ⴖ',		'Ⴗ' => 'ⴗ',		'Ⴘ' => 'ⴘ',
-		'Ⴙ' => 'ⴙ',		'Ⴚ' => 'ⴚ',		'Ⴛ' => 'ⴛ',		'Ⴜ' => 'ⴜ',
-		'Ⴝ' => '�',		'Ⴞ' => 'ⴞ',		'Ⴟ' => 'ⴟ',		'Ⴠ' => 'ⴠ',
-		'�' => 'ⴡ',		'Ⴢ' => 'ⴢ',		'Ⴣ' => 'ⴣ',		'Ⴤ' => 'ⴤ',
-		'Ⴥ' => 'ⴥ',		'Ḁ' => '�',		'Ḃ' => 'ḃ',		'Ḅ' => 'ḅ',
-		'Ḇ' => 'ḇ',		'Ḉ' => 'ḉ',		'Ḋ' => 'ḋ',		'Ḍ' => '�',
-		'Ḏ' => '�',		'�' => 'ḑ',		'Ḓ' => 'ḓ',		'Ḕ' => 'ḕ',
-		'Ḗ' => 'ḗ',		'Ḙ' => 'ḙ',		'Ḛ' => 'ḛ',		'Ḝ' => '�',
-		'Ḟ' => 'ḟ',		'Ḡ' => 'ḡ',		'Ḣ' => 'ḣ',		'Ḥ' => 'ḥ',
-		'Ḧ' => 'ḧ',		'Ḩ' => 'ḩ',		'Ḫ' => 'ḫ',		'Ḭ' => 'ḭ',
-		'Ḯ' => 'ḯ',		'Ḱ' => 'ḱ',		'Ḳ' => 'ḳ',		'Ḵ' => 'ḵ',
-		'Ḷ' => 'ḷ',		'Ḹ' => 'ḹ',		'Ḻ' => 'ḻ',		'Ḽ' => 'ḽ',
-		'Ḿ' => 'ḿ',		'Ṁ' => '�',		'Ṃ' => 'ṃ',		'Ṅ' => 'ṅ',
-		'Ṇ' => 'ṇ',		'Ṉ' => 'ṉ',		'Ṋ' => 'ṋ',		'Ṍ' => '�',
-		'Ṏ' => '�',		'�' => 'ṑ',		'Ṓ' => 'ṓ',		'Ṕ' => 'ṕ',
-		'Ṗ' => 'ṗ',		'Ṙ' => 'ṙ',		'Ṛ' => 'ṛ',		'Ṝ' => '�',
-		'Ṟ' => 'ṟ',		'Ṡ' => 'ṡ',		'Ṣ' => 'ṣ',		'Ṥ' => 'ṥ',
-		'Ṧ' => 'ṧ',		'Ṩ' => 'ṩ',		'Ṫ' => 'ṫ',		'Ṭ' => 'ṭ',
-		'Ṯ' => 'ṯ',		'Ṱ' => 'ṱ',		'Ṳ' => 'ṳ',		'Ṵ' => 'ṵ',
-		'Ṷ' => 'ṷ',		'Ṹ' => 'ṹ',		'Ṻ' => 'ṻ',		'Ṽ' => 'ṽ',
-		'Ṿ' => 'ṿ',		'Ẁ' => '�',		'Ẃ' => 'ẃ',		'Ẅ' => 'ẅ',
-		'Ẇ' => 'ẇ',		'Ẉ' => 'ẉ',		'Ẋ' => 'ẋ',		'Ẍ' => '�',
-		'Ẏ' => '�',		'�' => 'ẑ',		'Ẓ' => 'ẓ',		'Ẕ' => 'ẕ',
-		'ẖ' => 'ẖ',		'ẗ' => 'ẗ',		'ẘ' => 'ẘ',		'ẙ' => 'ẙ',
-		'ẚ' => 'aʾ',	'ẛ' => 'ṡ',		'Ạ' => 'ạ',		'Ả' => 'ả',
-		'Ấ' => 'ấ',		'Ầ' => 'ầ',		'Ẩ' => 'ẩ',		'Ẫ' => 'ẫ',
-		'Ậ' => 'ậ',		'Ắ' => 'ắ',		'Ằ' => 'ằ',		'Ẳ' => 'ẳ',
-		'Ẵ' => 'ẵ',		'Ặ' => 'ặ',		'Ẹ' => 'ẹ',		'Ẻ' => 'ẻ',
-		'Ẽ' => 'ẽ',		'Ế' => 'ế',		'Ề' => '�',		'Ể' => 'ể',
-		'Ễ' => 'ễ',		'Ệ' => 'ệ',		'Ỉ' => 'ỉ',		'Ị' => 'ị',
-		'Ọ' => '�',		'Ỏ' => '�',		'�' => 'ố',		'Ồ' => 'ồ',
-		'Ổ' => 'ổ',		'Ỗ' => 'ỗ',		'Ộ' => 'ộ',		'Ớ' => 'ớ',
-		'Ờ' => '�',		'Ở' => 'ở',		'Ỡ' => 'ỡ',		'Ợ' => 'ợ',
-		'Ụ' => 'ụ',		'Ủ' => 'ủ',		'Ứ' => 'ứ',		'Ừ' => 'ừ',
-		'Ử' => 'ử',		'Ữ' => 'ữ',		'Ự' => 'ự',		'Ỳ' => 'ỳ',
-		'Ỵ' => 'ỵ',		'Ỷ' => 'ỷ',		'Ỹ' => 'ỹ',		'Ἀ' => 'ἀ',
-		'Ἁ' => '�',		'Ἂ' => 'ἂ',		'Ἃ' => 'ἃ',		'Ἄ' => 'ἄ',
-		'�' => 'ἅ',		'Ἆ' => 'ἆ',		'�' => 'ἇ',		'Ἐ' => '�',
-		'Ἑ' => 'ἑ',		'Ἒ' => 'ἒ',		'Ἓ' => 'ἓ',		'Ἔ' => 'ἔ',
-		'�' => 'ἕ',		'Ἠ' => 'ἠ',		'Ἡ' => 'ἡ',		'Ἢ' => 'ἢ',
-		'Ἣ' => 'ἣ',		'Ἤ' => 'ἤ',		'Ἥ' => 'ἥ',		'Ἦ' => 'ἦ',
-		'Ἧ' => 'ἧ',		'Ἰ' => 'ἰ',		'Ἱ' => 'ἱ',		'Ἲ' => 'ἲ',
-		'Ἳ' => 'ἳ',		'Ἴ' => 'ἴ',		'Ἵ' => 'ἵ',		'Ἶ' => 'ἶ',
-		'Ἷ' => 'ἷ',		'Ὀ' => 'ὀ',		'Ὁ' => '�',		'Ὂ' => 'ὂ',
-		'Ὃ' => 'ὃ',		'Ὄ' => 'ὄ',		'�' => 'ὅ',		'�' => 'ὐ',
-		'ὒ' => 'ὒ',	'ὔ' => 'ὐ�',	'ὖ' => 'ὖ',		'Ὑ' => 'ὑ',
-		'Ὓ' => 'ὓ',		'�' => 'ὕ',		'Ὗ' => 'ὗ',		'Ὠ' => 'ὠ',
-		'Ὡ' => 'ὡ',		'Ὢ' => 'ὢ',		'Ὣ' => 'ὣ',		'Ὤ' => 'ὤ',
-		'Ὥ' => 'ὥ',		'Ὦ' => 'ὦ',		'Ὧ' => 'ὧ',		'ᾀ' => 'ἀι',
-		'�' => '�ι',	'ᾂ' => 'ἂι',	'ᾃ' => 'ἃι',	'ᾄ' => 'ἄι',
-		'ᾅ' => 'ἅι',	'ᾆ' => 'ἆι',	'ᾇ' => 'ἇι',	'ᾈ' => 'ᾀ',
-		'ᾉ' => '�',		'ᾊ' => 'ᾂ',		'ᾋ' => 'ᾃ',		'ᾌ' => 'ᾄ',
-		'�' => 'ᾅ',		'ᾎ' => 'ᾆ',		'�' => 'ᾇ',		'�' => 'ἠι',
-		'ᾑ' => 'ἡι',	'ᾒ' => 'ἢι',	'ᾓ' => 'ἣι',	'ᾔ' => 'ἤι',
-		'ᾕ' => 'ἥι',	'ᾖ' => 'ἦι',	'ᾗ' => 'ἧι',	'ᾘ' => '�',
-		'ᾙ' => 'ᾑ',		'ᾚ' => 'ᾒ',		'ᾛ' => 'ᾓ',		'ᾜ' => 'ᾔ',
-		'�' => 'ᾕ',		'ᾞ' => 'ᾖ',		'ᾟ' => 'ᾗ',		'ᾠ' => 'ὠι',
-		'ᾡ' => 'ὡι',	'ᾢ' => 'ὢι',	'ᾣ' => 'ὣι',	'ᾤ' => 'ὤι',
-		'ᾥ' => 'ὥι',	'ᾦ' => 'ὦι',	'ᾧ' => 'ὧι',	'ᾨ' => 'ᾠ',
-		'ᾩ' => 'ᾡ',		'ᾪ' => 'ᾢ',		'ᾫ' => 'ᾣ',		'ᾬ' => 'ᾤ',
-		'ᾭ' => 'ᾥ',		'ᾮ' => 'ᾦ',		'ᾯ' => 'ᾧ',		'ᾲ' => 'ὰι',
-		'ᾳ' => 'αι',	'ᾴ' => 'άι',	'ᾶ' => 'ᾶ',		'ᾷ' => 'ᾶι',
-		'Ᾰ' => 'ᾰ',		'Ᾱ' => 'ᾱ',		'Ὰ' => 'ὰ',		'Ά' => 'ά',
-		'ᾼ' => 'ᾳ',		'ι' => 'ι',		'ῂ' => 'ὴι',	'ῃ' => 'ηι',
-		'ῄ' => 'ήι',	'ῆ' => 'ῆ',		'ῇ' => 'ῆι',	'Ὲ' => 'ὲ',
-		'Έ' => 'έ',		'Ὴ' => 'ὴ',		'Ή' => 'ή',		'ῌ' => 'ῃ',
-		'ῒ' => 'ῒ',	'ΐ' => 'ϊ�',	'ῖ' => 'ῖ',		'ῗ' => 'ῗ',
-		'Ῐ' => '�',		'Ῑ' => 'ῑ',		'Ὶ' => 'ὶ',		'Ί' => 'ί',
-		'ῢ' => 'ῢ',	'ΰ' => 'ϋ�',	'ῤ' => '�̓',		'ῦ' => 'ῦ',
-		'ῧ' => 'ῧ',		'Ῠ' => 'ῠ',		'Ῡ' => 'ῡ',		'Ὺ' => 'ὺ',
-		'Ύ' => 'ύ',		'Ῥ' => 'ῥ',		'ῲ' => 'ὼι',	'ῳ' => 'ωι',
-		'ῴ' => 'ώι',	'ῶ' => 'ῶ',		'ῷ' => 'ῶι',	'Ὸ' => 'ὸ',
-		'Ό' => 'ό',		'Ὼ' => 'ὼ',		'Ώ' => 'ώ',		'ῼ' => 'ῳ',
-		'Ω' => 'ω',		'K' => 'k',		'Å' => 'å',		'Ⅎ' => 'ⅎ',
-		'â… ' => 'â…°',		'â…¡' => 'â…±',		'â…¢' => 'â…²',		'â…£' => 'â…³',
-		'â…¤' => 'â…´',		'â…¥' => 'â…µ',		'â…¦' => 'â…¶',		'â…§' => 'â…·',
-		'â…¨' => 'â…¸',		'â…©' => 'â…¹',		'â…ª' => 'â…º',		'â…«' => 'â…»',
-		'â…¬' => 'â…¼',		'â…­' => 'â…½',		'â…®' => 'â…¾',		'â…¯' => 'â…¿',
-		'Ↄ' => 'ↄ',		'Ⓐ' => '�',		'Ⓑ' => 'ⓑ',		'Ⓒ' => 'ⓒ',
-		'â’¹' => 'â““',		'â’º' => 'â“”',		'â’»' => 'â“•',		'â’¼' => 'â“–',
-		'Ⓗ' => 'ⓗ',		'Ⓘ' => 'ⓘ',		'Ⓙ' => 'ⓙ',		'Ⓚ' => 'ⓚ',
-		'�' => 'ⓛ',		'Ⓜ' => 'ⓜ',		'Ⓝ' => '�',		'Ⓞ' => 'ⓞ',
-		'Ⓟ' => 'ⓟ',		'Ⓠ' => 'ⓠ',		'Ⓡ' => 'ⓡ',		'Ⓢ' => 'ⓢ',
-		'Ⓣ' => 'ⓣ',		'Ⓤ' => 'ⓤ',		'Ⓥ' => 'ⓥ',		'Ⓦ' => 'ⓦ',
-		'�' => 'ⓧ',		'Ⓨ' => 'ⓨ',		'�' => 'ⓩ',		'Ⰰ' => 'ⰰ',
-		'â°�' => 'â°±',		'â°‚' => 'â°²',		'â°ƒ' => 'â°³',		'â°„' => 'â°´',
-		'â°…' => 'â°µ',		'â°†' => 'â°¶',		'â°‡' => 'â°·',		'â°ˆ' => 'â°¸',
-		'Ⰹ' => 'ⰹ',		'Ⰺ' => 'ⰺ',		'Ⰻ' => 'ⰻ',		'Ⰼ' => 'ⰼ',
-		'â°�' => 'â°½',		'â°Ž' => 'â°¾',		'â°�' => 'â°¿',		'â°�' => 'â±€',
-		'Ⱁ' => '�',		'Ⱂ' => 'ⱂ',		'Ⱃ' => 'ⱃ',		'Ⱄ' => 'ⱄ',
-		'Ⱅ' => 'ⱅ',		'Ⱆ' => 'ⱆ',		'Ⱇ' => 'ⱇ',		'Ⱈ' => 'ⱈ',
-		'Ⱉ' => 'ⱉ',		'Ⱊ' => 'ⱊ',		'Ⱋ' => 'ⱋ',		'Ⱌ' => 'ⱌ',
-		'�' => '�',		'Ⱎ' => 'ⱎ',		'Ⱏ' => '�',		'Ⱐ' => '�',
-		'Ⱑ' => 'ⱑ',		'Ⱒ' => 'ⱒ',		'Ⱓ' => 'ⱓ',		'Ⱔ' => 'ⱔ',
-		'Ⱕ' => 'ⱕ',		'Ⱖ' => 'ⱖ',		'Ⱗ' => 'ⱗ',		'Ⱘ' => 'ⱘ',
-		'Ⱙ' => 'ⱙ',		'Ⱚ' => 'ⱚ',		'Ⱛ' => 'ⱛ',		'Ⱜ' => 'ⱜ',
-		'Ⱝ' => '�',		'Ⱞ' => 'ⱞ',		'Ⱡ' => 'ⱡ',		'Ɫ' => 'ɫ',
-		'Ᵽ' => 'ᵽ',		'Ɽ' => 'ɽ',		'Ⱨ' => 'ⱨ',		'Ⱪ' => 'ⱪ',
-		'Ⱬ' => 'ⱬ',		'Ⱶ' => 'ⱶ',		'Ⲁ' => '�',		'Ⲃ' => 'ⲃ',
-		'Ⲅ' => 'ⲅ',		'Ⲇ' => 'ⲇ',		'Ⲉ' => 'ⲉ',		'Ⲋ' => 'ⲋ',
-		'Ⲍ' => '�',		'Ⲏ' => '�',		'�' => 'ⲑ',		'Ⲓ' => 'ⲓ',
-		'Ⲕ' => 'ⲕ',		'Ⲗ' => 'ⲗ',		'Ⲙ' => 'ⲙ',		'Ⲛ' => 'ⲛ',
-		'Ⲝ' => '�',		'Ⲟ' => 'ⲟ',		'Ⲡ' => 'ⲡ',		'Ⲣ' => 'ⲣ',
-		'Ⲥ' => 'ⲥ',		'Ⲧ' => 'ⲧ',		'Ⲩ' => 'ⲩ',		'Ⲫ' => 'ⲫ',
-		'Ⲭ' => 'ⲭ',		'Ⲯ' => 'ⲯ',		'Ⲱ' => 'ⲱ',		'Ⲳ' => 'ⲳ',
-		'Ⲵ' => 'ⲵ',		'Ⲷ' => 'ⲷ',		'Ⲹ' => 'ⲹ',		'Ⲻ' => 'ⲻ',
-		'Ⲽ' => 'ⲽ',		'Ⲿ' => 'ⲿ',		'Ⳁ' => '�',		'Ⳃ' => 'ⳃ',
-		'Ⳅ' => 'ⳅ',		'Ⳇ' => 'ⳇ',		'Ⳉ' => 'ⳉ',		'Ⳋ' => 'ⳋ',
-		'Ⳍ' => '�',		'Ⳏ' => '�',		'�' => 'ⳑ',		'Ⳓ' => 'ⳓ',
-		'Ⳕ' => 'ⳕ',		'Ⳗ' => 'ⳗ',		'Ⳙ' => 'ⳙ',		'Ⳛ' => 'ⳛ',
-		'Ⳝ' => '�',		'Ⳟ' => 'ⳟ',		'Ⳡ' => 'ⳡ',		'Ⳣ' => 'ⳣ',
-		'ff' => 'ff',	'�' => 'fi',	'fl' => 'fl',	'ffi' => 'ffi',
-		'ffl' => 'ffl',	'ſt' => 'st',	'st' => 'st',	'ﬓ' => 'մն',
-		'ﬔ' => 'մե',	'ﬕ' => 'մի',	'ﬖ' => 'վն',	'ﬗ' => 'մխ',
-		'A' => '�',		'B' => 'b',		'C' => 'c',		'D' => 'd',
-		'E' => 'e',		'F' => 'f',		'G' => 'g',		'H' => 'h',
-		'I' => 'i',		'J' => 'j',		'K' => 'k',		'L' => 'l',
-		'M' => '�',	'N' => 'n',		'O' => '�',		'P' => '�',
-		'Q' => 'q',		'R' => 'r',		'S' => 's',		'T' => 't',
-		'U' => 'u',		'V' => 'v',		'W' => 'w',	'X' => 'x',
-		'Y' => 'y',		'Z' => 'z',		'�' => '�',	'�' => '�',
-		'�' => '�',	'�' => '�',	'�' => '�',	'�' => '�',
-		'�' => '�',	'�' => '�',	'�' => '�',	'�' => '�',
-		'�' => '�',	'�' => '�',	'�' => '�',	'�' => '�',
-		'�' => '�',	'�' => '�',	'�' => '�',	'�' => '�',
-		'�' => '�',	'�' => '�',	'�' => '�',	'�' => '�',
-		'�' => '�',	'�' => '�',	'�' => '�',	'�' => '�',
-		'�' => '�',	'�' => '�',	'�' => '�',	'�' => '�',
-		'�' => '�',	'�' => '�',	'�' => '�',	'�' => '�',
-		'�' => '�',	'�' => '�',	'�' => '�',	'�' => '�',
-		'�' => '�',	'�' => '�',
+		'Y' => 'y',		'Z' => 'z',		'µ' => 'μ',		'À' => 'à',
+		'Á' => 'á',		'Â' => 'â',		'Ã' => 'ã',		'Ä' => 'ä',
+		'Å' => 'å',		'Æ' => 'æ',		'Ç' => 'ç',		'È' => 'è',
+		'É' => 'é',		'Ê' => 'ê',		'Ë' => 'ë',		'Ì' => 'ì',
+		'Í' => 'í',		'Î' => 'î',		'Ï' => 'ï',		'Ð' => 'ð',
+		'Ñ' => 'ñ',		'Ò' => 'ò',		'Ó' => 'ó',		'Ô' => 'ô',
+		'Õ' => 'õ',		'Ö' => 'ö',		'Ø' => 'ø',		'Ù' => 'ù',
+		'Ú' => 'ú',		'Û' => 'û',		'Ü' => 'ü',		'Ý' => 'ý',
+		'Þ' => 'þ',		'ß' => 'ss',	'Ā' => 'ā',		'Ă' => 'ă',
+		'Ą' => 'ą',		'Ć' => 'ć',		'Ĉ' => 'ĉ',		'Ċ' => 'ċ',
+		'Č' => 'č',		'Ď' => 'ď',		'Đ' => 'đ',		'Ē' => 'ē',
+		'Ĕ' => 'ĕ',		'Ė' => 'ė',		'Ę' => 'ę',		'Ě' => 'ě',
+		'Ĝ' => 'ĝ',		'Ğ' => 'ğ',		'Ġ' => 'ġ',		'Ģ' => 'ģ',
+		'Ĥ' => 'ĥ',		'Ħ' => 'ħ',		'Ĩ' => 'ĩ',		'Ī' => 'ī',
+		'Ĭ' => 'ĭ',		'Į' => 'į',		'İ' => 'i̇',		'IJ' => 'ij',
+		'Ĵ' => 'ĵ',		'Ķ' => 'ķ',		'Ĺ' => 'ĺ',		'Ļ' => 'ļ',
+		'Ľ' => 'ľ',		'Ŀ' => 'ŀ',		'Ł' => 'ł',		'Ń' => 'ń',
+		'Ņ' => 'ņ',		'Ň' => 'ň',		'ʼn' => 'ʼn',	'Ŋ' => 'ŋ',
+		'Ō' => 'ō',		'Ŏ' => 'ŏ',		'Ő' => 'ő',		'Œ' => 'œ',
+		'Ŕ' => 'ŕ',		'Ŗ' => 'ŗ',		'Ř' => 'ř',		'Ś' => 'ś',
+		'Ŝ' => 'ŝ',		'Ş' => 'ş',		'Š' => 'š',		'Ţ' => 'ţ',
+		'Ť' => 'ť',		'Ŧ' => 'ŧ',		'Ũ' => 'ũ',		'Ū' => 'ū',
+		'Ŭ' => 'ŭ',		'Ů' => 'ů',		'Ű' => 'ű',		'Ų' => 'ų',
+		'Ŵ' => 'ŵ',		'Ŷ' => 'ŷ',		'Ÿ' => 'ÿ',		'Ź' => 'ź',
+		'Ż' => 'ż',		'Ž' => 'ž',		'ſ' => 's',		'Ɓ' => 'ɓ',
+		'Ƃ' => 'ƃ',		'Ƅ' => 'ƅ',		'Ɔ' => 'ɔ',		'Ƈ' => 'ƈ',
+		'Ɖ' => 'ɖ',		'Ɗ' => 'ɗ',		'Ƌ' => 'ƌ',		'Ǝ' => 'ǝ',
+		'Ə' => 'ə',		'Ɛ' => 'ɛ',		'Ƒ' => 'ƒ',		'Ɠ' => 'ɠ',
+		'Ɣ' => 'ɣ',		'Ɩ' => 'ɩ',		'Ɨ' => 'ɨ',		'Ƙ' => 'ƙ',
+		'Ɯ' => 'ɯ',		'Ɲ' => 'ɲ',		'Ɵ' => 'ɵ',		'Ơ' => 'ơ',
+		'Ƣ' => 'ƣ',		'Ƥ' => 'ƥ',		'Ʀ' => 'ʀ',		'Ƨ' => 'ƨ',
+		'Ʃ' => 'ʃ',		'Ƭ' => 'ƭ',		'Ʈ' => 'ʈ',		'Ư' => 'ư',
+		'Ʊ' => 'ʊ',		'Ʋ' => 'ʋ',		'Ƴ' => 'ƴ',		'Ƶ' => 'ƶ',
+		'Ʒ' => 'ʒ',		'Ƹ' => 'ƹ',		'Ƽ' => 'ƽ',		'DŽ' => 'dž',
+		'Dž' => 'dž',		'LJ' => 'lj',		'Lj' => 'lj',		'NJ' => 'nj',
+		'Nj' => 'nj',		'Ǎ' => 'ǎ',		'Ǐ' => 'ǐ',		'Ǒ' => 'ǒ',
+		'Ǔ' => 'ǔ',		'Ǖ' => 'ǖ',		'Ǘ' => 'ǘ',		'Ǚ' => 'ǚ',
+		'Ǜ' => 'ǜ',		'Ǟ' => 'ǟ',		'Ǡ' => 'ǡ',		'Ǣ' => 'ǣ',
+		'Ǥ' => 'ǥ',		'Ǧ' => 'ǧ',		'Ǩ' => 'ǩ',		'Ǫ' => 'ǫ',
+		'Ǭ' => 'ǭ',		'Ǯ' => 'ǯ',		'ǰ' => 'ǰ',		'DZ' => 'dz',
+		'Dz' => 'dz',		'Ǵ' => 'ǵ',		'Ƕ' => 'ƕ',		'Ƿ' => 'ƿ',
+		'Ǹ' => 'ǹ',		'Ǻ' => 'ǻ',		'Ǽ' => 'ǽ',		'Ǿ' => 'ǿ',
+		'Ȁ' => 'ȁ',		'Ȃ' => 'ȃ',		'Ȅ' => 'ȅ',		'Ȇ' => 'ȇ',
+		'Ȉ' => 'ȉ',		'Ȋ' => 'ȋ',		'Ȍ' => 'ȍ',		'Ȏ' => 'ȏ',
+		'Ȑ' => 'ȑ',		'Ȓ' => 'ȓ',		'Ȕ' => 'ȕ',		'Ȗ' => 'ȗ',
+		'Ș' => 'ș',		'Ț' => 'ț',		'Ȝ' => 'ȝ',		'Ȟ' => 'ȟ',
+		'Ƞ' => 'ƞ',		'Ȣ' => 'ȣ',		'Ȥ' => 'ȥ',		'Ȧ' => 'ȧ',
+		'Ȩ' => 'ȩ',		'Ȫ' => 'ȫ',		'Ȭ' => 'ȭ',		'Ȯ' => 'ȯ',
+		'Ȱ' => 'ȱ',		'Ȳ' => 'ȳ',		'Ⱥ' => 'ⱥ',		'Ȼ' => 'ȼ',
+		'Ƚ' => 'ƚ',		'Ⱦ' => 'ⱦ',		'Ɂ' => 'ɂ',		'Ƀ' => 'ƀ',
+		'Ʉ' => 'ʉ',		'Ʌ' => 'ʌ',		'Ɇ' => 'ɇ',		'Ɉ' => 'ɉ',
+		'Ɋ' => 'ɋ',		'Ɍ' => 'ɍ',		'Ɏ' => 'ɏ',		'ͅ' => 'ι',
+		'Ά' => 'ά',		'Έ' => 'έ',		'Ή' => 'ή',		'Ί' => 'ί',
+		'Ό' => 'ό',		'Ύ' => 'ύ',		'Ώ' => 'ώ',		'ΐ' => 'ΐ',
+		'Α' => 'α',		'Β' => 'β',		'Γ' => 'γ',		'Δ' => 'δ',
+		'Ε' => 'ε',		'Ζ' => 'ζ',		'Η' => 'η',		'Θ' => 'θ',
+		'Ι' => 'ι',		'Κ' => 'κ',		'Λ' => 'λ',		'Μ' => 'μ',
+		'Ν' => 'ν',		'Ξ' => 'ξ',		'Ο' => 'ο',		'Π' => 'π',
+		'Ρ' => 'ρ',		'Σ' => 'σ',		'Τ' => 'τ',		'Υ' => 'υ',
+		'Φ' => 'φ',		'Χ' => 'χ',		'Ψ' => 'ψ',		'Ω' => 'ω',
+		'Ϊ' => 'ϊ',		'Ϋ' => 'ϋ',		'ΰ' => 'ΰ',	'ς' => 'σ',
+		'ϐ' => 'β',		'ϑ' => 'θ',		'ϕ' => 'φ',		'ϖ' => 'π',
+		'Ϙ' => 'ϙ',		'Ϛ' => 'ϛ',		'Ϝ' => 'ϝ',		'Ϟ' => 'ϟ',
+		'Ϡ' => 'ϡ',		'Ϣ' => 'ϣ',		'Ϥ' => 'ϥ',		'Ϧ' => 'ϧ',
+		'Ϩ' => 'ϩ',		'Ϫ' => 'ϫ',		'Ϭ' => 'ϭ',		'Ϯ' => 'ϯ',
+		'ϰ' => 'κ',		'ϱ' => 'ρ',		'ϴ' => 'θ',		'ϵ' => 'ε',
+		'Ϸ' => 'ϸ',		'Ϲ' => 'ϲ',		'Ϻ' => 'ϻ',		'Ͻ' => 'ͻ',
+		'Ͼ' => 'ͼ',		'Ͽ' => 'ͽ',		'Ѐ' => 'ѐ',		'Ё' => 'ё',
+		'Ђ' => 'ђ',		'Ѓ' => 'ѓ',		'Є' => 'є',		'Ѕ' => 'ѕ',
+		'І' => 'і',		'Ї' => 'ї',		'Ј' => 'ј',		'Љ' => 'љ',
+		'Њ' => 'њ',		'Ћ' => 'ћ',		'Ќ' => 'ќ',		'Ѝ' => 'ѝ',
+		'Ў' => 'ў',		'Џ' => 'џ',		'А' => 'а',		'Б' => 'б',
+		'В' => 'в',		'Г' => 'г',		'Д' => 'д',		'Е' => 'е',
+		'Ж' => 'ж',		'З' => 'з',		'И' => 'и',		'Й' => 'й',
+		'К' => 'к',		'Л' => 'л',		'М' => 'м',		'Н' => 'н',
+		'О' => 'о',		'П' => 'п',		'Р' => 'р',		'С' => 'с',
+		'Т' => 'т',		'У' => 'у',		'Ф' => 'ф',		'Х' => 'х',
+		'Ц' => 'ц',		'Ч' => 'ч',		'Ш' => 'ш',		'Щ' => 'щ',
+		'Ъ' => 'ъ',		'Ы' => 'ы',		'Ь' => 'ь',		'Э' => 'э',
+		'Ю' => 'ю',		'Я' => 'я',		'Ѡ' => 'ѡ',		'Ѣ' => 'ѣ',
+		'Ѥ' => 'ѥ',		'Ѧ' => 'ѧ',		'Ѩ' => 'ѩ',		'Ѫ' => 'ѫ',
+		'Ѭ' => 'ѭ',		'Ѯ' => 'ѯ',		'Ѱ' => 'ѱ',		'Ѳ' => 'ѳ',
+		'Ѵ' => 'ѵ',		'Ѷ' => 'ѷ',		'Ѹ' => 'ѹ',		'Ѻ' => 'ѻ',
+		'Ѽ' => 'ѽ',		'Ѿ' => 'ѿ',		'Ҁ' => 'ҁ',		'Ҋ' => 'ҋ',
+		'Ҍ' => 'ҍ',		'Ҏ' => 'ҏ',		'Ґ' => 'ґ',		'Ғ' => 'ғ',
+		'Ҕ' => 'ҕ',		'Җ' => 'җ',		'Ҙ' => 'ҙ',		'Қ' => 'қ',
+		'Ҝ' => 'ҝ',		'Ҟ' => 'ҟ',		'Ҡ' => 'ҡ',		'Ң' => 'ң',
+		'Ҥ' => 'ҥ',		'Ҧ' => 'ҧ',		'Ҩ' => 'ҩ',		'Ҫ' => 'ҫ',
+		'Ҭ' => 'ҭ',		'Ү' => 'ү',		'Ұ' => 'ұ',		'Ҳ' => 'ҳ',
+		'Ҵ' => 'ҵ',		'Ҷ' => 'ҷ',		'Ҹ' => 'ҹ',		'Һ' => 'һ',
+		'Ҽ' => 'ҽ',		'Ҿ' => 'ҿ',		'Ӏ' => 'ӏ',		'Ӂ' => 'ӂ',
+		'Ӄ' => 'ӄ',		'Ӆ' => 'ӆ',		'Ӈ' => 'ӈ',		'Ӊ' => 'ӊ',
+		'Ӌ' => 'ӌ',		'Ӎ' => 'ӎ',		'Ӑ' => 'ӑ',		'Ӓ' => 'ӓ',
+		'Ӕ' => 'ӕ',		'Ӗ' => 'ӗ',		'Ә' => 'ә',		'Ӛ' => 'ӛ',
+		'Ӝ' => 'ӝ',		'Ӟ' => 'ӟ',		'Ӡ' => 'ӡ',		'Ӣ' => 'ӣ',
+		'Ӥ' => 'ӥ',		'Ӧ' => 'ӧ',		'Ө' => 'ө',		'Ӫ' => 'ӫ',
+		'Ӭ' => 'ӭ',		'Ӯ' => 'ӯ',		'Ӱ' => 'ӱ',		'Ӳ' => 'ӳ',
+		'Ӵ' => 'ӵ',		'Ӷ' => 'ӷ',		'Ӹ' => 'ӹ',		'Ӻ' => 'ӻ',
+		'Ӽ' => 'ӽ',		'Ӿ' => 'ӿ',		'Ԁ' => 'ԁ',		'Ԃ' => 'ԃ',
+		'Ԅ' => 'ԅ',		'Ԇ' => 'ԇ',		'Ԉ' => 'ԉ',		'Ԋ' => 'ԋ',
+		'Ԍ' => 'ԍ',		'Ԏ' => 'ԏ',		'Ԑ' => 'ԑ',		'Ԓ' => 'ԓ',
+		'Ա' => 'ա',		'Բ' => 'բ',		'Գ' => 'գ',		'Դ' => 'դ',
+		'Ե' => 'ե',		'Զ' => 'զ',		'Է' => 'է',		'Ը' => 'ը',
+		'Թ' => 'թ',		'Ժ' => 'ժ',		'Ի' => 'ի',		'Լ' => 'լ',
+		'Խ' => 'խ',		'Ծ' => 'ծ',		'Կ' => 'կ',		'Հ' => 'հ',
+		'Ձ' => 'ձ',		'Ղ' => 'ղ',		'Ճ' => 'ճ',		'Մ' => 'մ',
+		'Յ' => 'յ',		'Ն' => 'ն',		'Շ' => 'շ',		'Ո' => 'ո',
+		'Չ' => 'չ',		'Պ' => 'պ',		'Ջ' => 'ջ',		'Ռ' => 'ռ',
+		'Ս' => 'ս',		'Վ' => 'վ',		'Տ' => 'տ',		'Ր' => 'ր',
+		'Ց' => 'ց',		'Ւ' => 'ւ',		'Փ' => 'փ',		'Ք' => 'ք',
+		'Օ' => 'օ',		'Ֆ' => 'ֆ',		'և' => 'եւ',		'Ⴀ' => 'ⴀ',
+		'Ⴁ' => 'ⴁ',		'Ⴂ' => 'ⴂ',		'Ⴃ' => 'ⴃ',		'Ⴄ' => 'ⴄ',
+		'Ⴅ' => 'ⴅ',		'Ⴆ' => 'ⴆ',		'Ⴇ' => 'ⴇ',		'Ⴈ' => 'ⴈ',
+		'Ⴉ' => 'ⴉ',		'Ⴊ' => 'ⴊ',		'Ⴋ' => 'ⴋ',		'Ⴌ' => 'ⴌ',
+		'Ⴍ' => 'ⴍ',		'Ⴎ' => 'ⴎ',		'Ⴏ' => 'ⴏ',		'Ⴐ' => 'ⴐ',
+		'Ⴑ' => 'ⴑ',		'Ⴒ' => 'ⴒ',		'Ⴓ' => 'ⴓ',		'Ⴔ' => 'ⴔ',
+		'Ⴕ' => 'ⴕ',		'Ⴖ' => 'ⴖ',		'Ⴗ' => 'ⴗ',		'Ⴘ' => 'ⴘ',
+		'Ⴙ' => 'ⴙ',		'Ⴚ' => 'ⴚ',		'Ⴛ' => 'ⴛ',		'Ⴜ' => 'ⴜ',
+		'Ⴝ' => 'ⴝ',		'Ⴞ' => 'ⴞ',		'Ⴟ' => 'ⴟ',		'Ⴠ' => 'ⴠ',
+		'Ⴡ' => 'ⴡ',		'Ⴢ' => 'ⴢ',		'Ⴣ' => 'ⴣ',		'Ⴤ' => 'ⴤ',
+		'Ⴥ' => 'ⴥ',		'Ḁ' => 'ḁ',		'Ḃ' => 'ḃ',		'Ḅ' => 'ḅ',
+		'Ḇ' => 'ḇ',		'Ḉ' => 'ḉ',		'Ḋ' => 'ḋ',		'Ḍ' => 'ḍ',
+		'Ḏ' => 'ḏ',		'Ḑ' => 'ḑ',		'Ḓ' => 'ḓ',		'Ḕ' => 'ḕ',
+		'Ḗ' => 'ḗ',		'Ḙ' => 'ḙ',		'Ḛ' => 'ḛ',		'Ḝ' => 'ḝ',
+		'Ḟ' => 'ḟ',		'Ḡ' => 'ḡ',		'Ḣ' => 'ḣ',		'Ḥ' => 'ḥ',
+		'Ḧ' => 'ḧ',		'Ḩ' => 'ḩ',		'Ḫ' => 'ḫ',		'Ḭ' => 'ḭ',
+		'Ḯ' => 'ḯ',		'Ḱ' => 'ḱ',		'Ḳ' => 'ḳ',		'Ḵ' => 'ḵ',
+		'Ḷ' => 'ḷ',		'Ḹ' => 'ḹ',		'Ḻ' => 'ḻ',		'Ḽ' => 'ḽ',
+		'Ḿ' => 'ḿ',		'Ṁ' => 'ṁ',		'Ṃ' => 'ṃ',		'Ṅ' => 'ṅ',
+		'Ṇ' => 'ṇ',		'Ṉ' => 'ṉ',		'Ṋ' => 'ṋ',		'Ṍ' => 'ṍ',
+		'Ṏ' => 'ṏ',		'Ṑ' => 'ṑ',		'Ṓ' => 'ṓ',		'Ṕ' => 'ṕ',
+		'Ṗ' => 'ṗ',		'Ṙ' => 'ṙ',		'Ṛ' => 'ṛ',		'Ṝ' => 'ṝ',
+		'Ṟ' => 'ṟ',		'Ṡ' => 'ṡ',		'Ṣ' => 'ṣ',		'Ṥ' => 'ṥ',
+		'Ṧ' => 'ṧ',		'Ṩ' => 'ṩ',		'Ṫ' => 'ṫ',		'Ṭ' => 'ṭ',
+		'Ṯ' => 'ṯ',		'Ṱ' => 'ṱ',		'Ṳ' => 'ṳ',		'Ṵ' => 'ṵ',
+		'Ṷ' => 'ṷ',		'Ṹ' => 'ṹ',		'Ṻ' => 'ṻ',		'Ṽ' => 'ṽ',
+		'Ṿ' => 'ṿ',		'Ẁ' => 'ẁ',		'Ẃ' => 'ẃ',		'Ẅ' => 'ẅ',
+		'Ẇ' => 'ẇ',		'Ẉ' => 'ẉ',		'Ẋ' => 'ẋ',		'Ẍ' => 'ẍ',
+		'Ẏ' => 'ẏ',		'Ẑ' => 'ẑ',		'Ẓ' => 'ẓ',		'Ẕ' => 'ẕ',
+		'ẖ' => 'ẖ',		'ẗ' => 'ẗ',		'ẘ' => 'ẘ',		'ẙ' => 'ẙ',
+		'ẚ' => 'aʾ',	'ẛ' => 'ṡ',		'Ạ' => 'ạ',		'Ả' => 'ả',
+		'Ấ' => 'ấ',		'Ầ' => 'ầ',		'Ẩ' => 'ẩ',		'Ẫ' => 'ẫ',
+		'Ậ' => 'ậ',		'Ắ' => 'ắ',		'Ằ' => 'ằ',		'Ẳ' => 'ẳ',
+		'Ẵ' => 'ẵ',		'Ặ' => 'ặ',		'Ẹ' => 'ẹ',		'Ẻ' => 'ẻ',
+		'Ẽ' => 'ẽ',		'Ế' => 'ế',		'Ề' => 'ề',		'Ể' => 'ể',
+		'Ễ' => 'ễ',		'Ệ' => 'ệ',		'Ỉ' => 'ỉ',		'Ị' => 'ị',
+		'Ọ' => 'ọ',		'Ỏ' => 'ỏ',		'Ố' => 'ố',		'Ồ' => 'ồ',
+		'Ổ' => 'ổ',		'Ỗ' => 'ỗ',		'Ộ' => 'ộ',		'Ớ' => 'ớ',
+		'Ờ' => 'ờ',		'Ở' => 'ở',		'Ỡ' => 'ỡ',		'Ợ' => 'ợ',
+		'Ụ' => 'ụ',		'Ủ' => 'ủ',		'Ứ' => 'ứ',		'Ừ' => 'ừ',
+		'Ử' => 'ử',		'Ữ' => 'ữ',		'Ự' => 'ự',		'Ỳ' => 'ỳ',
+		'Ỵ' => 'ỵ',		'Ỷ' => 'ỷ',		'Ỹ' => 'ỹ',		'Ἀ' => 'ἀ',
+		'Ἁ' => 'ἁ',		'Ἂ' => 'ἂ',		'Ἃ' => 'ἃ',		'Ἄ' => 'ἄ',
+		'Ἅ' => 'ἅ',		'Ἆ' => 'ἆ',		'Ἇ' => 'ἇ',		'Ἐ' => 'ἐ',
+		'Ἑ' => 'ἑ',		'Ἒ' => 'ἒ',		'Ἓ' => 'ἓ',		'Ἔ' => 'ἔ',
+		'Ἕ' => 'ἕ',		'Ἠ' => 'ἠ',		'Ἡ' => 'ἡ',		'Ἢ' => 'ἢ',
+		'Ἣ' => 'ἣ',		'Ἤ' => 'ἤ',		'Ἥ' => 'ἥ',		'Ἦ' => 'ἦ',
+		'Ἧ' => 'ἧ',		'Ἰ' => 'ἰ',		'Ἱ' => 'ἱ',		'Ἲ' => 'ἲ',
+		'Ἳ' => 'ἳ',		'Ἴ' => 'ἴ',		'Ἵ' => 'ἵ',		'Ἶ' => 'ἶ',
+		'Ἷ' => 'ἷ',		'Ὀ' => 'ὀ',		'Ὁ' => 'ὁ',		'Ὂ' => 'ὂ',
+		'Ὃ' => 'ὃ',		'Ὄ' => 'ὄ',		'Ὅ' => 'ὅ',		'ὐ' => 'ὐ',
+		'ὒ' => 'ὒ',	'ὔ' => 'ὔ',	'ὖ' => 'ὖ',		'Ὑ' => 'ὑ',
+		'Ὓ' => 'ὓ',		'Ὕ' => 'ὕ',		'Ὗ' => 'ὗ',		'Ὠ' => 'ὠ',
+		'Ὡ' => 'ὡ',		'Ὢ' => 'ὢ',		'Ὣ' => 'ὣ',		'Ὤ' => 'ὤ',
+		'Ὥ' => 'ὥ',		'Ὦ' => 'ὦ',		'Ὧ' => 'ὧ',		'ᾀ' => 'ἀι',
+		'ᾁ' => 'ἁι',	'ᾂ' => 'ἂι',	'ᾃ' => 'ἃι',	'ᾄ' => 'ἄι',
+		'ᾅ' => 'ἅι',	'ᾆ' => 'ἆι',	'ᾇ' => 'ἇι',	'ᾈ' => 'ᾀ',
+		'ᾉ' => 'ᾁ',		'ᾊ' => 'ᾂ',		'ᾋ' => 'ᾃ',		'ᾌ' => 'ᾄ',
+		'ᾍ' => 'ᾅ',		'ᾎ' => 'ᾆ',		'ᾏ' => 'ᾇ',		'ᾐ' => 'ἠι',
+		'ᾑ' => 'ἡι',	'ᾒ' => 'ἢι',	'ᾓ' => 'ἣι',	'ᾔ' => 'ἤι',
+		'ᾕ' => 'ἥι',	'ᾖ' => 'ἦι',	'ᾗ' => 'ἧι',	'ᾘ' => 'ᾐ',
+		'ᾙ' => 'ᾑ',		'ᾚ' => 'ᾒ',		'ᾛ' => 'ᾓ',		'ᾜ' => 'ᾔ',
+		'ᾝ' => 'ᾕ',		'ᾞ' => 'ᾖ',		'ᾟ' => 'ᾗ',		'ᾠ' => 'ὠι',
+		'ᾡ' => 'ὡι',	'ᾢ' => 'ὢι',	'ᾣ' => 'ὣι',	'ᾤ' => 'ὤι',
+		'ᾥ' => 'ὥι',	'ᾦ' => 'ὦι',	'ᾧ' => 'ὧι',	'ᾨ' => 'ᾠ',
+		'ᾩ' => 'ᾡ',		'ᾪ' => 'ᾢ',		'ᾫ' => 'ᾣ',		'ᾬ' => 'ᾤ',
+		'ᾭ' => 'ᾥ',		'ᾮ' => 'ᾦ',		'ᾯ' => 'ᾧ',		'ᾲ' => 'ὰι',
+		'ᾳ' => 'αι',	'ᾴ' => 'άι',	'ᾶ' => 'ᾶ',		'ᾷ' => 'ᾶι',
+		'Ᾰ' => 'ᾰ',		'Ᾱ' => 'ᾱ',		'Ὰ' => 'ὰ',		'Ά' => 'ά',
+		'ᾼ' => 'ᾳ',		'ι' => 'ι',		'ῂ' => 'ὴι',	'ῃ' => 'ηι',
+		'ῄ' => 'ήι',	'ῆ' => 'ῆ',		'ῇ' => 'ῆι',	'Ὲ' => 'ὲ',
+		'Έ' => 'έ',		'Ὴ' => 'ὴ',		'Ή' => 'ή',		'ῌ' => 'ῃ',
+		'ῒ' => 'ῒ',	'ΐ' => 'ΐ',	'ῖ' => 'ῖ',		'ῗ' => 'ῗ',
+		'Ῐ' => 'ῐ',		'Ῑ' => 'ῑ',		'Ὶ' => 'ὶ',		'Ί' => 'ί',
+		'ῢ' => 'ῢ',	'ΰ' => 'ΰ',	'ῤ' => 'ῤ',		'ῦ' => 'ῦ',
+		'ῧ' => 'ῧ',		'Ῠ' => 'ῠ',		'Ῡ' => 'ῡ',		'Ὺ' => 'ὺ',
+		'Ύ' => 'ύ',		'Ῥ' => 'ῥ',		'ῲ' => 'ὼι',	'ῳ' => 'ωι',
+		'ῴ' => 'ώι',	'ῶ' => 'ῶ',		'ῷ' => 'ῶι',	'Ὸ' => 'ὸ',
+		'Ό' => 'ό',		'Ὼ' => 'ὼ',		'Ώ' => 'ώ',		'ῼ' => 'ῳ',
+		'Ω' => 'ω',		'K' => 'k',		'Å' => 'å',		'Ⅎ' => 'ⅎ',
+		'Ⅰ' => 'ⅰ',		'Ⅱ' => 'ⅱ',		'Ⅲ' => 'ⅲ',		'Ⅳ' => 'ⅳ',
+		'Ⅴ' => 'ⅴ',		'Ⅵ' => 'ⅵ',		'Ⅶ' => 'ⅶ',		'Ⅷ' => 'ⅷ',
+		'Ⅸ' => 'ⅸ',		'Ⅹ' => 'ⅹ',		'Ⅺ' => 'ⅺ',		'Ⅻ' => 'ⅻ',
+		'Ⅼ' => 'ⅼ',		'Ⅽ' => 'ⅽ',		'Ⅾ' => 'ⅾ',		'Ⅿ' => 'ⅿ',
+		'Ↄ' => 'ↄ',		'Ⓐ' => 'ⓐ',		'Ⓑ' => 'ⓑ',		'Ⓒ' => 'ⓒ',
+		'Ⓓ' => 'ⓓ',		'Ⓔ' => 'ⓔ',		'Ⓕ' => 'ⓕ',		'Ⓖ' => 'ⓖ',
+		'Ⓗ' => 'ⓗ',		'Ⓘ' => 'ⓘ',		'Ⓙ' => 'ⓙ',		'Ⓚ' => 'ⓚ',
+		'Ⓛ' => 'ⓛ',		'Ⓜ' => 'ⓜ',		'Ⓝ' => 'ⓝ',		'Ⓞ' => 'ⓞ',
+		'Ⓟ' => 'ⓟ',		'Ⓠ' => 'ⓠ',		'Ⓡ' => 'ⓡ',		'Ⓢ' => 'ⓢ',
+		'Ⓣ' => 'ⓣ',		'Ⓤ' => 'ⓤ',		'Ⓥ' => 'ⓥ',		'Ⓦ' => 'ⓦ',
+		'Ⓧ' => 'ⓧ',		'Ⓨ' => 'ⓨ',		'Ⓩ' => 'ⓩ',		'Ⰰ' => 'ⰰ',
+		'Ⰱ' => 'ⰱ',		'Ⰲ' => 'ⰲ',		'Ⰳ' => 'ⰳ',		'Ⰴ' => 'ⰴ',
+		'Ⰵ' => 'ⰵ',		'Ⰶ' => 'ⰶ',		'Ⰷ' => 'ⰷ',		'Ⰸ' => 'ⰸ',
+		'Ⰹ' => 'ⰹ',		'Ⰺ' => 'ⰺ',		'Ⰻ' => 'ⰻ',		'Ⰼ' => 'ⰼ',
+		'Ⰽ' => 'ⰽ',		'Ⰾ' => 'ⰾ',		'Ⰿ' => 'ⰿ',		'Ⱀ' => 'ⱀ',
+		'Ⱁ' => 'ⱁ',		'Ⱂ' => 'ⱂ',		'Ⱃ' => 'ⱃ',		'Ⱄ' => 'ⱄ',
+		'Ⱅ' => 'ⱅ',		'Ⱆ' => 'ⱆ',		'Ⱇ' => 'ⱇ',		'Ⱈ' => 'ⱈ',
+		'Ⱉ' => 'ⱉ',		'Ⱊ' => 'ⱊ',		'Ⱋ' => 'ⱋ',		'Ⱌ' => 'ⱌ',
+		'Ⱍ' => 'ⱍ',		'Ⱎ' => 'ⱎ',		'Ⱏ' => 'ⱏ',		'Ⱐ' => 'ⱐ',
+		'Ⱑ' => 'ⱑ',		'Ⱒ' => 'ⱒ',		'Ⱓ' => 'ⱓ',		'Ⱔ' => 'ⱔ',
+		'Ⱕ' => 'ⱕ',		'Ⱖ' => 'ⱖ',		'Ⱗ' => 'ⱗ',		'Ⱘ' => 'ⱘ',
+		'Ⱙ' => 'ⱙ',		'Ⱚ' => 'ⱚ',		'Ⱛ' => 'ⱛ',		'Ⱜ' => 'ⱜ',
+		'Ⱝ' => 'ⱝ',		'Ⱞ' => 'ⱞ',		'Ⱡ' => 'ⱡ',		'Ɫ' => 'ɫ',
+		'Ᵽ' => 'ᵽ',		'Ɽ' => 'ɽ',		'Ⱨ' => 'ⱨ',		'Ⱪ' => 'ⱪ',
+		'Ⱬ' => 'ⱬ',		'Ⱶ' => 'ⱶ',		'Ⲁ' => 'ⲁ',		'Ⲃ' => 'ⲃ',
+		'Ⲅ' => 'ⲅ',		'Ⲇ' => 'ⲇ',		'Ⲉ' => 'ⲉ',		'Ⲋ' => 'ⲋ',
+		'Ⲍ' => 'ⲍ',		'Ⲏ' => 'ⲏ',		'Ⲑ' => 'ⲑ',		'Ⲓ' => 'ⲓ',
+		'Ⲕ' => 'ⲕ',		'Ⲗ' => 'ⲗ',		'Ⲙ' => 'ⲙ',		'Ⲛ' => 'ⲛ',
+		'Ⲝ' => 'ⲝ',		'Ⲟ' => 'ⲟ',		'Ⲡ' => 'ⲡ',		'Ⲣ' => 'ⲣ',
+		'Ⲥ' => 'ⲥ',		'Ⲧ' => 'ⲧ',		'Ⲩ' => 'ⲩ',		'Ⲫ' => 'ⲫ',
+		'Ⲭ' => 'ⲭ',		'Ⲯ' => 'ⲯ',		'Ⲱ' => 'ⲱ',		'Ⲳ' => 'ⲳ',
+		'Ⲵ' => 'ⲵ',		'Ⲷ' => 'ⲷ',		'Ⲹ' => 'ⲹ',		'Ⲻ' => 'ⲻ',
+		'Ⲽ' => 'ⲽ',		'Ⲿ' => 'ⲿ',		'Ⳁ' => 'ⳁ',		'Ⳃ' => 'ⳃ',
+		'Ⳅ' => 'ⳅ',		'Ⳇ' => 'ⳇ',		'Ⳉ' => 'ⳉ',		'Ⳋ' => 'ⳋ',
+		'Ⳍ' => 'ⳍ',		'Ⳏ' => 'ⳏ',		'Ⳑ' => 'ⳑ',		'Ⳓ' => 'ⳓ',
+		'Ⳕ' => 'ⳕ',		'Ⳗ' => 'ⳗ',		'Ⳙ' => 'ⳙ',		'Ⳛ' => 'ⳛ',
+		'Ⳝ' => 'ⳝ',		'Ⳟ' => 'ⳟ',		'Ⳡ' => 'ⳡ',		'Ⳣ' => 'ⳣ',
+		'ff' => 'ff',	'fi' => 'fi',	'fl' => 'fl',	'ffi' => 'ffi',
+		'ffl' => 'ffl',	'ſt' => 'st',	'st' => 'st',	'ﬓ' => 'մն',
+		'ﬔ' => 'մե',	'ﬕ' => 'մի',	'ﬖ' => 'վն',	'ﬗ' => 'մխ',
+		'A' => 'a',		'B' => 'b',		'C' => 'c',		'D' => 'd',
+		'E' => 'e',		'F' => 'f',		'G' => 'g',		'H' => 'h',
+		'I' => 'i',		'J' => 'j',		'K' => 'k',		'L' => 'l',
+		'M' => 'm',	'N' => 'n',		'O' => 'o',		'P' => 'p',
+		'Q' => 'q',		'R' => 'r',		'S' => 's',		'T' => 't',
+		'U' => 'u',		'V' => 'v',		'W' => 'w',	'X' => 'x',
+		'Y' => 'y',		'Z' => 'z',		'𐐀' => '𐐨',	'𐐁' => '𐐩',
+		'𐐂' => '𐐪',	'𐐃' => '𐐫',	'𐐄' => '𐐬',	'𐐅' => '𐐭',
+		'𐐆' => '𐐮',	'𐐇' => '𐐯',	'𐐈' => '𐐰',	'𐐉' => '𐐱',
+		'𐐊' => '𐐲',	'𐐋' => '𐐳',	'𐐌' => '𐐴',	'𐐍' => '𐐵',
+		'𐐎' => '𐐶',	'𐐏' => '𐐷',	'𐐐' => '𐐸',	'𐐑' => '𐐹',
+		'𐐒' => '𐐺',	'𐐓' => '𐐻',	'𐐔' => '𐐼',	'𐐕' => '𐐽',
+		'𐐖' => '𐐾',	'𐐗' => '𐐿',	'𐐘' => '𐑀',	'𐐙' => '𐑁',
+		'𐐚' => '𐑂',	'𐐛' => '𐑃',	'𐐜' => '𐑄',	'𐐝' => '𐑅',
+		'𐐞' => '𐑆',	'𐐟' => '𐑇',	'𐐠' => '𐑈',	'𐐡' => '𐑉',
+		'𐐢' => '𐑊',	'𐐣' => '𐑋',	'𐐤' => '𐑌',	'𐐥' => '𐑍',
+		'𐑎' => '𐐦',	'𐑏' => '𐐧',
 	);
 
 	return strtr($string, $case_folding);
@@ -299,253 +299,253 @@ function utf8_strtoupper($string)
 		'm' => 'M',		'n' => 'N',		'o' => 'O',		'p' => 'P',
 		'q' => 'Q',		'r' => 'R',		's' => 'S',		't' => 'T',
 		'u' => 'U',		'v' => 'V',		'w' => 'W',		'x' => 'X',
-		'y' => 'Y',		'z' => 'Z',		'μ' => 'µ',		'à' => 'À',
-		'á' => '�',		'â' => 'Â',		'ã' => 'Ã',		'ä' => 'Ä',
-		'å' => 'Å',		'æ' => 'Æ',		'ç' => 'Ç',		'è' => 'È',
-		'é' => 'É',		'ê' => 'Ê',		'ë' => 'Ë',		'ì' => 'Ì',
-		'í' => '�',		'î' => 'Î',		'ï' => '�',		'ð' => '�',
-		'ñ' => 'Ñ',		'ò' => 'Ò',		'ó' => 'Ó',		'ô' => 'Ô',
-		'õ' => 'Õ',		'ö' => 'Ö',		'ø' => 'Ø',		'ù' => 'Ù',
-		'ú' => 'Ú',		'û' => 'Û',		'ü' => 'Ü',		'ý' => '�',
-		'þ' => 'Þ',		'ss' => 'ß',	'�' => 'Ā',		'ă' => 'Ă',
-		'ą' => 'Ą',		'ć' => 'Ć',		'ĉ' => 'Ĉ',		'ċ' => 'Ċ',
-		'�' => 'Č',		'�' => 'Ď',		'đ' => '�',		'ē' => 'Ē',
-		'ĕ' => 'Ĕ',		'ė' => 'Ė',		'ę' => 'Ę',		'ě' => 'Ě',
-		'�' => 'Ĝ',		'ğ' => 'Ğ',		'ġ' => 'Ġ',		'ģ' => 'Ģ',
-		'ĥ' => 'Ĥ',		'ħ' => 'Ħ',		'ĩ' => 'Ĩ',		'ī' => 'Ī',
-		'ĭ' => 'Ĭ',		'į' => 'Į',		'i̇' => 'İ',		'ij' => 'IJ',
-		'ĵ' => 'Ĵ',		'ķ' => 'Ķ',		'ĺ' => 'Ĺ',		'ļ' => 'Ļ',
-		'ľ' => 'Ľ',		'ŀ' => 'Ŀ',		'ł' => '�',		'ń' => 'Ń',
-		'ņ' => 'Ņ',		'ň' => 'Ň',		'ʼn' => 'ʼn',	'ŋ' => 'Ŋ',
-		'�' => 'Ō',		'�' => 'Ŏ',		'ő' => '�',		'œ' => 'Œ',
-		'ŕ' => 'Ŕ',		'ŗ' => 'Ŗ',		'ř' => 'Ř',		'ś' => 'Ś',
-		'�' => 'Ŝ',		'ş' => 'Ş',		'š' => 'Š',		'ţ' => 'Ţ',
-		'ť' => 'Ť',		'ŧ' => 'Ŧ',		'ũ' => 'Ũ',		'ū' => 'Ū',
-		'ŭ' => 'Ŭ',		'ů' => 'Ů',		'ű' => 'Ű',		'ų' => 'Ų',
-		'ŵ' => 'Ŵ',		'ŷ' => 'Ŷ',		'ÿ' => 'Ÿ',		'ź' => 'Ź',
-		'ż' => 'Ż',		'ž' => 'Ž',		's' => 'ſ',		'ɓ' => '�',
-		'ƃ' => 'Ƃ',		'ƅ' => 'Ƅ',		'ɔ' => 'Ɔ',		'ƈ' => 'Ƈ',
-		'ɖ' => 'Ɖ',		'ɗ' => 'Ɗ',		'ƌ' => 'Ƌ',		'�' => 'Ǝ',
-		'ə' => '�',		'ɛ' => '�',		'ƒ' => 'Ƒ',		'ɠ' => 'Ɠ',
-		'ɣ' => 'Ɣ',		'ɩ' => 'Ɩ',		'ɨ' => 'Ɨ',		'ƙ' => 'Ƙ',
-		'ɯ' => 'Ɯ',		'ɲ' => '�',		'ɵ' => 'Ɵ',		'ơ' => 'Ơ',
-		'ƣ' => 'Ƣ',		'ƥ' => 'Ƥ',		'ʀ' => 'Ʀ',		'ƨ' => 'Ƨ',
-		'ʃ' => 'Ʃ',		'ƭ' => 'Ƭ',		'ʈ' => 'Ʈ',		'ư' => 'Ư',
-		'ʊ' => 'Ʊ',		'ʋ' => 'Ʋ',		'ƴ' => 'Ƴ',		'ƶ' => 'Ƶ',
-		'ʒ' => 'Ʒ',		'ƹ' => 'Ƹ',		'ƽ' => 'Ƽ',		'dž' => 'DŽ',
-		'dž' => 'Dž',		'lj' => 'LJ',		'lj' => 'Lj',		'nj' => 'NJ',
-		'nj' => 'Nj',		'ǎ' => '�',		'�' => '�',		'ǒ' => 'Ǒ',
-		'ǔ' => 'Ǔ',		'ǖ' => 'Ǖ',		'ǘ' => 'Ǘ',		'ǚ' => 'Ǚ',
-		'ǜ' => 'Ǜ',		'ǟ' => 'Ǟ',		'ǡ' => 'Ǡ',		'ǣ' => 'Ǣ',
-		'ǥ' => 'Ǥ',		'ǧ' => 'Ǧ',		'ǩ' => 'Ǩ',		'ǫ' => 'Ǫ',
-		'ǭ' => 'Ǭ',		'ǯ' => 'Ǯ',		'ǰ' => 'ǰ',		'dz' => 'DZ',
-		'dz' => 'Dz',		'ǵ' => 'Ǵ',		'ƕ' => 'Ƕ',		'ƿ' => 'Ƿ',
-		'ǹ' => 'Ǹ',		'ǻ' => 'Ǻ',		'ǽ' => 'Ǽ',		'ǿ' => 'Ǿ',
-		'�' => 'Ȁ',		'ȃ' => 'Ȃ',		'ȅ' => 'Ȅ',		'ȇ' => 'Ȇ',
-		'ȉ' => 'Ȉ',		'ȋ' => 'Ȋ',		'�' => 'Ȍ',		'�' => 'Ȏ',
-		'ȑ' => '�',		'ȓ' => 'Ȓ',		'ȕ' => 'Ȕ',		'ȗ' => 'Ȗ',
-		'ș' => 'Ș',		'ț' => 'Ț',		'�' => 'Ȝ',		'ȟ' => 'Ȟ',
-		'ƞ' => 'Ƞ',		'ȣ' => 'Ȣ',		'ȥ' => 'Ȥ',		'ȧ' => 'Ȧ',
-		'ȩ' => 'Ȩ',		'ȫ' => 'Ȫ',		'ȭ' => 'Ȭ',		'ȯ' => 'Ȯ',
-		'ȱ' => 'Ȱ',		'ȳ' => 'Ȳ',		'ⱥ' => 'Ⱥ',		'ȼ' => 'Ȼ',
-		'ƚ' => 'Ƚ',		'ⱦ' => 'Ⱦ',		'ɂ' => '�',		'ƀ' => 'Ƀ',
-		'ʉ' => 'Ʉ',		'ʌ' => 'Ʌ',		'ɇ' => 'Ɇ',		'ɉ' => 'Ɉ',
-		'ɋ' => 'Ɋ',		'�' => 'Ɍ',		'�' => 'Ɏ',		'ι' => 'ͅ',
-		'ά' => 'Ά',		'έ' => 'Έ',		'ή' => 'Ή',		'ί' => 'Ί',
-		'ό' => 'Ό',		'�' => 'Ύ',		'ώ' => '�',		'ϊ�' => '�',
-		'α' => 'Α',		'β' => 'Β',		'γ' => 'Γ',		'δ' => 'Δ',
-		'ε' => 'Ε',		'ζ' => 'Ζ',		'η' => 'Η',		'θ' => 'Θ',
-		'ι' => 'Ι',		'κ' => 'Κ',		'λ' => 'Λ',		'μ' => 'Μ',
-		'ν' => '�',		'ξ' => 'Ξ',		'ο' => 'Ο',		'π' => 'Π',
-		'�' => 'Ρ',		'σ' => 'Σ',		'τ' => 'Τ',		'υ' => 'Υ',
-		'φ' => 'Φ',		'χ' => 'Χ',		'ψ' => 'Ψ',		'ω' => 'Ω',
-		'ϊ' => 'Ϊ',		'ϋ' => 'Ϋ',		'ϋ�' => 'ΰ',	'σ' => 'ς',
-		'β' => '�',		'θ' => 'ϑ',		'φ' => 'ϕ',		'π' => 'ϖ',
-		'ϙ' => 'Ϙ',		'ϛ' => 'Ϛ',		'�' => 'Ϝ',		'ϟ' => 'Ϟ',
-		'ϡ' => 'Ϡ',		'ϣ' => 'Ϣ',		'ϥ' => 'Ϥ',		'ϧ' => 'Ϧ',
-		'ϩ' => 'Ϩ',		'ϫ' => 'Ϫ',		'ϭ' => 'Ϭ',		'ϯ' => 'Ϯ',
-		'κ' => 'ϰ',		'�' => 'ϱ',		'θ' => 'ϴ',		'ε' => 'ϵ',
-		'ϸ' => 'Ϸ',		'ϲ' => 'Ϲ',		'ϻ' => 'Ϻ',		'ͻ' => 'Ͻ',
-		'ͼ' => 'Ͼ',		'ͽ' => 'Ͽ',		'�' => 'Ѐ',		'ё' => '�',
-		'ђ' => 'Ђ',		'ѓ' => 'Ѓ',		'є' => 'Є',		'ѕ' => 'Ѕ',
-		'і' => 'І',		'ї' => 'Ї',		'ј' => 'Ј',		'љ' => 'Љ',
-		'њ' => 'Њ',		'ћ' => 'Ћ',		'ќ' => 'Ќ',		'�' => '�',
-		'ў' => 'Ў',		'џ' => '�',		'а' => '�',		'б' => 'Б',
-		'в' => 'В',		'г' => 'Г',		'д' => 'Д',		'е' => 'Е',
-		'ж' => 'Ж',		'з' => 'З',		'и' => 'И',		'й' => 'Й',
-		'к' => 'К',		'л' => 'Л',		'м' => 'М',		'н' => '�',
-		'о' => 'О',		'п' => 'П',		'р' => 'Р',		'�' => 'С',
-		'т' => 'Т',		'у' => 'У',		'ф' => 'Ф',		'х' => 'Х',
-		'ц' => 'Ц',		'ч' => 'Ч',		'ш' => 'Ш',		'щ' => 'Щ',
-		'ъ' => 'Ъ',		'ы' => 'Ы',		'ь' => 'Ь',		'�' => 'Э',
-		'ю' => 'Ю',		'�' => 'Я',		'ѡ' => 'Ѡ',		'ѣ' => 'Ѣ',
-		'ѥ' => 'Ѥ',		'ѧ' => 'Ѧ',		'ѩ' => 'Ѩ',		'ѫ' => 'Ѫ',
-		'ѭ' => 'Ѭ',		'ѯ' => 'Ѯ',		'ѱ' => 'Ѱ',		'ѳ' => 'Ѳ',
-		'ѵ' => 'Ѵ',		'ѷ' => 'Ѷ',		'ѹ' => 'Ѹ',		'ѻ' => 'Ѻ',
-		'ѽ' => 'Ѽ',		'ѿ' => 'Ѿ',		'�' => 'Ҁ',		'ҋ' => 'Ҋ',
-		'�' => 'Ҍ',		'�' => 'Ҏ',		'ґ' => '�',		'ғ' => 'Ғ',
-		'Ò•' => 'Ò”',		'Ò—' => 'Ò–',		'Ò™' => 'Ò˜',		'Ò›' => 'Òš',
-		'�' => 'Ҝ',		'ҟ' => 'Ҟ',		'ҡ' => 'Ҡ',		'ң' => 'Ң',
-		'Ò¥' => 'Ò¤',		'Ò§' => 'Ò¦',		'Ò©' => 'Ò¨',		'Ò«' => 'Òª',
-		'Ò­' => 'Ò¬',		'Ò¯' => 'Ò®',		'Ò±' => 'Ò°',		'Ò³' => 'Ò²',
-		'Òµ' => 'Ò´',		'Ò·' => 'Ò¶',		'Ò¹' => 'Ò¸',		'Ò»' => 'Òº',
-		'Ò½' => 'Ò¼',		'Ò¿' => 'Ò¾',		'Ó�' => 'Ó€',		'Ó‚' => 'Ó�',
-		'Ó„' => 'Óƒ',		'Ó†' => 'Ó…',		'Óˆ' => 'Ó‡',		'ÓŠ' => 'Ó‰',
-		'ӌ' => 'Ӌ',		'ӎ' => '�',		'ӑ' => '�',		'ӓ' => 'Ӓ',
-		'Ó•' => 'Ó”',		'Ó—' => 'Ó–',		'Ó™' => 'Ó˜',		'Ó›' => 'Óš',
-		'�' => 'Ӝ',		'ӟ' => 'Ӟ',		'ӡ' => 'Ӡ',		'ӣ' => 'Ӣ',
-		'Ó¥' => 'Ó¤',		'Ó§' => 'Ó¦',		'Ó©' => 'Ó¨',		'Ó«' => 'Óª',
-		'Ó­' => 'Ó¬',		'Ó¯' => 'Ó®',		'Ó±' => 'Ó°',		'Ó³' => 'Ó²',
-		'Óµ' => 'Ó´',		'Ó·' => 'Ó¶',		'Ó¹' => 'Ó¸',		'Ó»' => 'Óº',
-		'Ó½' => 'Ó¼',		'Ó¿' => 'Ó¾',		'Ô�' => 'Ô€',		'Ôƒ' => 'Ô‚',
-		'Ô…' => 'Ô„',		'Ô‡' => 'Ô†',		'Ô‰' => 'Ôˆ',		'Ô‹' => 'ÔŠ',
-		'�' => 'Ԍ',		'�' => 'Ԏ',		'ԑ' => '�',		'ԓ' => 'Ԓ',
-		'Õ¡' => 'Ô±',		'Õ¢' => 'Ô²',		'Õ£' => 'Ô³',		'Õ¤' => 'Ô´',
-		'Õ¥' => 'Ôµ',		'Õ¦' => 'Ô¶',		'Õ§' => 'Ô·',		'Õ¨' => 'Ô¸',
-		'Õ©' => 'Ô¹',		'Õª' => 'Ôº',		'Õ«' => 'Ô»',		'Õ¬' => 'Ô¼',
-		'Õ­' => 'Ô½',		'Õ®' => 'Ô¾',		'Õ¯' => 'Ô¿',		'Õ°' => 'Õ€',
-		'Õ±' => 'Õ�',		'Õ²' => 'Õ‚',		'Õ³' => 'Õƒ',		'Õ´' => 'Õ„',
-		'Õµ' => 'Õ…',		'Õ¶' => 'Õ†',		'Õ·' => 'Õ‡',		'Õ¸' => 'Õˆ',
-		'չ' => 'Չ',		'պ' => 'Պ',		'ջ' => 'Ջ',		'ռ' => 'Ռ',
-		'Õ½' => 'Õ�',		'Õ¾' => 'ÕŽ',		'Õ¿' => 'Õ�',		'Ö€' => 'Õ�',
-		'Ö�' => 'Õ‘',		'Ö‚' => 'Õ’',		'Öƒ' => 'Õ“',		'Ö„' => 'Õ”',
-		'Ö…' => 'Õ•',		'Ö†' => 'Õ–',		'Õ¥Ö‚' => 'Ö‡',		'â´€' => 'á‚ ',
-		'�' => 'Ⴁ',		'ⴂ' => 'Ⴂ',		'ⴃ' => 'Ⴃ',		'ⴄ' => 'Ⴄ',
-		'ⴅ' => 'Ⴅ',		'ⴆ' => 'Ⴆ',		'ⴇ' => 'Ⴇ',		'ⴈ' => 'Ⴈ',
-		'ⴉ' => 'Ⴉ',		'ⴊ' => 'Ⴊ',		'ⴋ' => 'Ⴋ',		'ⴌ' => 'Ⴌ',
-		'�' => 'Ⴍ',		'ⴎ' => 'Ⴎ',		'�' => 'Ⴏ',		'�' => 'Ⴐ',
-		'ⴑ' => 'Ⴑ',		'ⴒ' => 'Ⴒ',		'ⴓ' => 'Ⴓ',		'ⴔ' => 'Ⴔ',
-		'ⴕ' => 'Ⴕ',		'ⴖ' => 'Ⴖ',		'ⴗ' => 'Ⴗ',		'ⴘ' => 'Ⴘ',
-		'ⴙ' => 'Ⴙ',		'ⴚ' => 'Ⴚ',		'ⴛ' => 'Ⴛ',		'ⴜ' => 'Ⴜ',
-		'�' => 'Ⴝ',		'ⴞ' => 'Ⴞ',		'ⴟ' => 'Ⴟ',		'ⴠ' => 'Ⴠ',
-		'ⴡ' => '�',		'ⴢ' => 'Ⴢ',		'ⴣ' => 'Ⴣ',		'ⴤ' => 'Ⴤ',
-		'ⴥ' => 'Ⴥ',		'�' => 'Ḁ',		'ḃ' => 'Ḃ',		'ḅ' => 'Ḅ',
-		'ḇ' => 'Ḇ',		'ḉ' => 'Ḉ',		'ḋ' => 'Ḋ',		'�' => 'Ḍ',
-		'�' => 'Ḏ',		'ḑ' => '�',		'ḓ' => 'Ḓ',		'ḕ' => 'Ḕ',
-		'ḗ' => 'Ḗ',		'ḙ' => 'Ḙ',		'ḛ' => 'Ḛ',		'�' => 'Ḝ',
-		'ḟ' => 'Ḟ',		'ḡ' => 'Ḡ',		'ḣ' => 'Ḣ',		'ḥ' => 'Ḥ',
-		'ḧ' => 'Ḧ',		'ḩ' => 'Ḩ',		'ḫ' => 'Ḫ',		'ḭ' => 'Ḭ',
-		'ḯ' => 'Ḯ',		'ḱ' => 'Ḱ',		'ḳ' => 'Ḳ',		'ḵ' => 'Ḵ',
-		'ḷ' => 'Ḷ',		'ḹ' => 'Ḹ',		'ḻ' => 'Ḻ',		'ḽ' => 'Ḽ',
-		'ḿ' => 'Ḿ',		'�' => 'Ṁ',		'ṃ' => 'Ṃ',		'ṅ' => 'Ṅ',
-		'ṇ' => 'Ṇ',		'ṉ' => 'Ṉ',		'ṋ' => 'Ṋ',		'�' => 'Ṍ',
-		'�' => 'Ṏ',		'ṑ' => '�',		'ṓ' => 'Ṓ',		'ṕ' => 'Ṕ',
-		'ṗ' => 'Ṗ',		'ṙ' => 'Ṙ',		'ṛ' => 'Ṛ',		'�' => 'Ṝ',
-		'ṟ' => 'Ṟ',		'ṡ' => 'Ṡ',		'ṣ' => 'Ṣ',		'ṥ' => 'Ṥ',
-		'ṧ' => 'Ṧ',		'ṩ' => 'Ṩ',		'ṫ' => 'Ṫ',		'ṭ' => 'Ṭ',
-		'ṯ' => 'Ṯ',		'ṱ' => 'Ṱ',		'ṳ' => 'Ṳ',		'ṵ' => 'Ṵ',
-		'ṷ' => 'Ṷ',		'ṹ' => 'Ṹ',		'ṻ' => 'Ṻ',		'ṽ' => 'Ṽ',
-		'ṿ' => 'Ṿ',		'�' => 'Ẁ',		'ẃ' => 'Ẃ',		'ẅ' => 'Ẅ',
-		'ẇ' => 'Ẇ',		'ẉ' => 'Ẉ',		'ẋ' => 'Ẋ',		'�' => 'Ẍ',
-		'�' => 'Ẏ',		'ẑ' => '�',		'ẓ' => 'Ẓ',		'ẕ' => 'Ẕ',
-		'ẖ' => 'ẖ',		'ẗ' => 'ẗ',		'ẘ' => 'ẘ',		'ẙ' => 'ẙ',
-		'aʾ' => 'ẚ',	'ṡ' => 'ẛ',		'ạ' => 'Ạ',		'ả' => 'Ả',
-		'ấ' => 'Ấ',		'ầ' => 'Ầ',		'ẩ' => 'Ẩ',		'ẫ' => 'Ẫ',
-		'ậ' => 'Ậ',		'ắ' => 'Ắ',		'ằ' => 'Ằ',		'ẳ' => 'Ẳ',
-		'ẵ' => 'Ẵ',		'ặ' => 'Ặ',		'ẹ' => 'Ẹ',		'ẻ' => 'Ẻ',
-		'ẽ' => 'Ẽ',		'ế' => 'Ế',		'�' => 'Ề',		'ể' => 'Ể',
-		'ễ' => 'Ễ',		'ệ' => 'Ệ',		'ỉ' => 'Ỉ',		'ị' => 'Ị',
-		'�' => 'Ọ',		'�' => 'Ỏ',		'ố' => '�',		'ồ' => 'Ồ',
-		'ổ' => 'Ổ',		'ỗ' => 'Ỗ',		'ộ' => 'Ộ',		'ớ' => 'Ớ',
-		'�' => 'Ờ',		'ở' => 'Ở',		'ỡ' => 'Ỡ',		'ợ' => 'Ợ',
-		'ụ' => 'Ụ',		'ủ' => 'Ủ',		'ứ' => 'Ứ',		'ừ' => 'Ừ',
-		'ử' => 'Ử',		'ữ' => 'Ữ',		'ự' => 'Ự',		'ỳ' => 'Ỳ',
-		'ỵ' => 'Ỵ',		'ỷ' => 'Ỷ',		'ỹ' => 'Ỹ',		'ἀ' => 'Ἀ',
-		'�' => 'Ἁ',		'ἂ' => 'Ἂ',		'ἃ' => 'Ἃ',		'ἄ' => 'Ἄ',
-		'ἅ' => '�',		'ἆ' => 'Ἆ',		'ἇ' => '�',		'�' => 'Ἐ',
-		'ἑ' => 'Ἑ',		'ἒ' => 'Ἒ',		'ἓ' => 'Ἓ',		'ἔ' => 'Ἔ',
-		'ἕ' => '�',		'ἠ' => 'Ἠ',		'ἡ' => 'Ἡ',		'ἢ' => 'Ἢ',
-		'ἣ' => 'Ἣ',		'ἤ' => 'Ἤ',		'ἥ' => 'Ἥ',		'ἦ' => 'Ἦ',
-		'ἧ' => 'Ἧ',		'ἰ' => 'Ἰ',		'ἱ' => 'Ἱ',		'ἲ' => 'Ἲ',
-		'ἳ' => 'Ἳ',		'ἴ' => 'Ἴ',		'ἵ' => 'Ἵ',		'ἶ' => 'Ἶ',
-		'ἷ' => 'Ἷ',		'ὀ' => 'Ὀ',		'�' => 'Ὁ',		'ὂ' => 'Ὂ',
-		'ὃ' => 'Ὃ',		'ὄ' => 'Ὄ',		'ὅ' => '�',		'ὐ' => '�',
-		'ὒ' => 'ὒ',	'ὐ�' => 'ὔ',	'ὖ' => 'ὖ',		'ὑ' => 'Ὑ',
-		'ὓ' => 'Ὓ',		'ὕ' => '�',		'ὗ' => 'Ὗ',		'ὠ' => 'Ὠ',
-		'ὡ' => 'Ὡ',		'ὢ' => 'Ὢ',		'ὣ' => 'Ὣ',		'ὤ' => 'Ὤ',
-		'ὥ' => 'Ὥ',		'ὦ' => 'Ὦ',		'ὧ' => 'Ὧ',		'ἀι' => 'ᾀ',
-		'�ι' => '�',	'ἂι' => 'ᾂ',	'ἃι' => 'ᾃ',	'ἄι' => 'ᾄ',
-		'ἅι' => 'ᾅ',	'ἆι' => 'ᾆ',	'ἇι' => 'ᾇ',	'ᾀ' => 'ᾈ',
-		'�' => 'ᾉ',		'ᾂ' => 'ᾊ',		'ᾃ' => 'ᾋ',		'ᾄ' => 'ᾌ',
-		'ᾅ' => '�',		'ᾆ' => 'ᾎ',		'ᾇ' => '�',		'ἠι' => '�',
-		'ἡι' => 'ᾑ',	'ἢι' => 'ᾒ',	'ἣι' => 'ᾓ',	'ἤι' => 'ᾔ',
-		'ἥι' => 'ᾕ',	'ἦι' => 'ᾖ',	'ἧι' => 'ᾗ',	'�' => 'ᾘ',
-		'ᾑ' => 'ᾙ',		'ᾒ' => 'ᾚ',		'ᾓ' => 'ᾛ',		'ᾔ' => 'ᾜ',
-		'ᾕ' => '�',		'ᾖ' => 'ᾞ',		'ᾗ' => 'ᾟ',		'ὠι' => 'ᾠ',
-		'ὡι' => 'ᾡ',	'ὢι' => 'ᾢ',	'ὣι' => 'ᾣ',	'ὤι' => 'ᾤ',
-		'ὥι' => 'ᾥ',	'ὦι' => 'ᾦ',	'ὧι' => 'ᾧ',	'ᾠ' => 'ᾨ',
-		'ᾡ' => 'ᾩ',		'ᾢ' => 'ᾪ',		'ᾣ' => 'ᾫ',		'ᾤ' => 'ᾬ',
-		'ᾥ' => 'ᾭ',		'ᾦ' => 'ᾮ',		'ᾧ' => 'ᾯ',		'ὰι' => 'ᾲ',
-		'αι' => 'ᾳ',	'άι' => 'ᾴ',	'ᾶ' => 'ᾶ',		'ᾶι' => 'ᾷ',
-		'ᾰ' => 'Ᾰ',		'ᾱ' => 'Ᾱ',		'ὰ' => 'Ὰ',		'ά' => 'Ά',
-		'ᾳ' => 'ᾼ',		'ι' => 'ι',		'ὴι' => 'ῂ',	'ηι' => 'ῃ',
-		'ήι' => 'ῄ',	'ῆ' => 'ῆ',		'ῆι' => 'ῇ',	'ὲ' => 'Ὲ',
-		'έ' => 'Έ',		'ὴ' => 'Ὴ',		'ή' => 'Ή',		'ῃ' => 'ῌ',
-		'ῒ' => 'ῒ',	'ϊ�' => 'ΐ',	'ῖ' => 'ῖ',		'ῗ' => 'ῗ',
-		'�' => 'Ῐ',		'ῑ' => 'Ῑ',		'ὶ' => 'Ὶ',		'ί' => 'Ί',
-		'ῢ' => 'ῢ',	'ϋ�' => 'ΰ',	'�̓' => 'ῤ',		'ῦ' => 'ῦ',
-		'ῧ' => 'ῧ',		'ῠ' => 'Ῠ',		'ῡ' => 'Ῡ',		'ὺ' => 'Ὺ',
-		'ύ' => 'Ύ',		'ῥ' => 'Ῥ',		'ὼι' => 'ῲ',	'ωι' => 'ῳ',
-		'ώι' => 'ῴ',	'ῶ' => 'ῶ',		'ῶι' => 'ῷ',	'ὸ' => 'Ὸ',
-		'ό' => 'Ό',		'ὼ' => 'Ὼ',		'ώ' => 'Ώ',		'ῳ' => 'ῼ',
-		'ω' => 'Ω',		'k' => 'K',		'å' => 'Å',		'ⅎ' => 'Ⅎ',
-		'â…°' => 'â… ',		'â…±' => 'â…¡',		'â…²' => 'â…¢',		'â…³' => 'â…£',
-		'â…´' => 'â…¤',		'â…µ' => 'â…¥',		'â…¶' => 'â…¦',		'â…·' => 'â…§',
-		'â…¸' => 'â…¨',		'â…¹' => 'â…©',		'â…º' => 'â…ª',		'â…»' => 'â…«',
-		'â…¼' => 'â…¬',		'â…½' => 'â…­',		'â…¾' => 'â…®',		'â…¿' => 'â…¯',
-		'ↄ' => 'Ↄ',		'�' => 'Ⓐ',		'ⓑ' => 'Ⓑ',		'ⓒ' => 'Ⓒ',
-		'â““' => 'â’¹',		'â“”' => 'â’º',		'â“•' => 'â’»',		'â“–' => 'â’¼',
-		'ⓗ' => 'Ⓗ',		'ⓘ' => 'Ⓘ',		'ⓙ' => 'Ⓙ',		'ⓚ' => 'Ⓚ',
-		'ⓛ' => '�',		'ⓜ' => 'Ⓜ',		'�' => 'Ⓝ',		'ⓞ' => 'Ⓞ',
-		'ⓟ' => 'Ⓟ',		'ⓠ' => 'Ⓠ',		'ⓡ' => 'Ⓡ',		'ⓢ' => 'Ⓢ',
-		'ⓣ' => 'Ⓣ',		'ⓤ' => 'Ⓤ',		'ⓥ' => 'Ⓥ',		'ⓦ' => 'Ⓦ',
-		'ⓧ' => '�',		'ⓨ' => 'Ⓨ',		'ⓩ' => '�',		'ⰰ' => 'Ⰰ',
-		'â°±' => 'â°�',		'â°²' => 'â°‚',		'â°³' => 'â°ƒ',		'â°´' => 'â°„',
-		'â°µ' => 'â°…',		'â°¶' => 'â°†',		'â°·' => 'â°‡',		'â°¸' => 'â°ˆ',
-		'ⰹ' => 'Ⰹ',		'ⰺ' => 'Ⰺ',		'ⰻ' => 'Ⰻ',		'ⰼ' => 'Ⰼ',
-		'â°½' => 'â°�',		'â°¾' => 'â°Ž',		'â°¿' => 'â°�',		'â±€' => 'â°�',
-		'�' => 'Ⱁ',		'ⱂ' => 'Ⱂ',		'ⱃ' => 'Ⱃ',		'ⱄ' => 'Ⱄ',
-		'ⱅ' => 'Ⱅ',		'ⱆ' => 'Ⱆ',		'ⱇ' => 'Ⱇ',		'ⱈ' => 'Ⱈ',
-		'ⱉ' => 'Ⱉ',		'ⱊ' => 'Ⱊ',		'ⱋ' => 'Ⱋ',		'ⱌ' => 'Ⱌ',
-		'�' => '�',		'ⱎ' => 'Ⱎ',		'�' => 'Ⱏ',		'�' => 'Ⱐ',
-		'ⱑ' => 'Ⱑ',		'ⱒ' => 'Ⱒ',		'ⱓ' => 'Ⱓ',		'ⱔ' => 'Ⱔ',
-		'ⱕ' => 'Ⱕ',		'ⱖ' => 'Ⱖ',		'ⱗ' => 'Ⱗ',		'ⱘ' => 'Ⱘ',
-		'ⱙ' => 'Ⱙ',		'ⱚ' => 'Ⱚ',		'ⱛ' => 'Ⱛ',		'ⱜ' => 'Ⱜ',
-		'�' => 'Ⱝ',		'ⱞ' => 'Ⱞ',		'ⱡ' => 'Ⱡ',		'ɫ' => 'Ɫ',
-		'ᵽ' => 'Ᵽ',		'ɽ' => 'Ɽ',		'ⱨ' => 'Ⱨ',		'ⱪ' => 'Ⱪ',
-		'ⱬ' => 'Ⱬ',		'ⱶ' => 'Ⱶ',		'�' => 'Ⲁ',		'ⲃ' => 'Ⲃ',
-		'ⲅ' => 'Ⲅ',		'ⲇ' => 'Ⲇ',		'ⲉ' => 'Ⲉ',		'ⲋ' => 'Ⲋ',
-		'�' => 'Ⲍ',		'�' => 'Ⲏ',		'ⲑ' => '�',		'ⲓ' => 'Ⲓ',
-		'ⲕ' => 'Ⲕ',		'ⲗ' => 'Ⲗ',		'ⲙ' => 'Ⲙ',		'ⲛ' => 'Ⲛ',
-		'�' => 'Ⲝ',		'ⲟ' => 'Ⲟ',		'ⲡ' => 'Ⲡ',		'ⲣ' => 'Ⲣ',
-		'ⲥ' => 'Ⲥ',		'ⲧ' => 'Ⲧ',		'ⲩ' => 'Ⲩ',		'ⲫ' => 'Ⲫ',
-		'ⲭ' => 'Ⲭ',		'ⲯ' => 'Ⲯ',		'ⲱ' => 'Ⲱ',		'ⲳ' => 'Ⲳ',
-		'ⲵ' => 'Ⲵ',		'ⲷ' => 'Ⲷ',		'ⲹ' => 'Ⲹ',		'ⲻ' => 'Ⲻ',
-		'ⲽ' => 'Ⲽ',		'ⲿ' => 'Ⲿ',		'�' => 'Ⳁ',		'ⳃ' => 'Ⳃ',
-		'ⳅ' => 'Ⳅ',		'ⳇ' => 'Ⳇ',		'ⳉ' => 'Ⳉ',		'ⳋ' => 'Ⳋ',
-		'�' => 'Ⳍ',		'�' => 'Ⳏ',		'ⳑ' => '�',		'ⳓ' => 'Ⳓ',
-		'ⳕ' => 'Ⳕ',		'ⳗ' => 'Ⳗ',		'ⳙ' => 'Ⳙ',		'ⳛ' => 'Ⳛ',
-		'�' => 'Ⳝ',		'ⳟ' => 'Ⳟ',		'ⳡ' => 'Ⳡ',		'ⳣ' => 'Ⳣ',
-		'ff' => 'ff',	'fi' => '�',	'fl' => 'fl',	'ffi' => 'ffi',
-		'ffl' => 'ffl',	'st' => 'ſt',	'st' => 'st',	'մն' => 'ﬓ',
-		'մե' => 'ﬔ',	'մի' => 'ﬕ',	'վն' => 'ﬖ',	'մխ' => 'ﬗ',
-		'�' => 'A',		'b' => 'B',		'c' => 'C',		'd' => 'D',
-		'e' => 'E',		'f' => 'F',		'g' => 'G',		'h' => 'H',
-		'i' => 'I',		'j' => 'J',		'k' => 'K',		'l' => 'L',
-		'�' => 'M',	'n' => 'N',		'�' => 'O',		'�' => 'P',
-		'q' => 'Q',		'r' => 'R',		's' => 'S',		't' => 'T',
-		'u' => 'U',		'v' => 'V',		'w' => 'W',	'x' => 'X',
-		'y' => 'Y',		'z' => 'Z',		'�' => '�',	'�' => '�',
-		'�' => '�',	'�' => '�',	'�' => '�',	'�' => '�',
-		'�' => '�',	'�' => '�',	'�' => '�',	'�' => '�',
-		'�' => '�',	'�' => '�',	'�' => '�',	'�' => '�',
-		'�' => '�',	'�' => '�',	'�' => '�',	'�' => '�',
-		'�' => '�',	'�' => '�',	'�' => '�',	'�' => '�',
-		'�' => '�',	'�' => '�',	'�' => '�',	'�' => '�',
-		'�' => '�',	'�' => '�',	'�' => '�',	'�' => '�',
-		'�' => '�',	'�' => '�',	'�' => '�',	'�' => '�',
-		'�' => '�',	'�' => '�',	'�' => '�',	'�' => '�',
-		'�' => '�',	'�' => '�',
+		'y' => 'Y',		'z' => 'Z',		'μ' => 'µ',		'à' => 'À',
+		'á' => 'Á',		'â' => 'Â',		'ã' => 'Ã',		'ä' => 'Ä',
+		'å' => 'Å',		'æ' => 'Æ',		'ç' => 'Ç',		'è' => 'È',
+		'é' => 'É',		'ê' => 'Ê',		'ë' => 'Ë',		'ì' => 'Ì',
+		'í' => 'Í',		'î' => 'Î',		'ï' => 'Ï',		'ð' => 'Ð',
+		'ñ' => 'Ñ',		'ò' => 'Ò',		'ó' => 'Ó',		'ô' => 'Ô',
+		'õ' => 'Õ',		'ö' => 'Ö',		'ø' => 'Ø',		'ù' => 'Ù',
+		'ú' => 'Ú',		'û' => 'Û',		'ü' => 'Ü',		'ý' => 'Ý',
+		'þ' => 'Þ',		'ss' => 'ß',	'ā' => 'Ā',		'ă' => 'Ă',
+		'ą' => 'Ą',		'ć' => 'Ć',		'ĉ' => 'Ĉ',		'ċ' => 'Ċ',
+		'č' => 'Č',		'ď' => 'Ď',		'đ' => 'Đ',		'ē' => 'Ē',
+		'ĕ' => 'Ĕ',		'ė' => 'Ė',		'ę' => 'Ę',		'ě' => 'Ě',
+		'ĝ' => 'Ĝ',		'ğ' => 'Ğ',		'ġ' => 'Ġ',		'ģ' => 'Ģ',
+		'ĥ' => 'Ĥ',		'ħ' => 'Ħ',		'ĩ' => 'Ĩ',		'ī' => 'Ī',
+		'ĭ' => 'Ĭ',		'į' => 'Į',		'i̇' => 'İ',		'ij' => 'IJ',
+		'ĵ' => 'Ĵ',		'ķ' => 'Ķ',		'ĺ' => 'Ĺ',		'ļ' => 'Ļ',
+		'ľ' => 'Ľ',		'ŀ' => 'Ŀ',		'ł' => 'Ł',		'ń' => 'Ń',
+		'ņ' => 'Ņ',		'ň' => 'Ň',		'ʼn' => 'ʼn',	'ŋ' => 'Ŋ',
+		'ō' => 'Ō',		'ŏ' => 'Ŏ',		'ő' => 'Ő',		'œ' => 'Œ',
+		'ŕ' => 'Ŕ',		'ŗ' => 'Ŗ',		'ř' => 'Ř',		'ś' => 'Ś',
+		'ŝ' => 'Ŝ',		'ş' => 'Ş',		'š' => 'Š',		'ţ' => 'Ţ',
+		'ť' => 'Ť',		'ŧ' => 'Ŧ',		'ũ' => 'Ũ',		'ū' => 'Ū',
+		'ŭ' => 'Ŭ',		'ů' => 'Ů',		'ű' => 'Ű',		'ų' => 'Ų',
+		'ŵ' => 'Ŵ',		'ŷ' => 'Ŷ',		'ÿ' => 'Ÿ',		'ź' => 'Ź',
+		'ż' => 'Ż',		'ž' => 'Ž',		's' => 'ſ',		'ɓ' => 'Ɓ',
+		'ƃ' => 'Ƃ',		'ƅ' => 'Ƅ',		'ɔ' => 'Ɔ',		'ƈ' => 'Ƈ',
+		'ɖ' => 'Ɖ',		'ɗ' => 'Ɗ',		'ƌ' => 'Ƌ',		'ǝ' => 'Ǝ',
+		'ə' => 'Ə',		'ɛ' => 'Ɛ',		'ƒ' => 'Ƒ',		'ɠ' => 'Ɠ',
+		'ɣ' => 'Ɣ',		'ɩ' => 'Ɩ',		'ɨ' => 'Ɨ',		'ƙ' => 'Ƙ',
+		'ɯ' => 'Ɯ',		'ɲ' => 'Ɲ',		'ɵ' => 'Ɵ',		'ơ' => 'Ơ',
+		'ƣ' => 'Ƣ',		'ƥ' => 'Ƥ',		'ʀ' => 'Ʀ',		'ƨ' => 'Ƨ',
+		'ʃ' => 'Ʃ',		'ƭ' => 'Ƭ',		'ʈ' => 'Ʈ',		'ư' => 'Ư',
+		'ʊ' => 'Ʊ',		'ʋ' => 'Ʋ',		'ƴ' => 'Ƴ',		'ƶ' => 'Ƶ',
+		'ʒ' => 'Ʒ',		'ƹ' => 'Ƹ',		'ƽ' => 'Ƽ',		'dž' => 'DŽ',
+		'dž' => 'Dž',		'lj' => 'LJ',		'lj' => 'Lj',		'nj' => 'NJ',
+		'nj' => 'Nj',		'ǎ' => 'Ǎ',		'ǐ' => 'Ǐ',		'ǒ' => 'Ǒ',
+		'ǔ' => 'Ǔ',		'ǖ' => 'Ǖ',		'ǘ' => 'Ǘ',		'ǚ' => 'Ǚ',
+		'ǜ' => 'Ǜ',		'ǟ' => 'Ǟ',		'ǡ' => 'Ǡ',		'ǣ' => 'Ǣ',
+		'ǥ' => 'Ǥ',		'ǧ' => 'Ǧ',		'ǩ' => 'Ǩ',		'ǫ' => 'Ǫ',
+		'ǭ' => 'Ǭ',		'ǯ' => 'Ǯ',		'ǰ' => 'ǰ',		'dz' => 'DZ',
+		'dz' => 'Dz',		'ǵ' => 'Ǵ',		'ƕ' => 'Ƕ',		'ƿ' => 'Ƿ',
+		'ǹ' => 'Ǹ',		'ǻ' => 'Ǻ',		'ǽ' => 'Ǽ',		'ǿ' => 'Ǿ',
+		'ȁ' => 'Ȁ',		'ȃ' => 'Ȃ',		'ȅ' => 'Ȅ',		'ȇ' => 'Ȇ',
+		'ȉ' => 'Ȉ',		'ȋ' => 'Ȋ',		'ȍ' => 'Ȍ',		'ȏ' => 'Ȏ',
+		'ȑ' => 'Ȑ',		'ȓ' => 'Ȓ',		'ȕ' => 'Ȕ',		'ȗ' => 'Ȗ',
+		'ș' => 'Ș',		'ț' => 'Ț',		'ȝ' => 'Ȝ',		'ȟ' => 'Ȟ',
+		'ƞ' => 'Ƞ',		'ȣ' => 'Ȣ',		'ȥ' => 'Ȥ',		'ȧ' => 'Ȧ',
+		'ȩ' => 'Ȩ',		'ȫ' => 'Ȫ',		'ȭ' => 'Ȭ',		'ȯ' => 'Ȯ',
+		'ȱ' => 'Ȱ',		'ȳ' => 'Ȳ',		'ⱥ' => 'Ⱥ',		'ȼ' => 'Ȼ',
+		'ƚ' => 'Ƚ',		'ⱦ' => 'Ⱦ',		'ɂ' => 'Ɂ',		'ƀ' => 'Ƀ',
+		'ʉ' => 'Ʉ',		'ʌ' => 'Ʌ',		'ɇ' => 'Ɇ',		'ɉ' => 'Ɉ',
+		'ɋ' => 'Ɋ',		'ɍ' => 'Ɍ',		'ɏ' => 'Ɏ',		'ι' => 'ͅ',
+		'ά' => 'Ά',		'έ' => 'Έ',		'ή' => 'Ή',		'ί' => 'Ί',
+		'ό' => 'Ό',		'ύ' => 'Ύ',		'ώ' => 'Ώ',		'ΐ' => 'ΐ',
+		'α' => 'Α',		'β' => 'Β',		'γ' => 'Γ',		'δ' => 'Δ',
+		'ε' => 'Ε',		'ζ' => 'Ζ',		'η' => 'Η',		'θ' => 'Θ',
+		'ι' => 'Ι',		'κ' => 'Κ',		'λ' => 'Λ',		'μ' => 'Μ',
+		'ν' => 'Ν',		'ξ' => 'Ξ',		'ο' => 'Ο',		'π' => 'Π',
+		'ρ' => 'Ρ',		'σ' => 'Σ',		'τ' => 'Τ',		'υ' => 'Υ',
+		'φ' => 'Φ',		'χ' => 'Χ',		'ψ' => 'Ψ',		'ω' => 'Ω',
+		'ϊ' => 'Ϊ',		'ϋ' => 'Ϋ',		'ΰ' => 'ΰ',	'σ' => 'ς',
+		'β' => 'ϐ',		'θ' => 'ϑ',		'φ' => 'ϕ',		'π' => 'ϖ',
+		'ϙ' => 'Ϙ',		'ϛ' => 'Ϛ',		'ϝ' => 'Ϝ',		'ϟ' => 'Ϟ',
+		'ϡ' => 'Ϡ',		'ϣ' => 'Ϣ',		'ϥ' => 'Ϥ',		'ϧ' => 'Ϧ',
+		'ϩ' => 'Ϩ',		'ϫ' => 'Ϫ',		'ϭ' => 'Ϭ',		'ϯ' => 'Ϯ',
+		'κ' => 'ϰ',		'ρ' => 'ϱ',		'θ' => 'ϴ',		'ε' => 'ϵ',
+		'ϸ' => 'Ϸ',		'ϲ' => 'Ϲ',		'ϻ' => 'Ϻ',		'ͻ' => 'Ͻ',
+		'ͼ' => 'Ͼ',		'ͽ' => 'Ͽ',		'ѐ' => 'Ѐ',		'ё' => 'Ё',
+		'ђ' => 'Ђ',		'ѓ' => 'Ѓ',		'є' => 'Є',		'ѕ' => 'Ѕ',
+		'і' => 'І',		'ї' => 'Ї',		'ј' => 'Ј',		'љ' => 'Љ',
+		'њ' => 'Њ',		'ћ' => 'Ћ',		'ќ' => 'Ќ',		'ѝ' => 'Ѝ',
+		'ў' => 'Ў',		'џ' => 'Џ',		'а' => 'А',		'б' => 'Б',
+		'в' => 'В',		'г' => 'Г',		'д' => 'Д',		'е' => 'Е',
+		'ж' => 'Ж',		'з' => 'З',		'и' => 'И',		'й' => 'Й',
+		'к' => 'К',		'л' => 'Л',		'м' => 'М',		'н' => 'Н',
+		'о' => 'О',		'п' => 'П',		'р' => 'Р',		'с' => 'С',
+		'т' => 'Т',		'у' => 'У',		'ф' => 'Ф',		'х' => 'Х',
+		'ц' => 'Ц',		'ч' => 'Ч',		'ш' => 'Ш',		'щ' => 'Щ',
+		'ъ' => 'Ъ',		'ы' => 'Ы',		'ь' => 'Ь',		'э' => 'Э',
+		'ю' => 'Ю',		'я' => 'Я',		'ѡ' => 'Ѡ',		'ѣ' => 'Ѣ',
+		'ѥ' => 'Ѥ',		'ѧ' => 'Ѧ',		'ѩ' => 'Ѩ',		'ѫ' => 'Ѫ',
+		'ѭ' => 'Ѭ',		'ѯ' => 'Ѯ',		'ѱ' => 'Ѱ',		'ѳ' => 'Ѳ',
+		'ѵ' => 'Ѵ',		'ѷ' => 'Ѷ',		'ѹ' => 'Ѹ',		'ѻ' => 'Ѻ',
+		'ѽ' => 'Ѽ',		'ѿ' => 'Ѿ',		'ҁ' => 'Ҁ',		'ҋ' => 'Ҋ',
+		'ҍ' => 'Ҍ',		'ҏ' => 'Ҏ',		'ґ' => 'Ґ',		'ғ' => 'Ғ',
+		'ҕ' => 'Ҕ',		'җ' => 'Җ',		'ҙ' => 'Ҙ',		'қ' => 'Қ',
+		'ҝ' => 'Ҝ',		'ҟ' => 'Ҟ',		'ҡ' => 'Ҡ',		'ң' => 'Ң',
+		'ҥ' => 'Ҥ',		'ҧ' => 'Ҧ',		'ҩ' => 'Ҩ',		'ҫ' => 'Ҫ',
+		'ҭ' => 'Ҭ',		'ү' => 'Ү',		'ұ' => 'Ұ',		'ҳ' => 'Ҳ',
+		'ҵ' => 'Ҵ',		'ҷ' => 'Ҷ',		'ҹ' => 'Ҹ',		'һ' => 'Һ',
+		'ҽ' => 'Ҽ',		'ҿ' => 'Ҿ',		'ӏ' => 'Ӏ',		'ӂ' => 'Ӂ',
+		'ӄ' => 'Ӄ',		'ӆ' => 'Ӆ',		'ӈ' => 'Ӈ',		'ӊ' => 'Ӊ',
+		'ӌ' => 'Ӌ',		'ӎ' => 'Ӎ',		'ӑ' => 'Ӑ',		'ӓ' => 'Ӓ',
+		'ӕ' => 'Ӕ',		'ӗ' => 'Ӗ',		'ә' => 'Ә',		'ӛ' => 'Ӛ',
+		'ӝ' => 'Ӝ',		'ӟ' => 'Ӟ',		'ӡ' => 'Ӡ',		'ӣ' => 'Ӣ',
+		'ӥ' => 'Ӥ',		'ӧ' => 'Ӧ',		'ө' => 'Ө',		'ӫ' => 'Ӫ',
+		'ӭ' => 'Ӭ',		'ӯ' => 'Ӯ',		'ӱ' => 'Ӱ',		'ӳ' => 'Ӳ',
+		'ӵ' => 'Ӵ',		'ӷ' => 'Ӷ',		'ӹ' => 'Ӹ',		'ӻ' => 'Ӻ',
+		'ӽ' => 'Ӽ',		'ӿ' => 'Ӿ',		'ԁ' => 'Ԁ',		'ԃ' => 'Ԃ',
+		'ԅ' => 'Ԅ',		'ԇ' => 'Ԇ',		'ԉ' => 'Ԉ',		'ԋ' => 'Ԋ',
+		'ԍ' => 'Ԍ',		'ԏ' => 'Ԏ',		'ԑ' => 'Ԑ',		'ԓ' => 'Ԓ',
+		'ա' => 'Ա',		'բ' => 'Բ',		'գ' => 'Գ',		'դ' => 'Դ',
+		'ե' => 'Ե',		'զ' => 'Զ',		'է' => 'Է',		'ը' => 'Ը',
+		'թ' => 'Թ',		'ժ' => 'Ժ',		'ի' => 'Ի',		'լ' => 'Լ',
+		'խ' => 'Խ',		'ծ' => 'Ծ',		'կ' => 'Կ',		'հ' => 'Հ',
+		'ձ' => 'Ձ',		'ղ' => 'Ղ',		'ճ' => 'Ճ',		'մ' => 'Մ',
+		'յ' => 'Յ',		'ն' => 'Ն',		'շ' => 'Շ',		'ո' => 'Ո',
+		'չ' => 'Չ',		'պ' => 'Պ',		'ջ' => 'Ջ',		'ռ' => 'Ռ',
+		'ս' => 'Ս',		'վ' => 'Վ',		'տ' => 'Տ',		'ր' => 'Ր',
+		'ց' => 'Ց',		'ւ' => 'Ւ',		'փ' => 'Փ',		'ք' => 'Ք',
+		'օ' => 'Օ',		'ֆ' => 'Ֆ',		'եւ' => 'և',		'ⴀ' => 'Ⴀ',
+		'ⴁ' => 'Ⴁ',		'ⴂ' => 'Ⴂ',		'ⴃ' => 'Ⴃ',		'ⴄ' => 'Ⴄ',
+		'ⴅ' => 'Ⴅ',		'ⴆ' => 'Ⴆ',		'ⴇ' => 'Ⴇ',		'ⴈ' => 'Ⴈ',
+		'ⴉ' => 'Ⴉ',		'ⴊ' => 'Ⴊ',		'ⴋ' => 'Ⴋ',		'ⴌ' => 'Ⴌ',
+		'ⴍ' => 'Ⴍ',		'ⴎ' => 'Ⴎ',		'ⴏ' => 'Ⴏ',		'ⴐ' => 'Ⴐ',
+		'ⴑ' => 'Ⴑ',		'ⴒ' => 'Ⴒ',		'ⴓ' => 'Ⴓ',		'ⴔ' => 'Ⴔ',
+		'ⴕ' => 'Ⴕ',		'ⴖ' => 'Ⴖ',		'ⴗ' => 'Ⴗ',		'ⴘ' => 'Ⴘ',
+		'ⴙ' => 'Ⴙ',		'ⴚ' => 'Ⴚ',		'ⴛ' => 'Ⴛ',		'ⴜ' => 'Ⴜ',
+		'ⴝ' => 'Ⴝ',		'ⴞ' => 'Ⴞ',		'ⴟ' => 'Ⴟ',		'ⴠ' => 'Ⴠ',
+		'ⴡ' => 'Ⴡ',		'ⴢ' => 'Ⴢ',		'ⴣ' => 'Ⴣ',		'ⴤ' => 'Ⴤ',
+		'ⴥ' => 'Ⴥ',		'ḁ' => 'Ḁ',		'ḃ' => 'Ḃ',		'ḅ' => 'Ḅ',
+		'ḇ' => 'Ḇ',		'ḉ' => 'Ḉ',		'ḋ' => 'Ḋ',		'ḍ' => 'Ḍ',
+		'ḏ' => 'Ḏ',		'ḑ' => 'Ḑ',		'ḓ' => 'Ḓ',		'ḕ' => 'Ḕ',
+		'ḗ' => 'Ḗ',		'ḙ' => 'Ḙ',		'ḛ' => 'Ḛ',		'ḝ' => 'Ḝ',
+		'ḟ' => 'Ḟ',		'ḡ' => 'Ḡ',		'ḣ' => 'Ḣ',		'ḥ' => 'Ḥ',
+		'ḧ' => 'Ḧ',		'ḩ' => 'Ḩ',		'ḫ' => 'Ḫ',		'ḭ' => 'Ḭ',
+		'ḯ' => 'Ḯ',		'ḱ' => 'Ḱ',		'ḳ' => 'Ḳ',		'ḵ' => 'Ḵ',
+		'ḷ' => 'Ḷ',		'ḹ' => 'Ḹ',		'ḻ' => 'Ḻ',		'ḽ' => 'Ḽ',
+		'ḿ' => 'Ḿ',		'ṁ' => 'Ṁ',		'ṃ' => 'Ṃ',		'ṅ' => 'Ṅ',
+		'ṇ' => 'Ṇ',		'ṉ' => 'Ṉ',		'ṋ' => 'Ṋ',		'ṍ' => 'Ṍ',
+		'ṏ' => 'Ṏ',		'ṑ' => 'Ṑ',		'ṓ' => 'Ṓ',		'ṕ' => 'Ṕ',
+		'ṗ' => 'Ṗ',		'ṙ' => 'Ṙ',		'ṛ' => 'Ṛ',		'ṝ' => 'Ṝ',
+		'ṟ' => 'Ṟ',		'ṡ' => 'Ṡ',		'ṣ' => 'Ṣ',		'ṥ' => 'Ṥ',
+		'ṧ' => 'Ṧ',		'ṩ' => 'Ṩ',		'ṫ' => 'Ṫ',		'ṭ' => 'Ṭ',
+		'ṯ' => 'Ṯ',		'ṱ' => 'Ṱ',		'ṳ' => 'Ṳ',		'ṵ' => 'Ṵ',
+		'ṷ' => 'Ṷ',		'ṹ' => 'Ṹ',		'ṻ' => 'Ṻ',		'ṽ' => 'Ṽ',
+		'ṿ' => 'Ṿ',		'ẁ' => 'Ẁ',		'ẃ' => 'Ẃ',		'ẅ' => 'Ẅ',
+		'ẇ' => 'Ẇ',		'ẉ' => 'Ẉ',		'ẋ' => 'Ẋ',		'ẍ' => 'Ẍ',
+		'ẏ' => 'Ẏ',		'ẑ' => 'Ẑ',		'ẓ' => 'Ẓ',		'ẕ' => 'Ẕ',
+		'ẖ' => 'ẖ',		'ẗ' => 'ẗ',		'ẘ' => 'ẘ',		'ẙ' => 'ẙ',
+		'aʾ' => 'ẚ',	'ṡ' => 'ẛ',		'ạ' => 'Ạ',		'ả' => 'Ả',
+		'ấ' => 'Ấ',		'ầ' => 'Ầ',		'ẩ' => 'Ẩ',		'ẫ' => 'Ẫ',
+		'ậ' => 'Ậ',		'ắ' => 'Ắ',		'ằ' => 'Ằ',		'ẳ' => 'Ẳ',
+		'ẵ' => 'Ẵ',		'ặ' => 'Ặ',		'ẹ' => 'Ẹ',		'ẻ' => 'Ẻ',
+		'ẽ' => 'Ẽ',		'ế' => 'Ế',		'ề' => 'Ề',		'ể' => 'Ể',
+		'ễ' => 'Ễ',		'ệ' => 'Ệ',		'ỉ' => 'Ỉ',		'ị' => 'Ị',
+		'ọ' => 'Ọ',		'ỏ' => 'Ỏ',		'ố' => 'Ố',		'ồ' => 'Ồ',
+		'ổ' => 'Ổ',		'ỗ' => 'Ỗ',		'ộ' => 'Ộ',		'ớ' => 'Ớ',
+		'ờ' => 'Ờ',		'ở' => 'Ở',		'ỡ' => 'Ỡ',		'ợ' => 'Ợ',
+		'ụ' => 'Ụ',		'ủ' => 'Ủ',		'ứ' => 'Ứ',		'ừ' => 'Ừ',
+		'ử' => 'Ử',		'ữ' => 'Ữ',		'ự' => 'Ự',		'ỳ' => 'Ỳ',
+		'ỵ' => 'Ỵ',		'ỷ' => 'Ỷ',		'ỹ' => 'Ỹ',		'ἀ' => 'Ἀ',
+		'ἁ' => 'Ἁ',		'ἂ' => 'Ἂ',		'ἃ' => 'Ἃ',		'ἄ' => 'Ἄ',
+		'ἅ' => 'Ἅ',		'ἆ' => 'Ἆ',		'ἇ' => 'Ἇ',		'ἐ' => 'Ἐ',
+		'ἑ' => 'Ἑ',		'ἒ' => 'Ἒ',		'ἓ' => 'Ἓ',		'ἔ' => 'Ἔ',
+		'ἕ' => 'Ἕ',		'ἠ' => 'Ἠ',		'ἡ' => 'Ἡ',		'ἢ' => 'Ἢ',
+		'ἣ' => 'Ἣ',		'ἤ' => 'Ἤ',		'ἥ' => 'Ἥ',		'ἦ' => 'Ἦ',
+		'ἧ' => 'Ἧ',		'ἰ' => 'Ἰ',		'ἱ' => 'Ἱ',		'ἲ' => 'Ἲ',
+		'ἳ' => 'Ἳ',		'ἴ' => 'Ἴ',		'ἵ' => 'Ἵ',		'ἶ' => 'Ἶ',
+		'ἷ' => 'Ἷ',		'ὀ' => 'Ὀ',		'ὁ' => 'Ὁ',		'ὂ' => 'Ὂ',
+		'ὃ' => 'Ὃ',		'ὄ' => 'Ὄ',		'ὅ' => 'Ὅ',		'ὐ' => 'ὐ',
+		'ὒ' => 'ὒ',	'ὔ' => 'ὔ',	'ὖ' => 'ὖ',		'ὑ' => 'Ὑ',
+		'ὓ' => 'Ὓ',		'ὕ' => 'Ὕ',		'ὗ' => 'Ὗ',		'ὠ' => 'Ὠ',
+		'ὡ' => 'Ὡ',		'ὢ' => 'Ὢ',		'ὣ' => 'Ὣ',		'ὤ' => 'Ὤ',
+		'ὥ' => 'Ὥ',		'ὦ' => 'Ὦ',		'ὧ' => 'Ὧ',		'ἀι' => 'ᾀ',
+		'ἁι' => 'ᾁ',	'ἂι' => 'ᾂ',	'ἃι' => 'ᾃ',	'ἄι' => 'ᾄ',
+		'ἅι' => 'ᾅ',	'ἆι' => 'ᾆ',	'ἇι' => 'ᾇ',	'ᾀ' => 'ᾈ',
+		'ᾁ' => 'ᾉ',		'ᾂ' => 'ᾊ',		'ᾃ' => 'ᾋ',		'ᾄ' => 'ᾌ',
+		'ᾅ' => 'ᾍ',		'ᾆ' => 'ᾎ',		'ᾇ' => 'ᾏ',		'ἠι' => 'ᾐ',
+		'ἡι' => 'ᾑ',	'ἢι' => 'ᾒ',	'ἣι' => 'ᾓ',	'ἤι' => 'ᾔ',
+		'ἥι' => 'ᾕ',	'ἦι' => 'ᾖ',	'ἧι' => 'ᾗ',	'ᾐ' => 'ᾘ',
+		'ᾑ' => 'ᾙ',		'ᾒ' => 'ᾚ',		'ᾓ' => 'ᾛ',		'ᾔ' => 'ᾜ',
+		'ᾕ' => 'ᾝ',		'ᾖ' => 'ᾞ',		'ᾗ' => 'ᾟ',		'ὠι' => 'ᾠ',
+		'ὡι' => 'ᾡ',	'ὢι' => 'ᾢ',	'ὣι' => 'ᾣ',	'ὤι' => 'ᾤ',
+		'ὥι' => 'ᾥ',	'ὦι' => 'ᾦ',	'ὧι' => 'ᾧ',	'ᾠ' => 'ᾨ',
+		'ᾡ' => 'ᾩ',		'ᾢ' => 'ᾪ',		'ᾣ' => 'ᾫ',		'ᾤ' => 'ᾬ',
+		'ᾥ' => 'ᾭ',		'ᾦ' => 'ᾮ',		'ᾧ' => 'ᾯ',		'ὰι' => 'ᾲ',
+		'αι' => 'ᾳ',	'άι' => 'ᾴ',	'ᾶ' => 'ᾶ',		'ᾶι' => 'ᾷ',
+		'ᾰ' => 'Ᾰ',		'ᾱ' => 'Ᾱ',		'ὰ' => 'Ὰ',		'ά' => 'Ά',
+		'ᾳ' => 'ᾼ',		'ι' => 'ι',		'ὴι' => 'ῂ',	'ηι' => 'ῃ',
+		'ήι' => 'ῄ',	'ῆ' => 'ῆ',		'ῆι' => 'ῇ',	'ὲ' => 'Ὲ',
+		'έ' => 'Έ',		'ὴ' => 'Ὴ',		'ή' => 'Ή',		'ῃ' => 'ῌ',
+		'ῒ' => 'ῒ',	'ΐ' => 'ΐ',	'ῖ' => 'ῖ',		'ῗ' => 'ῗ',
+		'ῐ' => 'Ῐ',		'ῑ' => 'Ῑ',		'ὶ' => 'Ὶ',		'ί' => 'Ί',
+		'ῢ' => 'ῢ',	'ΰ' => 'ΰ',	'ῤ' => 'ῤ',		'ῦ' => 'ῦ',
+		'ῧ' => 'ῧ',		'ῠ' => 'Ῠ',		'ῡ' => 'Ῡ',		'ὺ' => 'Ὺ',
+		'ύ' => 'Ύ',		'ῥ' => 'Ῥ',		'ὼι' => 'ῲ',	'ωι' => 'ῳ',
+		'ώι' => 'ῴ',	'ῶ' => 'ῶ',		'ῶι' => 'ῷ',	'ὸ' => 'Ὸ',
+		'ό' => 'Ό',		'ὼ' => 'Ὼ',		'ώ' => 'Ώ',		'ῳ' => 'ῼ',
+		'ω' => 'Ω',		'k' => 'K',		'å' => 'Å',		'ⅎ' => 'Ⅎ',
+		'ⅰ' => 'Ⅰ',		'ⅱ' => 'Ⅱ',		'ⅲ' => 'Ⅲ',		'ⅳ' => 'Ⅳ',
+		'ⅴ' => 'Ⅴ',		'ⅵ' => 'Ⅵ',		'ⅶ' => 'Ⅶ',		'ⅷ' => 'Ⅷ',
+		'ⅸ' => 'Ⅸ',		'ⅹ' => 'Ⅹ',		'ⅺ' => 'Ⅺ',		'ⅻ' => 'Ⅻ',
+		'ⅼ' => 'Ⅼ',		'ⅽ' => 'Ⅽ',		'ⅾ' => 'Ⅾ',		'ⅿ' => 'Ⅿ',
+		'ↄ' => 'Ↄ',		'ⓐ' => 'Ⓐ',		'ⓑ' => 'Ⓑ',		'ⓒ' => 'Ⓒ',
+		'ⓓ' => 'Ⓓ',		'ⓔ' => 'Ⓔ',		'ⓕ' => 'Ⓕ',		'ⓖ' => 'Ⓖ',
+		'ⓗ' => 'Ⓗ',		'ⓘ' => 'Ⓘ',		'ⓙ' => 'Ⓙ',		'ⓚ' => 'Ⓚ',
+		'ⓛ' => 'Ⓛ',		'ⓜ' => 'Ⓜ',		'ⓝ' => 'Ⓝ',		'ⓞ' => 'Ⓞ',
+		'ⓟ' => 'Ⓟ',		'ⓠ' => 'Ⓠ',		'ⓡ' => 'Ⓡ',		'ⓢ' => 'Ⓢ',
+		'ⓣ' => 'Ⓣ',		'ⓤ' => 'Ⓤ',		'ⓥ' => 'Ⓥ',		'ⓦ' => 'Ⓦ',
+		'ⓧ' => 'Ⓧ',		'ⓨ' => 'Ⓨ',		'ⓩ' => 'Ⓩ',		'ⰰ' => 'Ⰰ',
+		'ⰱ' => 'Ⰱ',		'ⰲ' => 'Ⰲ',		'ⰳ' => 'Ⰳ',		'ⰴ' => 'Ⰴ',
+		'ⰵ' => 'Ⰵ',		'ⰶ' => 'Ⰶ',		'ⰷ' => 'Ⰷ',		'ⰸ' => 'Ⰸ',
+		'ⰹ' => 'Ⰹ',		'ⰺ' => 'Ⰺ',		'ⰻ' => 'Ⰻ',		'ⰼ' => 'Ⰼ',
+		'ⰽ' => 'Ⰽ',		'ⰾ' => 'Ⰾ',		'ⰿ' => 'Ⰿ',		'ⱀ' => 'Ⱀ',
+		'ⱁ' => 'Ⱁ',		'ⱂ' => 'Ⱂ',		'ⱃ' => 'Ⱃ',		'ⱄ' => 'Ⱄ',
+		'ⱅ' => 'Ⱅ',		'ⱆ' => 'Ⱆ',		'ⱇ' => 'Ⱇ',		'ⱈ' => 'Ⱈ',
+		'ⱉ' => 'Ⱉ',		'ⱊ' => 'Ⱊ',		'ⱋ' => 'Ⱋ',		'ⱌ' => 'Ⱌ',
+		'ⱍ' => 'Ⱍ',		'ⱎ' => 'Ⱎ',		'ⱏ' => 'Ⱏ',		'ⱐ' => 'Ⱐ',
+		'ⱑ' => 'Ⱑ',		'ⱒ' => 'Ⱒ',		'ⱓ' => 'Ⱓ',		'ⱔ' => 'Ⱔ',
+		'ⱕ' => 'Ⱕ',		'ⱖ' => 'Ⱖ',		'ⱗ' => 'Ⱗ',		'ⱘ' => 'Ⱘ',
+		'ⱙ' => 'Ⱙ',		'ⱚ' => 'Ⱚ',		'ⱛ' => 'Ⱛ',		'ⱜ' => 'Ⱜ',
+		'ⱝ' => 'Ⱝ',		'ⱞ' => 'Ⱞ',		'ⱡ' => 'Ⱡ',		'ɫ' => 'Ɫ',
+		'ᵽ' => 'Ᵽ',		'ɽ' => 'Ɽ',		'ⱨ' => 'Ⱨ',		'ⱪ' => 'Ⱪ',
+		'ⱬ' => 'Ⱬ',		'ⱶ' => 'Ⱶ',		'ⲁ' => 'Ⲁ',		'ⲃ' => 'Ⲃ',
+		'ⲅ' => 'Ⲅ',		'ⲇ' => 'Ⲇ',		'ⲉ' => 'Ⲉ',		'ⲋ' => 'Ⲋ',
+		'ⲍ' => 'Ⲍ',		'ⲏ' => 'Ⲏ',		'ⲑ' => 'Ⲑ',		'ⲓ' => 'Ⲓ',
+		'ⲕ' => 'Ⲕ',		'ⲗ' => 'Ⲗ',		'ⲙ' => 'Ⲙ',		'ⲛ' => 'Ⲛ',
+		'ⲝ' => 'Ⲝ',		'ⲟ' => 'Ⲟ',		'ⲡ' => 'Ⲡ',		'ⲣ' => 'Ⲣ',
+		'ⲥ' => 'Ⲥ',		'ⲧ' => 'Ⲧ',		'ⲩ' => 'Ⲩ',		'ⲫ' => 'Ⲫ',
+		'ⲭ' => 'Ⲭ',		'ⲯ' => 'Ⲯ',		'ⲱ' => 'Ⲱ',		'ⲳ' => 'Ⲳ',
+		'ⲵ' => 'Ⲵ',		'ⲷ' => 'Ⲷ',		'ⲹ' => 'Ⲹ',		'ⲻ' => 'Ⲻ',
+		'ⲽ' => 'Ⲽ',		'ⲿ' => 'Ⲿ',		'ⳁ' => 'Ⳁ',		'ⳃ' => 'Ⳃ',
+		'ⳅ' => 'Ⳅ',		'ⳇ' => 'Ⳇ',		'ⳉ' => 'Ⳉ',		'ⳋ' => 'Ⳋ',
+		'ⳍ' => 'Ⳍ',		'ⳏ' => 'Ⳏ',		'ⳑ' => 'Ⳑ',		'ⳓ' => 'Ⳓ',
+		'ⳕ' => 'Ⳕ',		'ⳗ' => 'Ⳗ',		'ⳙ' => 'Ⳙ',		'ⳛ' => 'Ⳛ',
+		'ⳝ' => 'Ⳝ',		'ⳟ' => 'Ⳟ',		'ⳡ' => 'Ⳡ',		'ⳣ' => 'Ⳣ',
+		'ff' => 'ff',	'fi' => 'fi',	'fl' => 'fl',	'ffi' => 'ffi',
+		'ffl' => 'ffl',	'st' => 'ſt',	'st' => 'st',	'մն' => 'ﬓ',
+		'մե' => 'ﬔ',	'մի' => 'ﬕ',	'վն' => 'ﬖ',	'մխ' => 'ﬗ',
+		'a' => 'A',		'b' => 'B',		'c' => 'C',		'd' => 'D',
+		'e' => 'E',		'f' => 'F',		'g' => 'G',		'h' => 'H',
+		'i' => 'I',		'j' => 'J',		'k' => 'K',		'l' => 'L',
+		'm' => 'M',	'n' => 'N',		'o' => 'O',		'p' => 'P',
+		'q' => 'Q',		'r' => 'R',		's' => 'S',		't' => 'T',
+		'u' => 'U',		'v' => 'V',		'w' => 'W',	'x' => 'X',
+		'y' => 'Y',		'z' => 'Z',		'𐐨' => '𐐀',	'𐐩' => '𐐁',
+		'𐐪' => '𐐂',	'𐐫' => '𐐃',	'𐐬' => '𐐄',	'𐐭' => '𐐅',
+		'𐐮' => '𐐆',	'𐐯' => '𐐇',	'𐐰' => '𐐈',	'𐐱' => '𐐉',
+		'𐐲' => '𐐊',	'𐐳' => '𐐋',	'𐐴' => '𐐌',	'𐐵' => '𐐍',
+		'𐐶' => '𐐎',	'𐐷' => '𐐏',	'𐐸' => '𐐐',	'𐐹' => '𐐑',
+		'𐐺' => '𐐒',	'𐐻' => '𐐓',	'𐐼' => '𐐔',	'𐐽' => '𐐕',
+		'𐐾' => '𐐖',	'𐐿' => '𐐗',	'𐑀' => '𐐘',	'𐑁' => '𐐙',
+		'𐑂' => '𐐚',	'𐑃' => '𐐛',	'𐑄' => '𐐜',	'𐑅' => '𐐝',
+		'𐑆' => '𐐞',	'𐑇' => '𐐟',	'𐑈' => '𐐠',	'𐑉' => '𐐡',
+		'𐑊' => '𐐢',	'𐑋' => '𐐣',	'𐑌' => '𐐤',	'𐑍' => '𐐥',
+		'𐐦' => '𐑎',	'𐐧' => '𐑏',
 	);
 
 	return strtr($string, $case_folding);

+ 107 - 70
Sources/Subs-Members.php

@@ -1,6 +1,8 @@
 <?php
 
 /**
+ * This file contains some useful functions for members and membergroups.
+ *
  * Simple Machines Forum (SMF)
  *
  * @package SMF
@@ -14,72 +16,23 @@
 if (!defined('SMF'))
 	die('Hacking attempt...');
 
-/* This file contains some useful functions for members and membergroups.
-
-	void deleteMembers(array $users, bool check_not_admin = false)
-		- delete of one or more members.
-		- requires profile_remove_own or profile_remove_any permission for
-		  respectively removing your own account or any account.
-		- non-admins cannot delete admins.
-		- changes author of messages, topics and polls to guest authors.
-		- removes all log entries concerning the deleted members, except the
-		  error logs, ban logs and moderation logs.
-		- removes these members' personal messages (only the inbox), avatars,
-		  ban entries, theme settings, moderator positions, poll votes, and
-		  karma votes.
-		- updates member statistics afterwards.
-
-	int registerMember(array options, bool return_errors)
-		- registers a member to the forum.
-		- returns the ID of the newly created member.
-		- allows two types of interface: 'guest' and 'admin'. The first
-		  includes hammering protection, the latter can perform the
-		  registration silently.
-		- the strings used in the options array are assumed to be escaped.
-		- allows to perform several checks on the input, e.g. reserved names.
-		- adjusts member statistics.
-		- if an error is detected will fatal error on all errors unless return_errors is true.
-
-	bool isReservedName(string name, int id_member = 0, bool is_name = true, bool fatal = true)
-		- checks if name is a reserved name or username.
-		- if is_name is false, the name is assumed to be a username.
-		- the id_member variable is used to ignore duplicate matches with the
-		  current member.
-
-	array groupsAllowedTo(string permission, int board_id = null)
-		- retrieves a list of membergroups that are allowed to do the given
-		  permission.
-		- if board_id is not null, a board permission is assumed.
-		- takes different permission settings into account.
-		- returns an array containing an array for the allowed membergroup ID's
-		  and an array for the denied membergroup ID's.
-
-	array membersAllowedTo(string permission, int board_id = null)
-		- retrieves a list of members that are allowed to do the given
-		  permission.
-		- if board_id is not null, a board permission is assumed.
-		- takes different permission settings into account.
-		- takes possible moderators (on board 'board_id') into account.
-		- returns an array containing member ID's.
-
-	int reattributePosts(int id_member, string email = false, string membername = false, bool add_to_post_count = false)
-		- reattribute guest posts to a specified member.
-		- does not check for any permissions.
-		- returns the number of successful reattributed posts.
-		- if add_to_post_count is set, the member's post count is increased.
-
-	void BuddyListToggle()
-		- add a member to your buddy list or remove it.
-		- requires profile_identity_own permission.
-		- called by ?action=buddy;u=x;session_id=y.
-		- redirects to ?action=profile;u=x.
-
-	void populateDuplicateMembers(&array members)
-		// !!!
-
-*/
-
-// Delete a group of/single member.
+/**
+ * Delete one or more members.
+ * Requires profile_remove_own or profile_remove_any permission for
+ * respectively removing your own account or any account.
+ * Non-admins cannot delete admins.
+ * The function:
+ * - changes author of messages, topics and polls to guest authors.
+ * - removes all log entries concerning the deleted members, except the
+ * error logs, ban logs and moderation logs.
+ * - removes these members' personal messages (only the inbox), avatars,
+ * ban entries, theme settings, moderator positions, poll votes, and
+ * karma votes.
+ * - updates member statistics afterwards.
+ *
+ * @param array $users
+ * @param bool $check_not_admin = false
+ */
 function deleteMembers($users, $check_not_admin = false)
 {
 	global $sourcedir, $modSettings, $user_info, $smcFunc;
@@ -456,6 +409,20 @@ function deleteMembers($users, $check_not_admin = false)
 	updateStats('member');
 }
 
+/**
+ * Registers a member to the forum.
+ * Allows two types of interface: 'guest' and 'admin'. The first
+ * includes hammering protection, the latter can perform the
+ * registration silently.
+ * The strings used in the options array are assumed to be escaped.
+ * Allows to perform several checks on the input, e.g. reserved names.
+ * The function will adjust member statistics.
+ * If an error is detected will fatal error on all errors unless return_errors is true.
+ *
+ * @param array $regOptions
+ * @param bool $return_errors - specify whether to return the errors
+ * @return int, the ID of the newly created member
+ */
 function registerMember(&$regOptions, $return_errors = false)
 {
 	global $scripturl, $txt, $modSettings, $context, $sourcedir;
@@ -894,7 +861,20 @@ function registerMember(&$regOptions, $return_errors = false)
 	return $memberID;
 }
 
-// Check if a name is in the reserved words list. (name, current member id, name/username?.)
+
+/**
+ * Check if a name is in the reserved words list.
+ * (name, current member id, name/username?.)
+ * - checks if name is a reserved name or username.
+ * - if is_name is false, the name is assumed to be a username.
+ * - the id_member variable is used to ignore duplicate matches with the
+ * current member.
+ *
+ * @param string $name
+ * @param int $current_ID_MEMBER
+ * @param bool $is_name
+ * @param bool $fatal
+ */
 function isReservedName($name, $current_ID_MEMBER = 0, $is_name = true, $fatal = true)
 {
 	global $user_info, $modSettings, $smcFunc, $context;
@@ -995,6 +975,17 @@ function isReservedName($name, $current_ID_MEMBER = 0, $is_name = true, $fatal =
 }
 
 // Get a list of groups that have a given permission (on a given board).
+/**
+ * Retrieves a list of membergroups that are allowed to do the given
+ * permission. (on the given board)
+ * If board_id is not null, a board permission is assumed.
+ * The function takes different permission settings into account.
+ *
+ * @param string $permission
+ * @param int $board_id = null
+ * @return an array containing an array for the allowed membergroup ID's
+ * and an array for the denied membergroup ID's.
+ */
 function groupsAllowedTo($permission, $board_id = null)
 {
 	global $modSettings, $board_info, $smcFunc;
@@ -1067,7 +1058,17 @@ function groupsAllowedTo($permission, $board_id = null)
 	return $member_groups;
 }
 
-// Get a list of members that have a given permission (on a given board).
+/**
+ * Retrieves a list of members that have a given permission
+ * (on a given board).
+ * If board_id is not null, a board permission is assumed.
+ * Takes different permission settings into account.
+ * Takes possible moderators (on board 'board_id') into account.
+ *
+ * @param string $permission
+ * @param int $board_id = null
+ * @return an array containing member ID's.
+ */
 function membersAllowedTo($permission, $board_id = null)
 {
 	global $smcFunc;
@@ -1102,7 +1103,18 @@ function membersAllowedTo($permission, $board_id = null)
 	return $members;
 }
 
-// This function is used to reassociate members with relevant posts.
+/**
+ * This function is used to reassociate members with relevant posts.
+ * Reattribute guest posts to a specified member.
+ * Does not check for any permissions.
+ * If add_to_post_count is set, the member's post count is increased.
+ *
+ * @param int $memID
+ * @param string $email = false
+ * @param string $membername = false
+ * @param bool $post_count = false
+ * @return the number of successful reattributed posts.
+ */
 function reattributePosts($memID, $email = false, $membername = false, $post_count = false)
 {
 	global $smcFunc;
@@ -1172,7 +1184,12 @@ function reattributePosts($memID, $email = false, $membername = false, $post_cou
 	return $smcFunc['db_affected_rows']();
 }
 
-// This simple function adds/removes the passed user from the current users buddy list.
+/**
+ * This simple function adds/removes the passed user from the current users buddy list.
+ * Requires profile_identity_own permission.
+ * Called by ?action=buddy;u=x;session_id=y.
+ * Redirects to ?action=profile;u=x.
+ */
 function BuddyListToggle()
 {
 	global $user_info;
@@ -1200,6 +1217,16 @@ function BuddyListToggle()
 	redirectexit('action=profile;u=' . $_REQUEST['u']);
 }
 
+/**
+ * Callback for createList().
+ *
+ * @param $start
+ * @param $items_per_page
+ * @param $sort
+ * @param $where
+ * @param $where_params
+ * @param $get_duplicates
+ */
 function list_getMembers($start, $items_per_page, $sort, $where, $where_params = array(), $get_duplicates = false)
 {
 	global $smcFunc;
@@ -1232,6 +1259,12 @@ function list_getMembers($start, $items_per_page, $sort, $where, $where_params =
 	return $members;
 }
 
+/**
+ * Callback for createList().
+ *
+ * @param $where
+ * @param $where_params
+ */
 function list_getNumMembers($where, $where_params = array())
 {
 	global $smcFunc, $modSettings;
@@ -1257,6 +1290,10 @@ function list_getNumMembers($where, $where_params = array())
 	return $num_members;
 }
 
+/**
+ *
+ * @param $members
+ */
 function populateDuplicateMembers(&$members)
 {
 	global $smcFunc;

+ 10 - 1
Sources/Subs-MembersOnline.php

@@ -33,6 +33,7 @@ function getMembersOnlineStats($membersOnlineOptions)
 
 	// The list can be sorted in several ways.
 	$allowed_sort_options = array(
+		'', // No sorting.
 		'log_time',
 		'real_name',
 		'show_online',
@@ -50,6 +51,10 @@ function getMembersOnlineStats($membersOnlineOptions)
 	elseif (!in_array($membersOnlineOptions['sort'], $allowed_sort_options))
 		trigger_error('Sort method for getMembersOnlineStats() function is not allowed', E_USER_NOTICE);
 
+	// Get it from the cache and send it back.
+	if (($temp = cache_get_data('membersOnlineStats-' . $membersOnlineOptions['sort'], 240)) !== null)
+		return $temp;
+
 	// Initialize the array that'll be returned later on.
 	$membersOnlineStats = array(
 		'users_online' => array(),
@@ -145,10 +150,11 @@ function getMembersOnlineStats($membersOnlineOptions)
 
 	// If there are spiders only and we're showing the detail, add them to the online list - at the bottom.
 	if (!empty($spider_finds) && $modSettings['show_spider_online'] > 1)
+	{
+		$sort = $membersOnlineOptions['sort'] === 'log_time' && $membersOnlineOptions['reverse_sort'] ? 0 : 'zzz_';
 		foreach ($spider_finds as $id => $count)
 		{
 			$link = $spiders[$id] . ($count > 1 ? ' (' . $count . ')' : '');
-			$sort = $membersOnlineOptions['sort'] = 'log_time' && $membersOnlineOptions['reverse_sort'] ? 0 : 'zzz_';
 			$membersOnlineStats['users_online'][$sort . $spiders[$id]] = array(
 				'id' => 0,
 				'username' => $spiders[$id],
@@ -162,6 +168,7 @@ function getMembersOnlineStats($membersOnlineOptions)
 			);
 			$membersOnlineStats['list_users_online'][$sort . $spiders[$id]] = $link;
 		}
+	}
 
 	// Time to sort the list a bit.
 	if (!empty($membersOnlineStats['users_online']))
@@ -184,6 +191,8 @@ function getMembersOnlineStats($membersOnlineOptions)
 	// Hidden and non-hidden members make up all online members.
 	$membersOnlineStats['num_users_online'] = count($membersOnlineStats['users_online']) + $membersOnlineStats['num_users_hidden'] - (isset($modSettings['show_spider_online']) && $modSettings['show_spider_online'] > 1 ? count($spider_finds) : 0);
 
+	cache_put_data('membersOnlineStats-' . $membersOnlineOptions['sort'], $membersOnlineStats, 240);
+	
 	return $membersOnlineStats;
 }
 

+ 12 - 10
Sources/Subs-Sound.php

@@ -1,6 +1,10 @@
 <?php
 
 /**
+ * Handles sound processing. In order to make sure the visual
+ * verification is still accessible for all users, a sound clip is being addded
+ * that reads the letters that are being shown.
+ * 
  * Simple Machines Forum (SMF)
  *
  * @package SMF
@@ -14,16 +18,14 @@
 if (!defined('SMF'))
 	die('Hacking attempt...');
 
-/*	This file handles sound processing. In order to make sure the visual
-	verification is still accessible for all users, a sound clip is being addded
-	that reads the letters that are being shown.
-
-	void createWaveFile(string word)
-		- creates a wave file that spells the letters of 'word'.
-		- Tries the user's language first, and defaults to english.
-		- Returns false on failure.
-		- used by VerificationCode() (Register.php).
-*/
+/**
+ * Creates a wave file that spells the letters of $word.
+ * Tries the user's language first, and defaults to english.
+ * Used by VerificationCode() (Register.php).
+ * 
+ * @param string $word
+ * @return bool false on failure
+ */
 
 function createWaveFile($word)
 {

+ 1 - 1
Sources/Subs.php

@@ -2560,7 +2560,7 @@ function redirectexit($setLocation = '', $refresh = false)
 	elseif (isset($_GET['debug']))
 		$setLocation = preg_replace('/^' . preg_quote($scripturl, '/') . '\\??/', $scripturl . '?debug;', $setLocation);
 
-	if (!empty($modSettings['queryless_urls']) && (empty($context['server']['is_cgi']) || @ini_get('cgi.fix_pathinfo') == 1 || @get_cfg_var('cgi.fix_pathinfo') == 1) && (!empty($context['server']['is_apache']) || !empty($context['server']['is_lighttpd'])))
+	if (!empty($modSettings['queryless_urls']) && (empty($context['server']['is_cgi']) || @ini_get('cgi.fix_pathinfo') == 1 || @get_cfg_var('cgi.fix_pathinfo') == 1) && (!empty($context['server']['is_apache']) || !empty($context['server']['is_lighttpd']] || !empty($context['server']['is_litespeed']))))
 	{
 		if (defined('SID') && SID != '')
 			$setLocation = preg_replace('/^' . preg_quote($scripturl, '/') . '\?(?:' . SID . '(?:;|&|&amp;))((?:board|topic)=[^#]+?)(#[^"]*?)?$/e', "\$scripturl . '/' . strtr('\$1', '&;=', '//,') . '.html\$2?' . SID", $setLocation);

+ 5 - 6
Sources/Xml.php

@@ -1,6 +1,8 @@
 <?php
 
 /**
+ * Maintains all XML-based interaction (mainly XMLhttp)
+ * 
  * Simple Machines Forum (SMF)
  *
  * @package SMF
@@ -14,11 +16,6 @@
 if (!defined('SMF'))
 	die('Hacking attempt...');
 
-/*	This file maintains all XML-based interaction (mainly XMLhttp).
-
-	void GetJumpTo()
-
-*/
 
 function XMLhttpMain()
 {
@@ -38,7 +35,9 @@ function XMLhttpMain()
 	$sub_actions[$_REQUEST['sa']]['function']();
 }
 
-// Get a list of boards and categories used for the jumpto dropdown.
+/**
+ * Get a list of boards and categories used for the jumpto dropdown.
+ */
 function GetJumpTo()
 {
 	global $user_info, $context, $smcFunc, $sourcedir;

+ 1 - 3
Themes/default/Admin.template.php

@@ -616,9 +616,7 @@ function template_edit_censored()
 
 	// Now provide a way to censor more words.
 	echo '
-					<noscript>
-						<div style="margin-top: 1ex;"><input type="text" name="censor_vulgar[]" size="20" class="input_text" /> => <input type="text" name="censor_proper[]" size="20" class="input_text" /></div>
-					</noscript>
+					<div style="margin-top: 1ex;"><input type="text" name="censor_vulgar[]" size="20" class="input_text" /> => <input type="text" name="censor_proper[]" size="20" class="input_text" /></div>
 					<div id="moreCensoredWords"></div><div style="margin-top: 1ex; display: none;" id="moreCensoredWords_link"><a href="#;" onclick="addNewWord(); return false;">', $txt['censor_clickadd'], '</a></div>
 					<script type="text/javascript"><!-- // --><![CDATA[
 						document.getElementById("moreCensoredWords_link").style.display = "";

+ 4 - 1
Themes/default/index.template.php

@@ -163,7 +163,10 @@ function template_html_above()
 
 	echo '
 </head>
-<body>';
+<body', 
+	// Style per page.
+	!empty($context['body_id']) ? ' id="' . $context['body_id'] . '"' : '', '>';
+
 }
 
 function template_body_above()

+ 3 - 0
Themes/default/languages/Help.english.php

@@ -363,6 +363,8 @@ $helptxt['globalCookies'] = 'Makes log in cookies available across subdomains.
 $helptxt['secureCookies'] = 'Enabling this option will force the cookies created for users on your forum to be marked as secure. Only enable this option if you are using HTTPS throughout your site as it will break cookie handling otherwise!';
 $helptxt['securityDisable'] = 'This <em>disables</em> the additional password check for the administration section. This is not recommended!';
 $helptxt['securityDisable_why'] = 'This is your current password. (the same one you use to login.)<br /><br />Having to type this helps ensure that you want to do whatever administration you are doing, and that it is <strong>you</strong> doing it.';
+$helptxt['securityDisable_moderate'] = 'This <em>disables</em> the additional password check for the moderation section. This is not recommended!';
+$helptxt['securityDisable_moderate_why'] = 'This is your current password. (the same one you use to login.)<br /><br />Having to type this helps ensure that you want to do whatever moderation you are doing, and that it is <strong>you</strong> doing it.';
 $helptxt['emailmembers'] = 'In this message you can use a few &quot;variables&quot;.  These are:<br />
 	{$board_url} - The URL to your forum.<br />
 	{$current_time} - The current time.<br />
@@ -378,6 +380,7 @@ $helptxt['attachmentEncryptFilenames'] = 'Encrypting attachment filenames allows
 	difficult to rebuild your database if something drastic happened.';
 
 $helptxt['failed_login_threshold'] = 'Set the number of failed login attempts before directing the user to the password reminder screen.';
+$helptxt['loginHistoryDays'] = 'The number of days to keep login history under user profile tracking. Default is 30 days.';
 $helptxt['oldTopicDays'] = 'If this option is enabled a warning will be displayed to the user when attempting to reply to a topic which has not had any new replies for the amount of time, in days, specified by this setting. Set this setting to 0 to disable the feature.';
 $helptxt['edit_wait_time'] = 'Number of seconds allowed for a post to be edited before logging the last edit date.';
 $helptxt['edit_disable_time'] = 'Number of minutes allowed to pass before a user can no longer edit a post they have made. Set to 0 disable. <br /><br /><em>Note: This will not affect any user who has permission to edit other people\'s posts.</em>';

+ 2 - 0
Themes/default/languages/ManageSettings.english.php

@@ -26,6 +26,7 @@ $txt['time_format'] = 'Default time format';
 $txt['setting_time_offset'] = 'Overall time offset<div class="smalltext">(added to the member specific option.)</div>';
 $txt['setting_default_timezone'] = 'Server timezone';
 $txt['failed_login_threshold'] = 'Failed login threshold';
+$txt['loginHistoryDays'] = 'Days to keep login history';
 $txt['lastActive'] = 'User online time threshold';
 $txt['trackStats'] = 'Track daily statistics';
 $txt['hitStats'] = 'Track daily page views (must have stats enabled)';
@@ -48,6 +49,7 @@ $txt['localCookies'] = 'Enable local storage of cookies<div class="smalltext">(S
 $txt['globalCookies'] = 'Use subdomain independent cookies<div class="smalltext">(turn off local cookies first!)</div>';
 $txt['secureCookies'] = 'Force cookies to be secure<div class="smalltext">(This only applies if you are using HTTPS - don\'t use otherwise!)</div>';
 $txt['securityDisable'] = 'Disable administration security';
+$txt['securityDisable_moderate'] = 'Disable moderation security';
 $txt['send_validation_onChange'] = 'Require reactivation after email change';
 $txt['approveAccountDeletion'] = 'Require admin approval when member deletes account';
 $txt['autoOptMaxOnline'] = 'Maximum users online when optimizing<div class="smalltext">(0 for no max.)</div>';

+ 3 - 0
Themes/default/languages/Profile.english.php

@@ -159,6 +159,7 @@ $txt['editIgnoreList'] = 'Edit Ignore List';
 $txt['trackUser'] = 'Track User';
 $txt['trackActivity'] = 'Activity';
 $txt['trackIP'] = 'IP Address';
+$txt['trackLogins'] = 'Logins';
 
 $txt['authentication'] = 'Authentication';
 $txt['change_authentication'] = 'From this section you can change how you login to the forum. You may choose to either use an OpenID account for your authentication, or alternatively switch to use a username and password.';
@@ -196,12 +197,14 @@ $txt['members_from_ip'] = 'Members from IP (range)';
 $txt['members_in_range'] = 'Members possibly in the same range';
 $txt['messages_from_ip'] = 'Messages posted from IP (range)';
 $txt['messages_from_ip_desc'] = 'Below is a list of all messages posted from this IP (range).';
+$txt['trackLogins_desc'] = 'Below is a list of all times this account was logged into.';
 $txt['most_recent_ip'] = 'Most recent IP address';
 $txt['why_two_ip_address'] = 'Why are there two IP addresses listed?';
 $txt['no_errors_from_ip'] = 'No error messages from the specified IP (range) found';
 $txt['no_errors_from_user'] = 'No error messages from the specified user found';
 $txt['no_members_from_ip'] = 'No members from the specified IP (range) found';
 $txt['no_messages_from_ip'] = 'No messages from the specified IP (range) found';
+$txt['trackLogins_none_found'] = 'No recent logins where found';
 $txt['none'] = 'None';
 $txt['own_profile_confirm'] = 'Are you sure you want to delete your account?';
 $txt['view_ips_by'] = 'View IPs used by';