diff --git a/src/sbbs3/js_archive.c b/src/sbbs3/js_archive.c
index 56562d480fa378b567bb19c708d65b93f843d204..a5c679bcd82127da5e4b4ec210dd9b920c624999 100644
--- a/src/sbbs3/js_archive.c
+++ b/src/sbbs3/js_archive.c
@@ -559,48 +559,48 @@ js_read(JSContext *cx, uintN argc, jsval *arglist)
 
 static jsSyncMethodSpec js_archive_functions[] = {
 	{ "create",		js_create,		1,	JSTYPE_NUMBER
-		,JSDOCSTR("[string format] [,boolean with_path=false] [,array file_list]")
+		,JSDOCSTR("[<i>string</i> format] [,<i>bool</i> with_path=false] [,<i>array</i> file_list]")
 		,JSDOCSTR("Create an archive of the specified format (e.g. 'zip', '7z', 'tgz').<br>"
 			"Returns the number of files archived.<br>"
 			"Will throw exception upon error.")
 		,31900
 	},
 	{ "read",		js_read,		1,	JSTYPE_STRING
-		,JSDOCSTR("string path/filename")
+		,JSDOCSTR("<i>string</i> path/filename")
 		,JSDOCSTR("Read and return the contents of the specified archived text file.")
 		,31900
 	},
 	{ "extract",	js_extract,		1,	JSTYPE_NUMBER
-		,JSDOCSTR("output_directory [,boolean with_path=false] [,boolean overwrite=true] [,number max_files=0] [,string file/pattern [...]] [,boolean recurse=false]")
+		,JSDOCSTR("output_directory [,<i>bool</i> with_path=false] [,<i>bool</i> overwrite=true] [,<i>number</i> max_files=0] [,<i>string</i> file/pattern [...]] [,<i>bool</i> recurse=false]")
 		,JSDOCSTR("Extract files from an archive to specified output directory.<br>"
 			"Returns the number of files extracted.<br>"
 			"Will throw exception upon error.")
 		,31900
 	},
 	{ "list",		js_list,		1,	JSTYPE_ARRAY
-		,JSDOCSTR("[,boolean hash=false] [,string file/pattern]")
-		,JSDOCSTR("Get list of archive contents as an array of objects.<br>"
-			"Archived object properties:<br>"
-			"<ol>"
-			"<li>string <tt>type</tt> - item type: 'file', 'link', or 'directory'"
-			"<li>string <tt>name</tt> - item path/name"
-			"<li>string <tt>path</tt> - source path"
-			"<li>string <tt>symlink</tt>"
-			"<li>string <tt>hardlink</tt>"
-			"<li>number <tt>size</tt> - item size in bytes"
-			"<li>number <tt>time</tt> - modification date/time in time_t format"
-			"<li>number <tt>mode</tt> - permissions/mode flags"
-			"<li>string <tt>user</tt> - owner name"
-			"<li>string <tt>group</tt> - owner group"
-			"<li>string <tt>format</tt> - archive format"
-			"<li>string <tt>compression</tt> - compression method"
-			"<li>string <tt>fflags</tt>"
-			"<li>number <tt>crc16</tt> - 16-bit CRC, when hash is true and type is file"
-			"<li>number <tt>crc32</tt> - 32-bit CRC, when hash is true and type is file"
-			"<li>string <tt>md5</tt> - hexadecimal MD-5 sum, when hash is true and type is file"
-			"<li>string <tt>sha1</tt> - hexadecimal SHA-1 sum, when hash is true and type is file"
-			"</ol>"
-			"When <tt>hash</tt> is <tt>true</tt>, calculates and returns hash/digest values of files in stored archive.")
+		,JSDOCSTR("[,<i>bool</i> hash=false] [,<i>string</i> file/pattern]")
+		,JSDOCSTR("Get list of archive contents as an array of objects, optionally filtered by a specified path/filename pattern."
+			"<p>Archived object properties:<table>"
+			"<tr><th align=left>Name<th align=left>Type<th align=left>Description"
+			"<tr><td><tt>type</tt><td>string<td>Item type: 'file', 'link', or 'directory'"
+			"<tr><td><tt>name</tt><td>string<td>Item path/name"
+			"<tr><td><tt>path</tt><td>string<td>Source path"
+			"<tr><td><tt>symlink</tt><td>string"
+			"<tr><td><tt>hardlink</tt><td>string"
+			"<tr><td><tt>size</tt><td>number<td>Item size in bytes"
+			"<tr><td><tt>time</tt><td>number<td>Modification date/time in time_t format"
+			"<tr><td><tt>mode</tt><td>number<td>Permissions/mode flags"
+			"<tr><td><tt>user</tt><td>string<td>Owner name"
+			"<tr><td><tt>group</tt><td>string<td>Owner group"
+			"<tr><td><tt>format</tt><td>string<td>Archive format"
+			"<tr><td><tt>compression</tt><td>string<td>Compression method"
+			"<tr><td><tt>fflags</tt><td>string"
+			"<tr><td><tt>crc16</tt><td>number<td>16-bit CRC, when <i>hash</i> is true and <tt>type</tt> is 'file'"
+			"<tr><td><tt>crc32</tt><td>number<td>32-bit CRC, when <i>hash</i> is true and <tt>type</tt> is 'file'"
+			"<tr><td><tt>md5</tt><td>string<td>Hexadecimal MD-5 sum, when <i>hash</i> is true and <tt>type</tt> is 'file'"
+			"<tr><td><tt>sha1</tt><td>string<td>Hexadecimal SHA-1 sum, when <i>hash</i> is true and <tt>type</tt> is 'file'"
+			"</table>"
+			"<p>When the <tt>hash</tt> parameter is <tt>true</tt>, calculates and returns hash/digest values of files in stored archive.")
 		,31900
 	},
 	{0}
diff --git a/src/sbbs3/js_bbs.cpp b/src/sbbs3/js_bbs.cpp
index 1020dd16781bbe16ab5703160470a141a61bbf6f..33ab96a8cb1c910724e840c3b54da45b22fb779c 100644
--- a/src/sbbs3/js_bbs.cpp
+++ b/src/sbbs3/js_bbs.cpp
@@ -4431,31 +4431,31 @@ js_select_user(JSContext *cx, uintN argc, jsval *arglist)
 
 static jsSyncMethodSpec js_bbs_functions[] = {
 	{"atcode",			js_atcode,			1,	JSTYPE_STRING,	JSDOCSTR("code_string")
-	,JSDOCSTR("Returns @-code value, specified <i>code</i> string does not include @ character delimiters")
+	,JSDOCSTR("Return @-code value, specified <i>code</i> string does not include @ character delimiters")
 	,310
 	},
 	{"expand_atcodes",	js_expand_atcodes,	1,	JSTYPE_STRING,	JSDOCSTR("string")
-	,JSDOCSTR("Returns string with @-code expanded values (formatting and some @-codes are not supported)")
+	,JSDOCSTR("Return string with @-code expanded values (formatting and some @-codes are not supported)")
 	,320
 	},
 	/* text.dat */
-	{"text",			js_text,			1,	JSTYPE_STRING,	JSDOCSTR("index_number [,default_text=<i>false</i>]")
-	,JSDOCSTR("Returns current text string (specified via 1-based string index number)"
+	{"text",			js_text,			1,	JSTYPE_STRING,	JSDOCSTR("index_number [,<i>bool</i> default_text=false]")
+	,JSDOCSTR("Return current text string (specified via 1-based string index number)"
 		"from text.dat/text.ini or replacement text or <i>null</i> upon error"
 		"<p>"
 		"<i>New in v3.20:</i><br>"
-		"Use <tt>bbs.text.<i>ID</i><tt> to obtain a text string index number from its corresponding ID (name).<br>"
-		"The <tt>default_text</tt> argument can be used to get a default langage (text.dat) string value."
+		"Use <tt>bbs.text.<i>ID</i></tt> to obtain a text string index number from its corresponding ID (name).<br>"
+		"The <tt>default_text</tt> argument can be used to get a <i>default</i> language (i.e. <tt>text.dat</tt> file) string value."
 	)
 	,310
 	},
 	{"replace_text",	js_replace_text,	2,	JSTYPE_BOOLEAN,	JSDOCSTR("index_number, text")
-	,JSDOCSTR("Replaces specified text.dat/text.ini string in memory")
+	,JSDOCSTR("Replace specified text.dat/text.ini string in memory")
 	,310
 	},
-	{"revert_text",		js_revert_text,		1,	JSTYPE_BOOLEAN,	JSDOCSTR("[index_number=<i>all</i>]")
-	,JSDOCSTR("Reverts specified text string to original text.dat/text.ini string; "
-		"if <i>index_number</i> unspecified, reverts all text lines")
+	{"revert_text",		js_revert_text,		1,	JSTYPE_BOOLEAN,	JSDOCSTR("[<i>number</i> index=<i>all</i>]")
+	,JSDOCSTR("Revert specified text string to original <tt>text.dat/text.ini</tt> string; "
+		"if <i>index</i> unspecified, reverts all text lines")
 	,310
 	},
 	{"load_text",		js_load_text,		1,	JSTYPE_BOOLEAN,	JSDOCSTR("base_filename")
@@ -4468,7 +4468,7 @@ static jsSyncMethodSpec js_bbs_functions[] = {
 	},
 	/* procedures */
 	{"newuser",			js_newuser,			0,	JSTYPE_VOID,	JSDOCSTR("")
-	,JSDOCSTR("Interactive new user procedure")
+	,JSDOCSTR("Initiate interactive new user registration procedure")
 	,310
 	},
 	{"login",			js_login,			4,	JSTYPE_BOOLEAN,	JSDOCSTR("user_name [,password_prompt] [,user_password] [,system_password]")
@@ -4477,26 +4477,26 @@ static jsSyncMethodSpec js_bbs_functions[] = {
 	,310
 	},
 	{"logon",			js_logon,			0,	JSTYPE_BOOLEAN,	JSDOCSTR("")
-	,JSDOCSTR("Interactive user-logon procedure")
+	,JSDOCSTR("Initiate interactive user-logon procedure")
 	,310
 	},
-	{"logoff",			js_logoff,			1,	JSTYPE_BOOLEAN,	JSDOCSTR("[prompt=<i>true</i>]")
-	,JSDOCSTR("Interactive user-logoff procedure, pass <i>false</i> for <i>prompt</i> argument to avoid yes/no prompt, returns <i>false</i> if denied logoff, "
+	{"logoff",			js_logoff,			1,	JSTYPE_BOOLEAN,	JSDOCSTR("[prompt=true]")
+	,JSDOCSTR("Initiate interactive user-logoff procedure, pass <tt>false</tt> for <i>prompt</i> argument to avoid yes/no prompt, returns <tt>false</tt> if denied logoff, "
 		"hangs-up (disconnects) upon completion of logoff")
 	,315
 	},
 	{"logout",			js_logout,			0,	JSTYPE_VOID,	JSDOCSTR("")
-	,JSDOCSTR("Non-interactive user-logout procedure, invoked implicitly upon user-disconnect. Only invoke this method to force a logout without a disconnect.")
+	,JSDOCSTR("Initiate non-interactive user-logout procedure, invoked implicitly upon user-disconnect. Only invoke this method to force a logout without a disconnect.")
 	,310
 	},
 	{"hangup",			js_hangup,			0,	JSTYPE_VOID,	JSDOCSTR("")
-	,JSDOCSTR("Hangup (disconnect) the connected user/client immediately")
+	,JSDOCSTR("Hang-up (disconnect) the connected user/client immediately")
 	,310
 	},
 	{"node_sync",		js_nodesync,		1,	JSTYPE_ALIAS },
-	{"nodesync",		js_nodesync,		1,	JSTYPE_VOID,	JSDOCSTR("[clear-line=<i>false</i>]")
+	{"nodesync",		js_nodesync,		1,	JSTYPE_VOID,	JSDOCSTR("[clear-line=false]")
 	,JSDOCSTR("Synchronize with node database, checks for messages, interruption, etc. (AKA node_sync), "
-	"clears the current console line if there's a message to print when <i>clear-line</i> is <i>true</i>.")
+	"clears the current console line if there's a message to print when <i>clear-line</i> is <tt>true</tt>.")
 	,310
 	},
 	{"auto_msg",		js_automsg,			0,	JSTYPE_VOID,	JSDOCSTR("")
@@ -4598,16 +4598,16 @@ static jsSyncMethodSpec js_bbs_functions[] = {
 	,JSDOCSTR("Display system statistics")
 	,310
 	},
-	{"node_stats",		js_node_stats,		0,	JSTYPE_VOID,	JSDOCSTR("[node_number=<i>current</i>]")
+	{"node_stats",		js_node_stats,		0,	JSTYPE_VOID,	JSDOCSTR("[<i>number</i> node=<i>current</i>]")
 	,JSDOCSTR("Display current (or specified) node statistics")
 	,310
 	},
-	{"list_users",		js_userlist,		0,	JSTYPE_VOID,	JSDOCSTR("[mode=<tt>UL_ALL</tt>]")
+	{"list_users",		js_userlist,		0,	JSTYPE_VOID,	JSDOCSTR("[mode=UL_ALL]")
 	,JSDOCSTR("Display user list"
 	"(see <tt>UL_*</tt> in <tt>sbbsdefs.js</tt> for valid <i>mode</i> values)")
 	,310
 	},
-	{"edit_user",		js_useredit,		0,	JSTYPE_VOID,	JSDOCSTR("[user_number=<i>current</i>]")
+	{"edit_user",		js_useredit,		0,	JSTYPE_VOID,	JSDOCSTR("[<i>number</i> user=<i>current</i>]")
 	,JSDOCSTR("Enter the user editor")
 	,310
 	},
@@ -4619,17 +4619,17 @@ static jsSyncMethodSpec js_bbs_functions[] = {
 	,JSDOCSTR("Display the logon list (optionally passing arguments to the logon list module)")
 	,310
 	},
-	{"read_mail",		js_readmail,		0,	JSTYPE_NUMBER,	JSDOCSTR("[which=<tt>MAIL_YOUR</tt>] [,user_number=<i>current</i>] [,loadmail_mode=<tt>0</tt>]")
+	{"read_mail",		js_readmail,		0,	JSTYPE_NUMBER,	JSDOCSTR("[<i>number</i> which=MAIL_YOUR] [,<i>number</i> user=<i>current</i>] [,<i>number</i> loadmail_mode=0]")
 	,JSDOCSTR("Read private e-mail"
 	"(see <tt>MAIL_*</tt> in <tt>sbbsdefs.js</tt> for valid <i>which</i> values), returns user-modified loadmail_mode value")
 	,310
 	},
-	{"email",			js_email,			1,	JSTYPE_BOOLEAN,	JSDOCSTR("to_user_number [,mode=<tt>WM_EMAIL</tt>] [,top=<i>none</i>] [,subject=<i>none</i>] [,object reply_header]")
-	,JSDOCSTR("Send private e-mail to a local user (<i>reply_header</i> added in v3.17c)")
+	{"email",			js_email,			1,	JSTYPE_BOOLEAN,	JSDOCSTR("<i>number</i> to_user [,<i>number</i> mode=WM_EMAIL] [,<i>string</i> top=none] [,<i>string</i> subject=none] [,<i>object</i> reply_header]")
+	,JSDOCSTR("Send private e-mail to a local user")
 	,310
 	},
-	{"netmail",			js_netmail,			1,	JSTYPE_BOOLEAN,	JSDOCSTR("[string address or array of addresses] [,mode=<tt>WM_NONE</tt>] [,subject=<i>none</i>] [,object reply_header]")
-	,JSDOCSTR("Send private netmail (<i>reply_header</i> added in v3.17c, <i>array of addresses</i> added in v3.18a)")
+	{"netmail",			js_netmail,			1,	JSTYPE_BOOLEAN,	JSDOCSTR("[<i>string</i> address or <i>array</i> of addresses] [,<i>number</i> mode=WM_NONE] [,<i>string</i> subject=none] [,<i>object</i> reply_header]")
+	,JSDOCSTR("Send private netmail")
 	,310
 	},
 	{"bulk_mail",		js_bulkmail,		0,	JSTYPE_VOID,	JSDOCSTR("[ars]")
@@ -4645,55 +4645,55 @@ static jsSyncMethodSpec js_bbs_functions[] = {
 		"specified by number or internal code")
 	,310
 	},
-	{"export_filelist",	js_export_filelist,	2,	JSTYPE_NUMBER,	JSDOCSTR("filename [,mode=<tt>FL_NONE</tt>]")
+	{"export_filelist",	js_export_filelist,	2,	JSTYPE_NUMBER,	JSDOCSTR("filename [,<i>number</i> mode=FL_NONE]")
 	,JSDOCSTR("Export list of files to a text file, optionally specifying a file list mode (e.g. <tt>FL_ULTIME</tt>), returning the number of files listed")
 	,319
 	},
-	{"list_files",		js_listfiles,		1,	JSTYPE_NUMBER,	JSDOCSTR("[directory=<i>current</i>] [,filespec=<tt>\"*.*\"</tt> or search_string] [,mode=<tt>FL_NONE</tt>]")
+	{"list_files",		js_listfiles,		1,	JSTYPE_NUMBER,	JSDOCSTR("[directory=<i>current</i>] [,<i>string</i> filespec=\"*.*\" or search_string] [,<i>number</i> mode=FL_NONE]")
 	,JSDOCSTR("List files in the specified file directory, "
 		"optionally specifying a file specification (wildcards) or a description search string, "
 		"and <i>mode</i> (bit-flags)")
 	,310
 	},
-	{"list_file_info",	js_listfileinfo,	1,	JSTYPE_NUMBER,	JSDOCSTR("[directory=<i>current</i>] [,filespec=<tt>\"*.*\"</tt>] [,mode=<tt>FI_INFO</tt>]")
+	{"list_file_info",	js_listfileinfo,	1,	JSTYPE_NUMBER,	JSDOCSTR("[directory=<i>current</i>] [,<i>string</i> filespec=\"*.*\"] [,<i>number</i> mode=FI_INFO]")
 	,JSDOCSTR("List extended file information for files in the specified file directory")
 	,310
 	},
-	{"post_msg",		js_post_msg,		1,	JSTYPE_BOOLEAN,	JSDOCSTR("[sub-board=<i>current</i>] [,mode=<tt>WM_NONE</tt>] [,object reply_header]")
+	{"post_msg",		js_post_msg,		1,	JSTYPE_BOOLEAN,	JSDOCSTR("[sub-board=<i>current</i>] [,<i>number</i> mode=WM_NONE] [,<i>object</i> reply_header]")
 	,JSDOCSTR("Post a message in the specified message sub-board (number or internal code) "
 		"with optional <i>mode</i> (bit-flags)<br>"
 		"If <i>reply_header</i> is specified (a header object returned from <i>MsgBase.get_msg_header()</i>), that header "
 		"will be used for the in-reply-to header fields.")
 	,313
 	},
-	{"forward_msg",		js_forward_msg,		2,	JSTYPE_BOOLEAN,	JSDOCSTR("object header, string to [,string subject] [,string comment]")
+	{"forward_msg",		js_forward_msg,		2,	JSTYPE_BOOLEAN,	JSDOCSTR("<i>object</i> header, <i>string</i> to [,<i>string</i> subject] [,<i>string</i> comment]")
 	,JSDOCSTR("Forward a message")
 	,31802
 	},
-	{"edit_msg",		js_edit_msg,		1,	JSTYPE_BOOLEAN,	JSDOCSTR("object header")
+	{"edit_msg",		js_edit_msg,		1,	JSTYPE_BOOLEAN,	JSDOCSTR("<i>object</i> header")
 	,JSDOCSTR("Edit a message")
 	,31802
 	},
-	{"show_msg",		js_show_msg,		1,	JSTYPE_BOOLEAN,	JSDOCSTR("object header [,mode=<tt>P_NONE</tt>] ")
+	{"show_msg",		js_show_msg,		1,	JSTYPE_BOOLEAN,	JSDOCSTR("<i>object</i> header [,<i>number</i> mode=P_NONE] ")
 	,JSDOCSTR("Show a message's header and body (text) with optional print <i>mode</i> (bit-flags)<br>"
 		"<i>header</i> must be a header object returned from <i>MsgBase.get_msg_header()</i>)")
 	,31702
 	},
-	{"show_msg_header",	js_show_msg_header,	1,	JSTYPE_VOID,	JSDOCSTR("object header [,subject] [,from] [,to]")
+	{"show_msg_header",	js_show_msg_header,	1,	JSTYPE_VOID,	JSDOCSTR("<i>object</i> header [,<i>string</i> subject] [,<i>string</i> from] [,<i>string</i> to]")
 	,JSDOCSTR("Show a message's header (only)<br>"
 		"<i>header</i> must be a header object returned from <i>MsgBase.get_msg_header()</i>)")
 	,31702
 	},
-	{"download_msg_attachments", js_download_msg_attachments, 1, JSTYPE_VOID, JSDOCSTR("object header")
+	{"download_msg_attachments", js_download_msg_attachments, 1, JSTYPE_VOID, JSDOCSTR("<i>object</i> header")
 	,JSDOCSTR("Prompt the user to download each of the message's file attachments (if there are any)<br>"
 		"<i>header</i> must be a header object returned from <i>MsgBase.get_msg_header()</i>)")
 	,31702
 	},
-	{"change_msg_attr", js_change_msg_attr, 1, JSTYPE_NUMBER, JSDOCSTR("object header")
+	{"change_msg_attr", js_change_msg_attr, 1, JSTYPE_NUMBER, JSDOCSTR("<i>object</i> header")
 	,JSDOCSTR("Prompt the user to modify the specified message header attributes")
 	,31702
 	},
-	{"cfg_msg_scan",	js_msgscan_cfg,		0,	JSTYPE_VOID,	JSDOCSTR("[type=<tt>SCAN_CFG_NEW</tt>]")
+	{"cfg_msg_scan",	js_msgscan_cfg,		0,	JSTYPE_VOID,	JSDOCSTR("[<i>number</i> type=SCAN_CFG_NEW]")
 	,JSDOCSTR("Configure message scan "
 		"(<i>type</i> is either <tt>SCAN_CFG_NEW</tt> or <tt>SCAN_CFG_TOYOU</tt>)")
 	,310
@@ -4711,30 +4711,30 @@ static jsSyncMethodSpec js_bbs_functions[] = {
 	,320
 	},
 	{"reload_msg_scan",	js_reload_msg_scan,	0,	JSTYPE_VOID,	JSDOCSTR("")
-	,JSDOCSTR("Re-loads message scan configuration and pointers from userbase")
+	,JSDOCSTR("Re-load message scan configuration and pointers from userbase")
 	,320
 	},
-	{"scan_subs",		js_scansubs,		0,	JSTYPE_VOID,	JSDOCSTR("[mode=<tt>SCAN_NEW</tt>] [,all=<tt>false</tt>]")
+	{"scan_subs",		js_scansubs,		0,	JSTYPE_VOID,	JSDOCSTR("[<i>number</i> mode=SCAN_NEW] [,<i>bool</i> all=false]")
 	,JSDOCSTR("Scan sub-boards for messages")
 	,310
 	},
-	{"scan_dirs",		js_scandirs,		0,	JSTYPE_VOID,	JSDOCSTR("[mode=<tt>FL_NONE</tt>] [,all=<tt>false</tt>]")
+	{"scan_dirs",		js_scandirs,		0,	JSTYPE_VOID,	JSDOCSTR("[<i>number</i> mode=FL_NONE] [,<i>bool<?i> all=false]")
 	,JSDOCSTR("Scan directories for files")
 	,310
 	},
 	{"scan_posts",		js_scanposts,		1,	JSTYPE_ALIAS },
-	{"scan_msgs",		js_scanposts,		1,	JSTYPE_BOOLEAN,	JSDOCSTR("[sub-board=<i>current</i>] [,mode=<tt>SCAN_READ</tt>] [,find]")
+	{"scan_msgs",		js_scanposts,		1,	JSTYPE_BOOLEAN,	JSDOCSTR("[sub-board=<i>current</i>] [,<i>number</i> mode=SCAN_READ] [,<i>string</i> find]")
 	,JSDOCSTR("Scan messages in the specified message sub-board (number or internal code), "
 		"optionally search for 'find' string (AKA scan_posts)")
 	,310
 	},
-	{"list_msgs",		js_listmsgs,		1,	JSTYPE_NUMBER,	JSDOCSTR("[sub-board=<i>current</i>] [,mode=<tt>SCAN_INDEX</tt>] [,message_number=<tt>0</tt>] [,find]")
+	{"list_msgs",		js_listmsgs,		1,	JSTYPE_NUMBER,	JSDOCSTR("[sub-board=<i>current</i>] [,<i>number</i> mode=SCAN_INDEX] [,<i>number</i> message_number=0] [,<i>string</i> find]")
 	,JSDOCSTR("List messages in the specified message sub-board (number or internal code), "
 		"optionally search for 'find' string, returns number of messages listed")
 	,314
 	},
 	/* menuing */
-	{"menu",			js_menu,			1,	JSTYPE_BOOLEAN,	JSDOCSTR("base_filename [,mode=<tt>P_NONE</tt>] [,object scope]")
+	{"menu",			js_menu,			1,	JSTYPE_BOOLEAN,	JSDOCSTR("base_filename [,<i>number</i> mode=P_NONE] [,<i>object</i> scope]")
 	,JSDOCSTR("Display a menu file from the text/menu directory.<br>"
 	"See <tt>P_*</tt> in <tt>sbbsdefs.js</tt> for <i>mode</i> flags.<br>"
 	"When <i>scope</i> is specified, <tt>@JS:property@</tt> codes will expand the referenced property names.<br>"
@@ -4742,10 +4742,10 @@ static jsSyncMethodSpec js_bbs_functions[] = {
 	,310
 	},
 	{"menu_exists",		js_menu_exists,		1,	JSTYPE_BOOLEAN,	JSDOCSTR("base_filename")
-	,JSDOCSTR("Returns true if the referenced menu file exists (i.e. in the text/menu directory)")
+	,JSDOCSTR("Return true if the referenced menu file exists (i.e. in the text/menu directory)")
 	,31700
 	},
-	{"log_key",			js_logkey,			1,	JSTYPE_BOOLEAN,	JSDOCSTR("key [,comma=<tt>false</tt>]")
+	{"log_key",			js_logkey,			1,	JSTYPE_BOOLEAN,	JSDOCSTR("key [,comma=false]")
 	,JSDOCSTR("Log key to node.log (comma optional)")
 	,310
 	},
@@ -4763,7 +4763,7 @@ static jsSyncMethodSpec js_bbs_functions[] = {
 	,310
 	},
 	/* xtrn programs/modules */
-	{"exec",			js_exec,			2,	JSTYPE_NUMBER,	JSDOCSTR("cmdline [,mode=<tt>EX_NONE</tt>] [,startup_dir]")
+	{"exec",			js_exec,			2,	JSTYPE_NUMBER,	JSDOCSTR("cmdline [,<i>number</i> mode=EX_NONE] [,<i>string</i> startup_dir]")
 	,JSDOCSTR("Execute a program, optionally changing current directory to <i>startup_dir</i> "
 	"(see <tt>EX_*</tt> in <tt>sbbsdefs.js</tt> for valid <i>mode</i> flags.)")
 	,310
@@ -4777,18 +4777,19 @@ static jsSyncMethodSpec js_bbs_functions[] = {
 	"(see <tt>EVENT_*</tt> in <tt>sbbsdefs.js</tt> for valid values)")
 	,310
 	},
-	{"telnet_gate",		js_telnet_gate,		1,	JSTYPE_BOOLEAN,	JSDOCSTR("address[:port] [,mode=<tt>TG_NONE</tt>] [,timeout=<tt>10</tt>]")
+	{"telnet_gate",		js_telnet_gate,		1,	JSTYPE_BOOLEAN,	JSDOCSTR("address[:port] [,<i>number</i> mode=TG_NONE] [,<i>number</i> timeout=10]")
 	,JSDOCSTR("External Telnet gateway (see <tt>TG_*</tt> in <tt>sbbsdefs.js</tt> for valid <i>mode</i> flags).")
 	,310
 	},
-	{"rlogin_gate",		js_rlogin_gate,		1,	JSTYPE_BOOLEAN,	JSDOCSTR("address[:port] [,client-user-name=<tt>user.alias</tt>, server-user-name=<tt>user.name</tt>, terminal=<tt>console.terminal</tt>] [,mode=<tt>TG_NONE</tt>]  [,timeout=<tt>10</tt>]")
+	{"rlogin_gate",		js_rlogin_gate,		1,	JSTYPE_BOOLEAN
+	,JSDOCSTR("address[:port] [,<i>string</i> client-user-name=<i>user.alias</i>, <i>string</i> server-user-name=<i>user.name</i>, <i>string</i> terminal=<i>console.terminal</i>] [,<i>number</i> mode=TG_NONE]  [,<i>number</i> timeout=10]")
 	,JSDOCSTR("External RLogin gateway (see <tt>TG_*</tt> in <tt>sbbsdefs.js</tt> for valid <i>mode</i> flags).")
 	,316
 	},
 	/* security */
 	{"check_filename",	js_checkfname,		1,	JSTYPE_BOOLEAN,	JSDOCSTR("filename")
 	,JSDOCSTR("Verify that the specified <i>filename</i> string is legal and allowed for upload "
-		"(based on system configuration), returns <i>true</i> if the filename is allowed.<br>"
+		"(based on system configuration), returns <tt>true</tt> if the filename is allowed.<br>"
 		"Note: Will display <tt>text/badfile.msg</tt> for matching filenames, if it exists.")
 	,31902
 	},
@@ -4803,7 +4804,7 @@ static jsSyncMethodSpec js_bbs_functions[] = {
 	},
 	/* chat/node stuff */
 	{"page_sysop",		js_pagesysop,		0,	JSTYPE_BOOLEAN,	JSDOCSTR("")
-	,JSDOCSTR("Page the sysop for chat, returns <i>false</i> if the sysop could not be paged")
+	,JSDOCSTR("Page the sysop for chat, returns <tt>false</tt> if the sysop could not be paged")
 	,310
 	},
 	{"page_guru",		js_pageguru,		0,	JSTYPE_BOOLEAN,	JSDOCSTR("")
@@ -4818,23 +4819,23 @@ static jsSyncMethodSpec js_bbs_functions[] = {
 	,JSDOCSTR("Use the private inter-node message prompt")
 	,310
 	},
-	{"private_chat",	js_private_chat,	0,	JSTYPE_VOID,	JSDOCSTR("[local=<i>false</i>]")
-	,JSDOCSTR("Enter private inter-node chat, or local sysop chat (if <i>local</i>=<i>true</i>)")
+	{"private_chat",	js_private_chat,	0,	JSTYPE_VOID,	JSDOCSTR("[local=false]")
+	,JSDOCSTR("Enter private inter-node chat, or local sysop chat (if <i>local</i>=<tt>true</tt>)")
 	,310
 	},
-	{"get_node_message",js_get_node_message,1,	JSTYPE_VOID,	JSDOCSTR("[clearline=<i>false</i>]")
+	{"get_node_message",js_get_node_message,1,	JSTYPE_VOID,	JSDOCSTR("[<i>bool</i> clear-line=false]")
 	,JSDOCSTR("Receive and display an inter-node message")
 	,310
 	},
-	{"put_node_message",js_put_node_message,2,	JSTYPE_BOOLEAN,	JSDOCSTR("[node_number] [,text]")
+	{"put_node_message",js_put_node_message,2,	JSTYPE_BOOLEAN,	JSDOCSTR("[<i>number</i> node_number] [,text]")
 	,JSDOCSTR("Send an inter-node message (specify a <i>node_number</i> value of <tt>-1</tt> for 'all active nodes')")
 	,31700
 	},
-	{"get_telegram",	js_get_telegram,	2,	JSTYPE_VOID,	JSDOCSTR("[user_number=<i>current</i>], [clearline=<i>false</i>]")
+	{"get_telegram",	js_get_telegram,	2,	JSTYPE_VOID,	JSDOCSTR("[<i>number</i> user_number=<i>current</i>], [<i>bool</i> clear-line=false]")
 	,JSDOCSTR("Receive and display waiting telegrams for specified (or current) user")
 	,310
 	},
-	{"put_telegram",	js_put_telegram,	2,	JSTYPE_BOOLEAN,	JSDOCSTR("[user_number] [,text]")
+	{"put_telegram",	js_put_telegram,	2,	JSTYPE_BOOLEAN,	JSDOCSTR("[<i>number</i> user_number] [,text]")
 	,JSDOCSTR("Send a telegram (short multi-line stored message) to a user")
 	,31700
 	},
@@ -4846,21 +4847,21 @@ static jsSyncMethodSpec js_bbs_functions[] = {
 	,JSDOCSTR("List active nodes only (who's online)")
 	,310
 	},
-	{"spy",				js_spy,				1,	JSTYPE_VOID,	JSDOCSTR("node_number")
+	{"spy",				js_spy,				1,	JSTYPE_VOID,	JSDOCSTR("<i>number</i> node")
 	,JSDOCSTR("Spy on a node")
 	,310
 	},
 	/* misc */
-	{"cmdstr",			js_cmdstr,			1,	JSTYPE_STRING,	JSDOCSTR("command_string [,fpath=<tt>\"\"</tt>] [,fspec=<tt>\"\"</tt>]")
+	{"cmdstr",			js_cmdstr,			1,	JSTYPE_STRING,	JSDOCSTR("command_string [,<i>string</i> fpath=\"\"] [,<i>string</i> fspec=\"\"]")
 	,JSDOCSTR("Return expanded command string using Synchronet command-line specifiers")
 	,310
 	},
 	/* input */
 	{"get_filespec",	js_getfilespec,		0,	JSTYPE_STRING,	JSDOCSTR("")
-	,JSDOCSTR("Returns a file specification input by the user (optionally with wildcards)")
+	,JSDOCSTR("Return a file specification input by the user (optionally with wildcards)")
 	,310
 	},
-	{"get_newscantime",	js_getnstime,		1,	JSTYPE_NUMBER,	JSDOCSTR("time=<i>current</i>")
+	{"get_newscantime",	js_getnstime,		1,	JSTYPE_NUMBER,	JSDOCSTR("[<i>number</i> time=<i>current</i>]")
 	,JSDOCSTR("Confirm or change a new-scan time, returns the new new-scan time value (<i>time_t</i> format)")
 	,310
 	},
@@ -4881,7 +4882,7 @@ static jsSyncMethodSpec js_bbs_functions[] = {
 	,JSDOCSTR("Verify the current user online meets the specified Access Requirements String")
 	,315
 	},
-	{"select_node",		js_select_node,		1,	JSTYPE_NUMBER,	JSDOCSTR("all_is_an_option=<i>false</i>")
+	{"select_node",		js_select_node,		1,	JSTYPE_NUMBER,	JSDOCSTR("<i>bool</i> all_is_an_option=false")
 	,JSDOCSTR("Choose an active node to interact with.<br>Returns the selected node number, 0 (for none) or -1 for 'All'.")
 	,31700
 	},
diff --git a/src/sbbs3/js_com.c b/src/sbbs3/js_com.c
index 03a7e6e0f10a36d13c6357f266734a0ec8c8bbf3..d1f892a7588d1d4a0b8a66b23eca6969da19160d 100644
--- a/src/sbbs3/js_com.c
+++ b/src/sbbs3/js_com.c
@@ -514,10 +514,10 @@ enum {
 #ifdef BUILD_JSDOCS
 static char* com_prop_desc[] = {
 	 "Error status for the last COM operation that failed - <small>READ ONLY</small>"
-	,"<i>true</i> if port is in a connected state - <small>READ ONLY</small>"
+	,"<tt>true</tt> if port is in a connected state - <small>READ ONLY</small>"
 	,"Enable debug logging"
 	,"COM handle (advanced uses only)"
-	,"<i>true</i> if binary data is to be sent in Network Byte Order (big end first), default is <i>true</i>"
+	,"<tt>true</tt> if binary data is to be sent in Network Byte Order (big end first), default is <tt>true</tt>"
 	,"COM port Baud rate"
 	,"Device name"
 	,"Data Terminal Ready"
@@ -713,23 +713,23 @@ static jsSyncMethodSpec js_com_functions[] = {
 	,315
 	},
 	{"writeBin",	js_sendbin,		1,	JSTYPE_ALIAS },
-	{"sendBin",		js_sendbin,		1,	JSTYPE_BOOLEAN,	JSDOCSTR("value [,bytes=<tt>4</tt>]")
+	{"sendBin",		js_sendbin,		1,	JSTYPE_BOOLEAN,	JSDOCSTR("value [,bytes=4]")
 	,JSDOCSTR("Send a binary integer over the port, default number of bytes is 4 (32-bits)")
 	,315
 	},
 	{"read",		js_recv,		1,	JSTYPE_ALIAS },
-	{"recv",		js_recv,		1,	JSTYPE_STRING,	JSDOCSTR("[maxlen=<tt>512</tt> [,timeout=<tt>30</tt>]]")
+	{"recv",		js_recv,		1,	JSTYPE_STRING,	JSDOCSTR("[maxlen=512 [,timeout=30]]")
 	,JSDOCSTR("Receive a string, default maxlen is 512 characters, default timeout is 30 seconds (AKA read)")
 	,315
 	},
 	{"readline",	js_recvline,	0,	JSTYPE_ALIAS },
 	{"readln",		js_recvline,	0,	JSTYPE_ALIAS },
-	{"recvline",	js_recvline,	0,	JSTYPE_STRING,	JSDOCSTR("[maxlen=<tt>512</tt>] [,timeout=<tt>30.0</tt>]")
+	{"recvline",	js_recvline,	0,	JSTYPE_STRING,	JSDOCSTR("[maxlen=512] [,timeout=30.0]")
 	,JSDOCSTR("Receive a line-feed terminated string, default maxlen is 512 characters, default timeout is 30 seconds (AKA readline and readln)")
 	,315
 	},
 	{"readBin",		js_recvbin,		0,	JSTYPE_ALIAS },
-	{"recvBin",		js_recvbin,		0,	JSTYPE_NUMBER,	JSDOCSTR("[bytes=<tt>4</tt> [,timeout=<tt>30</tt>]")
+	{"recvBin",		js_recvbin,		0,	JSTYPE_NUMBER,	JSDOCSTR("[bytes=4 [,timeout=30]")
 	,JSDOCSTR("Receive a binary integer from the port, default number of bytes is 4 (32-bits), default timeout is 30 seconds")
 	,315
 	},
@@ -816,7 +816,7 @@ js_com_constructor(JSContext *cx, uintN argc, jsval *arglist)
 #ifdef BUILD_JSDOCS
 	js_DescribeSyncObject(cx,obj,"Class used for serial port communications",31501);
 	js_DescribeSyncConstructor(cx,obj,"To create a new COM object: "
-		"var c = new COM('<i>device</i>')</tt><br>"
+		"<tt>var c = new COM('<i>device</i>')</tt><br>"
 		"where <i>device</i> = <tt>COMx</tt> (e.g. COM1) for Win32 or <tt>/dev/ttyXY</tt> for *nix (e.g. /dev/ttyu0)"
 		);
 	js_CreateArrayOfStrings(cx, obj, "_property_desc_list", com_prop_desc, JSPROP_READONLY);
diff --git a/src/sbbs3/js_conio.c b/src/sbbs3/js_conio.c
index 8fbe1f31c47a30d2ea2271968beb7f8404588727..cf95dbc470d695d704bc0ab6f9e2fa17400be6e5 100644
--- a/src/sbbs3/js_conio.c
+++ b/src/sbbs3/js_conio.c
@@ -1,9 +1,5 @@
-/* js_conio.c */
-
 /* Synchronet "conio" (console IO) object */
 
-/* $Id: js_conio.c,v 1.38 2020/04/12 20:30:48 rswindell Exp $ */
-
 /****************************************************************************
  * @format.tab-size 4		(Plain Text/Source Code File Header)			*
  * @format.use-tabs true	(see http://www.synchro.net/ptsc_hdr.html)		*
@@ -17,21 +13,9 @@
  * See the GNU General Public License for more details: gpl.txt or			*
  * http://www.fsf.org/copyleft/gpl.html										*
  *																			*
- * Anonymous FTP access to the most recent released source is available at	*
- * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net	*
- *																			*
- * Anonymous CVS access to the development source and modification history	*
- * is available at cvs.synchro.net:/cvsroot/sbbs, example:					*
- * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs login			*
- *     (just hit return, no password is necessary)							*
- * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs checkout src		*
- *																			*
  * For Synchronet coding style and modification guidelines, see				*
  * http://www.synchro.net/source.html										*
  *																			*
- * You are encouraged to submit any modifications (preferably in Unix diff	*
- * format) via e-mail to mods@synchro.net									*
- *																			*
  * Note: If this box doesn't appear square, then you need to fix your tabs.	*
  ****************************************************************************/
 
@@ -1029,7 +1013,7 @@ js_conio_ungetmouse(JSContext *cx, uintN argc, jsval *arglist)
 static jsSyncMethodSpec js_functions[] = {
 	{"init",			js_conio_init,			1
 		,JSTYPE_BOOLEAN,JSDOCSTR("[mode]")
-		,JSDOCSTR("Initializes the conio library and creates a window if needed.  "
+		,JSDOCSTR("Initialize the conio library and creates a window if needed.  "
 				"Mode is a string with one of the following values:<br>"
 				"<table><tr><td>\"AUTO\" (default)</td><td>Automatically select the \"best\" output mode.</td></tr><tr><td>"
 				"<tr><td>\"ANSI\"</td><td>Use ANSI escape sequences directly</td></tr><tr><td>"
@@ -1047,7 +1031,7 @@ static jsSyncMethodSpec js_functions[] = {
 	},
 	{"suspend",			js_conio_suspend,		0
 		,JSTYPE_VOID,JSDOCSTR("")
-		,JSDOCSTR("Suspends conio in CONIO or CURSES modes so the terminal can be used for other things."),315
+		,JSDOCSTR("Suspend conio in CONIO or CURSES modes so the terminal can be used for other things."),315
 	},
 	{"clreol",			js_conio_clreol,		0
 		,JSTYPE_VOID,JSDOCSTR("")
@@ -1055,51 +1039,51 @@ static jsSyncMethodSpec js_functions[] = {
 	},
 	{"clrscr",			js_conio_clrscr,		0
 		,JSTYPE_VOID,JSDOCSTR("")
-		,JSDOCSTR("Clears the screen"),315
+		,JSDOCSTR("Clear the screen"),315
 	},
 	{"wscroll",			js_conio_wscroll,		0
 		,JSTYPE_VOID,JSDOCSTR("")
-		,JSDOCSTR("Scrolls the currently defined window up by one line."),315
+		,JSDOCSTR("Scroll the currently defined window up by one line."),315
 	},
 	{"delline",			js_conio_delline,		0
 		,JSTYPE_VOID,JSDOCSTR("")
-		,JSDOCSTR("Deletes the current line and moves lines below up by one line."),315
+		,JSDOCSTR("Delete the current line and moves lines below up by one line."),315
 	},
 	{"insline",			js_conio_insline,		0
 		,JSTYPE_VOID,JSDOCSTR("")
-		,JSDOCSTR("Inserts a new blank line on the current line and scrolls lines below down to make room."),315
+		,JSDOCSTR("Insert a new blank line on the current line and scrolls lines below down to make room."),315
 	},
 	{"normvideo",		js_conio_normvideo,		0
 		,JSTYPE_VOID,JSDOCSTR("")
-		,JSDOCSTR("Sets the current attribute to \"normal\" (light grey on black)"),315
+		,JSDOCSTR("Set the current attribute to \"normal\" (light grey on black)"),315
 	},
 	{"getch",			js_conio_getch,			0
 		,JSTYPE_NUMBER,JSDOCSTR("")
-		,JSDOCSTR("Waits for and returns a character from the user.  Extended keys are returned as two characters."),315
+		,JSDOCSTR("Wait for and returns a character from the user.  Extended keys are returned as two characters."),315
 	},
 	{"getche",			js_conio_getche,		0
 		,JSTYPE_NUMBER,JSDOCSTR("")
-		,JSDOCSTR("Waits for a character from the user, then echos it.  Extended keys can not be returned and are lost."),315
+		,JSDOCSTR("Wait for a character from the user, then echos it.  Extended keys can not be returned and are lost."),315
 	},
 	{"beep",			js_conio_beep,			0
 		,JSTYPE_VOID,JSDOCSTR("")
-		,JSDOCSTR("Beeps."),315
+		,JSDOCSTR("Beep."),315
 	},
 	{"getfont",			js_conio_getfont,		1
 		,JSTYPE_NUMBER,JSDOCSTR("fnum")
-		,JSDOCSTR("Returns the current font ID or -1 if fonts aren't supported."),315
+		,JSDOCSTR("Return the current font ID or -1 if fonts aren't supported."),315
 	},
 	{"hidemouse",		js_conio_hidemouse,		0
 		,JSTYPE_NUMBER,JSDOCSTR("")
-		,JSDOCSTR("Hides the mouse cursor.  Returns -1 if it cannot be hidden."),315
+		,JSDOCSTR("Hide the mouse cursor.  Returns -1 if it cannot be hidden."),315
 	},
 	{"showmouse",		js_conio_showmouse,		0
 		,JSTYPE_NUMBER,JSDOCSTR("")
-		,JSDOCSTR("Shows the mouse cursor.  Returns -1 if it cannot be shown."),315
+		,JSDOCSTR("Show the mouse cursor.  Returns -1 if it cannot be shown."),315
 	},
 	{"setcursortype",	js_conio_setcursortype,	1
 		,JSTYPE_VOID,JSDOCSTR("type")
-		,JSDOCSTR("Sets the cursor type.  Legal values:<br>"
+		,JSDOCSTR("Set the cursor type.  Legal values:<br>"
 			"<table><tr><td>0</td><td>No cursor</td></tr>"
 			"<tr><td>1</td><td>Solid cursor (fills whole cell)</td></tr>"
 			"<tr><td>2</td><td>Normal cursor</td></tr></table>"
@@ -1107,35 +1091,35 @@ static jsSyncMethodSpec js_functions[] = {
 	},
 	{"gotoxy",			js_conio_gotoxy,		2
 		,JSTYPE_VOID,JSDOCSTR("x, y")
-		,JSDOCSTR("Moves the cursor to the given x/y position."),315
+		,JSDOCSTR("Move the cursor to the given x/y position."),315
 	},
 	{"putch",			js_conio_putch,			1
 		,JSTYPE_NUMBER,JSDOCSTR("charcode")
-		,JSDOCSTR("Puts the character with the specified ASCII character on the screen and advances the cursor.  Returns the character code passed in."),315
+		,JSDOCSTR("Put the character with the specified ASCII character on the screen and advances the cursor.  Returns the character code passed in."),315
 	},
 	{"ungetch",			js_conio_ungetch,		1
 		,JSTYPE_NUMBER,JSDOCSTR("charcode")
-		,JSDOCSTR("Pushes the specified charcode into the input buffer.  The next getch() call will get this character."),315
+		,JSDOCSTR("Push the specified charcode into the input buffer.  The next getch() call will get this character."),315
 	},
 	{"loadfont",		js_conio_loadfont,		1
 		,JSTYPE_VOID,JSDOCSTR("filename")
-		,JSDOCSTR("Loads the filename as the current font.  Returns -1 on failure."),315
+		,JSDOCSTR("Load the filename as the current font.  Returns -1 on failure."),315
 	},
 	{"settitle",		js_conio_settitle,		1
 		,JSTYPE_VOID,JSDOCSTR("title")
-		,JSDOCSTR("Sets the window title if possible."),315
+		,JSDOCSTR("Set the window title if possible."),315
 	},
 	{"setname",			js_conio_setname,		1
 		,JSTYPE_VOID,JSDOCSTR("name")
-		,JSDOCSTR("Sets the application name.  In some modes, this overwrites the window title."),315
+		,JSDOCSTR("Set the application name.  In some modes, this overwrites the window title."),315
 	},
 	{"cputs",			js_conio_cputs,			1
 		,JSTYPE_VOID,JSDOCSTR("string")
-		,JSDOCSTR("Outputs string to the console."),315
+		,JSDOCSTR("Output string to the console."),315
 	},
 	{"setfont",			js_conio_setfont,		2
 		,JSTYPE_NUMBER,JSDOCSTR("font [, force, fnum]")
-		,JSDOCSTR("Sets a current font to the specified font.  If force is set, will change video modes if the current one callot use the specified font.  fnum selects which current font to change:<br>"
+		,JSDOCSTR("Set a current font to the specified font.  If force is set, will change video modes if the current one callot use the specified font.  fnum selects which current font to change:<br>"
 			"<table><tr><td>0</td><td>Default font</td></tr>"
 			"<tr><td>1</td><td>Main font</td></tr>"
 			"<tr><td>2</td><td>First alternate font</td></tr>"
@@ -1146,27 +1130,27 @@ static jsSyncMethodSpec js_functions[] = {
 	},
 	{"getpass",			js_conio_getpass,		1
 		,JSTYPE_STRING,JSDOCSTR("prompt")
-		,JSDOCSTR("Prompts for a password, and waits for it to be entered.  Characters are not echoed to the screen."),315
+		,JSDOCSTR("Prompt for a password, and waits for it to be entered.  Characters are not echoed to the screen."),315
 	},
 	{"window",			js_conio_window,		4
 		,JSTYPE_VOID,JSDOCSTR("start_x, start_y, end_x, end_y")
-		,JSDOCSTR("Sets the current window."),315
+		,JSDOCSTR("Set the current window."),315
 	},
 	{"cgets",			js_conio_cgets,			1
 		,JSTYPE_VOID,JSDOCSTR("max_len")
-		,JSDOCSTR("Inputs a string, echoing as it's typed, with the specified max_len (up to 255)."),315
+		,JSDOCSTR("Input a string, echoing as it's typed, with the specified max_len (up to 255)."),315
 	},
 	{"movetext",		js_conio_movetext,		6
 		,JSTYPE_VOID,JSDOCSTR("start_x, start_y, end_x, end_y, dest_x, dest_y")
-		,JSDOCSTR("Copies the specified screen contents to dest_x/dest_y."),315
+		,JSDOCSTR("Copy the specified screen contents to dest_x/dest_y."),315
 	},
 	{"puttext",			js_conio_puttext,		5
 		,JSTYPE_BOOLEAN,JSDOCSTR("start_x, start_y, end_x, end_y, bytes")
-		,JSDOCSTR("Puts the contents of the bytes array onto the screen filling the specified rectange.  The array is a sequences if integers between 0 and 255 specifying first the ascii character code, then the attribute for that character."),315
+		,JSDOCSTR("Put the contents of the bytes array onto the screen filling the specified rectange.  The array is a sequences if integers between 0 and 255 specifying first the ascii character code, then the attribute for that character."),315
 	},
 	{"gettext",			js_conio_gettext,		4
 		,JSTYPE_ARRAY,JSDOCSTR("start_x, start_y, end_x, end_y")
-		,JSDOCSTR("Returns an array containing the characters and attributes for the specified rectangle."),315
+		,JSDOCSTR("Return an array containing the characters and attributes for the specified rectangle."),315
 	},
 	{0}
 };
@@ -1218,21 +1202,21 @@ static char* conio_prop_desc[] = {
 	"Enables direct video writes (does nothing)",
 	"Do not update the screen when characters are printed",
 	"Calling puttext() (and some other things implemented using it) can move the cursor position",
-	"The current video mode",
-	"",
+	"The current video mode - <small>READ ONLY</small>",
+	"Mouse enabled (1) or disabled (0) - <small>READ ONLY</small>",
 	"Delay in MS after getting an escape character before assuming it is not part of a sequence.  For curses and ANSI modes",
 	"Current text attribute",
-	"True if a keystroke is pending",
+	"True if a keystroke is pending - <small>READ ONLY</small>",
 	"Current x position on the screen",
 	"Current y position on the screen",
 	"Current text mode",
-	"Left column of current window",
-	"Top row of current window",
-	"Right column of current window",
-	"Bottom row of current window",
-	"Width of the screen",
-	"Height of the screen",
-	"Atrribute considered \"normal\"",
+	"Left column of current window - <small>READ ONLY</small>",
+	"Top row of current window - <small>READ ONLY</small>",
+	"Right column of current window - <small>READ ONLY</small>",
+	"Bottom row of current window - <small>READ ONLY</small>",
+	"Width of the screen - <small>READ ONLY</small>",
+	"Height of the screen - <small>READ ONLY</small>",
+	"Attribute considered \"normal\" - <small>READ ONLY</small>",
 	"Background colour",
 	"Foreground colour",
 	"Text in the clipboard",
diff --git a/src/sbbs3/js_console.cpp b/src/sbbs3/js_console.cpp
index 89e45f7f3f5dc7dde6d9204a921a9d82651e9828..d3f7449cd6793716d71657f53af6d1646f85b9ea 100644
--- a/src/sbbs3/js_console.cpp
+++ b/src/sbbs3/js_console.cpp
@@ -448,7 +448,7 @@ static const char* con_prop_desc[] = {
 	,"Length of last line sent to terminal (before a carriage-return or line-wrap)"
 	,"Duration of delay (in milliseconds) before each line-feed character is sent to the terminal"
 	,"Current display attributes (set with number or string value)"
-	,"Set to <i>true</i> if the terminal cursor is already at the top of the screen - <small>READ ONLY</small>"
+	,"<tt>true</tt> if the terminal cursor is already at the top of the screen - <small>READ ONLY</small>"
 	,"Number of remote terminal screen rows (in lines)"
 	,"Number of remote terminal screen columns (in character cells)"
 	,"Current tab stop interval (tab size), in columns"
@@ -469,12 +469,12 @@ static const char* con_prop_desc[] = {
 	,"Current yes/no question (set by yesno and noyes)"
 	,"Cursor position offset for use with <tt>getstr(K_USEOFFSET)</tt>"
 	,"Control key pass-through bit-mask, set bits represent control key combinations "
-		"<i>not</i> handled by <tt>inkey()</tt> method "
+		"<i>not</i> handled by <tt>inkey()</tt> method.<br> "
 		"This may optionally be specified as a string of characters. "
-		"The format of this string is [+-][@-_]. If neither plus nor minus is "
+		"The format of this string is [+-][@-_].<br>If neither plus nor minus is "
 		"the first character, the value will be replaced by one constructed "
-		"from the string. A + indicates that characters following will be "
-		"added to the set, and a - indicates they should be removed. "
+		"from the string.<br>A + indicates that characters following will be "
+		"added to the set, and a - indicates they should be removed.<br>"
 		"ex: <tt>console.ctrlkey_passthru=\"-UP+AB\"</tt> will clear CTRL-U and "
 		"CTRL-P and set CTRL-A and CTRL-B."
 	,"Number of bytes currently in the input buffer (from the remote client) - <small>READ ONLY</small>"
@@ -2390,34 +2390,34 @@ js_flush(JSContext *cx, uintN argc, jsval *arglist)
 }
 
 static jsSyncMethodSpec js_console_functions[] = {
-	{"inkey",			js_inkey,			0, JSTYPE_STRING,	JSDOCSTR("[mode=<tt>K_NONE</tt>] [,timeout=<tt>0</tt>]")
+	{"inkey",			js_inkey,			0, JSTYPE_STRING,	JSDOCSTR("[k_mode=K_NONE] [,timeout=0]")
 	,JSDOCSTR("Get a single key with optional <i>timeout</i> in milliseconds (defaults to 0, for no wait).<br>"
-		"Returns an empty string (or <tt>null</tt> when the <tt>K_NUL</tt> mode flag is used) if there is no input (e.g. timeout occurs).<br>"
-		"See <tt>K_*</tt> in <tt>sbbsdefs.js</tt> for <i>mode</i> flags.")
+		"Returns an empty string (or <tt>null</tt> when the <tt>K_NUL</tt> <i>k_mode</i> flag is used) if there is no input (e.g. timeout occurs).<br>"
+		"See <tt>K_*</tt> in <tt>sbbsdefs.js</tt> for <i>k_mode</i> flags.")
 	,311
 	},
-	{"getkey",			js_getkey,			0, JSTYPE_STRING,	JSDOCSTR("[mode=<tt>K_NONE</tt>]")
+	{"getkey",			js_getkey,			0, JSTYPE_STRING,	JSDOCSTR("[k_mode=K_NONE]")
 	,JSDOCSTR("Get a single key, with wait.<br>"
-		"See <tt>K_*</tt> in <tt>sbbsdefs.js</tt> for <i>mode</i> flags.")
+		"See <tt>K_*</tt> in <tt>sbbsdefs.js</tt> for <i>k_mode</i> flags.")
 	,310
 	},
-	{"getstr",			js_getstr,			0, JSTYPE_STRING,	JSDOCSTR("[string] [,maxlen=<tt>128</tt>] [,mode=<tt>K_NONE</tt>] [,history[]]")
+	{"getstr",			js_getstr,			0, JSTYPE_STRING,	JSDOCSTR("[<i>string</i> default_value] [,<i>number</i> maxlen=128] [,<i>number</i> k_mode=K_NONE] [,<i>array</i> history[]]")
 	,JSDOCSTR("Get a text string from the user.<br>"
-		"See <tt>K_*</tt> in <tt>sbbsdefs.js</tt> for <i>mode</i> flags.<br>"
-		"<i>history[]</i>, added in v3.17, allows a command history (string array) to be recalled using the up/down arrow keys."
+		"See <tt>K_*</tt> in <tt>sbbsdefs.js</tt> for <i>k_mode</i> flags.<br>"
+		"<i>history[]</i> allows a command history (array of strings) to be recalled using the up/down arrow keys."
 		)
 	,310
 	},
-	{"getnum",			js_getnum,			0, JSTYPE_NUMBER,	JSDOCSTR("[maxnum[, default]]")
+	{"getnum",			js_getnum,			0, JSTYPE_NUMBER,	JSDOCSTR("[<i>number</i> maxnum [,<i>number</i> default]]")
 	,JSDOCSTR("Get a number between 1 and <i>maxnum</i> from the user with a default value of <i>default</i>")
 	,310
 	},
-	{"getkeys",			js_getkeys,			1, JSTYPE_NUMBER,	JSDOCSTR("[keys] [,maxnum] [,mode=<tt>K_UPPER</tt>]")
+	{"getkeys",			js_getkeys,			1, JSTYPE_NUMBER,	JSDOCSTR("[<i>string</i> keys] [,<i>number></i> maxnum] [,<i>number</i> k_mode=K_UPPER]")
 	,JSDOCSTR("Get one key from of a list of valid command <i>keys</i> (any key, if not specified), "
 		"or a number between 1 and <i>maxnum</i>")
 	,310
 	},
-	{"gettemplate",		js_gettemplate,		1, JSTYPE_STRING,	JSDOCSTR("format [,string] [,mode=<tt>0</tt>]")
+	{"gettemplate",		js_gettemplate,		1, JSTYPE_STRING,	JSDOCSTR("<i>string</i> format [,<i>string</i> default_value] [,<i>number</i> k_mode=K_NONE]")
 	,JSDOCSTR("Get an input string based on specified template")
 	,310
 	},
@@ -2425,21 +2425,21 @@ static jsSyncMethodSpec js_console_functions[] = {
 	,JSDOCSTR("Put one or more characters in the keyboard input buffer")
 	,310
 	},
-	{"yesno",			js_yesno,			2, JSTYPE_BOOLEAN,	JSDOCSTR("question [,mode = P_NONE]")
-	,JSDOCSTR("YES/no question - returns <i>true</i> if 'yes' is selected")
+	{"yesno",			js_yesno,			2, JSTYPE_BOOLEAN,	JSDOCSTR("question [,<i>number</i> p_mode=P_NONE]")
+	,JSDOCSTR("YES/no question - returns <tt>true</tt> if 'yes' is selected")
 	,310
 	},
-	{"noyes",			js_noyes,			2, JSTYPE_BOOLEAN,	JSDOCSTR("question [,mode = P_NONE]")
-	,JSDOCSTR("NO/yes question - returns <i>true</i> if 'no' is selected")
+	{"noyes",			js_noyes,			2, JSTYPE_BOOLEAN,	JSDOCSTR("question [,<i>number</i> p_mode=P_NONE]")
+	,JSDOCSTR("NO/yes question - returns <tt>true</tt> if 'no' is selected")
 	,310
 	},
 	{"mnemonics",		js_mnemonics,		1, JSTYPE_VOID,		JSDOCSTR("text")
 	,JSDOCSTR("Print a mnemonics string, command keys highlighted with tilde (~) characters")
 	,310
 	},
-	{"clear",           js_clear,			0, JSTYPE_VOID,		JSDOCSTR("[attribute] [,autopause=<tt>true</tt>]")
+	{"clear",           js_clear,			0, JSTYPE_VOID,		JSDOCSTR("[<i>string</i> or <i>number</i> attribute] [,<i>bool</i> autopause=true]")
 	,JSDOCSTR("Clear screen and home cursor, "
-		"optionally (in v3.13b+) setting current attribute first")
+		"optionally setting current attribute first")
 	,310
 	},
 	{"home",            js_cursor_home,		0, JSTYPE_VOID,		JSDOCSTR("")
@@ -2448,28 +2448,28 @@ static jsSyncMethodSpec js_console_functions[] = {
 	},
 	{"clearline",       js_clearline,		0, JSTYPE_VOID,		JSDOCSTR("[attribute]")
 	,JSDOCSTR("Clear current line, "
-		"optionally (in v3.13b+) setting current attribute first")
+		"optionally setting current attribute first")
 	,310
 	},
 	{"cleartoeol",      js_cleartoeol,		0, JSTYPE_VOID,		JSDOCSTR("[attribute]")
 	,JSDOCSTR("Clear to end-of-line, "
-		"optionally (in v3.13b+) setting current attribute first")
+		"optionally setting current attribute first")
 	,311
 	},
-	{"crlf",            js_crlf,			0, JSTYPE_VOID,		JSDOCSTR("[count=<tt>1</tt>]")
+	{"crlf",            js_crlf,			0, JSTYPE_VOID,		JSDOCSTR("[count=1]")
 	,JSDOCSTR("Output <i>count</i> number of carriage-return/line-feed pairs (new-lines)")
 	,310
 	},
-	{"pause",			js_pause,			0, JSTYPE_BOOLEAN,	JSDOCSTR("[set_abort=true]")
-	,JSDOCSTR("Display pause prompt and wait for key hit, returns <i>false</i> if user responded with Quit/Abort key.<br>"
+	{"pause",			js_pause,			0, JSTYPE_BOOLEAN,	JSDOCSTR("[<i>bool</i> set_abort=true]")
+	,JSDOCSTR("Display pause prompt and wait for key hit, returns <tt>false</tt> if user responded with Quit/Abort key.<br>"
 		"Passing <tt>false</tt> for the <i>set_abort</i> argument will prevent the ''console.aborted'' flag from being set by this method.")
 	,310
 	},
-	{"beep",			js_beep,			1, JSTYPE_VOID,		JSDOCSTR("[count=<tt>1</tt>]")
+	{"beep",			js_beep,			1, JSTYPE_VOID,		JSDOCSTR("[count=1]")
 	,JSDOCSTR("Beep for <i>count</i> number of times (default count is 1)")
 	,311
 	},
-	{"print",			js_print,			1, JSTYPE_VOID,		JSDOCSTR("[value [,value][...]] or [string [,mode=<tt>P_NONE</tt>]]")
+	{"print",			js_print,			1, JSTYPE_VOID,		JSDOCSTR("[value [,value][...]] or [<i>string</i> text [,<i>number</i> p_mode=P_NONE]]")
 	,JSDOCSTR("Display one or more values as strings (supports Ctrl-A codes, Telnet-escaping, auto-screen pausing, etc.).<br>"
 		"Supports a limited set of <tt>P_*</tt> flags, e.g. <tt>P_PETSCII</tt> and <tt>P_UTF8</tt>."
 	)
@@ -2483,10 +2483,10 @@ static jsSyncMethodSpec js_console_functions[] = {
 	,JSDOCSTR("Display one or more values as raw strings followed by a single carriage-return/line-feed pair (new-line)")
 	,315
 	},
-	{"putmsg",			js_putmsg,			1, JSTYPE_VOID,		JSDOCSTR("text [,mode=<tt>P_NONE</tt>] [,orig_columns=0] [,object scope]")
+	{"putmsg",			js_putmsg,			1, JSTYPE_VOID,		JSDOCSTR("text [,<i>number</i> p_mode=P_NONE] [,<i>number</i> orig_columns=0] [,<i>object</i> scope]")
 	,JSDOCSTR("Display message text (Ctrl-A codes, @-codes, pipe codes, etc.).<br> "
-		"See <tt>P_*</tt> in <tt>sbbsdefs.js</tt> for <i>mode</i> flags.<br>"
-		"When <tt>P_WORDWRAP</tt> mode flag is specified, <i>orig_columns</i> specifies the original text column width, if known.<br>"
+		"See <tt>P_*</tt> in <tt>sbbsdefs.js</tt> for <i>p_mode</i> flags.<br>"
+		"When <tt>P_WORDWRAP</tt> p_mode flag is specified, <i>orig_columns</i> specifies the original text column width, if known.<br>"
 		"When <i>scope</i> is specified, <tt>@JS:property@</tt> codes will expand the referenced property names.")
 	,310
 	},
@@ -2502,26 +2502,26 @@ static jsSyncMethodSpec js_console_functions[] = {
 	,JSDOCSTR("Display a progress indication bar, updated every <i>interval</i> milliseconds")
 	,31902
 	},
-	{"strlen",			js_strlen,			1, JSTYPE_NUMBER,	JSDOCSTR("text [,mode=<tt>P_NONE</tt>]")
+	{"strlen",			js_strlen,			1, JSTYPE_NUMBER,	JSDOCSTR("text [,p_mode=P_NONE]")
 	,JSDOCSTR("Returns the printed-length (number of columns) of the specified <i>text</i>, accounting for Ctrl-A codes")
 	,310
 	},
-	{"printfile",		js_printfile,		1, JSTYPE_BOOLEAN,		JSDOCSTR("filename [,mode=<tt>P_NONE</tt>] [,orig_columns=0] [,object scope]")
-	,JSDOCSTR("Print a message text file with optional mode.<br>"
-		"When <tt>P_WORDWRAP</tt> mode flag is specified, <i>orig_columns</i> specifies the original text column width, if known.<br>"
+	{"printfile",		js_printfile,		1, JSTYPE_BOOLEAN,		JSDOCSTR("filename [,<i>number</i> p_mode=P_NONE] [,<i>number</i> orig_columns=0] [,<i>object</i> scope]")
+	,JSDOCSTR("Print a message text file with optional print mode.<br>"
+		"When <tt>P_WORDWRAP</tt> p_mode flag is specified, <i>orig_columns</i> specifies the original text column width, if known.<br>"
 		"When <i>scope</i> is specified, <tt>@JS:property@</tt> codes will expand the referenced property names.")
 	,310
 	},
-	{"printtail",		js_printtail,		2, JSTYPE_BOOLEAN,		JSDOCSTR("filename, lines [,mode=<tt>P_NONE</tt>] [,orig_columns=0] [,object scope]")
-	,JSDOCSTR("Print the last <i>n</i> lines of file with optional mode, original column width, and scope.")
+	{"printtail",		js_printtail,		2, JSTYPE_BOOLEAN,		JSDOCSTR("filename, <i>number</i> lines [,<i>number</i> p_mode=P_NONE] [,<i>number</i> orig_columns=0] [,<i>object</i> scope]")
+	,JSDOCSTR("Print the last <i>n</i> lines of file with optional print mode, original column width, and scope.")
 	,310
 	},
 	{"editfile",		js_editfile,		1, JSTYPE_BOOLEAN,		JSDOCSTR("filename")
 	,JSDOCSTR("Edit/create a text file using the user's preferred message editor")
 	,310
 	},
-	{"uselect",			js_uselect,			0, JSTYPE_NUMBER,	JSDOCSTR("[number, title, item] [,ars]")
-	,JSDOCSTR("User selection menu, first call for each item, then finally with no args (or just the default item number) to display select menu")
+	{"uselect",			js_uselect,			0, JSTYPE_NUMBER,	JSDOCSTR("[<i>number</i> index, title, item] [,ars]")
+	,JSDOCSTR("User selection menu, first call for each item, then finally with no args (or just the default item index number) to display select menu")
 	,312
 	},
 	{"saveline",		js_saveline,		0, JSTYPE_BOOLEAN,	JSDOCSTR("")
@@ -2551,29 +2551,29 @@ static jsSyncMethodSpec js_console_functions[] = {
 	,311
 	},
 	{"ansi_gotoxy",		js_gotoxy,			1, JSTYPE_ALIAS },
-	{"gotoxy",			js_gotoxy,			1, JSTYPE_VOID,		JSDOCSTR("[x,y] or [object { x,y }]")
+	{"gotoxy",			js_gotoxy,			1, JSTYPE_VOID,		JSDOCSTR("[x,y] or [<i>object</i> { x,y }]")
 	,JSDOCSTR("Move cursor to a specific screen coordinate (ANSI or PETSCII, 1-based values), "
 	"arguments can be separate x and y coordinates or an object with x and y properties "
 	"(like that returned from <tt>console.getxy()</tt>)")
 	,311
 	},
 	{"ansi_up",			js_cursor_up,		0, JSTYPE_ALIAS },
-	{"up",				js_cursor_up,		0, JSTYPE_VOID,		JSDOCSTR("[rows=<tt>1</tt>]")
+	{"up",				js_cursor_up,		0, JSTYPE_VOID,		JSDOCSTR("[rows=1]")
 	,JSDOCSTR("Move cursor up one or more rows")
 	,311
 	},
 	{"ansi_down",		js_cursor_down,		0, JSTYPE_ALIAS },
-	{"down",			js_cursor_down,		0, JSTYPE_VOID,		JSDOCSTR("[rows=<tt>1</tt>]")
+	{"down",			js_cursor_down,		0, JSTYPE_VOID,		JSDOCSTR("[rows=1]")
 	,JSDOCSTR("Move cursor down one or more rows")
 	,311
 	},
 	{"ansi_right",		js_cursor_right,	0, JSTYPE_ALIAS },
-	{"right",			js_cursor_right,	0, JSTYPE_VOID,		JSDOCSTR("[columns=<tt>1</tt>]")
+	{"right",			js_cursor_right,	0, JSTYPE_VOID,		JSDOCSTR("[columns=1]")
 	,JSDOCSTR("Move cursor right one or more columns")
 	,311
 	},
 	{"ansi_left",		js_cursor_left,		0, JSTYPE_ALIAS },
-	{"left",			js_cursor_left,		0, JSTYPE_VOID,		JSDOCSTR("[columns=<tt>1</tt>]")
+	{"left",			js_cursor_left,		0, JSTYPE_VOID,		JSDOCSTR("[columns=1]")
 	,JSDOCSTR("Move cursor left one or more columns")
 	,311
 	},
@@ -2589,17 +2589,17 @@ static jsSyncMethodSpec js_console_functions[] = {
 		"and returns the coordinates as an object (with <tt>x</tt> and <tt>y</tt> properties) or <tt>false</tt> on failure")
 	,311
 	},
-	{"lock_input",		js_lock_input,		1, JSTYPE_VOID,		JSDOCSTR("[lock=<tt>true</tt>]")
+	{"lock_input",		js_lock_input,		1, JSTYPE_VOID,		JSDOCSTR("[lock=true]")
 	,JSDOCSTR("Lock the user input thread (allowing direct client socket access)")
 	,310
 	},
-	{"telnet_cmd",		js_telnet_cmd,		3, JSTYPE_BOOLEAN,		JSDOCSTR("command [,option=<tt>0</tt>] [,timeout=<tt>0</tt>]")
+	{"telnet_cmd",		js_telnet_cmd,		3, JSTYPE_BOOLEAN,		JSDOCSTR("command [,option=0] [,timeout=0]")
 	,JSDOCSTR("Send Telnet command (with optional command option) to remote client"
-		", if the optional timeout is specified (in milliseconds, added in v3.17), then an acknowledgment will be expected and"
+		", if the optional timeout is specified (in milliseconds), then an acknowledgment will be expected and"
 		" the return value will indicate whether or not one was received")
 	,317
 	},
-	{"handle_ctrlkey",	js_handle_ctrlkey,	1, JSTYPE_BOOLEAN,	JSDOCSTR("key [,mode=<tt>K_NONE</tt>]")
+	{"handle_ctrlkey",	js_handle_ctrlkey,	1, JSTYPE_BOOLEAN,	JSDOCSTR("key [,k_mode=K_NONE]")
 	,JSDOCSTR("Call internal control key handler for specified control key, returns <tt>true</tt> if handled")
 	,311
 	},
@@ -2613,11 +2613,11 @@ static jsSyncMethodSpec js_console_functions[] = {
 	,JSDOCSTR("Update the node's <tt>terminal.ini</tt> file to match the current terminal settings")
 	,31802
 	},
-	{"backspace",		js_backspace,		0, JSTYPE_VOID,		JSDOCSTR("[count=<tt>1</tt>]")
+	{"backspace",		js_backspace,		0, JSTYPE_VOID,		JSDOCSTR("[count=1]")
 	,JSDOCSTR("Send a destructive backspace sequence")
 	,315
 	},
-	{"creturn",			js_creturn,			0, JSTYPE_VOID,		JSDOCSTR("[count=<tt>1</tt>]")
+	{"creturn",			js_creturn,			0, JSTYPE_VOID,		JSDOCSTR("[count=1]")
 	,JSDOCSTR("Send a carriage return sequence")
 	,31700
 	},
@@ -2625,7 +2625,7 @@ static jsSyncMethodSpec js_console_functions[] = {
 	,JSDOCSTR("Clear keyboard input buffer")
 	,315
 	},
-	{"getbyte",			js_getbyte,			1, JSTYPE_NUMBER,	JSDOCSTR("[timeout=<tt>0</tt>]")
+	{"getbyte",			js_getbyte,			1, JSTYPE_NUMBER,	JSDOCSTR("[timeout=0]")
 	,JSDOCSTR("Returns an unprocessed input byte from the remote terminal "
 		"with optional <i>timeout</i> in milliseconds (defaults to 0, for no wait), "
 		"returns <i>null</i> on failure (timeout)")
@@ -2635,8 +2635,8 @@ static jsSyncMethodSpec js_console_functions[] = {
 	,JSDOCSTR("Sends an unprocessed byte value to the remote terminal")
 	,31700
 	},
-	{"add_hotspot",		js_add_hotspot,		1,	JSTYPE_VOID,	JSDOCSTR("cmd [,bool hungry=<tt>true</tt>] [,min_x] [,max_x] [,y]")
-		,JSDOCSTR("Adds a mouse hot-spot (a clickable screen area that generates keyboard input)")
+	{"add_hotspot",		js_add_hotspot,		1,	JSTYPE_VOID,	JSDOCSTR("cmd [,<i>bool</i> hungry=true] [,min_x] [,max_x] [,y]")
+		,JSDOCSTR("Adds a mouse hot-spot (a click-able screen area that generates keyboard input)")
 		,31800
 		},
 	{"clear_hotspots",	js_clear_hotspots,		0,	JSTYPE_VOID,	JSDOCSTR("")
diff --git a/src/sbbs3/js_cryptcon.c b/src/sbbs3/js_cryptcon.c
index 5c523109f8c413ac02f25e7d273d42b8111a16b7..52756a8f088c6ebd489c60a05504f8ccda8fe183 100644
--- a/src/sbbs3/js_cryptcon.c
+++ b/src/sbbs3/js_cryptcon.c
@@ -999,7 +999,7 @@ js_cryptcon_constructor(JSContext *cx, uintN argc, jsval *arglist)
 #ifdef BUILD_JSDOCS
 	js_DescribeSyncObject(cx,obj,"Class used for encryption/decryption",31601);
 	js_DescribeSyncConstructor(cx,obj,"To create a new CryptContext object: "
-		"var c = new CryptContext('<i>algorithm</i>')</tt><br>"
+		"<tt>var c = new CryptContext('<i>algorithm</i>')</tt><br>"
 		"where <i>algorithm</i> is a property of CryptContext.ALGO"
 		);
 	js_CreateArrayOfStrings(cx, obj, "_property_desc_list", cryptcon_prop_desc, JSPROP_READONLY);
diff --git a/src/sbbs3/js_cryptkeyset.c b/src/sbbs3/js_cryptkeyset.c
index 3aa5bcf03169e606ba0b9a625b3e7a307cd8d475..f31afac50558d766f4a8580045b3dc4cccea40a9 100644
--- a/src/sbbs3/js_cryptkeyset.c
+++ b/src/sbbs3/js_cryptkeyset.c
@@ -1,5 +1,3 @@
-/* $Id: js_cryptkeyset.c,v 1.5 2018/02/23 11:40:14 deuce Exp $ */
-
 // Cyrptlib Keyset...
 
 #include "sbbs.h"
@@ -393,11 +391,11 @@ static jsSyncMethodSpec js_cryptkeyset_functions[] = {
 	,316
 	},
 	{"get_private_key",	js_get_private_key,	0,	JSTYPE_OBJECT,	"label, password"
-	,JSDOCSTR("Returns a CryptContext from the private key with <label> encrypted with &lt;password&gt;.")
+	,JSDOCSTR("Return a CryptContext from the private key with <label> encrypted with &lt;password&gt;.")
 	,316
 	},
 	{"get_public_key",	js_get_public_key,	0,	JSTYPE_OBJECT,	"label"
-	,JSDOCSTR("Returns a CryptCert from the public key with &lt;label&gt;.")
+	,JSDOCSTR("Return a CryptCert from the public key with &lt;label&gt;.")
 	,316
 	},
 	{0}
@@ -498,7 +496,7 @@ js_cryptkeyset_constructor(JSContext *cx, uintN argc, jsval *arglist)
 #ifdef BUILD_JSDOCS
 	js_DescribeSyncObject(cx,obj,"Class used for storing CryptContext keys",31601);
 	js_DescribeSyncConstructor(cx,obj,"To create a new CryptKeyset object: "
-		"var c = new CryptKeyset('<i>filename</i>' [ <i>opts = CryptKeyset.KEYOPT.NONE</i> ])</tt><br> "
+		"<tt>var c = new CryptKeyset('<i>filename</i>' [ <i>opts = CryptKeyset.KEYOPT.NONE</i> ])</tt><br> "
 		"where <i>filename</i> is the name of the file to create, and <i>opts</i> "
 		"is a value from CryptKeyset.KEYOPT"
 		);
diff --git a/src/sbbs3/js_file.c b/src/sbbs3/js_file.c
index 70881d74c6245296845b90bc592cd33f5abf2398..537f942f4e708d41ff70af59fd5deb3b959941ca 100644
--- a/src/sbbs3/js_file.c
+++ b/src/sbbs3/js_file.c
@@ -2856,7 +2856,7 @@ static const char* file_prop_desc[] = {
 #endif
 
 static jsSyncMethodSpec js_file_functions[] = {
-	{"open",			js_open,			1,	JSTYPE_BOOLEAN,	JSDOCSTR("[mode=<tt>\"w+\"</tt>] [,shareable=<tt>false</tt>] [,buffer_length]")
+	{"open",			js_open,			1,	JSTYPE_BOOLEAN,	JSDOCSTR("[<i>string</i> mode=\"w+\"] [,<i>bool</i> shareable=false] [,<i>number</i> buffer_length]")
 	,JSDOCSTR("Open file, <i>shareable</i> defaults to <i>false</i>, <i>buffer_length</i> defaults to 2048 bytes, "
 		"mode (default: <tt>'w+'</tt>) specifies the type of access requested for the file, as follows:<br>"
 		"<tt>r&nbsp</tt> open for reading; if the file does not exist or cannot be found, the open call fails<br>"
@@ -2866,14 +2866,14 @@ static jsSyncMethodSpec js_file_functions[] = {
 		"<tt>w+</tt> open an empty file for both reading and writing; if the given file exists, its contents are destroyed<br>"
 		"<tt>a+</tt> open for reading and appending<br>"
 		"<tt>b&nbsp</tt> open in binary (untranslated) mode; translations involving carriage-return and linefeed characters are suppressed (e.g. <tt>r+b</tt>)<br>"
-		"<tt>x&nbsp</tt> open a <i>non-shareable</i> file (that must not already exist) for <i>exclusive</i> access <i>(introduced in v3.17)</i><br>"
+		"<tt>x&nbsp</tt> open a <i>non-shareable</i> file (that must not already exist) for <i>exclusive</i> access<br>"
 		"<br><b>Note:</b> When using the <tt>iniSet</tt> methods to modify a <tt>.ini</tt> file, "
 		"the file must be opened for both reading <b>and</b> writing.<br>"
 		"<br><b>Note:</b> To open an existing or create a new file for both reading and writing "
 		"(e.g. updating an <tt>.ini</tt> file) "
 		"use the <i>exists</i> property like so:<br>"
 		"<tt>file.open(file.exists ? 'r+':'w+');</tt><br>"
-		"<br><b>Note:</b> When <i>shareable</i> is false, uses nopen() which will lock the file "
+		"<br><b>Note:</b> When <i>shareable</i> is <tt>false</tt>, uses the Synchronet <tt>nopen()</tt> function which will lock the file "
 		"and perform automatic retries.  The lock mode is as follows:<br>"
 		"<tt>r&nbsp</tt> DENYWRITE - Allows other scripts to open the file for reading, but not for writing.<br>"
 		"<tt>w&nbsp</tt> DENYALL - Does not allow other scripts to open the file when <i>shareable</i> is set to true<br>"
@@ -2881,15 +2881,15 @@ static jsSyncMethodSpec js_file_functions[] = {
 		"<tt>r+</tt> DENYALL - Does not allow other scripts to open the file when <i>shareable</i> is set to true<br>"
 		"<tt>w+</tt> DENYALL - Does not allow other scripts to open the file when <i>shareable</i> is set to true<br>"
 		"<tt>a+</tt> DENYALL - Does not allow other scripts to open the file when <i>shareable</i> is set to true<br>"
-		"When <i>shareable</i> is true uses fopen(), "
-		"and will only attempt to open the file once and will perform no locking.  The behavior "
-		"when one script has a file opened with <i>shareable</i> set to a different value than is used "
+		"<br>When <i>shareable</i> is <tt>true</tt> uses the standard C <tt>fopen()</tt> function, "
+		"and will only attempt to open the file once and will perform no locking.<br>"
+		"The behavior when one script has a file opened with <i>shareable</i> set to a different value than is used "
 		"with a new call is OS specific.  On Windows, the second open will always fail and on *nix, "
 		"the second open will always succeed.<br>"
 		)
 	,310
 	},
-	{"popen",			js_popen,			1,	JSTYPE_BOOLEAN,	JSDOCSTR("[mode=<tt>\"r+\"</tt>] [,buffer_length]")
+	{"popen",			js_popen,			1,	JSTYPE_BOOLEAN,	JSDOCSTR("[<i>string</i> mode=\"r+\"] [,<i>number</i> buffer_length]")
 	,JSDOCSTR("Open pipe to command, <i>buffer_length</i> defaults to 2048 bytes, "
 		"mode (default: <tt>'r+'</tt>) specifies the type of access requested for the file, as follows:<br>"
 		"<tt>r&nbsp</tt> read the programs stdout;<br>"
@@ -2921,16 +2921,16 @@ static jsSyncMethodSpec js_file_functions[] = {
 		"and clears error and end-of-file indicators")
 	,311
 	},
-	{"truncate",		js_truncate,		0,	JSTYPE_BOOLEAN,	JSDOCSTR("[length=<tt>0</tt>]")
+	{"truncate",		js_truncate,		0,	JSTYPE_BOOLEAN,	JSDOCSTR("[length=0]")
 	,JSDOCSTR("Changes the file <i>length</i> (default: 0) and repositions the file pointer "
 	"(<i>position</i>) to the new end-of-file")
 	,314
 	},
-	{"lock",			js_lock,			2,	JSTYPE_BOOLEAN,	JSDOCSTR("[offset=<tt>0</tt>] [,length=<i>file_length</i>-<i>offset</i>]")
+	{"lock",			js_lock,			2,	JSTYPE_BOOLEAN,	JSDOCSTR("[offset=0] [,length=<i>file_length</i>-<i>offset</i>]")
 	,JSDOCSTR("Lock file record for exclusive access (file must be opened <i>shareable</i>)")
 	,310
 	},
-	{"unlock",			js_unlock,			2,	JSTYPE_BOOLEAN,	JSDOCSTR("[offset=<tt>0</tt>] [,length=<i>file_length</i>-<i>offset</i>]")
+	{"unlock",			js_unlock,			2,	JSTYPE_BOOLEAN,	JSDOCSTR("[offset=0] [,length=<i>file_length</i>-<i>offset</i>]")
 	,JSDOCSTR("Unlock file record for exclusive access")
 	,310
 	},
@@ -2939,21 +2939,21 @@ static jsSyncMethodSpec js_file_functions[] = {
 		"<i>maxlen</i> defaults to the current length of the file minus the current file position")
 	,310
 	},
-	{"readln",			js_readln,			0,	JSTYPE_STRING,	JSDOCSTR("[maxlen=<tt>512</tt>]")
+	{"readln",			js_readln,			0,	JSTYPE_STRING,	JSDOCSTR("[maxlen=512]")
 	,JSDOCSTR("Read a line-feed terminated string, <i>maxlen</i> defaults to 512 characters. "
 		"Returns <i>null</i> upon end of file.")
 	,310
 	},
-	{"readBin",			js_readbin,			0,	JSTYPE_NUMBER,	JSDOCSTR("[bytes=<tt>4</tt> [,count=<tt>1</tt>]")
+	{"readBin",			js_readbin,			0,	JSTYPE_NUMBER,	JSDOCSTR("[bytes=4 [,count=1]]")
 	,JSDOCSTR("Read one or more binary integers from the file, default number of <i>bytes</i> is 4 (32-bits). "
 			  "if count is not equal to 1, an array is returned (even if no integers were read)")
 	,310
 	},
-	{"readAll",			js_readall,			0,	JSTYPE_ARRAY,	JSDOCSTR("[maxlen=<tt>512</tt>]")
+	{"readAll",			js_readall,			0,	JSTYPE_ARRAY,	JSDOCSTR("[maxlen=512]")
 	,JSDOCSTR("Read all lines into an array of strings, <i>maxlen</i> defaults to 512 characters")
 	,310
 	},
-	{"raw_read",		js_raw_read,		0,	JSTYPE_STRING,	JSDOCSTR("[maxlen=<i>1</i>]")
+	{"raw_read",		js_raw_read,		0,	JSTYPE_STRING,	JSDOCSTR("[maxlen=1]")
 	,JSDOCSTR("Read a string from underlying file descriptor. "
 				"Undefined results when mixed with any other read/write methods except raw_write, including indirect ones. "
 				"<i>maxlen</i> defaults to one")
@@ -2973,7 +2973,7 @@ static jsSyncMethodSpec js_file_functions[] = {
 	,JSDOCSTR("Write a new-line terminated string (a line of text) to the file")
 	,310
 	},
-	{"writeBin",		js_writebin,		1,	JSTYPE_BOOLEAN,	JSDOCSTR("value(s) [,bytes=<tt>4</tt>]")
+	{"writeBin",		js_writebin,		1,	JSTYPE_BOOLEAN,	JSDOCSTR("value(s) [,bytes=4]")
 	,JSDOCSTR("Write one or more binary integers to the file, default number of <i>bytes</i> is 4 (32-bits). "
 			  "If value is an array, writes the entire array to the file.")
 	,310
@@ -2988,8 +2988,7 @@ static jsSyncMethodSpec js_file_functions[] = {
 	,317
 	},
 	{"printf",			js_fprintf,			0,	JSTYPE_NUMBER,	JSDOCSTR("format [,args]")
-	,JSDOCSTR("Write a formatted string to the file (ala fprintf) - "
-		"<small>CAUTION: for experienced C programmers ONLY</small>")
+	,JSDOCSTR("Write a C-style formatted string to the file (ala the standard C <tt>fprintf</tt> function)")
 	,310
 	},
 	{"iniGetSections",	js_iniGetSections,	0,	JSTYPE_ARRAY,	JSDOCSTR("[prefix=<i>none</i>]")
@@ -3006,8 +3005,8 @@ static jsSyncMethodSpec js_file_functions[] = {
 	},
 	{"iniGetValue",		js_iniGetValue,		3,	JSTYPE_UNDEF,	JSDOCSTR("section, key [,default=<i>none</i>]")
 	,JSDOCSTR("Parse a key from a <tt>.ini</tt> file and return its value (format = '<tt>key = value</tt>'). "
-		"returns the specified <i>default</i> value if the key or value is missing or invalid. "
-		"to parse a key from the <i>root</i> section, pass <i>null</i> for <i>section</i>. "
+		"To parse a key from the <i>root</i> section, pass <i>null</i> for <i>section</i>. "
+		"Returns the specified <i>default</i> value if the key or value is missing or invalid.<br>"
 		"Returns a <i>bool</i>, <i>number</i>, <i>string</i>, or an <i>array of strings</i> "
 		"determined by the type of <i>default</i> value specified. "
 		"<br><b>Note:</b> To insure that any/all values are returned as a string (e.g. numeric passwords are <b>not</b> returned as a <i>number</i>), "
@@ -3020,36 +3019,36 @@ static jsSyncMethodSpec js_file_functions[] = {
 		"to set a key in the <i>root</i> section, pass <i>null</i> for <i>section</i>. ")
 	,312
 	},
-	{"iniGetObject",	js_iniGetObject,	1,	JSTYPE_OBJECT,	JSDOCSTR("[section=<i>root</i>] [,lowercase=<tt>false</tt>] "
-		"[,blanks=<tt>false</tt>]")
+	{"iniGetObject",	js_iniGetObject,	1,	JSTYPE_OBJECT,	JSDOCSTR("[section=<i>root</i>] [,<i>bool</i> lowercase=false] "
+		"[,<i>bool</i> blanks=false]")
 	,JSDOCSTR("Parse an entire section from a .ini file "
-		"and return all of its keys (optionally lowercased) and values as properties of an object. "
-		"If <i>section</i> is <tt>null</tt> or <tt>undefined</tt>, returns keys and values from the <i>root</i> section. "
-		"If <i>blanks</i> is <tt>true</tt> then empty string (instead of <tt>undefined</tt>) values may included in the returned object."
+		"and return all of its keys (optionally lowercased) and values as properties of an object.<br>"
+		"If <i>section</i> is <tt>null</tt> or <tt>undefined</tt>, returns keys and values from the <i>root</i> section.<br>"
+		"If <i>blanks</i> is <tt>true</tt> then empty string (instead of <tt>undefined</tt>) values may included in the returned object.<br>"
 		"Returns <i>null</i> if the specified <i>section</i> does not exist in the file or the file has not been opened.")
 	,311
 	},
-	{"iniSetObject",	js_iniSetObject,	2,	JSTYPE_BOOLEAN,	JSDOCSTR("section, object")
+	{"iniSetObject",	js_iniSetObject,	2,	JSTYPE_BOOLEAN,	JSDOCSTR("section, <i>object</i> object")
 	,JSDOCSTR("Write all the properties of the specified <i>object</i> as separate <tt>key=value</tt> pairs "
-		"in the specified <i>section</i> of a <tt>.ini</tt> file. "
-		"to write an object in the <i>root</i> section, pass <i>null</i> for <i>section</i>. "
+		"in the specified <i>section</i> of a <tt>.ini</tt> file.<br>"
+		"To write an object in the <i>root</i> section, pass <i>null</i> for <i>section</i>."
 		"<br><b>Note:</b> this method does not remove unreferenced keys from an existing section. "
 		"If your intention is to <i>replace</i> an existing section, use the <tt>iniRemoveSection</tt> function first." )
 	,312
 	},
-	{"iniGetAllObjects",js_iniGetAllObjects,1,	JSTYPE_ARRAY,	JSDOCSTR("[name_property] [,prefix=<i>none</i>] [,lowercase=<tt>false</tt>] "
-		"[,blanks=<tt>false</tt>]")
+	{"iniGetAllObjects",js_iniGetAllObjects,1,	JSTYPE_ARRAY,	JSDOCSTR("[<i>string</i> name_property] [,<i>bool</i> prefix=<i>none</i>] [,<i>bool</i> lowercase=false] "
+		"[,blanks=false]")
 	,JSDOCSTR("Parse all sections from a .ini file and return all (non-<i>root</i>) sections "
-		"in an array of objects with each section's keys (optionally lowercased) as properties of each object. "
+		"in an array of objects with each section's keys (optionally lowercased) as properties of each object.<br>"
 		"<i>name_property</i> is the name of the property to create to contain the section's name "
 		"(optionally lowercased, default is <tt>\"name\"</tt>), "
-		"the optional <i>prefix</i> has the same use as in the <tt>iniGetSections</tt> method. "
-		"If a (String) <i>prefix</i> is specified, it is removed from each section's name. "
+		"the optional <i>prefix</i> has the same use as in the <tt>iniGetSections</tt> method.<br>"
+		"If a (String) <i>prefix</i> is specified, it is removed from each section's name.<br>"
 		"If <i>blanks</i> is <tt>true</tt> then empty string (instead of <tt>undefined</tt>) values may be included in the returned objects."
 	)
 	,311
 	},
-	{"iniSetAllObjects",js_iniSetAllObjects,1,	JSTYPE_BOOLEAN,	JSDOCSTR("object array [,name_property=<tt>\"name\"</tt>]")
+	{"iniSetAllObjects",js_iniSetAllObjects,1,	JSTYPE_BOOLEAN,	JSDOCSTR("<i>object</i> array [,name_property=\"name\"]")
 	,JSDOCSTR("Write an array of objects to a .ini file, each object in its own section named "
 	"after the object's <i>name_property</i> (default: <tt>name</tt>)")
 	,312
@@ -3165,28 +3164,25 @@ js_file_constructor(JSContext *cx, uintN argc, jsval *arglist)
 
 #ifdef BUILD_JSDOCS
 	js_DescribeSyncObject(cx,obj,"Class used for opening, creating, reading, or writing files on the local file system<p>"
-		"Special features include:</h2><ol type=disc>"
+		"Special features include:</h2><ol style=list-style-type:disc>"
 			"<li>Exclusive-access files (default) or shared files<ol type=circle>"
 				"<li>optional record-locking"
 				"<li>buffered or non-buffered I/O"
 				"</ol>"
-			"<li>Support for binary files<ol type=circle>"
+			"<li>Support for binary files<ol style=list-style-type:circle>"
 				"<li>native or network byte order (endian)"
 				"<li>automatic Unix-to-Unix (<i>UUE</i>), yEncode (<i>yEnc</i>) or Base64 encoding/decoding"
 				"</ol>"
-			"<li>Support for ASCII text files<ol type=circle>"
-				"<li>supports line-based I/O<ol type=square>"
+			"<li>Support for ASCII text files<ol style=list-style-type:circle>"
+				"<li>supports line-based I/O<ol style=list-style-type:square>"
 					"<li>entire file may be read or written as an array of strings"
 					"<li>individual lines may be read or written one line at a time"
 					"</ol>"
-				"<li>supports fixed-length records<ol type=square>"
+				"<li>supports fixed-length records<ol style=list-style-type:square>"
 					"<li>optional end-of-text (<i>etx</i>) character for automatic record padding/termination"
 					"<li>Synchronet <tt>.dat</tt> files use an <i>etx</i> value of 3 (Ctrl-C)"
 					"</ol>"
-				"<li>supports <tt>.ini</tt> formated configuration files<ol type=square>"
-					"<li>concept and support of <i>root</i> ini sections added in v3.12"
-					"</ol>"
-				"<li>optional ROT13 encoding/translation"
+				"<li>supports <tt>.ini</tt> formatted configuration files"
 				"</ol>"
 			"<li>Dynamically-calculated industry standard checksums (e.g. CRC-16, CRC-32, MD5)"
 			"</ol>"
diff --git a/src/sbbs3/js_file_area.c b/src/sbbs3/js_file_area.c
index f10c1a098c8a7d1735587726558665b22155fab3..493bad57cc389179106a33469581b3b615991d1c 100644
--- a/src/sbbs3/js_file_area.c
+++ b/src/sbbs3/js_file_area.c
@@ -27,33 +27,33 @@
 static char* file_area_prop_desc[] = {
 	 "Minimum amount of available disk space (in bytes) required for user uploads to be allowed"
 	,"File area settings (bit-flags) - see <tt>FM_*</tt> in <tt>sbbsdefs.js</tt> for details"
-	,"Web file virtual path prefix <i>(introduced in v3.19c)</i>"
+	,"Web file virtual path prefix"
 	,NULL
 };
 
 static char* lib_prop_desc[] = {
-	 "Index into lib_list array (or -1 if not in array) <i>(introduced in v3.12)</i>"
+	 "Index into lib_list array (or -1 if not in array)"
 	,"Unique number for this library"
 	,"Name"
 	,"Description"
 	,"Access requirements"
 	,"Virtual directory name (for FTP or HTTP access)"
-	,"User has sufficient access to this library's directories <i>(introduced in v3.18)</i>"
-	,"Internal code prefix (for directories) <i>(introduced in v3.18c)</i>"
+	,"User has sufficient access to this library's directories"
+	,"Internal code prefix (for directories)"
 	,NULL
 };
 
 static char* dir_prop_desc[] = {
 
-	 "Index into dir_list array (or -1 if not in array) <i>(introduced in v3.12)</i>"
+	 "Index into dir_list array (or -1 if not in array)"
 	,"Unique number for this directory"
-	,"Library index <i>(introduced in v3.12)</i>"
+	,"Library index"
 	,"Library number"
-	,"Library name <i>(introduced in v3.12)</i>"
+	,"Library name"
 	,"Directory internal code"
 	,"Directory name"
 	,"Directory description"
-	,"Directory area tag for file echoes <i>(introduced in v3.19)</i>"
+	,"Directory area tag for file echoes"
 	,"Directory file storage location"
 	,"Directory access requirements"
 	,"Directory upload requirements"
@@ -72,16 +72,16 @@ static char* dir_prop_desc[] = {
 	,"Percent of file size awarded uploader in credits upon subsequent downloads"
 	,"Virtual directory name (for FTP or HTTP access)"
 	,"Virtual path (for FTP or HTTP access)"
-	,"Number of files currently in this directory <i>(introduced in v3.18c)</i>"
-	,"Timestamp of file base index of this directory <i>(introduced in v3.19)</i>"
-	,"User has sufficient access to view this directory (e.g. list files) <i>(introduced in v3.18)</i>"
+	,"Number of files currently in this directory"
+	,"Time-stamp of file base index of this directory"
+	,"User has sufficient access to view this directory (e.g. list files)"
 	,"User has sufficient access to upload files to this directory"
 	,"User has sufficient access to download files from this directory"
 	,"User is exempt from download credit costs (or the directory is configured for free downloads)"
 	,"User has operator access to this directory"
-	,"Directory is for offline storage <i>(introduced in v3.14)</i>"
-	,"Directory is for uploads only <i>(introduced in v3.14)</i>"
-	,"Directory is for uploads to sysop only <i>(introduced in v3.14)</i>"
+	,"Directory is for off-line storage"
+	,"Directory is for uploads only"
+	,"Directory is for uploads to sysop only"
 	,NULL
 };
 #endif
diff --git a/src/sbbs3/js_filebase.c b/src/sbbs3/js_filebase.c
index 44112f6c1e7d1dc412690800318bfb3fed513a0c..6d3c0c27a9022d9393c6e8f7b9959d745d864088 100644
--- a/src/sbbs3/js_filebase.c
+++ b/src/sbbs3/js_filebase.c
@@ -1599,9 +1599,9 @@ static char* filebase_prop_desc[] = {
 	,"Delay between file base open/lock retries (in milliseconds)"
 	,"First file number - <small>READ ONLY</small>"
 	,"Last file number - <small>READ ONLY</small>"
-	,"Timestamp of last file - <small>READ ONLY</small>"
+	,"Time-stamp of last file - <small>READ ONLY</small>"
 	,"Total number of files - <small>READ ONLY</small>"
-	,"Timestamp of file base index (only writable when file base is closed)"
+	,"Time-stamp of file base index (only writable when file base is closed)"
 	,"Maximum number of files before expiration - <small>READ ONLY</small>"
 	,"Maximum age (in days) of files to store - <small>READ ONLY</small>"
 	,"File base attributes - <small>READ ONLY</small>"
@@ -1623,7 +1623,7 @@ static jsSyncMethodSpec js_filebase_functions[] = {
 		,31900
 	},
 	{"get",				js_get_file,		2, JSTYPE_OBJECT
-		,JSDOCSTR("filename or file-meta-object [,detail=FileBase.DETAIL.NORM]")
+		,JSDOCSTR("<i>string</i> filename or <i>object</i> file-meta-object [,<i>number</i> detail=FileBase.DETAIL.NORM]")
 		,JSDOCSTR("Get a file metadata object or <tt>null</tt> on failure. "
 			"The file-meta-object may contain the following properties (depending on <i>detail</i> value):<br>"
 			"<table>"
@@ -1645,7 +1645,7 @@ static jsSyncMethodSpec js_filebase_functions[] = {
 			"<tr><td align=top><tt>cost</tt><td>File credit value (0=free)"
 			"<tr><td align=top><tt>time</tt><td>File modification date/time (in time_t format)"
 			"<tr><td align=top><tt>added</tt><td>Date/time file was uploaded/imported (in time_t format)"
-			"<tr><td align=top><tt>last_downlaoded</tt><td>Date/time file was last downloaded (in time_t format) or 0=never"
+			"<tr><td align=top><tt>last_downloaded</tt><td>Date/time file was last downloaded (in time_t format) or 0=never"
 			"<tr><td align=top><tt>times_downloaded</tt><td>Total number of times file has been downloaded"
 			"<tr><td align=top><tt>crc16</tt><td>16-bit CRC of file contents"
 			"<tr><td align=top><tt>crc32</tt><td>32-bit CRC of file contents"
@@ -1657,7 +1657,7 @@ static jsSyncMethodSpec js_filebase_functions[] = {
 		,31900
 	},
 	{"get_list",		js_get_file_list,	4, JSTYPE_ARRAY
-		,JSDOCSTR("[filespec] [,detail=FileBase.DETAIL.NORM] [,since-time=0] [,sort=true [,order]]")
+		,JSDOCSTR("[<i>string</i> filespec] [,<i>number</i> detail=FileBase.DETAIL.NORM] [,<i>number</i> since-time=0] [,<i>bool</i> sort=true [,<i>number</i> order]]")
 		,JSDOCSTR("Get a list (array) of file metadata objects"
 			", the default sort order is the sysop-configured order or <tt>FileBase.SORT.NAME_AI</tt>"
 			)
@@ -1665,43 +1665,43 @@ static jsSyncMethodSpec js_filebase_functions[] = {
 	},
 	{"get_name",		js_get_file_name,	1, JSTYPE_STRING
 		,JSDOCSTR("path/filename")
-		,JSDOCSTR("Returns index-formatted (e.g. shortened) version of filename without path (file base does not have to be open)")
+		,JSDOCSTR("Return index-formatted (e.g. shortened) version of filename without path (file base does not have to be open)")
 		,31900
 	},
 	{"get_names",		js_get_file_names,	3, JSTYPE_ARRAY
-		,JSDOCSTR("[filespec] [,since-time=0] [,sort=true [,order]]")
+		,JSDOCSTR("[<i>string</i> filespec] [,<i>number</i> since-time=0] [,<i>bool</i> sort=true [,<i>number</i> order]]")
 		,JSDOCSTR("Get a list of index-formatted (e.g. shortened) filenames (strings) from file base index"
 			", the default sort order is the sysop-configured order or <tt>FileBase.SORT.NAME_AI</tt>")
 		,31900
 	},
 	{"get_path",		js_get_file_path,	1, JSTYPE_STRING
-		,JSDOCSTR("filename or file-meta-object")
+		,JSDOCSTR("<i>string</i> filename or <i>object</i> file-meta-object")
 		,JSDOCSTR("Get the full path to the local file")
 		,31900
 	},
 	{"get_size",		js_get_file_size,	1, JSTYPE_NUMBER
-		,JSDOCSTR("filename or file-meta-object")
+		,JSDOCSTR("<i>string</i> filename or <i>object</i> file-meta-object")
 		,JSDOCSTR("Get the size of the local file, in bytes, or -1 if it does not exist")
 		,31900
 	},
 	{"get_time",		js_get_file_time,	1, JSTYPE_NUMBER
-		,JSDOCSTR("filename or file-meta-object")
+		,JSDOCSTR("<i>string</i> filename or <i>object</i> file-meta-object")
 		,JSDOCSTR("Get the modification date/time stamp of the local file")
 		,31900
 	},
 	{"add",				js_add_file,		1, JSTYPE_BOOLEAN
-		,JSDOCSTR("file-meta-object [,use_diz_always=false] [,object client=none]")
+		,JSDOCSTR("<i>object</i> file-meta-object [,<i>bool</i> use_diz_always=false] [,<i>object</i> client=none]")
 		,JSDOCSTR("Add a file to the file base, returning <tt>true</tt> on success or <tt>false</tt> upon failure.")
 		,31900
 	},
 	{"remove",			js_remove_file,		2, JSTYPE_BOOLEAN
-		,JSDOCSTR("filename [,delete=false]")
+		,JSDOCSTR("filename [,<i>bool</i> delete=false]")
 		,JSDOCSTR("Remove an existing file from the file base and optionally delete file"
 				", may throw exception on errors (e.g. file remove failure)")
 		,31900
 	},
 	{"update",			js_update_file,		3, JSTYPE_BOOLEAN
-		,JSDOCSTR("filename, file-meta-object [,use_diz_always=false] [,readd_always=false]")
+		,JSDOCSTR("filename, <i>object</i> file-meta-object [,<i>bool</i> use_diz_always=false] [,<i>bool</i> readd_always=false]")
 		,JSDOCSTR("Update an existing file in the file base"
 				", may throw exception on errors (e.g. file rename failure)")
 		,31900
@@ -1712,7 +1712,7 @@ static jsSyncMethodSpec js_filebase_functions[] = {
 		,31900
 	},
 	{"hash",			js_hash_file,		1, JSTYPE_OBJECT
-		,JSDOCSTR("filename_or_fullpath")
+		,JSDOCSTR("<i>string</i> filename_or_fullpath")
 		,JSDOCSTR("Calculate hashes of a file's contents (file base does not have to be open)")
 		,31900
 	},
@@ -1722,8 +1722,8 @@ static jsSyncMethodSpec js_filebase_functions[] = {
 		,31900
 	},
 	{"format_name",		js_format_file_name,1, JSTYPE_STRING
-		,JSDOCSTR("path/filename [,number size=12] [,boolean pad=false]")
-		,JSDOCSTR("Returns formatted (e.g. shortened) version of filename without path (file base does not have to be open) for display")
+		,JSDOCSTR("path/filename [,<i>number</i> size=12] [,<i>bool</i> pad=false]")
+		,JSDOCSTR("Return formatted (e.g. shortened) version of filename without path (file base does not have to be open) for display")
 		,31900
 	},
 	{0}
diff --git a/src/sbbs3/js_global.c b/src/sbbs3/js_global.c
index 1542a35aacfe646a9aa0b80881f972d22accccfe..4b3241316a58f55e0db75f3e9f1c6e6dacfad12e 100644
--- a/src/sbbs3/js_global.c
+++ b/src/sbbs3/js_global.c
@@ -4818,7 +4818,7 @@ js_qwknet_route(JSContext *cx, uintN argc, jsval *arglist)
 #endif
 
 static jsSyncMethodSpec js_global_functions[] = {
-	{"exit",			js_exit,			0,	JSTYPE_VOID,	"[exit_code]"
+	{"exit",			js_exit,			0,	JSTYPE_VOID,	"[number exit_code]"
 	,JSDOCSTR("Stop script execution, "
 		"optionally setting the global property <tt>exit_code</tt> to the specified numeric value")
 	,311
@@ -4827,11 +4827,11 @@ static jsSyncMethodSpec js_global_functions[] = {
 	,JSDOCSTR("[<i>bool</i> background or <i>object</i> scope,] <i>string</i> filename [,args]")
 	,JSDOCSTR("Load and execute a JavaScript module (<i>filename</i>), "
 		"optionally specifying a target <i>scope</i> object (default: <i>this</i>) "
-		"and a list of arguments to pass to the module (as <i>argv</i>). "
+		"and a list of arguments to pass to the module (as <i>argv</i>).<br>"
 		"Returns the result (last executed statement) of the executed script "
-		"or a newly created <i>Queue</i> object if <i>background</i> is <i>true</i>).<br><br>"
-		"<b>Background</b> (added in v3.12):<br>"
-		"If <i>background</i> is <i>true</i>, the loaded script runs in the background "
+		"or a newly created <i>Queue</i> object if <i>background</i> is <tt>true</tt>).<br><br>"
+		"<b>Background</b>:<br>"
+		"When the <i>background</i> parameter is <tt>true</tt>, the loaded script runs in the background "
 		"(in a child thread) but may communicate with the parent "
 		"script/thread by reading from and/or writing to the <i>parent_queue</i> "
 		"(an automatically created <i>Queue</i> object). " 
@@ -4848,33 +4848,33 @@ static jsSyncMethodSpec js_global_functions[] = {
 		"and a list of arguments to pass to the module (as <i>argv</i>) "
 		"IF AND ONLY IF the property named <i>propname</i> is not defined in "
 		"the target scope (a defined symbol with a value of undefined will not "
-		"cause the script to be loaded). "
+		"cause the script to be loaded).<br>"
 		"Returns the result (last executed statement) of the executed script "
 		"or null if the script is not executed. ")
 	,317
 	},
 	{"sleep",			js_mswait,			0,	JSTYPE_ALIAS },
-	{"mswait",			js_mswait,			0,	JSTYPE_NUMBER,	JSDOCSTR("[milliseconds=<tt>1</tt>]")
-	,JSDOCSTR("Millisecond wait/sleep routine (AKA sleep), returns number of elapsed clock ticks (in v3.13)")
+	{"mswait",			js_mswait,			0,	JSTYPE_NUMBER,	JSDOCSTR("[milliseconds=1]")
+	,JSDOCSTR("Pause execution for the specified number of milliseconds (AKA sleep), returns elapsed duration, in seconds")
 	,313
 	},
-	{"yield",			js_yield,			0,	JSTYPE_VOID,	JSDOCSTR("[forced=<tt>true</tt>]")
+	{"yield",			js_yield,			0,	JSTYPE_VOID,	JSDOCSTR("[forced=true]")
 	,JSDOCSTR("Release current thread time-slice, "
 		"a <i>forced</i> yield will yield to all other pending tasks (lowering CPU utilization), "
 		"a non-<i>forced</i> yield will yield only to pending tasks of equal or higher priority. "
-		"<i>forced</i> defaults to <i>true</i>")
+		"<i>forced</i> defaults to <tt>true</tt>")
 	,311
 	},
-	{"random",			js_random,			1,	JSTYPE_NUMBER,	JSDOCSTR("max_number=<tt>100</tt>")
+	{"random",			js_random,			1,	JSTYPE_NUMBER,	JSDOCSTR("max_number=100")
 	,JSDOCSTR("Return random integer between <tt>0</tt> and <i>max_number</i>-1")
 	,310
 	},		
 	{"time",			js_time,			0,	JSTYPE_NUMBER,	""
 	,JSDOCSTR("Return current time and date in Unix (time_t) format "
-		"(number of seconds since Jan-01-1970)")
+		"(number of seconds since January 1st, 1970 UTC)")
 	,310
 	},		
-	{"beep",			js_beep,			0,	JSTYPE_VOID,	JSDOCSTR("[frequency=<tt>500</tt>] [,duration=<tt>500</tt>]")
+	{"beep",			js_beep,			0,	JSTYPE_VOID,	JSDOCSTR("[frequency=500] [,duration=500]")
 	,JSDOCSTR("Produce a tone on the local speaker at specified frequency for specified duration (in milliseconds)")
 	,310
 	},		
@@ -4882,11 +4882,11 @@ static jsSyncMethodSpec js_global_functions[] = {
 	,JSDOCSTR("Play a waveform (.wav) sound file (currently, on Windows platforms only)")
 	,310
 	},		
-	{"ctrl",			js_ctrl,			1,	JSTYPE_STRING,	JSDOCSTR("number or string")
-	,JSDOCSTR("Return ASCII control character representing character passed - Example: <tt>ctrl('C') returns '\3'</tt>")
+	{"ctrl",			js_ctrl,			1,	JSTYPE_STRING,	JSDOCSTR("<i>number</i> or <i>string</i> value")
+	,JSDOCSTR("Return ASCII control character representing character value passed - Example: <tt>ctrl('C')</tt> returns string containing the single character string: <tt>'\\3'</tt>")
 	,311
 	},
-	{"ascii",			js_ascii,			1,	JSTYPE_UNDEF,	JSDOCSTR("[string text] or [number value]")
+	{"ascii",			js_ascii,			1,	JSTYPE_UNDEF,	JSDOCSTR("[<i>string</i> text] or [<i>number</i> value]")
 	,JSDOCSTR("Convert single character to numeric ASCII value or vice-versa (returns number OR string)")
 	,310
 	},		
@@ -4926,44 +4926,44 @@ static jsSyncMethodSpec js_global_functions[] = {
 	,JSDOCSTR("Expand line-feeds (LF) to carriage-return/line-feeds (CRLF), returns modified string")
 	,310
 	},
-	{"wildmatch",		js_wildmatch,		2,	JSTYPE_BOOLEAN, JSDOCSTR("[case_sensitive=<tt>false</tt>,] string [,pattern=<tt>'*'</tt>] [,path=<tt>false</tt>]")
-	,JSDOCSTR("Returns <tt>true</tt> if the <i>string</i> matches the wildcard <i>pattern</i> (wildcards supported are '*' and '?'), "
-	"if <i>path</i> is <tt>true</tt>, '*' will not match path delimeter characters (e.g. '/')")
+	{"wildmatch",		js_wildmatch,		2,	JSTYPE_BOOLEAN, JSDOCSTR("[<i>bool</i> case_sensitive=false,] filename [,pattern='*'] [,path=false]")
+	,JSDOCSTR("Return <tt>true</tt> if the <i>filename</i> matches the wildcard <i>pattern</i> (wildcard characters supported are '*' and '?'), "
+	"if <i>path</i> is <tt>true</tt>, '*' will not match path delimiter characters (e.g. '/')")
 	,314
 	},
 	{"backslash",		js_backslash,		1,	JSTYPE_STRING,	JSDOCSTR("path")
-	,JSDOCSTR("Returns directory path with trailing (platform-specific) path delimeter "
+	,JSDOCSTR("Return directory path with trailing (platform-specific) path delimiter "
 		"(i.e. \"slash\" or \"backslash\")")
 	,312
 	},
 	{"fullpath",		js_fullpath,		1,	JSTYPE_STRING,	JSDOCSTR("path")
-	,JSDOCSTR("Creates an absolute or full path name for the specified relative path name.")
+	,JSDOCSTR("Create and return an absolute or full path name for the specified relative path name.")
 	,315
 	},
 	{"file_getname",	js_getfname,		1,	JSTYPE_STRING,	JSDOCSTR("path/filename")
-	,JSDOCSTR("Returns filename portion of passed path string")
+	,JSDOCSTR("Return filename portion of passed path string")
 	,311
 	},
 	{"file_getext",		js_getfext,			1,	JSTYPE_STRING,	JSDOCSTR("path/filename")
-	,JSDOCSTR("Returns file extension portion of passed path/filename string (including '.') "
-		"or <i>undefined</i> if no extension is found")
+	,JSDOCSTR("Return file extension portion of passed path/filename string (including '.') "
+		"or <tt>undefined</tt> if no extension is found")
 	,311
 	},
 	{"file_getcase",	js_getfcase,		1,	JSTYPE_STRING,	JSDOCSTR("path/filename")
-	,JSDOCSTR("Returns correct case of filename (long version of filename on Windows) "
-		"or <i>undefined</i> if the file doesn't exist")
+	,JSDOCSTR("Return correct case of filename (long version of filename on Windows) "
+		"or <tt>undefined</tt> if the file doesn't exist")
 	,311
 	},
 	{"file_cfgname",	js_cfgfname,		2,	JSTYPE_STRING,	JSDOCSTR("path, filename")
-	,JSDOCSTR("Returns completed configuration filename from supplied <i>path</i> and <i>filename</i>, "
+	,JSDOCSTR("Return completed configuration filename from supplied <i>path</i> and <i>filename</i>, "
 	"optionally including the local hostname (e.g. <tt>path/file.<i>host</i>.<i>domain</i>.ext</tt> "
 	"or <tt>path/file.<i>host</i>.ext</tt>) if such a variation of the filename exists")
 	,312
 	},
 	{"file_getdosname",	js_dosfname,		1,	JSTYPE_STRING,	JSDOCSTR("path/filename")
-	,JSDOCSTR("Returns DOS-compatible (Micros~1 shortened) version of specified <i>path/filename</i>"
+	,JSDOCSTR("Return DOS-compatible (Micros~1 shortened) version of specified <i>path/filename</i>"
 		"(on Windows only)<br>"
-		"returns unmodified <i>path/filename</i> on other platforms")
+		"return unmodified <i>path/filename</i> on other platforms")
 	,315
 	},
 	{"file_exists",		js_fexist,			1,	JSTYPE_BOOLEAN,	JSDOCSTR("path/filename")
@@ -4983,15 +4983,15 @@ static jsSyncMethodSpec js_global_functions[] = {
 	,311
 	},
 	{"file_copy",		js_fcopy,			2,	JSTYPE_BOOLEAN,	JSDOCSTR("path/source, path/destination")
-	,JSDOCSTR("copy a file from one directory or filename to another")
+	,JSDOCSTR("Copy a file from one directory or filename to another")
 	,311
 	},
-	{"file_backup",		js_backup,			1,	JSTYPE_BOOLEAN,	JSDOCSTR("path/filename [,level=<tt>5</tt>] [,rename=<tt>false</tt>]")
+	{"file_backup",		js_backup,			1,	JSTYPE_BOOLEAN,	JSDOCSTR("path/filename [,level=5] [,rename=false]")
 	,JSDOCSTR("Backup the specified <i>filename</i> as <tt>filename.<i>number</i>.extension</tt> "
 		"where <i>number</i> is the backup number 0 through <i>level</i>-1 "
 		"(default backup <i>level</i> is 5), "
-		"if <i>rename</i> is <i>true</i>, the original file is renamed instead of copied "
-		"(default is <i>false</i>)")
+		"if <i>rename</i> is <tt>true</tt>, the original file is renamed instead of copied "
+		"(default is <tt>false</tt>)")
 	,311
 	},
 	{"file_isdir",		js_isdir,			1,	JSTYPE_BOOLEAN,	JSDOCSTR("path/filename")
@@ -5036,45 +5036,45 @@ static jsSyncMethodSpec js_global_functions[] = {
 	,311
 	},
 	{"file_touch",		js_ftouch,			1,	JSTYPE_BOOLEAN,	JSDOCSTR("path/filename")
-	,JSDOCSTR("Updates a file's last modification date/time to current time, "
+	,JSDOCSTR("Update a file's last modification date/time to current time, "
 		"creating an empty file if it doesn't already exist")
 	,311
 	},
-	{"file_mutex",		js_fmutex,			1,	JSTYPE_BOOLEAN,	JSDOCSTR("path/filename [,text=<i>local_hostname</i>] [,max_age=<tt>0</tt>]")
-	,JSDOCSTR("Attempts to create an mutual-exclusion (e.g. lock) file, "
+	{"file_mutex",		js_fmutex,			1,	JSTYPE_BOOLEAN,	JSDOCSTR("path/filename [,<i>string</i> text=<i>local_hostname</i>] [,<i>number</i> max_age=0]")
+	,JSDOCSTR("Attempt to create an mutual-exclusion (e.g. lock) file, "
 		"optionally with the contents of <i>text</i>. "
-		"If a non-zero <i>max_age</i> (supported in v3.13b+) is specified "
+		"If a non-zero <i>max_age</i> is specified "
 		"and the lock file exists, but is older than this value (in seconds), "
 		"it is presumed stale and removed/over-written")
 	,312
 	},
 	{"file_compare",	js_fcompare,		2,	JSTYPE_BOOLEAN,	JSDOCSTR("path/file1, path/file2")
-	,JSDOCSTR("Compare 2 files, returning <i>true</i> if they are identical, <i>false</i> otherwise")
+	,JSDOCSTR("Compare 2 files, returning <tt>true</tt> if they are identical, <tt>false</tt> otherwise")
 	,314
 	},
-	{"directory",		js_directory,		1,	JSTYPE_ARRAY,	JSDOCSTR("path/pattern [,flags=<tt>GLOB_MARK</tt>]")
-	,JSDOCSTR("Returns an array of directory entries, "
+	{"directory",		js_directory,		1,	JSTYPE_ARRAY,	JSDOCSTR("path/pattern [,flags=GLOB_MARK]")
+	,JSDOCSTR("Return an array of directory entries, "
 		"<i>pattern</i> is the path and filename or wildcards to search for (e.g. '/subdir/*.txt'), "
 		"<i>flags</i> is a set of optional <tt>glob</tt> bit-flags (default is <tt>GLOB_MARK</tt>)")
 	,310
 	},
-	{"dir_freespace",	js_freediskspace,	2,	JSTYPE_NUMBER,	JSDOCSTR("directory [,unit_size=<tt>1</tt>]")
-	,JSDOCSTR("Returns the amount of available disk space in the specified <i>directory</i> "
+	{"dir_freespace",	js_freediskspace,	2,	JSTYPE_NUMBER,	JSDOCSTR("directory [,unit_size=1]")
+	,JSDOCSTR("Return the amount of available disk space in the specified <i>directory</i> "
 		"using the specified <i>unit_size</i> in bytes (default: 1), "
 		"specify a <i>unit_size</i> of <tt>1024</tt> to return the available space in <i>kilobytes</i>.")
 	,311
 	},
-	{"disk_size",		js_disksize,		2,	JSTYPE_NUMBER,	JSDOCSTR("directory [,unit_size=<tt>1</tt>]")
-	,JSDOCSTR("Returns the total disk size of the specified <i>directory</i> "
+	{"disk_size",		js_disksize,		2,	JSTYPE_NUMBER,	JSDOCSTR("directory [,unit_size=1]")
+	,JSDOCSTR("Return the total disk size of the specified <i>directory</i> "
 		"using the specified <i>unit_size</i> in bytes (default: 1), "
 		"specify a <i>unit_size</i> of <tt>1024</tt> to return the total disk size in <i>kilobytes</i>.")
 	,314
 	},
-	{"socket_select",	js_socket_select,	0,	JSTYPE_ARRAY,	JSDOCSTR("[array of socket objects or descriptors] [,timeout=<tt>0</tt>] [,write=<tt>false</tt>]")
-	,JSDOCSTR("Checks an array of socket objects or descriptors for read or write ability (default is <i>read</i>), "
+	{"socket_select",	js_socket_select,	0,	JSTYPE_ARRAY,	JSDOCSTR("[array of socket objects or descriptors] [,<i>number</i> timeout=0] [,<i>bool</i> write=false]")
+	,JSDOCSTR("Check an array of socket objects or descriptors for read or write ability (default is <i>read</i>), "
 		"default timeout value is 0.0 seconds (immediate timeout), "
-		"returns an array of 0-based index values into the socket array, representing the sockets that were ready for reading or writing, or <i>null</i> on error. "
-		"If multiple arrays of sockets are passed, they are presumed to be in the order of read, write, and except.  In this case, the write parameter is ignored "
+		"returns an array of 0-based index values into the socket array, representing the sockets that were ready for reading or writing, or <tt>null</tt> on error. "
+		"If multiple arrays of sockets are passed, they are presumed to be in the order of read, write, and except.  In this case, the <i>write</i> parameter is ignored "
 		"and an object is returned instead with up to three properties \"read\", \"write\", and \"except\", corresponding to the passed arrays.  Empty passed "
 		"arrays will not have a corresponding property in the returned object.")
 	,311
@@ -5092,7 +5092,7 @@ static jsSyncMethodSpec js_global_functions[] = {
 	,310
 	},		
 	{"mkpath",			js_mkpath,			1,	JSTYPE_BOOLEAN,	JSDOCSTR("path/directory")
-	,JSDOCSTR("Make a path to a directory (creating all necessary sub-directories). Returns true if the directory already exists.")
+	,JSDOCSTR("Make a path to a directory (creating all necessary sub-directories). Returns <tt>true</tt> if the directory already exists.")
 	,315
 	},		
 	{"rmdir",			js_rmdir,			1,	JSTYPE_BOOLEAN,	JSDOCSTR("path/directory")
@@ -5104,14 +5104,14 @@ static jsSyncMethodSpec js_global_functions[] = {
 	,320
 	},
 	{"strftime",		js_strftime,		1,	JSTYPE_STRING,	JSDOCSTR("format [,time=<i>current</i>]")
-	,JSDOCSTR("Return a formatted time string (ala C strftime)")
+	,JSDOCSTR("Return a formatted time string (ala the standard C <tt>strftime</tt> function)")
 	,310
 	},		
 	{"format",			js_format,			1,	JSTYPE_STRING,	JSDOCSTR("format [,args]")
-	,JSDOCSTR("Return a formatted string (ala the standard C <tt>sprintf</tt> function)")
+	,JSDOCSTR("Return a C-style formatted string (ala the standard C <tt>sprintf</tt> function)")
 	,310
 	},
-	{"html_encode",		js_html_encode,		1,	JSTYPE_STRING,	JSDOCSTR("text [,ex_ascii=<tt>true</tt>] [,white_space=<tt>true</tt>] [,ansi=<tt>true</tt>] [,ctrl_a=<tt>true</tt>] [, state (object)]")
+	{"html_encode",		js_html_encode,		1,	JSTYPE_STRING,	JSDOCSTR("text [,<i>bool</i> ex_ascii=true] [,<i>bool</i> white_space=true] [,<i>bool</i> ansi=true] [,<i>bool</i> ctrl_a=true] [, state (object)]")
 	,JSDOCSTR("Return an HTML-encoded text string (using standard HTML character entities), "
 		"escaping IBM extended-ASCII (CP437), white-space characters, ANSI codes, and CTRL-A codes by default."
 		"Optionally storing the current ANSI state in <i>state</i> object")
@@ -5121,27 +5121,27 @@ static jsSyncMethodSpec js_global_functions[] = {
 	,JSDOCSTR("Return a decoded HTML-encoded text string")
 	,311
 	},
-	{"word_wrap",		js_word_wrap,		1,	JSTYPE_STRING,	JSDOCSTR("text [,line_length=<tt>79</tt> [, orig_line_length=<tt>79</tt> [, handle_quotes=<tt>true</tt> [, is_utf8=<tt>false</tt>]]]]")
-	,JSDOCSTR("Returns a word-wrapped version of the text string argument optionally handing quotes magically, "
-		"<i>line_length</i> defaults to <i>79</i>, <i>orig_line_length</i> defaults to <i>79</i>, "
-		"<i>handle_quotes</i> defaults to <i>true</i>, and <i>is_utf8</i> defaults to <i>false</i>")
+	{"word_wrap",		js_word_wrap,		1,	JSTYPE_STRING,	JSDOCSTR("text [,line_length=79 [,orig_line_length=79 [,<i>bool</i> handle_quotes=true [,<i>bool</i> is_utf8=false]]]]")
+	,JSDOCSTR("Return a word-wrapped version of the <i>text</i> string argument optionally handing quotes magically, "
+		"<i>line_length</i> defaults to <i>79</i>, <i>orig_line_length</i> defaults to <tt>79</tt>, "
+		"<i>handle_quotes</i> defaults to <tt>true</tt>, and <i>is_utf8</i> defaults to <tt>false</tt>")
 	,311
 	},
-	{"quote_msg",		js_quote_msg,		1,	JSTYPE_STRING,	JSDOCSTR("text [,line_length=<tt>79</tt>] [,prefix=<tt>\" > \"</tt>]")
-	,JSDOCSTR("Returns a quoted version of the message text string argument, <i>line_length</i> defaults to <i>79</i>, "
+	{"quote_msg",		js_quote_msg,		1,	JSTYPE_STRING,	JSDOCSTR("text [,line_length=79] [,prefix=\" > \"]")
+	,JSDOCSTR("Return a quoted version of the message <i>text</i> string argument, <i>line_length</i> defaults to <tt>79</tt>, "
 		"<i>prefix</i> defaults to <tt>\" > \"</tt>")
 	,311
 	},
 	{"rot13_translate",	js_rot13,			1,	JSTYPE_STRING,	JSDOCSTR("text")
-	,JSDOCSTR("Returns ROT13-translated version of text string (will encode or decode text)")
+	,JSDOCSTR("Return ROT13-translated version of text string (will encode or decode text)")
 	,311
 	},
 	{"base64_encode",	js_b64_encode,		1,	JSTYPE_STRING,	JSDOCSTR("text")
-	,JSDOCSTR("Returns base64-encoded version of text string or <i>null</i> on error")
+	,JSDOCSTR("Return base64-encoded version of text string or <tt>null</tt> on error")
 	,311
 	},
 	{"base64_decode",	js_b64_decode,		1,	JSTYPE_STRING,	JSDOCSTR("text")
-	,JSDOCSTR("Returns base64-decoded text string or <i>null</i> on error")
+	,JSDOCSTR("Return base64-decoded text string or <tt>null</tt> on error")
 	,311
 	},
 	{"crc16_calc",		js_crc16,			1,	JSTYPE_NUMBER,	JSDOCSTR("text")
@@ -5156,17 +5156,17 @@ static jsSyncMethodSpec js_global_functions[] = {
 	,JSDOCSTR("Calculate and return 32-bit checksum of text string")
 	,311
 	},
-	{"md5_calc",		js_md5_calc,		1,	JSTYPE_STRING,	JSDOCSTR("text [,hex=<tt>false</tt>]")
+	{"md5_calc",		js_md5_calc,		1,	JSTYPE_STRING,	JSDOCSTR("text [,<i>bool</i> hex=false]")
 	,JSDOCSTR("Calculate and return 128-bit MD5 digest of text string, result encoded in base64 (default) or hexadecimal")
 	,311
 	},
-	{"sha1_calc",		js_sha1_calc,		1,	JSTYPE_STRING,	JSDOCSTR("text [,hex=false]")
+	{"sha1_calc",		js_sha1_calc,		1,	JSTYPE_STRING,	JSDOCSTR("text [,<i>bool</i> hex=false]")
 	,JSDOCSTR("Calculate and return 160-bit SHA-1 digest of text string, result encoded in base64 (default) or hexadecimal")
 	,31900
 	},
 	{"gethostbyname",	js_resolve_ip,		1,	JSTYPE_ALIAS },
-	{"resolve_ip",		js_resolve_ip,		1,	JSTYPE_STRING,	JSDOCSTR("hostname [,array=<tt>false</tt>]")
-	,JSDOCSTR("Resolve IP address of specified hostname (AKA gethostbyname).  If <i>array</i> is true (added in 3.17), will return "
+	{"resolve_ip",		js_resolve_ip,		1,	JSTYPE_STRING,	JSDOCSTR("<i>string</i> hostname [,<i>bool</i> array=false]")
+	,JSDOCSTR("Resolve IP address of specified hostname (AKA gethostbyname).  If <i>array</i> is <tt>true</tt>, will return "
 	"an array of all addresses rather than just the first one (upon success).  Returns <tt>null</tt> if unable to resolve address.")
 	,311
 	},
@@ -5176,45 +5176,45 @@ static jsSyncMethodSpec js_global_functions[] = {
 	,311
 	},
 	{"netaddr_type",	js_netaddr_type,	1,	JSTYPE_NUMBER,	JSDOCSTR("email_address")
-	,JSDOCSTR("Returns the proper message <i>net_type</i> for the specified <i>email_address</i>, "
+	,JSDOCSTR("Return the proper message <i>net_type</i> for the specified <i>email_address</i>, "
 		"(e.g. <tt>NET_INTERNET</tt> for Internet e-mail or <tt>NET_NONE</tt> for local e-mail)")
 	,312
 	},
 	{"list_named_queues",js_list_named_queues,0,JSTYPE_ARRAY,	JSDOCSTR("")
-	,JSDOCSTR("Returns an array of <i>named queues</i> (created with the <i>Queue</i> constructor)")
+	,JSDOCSTR("Return an array of <i>named queues</i> (created with the <i>Queue</i> constructor)")
 	,312
 	},
-	{"flags_str",		js_flags_str,		1,	JSTYPE_UNDEF,	JSDOCSTR("[string] or [number]")
-	,JSDOCSTR("Convert a string of security flags (letters) into their numeric value or vice-versa "
-	"(returns number OR string) - (added in v3.13)")
+	{"flags_str",		js_flags_str,		1,	JSTYPE_UNDEF,	JSDOCSTR("[<i>string</i>] or [<i>number</i>]")
+	,JSDOCSTR("Convert a string of security flags (letters) into their numeric value or vice-versa, "
+	"returns number OR string")
 	,313
 	},
-	{"utf8_encode",		js_utf8_encode,		1,	JSTYPE_STRING,	JSDOCSTR("[string CP437] or [string UTF16] or [number codepoint]")
-	,JSDOCSTR("Returns UTF-8 encoded version of the specified CP437 text string, UTF-16 encoded text string, or a single Unicode <i>codepoint</i>")
+	{"utf8_encode",		js_utf8_encode,		1,	JSTYPE_STRING,	JSDOCSTR("[<i>string</i> CP437] or [<i>string</i> UTF16] or [<i>number</i> codepoint]")
+	,JSDOCSTR("Return UTF-8 encoded version of the specified CP437 text string, UTF-16 encoded text string, or a single Unicode <i>codepoint</i>")
 	,31702
 	},
 	{"utf8_decode",		js_utf8_decode,		1,	JSTYPE_STRING,	JSDOCSTR("text")
-		,JSDOCSTR("Returns CP437 representation of UTF-8 encoded text string or <i>null</i> on error (invalid UTF-8)")
+		,JSDOCSTR("Return CP437 representation of UTF-8 encoded text string or <tt>null</tt> on error (invalid UTF-8)")
 		,31702
 	},
 	{"utf8_get_width",		js_utf8_get_width,	1,	JSTYPE_NUMBER,	JSDOCSTR("text")
-		,JSDOCSTR("Returns the fixed printed-width of the specified string of UTF-8 encoded characters")
+		,JSDOCSTR("Return the fixed printed-width of the specified string of UTF-8 encoded characters")
 		,31702
 	},
 	{"str_is_utf8",			js_str_is_utf8,		1,	JSTYPE_BOOLEAN,	JSDOCSTR("text")
-		,JSDOCSTR("Returns <tt>true</tt> if the specified string contains only valid UTF-8 encoded and US-ASCII characters")
+		,JSDOCSTR("Return <tt>true</tt> if the specified string contains only valid UTF-8 encoded and US-ASCII characters")
 		,31702
 	},
 	{"str_is_utf16",		js_str_is_utf16,		1,	JSTYPE_BOOLEAN,	JSDOCSTR("text")
-		,JSDOCSTR("Returns <tt>true</tt> if the specified string contains one or more UTF-16 encoded characters")
+		,JSDOCSTR("Return <tt>true</tt> if the specified string contains one or more UTF-16 encoded characters")
 		,31702
 	},
 	{"str_is_ascii",		js_str_is_ascii,	1,	JSTYPE_BOOLEAN,	JSDOCSTR("text")
-		,JSDOCSTR("Returns <tt>true</tt> if the specified string contains only US-ASCII (no CP437 or UTF-8) characters")
+		,JSDOCSTR("Return <tt>true</tt> if the specified string contains only US-ASCII (no CP437 or UTF-8) characters")
 		,31702
 	},
 	{"str_has_ctrl",		js_str_has_ctrl,	1,	JSTYPE_BOOLEAN,	JSDOCSTR("text")
-		,JSDOCSTR("Returns <tt>true</tt> if the specified string contains any control characters (ASCII 0x01 - 0x1F)")
+		,JSDOCSTR("Return <tt>true</tt> if the specified string contains any control characters (ASCII 0x01 - 0x1F)")
 		,31702
 	},
 	{0}
@@ -5423,7 +5423,7 @@ BOOL js_CreateGlobalObject(JSContext* cx, scfg_t* cfg, jsSyncMethodSpec* methods
 
 #ifdef BUILD_JSDOCS
 	js_DescribeSyncObject(cx,*glob
-		,"Top-level functions and properties (common to all servers and services)",310);
+		,"Top-level functions and properties (common to all servers, services, and <i>JSexec</i>)",310);
 #endif
 
 	return(TRUE);
diff --git a/src/sbbs3/js_internal.c b/src/sbbs3/js_internal.c
index 83f17c8cdfc88f998df8e7bf8e868280f0f2b862..48debeb51ca62bdc9ecb28e46204e8bcfb1f9fc7 100644
--- a/src/sbbs3/js_internal.c
+++ b/src/sbbs3/js_internal.c
@@ -181,61 +181,79 @@ static JSBool js_set(JSContext *cx, JSObject *obj, jsid id, JSBool strict, jsval
 static jsSyncPropertySpec js_properties[] = {
 /*		 name,				tinyid,						flags,		ver	*/
 
-	{	"version",			PROP_VERSION,		PROP_FLAGS,			311 },
-	{	"auto_terminate",	PROP_AUTO_TERMINATE,JSPROP_ENUMERATE,	311 },
-	{	"terminated",		PROP_TERMINATED,	JSPROP_ENUMERATE,	311 },
-	{	"branch_counter",	PROP_COUNTER,		0,					311 },
-	{	"counter",			PROP_COUNTER,		JSPROP_ENUMERATE,	316 },
-	{	"branch_limit",		PROP_TIME_LIMIT,	0,					311 },
-	{	"time_limit",		PROP_TIME_LIMIT,	JSPROP_ENUMERATE,	316 },
-	{	"yield_interval",	PROP_YIELD_INTERVAL,JSPROP_ENUMERATE,	311 },
-	{	"gc_interval",		PROP_GC_INTERVAL,	JSPROP_ENUMERATE,	311 },
-	{	"gc_attempts",		PROP_GC_ATTEMPTS,	PROP_FLAGS,			311 },
+	{	"version",			PROP_VERSION,		PROP_FLAGS,			311
+		,JSDOCSTR("JavaScript engine version information (AKA system.js_version) - <small>READ ONLY</small>")
+	},
+	{	"auto_terminate",	PROP_AUTO_TERMINATE,JSPROP_ENUMERATE,	311
+		,JSDOCSTR("Set to <i>false</i> to disable the automatic termination of the script upon external request")
+	},
+	{	"terminated",		PROP_TERMINATED,	JSPROP_ENUMERATE,	311
+		,JSDOCSTR("Termination has been requested (stop execution as soon as possible)")
+	},
+	{	"branch_counter",	PROP_COUNTER,		0,					311
+		,JSDOCSTR("alias")
+	},
+	{	"counter",			PROP_COUNTER,		JSPROP_ENUMERATE,	316
+		,JSDOCSTR("Number of operation callbacks performed in this runtime")
+	},
+	{	"branch_limit",		PROP_TIME_LIMIT,	0,					311
+		,JSDOCSTR("alias")
+	},
+	{	"time_limit",		PROP_TIME_LIMIT,	JSPROP_ENUMERATE,	316
+		,JSDOCSTR("Maximum number of operation callbacks, used for infinite-loop detection (0=disabled)")
+	},
+	{	"yield_interval",	PROP_YIELD_INTERVAL,JSPROP_ENUMERATE,	311
+		,JSDOCSTR("Interval of periodic time-slice yields (lower number=higher frequency, 0=disabled)")
+	},
+	{	"gc_interval",		PROP_GC_INTERVAL,	JSPROP_ENUMERATE,	311
+		,JSDOCSTR("Interval of periodic garbage collection attempts (lower number=higher frequency, 0=disabled)")
+	},
+	{	"gc_attempts",		PROP_GC_ATTEMPTS,	PROP_FLAGS,			311
+		,JSDOCSTR("Number of garbage collections attempted in this runtime - <small>READ ONLY </small>")
+	},
 #ifdef jscntxt_h___
-	{	"gc_counter",		PROP_GC_COUNTER,	PROP_FLAGS,			311 },
-	{	"gc_last_bytes",	PROP_GC_LASTBYTES,	PROP_FLAGS,			311 },
-	{	"bytes",			PROP_BYTES,			PROP_FLAGS,			311 },
-	{	"max_bytes",		PROP_MAXBYTES,		JSPROP_ENUMERATE,	311 },
+	{	"gc_counter",		PROP_GC_COUNTER,	PROP_FLAGS,			311
+		,JSDOCSTR("Number of garbage collections performed in this runtime - <small>READ ONLY</small>")
+	},
+	{	"gc_last_bytes",	PROP_GC_LASTBYTES,	PROP_FLAGS,			311
+		,JSDOCSTR("Number of heap bytes in use after last garbage collection - <small>READ ONLY</small>")
+	},
+	{	"bytes",			PROP_BYTES,			PROP_FLAGS,			311
+		,JSDOCSTR("Number of heap bytes currently in use - <small>READ ONLY</small>")
+	},
+	{	"max_bytes",		PROP_MAXBYTES,		JSPROP_ENUMERATE,	311
+		,JSDOCSTR("Maximum number of bytes available for heap")
+	},
 #endif
-	{	"global",			PROP_GLOBAL,		PROP_FLAGS,			314 },
-	{	"options",			PROP_OPTIONS,		PROP_FLAGS,			31802 },
-	{	"do_callbacks",		PROP_KEEPGOING,		JSPROP_ENUMERATE,			31900 },
+	{	"global",			PROP_GLOBAL,		PROP_FLAGS,			314
+		,JSDOCSTR("Global (top level) object - <small>READ ONLY</small>")
+	},
+	{	"options",			PROP_OPTIONS,		PROP_FLAGS,			31802
+		,JSDOCSTR("Option flags - <small>READ ONLY</small>")
+	},
+	{	"do_callbacks",		PROP_KEEPGOING,		JSPROP_ENUMERATE,	31900
+		,JSDOCSTR("Do callbacks after script finishes running")
+	},
 	{0}
 };
 
 #ifdef BUILD_JSDOCS
 static char* prop_desc[] = {
-	 "JavaScript engine version information (AKA system.js_version)"
-	,"Set to <i>false</i> to disable the automatic termination of the script upon external request"
-	,"Termination has been requested (stop execution as soon as possible)"
-	,"Number of operation callbacks performed in this runtime"
-	,"Maximum number of operation callbacks, used for infinite-loop detection (0=disabled)"
-	,"Interval of periodic time-slice yields (lower number=higher frequency, 0=disabled)"
-	,"Interval of periodic garbage collection attempts (lower number=higher frequency, 0=disabled)"
-	,"Number of garbage collections attempted in this runtime - <small>READ ONLY</small>"
-#ifdef jscntxt_h___
-	,"Number of garbage collections performed in this runtime - <small>READ ONLY</small>"
-	,"Number of heap bytes in use after last garbage collection - <small>READ ONLY</small>"
-	,"Number of heap bytes currently in use - <small>READ ONLY</small>"
-	,"Maximum number of bytes available for heap"
-#endif
-	,"Global (top level) object - <small>READ ONLY</small>"
-	,"Option flags - <small>READ ONLY</small>"
-	,"Do callbacks after script finishes running"
 	/* New properties go here... */
-	,"load() search path array.<br>For relative load paths (e.g. not beginning with '/' or '\\'), "
-		"the path is assumed to be a sub-directory of the (configurable) mods or exec directories "
-		"and is searched accordingly. "
-		"So, by default, load(\"somefile.js\") will search in this order:<br>"
-		"mods/load/somefile.js<br>"
-		"exec/load/somefile.js<br>"
-		"mods/somefile.js<br>"
-		"exec/somefile.js<br>"
-	,"Full path and filename of JS file executed"
+	"Full path and filename of JS file executed"
 	,"JS filename executed (with no path)"
 	,"Directory of executed JS file"
 	,"Either the configured startup directory in SCFG (for externals) or the cwd when jsexec is started"
 	,"Global scope for this script"
+	,"<tt>load()</tt> search path array.<br>For relative load paths (e.g. not beginning with '/' or '\\'), "
+		"the path is assumed to be a sub-directory of the (configurable) mods or exec directories "
+		"and is searched accordingly.<br>"
+		"So, by default, <tt>load(\"somefile.js\")</tt> will search in this order:<tt><ol>"
+		"<li>mods/load/somefile.js"
+		"<li>exec/load/somefile.js"
+		"<li>mods/somefile.js"
+		"<li>exec/somefile.js"
+		"</ol></tt>"
 	,NULL
 };
 #endif
@@ -684,7 +702,7 @@ static JSBool js_getsize(JSContext *cx, uintN argc, jsval *arglist)
 	JSObject* tmp_obj;
 
 	if(!JSVAL_IS_OBJECT(argv[0])) {
-		JS_ReportError(cx, "get_size() error!  Parameter is not an object.");
+		JS_ReportError(cx, "Parameter is not an object.");
 		return(JS_FALSE);
 	}
 	tmp_obj=JSVAL_TO_OBJECT(argv[0]);
@@ -699,7 +717,7 @@ static JSBool js_flatten(JSContext *cx, uintN argc, jsval *arglist)
 	jsval	*argv=JS_ARGV(cx, arglist);
 
 	if(!JSVAL_IS_STRING(argv[0])) {
-		JS_ReportError(cx, "get_size() error!  Parameter is not a string.");
+		JS_ReportError(cx, "Parameter is not a string.");
 		return(JS_FALSE);
 	}
 	JS_FlattenString(cx, JSVAL_TO_STRING(argv[0]));
@@ -1439,9 +1457,9 @@ static jsSyncMethodSpec js_functions[] = {
 	,JSDOCSTR("Evaluate a JavaScript string in its own (secure) context, returning the result")
 	,311
 	},		
-	{"gc",				js_gc,				0,	JSTYPE_VOID,	JSDOCSTR("forced=<tt>true</tt>")
+	{"gc",				js_gc,				0,	JSTYPE_VOID,	JSDOCSTR("forced=true")
 	,JSDOCSTR("Perform a garbage collection operation (freeing memory for unused allocated objects), "
-		"if <i>forced</i> is <i>true</i> (the default) a garbage collection is always performed, "
+		"if <i>forced</i> is <tt>true</tt> (the default) a garbage collection is always performed, "
 		"otherwise it is only performed if deemed appropriate by the JavaScript engine")
 	,311
 	},
@@ -1449,25 +1467,25 @@ static jsSyncMethodSpec js_functions[] = {
 	,JSDOCSTR("Add a string to evaluate/execute (LIFO stack) upon script's termination (e.g. call of <tt>exit()</tt>)")
 	,313
 	},
-	{"report_error",	js_report_error,	1,	JSTYPE_VOID,	JSDOCSTR("error [,fatal=<tt>false</tt>]")
+	{"report_error",	js_report_error,	1,	JSTYPE_VOID,	JSDOCSTR("error [,fatal=false]")
 	,JSDOCSTR("Report an error using the standard JavaScript error reporting mechanism "
 	"(including script filename and line number), "
-	"if <i>fatal</i> is <i>true</i>, immediately terminates script")
+	"if <i>fatal</i> is <tt>true</tt>, immediately terminates script")
 	,313
 	},
-	{"get_parent",		js_get_parent,		1,	JSTYPE_OBJECT,	JSDOCSTR("object")
-	,JSDOCSTR("Return the parent of the specified object")
+	{"get_parent",		js_get_parent,		1,	JSTYPE_OBJECT,	JSDOCSTR("<i>object</i> child")
+	,JSDOCSTR("Return the parent of the specified child object")
 	,314
 	},
 	{"get_size",		js_getsize,			1,	JSTYPE_NUMBER,	JSDOCSTR("[object]")
 	,JSDOCSTR("Return the size in bytes the object uses in memory (forces GC) ")
 	,316
 	},
-	{"flatten_string",	js_flatten,			1,	JSTYPE_VOID,	JSDOCSTR("[string]")
+	{"flatten_string",	js_flatten,			1,	JSTYPE_VOID,	JSDOCSTR("<i>string</i> value")
 	,JSDOCSTR("Flatten a string, optimizing allocated memory used for concatenated strings")
 	,316
 	},
-	{"exec",	js_execfile,			1,	JSTYPE_NUMBER,	JSDOCSTR("filename [,startup_dir], <i>object</i> scope [,...]")
+	{"exec",	js_execfile,			1,	JSTYPE_NUMBER,	JSDOCSTR("<i>string</i> filename [,<i>string</i> startup_dir], <i>object</i> scope [,...]")
 	,JSDOCSTR("Execute a script within the specified <i>scope</i>.  The main difference between this method "
 	"and <tt>load()</tt> is that scripts invoked in this way can call <tt>exit()</tt> without terminating the caller.  If it does, any "
 	"<tt>on_exit()</tt> handlers will be evaluated in the script's scope when the script exits. <br>"
@@ -1502,12 +1520,12 @@ static jsSyncMethodSpec js_functions[] = {
 	,JSDOCSTR("Remove listeners added with <tt>js.addEventListener()</tt>.  <tt>id</tt> can be a string or an id returned by <tt>addEventListener()</tt>.  This does not remove already triggered callbacks from the run queue.")
 	,31900
 	},
-	{"dispatchEvent",	js_dispatchEvent,	1,	JSTYPE_VOID,	JSDOCSTR("eventName [,thisObj]")
+	{"dispatchEvent",	js_dispatchEvent,	1,	JSTYPE_VOID,	JSDOCSTR("eventName [,<i>object</i> thisObj]")
 	,JSDOCSTR("Add all listeners of eventName to the end of the run queue.  If <tt>thisObj</tt> is passed, specifies <tt>this</tt> in the callback (the <tt>js</tt> object is used otherwise).")
 	,31900
 	},
 	{"setImmediate",	js_setImmediate,	1,	JSTYPE_VOID,	JSDOCSTR("callback [,thisObj]")
-	,JSDOCSTR("Adds <tt>callback</tt> to the end of the run queue, where it will be called after all pending events are processed")
+	,JSDOCSTR("Add <tt>callback</tt> to the end of the run queue, where it will be called after all pending events are processed")
 	,31900
 	},
 	{0}
diff --git a/src/sbbs3/js_mqtt.c b/src/sbbs3/js_mqtt.c
index 3b12cc12be517dc93677b2dc862549ff3ecf951c..3f648639ff979b33f4a7eacbf2b17d49cf435391 100644
--- a/src/sbbs3/js_mqtt.c
+++ b/src/sbbs3/js_mqtt.c
@@ -610,8 +610,8 @@ static jsSyncPropertySpec js_mqtt_properties[] = {
 
 static jsSyncMethodSpec js_mqtt_functions[] = {
 	{"connect",		js_connect,   	0,	JSTYPE_BOOLEAN
-		,JSDOCSTR("[string broker_address] [,number broker_port] [,string username] [,string password]")
-		,JSDOCSTR("Connect to an MQTT broker")
+		,JSDOCSTR("[<i>string</i> broker_address] [,<i>number</i> broker_port] [,<i>string</i> username] [,<i>string</i> password]")
+		,JSDOCSTR("Connect to an MQTT broker, by default (i.e. no arguments provided), the broker configured in SCFG->Networks->MQTT")
 		,320
 	},
 	{"disconnect",	js_disconnect,	0,	JSTYPE_VOID
@@ -620,20 +620,20 @@ static jsSyncMethodSpec js_mqtt_functions[] = {
 		,320
 	},
 	{"publish",		js_publish,		4,	JSTYPE_BOOLEAN
-		,JSDOCSTR("[bool retain=false,] [number qos,] topic, data")
+		,JSDOCSTR("[<i>bool</i> retain=false,] [<i></i>number qos,] topic, data")
 		,JSDOCSTR("Publish a string to specified topic")
 		,320
 	},
 	{"subscribe",	js_subscribe,	2,	JSTYPE_BOOLEAN
-		,JSDOCSTR("[number qos,] topic")
+		,JSDOCSTR("[<i>number</i> qos,] topic")
 		,JSDOCSTR("Subscribe to specified topic at (optional) QOS level")
 		,320
 	},
 	{"read",		js_read,		0, 	JSTYPE_STRING
-		,JSDOCSTR("[timeout=0] [,bool verbpose=false]")
+		,JSDOCSTR("[<i>number</i> timeout=0] [,<i>bool</i> verbose=false]")
 		,JSDOCSTR("Read next message, optionally waiting for <i>timeout</i> milliseconds, "
 			"returns an object instead of a string when <i>verbose</i> is <tt>true</tt>. "
-			"Returns <i>false</i> when no message is available.")
+			"Returns <tt>false</tt> when no message is available.")
 		,320
 	},
 	{0}
@@ -740,7 +740,7 @@ static JSBool js_mqtt_constructor(JSContext* cx, uintN argc, jsval *arglist)
 #ifdef BUILD_JSDOCS
 	js_DescribeSyncObject(cx,obj,"Class used for MQTT communications",320);
 	js_DescribeSyncConstructor(cx,obj,"To create a new MQTT object: "
-		"var mqtt = new MQTT([client_id])</tt><br>"
+		"<tt>var mqtt = new MQTT([<i>client_id</i>])</tt><br>"
 		);
 	js_CreateArrayOfStrings(cx, obj, "_property_desc_list", com_prop_desc, JSPROP_READONLY);
 #endif
diff --git a/src/sbbs3/js_msg_area.c b/src/sbbs3/js_msg_area.c
index 15c7de7df2f3bc01382616c616037a14fe4a8700..a09818306a6f35e2c954f0360984783e0bc7d782 100644
--- a/src/sbbs3/js_msg_area.c
+++ b/src/sbbs3/js_msg_area.c
@@ -33,28 +33,28 @@ static char* msg_area_prop_desc[] = {
 };
 
 static char* msg_grp_prop_desc[] = {
-	 "Index into grp_list array (or -1 if not in array) <i>(introduced in v3.12)</i>"
+	 "Index into grp_list array (or -1 if not in array)"
 	,"Unique number for this message group"
 	,"Group name"
 	,"Group description"
 	,"Group access requirements"
-	,"User has sufficient access to list this group's sub-boards <i>(introduced in v3.18)</i>"
-	,"Internal code prefix (for sub-boards) <i>(introduced in v3.18c)</i>"
+	,"User has sufficient access to list this group's sub-boards"
+	,"Internal code prefix (for sub-boards)"
 	,NULL
 };
 
 static char* msg_sub_prop_desc[] = {
 
-	 "Index into sub_list array (or -1 if not in array) <i>(introduced in v3.12)</i>"
-	,"Group's index into grp_list array <i>(introduced in v3.12)</i>"
+	 "Index into sub_list array (or -1 if not in array)</i>"
+	,"Group's index into grp_list array</i>"
 	,"Unique number for this sub-board"
 	,"Group number"
-	,"Group name <i>(introduced in v3.12)</i>"
+	,"Group name</i>"
 	,"Sub-board internal code"
 	,"Sub-board name"
 	,"Sub-board description"
 	,"QWK conference name"
-	,"Area tag for FidoNet-style echoes, a.k.a. EchoTag <i>(introduced in v3.19)</i>"
+	,"Area tag for FidoNet-style echoes, a.k.a. EchoTag"
 	,"Newsgroup name (as configured or dynamically generated)"
 	,"Sub-board access requirements"
 	,"Sub-board reading requirements"
@@ -82,7 +82,7 @@ static char* msg_sub_prop_desc[] = {
 	,"User's current new message scan pointer (highest-read message number)"
 	,"User's message scan configuration (bit-flags) - see <tt>SCAN_CFG_*</tt> in <tt>sbbsdefs.js</tt> for details"
 	,"User's last-read message number"
-	,"Number of messages currently posted to this sub-board <i>(introduced in v3.18c)</i>"
+	,"Number of messages currently posted to this sub-board"
 	,NULL
 };
 #endif
diff --git a/src/sbbs3/js_msgbase.c b/src/sbbs3/js_msgbase.c
index 9e86a3e38d87823ad7a9a790d68126025622b671..2bd450683fe7c214f6cf5da2e801ca6ae89becfa 100644
--- a/src/sbbs3/js_msgbase.c
+++ b/src/sbbs3/js_msgbase.c
@@ -3109,58 +3109,59 @@ static jsSyncMethodSpec js_msgbase_functions[] = {
 	,JSDOCSTR("Close message base (if open)")
 	,310
 	},
-	{"get_msg_header",	js_get_msg_header,	4, JSTYPE_OBJECT,	JSDOCSTR("[by_offset=<tt>false</tt>,] number_or_offset_or_id [,expand_fields=<tt>true</tt>] [,include_votes=<tt>false</tt>]")
-	,JSDOCSTR("Returns a specific message header, <i>null</i> on failure. "
-	"<br><i>New in v3.12:</i> Pass <i>false</i> for the <i>expand_fields</i> argument (default: <i>true</i>) "
+	{"get_msg_header",	js_get_msg_header,	4, JSTYPE_OBJECT
+	,JSDOCSTR("[<i>bool</i> by_offset=false,] <i>number</i> number_or_offset or <i>string</i> id [,<i>bool</i> expand_fields=true] [,<i>bool</i> include_votes=false]")
+	,JSDOCSTR("Return a specific message header, <i>null</i> on failure. "
+	"<br>Pass <i>false</i> for the <i>expand_fields</i> argument (default: <i>true</i>) "
 	"if you will be re-writing the header later with <i>put_msg_header()</i>"
 	"<br>"
 	"Additional read-only header properties: <i>mime_version</i>, <i>content_type</i>, and <i>is_utf8</i>"
 	)
 	,312
 	},
-	{"get_all_msg_headers", js_get_all_msg_headers, 1, JSTYPE_OBJECT, JSDOCSTR("[include_votes=<tt>false</tt>] [,expand_fields=<tt>true</tt>]")
-	,JSDOCSTR("Returns an object (associative array) of all message headers \"indexed\" by message number.<br>"
+	{"get_all_msg_headers", js_get_all_msg_headers, 1, JSTYPE_OBJECT, JSDOCSTR("[<i>bool</i> include_votes=false] [,<i>bool</i> expand_fields=true]")
+	,JSDOCSTR("Return an object (associative array) of all message headers \"indexed\" by message number.<br>"
 	"Message headers returned by this function include additional properties: <tt>upvotes</tt>, <tt>downvotes</tt> and <tt>total_votes</tt>.<br>"
 	"Vote messages are excluded by default.")
 	,316
 	},
-	{"put_msg_header",	js_put_msg_header,	2, JSTYPE_BOOLEAN,	JSDOCSTR("[by_offset=<tt>false</tt>,] [number_or_offset_or_id,] object header")
+	{"put_msg_header",	js_put_msg_header,	2, JSTYPE_BOOLEAN,	JSDOCSTR("[<i>bool</i> by_offset=false,] [<i>number</i> number_or_offset or <i>string</i> id,] <i>object</i> header")
 	,JSDOCSTR("Modify an existing message header (must have been 'got' without expanded fields)")
 	,310
 	},
-	{"get_msg_body",	js_get_msg_body,	2, JSTYPE_STRING,	JSDOCSTR("[by_offset=<tt>false</tt>,] number_or_offset_or_id_or_header [,strip_ctrl_a=<tt>false</tt>] "
-		"[,dot_stuffing=<tt>false</tt>] [,include_tails=<tt>true</tt>] [,plain_text=<tt>false</tt>]")
-	,JSDOCSTR("Returns the entire body text of a specific message as a single String, <i>null</i> on failure. "
-	"The default behavior is to leave Ctrl-A codes intact, do not stuff dots (e.g. per RFC-821), and to include tails (if any) in the "
-		"returned body text. When <i>plain_text</i> is true, only the first plain-text portion of a multi-part MIME encoded message body is returned. "
-		"The first argument (following the optional <i>by_offset</i> boolean) must be either a number (message number or index-offset), string (message-ID), or object (message header). "
-		"The <i>by_offfset</i> (<tt>true</tt>) argument should only be passed when the argument following it is the numeric index-offset of the message to be "
-		"retrieved. By default (<i>by_offset</i>=<tt>false</tt>), a numeric argument would be interpreted as the message <i>number</i> to be retrieved."
-		"<br>"
+	{"get_msg_body",	js_get_msg_body,	2, JSTYPE_STRING,	JSDOCSTR("[<i>bool</i> by_offset=false,] <i>number</i> number_or_offset or <i>string</i> id or <i>object</i> header [,<i>bool</i> strip_ctrl_a=false] "
+		"[,<i>bool</i> dot_stuffing=false] [,<i>bool</i> include_tails=true] [,<i>bool</i> plain_text=false]")
+	,JSDOCSTR("Return the entire body text of a specific message as a single string or <i>null</i> on failure.<br>"
+		"The default behavior is to leave Ctrl-A codes intact, do not stuff dots (e.g. per RFC-821), and to include tails (if any) in the "
+		"returned body text.<br>"
+		"When <i>plain_text</i> is true, only the first plain-text portion of a multi-part MIME encoded message body is returned.<br>"
+		"The first argument (following the optional <i>by_offset</i> boolean) must be either a number (message number or index-offset), string (message-ID), or object (message header).<br>"
+		"The <i>by_offset</i> (<tt>true</tt>) argument should only be passed when the argument following it is the numeric index-offset of the message to be retrieved.<br>"
+		"By default (<i>by_offset</i>=<tt>false</tt>), a numeric argument would be interpreted as the message <i>number</i> to be retrieved.<br>"
 		"After reading a multi-part MIME-encoded message, new header properties may be available: <i>text_charset</i> and <i>text_subtype</i>."
 	)
 	,310
 	},
-	{"get_msg_tail",	js_get_msg_tail,	2, JSTYPE_STRING,	JSDOCSTR("[by_offset=<tt>false</tt>,] number_or_offset_or_id_or_header [,strip_ctrl_a]=<tt>false</tt>")
-	,JSDOCSTR("Returns the tail text of a specific message, <i>null</i> on failure")
+	{"get_msg_tail",	js_get_msg_tail,	2, JSTYPE_STRING,	JSDOCSTR("[<i>bool</i> by_offset=false,] <i>number</i> number_or_offset or <i>string</i> id or <i>object</i> header [,<i>bool</i> strip_ctrl_a=false]")
+	,JSDOCSTR("Return the tail text of a specific message, <i>null</i> on failure")
 	,310
 	},
-	{"get_msg_index",	js_get_msg_index,	3, JSTYPE_OBJECT,	JSDOCSTR("[by_offset=<tt>false</tt>,] number_or_offset, [include_votes=<tt>false</tt>]")
-	,JSDOCSTR("Returns a specific message index record, <i>null</i> on failure. "
-	"The index object will contain the following properties:<br>"
+	{"get_msg_index",	js_get_msg_index,	3, JSTYPE_OBJECT,	JSDOCSTR("[<i>bool</i> by_offset=false,] <i>number</i> number_or_offset, [<i>bool</i> include_votes=false]")
+	,JSDOCSTR("Return a specific message index record, <i>null</i> on failure."
+	"<p>The <i>index</i> object will contain the following properties:<br>"
 	"<table>"
 	"<tr><td align=top><tt>attr</tt><td>Attribute bit-flags"
 	"<tr><td align=top><tt>time</tt><td>Date/time imported (in time_t format)"
 	"<tr><td align=top><tt>number</tt><td>Message number"
 	"<tr><td align=top><tt>offset</tt><td>Record number in index file"
 	"</table>"
-	"Indexes of regular messages will contain the following additional properties:<br>"
+	"<p>Indexes of regular messages will contain the following additional properties:<br>"
 	"<table>"
 	"<tr><td align=top><tt>subject</tt><td>CRC-16 of lowercase message subject"
 	"<tr><td align=top><tt>to</tt><td>CRC-16 of lowercase recipient's name (or user number if e-mail)"
 	"<tr><td align=top><tt>from</tt><td>CRC-16 of lowercase sender's name (or user number if e-mail)"
 	"</table>"
-	"Indexes of vote messages will contain the following additional properties:<br>"
+	"<p>Indexes of vote messages will contain the following additional properties:<br>"
 	"<table>"
 	"<tr><td align=top><tt>vote</tt><td>vote value"
 	"<tr><td align=top><tt>remsg</tt><td>number of message this vote is in response to"
@@ -3174,12 +3175,12 @@ static jsSyncMethodSpec js_msgbase_functions[] = {
 		"This is the fastest method of obtaining a list of all message index records.")
 	,31702
 	},
-	{"remove_msg",		js_remove_msg,		2, JSTYPE_BOOLEAN,	JSDOCSTR("[by_offset=<tt>false</tt>,] number_or_offset_or_id")
+	{"remove_msg",		js_remove_msg,		2, JSTYPE_BOOLEAN,	JSDOCSTR("[<i>bool</i> by_offset=false,] <i>number</i> number_or_offset or <i>string</i> id")
 	,JSDOCSTR("Mark message for deletion")
 	,311
 	},
-	{"save_msg",		js_save_msg,		2, JSTYPE_BOOLEAN,	JSDOCSTR("object header [,client=<i>none</i>] [,body_text=<tt>\"\"</tt>] [,array rcpt_list=<i>none</i>]")
-	,JSDOCSTR("Create a new message in message base, the <i>header</i> object may contain the following properties:<br>"
+	{"save_msg",		js_save_msg,		2, JSTYPE_BOOLEAN,	JSDOCSTR("<i>object</i> header [,<i>object</i> client=<i>none</i>] [,body_text=\"\"] [,<i>array</i> rcpt_list=<i>none</i>]")
+	,JSDOCSTR("Create a new message in message base.<p>The <i>header</i> object may contain the following properties:<br>"
 	"<table>"
 	"<tr><td align=top><tt>subject</tt><td>Message subject <i>(required)</i>"
 	"<tr><td align=top><tt>to</tt><td>Recipient's name <i>(required)</i>"
@@ -3249,20 +3250,20 @@ static jsSyncMethodSpec js_msgbase_functions[] = {
 	"<tr><td align=top><tt>field_list[].data</tt><td>Other SMB header fields (data)"
 	"<tr><td align=top><tt>can_read</tt><td>true if the current user can read this validated or unmoderated message"
 	"</table>"
-	"<br><i>New in v3.12:</i> "
+	"<br>"
 	"The optional <i>client</i> argument is an instance of the <i>Client</i> class to be used for the "
-	"security log header fields (e.g. sender IP address, hostname, protocol, and port).  As of version 3.16c, the "
-	"global client object will be used if this is omitted."
-	"<br><br><i>New in v3.12:</i> "
+	"security log header fields (e.g. sender IP address, hostname, protocol, and port). The "
+	"global client object will be used if this parameter is omitted."
+	"<br><br>"
 	"The optional <i>rcpt_list</i> is an array of objects that specifies multiple recipients "
-	"for a single message (e.g. bulk e-mail). Each object in the array may include the following header properties "
+	"for a single message (e.g. bulk e-mail). Each recipient object in the array may include the following header properties "
 	"(described above): <br>"
 	"<i>to</i>, <i>to_ext</i>, <i>to_org</i>, <i>to_net_type</i>, <i>to_net_addr</i>, and <i>to_agent</i>"
 	)
 	,312
 	},
-	{"vote_msg",		js_vote_msg,		1, JSTYPE_BOOLEAN,	JSDOCSTR("object header")
-	,JSDOCSTR("Create a new vote in message base, the <i>header</i> object should contain the following properties:<br>"
+	{"vote_msg",		js_vote_msg,		1, JSTYPE_BOOLEAN,	JSDOCSTR("<i>object</i> header")
+	,JSDOCSTR("Create a new vote in message base.<p>The <i>header</i> object should contain the following properties:<br>"
 	"<table>"
 	"<tr><td align=top><tt>from</tt><td>Sender's name <i>(required)</i>"
 	"<tr><td align=top><tt>from_ext</tt><td>Sender's user number (if applicable)"
@@ -3275,8 +3276,8 @@ static jsSyncMethodSpec js_msgbase_functions[] = {
 	)
 	,317
 	},
-	{"add_poll",		js_add_poll,		1, JSTYPE_BOOLEAN,	JSDOCSTR("object header")
-	,JSDOCSTR("Create a new poll in message base, the <i>header</i> object should contain the following properties:<br>"
+	{"add_poll",		js_add_poll,		1, JSTYPE_BOOLEAN,	JSDOCSTR("<i>object</i> header")
+	,JSDOCSTR("Create a new poll in message base.<p>The <i>header</i> object should contain the following properties:<br>"
 	"<table>"
 	"<tr><td align=top><tt>subject</tt><td>Polling question <i>(required)</i>"
 	"<tr><td align=top><tt>from</tt><td>Sender's name <i>(required)</i>"
@@ -3292,10 +3293,10 @@ static jsSyncMethodSpec js_msgbase_functions[] = {
 	,317
 	},
 	{"how_user_voted",		js_how_user_voted,		2, JSTYPE_NUMBER,	JSDOCSTR("message number, user name or alias")
-	,JSDOCSTR("Returns 0 for no votes, 1 for an up-vote, 2 for a down-vote, or in the case of a poll-response: a bit-field of votes.")
+	,JSDOCSTR("Return 0 for no votes, 1 for an up-vote, 2 for a down-vote, or in the case of a poll-response: a bit-field of votes.")
 	,317
 	},
-	{"dump_msg_header",		js_dump_msg_header,		1,	JSTYPE_ARRAY,	JSDOCSTR("object header")
+	{"dump_msg_header",		js_dump_msg_header,		1,	JSTYPE_ARRAY,	JSDOCSTR("<i>object</i> header")
 		,JSDOCSTR("Dump a message header object to an array of strings for diagnostic uses")
 		,31702
 	},
diff --git a/src/sbbs3/js_queue.c b/src/sbbs3/js_queue.c
index ce2ae64a028ab69576f9f8a2ddd9c311464ff698..3c231581794e6cc0ca8b165f1516310138dc6247 100644
--- a/src/sbbs3/js_queue.c
+++ b/src/sbbs3/js_queue.c
@@ -264,11 +264,11 @@ enum {
 #ifdef BUILD_JSDOCS
 static char* queue_prop_desc[] = {
 	 "Name of the queue (if it has one)"
-	,"<i>true</i> if data is waiting to be read from queue"
+	,"<tt>true</tt> if data is waiting to be read from queue"
 	,"Number of values in the read queue"
 	,"Number of values in the write queue"
-	,"<i>true</i> if current thread is the owner/creator of the queue"
-	,"<i>true</i> if the owner of the queue has detached from the queue"
+	,"<tt>true</tt> if current thread is the owner/creator of the queue"
+	,"<tt>true</tt> if the owner of the queue has detached from the queue"
 	,NULL
 };
 #endif
@@ -335,18 +335,18 @@ static jsSyncPropertySpec js_queue_properties[] = {
 };
 
 static jsSyncMethodSpec js_queue_functions[] = {
-	{"poll",		js_poll,		1,	JSTYPE_UNDEF,	"[timeout=<tt>0</tt>]"
+	{"poll",		js_poll,		1,	JSTYPE_UNDEF,	"[<i>number</i> timeout=0]"
 	,JSDOCSTR("Wait for any value to be written to the queue for up to <i>timeout</i> milliseconds "
-		"(default: <i>0</i>), returns <i>true</i> or the <i>name</i> (string) of "
-		"the value waiting (if it has one), or <i>false</i> if no values are waiting")
+		"(default: <i>0</i>), returns <tt>true</tt> or the <i>name</i> (string) of "
+		"the value waiting (if it has one), or <tt>false</tt> if no values are waiting")
 	,312
 	},
-	{"read",		js_read,		1,	JSTYPE_UNDEF,	"[string name] or [timeout=<tt>0</tt>]"
+	{"read",		js_read,		1,	JSTYPE_UNDEF,	"[<i>string</i> name] or [<i>number</i>timeout=0]"
 	,JSDOCSTR("Read a value from the queue, if <i>name</i> not specified, reads next value "
 		"from the bottom of the queue (waiting up to <i>timeout</i> milliseconds)")
 	,313
 	},
-	{"peek",		js_peek,		1,	JSTYPE_UNDEF,	"[timeout=<tt>0</tt>]"
+	{"peek",		js_peek,		1,	JSTYPE_UNDEF,	"[<i>number</i> timeout=0]"
 	,JSDOCSTR("Peek at the value at the bottom of the queue, "
 		"wait up to <i>timeout</i> milliseconds for any value to be written "
 		"(default: <i>0</i>)")
diff --git a/src/sbbs3/js_socket.c b/src/sbbs3/js_socket.c
index 93e869e4c47d009025d3e584dd67ad7ce080755f..54ed73ad85aba42e49529aac563c625380c80929 100644
--- a/src/sbbs3/js_socket.c
+++ b/src/sbbs3/js_socket.c
@@ -2241,23 +2241,23 @@ static char* socket_prop_desc[] = {
 	/* Regular properties */
 	 "Error status for the last socket operation that failed - <small>READ ONLY</small>"
 	,"Error description for the last socket operation that failed - <small>READ ONLY</small>"
-	,"<i>true</i> if socket is in a connected state - <small>READ ONLY</small>"
-	,"<i>true</i> if socket can accept written data - Setting to false will shutdown the write end of the socket."
+	,"<tt>true</tt> if socket is in a connected state - <small>READ ONLY</small>"
+	,"<tt>true</tt> if socket can accept written data - Setting to false will shutdown the write end of the socket."
 	,"Alias for is_writeable"
-	,"<i>true</i> if data is waiting to be read from socket - <small>READ ONLY</small>"
+	,"<tt>true</tt> if data is waiting to be read from socket - <small>READ ONLY</small>"
 	,"Number of bytes waiting to be read - TLS sockets will never return more than 1 - <small>READ ONLY</small>"
 	,"Enable debug logging"
 	,"Socket descriptor (advanced uses only)"
-	,"Use non-blocking operation (default is <i>false</i>)"
+	,"Use non-blocking operation (default is <tt>false</tt>)"
 	,"Local IP address (string in dotted-decimal format)"
 	,"Local TCP or UDP port number"
 	,"Remote IP address (string in dotted-decimal format)"
 	,"Remote TCP or UDP port number"
 	,"Socket type, <tt>SOCK_STREAM</tt> (TCP) or <tt>SOCK_DGRAM</tt> (UDP)"
 	,"Socket protocol family, <tt>PF_INET</tt> (IPv4) or <tt>PF_INET6</tt> (IPv6)"
-	,"<i>true</i> if binary data is to be sent in Network Byte Order (big end first), default is <i>true</i>"
-	,"Set to <i>true</i> to enable SSL as a client on the socket"
-	,"Set to <i>true</i> to enable SSL as a server on the socket"
+	,"<tt>true</tt> if binary data is to be sent in Network Byte Order (big end first), default is <tt>true</tt>"
+	,"Set to <tt>true</tt> to enable SSL as a client on the socket"
+	,"Set to <tt>true</tt> to enable SSL as a server on the socket"
 
 	/* statically-defined properties: */
 	,"Array of socket option names supported by the current platform"
@@ -2605,7 +2605,7 @@ static jsSyncMethodSpec js_socket_functions[] = {
 		"optionally specifying a network interface (via <i>ip_address</i>)")
 	,311
 	},
-	{"connect",     js_connect,     2,	JSTYPE_BOOLEAN,	JSDOCSTR("host, port [,timeout=<tt>10.0</tt>]")
+	{"connect",     js_connect,     2,	JSTYPE_BOOLEAN,	JSDOCSTR("host, port [,timeout=10.0]")
 	,JSDOCSTR("Connect to a remote port (number or service name) on the specified host (IP address or host name)"
 	", default <i>timeout</i> value is <i>10.0</i> (seconds)")
 	,311
@@ -2638,33 +2638,33 @@ static jsSyncMethodSpec js_socket_functions[] = {
 	,310
 	},
 	{"writeBin",	js_sendbin,		1,	JSTYPE_ALIAS },
-	{"sendBin",		js_sendbin,		1,	JSTYPE_BOOLEAN,	JSDOCSTR("value [,bytes=<tt>4</tt>]")
+	{"sendBin",		js_sendbin,		1,	JSTYPE_BOOLEAN,	JSDOCSTR("value [,bytes=4]")
 	,JSDOCSTR("Send a binary integer over the socket, default number of bytes is 4 (32-bits)")
 	,311
 	},
 	{"read",		js_recv,		1,	JSTYPE_ALIAS },
-	{"recv",		js_recv,		1,	JSTYPE_STRING,	JSDOCSTR("[maxlen=<tt>512</tt>, [timeout_sec=<tt>120</tt>]]")
+	{"recv",		js_recv,		1,	JSTYPE_STRING,	JSDOCSTR("[maxlen=512, [timeout_sec=120]]")
 	,JSDOCSTR("Receive a string, default maxlen is 512 characters (AKA read)")
 	,310
 	},
-	{"peek",		js_peek,		0,	JSTYPE_STRING,	JSDOCSTR("[maxlen=<tt>512</tt>]")
+	{"peek",		js_peek,		0,	JSTYPE_STRING,	JSDOCSTR("[maxlen=512]")
 	,JSDOCSTR("Receive a string, default maxlen is 512 characters, leaves string in receive buffer (TLS sockets will never return more than one byte)")
 	,310
 	},
 	{"readline",	js_recvline,	0,	JSTYPE_ALIAS },
 	{"readln",		js_recvline,	0,	JSTYPE_ALIAS },
-	{"recvline",	js_recvline,	0,	JSTYPE_STRING,	JSDOCSTR("[maxlen=<tt>512</tt>] [,timeout=<tt>30.0</tt>]")
+	{"recvline",	js_recvline,	0,	JSTYPE_STRING,	JSDOCSTR("[maxlen=512] [,timeout=30]")
 	,JSDOCSTR("Receive a line-feed terminated string, default maxlen is 512 characters, default timeout is 30 seconds (AKA readline and readln)")
 	,310
 	},
-	{"recvfrom",	js_recvfrom,	0,	JSTYPE_OBJECT,	JSDOCSTR("[binary=<tt>false</tt>] [,maxlen=<tt>512</tt> or int_size=<tt>4</tt>]")
+	{"recvfrom",	js_recvfrom,	0,	JSTYPE_OBJECT,	JSDOCSTR("[binary=false] [,maxlen=512 or int_size=4]")
 	,JSDOCSTR("Receive data (string or integer) from a socket (typically UDP)"
 	"<p>returns object with <i>ip_address</i> and <i>port</i> of sender along with <i>data</i> properties"
-	"<p><i>binary</i> defaults to <i>false</i>, <i>maxlen</i> defaults to 512 chars, <i>int_size</i> defaults to 4 bytes (32-bits)")
+	"<p><i>binary</i> defaults to <tt>false</tt>, <i>maxlen</i> defaults to 512 chars, <i>int_size</i> defaults to 4 bytes (32-bits)")
 	,311
 	},
 	{"readBin",		js_recvbin,		0,	JSTYPE_ALIAS },
-	{"recvBin",		js_recvbin,		0,	JSTYPE_NUMBER,	JSDOCSTR("[bytes=<tt>4</tt>]")
+	{"recvBin",		js_recvbin,		0,	JSTYPE_NUMBER,	JSDOCSTR("[bytes=4]")
 	,JSDOCSTR("Receive a binary integer from the socket, default number of bytes is 4 (32-bits)")
 	,311
 	},
@@ -2678,21 +2678,21 @@ static jsSyncMethodSpec js_socket_functions[] = {
 	"(see <tt>sockopts</tt> in <tt>sockdefs.js</tt>) or number")
 	,310
 	},
-	{"ioctl",		js_ioctlsocket,	1,	JSTYPE_NUMBER,	JSDOCSTR("command [,argument=<tt>0</tt>]")
+	{"ioctl",		js_ioctlsocket,	1,	JSTYPE_NUMBER,	JSDOCSTR("command [,argument=0]")
 	,JSDOCSTR("Send socket IOCTL (advanced)")
 	,310
 	},
-	{"poll",		js_poll,		1,	JSTYPE_NUMBER,	JSDOCSTR("[timeout=<tt>0</tt>] [,write=<tt>false</tt>]")
+	{"poll",		js_poll,		1,	JSTYPE_NUMBER,	JSDOCSTR("[timeout=0] [,write=false]")
 	,JSDOCSTR("Poll socket for read or write ability (default is <i>read</i>), "
 	"default timeout value is 0.0 seconds (immediate timeout)")
 	,310
 	},
 	{"on",		js_on,		2,	JSTYPE_NUMBER,	JSDOCSTR("('read' | 'write'), callback")
-	,JSDOCSTR("Execute callback whenever socket is readable/writable.  Returns an id to be passed to js.clearOn()")
+	,JSDOCSTR("Execute callback whenever socket is readable/writable.  Returns an id to be passed to <tt>js.clearOn()</tt>")
 	,31900
 	},
 	{"once",	js_once,	2,	JSTYPE_NUMBER,	JSDOCSTR("('read' | 'write'), callback")
-	,JSDOCSTR("Execute callback next time socket is readable/writable  Returns and id to be passed to js.clearOnce()")
+	,JSDOCSTR("Execute callback next time socket is readable/writable  Returns and id to be passed to <tt>js.clearOnce()</tt>")
 	,31900
 	},
 	{"clearOn",	js_clearOn,	2,	JSTYPE_NUMBER,	JSDOCSTR("('read' | 'write'), id")
diff --git a/src/sbbs3/js_system.c b/src/sbbs3/js_system.c
index 052afc291b673ad70be0fe0a842883f8988e5b3e..492d1c91b7ed3305ecb899dfe376e38090bd39eb 100644
--- a/src/sbbs3/js_system.c
+++ b/src/sbbs3/js_system.c
@@ -407,171 +407,219 @@ static jsSyncPropertySpec js_system_properties[] = {
 /*		 name,						tinyid,				flags,				ver	*/
 
 #ifndef JSDOOR
-	{	"name",						SYS_PROP_NAME,		SYSOBJ_FLAGS,		310  },
-	{	"operator",					SYS_PROP_OP,		SYSOBJ_FLAGS,		310  },
-	{	"operator_available",		SYS_PROP_OP_AVAIL,	JSPROP_ENUMERATE,	31801  },
-	{	"guru",						SYS_PROP_GURU,		SYSOBJ_FLAGS,		32000 },
-	{	"qwk_id",					SYS_PROP_ID,		SYSOBJ_FLAGS,		310  },
-	{	"settings",					SYS_PROP_MISC,		JSPROP_ENUMERATE,	310  },
-	{	"login_settings",			SYS_PROP_LOGIN,		JSPROP_ENUMERATE,	32000  },
+	{	"name",						SYS_PROP_NAME,		SYSOBJ_FLAGS,		310
+		,JSDOCSTR("BBS name")
+	},
+	{	"operator",					SYS_PROP_OP,		SYSOBJ_FLAGS,		310
+		,JSDOCSTR("Operator name")
+	},
+	{	"operator_available",		SYS_PROP_OP_AVAIL,	JSPROP_ENUMERATE,	31801
+		,JSDOCSTR("Operator is available for chat")
+	},
+	{	"guru",						SYS_PROP_GURU,		SYSOBJ_FLAGS,		32000
+		,JSDOCSTR("Default Guru (AI) name")
+	},
+	{	"qwk_id",					SYS_PROP_ID,		SYSOBJ_FLAGS,		310
+		,JSDOCSTR("System QWK-ID (for QWK packets)")
+	},
+	{	"settings",					SYS_PROP_MISC,		JSPROP_ENUMERATE,	310
+		,JSDOCSTR("Settings bit-flags (see <tt>SYS_*</tt> in <tt>sbbsdefs.js</tt> for bit definitions)")
+	},
+	{	"login_settings",			SYS_PROP_LOGIN,		JSPROP_ENUMERATE,	32000
+		,JSDOCSTR("Login control settings bit-flags (see <tt>LOGIN_*</tt> in <tt>sbbsdefs.js</tt> for bit definitions)")
+	},
 	{	"inetaddr",					SYS_PROP_INETADDR,	JSPROP_READONLY,	310  },	/* alias */
-	{	"inet_addr",				SYS_PROP_INETADDR,	SYSOBJ_FLAGS,		311  },
-	{	"location",					SYS_PROP_LOCATION,	SYSOBJ_FLAGS,		310  },
-	{	"timezone",					SYS_PROP_TIMEZONE,	SYSOBJ_FLAGS,		310  },
-	{	"pwdays",					SYS_PROP_PWDAYS,	SYSOBJ_FLAGS,		310  },
-	{	"min_password_length",		SYS_PROP_MINPWLEN,	SYSOBJ_FLAGS,		31702  },
-	{	"max_password_length",		SYS_PROP_MAXPWLEN,	SYSOBJ_FLAGS,		31702  },
-	{	"deldays",					SYS_PROP_DELDAYS,	SYSOBJ_FLAGS,		310  },
-	{	"autodel",					SYS_PROP_AUTODEL,	SYSOBJ_FLAGS,		31702  },
-
-	{	"last_user",				SYS_PROP_LASTUSER		,SYSOBJ_FLAGS,	311  },
+	{	"inet_addr",				SYS_PROP_INETADDR,	SYSOBJ_FLAGS,		311
+		,JSDOCSTR("Internet address (host or domain name)")
+	},
+	{	"location",					SYS_PROP_LOCATION,	SYSOBJ_FLAGS,		310
+		,JSDOCSTR("Location (city, state)")
+	},
+	{	"timezone",					SYS_PROP_TIMEZONE,	SYSOBJ_FLAGS,		310
+		,JSDOCSTR("Timezone (use <i>system.zonestr()</i> to get string representation)")
+	},
+	{	"pwdays",					SYS_PROP_PWDAYS,	SYSOBJ_FLAGS,		310
+		,JSDOCSTR("Days between forced user password changes (<tt>0</tt>=<i>never</i>)")
+	},
+	{	"min_password_length",		SYS_PROP_MINPWLEN,	SYSOBJ_FLAGS,		31702
+		,JSDOCSTR("Minimum number of characters in user passwords")
+	},
+	{	"max_password_length",		SYS_PROP_MAXPWLEN,	SYSOBJ_FLAGS,		31702
+		,JSDOCSTR("Maximum number of characters in user passwords")
+	},
+	{	"deldays",					SYS_PROP_DELDAYS,	SYSOBJ_FLAGS,		310
+		,JSDOCSTR("Days to preserve deleted user records, record will not be reused/overwritten during this period")
+	},
+	{	"autodel",					SYS_PROP_AUTODEL,	SYSOBJ_FLAGS,		31702
+		,JSDOCSTR("Days of user inactivity before auto-deletion (<tt>0</tt>=<i>disabled</i>), N/A to P-exempt users")
+	},
+
+	{	"last_user",				SYS_PROP_LASTUSER		,SYSOBJ_FLAGS,	311
+		,JSDOCSTR("Last user record number in user database (includes deleted and inactive user records)")
+	},
 	{	"lastuser",					SYS_PROP_LASTUSER	,JSPROP_READONLY,	311  }, /* alias */
-	{	"last_useron",				SYS_PROP_LASTUSERON		,SYSOBJ_FLAGS,	310  },
+	{	"last_useron",				SYS_PROP_LASTUSERON		,SYSOBJ_FLAGS,	310
+		,JSDOCSTR("Name of last user to logoff")
+	},
 	{	"lastuseron",				SYS_PROP_LASTUSERON	,JSPROP_READONLY,	310  }, /* alias */
 #endif
-	{	"freediskspace",			SYS_PROP_FREEDISKSPACE	,SYSOBJ_FLAGS,	310  },
-	{	"freediskspacek",			SYS_PROP_FREEDISKSPACEK	,SYSOBJ_FLAGS,	310  },
+	{	"freediskspace",			SYS_PROP_FREEDISKSPACE	,SYSOBJ_FLAGS,	310
+		,JSDOCSTR("Amount of free disk space (in bytes)")
+	},
+	{	"freediskspacek",			SYS_PROP_FREEDISKSPACEK	,SYSOBJ_FLAGS,	310
+		,JSDOCSTR("Amount of free disk space (in kibibytes)")
+	},
 
 #ifndef JSDOOR
-	{	"nodes",					SYS_PROP_NODES,		SYSOBJ_FLAGS,		310  },
-	{	"last_node",				SYS_PROP_LASTNODE,	SYSOBJ_FLAGS,		310  },
+	{	"nodes",					SYS_PROP_NODES,		SYSOBJ_FLAGS,		310
+		,JSDOCSTR("Total number of Terminal Server nodes")
+	},
+	{	"last_node",				SYS_PROP_LASTNODE,	SYSOBJ_FLAGS,		310
+		,JSDOCSTR("Last displayable node number")
+	},
 	{	"lastnode",					SYS_PROP_LASTNODE,	JSPROP_READONLY,	310  }, /* alias */
 
-	{	"mqtt_enabled",				SYS_PROP_MQTT_ENABLED,	SYSOBJ_FLAGS,	320	},
-
-	{	"newuser_password",			SYS_PROP_NEW_PASS		,SYSOBJ_FLAGS,	310  },
-	{	"newuser_magic_word",		SYS_PROP_NEW_MAGIC		,SYSOBJ_FLAGS,	310  },
-	{	"newuser_level",			SYS_PROP_NEW_LEVEL		,SYSOBJ_FLAGS,	310  },
-	{	"newuser_flags1",			SYS_PROP_NEW_FLAGS1		,SYSOBJ_FLAGS,	310  },
-	{	"newuser_flags2",			SYS_PROP_NEW_FLAGS2		,SYSOBJ_FLAGS,	310  },
-	{	"newuser_flags3",			SYS_PROP_NEW_FLAGS3		,SYSOBJ_FLAGS,	310  },
-	{	"newuser_flags4",			SYS_PROP_NEW_FLAGS4		,SYSOBJ_FLAGS,	310  },
-	{	"newuser_restrictions",		SYS_PROP_NEW_REST		,SYSOBJ_FLAGS,	310  },
-	{	"newuser_exemptions",		SYS_PROP_NEW_EXEMPT		,SYSOBJ_FLAGS,	310  },
-	{	"newuser_credits",			SYS_PROP_NEW_CDT		,SYSOBJ_FLAGS,	310  },
-	{	"newuser_minutes",			SYS_PROP_NEW_MIN		,SYSOBJ_FLAGS,	310  },
-	{	"newuser_command_shell",	SYS_PROP_NEW_SHELL		,SYSOBJ_FLAGS,	310  },
-	{	"newuser_editor",			SYS_PROP_NEW_XEDIT		,SYSOBJ_FLAGS,	310  },
-	{	"newuser_settings",			SYS_PROP_NEW_MISC		,SYSOBJ_FLAGS,	310  },
-	{	"newuser_download_protocol",SYS_PROP_NEW_PROT		,SYSOBJ_FLAGS,	310  },
-	{	"newuser_expiration_days",	SYS_PROP_NEW_EXPIRE		,SYSOBJ_FLAGS,	310  },
-	{	"newuser_questions",		SYS_PROP_NEW_UQ			,SYSOBJ_FLAGS,	310  },
-
-	{	"expired_level",			SYS_PROP_EXPIRED_LEVEL	,SYSOBJ_FLAGS,	310  },
-	{	"expired_flags1",			SYS_PROP_EXPIRED_FLAGS1	,SYSOBJ_FLAGS,	310  },
-	{	"expired_flags2",			SYS_PROP_EXPIRED_FLAGS2	,SYSOBJ_FLAGS,	310  },
-	{	"expired_flags3",			SYS_PROP_EXPIRED_FLAGS3	,SYSOBJ_FLAGS,	310  },
-	{	"expired_flags4",			SYS_PROP_EXPIRED_FLAGS4	,SYSOBJ_FLAGS,	310  },
-	{	"expired_restrictions",		SYS_PROP_EXPIRED_REST	,SYSOBJ_FLAGS,	310  },
-	{	"expired_exemptions",		SYS_PROP_EXPIRED_EXEMPT	,SYSOBJ_FLAGS,	310  },
+	{	"mqtt_enabled",				SYS_PROP_MQTT_ENABLED,	SYSOBJ_FLAGS,	320
+		,JSDOCSTR("MQTT support (connection to MQTT broker) is enabled")
+	},
+
+	{	"newuser_password",			SYS_PROP_NEW_PASS		,SYSOBJ_FLAGS,	310
+		,JSDOCSTR("New user password (NUP, optional)")
+	},
+	{	"newuser_magic_word",		SYS_PROP_NEW_MAGIC		,SYSOBJ_FLAGS,	310
+		,JSDOCSTR("New user magic word (optional)")
+	},
+	{	"newuser_level",			SYS_PROP_NEW_LEVEL		,SYSOBJ_FLAGS,	310
+		,JSDOCSTR("New user security level")
+	},
+	{	"newuser_flags1",			SYS_PROP_NEW_FLAGS1		,SYSOBJ_FLAGS,	310
+		,JSDOCSTR("New user flag set #1")
+	},
+	{	"newuser_flags2",			SYS_PROP_NEW_FLAGS2		,SYSOBJ_FLAGS,	310
+		,JSDOCSTR("New user flag set #2")
+	},
+	{	"newuser_flags3",			SYS_PROP_NEW_FLAGS3		,SYSOBJ_FLAGS,	310
+		,JSDOCSTR("New user flag set #3")
+	},
+	{	"newuser_flags4",			SYS_PROP_NEW_FLAGS4		,SYSOBJ_FLAGS,	310
+		,JSDOCSTR("New user flag set #4")
+	},
+	{	"newuser_restrictions",		SYS_PROP_NEW_REST		,SYSOBJ_FLAGS,	310
+		,JSDOCSTR("New user restriction flags")
+	},
+	{	"newuser_exemptions",		SYS_PROP_NEW_EXEMPT		,SYSOBJ_FLAGS,	310
+		,JSDOCSTR("New user exemption flags")
+	},
+	{	"newuser_credits",			SYS_PROP_NEW_CDT		,SYSOBJ_FLAGS,	310
+		,JSDOCSTR("New user credits")
+	},
+	{	"newuser_minutes",			SYS_PROP_NEW_MIN		,SYSOBJ_FLAGS,	310
+		,JSDOCSTR("New user extra minutes")
+	},
+	{	"newuser_command_shell",	SYS_PROP_NEW_SHELL		,SYSOBJ_FLAGS,	310
+		,JSDOCSTR("New user default command shell")
+	},
+	{	"newuser_editor",			SYS_PROP_NEW_XEDIT		,SYSOBJ_FLAGS,	310
+		,JSDOCSTR("New user default external editor")
+	},
+	{	"newuser_settings",			SYS_PROP_NEW_MISC		,SYSOBJ_FLAGS,	310
+		,JSDOCSTR("New user default settings")
+	},
+	{	"newuser_download_protocol",SYS_PROP_NEW_PROT		,SYSOBJ_FLAGS,	310
+		,JSDOCSTR("New user default file transfer protocol (command key)")
+	},
+	{	"newuser_expiration_days",	SYS_PROP_NEW_EXPIRE		,SYSOBJ_FLAGS,	310
+		,JSDOCSTR("New user expiration days")
+	},
+	{	"newuser_questions",		SYS_PROP_NEW_UQ			,SYSOBJ_FLAGS,	310
+		,JSDOCSTR("New user questions/prompts (see <tt>UQ_*</tt> in <tt>sbbsdefs.js</tt> for bit definitions)")
+	},
+
+	{	"expired_level",			SYS_PROP_EXPIRED_LEVEL	,SYSOBJ_FLAGS,	310
+		,JSDOCSTR("Expired user security level")
+	},
+	{	"expired_flags1",			SYS_PROP_EXPIRED_FLAGS1	,SYSOBJ_FLAGS,	310
+		,JSDOCSTR("Expired user flag set #1")
+	},
+	{	"expired_flags2",			SYS_PROP_EXPIRED_FLAGS2	,SYSOBJ_FLAGS,	310
+		,JSDOCSTR("Expired user flag set #2")
+	},
+	{	"expired_flags3",			SYS_PROP_EXPIRED_FLAGS3	,SYSOBJ_FLAGS,	310
+		,JSDOCSTR("Expired user flag set #3")
+	},
+	{	"expired_flags4",			SYS_PROP_EXPIRED_FLAGS4	,SYSOBJ_FLAGS,	310
+		,JSDOCSTR("Expired user flag set #4")
+	},
+	{	"expired_restrictions",		SYS_PROP_EXPIRED_REST	,SYSOBJ_FLAGS,	310
+		,JSDOCSTR("Expired user restriction flags")
+	},
+	{	"expired_exemptions",		SYS_PROP_EXPIRED_EXEMPT	,SYSOBJ_FLAGS,	310
+		,JSDOCSTR("Expired user exemption flags")
+	},
 
 	/* directories */
-	{	"node_dir",					SYS_PROP_NODE_DIR		,SYSOBJ_FLAGS,	310  },
+	{	"node_dir",					SYS_PROP_NODE_DIR		,SYSOBJ_FLAGS,	310
+		,JSDOCSTR("Current node directory")
+	},
 #endif
-	{	"ctrl_dir",					SYS_PROP_CTRL_DIR		,SYSOBJ_FLAGS,	310  },
-	{	"data_dir",					SYS_PROP_DATA_DIR		,SYSOBJ_FLAGS,	310  },
-	{	"text_dir",					SYS_PROP_TEXT_DIR		,SYSOBJ_FLAGS,	310  },
-	{	"temp_dir",					SYS_PROP_TEMP_DIR		,SYSOBJ_FLAGS,	310  },
-	{	"exec_dir",					SYS_PROP_EXEC_DIR		,SYSOBJ_FLAGS,	310  },
-	{	"mods_dir",					SYS_PROP_MODS_DIR		,SYSOBJ_FLAGS,	310  },
-	{	"logs_dir",					SYS_PROP_LOGS_DIR		,SYSOBJ_FLAGS,	310  },
+	{	"ctrl_dir",					SYS_PROP_CTRL_DIR		,SYSOBJ_FLAGS,	310
+		,JSDOCSTR("Control file directory")
+	},
+	{	"data_dir",					SYS_PROP_DATA_DIR		,SYSOBJ_FLAGS,	310
+		,JSDOCSTR("Data file directory")
+	},
+	{	"text_dir",					SYS_PROP_TEXT_DIR		,SYSOBJ_FLAGS,	310
+		,JSDOCSTR("Text file directory")
+	},
+	{	"temp_dir",					SYS_PROP_TEMP_DIR		,SYSOBJ_FLAGS,	310
+		,JSDOCSTR("Temporary file directory")
+	},
+	{	"exec_dir",					SYS_PROP_EXEC_DIR		,SYSOBJ_FLAGS,	310
+		,JSDOCSTR("Executable file directory")
+	},
+	{	"mods_dir",					SYS_PROP_MODS_DIR		,SYSOBJ_FLAGS,	310
+		,JSDOCSTR("Modified modules directory (optional)")
+	},
+	{	"logs_dir",					SYS_PROP_LOGS_DIR		,SYSOBJ_FLAGS,	310
+		,JSDOCSTR("Log file directory")
+	},
 
 	/* filenames */
-	{	"devnull",					SYS_PROP_DEVNULL		,SYSOBJ_FLAGS,	311  },
-	{	"temp_path",				SYS_PROP_TEMP_PATH		,SYSOBJ_FLAGS,	312	 },
-	{	"cmd_shell",				SYS_PROP_CMD_SHELL		,SYSOBJ_FLAGS,	314	 },
+	{	"devnull",					SYS_PROP_DEVNULL		,SYSOBJ_FLAGS,	311
+		,JSDOCSTR("Platform-specific \"null\" device filename")
+	},
+	{	"temp_path",				SYS_PROP_TEMP_PATH		,SYSOBJ_FLAGS,	312
+		,JSDOCSTR("Platform-specific temporary file directory")
+	},
+	{	"cmd_shell",				SYS_PROP_CMD_SHELL		,SYSOBJ_FLAGS,	314
+		,JSDOCSTR("Platform-specific command processor/shell")
+	},
 
 	/* clock access */
-	{	"clock_ticks",				SYS_PROP_CLOCK			,SYSOBJ_FLAGS,	311  },
-	{	"clock_ticks_per_second",	SYS_PROP_CLOCK_PER_SEC	,SYSOBJ_FLAGS,	311  },
-	{	"timer",					SYS_PROP_TIMER			,SYSOBJ_FLAGS,	314	 },
+	{	"clock_ticks",				SYS_PROP_CLOCK			,SYSOBJ_FLAGS,	311
+		,JSDOCSTR("Amount of elapsed time in clock 'ticks'")
+	},
+	{	"clock_ticks_per_second",	SYS_PROP_CLOCK_PER_SEC	,SYSOBJ_FLAGS,	311
+		,JSDOCSTR("Number of clock ticks per second")
+	},
+	{	"timer",					SYS_PROP_TIMER			,SYSOBJ_FLAGS,	314
+		,JSDOCSTR("High-resolution timer, in seconds (fractional seconds supported)")
+	},
 
-	{	"local_host_name",			SYS_PROP_LOCAL_HOSTNAME	,SYSOBJ_FLAGS,	311  },
-	{	"name_servers",			SYS_PROP_NAME_SERVERS,SYSOBJ_FLAGS,	31802  },
+	{	"local_host_name",			SYS_PROP_LOCAL_HOSTNAME	,SYSOBJ_FLAGS,	311
+		,JSDOCSTR("Private host name that uniquely identifies this system on the local network")
+	},
+	{	"name_servers",				SYS_PROP_NAME_SERVERS	,SYSOBJ_FLAGS,	31802
+		,JSDOCSTR("Array of nameservers in use by the system")
+	},
 	/* last */
 	{0}
 };
 
 #ifdef BUILD_JSDOCS
 static char* sys_prop_desc[] = {
-	 "BBS name"
-	,"Operator name"
-	,"Operator is available for chat"
-	,"Default Guru (AI) name"
-	,"System QWK-ID (for QWK packets)"
-	,"Settings bit-flags (see <tt>SYS_*</tt> in <tt>sbbsdefs.js</tt> for bit definitions)"
-	,"Login control settings bit-flags (see <tt>LOGIN_*</tt> in <tt>sbbsdefs.js</tt> for bit definitions)"
-	,"Internet address (host or domain name)"
-	,"Location (city, state)"
-	,"Timezone (use <i>system.zonestr()</i> to get string representation)"
-	,"Days between forced user password changes (<tt>0</tt>=<i>never</i>)"
-	,"Minimum number of characters in user passwords"
-	,"Maximum number of characters in user passwords"
-	,"Days to preserve deleted user records, record will not be reused/overwritten during this period"
-	,"Days of user inactivity before auto-deletion (<tt>0</tt>=<i>disabled</i>), N/A to P-exempt users"
-
-	,"Last user record number in user database (includes deleted and inactive user records)"
-	,"Name of last user to logoff"
-	,"Amount of free disk space (in bytes)"
-	,"Amount of free disk space (in kibibytes)"
-
-	,"Total number of BBS nodes"
-	,"Last displayable node number"
-
-	,"MQTT support (connection to MQTT broker) is enabled"
-
-	,"New user password (NUP, optional)"
-	,"New user magic word (optional)"
-	,"New user security level"
-	,"New user flag set #1"
-	,"New user flag set #2"
-	,"New user flag set #3"
-	,"New user flag set #4"
-	,"New user restriction flags"
-	,"New user exemption flags"
-	,"New user credits"
-	,"New user extra minutes"
-	,"New user default command shell"
-	,"New user default external editor"
-	,"New user default settings"
-	,"New user default file transfer protocol (command key)"
-	,"New user expiration days"
-	,"New user questions/prompts (see <tt>UQ_*</tt> in <tt>sbbsdefs.js</tt> for bit definitions)"
-
-	,"Expired user security level"
-	,"Expired user flag set #1"
-	,"Expired user flag set #2"
-	,"Expired user flag set #3"
-	,"Expired user flag set #4"
-	,"Expired user restriction flags"
-	,"Expired user exemption flags"
-
-	/* directories */
-	,"Current node directory"
-	,"Control file directory"
-	,"Data file directory"
-	,"Text file directory"
-	,"Temporary file directory"
-	,"Executable file directory"
-	,"Modified modules directory (optional)"
-	,"Log file directory"
-
-	/* filenames */
-	,"Platform-specific \"null\" device filename"
-	,"Platform-specific temporary file directory"
-	,"Platform-specific command processor/shell"
-
-	/* clock */
-	,"Amount of elapsed time in clock 'ticks'"
-	,"Number of clock ticks per second"
-	,"High-resolution timer, in seconds (fractional seconds supported)"
-
-	,"Private host name that uniquely identifies this system on the local network"
-	,"Array of nameservers in use by the system"
-	/* INSERT new tabled properties here */
-
 	/* Manually created (non-tabled) properties */
-	,"Public host name that uniquely identifies this system on the Internet (usually the same as <i>system.inet_addr</i>)"
+	 "Public host name that uniquely identifies this system on the Internet (usually the same as <i>system.inet_addr</i>)"
 	,"Socket library version information"
 	,"Time/date system was brought online (in time_t format)"
 	,"Synchronet full version information (e.g. '3.10k Beta Debug')"
@@ -2146,27 +2194,27 @@ js_text(JSContext *cx, uintN argc, jsval *arglist)
 static jsSyncMethodSpec js_system_functions[] = {
 #ifndef JSDOOR
 	{"username",		js_username,		1,	JSTYPE_STRING,	JSDOCSTR("user_number")
-	,JSDOCSTR("Returns name of user in specified user record <i>number</i>, or empty string if not found")
+	,JSDOCSTR("Return name of user in specified user record <i>number</i>, or empty string if not found")
 	,311
 	},
 	{"alias",			js_alias,			1,	JSTYPE_STRING,	JSDOCSTR("alias")
-	,JSDOCSTR("Returns name of user that matches alias (if found in <tt>ctrl/alias.cfg</tt>)")
+	,JSDOCSTR("Return name of user that matches alias (if found in <tt>ctrl/alias.cfg</tt>)")
 	,310
 	},
 	{"find_login_id",	js_find_login_id,	1,	JSTYPE_NUMBER,	JSDOCSTR("user-id")
 	,JSDOCSTR("Find a user's login ID (alias, real name, or number), returns matching user record number or 0 if not found")
 	,32000
 	},
-	{"matchuser",		js_matchuser,		1,	JSTYPE_NUMBER,	JSDOCSTR("username [,sysop_alias=<tt>true</tt>]")
+	{"matchuser",		js_matchuser,		1,	JSTYPE_NUMBER,	JSDOCSTR("username [,sysop_alias=true]")
 	,JSDOCSTR("Exact user name matching, returns number of user whose name/alias matches <i>username</i> "
 		" or 0 if not found, matches well-known sysop aliases by default")
 	,310
 	},
-	{"matchuserdata",	js_matchuserdata,	2,	JSTYPE_NUMBER,	JSDOCSTR("field, data [,match_del=<tt>false</tt>] [,usernumber, match_next=<tt>false</tt>]")
-	,JSDOCSTR("Search user database for data in a specific field (see <tt>U_*</tt> in <tt>sbbsdefs.js</tt>), "
-		"if <i>match_del</i> is <tt>true</tt>, deleted user records are searched, "
+	{"matchuserdata",	js_matchuserdata,	2,	JSTYPE_NUMBER,	JSDOCSTR("field, data [,<i>bool</i> match_del=false] [,<i>number</i> usernumber, <i>bool</i> match_next=false]")
+	,JSDOCSTR("Search user database for data in a specific field (see <tt>U_*</tt> in <tt>sbbsdefs.js</tt>).<br>"
+		"If <i>match_del</i> is <tt>true</tt>, deleted user records are searched, "
 		"returns first matching user record number, optional <i>usernumber</i> specifies user record to skip, "
-		"or record at which to begin searching if optional <i>match_next</i> is <tt>true</tt>")
+		"or record at which to begin searching if optional <i>match_next</i> is <tt>true</tt>.")
 	,310
 	},
 #endif
@@ -2174,7 +2222,7 @@ static jsSyncMethodSpec js_system_functions[] = {
 	,JSDOCSTR("Search <tt>text/<i>basename</i>.can</tt> for pseudo-regexp")
 	,310
 	},
-	{"findstr",			js_findstr,			2,	JSTYPE_BOOLEAN,	JSDOCSTR("path/filename or array of strings, find_string")
+	{"findstr",			js_findstr,			2,	JSTYPE_BOOLEAN,	JSDOCSTR("path/filename or <i>array</i> of strings, find_string")
 	,JSDOCSTR("Search any trashcan/filter file or array of pattern strings (in <tt>*.can</tt> format) for <i>find_string</i>")
 	,310
 	},
@@ -2224,11 +2272,11 @@ static jsSyncMethodSpec js_system_functions[] = {
 	,310
 	},
 	{"get_telegram",	js_get_telegram,	1,	JSTYPE_STRING,	JSDOCSTR("user_number")
-	,JSDOCSTR("Returns any short text messages waiting for the specified user")
+	,JSDOCSTR("Return any short text messages waiting for the specified user")
 	,311
 	},
 	{"put_telegram",	js_put_telegram,	2,	JSTYPE_BOOLEAN,	JSDOCSTR("user_number, message_text")
-	,JSDOCSTR("Sends a user a short text message, delivered immediately or during next logon")
+	,JSDOCSTR("Send a user a short text message, delivered immediately or during next logon")
 	,310
 	},
 	{"notify",			js_notify,			2,	JSTYPE_BOOLEAN,	JSDOCSTR("user_number, subject [,message_text]")
@@ -2237,9 +2285,8 @@ static jsSyncMethodSpec js_system_functions[] = {
 	},
 	{"newuser",			js_new_user,		1,	JSTYPE_ALIAS },
 	{"new_user",		js_new_user,		1,	JSTYPE_OBJECT,	JSDOCSTR("name/alias [,client object]")
-	,JSDOCSTR("Creates a new user record, returns a new <a href=#User>User</a> object representing the new user account, on success.<br>"
-	"returns an numeric error code on failure (optional <i>client</i> object argument added in v3.15a.  As of 3.16c, the global "
-	"client object is used if the argument is omitted)")
+	,JSDOCSTR("Create a new user record, returns a new <a href=#User>User</a> object representing the new user account, on success.<br>"
+	"returns an numeric error code on failure")
 	,310
 	},
 	{"del_user",		js_del_user,		1,	JSTYPE_BOOLEAN,	JSDOCSTR("user_number")
@@ -2248,32 +2295,32 @@ static jsSyncMethodSpec js_system_functions[] = {
 	},
 #endif
 	{"exec",			js_sys_exec,		0,	JSTYPE_NUMBER,	JSDOCSTR("command-line")
-	,JSDOCSTR("Executes a native system/shell command-line, returns <i>0</i> on success")
+	,JSDOCSTR("Execute a native system/shell command-line, returns <i>0</i> on success")
 	,311
 	},
 	{"popen",			js_popen,			0,	JSTYPE_ARRAY,	JSDOCSTR("command-line")
-	,JSDOCSTR("Executes a native system/shell command-line, returns array of captured output lines on success "
+	,JSDOCSTR("Execute a native system/shell command-line, returns array of captured output lines on success "
 		"(<b>only functional on UNIX systems</b>)")
 	,311
 	},
 #ifndef JSDOOR
 	{"check_syspass",	js_chksyspass,		1,	JSTYPE_BOOLEAN,	JSDOCSTR("password")
-	,JSDOCSTR("Compares the supplied <i>password</i> against the system password and returns <i>true</i> if it matches")
+	,JSDOCSTR("Compare the supplied <i>password</i> against the system password and returns <tt>true</tt> if it matches")
 	,311
 	},
 	{"check_name",		js_chkname,			1,	JSTYPE_BOOLEAN,	JSDOCSTR("name/alias")
-	,JSDOCSTR("Checks that the provided name/alias string is suitable for a new user account, "
-		"returns <i>true</i> if it is valid")
+	,JSDOCSTR("Check that the provided name/alias string is suitable for a new user account, "
+		"returns <tt>true</tt> if it is valid")
 	,315
 	},
 	{"check_filename",	js_chkfname,		1,	JSTYPE_BOOLEAN,	JSDOCSTR("filename")
 	,JSDOCSTR("Verify that the specified <i>filename</i> string is legal and allowed for upload by users "
-		"(based on system configuration and filter files), returns <i>true</i> if the filename is allowed")
+		"(based on system configuration and filter files), returns <tt>true</tt> if the filename is allowed")
 	,31902
 	},
 	{"allowed_filename", js_allowed_fname,	1,	JSTYPE_BOOLEAN,	JSDOCSTR("filename")
 	,JSDOCSTR("Verify that the specified <i>filename</i> string is allowed for upload by users "
-		"(based on system configuration), returns <i>true</i> if the filename is allowed")
+		"(based on system configuration), returns <tt>true</tt> if the filename is allowed")
 	,31902
 	},
 	{"safest_filename",	js_safest_fname,	1,	JSTYPE_BOOLEAN,	JSDOCSTR("filename")
@@ -2282,22 +2329,22 @@ static jsSyncMethodSpec js_system_functions[] = {
 	},
 	{"illegal_filename", js_illegal_fname,	1,	JSTYPE_BOOLEAN,	JSDOCSTR("filename")
 	,JSDOCSTR("Check if the specified <i>filename</i> string contains illegal characters or sequences, "
-		"returns <i>true</i> if it is an illegal filename")
+		"returns <tt>true</tt> if it is an illegal filename")
 	,31902
 	},
 #endif
 	{"check_pid",		js_chkpid,			1,	JSTYPE_BOOLEAN,	JSDOCSTR("process-ID")
-	,JSDOCSTR("Checks that the provided process ID is a valid executing process on the system, "
-		"returns <i>true</i> if it is valid")
+	,JSDOCSTR("Check that the provided process ID is a valid executing process on the system, "
+		"returns <tt>true</tt> if it is valid")
 	,315
 	},
 	{"terminate_pid",	js_killpid,			1,	JSTYPE_BOOLEAN,	JSDOCSTR("process-ID")
-	,JSDOCSTR("Terminates executing process on the system with the specified process ID, "
-		"returns <i>true</i> on success")
+	,JSDOCSTR("Terminate executing process on the system with the specified process ID, "
+		"returns <tt>true</tt> on success")
 	,315
 	},
 	{"text",			js_text,			1,	JSTYPE_STRING,	JSDOCSTR("index_number")
-	,JSDOCSTR("Returns specified text string (see <tt>bbs.text()</tt> for details)")
+	,JSDOCSTR("Return specified text string (see <tt>bbs.text()</tt> for details)")
 	,31802
 	},
 	{0}
@@ -2727,7 +2774,7 @@ static JSBool js_system_resolve(JSContext *cx, JSObject *obj, jsid id)
 
 	#ifdef BUILD_JSDOCS
 			if(i==0) {
-				js_DescribeSyncObject(cx,nodeobj,"BBS node listing",310);
+				js_DescribeSyncObject(cx,nodeobj,"Terminal Server node listing",310);
 				js_CreateArrayOfStrings(cx, nodeobj, "_property_desc_list", node_prop_desc, JSPROP_READONLY);
 			}
 	#endif
diff --git a/src/sbbs3/js_uifc.c b/src/sbbs3/js_uifc.c
index 3f73639f40630b24d5a278821cbf90cbabe62975..87082e255fa5efc9d614f24bbad8568cf76a9e22 100644
--- a/src/sbbs3/js_uifc.c
+++ b/src/sbbs3/js_uifc.c
@@ -292,24 +292,24 @@ static JSClass js_uifc_getstrxy_ctx_class = {
     ,JSCLASS_HAS_PRIVATE	/* flags		*/
 	,JS_PropertyStub		/* addProperty	*/
 	,JS_PropertyStub		/* delProperty	*/
-	,js_getstrxy_ctx_get		/* getProperty	*/
-	,js_getstrxy_ctx_set		/* setProperty	*/
+	,js_getstrxy_ctx_get	/* getProperty	*/
+	,js_getstrxy_ctx_set	/* setProperty	*/
 	,JS_EnumerateStub		/* enumerate	*/
 	,JS_ResolveStub			/* resolve		*/
 	,JS_ConvertStub			/* convert		*/
 	,js_getstrxy_ctx_finalize	/* finalize		*/
 };
 static jsSyncPropertySpec js_uifc_list_class_properties[] = {
-/*       name               ,tinyid                 ,flags,             ver */
-    {   "cur"		,PROP_CUR 				,JSPROP_ENUMERATE,  317 },
-    {   "bar"  		      ,PROP_BAR    				,JSPROP_ENUMERATE,  317 },
-    {   "left" 		      ,PROP_LEFT    				,JSPROP_ENUMERATE,  31802 },
-    {   "top"  		      ,PROP_TOP    				,JSPROP_ENUMERATE,  31802 },
-    {   "width"		      ,PROP_WIDTH    				,JSPROP_ENUMERATE,  31802 },
+/*       name			,tinyid                 ,flags,             ver */
+    {   "cur"			,PROP_CUR 				,JSPROP_ENUMERATE,  317 },
+    {   "bar"			,PROP_BAR    			,JSPROP_ENUMERATE,  317 },
+    {   "left"			,PROP_LEFT    			,JSPROP_ENUMERATE,  31802 },
+    {   "top"			,PROP_TOP    			,JSPROP_ENUMERATE,  31802 },
+    {   "width"			,PROP_WIDTH    			,JSPROP_ENUMERATE,  31802 },
     {0}
 };
 static jsSyncPropertySpec js_uifc_showbuf_class_properties[] = {
-/*       name               ,tinyid                 ,flags,             ver */
+/*       name           ,tinyid                 ,flags,             ver */
     {   "cur"           ,PROP_CUR    ,JSPROP_ENUMERATE,  31802 },
     {   "bar"           ,PROP_BAR    ,JSPROP_ENUMERATE,  31802 },
     {   "left"          ,PROP_LEFT   ,JSPROP_ENUMERATE,  31802 },
@@ -319,7 +319,7 @@ static jsSyncPropertySpec js_uifc_showbuf_class_properties[] = {
     {0}
 };
 static jsSyncPropertySpec js_uifc_getstrxy_class_properties[] = {
-/*       name               ,tinyid                 ,flags,             ver */
+/*       name           ,tinyid                 ,flags,             ver */
     {   "lastkey"		,PROP_LASTKEY 				,JSPROP_ENUMERATE,  31802 },
     {0}
 };
@@ -543,20 +543,20 @@ static jsSyncPropertySpec js_properties[] = {
 };
 #ifdef BUILD_JSDOCS
 static char* uifc_prop_desc[] = {
-	 "uifc has been initialized"
-	,"current mode bits (see uifcdefs.js)"
-	,"a change has occurred in an input call.  You are expected to set this to false before calling the input if you care about it."
-	,"save buffer depth (advanced)"
-	,"current screen length"
-	,"current screen width"
-	,"when WIN_FIXEDHEIGHT is set, specifies the height used by a list method"
-	,"delay before a single ESC char is parsed and assumed to not be an ANSI sequence (advanced)"
-	,"text that will be displayed if F1 is pressed"
-	,"background colour"
-	,"frame colour"
-	,"text colour"
-	,"inverse colour"
-	,"lightbar colour"
+	 "UIFC library has been successfully initialized"
+	,"Current mode flags (see <tt>uifcdefs.js</tt>)"
+	,"A change has occurred in an input call.  You are expected to set this to false before calling the input if you care about it."
+	,"Save buffer depth (advanced)"
+	,"Current screen length"
+	,"Current screen width"
+	,"When <tt>WIN_FIXEDHEIGHT</tt> mode flag is set, specifies the height used by a list method"
+	,"Delay before a single ESC char is parsed and assumed to not be an ANSI sequence (advanced)"
+	,"Text that will be displayed when F1 or '?' keys are pressed"
+	,"Background colour"
+	,"Frame colour"
+	,"Text colour"
+	,"Inverse colour"
+	,"Lightbar colour"
 	,NULL
 };
 #endif
@@ -1122,11 +1122,11 @@ js_finalize(JSContext *cx, JSObject *obj)
 	JS_SetPrivate(cx,obj,NULL);
 }
 static jsSyncMethodSpec js_functions[] = {
-	{"init",            js_uifc_init,       1,	JSTYPE_BOOLEAN,	JSDOCSTR("string title [, string interface_mode]")
-	,JSDOCSTR("Initialize.  <tt>interface_mode</tt> is a string representing the desired console mode, one of 'STDIO', 'AUTO', "
-		"'X', 'CURSES', 'ANSI', 'CONIO', or 'SDL'."
-		"<p>"
-		"Return value is <tt>true</tt> upon successful UIFC library initialization, <tt>false</tt> upon error."
+	{"init",            js_uifc_init,       1,	JSTYPE_BOOLEAN,	JSDOCSTR("<i>string</i> title [,<i>string</i> interface_mode]")
+	,JSDOCSTR("Initialize the UIFC library with the specified application/script title (e.g. name and maybe version).<br>"
+		"<tt>interface_mode</tt> is a string representing the desired console mode, one of 'STDIO', 'AUTO', "
+		"'X', 'CURSES', 'ANSI', 'CONIO', or 'SDL' (see <tt>conio.init()</tt> for details).<br>"
+		"Return <tt>true</tt> upon successful UIFC library initialization, <tt>false</tt> upon error."
 	)
 	,314
 	},
@@ -1134,65 +1134,66 @@ static jsSyncMethodSpec js_functions[] = {
 	,JSDOCSTR("Uninitialize the UIFC library")
 	,314
 	},
-	{"msg",				js_uifc_msg,		1,	JSTYPE_VOID,	JSDOCSTR("string text")
+	{"msg",				js_uifc_msg,		1,	JSTYPE_VOID,	JSDOCSTR("<i>string</i> text")
 	,JSDOCSTR("Print a short text message and wait for user acknowledgment")
 	,314
 	},
-	{"pop",				js_uifc_pop,		1,	JSTYPE_VOID,	JSDOCSTR("[string text]")
+	{"pop",				js_uifc_pop,		1,	JSTYPE_VOID,	JSDOCSTR("[<i>string</i> text]")
 	,JSDOCSTR("Pop-up (or down) a short text message. Pop-down by passing no <i>text</i> argument.")
 	,314
 	},
-	{"input",			js_uifc_input,		0,	JSTYPE_STRING,	JSDOCSTR("[number mode] [,number left] [,number top] [,string prompt] [,string default] [,number maxlen [,number kmode]]")
+	{"input",			js_uifc_input,		0,	JSTYPE_STRING,	JSDOCSTR("[<i>number</i> mode] [,<i>number</i> left] [,<i>number</i> top] [,<i>string</i> prompt] [,<i>string</i> default] [,<i>number</i> maxlen [,<i>number</i> k_mode]]")
 	,JSDOCSTR("Prompt for a string input.<br>"
 		"<tt>mode</tt> is an optional combination of <tt>WIN_</tt> mode flags from <tt>uifcdefs.js</tt>.<br>"
 		"<tt>left</tt> and <tt>top</tt> are optional window offsets to display the input dialog box.<br>"
 		"<tt>prompt</tt> is an optional text string to display as part of the string input dialog box.<br>"
-		"<tt>default</tt> is an optional original text string that the user can edit (requires the <tt>K_EDIT kmode</tt> flag).<br>"
-		"<tt>maxlen</tt> is an optional maximium input string length (default is 40 characters).<br>"
-		"<tt>kmode</tt> is an optional combination of <tt>K_</tt> mode flags from either <tt>sbbsdefs.js</tt> or <tt>uifcdefs.js</tt>."
+		"<tt>default</tt> is an optional original text string that the user can edit (requires the <tt>K_EDIT k_mode</tt> flag).<br>"
+		"<tt>maxlen</tt> is an optional maximum input string length (default is 40 characters).<br>"
+		"<tt>k_mode</tt> is an optional combination of <tt>K_</tt> mode flags from either <tt>sbbsdefs.js</tt> or <tt>uifcdefs.js</tt>."
 		"<p>"
-		"Return value is the new/edited string or <tt>undefined</tt> if editing was aborted (e.g. via ESC key press)."
+		"Return the new/edited string or <tt>undefined</tt> if editing was aborted (e.g. via ESC key press)."
 	)
 	,314
 	},
-	{"list",			js_uifc_list,		0,	JSTYPE_NUMBER,	JSDOCSTR("[number mode,] string title, array options [,uifc.list.CTX object]")
+	{"list",			js_uifc_list,		0,	JSTYPE_NUMBER,	JSDOCSTR("[<i>number</i> mode,] <i>string</i> title, <i>array</i> options [,<i>uifc.list.CTX</i> ctx]")
 	,JSDOCSTR("Select from a list of displayed options.<br>"
 		"<tt>title</tt> is the brief description of the list (menu) to be displayed in the list heading.<br>"
 		"<tt>options</tt> is an array of items (typically strings) that comprise the displayed list.<br>"
-		"The <tt>CTX</tt> (context) object can be created using <tt>new uifc.list.CTX()</tt> and if the same object is passed in successive calls, allows <tt>WIN_SAV</tt> to work correctly.<br>"
-		"The context object has the following properties and optional arguments to its constructor:<br><tt>cur, bar, top, left, width</tt>"
+		"The <tt>CTX</tt> (context) object can be created using <tt>new uifc.list.CTX</tt> and if the same object is passed in successive calls, allows <tt>WIN_SAV</tt> to work correctly.<br>"
+		"The context object has the following properties (<i>numbers</i>):<br><tt>cur, bar, top, left, width</tt>"
 		"<p>"
-		"Return value is <tt>-1</tt> if list is aborted (e.g. via ESC key press), <tt>false</tt> upon error (e.g. no option array provided),<br>"
-		"or the 0-based numeric index of the option selected by the user. Other negative values may be returned in advanced modes/use-cases (e.g. copy/paste)"
+		"Return <tt>-1</tt> if list is aborted (e.g. via ESC key press), <tt>false</tt> upon error (e.g. no option array provided), "
+		"or the 0-based numeric index of the option selected by the user.<br>"
+		"Other negative values may be returned in advanced modes/use-cases (e.g. copy/paste), see <tt>MSK_</tt> and related <tt>WIN_</tt> constants/comments in <tt>uifcdefs.js</tt> for details."
 	)
 	,314
 	},
 	{"showhelp",			js_uifc_showhelp,	0,	JSTYPE_VOID,	JSDOCSTR("")
-	,JSDOCSTR("Shows the current help text")
+	,JSDOCSTR("Show the current help text")
 	,317
 	},
-	{"scrn",			js_uifc_scrn,		1,	JSTYPE_BOOLEAN,	JSDOCSTR("string text")
+	{"scrn",			js_uifc_scrn,		1,	JSTYPE_BOOLEAN,	JSDOCSTR("<i>string</i> text")
 	,JSDOCSTR("Fill the screen with the appropriate background attribute.  string is the title for the application banner.")
 	,31802
 	},
-	{"showbuf",			js_uifc_showbuf,	7,	JSTYPE_VOID,	JSDOCSTR("number mode, string title, string helpbuf [,uifc.showbuf.CTX object]")
-	,JSDOCSTR("Shows a scrollable text buffer - optionally parsing \"help markup codes\"<br>"
-		"The context object can be created using <tt>new uifc.showbuf.CTX()</tt> and if the same object is passed, allows <tt>WIN_SAV</tt> to work correctly.<br>"
-		"The context object has the following properties and optional arguments to its constructor:<br><tt>cur, bar, top, left, width, height</tt>")
+	{"showbuf",			js_uifc_showbuf,	7,	JSTYPE_VOID,	JSDOCSTR("<i>number</i> mode, <i>string</i> title, <i>string</i> helpbuf [,<i>uifc.showbuf.CTX</i> ctx]")
+	,JSDOCSTR("Show a scrollable text buffer - optionally parsing \"help markup codes\"<br>"
+		"The context object can be created using <tt>new uifc.showbuf.CTX</tt> and if the same object is passed, allows <tt>WIN_SAV</tt> to work correctly.<br>"
+		"The context object has the following properties (<i>numbers</i>):<br><tt>cur, bar, top, left, width, height</tt>")
 	,31802
 	},
-	{"timedisplay",			js_uifc_timedisplay,	0,	JSTYPE_VOID,	JSDOCSTR("[bool force = false]")
-	,JSDOCSTR("Updates time in upper right corner of screen with current time in ASCII/Unix format")
+	{"timedisplay",			js_uifc_timedisplay,	0,	JSTYPE_VOID,	JSDOCSTR("[<i>bool<i/> force = false]")
+	,JSDOCSTR("Update time in upper right corner of screen with current time in ASCII/Unix format")
 	,31802
 	},
-	{"bottomline",			js_uifc_bottomline,	1,	JSTYPE_VOID,	JSDOCSTR("number mode")
-	,JSDOCSTR("Displays the bottom line using the WIN_* mode flags")
+	{"bottomline",			js_uifc_bottomline,	1,	JSTYPE_VOID,	JSDOCSTR("<i>number</i> mode")
+	,JSDOCSTR("Display the bottom line using the <tt>WIN_*</tt> mode flags")
 	,31802
 	},
-	{"getstrxy",			js_uifc_getstrxy,	7,	JSTYPE_STRING,	JSDOCSTR("number left, number top, number width, number max, number mode[, string original][, uifc.getstrxy.CTX object]")
+	{"getstrxy",			js_uifc_getstrxy,	7,	JSTYPE_STRING,	JSDOCSTR("<i>number</i> left, <i>number</i> top, <i>number</i> width, <i>number</i> max, <i>number</i> mode [,<i>string</i> original][, <i>uifc.getstrxy.CTX</i> ctx]")
 	,JSDOCSTR("String input/exit box at a specified position"
-		"The context object can be created using <tt>new uifc.showbuf.CTX()</tt> and if the same object is passed, allows <tt>WIN_SAV</tt> to work correctly.<br>"
-		"The context object has the following properties: <tt>lastkey</tt>")
+		"The context object can be created using <tt>new uifc.showbuf.CTX</tt> and if the same object is passed, allows <tt>WIN_SAV</tt> to work correctly.<br>"
+		"The context object has the following properties: <i>number</i> <tt>lastkey</tt>")
 	,31802
 	},
 	{0}
diff --git a/src/sbbs3/js_user.c b/src/sbbs3/js_user.c
index 93fc693de5cc47536a9b0907c0dc4599b04ec40f..c3e51b1ed7645d17d65b60bd34dd8b654498e92f 100644
--- a/src/sbbs3/js_user.c
+++ b/src/sbbs3/js_user.c
@@ -1391,14 +1391,14 @@ static jsSyncMethodSpec js_user_functions[] = {
 	,31800
 	},
 	{"get_time_left",	js_get_time_left,	1,	JSTYPE_NUMBER,	JSDOCSTR("start_time")
-	,JSDOCSTR("Returns the user's available remaining time online, in seconds,<br>"
+	,JSDOCSTR("Return the user's available remaining time online, in seconds, "
 	"based on the passed <i>start_time</i> value (in time_t format)<br>"
 	"Note: this method does not account for pending forced timed events<br>"
 	"Note: for the pre-defined user object on the BBS, you almost certainly want bbs.get_time_left() instead.")
 	,31401
 	},
 	{"close",			js_user_close,		0,	JSTYPE_VOID,	JSDOCSTR("")
-	,JSDOCSTR("Close the <tt>user.tab</tt> file, if open. The file will be auto-reopened if necessary.")
+	,JSDOCSTR("Close the <tt>user.tab</tt> file, if open. The file will be automatically reopened if necessary.")
 	,31902
 	},
 	{0}
diff --git a/src/sbbs3/js_xtrn_area.c b/src/sbbs3/js_xtrn_area.c
index 2f7cf8a4f1be854ba125f17fbca00f6ce56d4579..c58da772a8deb259255c4e348308c005b5af6116 100644
--- a/src/sbbs3/js_xtrn_area.c
+++ b/src/sbbs3/js_xtrn_area.c
@@ -27,22 +27,22 @@
 
 static char* xtrn_sec_prop_desc[] = {
 
-	 "Index into sec_list array (or -1 if not in index) <i>(introduced in v3.12)</i>"
+	 "Index into sec_list array (or -1 if not in index)"
 	,"Unique number for this external program section"
 	,"External program section internal code"
 	,"External program section name"
 	,"External program section access requirements"
-	,"User has sufficient access to enter this section <i>(introduced in v3.15)</i>"
+	,"User has sufficient access to enter this section"
 	,NULL
 };
 
 static char* xtrn_prog_prop_desc[] = {
 
-	 "Index into prog_list array (or -1 if not in index) <i>(introduced in v3.12)</i>"
+	 "Index into prog_list array (or -1 if not in index)"
 	,"Program number"
-	,"Program section index <i>(introduced in v3.12)</i>"
+	,"Program section index"
 	,"Program section number"
-	,"Program section internal code <i>(introduced in v3.12)</i>"
+	,"Program section internal code"
 	,"Internal code"
 	,"Name"
 	,"Command-line"
diff --git a/src/sbbs3/main.cpp b/src/sbbs3/main.cpp
index 5df059a26c82662230a0b833a07b3707fe5767fd..c641f93a47c39d81e4ed7340f9ae55d6534ed0bb 100644
--- a/src/sbbs3/main.cpp
+++ b/src/sbbs3/main.cpp
@@ -525,7 +525,7 @@ js_DescribeSyncConstructor(JSContext* cx, JSObject* obj, const char* str)
 #ifdef BUILD_JSDOCS
 
 static const char* method_array_name = "_method_list";
-static const char* propver_array_name = "_property_ver_list";
+static const char* property_array_name = "_property_list";
 
 /*
  * from jsatom.c:
@@ -550,19 +550,16 @@ JSBool
 js_DefineSyncProperties(JSContext *cx, JSObject *obj, jsSyncPropertySpec* props)
 {
 	uint		i;
-	int		ver;
+	int			ver;
 	jsval		val;
-	jsuint		len=0;
+	JSString*	js_str;
 	JSObject*	array;
+	JSObject*	prop;
 
-	if((array=JS_NewArrayObject(cx, 0, NULL))==NULL)
+	if((array=JS_NewObject(cx, NULL, NULL, obj))==NULL)
 		return(JS_FALSE);
 
-	if(!JS_DefineProperty(cx, obj, propver_array_name, OBJECT_TO_JSVAL(array)
-		,NULL,NULL,JSPROP_READONLY))
-		return(JS_FALSE);
-
-	for(i=0;props[i].name;i++) {
+	for(i=0; props[i].name != NULL; ++i) {
 		if (props[i].tinyid < 256 && props[i].tinyid > -129) {
 			if(!JS_DefinePropertyWithTinyId(cx, obj, /* Never reserve any "slots" for properties */
 			    props[i].name,props[i].tinyid, JSVAL_VOID, NULL, NULL, props[i].flags|JSPROP_SHARED))
@@ -572,16 +569,29 @@ js_DefineSyncProperties(JSContext *cx, JSObject *obj, jsSyncPropertySpec* props)
 			if(!JS_DefineProperty(cx, obj, props[i].name, JSVAL_VOID, NULL, NULL, props[i].flags|JSPROP_SHARED))
 				return(JS_FALSE);
 		}
-		if(props[i].flags&JSPROP_ENUMERATE) {	/* No need to version invisible props */
-			if((ver=props[i].ver) < 10000)		/* auto convert 313 to 31300 */
-				ver*=100;
-			val = INT_TO_JSVAL(ver);
-			if(!JS_SetElement(cx, array, len++, &val))
-				return(JS_FALSE);
+		if (!(props[i].flags & JSPROP_ENUMERATE))	/* No need to document invisible props */
+			continue;
+
+		prop = JS_NewObject(cx, NULL, NULL, array);
+		if (prop == NULL)
+			return JS_FALSE;
+
+		if((ver=props[i].ver) < 10000)		/* auto convert 313 to 31300 */
+			ver*=100;
+		val = INT_TO_JSVAL(ver);
+		JS_SetProperty(cx, prop, "ver", &val);
+
+		if (props[i].desc != NULL) {
+			if ((js_str = JS_NewStringCopyZ(cx, props[i].desc)) == NULL)
+				return JS_FALSE;
+			val = STRING_TO_JSVAL(js_str);
+			JS_SetProperty(cx, prop, "desc", &val);
 		}
+		if (!JS_DefineProperty(cx, array, props[i].name, OBJECT_TO_JSVAL(prop), NULL, NULL, JSPROP_READONLY | JSPROP_ENUMERATE))
+			return JS_FALSE;
 	}
 
-	return(JS_TRUE);
+	return JS_DefineProperty(cx, obj, property_array_name, OBJECT_TO_JSVAL(array), NULL, NULL, JSPROP_READONLY);
 }
 
 JSBool
@@ -589,7 +599,7 @@ js_DefineSyncMethods(JSContext* cx, JSObject* obj, jsSyncMethodSpec *funcs)
 {
 	int			i;
 	jsuint		len=0;
-	int		ver;
+	int			ver;
 	jsval		val;
 	JSObject*	method;
 	JSObject*	method_array;
@@ -601,16 +611,16 @@ js_DefineSyncMethods(JSContext* cx, JSObject* obj, jsSyncMethodSpec *funcs)
 	if(JS_GetProperty(cx,obj,method_array_name,&val) && val!=JSVAL_VOID) {
 		method_array=JSVAL_TO_OBJECT(val);
 		// If the first item is already in the list, don't do anything.
-		if(!JS_GetArrayLength(cx, method_array, &len))
+		if (!JS_GetArrayLength(cx, method_array, &len))
 			return(JS_FALSE);
-		for(i=0; i<(int)len; i++) {
-			if(JS_GetElement(cx, method_array, i, &val)!=JS_TRUE || val == JSVAL_VOID)
+		for (i = 0; i < (int)len; i++) {
+			if (JS_GetElement(cx, method_array, i, &val) != JS_TRUE || val == JSVAL_VOID)
 				continue;
 			JS_GetProperty(cx, JSVAL_TO_OBJECT(val), "name", &val);
 			JSVALUE_TO_RASTRING(cx, val, str, &str_len, NULL);
-			if(str==NULL)
+			if (str == NULL)
 				continue;
-			if(strcmp(str, funcs[0].name)==0)
+			if (strcmp(str, funcs[0].name) == 0)
 				return(JS_TRUE);
 		}
 	}
@@ -618,11 +628,11 @@ js_DefineSyncMethods(JSContext* cx, JSObject* obj, jsSyncMethodSpec *funcs)
 		if((method_array=JS_NewArrayObject(cx, 0, NULL))==NULL)
 			return(JS_FALSE);
 		if(!JS_DefineProperty(cx, obj, method_array_name, OBJECT_TO_JSVAL(method_array)
-				, NULL, NULL, 0))
+			, NULL, NULL, 0))
 			return(JS_FALSE);
 	}
 
-	for(i=0;funcs[i].name;i++) {
+	for(i=0; funcs[i].name != NULL; ++i) {
 
 		if(!JS_DefineFunction(cx, obj, funcs[i].name, funcs[i].call, funcs[i].nargs, 0))
 			return(JS_FALSE);
@@ -630,12 +640,11 @@ js_DefineSyncMethods(JSContext* cx, JSObject* obj, jsSyncMethodSpec *funcs)
 		if(funcs[i].type==JSTYPE_ALIAS)
 			continue;
 
-		method = JS_NewObject(cx, NULL, NULL, method_array);	/* exception here June-7-2003 */
-
+		method = JS_NewObject(cx, NULL, NULL, method_array);
 		if(method==NULL)
 			return(JS_FALSE);
 
-		if(funcs[i].name!=NULL) {
+		if (funcs[i].name!=NULL) {
 			if((js_str=JS_NewStringCopyZ(cx,funcs[i].name))==NULL)
 				return(JS_FALSE);
 			val = STRING_TO_JSVAL(js_str);
@@ -1199,54 +1208,59 @@ js_prompt(JSContext *cx, uintN argc, jsval *arglist)
 }
 
 static jsSyncMethodSpec js_global_functions[] = {
-	{"log",				js_log,				1,	JSTYPE_STRING,	JSDOCSTR("[level,] value [,value]")
+	{"log",				js_log,				1,	JSTYPE_STRING,	JSDOCSTR("[<i>number</i> level=LOG_INFO,] value [,value]")
 	,JSDOCSTR("Add a line of text to the server and/or system log, "
 		"<i>values</i> are typically string constants or variables, "
-		"<i>level</i> is the debug level/priority (default: <tt>LOG_INFO</tt>)")
+		"<i>level</i> is the severity of the message to be logged, one of the globally-defined values, in decreasing severity:<br>"
+		"<tt>LOG_EMERG, LOG_ALERT, LOG_CRIT, LOG_ERR, LOG_WARNING, LOG_NOTICE, LOG_INFO, and LOG_DEBUG</tt> (default: <tt>LOG_INFO</tt>)")
 	,311
 	},
-	{"read",			js_read,			0,	JSTYPE_STRING,	JSDOCSTR("[count]")
-	,JSDOCSTR("Read up to count characters from input stream")
+	{"read",			js_read,			0,	JSTYPE_STRING,	JSDOCSTR("[count=128]")
+	,JSDOCSTR("Read up to <tt>count</tt> characters from input stream and return as a string or <tt>undefined</tt> upon error")
 	,311
 	},
-	{"readln",			js_readln,			0,	JSTYPE_STRING,	JSDOCSTR("[count]")
-	,JSDOCSTR("Read a single line, up to count characters, from input stream")
+	{"readln",			js_readln,			0,	JSTYPE_STRING,	JSDOCSTR("[count=128]")
+	,JSDOCSTR("Read a single line, up to <tt>count</tt> characters, from input stream and return as a string or <tt>undefined</tt> upon error")
 	,311
 	},
 	{"write",			js_write,			0,	JSTYPE_VOID,	JSDOCSTR("value [,value]")
-	,JSDOCSTR("Send one or more values (typically strings) to the server output")
+	,JSDOCSTR("Send one or more values (typically strings) to the output stream")
 	,311
 	},
-	{"write_raw",			js_write_raw,			0,	JSTYPE_VOID,	JSDOCSTR("value [,value]")
-	,JSDOCSTR("Send a stream of bytes (possibly containing NULLs or special control code sequences) to the server output")
+	{"write_raw",		js_write_raw,			0,	JSTYPE_VOID,	JSDOCSTR("value [,value]")
+	,JSDOCSTR("Send a stream of bytes (possibly containing NUL or special control code sequences) to the output stream")
 	,314
 	},
 	{"print",			js_writeln,			0,	JSTYPE_ALIAS },
     {"writeln",         js_writeln,         0,	JSTYPE_VOID,	JSDOCSTR("value [,value]")
-	,JSDOCSTR("Send a line of text to the console or event log with automatic line termination (CRLF), "
+	,JSDOCSTR("Send a line of text to the output stream with automatic line termination (CRLF), "
 		"<i>values</i> are typically string constants or variables (AKA print)")
 	,311
 	},
-    {"printf",          js_printf,          1,	JSTYPE_STRING,	JSDOCSTR("string format [,value][,value]")
-	,JSDOCSTR("Print a formatted string - <small>CAUTION: for experienced C programmers ONLY</small>")
+    {"printf",          js_printf,          1,	JSTYPE_STRING,	JSDOCSTR("<i>string</i> format [,value][,value]")
+	,JSDOCSTR("Send a C-style formatted string of text to the output stream")
 	,310
 	},
 	{"alert",			js_alert,			1,	JSTYPE_VOID,	JSDOCSTR("value")
-	,JSDOCSTR("Print an alert message (ala client-side JS)")
+	,JSDOCSTR("Send an alert message (ala client-side JS) to the output stream")
 	,310
 	},
-	{"prompt",			js_prompt,			1,	JSTYPE_STRING,	JSDOCSTR("[text] [,value] [,mode=K_EDIT]")
-	,JSDOCSTR("Displays a prompt (<i>text</i>) and returns a string of user input (ala client-side JS)")
+	{"prompt",			js_prompt,			1,	JSTYPE_STRING,	JSDOCSTR("[<i>string</i> text] [,<i>string</i> value] [,<i>number</i> k_mode=K_EDIT]")
+	,JSDOCSTR("Display a prompt (<tt>text</tt>) and return a string of user input (ala client-side JS) or <tt>null</tt> upon no-input<br>"
+		"<tt>value</tt> is an optional default string to be edited (used with the <tt>k_mode K_EDIT</tt> flag)<br>"
+		"See <tt>sbbsdefs.js</tt> for all valid <tt>K_</tt> (keyboard-input) mode flags.")
 	,310
 	},
 	{"confirm",			js_confirm,			1,	JSTYPE_BOOLEAN,	JSDOCSTR("value")
-	,JSDOCSTR("Displays a Yes/No prompt and returns <i>true</i> or <i>false</i> "
-		"based on user's confirmation (ala client-side JS, <i>true</i> = yes)")
+	,JSDOCSTR("Display a Yes/No prompt and return <tt>true</tt> or <tt>false</tt> "
+		"based on user's confirmation (ala client-side JS, <tt>true</tt> = yes)<br>"
+		"see also <tt>console.yesno()<tt>")
 	,310
 	},
 	{"deny",			js_deny,			1,	JSTYPE_BOOLEAN,	JSDOCSTR("value")
-	,JSDOCSTR("Displays a No/Yes prompt and returns <i>true</i> or <i>false</i> "
-		"based on user's denial (<i>true</i> = no)")
+	,JSDOCSTR("Display a No/Yes prompt and returns <tt>true</tt> or <tt>false</tt> "
+		"based on user's denial (<tt>true</tt> = no)<br>"
+		"see also <tt>console.noyes()<tt>")
 	,31501
 	},
     {0}
diff --git a/src/sbbs3/sbbs.h b/src/sbbs3/sbbs.h
index f94663dd2c9e42bac45dad9bd34002552d6eb1c2..8115232e2dffe0272762a1cef459e36e5f7b0659 100644
--- a/src/sbbs3/sbbs.h
+++ b/src/sbbs3/sbbs.h
@@ -1334,6 +1334,7 @@ extern "C" {
 		int             tinyid;
 		uint8_t         flags;
 		int				ver;		/* version added/modified */
+		const char*		desc;		/* description */
 	} jsSyncPropertySpec;
 
 	typedef struct {