SkyPhoneImei = {} function SkyPhoneImei.CheckDigit(body) if type(body) ~= "string" or not body:match("^%d%d%d%d%d%d%d%d%d%d%d%d%d%d$") then return nil end local sum = 0 for index = 1, 14 do local digit = tonumber(body:sub(index, index)) if index % 2 == 0 then digit = digit * 2 if digit > 9 then digit = digit - 9 end end sum = sum + digit end return tostring((10 - (sum % 10)) % 10) end function SkyPhoneImei.FromEntropy(entropy) if type(entropy) ~= "string" then return nil end local digits = {} for character in entropy:lower():gmatch("[0-9a-f]") do digits[#digits + 1] = tostring(tonumber(character, 16) % 10) if #digits == 14 then break end end if #digits ~= 14 then return nil end local body = table.concat(digits) return body .. SkyPhoneImei.CheckDigit(body) end function SkyPhoneImei.IsValid(value) if type(value) ~= "string" or not value:match("^%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d$") then return false end return value:sub(15, 15) == SkyPhoneImei.CheckDigit(value:sub(1, 14)) end function SkyPhoneImei.Reserve(entropy_factory, reserve) for _ = 1, 20 do local imei = SkyPhoneImei.FromEntropy(entropy_factory()) if imei and reserve(imei) then return imei end end return nil end