--[[
	MCom
	 	A set of utility functions to simplify addon creation
	
	By: Mugendai
	Contact: mugekun@gmail.com
	
	MCom provides several functions designed to lower the amount of code
	required to make an addon be configurable.  It helps to handle the
	things that need to go on to handle user input, either via console
	or via some GUI(like Cosmos or Khaos).
	
	It aims mainly at tasks that are repeated in multiple places in every addon.
	Any addon that wants to have chat commands needs a chat handler, and functions
	for each command it can accept.  It also needs functions for updating
	the variables that have to do with configuration.  Addons may also need
	wrapper functions for a GUI interface.  They may also need to have multiple
	registers to support multiple GUIs, such as Cosmos and Khaos.
	
	These things are all handled by MCom either by registering with it for such
	functions, or by calling functions that do the repetative part.
	
	$Id: MCom.lua 2641 2005-10-17 09:26:21Z mugendai $
	$Rev: 2641 $
	$LastChangedBy: mugendai $
	$Date: 2005-10-17 04:26:21 -0500 (Mon, 17 Oct 2005) $
]]--

--If we should update/declare MCom, then do so now
if (MCom_Update) then

	if (not Khaos) then
		-- Provide Khaos config keywords for MCom mods for when Khaos isn't around
		K_TEXT = "text";
		K_CHECKBOX = "text"; -- Not a typo. Checkboxes use the "text" type to describe their right-side
		K_BUTTON = "button";
		K_SLIDER = "slider";
		K_EDITBOX = "editbox";
		K_PULLDOWN = "pulldown";
		K_COLORPICKER = "colorpicker";
		K_HEADER = "separator";
	end
	
	if (not myAddOnsList) then
		MYADDONS_CATEGORY_BARS = "Bars";
		MYADDONS_CATEGORY_CHAT = "Chat";
		MYADDONS_CATEGORY_CLASS = "Class";
		MYADDONS_CATEGORY_COMBAT = "Combat";
		MYADDONS_CATEGORY_COMPILATIONS = "Compilations";
		MYADDONS_CATEGORY_GUILD = "Guild";
		MYADDONS_CATEGORY_INVENTORY = "Inventory";
		MYADDONS_CATEGORY_MAP = "Map";
		MYADDONS_CATEGORY_OTHERS = "Others";
		MYADDONS_CATEGORY_PROFESSIONS = "Professions";
		MYADDONS_CATEGORY_QUESTS = "Quests";
		MYADDONS_CATEGORY_RAID = "Raid";
	end

	--------------------------------------------------
	--
	-- Public Library Functions
	--
	--------------------------------------------------
	--[[
	 	registerSmart ( {reglist} )
		 	A single function that can register a chat command, and a UI variable at the same time.
		 	You pass only the data you need to, and it will do anything it can with that data.
		 	If you pass enough data to register a UI command and callback, a slash command, a super slash command,
		 	and a sub slash command, this will do all of those things.
		
		Args:
		 	reglist - the table of options, some options will be listed more than once to show when they are needed, but only set them once
		 	 	{
		 	 	Data required to register a Cosmos or Khaos command:
		 	 	 	(string) uivar - the name of the UI variable
		 	 	 	(string) uitype - the type of UI variable
		 	 	 	(string) uilabel - the label of the UI variable
		 	 	 	
		 	 	Data required to register a Khaos command:
		 	 		(string) uisec - the ID of the Khaos set to put the option in
		 	 	 	
		 	 	Optional data for Cosmos or Khaos options:
		 	 		(function) func -	the function to call when this variable changes, see addSlashCommand for further details on the function
		 	 	 										if this is not passed, a generic callback will be provided for you
		 	 	 	(string) varbool - the name of the boolean variable to use in the generic setter
		 	 	 	(string) varnum - the name of the number variable to use in the generic setter
		 	 	 	(string) varstring - the name of the editbox variable to use in the generic setter
		 	 	 	(string) varchoice - the name of the pulldown variable to use in the generic setter
		 	 	 	(string) varcolor - the name of the color variable to use in the generic setter
		 	 	 	(function) update - this function will be called when using the generic setter, and the variable is updated
		 	 	 	(function) noupdate - this function will be called when using the generic setter, and the variable is not updated
		 	 	 	(function) anyupdate - this function will be called when using the generic setter, whether the variable is updated or not
		 	 	 	(boolean) hasbool - set to true if this option has a checkbox in it
		 	 	 	
		 	 	 	(table) uioption -	this can either be a table in the form of a Cosmos registration, or a KhaosOption.  If it is passed
		 	 	 											then it will be used to pull as much data as MCom can make use of out of it.  This can allow you to
		 	 	 											pass a Cosmos style option, that registers a Khaos option, for instance.  It also allows you to set
		 	 	 											anything in the Khaos option that MCom doesn't have an argument for.
		 	 	 											If this is a Khaos option, it can include an entry called mcopts, which is a table of MCom options to set
		 	 	 											for the option
		 	 	 	(string) uisec -	the ID of the section/set to put the option in, if the section/set already exists, the option wil be
		 	 	 										added to it, if it doesn't exist, it will be created
		 	 	 	(string) uiseclabel - the name of the section/set to put the option in
		 	 	 	(string) uisecdesc - the description of the section/set to put the option in
		 	 	 		NOTE: Once passed, the uisec variables will be stored as defaults for further commands
		 	 	 	(string) uisep -	the ID of the separator/header to put the option in, if the separator/header already exists, then the
		 	 	 										option will be added after it, if it doesn't exist, it will be created
		 	 	 		NOTE: Once passed, the uisep variable will be stored as default for further commands
		 	 	 	(string) uiseplabel - the name of the separator/header to put the option in
		 	 	 	(string) uisepdesc - the description of the separator/header to put the option in
		 	 	 	(string) uidesc - the description of the UI variable
		 	 	 	(number) uicheck - the default value for a checkbox, 1 or 0
		 	 	 	(number) uislider - the default value for a slider
		 	 	 	(number) uimin - the minimum value for a slider
		 	 	 	(number) uimax - the maximum value for a slider
		 	 	 	(string) uitext - the text to show on a UI control
		 	 	 	(number) uistep - the increment to use for a slider
		 	 	 	(number) uitexton - whether to show the text for the control or not, 1 or 0
		 	 	 	(string) uisuffix - the suffix to show at the end of the slider text
		 	 	 	(number) uimul - how much to multiple the slider value by when displaying it

		 	 	Optional data for Khaos only options:
		 	 		(table)	uiset - this can be an entire KhaosSet, and if it is, the whole thing will be MCom registered
		 	 		(string) uifolder - the Khaos folder to put the option in, if you don't pass this, and uicat is passed with a compatible type, uicat will be used
		 	 			NOTE: Once passed, the uifolder variable will be stored as default for further commands
		 	 		(string) uisecdiff - the difficulty of the set to put the option in
		 	 		(string) uiseccall - the callback of the set to put the option in
		 	 		(string) uisecdef - the default of the set to put the option in
		 	 		(string) uiseccom - the commands list of the set to put the option in
		 	 			NOTE: Once passed, the uisec variables will be stored as defaults for further commands
		 	 		(string) uisepdiff - the difficulty of the header to put the option in
		 	 		(string) uisepcall - the callback of the header to put the option in
		 	 		(string) uisepdef - the default of the header to put the option in
		 	 		(string) uikey - the key to use for the option
		 	 		(string) uivalue - the value to use for the option
		 	 		(number) uidiff - the difficulty of the option
		 	 		{ key = { value = requirement } } uidep -	A table listing what key's in a Khaos option set need to have what value set to what requirement
																										for the option to be enabled
		 	 		(boolean) uiradio - set to true if the option has a radio control
		 	 		(function) uifeedback - the function to call to show feedback data
		 	 		(table) uisetup - the control setup structure
		 	 		(string) uisliderlow - the text to show on the lower potion of the slider control
		 	 		(string) uisliderhigh - the text to show on the higher potion of the slider control
		 	 		(function) uisliderfunc - the function to use to setup the text to show on the slider
		 	 		{	string = value, ... } choices -	A list of choices and values to use when using a pulldown, string is the string shown in the pulldown
																						and value is the value that should be associated with that string.
					(boolean) multichoice - set to true if more than one option can be selected in a pulldown
					(boolean) hasopacity - set to true if a colorpicker should also have an opacity slider
					(color) uicolor - the default color to use in a color picker
					(string/table) uichoice - the default option(s) to be selected in a pulldown
					(string) uistring - the default string to be set in a textbox
					(table) uicallon - the default string to be set in a textbox
					(boolean) uidischeck - the value of a checkbox when the option set is disabled
					(number) uidisslider - the value of a slider when the option set is disabled
					(color) uidiscolor - the value of a color picker when the option set is disabled
					(string/table) uidischoice - the value of a pulldown when the option set is disabled
					(string) uidisstring - the value of a text box when the option set is disabled
						NOTE: Disabled options will use default settings, if they are not passed or nil
					
				Data required to register with myAddOns
					NOTE: You do not have to wait for VARIABLES_LOADED to register for myAddOns via MCom
								Also, if you have set any section info for a Khaos or Cosmos section, that will be used with myAddOns
					(string) addonname - This must be the exact same as the title in the toc file.  Defaults to uisec.
						or
					(string) uisec -	Where to place the addon in the myAddOnsList, defaults to uiseclabel
						or
					(string) uiseclabel - The name to show in myAddOns, defaults to uisec
					
				Optional data for registering with myAddOns
					(string) uisec -	Where to place the addon in the myAddOnsList, defaults to uiseclabel
		 	 	 	(string) uiseclabel - The name to show in myAddOns, defaults to uisec
		 	 	 	(string) uisecdesc - NO LONGER USED BY myAddOns - The description to show in myAddOns, defaults to uiseclabel
		 	 	 	(string or number) uiver - The version to show in the UI
		 	 	 	(string) uidate - The date this version of the addon was released
		 	 	 	(string) uiauthor - The name of the author of the addon
		 	 	 	(string) uiwww - The website the addon can be found at, if any
		 	 	 	(string) uimail - The email address the author can be reached at
		 	 	 	(string) uicat - The category to place the addon in, if you don't pass this, and uifolder is passed with a compatible type, uifolder will be used
		 	 	 	(string) uiframe - NO LONGER USED BY myAddOns - The name of the frame used to detect if your addon is loaded
		 	 	 	(string) uioptionsframe -	The name of the frame to show when the myAddOns options button is pressed for this Addon.  If this is not passed, and
		 	 	 														you are registering a Cosmos or Khaos option at the same time as this, then Cosmos or Khaos will be set as the options frame.
		 	 	 														This will also add the frame to UIPanelWindows
		 	 	 	( string or {string} ) uihelp - The help text to display in myAddOns and in slash command, and Khaos help.  If it is a table, each entry is a page.

				Data required to register a standard slash command:
					(string) command - the name of the slash command Ex: "/command", or {"/command", "/com"}
					(string) comtype -	[Required if uitype is not passed, takes precidence over uitype]
															the type of data you are expecting from this slash command
									 						MCOM_BOOLT - Expects boolean data, an on, off, 1, or 0
									 						MCOM_NUMT - Expects a number value
									 						MCOM_MULTIT -	Expects a boolean and then a number value, Ex: "/command on 3", this has been surplanted via simply
									 													using hasbool with MCOM_NUMT
									 						MCOM_STRINGT - Expects any string
									 						MCOM_COLORT - Expects a color setup, and optionally opacity
									 						MCOM_CHOICET - Expects a choice from a list of choices, or optionaly multiple choices
									 						MCOM_SIMPLET - No input needed, just calls the function
					
				Optional data for a standard slash command, or sub command:
					(function) func -	the function to call when this variable changes, see addSlashCommand for further details on the function
		 	 	 										if this is not passed, a generic callback will be provided for you
		 	 	 	(boolean) hasbool - set to true if this option has a boolean portion
		 	 	 	(string) varbool - the name of the boolean variable to use in the generic setter
		 	 	 	(string) varnum - the name of the number variable to use in the generic setter
		 	 	 	(string) varstring - the name of the string variable to use in the generic setter
		 	 	 	(string) varchoice - the name of the choice variable to use in the generic setter
		 	 	 	(string) varcolor - the name of the color variable to use in the generic setter
		 	 	 	(number) varmin -	the minimum value the number variable can be set to when using the generic setter
		 	 	 										if not passed, and uimin is passed, uimin will be used
		 	 	 	(number) varmax -	the maximum value the number variable can be set to when using the generic setter
		 	 	 										if not passed, and uimax is passed, uimax will be used
		 	 	 	(function) update - this function will be called when using the generic setter, and the variable is updated
		 	 	 	(function) noupdate - this function will be called when using the generic setter, and the variable is not updated
		 	 	 	(function) anyupdate - this function will be called when using the generic setter, whether the variable is updated or not
		 	 	 	(string) textname -	specifies the name of the option to display when printing status changes without a UI, only used if
		 	 	 											textbool/num/string/choice/color aren't
		 	 	 	(string) textbool, textnum, textstring, textchoice, textcolor -	the string to print for the corrisponding portion, when not using a UI,
		 	 	 																																	and the variable has been updated in the generic setter.  If this string
		 	 	 																																	contains a %s, then it will be replaced with the value its updated to.
		 	 	 	(boolean) textshow - if this is true, then the text will be printed on update, whether or not a UI is around(when using the generic setter)
		 	 	 	(number) commul - the value to multiply the number by when showing it's status
		 	 	 	(number) cominmul - the value to multiply the number by when it is passed in by the user
					(string) comaction -	The action to perform, see Sky documentation for further details
		 			(number) comsticky -	Whether the command is sticky or not(1 or 0), see Sky documentation for further details
		 			(boolean) multichoice - set to true if more than one option can be selected in an MCOM_CHOICET
		 			(boolean) hasopacity - set to true if an MCOM_COLORT should also have an opacity setting
		 		
		 		Optional data for a standard slash command only:
		 			(string) comhelp -	What message to display as help in Sky for this command, see Sky documentation for further details
		 			({string}) extrahelp -	A table of extra help messages to display, each line in the table is a separate line when printed.
					
				Data required to register a super slash command:
					(string) supercom - the name of the super slash command Ex: "/command", or {"/command", "/com"}
					
				Optional data for a super slash command:
					(string) comaction -	The action to perform, see Sky documentation for further details
		 			(number) comsticky -	Whether the command is sticky or not(1 or 0), see Sky documentation for further details
		 			(string) comhelp -	What message to display as help in Sky for this command, see Sky documentation for further details
		 			({string}) extrahelp -	A table of extra help messages to display, each line in the table is a separate line when printed.
					
				Data required to register a sub slash command:
					(string) supercom - the name of the super slash command to use for this sub slash command Ex: "/command", or {"/command", "/com"}
					(string) subcom - the name of the sub command, Ex: "command", or {"command", "com"}
					
					(string) comtype -	[Required if uitype is not passed], see above for details

				Optional data for a sub command only:
					(string) subhelp -	What message to display next to the sub command when listing sub commands in the help output.
															NOTE: if this is an MCOM_CHOICET then if you put a %s in this string, it will be replaced with a list of
															the choices you passed.
					
				Data required for a slash command to update a Cosmos or Khaos variable:
					(string) uivar -	The UI variable that should be updated

				Data required for a slash command to update a Cosmos or Khaos variable, if func does not return a value:
		 			(string) varbool -	The variable that the UI variable should be set by
		 												This should be a string containing the name of the variable to update, this can include .'s for tables, Ex: "Something.Value"
		 												When type is MULTI, this specifies the bool variable
		 			(string) varnum - The same as comnum, but used to specify the number variable when type is MULTI, only used for MULTI type
				
				Data required for a slash command to update a Khaos variable:
					(string) uisec - The option set ID that the uivar is found in	
				
				Data required for a slash command to when type is MCOM_CHOICET:
					{	string = value, ... } choices -	A list of choices and values to use when using a MCOM_CHOICET, string is the string passed in from the console
																						and value is the value that should be associated with that string.
				
				Data required for help window:
					( string or {string} ) infotext -	If this is passed the text will be shown in a help window then the slash command help is used, or when the help button
																						is pressed in Khaos or Cosmos, this is also used for myAddOns help if uihelp was not passed.  If it is a table, each
																						entry is a page.
				
				Optional data for help window:
					(string) name - Sets the name to refer to the addon as in the help window
					(string) infotitle - Sets the title of the help window, if not passed, then name is used with a default string, Ex. "AddonName Help"
		 	 	}
	]]--
	MCom.registerSmart = function ( inreglist )
		--Get a copy of the registration table
		local reglist;
		if ( type(inreglist) == "table" ) then
			reglist = MCom.table.copy(inreglist);
		end
		--Make sure reglist is here, and a table
		if (type(reglist) == "table") then
			--Register the Khaos options set if it has been passed
			if ( type(reglist.uiset) == "table" ) then
				MCom.uisec = reglist.uiset.id;
				MCom.uiseclabel = reglist.uiset.text;
				MCom.uisecdesc = reglist.uiset.helptext;
				MCom.uisecdiff = reglist.uiset.difficulty;
				MCom.uisecdef = reglist.uiset.default;
				MCom.uiseccall = reglist.uiset.callback;
				MCom.uiseccom = reglist.uiset.commands;
				--Register each option in the list
				if ( type(reglist.uiset.options) == "table" ) then
					for curOption = 1, getn(reglist.uiset.options) do
						local newMComSet = MCom.table.copy(reglist);
						newMComSet.uiset = nil;
						newMComSet.uioption = reglist.uiset.options[curOption];
						MCom.registerSmart( newMComSet );
					end
				end
			end
			
			--Support for old sytax variables
			if (reglist.comvar) then
				reglist.varbool = reglist.comvar;
			end
			if (reglist.comvarmulti) then
				reglist.varnum = reglist.comvarmulti;
			end
			
			--This will be set to true if we find that uioption is in Khaos format.
			local isKhaosOption = nil;
			
			--If option data has been passed use any of it, as needed
			if ( type(reglist.uioption) == "table" ) then
				--If the option data seems to be Khaos style, then parse it as such
				if (	(reglist.uioption.id ~= nil) or (reglist.uioption.key ~= nil) or (reglist.uioption.value ~= nil) or 
							(reglist.uioption.text ~= nil) or (reglist.uioption.diificulty ~= nil) or (reglist.uioption.helptext ~= nil) or 
							(reglist.uioption.callback ~= nil) or (reglist.uioption.feedback ~= nil) or (reglist.uioption.check ~= nil) or 
							(reglist.uioption.radio ~= nil) or (reglist.uioption.type ~= nil) or (reglist.uioption.setup ~= nil) or 
							(reglist.uioption.default ~= nil) or (reglist.uioption.disabled ~= nil) or (reglist.uioption.dependencies ~= nil) or
							(reglist.uioption.mcopts ~= nil)
				) then
					isKhaosOption = true;
					if (reglist.uivar == nil) then
						reglist.uivar = reglist.uioption.id;
					end
					if (reglist.uikey == nil) then
						reglist.uikey = reglist.uioption.key;
					end
					if (reglist.uivalue == nil) then
						reglist.uivalue = reglist.uioption.value;
					end
					if (reglist.uilabel == nil) then
						reglist.uilabel = reglist.uioption.text;
					end
					if (reglist.uidiff == nil) then
						reglist.uidiff = reglist.uioption.difficulty;
					end
					if (reglist.uidesc == nil) then
						reglist.uidesc = reglist.uioption.helptext;
					end
					if (reglist.uifunc == nil) then
						reglist.uifunc = reglist.uioption.callback;
						--If this is a Khaos style function, going into Cosmos, then convert the values to Cosmos style
						if ((not Khaos) and CosmosMaster_Init and reglist.uifunc) then
							reglist.uifunc = function (check, value) reglist.uioption.callback({ checked = (check == 1); slider = value; }); end;
						end
					end
					if (reglist.hasbool == nil) then
						reglist.hasbool = reglist.uioption.check;
					end
					if (reglist.uiradio == nil) then
						reglist.uiradio = reglist.uioption.radio;
					end
					if (reglist.uitype == nil) then
						reglist.uitype = reglist.uioption.type;
					end
					if ( type(reglist.uioption.setup) == "table" ) then
						if (reglist.uisetup == nil) then
							reglist.uisetup = reglist.uioption.setup;
						end
						if (reglist.uitext == nil) then
							if ( (reglist.uitype == K_BUTTON) or (reglist.uitype == "BUTTON") ) then
								reglist.uitext = reglist.uioption.setup.buttonText;
							elseif ( (reglist.uitype == K_SLIDER) or (reglist.uitype == "SLIDER") or (reglist.uitype == "BOTH") ) then
								reglist.uitext = reglist.uioption.setup.sliderText;
							end
						end
						if (reglist.uimin == nil) then
							reglist.uimin = reglist.uioption.setup.sliderMin;
						end
						if (reglist.uimax == nil) then
							reglist.uimax = reglist.uioption.setup.sliderMax;
						end
						if (reglist.uistep == nil) then
							reglist.uistep = reglist.uioption.setup.sliderStep;
						end
						if (reglist.uisliderlow == nil) then
							reglist.uisliderlow = reglist.uioption.setup.sliderLowText;
						end
						if (reglist.uisliderhigh == nil) then
							reglist.uisliderhigh = reglist.uioption.setup.sliderHighText;
						end
						if (reglist.uisliderfunc == nil) then
							reglist.uisliderfunc = reglist.uioption.setup.sliderDisplayFunc;
						end
						if (reglist.choices == nil) then
							reglist.choices = reglist.uioption.setup.options;
						end
						if (reglist.multichoice == nil) then
							reglist.multichoice = reglist.uioption.setup.multiSelect;
						end
						if (reglist.hasopacity == nil) then
							reglist.hasopacity = reglist.uioption.setup.hasOpacity;
						end
						if (reglist.uicallon == nil) then
							reglist.uicallon = reglist.uioption.setup.callOn;
						end
					end
					if (reglist.uifeedback == nil) then
						reglist.uifeedback = reglist.uioption.feedback;
					end
					if ( type(reglist.uioption.default) == "table" ) then
						if (reglist.uicheck == nil) then
							reglist.uicheck = reglist.uioption.default.checked;
							if (reglist.uicheck) then
								reglist.uicheck = 1;
							else
								reglist.uicheck = 0;
							end
						end
						if (reglist.uislider == nil) then
							reglist.uislider = reglist.uioption.default.slider;
						end
						if (reglist.uicolor == nil) then
							reglist.uicolor = reglist.uioption.default.color;
						end
						if (reglist.uitype == K_EDITBOX) then
							if (reglist.uistring == nil) then
								reglist.uistring = reglist.uioption.default.value;
							end
						end
						if (reglist.uitype == K_PULLDOWN) then
							if (reglist.uichoice == nil) then
								reglist.uichoice = reglist.uioption.default.value;
							end
						end
					end
					if ( type(reglist.uioption.disabled) == "table" ) then
						if (reglist.uidischeck == nil) then
							reglist.uidischeck = reglist.uioption.disabled.checked;
							if (reglist.uidischeck) then
								reglist.uidischeck = 1;
							else
								reglist.uidischeck = 0;
							end
						end
						if (reglist.uidisslider == nil) then
							reglist.uidisslider = reglist.uioption.disabled.slider;
						end
						if (reglist.uidiscolor == nil) then
							reglist.uidiscolor = reglist.uioption.disabled.color;
						end
						if (reglist.uitype == K_EDITBOX) then
							if (reglist.uidisstring == nil) then
								reglist.uidisstring = reglist.uioption.disabled.value;
							end
						end
						if (reglist.uitype == K_PULLDOWN) then
							if (reglist.uidischoice == nil) then
								reglist.uidischoice = reglist.uioption.disabled.value;
							end
						end
					end
					if (reglist.uidep == nil) then
						reglist.uidep = reglist.uioption.dependencies;
					end

					--If an MCom option set is in here, then use it
					if ( type(reglist.uioption.mcopts) == "table" ) then
						for curOpt in reglist.uioption.mcopts do
							reglist[curOpt] = reglist.uioption.mcopts[curOpt];
						end
					end
				else
					--If it's not Khaos style, we treat it as Cosmos style
					if (reglist.uivar == nil) then
						reglist.uivar = reglist.uioption[1];
					end
					if (reglist.uitype == nil) then
						reglist.uitype = reglist.uioption[2];
					end
					if (reglist.uilabel == nil) then
						reglist.uilabel = reglist.uioption[3];
					end
					if (reglist.uidesc == nil) then
						reglist.uidesc = reglist.uioption[4];
					end
					if (reglist.uifunc == nil) then
						reglist.uifunc = reglist.uioption[5];
						--If it's a Cosmos style function, being used in Khaos then convert the arguments to match
						if (Khaos and (not CosmosMaster_Init) and reglist.uifunc) then
							local checkFunc = function (check)
								if (check) then
									return 1;
								else
									return 0;
								end
							end
							reglist.uifunc = function (state) reglist.uioption[5]( checkFunc(state.checked) , state.slider); end;
							if ( reglist.func == nil ) then
								if (reglist.uitype == "SLIDER") then
									reglist.func = function (value) reglist.uioption[5](0,value); end;
								else
									reglist.func = function (bool, value) reglist.uioption[5](bool,value); end;
								end
							end
						end
					end
					if (reglist.uicheck == nil) then
						reglist.uicheck = reglist.uioption[6];
					end
					if (reglist.uislider == nil) then
						reglist.uislider = reglist.uioption[7];
					end
					if (reglist.uimin == nil) then
						reglist.uimin = reglist.uioption[8];
					end
					if (reglist.uimax == nil) then
						reglist.uimax = reglist.uioption[9];
					end
					if (reglist.uitext == nil) then
						reglist.uitext = reglist.uioption[10];
					end
					if (reglist.uistep == nil) then
						reglist.uistep = reglist.uioption[11];
					end
					if (reglist.uitexton == nil) then
						reglist.uitexton = reglist.uioption[12];
					end
					if (reglist.uisuffix == nil) then
						reglist.uisuffix = reglist.uioption[13];
					end
					if (reglist.uimul == nil) then
						reglist.uimul = reglist.uioption[14];
					end
				end
			end
			
			--Default our regtype to nil
			local regtype = nil;
			--If we have uitype, then figure out the MCOM type for it
			if (reglist.uitype) then
				--If we are doing Khaos, then use it's types, and convert Cosmos types
				--to Khaos types
				if (Khaos) then
						if ( reglist.uitype == K_TEXT ) then
							if (reglist.hasbool == true) then
								regtype = MCOM_BOOLT;
							end
						elseif ( reglist.uitype == K_SLIDER ) then
							regtype = MCOM_NUMT;
						elseif ( reglist.uitype == K_EDITBOX ) then
							regtype = MCOM_STRINGT;
						elseif ( reglist.uitype == K_BUTTON ) then
							regtype = MCOM_SIMPLET;
						elseif ( reglist.uitype == K_PULLDOWN ) then
							regtype = MCOM_CHOICET;
						elseif ( reglist.uitype == K_COLORPICKER ) then
							regtype = MCOM_COLORT;
						elseif (reglist.uitype == "CHECKBOX") then
							reglist.uitype = K_TEXT;
							regtype = MCOM_BOOLT;
							reglist.hasbool = true;
						elseif (reglist.uitype == "SLIDER") then
							reglist.uitype = K_SLIDER;
							regtype = MCOM_NUMT;
						elseif (reglist.uitype == "BOTH") then
							reglist.uitype = K_SLIDER;
							reglist.hasbool = true;
							regtype = MCOM_MULTIT;
						elseif (reglist.uitype == "BUTTON") then
							reglist.uitype = K_BUTTON;
							regtype = MCOM_SIMPLET;
						elseif (reglist.uitype == "SEPARATOR") then
							reglist.uitype = K_HEADER;
						end
				else
					--If we are doing Cosmos, then use it's types, and convert Khaos types
					--to Cosmos types
					if ( reglist.uitype == K_TEXT ) then
						if (reglist.hasbool == true) then
							regtype = MCOM_BOOLT;
							reglist.uitype = "CHECKBOX";
						end
					elseif ( reglist.uitype == K_SLIDER ) then
						regtype = MCOM_NUMT;
						reglist.uitype = "SLIDER";
						if (reglist.hasbool == true) then
							reglist.uitype = "BOTH";
						end
					elseif ( reglist.uitype == K_EDITBOX ) then
						regtype = MCOM_STRINGT;
					elseif ( reglist.uitype == K_BUTTON ) then
						regtype = MCOM_SIMPLET;
						reglist.uitype = "BUTTON";
					elseif ( reglist.uitype == K_PULLDOWN ) then
						regtype = MCOM_CHOICET;
					elseif ( reglist.uitype == K_COLORPICKER ) then
						regtype = MCOM_COLORT;
					elseif (reglist.uitype == K_HEADER) then
							reglist.uitype = "SEPARATOR";
					elseif (reglist.uitype == "CHECKBOX") then
						regtype = MCOM_BOOLT;
						reglist.hasbool = true;
					elseif (reglist.uitype == "SLIDER") then
						regtype = MCOM_NUMT;
					elseif (reglist.uitype == "BOTH") then
						regtype = MCOM_MULTIT;
					elseif (reglist.uitype == "BUTTON") then
						regtype = MCOM_SIMPLET;
					end
				end
			end
			--If we have the comtype, use it instead of the uitype
			if (reglist.comtype) then
				regtype = reglist.comtype;
			end
			
			--If regtype is not set, and we have check set, then set type is BOOLT.
			if ( (regtype == nil) and (reglist.hasbool == true) ) then
				regtype = MCOM_BOOLT;
			end
			--If regtype is BOOLT, and we dont have check set, then set it.
			if ( (regtype == MCOM_BOOLT) and (not reglist.hasbool) ) then
				reglist.hasbool = true;
			end
			--If regtype is MULTIT, and we dont have check set, then set it.
			if ( (regtype == MCOM_MULTIT) and (not reglist.hasbool) ) then
				reglist.hasbool = true;
			end
			
			--If no min, max, or mul were provided for the setter, but was provided for the UI, then use the ui values
			--and visa versa
			if ( reglist.uimin and (not reglist.varmin) ) then
				reglist.varmin = reglist.uimin;
			elseif ( reglist.varmin and (not reglist.uimin) ) then
				reglist.uimin = reglist.varmin;
			end
			if ( reglist.uimax and (not reglist.varmax) ) then
				reglist.varmax = reglist.uimax;
			elseif ( reglist.varmax and (not reglist.uimax) ) then
				reglist.uimax = reglist.varmax;
			end
			if ( reglist.uimul and (not reglist.commul) ) then
				reglist.commul = reglist.uimul;
			elseif ( reglist.commul and (not reglist.uimul) ) then
				reglist.uimul = reglist.commul;
			end
			if ( not reglist.uimul ) then
				reglist.uimul = 1;
			end
			if ( reglist.commul and ( not reglist.cominmul ) ) then
				reglist.cominmul = 1 / reglist.commul;
			end
			if ( not reglist.commul ) then
				reglist.commul = 1;
			end
			if ( not reglist.cominmul ) then
				reglist.cominmul = 1;
			end
			
			if (not reglist.func) then
				if (reglist.uifunc) then
					--If there was no function passed, but a ui func was passed, use the uifunc
					reglist.func = reglist.uifunc;
				else
					--If textname wasn't passed, try and make it from other data
					if (not reglist.textname) then
						reglist.textname = reglist.uilabel;
					end
					if (not reglist.textname) then
						if ( type(reglist.subcom) == "table" ) then
							reglist.textname = reglist.subcom[1];
						else
							reglist.textname = reglist.subcom;
						end
					end
					if (not reglist.textname) then
						if ( type(reglist.command) == "table" ) then
							reglist.textname = reglist.command[1];
						else
							reglist.textname = reglist.command;
						end
					end
					
					--Generate defaults for the text strings if none are passed
					if (reglist.textname) then
						if (not reglist.textbool) then
							reglist.textbool = string.format(MCOM_CHAT_STATUS_B, reglist.textname);
						end
						if (not reglist.textnum) then
							reglist.textnum = string.format(MCOM_CHAT_STATUS_N, reglist.textname);
						end
						if (not reglist.textstring) then
							reglist.textstring = string.format(MCOM_CHAT_STATUS_S, reglist.textname);
						end
						if (not reglist.textchoice) then
							reglist.textchoice = string.format(MCOM_CHAT_STATUS_C, reglist.textname);
						end
						if (not reglist.textcolor) then
							reglist.textcolor = string.format(MCOM_CHAT_STATUS_K, reglist.textname);
						end
					end
					
					--If there was no function passed, then provide our own generic function
					if ((regtype == MCOM_BOOLT) and reglist.varbool) then
						reglist.func =	function (checked)
															if (MCom.updateVar(reglist.varbool, checked, MCOM_BOOLT)) then
																--If there is a function to run on an update, call it
																if (reglist.update and (type(reglist.update) == "function")) then
																	reglist.update(reglist.varbool);
																end

																if (reglist.textbool) then
																	--Print output to let the player know the command succeeded, if there is no UI
																	MCom.printStatus(reglist.textbool, MCom.getStringVar(reglist.varbool), true, reglist.textshow);
																end
															else
																--If there is a function to run on an attempted update, that resulted in no change, then run it
																if (reglist.noupdate and (type(reglist.noupdate) == "function")) then
																	reglist.noupdate(reglist.varbool);
																end
															end
															--If there is a function to run on any update, then run it
															if (reglist.anyupdate and (type(reglist.anyupdate) == "function")) then
																reglist.anyupdate(reglist.varbool);
															end
														end;
					elseif ( ( (regtype == MCOM_NUMT) and (not reglist.hasbool) ) and reglist.varnum ) then
						reglist.func =	function (value)
															if (MCom.updateVar(reglist.varnum, value, MCOM_NUMT, reglist.varmin, reglist.varmax)) then
																--If there is a function to run on an update, call it
																if (reglist.update and (type(reglist.update) == "function")) then
																	reglist.update(reglist.varnum);
																end

																if (reglist.textnum) then
																	--Print output to let the player know the command succeeded, if there is no UI
																	if (value and reglist.commul and MCom.getStringVar(reglist.varnum)) then
																		value = MCom.math.round( ( MCom.getStringVar(reglist.varnum) * reglist.commul ) * 100 ) / 100;
																	else
																		value = MCom.getStringVar(reglist.varnum);
																	end
																	MCom.printStatus(reglist.textnum, value, nil, reglist.textshow);
																end
															else
																--If there is a function to run on an attempted update, that resulted in no change, then run it
																if (reglist.noupdate and (type(reglist.noupdate) == "function")) then
																	reglist.noupdate(reglist.varnum);
																end
															end
															--If there is a function to run on any update, then run it
															if (reglist.anyupdate and (type(reglist.anyupdate) == "function")) then
																reglist.anyupdate(reglist.varnum);
															end
														end;
					elseif ( ( (regtype == MCOM_STRINGT) and (not reglist.hasbool) ) and reglist.varstring ) then
						reglist.func =	function (value)
															if (MCom.updateVar(reglist.varstring, value, MCOM_STRINGT)) then
																--If there is a function to run on an update, call it
																if (reglist.update and (type(reglist.update) == "function")) then
																	reglist.update(reglist.varstring);
																end
																
																if (reglist.textstring) then
																	--Print output to let the player know the command succeeded, if there is no UI
																	MCom.printStatus(reglist.textstring, MCom.getStringVar(reglist.varstring), nil, reglist.textshow);
																end
															else
																--If there is a function to run on an attempted update, that resulted in no change, then run it
																if (reglist.noupdate and (type(reglist.noupdate) == "function")) then
																	reglist.noupdate(reglist.varstring);
																end
															end
															--If there is a function to run on any update, then run it
															if (reglist.anyupdate and (type(reglist.anyupdate) == "function")) then
																reglist.anyupdate(reglist.varstring);
															end
														end;
					elseif ( ( (regtype == MCOM_CHOICET) and (not reglist.hasbool) ) and reglist.varchoice ) then
						reglist.func =	function (value, name)
															if (MCom.updateVar(reglist.varchoice, value, MCOM_CHOICET)) then
																--If there is a function to run on an update, call it
																if (reglist.update and (type(reglist.update) == "function")) then
																	reglist.update(reglist.varchoice);
																end
																
																if (reglist.textchoice) then
																	--Print output to let the player know the command succeeded, if there is no UI
																	MCom.printStatus(reglist.textchoice, name, nil, reglist.textshow);
																end
															else
																--If there is a function to run on an attempted update, that resulted in no change, then run it
																if (reglist.noupdate and (type(reglist.noupdate) == "function")) then
																	reglist.noupdate(reglist.varchoice);
																end
															end
															--If there is a function to run on any update, then run it
															if (reglist.anyupdate and (type(reglist.anyupdate) == "function")) then
																reglist.anyupdate(reglist.varchoice);
															end
														end;
					elseif ( ( (regtype == MCOM_COLORT) and (not reglist.hasbool) ) and reglist.varcolor ) then
						reglist.func =	function (value)
															if (MCom.updateVar(reglist.varcolor, value, MCOM_COLORT)) then
																--If there is a function to run on an update, call it
																if (reglist.update and (type(reglist.update) == "function")) then
																	reglist.update(reglist.varcolor);
																end
																
																if (reglist.textcolor) then
																	--Build a color string
																	local curColor = MCom.getStringVar(reglist.varstring);
																	local curColString = "";
																	if ( type(curColor) == "table" ) then
																		if (curColor.r) then
																			curColString = string.format(MCOM_CHAT_COM_K_R, MCom.math.round(curColor.r * 100));
																		end
																		if (curColor.g) then
																			if ( curColString ~= "" ) then
																				curColString = curColString..", ";
																			end
																			curColString = curColString..string.format(MCOM_CHAT_COM_K_G, MCom.math.round(curColor.g * 100));
																		end
																		if (curColor.b) then
																			if ( curColString ~= "" ) then
																				curColString = curColString..", ";
																			end
																			curColString = curColString..string.format(MCOM_CHAT_COM_K_B, MCom.math.round(curColor.b * 100));
																		end
																		if (reglist.hasopacity) then
																			local displayOpacity = 1;
																			if (curColor.opacity) then
																				displayOpacity = curColor.opacity;
																			end
																			if ( curColString ~= "" ) then
																				curColString = curColString..", ";
																			end
																			curColString = curColString..string.format(MCOM_CHAT_COM_K_O, MCom.math.round(displayOpacity * 100));
																		end
																	end
																	--Print output to let the player know the command succeeded, if there is no UI
																	MCom.printStatus(reglist.textcolor, curColString, nil, reglist.textshow);
																end
															else
																--If there is a function to run on an attempted update, that resulted in no change, then run it
																if (reglist.noupdate and (type(reglist.noupdate) == "function")) then
																	reglist.noupdate(reglist.varcolor);
																end
															end
															--If there is a function to run on any update, then run it
															if (reglist.anyupdate and (type(reglist.anyupdate) == "function")) then
																reglist.anyupdate(reglist.varcolor);
															end
														end;
					elseif ( ( (regtype == MCOM_MULTIT) or ( (regtype == MCOM_NUMT) and reglist.hasbool ) ) and reglist.varbool and reglist.varnum ) then
						reglist.func =	function (checked, value)
															if (MCom.updateVar(reglist.varbool, checked, MCOM_BOOLT)) then
																--If there is a function to run on an update, call it
																if (reglist.update and (type(reglist.update) == "function")) then
																	reglist.update(reglist.varbool);
																end
																
																if (reglist.textbool) then
																	--Print output to let the player know the command succeeded, if there is no UI
																	MCom.printStatus(reglist.textbool, MCom.getStringVar(reglist.varbool), true, reglist.textshow);
																end
															else
																--If there is a function to run on an attempted update, that resulted in no change, then run it
																if (reglist.noupdate and (type(reglist.noupdate) == "function")) then
																	reglist.noupdate(reglist.varbool);
																end
															end
															--If there is a function to run on any update, then run it
															if (reglist.anyupdate and (type(reglist.anyupdate) == "function")) then
																reglist.anyupdate(reglist.varbool);
															end
															
															--If no value was passed, then don't set it
															if (value) then
																if (MCom.updateVar(reglist.varnum, value, MCOM_NUMT, reglist.varmin, reglist.varmax)) then
																	--If there is a function to run on an update, call it
																	if (reglist.update and (type(reglist.update) == "function")) then
																		reglist.update(reglist.varnum);
																	end
																	
																	if (reglist.textnum) then
																		--Print output to let the player know the command succeeded, if there is no UI
																		if (value and reglist.commul and MCom.getStringVar(reglist.varnum)) then
																			value = MCom.math.round( ( MCom.getStringVar(reglist.varnum) * reglist.commul ) * 100 ) / 100;
																		else
																			value = MCom.getStringVar(reglist.varnum);
																		end
																		MCom.printStatus(reglist.textnum, value, nil, reglist.textshow);
																	end
																else
																	--If there is a function to run on an attempted update, that resulted in no change, then run it
																	if (reglist.noupdate and (type(reglist.noupdate) == "function")) then
																		reglist.noupdate(reglist.varnum);
																	end
																end
															end
															--If there is a function to run on any update, then run it
															if (reglist.anyupdate and (type(reglist.anyupdate) == "function")) then
																reglist.anyupdate(reglist.varnum);
															end
														end;
					elseif ( ( ( (regtype == MCOM_STRINGT) and reglist.hasbool ) ) and reglist.varbool and reglist.varstring ) then
						reglist.func =	function (checked, value)
															if (MCom.updateVar(reglist.varbool, checked, MCOM_BOOLT)) then
																--If there is a function to run on an update, call it
																if (reglist.update and (type(reglist.update) == "function")) then
																	reglist.update(reglist.varbool);
																end
																
																if (reglist.textbool) then
																	--Print output to let the player know the command succeeded, if there is no UI
																	MCom.printStatus(reglist.textbool, MCom.getStringVar(reglist.varbool), true, reglist.textshow);
																end
															else
																--If there is a function to run on an attempted update, that resulted in no change, then run it
																if (reglist.noupdate and (type(reglist.noupdate) == "function")) then
																	reglist.noupdate(reglist.varbool);
																end
															end
															--If there is a function to run on any update, then run it
															if (reglist.anyupdate and (type(reglist.anyupdate) == "function")) then
																reglist.anyupdate(reglist.varbool);
															end
															
															--If no value was passed, then don't set it
															if (value) then
																if (MCom.updateVar(reglist.varstring, value, MCOM_STRINGT)) then
																	--If there is a function to run on an update, call it
																	if (reglist.update and (type(reglist.update) == "function")) then
																		reglist.update(reglist.varstring);
																	end
																	
																	if (reglist.textstring) then
																		--Print output to let the player know the command succeeded, if there is no UI
																		MCom.printStatus(reglist.textstring, MCom.getStringVar(reglist.varstring), nil, reglist.textshow);
																	end
																else
																	--If there is a function to run on an attempted update, that resulted in no change, then run it
																	if (reglist.noupdate and (type(reglist.noupdate) == "function")) then
																		reglist.noupdate(reglist.varstring);
																	end
																end
															end
															--If there is a function to run on any update, then run it
															if (reglist.anyupdate and (type(reglist.anyupdate) == "function")) then
																reglist.anyupdate(reglist.varstring);
															end
														end;
					elseif ( ( ( (regtype == MCOM_CHOICET) and reglist.hasbool ) ) and reglist.varbool and reglist.varchoice ) then
						reglist.func =	function (checked, value, name)
															if (MCom.updateVar(reglist.varbool, checked, MCOM_BOOLT)) then
																--If there is a function to run on an update, call it
																if (reglist.update and (type(reglist.update) == "function")) then
																	reglist.update(reglist.varbool);
																end
																
																if (reglist.textbool) then
																	--Print output to let the player know the command succeeded, if there is no UI
																	MCom.printStatus(reglist.textbool, MCom.getStringVar(reglist.varbool), true, reglist.textshow);
																end
															else
																--If there is a function to run on an attempted update, that resulted in no change, then run it
																if (reglist.noupdate and (type(reglist.noupdate) == "function")) then
																	reglist.noupdate(reglist.varbool);
																end
															end
															--If there is a function to run on any update, then run it
															if (reglist.anyupdate and (type(reglist.anyupdate) == "function")) then
																reglist.anyupdate(reglist.varbool);
															end
															
															--If no value was passed, then don't set it
															if (value) then
																if (MCom.updateVar(reglist.varchoice, value, MCOM_CHOICET)) then
																	--If there is a function to run on an update, call it
																	if (reglist.update and (type(reglist.update) == "function")) then
																		reglist.update(reglist.varchoice);
																	end
																	
																	if (reglist.textchoice) then
																		--Print output to let the player know the command succeeded, if there is no UI
																		MCom.printStatus(reglist.textchoice, name, nil, reglist.textshow);
																	end
																else
																	--If there is a function to run on an attempted update, that resulted in no change, then run it
																	if (reglist.noupdate and (type(reglist.noupdate) == "function")) then
																		reglist.noupdate(reglist.varchoice);
																	end
																end
															end
															--If there is a function to run on any update, then run it
															if (reglist.anyupdate and (type(reglist.anyupdate) == "function")) then
																reglist.anyupdate(reglist.varchoice);
															end
														end;
					elseif ( ( ( (regtype == MCOM_COLORT) and reglist.hasbool ) ) and reglist.varbool and reglist.varcolor ) then
						reglist.func =	function (checked, value)
															if (MCom.updateVar(reglist.varbool, checked, MCOM_BOOLT)) then
																--If there is a function to run on an update, call it
																if (reglist.update and (type(reglist.update) == "function")) then
																	reglist.update(reglist.varbool);
																end
																
																if (reglist.textbool) then
																	--Print output to let the player know the command succeeded, if there is no UI
																	MCom.printStatus(reglist.textbool, MCom.getStringVar(reglist.varbool), true, reglist.textshow);
																end
															else
																--If there is a function to run on an attempted update, that resulted in no change, then run it
																if (reglist.noupdate and (type(reglist.noupdate) == "function")) then
																	reglist.noupdate(reglist.varbool);
																end
															end
															--If there is a function to run on any update, then run it
															if (reglist.anyupdate and (type(reglist.anyupdate) == "function")) then
																reglist.anyupdate(reglist.varbool);
															end
															
															--If no value was passed, then don't set it
															if (value) then
																if (MCom.updateVar(reglist.varcolor, value, MCOM_COLORT)) then
																	--If there is a function to run on an update, call it
																	if (reglist.update and (type(reglist.update) == "function")) then
																		reglist.update(reglist.varcolor);
																	end
																	
																	if (reglist.textcolor) then
																		--Build a color string
																		local curColor = MCom.getStringVar(reglist.varstring);
																		local curColString = "";
																		if ( type(curColor) == "table" ) then
																			if (curColor.r) then
																				curColString = string.format(MCOM_CHAT_COM_K_R, MCom.math.round(curColor.r * 100));
																			end
																			if (curColor.g) then
																				if ( curColString ~= "" ) then
																					curColString = curColString..", ";
																				end
																				curColString = curColString..string.format(MCOM_CHAT_COM_K_G, MCom.math.round(curColor.g * 100));
																			end
																			if (curColor.b) then
																				if ( curColString ~= "" ) then
																					curColString = curColString..", ";
																				end
																				curColString = curColString..string.format(MCOM_CHAT_COM_K_B, MCom.math.round(curColor.b * 100));
																			end
																			if (reglist.hasopacity) then
																				local displayOpacity = 1;
																				if (curColor.opacity) then
																					displayOpacity = curColor.opacity;
																				end
																				if ( curColString ~= "" ) then
																					curColString = curColString..", ";
																				end
																				curColString = curColString..string.format(MCOM_CHAT_COM_K_O, MCom.math.round(displayOpacity * 100));
																			end
																		end
																		--Print output to let the player know the command succeeded, if there is no UI
																		MCom.printStatus(reglist.textcolor, curColString, nil, reglist.textshow);
																	end
																else
																	--If there is a function to run on an attempted update, that resulted in no change, then run it
																	if (reglist.noupdate and (type(reglist.noupdate) == "function")) then
																		reglist.noupdate(reglist.varcolor);
																	end
																end
															end
															--If there is a function to run on any update, then run it
															if (reglist.anyupdate and (type(reglist.anyupdate) == "function")) then
																reglist.anyupdate(reglist.varcolor);
															end
														end;
					end
				end
			end

			--If uifolder was not passed, see if there is a compatable uicat for it
			if (not reglist.uifolder) then
				if (reglist.uicat == MYADDONS_CATEGORY_BARS) then
					reglist.uifolder = "bars";
				elseif (reglist.uicat == MYADDONS_CATEGORY_CHAT) then
					reglist.uifolder = "chat";
				elseif (reglist.uicat == MYADDONS_CATEGORY_COMBAT) then
					reglist.uifolder = "combat";
				elseif (reglist.uicat == MYADDONS_CATEGORY_INVENTORY) then
					reglist.uifolder = "inventory";
				elseif (reglist.uicat == MYADDONS_CATEGORY_QUESTS) then
					reglist.uifolder = "quest";
				end
			end

			if (reglist.uitype == "SECTION") then
				--If a Cosmos section has been passed, then we need to store it's data so that
				--when we are ready to register an option, we can then create the option set
				--based on the section data
				MCom.uifolder = reglist.uifolder;
				MCom.uisec = reglist.uisec;
				MCom.uisecabel = reglist.uiseclabel;
				MCom.uisecdesc = reglist.uisecdesc;
				MCom.uisecdiff = reglist.uisecdiff;
				MCom.uiseccall = reglist.uiseccall;
				MCom.uisecdef = reglist.uisecdef;
				MCom.uiseccom = reglist.uiseccom;
				if (not reglist.uisec) then
					reglist.uisec = reglist.uivar;
					MCom.uisec = reglist.uivar;
				end
				if (not reglist.uiseclabel) then
					MCom.uiseclabel = reglist.uilabel;
				end
				if (not reglist.uisecdesc) then
					MCom.uisecdesc = reglist.uidesc;
				end
			end
			
			--If no set was passed, then use the previously stored one
			if (not reglist.uisec) then
				reglist.uisec = MCom.uisec;
			end

			--If the previously stored set exists, and is the same as the one passed, then pull
			--the data from it
			if ( MCom.uisec and (MCom.uisec == reglist.uisec) ) then
				if (not reglist.uiseclabel) then
					reglist.uiseclabel = MCom.uiseclabel;
				end
				if (not reglist.uisecdesc) then
					reglist.uisecdesc = MCom.uisecdesc;
				end
				if (not reglist.uisecdiff) then
					reglist.uisecdiff = MCom.uisecdiff;
				end
				if (not reglist.uiseccall) then
					reglist.uiseccall = MCom.uiseccall;
				end
				if (not reglist.uisecdef) then
					reglist.uisecdef = MCom.uisecdef;
				end
				if (not reglist.uiseccom) then
					reglist.uiseccom = MCom.uiseccom;
				end
			end
			
			--Setup stored set with current data
			MCom.uisec = reglist.uisec;
			MCom.uiseclabel = reglist.uiseclabel;
			MCom.uisecdesc = reglist.uisecdesc;
			MCom.uisecdiff = reglist.uisecdiff;
			MCom.uiseccall = reglist.uiseccall;
			MCom.uisecdef = reglist.uisecdef;
			MCom.uiseccom = reglist.uiseccom;

			--If MyAddOns is loaded, then try to register with it
			if ( myAddOnsList and (MCom.uisec or MCom.uiseclabel or reglist.addonname) ) then
				--Figure out an entry, label, and description
				local addonEntry = MCom.uisec;
				if (not addonEntry) then
					addonEntry = reglist.addonname;
				end
				if (not addonEntry) then
					addonEntry = MCom.uilabel;
				end
				local addonName = reglist.addonname;
				if (not addonName) then
					addonName = addonEntry;
				end
				if (not addonName) then
					addonName = reglist.uiseclabel;
				end
				if ( (not myAddOnsFrame_Register) and MCom.uiseclabel ) then
					addonName = MCom.uiseclabel;
				end
				local addonDesc = reglist.uisecdesc;
				if (not addonDesc) then
					addonDesc = addonName;
				end
				if (not MCom.MyAddOnsList) then
					MCom.MyAddOnsList = {};
				end

				--Default the addon list to an internal one that MCom keeps, until loading is done
				local addonList = MCom.MyAddOnsList;
				--If we have finished loading MyAddOns, then go ahead and use its list
				if (MCom.MyAddOnsLoaded) then
					addonList = myAddOnsList;
				elseif (not MCom.MyAddonsHooked) then
					--If variables haven't loaded yet, then store the registered addons in a temporary list
					--that will will use to add to the real list once variables have loaded
					MCom.MyAddonsHooked = true;
					--Hook the MyAddOns event function so we know when variables have loaded
					MCom.util.hook("myAddOnsFrame_OnEvent", "MCom.myAddOnsFrame_OnEvent", "after");
				end

				--Only add this to the list if it isn't already there
				if ( not addonList[addonEntry] ) then
					--If category wasn't passed see if a compatable folder was passed
					if (not reglist.uicat) then
						if (reglist.uifolder == "bars") then
							reglist.uicat = MYADDONS_CATEGORY_BARS;
						elseif (reglist.uifolder == "chat") then
							reglist.uicat = MYADDONS_CATEGORY_CHAT;
						elseif (reglist.uifolder == "combat") then
							reglist.uicat = MYADDONS_CATEGORY_COMBAT;
						elseif (reglist.uifolder == "inventory") then
							reglist.uicat = MYADDONS_CATEGORY_INVENTORY;
						elseif (reglist.uifolder == "quest") then
							reglist.uicat = MYADDONS_CATEGORY_QUESTS;
						else
							reglist.uicat = MYADDONS_CATEGORY_OTHERS;
						end
					end

					--If no options frame was passed, and this is a Cosmos or Khaos registration, then set
					--the options frame to be the Khaos or Cosmos options frame
					if (not reglist.uioptionsframe) then
						if (Khaos and reglist.uivar and reglist.uitype and reglist.uilabel) then
							reglist.uioptionsframe = "KhaosFrame";
						elseif (CosmosMaster_Init and reglist.uivar and reglist.uitype and reglist.uilabel ) then
							reglist.uioptionsframe = "CosmosMasterFrame";
						end
					end
					--If an options frame was passed, and it isn't in the UIPanel's list, then add it
					if (reglist.uioptionsframe and ( not UIPanelWindows[reglist.uioptionsframe] ) ) then
						UIPanelWindows[reglist.uioptionsframe] = {area = "center", pushable = 0};
					end
					--If uihelp wasn't passed, use infotext
					if (not reglist.uihelp) then
						reglist.uihelp = reglist.infotext;
					end
					--Make usre uihelp is a table or boolean
					if (reglist.uihelp and (type(reglist.uihelp) ~= "table") and (type(reglist.uihelp) ~= "boolean") ) then
						reglist.uihelp = { reglist.uihelp };
					end
					--Add the addon to the list
					addonList[addonEntry] = {
						details = {
							name = addonName;
							description = addonDesc;
							version = reglist.uiver;
							releaseDate = reglist.uidate,
							author = reglist.uiauthor,
							email = reglist.uimail,
							website = reglist.uiwww,
							category = reglist.uicat;
							frame = reglist.uiframe;
							optionsframe = reglist.uioptionsframe;
						};
						help = reglist.uihelp;
						supercom = reglist.supercom;
					};
				end
			end
			
			--If the variable name is not prefixed with COS_ and cosmos is the UI then put it on there
			if ( reglist.uivar and CosmosMaster_Init and (not Khaos) ) then
				if ( (string.len(reglist.uivar) < 4) or (string.sub(reglist.uivar, 1, 4) ~= "COS_") ) then
					reglist.uivar = "COS_"..reglist.uivar;
				end
			end

			if (Khaos and reglist.uivar and reglist.uitype and reglist.uilabel) then
				--If we have Khaos and the data needed to register with it, then try to work that out
				if (reglist.uitype ~= "SECTION") then
					--Only work with valid Khaos types
					if (	(reglist.uitype == K_HEADER) or (reglist.uitype == K_TEXT) or (reglist.uitype == K_CHECKBOX) or
								(reglist.uitype == K_BUTTON) or (reglist.uitype == K_SLIDER) or (reglist.uitype == K_EDITBOX) or
								(reglist.uitype == K_PULLDOWN) or (reglist.uitype == K_COLORPICKER)	) then
						--We have now go through the proccess of preparing a Khaos option, then we will register it
						--If a folder has been passed then store it for use now, and for future registers
						if (reglist.uifolder) then
							MCom.uifolder = reglist.uifolder;
						end
						--If a separator has been passed then store it for use now, and for future registers
						if (reglist.uisep) then
							MCom.uisep = reglist.uisep;
						end
						if (reglist.uitype == K_HEADER) then
							MCom.uisep = reglist.uivar;
						end
					
						--If we don't have a uifunc yet, then wrap the func
						if ( (not reglist.uifunc) and reglist.func ) then
							--Wrap it for Khaos
							reglist.uifunc = function (state, keypressed) MCom.SetFromKUI(reglist.uivar, state, keypressed, reglist.choices); end;
							--Add the function to the list of callback functions
							if (reglist.uitype) then
								--Only do this for UI elements that have options
								if ((reglist.uitype == K_SLIDER) or (reglist.uitype == K_PULLDOWN) or (reglist.uitype == K_EDITBOX) or (reglist.uitype == K_COLORPICKER) or (reglist.uitype == K_BUTTON) or ( (reglist.uitype == K_TEXT) and (reglist.hasbool) ) ) then
									--If there is no function list yet, then make it
									if (not MCom.UIFuncList) then
										MCom.UIFuncList = {};
									end
									--If this function is not yet in the list, then make it
									if (not MCom.UIFuncList[reglist.uivar]) then
										MCom.UIFuncList[reglist.uivar] = {};
									end
									MCom.UIFuncList[reglist.uivar].func = reglist.func;
									MCom.UIFuncList[reglist.uivar].uitype = reglist.uitype;
									MCom.UIFuncList[reglist.uivar].hasbool = reglist.hasbool;
								end
							end
						end
						
						--Make our option structure
						local kOption = {};
						--If uioption is a Khaos style option, use it as our option structure
						if (isKhaosOption) then
							kOption = reglist.uioption;
						end
						
						--Setup the varying parts of the option with MCom data
						kOption.id = reglist.uivar;
						kOption.key = reglist.uikey;
						kOption.value = reglist.uivalue;
						kOption.text = reglist.uilabel;
						kOption.difficulty = reglist.uidiff;
						kOption.helptext = reglist.uidesc;
						kOption.callback = reglist.uifunc;
						if ( reglist.hasbool == nil ) then
							if ( (regtype == MCOM_BOOLT) or (regtype == MCOM_MULTIT) ) then
								reglist.hasbool = true;
							end
						end
						kOption.check = reglist.hasbool;
						kOption.radio = reglist.uiradio;
						kOption.type = reglist.uitype;
						--Setup the setup structure
						if ( type(reglist.uisetup) == "table" ) then
							kOption.setup = reglist.uisetup;
						else
							kOption.setup = {};
						end
						if (reglist.uitype == K_BUTTON) then
							kOption.setup.buttonText = reglist.uitext;
						end

						--Setup the slider
						if (reglist.uitype == K_SLIDER) then
							kOption.setup.sliderMin = reglist.uimin;
							kOption.setup.sliderMax = reglist.uimax;
							kOption.setup.sliderStep = reglist.uistep;
							--If no slider display func has been passed, then make a generic one, that behaves the same
							--as the one in Cosmos
							kOption.setup.sliderLowText = reglist.uisliderlow;
							kOption.setup.sliderHighText = reglist.uisliderhigh;
							kOption.setup.sliderText = reglist.text;
							if (not reglist.uisuffix) then
								reglist.uisuffix = "";
							end
							sliderDisplayFunc = reglist.uisliderfunc;
							if (sliderDisplayFunc == nil) then
								kOption.setup.sliderDisplayFunc = function ( value ) return ( MCom.math.round( ( value * reglist.uimul ) * 100 ) / 100 )..reglist.uisuffix;  end;
							end
						end
						kOption.setup.options = reglist.choices;
						kOption.setup.multiSelect = reglist.multichoice;
						kOption.setup.hasOpacity = reglist.hasopacity;
						kOption.setup.callOn = reglist.uicallon;

						kOption.feedback = reglist.uifeedback;
						--If no feedback has been passed, then make a generic feedback function
						if (not kOption.feedback) then
							if ( reglist.uitype ~= K_HEADER and reglist.uitype ~= K_BUTTON ) then 
								kOption.feedback = function(state)
									local retString;	--The string to return
									--If it is has a check or radio then set the return string up for that
									if (kOption.check ) then
										if ( state.checked ) then
											retString = string.format(MCOM_FEEDBACK_CHECK, kOption.text, MCOM_CHAT_ENABLED);
										else
											retString = string.format(MCOM_FEEDBACK_CHECK, kOption.text, MCOM_CHAT_DISABLED);
										end
									elseif (kOption.radio ) then
										if ( state.value ) then
											retString = string.format(MCOM_FEEDBACK_RADIO, kOption.text, state.value);
										end
									end
									--If it has a slider then set the string up for that
									if (reglist.uitype == K_SLIDER) then
										if ( state.slider ) then
											if (not retString) then
												retString = string.format(MCOM_FEEDBACK_SLIDER, kOption.text, kOption.setup.sliderDisplayFunc(state.slider) );
											else
												--If we also have a check or radio, then use a version that displays both that, and this
												retString = string.format(MCOM_FEEDBACK_SLIDER_M, retString, kOption.setup.sliderDisplayFunc(state.slider) );
											end
										end
									end
									if (reglist.uitype == K_EDITBOX) then
										if ( state.value ) then
											if (not retString) then
												retString = string.format(MCOM_FEEDBACK_EDITBOX, kOption.text, state.value);
											else
												--If we also have a check or radio, then use a version that displays both that, and this
												retString = string.format(MCOM_FEEDBACK_EDITBOX_M, retString, state.value);
											end
										end
									end
									if (reglist.uitype == K_COLORPICKER) then
										if ( state.color ) then
											if (not retString) then
												retString = string.format(MCOM_FEEDBACK_COLOR, MCom.string.colorToString(state.color), kOption.text);
											else
												--If we also have a check or radio, then use a version that displays both that, and this
												retString = string.format(MCOM_FEEDBACK_COLOR_M, MCom.string.colorToString(state.color), retString);
											end
										end
									end
									if (reglist.uitype == K_CHOICE) then
										if ( state.value ) then
											--Create a text list of options
											local options;
											if ( type(state.value) == "table" ) then
												for curOption = 1, table.getn(state.value) do
													if (options) then
														options = options..", "..state.value[curOption];
													else
														options = state.value[curOption];
													end
												end
											else
												options = state.value;
											end
											if (not retString) then
												retString = string.format(MCOM_FEEDBACK_CHOICE, kOption.text, options);
											else
												--If we also have a check or radio, then use a version that displays both that, and this
												retString = string.format(MCOM_FEEDBACK_CHOICE_M, retString, options);
											end
										end
									end
									return retString;
								end
							end
						end

						--Convert the default check state to Khaos style
						if ( reglist.uicheck and ( (reglist.uicheck == 1) or (reglist.uicheck == true) ) ) then
							reglist.uicheck = true;
						else
							reglist.uicheck = false;
						end
						--Convert the disabled check to Khaos format
						if ( reglist.uidischeck and ( (reglist.uidischeck == 1) or (reglist.uidischeck == true) ) ) then
							reglist.uidischeck = true;
						elseif (reglist.uidischeck == 0) then
							reglist.uidischeck = false;
						end

						--Setup the default structure
						kOption.default = {};
						if (reglist.hasbool) then
							kOption.default.checked = reglist.uicheck;
						end
						if (reglist.uitype == K_SLIDER) then
							kOption.default.slider = reglist.uislider;
							if (kOption.default.slider == nil) then
								kOption.default.slider = reglist.uimax;
							end
							if (kOption.default.slider == nil) then
								kOption.default.slider = reglist.uimin;
							end
							if (kOption.default.slider == nil) then
								kOption.default.slider = 1;
							end
						end
						if (reglist.uitype == K_COLORPICKER) then
							kOption.default.color = reglist.uicolor;
						end
						if ( (reglist.uitype == K_PULLDOWN) ) then
							kOption.default.value = reglist.uichoice;
						end
						if ( (reglist.uitype == K_EDITBOX) ) then
							kOption.default.value = reglist.uistring;
						end
						
						--Setup the disabled structure
						--fallback to default, if disabled is not passed
						kOption.disabled = {};
						if (reglist.hasbool) then
							kOption.disabled.checked = reglist.uidischeck;
							if (kOption.disabled.checked == nil) then
								kOption.disabled.checked = reglist.uicheck;
							end
						end
						if (reglist.uitype == K_SLIDER) then
							kOption.disabled.slider = reglist.uidisslider;
							if (kOption.disabled.slider == nil) then
								kOption.disabled.slider = reglist.uislider;
							end
							if (kOption.disabled.slider == nil) then
								kOption.disabled.slider = reglist.uimax;
							end
							if (kOption.disabled.slider == nil) then
								kOption.disabled.slider = reglist.uimin;
							end
							if (kOption.disabled.slider == nil) then
								kOption.disabled.slider = 1;
							end
						end
						if (reglist.uitype == K_COLORPICKER) then
							kOption.disabled.color = reglist.uidiscolor;
							if (kOption.disabled.color == nil) then
								kOption.disabled.color = reglist.uicolor;
							end
						end
						if ( (reglist.uitype == K_PULLDOWN) ) then
							kOption.disabled.value = reglist.uidisstring;
							if (kOption.disabled.value == nil) then
								kOption.disabled.value = reglist.uistring;
							end
						end
						if ( (reglist.uitype == K_EDITBOX) ) then
							kOption.disabled.value = reglist.uidischoice;
							if (kOption.disabled.value == nil) then
								kOption.disabled.value = reglist.uichoice;
							end
						end
						--Setup the option dependencies
						kOption.dependencies = reglist.uidep;

						--Pull the option set from Khaos
						local optionSet = KhaosData.configurationSets[MCom.uisec];
						--Will be set to true if we need to register this set(as in, it has not yet been registered)
						local needsReg = false;
						--If the set didn't yet exist, then create it
						if (not optionSet) then
							needsReg = true;	--New set, so we need to register it
							optionSet = {	id = reglist.uisec;
														text = reglist.uiseclabel;
														helptext = reglist.uisecdesc;
														difficulty = reglist.uisecdiff;
														callback =  reglist.uiseccall;
														default = reglist.uisecdef;
														commands = reglist.uiseccom };
						end
						
						--If there is no option structure in this set yet, then make one
						if (not optionSet.options) then
							optionSet.options = {};
						end
						
						--Check that this option does not already exist
						local alreadyExists = false;
						for curOpt = 1, table.getn(optionSet.options) do
							if (optionSet.options[curOpt].id == reglist.uivar) then
								alreadyExists = true;
								break;
							end
						end
						
						--Only proceed further if the option doesn't already exist
						if (not alreadyExists) then
							--Default the option insertion position to the end of the option list
							local optionPos = table.getn(optionSet.options);
							
							--If we have a header specified, then try to find the last position after it
							--and if it doesn't exist yet.. then make it
							if (MCom.uisep) then
								local foundHeader = false;	--Set true if we find the header
								--Try to find the header
								for curOpt = 1, table.getn(optionSet.options) do
									--If we have found the header, and we have made it to the next header
									--then break here, to put the option just before this header
									if (foundHeader) then
										if (optionSet.options[curOpt].type == K_HEADER) then
											break;
										end
									end
									--If we found the header, set foundHeader
									if (optionSet.options[curOpt].id == MCom.uisep) then
										foundHeader = true;
									end
									--Set the current option position to this postition
									optionPos = curOpt;
								end
								--If we didn't find the passed header, then make it, at the last spot in the list
								if (not foundHeader) then
									--Make sure a header was passed
									if (reglist.uisep) then
										--If no label was passed for the header, use the header variable name
										if (not reglist.uiseplabel) then
											reglist.uiseplabel = reglist.uisep;
										end
										--If no description was passed for the header, use the header label
										if (not reglist.uisepdesc) then
											reglist.uisepdesc = reglist.uiseplabel;
										end
										--Make the header option structure
										local hOption = {	id = reglist.uisep;
																			text = reglist.uiseplabel;
																			helptext = reglist.uisepdesc;
																			type = K_HEADER;
																			difficulty = reglist.uisepdiff; };
										--Itterate the option position up one
										optionPos = optionPos + 1;
										--Shove the header in the last slot in the list
										table.insert(optionSet.options, optionPos, hOption);
									else
										--If we didn't find the header, and there wasn't one passed... then clean out the
										--stored header
										MCom.uisep = nil;
									end								
								end
							end
							
							--Shove the option into the next spot in the table
							table.insert(optionSet.options, optionPos + 1, kOption);

							if (needsReg) then
								--If the option set hasn't been registered yet.. then register it
								Khaos.registerOptionSet(MCom.uifolder, optionSet);
							else
								--If the option set has been registered, then we need to validate it, to make sure it's kuhl
								Khaos.validateOptionSet(optionSet);
							end
						end
					end
				end
			elseif (CosmosMaster_Init and reglist.uivar and reglist.uitype and reglist.uilabel ) then
				--Only register valid Cosmos types
				if (	(reglist.uitype == "SECTION") or (reglist.uitype == "SEPARATOR") or (reglist.uitype == "BUTTON") or
							(reglist.uitype == "CHECKBOX") or (reglist.uitype == "SLIDER") or (reglist.uitype == "BOTH")	) then
					--If we don't have Khaos, but do have Cosmos, then register for Cosmos
					--If the section has been passed, then register it
					if (reglist.uisec) then
						--If the section variable name is not prefixed with COS_ then put it on there
						if ( (string.len(reglist.uisec) < 4) or (string.sub(reglist.uisec, 1, 4) ~= "COS_") ) then
							reglist.uisec = "COS_"..reglist.uisec;
						end
						--Register the section
						Cosmos_RegisterConfiguration(reglist.uisec, "SECTION", reglist.uiseclabel, reglist.uisecdesc);
					end
					--If the separator has been passed, then register it
					if (reglist.uisep) then
						--If the separator variable name is not prefixed with COS_ then put it on there
						if ( (string.len(reglist.uisep) < 4) or (string.sub(reglist.uisep, 1, 4) ~= "COS_") ) then
							reglist.uisep = "COS_"..reglist.uisep;
						end
						--If no label is passed for the separator, then use the variable name
						if (not reglist.uiseplabel) then
							reglist.uiseplabel = reglist.uisep;
						end
						--If no description is passed for the separator, then use the label
						if (not reglist.uisepdesc) then
							reglist.uisepdesc = reglist.uiseplabel;
						end
						--Register the seperator
						Cosmos_RegisterConfiguration(reglist.uisep, "SEPARATOR", reglist.uiseplabel, reglist.uisepdesc);
					end

					--If we don't have a uifunc yet, then wrap the func
					if ( (not reglist.uifunc) and reglist.func ) then
						reglist.uifunc = function (checked, value) MCom.SetFromUI(reglist.uivar, checked, value); end;
						
						--Add the function to the list of callback functions
						if (reglist.uitype) then
							--Only do this for UI elements that have options
							if ((reglist.uitype == "CHECKBOX") or (reglist.uitype == "SLIDER") or (reglist.uitype == "BOTH") or (reglist.uitype == "BUTTON")) then
								if (not MCom.UIFuncList) then
									MCom.UIFuncList = {};
								end
								if (not MCom.UIFuncList[reglist.uivar]) then
									MCom.UIFuncList[reglist.uivar] = {};
								end
								MCom.UIFuncList[reglist.uivar].func = reglist.func;
								MCom.UIFuncList[reglist.uivar].uitype = reglist.uitype;
								MCom.UIFuncList[reglist.uivar].hasbool = reglist.hasbool;
							end
						end
					end
					
					--Convert the default check state to Cosmos style
					if ( reglist.uicheck and ( (reglist.uicheck == 1) or (reglist.uicheck == true) ) ) then
						reglist.uicheck = 1;
					else
						reglist.uicheck = 0;
					end
					
					--Register with Cosmos if available
					Cosmos_RegisterConfiguration(reglist.uivar, reglist.uitype, reglist.uilabel, reglist.uidesc,
						reglist.uifunc,	reglist.uicheck, reglist.uislider, reglist.uimin, reglist.uimax, reglist.uitext,
						reglist.uistep, reglist.uitexton, reglist.uisuffix, reglist.uimul
					);
				end
			end
			
			--If we have enough data to register a slash command, then do it
			--We need to make sure to pass the right ordered var data to the function
			local comVar = reglist.varbool;
			local comVarMulti = reglist.varnum;
			if (regtype == MCOM_STRINGT) then
				comVarMulti = reglist.varstring;
			elseif (regtype == MCOM_CHOICET) then
				comVarMulti = reglist.varchoice;
			elseif (regtype == MCOM_COLORT) then
				comVarMulti = reglist.varcolor;
			end
			if (not comVar) then
				comVar = comVarMulti;
				comVarMulti = nil;
			end
			if (reglist.command and reglist.func) then
				--If no command help was passed, but a ui description was, then use the ui description
				if ( ( not reglist.bomhelp ) and ( reglist.uidesc ) ) then
					reglist.bomhelp = reglist.uidesc;
				end
				MCom.addSlashCom(reglist.command, reglist.func, reglist.comaction, reglist.comsticky, reglist.comhelp, regtype, reglist.uisec, reglist.uivar, comVar, comVarMulti, reglist.varmin, reglist.varmax, reglist.commul, reglist.cominmul, reglist.hasbool, reglist.choices, reglist.multichoice, reglist.hasopacity, reglist.extrahelp);
			end
			--If we have enough data to register a super slash command, then do it
			if (reglist.supercom) then
				MCom.addSlashSuperCom(reglist.supercom, reglist.comaction, reglist.comsticky, reglist.comhelp, reglist.extrahelp);
			end
			--If we have enough data to register a sub slash command, then do it
			if (reglist.supercom and reglist.subcom and reglist.func) then
				--If no sub command help was passed, but a ui description was, then use the ui description
				if ( ( not reglist.subhelp ) and ( reglist.uidesc ) ) then
					reglist.subhelp = reglist.uidesc;
				end
				MCom.addSlashSubCom(reglist.supercom, reglist.subcom, reglist.func, reglist.subhelp, regtype, reglist.uisec, reglist.uivar, comVar, comVarMulti, reglist.varmin, reglist.varmax, reglist.commul, reglist.cominmul, reglist.hasbool, reglist.choices, reglist.multichoice, reglist.hasopacity);
			end

			--If we should be adding an info option, then handle this now
			if (reglist.infotext) then
				--Setup a function to display addon information, if data is available for it
				local infofunc = nil;
				if (reglist.infotext) then
					--If reglist.infotext isn't already a table, then turn it into one
					if (type(reglist.infotext) ~= "table") then
						reglist.infotext = { reglist.infotext };
					end
					--Setup a default info title if we dont have one
					local curInfoTitle = reglist.infotitle;
					if (not curInfoTitle) then
						curInfoTitle = MCOM_HELP_GENERIC_TITLE;
						if (reglist.name) then
							curInfoTitle = string.format(MCOM_HELP_TITLE, reglist.name);
						end
					end
				
					--If this is not a boolean, then add the slash command info to the end of the text as a new page
					if ( type(reglist.infotext) ~= "boolean" ) then
						infofunc = function ()
							--Get the info text and title
							local infotext = MCom.table.copy(reglist.infotext);
							local infotitle = curInfoTitle;
							--If the text isn't a table turn it into one
							if (type(infotext) ~= "table" ) then
								infotext = { infotext };
							end
							if (reglist.supercom) then
								--Add the slash command info on to it
								infotext[table.getn(infotext) + 1] = MCom.PrintSlashCommandInfo(MCom.getComID(reglist.supercom), true);
							end
							--Show the text frame
							MCom.textFrame( { text = infotext; title = infotitle; } );
						end;
					elseif ( reglist.supercom ) then
						infofunc = function ()
							--Set the text as the slash command info
							local infotext = MCom.PrintSlashCommandInfo(MCom.getComID(reglist.supercom), true);
							local infotitle = curInfoTitle;
							--Show the text frame
							MCom.textFrame( { text = infotext; title = infotitle; } );
						end;
					end
				end
				
				--If we have an info function, then add options to access it
				if (infofunc) then
					--Use the generic description
					local infoDesc = MCOM_HELP_GENERIC;
					--If a name has been passed for this mod, then use it in the description
					if (reglist.name) then
						infoDesc = string.format(MCOM_HELP_CONFIG_INFO, reglist.name);
					end
					--If we have Khaos or Cosmos then register with them
					if (Khaos or CosmosMaster_Init and reglist.name) then
						--Setup the difficulty of the help button
						local infodiff = reglist.uisecdiff;
						if (not infodiff) then
							infodiff = reglist.uidiff;
						end
						if (not infodiff) then
							infodiff = 1;
						end
						--Setup the name to display
						local infoName = string.format(MCOM_HELP_CONFIG, reglist.name);
						--Register the option
						MCom.registerSmart( {
							uivar = reglist.name.."MComInfo";									--The option name for the UI
							uitype = K_BUTTON;																--The option type for the UI
							uilabel = infoName;																--The label to use for the checkbox in the UI
							uidesc = infoDesc;																--The description to use for the checkbox in the UI
							uidiff = infodiff;																--The option's difficulty in Khaos
							uifunc = infofunc;																--The function to call
							uitext = MCOM_HELP_GENERIC_TITLE;									--The text to show on the button
						} );
					end
					--Register the sub slash command
					if ( reglist.supercom ) then
						MCom.registerSmart( {
							supercom = reglist.supercom;
							subcom = MCOM_HELP_COMMAND;
							subhelp = infoDesc;
							comtype = MCOM_SIMPLET;
							func = infofunc;
						} );
					end
				end
			end
		end
	end;
	
	--[[
	 	getStringVar ( string value )
		 	Accepts a variable as a string, and returns the value.
		 	However this can parse complex variable names that contain .
		 	such as "Something.Variable"
		 	
		 	It does not handle "Something['Variable']".. Just use the .
		 	format instead.  This also works for number indexes.
		
		Args:
		 	varString - the variable to get, encapsulated in a string, ex:
		 	"Something.Variable.Monkey.Hippo"
	 
		Returns:
		 	the contents of the variable in the passed string
	]]--
	MCom.getStringVar = function (varString)
		if (Sea and Sea.util and Sea.util.getValue) then
			return Sea.util.getValue(varString);
		else
			--Legorols get string var code, no GCs, and no need to store each entry
			if ( type(varString) ~= "string" ) then
				return nil;
			end;
			
			-- Table we reuse with calls to split
			if ( not MCom.valueTable ) then
				MCom.valueTable = {};
			end
			
			-- Split the variable name at ".", first field is a global name
			local fields = MCom.util.split(varString, ".", MCom.valueTable);
			local encloser, member = getglobal(fields[1]), fields[2];
			
			-- If encloser is the only field, it's a global, return its value
			if ( not member ) then
				return encloser;
			end
			
			-- If there are subsequent fields present, get to deeper levels
			for i = 3, table.getn(fields) do
				if ( type(encloser) ~= "table" ) then
					return nil;
				end
				encloser = encloser[member];
				member = fields[i];
			end
			
			-- Encloser is now the last but one field, member is the last field
			if ( type(encloser) == "table" ) then
				return encloser[member];
			end
			-- Error occured, encloser is not a table, return nil
		end
	end;
	--Alias for compatability
	MCom.stringToVar = MCom.getStringVar;
	
	--[[
	 	stringVarToGetFunc ( string varString )
		 	Accepts a variable as a string, and returns a function that
		 	returns the value.
		 	However this can parse complex variable names that contain .
		 	such as "Something.Variable"
		 	
		 	This is alot like getStringVar.  However, getStringVar has to
		 	generate several objects that will need to be garbage
		 	collected.  The function returned by stringVarToFunc does
		 	not generate any amount of GCs worth worying about.  So if
		 	you are needing to do this very often, like OnUpdate, then
		 	it is best to use this function to convert to a function,
		 	and simply call that functin to get the data you need.		 	

		 	It does not handle "Something['Variable']".. Just use the .
		 	format instead.  This also works for number indexes.
		
		Args:
		 	varString - the variable to get, encapsulated in a string, ex:
		 	"Something.Variable.Monkey.Hippo"
	 
		Returns:
		 	a function that when called will return the data in the passed variable
	]]--
	MCom.stringVarToGetFunc = function (varString)
		if ( type(varString) == "string" ) then
			--Seperate the variable by the .'s into a list
			local valList = MCom.util.split(varString, ".");
			--The function we will return
			local varFunc;
			
			--Only proceed if we have a variable to work with
			if (valList and valList[1]) then
				--If it's a table make it a function that will parse the parts
				if (getn(valList) > 1) then
					--Create the function
					varFunc = function ()
						--Get the global variable
						local value = getglobal(valList[1]);
						--Go through each entry in the table and get that variable
						for curPart = 2, getn(valList) do
							--Only get the variable if it is a table
							if ( ( type(value) == "table" ) and value[ valList[curPart] ] ) then
								--Get the variable
								value = value[ valList[curPart] ];
							else
								--Something was invalid, return nil
								return;
							end
						end
						--We got the value, so return it
						return value;
					end;
				else
					--This is a simple variable, so just return the global
					varFunc = function ()
						return getglobal(valList[1]);
					end;
				end
			end
			--Return the function
			return varFunc;
		end
	end;
	
	--[[
	 	setStringVar ( string varString, value )
		 	Sets a variable, specified by a string, to a value.
		 	However this can parse complex variable names that contain .
		 	such as "Something.Variable"
		 	
		 	It does not handle "Something['Variable']".. Just use the .
		 	format instead.  This also works for number indexes.
		
		Args:
		 	varString - the variable to set, encapsulated in a string, ex:
		 		"Something.Variable.Monkey.Hippo"
		 	value - the value to set the variable to, can be any type
	]]--
	MCom.setStringVar = function (varString, value)
		if (Sea and Sea.util and Sea.util.setValue) then
			return Sea.util.setValue(varString, value);
		else
			--Legorols set string var code, no GCs, and no need to store each entry
			if ( type(varString) ~= "string" ) then
				return false;
			end;
			
			-- Table we reuse with calls to split
			if ( not MCom.valueTable ) then
				MCom.valueTable = {};
			end
			
			-- Split the variable name at ".", first field is a global name
			local fields = MCom.util.split(varString, ".", MCom.valueTable);
			local encloser, member = getglobal(fields[1]), fields[2];
			
			-- If encloser is the only field, variable is a global, set its value
			if ( not member ) then
				setglobal(varString, value);
				return true;
			end
			
			-- If there are subsequent fields present, get to deeper levels
			for i = 3, table.getn(fields) do
				if ( type(encloser) ~= "table" ) then
					return false;
				end
				encloser = encloser[member];
				member = fields[i];
			end
			
			-- Encloser is now the last but one field, member is the last field
			if ( type(encloser) == "table" ) then
				encloser[member] = value;
				return true;
			end
			
			-- Error occured, encloser is not a table
			return false;
		end
	end;
	
	--[[
	 	stringVarToSetFunc ( string varString )
		 	Returns a function that can be used to set the passed string
		 	to a value.  However this can parse complex variable names
		 	that contain . such as "Something.Variable"
		 	
		 	This is alot like setStringVar.  However, setStringVar has to
		 	generate several objects that will need to be garbage
		 	collected.  The function returned by stringVarToSetFunc does
		 	not generate any amount of GCs worth worying about.  So if
		 	you are needing to do this very often, like OnUpdate, then
		 	it is best to use this function to convert to a function,
		 	and simply call that functin to set the data you need.		 	

		 	It does not handle "Something['Variable']".. Just use the .
		 	format instead.  This also works for number indexes.
		
		Args:
		 	varString - the variable to set, encapsulated in a string, ex:
		 	"Something.Variable.Monkey.Hippo"
	 
		Returns:
		 	function ( number value) - a function that when called will
		 	set the string passed here, to	the value passed to the function.
	]]--
	MCom.stringVarToSetFunc = function (varString)
		if ( type(varString) == "string" ) then
			--Seperate the variable by the .'s into a list
			local valList = MCom.util.split(varString, ".");
			--The function we will return
			local varFunc;
			
			--Only proceed if we have a variable to work with
			if (valList and valList[1]) then
				--If it's a table make it a function that will parse the parts
				if (getn(valList) > 1) then
					--Create the function
					varFunc = function (value)
						--Get the global variable
						local var = getglobal(valList[1]);
						--Go through each entry in the table and get that variable
						for curPart = 2, getn(valList) do
							--If we have reached the last entry in the list, then set it
							if ( curPart == getn(valList) ) then
								if ( type(var) == "table" ) then
									var[ valList[curPart] ] = value;
								else
									return;
								end
							else
								--Only get the variable if it is a table
								if ( ( type(var) == "table" ) and var[ valList[curPart] ] ) then
									--Get the variable
									var = var[ valList[curPart] ];
								else
									--Something was invalid, return nil
									return;
								end
							end
						end
					end;
				else
					--This is a simple variable, so just return the global
					varFunc = function (value)
						setglobal(valList[1], value);
					end;
				end
			end
			--Return the function
			return varFunc;
		end
	end;
	
	--[[
	 	updateVar ( string varname, value [, string vartype, number varmin, number varmax] )
		 	updates the variable contained in varname, to value.
		 	Handles things different based on the type of var varname is.
		 	If it should be a bool, then it only accepts 1 and 0, or -1 to invert the current setting.
		 	For number, it makes sure it is in the range varmin and varmax.
		
		Args:
		 	varname - name of the variable to update, wrapped in a string, can be complex like "Something.Variable"
		 	value - what to set it to, should be 1, 0, or -1 for bool, any number for number type, or any string for string type
	
		Optional: 
		 	vartype - should be one of the MCOM_ types
		 	varmin - specifies the minimum value for a number type
		 	varmax - specifies the maximum value for a number type
	 
		Returns:
		 	if the value changed from its origional value, returns true
	]]--
	MCom.updateVar = function (varname, value, vartype, varmin, varmax)
		if (varname and value) then
			-- store the old value of the variable
			local oldValue = MCom.getStringVar(varname);

			if (vartype == MCOM_BOOLT) then
				--If a -1 is passed, invert the value
				if (value and (value == -1)) then
					if (oldValue == 1) then
						value = 0;
					else
						value = 1;
					end
				end
				
				--Update the value
				if (value and (value==1)) then
					value = 1;
				else
					value = 0;
				end
			elseif (vartype == MCOM_NUMT) then
				--if its a number and max/min were specified, make sure it's in range
				if (varmin and (value < varmin)) then
					value = varmin;
				end
				if (varmax and (value > varmax)) then
					value = varmax;
				end
			end
			
			local didUpdate = false;
			if (vartype == MCOM_COLORT) then
				--If we don't have an old value, then make one
				if ( not oldValue ) then
					didUpdate = true;
					oldValue = {};
				end
				--if its a color then make sure the color parts are in range
				if (value.r) then
					if (value.r > 1) then
						value.r = 1;
					end
					if (value.r < 0) then
						value.r = 0;
					end
					if (oldValue.r ~= value.r) then
						didUpdate = true;
					end
				else
					value.r = oldValue.r;
				end
				if (value.g) then
					if (value.g > 1) then
						value.g = 1;
					end
					if (value.g < 0) then
						value.g = 0;
					end
					if (oldValue.g ~= value.g) then
						didUpdate = true;
					end
				else
					value.g = oldValue.g;
				end
				if (value.b) then
					if (value.b > 1) then
						value.b = 1;
					end
					if (value.b < 0) then
						value.b = 0;
					end
					if (oldValue.b ~= value.b) then
						didUpdate = true;
					end
				else
					value.b = oldValue.b;
				end
				if (value.opacity) then
					if (value.opacity > 1) then
						value.opacity = 1;
					end
					if (value.opacity < 0) then
						value.opacity = 0;
					end
					if (oldValue.opacity ~= value.opacity) then
						didUpdate = true;
					end
				else
					value.opacity = oldValue.opacity;
				end
			else	
				--if the value changed, return true
				if (value ~= oldValue) then
					didUpdate = true;
				end
			end
			
			if (didUpdate) then
				MCom.setStringVar(varname, value);
				return true;
			end
		end
	end;

	--[[
	 	printStatus ( string text, [string/number/bool] value, bool isbool, bool show )
		 	If Cosmos is not found printStatus will print out a status message, intended to let user know when an option has
		 	been changed, when there is no GUI available.
		
		Args:
		 	text -		the text to print, this can include a %s, and value(or enabled/disabled for bool) will be put in place of the %s
		 						Ex: "This option has been %s" for bool, or "This option has been set to %s" for number or string
	
		Optional: 
			value -		what value to display, can be a string, a number, or a bool
		 	isbool -	if this is true, then the value will be treated as a bool, and if true(or 1) then the %s will contain
		 						the world "Enabled" or "Disabled" for false(or 0)
		 	show - if this is true, then the text will be printed whether there is a UI or not
	]]--
	MCom.printStatus = function (text, value, isbool, show)
		if ( ( not MCom.hasUI() ) or show ) then
			--Convert to string
			if (type(value) == "number") then
				value = tostring(value);
			end
			--If it's boolean or nill convert to 1 or 0
			if ((type(value) == "boolean") or (type(value) == "nil")) then
				if (value) then
					value = "1";
				else
					value = "0";
				end
			end
			if (type(value) == "string") then
				local outText = value;
				--If it's a bool convert to Enabled/Disabled
				if (isbool) then
					outText = MCOM_CHAT_DISABLED;
					if (value == "1") then
						outText = MCOM_CHAT_ENABLED;
					end
				end
				--Format and print the message
				local msg = string.format(text, outText);
				MCom.IO.printc(ChatTypeInfo["SYSTEM"], msg);
			end
		end	
	end;
	
	--[[
	 	hasUI ( )
		 	Tells whether or not a UI, like Cosmos or Khaos is present.
	 
		Returns:
		 	true - there is a UI
		 	false - there is no UI
	]]--
	MCom.hasUI = function (varString)
		local hasUI = true;
		if ( ( CosmosMaster_Init == nil ) and ( Khaos == nil ) ) then 
			hasUI = false;
		end
		
		return hasUI;
	end;
	
	--[[
	 	updateUI ( string slashcom, string subcom )
		 	Updates the UI(Cosmos or Khaos) with the values of the variable associated with the slash command
		 	passed to the function.  If this is done on a super slash command, then all sub commands
		 	will be updated, unless a specific on is specified.
		
		Args:
		 	slashcom - The slash commmand, or super slash command to update the variable from.
	
		Optional: 
		 	subcom -	If slashcom is a super slash command, you can use this to specify which slash
		 						command to update.
	]]--
	MCom.updateUI = function (slashcom, subcom)
		if (MCom.SlashComs) then
			--Get the command IDs
			local comid, subcomid = MCom.getComID(slashcom, subcom);
			if (comid) then
				--Get the command
				local command = MCom.SlashComs[comid];
				--If we have a subcommand, then lets use it
				if (subcomid) then
					command = { command.commands[subcomid] };
				elseif (command.commands) then
					command = command.commands;
				end
				
				--If command isnt a table, then turn it into one
				if (type(command) ~= "table") then
					command = { command };
				end
				local didUpdate = nil;
				if (KhaosData and KhaosData.configurationSets) then
					--If we have Khaos around, then lets update for it
					local curCom = nil;
					local newValMulti = nil;
					local newVal = nil;
					--Go trhough all commands and update them
					for curComID in command do
						--Grab the current command structure
						curCom = command[curComID];
						if (curCom.uisec and KhaosData.configurationSets[curCom.uisec] and curCom.uivar and curCom.comvar) then
							--get the value of the variable
							newVal = MCom.getStringVar(curCom.comvar);
							if (newVal) then
								--Grab the second variable, if there is one
								newValMulti = MCom.getStringVar(curCom.comvarmulti);
								
								--Deault param to change is value
								local param = "value";
								--If it's a boolean, or we have a boolean as well.. then update the boolean part
								if ( (curCom.comtype == MCOM_BOOLT) or (curCom.comtype == MCOM_MULTIT) or curCom.hasbool) then
									--Make sure the value is in true/false form
									if (newVal == 1) then
										newVal = true;
									else
										newVal = false;
									end
									--Update the value
									Khaos.setSetKeyParameter(curCom.uisec, curCom.uivar, "checked", newVal);
								end
								--If it isn't a boolean type then proccess either the other types, or secondary part
								if ( curCom.comtype ~= MCOM_BOOLT ) then
									--If we have a second part variable, then use it now
									if (newValMulti) then
										newVal = newValMulti;
									end
									
									--Handle number types as sliders
									if ( (curCom.comtype == MCOM_NUMT) or (curCom.comtype == MCOM_MULTIT) ) then
										param = "slider";
									end
									
									--Handle color types as color pickers
									if (curCom.comtype == MCOM_COLORT) then
										param = "color";
									end
									
									--Update the value
									Khaos.setSetKeyParameter(curCom.uisec, curCom.uivar, param, newVal);
								end
								didUpdate = true;
							end
						end
					end
					--If we updated something, then update the Khaos display
					if (didUpdate) then
						Khaos.refresh();
					end
				else
					--We only need to update Cosmos if it exists
					if (CosmosMaster_Init) then
						local curCom = nil;
						local newValMulti = nil;
						local newVal = nil;
						--Go trhough all commands and update them
						for curComID in command do
							curCom = command[curComID];
							if (curCom.uivar and curCom.comvar) then
								--get the value of the variable
								newVal = MCom.getStringVar(curCom.comvar);
								if (newVal) then
									newValMulti = MCom.getStringVar(curCom.comvarmulti);
									if ((curCom.comtype ~= MCOM_MULTIT) or ((curCom.comtype == MCOM_MULTIT) and newValMulti)) then
										--if its a boolean, then set the checkbox
										if ((curCom.comtype == MCOM_BOOLT) or (curCom.comtype == MCOM_MULTIT)) then
											Cosmos_UpdateValue(curCom.uivar, CSM_CHECKONOFF, newVal);
											didUpdate = true;
										end
										--if its a number, then set the slider
										if ((curCom.comtype == MCOM_NUMT) or (curCom.comtype == MCOM_MULTIT)) then
											if (curCom.comtype == MCOM_MULTIT) then
												newVal = newValMulti;
											end
											Cosmos_UpdateValue(curCom.uivar, CSM_SLIDERVALUE, newVal);
											didUpdate = true;
										end
									end
								end
							end
						end
						--If we updated something, then update the Cosmos display
						if (didUpdate) then
							CosmosMaster_DrawData();
						end
					end
				end
			end
		end
	end;
	
	
	--[[
	 	getComID ( [string/number] slashcom, string subcom )
		 	Gets the ID of the slashcom in the slash commands list, as well as a
		 	sub slash command, if you specify that you want a sub commands ID.
		
		Args:
		 	slashcom -	The slash commmand, or super slash command to get the ID of.
		 							If you pass the ID itself, that ID will be used when getting
		 							the sub command.  This can be a list of commands, instead of
		 							just one, in which case, it will return the first one in the
		 							list that it finds. Don't forget the / ex. "/command"
		Optional:
		 	slashcom -	The sub command you want to get, if you want one.  This can
		 							be a list instead of just one command, the first one found
		 							will be used.
		 	
		Returns:
			commandid - If it finds the command, it returns the ID, otherwise it returns nil.
			subcommand - If it finds the subcommand it also returns that, otherwise, nil.
	]]--
	MCom.getComID = function (command, subcom)
		local commandid = nil;
		local subcommandid = nil;
		if (MCom.SlashComs) then
			--If the ID was passed, then use it
			if ((type(command) == "number") and MCom.SlashComs[command]) then
				commandid = command;
			else
				--make sure command is a table
				if (type(command) ~= "table") then
					command = {command};
				end
				--find the command in the table
				for curCom in command do
					for curListCom in MCom.SlashComs do
						if (MCom.SlashComs[curListCom].basecommand) then
							for curBaseCom in MCom.SlashComs[curListCom].basecommand do
								if (MCom.SlashComs[curListCom].basecommand[curBaseCom] == command[curCom]) then
									commandid = curListCom;
									break;
								end
							end
							if (commandid) then
								break;
							end
						end
					end
				end
			end			
			
			if (commandid and subcom) then
				--make sure sub command is a table
				if (type(subcom) ~= "table") then
					subcom = {subcom};
				end
				--Try and find the subcommand in the list
				for curSub in subcom do
					for curCom in MCom.SlashComs[commandid].commands do
						if (MCom.SlashComs[commandid].commands[curCom].command) then
							for curComCom in MCom.SlashComs[commandid].commands[curCom].command do
								if (MCom.SlashComs[commandid].commands[curCom].command[curComCom] == subcom[curSub]) then
									subcommandid = curCom;
									break;
								end
							end
							if (subcommandid) then
								break;
							end
						end
					end
				end
			end			
		end
		return commandid, subcommandid;
	end;

	--[[
	 	saveConfig ( {reglist} )
	 		This will store all of the variables you want into a per realm, per character table(MComStorage) inside the passed variable.
	 		This is meant to facilatate storing/loading variables on a per realm, per character basis.  You must register the passed
	 		variable for saving, yourself.
	 		
	 	Args:
	 		reglist - This contains all options for this save procedure
	 			{
	 			Required:
	 				(string) configVar -	The name of the config variable, this should have been registered for save by you, and must be a table with a simple
	 															variable name.  IE no .'s or []'s
	 			
	 			Optional:
	 				(string) storeVar -	The name of the variable to load/store the data in.  If not passed then configVar.MComStorage is used.  Remember to register
	 														it for saving.
	 				(string) exactVar -	If you pass this, then data will be stored in this var, regardless of realm/character.  It will go into this exact var.  This
	 														takes precidence over storeVar.
	 				(string) realm	- This allows you to specify the realm to store to, if not passed, then the current realm will be used.
	 				(string) character	- This allows you to specify the character to store to, if not passed, then the current character will be used.
	 				NOTE: For all the following, this will only work on root level variables.  I.E. Whatever_Config.Variable.  For this you would pass "Variable"
	 				(string or table) saveList -	The names of all variables in the config to be stored, if this is not passed, then MCom will try to store
	 																			all variables except the MComStorage variable.
	 				(string or table) ignoreList - The names of any variables that you want MCom to not store.
	 				(string or table) uiList -	These variables will only be stored if there is no UI available.  Any options that you have the UI controlling
	 																		should be included in here, so you can leave it up to the UI to properly load/save them.
	 				(string or table) nonUIList -	If this list is declared, then uiList will be ignored, and all variables, except these, will be considered UI
	 																			variables.
	 				(string or table) forceList -	After going through the normal vars, MCom will go through and save these vars, even if they are nil.  This list
	 																			is affected by the rules set by the above lists as well.
	 			}
	 	
	 	Returns:
	 			true - Some data was saved
	 			false - No data was saved
	]]--
	MCom.saveConfig = function ( reglist )
		--We will set this true, if we saved any data
		local didSave = false;
		--Make sure we have the required info in the right form
		if ( reglist and ( type(reglist) == "table" ) and reglist.configVar ) then
			--Get the config variable table
			local varTable = MCom.getStringVar(reglist.configVar);
			--Only proceed if the config variable is a table
			if ( type(varTable) == "table" ) then
				--Get the realm and character name
				local realm = reglist.realm;
				if (not realm) then
					realm = GetCVar("RealmName");
				end
				local character = reglist.character;
				if (not character) then
					character = UnitName("player")
				end
				
				--Setup the variable to store data in.
				local storeVar = MCom.getStringVar(reglist.exactVar);
				--If we don't have an exactVar and we have the server and character name then generate the storeVar
				if ( (not storeVar) and realm and character and ( ( character ~= UKNOWNBEING ) and ( character ~= UNKNOWNOBJECT ) ) ) then
					--Get the storage var if one was passed
					storeVar = MCom.getStringVar(reglist.storeVar);
					if (not storeVar) then
						--If the MComStorage variable isn't there yet, or isn't a table, then set it as an empty table
						if (type(varTable.MComStorage) ~= "table") then
							varTable.MComStorage = {};
						end
						storeVar = varTable.MComStorage;
					end
					
					--If this realm doesn't exist, then create it
					if (not storeVar[realm]) then
						storeVar[realm] = {};
					end
					--If this character doesn't exist, then create it
					if (not storeVar[realm][character]) then
						storeVar[realm][character] = {};
					end
					--Set storeVar to use the current realm/char
					storeVar = storeVar[realm][character];
				end
				
				--If we have the variable to store to, then we are good to go
				if (storeVar) then
					--Go through all the variables in the table
					for curVar in varTable do
						--Ignore the MComStorage variable
						if (curVar ~= "MComStorage") then
							--This will become true if we shouldn't store this variable
							local doIgnore = false;
							
							--If we have a list of vars to save, then go through them, and if this var is not in there, then ignore it
							if (reglist.saveList) then
								--Default to ignoring now
								doIgnore = true;
								--Make sure the saveList is a table
								if (type(reglist.saveList) ~= "table") then
									reglist.saveList = { reglist.saveList };
								end
								--Go through the list and see if we find the variable, if we do, then we don't ignore it
								for i, curSaveCheck in reglist.saveList do
									if (curVar == curSaveCheck) then
										doIgnore = false;
										break;
									end
								end
							end
							
							--If we are supposed to ignore this guy, then do so now
							if (not doIgnore) then
								--If we have a list of vars to ignore, then go through them, and if this var is in there, then ignore it
								if (reglist.ignoreList) then
									--Make sure the ignoreList is a table
									if (type(reglist.ignoreList) ~= "table") then
										reglist.ignoreList = { reglist.ignoreList };
									end
									--Go through the list and see if we find the variable, if we do, then ignore it
									for i, curIgnoreCheck in reglist.ignoreList do
										if (curVar == curIgnoreCheck) then
											doIgnore = true;
											break;
										end
									end
								end
								
								--If we are supposed to ignore this guy, then do so now
								if (not doIgnore) then
									if (reglist.nonUIList) then
										--Since these are UI vars, then we should only be ignoring them if the UI is around
										if ( MCom.hasUI() ) then
											--Unless we find this in the list, we should be ignoring it
											doIgnore = true;
											--Make sure the nonUIList is a table
											if (type(reglist.nonUIList) ~= "table") then
												nonUIList = { reglist.nonUIList };
											end
											--Go through the list and see if we find the variable, if we do, then don't ignore it
											for i, curUICheck in reglist.nonUIList do
												if (curVar == curUICheck) then
													doIgnore = false;
													break;
												end
											end
										end
									else
										if (reglist.uiList) then
											--Since these are UI vars, then we should only be ignoring them if the UI is around
											if ( MCom.hasUI() ) then
												--Make sure the uiList is a table
												if (type(reglist.uiList) ~= "table") then
													uiList = { reglist.uiList };
												end
												--Go through the list and see if we find the variable, if we do, then ignore it
												for i, curUICheck in reglist.uiList do
													if (curVar == curUICheck) then
														doIgnore = true;
														break;
													end
												end
											end
										end
									end
									
									--If we are supposed to ignore this guy, then do so now
									if (not doIgnore) then
										--Store the variable
										storeVar[curVar] = varTable[curVar];
										--Set that we saved data
										didSave = true;
									end
								end
							end
						end
					end
					
					--If a forced list has been passed, then go through it
					if (reglist.forceList) then
						--Make sure it is a table
						if ( type(reglist.forceList) ~= "table" ) then
							reglist.forceList = { reglist.forceList };
						end
						--Go through all the variables in the table
						for i, curVar in reglist.forceList do
							--Ignore the MComStorage variable
							if (curVar ~= "MComStorage") then
								--This will become true if we shouldn't store this variable
								local doIgnore = false;
								
								--If we have a list of vars to save, then go through them, and if this var is not in there, then ignore it
								if (reglist.saveList) then
									--Default to ignoring now
									doIgnore = true;
									--Make sure the saveList is a table
									if (type(reglist.saveList) ~= "table") then
										reglist.saveList = { reglist.saveList };
									end
									--Go through the list and see if we find the variable, if we do, then we don't ignore it
									for i, curSaveCheck in reglist.saveList do
										if (curVar == curSaveCheck) then
											doIgnore = false;
											break;
										end
									end
								end
								
								--If we are supposed to ignore this guy, then do so now
								if (not doIgnore) then
									--If we have a list of vars to ignore, then go through them, and if this var is in there, then ignore it
									if (reglist.ignoreList) then
										--Make sure the ignoreList is a table
										if (type(reglist.ignoreList) ~= "table") then
											reglist.ignoreList = { reglist.ignoreList };
										end
										--Go through the list and see if we find the variable, if we do, then ignore it
										for i, curIgnoreCheck in reglist.ignoreList do
											if (curVar == curIgnoreCheck) then
												doIgnore = true;
												break;
											end
										end
									end
									
									--If we are supposed to ignore this guy, then do so now
									if (not doIgnore) then
										if (reglist.nonUIList) then
											--Since these are UI vars, then we should only be ignoring them if the UI is around
											if ( MCom.hasUI() ) then
												--Unless we find this in the list, we should be ignoring it
												doIgnore = true;
												--Make sure the nonUIList is a table
												if (type(reglist.nonUIList) ~= "table") then
													nonUIList = { reglist.nonUIList };
												end
												--Go through the list and see if we find the variable, if we do, then don't ignore it
												for i, curUICheck in reglist.nonUIList do
													if (curVar == curUICheck) then
														doIgnore = false;
														break;
													end
												end
											end
										else
											if (reglist.uiList) then
												--Since these are UI vars, then we should only be ignoring them if the UI is around
												if ( MCom.hasUI() ) then
													--Make sure the uiList is a table
													if (type(reglist.uiList) ~= "table") then
														uiList = { reglist.uiList };
													end
													--Go through the list and see if we find the variable, if we do, then ignore it
													for i, curUICheck in reglist.uiList do
														if (curVar == curUICheck) then
															doIgnore = true;
															break;
														end
													end
												end
											end
										end
										
										--If we are supposed to ignore this guy, then do so now
										if (not doIgnore) then
											--Store the variable
											storeVar[curVar] = varTable[curVar];
											--Set that we saved data
											didSave = true;
										end
									end
								end
							end
						end
					end
				end
			end
		end
		--Return if we saved data or not
		return didSave;
	end;

	--[[
	 	loadConfig ( {reglist} )
	 		This will load all variables stored in the passed table in MComStorage.  This only works on variables that have stored the data using
	 		MCom.saveConfig
	 		
	 	Args:
	 		reglist - This contains all options for this load procedure
	 			{
	 			Required:
	 				(string) configVar -	The name of the config variable, this should have been registered for save by you, and must be a table with a simple
	 															variable name.  IE no .'s or []'s
	 			
	 			Optional:
	 				(string) storeVar -	The name of the variable to load/store the data in.  If not passed then configVar.MComStorage is used.  Remember to register
	 														it for saving.
	 				(string) exactVar -	If you pass this, then data will be loaded from this var, regardless of realm/character.  It will get from this exact var.  This
	 														takes precidence over storeVar.
	 				(string) realm	- This allows you to specify the realm to load from, if not passed, then the current realm will be used.
	 				(string) character	- This allows you to specify the character to load from, if not passed, then the current character will be used.
	 				NOTE: For all the following, this will only work on root level variables.  I.E. Whatever_Config.Variable.  For this you would pass "Variable"
	 				(string or table) loadList -	The names of all variables in the config to be loaded, if this is not passed, then MCom will try to load
	 																			all variables except the MComStorage variable.
	 				(string or table) ignoreList - The names of any variables that you want MCom to not load.
	 				(string or table) uiList -	These variables will only be loaded if there is no UI available.  Any options that you have the UI controlling
	 																		should be included in here, so you can leave it up to the UI to properly load/save them.
	 				(string or table) nonUIList -	If this list is declared, then uiList will be ignored, and all variables, except these, will be considered UI
	 																			variables.
	 				(string or table) forceList -	After going through the normal vars, MCom will go through and load these vars, even if they are nil.
	 																			is affected by the rules set by the above lists as well.
	 			}
	 		
	 		Returns:
	 			true - Some data was loaded
	 			false - No data was loaded
	]]--
	MCom.loadConfig = function ( reglist )
		--We will set this true, if we loaded any data
		local didLoad = false;
		--Make sure we have the required info in the right form
		if ( reglist and ( type(reglist) == "table" ) and reglist.configVar ) then
			--Get the config variable table
			local varTable = MCom.getStringVar(reglist.configVar);
			--Only proceed if the config variable is a table
			if ( type(varTable) == "table" ) then
				
				
				--Get the realm and character name
				local realm = reglist.realm;
				if (not realm) then
					realm = GetCVar("RealmName");
				end
				local character = reglist.character;
				if (not character) then
					character = UnitName("player")
				end
				
				--Setup the variable to load data from
				local storeVar = MCom.getStringVar(reglist.exactVar);
				--If we don't have an exactVar and we have the server and character name then generate the storeVar
				if ( (not storeVar) and realm and character and ( ( character ~= UKNOWNBEING ) and ( character ~= UNKNOWNOBJECT ) ) ) then
					--Get the storage var if one was passed
					storeVar = MCom.getStringVar(reglist.storeVar);
					if (not storeVar) then
						--If the MComStorage variable isn't there yet, or isn't a table, then set it as an empty table
						if (type(varTable.MComStorage) ~= "table") then
							varTable.MComStorage = {};
						end
						storeVar = varTable.MComStorage;
					end
					
					--If this realm doesn't exist, then create it
					if (not storeVar[realm]) then
						storeVar[realm] = {};
					end
					--If this character doesn't exist, then create it
					if (not storeVar[realm][character]) then
						storeVar[realm][character] = {};
					end
					--Set storeVar to use the current realm/char
					storeVar = storeVar[realm][character];
				end
				
				--If we have the variable to load from, then we are good to go
				if (storeVar) then
					--Go through all the variables in the table
					for curVar in storeVar do
						--This will become true if we shouldn't load this variable
						local doIgnore = false;
						
						--If we have a list of vars to load, then go through them, and if this var is not in there, then ignore it
						if (reglist.loadList) then
							--Default to ignoring now
							doIgnore = true;
							--Make sure the loadList is a table
							if (type(reglist.loadList) ~= "table") then
								reglist.loadList = { reglist.loadList };
							end
							--Go through the list and see if we find the variable, if we do, then we don't ignore it
							for i, curLoadCheck in reglist.loadList do
								if (curVar == curLoadCheck) then
									doIgnore = false;
									break;
								end
							end
						end
						
						--If we are supposed to ignore this guy, then do so now
						if (not doIgnore) then
							--If we have a list of vars to ignore, then go through them, and if this var is in there, then ignore it
							if (reglist.ignoreList) then
								--Make sure the ignoreList is a table
								if (type(reglist.ignoreList) ~= "table") then
									reglist.ignoreList = { reglist.ignoreList };
								end
								--Go through the list and see if we find the variable, if we do, then ignore it
								for i, curIgnoreCheck in reglist.ignoreList do
									if (curVar == curIgnoreCheck) then
										doIgnore = true;
										break;
									end
								end
							end
							
							--If we are supposed to ignore this guy, then do so now
							if (not doIgnore) then
								if (reglist.nonUIList) then
									--Since these are UI vars, then we should only be ignoring them if the UI is around
									if ( MCom.hasUI() ) then
										--Unless we find this in the list, we should be ignoring it
										doIgnore = true;
										--Make sure the nonUIList is a table
										if (type(reglist.nonUIList) ~= "table") then
											nonUIList = { reglist.nonUIList };
										end
										--Go through the list and see if we find the variable, if we do, then don't ignore it
										for i, curUICheck in reglist.nonUIList do
											if (curVar == curUICheck) then
												doIgnore = false;
												break;
											end
										end
									end
								else
									if (reglist.uiList) then
										--Since these are UI vars, then we should only be ignoring them if the UI is around
										if ( MCom.hasUI() ) then
											--Make sure the uiList is a table
											if (type(reglist.uiList) ~= "table") then
												uiList = { reglist.uiList };
											end
											--Go through the list and see if we find the variable, if we do, then ignore it
											for i, curUICheck in reglist.uiList do
												if (curVar == curUICheck) then
													doIgnore = true;
													break;
												end
											end
										end
									end
								end
									
								--If we are supposed to ignore this guy, then do so now
								if (not doIgnore) then
									--Load the variable
									varTable[curVar] = storeVar[curVar];
									--Set that we loaded data
									didLoad = true;
								end
							end
						end
					end
					
					--If a forced list has been passed, then go through it
					if (reglist.forceList) then
						--Make sure it is a table
						if ( type(reglist.forceList) ~= "table" ) then
							reglist.forceList = { reglist.forceList };
						end
						--Go through all the variables in the table
						for i, curVar in reglist.forceList do
							--This will become true if we shouldn't load this variable
							local doIgnore = false;
							
							--If we have a list of vars to load, then go through them, and if this var is not in there, then ignore it
							if (reglist.loadList) then
								--Default to ignoring now
								doIgnore = true;
								--Make sure the loadList is a table
								if (type(reglist.loadList) ~= "table") then
									reglist.loadList = { reglist.loadList };
								end
								--Go through the list and see if we find the variable, if we do, then we don't ignore it
								for i, curLoadCheck in reglist.loadList do
									if (curVar == curLoadCheck) then
										doIgnore = false;
										break;
									end
								end
							end
							
							--If we are supposed to ignore this guy, then do so now
							if (not doIgnore) then
								--If we have a list of vars to ignore, then go through them, and if this var is in there, then ignore it
								if (reglist.ignoreList) then
									--Make sure the ignoreList is a table
									if (type(reglist.ignoreList) ~= "table") then
										reglist.ignoreList = { reglist.ignoreList };
									end
									--Go through the list and see if we find the variable, if we do, then ignore it
									for i, curIgnoreCheck in reglist.ignoreList do
										if (curVar == curIgnoreCheck) then
											doIgnore = true;
											break;
										end
									end
								end
								
								--If we are supposed to ignore this guy, then do so now
								if (not doIgnore) then
									if (reglist.nonUIList) then
										--Since these are UI vars, then we should only be ignoring them if the UI is around
										if ( MCom.hasUI() ) then
											--Unless we find this in the list, we should be ignoring it
											doIgnore = true;
											--Make sure the nonUIList is a table
											if (type(reglist.nonUIList) ~= "table") then
												nonUIList = { reglist.nonUIList };
											end
											--Go through the list and see if we find the variable, if we do, then don't ignore it
											for i, curUICheck in reglist.nonUIList do
												if (curVar == curUICheck) then
													doIgnore = false;
													break;
												end
											end
										end
									else
										if (reglist.uiList) then
											--Since these are UI vars, then we should only be ignoring them if the UI is around
											if ( MCom.hasUI() ) then
												--Make sure the uiList is a table
												if (type(reglist.uiList) ~= "table") then
													uiList = { reglist.uiList };
												end
												--Go through the list and see if we find the variable, if we do, then ignore it
												for i, curUICheck in reglist.uiList do
													if (curVar == curUICheck) then
														doIgnore = true;
														break;
													end
												end
											end
										end
									end
										
									--If we are supposed to ignore this guy, then do so now
									if (not doIgnore) then
										--Load the variable
										varTable[curVar] = storeVar[curVar];
										--Set that we loaded data
										didLoad = true;
									end
								end
							end
						end
					end
				end
			end
		end
		--Return if we loaded data or not
		return didLoad;
	end;

	--[[
	 	safeLoad ( configVar )
	 		Used to ensure that when variables are loaded into a table based variable, that none of the defaults
	 		are niled out.
	 		Call this after you have setup the defaults for your table, but before VARIABLES_LOADED occurs.
	 		When the variables are loaded, anything that is missing will be filled in with the defaults.

	 	Args:
 			Required:
 				(string) configVar -	The name of the config variable, this should have been registered for save by you, and must be a table with a simple
 															variable name.  IE no .'s or []'s
	]]--
	MCom.safeLoad = function ( configVar )
		if (not MCom.didVarsLoaded) then
			--Get the actual config table
			local varTable = MCom.getStringVar(configVar);
			if ( type(varTable) == "table" ) then
				--If we don't have a table of safe loads yet, then make one
				if (not MCom.safeLoads) then
					MCom.safeLoads = {};
				end
				if (not MCom.safeLoads.addonLoaded) then
					MCom.safeLoads.addonLoaded = {};
				end
				if (not MCom.safeLoads.varsLoaded) then
					MCom.safeLoads.varsLoaded = {};
				end

				--Store this config for loading later
				MCom.safeLoads.addonLoaded[configVar] = varTable;

				--Hook for the VARIABLES_LOADED event
				if (not MCom.HookedOnEvent) then
					MCom.HookedOnEvent = true;
					MCom.util.hook("UIParent_OnEvent", "MCom.UIParent_OnEvent", "after");
				end
				--Hook for the ADDON_LOADED event
				if (not MCom.RegisteredAddonLoaded) then
					UIParent:RegisterEvent("ADDON_LOADED");
				end
			end
		end
	end;

	--[[
	 	varsLoaded
	 		This will simply check to see if the variables needed to be able to use MCom.loadConfig have been loaded.
	 		To use this properly you must have an OnEvent function.  You must have registered for the "UNIT_NAME_UPDATE"
	 		event.  In your OnEvent handler you need to check if that event has occured, and if it has if the arg1 is player.
	 		You should also have a variable that keeps up with whether or not you have loaded your config, and only try to
	 		do so if it hasn't loaded.
	 		
	 		Ex	(somewhere in the OnLoad handler) this will either register with the UI to call ModName.LoadConfig when
	 				they load their configuration, or it will register a "UNIT_NAME_UPDATE" event for you:
	 		MCom.registerForLoad(ModName.LoadConfig);
	 		
	 		Ex	(somewhere in the OnEvent handler) this will handle waiting till the right vars are loaded before calling
	 				the config, when there is no UI around:
	 		if (( event == "UNIT_NAME_UPDATE" ) and (arg1 == "player") and (not ModName.VarsLoaded)) then
				if ( MCom.varsLoaded() ) then
					ModName.VarsLoaded = true;
					ModName.LoadConfig();
				end
			end
			
			NOTE: Make sure you're LoadConfig function only loads the config once, as some UIs might call the function more
						than once.
		
		Returns:
			true - the variables needed to load the config are present and proper
			false - the variables needed to load the config are not present or not proper
		 	
	]]--
	MCom.varsLoaded = function ()
		--Get the realm and character names
		local realm = GetCVar("RealmName");
		local character = UnitName("player");
		--If we have the needed data, in proper format, then return true, otherwise return false
		if ( realm and character and ( character ~= UKNOWNBEING ) and ( character ~= UNKNOWNOBJECT ) ) then
			return true;
		end
		return false;
	end;
	
	--[[
	 	registerVarsLoaded ( function callback )
	 		This will call the passed function back when the variables have been loaded by the game, or the
	 		UI.  This would be an optimal time to load 
		
		Args:
			callback( vltype ) - the function to be called when the variables have been loaded
				Args:
					(string) vltype - indicates what kind of load has occured, "UIParent" for normal, "Khaos", or "Cosmos"
	]]--
	MCom.registerVarsLoaded = function ( callback )
		--Add this callback to the list
		if (not MCom.varsLoadedList) then
			MCom.varsLoadedList = {};
		end
		table.insert(MCom.varsLoadedList, callback);

		--Only register for the load notice once
		if (not MCom.LoadNoticeRegistered) then
			MCom.LoadNoticeRegistered = true;
			--Try to register with Khaos
			if (Khaos) then
				Khaos.registerConfigurationLoadNotice( { onConfigurationChange = MCom.VariablesLoaded; id = "MCom"; description = "Handles all MCom registered load notices"; } );
			elseif (Cosmos_RegisterVarsLoaded) then
				--Try to register with Cosmos
				Cosmos_RegisterVarsLoaded( MCom.VariablesLoaded );
			else
				--Hook the event function of UIParent so we know when VARS_LOADED occurs
				if (not MCom.HookedOnEvent) then
					MCom.HookedOnEvent = true;
					MCom.util.hook("UIParent_OnEvent", "MCom.UIParent_OnEvent", "after");
				end
				MCom.UseVarsLoadedEvent = true;
			end
		end
	end;
	
	--[[
	 	DEPRICATED!  For Backward compatability only.
	 	USE MCom.registerVarsLoaded
	]]--
	MCom.registerForLoad = function ( callback )
		--Try to register with Khaos
		if (Khaos and this:GetName()) then
			Khaos.registerConfigurationLoadNotice( { onConfigurationChange = callback; id = this:GetName(); description = ""; } );
		elseif (Cosmos_RegisterVarsLoaded) then
			--Try to register with Cosmos
			Cosmos_RegisterVarsLoaded( callback );
		else
			--No UI around, so we register the event
			this:RegisterEvent( "UNIT_NAME_UPDATE" );
		end
		return false;
	end;

	--[[
	 	addSlashCom ( [string/{string, ...}] command, function comfunc, string comaction, bool comsticky, string comhelp, string comtype, string uisec, string uivar, string comvar, string comvarmulti, number commin, number commax, number commul, number cominmul, bool hasbool, {string = string, ...} choices, bool multichoice, bool hasopacity, {string, ...} extrahelp )
		 	Registers a standard slash command.  This will register with Sky, if it exists.
		 	addSlashCom makes its own chat handler function.  The function expects a particular kind of input, specified by comtype.
		 	
		 	For boolean input, it will require that the user pass on, off, 1, or 0, to consider the command valid. It will then call
		 	the function you pass, and will pass a 1, 0, or a -1, standing for True, False, and no input(I suggest you make it invert
		 	the current value in this case).  If Cosmos is loaded, and you have passed uivar and comvar, it will update the cosmos
		 	variable after the function has completed.
		 	
		 	If the slash command is already registered with MCom, nothing will happen.
		
		Args:
		 	command -	The slash command(s) you want to register. Ex: "/command". This can be a string or a table of strings if you
		 						want more than one command.
		 	comfunc -	The function that the should be called when the slash command is used, and valid.  If the function returns a value
		 						that value will be used to update a cosmos variable, if uivar has been passed.  You don't have to return a value
		 						to do this, but if you don't then you need to use comvar, and comvarmulti(for multi type).  For multi type it
		 						should return the bool then the value, like so: "return enabled, value;"
		 						BOOL - function (bool enabled)
		 						NUMBER - function (number value)
		 						MULTI - function (bool enabled, number value)
		 						STRING - function (string value)
		 						SIMPLE - function ()
	
		Optional: 
		 	comaction -	The action to perform, see Sky documentation for further details
		 	comsticky -	Whether the command is sticky or not(1 or 0), see Sky documentation for further details
		 	comhelp -	What message to display as help in Sky for this command, see Sky documentation for further details
		 	comtype -	the type of data you are expecting from this slash command
		 						MCOM_BOOLT - Expects boolean data, an on, off, 1, or 0
		 						MCOM_NUMT - Expects a number value
		 						MCOM_MULTIT - Expects a boolean and then a number value, Ex: "/command on 3"
		 						MCOM_STRINGT - Expects any string
		 						MCOM_SIMPLET - No input needed, just calls the function
		 	commin - the minimum value the number variable can be set to, for help display only
		 	commax - the maximum value the number variable can be set to, for help display only
		 	commul - the value to multiply the number by when showing it's status
		 	cominmul - A value to multiply the number passed in by the user(for number types only)
		 	hasbool - If this option has a boolean part, set this to true
		 	multichoice - Set this true if this is a choice type and can have multiple choices selected
		 	hasopacity - Set this true if this is a color type that should also have an opacity setting
		 	extrahelp - A table of extra help messages to display, each line is printed on a seperate line
		 	
		These are required if you want to update a Cosmos or Khaos variable:
		 	uivar -	The Cosmos variable that should be updated, if you want this slash command to update a cosmos variable
		These are required if you want to update a Cosmos or Khaos variable, and your function doesn't return the updated value:
		 	comvar -	The variable that the cosmos variable should be set by, if you want this slash command to update a cosmos variable
		 						This should be a string containing the name of the variable to update, this can include .'s for tables, Ex: "Something.Value"
		 						When type is MULTI, this specifies the bool variable
		 	comvarmulti - The same as comvar, but used to specify the number variable when type is MULTI, only used for MULTI type
		 	
		This is required if you want to update a Khaos variable:
			uisec - The option set ID that the uivar is found in
			
		This is required is you are using a MCOM_CHOICET type:
			choices - The list of choices
	]]--
	MCom.addSlashCom = function (command, comfunc, comaction, comsticky, comhelp, comtype, uisec, uivar, comvar, comvarmulti, commin, commax, commul, cominmul, hasbool, choices, multichoice, hasopacity, extrahelp)
		--We need at bare minimum command, and comfunc
		if (command and comfunc) then
			--If we dont have our chat command list yet, make one
			if (not MCom.SlashComs) then
				MCom.SlashComs = {};
			end
			--make sure command is a table
			if (type(command) ~= "table") then
				command = {command};
			end

			--If the command is not in the list yet, then add it
			if (not MCom.getComID(command)) then
				table.insert(MCom.SlashComs, {});
				local commandid = getn(MCom.SlashComs);

				--Set the commands various elements
				MCom.SlashComs[commandid].basecommand = command;
				MCom.SlashComs[commandid].comfunc = comfunc;
				if (comtype) then
					MCom.SlashComs[commandid].comtype = comtype;
				elseif (MCom.SlashComs[commandid].comtype == nil) then
					--Default to simple type
					MCom.SlashComs[commandid].comtype = MCOM_SIMPLET;
				end
				if (uisec) then
					MCom.SlashComs[commandid].uisec = uisec;
				end
				if (uivar) then
					MCom.SlashComs[commandid].uivar = uivar;
				end
				if (comvar) then
					MCom.SlashComs[commandid].comvar = comvar;
				end
				if (comvarmulti) then
					MCom.SlashComs[commandid].comvarmulti = comvarmulti;
				end
				if (commim) then
					MCom.SlashComs[commandid].commin = commin;
				end
				if (commax) then
					MCom.SlashComs[commandid].commax = commax;
				end
				if (commul) then
					MCom.SlashComs[commandid].commul = commul;
				end
				if (cominmul) then
					MCom.SlashComs[commandid].cominmul = cominmul;
				end
				if (extrahelp) then
					MCom.SlashComs[commandid].extrahelp = extrahelp;
				end
				if (hasbool) then
					MCom.SlashComs[commandid].hasbool = hasbool;
				end
				if (choices) then
					MCom.SlashComs[commandid].choices = choices;
				end
				if (multichoice) then
					MCom.SlashComs[commandid].multichoice = multichoice;
				end
				if (hasopacity) then
					MCom.SlashComs[commandid].hasopacity = hasopacity;
				end
				
				--Register the command with Sky, or the default method
				if ( Sky ) then
					--Register the command with Sky
					Sky.registerSlashCommand(
						{
							id=string.upper(command[1]).."_COMMAND";
							commands = command;
							onExecute = function (msg) MCom.SlashCommandHandler(commandid, msg); end;
							action = comaction;
							sticky = comsticky;
							helpText = comhelp;
						}
					);
				else
					SlashCmdList[string.upper(string.sub(command[1], 2))] = function (msg) MCom.SlashCommandHandler(commandid, msg); end;
					for curCom = 1, getn(command) do
						setglobal("SLASH_"..string.upper(string.sub(command[1], 2))..curCom, command[curCom]);
					end
				end
			end
		end
	end;
	
	--[[
	 	addSlashSuperCom ( [string/{string, ...}] command, string comaction, number comsticky, string comhelp )
		 	This registers a slash command that will have sub commands in it.  See addSlashSubCom for more details on sub commands.
		 	
		 	If the slash command is already registered with MCom, nothing will happen.
		
		Args:
		 	command -	The slash command(s) you want to register. Ex: "/command". This can be a string or a table of strings if you
		 						want more than one command.
	
		Optional: 
		 	comaction -	The action to perform, see Sky documentation for further details
		 	comsticky -	Whether the command is sticky or not(1 or 0), see Sky documentation for further details
		 	comhelp -	What message to display as help in Sky for this command, see Sky documentation for further details
		 	extrahelp - A table of extra help messages to display, each line is printed on a seperate line
	]]--
	MCom.addSlashSuperCom = function (command, comaction, comsticky, comhelp, extrahelp)
		--We need at bare minimum command
		if (command) then
			--If we dont have our chat command list yet, make one
			if (not MCom.SlashComs) then
				MCom.SlashComs = {};
			end
			--make sure command is a table
			if (type(command) ~= "table") then
				command = {command};
			end
			
			--If the command is not in the list yet, then add it
			if (not MCom.getComID(command)) then
				table.insert(MCom.SlashComs, {});
				local commandid = getn(MCom.SlashComs);

				MCom.SlashComs[commandid].basecommand = command;
				if (extrahelp) then
					MCom.SlashComs[commandid].extrahelp = extrahelp;
				end
				
				--Register the command with Sky, or the default method
				if ( Sky ) then
					Sky.registerSlashCommand(
						{
							id=string.upper(command[1]).."_COMMAND";
							commands = command;
							onExecute = function (msg) MCom.SlashCommandHandler(commandid, msg); end;
							action = comaction;
							sticky = comsticky;
							helpText = comhelp;
						}
					);
				else
					SlashCmdList[string.upper(string.sub(command[1], 2))] = function (msg) MCom.SlashCommandHandler(commandid, msg); end;
					for curCom = 1, getn(command) do
						setglobal("SLASH_"..string.upper(string.sub(command[1], 2))..curCom, command[curCom]);
					end
				end
			end
		end
	end;
	
	--[[
	 	addSlashSubCom ( [string/{string, ...}] basecommand, [string/{string, ...}] subcommand, function comfunc, string comhelp, string comtype, string uisec, string uivar, string comvar, string comvarmulti, number commin, number commax, number commul, number cominmul, bool hasbool, {string = string, ...} choices, bool multichoice, bool hasopacity)
		 	This is like addSlashCom, but it registers a sub command to be used with a super command.
		 	A sub command is one that is entered after the super command is entered.
		 	Example:
		 	Normal command: "/modcommand on"
		 	Sub command, with super command of mod: "/mod command on"
		 	
		 	Using super and sub commands allows you to register only one actual real command, which helps to clean up the listing of slash
		 	commands, and helps to prevent using a slash command that may already be there.  It also makes it easier for the user to remember
		 	and use, as if the user simply types the super command by itself they will get a listing of all sub commands, and usage.
		 	
		 	If the slash command is already registered with MCom, nothing will happen.
		
		Args:
		 	basecommand -	The super command that this sub command goes with.  Can be a single command or a list of commands.
		 	subcommand -	The sub command(s) you want to register. Ex: "command". This can be a string or a table of strings if you
		 						want more than one command.
		 	comfunc -	The function that the should be called when the slash command is used, and valid.  If the function returns a value
		 						that value will be used to update a cosmos variable, if uivar has been passed.  You don't have to return a value
		 						to do this, but if you don't then you need to use comvar, and comvarmulti(for multi type).  For multi type it
		 						should return the bool then the value, like so: "return enabled, value;"
		 						BOOL - function (bool enabled)
		 						NUMBER - function (number value)
		 						MULTI - function (bool enabled, number value)
		 						STRING - function (string value)
		 						SIMPLE - function ()
	
		Optional: 
		 	comhelp -	What message to display next to the sub command when listing sub commands in the help output.
		 						NOTE: if this is an MCOM_CHOICET then if you put a %s in this string, it will be replaces with a list of
								the choices you passed.
		 	comtype -	the type of data you are expecting from this slash command
		 						MCOM_BOOLT - Expects boolean data, an on, off, 1, or 0
		 						MCOM_NUMT - Expects a number value
		 						MCOM_MULTIT - Expects a boolean and then a number value, Ex: "/command on 3"
		 						MCOM_STRINGT - Expects any string
		 						MCOM_SIMPLET - No input needed, just calls the function
		 	commin - the minimum value the number variable can be set to, for help display only
		 	commax - the maximum value the number variable can be set to, for help display only
		 	commul - the value to multiply the number by when showing it's status
		 	cominmul - A value to multiply the number passed in by the user(for number types only)
		 	hasbool - If this option has a boolean part, set this to true
		 	multichoice - Set this true if this is a choice type and can have multiple choices selected
		 	hasopacity - Set this true if this is a color type that should also have an opacity setting
		 	
		These are required if you want to update a Cosmos variable:
		 	uivar -	The Cosmos variable that should be updated, if you want this slash command to update a cosmos variable
		These are required if you want to update a Cosmos variable, and your function doesn't return the updated value:
		 	comvar -	The variable that the cosmos variable should be set by, if you want this slash command to update a cosmos variable
		 						This should be a string containing the name of the variable to update, this can include .'s for tables, Ex: "Something.Value"
		 						When type is MULTI, this specifies the bool variable
		 	comvarmulti - The same as comvar, but used to specify the number variable when type is MULTI, only used for MULTI type
		 	
		This is required if you want to update a Khaos variable:
			uisec - The option set ID that the uivar is found in
			
		This is required is you are using a MCOM_CHOICET type:
			choices - The list of choices
	]]--
	MCom.addSlashSubCom = function (basecommand, subcommand, comfunc, comhelp, comtype, uisec, uivar, comvar, comvarmulti, commin, commax, commul, cominmul, hasbool, choices, multichoice, hasopacity)
		--We need at bare minimum commandid, subcommand, and comfunc
		if (basecommand and subcommand and comfunc) then
			--If we don't have a chat com list, then we shouldn't do anything
			if (MCom.SlashComs) then
				--Make sure basecommand is a table
				if (type(basecommand) ~= "table") then
					basecommand = {basecommand};
				end
				
				--get the ID of the super command, if it is in the list
				local commandid = MCom.getComID(basecommand);		
				
				--no commandid means no nothing
				if (commandid) then
					--If this super command doesn't have a list of sub commands yet, then make one
					if (not MCom.SlashComs[commandid].commands) then
						MCom.SlashComs[commandid].commands = {};
					end
					
					--If the sub command isn't a table turn it to one
					if (type(subcommand) ~= "table") then
						subcommand = {subcommand};
					end
					
					--Try and find the subcommand in the list
					local monkey, subcommandid = MCom.getComID(commandid, subcommand);
					
					--Make sure this sub command doesn't already exist
					if (not subcommandid) then
						--Make the sub command
						table.insert(MCom.SlashComs[commandid].commands, {});
						subcommandid = getn(MCom.SlashComs[commandid].commands);
						
						--Setup the sub commands elements
						MCom.SlashComs[commandid].commands[subcommandid].command = subcommand;
						MCom.SlashComs[commandid].commands[subcommandid].comfunc = comfunc;
						if (comhelp) then
							MCom.SlashComs[commandid].commands[subcommandid].comhelp = comhelp;
						end
						if (comtype) then
							MCom.SlashComs[commandid].commands[subcommandid].comtype = comtype;
						elseif (MCom.SlashComs[commandid].commands[subcommandid].comtype == nil) then
							--Default to simple type
							MCom.SlashComs[commandid].commands[subcommandid].comtype = MCOM_SIMPLET;
						end
						if (uisec) then
							MCom.SlashComs[commandid].commands[subcommandid].uisec = uisec;
						end
						if (uivar) then
							MCom.SlashComs[commandid].commands[subcommandid].uivar = uivar;
						end
						if (comvar) then
							MCom.SlashComs[commandid].commands[subcommandid].comvar = comvar;
						end
						if (comvarmulti) then
							MCom.SlashComs[commandid].commands[subcommandid].comvarmulti = comvarmulti;
						end
						if (commin) then
							MCom.SlashComs[commandid].commands[subcommandid].commin = commin;
						end
						if (commax) then
							MCom.SlashComs[commandid].commands[subcommandid].commax = commax;
						end
						if (commul) then
							MCom.SlashComs[commandid].commands[subcommandid].commul = commul;
						end
						if (cominmul) then
							MCom.SlashComs[commandid].commands[subcommandid].cominmul = cominmul;
						end
						if (hasbool) then
							MCom.SlashComs[commandid].commands[subcommandid].hasbool = hasbool;
						end
						if (choices) then
							MCom.SlashComs[commandid].commands[subcommandid].choices = choices;
						end
						if (multichoice) then
							MCom.SlashComs[commandid].commands[subcommandid].multichoice = multichoice;
						end
						if (hasopacity) then
							MCom.SlashComs[commandid].commands[subcommandid].hasopacity = hasopacity;
						end
					end
				end				
			end
		end
	end;
	
	--[[
		callHook ( (string) hook, (any) a1..a20 )
			Calls the origional hooked function.

		Args:
			(string) hook - The name of the origional function to call
			(any) a1..a20 - Any variables that need to be passed to the function

		Returns:
			Whatever the passed function returns
	]]--
	MCom.callHook = function ( hook, a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20 )
		--Make sure we have a hook
		if ( hook ) then
			--If we can use Sea, then do so
			if ( Sea ) then
				if ( Sea.util and Sea.util.Hooks and Sea.util.Hooks[hook] and Sea.util.Hooks[hook].orig ) then
					return Sea.util.Hooks[hook].orig(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20);
				end
			elseif ( MCom.util.Hooks and MCom.util.Hooks[hook] and MCom.util.Hooks[hook].orig ) then
				--Use the MCom list if Sea isn't available
				return MCom.util.Hooks[hook].orig(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20);
			end
		end
	end;
	
	--[[
		textFrame ( { reglist } )
			Displays the passed text in a multipage scrollable frame.
			This will not be available if the ItemTextFrame has been opened by the game.
			
		Args:
	 		reglist -	Either a table with the options, or a string or list of strings to display as
	 							the text.
	 			{
	 			Required:
	 				(string or table) text -	The text you want to display, if this is a table, then each
	 																	numbered entry will be a page.
	 			
	 			Optional:
	 				(string) title -	The title to display at the top of the frame.
	 				(string) material -	The appearance to use for the frame, can be "Stone", "Parchment", "Marble", "Silver",
	 														or "Bronze", defaults to "Stone" font with a black background.
	 				(number) textscale -	What size to scale the text to, relative to normal (Ex. 1 is normal, 0.5 is half),
	 															defaults to 0.85
	 			}
	 	
	 	Returns:
	 		true - The text frame was displayed
	 		true - The text frame was not displayed
	]]--
	MCom.textFrame = function ( reglist )
		--We have to have a reglist
		if (reglist) then
			--We need to hook some of the functions of the ItemTextFrame so we can have it
			--behave properly for this usage.
			local TextFrame = "MComText";
			if ( not getglobal(TextFrame.."Frame") ) then
				TextFrame = "ItemText";
				if (not MCom.HasHookedText) then
					MCom.HasHookedText = true;
					MCom.util.hook("ItemTextNextPage", "MCom.ItemTextNextPage", "after");
					MCom.util.hook("ItemTextPrevPage", "MCom.ItemTextPrevPage", "after");
					MCom.util.hook("CloseItemText", "MCom.CloseItemText", "after");
					MCom.util.hook("ItemTextFrame_OnEvent", "MCom.ItemTextFrame_OnEvent", "before");
				end
			end

			--Only display the frame if it isn't already visible
			if ( (not MCom.NoTextAvail) and ( not getglobal(TextFrame.."Frame"):IsVisible() ) ) then
				--If this isn't a table, then turn it into one
				if ( type(reglist) ~= "table" ) then
					reglist = { text = { reglist }; };
				end
				--If this is a table of strings, then move the strings into text
				if ( ( not reglist.text ) and reglist[1] ) then
					reglist.text = {};
					for curPage = 1, table.getn(reglist) do
						reglist.text[curPage] = reglist[curPage];
						reglist[curPage] = nil;
					end
				end
				--If text isn't a table then make it one
				if ( type(reglist.text) ~= "table" ) then
					reglist.text = { reglist.text };
				end
				--Set the current text and page, to what was passed
				MCom.CurText = reglist.text;
				MCom.CurTextPage = 1;
				--If there was no title passed, set it as an empty string
				if (not reglist.title) then
					reglist.title = "";
				end
				--Got through all the pages and add some extra fluff new lines to let the user scroll down further
				for curPage in MCom.CurText do
					if (MCom.CurText[curPage]) then
						MCom.CurText[curPage] = MCom.CurText[curPage].."\n\n\n\n";
					end
				end
				--Set the title of the frame
				getglobal(TextFrame.."TitleText"):SetText(reglist.title);
				--Hide the scrollframe and status bar
				getglobal(TextFrame.."ScrollFrame"):Hide();
				getglobal(TextFrame.."StatusBar"):Hide();
				--Setup the look of the frame to the passed look
				local material = Stone;
				--Make sure the material is one of the available materials
				local textColor = {1,1,1};
				if ( reglist.material and MATERIAL_TEXT_COLOR_TABLE[reglist.material] ) then
					material = reglist.material;
					textColor = MATERIAL_TEXT_COLOR_TABLE[material];
				end
				getglobal(TextFrame.."PageText"):SetTextColor(textColor[1], textColor[2], textColor[3]);

				if (not material) then
					if (MComTextFrame) then
						MComTextTopLeft:Show();
						MComTextTop:Show();
						MComTextTopRight:Show();
						MComTextBotLeft:Show();
						MComTextBot:Show();
						MComTextBotRight:Show();
						MComItemTextTopLeft:Hide();
						MComItemTextTopRight:Hide();
						MComItemTextBotLeft:Hide();
						MComItemTextBotRight:Hide();
						getglobal(TextFrame.."MaterialTopLeft"):Hide();
						getglobal(TextFrame.."MaterialTopRight"):Hide();
						getglobal(TextFrame.."MaterialBotLeft"):Hide();
						getglobal(TextFrame.."MaterialBotRight"):Hide();
						MComSpellBookIcon:Hide();
						MComTextFrame:SetWidth(512);
						MComTextCloseButton:SetPoint("CENTER", MComTextFrame, "TOPRIGHT", -58, -19);
						MComTextScrollFrame:SetPoint("TOPRIGHT", MComTextFrame, "TOPRIGHT", -82, -58);
						MComTextScrollFrame:SetWidth(408);
						MComTextScrollFrame:SetHeight(406);
						MComTextScrollFrameMiddle:Show();
						MComTextTitleText:SetPoint("CENTER", MComTextFrame, "CENTER", -14, 230);
						MComTextCurrentPage:SetPoint("TOP", MComTextFrame, "TOP", -14, -34);
						MComTextNextPageButton:SetPoint("CENTER", MComTextFrame, "TOPRIGHT", -86, -32);
						MComTextPrevPageButton:SetPoint("CENTER", MComTextFrame, "TOPLEFT", 32, -32);
						MComTextPageText:SetWidth(400);
					else
						getglobal(TextFrame.."MaterialTopLeft"):SetVertexColor(0,0,0);
						getglobal(TextFrame.."MaterialTopRight"):SetVertexColor(0,0,0);
						getglobal(TextFrame.."MaterialBotLeft"):SetVertexColor(0,0,0);
						getglobal(TextFrame.."MaterialBotRight"):SetVertexColor(0,0,0);
					end
				else
					if (MComTextFrame) then
						MComTextTopLeft:Hide();
						MComTextTop:Hide();
						MComTextTopRight:Hide();
						MComTextBotLeft:Hide();
						MComTextBot:Hide();
						MComTextBotRight:Hide();
						MComItemTextTopLeft:Show();
						MComItemTextTopRight:Show();
						MComItemTextBotLeft:Show();
						MComItemTextBotRight:Show();
						MComSpellBookIcon:Show();
						MComTextFrame:SetWidth(384);
						MComTextCloseButton:SetPoint("CENTER", MComTextFrame, "TOPRIGHT", -45, -26);
						MComTextScrollFrame:SetPoint("TOPRIGHT", MComTextFrame, "TOPRIGHT", -66, -76);
						MComTextScrollFrame:SetWidth(280);
						MComTextScrollFrame:SetHeight(355);
						MComTextScrollFrameMiddle:Hide();
						MComTextTitleText:SetPoint("CENTER", MComTextFrame, "CENTER", 6, 230);
						MComTextCurrentPage:SetPoint("TOP", MComTextFrame, "TOP", 10, -50);
						MComTextNextPageButton:SetPoint("CENTER", MComTextFrame, "TOPRIGHT", -55, -56);
						MComTextPrevPageButton:SetPoint("CENTER", MComTextFrame, "TOPLEFT", 90, -56);
						MComTextPageText:SetWidth(270);
					end
					getglobal(TextFrame.."MaterialTopLeft"):SetVertexColor(1,1,1);
					getglobal(TextFrame.."MaterialTopRight"):SetVertexColor(1,1,1);
					getglobal(TextFrame.."MaterialBotLeft"):SetVertexColor(1,1,1);
					getglobal(TextFrame.."MaterialBotRight"):SetVertexColor(1,1,1);
				end

				--If the look is parchment, then hide the extra textures
				if ( material == "Parchment" ) then
					getglobal(TextFrame.."MaterialTopLeft"):Hide();
					getglobal(TextFrame.."MaterialTopRight"):Hide();
					getglobal(TextFrame.."MaterialBotLeft"):Hide();
					getglobal(TextFrame.."MaterialBotRight"):Hide();
				elseif (material) then
					getglobal(TextFrame.."MaterialTopLeft"):Show();
					getglobal(TextFrame.."MaterialTopRight"):Show();
					getglobal(TextFrame.."MaterialBotLeft"):Show();
					getglobal(TextFrame.."MaterialBotRight"):Show();
					getglobal(TextFrame.."MaterialTopLeft"):SetTexture("Interface\\ItemTextFrame\\ItemText-"..material.."-TopLeft");
					getglobal(TextFrame.."MaterialTopRight"):SetTexture("Interface\\ItemTextFrame\\ItemText-"..material.."-TopRight");
					getglobal(TextFrame.."MaterialBotLeft"):SetTexture("Interface\\ItemTextFrame\\ItemText-"..material.."-BotLeft");
					getglobal(TextFrame.."MaterialBotRight"):SetTexture("Interface\\ItemTextFrame\\ItemText-"..material.."-BotRight");
				end
				--Default the scrollbar positions for all pages to the top
				MCom.CurText.Scroll = {};
				for curPage in MCom.CurText do
					MCom.CurText.Scroll[curPage] = { Value = 0; };
				end
				
				--Resize the text
				if (not reglist.textscale) then
					reglist.textscale = 0.85;
					if (MComTextFrame) then
						reglist.textscale = 1;
					end
				end
				MCom.PageWidth = getglobal(TextFrame.."PageText"):GetWidth();
				MCom.PageScale = getglobal(TextFrame.."PageText"):GetScale();
				getglobal(TextFrame.."PageText"):SetWidth(MCom.PageWidth / reglist.textscale);
				getglobal(TextFrame.."PageText"):SetScale(MCom.PageScale * reglist.textscale);
				
				--Update it with the new text
				MCom.UpdateTextPage();
				--Show the frame
				getglobal(TextFrame.."Frame"):Show();
				return true;
			end
		end
		return false;
	end
	
	--------------------------------------------------
	--
	-- Private Library Functions
	--
	--------------------------------------------------
	--[[ Updates the text in the text frame ]]--
	MCom.UpdateTextPage = function ()
		--Only do this if CurText is a table
		if ( type(MCom.CurText) == "table" ) then
			local TextFrame = "MComText";
			if ( not getglobal(TextFrame.."Frame") ) then
				TextFrame = "ItemText";
			end
			--If there is more than one page then setup the frame for that
			if ( table.getn(MCom.CurText) > 1 ) then
				--Show the text that shows the current page number
				local pageText = string.format(MCOM_PAGE_TEXT, MCom.CurTextPage, table.getn(MCom.CurText));
				if (pageText) then
					getglobal(TextFrame.."CurrentPage"):SetText(pageText);
					getglobal(TextFrame.."CurrentPage"):Show();
				else
					getglobal(TextFrame.."CurrentPage"):Hide();
				end
				--If we have gone passed the first page, then enable the previous page button
				if ( MCom.CurTextPage > 1 ) then
					getglobal(TextFrame.."PrevPageButton"):Show();
				else
					getglobal(TextFrame.."PrevPageButton"):Hide();
				end
				--If we are not on the last page, then enable the next page button
				if ( MCom.CurTextPage < table.getn(MCom.CurText) ) then
					getglobal(TextFrame.."NextPageButton"):Show();
				else
					getglobal(TextFrame.."NextPageButton"):Hide();
				end
			else
				--There is only one page, so hide the page controls
				getglobal(TextFrame.."CurrentPage"):Hide();
				getglobal(TextFrame.."PrevPageButton"):Hide();
				getglobal(TextFrame.."NextPageButton"):Hide();
			end
			
			--Hide the scroll frame
			getglobal(TextFrame.."ScrollFrame"):Hide();
			--Set the text for this page
			getglobal(TextFrame.."PageText"):SetText(MCom.CurText[MCom.CurTextPage]);
			--Update the scrollframe and show if neccisary
			getglobal(TextFrame.."ScrollFrame"):UpdateScrollChildRect();
			getglobal(TextFrame.."ScrollFrame"):Show();
			--Reset the scroll bar position to the one stored for this page
			getglobal(TextFrame.."ScrollFrameScrollBar"):SetValue(MCom.CurText.Scroll[MCom.CurTextPage].Value);
		else
			MCom.CurText = nil;
		end
	end;

	--[[ Adds any entry missing in the toTable from the fromTable ]]--
	MCom.LoadSafeTable = function (toTable, fromTable)
		--Make sure we have tables to work with
		if ( ( type(toTable) == "table" ) and ( type(fromTable) == "table" ) ) then
			--Go through each entry in the from table
			for curEntry in fromTable do
				--If the from entry is a table, then we need to parse each of its entries
				if ( type( fromTable[curEntry] ) == "table" ) then
					--If the to table is not already a table, then turn it into one
					if ( type( toTable[curEntry] ) ~= "table" ) then
						toTable[curEntry] = {};
					end
					--Load the entries from the current from table entry into the current to table entry
					MCom.LoadSafeTable( toTable[curEntry], fromTable[curEntry] );
				elseif ( toTable[curEntry] == nil ) then
					--If this entry is not a table, and it is nil, then load from the from table
					toTable[curEntry] = fromTable[curEntry];
				end
			end
		end
	end;

	--[[ Calls all frames registered for variables loaded notification ]]--
	MCom.VariablesLoaded = function ()
		--Only proceed if we have a list of callbacks
		if ( type(MCom.varsLoadedList) == "table" ) then
			--Figure out what type of load notice was used
			local regType = "UIParent";
			if (Khaos) then
				regType = "Khaos";
			elseif (Cosmos_RegisterVarsLoaded) then
				regType = "Cosmos";
			end
			--Call all the callbacks, and pass the type of load notice
			for i = 1, table.getn(MCom.varsLoadedList) do
				if ( type(MCom.varsLoadedList[i]) == "function" ) then
					MCom.varsLoadedList[i](regType);
				end
			end
		end
	end;

	--[[ Parses a boolean command ]]--
	MCom.ParseBoolCommand = function (value)
		--If it's a boolean then treat it as one
		if (value) then
			value = string.upper(value);
			if ( string.find(value, string.upper(MCOM_CHAT_ON) ) ) then
				value = 1;
			else
				if ( string.find(value, string.upper(MCOM_CHAT_OFF) ) ) then
					value = 0;
				else
					if ( string.find(value, "1") ) then
						value = 1;
					else
						if ( string.find(value, "0") ) then
							value = 0;
						else									
							value = nil;
						end
					end
				end
			end
		else
			--If there was no data passed for this boolean, then send -1 to the functions
			value = -1;
		end
		
		return value;
	end;
	
	--[[ Parses a number command ]]--
	MCom.ParseNumCommand = function (cominmul, value)
		if (value) then
			--Get the valid decimal portion only
			local dump, dump1;
			dump, dump1, value = string.find(value, "(%d*%.*%d+)");
			--If we got a valid decimal, multiply it by cominmul
			if (value) then
				if (not cominmul) then
					cominmul = 1;
				end
				value = value * cominmul;
			end
		end
		
		return value;
	end;

	--[[ Parses a choice command ]]--
	MCom.ParseChoiceCommand = function (choices, multichoice, value)
		retVal = nil;
		name = nil;
		--Make sure we have the needed data
		if (choices and value) then
			--Split the list by spaces
			value = MCom.util.split(value, " ");
			--Make sure it is in table format
			if (type(value) ~= "table") then
				value = {value};
			end
			--Go through all passed choices, and keep any that are in the available list
			for choice in value do
				local curChoice = value[choice];
				--If this isn't a viable choice, then see if there is one with any capitalization
				if (not choices[curChoice]) then
					for curCheck in choices do
						if ( string.lower(curChoice) == string.lower( curCheck ) ) then
							curChoice = curCheck;
							break;
						end
					end
				end
				--Make sure we have a good choice
				if ( choices[curChoice] ) then
					--If it is multichoice, add it to the list
					if (multichoice) then
						if (retVal == nil) then
							retVal = {};
						end
						table.insert(retVal, choices[curChoice]);
						--Make a named list of the selected choices
						if (name) then
							name = name..", "..curChoice;
						else
							name = curChoice;
						end
					else
						--If it's single choice, then return it
						retVal = choices[curChoice];
						name = curChoice;
						break;
					end
				end
			end
		end
		
		return retVal, name;
	end;
	
	--[[ Parses a color command ]]--
	MCom.ParseColorCommand = function (hasopacity, value1, value2, value3, value4)
		local value = nil;
		local dump, dump1;
		--Make sure we have atleast the R the G and the B
		if (value1 and value2 and value3) then
			--Get valid decimals for all three values, and divide them to a percent format
			value = {};
			dump, dump1, value1 = string.find(value1, "(%d*%.*%d+)");
			if (value1) then
				value.r = value1/100;
			end
			dump, dump1, value2 = string.find(value2, "(%d*%.*%d+)");
			if (value1) then
				value.g = value2/100;
			end
			dump, dump1, value3 = string.find(value3, "(%d*%.*%d+)");
			if (value3) then
				value.b = value3/100;
			end
			if (hasopacity and value4) then
				--If we are supposed to have an opacity part then
				--Get a valid decimal for opacity, and divide it to a percent format
				dump, dump1, value3 = string.find(value4, "(%d*%.*%d+)");
				if (value4) then
					value.opacity = value4/100;
				end
			end
			--If we didn't have all three values, then return nil
			if ( not (value1 and value2 and value3) ) then
				value = nil;
			end
			--If we are supposed to have opacity, and it wasn't passed, then return nil
			if (hasopacity and (not value4) ) then
				value = nil;
			end
		end
		
		return value;
	end;

	--[[ The slash command handler used by MCom slash commands ]]--
	MCom.SlashCommandHandler = function (commandid, msg)
		--Only works if we have some registered slash commands
		if (MCom.SlashComs and MCom.SlashComs[commandid]) then
			--Get a shorthand for the current command
			curCommand = MCom.SlashComs[commandid];
			--Only proccess the message if there is one
			if ((msg and (msg ~= "")) or ((curCommand.comtype) and (curCommand.comtype == MCOM_BOOLT))) then
				local subcommand, value;
				local isSimple = true;	--Set true if the command is a standard, not super, slash command
				local comType = nil;		--Stores the type of command
				local badCommand = nil;	--Set true if the data for the command turns out bad
				
				if (not curCommand.commands) then
					--This is simple so unpack it to the values
					if (msg) then
						value = MCom.util.split(msg, " ");
					end
				else
					--This is a super command, so unpack the subcommand and values
					isSimple = nil;
					--Get the position of the subcommand, and the rest goes into msg2
					local first, last, msg2 = string.find(msg, " (.*)");
					--If we got the subcommand position then get that portion to the subcommand
					if (first) then
						subcommand = string.sub(msg, 1, first - 1);
					else
						--If we didn't find a position then we have only the subcommand
						subcommand = msg;
					end
					--Move the rest of the values into msg
					msg = msg2;
					--If we have values in msg, then parse them out
					if (msg) then
						value = MCom.util.split(msg, " ");
					end
					
					if (subcommand) then
						--Try and find an exact match of the subcommand in the list
						local subcommandid = nil;
						for curCom in MCom.SlashComs[commandid].commands do
							if (MCom.SlashComs[commandid].commands[curCom].command) then
								for curComCom in MCom.SlashComs[commandid].commands[curCom].command do
									if (MCom.SlashComs[commandid].commands[curCom].command[curComCom] == subcommand) then
										subcommandid = curCom;
										break;
									end
								end
								if (subcommandid) then
									break;
								end
							end
						end
						
						if (not subcommandid) then
							--Try and find a similar match of the subcommand in the list
							for curCom in MCom.SlashComs[commandid].commands do
								if (MCom.SlashComs[commandid].commands[curCom].command) then
									for curComCom in MCom.SlashComs[commandid].commands[curCom].command do
										if (string.find(MCom.SlashComs[commandid].commands[curCom].command[curComCom], subcommand)) then
											subcommandid = curCom;
											break;
										end
									end
									if (subcommandid) then
										break;
									end
								end
							end
						end
						
						if (not subcommandid) then
							--We didn't find the sub command, so we've got a bad command
							badCommand = true;
						else
							--We found the sub command so change curCommand to point at it
							curCommand = curCommand.commands[subcommandid];
						end
					else
						--No subcommand passed, so thats a bad command
						badCommand = true;
					end
				end
				--We only want to continue if the command was good
				if (not badCommand) then
					--Get the command type
					if (curCommand.comtype) then
						comType = curCommand.comtype;
					end
					
					local retVal, retVal2;

					if ( ( (comType == MCOM_BOOLT) or curCommand.hasbool ) and (value == nil) ) then
						--If nothing was passed and its a bool command then invert it
						curCommand.comfunc(-1);
					elseif ( (comType ~= MCOM_SIMPLET) ) then
						--If it's not a simply command parse the data if we have data
						if (value) then
							--Setup a list of variables to use for checking the passed data
							local checkVal = value[1];
							local checkVal2 = value[2];
							local checkVal3 = value[3];
							local checkVal4 = value[4];
							--This stores the boolean portion of the command, if it has two parts
							local boolVal = value;
							--This stores the display name for choice types
							local name = nil;
							if ( (comType == MCOM_MULTIT) or (curCommand.hasbool and (comType ~= MCOM_BOOLT)) ) then
								--Since the first value was the boolean, move the other values down in the list
								checkVal = value[2];
								checkVal2 = value[3];
								checkVal3 = value[4];
								checkVal4 = value[5];
								
								--Remove the boolean part of the message
								local dump1, dump2;
								dump1, dump2, msg = string.find(msg, " (.*)");
							end
							
							--If it is a multi part, or a boolean, then parse the first value as boolean
							if ( (comType == MCOM_BOOLT) or (comType == MCOM_MULTIT) or curCommand.hasbool ) then
								boolVal = MCom.ParseBoolCommand(value[1]);
								value = boolVal;
							end
							
							--Parse the value, or secondary as the appropriate type
							if ( (comType == MCOM_NUMT) or (comType == MCOM_MULTIT) ) then
								value = MCom.ParseNumCommand(curCommand.cominmul, checkVal);
							elseif (comType == MCOM_STRINGT) then
								--For string we pass the message so spaces can be included
								value = msg;
							elseif (comType == MCOM_CHOICET) then
								--For choice we pass the message so as many passed choices as are passed can be used on a multichoice
								value, name = MCom.ParseChoiceCommand(curCommand.choices, curCommand.multichoice, msg);
							elseif (comType == MCOM_COLORT) then
								value = MCom.ParseColorCommand(curCommand.hasopacity, checkVal, checkVal2, checkVal3, checkVal4);
							end
							
							if ( (comType == MCOM_MULTIT) or (curCommand.hasbool and (comType ~= MCOM_BOOLT)) ) then
								--Handle the two part commands
								if (boolVal or value) then
									--Call the function
									retVal, retVal2 = curCommand.comfunc(boolVal, value, name);
								else
									--We got bad data
									badCommand = true;
								end
							else
								--Handle the one part commands
								if (value) then
									--Call the function
									retVal = curCommand.comfunc(value, name);
								else
									--We got bad data
									badCommand = true;
								end
							end
						else
							badCommand = true;
						end
					else
						--It's a simple type, so just call it and quit
						curCommand.comfunc();
						return;
					end

					if (not badCommand) then
						--If Khaos is around, then we update the variable with it, if possible
						if (Khaos and (curCommand.comvar or retVal) and curCommand.uivar and curCommand.uisec) then
							--Make sure the passed set exists
							if ( KhaosData.configurationSets and (KhaosData.configurationSets[curCommand.uisec]) ) then
								--get the value of the variable
								local newVal = MCom.getStringVar(curCommand.comvar);
								--If a value was returned from the setter function, then use it
								if (retVal) then
									newVal = retVal;
								end
								if (newVal) then
									--Get the second part variable if there is one
									local newValMulti = MCom.getStringVar(curCommand.comvarmulti);
									--If a value was returned from the setter function from the second part, then use it
									if (retVal2) then
										newValMulti = retVal2;
									end
									
									--Default param type is value
									local param = "value";
									--If we have a boolean type, or boolean portion, then update that
									if ( (comType == MCOM_BOOLT) or (comType == MCOM_MULTIT) or curCommand.hasbool) then
										--Make sure its in true/false format
										if (newVal == 1) then
											newVal = true;
										else
											newVal = false;
										end
										--Update the boolean variable
										Khaos.setSetKeyParameter(curCommand.uisec, curCommand.uivar, "checked", newVal);
									end
									--If it isn't a boolean type, then update the other types, or secondary variable
									if ( comType ~= MCOM_BOOLT ) then
										--If we have a secondary variable, then switch to using it
										if (newValMulti) then
											newVal = newValMulti;
										end
										
										--Treat number types as sliders
										if ( (comType == MCOM_NUMT) or (comType == MCOM_MULTIT) ) then
											param = "slider";
										end
										
										--Treat color types as color pickers
										if (comType == MCOM_COLORT) then
											param = "color";
										end
									
										--Update the variable
										Khaos.setSetKeyParameter(curCommand.uisec, curCommand.uivar, param, newVal);
									end
								end
							end
						else
							if(CosmosMaster_Init and (curCommand.comvar or retVal) and curCommand.uivar) then
								--get the value of the variable
								local newVal = MCom.getStringVar(curCommand.comvar);
								if (retVal) then
									newVal = retVal;
								end
								if (newVal) then
									local newValMulti = MCom.getStringVar(curCommand.comvarmulti);
									if (retVal2) then
										newValMulti = retVal2;
									end
									if (((comType ~= MCOM_MULTIT) and (not ((comType ~= MCOM_BOOLT) and curCommand.hasbool))) or (((comType == MCOM_MULTIT) or ((comType ~= MCOM_BOOLT) and curCommand.hasbool)) and newValMulti)) then
										--if its a boolean, then set the checkbox
										if ((comType == MCOM_BOOLT) or (comType == MCOM_MULTIT)) then
											Cosmos_UpdateValue(curCommand.uivar, CSM_CHECKONOFF, newVal);
										end
										--if its a number, then set the slider
										if ((comType == MCOM_NUMT) or (comType == MCOM_MULTIT)) then
											if (comType == MCOM_MULTIT) then
												newVal = newValMulti;
											end
											Cosmos_UpdateValue(curCommand.uivar, CSM_SLIDERVALUE, newVal);
										end
									end
								end
							end
						end
						return;
					end
				end
			elseif ((curCommand.comtype) and (curCommand.comtype == MCOM_SIMPLET)) then
				--If the command is a standard simple command, then just execute it
				curCommand.comfunc();
				return;
			end
			
			--If we didn't find any valid commands we print out the help
			local infoText = MCom.PrintSlashCommandInfo(commandid, true);
			MCom.textFrame( { text = infoText; title = MCOM_HELP_GENERIC_TITLE; } );
		end
	end;

	--[[ Either prints out, or adds to a string the current chat line ]]--
	MCom.PrintSlashCommandLine = function ( asString, chatLine, extraLine )
		--If it's supposed to be in a string then add this to the string
		if ( asString ) then
			--If it isn't a string yet, then just set it to this line
			if ( type(asString) ~= "string" ) then
				asString = chatLine;
			else
				--It's already a string so add a newline and then this line
				if (extraLine) then
					asString = asString.."\n\n"..chatLine
				else
					asString = asString.."\n"..chatLine
				end
			end
			--Return the string
			return asString;
		else
			--Print out the chat line
			MCom.IO.printc(ChatTypeInfo["SYSTEM"], chatLine);
		end
	end

	--[[ Prints the help for a chat command	]]--
	MCom.PrintSlashCommandInfo = function (commandid, asString)
		if (MCom.SlashComs[commandid]) then
			local chatLine = ""; --The current line of text to be printed
			local basecommand = MCom.SlashComs[commandid].basecommand[1];

			--Construct a list of the aliases for the command, if any
			local aliasList = "";
			if (getn(MCom.SlashComs[commandid].basecommand) > 1) then
				for curCom = 2, getn(MCom.SlashComs[commandid].basecommand) do
					if (aliasList ~= "") then
						aliasList = aliasList..", ";
					else
						aliasList = basecommand..", ";
					end
					aliasList = aliasList..MCom.SlashComs[commandid].basecommand[curCom];
				end
			end

			--Print list of aliases, if there are any
			if (aliasList ~= "") then
				chatLine = string.format(MCOM_CHAT_COM_ALIAS, aliasList);
				asString = MCom.PrintSlashCommandLine(asString, chatLine, true);
			end

			local isSimple = true;		--Set true if this command does not have sub commands
			local eSample = nil;			--Set to something if a simple command is found
			local bSample = nil;			--Set to something if a bool command is found
			local nSample = nil;			--Set to something if a num command is found
			local nSampleV = nil;			--Set to and example value for a number command
			local sSample = nil;			--Set to something if a string command is found
			local cSample = nil;			--Set to something if a choice command is found
			local cnSampleV = nil;		--Set to and example value for a choice command
			local cmSample = nil;			--Set to something if a multi choice command is found
			local cmnSampleV = nil;		--Set to and example value for a multi choice command
			local koSample = nil;			--Set to something if a color with opacity command is found
			local bnSample = nil;			--Set to something if a bool and num command is found
			local bnSampleV = nil;		--Set to and example value for a bool and number command
			local bsSample = nil;			--Set to something if a bool and string command is found
			local bcSample = nil;			--Set to something if a bool and choice command is found
			local bcnSampleV = nil;		--Set to and example value for a bool and choice command
			local bcmSample = nil;		--Set to something if a bool and multi choice command is found
			local bcmnSampleV = nil;	--Set to and example value for a bool and multi choice command
			local bkoSample = nil;		--Set to something if a bool and color with opacity command is found

			--If this command has sub commands, then print a list of them
			if (MCom.SlashComs[commandid].commands) then
				asString = MCom.PrintSlashCommandLine(asString, MCOM_CHAT_COM_COMMANDS, true);
				isSimple = nil;	--This is not a simple command, lets remember that
				for curCom = 1, getn(MCom.SlashComs[commandid].commands) do
					local curComType = MCOM_SIMPLET;	--Default our type to simple
					local curComBool = false;					--Default has bool to false
					local curComChoices = nil;				--The choices for a choice type
					local curComMulti = false;				--Default multi choice to false
					local curComOpacity = false;			--Default has opacity to false
					local curComValue = nil;					--The value of the variable associated with the command
					local curComValueMulti = nil;			--The value of the multi variable associated with the command
					local curComMin = nil;						--The minimum a value can be set to
					local curComMax = nil;						--The maximum a value can be set to
					local curComMul = 1;							--The value to multiply numbers by when showing status
					--If a type is specified look it up
					if (MCom.SlashComs[commandid].commands[curCom].comtype) then
						curComType = MCom.SlashComs[commandid].commands[curCom].comtype;
					end
					--If a hasbool is specified look it up
					if (MCom.SlashComs[commandid].commands[curCom].hasbool) then
						curComBool = true;
					end
					--If choices are specified look them up
					if (MCom.SlashComs[commandid].commands[curCom].choices) then
						curComChoices = MCom.SlashComs[commandid].commands[curCom].choices;
					end
					--If a multichoioce is specified look it up
					if (MCom.SlashComs[commandid].commands[curCom].multichoice) then
						curComMulti = true;
					end
					--If a hasopacity is specified look it up
					if (MCom.SlashComs[commandid].commands[curCom].hasopacity) then
						curComOpacity = MCom.SlashComs[commandid].commands[curCom].hasopacity;
					end
					--If a comvar is specified look it up
					if (MCom.SlashComs[commandid].commands[curCom].comvar ~= nil) then
						curComValue = MCom.getStringVar(MCom.SlashComs[commandid].commands[curCom].comvar);
					end
					--If a comvarmulti is specified look it up
					if (MCom.SlashComs[commandid].commands[curCom].comvarmulti ~= nil) then
						curComValueMulti = MCom.getStringVar(MCom.SlashComs[commandid].commands[curCom].comvarmulti);
					end
					--If a commin is specified look it up
					if (MCom.SlashComs[commandid].commands[curCom].commin ~= nil) then
						curComMin = MCom.SlashComs[commandid].commands[curCom].commin;
					end
					--If a commax is specified look it up
					if (MCom.SlashComs[commandid].commands[curCom].commax ~= nil) then
						curComMax = MCom.SlashComs[commandid].commands[curCom].commax;
					end
					--If a commul is specified look it up
					if (MCom.SlashComs[commandid].commands[curCom].commul ~= nil) then
						curComMul = MCom.SlashComs[commandid].commands[curCom].commul;
					end
					
					--Store this command as a sample of whatever type it is
					if ((not eSample) and (curComType == MCOM_SIMPLET)) then
						eSample = MCom.SlashComs[commandid].commands[curCom].command[1];
					end
					if ((not bSample) and (curComType == MCOM_BOOLT)) then
						bSample = MCom.SlashComs[commandid].commands[curCom].command[1];
					end
					if (not curComBool) then
						if ((not nSample) and (curComType == MCOM_NUMT)) then
							nSample = MCom.SlashComs[commandid].commands[curCom].command[1];
							--Get a valid sample number
							nSampleV = curComMin;
							if (not nSampleV) then
								nSampleV = curComMax;
							end
							if (not nSampleV) then
								nSampleV = MCOM_CHAT_COM_EXAMPLE_O_N;
							end
						end
						if ((not sSample) and (curComType == MCOM_STRINGT)) then
							sSample = MCom.SlashComs[commandid].commands[curCom].command[1];
						end
						if (not curComMulti) then
							if ((not cSample) and (curComType == MCOM_CHOICET)) then
								cSample = MCom.SlashComs[commandid].commands[curCom].command[1];
								--Get a valid sample choice
								for sampleV in curComChoices do
									cSampleV = sampleV;
									break;
								end
							end
						else
							if ((not cmSample) and (curComType == MCOM_CHOICET)) then
								cmSample = MCom.SlashComs[commandid].commands[curCom].command[1];
								--Get a valid sample choice
								local count = 0;
								--Construct an example with two valid choices
								for sampleV in curComChoices do
									count = count + 1;
									if (cmSampleV) then
										cmSampleV = cmSampleV.." "..sampleV;
									else
										cmSampleV = sampleV;
									end
									if (count > 1) then
										break;
									end
								end
							end
						end
						if (not curComOpacity) then
							if ((not kSample) and (curComType == MCOM_COLORT)) then
								kSample = MCom.SlashComs[commandid].commands[curCom].command[1];
							end
						else
							if ((not koSample) and (curComType == MCOM_COLORT)) then
								koSample = MCom.SlashComs[commandid].commands[curCom].command[1];
							end
						end
					else
						if ((not bnSample) and ((curComType == MCOM_NUMT) or (curComType == MCOM_MULTIT))) then
							bnSample = MCom.SlashComs[commandid].commands[curCom].command[1];
							--Get a valid sample number
							bnSampleV = curComMin;
							if (not bnSampleV) then
								bnSampleV = curComMax;
							end
							if (not bnSampleV) then
								bnSampleV = MCOM_CHAT_COM_EXAMPLE_O_N;
							end
						end
						if ((not bsSample) and (curComType == MCOM_STRINGT)) then
							bsSample = MCom.SlashComs[commandid].commands[curCom].command[1];
						end
						if (not curComMulti) then
							if ((not bcSample) and (curComType == MCOM_CHOICET)) then
								bcSample = MCom.SlashComs[commandid].commands[curCom].command[1];
								--Get a valid sample choice
								for sampleV in curComChoices do
									bcSampleV = sampleV;
									break;
								end
							end
						else
							if ((not bcmSample) and (curComType == MCOM_CHOICET)) then
								bcmSample = MCom.SlashComs[commandid].commands[curCom].command[1];
								--Get a valid sample choice
								local count = 0;
								--Construct an example with two valid choices
								for sampleV in curComChoices do
									count = count + 1;
									if (bcmSampleV) then
										bcmSampleV = bcmSampleV.." "..sampleV;
									else
										bcmSampleV = sampleV;
									end
									if (count > 1) then
										break;
									end
								end
							end
						end
						if (not curComOpacity) then
							if ((not bkSample) and (curComType == MCOM_COLORT)) then
								bkSample = MCom.SlashComs[commandid].commands[curCom].command[1];
							end
						else
							if ((not bkoSample) and (curComType == MCOM_COLORT)) then
								bkoSample = MCom.SlashComs[commandid].commands[curCom].command[1];
							end
						end
					end
					
					--If help was specified look it up
					local curHelp = MCOM_CHAT_COM_NOINFO;
					if (MCom.SlashComs[commandid].commands[curCom].comhelp) then
						curHelp = MCom.SlashComs[commandid].commands[curCom].comhelp;
					end
					--If we have a choice type, then make a list of the choices, and tack that onto the help
					if ( curComType == MCOM_CHOICET ) then
						if (curHelp == MCOM_CHAT_COM_NOINFO) then
							curHelp = MCOM_CHAT_COM_CLIST;
						end
						local curChoices = nil;
						for curChoice in curComChoices do
							if (curChoices) then
								curChoices = curChoices..", "..curChoice;
							else
								curChoices = curChoice;
							end
						end
						curHelp = string.format(curHelp, curChoices);
					end
					
					--If we have aliases for this sub command then make a list
					local comList = MCom.SlashComs[commandid].commands[curCom].command[1];
					if (getn(MCom.SlashComs[commandid].commands[curCom].command) > 1) then
						for curAlias = 2, getn(MCom.SlashComs[commandid].commands[curCom].command) do
							comList = comList.."/"..MCom.SlashComs[commandid].commands[curCom].command[curAlias];
						end
					end
		
					--Prepare the type string
					local curComTypeString = curComType;
					if ( curComType == MCOM_MULTIT ) then
						curComTypeString = MCOM_NUMT;
					end
					if ( curComMulti and (curComType == MCOM_CHOICET) ) then
						curComTypeString = MCOM_CHAT_C_M;
					end
					if ( curComOpacity and (curComType == MCOM_COLORT) ) then
						curComTypeString = MCOM_CHAT_K_O;
					end
					if ( curComBool and (not (curComType == MCOM_BOOLT) ) ) then
						curComTypeString = MCOM_BOOLT..curComTypeString;
					end
					--If we have a number type, then display the min and max values
					if ( ( curComType == MCOM_NUMT ) or ( curComType == MCOM_MULTIT ) ) then
						local curRangeString = nil;
						if (curComMin) then
							curRangeString = string.format(MCOM_CHAT_COM_N_MIN, curComMin * curComMul);
						end
						if (curComMax) then
							if (curRangeString) then
								curRangeString = curRangeString..", ";
							else
								curRangeString = "";
							end
							curRangeString = curRangeString..string.format(MCOM_CHAT_COM_N_MAX, curComMax * curComMul);
						end
						if (curRangeString) then
							curComTypeString = curComTypeString..string.format(MCOM_CHAT_COM_N_RANGE, curRangeString);
						end
					end

					--Prepare the command info
					local curValString = nil;
					if ( ( curComType == MCOM_SIMPLET ) or ( curComValue == nil ) ) then
						chatLine = string.format(MCOM_CHAT_COM_SUBCOMMAND_S, comList, curComTypeString, curHelp);
					elseif ( curComValue ~= nil ) then
						--If it is a bool, or has a bool, then get the boolean part
						if ( curComBool or ( curComType == MCOM_BOOLT ) ) then
							if ( curComValue == 1 ) then
								curValString = MCOM_CHAT_ON;
							else
								curValString = MCOM_CHAT_OFF;
							end
						end
						--If this doesn't have a boolean part, then handle curcomvalue
						if (not curComBool) then
							--Handle number type
							if ( ( curComType == MCOM_NUMT ) or ( curComType == MCOM_MULTIT ) ) then
								curValString = ( MCom.math.round( ( curComValue * curComMul ) * 100 ) / 100 );
							end
							--Handle string type
							if ( curComType == MCOM_STRINGT ) then
								curValString = curComValue;
							end
							--If it's a choice type, then handle the one choice, or a list of choices
							if (curComType == MCOM_CHOICET) then
								--If we don't have a table of choices, then just use the values
								if ( type(curComChoices) ~= "table" ) then
									--If this can not have multiple choices, then use just the one
									if (not curComMulti) then
										curValString = curComValue;
									elseif ( type(curComValue) == "table" ) then
										--This is a multi choice selection, so make a list of selected choices
										curValString = curComValue[1];
										if ( curValString ~= nil ) then
											for curVal = 2, table.getn(curComValue) do
												if ( curComValue[curVal] ~= nil ) then
													curValString = curValString..", "..curComValue[curVal];
												end
											end
										end
									end
								else
									--If we have a table of choices, then make a table indexed by value
									local curChoiceDex = {};
									for curChoice in curComChoices do
										curChoiceDex[curComChoices[curChoice]] = curChoice;
									end
									--If this can not have multiple choices, then use just the one
									if (not curComMulti) then
										curValString = curChoiceDex[curComValue];
									elseif ( type(curComValue) == "table" ) then
										--This is a multi choice selection, so make a list of selected choices
										curValString = curChoiceDex[curComValue[1]];
										if ( curValString ~= nil ) then
											for curVal = 2, table.getn(curComValue) do
												if ( ( curComValue[curVal] ~= nil ) and ( curChoiceDex[curComValue[curVal]] ~= nil ) ) then
													curValString = curValString..", "..curChoiceDex[curComValue[curVal]];
												end
											end
										end
									end
								end
							end
							--If it's a color type, then handle the color parts
							if (curComType == MCOM_COLORT) then
								if ( type(curComValue) == "table" ) then
									local curColString = "";
									if (curComValue.r) then
										curColString = string.format(MCOM_CHAT_COM_K_R, MCom.math.round(curComValue.r * 100));
									end
									if (curComValue.g) then
										if ( curColString ~= "" ) then
											curColString = curColString..", ";
										end
										curColString = curColString..string.format(MCOM_CHAT_COM_K_G, MCom.math.round(curComValue.g * 100));
									end
									if (curComValue.b) then
										if ( curColString ~= "" ) then
											curColString = curColString..", ";
										end
										curColString = curColString..string.format(MCOM_CHAT_COM_K_B, MCom.math.round(curComValue.b * 100));
									end
									if (curComOpacity) then
										local displayOpacity = 1;
										if (curComValue.opacity) then
											displayOpacity = curComValue.opacity;
										end
										if ( curColString ~= "" ) then
											curColString = curColString..", ";
										end
										curColString = curColString..string.format(MCOM_CHAT_COM_K_O, MCom.math.round(displayOpacity * 100));
									end
									if ( curColString ~= "" ) then
										curColString = curColString..", ";
									end
									curColString = curColString..string.format(MCOM_CHAT_COM_K_X, MCom.string.colorToString(curComValue));
									curValString = curColString;
								end
							end
						elseif ( curComValueMulti ~= nil ) then
							--If we have a second variable, then prepare the second part of the string
							if ( curValString == nil ) then
								curValString = "";
							else
								curValString = curValString..", ";
							end
							--Handle number type
							if ( ( curComType == MCOM_NUMT ) or ( curComType == MCOM_MULTIT ) ) then
								curValString = curValString..( MCom.math.round( ( curComValueMulti * curComMul ) * 100 ) / 100 );
							end
							--Handle string type
							if ( curComType == MCOM_STRINGT ) then
								curValString = curValString..curComValueMulti;
							end
							--If it's a choice type, then handle the one choice, or a list of choices
							if (curComType == MCOM_CHOICET) then
								--If we don't have a table of choices, then just use the values
								if ( type(curComChoices) ~= "table" ) then
									--If this can not have multiple choices, then use just the one
									if (not curComMulti) then
										curValString = curValString..curComValueMulti;
									elseif ( type(curComValueMulti) == "table" ) then
										--This is a multi choice selection, so make a list of selected choices
										curValString = curValString..curComValueMulti[1];
										if ( curComValueMulti[1] ~= nil ) then
											for curVal = 2, table.getn(curComValueMulti) do
												if ( curComValueMulti[curVal] ~= nil ) then
													curValString = curValString..", "..curComValueMulti[curVal];
												end
											end
										end
									end
								else
									--If we have a table of choices, then make a table indexed by value
									local curChoiceDex = {};
									for curChoice in curComChoices do
										curChoiceDex[curComChoices[curChoice]] = curChoice;
									end
									--If this can not have multiple choices, then use just the one
									if (not curComMulti) then
										curValString = curValString..curChoiceDex[curComValueMulti];
									elseif ( type(curComValueMulti) == "table" ) then
										--This is a multi choice selection, so make a list of selected choices
										curValString = curValString..curChoiceDex[curComValueMulti[1]];
										if ( curChoiceDex[curComValueMulti[1]] ~= nil ) then
											for curVal = 2, table.getn(curComValueMulti) do
												if ( ( curComValueMulti[curVal] ~= nil ) and ( curChoiceDex[curComValueMulti[curVal]] ~= nil ) ) then
													curValString = curValString..", "..curChoiceDex[curComValueMulti[curVal]];
												end
											end
										end
									end
								end
							end
							--If it's a color type, then handle the color parts
							if (curComType == MCOM_COLORT) then
								if ( type(curComValueMulti) == "table" ) then
									local curColString = "";
									if (curComValueMulti.r) then
										curColString = string.format(MCOM_CHAT_COM_K_R, MCom.math.round(curComValueMulti.r * 100));
									end
									if (curComValueMulti.g) then
										if ( curColString ~= "" ) then
											curColString = curColString.." ";
										end
										curColString = curColString..string.format( MCOM_CHAT_COM_K_G, MCom.math.round(curComValueMulti.g * 100));
									end
									if (curComValueMulti.b) then
										if ( curColString ~= "" ) then
											curColString = curColString.." ";
										end
										curColString = curColString..string.format(MCOM_CHAT_COM_K_B, MCom.math.round(curComValueMulti.b * 100));
									end
									if (curComOpacity) then
										if (curComValueMulti.opacity) then
											if ( curColString ~= "" ) then
												curColString = curColString.." ";
											end
											curColString = curColString..string.format(MCOM_CHAT_COM_K_O, MCom.math.round(curComValueMulti.opacity * 100));
										end
									end
									if ( curColString ~= "" ) then
										curColString = curColString..", ";
									end
									curColString = curColString..string.format(MCOM_CHAT_COM_K_X, MCom.string.colorToString(curComValueMulti));
									curValString = curValString..curColString;
								end
							end
						end
						if ( ( curValString ~= nil ) and ( curValString ~= "" ) and ( curValString ~= ", " ) ) then
							chatLine = string.format(MCOM_CHAT_COM_SUBCOMMAND, comList, curComTypeString, curValString, curHelp);
						else
							chatLine = string.format(MCOM_CHAT_COM_SUBCOMMAND_S, comList, curComTypeString, curHelp);
						end
					end

					--Print out the command info
					asString = MCom.PrintSlashCommandLine(asString, chatLine, true);
				end
			else
				--This is a simple command, find out what type it is, and set the correct sample
				if (MCom.SlashComs[commandid].comtype == MCOM_BOOLT) then
					bSample = true;
				else
					if (not MCom.SlashComs[commandid].hasbool) then
						if (MCom.SlashComs[commandid].comtype == MCOM_NUMT) then
							nSample = true;
							--Get a valid sample number
							nSampleV = MCom.SlashComs[commandid].commin;
							if (not nSampleV) then
								nSampleV = MCom.SlashComs[commandid].commax;
							end
							if (not nSampleV) then
								nSampleV = MCOM_CHAT_COM_EXAMPLE_O_N;
							end
						elseif (MCom.SlashComs[commandid].comtype == MCOM_STRINGT) then
							sSample = true;
						elseif (MCom.SlashComs[commandid].comtype == MCOM_CHOICET) then
							if (not MCom.SlashComs[commandid].multichoice) then
								cSample = true;
								--Get a valid sample choice
								for sampleV in MCom.SlashComs[commandid].choices do
									cSampleV = sampleV;
									break;
								end
							else
								cmSample = true;
								--Get a valid sample choice
								local count = 0;
								--Construct an example with two valid choices
								for sampleV in MCom.SlashComs[commandid].choices do
									count = count + 1;
									if (cmSampleV) then
										cmSampleV = cmSampleV.." "..sampleV;
									else
										cmSampleV = sampleV;
									end
									if (count > 1) then
										break;
									end
								end
							end
						elseif (MCom.SlashComs[commandid].comtype == MCOM_COLORT) then
							if (not MCom.SlashComs[commandid].hasopacity) then
								kSample = true;
							else
								okSample = true;
							end
						else
							eSample = true;
						end
					else
						if (MCom.SlashComs[commandid].comtype == MCOM_NUMT) then
							bnSample = true;
						elseif (MCom.SlashComs[commandid].comtype == MCOM_MULTIT) then
							bnSample = true;
							--Get a valid sample number
							bnSampleV = MCom.SlashComs[commandid].commin;
							if (not bnSampleV) then
								bnSampleV = MCom.SlashComs[commandid].commax;
							end
							if (not bnSampleV) then
								bnSampleV = MCOM_CHAT_COM_EXAMPLE_O_N;
							end
						elseif (MCom.SlashComs[commandid].comtype == MCOM_STRINGT) then
							bsSample = true;
						elseif (MCom.SlashComs[commandid].comtype == MCOM_CHOICET) then
							if (not MCom.SlashComs[commandid].multichoice) then
								bcSample = true;
								--Get a valid sample choice
								for sampleV in MCom.SlashComs[commandid].choices do
									bcSampleV = sampleV;
									break;
								end
							else
								bcmSample = true;
								--Get a valid sample choice
								local count = 0;
								--Construct an example with two valid choices
								for sampleV in MCom.SlashComs[commandid].choices do
									count = count + 1;
									if (bcmSampleV) then
										bcmSampleV = bcmSampleV.." "..sampleV;
									else
										bcmSampleV = sampleV;
									end
									if (count > 1) then
										break;
									end
								end
							end
						elseif (MCom.SlashComs[commandid].comtype == MCOM_COLORT) then
							if (not MCom.SlashComs[commandid].hasopacity) then
								bkSample = true;
							else
								bokSample = true;
							end
						else
							eSample = true;
						end
					end
				end
			end	
			
			--Print basic usage info
			local usageLine = MCOM_CHAT_COM_USAGE;
			if (bSample or bnSample or bsSample or bcSample or bcmSample or bkSample or bkoSample) then
				usageLine = usageLine.."\n\n"..MCOM_CHAT_COM_USAGE_B;
			end
			if (bnSample) then
				usageLine = usageLine.."\n\n"..string.format(MCOM_CHAT_COM_USAGE_B_M, MCOM_NUMT, MCOM_CHAT_COM_USAGE_B_N);
			elseif (bsSample) then
				usageLine = usageLine.."\n\n"..string.format(MCOM_CHAT_COM_USAGE_B_M, MCOM_STRINGT, MCOM_CHAT_COM_USAGE_B_S);
			elseif (bcSample or bcmSample) then
				usageLine = usageLine.."\n\n"..string.format(MCOM_CHAT_COM_USAGE_B_M, MCOM_CHOICET, MCOM_CHAT_COM_USAGE_B_C);
			elseif (bkSample or bkoSample) then
				usageLine = usageLine.."\n\n"..string.format(MCOM_CHAT_COM_USAGE_B_M, MCOM_COLORT, MCOM_CHAT_COM_USAGE_B_K);
			end
			asString = MCom.PrintSlashCommandLine(asString, usageLine, true);
			
			--Print detailed usage info
			if (isSimple) then
				--If its simple we print the simple versions of the usage info, but only for the command type
				if (eSample) then
					chatLine = string.format(MCOM_CHAT_COM_USAGE_S_E, basecommand);
					asString = MCom.PrintSlashCommandLine(asString, chatLine, true);
				end
				if (bSample) then
					chatLine = string.format(MCOM_CHAT_COM_USAGE_S_S, basecommand, MCOM_CHAT_COM_B);
					asString = MCom.PrintSlashCommandLine(asString, chatLine, true);
				end
				if (nSample) then
					chatLine = string.format(MCOM_CHAT_COM_USAGE_S_S, basecommand, MCOM_CHAT_COM_N);
					asString = MCom.PrintSlashCommandLine(asString, chatLine, true);
				end
				if (sSample) then
					chatLine = string.format(MCOM_CHAT_COM_USAGE_S_S, basecommand, MCOM_CHAT_COM_S);
					asString = MCom.PrintSlashCommandLine(asString, chatLine, true);
				end
				if (cSample) then
					chatLine = string.format(MCOM_CHAT_COM_USAGE_S_S, basecommand, MCOM_CHAT_COM_C);
					asString = MCom.PrintSlashCommandLine(asString, chatLine, true);
				end
				if (cmSample) then
					chatLine = string.format(MCOM_CHAT_COM_USAGE_S_S, basecommand, MCOM_CHAT_COM_C_M);
					asString = MCom.PrintSlashCommandLine(asString, chatLine, true);
				end
				if (kSample) then
					chatLine = string.format(MCOM_CHAT_COM_USAGE_S_S, basecommand, MCOM_CHAT_COM_K);
					asString = MCom.PrintSlashCommandLine(asString, chatLine, true);
				end
				if (koSample) then
					chatLine = string.format(MCOM_CHAT_COM_USAGE_S_S, basecommand, MCOM_CHAT_COM_K_O);
					asString = MCom.PrintSlashCommandLine(asString, chatLine, true);
				end
				if (bnSample) then
					chatLine = string.format(MCOM_CHAT_COM_USAGE_S_M, basecommand, MCOM_CHAT_COM_N);
					asString = MCom.PrintSlashCommandLine(asString, chatLine, true);
				end
				if (bsSample) then
					chatLine = string.format(MCOM_CHAT_COM_USAGE_S_M, basecommand, MCOM_CHAT_COM_S);
					asString = MCom.PrintSlashCommandLine(asString, chatLine, true);
				end
				if (bcSample) then
					chatLine = string.format(MCOM_CHAT_COM_USAGE_S_M, basecommand, MCOM_CHAT_COM_C);
					asString = MCom.PrintSlashCommandLine(asString, chatLine, true);
				end
				if (bcmSample) then
					chatLine = string.format(MCOM_CHAT_COM_USAGE_S_M, basecommand, MCOM_CHAT_COM_C_M);
					asString = MCom.PrintSlashCommandLine(asString, chatLine, true);
				end
				if (bkSample) then
					chatLine = string.format(MCOM_CHAT_COM_USAGE_S_M, basecommand, MCOM_CHAT_COM_K);
					asString = MCom.PrintSlashCommandLine(asString, chatLine, true);
				end
				if (bkoSample) then
					chatLine = string.format(MCOM_CHAT_COM_USAGE_S_M, basecommand, MCOM_CHAT_COM_K_O);
					asString = MCom.PrintSlashCommandLine(asString, chatLine, true);
				end
			else
				--If its not simple then we print usage info for any type of subcommand used
				if (eSample) then
					chatLine = string.format(MCOM_CHAT_COM_USAGE_E, basecommand);
					asString = MCom.PrintSlashCommandLine(asString, chatLine, true);
				end
				if (bSample) then
					chatLine = string.format(MCOM_CHAT_COM_USAGE_S, MCOM_BOOLT, basecommand, MCOM_CHAT_COM_B);
					asString = MCom.PrintSlashCommandLine(asString, chatLine, true);
				end
				if (nSample) then
					chatLine = string.format(MCOM_CHAT_COM_USAGE_S, MCOM_NUMT, basecommand, MCOM_CHAT_COM_N);
					asString = MCom.PrintSlashCommandLine(asString, chatLine, true);
				end
				if (sSample) then
					chatLine = string.format(MCOM_CHAT_COM_USAGE_S, MCOM_STRINGT, basecommand, MCOM_CHAT_COM_S);
					asString = MCom.PrintSlashCommandLine(asString, chatLine, true);
				end
				if (cSample) then
					chatLine = string.format(MCOM_CHAT_COM_USAGE_S, MCOM_CHOICET, basecommand, MCOM_CHAT_COM_C);
					asString = MCom.PrintSlashCommandLine(asString, chatLine, true);
				end
				if (cmSample) then
					chatLine = string.format(MCOM_CHAT_COM_USAGE_S, MCOM_CHAT_C_M, basecommand, MCOM_CHAT_COM_C_M);
					asString = MCom.PrintSlashCommandLine(asString, chatLine, true);
				end
				if (kSample) then
					chatLine = string.format(MCOM_CHAT_COM_USAGE_S, MCOM_COLORT, basecommand, MCOM_CHAT_COM_K);
					asString = MCom.PrintSlashCommandLine(asString, chatLine, true);
				end
				if (koSample) then
					chatLine = string.format(MCOM_CHAT_COM_USAGE_S, MCOM_CHAT_K_O, basecommand, MCOM_CHAT_COM_K_O);
					asString = MCom.PrintSlashCommandLine(asString, chatLine, true);
				end
				if (bnSample) then
					chatLine = string.format(MCOM_CHAT_COM_USAGE_M, MCOM_BOOLT..MCOM_NUMT, basecommand, MCOM_CHAT_COM_N);
					asString = MCom.PrintSlashCommandLine(asString, chatLine, true);
				end
				if (bsSample) then
					chatLine = string.format(MCOM_CHAT_COM_USAGE_M, MCOM_BOOLT..MCOM_STRINGT, basecommand, MCOM_CHAT_COM_S);
					asString = MCom.PrintSlashCommandLine(asString, chatLine, true);
				end
				if (bcSample) then
					chatLine = string.format(MCOM_CHAT_COM_USAGE_M, MCOM_BOOLT..MCOM_CHOICET, basecommand, MCOM_CHAT_COM_C);
					asString = MCom.PrintSlashCommandLine(asString, chatLine, true);
				end
				if (bcmSample) then
					chatLine = string.format(MCOM_CHAT_COM_USAGE_M, MCOM_BOOLT..MCOM_CHAT_C_M, basecommand, MCOM_CHAT_COM_C_M);
					asString = MCom.PrintSlashCommandLine(asString, chatLine, true);
				end
				if (bkSample) then
					chatLine = string.format(MCOM_CHAT_COM_USAGE_M, MCOM_BOOLT..MCOM_COLORT, basecommand, MCOM_CHAT_COM_K);
					asString = MCom.PrintSlashCommandLine(asString, chatLine, true);
				end
				if (bkoSample) then
					chatLine = string.format(MCOM_CHAT_COM_USAGE_M, MCOM_BOOLT..MCOM_CHAT_K_O, basecommand, MCOM_CHAT_COM_K_M);
					asString = MCom.PrintSlashCommandLine(asString, chatLine, true);
				end
			end
			
			--Print extra help for the command
			if (MCom.SlashComs[commandid].extrahelp) then
				if (type(MCom.SlashComs[commandid].extrahelp) ~= "table") then
					MCom.SlashComs[commandid].extrahelp = { MCom.SlashComs[commandid].extrahelp };
				end
				--Add an extra line before the extra help
				if (asString) then
					asString = asString.."\n";
				end
				for curHelp in MCom.SlashComs[commandid].extrahelp do
					asString = MCom.PrintSlashCommandLine(asString, MCom.SlashComs[commandid].extrahelp[curHelp]);
				end
			end
			
			--Print example usage
			asString = MCom.PrintSlashCommandLine(asString, MCOM_CHAT_COM_EXAMPLE, true);
			if (isSimple) then
				--If it's simple we print an example for the appropriate type
				if (eSample) then
					chatLine = string.format(MCOM_CHAT_COM_EXAMPLE_S_E, basecommand);
					asString = MCom.PrintSlashCommandLine(asString, chatLine);
				end
				if (bSample) then
					chatLine = string.format(MCOM_CHAT_COM_EXAMPLE_S_S, basecommand, MCOM_CHAT_COM_EXAMPLE_O_B);
					asString = MCom.PrintSlashCommandLine(asString, chatLine);
				end
				if (nSample) then
					chatLine = string.format(MCOM_CHAT_COM_EXAMPLE_S_S, basecommand, nSampleV);
					asString = MCom.PrintSlashCommandLine(asString, chatLine);
				end
				if (sSample) then
					chatLine = string.format(MCOM_CHAT_COM_EXAMPLE_S_S, basecommand, MCOM_CHAT_COM_EXAMPLE_O_S);
					asString = MCom.PrintSlashCommandLine(asString, chatLine);
				end
				if (cSample) then
					chatLine = string.format(MCOM_CHAT_COM_EXAMPLE_S_S, basecommand, cSampleV);
					asString = MCom.PrintSlashCommandLine(asString, chatLine);
				end
				if (cmSample) then
					chatLine = string.format(MCOM_CHAT_COM_EXAMPLE_S_S, basecommand, cmSampleV);
					asString = MCom.PrintSlashCommandLine(asString, chatLine);
				end
				if (kSample) then
					chatLine = string.format(MCOM_CHAT_COM_EXAMPLE_S_S, basecommand, MCOM_CHAT_COM_EXAMPLE_O_K);
					asString = MCom.PrintSlashCommandLine(asString, chatLine);
				end
				if (koSample) then
					chatLine = string.format(MCOM_CHAT_COM_EXAMPLE_S_S, basecommand, MCOM_CHAT_COM_EXAMPLE_O_K_O);
					asString = MCom.PrintSlashCommandLine(asString, chatLine);
				end
				if (bnSample) then
					chatLine = string.format(MCOM_CHAT_COM_EXAMPLE_S_M, basecommand, bnSampleV);
					asString = MCom.PrintSlashCommandLine(asString, chatLine);
				end
				if (bsSample) then
					chatLine = string.format(MCOM_CHAT_COM_EXAMPLE_S_M, basecommand, MCOM_CHAT_COM_EXAMPLE_O_S);
					asString = MCom.PrintSlashCommandLine(asString, chatLine);
				end
				if (bcSample) then
					chatLine = string.format(MCOM_CHAT_COM_EXAMPLE_S_M, basecommand, bcSampleV);
					asString = MCom.PrintSlashCommandLine(asString, chatLine);
				end
				if (bcmSample) then
					chatLine = string.format(MCOM_CHAT_COM_EXAMPLE_S_M, basecommand, bcmSampleV);
					asString = MCom.PrintSlashCommandLine(asString, chatLine);
				end
				if (bkSample) then
					chatLine = string.format(MCOM_CHAT_COM_EXAMPLE_S_M, basecommand, MCOM_CHAT_COM_EXAMPLE_O_K);
					asString = MCom.PrintSlashCommandLine(asString, chatLine);
				end
				if (bkoSample) then
					chatLine = string.format(MCOM_CHAT_COM_EXAMPLE_S_M, basecommand, MCOM_CHAT_COM_EXAMPLE_O_K_O);
					asString = MCom.PrintSlashCommandLine(asString, chatLine);
				end
			else
				--If it's not simple we print an example for each type used
				if (eSample) then
					chatLine = string.format(MCOM_CHAT_COM_EXAMPLE_E, basecommand, eSample);
					asString = MCom.PrintSlashCommandLine(asString, chatLine);
				end
				if (bSample) then
					chatLine = string.format(MCOM_CHAT_COM_EXAMPLE_S, basecommand, bSample, MCOM_CHAT_COM_EXAMPLE_O_B);
					asString = MCom.PrintSlashCommandLine(asString, chatLine);
				end
				if (nSample) then
					chatLine = string.format(MCOM_CHAT_COM_EXAMPLE_S, basecommand, nSample, nSampleV);
					asString = MCom.PrintSlashCommandLine(asString, chatLine);
				end
				if (sSample) then
					chatLine = string.format(MCOM_CHAT_COM_EXAMPLE_S, basecommand, sSample, MCOM_CHAT_COM_EXAMPLE_O_S);
					asString = MCom.PrintSlashCommandLine(asString, chatLine);
				end
				if (cSample) then
					chatLine = string.format(MCOM_CHAT_COM_EXAMPLE_S, basecommand, cSample, cSampleV);
					asString = MCom.PrintSlashCommandLine(asString, chatLine);
				end
				if (cmSample) then
					chatLine = string.format(MCOM_CHAT_COM_EXAMPLE_S, basecommand, cmSample, cmSampleV);
					asString = MCom.PrintSlashCommandLine(asString, chatLine);
				end
				if (kSample) then
					chatLine = string.format(MCOM_CHAT_COM_EXAMPLE_S, basecommand, kSample, MCOM_CHAT_COM_EXAMPLE_O_K);
					asString = MCom.PrintSlashCommandLine(asString, chatLine);
				end
				if (koSample) then
					chatLine = string.format(MCOM_CHAT_COM_EXAMPLE_S, basecommand, koSample, MCOM_CHAT_COM_EXAMPLE_O_K_O);
					asString = MCom.PrintSlashCommandLine(asString, chatLine);
				end
				if (bnSample) then
					chatLine = string.format(MCOM_CHAT_COM_EXAMPLE_M, basecommand, bnSample, bnSampleV);
					asString = MCom.PrintSlashCommandLine(asString, chatLine);
				end
				if (bsSample) then
					chatLine = string.format(MCOM_CHAT_COM_EXAMPLE_M, basecommand, bsSample, MCOM_CHAT_COM_EXAMPLE_O_S);
					asString = MCom.PrintSlashCommandLine(asString, chatLine);
				end
				if (bcSample) then
					chatLine = string.format(MCOM_CHAT_COM_EXAMPLE_M, basecommand, bcSample, bcSampleV);
					asString = MCom.PrintSlashCommandLine(asString, chatLine);
				end
				if (bcmSample) then
					chatLine = string.format(MCOM_CHAT_COM_EXAMPLE_M, basecommand, bcmSample, bcmSampleV);
					asString = MCom.PrintSlashCommandLine(asString, chatLine);
				end
				if (bkSample) then
					chatLine = string.format(MCOM_CHAT_COM_EXAMPLE_M, basecommand, bkSample, MCOM_CHAT_COM_EXAMPLE_O_K);
					asString = MCom.PrintSlashCommandLine(asString, chatLine);
				end
				if (bkoSample) then
					chatLine = string.format(MCOM_CHAT_COM_EXAMPLE_M, basecommand, bkoSample, MCOM_CHAT_COM_EXAMPLE_O_K_O);
					asString = MCom.PrintSlashCommandLine(asString, chatLine);
				end
			end
		end
		--Return the string
		return asString;
	end;
	
	--[[ The Cosmos callback function handler ]]--
	MCom.SetFromUI = function (option, checked, value)
		if (not MCom.UIFuncList) then
			MCom.UIFuncList = {};
		end
		
		--Get the info for this function
		local funcInfo = MCom.UIFuncList[option];
		if (funcInfo) then
			local func = funcInfo.func;
			local funcType = funcInfo.uitype;
			--Call the appropriate kind of function for this kind of element
			if (func and funcType) then
				if (funcType == "CHECKBOX") then
					func(checked);
				elseif (funcType == "SLIDER") then
					func(value);
				elseif (funcType == "BOTH") then
					func(checked, value);
				else
					func();
				end
			end
		end
	end;
	
	--[[ The Khaos callback function handler ]]--
	MCom.SetFromKUI = function (option, state, keypressed, choices)
		if (not MCom.UIFuncList) then
			MCom.UIFuncList = {};
		end
		
		--Get the info for this function
		local funcInfo = MCom.UIFuncList[option];
		if (funcInfo) then
			local func = funcInfo.func;
			local funcType = funcInfo.uitype;
			
			--split into hasbool and not hasbool sections.
			
			--Call the appropriate kind of function for this kind of element
			if (func and funcType) then
				local checked = nil;
				if (funcInfo.hasbool) then
					checked = 0;
					if (state and state.checked) then
						checked = 1;
					end
				end
				
				local value = nil;
				local name = nil;
				--If it's a bool then call it as such
				if ((funcType == K_TEXT) and funcInfo.hasbool) then
					func(checked);
				else
					--Handle the value from the right variable for this type
					if (funcType == K_SLIDER) then
						value = state.slider;
					elseif ( funcType ==  K_EDITBOX ) then
						value = state.value;
					elseif (funcType == K_PULLDOWN) then
						value = state.value;
						--If we don't have a table of choices, then just use the values
						if ( type(choices) ~= "table" ) then
							--If this can not have multiple choices, then use just the one
							if ( type(value) ~= "table" ) then
								name = value;
							else
								--This is a multi choice selection, so make a list of selected choices
								name = value[1];
								if ( name ~= nil ) then
									for curVal = 2, table.getn(value) do
										if ( value[curVal] ~= nil ) then
											name = name..", "..value[curVal];
										end
									end
								end
							end
						else
							--If we have a table of choices, then make a table indexed by value
							local curChoiceDex = {};
							for curChoice in choices do
								curChoiceDex[choices[curChoice]] = curChoice;
							end
							--If this can not have multiple choices, then use just the one
							if ( type(value) ~= "table" ) then
								name = curChoiceDex[value];
							else
								--This is a multi choice selection, so make a list of selected choices
								name = curChoiceDex[value[1]];
								if ( name ~= nil ) then
									for curVal = 2, table.getn(value) do
										if ( ( value[curVal] ~= nil ) and ( curChoiceDex[value[curVal]] ~= nil ) ) then
											name = name..", "..curChoiceDex[value[curVal]];
										end
									end
								end
							end
						end
					elseif (funcType ==  K_COLORPICKER) then
						value = state.color;
					end
					
					--If it's a button, then just call it
					if (funcType == K_BUTTON) then
						func();
					else
						--If it has a bool call it with the bool, and the value, otherwise, just the value
						if (funcInfo.hasbool) then
							func(checked, value, name);
						else
							func(value, name);
						end
					end
				end
			end
		end
	end;

	--------------------------------------------------
	--
	-- Hooked Functions
	--
	--------------------------------------------------
	MCom.ItemTextPrevPage = function ()
		--Switch to the previous page if there is one
		if ( type(MCom.CurText) == "table" ) then
			local TextFrame = "MComText";
			if ( not getglobal(TextFrame.."Frame") ) then
				TextFrame = "ItemText";
			end
			if ( MCom.CurTextPage > 1 ) then
				--Store the current position and range of the scrollbar so we can restore this, the next time the page is visited
				MCom.CurText.Scroll[MCom.CurTextPage].Value = getglobal(TextFrame.."ScrollFrameScrollBar"):GetValue();
				MCom.CurText.Scroll[MCom.CurTextPage].Range = getglobal(TextFrame.."ScrollFrame"):GetVerticalScrollRange();
				--Flip the page
				MCom.CurTextPage = MCom.CurTextPage - 1;
				--If a scroll range was recorded for this page, then adjust to those values
				if (MCom.CurText.Scroll[MCom.CurTextPage].Range) then
					getglobal(TextFrame.."ScrollFrameScrollBar"):SetMinMaxValues(0, MCom.CurText.Scroll[MCom.CurTextPage].Range);
				end
				--Update the page
				MCom.UpdateTextPage();
			end
		else
			MCom.CurText = nil;
		end
	end;

	MCom.ItemTextNextPage = function ()
		--Switch to the previous page if there is one
		if ( type(MCom.CurText) == "table" ) then
			local TextFrame = "MComText";
			if ( not getglobal(TextFrame.."Frame") ) then
				TextFrame = "ItemText";
			end
			if ( MCom.CurTextPage < table.getn(MCom.CurText) ) then
				--Store the current position and range of the scrollbar so we can restore this, the next time the page is visited
				MCom.CurText.Scroll[MCom.CurTextPage].Value = getglobal(TextFrame.."ScrollFrameScrollBar"):GetValue();
				MCom.CurText.Scroll[MCom.CurTextPage].Range = getglobal(TextFrame.."ScrollFrame"):GetVerticalScrollRange();
				--Flip the page
				MCom.CurTextPage = MCom.CurTextPage + 1;
				--If a scroll range was recorded for this page, then adjust to those values
				if (MCom.CurText.Scroll[MCom.CurTextPage].Range) then
					getglobal(TextFrame.."ScrollFrameScrollBar"):SetMinMaxValues(0, MCom.CurText.Scroll[MCom.CurTextPage].Range);
				end
				--Update the page
				MCom.UpdateTextPage();
			end
		else
			MCom.CurText = nil;
		end
	end;
	
	--When the item text is closed, let's reset it to normal, and confirm that MCom
	--can now make use of it
	MCom.CloseItemText = function ()
		local TextFrame = "MComText";
		if ( not getglobal(TextFrame.."Frame") ) then
			TextFrame = "ItemText";
		end
		MCom.CurText = nil;
		MCom.NoTextAvail = nil;
		--Remove the vertex color
		getglobal(TextFrame.."MaterialTopLeft"):SetVertexColor(1,1,1);
		getglobal(TextFrame.."MaterialTopRight"):SetVertexColor(1,1,1);
		getglobal(TextFrame.."MaterialBotLeft"):SetVertexColor(1,1,1);
		getglobal(TextFrame.."MaterialBotRight"):SetVertexColor(1,1,1);
		
		--Resize the text to normal
		if (MCom.PageWidth and MCom.PageScale) then
			getglobal(TextFrame.."PageText"):SetWidth(MCom.PageWidth);
			getglobal(TextFrame.."PageText"):SetScale(MCom.PageScale);
		end
	end;

	MCom.ItemTextFrame_OnEvent = function (event)
		--If the game is doing something with the text frame, then clear the MCom text
		--and set the frame as unavailable for MCom to use
		if (	( event == "ITEM_TEXT_BEGIN" ) or ( event == "ITEM_TEXT_TRANSLATION" ) or
					( event == "ITEM_TEXT_READY" ) ) then
			local TextFrame = "MComText";
			if ( not getglobal(TextFrame.."Frame") ) then
				TextFrame = "ItemText";
				MCom.CurText = nil;
				MCom.NoTextAvail = true;
				--Remove the vertex color
				getglobal(TextFrame.."MaterialTopLeft"):SetVertexColor(1,1,1);
				getglobal(TextFrame.."MaterialTopRight"):SetVertexColor(1,1,1);
				getglobal(TextFrame.."MaterialBotLeft"):SetVertexColor(1,1,1);
				getglobal(TextFrame.."MaterialBotRight"):SetVertexColor(1,1,1);
				
				--Resize the text to normal
				if (MCom.PageWidth and MCom.PageScale) then
					getglobal(TextFrame.."PageText"):SetWidth(MCom.PageWidth);
					getglobal(TextFrame.."PageText"):SetScale(MCom.PageScale);
				end
			end
		end
	end;
	
	MCom.myAddOnsFrame_OnEvent = function ()
		--If this is variables loaded, then load in the MCom registered addons
		if (event == "VARIABLES_LOADED") then
			MCom.MyAddOnsLoaded = true;
			--If this vesion of myAddons supports the registration method, then use it
			if(myAddOnsFrame_Register) then
				for curAddon in MCom.MyAddOnsList do
					local help = nil;
					--If we have a table of help, then get a copy of it, and add the slash command help if available
					if ( type(MCom.MyAddOnsList[curAddon].help) == "table" ) then
						help = MCom.table.copy(MCom.MyAddOnsList[curAddon].help);
						if (MCom.MyAddOnsList[curAddon].supercom) then
							--Add the slash command info on to it
							help[table.getn(help) + 1] = MCom.PrintSlashCommandInfo(MCom.getComID(MCom.MyAddOnsList[curAddon].supercom), true);
						end
					elseif ( ( MCom.MyAddOnsList[curAddon].help == "boolean" ) and MCom.MyAddOnsList[curAddon].help and MCom.MyAddOnsList[curAddon].supercom ) then
						--If help is a boolean and we have slash command info, then generate the help from the slash command info
						help = MCom.PrintSlashCommandInfo(MCom.getComID(MCom.MyAddOnsList[curAddon].supercom), true);
					end
					 -- Register the addon in myAddOns
					myAddOnsFrame_Register(MCom.MyAddOnsList[curAddon].details, help);
				end
			else
				--Use the old method of adding an addon to the list
				for curAddon in MCom.MyAddOnsList do
					myAddOnsList[curAddon] = MCom.MyAddOnsList[curAddon].details;
				end
			end
		end
	end;

	MCom.UIParent_OnEvent = function ()
		if ( event == "VARIABLES_LOADED" ) then
			if (not MCom.didVarsLoaded) then
				MCom.didVarsLoaded = true;
				--If we have anything that needs to be safe loaded, then load it now
				if ( type(MCom.safeLoads) == "table" ) then
					local curConfig;
					if ( type(MCom.safeLoads.varsLoaded) == "table" ) then
						--Load any safe load that has changed
						for curLoad in MCom.safeLoads.varsLoaded do
							--Get the variable for the current safe load
							curConfig = MCom.getStringVar(curLoad);
							--Load the stored data into the empty entries of the current config if the table has been replaced
							if ( ( type(curConfig) == "table" ) and ( curConfig ~= MCom.safeLoads.varsLoaded[curLoad] ) ) then
								MCom.LoadSafeTable( curConfig, MCom.safeLoads.varsLoaded[curLoad] );
							end
						end
					end

					--Deal with any old style entries
					for curLoad in MCom.safeLoads do
						if ( ( curLoad ~= "addonLoaded" ) and ( curLoad ~= "varsLoaded" ) ) then
							--Get the variable for the current safe load
							curConfig = MCom.getStringVar(curLoad);
							--Load the stored data into the empty entries of the current config
							if ( ( type(curConfig) == "table" ) ) then
								MCom.LoadSafeTable( curConfig, MCom.safeLoads[curLoad] );
							end
						end
					end
				end

				--Clear the safe loads table
				MCom.safeLoads = nil;

				--If we are using this as the vars loaded event, then call the vars loaded callbacks
				if (MCom.UseVarsLoadedEvent) then
					MCom.VariablesLoaded();
				end
			end
		end

		if ( event == "ADDON_LOADED" ) then
			--If we have anything that needs to be safe loaded, then load it now
			if ( type(MCom.safeLoads) == "table" ) then
				local curConfig;
				if ( type(MCom.safeLoads.addonLoaded) == "table" ) then
					--Load any safe load that has changed
					for curLoad in MCom.safeLoads.addonLoaded do
						--Get the variable for the current safe load
						curConfig = MCom.getStringVar(curLoad);
						--Load the stored data into the empty entries of the current config if the table has been replaced
						if ( ( type(curConfig) == "table" ) and ( curConfig ~= MCom.safeLoads.addonLoaded[curLoad] ) ) then
							MCom.LoadSafeTable( curConfig, MCom.safeLoads.addonLoaded[curLoad] );
							--Move the entry to the variables loaded table to be checked for loading once more
							MCom.safeLoads.varsLoaded[curLoad] = MCom.safeLoads.addonLoaded[curLoad];
							MCom.safeLoads.addonLoaded[curLoad] = nil;
						end
					end
				end
				
				--Deal with any old style entries
				for curLoad in MCom.safeLoads do
					if ( ( curLoad ~= "addonLoaded" ) and ( curLoad ~= "varsLoaded" ) ) then
						--Get the variable for the current safe load
						curConfig = MCom.getStringVar(curLoad);
						--Load the stored data into the empty entries of the current config
						if ( ( type(curConfig) == "table" ) ) then
							MCom.LoadSafeTable( curConfig, MCom.safeLoads[curLoad] );
						end
					end
				end
			end
		end
	end

	--------------------------------------------------
	--
	-- Sea Wrapper Functions
	--
	--------------------------------------------------
	--Wrappers used to ensure MCom functions without Sea, for those who just
	--absolutely refuse to use Sea
	MCom.math = {};
	MCom.math.round = function (x)
		if (Sea and Sea.math and Sea.math.round) then
			--Call origional
			return Sea.math.round(x);
		else
			--Same as origional
			if(x - math.floor(x) > 0.5) then
				x = x + 0.5;
			end
			return math.floor(x);
		end
	end;

	MCom.math.hexFromInt = function (intval, minlength)
		if (Sea and Sea.math and Sea.math.hexFromInt) then
			--Call origional
			return Sea.math.hexFromInt(intval, minlength);
		else
			--Same as origional
			if ( minlength == nil )	then 
				minlength = "2";
			end
			return string.format("%"..minlength.."x", intval );
		end
	end;

	MCom.table = {};
	MCom.table.copy = function ( t, recursionList ) 
		if (Sea and Sea.table and Sea.table.copy) then
			--Call origional
			return Sea.table.copy(t, recursionList);
		else
			--Same as origional
			if ( not recursionList ) then recursionList = {} end;
			if ( type(t) ~= "table" ) then 
				return t;
			end
	
			local newTable = {};
			if ( recursionList[t] ) then
				return recursionList[t];
			else
				recursionList[t] = newTable;
				for k,v in t do
					--If it's a table we want to recurse.  But the second half of this if checks to see if it
					--is a reference to a frame, which looks like a table, and does a normal copy in such a
					--case
					if ( ( type(v) == "table" ) and not ( v[0] and ( type(v[0]) == "userdata" ) ) ) then 
						newTable[k] = MCom.table.copy(v, recursionList);
					else
						newTable[k] = v;
					end
				end
	
				return newTable;
			end
		end
	end;

	MCom.table.push = function ( table, val ) 
		if (Sea and Sea.table and Sea.table.copy) then
			--Call origional
			return Sea.table.push(table, val);
		else
			--Same as origional
			if(not table or not table.n) then
				return nil;
			end
			table.n = table.n+1;
			table[table.n] = val;
		end
	end;

	MCom.IO = {};
	MCom.IO.printc = function ( color, pString )
		if (Sea and Sea.IO and Sea.IO.printc) then
			--Call origional
			Sea.IO.printc(color, pString);
		else
			--Simple colored print, not as capable as Sea's functions
			if ( color == nil ) then 
				color = NORMAL_FONT_COLOR;
			end
			ChatFrame1:AddMessage(pString, color.r, color.g, color.b);
		end
	end;
	
	MCom.util = {};
	MCom.util.split = function ( text, separator, oldTable, noPurge )
		if (Sea and Sea.util and Sea.util.split and Sea.version) then
			--Call origional
			return Sea.util.split( text, separator, oldTable, noPurge );
		else
			--Using Legorols version
			local value;
    	local init, mstart, mend = 1;
			local t, oldn = oldTable, 0;
			
			if ( not t ) then
				t = {};
			else
				oldn = table.getn(t);
				table.setn(t, 0);
			end
			
			-- Using string.find instead of string.gfind to avoid garbage generation		
	    repeat
				mstart, mend, value = string.find(text, "([^"..separator.."]+)", init);
				if ( value ) then
					table.insert(t, value)
					init = mend + 1;
				end
	    until not value;
			
			if ( not noPurge ) then
				for i = table.getn(t)+1, oldn do
					t[i] = nil;
				end
			end
			
			return t;
		end
	end;
	
	MCom.util.hook = function (orig, new, hooktype, scriptElementName)
		if (Sea and Sea.util and Sea.util.hook and Sea.version and ( Sea.version >= 1.05 ) ) then
			Sea.util.hook(orig, new, hooktype, scriptElementName);
		else
			--Modified hook function from origional, uses Sea's hook list if available
			if (not MCom.util.Hooks) then
				MCom.util.Hooks = {};
			end
			local hookList = MCom.util.Hooks;

			--If Sea is around, then use it's list
			if (Sea and Sea.util and Sea.util.hook) then
				if(not Sea.util.Hooks) then
					Sea.util.Hooks = {};
				end
				hookList = Sea.util.Hooks;
			end

			local origCopy = orig;
			if (scriptElementName) then
				orig = orig.."."..scriptElementName;
			end

			if(not hooktype) then
				hooktype = "before";
			end
			if(not hookList[orig]) then
				hookList[orig] = {};
				hookList[orig].before = {};
				hookList[orig].before.n = 0;
				hookList[orig].after = {};
				hookList[orig].after.n = 0;
				hookList[orig].hide = {};
				hookList[orig].hide.n = 0;
				hookList[orig].replace = {};
				hookList[orig].replace.n = 0;
				hookList[orig].orig = MCom.getStringVar(orig);
				-- Set up the hook the first time
				if (scriptElementName) then
					hookList[orig].orig = MCom.getStringVar(origCopy):GetScript(scriptElementName);
					MCom.getStringVar(origCopy):SetScript(scriptElementName, function(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20) return MCom.util.hookHandler(orig,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20); end);
				else
					hookList[orig].orig = MCom.getStringVar(orig);
					MCom.setStringVar(orig,function(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20) return MCom.util.hookHandler(orig,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20); end);
				end
			else
				for key,value in hookList[orig][hooktype] do
					-- NOTE THIS SHOULD BE VALUE! VALUE! *NOT* KEY!
					if(value == MCom.getStringVar(new)) then
						return;
					end
				end
			end
			-- intentionally will error if bad type is passed
			MCom.table.push(hookList[orig][hooktype], MCom.getStringVar(new));
		end
	end;

	MCom.util.unhook = function (orig, new, hooktype, scriptElementName)
		if (Sea and Sea.util and Sea.util.unhook and Sea.version and ( Sea.version >= 1.05 ) ) then
			Sea.util.unhook(orig, new, hooktype, scriptElementName);
		else
			--Modified unhook function from origional, uses Sea's hook list if available
			if (not MCom.util.Hooks) then
				MCom.util.Hooks = {};
			end		
			local hookList = MCom.util.Hooks;
			--If Sea is around, then use it's list
			if (Sea and Sea.util and Sea.util.hook) then
				if(not Sea.util.Hooks) then
					Sea.util.Hooks = {};
				end
				hookList = Sea.util.Hooks;
			end

			if(not hooktype) then
				hooktype = "before";
			end
			local l,g;
			local origCopy = orig;
			if (scriptElementName) then
				orig = orig.."."..scriptElementName;
			end
			if(not hookList[orig]) then
				hookList[orig] = {};
				hookList[orig].before = {};
				hookList[orig].before.n = 0;
				hookList[orig].after = {};
				hookList[orig].after.n = 0;
				hookList[orig].hide = {};
				hookList[orig].hide.n = 0;
				hookList[orig].replace = {};
				hookList[orig].replace.n = 0;
				if (scriptElementName) then
					hookList[orig].orig = MCom.getStringVar(origCopy):GetScript(scriptElementName);
					MCom.getStringVar(origCopy):SetScript(scriptElementName, function(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20) return MCom.util.hookHandler(orig,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20); end);
				else
					hookList[orig].orig = MCom.getStringVar(orig);
					MCom.setStringVar(orig,function(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20) return MCom.util.hookHandler(orig,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20); end);
				end
			end
			l = hookList[orig][hooktype];
			g = MCom.getStringVar(new);
			if ( l ) then 
				for key,value in l do
					if(value == g) then
						l[key] = nil;
						return;
					end
				end
			end
		end
	end;

	if (Sea and Sea.util and Sea.util.hookHandler and Sea.version) then
		MCom.util.hookHandler = Sea.util.hookHandler;
	else
		MCom.util.hookHandler = function (name,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
			local called = false;
			local continue = true;
			local retval = nil;
			local ra1,ra2,ra3,ra4,ra5,ra6,ra7,ra8,ra9,ra10,ra11,ra12,ra13,ra14,ra15,ra16,ra17,ra18,ra19,ra20;
			local hookList = MCom.util.Hooks;

			--If Sea is around, then use it's list
			if (Sea and Sea.util and Sea.util.hook) then
				hookList = Sea.util.Hooks;
			end

			if ( not hookList[name] ) then
				hookList[name] = {};
				hookList[name].before = {};
				hookList[name].before.n = 0;
				hookList[name].after = {};
				hookList[name].after.n = 0;
				hookList[name].hide = {};
				hookList[name].hide.n = 0;
				hookList[name].replace = {};
				hookList[name].replace.n = 0;
			end
			for key,value in hookList[name].hide do
				if(type(value) == "function") then
					if(not value(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)) then
						continue = false;
					end
					called = true;
				end
			end
			if(not continue) then
				return;
			end
			for key,value in hookList[name].before do
				if(type(value) == "function") then
					value(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20);
					called = true;
				end
			end
			continue = false;
			local replacedFunction = false;
			for key,value in hookList[name].replace do
				if(type(value) == "function") then
					replacedFunction = true;
					local callOrig = false;
					callOrig,ra1,ra2,ra3,ra4,ra5,ra6,ra7,ra8,ra9,ra10,ra11,ra12,ra13,ra14,ra15,ra16,ra17,ra18,ra19,ra20 = value(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20);
					if(callOrig) then
						continue = true;
					else
						retval = true;
					end
					called = true;
				end
			end
			if(continue or (not replacedFunction)) then
				if (hookList[name].orig) then
		  		ra1,ra2,ra3,ra4,ra5,ra6,ra7,ra8,ra9,ra10,ra11,ra12,ra13,ra14,ra15,ra16,ra17,ra18,ra19,ra20 = hookList[name].orig(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20);
		  	end
		  	retval = true;
			end
			for key,value in hookList[name].after do
				if(type(value) == "function") then
					value(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20);
					called = true;
				end
			end
			if(not called) then
				--[[ Disabled Complete Unhhoking Sept 17, 2005 - Incompatible with Frame Script Element Hooks - Liable to erase hooks loaded after the first hook.
				MCom.setStringVar(name,hookList[name].orig);
				hookList[name] = nil;
				]]--
			end
			if (retval) then
				if (type(ra1) == "table") then
					return unpack(ra1);
				else
					return ra1,ra2,ra3,ra4,ra5,ra6,ra7,ra8,ra9,ra10,ra11,ra12,ra13,ra14,ra15,ra16,ra17,ra18,ra19,ra20;
				end
			end
		end;
	end;

	MCom.wow = { tooltip = {}; };
	MCom.wow.tooltip.get = function ( tooltip, row, value )
		if (Sea and Sea.wow and Sea.wow.tooltip and Sea.wow.tooltip.get) then
			--Call origional
			return Sea.wow.tooltip.get( tooltip, row, value );
		else
			--Default to GameTooltip
			if (not tooltip) then
				tooltip = "GameTooltip";
			end
			--Default to first row
			if (not row) then
				row = 1;
			end

			local text, left, right, leftRed, leftGreen, leftBlue, leftAlpha, rightRed, rightGreen, rightBlue, rightAlpha;

			--Get the left tooltip
			if ( ( value == nil ) or ( value == "left" ) or ( value == "leftColor" ) ) then
				text = getglobal(tooltip.."TextLeft"..row);

				--Get the left tooltip text
				if ( ( value == nil ) or ( value == "left" ) ) then
					if ( text and text:IsVisible() ) then
						left = text:GetText();
					end
					--If this is all they want, then return it now
					if ( value == "left" ) then
						return left;
					end
				end
				--Get the left tooltip color
				if ( ( value == nil ) or ( value == "leftColor" ) ) then
					if ( text and text:IsVisible() ) then
						leftRed, leftGreen, leftBlue, leftAlpha = text:GetTextColor();
					end
					--If this is all they want, then return it now
					if ( value == "leftColor" ) then
						return leftRed, leftGreen, leftBlue, leftAlpha;
					end
				end
			end
			
			--Get the right tooltip
			if ( ( value == nil ) or ( value == "right" ) or ( value == "rightColor" ) ) then
				text = getglobal(tooltip.."TextRight"..row);

				--Get the right tooltip text
				if ( ( value == nil ) or ( value == "right" ) ) then
					if ( text and text:IsVisible() ) then
						right = text:GetText();
					end
					--If this is all they want, then return it now
					if ( value == "right" ) then
						return right;
					end
				end
				--Get the right tooltip color
				if ( ( value == nil ) or ( value == "rightColor" ) ) then

					if ( text and text:IsVisible() ) then
						rightRed, rightGreen, rightBlue, rightAlpha = text:GetTextColor();
					end
					--If this is all they want, then return it now
					if ( value == "rightColor" ) then
						return rightRed, rightGreen, rightBlue, rightAlpha;
					end
				end
			end

			--If no individual value was specified, return the entire row
			return left, right, leftRed, leftGreen, leftBlue, leftAlpha, rightRed, rightGreen, rightBlue, rightAlpha;
		end
	end;

	MCom.string = {};
	MCom.string.colorToString = function ( color )
		if (Sea and Sea.string and Sea.string.colorToString) then
			--Call origional
			return Sea.string.colorToString(color);

		else
			if ( not color ) then 
				return "FFFFFFFF";
			end
			local rString =  MCom.math.hexFromInt(math.floor(255*color.r));
			local gString =  MCom.math.hexFromInt(math.floor(255*color.g));
			local bString =  MCom.math.hexFromInt(math.floor(255*color.b));
			local aString;
		
			if ( color.a ) then 
				aString = MCom.math.hexFromInt(math.floor(255*color.a));
			elseif ( color.opacity ) then 
				aString = MCom.math.hexFromInt(math.floor(255*color.opacity));
			end
		
			if ( aString ) then
				return aString..rString..gString..bString;
			else
				return rString..gString..bString;
	
		end;
		end
	end;
end