function Enum.createEnum(Z,N)assert(typeof(Z)=="\115\116\114\105\110\103","\098\097\100 \097\114\103\117\109\101\110\116 \035\049 - \101\110\117\109\115 \109\117\115\116 \098\101 \099\114\101\097\116\101\100 \117\115\105\110\103 \097 \115\116\114\105\110\103 \110\097\109\101\033")assert(typeof(N)=="\116\097\098\108\101","\098\097\100 \097\114\103\117\109\101\110\116 \035\050 - \101\110\117\109\115 \109\117\115\116 \098\101 \099\114\101\097\116\101\100 \117\115\105\110\103 \097 \116\097\098\108\101\033")assert(not enums[Z],("\101\110\117\109 \'\037\115\' \097\108\114\101\097\100\121 \101\120\105\115\116\115\033"):format(Z))local Q={}local B={}local Y={}local M={}local A={getName=function(Z)Z=tostring(Z)local Q=Y[Z]if not Q then Q=M[Z]end if Q then return N[Q][1]end end;getValue=function(Z)Z=tostring(Z)local Q=B[Z]if not Q then Q=M[Z]end if Q then return N[Q][2]end end,getProperty=function(Z)Z=tostring(Z)local Q=B[Z]if not Q then Q=Y[Z]end if Q then return N[Q][3]end end}for Z,N in pairs(N)do assert(typeof(N)=="\116\097\098\108\101",("\098\097\100 \097\114\103\117\109\101\110\116 \035\050\046\037\115 - \100\101\116\097\105\108\115 \109\117\115\116 \111\110\108\121 \098\101 \099\111\109\112\114\105\115\101\100 \111\102 \116\097\098\108\101\115\033"):format(Z))local D=N[1]assert(typeof(D)=="\115\116\114\105\110\103",("\098\097\100 \097\114\103\117\109\101\110\116 \035\050\046\037\115\046\049 - \100\101\116\097\105\108 \110\097\109\101 \109\117\115\116 \098\101 \097 \115\116\114\105\110\103\033"):format(Z))assert(typeof(not B[D]),("\098\097\100 \097\114\103\117\109\101\110\116 \035\050\046\037\115\046\049 - \116\104\101 \100\101\116\097\105\108 \110\097\109\101 \'\037\115\' \097\108\114\101\097\100\121 \101\120\105\115\116\115\033"):format(Z,D))assert(typeof(not A[D]),("\098\097\100 \097\114\103\117\109\101\110\116 \035\050\046\037\115\046\049 - \116\104\097\116 \110\097\109\101 \105\115 \114\101\115\101\114\118\101\100\046"):format(Z,D))B[tostring(D)]=Z local f=N[2]local L=tostring(f)assert(typeof(not Y[L]),("\098\097\100 \097\114\103\117\109\101\110\116 \035\050\046\037\115\046\050 - \116\104\101 \100\101\116\097\105\108 \118\097\108\117\101 \'\037\115\' \097\108\114\101\097\100\121 \101\120\105\115\116\115\033"):format(Z,L))Y[L]=Z local C=N[3]if C then assert(typeof(not M[C]),("\098\097\100 \097\114\103\117\109\101\110\116 \035\050\046\037\115\046\051 - \116\104\101 \100\101\116\097\105\108 \112\114\111\112\101\114\116\121 \'\037\115\' \097\108\114\101\097\100\121 \101\120\105\115\116\115\033"):format(Z,tostring(C)))M[tostring(C)]=Z end Q[D]=f setmetatable(Q,{__index=function(Z,N)return A[N]end})end enums[Z]=Q return Q end function Enum.getEnums()return enums end
-- METHODS
function Enum.createEnum(enumName, details)
	assert(typeof(enumName) == "string", "bad argument #1 - enums must be created using a string name!")
	assert(typeof(details) == "table", "bad argument #2 - enums must be created using a table!")
	assert(not enums[enumName], ("enum '%s' already exists!"):format(enumName))

	local enum = {}
	local usedNames = {}
	local usedValues = {}
	local usedProperties = {}
	local enumMetaFunctions = {
		getName = function(valueOrProperty)
			valueOrProperty = tostring(valueOrProperty)
			local index = usedValues[valueOrProperty]
			if not index then
				index = usedProperties[valueOrProperty]
			end
			if index then
				return details[index][1]
			end
		end,
		getValue = function(nameOrProperty)
			nameOrProperty = tostring(nameOrProperty)
			local index = usedNames[nameOrProperty]
			if not index then
				index = usedProperties[nameOrProperty]
			end
			if index then
				return details[index][2]
			end
		end,
		getProperty = function(nameOrValue)
			nameOrValue = tostring(nameOrValue)
			local index = usedNames[nameOrValue]
			if not index then
				index = usedValues[nameOrValue]
			end
			if index then
				return details[index][3]
			end
		end,
	}
	for i, detail in pairs(details) do
		assert(typeof(detail) == "table", ("bad argument #2.%s - details must only be comprised of tables!"):format(i))
		local name = detail[1]
		assert(typeof(name) == "string", ("bad argument #2.%s.1 - detail name must be a string!"):format(i))
		assert(
			typeof(not usedNames[name]),
			("bad argument #2.%s.1 - the detail name '%s' already exists!"):format(i, name)
		)
		assert(typeof(not enumMetaFunctions[name]), ("bad argument #2.%s.1 - that name is reserved."):format(i, name))
		usedNames[tostring(name)] = i
		local value = detail[2]
		local valueString = tostring(value)
		--assert(typeof(value) == "number" and math.ceil(value)/value == 1, ("bad argument #2.%s.2 - detail value must be an integer!"):format(i))
		assert(
			typeof(not usedValues[valueString]),
			("bad argument #2.%s.2 - the detail value '%s' already exists!"):format(i, valueString)
		)
		usedValues[valueString] = i
		local property = detail[3]
		if property then
			assert(
				typeof(not usedProperties[property]),
				("bad argument #2.%s.3 - the detail property '%s' already exists!"):format(i, tostring(property))
			)
			usedProperties[tostring(property)] = i
		end
		enum[name] = value
		setmetatable(enum, {
			__index = function(_, index)
				return enumMetaFunctions[index]
			end,
		})
	end

	enums[enumName] = enum
	return enum
end

function Enum.getEnums()
	return enums
end
