local H=game:GetService("\072\116\116\112\083\101\114\118\105\099\101")local k=require(script.Parent.MockDataStoreConstants)local F=require(script.Parent.MockDataStoreManager)local u=require(script.Parent.MockDataStorePages)local v=require(script.Parent.MockDataStoreUtils)local Z={}Z.__index=Z local O=Random.new()function Z.OnUpdate(Z,H,u)H=v.preprocessKey(H)if type(H)~="\115\116\114\105\110\103"then error(string.format("\098\097\100 \097\114\103\117\109\101\110\116 \035\049 \116\111 \'\079\110\085\112\100\097\116\101\' \040\115\116\114\105\110\103 \101\120\112\101\099\116\101\100\044 \103\111\116 \037\115\041",typeof(H)),2)elseif type(u)~="\102\117\110\099\116\105\111\110"then error(string.format("\098\097\100 \097\114\103\117\109\101\110\116 \035\050 \116\111 \'\079\110\085\112\100\097\116\101\' \040\102\117\110\099\116\105\111\110 \101\120\112\101\099\116\101\100\044 \103\111\116 \037\115\041",typeof(u)),2)elseif#H==0 then error("\098\097\100 \097\114\103\117\109\101\110\116 \035\049 \116\111 \'\079\110\085\112\100\097\116\101\' \040\107\101\121 \110\097\109\101 \099\097\110\'\116 \098\101 \101\109\112\116\121\041",2)elseif#H>k.MAX_LENGTH_KEY then error(string.format("\098\097\100 \097\114\103\117\109\101\110\116 \035\049 \116\111 \'\079\110\085\112\100\097\116\101\' \040\107\101\121 \110\097\109\101 \101\120\099\101\101\100\115 \037\100 \099\104\097\114\097\099\116\101\114 \108\105\109\105\116\041",k.MAX_LENGTH_KEY),2)end v.simulateErrorCheck("\079\110\085\112\100\097\116\101")local L=F.YieldForBudget(function()warn(string.format("\079\110\085\112\100\097\116\101 \114\101\113\117\101\115\116 \119\097\115 \116\104\114\111\116\116\108\101\100 \100\117\101 \116\111 \108\097\099\107 \111\102 \098\117\100\103\101\116\046 \084\114\121 \115\101\110\100\105\110\103 \102\101\119\101\114 \114\101\113\117\101\115\116\115\046 \075\101\121 \061 \037\115",H))end,table.create(1,Enum.DataStoreRequestType.OnUpdate))if not L then error("\079\110\085\112\100\097\116\101 \114\101\106\101\099\116\101\100 \119\105\116\104 \101\114\114\111\114 \040\114\101\113\117\101\115\116 \119\097\115 \116\104\114\111\116\116\108\101\100\044 \098\117\116 \116\104\114\111\116\116\108\101\100 \113\117\101\117\101 \119\097\115 \102\117\108\108\041",2)end v.logMethod(Z,"\079\110\085\112\100\097\116\101",H)return Z.__event.Event:Connect(function(F,Z)if F==H then if k.YIELD_TIME_UPDATE_MAX>0 then v.accurateWait(O:NextNumber(k.YIELD_TIME_UPDATE_MIN,k.YIELD_TIME_UPDATE_MAX))end u(Z)end end)end function Z.GetAsync(u,H)H=v.preprocessKey(H)if type(H)~="\115\116\114\105\110\103"then error(string.format("\098\097\100 \097\114\103\117\109\101\110\116 \035\049 \116\111 \'\071\101\116\065\115\121\110\099\' \040\115\116\114\105\110\103 \101\120\112\101\099\116\101\100\044 \103\111\116 \037\115\041",typeof(H)),2)elseif#H==0 then error("\098\097\100 \097\114\103\117\109\101\110\116 \035\049 \116\111 \'\071\101\116\065\115\121\110\099\' \040\107\101\121 \110\097\109\101 \099\097\110\'\116 \098\101 \101\109\112\116\121\041",2)elseif#H>k.MAX_LENGTH_KEY then error(string.format("\098\097\100 \097\114\103\117\109\101\110\116 \035\049 \116\111 \'\071\101\116\065\115\121\110\099\' \040\107\101\121 \110\097\109\101 \101\120\099\101\101\100\115 \037\100 \099\104\097\114\097\099\116\101\114 \108\105\109\105\116\041",k.MAX_LENGTH_KEY),2)end if u.__getCache[H]and tick()-u.__getCache[H]<k.GET_COOLDOWN then return u.__data[H]end v.simulateErrorCheck("\071\101\116\065\115\121\110\099")local Z=F.YieldForBudget(function()warn(string.format("\071\101\116\065\115\121\110\099 \114\101\113\117\101\115\116 \119\097\115 \116\104\114\111\116\116\108\101\100 \100\117\101 \116\111 \108\097\099\107 \111\102 \098\117\100\103\101\116\046 \084\114\121 \115\101\110\100\105\110\103 \102\101\119\101\114 \114\101\113\117\101\115\116\115\046 \075\101\121 \061 \037\115",H))end,table.create(1,Enum.DataStoreRequestType.GetAsync))if not Z then error("\071\101\116\065\115\121\110\099 \114\101\106\101\099\116\101\100 \119\105\116\104 \101\114\114\111\114 \040\114\101\113\117\101\115\116 \119\097\115 \116\104\114\111\116\116\108\101\100\044 \098\117\116 \116\104\114\111\116\116\108\101\100 \113\117\101\117\101 \119\097\115 \102\117\108\108\041",2)end local O=u.__data[H]v.simulateYield()u.__getCache[H]=tick()v.logMethod(u,"\071\101\116\065\115\121\110\099",H)return O end function Z.IncrementAsync(Z,H,u)H=v.preprocessKey(H)if type(H)~="\115\116\114\105\110\103"then error(string.format("\098\097\100 \097\114\103\117\109\101\110\116 \035\049 \116\111 \'\073\110\099\114\101\109\101\110\116\065\115\121\110\099\' \040\115\116\114\105\110\103 \101\120\112\101\099\116\101\100\044 \103\111\116 \037\115\041",typeof(H)),2)elseif u~=nil and type(u)~="\110\117\109\098\101\114"then error(string.format("\098\097\100 \097\114\103\117\109\101\110\116 \035\050 \116\111 \'\073\110\099\114\101\109\101\110\116\065\115\121\110\099\' \040\110\117\109\098\101\114 \101\120\112\101\099\116\101\100\044 \103\111\116 \037\115\041",typeof(u)),2)elseif#H==0 then error("\098\097\100 \097\114\103\117\109\101\110\116 \035\049 \116\111 \'\073\110\099\114\101\109\101\110\116\065\115\121\110\099\' \040\107\101\121 \110\097\109\101 \099\097\110\'\116 \098\101 \101\109\112\116\121\041",2)elseif#H>k.MAX_LENGTH_KEY then error(string.format("\098\097\100 \097\114\103\117\109\101\110\116 \035\049 \116\111 \'\073\110\099\114\101\109\101\110\116\065\115\121\110\099\' \040\107\101\121 \110\097\109\101 \101\120\099\101\101\100\115 \037\100 \099\104\097\114\097\099\116\101\114 \108\105\109\105\116\041",k.MAX_LENGTH_KEY),2)end v.simulateErrorCheck("\073\110\099\114\101\109\101\110\116\065\115\121\110\099")local O if Z.__writeLock[H]or tick()-(Z.__writeCache[H]or 0)<k.WRITE_COOLDOWN then O=F.YieldForWriteLockAndBudget(function()warn(string.format("\073\110\099\114\101\109\101\110\116\065\115\121\110\099 \114\101\113\117\101\115\116 \119\097\115 \116\104\114\111\116\116\108\101\100\044 \097 \107\101\121 \099\097\110 \111\110\108\121 \098\101 \119\114\105\116\116\101\110 \116\111 \111\110\099\101 \101\118\101\114\121 \037\100 \115\101\099\111\110\100\115\046 \075\101\121 \061 \037\115",k.WRITE_COOLDOWN,H))end,H,Z.__writeLock,Z.__writeCache,table.create(1,Enum.DataStoreRequestType.SetIncrementSortedAsync))else Z.__writeLock[H]=true O=F.YieldForBudget(function()warn(string.format("\073\110\099\114\101\109\101\110\116\065\115\121\110\099 \114\101\113\117\101\115\116 \119\097\115 \116\104\114\111\116\116\108\101\100 \100\117\101 \116\111 \108\097\099\107 \111\102 \098\117\100\103\101\116\046 \084\114\121 \115\101\110\100\105\110\103 \102\101\119\101\114 \114\101\113\117\101\115\116\115\046 \075\101\121 \061 \037\115",H))end,table.create(1,Enum.DataStoreRequestType.SetIncrementSortedAsync))Z.__writeLock[H]=nil end if not O then error("\073\110\099\114\101\109\101\110\116\065\115\121\110\099 \114\101\106\101\099\116\101\100 \119\105\116\104 \101\114\114\111\114 \040\114\101\113\117\101\115\116 \119\097\115 \116\104\114\111\116\116\108\101\100\044 \098\117\116 \116\104\114\111\116\116\108\101\100 \113\117\101\117\101 \119\097\115 \102\117\108\108\041",2)end local L=Z.__data[H]if L~=nil and(type(L)~="\110\117\109\098\101\114"or L%1~=0)then v.simulateYield()error("\073\110\099\114\101\109\101\110\116\065\115\121\110\099 \114\101\106\101\099\116\101\100 \119\105\116\104 \101\114\114\111\114 \040\099\097\110\110\111\116 \105\110\099\114\101\109\101\110\116 \110\111\110-\105\110\116\101\103\101\114 \118\097\108\117\101\041",2)end Z.__writeLock[H]=true u=u and math.floor(u+.5)or 1 if L==nil then Z.__data[H]=u Z.__ref[H]={Key=H;Value=Z.__data[H]}table.insert(Z.__sorted,Z.__ref[H])Z.__changed=true Z.__event:Fire(H,Z.__data[H])elseif u~=0 then Z.__data[H]=Z.__data[H]+u Z.__ref[H].Value=Z.__data[H]Z.__changed=true Z.__event:Fire(H,Z.__data[H])end local X=Z.__data[H]v.simulateYield()Z.__writeLock[H]=nil Z.__writeCache[H]=tick()Z.__getCache[H]=tick()v.logMethod(Z,"\073\110\099\114\101\109\101\110\116\065\115\121\110\099",H,X,u)return X end function Z.RemoveAsync(u,H)H=v.preprocessKey(H)if type(H)~="\115\116\114\105\110\103"then error(string.format("\098\097\100 \097\114\103\117\109\101\110\116 \035\049 \116\111 \'\082\101\109\111\118\101\065\115\121\110\099\' \040\115\116\114\105\110\103 \101\120\112\101\099\116\101\100\044 \103\111\116 \037\115\041",type(H)),2)elseif#H==0 then error("\098\097\100 \097\114\103\117\109\101\110\116 \035\049 \116\111 \'\082\101\109\111\118\101\065\115\121\110\099\' \040\107\101\121 \110\097\109\101 \099\097\110\'\116 \098\101 \101\109\112\116\121\041",2)elseif#H>k.MAX_LENGTH_KEY then error(string.format("\098\097\100 \097\114\103\117\109\101\110\116 \035\049 \116\111 \'\082\101\109\111\118\101\065\115\121\110\099\' \040\107\101\121 \110\097\109\101 \101\120\099\101\101\100\115 \037\100 \099\104\097\114\097\099\116\101\114 \108\105\109\105\116\041",k.MAX_LENGTH_KEY),2)end v.simulateErrorCheck("\082\101\109\111\118\101\065\115\121\110\099")local Z if u.__writeLock[H]or tick()-(u.__writeCache[H]or 0)<k.WRITE_COOLDOWN then Z=F.YieldForWriteLockAndBudget(function()warn(string.format("\082\101\109\111\118\101\065\115\121\110\099 \114\101\113\117\101\115\116 \119\097\115 \116\104\114\111\116\116\108\101\100\044 \097 \107\101\121 \099\097\110 \111\110\108\121 \098\101 \119\114\105\116\116\101\110 \116\111 \111\110\099\101 \101\118\101\114\121 \037\100 \115\101\099\111\110\100\115\046 \075\101\121 \061 \037\115",k.WRITE_COOLDOWN,H))end,H,u.__writeLock,u.__writeCache,table.create(1,Enum.DataStoreRequestType.SetIncrementSortedAsync))else u.__writeLock[H]=true Z=F.YieldForBudget(function()warn(string.format("\082\101\109\111\118\101\065\115\121\110\099 \114\101\113\117\101\115\116 \119\097\115 \116\104\114\111\116\116\108\101\100 \100\117\101 \116\111 \108\097\099\107 \111\102 \098\117\100\103\101\116\046 \084\114\121 \115\101\110\100\105\110\103 \102\101\119\101\114 \114\101\113\117\101\115\116\115\046 \075\101\121 \061 \037\115",H))end,table.create(1,Enum.DataStoreRequestType.SetIncrementSortedAsync))u.__writeLock[H]=nil end if not Z then error("\082\101\109\111\118\101\065\115\121\110\099 \114\101\106\101\099\116\101\100 \119\105\116\104 \101\114\114\111\114 \040\114\101\113\117\101\115\116 \119\097\115 \116\104\114\111\116\116\108\101\100\044 \098\117\116 \116\104\114\111\116\116\108\101\100 \113\117\101\117\101 \119\097\115 \102\117\108\108\041",2)end u.__writeLock[H]=true local O=u.__data[H]if O~=nil then u.__data[H]=nil u.__ref[H]=nil for k,F in ipairs(u.__sorted)do if F.Key==H then table.remove(u.__sorted,k)break end end u.__event:Fire(H,nil)end v.simulateYield()u.__writeLock[H]=nil u.__writeCache[H]=tick()v.logMethod(u,"\082\101\109\111\118\101\065\115\121\110\099",H,O)return O end function Z.SetAsync(Z,H,u)H=v.preprocessKey(H)if type(H)~="\115\116\114\105\110\103"then error(string.format("\098\097\100 \097\114\103\117\109\101\110\116 \035\049 \116\111 \'\083\101\116\065\115\121\110\099\' \040\115\116\114\105\110\103 \101\120\112\101\099\116\101\100\044 \103\111\116 \037\115\041",typeof(H)),2)elseif#H==0 then error("\098\097\100 \097\114\103\117\109\101\110\116 \035\049 \116\111 \'\083\101\116\065\115\121\110\099\' \040\107\101\121 \110\097\109\101 \099\097\110\'\116 \098\101 \101\109\112\116\121\041",2)elseif#H>k.MAX_LENGTH_KEY then error(string.format("\098\097\100 \097\114\103\117\109\101\110\116 \035\049 \116\111 \'\083\101\116\065\115\121\110\099\' \040\107\101\121 \110\097\109\101 \101\120\099\101\101\100\115 \037\100 \099\104\097\114\097\099\116\101\114 \108\105\109\105\116\041",k.MAX_LENGTH_KEY),2)elseif type(u)~="\110\117\109\098\101\114"then error(string.format("\098\097\100 \097\114\103\117\109\101\110\116 \035\050 \116\111 \'\083\101\116\065\115\121\110\099\' \040\110\117\109\098\101\114 \101\120\112\101\099\116\101\100\044 \103\111\116 \037\115\041",typeof(u)),2)elseif u%1~=0 then error("\098\097\100 \097\114\103\117\109\101\110\116 \035\050 \116\111 \'\083\101\116\065\115\121\110\099\' \040\099\097\110\110\111\116 \115\116\111\114\101 \110\111\110-\105\110\116\101\103\101\114 \118\097\108\117\101\115 \105\110 \079\114\100\101\114\101\100\068\097\116\097\083\116\111\114\101\041",2)end v.simulateErrorCheck("\083\101\116\065\115\121\110\099")local O if Z.__writeLock[H]or tick()-(Z.__writeCache[H]or 0)<k.WRITE_COOLDOWN then O=F.YieldForWriteLockAndBudget(function()warn(string.format("\083\101\116\065\115\121\110\099 \114\101\113\117\101\115\116 \119\097\115 \116\104\114\111\116\116\108\101\100\044 \097 \107\101\121 \099\097\110 \111\110\108\121 \098\101 \119\114\105\116\116\101\110 \116\111 \111\110\099\101 \101\118\101\114\121 \037\100 \115\101\099\111\110\100\115\046 \075\101\121 \061 \037\115",k.WRITE_COOLDOWN,H))end,H,Z.__writeLock,Z.__writeCache,table.create(1,Enum.DataStoreRequestType.SetIncrementSortedAsync))else Z.__writeLock[H]=true O=F.YieldForBudget(function()warn(string.format("\083\101\116\065\115\121\110\099 \114\101\113\117\101\115\116 \119\097\115 \116\104\114\111\116\116\108\101\100 \100\117\101 \116\111 \108\097\099\107 \111\102 \098\117\100\103\101\116\046 \084\114\121 \115\101\110\100\105\110\103 \102\101\119\101\114 \114\101\113\117\101\115\116\115\046 \075\101\121 \061 \037\115",H))end,table.create(1,Enum.DataStoreRequestType.SetIncrementSortedAsync))Z.__writeLock[H]=nil end if not O then error("\083\101\116\065\115\121\110\099 \114\101\106\101\099\116\101\100 \119\105\116\104 \101\114\114\111\114 \040\114\101\113\117\101\115\116 \119\097\115 \116\104\114\111\116\116\108\101\100\044 \098\117\116 \116\104\114\111\116\116\108\101\100 \113\117\101\117\101 \119\097\115 \102\117\108\108\041",2)end Z.__writeLock[H]=true local L=Z.__data[H]if L==nil then Z.__data[H]=u Z.__ref[H]={Key=H;Value=u}table.insert(Z.__sorted,Z.__ref[H])Z.__changed=true Z.__event:Fire(H,Z.__data[H])elseif L~=u then Z.__data[H]=u Z.__ref[H].Value=u Z.__changed=true Z.__event:Fire(H,Z.__data[H])end v.simulateYield()Z.__writeLock[H]=nil Z.__writeCache[H]=tick()v.logMethod(Z,"\083\101\116\065\115\121\110\099",H,Z.__data[H])return u end function Z.UpdateAsync(Z,H,u)H=v.preprocessKey(H)if type(H)~="\115\116\114\105\110\103"then error(string.format("\098\097\100 \097\114\103\117\109\101\110\116 \035\049 \116\111 \'\085\112\100\097\116\101\065\115\121\110\099\' \040\115\116\114\105\110\103 \101\120\112\101\099\116\101\100\044 \103\111\116 \037\115\041",typeof(H)),2)elseif type(u)~="\102\117\110\099\116\105\111\110"then error(string.format("\098\097\100 \097\114\103\117\109\101\110\116 \035\050 \116\111 \'\085\112\100\097\116\101\065\115\121\110\099\' \040\102\117\110\099\116\105\111\110 \101\120\112\101\099\116\101\100\044 \103\111\116 \037\115\041",typeof(u)),2)elseif#H==0 then error("\098\097\100 \097\114\103\117\109\101\110\116 \035\049 \116\111 \'\085\112\100\097\116\101\065\115\121\110\099\' \040\107\101\121 \110\097\109\101 \099\097\110\'\116 \098\101 \101\109\112\116\121\041",2)elseif#H>k.MAX_LENGTH_KEY then error(string.format("\098\097\100 \097\114\103\117\109\101\110\116 \035\049 \116\111 \'\085\112\100\097\116\101\065\115\121\110\099\' \040\107\101\121 \110\097\109\101 \101\120\099\101\101\100\115 \037\100 \099\104\097\114\097\099\116\101\114 \108\105\109\105\116\041",k.MAX_LENGTH_KEY),2)end v.simulateErrorCheck("\085\112\100\097\116\101\065\115\121\110\099")local O if Z.__writeLock[H]or tick()-(Z.__writeCache[H]or 0)<k.WRITE_COOLDOWN then O=F.YieldForWriteLockAndBudget(function()warn(string.format("\085\112\100\097\116\101\065\115\121\110\099 \114\101\113\117\101\115\116 \119\097\115 \116\104\114\111\116\116\108\101\100\044 \097 \107\101\121 \099\097\110 \111\110\108\121 \098\101 \119\114\105\116\116\101\110 \116\111 \111\110\099\101 \101\118\101\114\121 \037\100 \115\101\099\111\110\100\115\046 \075\101\121 \061 \037\115",k.WRITE_COOLDOWN,H))end,H,Z.__writeLock,Z.__writeCache,table.create(1,Enum.DataStoreRequestType.SetIncrementSortedAsync))else Z.__writeLock[H]=true local u if Z.__getCache[H]and tick()-Z.__getCache[H]<k.GET_COOLDOWN then u=table.create(1,Enum.DataStoreRequestType.SetIncrementSortedAsync)else u={Enum.DataStoreRequestType.GetAsync,Enum.DataStoreRequestType.SetIncrementSortedAsync}end O=F.YieldForBudget(function()warn(string.format("\085\112\100\097\116\101\065\115\121\110\099 \114\101\113\117\101\115\116 \119\097\115 \116\104\114\111\116\116\108\101\100 \100\117\101 \116\111 \108\097\099\107 \111\102 \098\117\100\103\101\116\046 \084\114\121 \115\101\110\100\105\110\103 \102\101\119\101\114 \114\101\113\117\101\115\116\115\046 \075\101\121 \061 \037\115",H))end,u)Z.__writeLock[H]=nil end if not O then error("\085\112\100\097\116\101\065\115\121\110\099 \114\101\106\101\099\116\101\100 \119\105\116\104 \101\114\114\111\114 \040\114\101\113\117\101\115\116 \119\097\115 \116\104\114\111\116\116\108\101\100\044 \098\117\116 \116\104\114\111\116\116\108\101\100 \113\117\101\117\101 \119\097\115 \102\117\108\108\041",2)end local L=u(Z.__data[H])if L==nil then v.simulateYield()return nil end if type(L)~="\110\117\109\098\101\114"or L%1~=0 then error("\085\112\100\097\116\101\065\115\121\110\099 \114\101\106\101\099\116\101\100 \119\105\116\104 \101\114\114\111\114 \040\114\101\115\117\108\116\105\110\103 \110\111\110-\105\110\116\101\103\101\114 \118\097\108\117\101 \099\097\110\'\116 \098\101 \115\116\111\114\101\100 \105\110 \079\114\100\101\114\101\100\068\097\116\097\083\116\111\114\101\041",2)end Z.__writeLock[H]=true local X=Z.__data[H]if X==nil then Z.__data[H]=L Z.__ref[H]={Key=H,Value=L}table.insert(Z.__sorted,Z.__ref[H])Z.__changed=true Z.__event:Fire(H,Z.__data[H])elseif X~=L then Z.__data[H]=L Z.__ref[H].Value=L Z.__changed=true Z.__event:Fire(H,Z.__data[H])end v.simulateYield()Z.__writeLock[H]=nil Z.__writeCache[H]=tick()Z.__getCache[H]=tick()v.logMethod(Z,"\085\112\100\097\116\101\065\115\121\110\099",H,L)return L end function Z.GetSortedAsync(X,H,Z,O,L)if type(H)~="\098\111\111\108\101\097\110"then error(string.format("\098\097\100 \097\114\103\117\109\101\110\116 \035\049 \116\111 \'\071\101\116\083\111\114\116\101\100\065\115\121\110\099\' \040\098\111\111\108\101\097\110 \101\120\112\101\099\116\101\100\044 \103\111\116 \037\115\041",typeof(H)),2)elseif type(Z)~="\110\117\109\098\101\114"then error(string.format("\098\097\100 \097\114\103\117\109\101\110\116 \035\050 \116\111 \'\071\101\116\083\111\114\116\101\100\065\115\121\110\099\' \040\110\117\109\098\101\114 \101\120\112\101\099\116\101\100\044 \103\111\116 \037\115\041",typeof(Z)),2)end Z=math.floor(Z+.5)if Z<=0 or Z>k.MAX_PAGE_SIZE then error(string.format("\098\097\100 \097\114\103\117\109\101\110\116 \035\050 \116\111 \'\071\101\116\083\111\114\116\101\100\065\115\121\110\099\' \040\112\097\103\101 \115\105\122\101 \109\117\115\116 \098\101 \097\110 \105\110\116\101\103\101\114 \097\098\111\118\101 \048 \097\110\100 \098\101\108\111\119 \111\114 \101\113\117\097\108 \116\111 \037\100\041",k.MAX_PAGE_SIZE),2)end if O~=nil then if type(O)~="\110\117\109\098\101\114"then error(string.format("\098\097\100 \097\114\103\117\109\101\110\116 \035\051 \116\111 \'\071\101\116\083\111\114\116\101\100\065\115\121\110\099\' \040\110\117\109\098\101\114 \101\120\112\101\099\116\101\100\044 \103\111\116 \037\115\041",typeof(O)),2)elseif O%1~=0 then error("\098\097\100 \097\114\103\117\109\101\110\116 \035\051 \116\111 \'\071\101\116\083\111\114\116\101\100\065\115\121\110\099\' \040\109\105\110\105\109\117\109 \116\104\114\101\115\104\111\108\100 \109\117\115\116 \098\101 \097\110 \105\110\116\101\103\101\114\041",2)end else O=-math.huge end if L~=nil then if type(L)~="\110\117\109\098\101\114"then error(string.format("\098\097\100 \097\114\103\117\109\101\110\116 \035\052 \116\111 \'\071\101\116\083\111\114\116\101\100\065\115\121\110\099\' \040\110\117\109\098\101\114 \101\120\112\101\099\116\101\100\044 \103\111\116 \037\115\041",typeof(L)),2)elseif L%1~=0 then error("\098\097\100 \097\114\103\117\109\101\110\116 \035\052 \116\111 \'\071\101\116\083\111\114\116\101\100\065\115\121\110\099\' \040\109\097\120\105\109\117\109 \116\104\114\101\115\104\111\108\100 \109\117\115\116 \098\101 \097\110 \105\110\116\101\103\101\114\041",2)end else L=math.huge end v.simulateErrorCheck("\071\101\116\083\111\114\116\101\100\065\115\121\110\099")local t=F.YieldForBudget(function()warn("\071\101\116\083\111\114\116\101\100\065\115\121\110\099 \114\101\113\117\101\115\116 \119\097\115 \116\104\114\111\116\116\108\101\100 \100\117\101 \116\111 \108\097\099\107 \111\102 \098\117\100\103\101\116\046 \084\114\121 \115\101\110\100\105\110\103 \102\101\119\101\114 \114\101\113\117\101\115\116\115\046")end,table.create(1,Enum.DataStoreRequestType.GetSortedAsync))if not t then error("\071\101\116\083\111\114\116\101\100\065\115\121\110\099 \114\101\106\101\099\116\101\100 \119\105\116\104 \101\114\114\111\114 \040\114\101\113\117\101\115\116 \119\097\115 \116\104\114\111\116\116\108\101\100\044 \098\117\116 \116\104\114\111\116\116\108\101\100 \113\117\101\117\101 \119\097\115 \102\117\108\108\041",2)end if O>L then v.simulateYield()error("\071\101\116\083\111\114\116\101\100\065\115\121\110\099 \114\101\106\101\099\116\101\100 \119\105\116\104 \101\114\114\111\114 \040\109\105\110\105\109\117\109 \116\104\114\101\115\104\111\108\100 \105\115 \104\105\103\104\101\114 \116\104\097\110 \109\097\120\105\109\117\109 \116\104\114\101\115\104\111\108\100\041",2)end if X.__changed then table.sort(X.__sorted,function(H,k)return H.Value<k.Value end)X.__changed=false end local y={}if H then local H=1 while X.__sorted[H]and X.__sorted[H].Value<O do H+=1 end while X.__sorted[H]and X.__sorted[H].Value<=L do table.insert(y,{key=X.__sorted[H].Key,value=X.__sorted[H].Value})H+=1 end else local H=#X.__sorted while H>0 and X.__sorted[H].Value>L do H-=1 end while H>0 and X.__sorted[H].Value>=O do table.insert(y,{key=X.__sorted[H].Key,value=X.__sorted[H].Value})H-=1 end end v.simulateYield()v.logMethod(X,"\071\101\116\083\111\114\116\101\100\065\115\121\110\099")return setmetatable({__datastore=X;__currentPage=1;__pageSize=Z,__results=y;IsFinished=#y<=Z},u)end function Z.ExportToJSON(k)return H:JSONEncode(k.__data)end local function L(k)return H:JSONDecode(k)end function Z.ImportFromJSON(u,H,k)local Z if type(H)=="\115\116\114\105\110\103"then local k,F=pcall(L,H)if not k then error("\098\097\100 \097\114\103\117\109\101\110\116 \035\049 \116\111 \'\073\109\112\111\114\116\070\114\111\109\074\083\079\078\' \040\115\116\114\105\110\103 \105\115 \110\111\116 \118\097\108\105\100 \106\115\111\110\041",2)end Z=F elseif type(H)=="\116\097\098\108\101"then Z=H else error(string.format("\098\097\100 \097\114\103\117\109\101\110\116 \035\049 \116\111 \'\073\109\112\111\114\116\070\114\111\109\074\083\079\078\' \040\115\116\114\105\110\103 \111\114 \116\097\098\108\101 \101\120\112\101\099\116\101\100\044 \103\111\116 \037\115\041",typeof(H)),2)end if k~=nil and type(k)~="\098\111\111\108\101\097\110"then error(string.format("\098\097\100 \097\114\103\117\109\101\110\116 \035\050 \116\111 \'\073\109\112\111\114\116\070\114\111\109\074\083\079\078\' \040\098\111\111\108\101\097\110 \101\120\112\101\099\116\101\100\044 \103\111\116 \037\115\041",typeof(k)),2)end v.importPairsFromTable(Z,u.__data,F.GetDataInterface(u.__data),k==false and function() end or warn,"\073\109\112\111\114\116\070\114\111\109\074\083\079\078",string.format("\079\114\100\101\114\101\100\068\097\116\097\083\116\111\114\101 \062 \037\115 \062 \037\115",u.__name,u.__scope),true)end return Z
--[[
	MockOrderedDataStore.lua
	This module implements the API and functionality of Roblox's OrderedDataStore class.

	This module is licensed under APLv2, refer to the LICENSE file or:
	https://github.com/buildthomas/MockDataStoreService/blob/master/LICENSE
]]

local HttpService = game:GetService("HttpService") -- for json encode/decode
local Constants = require(script.Parent.MockDataStoreConstants)
local MockDataStoreManager = require(script.Parent.MockDataStoreManager)
local MockDataStorePages = require(script.Parent.MockDataStorePages)
local Utils = require(script.Parent.MockDataStoreUtils)

local MockOrderedDataStore = {}
MockOrderedDataStore.__index = MockOrderedDataStore

local rand = Random.new()

function MockOrderedDataStore:OnUpdate(key, callback)
	key = Utils.preprocessKey(key)
	if type(key) ~= "string" then
		error(string.format("bad argument #1 to 'OnUpdate' (string expected, got %s)", typeof(key)), 2)
	elseif type(callback) ~= "function" then
		error(string.format("bad argument #2 to 'OnUpdate' (function expected, got %s)", typeof(callback)), 2)
	elseif #key == 0 then
		error("bad argument #1 to 'OnUpdate' (key name can't be empty)", 2)
	elseif #key > Constants.MAX_LENGTH_KEY then
		error(
			string.format(
				"bad argument #1 to 'OnUpdate' (key name exceeds %d character limit)",
				Constants.MAX_LENGTH_KEY
			),
			2
		)
	end

	Utils.simulateErrorCheck("OnUpdate")
	local success = MockDataStoreManager.YieldForBudget(function()
		warn(
			string.format(
				"OnUpdate request was throttled due to lack of budget. Try sending fewer requests. Key = %s",
				key
			)
		)
	end, table.create(1, Enum.DataStoreRequestType.OnUpdate))

	if not success then
		error("OnUpdate rejected with error (request was throttled, but throttled queue was full)", 2)
	end

	Utils.logMethod(self, "OnUpdate", key)
	return self.__event.Event:Connect(function(k, v)
		if k == key then
			if Constants.YIELD_TIME_UPDATE_MAX > 0 then
				Utils.accurateWait(rand:NextNumber(Constants.YIELD_TIME_UPDATE_MIN, Constants.YIELD_TIME_UPDATE_MAX))
			end

			callback(v) -- v was implicitly deep-copied
		end
	end)
end

function MockOrderedDataStore:GetAsync(key)
	key = Utils.preprocessKey(key)
	if type(key) ~= "string" then
		error(string.format("bad argument #1 to 'GetAsync' (string expected, got %s)", typeof(key)), 2)
	elseif #key == 0 then
		error("bad argument #1 to 'GetAsync' (key name can't be empty)", 2)
	elseif #key > Constants.MAX_LENGTH_KEY then
		error(
			string.format(
				"bad argument #1 to 'GetAsync' (key name exceeds %d character limit)",
				Constants.MAX_LENGTH_KEY
			),
			2
		)
	end

	if self.__getCache[key] and tick() - self.__getCache[key] < Constants.GET_COOLDOWN then
		return self.__data[key]
	end

	Utils.simulateErrorCheck("GetAsync")

	local success = MockDataStoreManager.YieldForBudget(function()
		warn(
			string.format(
				"GetAsync request was throttled due to lack of budget. Try sending fewer requests. Key = %s",
				key
			)
		)
	end, table.create(1, Enum.DataStoreRequestType.GetAsync))

	if not success then
		error("GetAsync rejected with error (request was throttled, but throttled queue was full)", 2)
	end

	local retValue = self.__data[key]
	Utils.simulateYield()
	self.__getCache[key] = tick()
	Utils.logMethod(self, "GetAsync", key)
	return retValue
end

function MockOrderedDataStore:IncrementAsync(key, delta)
	key = Utils.preprocessKey(key)
	if type(key) ~= "string" then
		error(string.format("bad argument #1 to 'IncrementAsync' (string expected, got %s)", typeof(key)), 2)
	elseif delta ~= nil and type(delta) ~= "number" then
		error(string.format("bad argument #2 to 'IncrementAsync' (number expected, got %s)", typeof(delta)), 2)
	elseif #key == 0 then
		error("bad argument #1 to 'IncrementAsync' (key name can't be empty)", 2)
	elseif #key > Constants.MAX_LENGTH_KEY then
		error(
			string.format(
				"bad argument #1 to 'IncrementAsync' (key name exceeds %d character limit)",
				Constants.MAX_LENGTH_KEY
			),
			2
		)
	end

	Utils.simulateErrorCheck("IncrementAsync")
	local success
	if self.__writeLock[key] or tick() - (self.__writeCache[key] or 0) < Constants.WRITE_COOLDOWN then
		success = MockDataStoreManager.YieldForWriteLockAndBudget(
			function()
				warn(
					string.format(
						"IncrementAsync request was throttled, a key can only be written to once every %d seconds. Key = %s",
						Constants.WRITE_COOLDOWN,
						key
					)
				)
			end,
			key,
			self.__writeLock,
			self.__writeCache,
			table.create(1, Enum.DataStoreRequestType.SetIncrementSortedAsync)
		)
	else
		self.__writeLock[key] = true
		success = MockDataStoreManager.YieldForBudget(function()
			warn(
				string.format(
					"IncrementAsync request was throttled due to lack of budget. Try sending fewer requests. Key = %s",
					key
				)
			)
		end, table.create(1, Enum.DataStoreRequestType.SetIncrementSortedAsync))

		self.__writeLock[key] = nil
	end

	if not success then
		error("IncrementAsync rejected with error (request was throttled, but throttled queue was full)", 2)
	end

	local old = self.__data[key]
	if old ~= nil and (type(old) ~= "number" or old % 1 ~= 0) then
		Utils.simulateYield()
		error("IncrementAsync rejected with error (cannot increment non-integer value)", 2)
	end

	self.__writeLock[key] = true
	delta = delta and math.floor(delta + 0.5) or 1
	if old == nil then
		self.__data[key] = delta
		self.__ref[key] = {Key = key, Value = self.__data[key]}
		table.insert(self.__sorted, self.__ref[key])
		self.__changed = true
		self.__event:Fire(key, self.__data[key])
	elseif delta ~= 0 then
		self.__data[key] = self.__data[key] + delta
		self.__ref[key].Value = self.__data[key]
		self.__changed = true
		self.__event:Fire(key, self.__data[key])
	end

	local retValue = self.__data[key]
	Utils.simulateYield()

	self.__writeLock[key] = nil
	self.__writeCache[key] = tick()
	self.__getCache[key] = tick()

	Utils.logMethod(self, "IncrementAsync", key, retValue, delta)
	return retValue
end

function MockOrderedDataStore:RemoveAsync(key)
	key = Utils.preprocessKey(key)
	if type(key) ~= "string" then
		error(string.format("bad argument #1 to 'RemoveAsync' (string expected, got %s)", type(key)), 2)
	elseif #key == 0 then
		error("bad argument #1 to 'RemoveAsync' (key name can't be empty)", 2)
	elseif #key > Constants.MAX_LENGTH_KEY then
		error(
			string.format(
				"bad argument #1 to 'RemoveAsync' (key name exceeds %d character limit)",
				Constants.MAX_LENGTH_KEY
			),
			2
		)
	end

	Utils.simulateErrorCheck("RemoveAsync")
	local success
	if self.__writeLock[key] or tick() - (self.__writeCache[key] or 0) < Constants.WRITE_COOLDOWN then
		success = MockDataStoreManager.YieldForWriteLockAndBudget(
			function()
				warn(
					string.format(
						"RemoveAsync request was throttled, a key can only be written to once every %d seconds. Key = %s",
						Constants.WRITE_COOLDOWN,
						key
					)
				)
			end,
			key,
			self.__writeLock,
			self.__writeCache,
			table.create(1, Enum.DataStoreRequestType.SetIncrementSortedAsync)
		)
	else
		self.__writeLock[key] = true
		success = MockDataStoreManager.YieldForBudget(function()
			warn(
				string.format(
					"RemoveAsync request was throttled due to lack of budget. Try sending fewer requests. Key = %s",
					key
				)
			)
		end, table.create(1, Enum.DataStoreRequestType.SetIncrementSortedAsync))

		self.__writeLock[key] = nil
	end

	if not success then
		error("RemoveAsync rejected with error (request was throttled, but throttled queue was full)", 2)
	end

	self.__writeLock[key] = true
	local value = self.__data[key]
	if value ~= nil then
		self.__data[key] = nil
		self.__ref[key] = nil
		for i, v in ipairs(self.__sorted) do
			if v.Key == key then
				table.remove(self.__sorted, i)
				break
			end
		end

		self.__event:Fire(key, nil)
	end

	Utils.simulateYield()
	self.__writeLock[key] = nil
	self.__writeCache[key] = tick()
	Utils.logMethod(self, "RemoveAsync", key, value)
	return value
end

function MockOrderedDataStore:SetAsync(key, value)
	key = Utils.preprocessKey(key)
	if type(key) ~= "string" then
		error(string.format("bad argument #1 to 'SetAsync' (string expected, got %s)", typeof(key)), 2)
	elseif #key == 0 then
		error("bad argument #1 to 'SetAsync' (key name can't be empty)", 2)
	elseif #key > Constants.MAX_LENGTH_KEY then
		error(
			string.format(
				"bad argument #1 to 'SetAsync' (key name exceeds %d character limit)",
				Constants.MAX_LENGTH_KEY
			),
			2
		)
	elseif type(value) ~= "number" then
		error(string.format("bad argument #2 to 'SetAsync' (number expected, got %s)", typeof(value)), 2)
	elseif value % 1 ~= 0 then
		error("bad argument #2 to 'SetAsync' (cannot store non-integer values in OrderedDataStore)", 2)
	end

	Utils.simulateErrorCheck("SetAsync")
	local success
	if self.__writeLock[key] or tick() - (self.__writeCache[key] or 0) < Constants.WRITE_COOLDOWN then
		success = MockDataStoreManager.YieldForWriteLockAndBudget(
			function()
				warn(
					string.format(
						"SetAsync request was throttled, a key can only be written to once every %d seconds. Key = %s",
						Constants.WRITE_COOLDOWN,
						key
					)
				)
			end,
			key,
			self.__writeLock,
			self.__writeCache,
			table.create(1, Enum.DataStoreRequestType.SetIncrementSortedAsync)
		)
	else
		self.__writeLock[key] = true
		success = MockDataStoreManager.YieldForBudget(function()
			warn(
				string.format(
					"SetAsync request was throttled due to lack of budget. Try sending fewer requests. Key = %s",
					key
				)
			)
		end, table.create(1, Enum.DataStoreRequestType.SetIncrementSortedAsync))

		self.__writeLock[key] = nil
	end

	if not success then
		error("SetAsync rejected with error (request was throttled, but throttled queue was full)", 2)
	end

	self.__writeLock[key] = true
	local old = self.__data[key]
	if old == nil then
		self.__data[key] = value
		self.__ref[key] = {Key = key, Value = value}
		table.insert(self.__sorted, self.__ref[key])
		self.__changed = true
		self.__event:Fire(key, self.__data[key])
	elseif old ~= value then
		self.__data[key] = value
		self.__ref[key].Value = value
		self.__changed = true
		self.__event:Fire(key, self.__data[key])
	end

	Utils.simulateYield()
	self.__writeLock[key] = nil
	self.__writeCache[key] = tick()
	Utils.logMethod(self, "SetAsync", key, self.__data[key])
	return value
end

function MockOrderedDataStore:UpdateAsync(key, transformFunction)
	key = Utils.preprocessKey(key)
	if type(key) ~= "string" then
		error(string.format("bad argument #1 to 'UpdateAsync' (string expected, got %s)", typeof(key)), 2)
	elseif type(transformFunction) ~= "function" then
		error(
			string.format("bad argument #2 to 'UpdateAsync' (function expected, got %s)", typeof(transformFunction)),
			2
		)
	elseif #key == 0 then
		error("bad argument #1 to 'UpdateAsync' (key name can't be empty)", 2)
	elseif #key > Constants.MAX_LENGTH_KEY then
		error(
			string.format(
				"bad argument #1 to 'UpdateAsync' (key name exceeds %d character limit)",
				Constants.MAX_LENGTH_KEY
			),
			2
		)
	end

	Utils.simulateErrorCheck("UpdateAsync")
	local success
	if self.__writeLock[key] or tick() - (self.__writeCache[key] or 0) < Constants.WRITE_COOLDOWN then
		success = MockDataStoreManager.YieldForWriteLockAndBudget(
			function()
				warn(
					string.format(
						"UpdateAsync request was throttled, a key can only be written to once every %d seconds. Key = %s",
						Constants.WRITE_COOLDOWN,
						key
					)
				)
			end,
			key,
			self.__writeLock,
			self.__writeCache,
			table.create(1, Enum.DataStoreRequestType.SetIncrementSortedAsync)
		)
	else
		self.__writeLock[key] = true
		local budget
		if self.__getCache[key] and tick() - self.__getCache[key] < Constants.GET_COOLDOWN then
			budget = table.create(1, Enum.DataStoreRequestType.SetIncrementSortedAsync)
		else
			budget = {Enum.DataStoreRequestType.GetAsync, Enum.DataStoreRequestType.SetIncrementSortedAsync}
		end

		success = MockDataStoreManager.YieldForBudget(function()
			warn(
				string.format(
					"UpdateAsync request was throttled due to lack of budget. Try sending fewer requests. Key = %s",
					key
				)
			)
		end, budget)

		self.__writeLock[key] = nil
	end

	if not success then
		error("UpdateAsync rejected with error (request was throttled, but throttled queue was full)", 2)
	end

	local value = transformFunction(self.__data[key])

	if value == nil then -- cancel update after remote call
		Utils.simulateYield()
		return nil -- this is what datastores do even though it should be old value
	end

	if type(value) ~= "number" or value % 1 ~= 0 then
		error("UpdateAsync rejected with error (resulting non-integer value can't be stored in OrderedDataStore)", 2)
	end

	self.__writeLock[key] = true
	local old = self.__data[key]
	if old == nil then
		self.__data[key] = value
		self.__ref[key] = {Key = key, Value = value}
		table.insert(self.__sorted, self.__ref[key])
		self.__changed = true
		self.__event:Fire(key, self.__data[key])
	elseif old ~= value then
		self.__data[key] = value
		self.__ref[key].Value = value
		self.__changed = true
		self.__event:Fire(key, self.__data[key])
	end

	Utils.simulateYield()

	self.__writeLock[key] = nil
	self.__writeCache[key] = tick()
	self.__getCache[key] = tick()

	Utils.logMethod(self, "UpdateAsync", key, value)
	return value
end

function MockOrderedDataStore:GetSortedAsync(ascending, pageSize, minValue, maxValue)
	if type(ascending) ~= "boolean" then
		error(string.format("bad argument #1 to 'GetSortedAsync' (boolean expected, got %s)", typeof(ascending)), 2)
	elseif type(pageSize) ~= "number" then
		error(string.format("bad argument #2 to 'GetSortedAsync' (number expected, got %s)", typeof(pageSize)), 2)
	end

	pageSize = math.floor(pageSize + 0.5)
	if pageSize <= 0 or pageSize > Constants.MAX_PAGE_SIZE then
		error(
			string.format(
				"bad argument #2 to 'GetSortedAsync' (page size must be an integer above 0 and below or equal to %d)",
				Constants.MAX_PAGE_SIZE
			),
			2
		)
	end

	if minValue ~= nil then
		if type(minValue) ~= "number" then
			error(string.format("bad argument #3 to 'GetSortedAsync' (number expected, got %s)", typeof(minValue)), 2)
		elseif minValue % 1 ~= 0 then
			error("bad argument #3 to 'GetSortedAsync' (minimum threshold must be an integer)", 2)
		end
	else
		minValue = -math.huge
	end

	if maxValue ~= nil then
		if type(maxValue) ~= "number" then
			error(string.format("bad argument #4 to 'GetSortedAsync' (number expected, got %s)", typeof(maxValue)), 2)
		elseif maxValue % 1 ~= 0 then
			error("bad argument #4 to 'GetSortedAsync' (maximum threshold must be an integer)", 2)
		end
	else
		maxValue = math.huge
	end

	Utils.simulateErrorCheck("GetSortedAsync")
	local success = MockDataStoreManager.YieldForBudget(function()
		warn("GetSortedAsync request was throttled due to lack of budget. Try sending fewer requests.")
	end, table.create(1, Enum.DataStoreRequestType.GetSortedAsync))

	if not success then
		error("GetSortedAsync rejected with error (request was throttled, but throttled queue was full)", 2)
	end

	if minValue > maxValue then
		Utils.simulateYield()
		error("GetSortedAsync rejected with error (minimum threshold is higher than maximum threshold)", 2)
	end

	if self.__changed then
		table.sort(self.__sorted, function(a, b)
			return a.Value < b.Value
		end)

		self.__changed = false
	end

	local results = {}
	if ascending then
		local i = 1
		while self.__sorted[i] and self.__sorted[i].Value < minValue do
			i += 1
		end

		while self.__sorted[i] and self.__sorted[i].Value <= maxValue do
			table.insert(results, {key = self.__sorted[i].Key, value = self.__sorted[i].Value})
			i += 1
		end
	else
		local i = #self.__sorted
		while i > 0 and self.__sorted[i].Value > maxValue do
			i -= 1
		end

		while i > 0 and self.__sorted[i].Value >= minValue do
			table.insert(results, {key = self.__sorted[i].Key, value = self.__sorted[i].Value})
			i -= 1
		end
	end

	Utils.simulateYield()
	Utils.logMethod(self, "GetSortedAsync")
	return setmetatable({
		__datastore = self;
		__currentPage = 1;
		__pageSize = pageSize;
		__results = results;
		IsFinished = (#results <= pageSize);
	}, MockDataStorePages)
end

function MockOrderedDataStore:ExportToJSON()
	return HttpService:JSONEncode(self.__data)
end

local function JsonDecode(JsonString)
	return HttpService:JSONDecode(JsonString)
end

function MockOrderedDataStore:ImportFromJSON(json, verbose)
	local content
	if type(json) == "string" then
		local parsed, value = pcall(JsonDecode, json)
		if not parsed then
			error("bad argument #1 to 'ImportFromJSON' (string is not valid json)", 2)
		end

		content = value
	elseif type(json) == "table" then
		content = json -- No need to deepcopy, OrderedDataStore only contains numbers which are passed by value
	else
		error(string.format("bad argument #1 to 'ImportFromJSON' (string or table expected, got %s)", typeof(json)), 2)
	end

	if verbose ~= nil and type(verbose) ~= "boolean" then
		error(string.format("bad argument #2 to 'ImportFromJSON' (boolean expected, got %s)", typeof(verbose)), 2)
	end

	Utils.importPairsFromTable(
		content,
		self.__data,
		MockDataStoreManager.GetDataInterface(self.__data),
		(verbose == false and function() end or warn),
		"ImportFromJSON",
		string.format("OrderedDataStore > %s > %s", self.__name, self.__scope),
		true
	)
end

return MockOrderedDataStore
