Add love.filesystem.getInfo. Deprecate love.filesystem.exists/isDirectory/isFile/isSymlink/getLastModified/getSize. Resolves issue #641.

--HG--
branch : minor
This commit is contained in:
Alex Szpakowski
2017-08-27 18:14:54 -03:00
parent fcd9f1526c
commit 9d0e984c3d
9 changed files with 227 additions and 201 deletions
+7 -7
View File
@@ -115,19 +115,19 @@ bool File::getConstant(BufferMode in, const char *&out)
StringMap<File::Mode, File::MODE_MAX_ENUM>::Entry File::modeEntries[] =
{
{"c", File::MODE_CLOSED},
{"r", File::MODE_READ},
{"w", File::MODE_WRITE},
{"a", File::MODE_APPEND},
{ "c", MODE_CLOSED },
{ "r", MODE_READ },
{ "w", MODE_WRITE },
{ "a", MODE_APPEND },
};
StringMap<File::Mode, File::MODE_MAX_ENUM> File::modes(File::modeEntries, sizeof(File::modeEntries));
StringMap<File::BufferMode, File::BUFFER_MAX_ENUM>::Entry File::bufferModeEntries[] =
{
{"none", File::BUFFER_NONE},
{"line", File::BUFFER_LINE},
{"full", File::BUFFER_FULL},
{ "none", BUFFER_NONE },
{ "line", BUFFER_LINE },
{ "full", BUFFER_FULL },
};
StringMap<File::BufferMode, File::BUFFER_MAX_ENUM> File::bufferModes(File::bufferModeEntries, sizeof(File::bufferModeEntries));
+20
View File
@@ -120,5 +120,25 @@ std::string Filesystem::getExecutablePath() const
#endif
}
bool Filesystem::getConstant(const char *in, FileType &out)
{
return fileTypes.find(in, out);
}
bool Filesystem::getConstant(FileType in, const char *&out)
{
return fileTypes.find(in, out);
}
StringMap<Filesystem::FileType, Filesystem::FILETYPE_MAX_ENUM>::Entry Filesystem::fileTypeEntries[] =
{
{ "file", FILETYPE_FILE },
{ "directory", FILETYPE_DIRECTORY },
{ "symlink", FILETYPE_SYMLINK },
{ "other", FILETYPE_OTHER },
};
StringMap<Filesystem::FileType, Filesystem::FILETYPE_MAX_ENUM> Filesystem::fileTypes(Filesystem::fileTypeEntries, sizeof(Filesystem::fileTypeEntries));
} // filesystem
} // love
+29 -35
View File
@@ -25,6 +25,7 @@
#include "common/config.h"
#include "common/Module.h"
#include "common/int.h"
#include "common/StringMap.h"
#include "FileData.h"
#include "File.h"
@@ -61,6 +62,23 @@ class Filesystem : public Module
{
public:
enum FileType
{
FILETYPE_FILE,
FILETYPE_DIRECTORY,
FILETYPE_SYMLINK,
FILETYPE_OTHER,
FILETYPE_MAX_ENUM
};
struct Info
{
// Numbers will be -1 if they cannot be determined.
int64 size;
int64 modtime;
FileType type;
};
static love::Type type;
Filesystem();
@@ -167,28 +185,10 @@ public:
virtual std::string getRealDirectory(const char *filename) const = 0;
/**
* Checks if a path exists.
* @param path The path to check.
* Gets information about the item at the specified filepath. Returns false
* if nothing exists at the path.
**/
virtual bool exists(const char *path) const = 0;
/**
* Checks if a path is a directory.
* @param dir The directory name to check.
**/
virtual bool isDirectory(const char *dir) const = 0;
/**
* Checks if a filename exists.
* @param file The filename to check.
**/
virtual bool isFile(const char *file) const = 0;
/**
* Gets whether a filepath is actually a symlink.
* Always returns false if symlinks are not enabled.
**/
virtual bool isSymlink(const char *filename) const = 0;
virtual bool getInfo(const char *filepath, Info &info) const = 0;
/**
* Creates a directory. Write dir must be set.
@@ -231,19 +231,6 @@ public:
**/
virtual void getDirectoryItems(const char *dir, std::vector<std::string> &items) = 0;
/**
* Gets the last modification time of a file, in seconds
* since the Unix epoch.
* @param filename The name of the file.
**/
virtual int64 getLastModified(const char *filename) const = 0;
/**
* Gets the size of a file in bytes.
* @param filename The name of the file.
**/
virtual int64 getSize(const char *filename) const = 0;
/**
* Enable or disable symbolic link support in love.filesystem.
**/
@@ -274,10 +261,17 @@ public:
**/
virtual std::string getExecutablePath() const;
static bool getConstant(const char *in, FileType &out);
static bool getConstant(FileType in, const char *&out);
private:
//should we save external or internal for Android
// Should we save external or internal for Android
bool useExternal;
static StringMap<FileType, FILETYPE_MAX_ENUM>::Entry fileTypeEntries[];
static StringMap<FileType, FILETYPE_MAX_ENUM> fileTypes;
}; // Filesystem
} // filesystem
+34 -69
View File
@@ -566,60 +566,53 @@ std::string Filesystem::getRealDirectory(const char *filename) const
return std::string(dir);
}
bool Filesystem::exists(const char *path) const
{
if (!PHYSFS_isInit())
return false;
return PHYSFS_exists(path) != 0;
}
bool Filesystem::isDirectory(const char *dir) const
bool Filesystem::getInfo(const char *filepath, Info &info) const
{
if (!PHYSFS_isInit())
return false;
#ifdef LOVE_USE_PHYSFS_2_1
PHYSFS_Stat stat = {};
if (PHYSFS_stat(dir, &stat))
return stat.filetype == PHYSFS_FILETYPE_DIRECTORY;
if (!PHYSFS_stat(filepath, &stat))
return false;
info.size = (int64) stat.filesize;
info.modtime = (int64) stat.modtime;
if (stat.filetype == PHYSFS_FILETYPE_REGULAR)
info.type = FILETYPE_FILE;
else if (stat.filetype == PHYSFS_FILETYPE_DIRECTORY)
info.type = FILETYPE_DIRECTORY;
else if (stat.filetype == PHYSFS_FILETYPE_SYMLINK)
info.type = FILETYPE_SYMLINK;
else
return false;
info.type = FILETYPE_OTHER;
#else
return PHYSFS_isDirectory(dir) != 0 && !isSymlink(dir);
#endif
}
bool Filesystem::isFile(const char *file) const
{
if (!PHYSFS_isInit())
if (!PHYSFS_exists(filepath))
return false;
#ifdef LOVE_USE_PHYSFS_2_1
PHYSFS_Stat stat = {};
if (PHYSFS_stat(file, &stat))
return stat.filetype == PHYSFS_FILETYPE_REGULAR;
try
{
File file(filepath);
info.size = file.getSize();
}
catch (love::Exception &)
{
info.size = -1;
}
info.modtime = (int64) PHYSFS_getLastModTime(filepath);
if (PHYSFS_isSymbolicLink(filepath))
info.type = FILETYPE_SYMLINK;
else if (PHYSFS_isDirectory(filepath))
info.type = FILETYPE_DIRECTORY;
else
return false;
#else
return PHYSFS_exists(file) && !isDirectory(file) && !isSymlink(file);
#endif
}
info.type = FILETYPE_FILE;
bool Filesystem::isSymlink(const char *filename) const
{
if (!PHYSFS_isInit())
return false;
#ifdef LOVE_USE_PHYSFS_2_1
PHYSFS_Stat stat = {};
if (PHYSFS_stat(filename, &stat))
return stat.filetype == PHYSFS_FILETYPE_SYMLINK;
else
return false;
#else
return PHYSFS_isSymbolicLink(filename) != 0;
#endif
return true;
}
bool Filesystem::createDirectory(const char *dir)
@@ -698,34 +691,6 @@ void Filesystem::getDirectoryItems(const char *dir, std::vector<std::string> &it
PHYSFS_freeList(rc);
}
int64 Filesystem::getLastModified(const char *filename) const
{
PHYSFS_sint64 time = -1;
if (!PHYSFS_isInit())
return -1;
#ifdef LOVE_USE_PHYSFS_2_1
PHYSFS_Stat stat = {};
if (PHYSFS_stat(filename, &stat))
time = stat.modtime;
#else
time = PHYSFS_getLastModTime(filename);
#endif
if (time == -1)
throw love::Exception("Could not determine file modification date.");
return time;
}
int64 Filesystem::getSize(const char *filename) const
{
File file(filename);
int64 size = file.getSize();
return size;
}
void Filesystem::setSymlinksEnabled(bool enable)
{
if (!PHYSFS_isInit())
+1 -7
View File
@@ -72,10 +72,7 @@ public:
std::string getRealDirectory(const char *filename) const;
bool exists(const char *path) const;
bool isDirectory(const char *dir) const;
bool isFile(const char *file) const;
bool isSymlink(const char *filename) const;
bool getInfo(const char *filepath, Info &info) const;
bool createDirectory(const char *dir);
@@ -87,9 +84,6 @@ public:
void getDirectoryItems(const char *dir, std::vector<std::string> &items);
int64 getLastModified(const char *filename) const;
int64 getSize(const char *filename) const;
void setSymlinksEnabled(bool enable);
bool areSymlinksEnabled() const;
+123 -71
View File
@@ -358,31 +358,40 @@ int w_getExecutablePath(lua_State *L)
return 1;
}
int w_exists(lua_State *L)
int w_getInfo(lua_State *L)
{
const char *arg = luaL_checkstring(L, 1);
luax_pushboolean(L, instance()->exists(arg));
return 1;
}
const char *filepath = luaL_checkstring(L, 1);
Filesystem::Info info = {};
int w_isDirectory(lua_State *L)
{
const char *arg = luaL_checkstring(L, 1);
luax_pushboolean(L, instance()->isDirectory(arg));
return 1;
}
if (instance()->getInfo(filepath, info))
{
const char *typestr = nullptr;
if (!Filesystem::getConstant(info.type, typestr))
return luaL_error(L, "Unknown file type.");
int w_isFile(lua_State *L)
{
const char *arg = luaL_checkstring(L, 1);
luax_pushboolean(L, instance()->isFile(arg));
return 1;
}
lua_createtable(L, 0, 3);
lua_pushstring(L, typestr);
lua_setfield(L, -2, "type");
// Lua numbers (doubles) can't fit the full range of 64 bit ints.
info.size = std::min(info.size, 0x20000000000000LL);
if (info.size >= 0)
{
lua_pushnumber(L, (lua_Number) info.size);
lua_setfield(L, -2, "size");
}
info.modtime = std::min(info.modtime, 0x20000000000000LL);
if (info.modtime >= 0)
{
lua_pushnumber(L, (lua_Number) info.modtime);
lua_setfield(L, -2, "modtime");
}
}
else
lua_pushnil(L);
int w_isSymlink(lua_State *L)
{
const char *filename = luaL_checkstring(L, 1);
luax_pushboolean(L, instance()->isSymlink(filename));
return 1;
}
@@ -551,48 +560,6 @@ int w_load(lua_State *L)
}
}
int w_getLastModified(lua_State *L)
{
const char *filename = luaL_checkstring(L, 1);
int64 time = 0;
try
{
time = instance()->getLastModified(filename);
}
catch (love::Exception &e)
{
return luax_ioError(L, "%s", e.what());
}
lua_pushnumber(L, static_cast<lua_Number>(time));
return 1;
}
int w_getSize(lua_State *L)
{
const char *filename = luaL_checkstring(L, 1);
int64 size = -1;
try
{
size = instance()->getSize(filename);
}
catch (love::Exception &e)
{
return luax_ioError(L, "%s", e.what());
}
// Error on failure or if size does not fit into a double precision floating-point number.
if (size == -1)
return luax_ioError(L, "Could not determine file size.");
else if (size >= 0x20000000000000LL)
return luax_ioError(L, "Size too large to fit into a Lua number!");
lua_pushnumber(L, (lua_Number) size);
return 1;
}
int w_setSymlinksEnabled(lua_State *L)
{
instance()->setSymlinksEnabled(luax_checkboolean(L, 1));
@@ -702,7 +669,8 @@ int loader(lua_State *L)
{
replaceAll(element, "?", modulename);
if (inst->isFile(element.c_str()))
Filesystem::Info info = {};
if (inst->getInfo(element.c_str(), info) && info.type != Filesystem::FILETYPE_DIRECTORY)
{
lua_pop(L, 1);
lua_pushstring(L, element.c_str());
@@ -760,7 +728,8 @@ int extloader(lua_State *L)
// And ? with just the filename
replaceAll(element, "?", tokenized_name);
if (!inst->isFile(element.c_str()))
Filesystem::Info info = {};
if (!inst->getInfo(element.c_str(), info) || info.type == Filesystem::FILETYPE_DIRECTORY)
continue;
// Now resolve the full path, as we're bypassing physfs for the next part.
@@ -799,6 +768,85 @@ int extloader(lua_State *L)
return 1;
}
// Deprecated functions.
int w_exists(lua_State *L)
{
luax_markdeprecated(L, "love.filesystem.exists", API_FUNCTION, DEPRECATED_REPLACED, "love.filesystem.getInfo");
const char *arg = luaL_checkstring(L, 1);
Filesystem::Info info = {};
luax_pushboolean(L, instance()->getInfo(arg, info));
return 1;
}
int w_isDirectory(lua_State *L)
{
luax_markdeprecated(L, "love.filesystem.exists", API_FUNCTION, DEPRECATED_REPLACED, "love.filesystem.getInfo");
const char *arg = luaL_checkstring(L, 1);
Filesystem::Info info = {};
bool exists = instance()->getInfo(arg, info);
luax_pushboolean(L, exists && info.type == Filesystem::FILETYPE_DIRECTORY);
return 1;
}
int w_isFile(lua_State *L)
{
luax_markdeprecated(L, "love.filesystem.isFile", API_FUNCTION, DEPRECATED_REPLACED, "love.filesystem.getInfo");
const char *arg = luaL_checkstring(L, 1);
Filesystem::Info info = {};
bool exists = instance()->getInfo(arg, info);
luax_pushboolean(L, exists && info.type == Filesystem::FILETYPE_FILE);
return 1;
}
int w_isSymlink(lua_State *L)
{
luax_markdeprecated(L, "love.filesystem.isSymlink", API_FUNCTION, DEPRECATED_REPLACED, "love.filesystem.getInfo");
const char *filename = luaL_checkstring(L, 1);
Filesystem::Info info = {};
bool exists = instance()->getInfo(filename, info);
luax_pushboolean(L, exists && info.type == Filesystem::FILETYPE_SYMLINK);
return 1;
}
int w_getLastModified(lua_State *L)
{
luax_markdeprecated(L, "love.filesystem.getLastModified", API_FUNCTION, DEPRECATED_REPLACED, "love.filesystem.getInfo");
const char *filename = luaL_checkstring(L, 1);
Filesystem::Info info = {};
bool exists = instance()->getInfo(filename, info);
if (!exists)
return luax_ioError(L, "File does not exist");
else if (info.modtime == -1)
return luax_ioError(L, "Could not determine file modification date.");
lua_pushnumber(L, (lua_Number) info.modtime);
return 1;
}
int w_getSize(lua_State *L)
{
luax_markdeprecated(L, "love.filesystem.getSize", API_FUNCTION, DEPRECATED_REPLACED, "love.filesystem.getInfo");
const char *filename = luaL_checkstring(L, 1);
Filesystem::Info info = {};
bool exists = instance()->getInfo(filename, info);
if (!exists)
luax_ioError(L, "File does not exist");
else if (info.size == -1)
return luax_ioError(L, "Could not determine file size.");
else if (info.size >= 0x20000000000000LL)
return luax_ioError(L, "Size too large to fit into a Lua number!");
lua_pushnumber(L, (lua_Number) info.size);
return 1;
}
// List of functions to wrap.
static const luaL_Reg functions[] =
{
@@ -820,10 +868,6 @@ static const luaL_Reg functions[] =
{ "getSourceBaseDirectory", w_getSourceBaseDirectory },
{ "getRealDirectory", w_getRealDirectory },
{ "getExecutablePath", w_getExecutablePath },
{ "exists", w_exists },
{ "isDirectory", w_isDirectory },
{ "isFile", w_isFile },
{ "isSymlink", w_isSymlink },
{ "createDirectory", w_createDirectory },
{ "remove", w_remove },
{ "read", w_read },
@@ -832,8 +876,7 @@ static const luaL_Reg functions[] =
{ "getDirectoryItems", w_getDirectoryItems },
{ "lines", w_lines },
{ "load", w_load },
{ "getLastModified", w_getLastModified },
{ "getSize", w_getSize },
{ "getInfo", w_getInfo },
{ "setSymlinksEnabled", w_setSymlinksEnabled },
{ "areSymlinksEnabled", w_areSymlinksEnabled },
{ "newFileData", w_newFileData },
@@ -841,6 +884,15 @@ static const luaL_Reg functions[] =
{ "setRequirePath", w_setRequirePath },
{ "getCRequirePath", w_getCRequirePath },
{ "setCRequirePath", w_setCRequirePath },
// Deprecated.
{ "exists", w_exists },
{ "isDirectory", w_isDirectory },
{ "isFile", w_isFile },
{ "isSymlink", w_isSymlink },
{ "getLastModified", w_getLastModified },
{ "getSize", w_getSize },
{ 0, 0 }
};
+2 -1
View File
@@ -1220,7 +1220,8 @@ static int w_getShaderSource(lua_State *L, int startidx, bool gles, Shader::Shad
size_t slen = 0;
const char *str = lua_tolstring(L, i, &slen);
if (fs != nullptr && fs->isFile(str))
Filesystem::Info info = {};
if (fs != nullptr && fs->getInfo(str, info))
{
FileData *fd = nullptr;
luax_catchexcept(L, [&](){ fd = fs->read(str); });
+3 -3
View File
@@ -351,7 +351,7 @@ function love.boot()
-- before the save directory (the identity should be appended.)
pcall(love.filesystem.setIdentity, identity, true)
if can_has_game and not (love.filesystem.isFile("main.lua") or love.filesystem.isFile("conf.lua")) then
if can_has_game and not (love.filesystem.getInfo("main.lua") or love.filesystem.getInfo("conf.lua")) then
no_game_code = true
end
@@ -425,7 +425,7 @@ function love.init()
-- If config file exists, load it and allow it to update config table.
local confok, conferr
if (not love.conf) and love.filesystem and love.filesystem.isFile("conf.lua") then
if (not love.conf) and love.filesystem and love.filesystem.getInfo("conf.lua") then
confok, conferr = pcall(require, "conf")
end
@@ -539,7 +539,7 @@ function love.init()
if love.filesystem then
love.filesystem._setAndroidSaveExternal(c.externalstorage)
love.filesystem.setIdentity(c.identity or love.filesystem.getIdentity(), c.appendidentity)
if love.filesystem.isFile("main.lua") then
if love.filesystem.getInfo("main.lua") then
require("main")
end
end
+8 -8
View File
@@ -661,10 +661,10 @@ const unsigned char boot_lua[] =
0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2c, 0x20, 0x74, 0x72, 0x75, 0x65, 0x29, 0x0a,
0x09, 0x69, 0x66, 0x20, 0x63, 0x61, 0x6e, 0x5f, 0x68, 0x61, 0x73, 0x5f, 0x67, 0x61, 0x6d, 0x65, 0x20, 0x61,
0x6e, 0x64, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x28, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73,
0x79, 0x73, 0x74, 0x65, 0x6d, 0x2e, 0x69, 0x73, 0x46, 0x69, 0x6c, 0x65, 0x28, 0x22, 0x6d, 0x61, 0x69, 0x6e,
0x2e, 0x6c, 0x75, 0x61, 0x22, 0x29, 0x20, 0x6f, 0x72, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x66, 0x69, 0x6c,
0x65, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x2e, 0x69, 0x73, 0x46, 0x69, 0x6c, 0x65, 0x28, 0x22, 0x63, 0x6f,
0x6e, 0x66, 0x2e, 0x6c, 0x75, 0x61, 0x22, 0x29, 0x29, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a,
0x79, 0x73, 0x74, 0x65, 0x6d, 0x2e, 0x67, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x28, 0x22, 0x6d, 0x61, 0x69,
0x6e, 0x2e, 0x6c, 0x75, 0x61, 0x22, 0x29, 0x20, 0x6f, 0x72, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x66, 0x69,
0x6c, 0x65, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x2e, 0x67, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x28, 0x22,
0x63, 0x6f, 0x6e, 0x66, 0x2e, 0x6c, 0x75, 0x61, 0x22, 0x29, 0x29, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a,
0x09, 0x09, 0x6e, 0x6f, 0x5f, 0x67, 0x61, 0x6d, 0x65, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x3d, 0x20, 0x74,
0x72, 0x75, 0x65, 0x0a,
0x09, 0x65, 0x6e, 0x64, 0x0a,
@@ -783,8 +783,8 @@ const unsigned char boot_lua[] =
0x09, 0x69, 0x66, 0x20, 0x28, 0x6e, 0x6f, 0x74, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x63, 0x6f, 0x6e, 0x66,
0x29, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x79, 0x73,
0x74, 0x65, 0x6d, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73,
0x79, 0x73, 0x74, 0x65, 0x6d, 0x2e, 0x69, 0x73, 0x46, 0x69, 0x6c, 0x65, 0x28, 0x22, 0x63, 0x6f, 0x6e, 0x66,
0x2e, 0x6c, 0x75, 0x61, 0x22, 0x29, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a,
0x79, 0x73, 0x74, 0x65, 0x6d, 0x2e, 0x67, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x28, 0x22, 0x63, 0x6f, 0x6e,
0x66, 0x2e, 0x6c, 0x75, 0x61, 0x22, 0x29, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a,
0x09, 0x09, 0x63, 0x6f, 0x6e, 0x66, 0x6f, 0x6b, 0x2c, 0x20, 0x63, 0x6f, 0x6e, 0x66, 0x65, 0x72, 0x72, 0x20,
0x3d, 0x20, 0x70, 0x63, 0x61, 0x6c, 0x6c, 0x28, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x2c, 0x20, 0x22,
0x63, 0x6f, 0x6e, 0x66, 0x22, 0x29, 0x0a,
@@ -999,8 +999,8 @@ const unsigned char boot_lua[] =
0x29, 0x2c, 0x20, 0x63, 0x2e, 0x61, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74,
0x79, 0x29, 0x0a,
0x09, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x79, 0x73, 0x74,
0x65, 0x6d, 0x2e, 0x69, 0x73, 0x46, 0x69, 0x6c, 0x65, 0x28, 0x22, 0x6d, 0x61, 0x69, 0x6e, 0x2e, 0x6c, 0x75,
0x61, 0x22, 0x29, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a,
0x65, 0x6d, 0x2e, 0x67, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x28, 0x22, 0x6d, 0x61, 0x69, 0x6e, 0x2e, 0x6c,
0x75, 0x61, 0x22, 0x29, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a,
0x09, 0x09, 0x09, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x28, 0x22, 0x6d, 0x61, 0x69, 0x6e, 0x22, 0x29, 0x0a,
0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a,
0x09, 0x65, 0x6e, 0x64, 0x0a,