local m={}local function o(m,o)error(("\066\097\100 \105\110\100\101\120 \037\113"):format(tostring(o)),2)end local j={__index=o,__newindex=o}function m.readonly(m)return setmetatable(m,j)end function m.copyTable(m)local o={}for m,j in pairs(m)do o[m]=j end return o end function m.count(m)local o=0 for m,j in pairs(m)do o=o+1 end return o end function m.getOrCreateValue(m,o,j,h)assert(typeof(m)=="\073\110\115\116\097\110\099\101","\066\097\100 \097\114\103\117\109\101\110\116 \'\112\097\114\101\110\116\'")assert(type(o)=="\115\116\114\105\110\103","\066\097\100 \097\114\103\117\109\101\110\116 \'\105\110\115\116\097\110\099\101\084\121\112\101\'")assert(type(j)=="\115\116\114\105\110\103","\066\097\100 \097\114\103\117\109\101\110\116 \'\110\097\109\101\'")local F=m:FindFirstChild(j)if F then if not F:IsA(o)then warn(("\091\085\116\105\108\115\046\103\101\116\079\114\067\114\101\097\116\101\086\097\108\117\101\093 - \086\097\108\117\101 \111\102 \116\121\112\101 \037\113 \111\102 \110\097\109\101 \037\113 \105\115 \111\102 \116\121\112\101 \037\113 \105\110 \037\115 \105\110\115\116\101\097\100"):format(o,j,F.ClassName,F:GetFullName()))end return F else local F=Instance.new(o)F.Name=j F.Value=h F.Parent=m return F end end function m.getValue(m,o,j,h)assert(typeof(m)=="\073\110\115\116\097\110\099\101","\066\097\100 \097\114\103\117\109\101\110\116 \'\112\097\114\101\110\116\'")assert(type(o)=="\115\116\114\105\110\103","\066\097\100 \097\114\103\117\109\101\110\116 \'\105\110\115\116\097\110\099\101\084\121\112\101\'")assert(type(j)=="\115\116\114\105\110\103","\066\097\100 \097\114\103\117\109\101\110\116 \'\110\097\109\101\'")local F=m:FindFirstChild(j)if F then if F:IsA(o)then return F.Value else warn(("\091\085\116\105\108\115\046\103\101\116\086\097\108\117\101\093 - \086\097\108\117\101 \111\102 \116\121\112\101 \037\113 \111\102 \110\097\109\101 \037\113 \105\115 \111\102 \116\121\112\101 \037\113 \105\110 \037\115 \105\110\115\116\101\097\100"):format(o,j,F.ClassName,F:GetFullName()))return nil end else return h end end function m.setValue(m,o,j,h)assert(typeof(m)=="\073\110\115\116\097\110\099\101","\066\097\100 \097\114\103\117\109\101\110\116 \'\112\097\114\101\110\116\'")assert(type(o)=="\115\116\114\105\110\103","\066\097\100 \097\114\103\117\109\101\110\116 \'\105\110\115\116\097\110\099\101\084\121\112\101\'")assert(type(j)=="\115\116\114\105\110\103","\066\097\100 \097\114\103\117\109\101\110\116 \'\110\097\109\101\'")local F=m:FindFirstChild(j)if F then if not F:IsA(o)then warn(("\091\085\116\105\108\115\046\115\101\116\086\097\108\117\101\093 - \086\097\108\117\101 \111\102 \116\121\112\101 \037\113 \111\102 \110\097\109\101 \037\113 \105\115 \111\102 \116\121\112\101 \037\113 \105\110 \037\115 \105\110\115\116\101\097\100"):format(o,j,F.ClassName,F:GetFullName()))end F.Value=h else local F=Instance.new(o)F.Name=j F.Value=h F.Parent=m end end function m.getOrCreateFolder(m,o)local j=m:FindFirstChild(o)if j then return j else local j=Instance.new("\070\111\108\100\101\114")j.Name=o j.Parent=m return j end end return m


local Utils = {}

local function errorOnIndex(_, index)
	error(("Bad index %q"):format(tostring(index)), 2)
end

local READ_ONLY_METATABLE = {
	__index = errorOnIndex;
	__newindex = errorOnIndex;
}

function Utils.readonly(_table)
	return setmetatable(_table, READ_ONLY_METATABLE)
end

function Utils.copyTable(target)
	local new = {}
	for key, value in pairs(target) do
		new[key] = value
	end
	return new
end

function Utils.count(_table)
	local count = 0
	for _, _ in pairs(_table) do
		count = count + 1
	end
	return count
end

function Utils.getOrCreateValue(parent, instanceType, name, defaultValue)
	assert(typeof(parent) == "Instance", "Bad argument 'parent'")
	assert(type(instanceType) == "string", "Bad argument 'instanceType'")
	assert(type(name) == "string", "Bad argument 'name'")

	local foundChild = parent:FindFirstChild(name)
	if foundChild then
		if not foundChild:IsA(instanceType) then
			warn(("[Utils.getOrCreateValue] - Value of type %q of name %q is of type %q in %s instead")
				:format(instanceType, name, foundChild.ClassName, foundChild:GetFullName()))
		end

		return foundChild
	else
		local newChild = Instance.new(instanceType)
		newChild.Name = name
		newChild.Value = defaultValue
		newChild.Parent = parent

		return newChild
	end
end

function Utils.getValue(parent, instanceType, name, default)
	assert(typeof(parent) == "Instance", "Bad argument 'parent'")
	assert(type(instanceType) == "string", "Bad argument 'instanceType'")
	assert(type(name) == "string", "Bad argument 'name'")

	local foundChild = parent:FindFirstChild(name)
	if foundChild then
		if foundChild:IsA(instanceType) then
			return foundChild.Value
		else
			warn(("[Utils.getValue] - Value of type %q of name %q is of type %q in %s instead")
				:format(instanceType, name, foundChild.ClassName, foundChild:GetFullName()))
			return nil
		end
	else
		return default
	end
end

function Utils.setValue(parent, instanceType, name, value)
	assert(typeof(parent) == "Instance", "Bad argument 'parent'")
	assert(type(instanceType) == "string", "Bad argument 'instanceType'")
	assert(type(name) == "string", "Bad argument 'name'")

	local foundChild = parent:FindFirstChild(name)
	if foundChild then
		if not foundChild:IsA(instanceType) then
			warn(("[Utils.setValue] - Value of type %q of name %q is of type %q in %s instead")
				:format(instanceType, name, foundChild.ClassName, foundChild:GetFullName()))
		end

		foundChild.Value = value
	else
		local newChild = Instance.new(instanceType)
		newChild.Name = name
		newChild.Value = value
		newChild.Parent = parent
	end
end


function Utils.getOrCreateFolder(parent, folderName)
	local found = parent:FindFirstChild(folderName)
	if found then
		return found
	else
		local folder = Instance.new("Folder")
		folder.Name = folderName
		folder.Parent = parent
		return folder
	end
end


return Utils
