Add new*Texture variants which don't require image files.

Update the no-game screen to avoid deprecated functions.
This commit is contained in:
Alex Szpakowski
2020-02-12 20:07:35 -04:00
parent ceb854db5b
commit 8478a870a9
3 changed files with 291 additions and 241 deletions
+239 -195
View File
@@ -700,30 +700,6 @@ static void parseDPIScale(Data *d, float *dpiscale)
} }
} }
static Texture::Settings w__optImageSettings(lua_State *L, int idx, bool &setdpiscale)
{
Texture::Settings s;
setdpiscale = false;
if (!lua_isnoneornil(L, idx))
{
luax_checktablefields<Texture::SettingType>(L, idx, "texture setting name", Texture::getConstant);
s.mipmaps = luax_boolflag(L, idx, "mipmaps", false) ? Texture::MIPMAPS_MANUAL : Texture::MIPMAPS_NONE;
s.linear = luax_boolflag(L, idx, Texture::getConstant(Texture::SETTING_LINEAR), s.linear);
lua_getfield(L, idx, Texture::getConstant(Texture::SETTING_DPI_SCALE));
if (lua_isnumber(L, -1))
{
s.dpiScale = (float) lua_tonumber(L, -1);
setdpiscale = true;
}
lua_pop(L, 1);
}
return s;
}
static std::pair<StrongRef<image::ImageData>, StrongRef<image::CompressedImageData>> static std::pair<StrongRef<image::ImageData>, StrongRef<image::CompressedImageData>>
getImageData(lua_State *L, int idx, bool allowcompressed, float *dpiscale) getImageData(lua_State *L, int idx, bool allowcompressed, float *dpiscale)
{ {
@@ -891,35 +867,60 @@ int w_newTexture(lua_State *L)
luax_checkgraphicscreated(L); luax_checkgraphicscreated(L);
Texture::Slices slices(TEXTURE_2D); Texture::Slices slices(TEXTURE_2D);
Texture::Slices *slicesref = &slices;
Texture::Settings settings;
settings.type = TEXTURE_2D;
bool dpiscaleset = false; bool dpiscaleset = false;
Texture::Settings settings = w__optImageSettings(L, 2, dpiscaleset);
float *autodpiscale = dpiscaleset ? nullptr : &settings.dpiScale;
if (lua_istable(L, 1)) if (lua_type(L, 1) == LUA_TNUMBER)
{ {
int n = std::max(1, (int) luax_objlen(L, 1)); slicesref = nullptr;
for (int i = 0; i < n; i++)
settings.width = (int) luaL_checkinteger(L, 1);
settings.height = (int) luaL_checkinteger(L, 2);
int startidx = 3;
if (lua_type(L, 3) == LUA_TNUMBER)
{ {
lua_rawgeti(L, 1, i + 1); settings.layers = (int) luaL_checkinteger(L, 3);
auto data = getImageData(L, -1, true, i == 0 ? autodpiscale : nullptr); settings.type = TEXTURE_2D_ARRAY;
if (data.first.get()) startidx = 4;
slices.set(0, i, data.first);
else
slices.set(0, i, data.second->getSlice(0, 0));
} }
lua_pop(L, n);
luax_checktexturesettings(L, startidx, true, true, false, OptionalBool(), settings, dpiscaleset);
} }
else else
{ {
auto data = getImageData(L, 1, true, autodpiscale); luax_checktexturesettings(L, 2, true, false, false, OptionalBool(), settings, dpiscaleset);
if (data.first.get()) float *autodpiscale = dpiscaleset ? nullptr : &settings.dpiScale;
slices.set(0, 0, data.first);
if (lua_istable(L, 1))
{
int n = std::max(1, (int) luax_objlen(L, 1));
for (int i = 0; i < n; i++)
{
lua_rawgeti(L, 1, i + 1);
auto data = getImageData(L, -1, true, i == 0 ? autodpiscale : nullptr);
if (data.first.get())
slices.set(0, i, data.first);
else
slices.set(0, i, data.second->getSlice(0, 0));
}
lua_pop(L, n);
}
else else
slices.add(data.second, 0, 0, false, settings.mipmaps != Texture::MIPMAPS_NONE); {
auto data = getImageData(L, 1, true, autodpiscale);
if (data.first.get())
slices.set(0, 0, data.first);
else
slices.add(data.second, 0, 0, false, settings.mipmaps != Texture::MIPMAPS_NONE);
}
} }
return w__pushNewTexture(L, &slices, settings); return w__pushNewTexture(L, slicesref, settings);
} }
int w_newCubeTexture(lua_State *L) int w_newCubeTexture(lua_State *L)
@@ -927,93 +928,106 @@ int w_newCubeTexture(lua_State *L)
luax_checkgraphicscreated(L); luax_checkgraphicscreated(L);
Texture::Slices slices(TEXTURE_CUBE); Texture::Slices slices(TEXTURE_CUBE);
Texture::Slices *slicesref = &slices;
Texture::Settings settings;
settings.type = TEXTURE_CUBE;
bool dpiscaleset = false; bool dpiscaleset = false;
Texture::Settings settings = w__optImageSettings(L, 2, dpiscaleset);
float *autodpiscale = dpiscaleset ? nullptr : &settings.dpiScale;
auto imagemodule = Module::getInstance<love::image::Image>(Module::M_IMAGE); if (lua_type(L, 1) == LUA_TNUMBER)
if (!lua_istable(L, 1))
{ {
auto data = getImageData(L, 1, true, autodpiscale); slicesref = nullptr;
settings.width = settings.height = (int) luaL_checkinteger(L, 1);
std::vector<StrongRef<love::image::ImageData>> faces; luax_checktexturesettings(L, 2, true, false, false, OptionalBool(), settings, dpiscaleset);
if (data.first.get())
{
luax_catchexcept(L, [&](){ faces = imagemodule->newCubeFaces(data.first); });
for (int i = 0; i < (int) faces.size(); i++)
slices.set(i, 0, faces[i]);
}
else
slices.add(data.second, 0, 0, true, settings.mipmaps != Texture::MIPMAPS_NONE);
} }
else else
{ {
int tlen = (int) luax_objlen(L, 1); luax_checktexturesettings(L, 2, true, false, false, OptionalBool(), settings, dpiscaleset);
float *autodpiscale = dpiscaleset ? nullptr : &settings.dpiScale;
if (luax_isarrayoftables(L, 1)) auto imagemodule = Module::getInstance<love::image::Image>(Module::M_IMAGE);
if (!lua_istable(L, 1))
{ {
if (tlen != 6) auto data = getImageData(L, 1, true, autodpiscale);
return luaL_error(L, "Cubemap images must have 6 faces.");
for (int face = 0; face < tlen; face++) std::vector<StrongRef<love::image::ImageData>> faces;
if (data.first.get())
{ {
lua_rawgeti(L, 1, face + 1); luax_catchexcept(L, [&](){ faces = imagemodule->newCubeFaces(data.first); });
luaL_checktype(L, -1, LUA_TTABLE);
int miplen = std::max(1, (int) luax_objlen(L, -1)); for (int i = 0; i < (int) faces.size(); i++)
slices.set(i, 0, faces[i]);
for (int mip = 0; mip < miplen; mip++)
{
lua_rawgeti(L, -1, mip + 1);
auto data = getImageData(L, -1, true, face == 0 && mip == 0 ? autodpiscale : nullptr);
if (data.first.get())
slices.set(face, mip, data.first);
else
slices.set(face, mip, data.second->getSlice(0, 0));
lua_pop(L, 1);
}
} }
else
slices.add(data.second, 0, 0, true, settings.mipmaps != Texture::MIPMAPS_NONE);
} }
else else
{ {
bool usemipmaps = false; int tlen = (int) luax_objlen(L, 1);
for (int i = 0; i < tlen; i++) if (luax_isarrayoftables(L, 1))
{ {
lua_rawgeti(L, 1, i + 1); if (tlen != 6)
return luaL_error(L, "Cubemap images must have 6 faces.");
auto data = getImageData(L, -1, true, i == 0 ? autodpiscale : nullptr); for (int face = 0; face < tlen; face++)
if (data.first.get())
{ {
if (usemipmaps || data.first->getWidth() != data.first->getHeight()) lua_rawgeti(L, 1, face + 1);
luaL_checktype(L, -1, LUA_TTABLE);
int miplen = std::max(1, (int) luax_objlen(L, -1));
for (int mip = 0; mip < miplen; mip++)
{ {
usemipmaps = true; lua_rawgeti(L, -1, mip + 1);
std::vector<StrongRef<love::image::ImageData>> faces; auto data = getImageData(L, -1, true, face == 0 && mip == 0 ? autodpiscale : nullptr);
luax_catchexcept(L, [&](){ faces = imagemodule->newCubeFaces(data.first); }); if (data.first.get())
slices.set(face, mip, data.first);
else
slices.set(face, mip, data.second->getSlice(0, 0));
for (int face = 0; face < (int) faces.size(); face++) lua_pop(L, 1);
slices.set(face, i, faces[i]); }
}
}
else
{
bool usemipmaps = false;
for (int i = 0; i < tlen; i++)
{
lua_rawgeti(L, 1, i + 1);
auto data = getImageData(L, -1, true, i == 0 ? autodpiscale : nullptr);
if (data.first.get())
{
if (usemipmaps || data.first->getWidth() != data.first->getHeight())
{
usemipmaps = true;
std::vector<StrongRef<love::image::ImageData>> faces;
luax_catchexcept(L, [&](){ faces = imagemodule->newCubeFaces(data.first); });
for (int face = 0; face < (int) faces.size(); face++)
slices.set(face, i, faces[i]);
}
else
slices.set(i, 0, data.first);
} }
else else
slices.set(i, 0, data.first); slices.add(data.second, i, 0, false, settings.mipmaps != Texture::MIPMAPS_NONE);
} }
else
slices.add(data.second, i, 0, false, settings.mipmaps != Texture::MIPMAPS_NONE);
} }
}
lua_pop(L, tlen); lua_pop(L, tlen);
}
} }
return w__pushNewTexture(L, &slices, settings); return w__pushNewTexture(L, slicesref, settings);
} }
int w_newArrayTexture(lua_State *L) int w_newArrayTexture(lua_State *L)
@@ -1021,63 +1035,78 @@ int w_newArrayTexture(lua_State *L)
luax_checkgraphicscreated(L); luax_checkgraphicscreated(L);
Texture::Slices slices(TEXTURE_2D_ARRAY); Texture::Slices slices(TEXTURE_2D_ARRAY);
Texture::Slices *slicesref = &slices;
Texture::Settings settings;
settings.type = TEXTURE_2D_ARRAY;
bool dpiscaleset = false; bool dpiscaleset = false;
Texture::Settings settings = w__optImageSettings(L, 2, dpiscaleset);
float *autodpiscale = dpiscaleset ? nullptr : &settings.dpiScale;
if (lua_istable(L, 1)) if (lua_type(L, 1) == LUA_TNUMBER)
{ {
int tlen = std::max(1, (int) luax_objlen(L, 1)); slicesref = nullptr;
settings.width = (int) luaL_checkinteger(L, 1);
if (luax_isarrayoftables(L, 1)) settings.height = (int) luaL_checkinteger(L, 2);
{ settings.layers = (int) luaL_checkinteger(L, 3);
for (int slice = 0; slice < tlen; slice++) luax_checktexturesettings(L, 4, true, false, false, OptionalBool(), settings, dpiscaleset);
{
lua_rawgeti(L, 1, slice + 1);
luaL_checktype(L, -1, LUA_TTABLE);
int miplen = std::max(1, (int) luax_objlen(L, -1));
for (int mip = 0; mip < miplen; mip++)
{
lua_rawgeti(L, -1, mip + 1);
auto data = getImageData(L, -1, true, slice == 0 && mip == 0 ? autodpiscale : nullptr);
if (data.first.get())
slices.set(slice, mip, data.first);
else
slices.set(slice, mip, data.second->getSlice(0, 0));
lua_pop(L, 1);
}
}
}
else
{
for (int slice = 0; slice < tlen; slice++)
{
lua_rawgeti(L, 1, slice + 1);
auto data = getImageData(L, -1, true, slice == 0 ? autodpiscale : nullptr);
if (data.first.get())
slices.set(slice, 0, data.first);
else
slices.add(data.second, slice, 0, false, settings.mipmaps != Texture::MIPMAPS_NONE);
}
}
lua_pop(L, tlen);
} }
else else
{ {
auto data = getImageData(L, 1, true, autodpiscale); luax_checktexturesettings(L, 2, true, false, false, OptionalBool(), settings, dpiscaleset);
if (data.first.get()) float *autodpiscale = dpiscaleset ? nullptr : &settings.dpiScale;
slices.set(0, 0, data.first);
if (lua_istable(L, 1))
{
int tlen = std::max(1, (int) luax_objlen(L, 1));
if (luax_isarrayoftables(L, 1))
{
for (int slice = 0; slice < tlen; slice++)
{
lua_rawgeti(L, 1, slice + 1);
luaL_checktype(L, -1, LUA_TTABLE);
int miplen = std::max(1, (int) luax_objlen(L, -1));
for (int mip = 0; mip < miplen; mip++)
{
lua_rawgeti(L, -1, mip + 1);
auto data = getImageData(L, -1, true, slice == 0 && mip == 0 ? autodpiscale : nullptr);
if (data.first.get())
slices.set(slice, mip, data.first);
else
slices.set(slice, mip, data.second->getSlice(0, 0));
lua_pop(L, 1);
}
}
}
else
{
for (int slice = 0; slice < tlen; slice++)
{
lua_rawgeti(L, 1, slice + 1);
auto data = getImageData(L, -1, true, slice == 0 ? autodpiscale : nullptr);
if (data.first.get())
slices.set(slice, 0, data.first);
else
slices.add(data.second, slice, 0, false, settings.mipmaps != Texture::MIPMAPS_NONE);
}
}
lua_pop(L, tlen);
}
else else
slices.add(data.second, 0, 0, true, settings.mipmaps != Texture::MIPMAPS_NONE); {
auto data = getImageData(L, 1, true, autodpiscale);
if (data.first.get())
slices.set(0, 0, data.first);
else
slices.add(data.second, 0, 0, true, settings.mipmaps != Texture::MIPMAPS_NONE);
}
} }
return w__pushNewTexture(L, &slices, settings); return w__pushNewTexture(L, slicesref, settings);
} }
int w_newVolumeTexture(lua_State *L) int w_newVolumeTexture(lua_State *L)
@@ -1087,70 +1116,85 @@ int w_newVolumeTexture(lua_State *L)
auto imagemodule = Module::getInstance<love::image::Image>(Module::M_IMAGE); auto imagemodule = Module::getInstance<love::image::Image>(Module::M_IMAGE);
Texture::Slices slices(TEXTURE_VOLUME); Texture::Slices slices(TEXTURE_VOLUME);
Texture::Slices *slicesref = &slices;
Texture::Settings settings;
settings.type = TEXTURE_VOLUME;
bool dpiscaleset = false; bool dpiscaleset = false;
Texture::Settings settings = w__optImageSettings(L, 2, dpiscaleset);
float *autodpiscale = dpiscaleset ? nullptr : &settings.dpiScale;
if (lua_istable(L, 1)) if (lua_type(L, 1) == LUA_TNUMBER)
{ {
int tlen = std::max(1, (int) luax_objlen(L, 1)); slicesref = nullptr;
settings.width = (int) luaL_checkinteger(L, 1);
if (luax_isarrayoftables(L, 1)) settings.height = (int) luaL_checkinteger(L, 2);
{ settings.layers = (int) luaL_checkinteger(L, 3);
for (int mip = 0; mip < tlen; mip++) luax_checktexturesettings(L, 4, true, false, false, OptionalBool(), settings, dpiscaleset);
{
lua_rawgeti(L, 1, mip + 1);
luaL_checktype(L, -1, LUA_TTABLE);
int slicelen = std::max(1, (int) luax_objlen(L, -1));
for (int slice = 0; slice < slicelen; slice++)
{
lua_rawgeti(L, -1, mip + 1);
auto data = getImageData(L, -1, true, slice == 0 && mip == 0 ? autodpiscale : nullptr);
if (data.first.get())
slices.set(slice, mip, data.first);
else
slices.set(slice, mip, data.second->getSlice(0, 0));
lua_pop(L, 1);
}
}
}
else
{
for (int layer = 0; layer < tlen; layer++)
{
lua_rawgeti(L, 1, layer + 1);
auto data = getImageData(L, -1, true, layer == 0 ? autodpiscale : nullptr);
if (data.first.get())
slices.set(layer, 0, data.first);
else
slices.add(data.second, layer, 0, false, settings.mipmaps != Texture::MIPMAPS_NONE);
}
}
lua_pop(L, tlen);
} }
else else
{ {
auto data = getImageData(L, 1, true, autodpiscale); luax_checktexturesettings(L, 2, true, false, false, OptionalBool(), settings, dpiscaleset);
float *autodpiscale = dpiscaleset ? nullptr : &settings.dpiScale;
if (data.first.get()) if (lua_istable(L, 1))
{ {
std::vector<StrongRef<love::image::ImageData>> layers; int tlen = std::max(1, (int) luax_objlen(L, 1));
luax_catchexcept(L, [&](){ layers = imagemodule->newVolumeLayers(data.first); });
for (int i = 0; i < (int) layers.size(); i++) if (luax_isarrayoftables(L, 1))
slices.set(i, 0, layers[i]); {
for (int mip = 0; mip < tlen; mip++)
{
lua_rawgeti(L, 1, mip + 1);
luaL_checktype(L, -1, LUA_TTABLE);
int slicelen = std::max(1, (int) luax_objlen(L, -1));
for (int slice = 0; slice < slicelen; slice++)
{
lua_rawgeti(L, -1, mip + 1);
auto data = getImageData(L, -1, true, slice == 0 && mip == 0 ? autodpiscale : nullptr);
if (data.first.get())
slices.set(slice, mip, data.first);
else
slices.set(slice, mip, data.second->getSlice(0, 0));
lua_pop(L, 1);
}
}
}
else
{
for (int layer = 0; layer < tlen; layer++)
{
lua_rawgeti(L, 1, layer + 1);
auto data = getImageData(L, -1, true, layer == 0 ? autodpiscale : nullptr);
if (data.first.get())
slices.set(layer, 0, data.first);
else
slices.add(data.second, layer, 0, false, settings.mipmaps != Texture::MIPMAPS_NONE);
}
}
lua_pop(L, tlen);
} }
else else
slices.add(data.second, 0, 0, true, settings.mipmaps != Texture::MIPMAPS_NONE); {
auto data = getImageData(L, 1, true, autodpiscale);
if (data.first.get())
{
std::vector<StrongRef<love::image::ImageData>> layers;
luax_catchexcept(L, [&](){ layers = imagemodule->newVolumeLayers(data.first); });
for (int i = 0; i < (int) layers.size(); i++)
slices.set(i, 0, layers[i]);
}
else
slices.add(data.second, 0, 0, true, settings.mipmaps != Texture::MIPMAPS_NONE);
}
} }
return w__pushNewTexture(L, &slices, settings); return w__pushNewTexture(L, slicesref, settings);
} }
int w_newCanvas(lua_State *L) int w_newCanvas(lua_State *L)
+13 -13
View File
@@ -3186,21 +3186,21 @@ function love.nogame()
R.bg.cloud_3 = R.bg[dpiscale].cloud_3_png R.bg.cloud_3 = R.bg[dpiscale].cloud_3_png
R.bg.cloud_4 = R.bg[dpiscale].cloud_4_png R.bg.cloud_4 = R.bg[dpiscale].cloud_4_png
img_duckloon_normal = love.graphics.newImage(R.duckloon.normal, settings) img_duckloon_normal = love.graphics.newTexture(R.duckloon.normal, settings)
img_duckloon_blink = love.graphics.newImage(R.duckloon.blink, settings) img_duckloon_blink = love.graphics.newTexture(R.duckloon.blink, settings)
img_n = love.graphics.newImage(R.chain.n, settings) img_n = love.graphics.newTexture(R.chain.n, settings)
img_o = love.graphics.newImage(R.chain.o, settings) img_o = love.graphics.newTexture(R.chain.o, settings)
img_g = love.graphics.newImage(R.chain.g, settings) img_g = love.graphics.newTexture(R.chain.g, settings)
img_a = love.graphics.newImage(R.chain.a, settings) img_a = love.graphics.newTexture(R.chain.a, settings)
img_m = love.graphics.newImage(R.chain.m, settings) img_m = love.graphics.newTexture(R.chain.m, settings)
img_e = love.graphics.newImage(R.chain.e, settings) img_e = love.graphics.newTexture(R.chain.e, settings)
img_square = love.graphics.newImage(R.chain.square, settings) img_square = love.graphics.newTexture(R.chain.square, settings)
img_cloud_1 = love.graphics.newImage(R.bg.cloud_1, settings) img_cloud_1 = love.graphics.newTexture(R.bg.cloud_1, settings)
img_cloud_2 = love.graphics.newImage(R.bg.cloud_2, settings) img_cloud_2 = love.graphics.newTexture(R.bg.cloud_2, settings)
img_cloud_3 = love.graphics.newImage(R.bg.cloud_3, settings) img_cloud_3 = love.graphics.newTexture(R.bg.cloud_3, settings)
img_cloud_4 = love.graphics.newImage(R.bg.cloud_4, settings) img_cloud_4 = love.graphics.newTexture(R.bg.cloud_4, settings)
cloud_images = { cloud_images = {
img_cloud_1, img_cloud_1,
+39 -33
View File
@@ -11936,54 +11936,60 @@ const unsigned char nogame_lua[] =
0x0a, 0x0a,
0x09, 0x09, 0x69, 0x6d, 0x67, 0x5f, 0x64, 0x75, 0x63, 0x6b, 0x6c, 0x6f, 0x6f, 0x6e, 0x5f, 0x6e, 0x6f, 0x72, 0x09, 0x09, 0x69, 0x6d, 0x67, 0x5f, 0x64, 0x75, 0x63, 0x6b, 0x6c, 0x6f, 0x6f, 0x6e, 0x5f, 0x6e, 0x6f, 0x72,
0x6d, 0x61, 0x6c, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x6d, 0x61, 0x6c, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63,
0x73, 0x2e, 0x6e, 0x65, 0x77, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x28, 0x52, 0x2e, 0x64, 0x75, 0x63, 0x6b, 0x6c, 0x73, 0x2e, 0x6e, 0x65, 0x77, 0x54, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x28, 0x52, 0x2e, 0x64, 0x75, 0x63,
0x6f, 0x6f, 0x6e, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2c, 0x20, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x6b, 0x6c, 0x6f, 0x6f, 0x6e, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2c, 0x20, 0x73, 0x65, 0x74, 0x74,
0x67, 0x73, 0x29, 0x0a, 0x69, 0x6e, 0x67, 0x73, 0x29, 0x0a,
0x09, 0x09, 0x69, 0x6d, 0x67, 0x5f, 0x64, 0x75, 0x63, 0x6b, 0x6c, 0x6f, 0x6f, 0x6e, 0x5f, 0x62, 0x6c, 0x69, 0x09, 0x09, 0x69, 0x6d, 0x67, 0x5f, 0x64, 0x75, 0x63, 0x6b, 0x6c, 0x6f, 0x6f, 0x6e, 0x5f, 0x62, 0x6c, 0x69,
0x6e, 0x6b, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x6e, 0x6b, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73,
0x2e, 0x6e, 0x65, 0x77, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x28, 0x52, 0x2e, 0x64, 0x75, 0x63, 0x6b, 0x6c, 0x6f, 0x2e, 0x6e, 0x65, 0x77, 0x54, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x28, 0x52, 0x2e, 0x64, 0x75, 0x63, 0x6b,
0x6f, 0x6e, 0x2e, 0x62, 0x6c, 0x69, 0x6e, 0x6b, 0x2c, 0x20, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x6c, 0x6f, 0x6f, 0x6e, 0x2e, 0x62, 0x6c, 0x69, 0x6e, 0x6b, 0x2c, 0x20, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e,
0x29, 0x0a, 0x67, 0x73, 0x29, 0x0a,
0x0a, 0x0a,
0x09, 0x09, 0x69, 0x6d, 0x67, 0x5f, 0x6e, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x09, 0x09, 0x69, 0x6d, 0x67, 0x5f, 0x6e, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61,
0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x6e, 0x65, 0x77, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x28, 0x52, 0x2e, 0x63, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x6e, 0x65, 0x77, 0x54, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x28, 0x52,
0x68, 0x61, 0x69, 0x6e, 0x2e, 0x6e, 0x2c, 0x20, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x29, 0x0a, 0x2e, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x2e, 0x6e, 0x2c, 0x20, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73,
0x29, 0x0a,
0x09, 0x09, 0x69, 0x6d, 0x67, 0x5f, 0x6f, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x09, 0x09, 0x69, 0x6d, 0x67, 0x5f, 0x6f, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61,
0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x6e, 0x65, 0x77, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x28, 0x52, 0x2e, 0x63, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x6e, 0x65, 0x77, 0x54, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x28, 0x52,
0x68, 0x61, 0x69, 0x6e, 0x2e, 0x6f, 0x2c, 0x20, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x29, 0x0a, 0x2e, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x2e, 0x6f, 0x2c, 0x20, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73,
0x29, 0x0a,
0x09, 0x09, 0x69, 0x6d, 0x67, 0x5f, 0x67, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x09, 0x09, 0x69, 0x6d, 0x67, 0x5f, 0x67, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61,
0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x6e, 0x65, 0x77, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x28, 0x52, 0x2e, 0x63, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x6e, 0x65, 0x77, 0x54, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x28, 0x52,
0x68, 0x61, 0x69, 0x6e, 0x2e, 0x67, 0x2c, 0x20, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x29, 0x0a, 0x2e, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x2e, 0x67, 0x2c, 0x20, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73,
0x29, 0x0a,
0x09, 0x09, 0x69, 0x6d, 0x67, 0x5f, 0x61, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x09, 0x09, 0x69, 0x6d, 0x67, 0x5f, 0x61, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61,
0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x6e, 0x65, 0x77, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x28, 0x52, 0x2e, 0x63, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x6e, 0x65, 0x77, 0x54, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x28, 0x52,
0x68, 0x61, 0x69, 0x6e, 0x2e, 0x61, 0x2c, 0x20, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x29, 0x0a, 0x2e, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x2e, 0x61, 0x2c, 0x20, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73,
0x29, 0x0a,
0x09, 0x09, 0x69, 0x6d, 0x67, 0x5f, 0x6d, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x09, 0x09, 0x69, 0x6d, 0x67, 0x5f, 0x6d, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61,
0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x6e, 0x65, 0x77, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x28, 0x52, 0x2e, 0x63, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x6e, 0x65, 0x77, 0x54, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x28, 0x52,
0x68, 0x61, 0x69, 0x6e, 0x2e, 0x6d, 0x2c, 0x20, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x29, 0x0a, 0x2e, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x2e, 0x6d, 0x2c, 0x20, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73,
0x29, 0x0a,
0x09, 0x09, 0x69, 0x6d, 0x67, 0x5f, 0x65, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x09, 0x09, 0x69, 0x6d, 0x67, 0x5f, 0x65, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61,
0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x6e, 0x65, 0x77, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x28, 0x52, 0x2e, 0x63, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x6e, 0x65, 0x77, 0x54, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x28, 0x52,
0x68, 0x61, 0x69, 0x6e, 0x2e, 0x65, 0x2c, 0x20, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x29, 0x0a, 0x2e, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x2e, 0x65, 0x2c, 0x20, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73,
0x29, 0x0a,
0x09, 0x09, 0x69, 0x6d, 0x67, 0x5f, 0x73, 0x71, 0x75, 0x61, 0x72, 0x65, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x76, 0x09, 0x09, 0x69, 0x6d, 0x67, 0x5f, 0x73, 0x71, 0x75, 0x61, 0x72, 0x65, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x76,
0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x6e, 0x65, 0x77, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x6e, 0x65, 0x77, 0x54, 0x65, 0x78, 0x74,
0x65, 0x28, 0x52, 0x2e, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x2e, 0x73, 0x71, 0x75, 0x61, 0x72, 0x65, 0x2c, 0x20, 0x75, 0x72, 0x65, 0x28, 0x52, 0x2e, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x2e, 0x73, 0x71, 0x75, 0x61, 0x72, 0x65,
0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x29, 0x0a, 0x2c, 0x20, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x29, 0x0a,
0x0a, 0x0a,
0x09, 0x09, 0x69, 0x6d, 0x67, 0x5f, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x5f, 0x31, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x09, 0x09, 0x69, 0x6d, 0x67, 0x5f, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x5f, 0x31, 0x20, 0x3d, 0x20, 0x6c, 0x6f,
0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x6e, 0x65, 0x77, 0x49, 0x6d, 0x61, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x6e, 0x65, 0x77, 0x54, 0x65, 0x78,
0x67, 0x65, 0x28, 0x52, 0x2e, 0x62, 0x67, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x5f, 0x31, 0x2c, 0x20, 0x73, 0x74, 0x75, 0x72, 0x65, 0x28, 0x52, 0x2e, 0x62, 0x67, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x5f, 0x31, 0x2c,
0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x29, 0x0a, 0x20, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x29, 0x0a,
0x09, 0x09, 0x69, 0x6d, 0x67, 0x5f, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x5f, 0x32, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x09, 0x09, 0x69, 0x6d, 0x67, 0x5f, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x5f, 0x32, 0x20, 0x3d, 0x20, 0x6c, 0x6f,
0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x6e, 0x65, 0x77, 0x49, 0x6d, 0x61, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x6e, 0x65, 0x77, 0x54, 0x65, 0x78,
0x67, 0x65, 0x28, 0x52, 0x2e, 0x62, 0x67, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x5f, 0x32, 0x2c, 0x20, 0x73, 0x74, 0x75, 0x72, 0x65, 0x28, 0x52, 0x2e, 0x62, 0x67, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x5f, 0x32, 0x2c,
0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x29, 0x0a, 0x20, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x29, 0x0a,
0x09, 0x09, 0x69, 0x6d, 0x67, 0x5f, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x5f, 0x33, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x09, 0x09, 0x69, 0x6d, 0x67, 0x5f, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x5f, 0x33, 0x20, 0x3d, 0x20, 0x6c, 0x6f,
0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x6e, 0x65, 0x77, 0x49, 0x6d, 0x61, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x6e, 0x65, 0x77, 0x54, 0x65, 0x78,
0x67, 0x65, 0x28, 0x52, 0x2e, 0x62, 0x67, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x5f, 0x33, 0x2c, 0x20, 0x73, 0x74, 0x75, 0x72, 0x65, 0x28, 0x52, 0x2e, 0x62, 0x67, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x5f, 0x33, 0x2c,
0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x29, 0x0a, 0x20, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x29, 0x0a,
0x09, 0x09, 0x69, 0x6d, 0x67, 0x5f, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x5f, 0x34, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x09, 0x09, 0x69, 0x6d, 0x67, 0x5f, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x5f, 0x34, 0x20, 0x3d, 0x20, 0x6c, 0x6f,
0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x6e, 0x65, 0x77, 0x49, 0x6d, 0x61, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x6e, 0x65, 0x77, 0x54, 0x65, 0x78,
0x67, 0x65, 0x28, 0x52, 0x2e, 0x62, 0x67, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x5f, 0x34, 0x2c, 0x20, 0x73, 0x74, 0x75, 0x72, 0x65, 0x28, 0x52, 0x2e, 0x62, 0x67, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x5f, 0x34, 0x2c,
0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x29, 0x0a, 0x20, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x29, 0x0a,
0x0a, 0x0a,
0x09, 0x09, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x5f, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x73, 0x20, 0x3d, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x5f, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x73, 0x20, 0x3d, 0x20, 0x7b, 0x0a,
0x09, 0x09, 0x09, 0x69, 0x6d, 0x67, 0x5f, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x5f, 0x31, 0x2c, 0x0a, 0x09, 0x09, 0x09, 0x69, 0x6d, 0x67, 0x5f, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x5f, 0x31, 0x2c, 0x0a,