local C={}local p local d do p={}d={}local C="\065\066\067\068\069\070\071\072\073\074\075\076\077\078\079\080\081\082\083\084\085\086\087\088\089\090\097\098\099\100\101\102\103\104\105\106\107\108\109\110\111\112\113\114\115\116\117\118\119\120\121\122\048\049\050\051\052\053\054\055\056\057\043\047"for x=1,#C,1 do local I=C:sub(x,x)p[x-1]=I d[I]=x-1 end end local x do x={}for C=0,64,1 do x[C]=2^C end end local I local X do I={}X={}for C=0,63,1 do local p=BrickColor.palette(C)I[p.Number]=C X[C]=p end end local g,b=math.floor,table.insert function ToBase(C,p)C=g(C)if not p or p==10 then return tostring(C)end local d="\048\049\050\051\052\053\054\055\056\057\065\066\067\068\069\070\071\072\073\074\075\076\077\078\079\080\081\082\083\084\085\086\087\088\089\090"local x={}local I=""if C<0 then I="-"C=-C end repeat local I=C%p+1 C=g(C/p)b(x,1,d:sub(I,I))until C==0 return I..table.concat(x,"")end function C.Create()local C={}local g=0 local b={}function C.ResetPtr(C)g=0 end function C.Reset(C)b={}g=0 end local y=false function C.SetDebug(p,C)y=C end function C.FromString(d,p)C:Reset()for C=1,#p,1 do local d=(p:sub(C,C)):byte()for C=1,8,1 do g=g+1 b[g]=d%2 d=math.floor(d/2)end end g=0 end function C.ToString(C)local p=""local d=0 local I=0 for C=1,math.ceil(#b/8)*8,1 do d=d+x[I]*(b[C]or 0)I=I+1 if I>=8 then p=p..string.char(d)d=0 I=0 end end return p end function C.FromBase64(x,p)C:Reset()for C=1,#p,1 do local x=d[p:sub(C,C)]assert(x,"\066\097\100 \099\104\097\114\097\099\116\101\114\058 \048\120"..ToBase((p:sub(C,C)):byte(),16))for C=1,6,1 do g=g+1 b[g]=x%2 x=math.floor(x/2)end assert(x==0,"\067\104\097\114\097\099\116\101\114 \118\097\108\117\101 \048\120"..(ToBase(d[p:sub(C,C)],16).." \116\111\111 \108\097\114\103\101"))end C:ResetPtr()end function C.ToBase64(C)local d={}local I=0 local X=0 for C=1,math.ceil(#b/6)*6,1 do I=I+x[X]*(b[C]or 0)X=X+1 if X>=6 then table.insert(d,p[I])I=0 X=0 end end return table.concat(d)end function C.Dump(C)local p=""local d=""local I=0 local X=0 for C=1,math.ceil(#b/8)*8,1 do d=d..(b[C]or 0)I=I+x[X]*(b[C]or 0)X=X+1 if X>=8 then d=d.." "p=p..("\048\120"..(ToBase(I,16).." "))I=0 X=0 end end print("\066\121\116\101\115\058",p)print("\066\105\116\115\058",d)end local function v(C)g=g+1 b[g]=C end local function A(C)g=g+1 return b[g]end function C.WriteUnsigned(x,C,p,d)assert(C,"\066\097\100 \097\114\103\117\109\101\110\116\115 \116\111 \066\105\116\066\117\102\102\101\114\058\058\087\114\105\116\101\085\110\115\105\103\110\101\100 \040\077\105\115\115\105\110\103 \066\105\116\087\105\100\116\104\041")assert(p,"\066\097\100 \097\114\103\117\109\101\110\116\115 \116\111 \066\105\116\066\117\102\102\101\114\058\058\087\114\105\116\101\085\110\115\105\103\110\101\100 \040\077\105\115\115\105\110\103 \086\097\108\117\101\041")assert(p>=0,"\078\101\103\097\116\105\118\101 \118\097\108\117\101 \116\111 \066\105\116\066\117\102\102\101\114\058\058\087\114\105\116\101\085\110\115\105\103\110\101\100")assert(math.floor(p)==p,"\078\111\110-\105\110\116\101\103\101\114 \118\097\108\117\101 \116\111 \066\105\116\066\117\102\102\101\114\058\058\087\114\105\116\101\085\110\115\105\103\110\101\100")if y and not d then print("\087\114\105\116\101\085\110\115\105\103\110\101\100\091"..(C.."\093\058"),p)end for C=1,C,1 do v(p%2)p=math.floor(p/2)end assert(p==0,"\086\097\108\117\101 "..(tostring(p)..(" \104\097\115 \119\105\100\116\104 \103\114\101\097\116\101\114 \116\104\097\110 "..(C.."\098\105\116\115"))))end function C.ReadUnsigned(d,C,p)local I=0 for C=1,C,1 do I=I+A()*x[C-1]end if y and not p then print("\082\101\097\100\085\110\115\105\103\110\101\100\091"..(C.."\093\058"),I)end return I end function C.WriteSigned(x,p,d)assert(p and d,"\066\097\100 \097\114\103\117\109\101\110\116\115 \116\111 \066\105\116\066\117\102\102\101\114\058\058\087\114\105\116\101\083\105\103\110\101\100 \040\068\105\100 \121\111\117 \102\111\114\103\101\116 \097 \098\105\116\087\105\100\116\104\063\041")assert(math.floor(d)==d,"\078\111\110-\105\110\116\101\103\101\114 \118\097\108\117\101 \116\111 \066\105\116\066\117\102\102\101\114\058\058\087\114\105\116\101\083\105\103\110\101\100")if y then print("\087\114\105\116\101\083\105\103\110\101\100\091"..(p.."\093\058"),d)end if d<0 then v(1)d=-d else v(0)end C:WriteUnsigned(p-1,d,true)end function C.ReadSigned(d,p)local x=-1^A()local I=C:ReadUnsigned(p-1,true)if y then print("\082\101\097\100\083\105\103\110\101\100\091"..(p.."\093\058"),x*I)end return x*I end function C.WriteString(d,p)local x=7 for C=1,#p,1 do if(p:sub(C,C)):byte()>127 then x=8 break end end if x==7 then C:WriteBool(false)else C:WriteBool(true)end for d=1,#p,1 do local I=(p:sub(d,d)):byte()if I==16 then C:WriteUnsigned(x,16)C:WriteBool(true)else C:WriteUnsigned(x,I)end end C:WriteUnsigned(x,16)C:WriteBool(false)end function C.ReadString(p)local d if C:ReadBool()then d=8 else d=7 end local x=""while true do local p=C:ReadUnsigned(d)if p==16 then local p=C:ReadBool()if p then x=x..string.char(16)else break end else x=x..string.char(p)end end return x end function C.WriteBool(d,p)if y then print("\087\114\105\116\101\066\111\111\108\091\049\093\058",p and"\049"or"\048")end if p then C:WriteUnsigned(1,1,true)else C:WriteUnsigned(1,0,true)end end function C.ReadBool(p)local d=C:ReadUnsigned(1,true)==1 if y then print("\082\101\097\100\066\111\111\108\091\049\093\058",d and"\049"or"\048")end return d end function C.WriteFloat(X,p,d,I)assert(p and(d and I))local g=1 if I<0 then I=-I g=-1 end local b,y=math.frexp(I)if y==0 and b==0 then C:WriteUnsigned((p+d)+1,0)return else b=((b-.5)/.5)*x[p]end if g==-1 then C:WriteBool(true)else C:WriteBool(false)end b=math.floor(b+.5)C:WriteUnsigned(p,b)local v=x[d-1]-1 if y>v then y=v end if y<-v then y=-v end C:WriteSigned(d,y)end function C.ReadFloat(I,p,d)assert(p and d)local X=1 if C:ReadBool()then X=-1 end local g=C:ReadUnsigned(p)local b=C:ReadSigned(d)if b==0 and g==0 then return 0 end g=(g/x[p])*.5+.5 return X*math.ldexp(g,b)end function C.WriteFloat32(d,p)C:WriteFloat(23,8,p)end function C.ReadFloat32(p)return C:ReadFloat(23,8)end function C.WriteFloat64(d,p)C:WriteFloat(52,11,p)end function C.ReadFloat64(p)return C:ReadFloat(52,11)end function C.WriteBrickColor(d,p)local x=I[p.Number]if not x then warn("\065\116\116\101\109\112\116 \116\111 \115\101\114\105\097\108\105\122\101 \110\111\110-\112\097\108\108\101\116\101 \066\114\105\099\107\067\111\108\111\114 \096"..(tostring(p)..("\096 \040\035"..(p.Number.."\041\044 \117\115\105\110\103 \076\105\103\104\116 \083\116\111\110\101 \071\114\101\121 \105\110\115\116\101\097\100\046"))))x=I[(BrickColor.new(1032)).Number]end C:WriteUnsigned(6,x)end function C.ReadBrickColor(p)return X[C:ReadUnsigned(6)]end local function k(C)return math.floor(C+.5)end function C.WriteRotation(d,p)local x=p.lookVector local I=math.atan2(-x.X,-x.Z)local X=(x.X^2+x.Z^2)^.5 local g=math.atan2(x.Y,X)local b=(CFrame.new(p.p)*CFrame.Angles(0,I,0))*CFrame.Angles(g,0,0)local y,v,A=(b:inverse()*p):toEulerAnglesXYZ()local Q=A I=k((I/math.pi)*2097151.0)Q=k((Q/math.pi)*1048575.0)g=k((g/(math.pi/2))*1048575.0)C:WriteSigned(22,I)C:WriteSigned(21,Q)C:WriteSigned(21,g)end function C.ReadRotation(p)local d=C:ReadSigned(22)local x=C:ReadSigned(21)local I=C:ReadSigned(21)d=math.pi*(d/2097151.0)x=math.pi*(x/1048575.0)I=(math.pi/2)*(I/1048575.0)local X=CFrame.Angles(0,d,0)X=X*CFrame.Angles(I,0,0)X=X*CFrame.Angles(0,0,x)return X end return C end return C
--[[
	
==========================================================================
==                                	API                                 ==

Constructor: BitBuffer.Create()

Read/Write pairs for reading data from or writing data to the BitBuffer:
	BitBuffer:WriteUnsigned(bitWidth, value)
	BitBuffer:ReadUnsigned(bitWidth)
		Read / Write an unsigned value with a given number of bits. The 
		value must be a positive integer. For instance, if bitWidth is
		4, then there will be 4 magnitude bits, for a value in the
		range [0, 2^4-1] = [0, 15]
		
	BitBuffer:WriteSigned(bitWidth, value)
	BitBuffer:ReadSigned(bitWidth)
		Read / Write a a signed value with a given number of bits. For
		instance, if bitWidth is 4 then there will be 1 sign bit and
		3 magnitude bits, a value in the range [-2^3+1, 2^3-1] = [-7, 7]
		
	BitBuffer:WriteFloat(mantissaBitWidth, exponentBitWidth, value)
	BitBuffer:ReadFloat(mantissaBitWidth, exponentBitWidth)
		Read / Write a floating point number with a given mantissa and
		exponent size in bits.
		
	BitBuffer:WriteFloat32(value)
	BitBuffer:ReadFloat32()
	BitBuffer:WriteFloat64(value)
	BitBuffer:ReadFloat64()
		Read and write the common types of floating point number that
		are used in code. If you want to 100% accurately save an
		arbitrary Lua number, then you should use the Float64 format. If
		your number is known to be smaller, or you want to save space
		and don't need super high precision, then a Float32 will often
		suffice. For instance, the Transparency of an object will do
		just fine as a Float32.
		
	BitBuffer:WriteBool(value)
	BitBuffer:ReadBool()
		Read / Write a boolean (true / false) value. Takes one bit worth
		of space to store.
		
	BitBuffer:WriteString(str)
	BitBuffer:ReadString()
		Read / Write a variable length string. The string may contain
		embedded nulls. Only 7 bits / character will be used if the
		string contains no non-printable characters (greater than 0x80).
		
	BitBuffer:WriteBrickColor(color)
	BitBuffer:ReadBrickColor()
		Read / Write a roblox BrickColor. Provided as an example of 
		reading / writing a derived data type.
		
	BitBuffer:WriteRotation(cframe)
	BitBuffer:ReadRotation()
		Read / Write the rotation part of a given CFrame. Encodes the 
		rotation in question into 64bits, which is a good size to get
		a pretty dense packing, but still while having errors well within 
		the threshold that Roblox uses for stuff like MakeJoints() 
		detecting adjacency. Will also perfectly reproduce rotations which
		are orthagonally aligned, or inverse-power-of-two rotated on only
		a single axix. For other rotations, the results may not be
		perfectly stable through read-write cycles (if you read/write an
		arbitrary rotation thousands of times there may be detectable
		"drift")
	
		
From/To pairs for dumping out the BitBuffer to another format:
	BitBuffer:ToString()
	BitBuffer:FromString(str)
		Will replace / dump out the contents of the buffer to / from
		a binary chunk encoded as a Lua string. This string is NOT
		suitable for storage in the Roblox DataStores, as they do
		not handle non-printable characters well.
		
	BitBuffer:ToBase64()
	BitBuffer:FromBase64(str)
		Will replace / dump out the contents of the buffer to / from
		a set of Base64 encoded data, as a Lua string. This string
		only consists of Base64 printable characters, so it is
		ideal for storage in Roblox DataStores.
		
Buffer / Position Manipulation
	BitBuffer:ResetPtr()
		Will Reset the point in the buffer that is being read / written
		to back to the start of the buffer.
		
	BitBuffer:Reset()
		Will reset the buffer to a clean state, with no contents.

Example Usage:
	local function SaveToBuffer(buffer, userData)
		buffer:WriteString(userData.HeroName)
		buffer:WriteUnsigned(14, userData.Score) --> 14 bits -> [0, 2^14-1] -> [0, 16383]
		buffer:WriteBool(userData.HasDoneSomething)
		buffer:WriteUnsigned(10, #userData.ItemList) --> [0, 1023]
		for _, itemInfo in pairs(userData.ItemList) do
			buffer:WriteString(itemInfo.Identifier)
			buffer:WriteUnsigned(10, itemInfo.Count) --> [0, 1023]
		end
	end
	local function LoadFromBuffer(buffer, userData)
		userData.HeroName = buffer:ReadString()
		userData.Score = buffer:ReadUnsigned(14)
		userData.HasDoneSomething = buffer:ReadBool()
		local itemCount = buffer:ReadUnsigned(10)
		for i = 1, itemCount do
			local itemInfo = {}
			itemInfo.Identifier = buffer:ReadString()
			itemInfo.Count = buffer:ReadUnsigned(10)
			table.insert(userData.ItemList, itemInfo)
		end
	end
	--...
	local buff = BitBuffer.Create()
	SaveToBuffer(buff, someUserData)
	myDataStore:SetAsync(somePlayer.userId, buff:ToBase64())
	--...
	local data = myDataStore:GetAsync(somePlayer.userId)
	local buff = BitBuffer.Create()
	buff:FromBase64(data)
	LoadFromBuffer(buff, someUserData)
--]]

local BitBuffer = {}

--[[
String Encoding:
	   Char 1   Char 2
str:  LSB--MSB LSB--MSB
Bit#  1,2,...8 9,...,16
--]]

local NumberToBase64; local Base64ToNumber; do
	NumberToBase64 = {}
	Base64ToNumber = {}
	local chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
	for i = 1, #chars do
		local ch = chars:sub(i, i)
		NumberToBase64[i-1] = ch
		Base64ToNumber[ch] = i-1
	end
end

local PowerOfTwo; do
	PowerOfTwo = {}
	for i = 0, 64 do
		PowerOfTwo[i] = 2^i
	end
end

local BrickColorToNumber; local NumberToBrickColor; do
	BrickColorToNumber = {}
	NumberToBrickColor = {}
	for i = 0, 63 do
		local color = BrickColor.palette(i)
		BrickColorToNumber[color.Number] = i
		NumberToBrickColor[i] = color
	end
end

local floor,insert = math.floor, table.insert
function ToBase(n, b)
    n = floor(n)
    if not b or b == 10 then return tostring(n) end
    local digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    local t = {}
    local sign = ""
    if n < 0 then
        sign = "-"
    n = -n
    end
    repeat
        local d = (n % b) + 1
        n = floor(n / b)
        insert(t, 1, digits:sub(d, d))
    until n == 0
    return sign..table.concat(t, "")
end

function BitBuffer.Create()
	local this = {}
	
	-- Tracking
	local mBitPtr = 0
	local mBitBuffer = {}
	
	function this:ResetPtr()
		mBitPtr = 0
	end
	function this:Reset()
		mBitBuffer = {}
		mBitPtr = 0
	end
	
	-- Set debugging on
	local mDebug = false
	function this:SetDebug(state)
		mDebug = state
	end
	
	-- Read / Write to a string
	function this:FromString(str)
		this:Reset()
		for i = 1, #str do
			local ch = str:sub(i, i):byte()
			for i = 1, 8 do
				mBitPtr = mBitPtr + 1
				mBitBuffer[mBitPtr] = ch % 2
				ch = math.floor(ch / 2)
			end
		end
		mBitPtr = 0
	end
	function this:ToString()
		local str = ""
		local accum = 0
		local pow = 0
		for i = 1, math.ceil((#mBitBuffer) / 8)*8 do
			accum = accum + PowerOfTwo[pow]*(mBitBuffer[i] or 0)
			pow = pow + 1
			if pow >= 8 then
				str = str..string.char(accum)
				accum = 0
				pow = 0
			end
		end
		return str
	end
	
	-- Read / Write to base64
	function this:FromBase64(str)
		this:Reset()
		for i = 1, #str do
			local ch = Base64ToNumber[str:sub(i, i)]
			assert(ch, "Bad character: 0x"..ToBase(str:sub(i, i):byte(), 16))
			for i = 1, 6 do
				mBitPtr = mBitPtr + 1
				mBitBuffer[mBitPtr] = ch % 2
				ch = math.floor(ch / 2)
			end
			assert(ch == 0, "Character value 0x"..ToBase(Base64ToNumber[str:sub(i, i)], 16).." too large")
		end
		this:ResetPtr()
	end
	function this:ToBase64()
		local strtab = {}
		local accum = 0
		local pow = 0
		for i = 1, math.ceil((#mBitBuffer) / 6)*6 do
			accum = accum + PowerOfTwo[pow]*(mBitBuffer[i] or 0)
			pow = pow + 1
			if pow >= 6 then
				table.insert(strtab, NumberToBase64[accum])
				accum = 0
				pow = 0
			end
		end
		return table.concat(strtab)
	end	
	
	-- Dump
	function this:Dump()
		local str = ""
		local str2 = ""
		local accum = 0
		local pow = 0
		for i = 1, math.ceil((#mBitBuffer) / 8)*8 do
			str2 = str2..(mBitBuffer[i] or 0)
			accum = accum + PowerOfTwo[pow]*(mBitBuffer[i] or 0)
			--print(pow..": +"..PowerOfTwo[pow].."*["..(mBitBuffer[i] or 0).."] -> "..accum)
			pow = pow + 1
			if pow >= 8 then
				str2 = str2.." "
				str = str.."0x"..ToBase(accum, 16).." "
				accum = 0
				pow = 0
			end
		end
		print("Bytes:", str)
		print("Bits:", str2)
	end
	
	-- Read / Write a bit
	local function writeBit(v)
		mBitPtr = mBitPtr + 1
		mBitBuffer[mBitPtr] = v
	end
	local function readBit(v)
		mBitPtr = mBitPtr + 1
		return mBitBuffer[mBitPtr]
	end
	
	-- Read / Write an unsigned number
	function this:WriteUnsigned(w, value, printoff)
		assert(w, "Bad arguments to BitBuffer::WriteUnsigned (Missing BitWidth)")
		assert(value, "Bad arguments to BitBuffer::WriteUnsigned (Missing Value)")
		assert(value >= 0, "Negative value to BitBuffer::WriteUnsigned")
		assert(math.floor(value) == value, "Non-integer value to BitBuffer::WriteUnsigned")
		if mDebug and not printoff then
			print("WriteUnsigned["..w.."]:", value)
		end
		-- Store LSB first
		for i = 1, w do
			writeBit(value % 2)
			value = math.floor(value / 2)
		end
		assert(value == 0, "Value "..tostring(value).." has width greater than "..w.."bits")
	end 
	function this:ReadUnsigned(w, printoff)
		local value = 0
		for i = 1, w do
			value = value + readBit() * PowerOfTwo[i-1]
		end
		if mDebug and not printoff then
			print("ReadUnsigned["..w.."]:", value)
		end
		return value
	end
	
	-- Read / Write a signed number
	function this:WriteSigned(w, value)
		assert(w and value, "Bad arguments to BitBuffer::WriteSigned (Did you forget a bitWidth?)")
		assert(math.floor(value) == value, "Non-integer value to BitBuffer::WriteSigned")
		if mDebug then
			print("WriteSigned["..w.."]:", value)
		end
		-- Write sign
		if value < 0 then
			writeBit(1)
			value = -value
		else
			writeBit(0)
		end
		-- Write value
		this:WriteUnsigned(w-1, value, true)
	end
	function this:ReadSigned(w)
		-- Read sign
		local sign = (-1)^readBit()
		-- Read value
		local value = this:ReadUnsigned(w-1, true)
		if mDebug then
			print("ReadSigned["..w.."]:", sign*value)
		end
		return sign*value
	end
	
	-- Read / Write a string. May contain embedded nulls (string.char(0))
	function this:WriteString(s)
		-- First check if it's a 7 or 8 bit width of string
		local bitWidth = 7
		for i = 1, #s do
			if s:sub(i, i):byte() > 127 then
				bitWidth = 8
				break
			end
		end
		
		-- Write the bit width flag
		if bitWidth == 7 then
			this:WriteBool(false)
		else
			this:WriteBool(true) -- wide chars
		end
	
		-- Now write out the string, terminated with "0x10, 0b0"
		-- 0x10 is encoded as "0x10, 0b1"
		for i = 1, #s do
			local ch = s:sub(i, i):byte()
			if ch == 0x10 then
				this:WriteUnsigned(bitWidth, 0x10)
				this:WriteBool(true)
			else
				this:WriteUnsigned(bitWidth, ch)
			end
		end
		
		-- Write terminator
		this:WriteUnsigned(bitWidth, 0x10)
		this:WriteBool(false)
	end
	function this:ReadString()
		-- Get bit width
		local bitWidth;
		if this:ReadBool() then
			bitWidth = 8
		else
			bitWidth = 7
		end
		
		-- Loop
		local str = ""
		while true do
			local ch = this:ReadUnsigned(bitWidth)
			if ch == 0x10 then
				local flag = this:ReadBool()
				if flag then
					str = str..string.char(0x10)
				else
					break
				end
			else
				str = str..string.char(ch)
			end
		end
		return str
	end
	
	-- Read / Write a bool
	function this:WriteBool(v)
		if mDebug then
			print("WriteBool[1]:", v and "1" or "0")
		end
		if v then
			this:WriteUnsigned(1, 1, true)
		else
			this:WriteUnsigned(1, 0, true)
		end
	end
	function this:ReadBool()
		local v = (this:ReadUnsigned(1, true) == 1)
		if mDebug then
			print("ReadBool[1]:", v and "1" or "0")
		end
		return v
	end
	
	-- Read / Write a floating point number with |wfrac| fraction part
	-- bits, |wexp| exponent part bits, and one sign bit.
	function this:WriteFloat(wfrac, wexp, f)
		assert(wfrac and wexp and f)
		
		-- Sign
		local sign = 1
		if f < 0 then
			f = -f
			sign = -1
		end
		
		-- Decompose
		local mantissa, exponent = math.frexp(f)
		if exponent == 0 and mantissa == 0 then
			this:WriteUnsigned(wfrac + wexp + 1, 0)
			return
		else
			mantissa = ((mantissa - 0.5)/0.5 * PowerOfTwo[wfrac])
		end
		
		-- Write sign
		if sign == -1 then
			this:WriteBool(true)
		else
			this:WriteBool(false)
		end
		
		-- Write mantissa
		mantissa = math.floor(mantissa + 0.5) -- Not really correct, should round up/down based on the parity of |wexp|
		this:WriteUnsigned(wfrac, mantissa)
		
		-- Write exponent
		local maxExp = PowerOfTwo[wexp-1]-1
		if exponent > maxExp then
			exponent = maxExp
		end
		if exponent < -maxExp then
			exponent = -maxExp
		end
		this:WriteSigned(wexp, exponent)	
	end
	function this:ReadFloat(wfrac, wexp)
		assert(wfrac and wexp)
		
		-- Read sign
		local sign = 1
		if this:ReadBool() then
			sign = -1
		end
		
		-- Read mantissa
		local mantissa = this:ReadUnsigned(wfrac)
		
		-- Read exponent
		local exponent = this:ReadSigned(wexp)
		if exponent == 0 and mantissa == 0 then
			return 0
		end
		
		-- Convert mantissa
		mantissa = mantissa / PowerOfTwo[wfrac] * 0.5 + 0.5
		
		-- Output
		return sign * math.ldexp(mantissa, exponent)
	end
	
	-- Read / Write single precision floating point
	function this:WriteFloat32(f)
		this:WriteFloat(23, 8, f)
	end
	function this:ReadFloat32()
		return this:ReadFloat(23, 8)
	end
	
	-- Read / Write double precision floating point
	function this:WriteFloat64(f)
		this:WriteFloat(52, 11, f)
	end
	function this:ReadFloat64()
		return this:ReadFloat(52, 11)
	end
	
	-- Read / Write a BrickColor
	function this:WriteBrickColor(b)
		local pnum = BrickColorToNumber[b.Number]
		if not pnum then
			warn("Attempt to serialize non-pallete BrickColor `"..tostring(b).."` (#"..b.Number.."), using Light Stone Grey instead.")
			pnum = BrickColorToNumber[BrickColor.new(1032).Number]
		end
		this:WriteUnsigned(6, pnum)
	end
	function this:ReadBrickColor()
		return NumberToBrickColor[this:ReadUnsigned(6)]
	end
	
	-- Read / Write a rotation as a 64bit value.
	local function round(n)
		return math.floor(n + 0.5)
	end
	function this:WriteRotation(cf)
		local lookVector = cf.lookVector
		local azumith = math.atan2(-lookVector.X, -lookVector.Z)
		local ybase = (lookVector.X^2 + lookVector.Z^2)^0.5
		local elevation = math.atan2(lookVector.Y, ybase)
		local withoutRoll = CFrame.new(cf.p) * CFrame.Angles(0, azumith, 0) * CFrame.Angles(elevation, 0, 0)
		local x, y, z = (withoutRoll:inverse()*cf):toEulerAnglesXYZ()
		local roll = z
		-- Atan2 -> in the range [-pi, pi] 
		azumith   = round((azumith   /  math.pi   ) * (2^21-1))
		roll      = round((roll      /  math.pi   ) * (2^20-1))
		elevation = round((elevation / (math.pi/2)) * (2^20-1))
		--
		this:WriteSigned(22, azumith)
		this:WriteSigned(21, roll)
		this:WriteSigned(21, elevation)
	end
	function this:ReadRotation()
		local azumith   = this:ReadSigned(22)
		local roll      = this:ReadSigned(21)
		local elevation = this:ReadSigned(21)
		--
		azumith =    math.pi    * (azumith / (2^21-1))
		roll =       math.pi    * (roll    / (2^20-1))
		elevation = (math.pi/2) * (elevation / (2^20-1))
		--
		local rot = CFrame.Angles(0, azumith, 0)
		rot = rot * CFrame.Angles(elevation, 0, 0)
		rot = rot * CFrame.Angles(0, 0, roll)
		--
		return rot
	end
	
	return this
end

return BitBuffer