From bfca659e378f193aff55d2ad89a4d5f3cdbdebbe Mon Sep 17 00:00:00 2001 From: Jack Robinson Date: Tue, 31 Aug 2021 21:22:06 +1200 Subject: [PATCH 01/43] Fix #1721: floor result of scaling kerning based on dpi --- src/modules/graphics/Font.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/graphics/Font.cpp b/src/modules/graphics/Font.cpp index eb9f29742..967fe78f2 100644 --- a/src/modules/graphics/Font.cpp +++ b/src/modules/graphics/Font.cpp @@ -333,7 +333,7 @@ float Font::getKerning(uint32 leftglyph, uint32 rightglyph) if (it != kerning.end()) return it->second; - float k = rasterizers[0]->getKerning(leftglyph, rightglyph) / dpiScale + 0.5f; + float k = floorf(rasterizers[0]->getKerning(leftglyph, rightglyph) / dpiScale + 0.5f); for (const auto &r : rasterizers) { From a066e18aa62ec5b01a0b97a679cb1100f3b2617f Mon Sep 17 00:00:00 2001 From: Miku AuahDark Date: Wed, 15 Sep 2021 23:19:53 +0800 Subject: [PATCH 02/43] Register custom Lua PANIC handler that shows message box. Some users complained that LOVE simply closes when it reaches certain memory limit. Note that this is not a foolproof solution. See the comments. The real fix for this is to switch LuaJIT to GC64 mode on x64. --- src/modules/love/love.cpp | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/modules/love/love.cpp b/src/modules/love/love.cpp index 8a31f042c..e6e369802 100644 --- a/src/modules/love/love.cpp +++ b/src/modules/love/love.cpp @@ -23,6 +23,7 @@ #include "common/version.h" #include "common/deprecation.h" #include "common/runtime.h" +#include "modules/window/Window.h" #include "love.h" @@ -503,6 +504,33 @@ int luaopen_love(lua_State *L) love::luax_preload(L, luaopen_luautf8, "utf8"); #endif +#ifdef LOVE_ENABLE_WINDOW + // In some environments, LuaJIT is limited to 2GB and LuaJIT sometimes panic when it + // reaches OOM and closes the whole program, leaving the user confused about what's + // going on. + // We can't recover the state at this point, but it's better to inform user that + // something very bad happening instead of silently exiting. + // Note that this is not foolproof. In some cases, the whole process crashes by + // uncaught exception that LuaJIT throws or simply exit as if calling + // love.event.quit("not enough memory") + lua_atpanic(L, [](lua_State *L) + { + using namespace love; + using namespace love::window; + + char message[128]; + Window* windowModule = Module::getInstance(Module::M_WINDOW); + + snprintf(message, sizeof(message), "PANIC: unprotected error in call to Lua API (%s)", lua_tostring(L, -1)); + + if (windowModule) + windowModule->showMessageBox("Lua Fatal Error", message, Window::MESSAGEBOX_ERROR, windowModule->isOpen()); + + fprintf(stderr, "%s\n", message); + return 0; + }); +#endif + return 1; } From ae300d9b11aa85d366adb8666887970ff661223d Mon Sep 17 00:00:00 2001 From: Miku AuahDark Date: Thu, 16 Sep 2021 22:26:54 +0800 Subject: [PATCH 03/43] Revert "Enable JIT in Android" This reverts commit b092347823bdba79ee5dbed5704c43ddc46cbb2d. --- src/modules/love/love.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/modules/love/love.cpp b/src/modules/love/love.cpp index 9ae8f5c2e..a9900c2bb 100644 --- a/src/modules/love/love.cpp +++ b/src/modules/love/love.cpp @@ -36,6 +36,10 @@ #ifdef LOVE_ANDROID #include +extern "C" +{ +#include "luajit.h" +} #endif // LOVE_ANDROID #ifdef LOVE_LEGENDARY_CONSOLE_IO_HACK @@ -432,6 +436,7 @@ int luaopen_love(lua_State *L) lua_setfield(L, -2, "_version_codename"); #ifdef LOVE_ANDROID + luaJIT_setmode(L, 0, LUAJIT_MODE_ENGINE | LUAJIT_MODE_OFF); lua_register(L, "print", w_print_sdl_log); #endif From de368ade4a0ca9240ec560b8185feb4b1e0149a2 Mon Sep 17 00:00:00 2001 From: Miku AuahDark Date: Tue, 21 Sep 2021 22:52:50 +0800 Subject: [PATCH 04/43] Break OggDemuxer::readPage loop on EOF. --- src/modules/video/theora/OggDemuxer.cpp | 19 ++++++++++++++----- src/modules/video/theora/OggDemuxer.h | 2 +- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/modules/video/theora/OggDemuxer.cpp b/src/modules/video/theora/OggDemuxer.cpp index f5a14d936..acc6f9849 100644 --- a/src/modules/video/theora/OggDemuxer.cpp +++ b/src/modules/video/theora/OggDemuxer.cpp @@ -43,7 +43,7 @@ OggDemuxer::~OggDemuxer() ogg_sync_clear(&sync); } -void OggDemuxer::readPage() +void OggDemuxer::readPage(bool throweof) { char *syncBuffer = nullptr; while (ogg_sync_pageout(&sync, &page) != 1) @@ -53,6 +53,9 @@ void OggDemuxer::readPage() syncBuffer = ogg_sync_buffer(&sync, 8192); size_t read = file->read(syncBuffer, 8192); + if (read == 0 && throweof) + throw love::Exception("Invalid stream"); + ogg_sync_wrote(&sync, read); } } @@ -118,22 +121,23 @@ OggDemuxer::StreamType OggDemuxer::findStream() if (streamInited) { eos = false; + streamInited = false; file->seek(0); ogg_stream_clear(&stream); ogg_sync_reset(&sync); } - streamInited = true; while (true) { // If this page isn't at the start of a stream, we've seen all streams - readPage(); + readPage(true); if (!ogg_page_bos(&page)) break; videoSerial = ogg_page_serialno(&page); ogg_stream_init(&stream, videoSerial); ogg_stream_pagein(&stream, &page); + streamInited = true; StreamType type = determineType(); switch(type) @@ -145,10 +149,15 @@ OggDemuxer::StreamType OggDemuxer::findStream() } ogg_stream_clear(&stream); + streamInited = false; + } + + if (streamInited) + { + streamInited = false; + ogg_stream_clear(&stream); } - streamInited = false; - ogg_stream_clear(&stream); ogg_sync_reset(&sync); return TYPE_UNKNOWN; diff --git a/src/modules/video/theora/OggDemuxer.h b/src/modules/video/theora/OggDemuxer.h index a6b2de900..f55a352d2 100644 --- a/src/modules/video/theora/OggDemuxer.h +++ b/src/modules/video/theora/OggDemuxer.h @@ -67,7 +67,7 @@ private: int videoSerial; bool eos; - void readPage(); + void readPage(bool throweof = false); StreamType determineType(); }; // OggDemuxer From 75a3e5db015c05699d0e9f2314801ace505fbd48 Mon Sep 17 00:00:00 2001 From: Miku AuahDark Date: Sat, 25 Sep 2021 08:17:41 +0800 Subject: [PATCH 05/43] Fix VS2013 compilation of a066e18. --- src/modules/love/love.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/modules/love/love.cpp b/src/modules/love/love.cpp index e6e369802..a437beaa0 100644 --- a/src/modules/love/love.cpp +++ b/src/modules/love/love.cpp @@ -33,6 +33,12 @@ #ifdef LOVE_WINDOWS #include + +#if defined(_MSC_VER) && (_MSC_VER < 1900) +// VS 2013 and earlier doesn't have snprintf +#define snprintf sprintf_s +#endif // defined(_MSC_VER) && (_MSC_VER < 1900) + #endif // LOVE_WINDOWS #ifdef LOVE_ANDROID From ad2de2702a3af9832480cd5616cc01dbcfd1f2f2 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Sat, 2 Oct 2021 15:32:07 -0300 Subject: [PATCH 06/43] Fix a missing #include causing a potential compile error --- src/modules/graphics/wrap_Buffer.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/modules/graphics/wrap_Buffer.cpp b/src/modules/graphics/wrap_Buffer.cpp index 20102cdc2..fcfa763b3 100644 --- a/src/modules/graphics/wrap_Buffer.cpp +++ b/src/modules/graphics/wrap_Buffer.cpp @@ -22,6 +22,8 @@ #include "Buffer.h" #include "common/Data.h" +#include + namespace love { namespace graphics From 457480548648ea894905c5f70a5d4cedfa64f105 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Sun, 10 Oct 2021 22:08:56 -0300 Subject: [PATCH 07/43] Make rounded rectangles more robust. - rx and ry parameters are set to 0 if they're negative. - automatic points calculation doesn't cause an unnecessarily large amount of points when rx or ry are greater than half the rectangle's size. --- src/modules/graphics/Graphics.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/modules/graphics/Graphics.cpp b/src/modules/graphics/Graphics.cpp index 741c5c516..f8bb086f0 100644 --- a/src/modules/graphics/Graphics.cpp +++ b/src/modules/graphics/Graphics.cpp @@ -1350,7 +1350,7 @@ void Graphics::rectangle(DrawMode mode, float x, float y, float w, float h) void Graphics::rectangle(DrawMode mode, float x, float y, float w, float h, float rx, float ry, int points) { - if (rx == 0 || ry == 0) + if (rx <= 0 || ry <= 0) { rectangle(mode, x, y, w, h); return; @@ -1409,7 +1409,8 @@ void Graphics::rectangle(DrawMode mode, float x, float y, float w, float h, floa void Graphics::rectangle(DrawMode mode, float x, float y, float w, float h, float rx, float ry) { - rectangle(mode, x, y, w, h, rx, ry, calculateEllipsePoints(rx, ry)); + int points = calculateEllipsePoints(std::min(rx, std::abs(w/2)), std::min(ry, std::abs(h/2))); + rectangle(mode, x, y, w, h, rx, ry, points); } void Graphics::circle(DrawMode mode, float x, float y, float radius, int points) From e5954af38e325692154a32fcc44fb419a7b7c39e Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Sat, 16 Oct 2021 21:14:38 -0300 Subject: [PATCH 08/43] update Github Actions builds to pull megasource from the new main branch --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 58d9dd6d1..65f5b4a63 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -51,7 +51,7 @@ jobs: with: path: megasource repository: love2d/megasource - ref: master + ref: main - name: Checkout uses: actions/checkout@v2 with: From 28372bff7ec98637764a802bece5e9921816dd75 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Sat, 16 Oct 2021 21:15:58 -0300 Subject: [PATCH 09/43] Update readme to refer to new main branch name --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 3d9affc6b..da777de6b 100644 --- a/readme.md +++ b/readme.md @@ -12,7 +12,7 @@ If you need further help, feel free to ask on our [forums][forums], our [Discord Repository ---------- -We use the 'master' branch for patch development of the current major release, and therefore it should not be considered stable. +We use the 'main' branch for patch development of the current major release, and therefore it should not be considered stable. There may also be a branch for the next major version in development, which is named after that version. We tag all our releases (since we started using mercurial and git), and have binary downloads available for them. From 9b8a422d95fdf583ebe7f49d2537c4a7b2a80e5f Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Sat, 16 Oct 2021 21:25:05 -0300 Subject: [PATCH 10/43] update lodepng to latest code --- src/libraries/lodepng/lodepng.cpp | 185 ++++++++++++++++++++++-------- src/libraries/lodepng/lodepng.h | 108 ++++++++++++++--- 2 files changed, 227 insertions(+), 66 deletions(-) diff --git a/src/libraries/lodepng/lodepng.cpp b/src/libraries/lodepng/lodepng.cpp index ee8cf33d2..c6e7f384c 100644 --- a/src/libraries/lodepng/lodepng.cpp +++ b/src/libraries/lodepng/lodepng.cpp @@ -1,7 +1,7 @@ /* -LodePNG version 20200306 +LodePNG version 20210627 -Copyright (c) 2005-2020 Lode Vandevenne +Copyright (c) 2005-2021 Lode Vandevenne This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -44,7 +44,7 @@ Rename this file to lodepng.cpp to use it for C++, or to lodepng.c to use it for #pragma warning( disable : 4996 ) /*VS does not like fopen, but fopen_s is not standard C so unusable here*/ #endif /*_MSC_VER */ -const char* LODEPNG_VERSION_STRING = "20200306"; +const char* LODEPNG_VERSION_STRING = "20210627"; /* This source file is built up in the following large parts. The code sections @@ -299,6 +299,7 @@ static void string_cleanup(char** out) { *out = NULL; } +/*also appends null termination character*/ static char* alloc_string_sized(const char* in, size_t insize) { char* out = (char*)lodepng_malloc(insize + 1); if(out) { @@ -1260,7 +1261,7 @@ static unsigned getTreeInflateDynamic(HuffmanTree* tree_ll, HuffmanTree* tree_d, /*inflate a block with dynamic of fixed Huffman tree. btype must be 1 or 2.*/ static unsigned inflateHuffmanBlock(ucvector* out, LodePNGBitReader* reader, - unsigned btype) { + unsigned btype, size_t max_output_size) { unsigned error = 0; HuffmanTree tree_ll; /*the huffman tree for literal and length codes*/ HuffmanTree tree_d; /*the huffman tree for distance codes*/ @@ -1341,6 +1342,9 @@ static unsigned inflateHuffmanBlock(ucvector* out, LodePNGBitReader* reader, /* TODO: revise error codes 10,11,50: the above comment is no longer valid */ ERROR_BREAK(51); /*error, bit pointer jumps past memory*/ } + if(max_output_size && out->size > max_output_size) { + ERROR_BREAK(109); /*error, larger than max size*/ + } } HuffmanTree_cleanup(&tree_ll); @@ -1398,9 +1402,9 @@ static unsigned lodepng_inflatev(ucvector* out, if(BTYPE == 3) return 20; /*error: invalid BTYPE*/ else if(BTYPE == 0) error = inflateNoCompression(out, &reader, settings); /*no compression*/ - else error = inflateHuffmanBlock(out, &reader, BTYPE); /*compression, BTYPE 01 or 10*/ - - if(error) return error; + else error = inflateHuffmanBlock(out, &reader, BTYPE, settings->max_output_size); /*compression, BTYPE 01 or 10*/ + if(!error && settings->max_output_size && out->size > settings->max_output_size) error = 109; + if(error) break; } return error; @@ -1421,6 +1425,12 @@ static unsigned inflatev(ucvector* out, const unsigned char* in, size_t insize, if(settings->custom_inflate) { unsigned error = settings->custom_inflate(&out->data, &out->size, in, insize, settings); out->allocsize = out->size; + if(error) { + /*the custom inflate is allowed to have its own error codes, however, we translate it to code 110*/ + error = 110; + /*if there's a max output size, and the custom zlib returned error, then indicate that error instead*/ + if(settings->max_output_size && out->size > settings->max_output_size) error = 109; + } return error; } else { return lodepng_inflatev(out, in, insize, settings); @@ -2116,7 +2126,9 @@ static unsigned deflate(unsigned char** out, size_t* outsize, const unsigned char* in, size_t insize, const LodePNGCompressSettings* settings) { if(settings->custom_deflate) { - return settings->custom_deflate(out, outsize, in, insize, settings); + unsigned error = settings->custom_deflate(out, outsize, in, insize, settings); + /*the custom deflate is allowed to have its own error codes, however, we translate it to code 111*/ + return error ? 111 : 0; } else { return lodepng_deflate(out, outsize, in, insize, settings); } @@ -2213,10 +2225,16 @@ unsigned lodepng_zlib_decompress(unsigned char** out, size_t* outsize, const uns /*expected_size is expected output size, to avoid intermediate allocations. Set to 0 if not known. */ static unsigned zlib_decompress(unsigned char** out, size_t* outsize, size_t expected_size, const unsigned char* in, size_t insize, const LodePNGDecompressSettings* settings) { + unsigned error; if(settings->custom_zlib) { - return settings->custom_zlib(out, outsize, in, insize, settings); + error = settings->custom_zlib(out, outsize, in, insize, settings); + if(error) { + /*the custom zlib is allowed to have its own error codes, however, we translate it to code 110*/ + error = 110; + /*if there's a max output size, and the custom zlib returned error, then indicate that error instead*/ + if(settings->max_output_size && *outsize > settings->max_output_size) error = 109; + } } else { - unsigned error; ucvector v = ucvector_init(*out, *outsize); if(expected_size) { /*reserve the memory to avoid intermediate reallocations*/ @@ -2226,8 +2244,8 @@ static unsigned zlib_decompress(unsigned char** out, size_t* outsize, size_t exp error = lodepng_zlib_decompressv(&v, in, insize, settings); *out = v.data; *outsize = v.size; - return error; } + return error; } #endif /*LODEPNG_COMPILE_DECODER*/ @@ -2275,7 +2293,9 @@ unsigned lodepng_zlib_compress(unsigned char** out, size_t* outsize, const unsig static unsigned zlib_compress(unsigned char** out, size_t* outsize, const unsigned char* in, size_t insize, const LodePNGCompressSettings* settings) { if(settings->custom_zlib) { - return settings->custom_zlib(out, outsize, in, insize, settings); + unsigned error = settings->custom_zlib(out, outsize, in, insize, settings); + /*the custom zlib is allowed to have its own error codes, however, we translate it to code 111*/ + return error ? 111 : 0; } else { return lodepng_zlib_compress(out, outsize, in, insize, settings); } @@ -2334,13 +2354,14 @@ const LodePNGCompressSettings lodepng_default_compress_settings = {2, 1, DEFAULT void lodepng_decompress_settings_init(LodePNGDecompressSettings* settings) { settings->ignore_adler32 = 0; settings->ignore_nlen = 0; + settings->max_output_size = 0; settings->custom_zlib = 0; settings->custom_inflate = 0; settings->custom_context = 0; } -const LodePNGDecompressSettings lodepng_default_decompress_settings = {0, 0, 0, 0, 0}; +const LodePNGDecompressSettings lodepng_default_decompress_settings = {0, 0, 0, 0, 0, 0}; #endif /*LODEPNG_COMPILE_DECODER*/ @@ -2872,8 +2893,8 @@ static void LodePNGText_cleanup(LodePNGInfo* info) { static unsigned LodePNGText_copy(LodePNGInfo* dest, const LodePNGInfo* source) { size_t i = 0; - dest->text_keys = 0; - dest->text_strings = 0; + dest->text_keys = NULL; + dest->text_strings = NULL; dest->text_num = 0; for(i = 0; i != source->text_num; ++i) { CERROR_TRY_RETURN(lodepng_add_text(dest, source->text_keys[i], source->text_strings[i])); @@ -2932,10 +2953,10 @@ static void LodePNGIText_cleanup(LodePNGInfo* info) { static unsigned LodePNGIText_copy(LodePNGInfo* dest, const LodePNGInfo* source) { size_t i = 0; - dest->itext_keys = 0; - dest->itext_langtags = 0; - dest->itext_transkeys = 0; - dest->itext_strings = 0; + dest->itext_keys = NULL; + dest->itext_langtags = NULL; + dest->itext_transkeys = NULL; + dest->itext_strings = NULL; dest->itext_num = 0; for(i = 0; i != source->itext_num; ++i) { CERROR_TRY_RETURN(lodepng_add_itext(dest, source->itext_keys[i], source->itext_langtags[i], @@ -4093,10 +4114,12 @@ static unsigned unfilterScanline(unsigned char* recon, const unsigned char* scan case 0: for(i = 0; i != length; ++i) recon[i] = scanline[i]; break; - case 1: + case 1: { + size_t j = 0; for(i = 0; i != bytewidth; ++i) recon[i] = scanline[i]; - for(i = bytewidth; i < length; ++i) recon[i] = scanline[i] + recon[i - bytewidth]; + for(i = bytewidth; i != length; ++i, ++j) recon[i] = scanline[i] + recon[j]; break; + } case 2: if(precon) { for(i = 0; i != length; ++i) recon[i] = scanline[i] + precon[i]; @@ -4106,24 +4129,56 @@ static unsigned unfilterScanline(unsigned char* recon, const unsigned char* scan break; case 3: if(precon) { + size_t j = 0; for(i = 0; i != bytewidth; ++i) recon[i] = scanline[i] + (precon[i] >> 1u); - for(i = bytewidth; i < length; ++i) recon[i] = scanline[i] + ((recon[i - bytewidth] + precon[i]) >> 1u); + /* Unroll independent paths of this predictor. A 6x and 8x version is also possible but that adds + too much code. Whether this speeds up anything depends on compiler and settings. */ + if(bytewidth >= 4) { + for(; i + 3 < length; i += 4, j += 4) { + unsigned char s0 = scanline[i + 0], r0 = recon[j + 0], p0 = precon[i + 0]; + unsigned char s1 = scanline[i + 1], r1 = recon[j + 1], p1 = precon[i + 1]; + unsigned char s2 = scanline[i + 2], r2 = recon[j + 2], p2 = precon[i + 2]; + unsigned char s3 = scanline[i + 3], r3 = recon[j + 3], p3 = precon[i + 3]; + recon[i + 0] = s0 + ((r0 + p0) >> 1u); + recon[i + 1] = s1 + ((r1 + p1) >> 1u); + recon[i + 2] = s2 + ((r2 + p2) >> 1u); + recon[i + 3] = s3 + ((r3 + p3) >> 1u); + } + } else if(bytewidth >= 3) { + for(; i + 2 < length; i += 3, j += 3) { + unsigned char s0 = scanline[i + 0], r0 = recon[j + 0], p0 = precon[i + 0]; + unsigned char s1 = scanline[i + 1], r1 = recon[j + 1], p1 = precon[i + 1]; + unsigned char s2 = scanline[i + 2], r2 = recon[j + 2], p2 = precon[i + 2]; + recon[i + 0] = s0 + ((r0 + p0) >> 1u); + recon[i + 1] = s1 + ((r1 + p1) >> 1u); + recon[i + 2] = s2 + ((r2 + p2) >> 1u); + } + } else if(bytewidth >= 2) { + for(; i + 1 < length; i += 2, j += 2) { + unsigned char s0 = scanline[i + 0], r0 = recon[j + 0], p0 = precon[i + 0]; + unsigned char s1 = scanline[i + 1], r1 = recon[j + 1], p1 = precon[i + 1]; + recon[i + 0] = s0 + ((r0 + p0) >> 1u); + recon[i + 1] = s1 + ((r1 + p1) >> 1u); + } + } + for(; i != length; ++i, ++j) recon[i] = scanline[i] + ((recon[j] + precon[i]) >> 1u); } else { + size_t j = 0; for(i = 0; i != bytewidth; ++i) recon[i] = scanline[i]; - for(i = bytewidth; i < length; ++i) recon[i] = scanline[i] + (recon[i - bytewidth] >> 1u); + for(i = bytewidth; i != length; ++i, ++j) recon[i] = scanline[i] + (recon[j] >> 1u); } break; case 4: if(precon) { + size_t j = 0; for(i = 0; i != bytewidth; ++i) { recon[i] = (scanline[i] + precon[i]); /*paethPredictor(0, precon[i], 0) is always precon[i]*/ } - /* Unroll independent paths of the paeth predictor. A 6x and 8x version would also be possible but that - adds too much code. Whether this actually speeds anything up at all depends on compiler and settings. */ + /* Unroll independent paths of the paeth predictor. A 6x and 8x version is also possible but that + adds too much code. Whether this speeds up anything depends on compiler and settings. */ if(bytewidth >= 4) { - for(; i + 3 < length; i += 4) { - size_t j = i - bytewidth; + for(; i + 3 < length; i += 4, j += 4) { unsigned char s0 = scanline[i + 0], s1 = scanline[i + 1], s2 = scanline[i + 2], s3 = scanline[i + 3]; unsigned char r0 = recon[j + 0], r1 = recon[j + 1], r2 = recon[j + 2], r3 = recon[j + 3]; unsigned char p0 = precon[i + 0], p1 = precon[i + 1], p2 = precon[i + 2], p3 = precon[i + 3]; @@ -4134,8 +4189,7 @@ static unsigned unfilterScanline(unsigned char* recon, const unsigned char* scan recon[i + 3] = s3 + paethPredictor(r3, p3, q3); } } else if(bytewidth >= 3) { - for(; i + 2 < length; i += 3) { - size_t j = i - bytewidth; + for(; i + 2 < length; i += 3, j += 3) { unsigned char s0 = scanline[i + 0], s1 = scanline[i + 1], s2 = scanline[i + 2]; unsigned char r0 = recon[j + 0], r1 = recon[j + 1], r2 = recon[j + 2]; unsigned char p0 = precon[i + 0], p1 = precon[i + 1], p2 = precon[i + 2]; @@ -4145,8 +4199,7 @@ static unsigned unfilterScanline(unsigned char* recon, const unsigned char* scan recon[i + 2] = s2 + paethPredictor(r2, p2, q2); } } else if(bytewidth >= 2) { - for(; i + 1 < length; i += 2) { - size_t j = i - bytewidth; + for(; i + 1 < length; i += 2, j += 2) { unsigned char s0 = scanline[i + 0], s1 = scanline[i + 1]; unsigned char r0 = recon[j + 0], r1 = recon[j + 1]; unsigned char p0 = precon[i + 0], p1 = precon[i + 1]; @@ -4156,16 +4209,17 @@ static unsigned unfilterScanline(unsigned char* recon, const unsigned char* scan } } - for(; i != length; ++i) { - recon[i] = (scanline[i] + paethPredictor(recon[i - bytewidth], precon[i], precon[i - bytewidth])); + for(; i != length; ++i, ++j) { + recon[i] = (scanline[i] + paethPredictor(recon[i - bytewidth], precon[i], precon[j])); } } else { + size_t j = 0; for(i = 0; i != bytewidth; ++i) { recon[i] = scanline[i]; } - for(i = bytewidth; i < length; ++i) { + for(i = bytewidth; i != length; ++i, ++j) { /*paethPredictor(recon[i - bytewidth], 0, 0) is always recon[i - bytewidth]*/ - recon[i] = (scanline[i] + recon[i - bytewidth]); + recon[i] = (scanline[i] + recon[j]); } } break; @@ -4447,10 +4501,13 @@ static unsigned readChunk_tEXt(LodePNGInfo* info, const unsigned char* data, siz } /*compressed text chunk (zTXt)*/ -static unsigned readChunk_zTXt(LodePNGInfo* info, const LodePNGDecompressSettings* zlibsettings, +static unsigned readChunk_zTXt(LodePNGInfo* info, const LodePNGDecoderSettings* decoder, const unsigned char* data, size_t chunkLength) { unsigned error = 0; + /*copy the object to change parameters in it*/ + LodePNGDecompressSettings zlibsettings = decoder->zlibsettings; + unsigned length, string2_begin; char *key = 0; unsigned char* str = 0; @@ -4473,12 +4530,14 @@ static unsigned readChunk_zTXt(LodePNGInfo* info, const LodePNGDecompressSetting if(string2_begin > chunkLength) CERROR_BREAK(error, 75); /*no null termination, corrupt?*/ length = (unsigned)chunkLength - string2_begin; + zlibsettings.max_output_size = decoder->max_text_size; /*will fail if zlib error, e.g. if length is too small*/ error = zlib_decompress(&str, &size, 0, &data[string2_begin], - length, zlibsettings); + length, &zlibsettings); + /*error: compressed text larger than decoder->max_text_size*/ + if(error && size > zlibsettings.max_output_size) error = 112; if(error) break; error = lodepng_add_text_sized(info, key, (char*)str, size); - break; } @@ -4489,11 +4548,14 @@ static unsigned readChunk_zTXt(LodePNGInfo* info, const LodePNGDecompressSetting } /*international text chunk (iTXt)*/ -static unsigned readChunk_iTXt(LodePNGInfo* info, const LodePNGDecompressSettings* zlibsettings, +static unsigned readChunk_iTXt(LodePNGInfo* info, const LodePNGDecoderSettings* decoder, const unsigned char* data, size_t chunkLength) { unsigned error = 0; unsigned i; + /*copy the object to change parameters in it*/ + LodePNGDecompressSettings zlibsettings = decoder->zlibsettings; + unsigned length, begin, compressed; char *key = 0, *langtag = 0, *transkey = 0; @@ -4550,9 +4612,12 @@ static unsigned readChunk_iTXt(LodePNGInfo* info, const LodePNGDecompressSetting if(compressed) { unsigned char* str = 0; size_t size = 0; + zlibsettings.max_output_size = decoder->max_text_size; /*will fail if zlib error, e.g. if length is too small*/ error = zlib_decompress(&str, &size, 0, &data[begin], - length, zlibsettings); + length, &zlibsettings); + /*error: compressed text larger than decoder->max_text_size*/ + if(error && size > zlibsettings.max_output_size) error = 112; if(!error) error = lodepng_add_itext_sized(info, key, langtag, transkey, (char*)str, size); lodepng_free(str); } else { @@ -4628,11 +4693,13 @@ static unsigned readChunk_sRGB(LodePNGInfo* info, const unsigned char* data, siz return 0; /* OK */ } -static unsigned readChunk_iCCP(LodePNGInfo* info, const LodePNGDecompressSettings* zlibsettings, +static unsigned readChunk_iCCP(LodePNGInfo* info, const LodePNGDecoderSettings* decoder, const unsigned char* data, size_t chunkLength) { unsigned error = 0; unsigned i; size_t size = 0; + /*copy the object to change parameters in it*/ + LodePNGDecompressSettings zlibsettings = decoder->zlibsettings; unsigned length, string2_begin; @@ -4655,9 +4722,12 @@ static unsigned readChunk_iCCP(LodePNGInfo* info, const LodePNGDecompressSetting if(string2_begin > chunkLength) return 75; /*no null termination, corrupt?*/ length = (unsigned)chunkLength - string2_begin; + zlibsettings.max_output_size = decoder->max_icc_size; error = zlib_decompress(&info->iccp_profile, &size, 0, &data[string2_begin], - length, zlibsettings); + length, &zlibsettings); + /*error: ICC profile larger than decoder->max_icc_size*/ + if(error && size > zlibsettings.max_output_size) error = 113; info->iccp_profile_size = size; if(!error && !info->iccp_profile_size) error = 100; /*invalid ICC profile size*/ return error; @@ -4688,9 +4758,9 @@ unsigned lodepng_inspect_chunk(LodePNGState* state, size_t pos, } else if(lodepng_chunk_type_equals(chunk, "tEXt")) { error = readChunk_tEXt(&state->info_png, data, chunkLength); } else if(lodepng_chunk_type_equals(chunk, "zTXt")) { - error = readChunk_zTXt(&state->info_png, &state->decoder.zlibsettings, data, chunkLength); + error = readChunk_zTXt(&state->info_png, &state->decoder, data, chunkLength); } else if(lodepng_chunk_type_equals(chunk, "iTXt")) { - error = readChunk_iTXt(&state->info_png, &state->decoder.zlibsettings, data, chunkLength); + error = readChunk_iTXt(&state->info_png, &state->decoder, data, chunkLength); } else if(lodepng_chunk_type_equals(chunk, "tIME")) { error = readChunk_tIME(&state->info_png, data, chunkLength); } else if(lodepng_chunk_type_equals(chunk, "pHYs")) { @@ -4702,7 +4772,7 @@ unsigned lodepng_inspect_chunk(LodePNGState* state, size_t pos, } else if(lodepng_chunk_type_equals(chunk, "sRGB")) { error = readChunk_sRGB(&state->info_png, data, chunkLength); } else if(lodepng_chunk_type_equals(chunk, "iCCP")) { - error = readChunk_iCCP(&state->info_png, &state->decoder.zlibsettings, data, chunkLength); + error = readChunk_iCCP(&state->info_png, &state->decoder, data, chunkLength); #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ } else { /* unhandled chunk is ok (is not an error) */ @@ -4820,13 +4890,13 @@ static void decodeGeneric(unsigned char** out, unsigned* w, unsigned* h, } else if(lodepng_chunk_type_equals(chunk, "zTXt")) { /*compressed text chunk (zTXt)*/ if(state->decoder.read_text_chunks) { - state->error = readChunk_zTXt(&state->info_png, &state->decoder.zlibsettings, data, chunkLength); + state->error = readChunk_zTXt(&state->info_png, &state->decoder, data, chunkLength); if(state->error) break; } } else if(lodepng_chunk_type_equals(chunk, "iTXt")) { /*international text chunk (iTXt)*/ if(state->decoder.read_text_chunks) { - state->error = readChunk_iTXt(&state->info_png, &state->decoder.zlibsettings, data, chunkLength); + state->error = readChunk_iTXt(&state->info_png, &state->decoder, data, chunkLength); if(state->error) break; } } else if(lodepng_chunk_type_equals(chunk, "tIME")) { @@ -4845,7 +4915,7 @@ static void decodeGeneric(unsigned char** out, unsigned* w, unsigned* h, state->error = readChunk_sRGB(&state->info_png, data, chunkLength); if(state->error) break; } else if(lodepng_chunk_type_equals(chunk, "iCCP")) { - state->error = readChunk_iCCP(&state->info_png, &state->decoder.zlibsettings, data, chunkLength); + state->error = readChunk_iCCP(&state->info_png, &state->decoder, data, chunkLength); if(state->error) break; #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ } else /*it's not an implemented chunk type, so ignore it: skip over the data*/ { @@ -4871,7 +4941,7 @@ static void decodeGeneric(unsigned char** out, unsigned* w, unsigned* h, if(!IEND) chunk = lodepng_chunk_next_const(chunk, in + insize); } - if(state->info_png.color.colortype == LCT_PALETTE && !state->info_png.color.palette) { + if(!state->error && state->info_png.color.colortype == LCT_PALETTE && !state->info_png.color.palette) { state->error = 106; /* error: PNG file must have PLTE chunk if color type is palette */ } @@ -4955,6 +5025,11 @@ unsigned lodepng_decode_memory(unsigned char** out, unsigned* w, unsigned* h, co lodepng_state_init(&state); state.info_raw.colortype = colortype; state.info_raw.bitdepth = bitdepth; +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + /*disable reading things that this function doesn't output*/ + state.decoder.read_text_chunks = 0; + state.decoder.remember_unknown_chunks = 0; +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ error = lodepng_decode(out, w, h, &state, in, insize); lodepng_state_cleanup(&state); return error; @@ -4997,6 +5072,8 @@ void lodepng_decoder_settings_init(LodePNGDecoderSettings* settings) { #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS settings->read_text_chunks = 1; settings->remember_unknown_chunks = 0; + settings->max_text_size = 16777216; + settings->max_icc_size = 16777216; /* 16MB is much more than enough for any reasonable ICC profile */ #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ settings->ignore_crc = 0; settings->ignore_critical = 0; @@ -6204,6 +6281,16 @@ const char* lodepng_error_text(unsigned code) { case 106: return "PNG file must have PLTE chunk if color type is palette"; case 107: return "color convert from palette mode requested without setting the palette data in it"; case 108: return "tried to add more than 256 values to a palette"; + /*this limit can be configured in LodePNGDecompressSettings*/ + case 109: return "tried to decompress zlib or deflate data larger than desired max_output_size"; + case 110: return "custom zlib or inflate decompression failed"; + case 111: return "custom zlib or deflate compression failed"; + /*max text size limit can be configured in LodePNGDecoderSettings. This error prevents + unreasonable memory consumption when decoding due to impossibly large text sizes.*/ + case 112: return "compressed text unreasonably large"; + /*max ICC size limit can be configured in LodePNGDecoderSettings. This error prevents + unreasonable memory consumption when decoding due to impossibly large ICC profile*/ + case 113: return "ICC profile unreasonably large"; } return "unknown error code"; } diff --git a/src/libraries/lodepng/lodepng.h b/src/libraries/lodepng/lodepng.h index a386459f9..3e1da92de 100644 --- a/src/libraries/lodepng/lodepng.h +++ b/src/libraries/lodepng/lodepng.h @@ -1,7 +1,7 @@ /* -LodePNG version 20200306 +LodePNG version 20210627 -Copyright (c) 2005-2020 Lode Vandevenne +Copyright (c) 2005-2021 Lode Vandevenne This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -142,16 +142,24 @@ unsigned lodepng_decode24(unsigned char** out, unsigned* w, unsigned* h, /* Load PNG from disk, from file with given name. Same as the other decode functions, but instead takes a filename as input. -*/ + +NOTE: Wide-character filenames are not supported, you can use an external method +to handle such files and decode in-memory.*/ unsigned lodepng_decode_file(unsigned char** out, unsigned* w, unsigned* h, const char* filename, LodePNGColorType colortype, unsigned bitdepth); -/*Same as lodepng_decode_file, but always decodes to 32-bit RGBA raw image.*/ +/*Same as lodepng_decode_file, but always decodes to 32-bit RGBA raw image. + +NOTE: Wide-character filenames are not supported, you can use an external method +to handle such files and decode in-memory.*/ unsigned lodepng_decode32_file(unsigned char** out, unsigned* w, unsigned* h, const char* filename); -/*Same as lodepng_decode_file, but always decodes to 24-bit RGB raw image.*/ +/*Same as lodepng_decode_file, but always decodes to 24-bit RGB raw image. + +NOTE: Wide-character filenames are not supported, you can use an external method +to handle such files and decode in-memory.*/ unsigned lodepng_decode24_file(unsigned char** out, unsigned* w, unsigned* h, const char* filename); #endif /*LODEPNG_COMPILE_DISK*/ @@ -191,17 +199,26 @@ unsigned lodepng_encode24(unsigned char** out, size_t* outsize, /* Converts raw pixel data into a PNG file on disk. Same as the other encode functions, but instead takes a filename as output. + NOTE: This overwrites existing files without warning! -*/ + +NOTE: Wide-character filenames are not supported, you can use an external method +to handle such files and encode in-memory.*/ unsigned lodepng_encode_file(const char* filename, const unsigned char* image, unsigned w, unsigned h, LodePNGColorType colortype, unsigned bitdepth); -/*Same as lodepng_encode_file, but always encodes from 32-bit RGBA raw image.*/ +/*Same as lodepng_encode_file, but always encodes from 32-bit RGBA raw image. + +NOTE: Wide-character filenames are not supported, you can use an external method +to handle such files and encode in-memory.*/ unsigned lodepng_encode32_file(const char* filename, const unsigned char* image, unsigned w, unsigned h); -/*Same as lodepng_encode_file, but always encodes from 24-bit RGB raw image.*/ +/*Same as lodepng_encode_file, but always encodes from 24-bit RGB raw image. + +NOTE: Wide-character filenames are not supported, you can use an external method +to handle such files and encode in-memory.*/ unsigned lodepng_encode24_file(const char* filename, const unsigned char* image, unsigned w, unsigned h); #endif /*LODEPNG_COMPILE_DISK*/ @@ -223,6 +240,9 @@ unsigned decode(std::vector& out, unsigned& w, unsigned& h, /* Converts PNG file from disk to raw pixel data in memory. Same as the other decode functions, but instead takes a filename as input. + +NOTE: Wide-character filenames are not supported, you can use an external method +to handle such files and decode in-memory. */ unsigned decode(std::vector& out, unsigned& w, unsigned& h, const std::string& filename, @@ -243,7 +263,11 @@ unsigned encode(std::vector& out, /* Converts 32-bit RGBA raw pixel data into a PNG file on disk. Same as the other encode functions, but instead takes a filename as output. + NOTE: This overwrites existing files without warning! + +NOTE: Wide-character filenames are not supported, you can use an external method +to handle such files and decode in-memory. */ unsigned encode(const std::string& filename, const unsigned char* in, unsigned w, unsigned h, @@ -270,12 +294,21 @@ struct LodePNGDecompressSettings { unsigned ignore_adler32; /*if 1, continue and don't give an error message if the Adler32 checksum is corrupted*/ unsigned ignore_nlen; /*ignore complement of len checksum in uncompressed blocks*/ - /*use custom zlib decoder instead of built in one (default: null)*/ + /*Maximum decompressed size, beyond this the decoder may (and is encouraged to) stop decoding, + return an error, output a data size > max_output_size and all the data up to that point. This is + not hard limit nor a guarantee, but can prevent excessive memory usage. This setting is + ignored by the PNG decoder, but is used by the deflate/zlib decoder and can be used by custom ones. + Set to 0 to impose no limit (the default).*/ + size_t max_output_size; + + /*use custom zlib decoder instead of built in one (default: null). + Should return 0 if success, any non-0 if error (numeric value not exposed).*/ unsigned (*custom_zlib)(unsigned char**, size_t*, const unsigned char*, size_t, const LodePNGDecompressSettings*); /*use custom deflate decoder instead of built in one (default: null) - if custom_zlib is not null, custom_inflate is ignored (the zlib format uses deflate)*/ + if custom_zlib is not null, custom_inflate is ignored (the zlib format uses deflate). + Should return 0 if success, any non-0 if error (numeric value not exposed).*/ unsigned (*custom_inflate)(unsigned char**, size_t*, const unsigned char*, size_t, const LodePNGDecompressSettings*); @@ -454,30 +487,36 @@ typedef struct LodePNGInfo { unsigned background_b; /*blue component of suggested background color*/ /* - non-international text chunks (tEXt and zTXt) + Non-international text chunks (tEXt and zTXt) The char** arrays each contain num strings. The actual messages are in text_strings, while text_keys are keywords that give a short description what the actual text represents, e.g. Title, Author, Description, or anything else. - All the string fields below including keys, names and language tags are null terminated. + All the string fields below including strings, keys, names and language tags are null terminated. The PNG specification uses null characters for the keys, names and tags, and forbids null characters to appear in the main text which is why we can use null termination everywhere here. - A keyword is minimum 1 character and maximum 79 characters long. It's - discouraged to use a single line length longer than 79 characters for texts. + A keyword is minimum 1 character and maximum 79 characters long (plus the + additional null terminator). It's discouraged to use a single line length + longer than 79 characters for texts. Don't allocate these text buffers yourself. Use the init/cleanup functions correctly and use lodepng_add_text and lodepng_clear_text. + + Standard text chunk keywords and strings are encoded using Latin-1. */ size_t text_num; /*the amount of texts in these char** buffers (there may be more texts in itext)*/ char** text_keys; /*the keyword of a text chunk (e.g. "Comment")*/ char** text_strings; /*the actual text*/ /* - international text chunks (iTXt) + International text chunks (iTXt) Similar to the non-international text chunks, but with additional strings - "langtags" and "transkeys". + "langtags" and "transkeys", and the following text encodings are used: + keys: Latin-1, langtags: ASCII, transkeys and strings: UTF-8. + keys must be 1-79 characters (plus the additional null terminator), the other + strings are any length. */ size_t itext_num; /*the amount of international texts in this PNG*/ char** itext_keys; /*the English keyword of the text chunk (e.g. "Comment")*/ @@ -639,8 +678,19 @@ typedef struct LodePNGDecoderSettings { #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS unsigned read_text_chunks; /*if false but remember_unknown_chunks is true, they're stored in the unknown chunks*/ + /*store all bytes from unknown chunks in the LodePNGInfo (off by default, useful for a png editor)*/ unsigned remember_unknown_chunks; + + /* maximum size for decompressed text chunks. If a text chunk's text is larger than this, an error is returned, + unless reading text chunks is disabled or this limit is set higher or disabled. Set to 0 to allow any size. + By default it is a value that prevents unreasonably large strings from hogging memory. */ + size_t max_text_size; + + /* maximum size for compressed ICC chunks. If the ICC profile is larger than this, an error will be returned. Set to + 0 to allow any size. By default this is a value that prevents ICC profiles that would be much larger than any + legitimate profile could be to hog memory. */ + size_t max_icc_size; #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ } LodePNGDecoderSettings; @@ -950,6 +1000,9 @@ out: output parameter, contains pointer to loaded buffer. outsize: output parameter, size of the allocated out buffer filename: the path to the file to load return value: error code (0 means ok) + +NOTE: Wide-character filenames are not supported, you can use an external method +to handle such files and decode in-memory. */ unsigned lodepng_load_file(unsigned char** out, size_t* outsize, const char* filename); @@ -960,6 +1013,9 @@ buffer: the buffer to write buffersize: size of the buffer to write filename: the path to the file to save to return value: error code (0 means ok) + +NOTE: Wide-character filenames are not supported, you can use an external method +to handle such files and encode in-memory */ unsigned lodepng_save_file(const unsigned char* buffer, size_t buffersize, const char* filename); #endif /*LODEPNG_COMPILE_DISK*/ @@ -1000,12 +1056,18 @@ unsigned encode(std::vector& out, /* Load a file from disk into an std::vector. return value: error code (0 means ok) + +NOTE: Wide-character filenames are not supported, you can use an external method +to handle such files and decode in-memory */ unsigned load_file(std::vector& buffer, const std::string& filename); /* Save the binary data in an std::vector to a file on disk. The file is overwritten without warning. + +NOTE: Wide-character filenames are not supported, you can use an external method +to handle such files and encode in-memory */ unsigned save_file(const std::vector& buffer, const std::string& filename); #endif /* LODEPNG_COMPILE_DISK */ @@ -1505,6 +1567,11 @@ of the error in English as a string. Check the implementation of lodepng_error_text to see the meaning of each code. +It is not recommended to use the numerical values to programmatically make +different decisions based on error types as the numbers are not guaranteed to +stay backwards compatible. They are for human consumption only. Programmatically +only 0 or non-0 matter. + 8. chunks and PNG editing ------------------------- @@ -1678,6 +1745,9 @@ try to fix it if the compiler is modern and standards compliant. This decoder example shows the most basic usage of LodePNG. More complex examples can be found on the LodePNG website. +NOTE: these examples do not support wide-character filenames, you can use an +external method to handle such files and encode or decode in-memory + 10.1. decoder C++ example ------------------------- @@ -1775,6 +1845,10 @@ symbol. Not all changes are listed here, the commit history in github lists more: https://github.com/lvandeve/lodepng +*) 27 jun 2021: added warnings that file reading/writing functions don't support + wide-character filenames (support for this is not planned, opening files is + not the core part of PNG decoding/decoding and is platform dependent). +*) 17 okt 2020: prevent decoding too large text/icc chunks by default. *) 06 mar 2020: simplified some of the dynamic memory allocations. *) 12 jan 2020: (!) added 'end' argument to lodepng_chunk_next to allow correct overflow checks. @@ -1941,5 +2015,5 @@ Domain: gmail dot com. Account: lode dot vandevenne. -Copyright (c) 2005-2020 Lode Vandevenne +Copyright (c) 2005-2021 Lode Vandevenne */ From 0f4adbab0dc51397e722ab1870b68579e47b4900 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Sat, 16 Oct 2021 21:28:22 -0300 Subject: [PATCH 11/43] update stb_image from 2.26 to 2.27 --- src/libraries/stb/stb_image.h | 281 +++++++++++++++++++++++++--------- 1 file changed, 208 insertions(+), 73 deletions(-) diff --git a/src/libraries/stb/stb_image.h b/src/libraries/stb/stb_image.h index accef4839..d60371b95 100644 --- a/src/libraries/stb/stb_image.h +++ b/src/libraries/stb/stb_image.h @@ -1,4 +1,4 @@ -/* stb_image - v2.26 - public domain image loader - http://nothings.org/stb +/* stb_image - v2.27 - public domain image loader - http://nothings.org/stb no warranty implied; use at your own risk Do this: @@ -48,6 +48,7 @@ LICENSE RECENT REVISION HISTORY: + 2.27 (2021-07-11) document stbi_info better, 16-bit PNM support, bug fixes 2.26 (2020-07-13) many minor fixes 2.25 (2020-02-02) fix warnings 2.24 (2020-02-02) fix warnings; thread-local failure_reason and flip_vertically @@ -89,7 +90,7 @@ RECENT REVISION HISTORY: Jeremy Sawicki (handle all ImageNet JPGs) Optimizations & bugfixes Mikhail Morozov (1-bit BMP) Fabian "ryg" Giesen Anael Seghezzi (is-16-bit query) - Arseny Kapoulkine + Arseny Kapoulkine Simon Breuss (16-bit PNM) John-Mark Allen Carmelo J Fdez-Aguera @@ -102,7 +103,7 @@ RECENT REVISION HISTORY: Thomas Ruf Ronny Chevalier github:rlyeh Janez Zemva John Bartholomew Michal Cichon github:romigrou Jonathan Blow Ken Hamada Tero Hanninen github:svdijk - Laurent Gomila Cort Stratton github:snagar + Eugene Golushkov Laurent Gomila Cort Stratton github:snagar Aruelien Pocheville Sergio Gonzalez Thibault Reuille github:Zelex Cass Everitt Ryamond Barbiero github:grim210 Paul Du Bois Engin Manap Aldo Culquicondor github:sammyhw @@ -110,11 +111,13 @@ RECENT REVISION HISTORY: Josh Tobin Matthew Gregan github:poppolopoppo Julian Raschke Gregory Mullen Christian Floisand github:darealshinji Baldur Karlsson Kevin Schmidt JR Smith github:Michaelangel007 - Brad Weinberger Matvey Cherevko [reserved] + Brad Weinberger Matvey Cherevko github:mosra Luca Sas Alexander Veselov Zack Middleton [reserved] Ryan C. Gordon [reserved] [reserved] DO NOT ADD YOUR NAME HERE + Jacko Dirks + To add your name to the credits, pick a random blank space in the middle and fill it. 80% of merge conflicts on stb PRs are due to people adding their name at the end of the credits. @@ -176,6 +179,32 @@ RECENT REVISION HISTORY: // // Paletted PNG, BMP, GIF, and PIC images are automatically depalettized. // +// To query the width, height and component count of an image without having to +// decode the full file, you can use the stbi_info family of functions: +// +// int x,y,n,ok; +// ok = stbi_info(filename, &x, &y, &n); +// // returns ok=1 and sets x, y, n if image is a supported format, +// // 0 otherwise. +// +// Note that stb_image pervasively uses ints in its public API for sizes, +// including sizes of memory buffers. This is now part of the API and thus +// hard to change without causing breakage. As a result, the various image +// loaders all have certain limits on image size; these differ somewhat +// by format but generally boil down to either just under 2GB or just under +// 1GB. When the decoded image would be larger than this, stb_image decoding +// will fail. +// +// Additionally, stb_image will reject image files that have any of their +// dimensions set to a larger value than the configurable STBI_MAX_DIMENSIONS, +// which defaults to 2**24 = 16777216 pixels. Due to the above memory limit, +// the only way to have an image with such dimensions load correctly +// is for it to have a rather extreme aspect ratio. Either way, the +// assumption here is that such larger images are likely to be malformed +// or malicious. If you do need to load an image with individual dimensions +// larger than that, and it still fits in the overall size limit, you can +// #define STBI_MAX_DIMENSIONS on your own to be something larger. +// // =========================================================================== // // UNICODE: @@ -281,11 +310,10 @@ RECENT REVISION HISTORY: // // iPhone PNG support: // -// By default we convert iphone-formatted PNGs back to RGB, even though -// they are internally encoded differently. You can disable this conversion -// by calling stbi_convert_iphone_png_to_rgb(0), in which case -// you will always just get the native iphone "format" through (which -// is BGR stored in RGB). +// We optionally support converting iPhone-formatted PNGs (which store +// premultiplied BGRA) back to RGB, even though they're internally encoded +// differently. To enable this conversion, call +// stbi_convert_iphone_png_to_rgb(1). // // Call stbi_set_unpremultiply_on_load(1) as well to force a divide per // pixel to remove any premultiplied alpha *only* if the image file explicitly @@ -489,6 +517,8 @@ STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip); // as above, but only applies to images loaded on the thread that calls the function // this function is only available if your compiler supports thread-local variables; // calling it will fail to link if your compiler doesn't +STBIDEF void stbi_set_unpremultiply_on_load_thread(int flag_true_if_should_unpremultiply); +STBIDEF void stbi_convert_iphone_png_to_rgb_thread(int flag_true_if_should_convert); STBIDEF void stbi_set_flip_vertically_on_load_thread(int flag_true_if_should_flip); // ZLIB client - used by PNG, available for other purposes @@ -634,7 +664,7 @@ typedef unsigned char validate_uint32[sizeof(stbi__uint32)==4 ? 1 : -1]; #ifdef STBI_HAS_LROTL #define stbi_lrot(x,y) _lrotl(x,y) #else - #define stbi_lrot(x,y) (((x) << (y)) | ((x) >> (32 - (y)))) + #define stbi_lrot(x,y) (((x) << (y)) | ((x) >> (-(y) & 31))) #endif #if defined(STBI_MALLOC) && defined(STBI_FREE) && (defined(STBI_REALLOC) || defined(STBI_REALLOC_SIZED)) @@ -748,9 +778,12 @@ static int stbi__sse2_available(void) #ifdef STBI_NEON #include -// assume GCC or Clang on ARM targets +#ifdef _MSC_VER +#define STBI_SIMD_ALIGN(type, name) __declspec(align(16)) type name +#else #define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16))) #endif +#endif #ifndef STBI_SIMD_ALIGN #define STBI_SIMD_ALIGN(type, name) type name @@ -924,6 +957,7 @@ static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp); static int stbi__pnm_test(stbi__context *s); static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp); +static int stbi__pnm_is16(stbi__context *s); #endif static @@ -998,7 +1032,7 @@ static int stbi__mad3sizes_valid(int a, int b, int c, int add) } // returns 1 if "a*b*c*d + add" has no negative terms/factors and doesn't overflow -#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) +#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) || !defined(STBI_NO_PNM) static int stbi__mad4sizes_valid(int a, int b, int c, int d, int add) { return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a*b, c) && @@ -1021,7 +1055,7 @@ static void *stbi__malloc_mad3(int a, int b, int c, int add) return stbi__malloc(a*b*c + add); } -#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) +#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) || !defined(STBI_NO_PNM) static void *stbi__malloc_mad4(int a, int b, int c, int d, int add) { if (!stbi__mad4sizes_valid(a, b, c, d, add)) return NULL; @@ -1087,9 +1121,8 @@ static void *stbi__load_main(stbi__context *s, int *x, int *y, int *comp, int re ri->channel_order = STBI_ORDER_RGB; // all current input & output are this, but this is here so we can add BGR order ri->num_channels = 0; - #ifndef STBI_NO_JPEG - if (stbi__jpeg_test(s)) return stbi__jpeg_load(s,x,y,comp,req_comp, ri); - #endif + // test the formats with a very explicit header first (at least a FOURCC + // or distinctive magic number first) #ifndef STBI_NO_PNG if (stbi__png_test(s)) return stbi__png_load(s,x,y,comp,req_comp, ri); #endif @@ -1107,6 +1140,13 @@ static void *stbi__load_main(stbi__context *s, int *x, int *y, int *comp, int re #ifndef STBI_NO_PIC if (stbi__pic_test(s)) return stbi__pic_load(s,x,y,comp,req_comp, ri); #endif + + // then the formats that can end up attempting to load with just 1 or 2 + // bytes matching expectations; these are prone to false positives, so + // try them later + #ifndef STBI_NO_JPEG + if (stbi__jpeg_test(s)) return stbi__jpeg_load(s,x,y,comp,req_comp, ri); + #endif #ifndef STBI_NO_PNM if (stbi__pnm_test(s)) return stbi__pnm_load(s,x,y,comp,req_comp, ri); #endif @@ -1262,12 +1302,12 @@ static void stbi__float_postprocess(float *result, int *x, int *y, int *comp, in #ifndef STBI_NO_STDIO -#if defined(_MSC_VER) && defined(STBI_WINDOWS_UTF8) +#if defined(_WIN32) && defined(STBI_WINDOWS_UTF8) STBI_EXTERN __declspec(dllimport) int __stdcall MultiByteToWideChar(unsigned int cp, unsigned long flags, const char *str, int cbmb, wchar_t *widestr, int cchwide); STBI_EXTERN __declspec(dllimport) int __stdcall WideCharToMultiByte(unsigned int cp, unsigned long flags, const wchar_t *widestr, int cchwide, char *str, int cbmb, const char *defchar, int *used_default); #endif -#if defined(_MSC_VER) && defined(STBI_WINDOWS_UTF8) +#if defined(_WIN32) && defined(STBI_WINDOWS_UTF8) STBIDEF int stbi_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input) { return WideCharToMultiByte(65001 /* UTF8 */, 0, input, -1, buffer, (int) bufferlen, NULL, NULL); @@ -1277,16 +1317,16 @@ STBIDEF int stbi_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wch static FILE *stbi__fopen(char const *filename, char const *mode) { FILE *f; -#if defined(_MSC_VER) && defined(STBI_WINDOWS_UTF8) +#if defined(_WIN32) && defined(STBI_WINDOWS_UTF8) wchar_t wMode[64]; wchar_t wFilename[1024]; - if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename))) + if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename)/sizeof(*wFilename))) return 0; - if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode))) + if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode)/sizeof(*wMode))) return 0; -#if _MSC_VER >= 1400 +#if defined(_MSC_VER) && _MSC_VER >= 1400 if (0 != _wfopen_s(&f, wFilename, wMode)) f = 0; #else @@ -1662,7 +1702,8 @@ static int stbi__get16le(stbi__context *s) static stbi__uint32 stbi__get32le(stbi__context *s) { stbi__uint32 z = stbi__get16le(s); - return z + (stbi__get16le(s) << 16); + z += (stbi__uint32)stbi__get16le(s) << 16; + return z; } #endif @@ -2090,13 +2131,12 @@ stbi_inline static int stbi__extend_receive(stbi__jpeg *j, int n) int sgn; if (j->code_bits < n) stbi__grow_buffer_unsafe(j); - sgn = (stbi__int32)j->code_buffer >> 31; // sign bit is always in MSB + sgn = j->code_buffer >> 31; // sign bit always in MSB; 0 if MSB clear (positive), 1 if MSB set (negative) k = stbi_lrot(j->code_buffer, n); - if (n < 0 || n >= (int) (sizeof(stbi__bmask)/sizeof(*stbi__bmask))) return 0; j->code_buffer = k & ~stbi__bmask[n]; k &= stbi__bmask[n]; j->code_bits -= n; - return k + (stbi__jbias[n] & ~sgn); + return k + (stbi__jbias[n] & (sgn - 1)); } // get some unsigned bits @@ -2146,7 +2186,7 @@ static int stbi__jpeg_decode_block(stbi__jpeg *j, short data[64], stbi__huffman if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); t = stbi__jpeg_huff_decode(j, hdc); - if (t < 0) return stbi__err("bad huffman code","Corrupt JPEG"); + if (t < 0 || t > 15) return stbi__err("bad huffman code","Corrupt JPEG"); // 0 all the ac values now so we can do it 32-bits at a time memset(data,0,64*sizeof(data[0])); @@ -2203,12 +2243,12 @@ static int stbi__jpeg_decode_block_prog_dc(stbi__jpeg *j, short data[64], stbi__ // first scan for DC coefficient, must be first memset(data,0,64*sizeof(data[0])); // 0 all the ac values now t = stbi__jpeg_huff_decode(j, hdc); - if (t == -1) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); + if (t < 0 || t > 15) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); diff = t ? stbi__extend_receive(j, t) : 0; dc = j->img_comp[b].dc_pred + diff; j->img_comp[b].dc_pred = dc; - data[0] = (short) (dc << j->succ_low); + data[0] = (short) (dc * (1 << j->succ_low)); } else { // refinement scan for DC coefficient if (stbi__jpeg_get_bit(j)) @@ -2245,7 +2285,7 @@ static int stbi__jpeg_decode_block_prog_ac(stbi__jpeg *j, short data[64], stbi__ j->code_buffer <<= s; j->code_bits -= s; zig = stbi__jpeg_dezigzag[k++]; - data[zig] = (short) ((r >> 8) << shift); + data[zig] = (short) ((r >> 8) * (1 << shift)); } else { int rs = stbi__jpeg_huff_decode(j, hac); if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); @@ -2263,7 +2303,7 @@ static int stbi__jpeg_decode_block_prog_ac(stbi__jpeg *j, short data[64], stbi__ } else { k += r; zig = stbi__jpeg_dezigzag[k++]; - data[zig] = (short) (stbi__extend_receive(j,s) << shift); + data[zig] = (short) (stbi__extend_receive(j,s) * (1 << shift)); } } } while (k <= j->spec_end); @@ -3227,6 +3267,13 @@ static int stbi__process_frame_header(stbi__jpeg *z, int scan) if (z->img_comp[i].v > v_max) v_max = z->img_comp[i].v; } + // check that plane subsampling factors are integer ratios; our resamplers can't deal with fractional ratios + // and I've never seen a non-corrupted JPEG file actually use them + for (i=0; i < s->img_n; ++i) { + if (h_max % z->img_comp[i].h != 0) return stbi__err("bad H","Corrupt JPEG"); + if (v_max % z->img_comp[i].v != 0) return stbi__err("bad V","Corrupt JPEG"); + } + // compute interleaved mcu info z->img_h_max = h_max; z->img_v_max = v_max; @@ -3782,6 +3829,10 @@ static stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp else decode_n = z->s->img_n; + // nothing to do if no components requested; check this now to avoid + // accessing uninitialized coutput[0] later + if (decode_n <= 0) { stbi__cleanup_jpeg(z); return NULL; } + // resample and color-convert { int k; @@ -3924,6 +3975,7 @@ static void *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int re { unsigned char* result; stbi__jpeg* j = (stbi__jpeg*) stbi__malloc(sizeof(stbi__jpeg)); + if (!j) return stbi__errpuc("outofmem", "Out of memory"); STBI_NOTUSED(ri); j->s = s; stbi__setup_jpeg(j); @@ -3936,6 +3988,7 @@ static int stbi__jpeg_test(stbi__context *s) { int r; stbi__jpeg* j = (stbi__jpeg*)stbi__malloc(sizeof(stbi__jpeg)); + if (!j) return stbi__err("outofmem", "Out of memory"); j->s = s; stbi__setup_jpeg(j); r = stbi__decode_jpeg_header(j, STBI__SCAN_type); @@ -3960,6 +4013,7 @@ static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp) { int result; stbi__jpeg* j = (stbi__jpeg*) (stbi__malloc(sizeof(stbi__jpeg))); + if (!j) return stbi__err("outofmem", "Out of memory"); j->s = s; result = stbi__jpeg_info_raw(j, x, y, comp); STBI_FREE(j); @@ -3979,6 +4033,7 @@ static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp) // fast-way is faster to check than jpeg huffman, but slow way is slower #define STBI__ZFAST_BITS 9 // accelerate all cases in default tables #define STBI__ZFAST_MASK ((1 << STBI__ZFAST_BITS) - 1) +#define STBI__ZNSYMS 288 // number of symbols in literal/length alphabet // zlib-style huffman encoding // (jpegs packs from left, zlib from right, so can't share code) @@ -3988,8 +4043,8 @@ typedef struct stbi__uint16 firstcode[16]; int maxcode[17]; stbi__uint16 firstsymbol[16]; - stbi_uc size[288]; - stbi__uint16 value[288]; + stbi_uc size[STBI__ZNSYMS]; + stbi__uint16 value[STBI__ZNSYMS]; } stbi__zhuffman; stbi_inline static int stbi__bitreverse16(int n) @@ -4120,7 +4175,7 @@ static int stbi__zhuffman_decode_slowpath(stbi__zbuf *a, stbi__zhuffman *z) if (s >= 16) return -1; // invalid code! // code size is s, so: b = (k >> (16-s)) - z->firstcode[s] + z->firstsymbol[s]; - if (b >= sizeof (z->size)) return -1; // some data was corrupt somewhere! + if (b >= STBI__ZNSYMS) return -1; // some data was corrupt somewhere! if (z->size[b] != s) return -1; // was originally an assert, but report failure instead. a->code_buffer >>= s; a->num_bits -= s; @@ -4317,7 +4372,7 @@ static int stbi__parse_zlib_header(stbi__zbuf *a) return 1; } -static const stbi_uc stbi__zdefault_length[288] = +static const stbi_uc stbi__zdefault_length[STBI__ZNSYMS] = { 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, @@ -4363,7 +4418,7 @@ static int stbi__parse_zlib(stbi__zbuf *a, int parse_header) } else { if (type == 1) { // use fixed code lengths - if (!stbi__zbuild_huffman(&a->z_length , stbi__zdefault_length , 288)) return 0; + if (!stbi__zbuild_huffman(&a->z_length , stbi__zdefault_length , STBI__ZNSYMS)) return 0; if (!stbi__zbuild_huffman(&a->z_distance, stbi__zdefault_distance, 32)) return 0; } else { if (!stbi__compute_huffman_codes(a)) return 0; @@ -4759,6 +4814,7 @@ static int stbi__create_png_image(stbi__png *a, stbi_uc *image_data, stbi__uint3 // de-interlacing final = (stbi_uc *) stbi__malloc_mad3(a->s->img_x, a->s->img_y, out_bytes, 0); + if (!final) return stbi__err("outofmem", "Out of memory"); for (p=0; p < 7; ++p) { int xorig[] = { 0,4,0,2,0,1,0 }; int yorig[] = { 0,0,4,0,2,0,1 }; @@ -4879,19 +4935,46 @@ static int stbi__expand_png_palette(stbi__png *a, stbi_uc *palette, int len, int return 1; } -static int stbi__unpremultiply_on_load = 0; -static int stbi__de_iphone_flag = 0; +static int stbi__unpremultiply_on_load_global = 0; +static int stbi__de_iphone_flag_global = 0; STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply) { - stbi__unpremultiply_on_load = flag_true_if_should_unpremultiply; + stbi__unpremultiply_on_load_global = flag_true_if_should_unpremultiply; } STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert) { - stbi__de_iphone_flag = flag_true_if_should_convert; + stbi__de_iphone_flag_global = flag_true_if_should_convert; } +#ifndef STBI_THREAD_LOCAL +#define stbi__unpremultiply_on_load stbi__unpremultiply_on_load_global +#define stbi__de_iphone_flag stbi__de_iphone_flag_global +#else +static STBI_THREAD_LOCAL int stbi__unpremultiply_on_load_local, stbi__unpremultiply_on_load_set; +static STBI_THREAD_LOCAL int stbi__de_iphone_flag_local, stbi__de_iphone_flag_set; + +STBIDEF void stbi__unpremultiply_on_load_thread(int flag_true_if_should_unpremultiply) +{ + stbi__unpremultiply_on_load_local = flag_true_if_should_unpremultiply; + stbi__unpremultiply_on_load_set = 1; +} + +STBIDEF void stbi_convert_iphone_png_to_rgb_thread(int flag_true_if_should_convert) +{ + stbi__de_iphone_flag_local = flag_true_if_should_convert; + stbi__de_iphone_flag_set = 1; +} + +#define stbi__unpremultiply_on_load (stbi__unpremultiply_on_load_set \ + ? stbi__unpremultiply_on_load_local \ + : stbi__unpremultiply_on_load_global) +#define stbi__de_iphone_flag (stbi__de_iphone_flag_set \ + ? stbi__de_iphone_flag_local \ + : stbi__de_iphone_flag_global) +#endif // STBI_THREAD_LOCAL + static void stbi__de_iphone(stbi__png *z) { stbi__context *s = z->s; @@ -5272,6 +5355,32 @@ typedef struct int extra_read; } stbi__bmp_data; +static int stbi__bmp_set_mask_defaults(stbi__bmp_data *info, int compress) +{ + // BI_BITFIELDS specifies masks explicitly, don't override + if (compress == 3) + return 1; + + if (compress == 0) { + if (info->bpp == 16) { + info->mr = 31u << 10; + info->mg = 31u << 5; + info->mb = 31u << 0; + } else if (info->bpp == 32) { + info->mr = 0xffu << 16; + info->mg = 0xffu << 8; + info->mb = 0xffu << 0; + info->ma = 0xffu << 24; + info->all_a = 0; // if all_a is 0 at end, then we loaded alpha channel but it was all 0 + } else { + // otherwise, use defaults, which is all-0 + info->mr = info->mg = info->mb = info->ma = 0; + } + return 1; + } + return 0; // error +} + static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info) { int hsz; @@ -5299,6 +5408,8 @@ static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info) if (hsz != 12) { int compress = stbi__get32le(s); if (compress == 1 || compress == 2) return stbi__errpuc("BMP RLE", "BMP type not supported: RLE"); + if (compress >= 4) return stbi__errpuc("BMP JPEG/PNG", "BMP type not supported: unsupported compression"); // this includes PNG/JPEG modes + if (compress == 3 && info->bpp != 16 && info->bpp != 32) return stbi__errpuc("bad BMP", "bad BMP"); // bitfields requires 16 or 32 bits/pixel stbi__get32le(s); // discard sizeof stbi__get32le(s); // discard hres stbi__get32le(s); // discard vres @@ -5313,17 +5424,7 @@ static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info) } if (info->bpp == 16 || info->bpp == 32) { if (compress == 0) { - if (info->bpp == 32) { - info->mr = 0xffu << 16; - info->mg = 0xffu << 8; - info->mb = 0xffu << 0; - info->ma = 0xffu << 24; - info->all_a = 0; // if all_a is 0 at end, then we loaded alpha channel but it was all 0 - } else { - info->mr = 31u << 10; - info->mg = 31u << 5; - info->mb = 31u << 0; - } + stbi__bmp_set_mask_defaults(info, compress); } else if (compress == 3) { info->mr = stbi__get32le(s); info->mg = stbi__get32le(s); @@ -5338,6 +5439,7 @@ static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info) return stbi__errpuc("bad BMP", "bad BMP"); } } else { + // V4/V5 header int i; if (hsz != 108 && hsz != 124) return stbi__errpuc("bad BMP", "bad BMP"); @@ -5345,6 +5447,8 @@ static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info) info->mg = stbi__get32le(s); info->mb = stbi__get32le(s); info->ma = stbi__get32le(s); + if (compress != 3) // override mr/mg/mb unless in BI_BITFIELDS mode, as per docs + stbi__bmp_set_mask_defaults(info, compress); stbi__get32le(s); // discard color space for (i=0; i < 12; ++i) stbi__get32le(s); // discard color space parameters @@ -5394,8 +5498,7 @@ static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req psize = (info.offset - info.extra_read - info.hsz) >> 2; } if (psize == 0) { - STBI_ASSERT(info.offset == s->callback_already_read + (int) (s->img_buffer - s->img_buffer_original)); - if (info.offset != s->callback_already_read + (s->img_buffer - s->buffer_start)) { + if (info.offset != s->callback_already_read + (s->img_buffer - s->img_buffer_original)) { return stbi__errpuc("bad offset", "Corrupt BMP"); } } @@ -6342,6 +6445,7 @@ static void *stbi__pic_load(stbi__context *s,int *px,int *py,int *comp,int req_c // intermediate buffer is RGBA result = (stbi_uc *) stbi__malloc_mad3(x, y, 4, 0); + if (!result) return stbi__errpuc("outofmem", "Out of memory"); memset(result, 0xff, x*y*4); if (!stbi__pic_load_core(s,x,y,comp, result)) { @@ -6457,6 +6561,7 @@ static int stbi__gif_header(stbi__context *s, stbi__gif *g, int *comp, int is_in static int stbi__gif_info_raw(stbi__context *s, int *x, int *y, int *comp) { stbi__gif* g = (stbi__gif*) stbi__malloc(sizeof(stbi__gif)); + if (!g) return stbi__err("outofmem", "Out of memory"); if (!stbi__gif_header(s, g, comp, 1)) { STBI_FREE(g); stbi__rewind( s ); @@ -6766,6 +6871,17 @@ static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, i } } +static void *stbi__load_gif_main_outofmem(stbi__gif *g, stbi_uc *out, int **delays) +{ + STBI_FREE(g->out); + STBI_FREE(g->history); + STBI_FREE(g->background); + + if (out) STBI_FREE(out); + if (delays && *delays) STBI_FREE(*delays); + return stbi__errpuc("outofmem", "Out of memory"); +} + static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, int *z, int *comp, int req_comp) { if (stbi__gif_test(s)) { @@ -6777,6 +6893,10 @@ static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, int stride; int out_size = 0; int delays_size = 0; + + STBI_NOTUSED(out_size); + STBI_NOTUSED(delays_size); + memset(&g, 0, sizeof(g)); if (delays) { *delays = 0; @@ -6794,26 +6914,29 @@ static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, if (out) { void *tmp = (stbi_uc*) STBI_REALLOC_SIZED( out, out_size, layers * stride ); - if (NULL == tmp) { - STBI_FREE(g.out); - STBI_FREE(g.history); - STBI_FREE(g.background); - return stbi__errpuc("outofmem", "Out of memory"); - } + if (!tmp) + return stbi__load_gif_main_outofmem(&g, out, delays); else { out = (stbi_uc*) tmp; out_size = layers * stride; } if (delays) { - *delays = (int*) STBI_REALLOC_SIZED( *delays, delays_size, sizeof(int) * layers ); + int *new_delays = (int*) STBI_REALLOC_SIZED( *delays, delays_size, sizeof(int) * layers ); + if (!new_delays) + return stbi__load_gif_main_outofmem(&g, out, delays); + *delays = new_delays; delays_size = layers * sizeof(int); } } else { out = (stbi_uc*)stbi__malloc( layers * stride ); + if (!out) + return stbi__load_gif_main_outofmem(&g, out, delays); out_size = layers * stride; if (delays) { *delays = (int*) stbi__malloc( layers * sizeof(int) ); + if (!*delays) + return stbi__load_gif_main_outofmem(&g, out, delays); delays_size = layers * sizeof(int); } } @@ -7138,9 +7261,10 @@ static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp) info.all_a = 255; p = stbi__bmp_parse_header(s, &info); - stbi__rewind( s ); - if (p == NULL) + if (p == NULL) { + stbi__rewind( s ); return 0; + } if (x) *x = s->img_x; if (y) *y = s->img_y; if (comp) { @@ -7206,8 +7330,8 @@ static int stbi__psd_is16(stbi__context *s) stbi__rewind( s ); return 0; } - (void) stbi__get32be(s); - (void) stbi__get32be(s); + STBI_NOTUSED(stbi__get32be(s)); + STBI_NOTUSED(stbi__get32be(s)); depth = stbi__get16be(s); if (depth != 16) { stbi__rewind( s ); @@ -7286,7 +7410,6 @@ static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp) // Known limitations: // Does not support comments in the header section // Does not support ASCII image data (formats P2 and P3) -// Does not support 16-bit-per-channel #ifndef STBI_NO_PNM @@ -7307,7 +7430,8 @@ static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req stbi_uc *out; STBI_NOTUSED(ri); - if (!stbi__pnm_info(s, (int *)&s->img_x, (int *)&s->img_y, (int *)&s->img_n)) + ri->bits_per_channel = stbi__pnm_info(s, (int *)&s->img_x, (int *)&s->img_y, (int *)&s->img_n); + if (ri->bits_per_channel == 0) return 0; if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); @@ -7317,12 +7441,12 @@ static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req *y = s->img_y; if (comp) *comp = s->img_n; - if (!stbi__mad3sizes_valid(s->img_n, s->img_x, s->img_y, 0)) + if (!stbi__mad4sizes_valid(s->img_n, s->img_x, s->img_y, ri->bits_per_channel / 8, 0)) return stbi__errpuc("too large", "PNM too large"); - out = (stbi_uc *) stbi__malloc_mad3(s->img_n, s->img_x, s->img_y, 0); + out = (stbi_uc *) stbi__malloc_mad4(s->img_n, s->img_x, s->img_y, ri->bits_per_channel / 8, 0); if (!out) return stbi__errpuc("outofmem", "Out of memory"); - stbi__getn(s, out, s->img_n * s->img_x * s->img_y); + stbi__getn(s, out, s->img_n * s->img_x * s->img_y * (ri->bits_per_channel / 8)); if (req_comp && req_comp != s->img_n) { out = stbi__convert_format(out, s->img_n, req_comp, s->img_x, s->img_y); @@ -7398,11 +7522,19 @@ static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp) stbi__pnm_skip_whitespace(s, &c); maxv = stbi__pnm_getinteger(s, &c); // read max value - - if (maxv > 255) - return stbi__err("max value > 255", "PPM image not 8-bit"); + if (maxv > 65535) + return stbi__err("max value > 65535", "PPM image supports only 8-bit and 16-bit images"); + else if (maxv > 255) + return 16; else - return 1; + return 8; +} + +static int stbi__pnm_is16(stbi__context *s) +{ + if (stbi__pnm_info(s, NULL, NULL, NULL) == 16) + return 1; + return 0; } #endif @@ -7458,6 +7590,9 @@ static int stbi__is_16_main(stbi__context *s) if (stbi__psd_is16(s)) return 1; #endif + #ifndef STBI_NO_PNM + if (stbi__pnm_is16(s)) return 1; + #endif return 0; } From e27a71f798787f1f0a8b18d2adffc68244cbf70f Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Tue, 19 Oct 2021 21:22:26 -0300 Subject: [PATCH 12/43] Move boot.lua to src/modules/love/ with raw string literal format. Split it up into 3 files to keep under VS2013's raw string literal character limit. Now boot.lua doesn't need a regeneration step when it's modified. --- .../xcode/liblove.xcodeproj/project.pbxproj | 8 +- src/modules/love/arg.lua | 186 ++ src/modules/love/boot.lua | 379 ++++ src/modules/love/callbacks.lua | 316 ++++ src/modules/love/love.cpp | 37 +- src/scripts/boot.lua | 808 --------- src/scripts/boot.lua.h | 1596 ----------------- 7 files changed, 919 insertions(+), 2411 deletions(-) create mode 100644 src/modules/love/arg.lua create mode 100644 src/modules/love/boot.lua create mode 100644 src/modules/love/callbacks.lua delete mode 100644 src/scripts/boot.lua delete mode 100644 src/scripts/boot.lua.h diff --git a/platform/xcode/liblove.xcodeproj/project.pbxproj b/platform/xcode/liblove.xcodeproj/project.pbxproj index 5b306d07e..3e3226bc0 100644 --- a/platform/xcode/liblove.xcodeproj/project.pbxproj +++ b/platform/xcode/liblove.xcodeproj/project.pbxproj @@ -1267,7 +1267,6 @@ 217DFBD41D9F6D490055D849 /* url.lua.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = url.lua.h; sourceTree = ""; }; 217DFBD51D9F6D490055D849 /* usocket.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = usocket.c; sourceTree = ""; }; 217DFBD61D9F6D490055D849 /* usocket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = usocket.h; sourceTree = ""; }; - 503971A86B7167A91B670FBA /* boot.lua.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = boot.lua.h; sourceTree = ""; }; FA08F5AE16C7525600F007B5 /* liblove-macosx.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = "liblove-macosx.plist"; path = "macosx/liblove-macosx.plist"; sourceTree = ""; }; FA0A3A5D23366CE9001C269E /* floattypes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = floattypes.h; sourceTree = ""; }; FA0A3A5E23366CE9001C269E /* floattypes.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = floattypes.cpp; sourceTree = ""; }; @@ -1777,6 +1776,8 @@ FA1E887D1DF363CD00E808AA /* Filter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Filter.h; sourceTree = ""; }; FA1E88811DF363DB00E808AA /* Filter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Filter.cpp; sourceTree = ""; }; FA1E88821DF363DB00E808AA /* Filter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Filter.h; sourceTree = ""; }; + FA1E95B4271F932B0044CF08 /* arg.lua */ = {isa = PBXFileReference; lastKnownFileType = text; path = arg.lua; sourceTree = ""; }; + FA1E95B5271F932B0044CF08 /* callbacks.lua */ = {isa = PBXFileReference; lastKnownFileType = text; path = callbacks.lua; sourceTree = ""; }; FA24348021D401CB00B8918A /* pch.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = pch.cpp; sourceTree = ""; }; FA24348121D401CB00B8918A /* attribute.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = attribute.h; sourceTree = ""; }; FA24348221D401CB00B8918A /* attribute.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = attribute.cpp; sourceTree = ""; }; @@ -2101,8 +2102,6 @@ isa = PBXGroup; children = ( FA577A8C16C71D3600860150 /* auto.lua */, - FA577A8D16C71D3600860150 /* boot.lua */, - 503971A86B7167A91B670FBA /* boot.lua.h */, FA283EDC1B27CFAA00C70067 /* nogame.lua */, FA283EDD1B27CFAA00C70067 /* nogame.lua.h */, ); @@ -2964,6 +2963,9 @@ FA0B7BFD1A95902C000E1D17 /* love */ = { isa = PBXGroup; children = ( + FA1E95B4271F932B0044CF08 /* arg.lua */, + FA577A8D16C71D3600860150 /* boot.lua */, + FA1E95B5271F932B0044CF08 /* callbacks.lua */, FA0B7BFE1A95902C000E1D17 /* love.cpp */, FA0B7BFF1A95902C000E1D17 /* love.h */, ); diff --git a/src/modules/love/arg.lua b/src/modules/love/arg.lua new file mode 100644 index 000000000..8a3eacc87 --- /dev/null +++ b/src/modules/love/arg.lua @@ -0,0 +1,186 @@ +R"luastring"--( +-- DO NOT REMOVE THE ABOVE LINE. It is used to load this file as a C++ string. +-- There is a matching delimiter at the bottom of the file. + +--[[ +Copyright (c) 2006-2021 LOVE Development Team + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +--]] + +local love = require("love") + +-- Used for setup: +love.path = {} +love.arg = {} + +-- Replace any \ with /. +function love.path.normalslashes(p) + return p:gsub("\\", "/") +end + +-- Makes sure there is a slash at the end +-- of a path. +function love.path.endslash(p) + if p:sub(-1) ~= "/" then + return p .. "/" + else + return p + end +end + +-- Checks whether a path is absolute or not. +function love.path.abs(p) + + local tmp = love.path.normalslashes(p) + + -- Path is absolute if it starts with a "/". + if tmp:find("/") == 1 then + return true + end + + -- Path is absolute if it starts with a + -- letter followed by a colon. + if tmp:find("%a:") == 1 then + return true + end + + -- Relative. + return false + +end + +-- Converts any path into a full path. +function love.path.getFull(p) + + if love.path.abs(p) then + return love.path.normalslashes(p) + end + + local cwd = love.filesystem.getWorkingDirectory() + cwd = love.path.normalslashes(cwd) + cwd = love.path.endslash(cwd) + + -- Construct a full path. + local full = cwd .. love.path.normalslashes(p) + + -- Remove trailing /., if applicable + return full:match("(.-)/%.$") or full +end + +-- Returns the leaf of a full path. +function love.path.leaf(p) + p = love.path.normalslashes(p) + + local a = 1 + local last = p + + while a do + a = p:find("/", a+1) + + if a then + last = p:sub(a+1) + end + end + + return last +end + +-- Finds the key in the table with the lowest integral index. The lowest +-- will typically the executable, for instance "lua5.1.exe". +function love.arg.getLow(a) + local m = math.huge + for k,v in pairs(a) do + if k < m then + m = k + end + end + return a[m], m +end + +love.arg.options = { + console = { a = 0 }, + fused = {a = 0 }, + game = { a = 1 } +} + +love.arg.optionIndices = {} + +function love.arg.parseOption(m, i) + m.set = true + + if m.a > 0 then + m.arg = {} + for j=i,i+m.a-1 do + love.arg.optionIndices[j] = true + table.insert(m.arg, arg[j]) + end + end + + return m.a +end + +function love.arg.parseOptions() + + local game + local argc = #arg + + local i = 1 + while i <= argc do + -- Look for options. + local m = arg[i]:match("^%-%-(.*)") + + if m and m ~= "" and love.arg.options[m] and not love.arg.options[m].set then + love.arg.optionIndices[i] = true + i = i + love.arg.parseOption(love.arg.options[m], i+1) + elseif m == "" then -- handle '--' as an option + love.arg.optionIndices[i] = true + if not game then -- handle '--' followed by game name + game = i + 1 + end + break + elseif not game then + game = i + end + i = i + 1 + end + + if not love.arg.options.game.set then + love.arg.parseOption(love.arg.options.game, game or 0) + end +end + +-- Returns the arguments that are passed to your game via love.load() +-- arguments that were parsed as options are skipped. +function love.arg.parseGameArguments(a) + local out = {} + + local _, lowindex = love.arg.getLow(a) + + local o = lowindex + for i=lowindex, #a do + if not love.arg.optionIndices[i] then + out[o] = a[i] + o = o + 1 + end + end + + return out +end + +-- DO NOT REMOVE THE NEXT LINE. It is used to load this file as a C++ string. +--)luastring"--" diff --git a/src/modules/love/boot.lua b/src/modules/love/boot.lua new file mode 100644 index 000000000..4d6320eb3 --- /dev/null +++ b/src/modules/love/boot.lua @@ -0,0 +1,379 @@ +R"luastring"--( +-- DO NOT REMOVE THE ABOVE LINE. It is used to load this file as a C++ string. +-- There is a matching delimiter at the bottom of the file. + +--[[ +Copyright (c) 2006-2021 LOVE Development Team + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +--]] + +-- Make sure love exists. +local love = require("love") + +-- Essential code boot/init. +require("love.arg") +require("love.callbacks") + +local function uridecode(s) + return s:gsub("%%%x%x", function(str) + return string.char(tonumber(str:sub(2), 16)) + end) +end + +local no_game_code = false +local invalid_game_path = nil + +-- This can't be overridden. +function love.boot() + + -- This is absolutely needed. + require("love.filesystem") + + local arg0 = love.arg.getLow(arg) + love.filesystem.init(arg0) + + local exepath = love.filesystem.getExecutablePath() + if #exepath == 0 then + -- This shouldn't happen, but just in case we'll fall back to arg0. + exepath = arg0 + end + + no_game_code = false + invalid_game_path = nil + + -- Is this one of those fancy "fused" games? + local can_has_game = pcall(love.filesystem.setSource, exepath) + + -- It's a fused game, don't parse --game argument + if can_has_game then + love.arg.options.game.set = true + end + + -- Parse options now that we know which options we're looking for. + love.arg.parseOptions() + + local o = love.arg.options + + local is_fused_game = can_has_game or love.arg.options.fused.set + + love.filesystem.setFused(is_fused_game) + + love.setDeprecationOutput(not love.filesystem.isFused()) + + local identity = "" + if not can_has_game and o.game.set and o.game.arg[1] then + local nouri = o.game.arg[1] + + if nouri:sub(1, 7) == "file://" then + nouri = uridecode(nouri:sub(8)) + end + + local full_source = love.path.getFull(nouri) + can_has_game = pcall(love.filesystem.setSource, full_source) + + if not can_has_game then + invalid_game_path = full_source + end + + -- Use the name of the source .love as the identity for now. + identity = love.path.leaf(full_source) + else + -- Use the name of the exe as the identity for now. + identity = love.path.leaf(exepath) + end + + -- Try to use the archive containing main.lua as the identity name. It + -- might not be available, in which case the fallbacks above are used. + local realdir = love.filesystem.getRealDirectory("main.lua") + if realdir then + identity = love.path.leaf(realdir) + end + + identity = identity:gsub("^([%.]+)", "") -- strip leading "."'s + identity = identity:gsub("%.([^%.]+)$", "") -- strip extension + identity = identity:gsub("%.", "_") -- replace remaining "."'s with "_" + identity = #identity > 0 and identity or "lovegame" + + -- When conf.lua is initially loaded, the main source should be checked + -- before the save directory (the identity should be appended.) + pcall(love.filesystem.setIdentity, identity, true) + + if can_has_game and not (love.filesystem.getInfo("main.lua") or love.filesystem.getInfo("conf.lua")) then + no_game_code = true + end + + if not can_has_game then + local nogame = require("love.nogame") + nogame() + end +end + +function love.init() + + -- Create default configuration settings. + -- NOTE: Adding a new module to the modules list + -- will NOT make it load, see below. + local c = { + title = "Untitled", + version = love._version, + window = { + width = 800, + height = 600, + x = nil, + y = nil, + minwidth = 1, + minheight = 1, + fullscreen = false, + fullscreentype = "desktop", + display = 1, + vsync = 1, + msaa = 0, + borderless = false, + resizable = false, + centered = true, + highdpi = false, + usedpiscale = true, + }, + modules = { + data = true, + event = true, + keyboard = true, + mouse = true, + timer = true, + joystick = true, + touch = true, + image = true, + graphics = true, + audio = true, + math = true, + physics = true, + sound = true, + system = true, + font = true, + thread = true, + window = true, + video = true, + }, + audio = { + mixwithsystem = true, -- Only relevant for Android / iOS. + mic = false, -- Only relevant for Android. + }, + console = false, -- Only relevant for windows. + identity = false, + appendidentity = false, + externalstorage = false, -- Only relevant for Android. + accelerometerjoystick = true, -- Only relevant for Android / iOS. + gammacorrect = false, + } + + -- Console hack, part 1. + local openedconsole = false + if love.arg.options.console.set and love._openConsole then + love._openConsole() + openedconsole = true + end + + -- 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.getInfo("conf.lua") then + confok, conferr = pcall(require, "conf") + end + + -- Yes, conf.lua might not exist, but there are other ways of making + -- love.conf appear, so we should check for it anyway. + if love.conf then + confok, conferr = pcall(love.conf, c) + -- If love.conf errors, we'll trigger the error after loading modules so + -- the error message can be displayed in the window. + end + + -- Console hack, part 2. + if c.console and love._openConsole and not openedconsole then + love._openConsole() + end + + -- Hack for disabling accelerometer-as-joystick on Android / iOS. + if love._setAccelerometerAsJoystick then + love._setAccelerometerAsJoystick(c.accelerometerjoystick) + end + + if love._setGammaCorrect then + love._setGammaCorrect(c.gammacorrect) + end + + if love._setAudioMixWithSystem then + if c.audio and c.audio.mixwithsystem ~= nil then + love._setAudioMixWithSystem(c.audio.mixwithsystem) + end + end + + if love._requestRecordingPermission then + love._requestRecordingPermission(c.audio and c.audio.mic) + end + + -- Gets desired modules. + for k,v in ipairs{ + "data", + "thread", + "timer", + "event", + "keyboard", + "joystick", + "mouse", + "touch", + "sound", + "system", + "audio", + "image", + "video", + "font", + "window", + "graphics", + "math", + "physics", + } do + if c.modules[v] then + require("love." .. v) + end + end + + if love.event then + love.createhandlers() + end + + -- Check the version + c.version = tostring(c.version) + if not love.isVersionCompatible(c.version) then + local major, minor, revision = c.version:match("^(%d+)%.(%d+)%.(%d+)$") + if (not major or not minor or not revision) or (major ~= love._version_major and minor ~= love._version_minor) then + local msg = ("This game indicates it was made for version '%s' of LOVE.\n".. + "It may not be compatible with the running version (%s)."):format(c.version, love._version) + + print(msg) + + if love.window then + love.window.showMessageBox("Compatibility Warning", msg, "warning") + end + end + end + + if not confok and conferr then + error(conferr) + end + + -- Setup window here. + if c.window and c.modules.window then + love.window.setTitle(c.window.title or c.title) + assert(love.window.setMode(c.window.width, c.window.height, + { + fullscreen = c.window.fullscreen, + fullscreentype = c.window.fullscreentype, + vsync = c.window.vsync, + msaa = c.window.msaa, + stencil = c.window.stencil, + depth = c.window.depth, + resizable = c.window.resizable, + minwidth = c.window.minwidth, + minheight = c.window.minheight, + borderless = c.window.borderless, + centered = c.window.centered, + display = c.window.display, + highdpi = c.window.highdpi, + usedpiscale = c.window.usedpiscale, + x = c.window.x, + y = c.window.y, + }), "Could not set window mode") + if c.window.icon then + assert(love.image, "If an icon is set in love.conf, love.image must be loaded!") + love.window.setIcon(love.image.newImageData(c.window.icon)) + end + end + + -- Our first timestep, because window creation can take some time + if love.timer then + love.timer.step() + end + + if love.filesystem then + love.filesystem._setAndroidSaveExternal(c.externalstorage) + love.filesystem.setIdentity(c.identity or love.filesystem.getIdentity(), c.appendidentity) + if love.filesystem.getInfo("main.lua") then + require("main") + end + end + + if no_game_code then + error("No code to run\nYour game might be packaged incorrectly.\nMake sure main.lua is at the top level of the zip.") + elseif invalid_game_path then + error("Cannot load game at path '" .. invalid_game_path .. "'.\nMake sure a folder exists at the specified path.") + end +end + +local print, debug, tostring = print, debug, tostring + +local function error_printer(msg, layer) + print((debug.traceback("Error: " .. tostring(msg), 1+(layer or 1)):gsub("\n[^\n]+$", ""))) +end + +----------------------------------------------------------- +-- The root of all calls. +----------------------------------------------------------- + +return function() + local func + local inerror = false + + local function deferErrhand(...) + local errhand = love.errorhandler or love.errhand + local handler = (not inerror and errhand) or error_printer + inerror = true + func = handler(...) + end + + local function earlyinit() + -- If love.boot fails, return 1 and finish immediately + local result = xpcall(love.boot, error_printer) + if not result then return 1 end + + -- If love.init or love.run fails, don't return a value, + -- as we want the error handler to take over + result = xpcall(love.init, deferErrhand) + if not result then return end + + -- NOTE: We can't assign to func directly, as we'd + -- overwrite the result of deferErrhand with nil on error + local main + result, main = xpcall(love.run, deferErrhand) + if result then + func = main + end + end + + func = earlyinit + + while func do + local _, retval = xpcall(func, deferErrhand) + if retval then return retval end + coroutine.yield() + end + + return 1 +end + +-- DO NOT REMOVE THE NEXT LINE. It is used to load this file as a C++ string. +--)luastring"--" diff --git a/src/modules/love/callbacks.lua b/src/modules/love/callbacks.lua new file mode 100644 index 000000000..38ee277ac --- /dev/null +++ b/src/modules/love/callbacks.lua @@ -0,0 +1,316 @@ +R"luastring"--( +-- DO NOT REMOVE THE ABOVE LINE. It is used to load this file as a C++ string. +-- There is a matching delimiter at the bottom of the file. + +--[[ +Copyright (c) 2006-2021 LOVE Development Team + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +--]] + +local love = require("love") + +function love.createhandlers() + + -- Standard callback handlers. + love.handlers = setmetatable({ + keypressed = function (b,s,r) + if love.keypressed then return love.keypressed(b,s,r) end + end, + keyreleased = function (b,s) + if love.keyreleased then return love.keyreleased(b,s) end + end, + textinput = function (t) + if love.textinput then return love.textinput(t) end + end, + textedited = function (t,s,l) + if love.textedited then return love.textedited(t,s,l) end + end, + mousemoved = function (x,y,dx,dy,t) + if love.mousemoved then return love.mousemoved(x,y,dx,dy,t) end + end, + mousepressed = function (x,y,b,t,c) + if love.mousepressed then return love.mousepressed(x,y,b,t,c) end + end, + mousereleased = function (x,y,b,t,c) + if love.mousereleased then return love.mousereleased(x,y,b,t,c) end + end, + wheelmoved = function (x,y) + if love.wheelmoved then return love.wheelmoved(x,y) end + end, + touchpressed = function (id,x,y,dx,dy,p) + if love.touchpressed then return love.touchpressed(id,x,y,dx,dy,p) end + end, + touchreleased = function (id,x,y,dx,dy,p) + if love.touchreleased then return love.touchreleased(id,x,y,dx,dy,p) end + end, + touchmoved = function (id,x,y,dx,dy,p) + if love.touchmoved then return love.touchmoved(id,x,y,dx,dy,p) end + end, + joystickpressed = function (j,b) + if love.joystickpressed then return love.joystickpressed(j,b) end + end, + joystickreleased = function (j,b) + if love.joystickreleased then return love.joystickreleased(j,b) end + end, + joystickaxis = function (j,a,v) + if love.joystickaxis then return love.joystickaxis(j,a,v) end + end, + joystickhat = function (j,h,v) + if love.joystickhat then return love.joystickhat(j,h,v) end + end, + gamepadpressed = function (j,b) + if love.gamepadpressed then return love.gamepadpressed(j,b) end + end, + gamepadreleased = function (j,b) + if love.gamepadreleased then return love.gamepadreleased(j,b) end + end, + gamepadaxis = function (j,a,v) + if love.gamepadaxis then return love.gamepadaxis(j,a,v) end + end, + joystickadded = function (j) + if love.joystickadded then return love.joystickadded(j) end + end, + joystickremoved = function (j) + if love.joystickremoved then return love.joystickremoved(j) end + end, + focus = function (f) + if love.focus then return love.focus(f) end + end, + mousefocus = function (f) + if love.mousefocus then return love.mousefocus(f) end + end, + visible = function (v) + if love.visible then return love.visible(v) end + end, + quit = function () + return + end, + threaderror = function (t, err) + if love.threaderror then return love.threaderror(t, err) end + end, + resize = function (w, h) + if love.resize then return love.resize(w, h) end + end, + filedropped = function (f) + if love.filedropped then return love.filedropped(f) end + end, + directorydropped = function (dir) + if love.directorydropped then return love.directorydropped(dir) end + end, + lowmemory = function () + if love.lowmemory then love.lowmemory() end + collectgarbage() + collectgarbage() + end, + displayrotated = function (display, orient) + if love.displayrotated then return love.displayrotated(display, orient) end + end, + }, { + __index = function(self, name) + error("Unknown event: " .. name) + end, + }) + +end + +----------------------------------------------------------- +-- Default callbacks. +----------------------------------------------------------- + +function love.run() + if love.load then love.load(love.arg.parseGameArguments(arg), arg) end + + -- We don't want the first frame's dt to include time taken by love.load. + if love.timer then love.timer.step() end + + local dt = 0 + + -- Main loop time. + return function() + -- Process events. + if love.event then + love.event.pump() + for name, a,b,c,d,e,f in love.event.poll() do + if name == "quit" then + if not love.quit or not love.quit() then + return a or 0 + end + end + love.handlers[name](a,b,c,d,e,f) + end + end + + -- Update dt, as we'll be passing it to update + if love.timer then dt = love.timer.step() end + + -- Call update and draw + if love.update then love.update(dt) end -- will pass 0 if love.timer is disabled + + if love.graphics and love.graphics.isActive() then + love.graphics.origin() + love.graphics.clear(love.graphics.getBackgroundColor()) + + if love.draw then love.draw() end + + love.graphics.present() + end + + if love.timer then love.timer.sleep(0.001) end + end + +end + +local debug, print, tostring, error = debug, print, tostring, error + +function love.threaderror(t, err) + error("Thread error ("..tostring(t)..")\n\n"..err, 0) +end + +local utf8 = require("utf8") + +local function error_printer(msg, layer) + print((debug.traceback("Error: " .. tostring(msg), 1+(layer or 1)):gsub("\n[^\n]+$", ""))) +end + +function love.errhand(msg) + msg = tostring(msg) + + error_printer(msg, 2) + + if not love.window or not love.graphics or not love.event then + return + end + + if not love.graphics.isCreated() or not love.window.isOpen() then + local success, status = pcall(love.window.setMode, 800, 600) + if not success or not status then + return + end + end + + -- Reset state. + if love.mouse then + love.mouse.setVisible(true) + love.mouse.setGrabbed(false) + love.mouse.setRelativeMode(false) + if love.mouse.isCursorSupported() then + love.mouse.setCursor() + end + end + if love.joystick then + -- Stop all joystick vibrations. + for i,v in ipairs(love.joystick.getJoysticks()) do + v:setVibration() + end + end + if love.audio then love.audio.stop() end + + love.graphics.reset() + local font = love.graphics.setNewFont(14) + + love.graphics.setColor(1, 1, 1) + + local trace = debug.traceback() + + love.graphics.origin() + + local sanitizedmsg = {} + for char in msg:gmatch(utf8.charpattern) do + table.insert(sanitizedmsg, char) + end + sanitizedmsg = table.concat(sanitizedmsg) + + local err = {} + + table.insert(err, "Error\n") + table.insert(err, sanitizedmsg) + + if #sanitizedmsg ~= #msg then + table.insert(err, "Invalid UTF-8 string in error message.") + end + + table.insert(err, "\n") + + for l in trace:gmatch("(.-)\n") do + if not l:match("boot.lua") then + l = l:gsub("stack traceback:", "Traceback\n") + table.insert(err, l) + end + end + + local p = table.concat(err, "\n") + + p = p:gsub("\t", "") + p = p:gsub("%[string \"(.-)\"%]", "%1") + + local function draw() + local pos = 70 + love.graphics.clear(89/255, 157/255, 220/255) + love.graphics.printf(p, pos, pos, love.graphics.getWidth() - pos) + love.graphics.present() + end + + local fullErrorText = p + local function copyToClipboard() + if not love.system then return end + love.system.setClipboardText(fullErrorText) + p = p .. "\nCopied to clipboard!" + draw() + end + + if love.system then + p = p .. "\n\nPress Ctrl+C or tap to copy this error" + end + + return function() + love.event.pump() + + for e, a, b, c in love.event.poll() do + if e == "quit" then + return 1 + elseif e == "keypressed" and a == "escape" then + return 1 + elseif e == "keypressed" and a == "c" and love.keyboard.isDown("lctrl", "rctrl") then + copyToClipboard() + elseif e == "touchpressed" then + local name = love.window.getTitle() + if #name == 0 or name == "Untitled" then name = "Game" end + local buttons = {"OK", "Cancel"} + if love.system then + buttons[3] = "Copy to clipboard" + end + local pressed = love.window.showMessageBox("Quit "..name.."?", "", buttons) + if pressed == 1 then + return 1 + elseif pressed == 3 then + copyToClipboard() + end + end + end + + draw() + + if love.timer then + love.timer.sleep(0.1) + end + end + +end + +-- DO NOT REMOVE THE NEXT LINE. It is used to load this file as a C++ string. +--)luastring"--" diff --git a/src/modules/love/love.cpp b/src/modules/love/love.cpp index a437beaa0..5728514ad 100644 --- a/src/modules/love/love.cpp +++ b/src/modules/love/love.cpp @@ -81,9 +81,21 @@ extern "C" # include "audio/Audio.h" #endif -// Scripts +// Scripts. #include "scripts/nogame.lua.h" -#include "scripts/boot.lua.h" + +// Put the Lua code directly into a raw string literal. +static const char arg_lua[] = +#include "arg.lua" +; + +static const char callbacks_lua[] = +#include "callbacks.lua" +; + +static const char boot_lua[] = +#include "boot.lua" +; // All modules define a c-accessible luaopen // so let's make use of those, instead @@ -148,6 +160,8 @@ extern "C" extern int luaopen_love_window(lua_State*); #endif extern int luaopen_love_nogame(lua_State*); + extern int luaopen_love_arg(lua_State*); + extern int luaopen_love_callbacks(lua_State*); extern int luaopen_love_boot(lua_State*); } @@ -210,6 +224,8 @@ static const luaL_Reg modules[] = { { "love.window", luaopen_love_window }, #endif { "love.nogame", luaopen_love_nogame }, + { "love.arg", luaopen_love_arg }, + { "love.callbacks", luaopen_love_callbacks }, { "love.boot", luaopen_love_boot }, { 0, 0 } }; @@ -641,13 +657,26 @@ int luaopen_love_nogame(lua_State *L) return 1; } -int luaopen_love_boot(lua_State *L) +int luaopen_love_arg(lua_State *L) { - if (luaL_loadbuffer(L, (const char *)love::boot_lua, sizeof(love::boot_lua), "boot.lua") == 0) + if (luaL_loadbuffer(L, arg_lua, sizeof(arg_lua), "arg.lua") == 0) lua_call(L, 0, 1); return 1; } +int luaopen_love_callbacks(lua_State *L) +{ + if (luaL_loadbuffer(L, callbacks_lua, sizeof(callbacks_lua), "callbacks.lua") == 0) + lua_call(L, 0, 1); + return 1; +} +int luaopen_love_boot(lua_State *L) +{ + if (luaL_loadbuffer(L, boot_lua, sizeof(boot_lua), "boot.lua") == 0) + lua_call(L, 0, 1); + + return 1; +} diff --git a/src/scripts/boot.lua b/src/scripts/boot.lua deleted file mode 100644 index a4f8be15f..000000000 --- a/src/scripts/boot.lua +++ /dev/null @@ -1,808 +0,0 @@ ---[[ -Copyright (c) 2006-2021 LOVE Development Team - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any damages -arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it -freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. -2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. -3. This notice may not be removed or altered from any source distribution. ---]] - --- Make sure love exists. -local love = require("love") - --- Used for setup: -love.path = {} -love.arg = {} - --- Replace any \ with /. -function love.path.normalslashes(p) - return p:gsub("\\", "/") -end - --- Makes sure there is a slash at the end --- of a path. -function love.path.endslash(p) - if p:sub(-1) ~= "/" then - return p .. "/" - else - return p - end -end - --- Checks whether a path is absolute or not. -function love.path.abs(p) - - local tmp = love.path.normalslashes(p) - - -- Path is absolute if it starts with a "/". - if tmp:find("/") == 1 then - return true - end - - -- Path is absolute if it starts with a - -- letter followed by a colon. - if tmp:find("%a:") == 1 then - return true - end - - -- Relative. - return false - -end - --- Converts any path into a full path. -function love.path.getFull(p) - - if love.path.abs(p) then - return love.path.normalslashes(p) - end - - local cwd = love.filesystem.getWorkingDirectory() - cwd = love.path.normalslashes(cwd) - cwd = love.path.endslash(cwd) - - -- Construct a full path. - local full = cwd .. love.path.normalslashes(p) - - -- Remove trailing /., if applicable - return full:match("(.-)/%.$") or full -end - --- Returns the leaf of a full path. -function love.path.leaf(p) - p = love.path.normalslashes(p) - - local a = 1 - local last = p - - while a do - a = p:find("/", a+1) - - if a then - last = p:sub(a+1) - end - end - - return last -end - --- Finds the key in the table with the lowest integral index. The lowest --- will typically the executable, for instance "lua5.1.exe". -function love.arg.getLow(a) - local m = math.huge - for k,v in pairs(a) do - if k < m then - m = k - end - end - return a[m], m -end - -love.arg.options = { - console = { a = 0 }, - fused = {a = 0 }, - game = { a = 1 } -} - -love.arg.optionIndices = {} - -function love.arg.parseOption(m, i) - m.set = true - - if m.a > 0 then - m.arg = {} - for j=i,i+m.a-1 do - love.arg.optionIndices[j] = true - table.insert(m.arg, arg[j]) - end - end - - return m.a -end - -function love.arg.parseOptions() - - local game - local argc = #arg - - local i = 1 - while i <= argc do - -- Look for options. - local m = arg[i]:match("^%-%-(.*)") - - if m and m ~= "" and love.arg.options[m] and not love.arg.options[m].set then - love.arg.optionIndices[i] = true - i = i + love.arg.parseOption(love.arg.options[m], i+1) - elseif m == "" then -- handle '--' as an option - love.arg.optionIndices[i] = true - if not game then -- handle '--' followed by game name - game = i + 1 - end - break - elseif not game then - game = i - end - i = i + 1 - end - - if not love.arg.options.game.set then - love.arg.parseOption(love.arg.options.game, game or 0) - end -end - --- Returns the arguments that are passed to your game via love.load() --- arguments that were parsed as options are skipped. -function love.arg.parseGameArguments(a) - local out = {} - - local _, lowindex = love.arg.getLow(a) - - local o = lowindex - for i=lowindex, #a do - if not love.arg.optionIndices[i] then - out[o] = a[i] - o = o + 1 - end - end - - return out -end - -function love.createhandlers() - - -- Standard callback handlers. - love.handlers = setmetatable({ - keypressed = function (b,s,r) - if love.keypressed then return love.keypressed(b,s,r) end - end, - keyreleased = function (b,s) - if love.keyreleased then return love.keyreleased(b,s) end - end, - textinput = function (t) - if love.textinput then return love.textinput(t) end - end, - textedited = function (t,s,l) - if love.textedited then return love.textedited(t,s,l) end - end, - mousemoved = function (x,y,dx,dy,t) - if love.mousemoved then return love.mousemoved(x,y,dx,dy,t) end - end, - mousepressed = function (x,y,b,t,c) - if love.mousepressed then return love.mousepressed(x,y,b,t,c) end - end, - mousereleased = function (x,y,b,t,c) - if love.mousereleased then return love.mousereleased(x,y,b,t,c) end - end, - wheelmoved = function (x,y) - if love.wheelmoved then return love.wheelmoved(x,y) end - end, - touchpressed = function (id,x,y,dx,dy,p) - if love.touchpressed then return love.touchpressed(id,x,y,dx,dy,p) end - end, - touchreleased = function (id,x,y,dx,dy,p) - if love.touchreleased then return love.touchreleased(id,x,y,dx,dy,p) end - end, - touchmoved = function (id,x,y,dx,dy,p) - if love.touchmoved then return love.touchmoved(id,x,y,dx,dy,p) end - end, - joystickpressed = function (j,b) - if love.joystickpressed then return love.joystickpressed(j,b) end - end, - joystickreleased = function (j,b) - if love.joystickreleased then return love.joystickreleased(j,b) end - end, - joystickaxis = function (j,a,v) - if love.joystickaxis then return love.joystickaxis(j,a,v) end - end, - joystickhat = function (j,h,v) - if love.joystickhat then return love.joystickhat(j,h,v) end - end, - gamepadpressed = function (j,b) - if love.gamepadpressed then return love.gamepadpressed(j,b) end - end, - gamepadreleased = function (j,b) - if love.gamepadreleased then return love.gamepadreleased(j,b) end - end, - gamepadaxis = function (j,a,v) - if love.gamepadaxis then return love.gamepadaxis(j,a,v) end - end, - joystickadded = function (j) - if love.joystickadded then return love.joystickadded(j) end - end, - joystickremoved = function (j) - if love.joystickremoved then return love.joystickremoved(j) end - end, - focus = function (f) - if love.focus then return love.focus(f) end - end, - mousefocus = function (f) - if love.mousefocus then return love.mousefocus(f) end - end, - visible = function (v) - if love.visible then return love.visible(v) end - end, - quit = function () - return - end, - threaderror = function (t, err) - if love.threaderror then return love.threaderror(t, err) end - end, - resize = function (w, h) - if love.resize then return love.resize(w, h) end - end, - filedropped = function (f) - if love.filedropped then return love.filedropped(f) end - end, - directorydropped = function (dir) - if love.directorydropped then return love.directorydropped(dir) end - end, - lowmemory = function () - if love.lowmemory then love.lowmemory() end - collectgarbage() - collectgarbage() - end, - displayrotated = function (display, orient) - if love.displayrotated then return love.displayrotated(display, orient) end - end, - }, { - __index = function(self, name) - error("Unknown event: " .. name) - end, - }) - -end - -local function uridecode(s) - return s:gsub("%%%x%x", function(str) - return string.char(tonumber(str:sub(2), 16)) - end) -end - -local no_game_code = false -local invalid_game_path = nil - --- This can't be overridden. -function love.boot() - - -- This is absolutely needed. - require("love.filesystem") - - local arg0 = love.arg.getLow(arg) - love.filesystem.init(arg0) - - local exepath = love.filesystem.getExecutablePath() - if #exepath == 0 then - -- This shouldn't happen, but just in case we'll fall back to arg0. - exepath = arg0 - end - - no_game_code = false - invalid_game_path = nil - - -- Is this one of those fancy "fused" games? - local can_has_game = pcall(love.filesystem.setSource, exepath) - - -- It's a fused game, don't parse --game argument - if can_has_game then - love.arg.options.game.set = true - end - - -- Parse options now that we know which options we're looking for. - love.arg.parseOptions() - - local o = love.arg.options - - local is_fused_game = can_has_game or love.arg.options.fused.set - - love.filesystem.setFused(is_fused_game) - - love.setDeprecationOutput(not love.filesystem.isFused()) - - local identity = "" - if not can_has_game and o.game.set and o.game.arg[1] then - local nouri = o.game.arg[1] - - if nouri:sub(1, 7) == "file://" then - nouri = uridecode(nouri:sub(8)) - end - - local full_source = love.path.getFull(nouri) - can_has_game = pcall(love.filesystem.setSource, full_source) - - if not can_has_game then - invalid_game_path = full_source - end - - -- Use the name of the source .love as the identity for now. - identity = love.path.leaf(full_source) - else - -- Use the name of the exe as the identity for now. - identity = love.path.leaf(exepath) - end - - -- Try to use the archive containing main.lua as the identity name. It - -- might not be available, in which case the fallbacks above are used. - local realdir = love.filesystem.getRealDirectory("main.lua") - if realdir then - identity = love.path.leaf(realdir) - end - - identity = identity:gsub("^([%.]+)", "") -- strip leading "."'s - identity = identity:gsub("%.([^%.]+)$", "") -- strip extension - identity = identity:gsub("%.", "_") -- replace remaining "."'s with "_" - identity = #identity > 0 and identity or "lovegame" - - -- When conf.lua is initially loaded, the main source should be checked - -- before the save directory (the identity should be appended.) - pcall(love.filesystem.setIdentity, identity, true) - - if can_has_game and not (love.filesystem.getInfo("main.lua") or love.filesystem.getInfo("conf.lua")) then - no_game_code = true - end - - if not can_has_game then - local nogame = require("love.nogame") - nogame() - end -end - -function love.init() - - -- Create default configuration settings. - -- NOTE: Adding a new module to the modules list - -- will NOT make it load, see below. - local c = { - title = "Untitled", - version = love._version, - window = { - width = 800, - height = 600, - x = nil, - y = nil, - minwidth = 1, - minheight = 1, - fullscreen = false, - fullscreentype = "desktop", - display = 1, - vsync = 1, - msaa = 0, - borderless = false, - resizable = false, - centered = true, - highdpi = false, - usedpiscale = true, - }, - modules = { - data = true, - event = true, - keyboard = true, - mouse = true, - timer = true, - joystick = true, - touch = true, - image = true, - graphics = true, - audio = true, - math = true, - physics = true, - sound = true, - system = true, - font = true, - thread = true, - window = true, - video = true, - }, - audio = { - mixwithsystem = true, -- Only relevant for Android / iOS. - mic = false, -- Only relevant for Android. - }, - console = false, -- Only relevant for windows. - identity = false, - appendidentity = false, - externalstorage = false, -- Only relevant for Android. - accelerometerjoystick = true, -- Only relevant for Android / iOS. - gammacorrect = false, - } - - -- Console hack, part 1. - local openedconsole = false - if love.arg.options.console.set and love._openConsole then - love._openConsole() - openedconsole = true - end - - -- 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.getInfo("conf.lua") then - confok, conferr = pcall(require, "conf") - end - - -- Yes, conf.lua might not exist, but there are other ways of making - -- love.conf appear, so we should check for it anyway. - if love.conf then - confok, conferr = pcall(love.conf, c) - -- If love.conf errors, we'll trigger the error after loading modules so - -- the error message can be displayed in the window. - end - - -- Console hack, part 2. - if c.console and love._openConsole and not openedconsole then - love._openConsole() - end - - -- Hack for disabling accelerometer-as-joystick on Android / iOS. - if love._setAccelerometerAsJoystick then - love._setAccelerometerAsJoystick(c.accelerometerjoystick) - end - - if love._setGammaCorrect then - love._setGammaCorrect(c.gammacorrect) - end - - if love._setAudioMixWithSystem then - if c.audio and c.audio.mixwithsystem ~= nil then - love._setAudioMixWithSystem(c.audio.mixwithsystem) - end - end - - if love._requestRecordingPermission then - love._requestRecordingPermission(c.audio and c.audio.mic) - end - - -- Gets desired modules. - for k,v in ipairs{ - "data", - "thread", - "timer", - "event", - "keyboard", - "joystick", - "mouse", - "touch", - "sound", - "system", - "audio", - "image", - "video", - "font", - "window", - "graphics", - "math", - "physics", - } do - if c.modules[v] then - require("love." .. v) - end - end - - if love.event then - love.createhandlers() - end - - -- Check the version - c.version = tostring(c.version) - if not love.isVersionCompatible(c.version) then - local major, minor, revision = c.version:match("^(%d+)%.(%d+)%.(%d+)$") - if (not major or not minor or not revision) or (major ~= love._version_major and minor ~= love._version_minor) then - local msg = ("This game indicates it was made for version '%s' of LOVE.\n".. - "It may not be compatible with the running version (%s)."):format(c.version, love._version) - - print(msg) - - if love.window then - love.window.showMessageBox("Compatibility Warning", msg, "warning") - end - end - end - - if not confok and conferr then - error(conferr) - end - - -- Setup window here. - if c.window and c.modules.window then - love.window.setTitle(c.window.title or c.title) - assert(love.window.setMode(c.window.width, c.window.height, - { - fullscreen = c.window.fullscreen, - fullscreentype = c.window.fullscreentype, - vsync = c.window.vsync, - msaa = c.window.msaa, - stencil = c.window.stencil, - depth = c.window.depth, - resizable = c.window.resizable, - minwidth = c.window.minwidth, - minheight = c.window.minheight, - borderless = c.window.borderless, - centered = c.window.centered, - display = c.window.display, - highdpi = c.window.highdpi, - usedpiscale = c.window.usedpiscale, - x = c.window.x, - y = c.window.y, - }), "Could not set window mode") - if c.window.icon then - assert(love.image, "If an icon is set in love.conf, love.image must be loaded!") - love.window.setIcon(love.image.newImageData(c.window.icon)) - end - end - - -- Our first timestep, because window creation can take some time - if love.timer then - love.timer.step() - end - - if love.filesystem then - love.filesystem._setAndroidSaveExternal(c.externalstorage) - love.filesystem.setIdentity(c.identity or love.filesystem.getIdentity(), c.appendidentity) - if love.filesystem.getInfo("main.lua") then - require("main") - end - end - - if no_game_code then - error("No code to run\nYour game might be packaged incorrectly.\nMake sure main.lua is at the top level of the zip.") - elseif invalid_game_path then - error("Cannot load game at path '" .. invalid_game_path .. "'.\nMake sure a folder exists at the specified path.") - end -end - ------------------------------------------------------------ --- Default callbacks. ------------------------------------------------------------ - -function love.run() - if love.load then love.load(love.arg.parseGameArguments(arg), arg) end - - -- We don't want the first frame's dt to include time taken by love.load. - if love.timer then love.timer.step() end - - local dt = 0 - - -- Main loop time. - return function() - -- Process events. - if love.event then - love.event.pump() - for name, a,b,c,d,e,f in love.event.poll() do - if name == "quit" then - if not love.quit or not love.quit() then - return a or 0 - end - end - love.handlers[name](a,b,c,d,e,f) - end - end - - -- Update dt, as we'll be passing it to update - if love.timer then dt = love.timer.step() end - - -- Call update and draw - if love.update then love.update(dt) end -- will pass 0 if love.timer is disabled - - if love.graphics and love.graphics.isActive() then - love.graphics.origin() - love.graphics.clear(love.graphics.getBackgroundColor()) - - if love.draw then love.draw() end - - love.graphics.present() - end - - if love.timer then love.timer.sleep(0.001) end - end - -end - -local debug, print, error = debug, print, error - -function love.threaderror(t, err) - error("Thread error ("..tostring(t)..")\n\n"..err, 0) -end - -local utf8 = require("utf8") - -local function error_printer(msg, layer) - print((debug.traceback("Error: " .. tostring(msg), 1+(layer or 1)):gsub("\n[^\n]+$", ""))) -end - -function love.errhand(msg) - msg = tostring(msg) - - error_printer(msg, 2) - - if not love.window or not love.graphics or not love.event then - return - end - - if not love.graphics.isCreated() or not love.window.isOpen() then - local success, status = pcall(love.window.setMode, 800, 600) - if not success or not status then - return - end - end - - -- Reset state. - if love.mouse then - love.mouse.setVisible(true) - love.mouse.setGrabbed(false) - love.mouse.setRelativeMode(false) - if love.mouse.isCursorSupported() then - love.mouse.setCursor() - end - end - if love.joystick then - -- Stop all joystick vibrations. - for i,v in ipairs(love.joystick.getJoysticks()) do - v:setVibration() - end - end - if love.audio then love.audio.stop() end - - love.graphics.reset() - local font = love.graphics.setNewFont(14) - - love.graphics.setColor(1, 1, 1) - - local trace = debug.traceback() - - love.graphics.origin() - - local sanitizedmsg = {} - for char in msg:gmatch(utf8.charpattern) do - table.insert(sanitizedmsg, char) - end - sanitizedmsg = table.concat(sanitizedmsg) - - local err = {} - - table.insert(err, "Error\n") - table.insert(err, sanitizedmsg) - - if #sanitizedmsg ~= #msg then - table.insert(err, "Invalid UTF-8 string in error message.") - end - - table.insert(err, "\n") - - for l in trace:gmatch("(.-)\n") do - if not l:match("boot.lua") then - l = l:gsub("stack traceback:", "Traceback\n") - table.insert(err, l) - end - end - - local p = table.concat(err, "\n") - - p = p:gsub("\t", "") - p = p:gsub("%[string \"(.-)\"%]", "%1") - - local function draw() - local pos = 70 - love.graphics.clear(89/255, 157/255, 220/255) - love.graphics.printf(p, pos, pos, love.graphics.getWidth() - pos) - love.graphics.present() - end - - local fullErrorText = p - local function copyToClipboard() - if not love.system then return end - love.system.setClipboardText(fullErrorText) - p = p .. "\nCopied to clipboard!" - draw() - end - - if love.system then - p = p .. "\n\nPress Ctrl+C or tap to copy this error" - end - - return function() - love.event.pump() - - for e, a, b, c in love.event.poll() do - if e == "quit" then - return 1 - elseif e == "keypressed" and a == "escape" then - return 1 - elseif e == "keypressed" and a == "c" and love.keyboard.isDown("lctrl", "rctrl") then - copyToClipboard() - elseif e == "touchpressed" then - local name = love.window.getTitle() - if #name == 0 or name == "Untitled" then name = "Game" end - local buttons = {"OK", "Cancel"} - if love.system then - buttons[3] = "Copy to clipboard" - end - local pressed = love.window.showMessageBox("Quit "..name.."?", "", buttons) - if pressed == 1 then - return 1 - elseif pressed == 3 then - copyToClipboard() - end - end - end - - draw() - - if love.timer then - love.timer.sleep(0.1) - end - end - -end - ------------------------------------------------------------ --- The root of all calls. ------------------------------------------------------------ - -return function() - local func - local inerror = false - - local function deferErrhand(...) - local errhand = love.errorhandler or love.errhand - local handler = (not inerror and errhand) or error_printer - inerror = true - func = handler(...) - end - - local function earlyinit() - -- If love.boot fails, return 1 and finish immediately - local result = xpcall(love.boot, error_printer) - if not result then return 1 end - - -- If love.init or love.run fails, don't return a value, - -- as we want the error handler to take over - result = xpcall(love.init, deferErrhand) - if not result then return end - - -- NOTE: We can't assign to func directly, as we'd - -- overwrite the result of deferErrhand with nil on error - local main - result, main = xpcall(love.run, deferErrhand) - if result then - func = main - end - end - - func = earlyinit - - while func do - local _, retval = xpcall(func, deferErrhand) - if retval then return retval end - coroutine.yield() - end - - return 1 -end diff --git a/src/scripts/boot.lua.h b/src/scripts/boot.lua.h deleted file mode 100644 index dbed15b65..000000000 --- a/src/scripts/boot.lua.h +++ /dev/null @@ -1,1596 +0,0 @@ -/** - * Copyright (c) 2006-2021 LOVE Development Team - * - * This software is provided 'as-is', without any express or implied - * warranty. In no event will the authors be held liable for any damages - * arising from the use of this software. - * - * Permission is granted to anyone to use this software for any purpose, - * including commercial applications, and to alter it and redistribute it - * freely, subject to the following restrictions: - * - * 1. The origin of this software must not be misrepresented; you must not - * claim that you wrote the original software. If you use this software - * in a product, an acknowledgment in the product documentation would be - * appreciated but is not required. - * 2. Altered source versions must be plainly marked as such, and must not be - * misrepresented as being the original software. - * 3. This notice may not be removed or altered from any source distribution. - **/ - -namespace love -{ - -// [boot.lua] -const unsigned char boot_lua[] = -{ - - 0x2d, 0x2d, 0x5b, 0x5b, 0x0a, - 0x43, 0x6f, 0x70, 0x79, 0x72, 0x69, 0x67, 0x68, 0x74, 0x20, 0x28, 0x63, 0x29, 0x20, 0x32, 0x30, 0x30, 0x36, - 0x2d, 0x32, 0x30, 0x32, 0x31, 0x20, 0x4c, 0x4f, 0x56, 0x45, 0x20, 0x44, 0x65, 0x76, 0x65, 0x6c, 0x6f, 0x70, - 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x54, 0x65, 0x61, 0x6d, 0x0a, - 0x0a, - 0x54, 0x68, 0x69, 0x73, 0x20, 0x73, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x20, 0x69, 0x73, 0x20, 0x70, - 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x64, 0x20, 0x27, 0x61, 0x73, 0x2d, 0x69, 0x73, 0x27, 0x2c, 0x20, 0x77, - 0x69, 0x74, 0x68, 0x6f, 0x75, 0x74, 0x20, 0x61, 0x6e, 0x79, 0x20, 0x65, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, - 0x20, 0x6f, 0x72, 0x20, 0x69, 0x6d, 0x70, 0x6c, 0x69, 0x65, 0x64, 0x0a, - 0x77, 0x61, 0x72, 0x72, 0x61, 0x6e, 0x74, 0x79, 0x2e, 0x20, 0x20, 0x49, 0x6e, 0x20, 0x6e, 0x6f, 0x20, 0x65, - 0x76, 0x65, 0x6e, 0x74, 0x20, 0x77, 0x69, 0x6c, 0x6c, 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, 0x75, 0x74, 0x68, - 0x6f, 0x72, 0x73, 0x20, 0x62, 0x65, 0x20, 0x68, 0x65, 0x6c, 0x64, 0x20, 0x6c, 0x69, 0x61, 0x62, 0x6c, 0x65, - 0x20, 0x66, 0x6f, 0x72, 0x20, 0x61, 0x6e, 0x79, 0x20, 0x64, 0x61, 0x6d, 0x61, 0x67, 0x65, 0x73, 0x0a, - 0x61, 0x72, 0x69, 0x73, 0x69, 0x6e, 0x67, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x74, 0x68, 0x65, 0x20, 0x75, - 0x73, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x73, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, - 0x65, 0x2e, 0x0a, - 0x0a, - 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x69, 0x73, 0x20, 0x67, 0x72, 0x61, 0x6e, - 0x74, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x61, 0x6e, 0x79, 0x6f, 0x6e, 0x65, 0x20, 0x74, 0x6f, 0x20, 0x75, - 0x73, 0x65, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x73, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x20, 0x66, - 0x6f, 0x72, 0x20, 0x61, 0x6e, 0x79, 0x20, 0x70, 0x75, 0x72, 0x70, 0x6f, 0x73, 0x65, 0x2c, 0x0a, - 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x72, 0x63, 0x69, - 0x61, 0x6c, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2c, 0x20, 0x61, - 0x6e, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x61, 0x6c, 0x74, 0x65, 0x72, 0x20, 0x69, 0x74, 0x20, 0x61, 0x6e, 0x64, - 0x20, 0x72, 0x65, 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x20, 0x69, 0x74, 0x0a, - 0x66, 0x72, 0x65, 0x65, 0x6c, 0x79, 0x2c, 0x20, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x20, 0x74, 0x6f, - 0x20, 0x74, 0x68, 0x65, 0x20, 0x66, 0x6f, 0x6c, 0x6c, 0x6f, 0x77, 0x69, 0x6e, 0x67, 0x20, 0x72, 0x65, 0x73, - 0x74, 0x72, 0x69, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x3a, 0x0a, - 0x0a, - 0x31, 0x2e, 0x20, 0x54, 0x68, 0x65, 0x20, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x20, 0x6f, 0x66, 0x20, 0x74, - 0x68, 0x69, 0x73, 0x20, 0x73, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, - 0x6e, 0x6f, 0x74, 0x20, 0x62, 0x65, 0x20, 0x6d, 0x69, 0x73, 0x72, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, - 0x74, 0x65, 0x64, 0x3b, 0x20, 0x79, 0x6f, 0x75, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x6e, 0x6f, 0x74, 0x0a, - 0x20, 0x20, 0x20, 0x63, 0x6c, 0x61, 0x69, 0x6d, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x79, 0x6f, 0x75, 0x20, - 0x77, 0x72, 0x6f, 0x74, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, - 0x20, 0x73, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x2e, 0x20, 0x49, 0x66, 0x20, 0x79, 0x6f, 0x75, 0x20, - 0x75, 0x73, 0x65, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x73, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x0a, - 0x20, 0x20, 0x20, 0x69, 0x6e, 0x20, 0x61, 0x20, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x2c, 0x20, 0x61, - 0x6e, 0x20, 0x61, 0x63, 0x6b, 0x6e, 0x6f, 0x77, 0x6c, 0x65, 0x64, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x69, - 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x20, 0x64, 0x6f, 0x63, 0x75, - 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x77, 0x6f, 0x75, 0x6c, 0x64, 0x20, 0x62, 0x65, 0x0a, - 0x20, 0x20, 0x20, 0x61, 0x70, 0x70, 0x72, 0x65, 0x63, 0x69, 0x61, 0x74, 0x65, 0x64, 0x20, 0x62, 0x75, 0x74, - 0x20, 0x69, 0x73, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x2e, 0x0a, - 0x32, 0x2e, 0x20, 0x41, 0x6c, 0x74, 0x65, 0x72, 0x65, 0x64, 0x20, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x20, - 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, 0x20, 0x70, - 0x6c, 0x61, 0x69, 0x6e, 0x6c, 0x79, 0x20, 0x6d, 0x61, 0x72, 0x6b, 0x65, 0x64, 0x20, 0x61, 0x73, 0x20, 0x73, - 0x75, 0x63, 0x68, 0x2c, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x6e, 0x6f, 0x74, 0x20, - 0x62, 0x65, 0x0a, - 0x20, 0x20, 0x20, 0x6d, 0x69, 0x73, 0x72, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x65, 0x64, 0x20, - 0x61, 0x73, 0x20, 0x62, 0x65, 0x69, 0x6e, 0x67, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6f, 0x72, 0x69, 0x67, 0x69, - 0x6e, 0x61, 0x6c, 0x20, 0x73, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x2e, 0x0a, - 0x33, 0x2e, 0x20, 0x54, 0x68, 0x69, 0x73, 0x20, 0x6e, 0x6f, 0x74, 0x69, 0x63, 0x65, 0x20, 0x6d, 0x61, 0x79, - 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x62, 0x65, 0x20, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x20, 0x6f, 0x72, - 0x20, 0x61, 0x6c, 0x74, 0x65, 0x72, 0x65, 0x64, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x61, 0x6e, 0x79, 0x20, - 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x20, 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, - 0x6e, 0x2e, 0x0a, - 0x2d, 0x2d, 0x5d, 0x5d, 0x0a, - 0x0a, - 0x2d, 0x2d, 0x20, 0x4d, 0x61, 0x6b, 0x65, 0x20, 0x73, 0x75, 0x72, 0x65, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x20, - 0x65, 0x78, 0x69, 0x73, 0x74, 0x73, 0x2e, 0x0a, - 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x20, 0x3d, 0x20, 0x72, 0x65, 0x71, 0x75, 0x69, - 0x72, 0x65, 0x28, 0x22, 0x6c, 0x6f, 0x76, 0x65, 0x22, 0x29, 0x0a, - 0x0a, - 0x2d, 0x2d, 0x20, 0x55, 0x73, 0x65, 0x64, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x73, 0x65, 0x74, 0x75, 0x70, 0x3a, 0x0a, - 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x70, 0x61, 0x74, 0x68, 0x20, 0x3d, 0x20, 0x7b, 0x7d, 0x0a, - 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x61, 0x72, 0x67, 0x20, 0x3d, 0x20, 0x7b, 0x7d, 0x0a, - 0x0a, - 0x2d, 0x2d, 0x20, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x20, 0x61, 0x6e, 0x79, 0x20, 0x5c, 0x20, 0x77, - 0x69, 0x74, 0x68, 0x20, 0x2f, 0x2e, 0x0a, - 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x70, 0x61, 0x74, 0x68, - 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x73, 0x6c, 0x61, 0x73, 0x68, 0x65, 0x73, 0x28, 0x70, 0x29, 0x0a, - 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x70, 0x3a, 0x67, 0x73, 0x75, 0x62, 0x28, 0x22, 0x5c, 0x5c, - 0x22, 0x2c, 0x20, 0x22, 0x2f, 0x22, 0x29, 0x0a, - 0x65, 0x6e, 0x64, 0x0a, - 0x0a, - 0x2d, 0x2d, 0x20, 0x4d, 0x61, 0x6b, 0x65, 0x73, 0x20, 0x73, 0x75, 0x72, 0x65, 0x20, 0x74, 0x68, 0x65, 0x72, - 0x65, 0x20, 0x69, 0x73, 0x20, 0x61, 0x20, 0x73, 0x6c, 0x61, 0x73, 0x68, 0x20, 0x61, 0x74, 0x20, 0x74, 0x68, - 0x65, 0x20, 0x65, 0x6e, 0x64, 0x0a, - 0x2d, 0x2d, 0x20, 0x6f, 0x66, 0x20, 0x61, 0x20, 0x70, 0x61, 0x74, 0x68, 0x2e, 0x0a, - 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x70, 0x61, 0x74, 0x68, - 0x2e, 0x65, 0x6e, 0x64, 0x73, 0x6c, 0x61, 0x73, 0x68, 0x28, 0x70, 0x29, 0x0a, - 0x09, 0x69, 0x66, 0x20, 0x70, 0x3a, 0x73, 0x75, 0x62, 0x28, 0x2d, 0x31, 0x29, 0x20, 0x7e, 0x3d, 0x20, 0x22, - 0x2f, 0x22, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, - 0x09, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x70, 0x20, 0x2e, 0x2e, 0x20, 0x22, 0x2f, 0x22, 0x0a, - 0x09, 0x65, 0x6c, 0x73, 0x65, 0x0a, - 0x09, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x70, 0x0a, - 0x09, 0x65, 0x6e, 0x64, 0x0a, - 0x65, 0x6e, 0x64, 0x0a, - 0x0a, - 0x2d, 0x2d, 0x20, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x73, 0x20, 0x77, 0x68, 0x65, 0x74, 0x68, 0x65, 0x72, 0x20, - 0x61, 0x20, 0x70, 0x61, 0x74, 0x68, 0x20, 0x69, 0x73, 0x20, 0x61, 0x62, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x65, - 0x20, 0x6f, 0x72, 0x20, 0x6e, 0x6f, 0x74, 0x2e, 0x0a, - 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x70, 0x61, 0x74, 0x68, - 0x2e, 0x61, 0x62, 0x73, 0x28, 0x70, 0x29, 0x0a, - 0x0a, - 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x74, 0x6d, 0x70, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, - 0x70, 0x61, 0x74, 0x68, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x73, 0x6c, 0x61, 0x73, 0x68, 0x65, 0x73, - 0x28, 0x70, 0x29, 0x0a, - 0x0a, - 0x09, 0x2d, 0x2d, 0x20, 0x50, 0x61, 0x74, 0x68, 0x20, 0x69, 0x73, 0x20, 0x61, 0x62, 0x73, 0x6f, 0x6c, 0x75, - 0x74, 0x65, 0x20, 0x69, 0x66, 0x20, 0x69, 0x74, 0x20, 0x73, 0x74, 0x61, 0x72, 0x74, 0x73, 0x20, 0x77, 0x69, - 0x74, 0x68, 0x20, 0x61, 0x20, 0x22, 0x2f, 0x22, 0x2e, 0x0a, - 0x09, 0x69, 0x66, 0x20, 0x74, 0x6d, 0x70, 0x3a, 0x66, 0x69, 0x6e, 0x64, 0x28, 0x22, 0x2f, 0x22, 0x29, 0x20, - 0x3d, 0x3d, 0x20, 0x31, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, - 0x09, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x74, 0x72, 0x75, 0x65, 0x0a, - 0x09, 0x65, 0x6e, 0x64, 0x0a, - 0x0a, - 0x09, 0x2d, 0x2d, 0x20, 0x50, 0x61, 0x74, 0x68, 0x20, 0x69, 0x73, 0x20, 0x61, 0x62, 0x73, 0x6f, 0x6c, 0x75, - 0x74, 0x65, 0x20, 0x69, 0x66, 0x20, 0x69, 0x74, 0x20, 0x73, 0x74, 0x61, 0x72, 0x74, 0x73, 0x20, 0x77, 0x69, - 0x74, 0x68, 0x20, 0x61, 0x0a, - 0x09, 0x2d, 0x2d, 0x20, 0x6c, 0x65, 0x74, 0x74, 0x65, 0x72, 0x20, 0x66, 0x6f, 0x6c, 0x6c, 0x6f, 0x77, 0x65, - 0x64, 0x20, 0x62, 0x79, 0x20, 0x61, 0x20, 0x63, 0x6f, 0x6c, 0x6f, 0x6e, 0x2e, 0x0a, - 0x09, 0x69, 0x66, 0x20, 0x74, 0x6d, 0x70, 0x3a, 0x66, 0x69, 0x6e, 0x64, 0x28, 0x22, 0x25, 0x61, 0x3a, 0x22, - 0x29, 0x20, 0x3d, 0x3d, 0x20, 0x31, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, - 0x09, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x74, 0x72, 0x75, 0x65, 0x0a, - 0x09, 0x65, 0x6e, 0x64, 0x0a, - 0x0a, - 0x09, 0x2d, 0x2d, 0x20, 0x52, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x76, 0x65, 0x2e, 0x0a, - 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x0a, - 0x0a, - 0x65, 0x6e, 0x64, 0x0a, - 0x0a, - 0x2d, 0x2d, 0x20, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x73, 0x20, 0x61, 0x6e, 0x79, 0x20, 0x70, 0x61, - 0x74, 0x68, 0x20, 0x69, 0x6e, 0x74, 0x6f, 0x20, 0x61, 0x20, 0x66, 0x75, 0x6c, 0x6c, 0x20, 0x70, 0x61, 0x74, - 0x68, 0x2e, 0x0a, - 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x70, 0x61, 0x74, 0x68, - 0x2e, 0x67, 0x65, 0x74, 0x46, 0x75, 0x6c, 0x6c, 0x28, 0x70, 0x29, 0x0a, - 0x0a, - 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x70, 0x61, 0x74, 0x68, 0x2e, 0x61, 0x62, 0x73, 0x28, - 0x70, 0x29, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, - 0x09, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x70, 0x61, 0x74, 0x68, - 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x73, 0x6c, 0x61, 0x73, 0x68, 0x65, 0x73, 0x28, 0x70, 0x29, 0x0a, - 0x09, 0x65, 0x6e, 0x64, 0x0a, - 0x0a, - 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x63, 0x77, 0x64, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, - 0x66, 0x69, 0x6c, 0x65, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x2e, 0x67, 0x65, 0x74, 0x57, 0x6f, 0x72, 0x6b, - 0x69, 0x6e, 0x67, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x28, 0x29, 0x0a, - 0x09, 0x63, 0x77, 0x64, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x70, 0x61, 0x74, 0x68, 0x2e, 0x6e, - 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x73, 0x6c, 0x61, 0x73, 0x68, 0x65, 0x73, 0x28, 0x63, 0x77, 0x64, 0x29, 0x0a, - 0x09, 0x63, 0x77, 0x64, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x70, 0x61, 0x74, 0x68, 0x2e, 0x65, - 0x6e, 0x64, 0x73, 0x6c, 0x61, 0x73, 0x68, 0x28, 0x63, 0x77, 0x64, 0x29, 0x0a, - 0x0a, - 0x09, 0x2d, 0x2d, 0x20, 0x43, 0x6f, 0x6e, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x20, 0x61, 0x20, 0x66, 0x75, - 0x6c, 0x6c, 0x20, 0x70, 0x61, 0x74, 0x68, 0x2e, 0x0a, - 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x75, 0x6c, 0x6c, 0x20, 0x3d, 0x20, 0x63, 0x77, 0x64, 0x20, - 0x2e, 0x2e, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x70, 0x61, 0x74, 0x68, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, - 0x6c, 0x73, 0x6c, 0x61, 0x73, 0x68, 0x65, 0x73, 0x28, 0x70, 0x29, 0x0a, - 0x0a, - 0x09, 0x2d, 0x2d, 0x20, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x20, 0x74, 0x72, 0x61, 0x69, 0x6c, 0x69, 0x6e, - 0x67, 0x20, 0x2f, 0x2e, 0x2c, 0x20, 0x69, 0x66, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x62, 0x6c, - 0x65, 0x0a, - 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x66, 0x75, 0x6c, 0x6c, 0x3a, 0x6d, 0x61, 0x74, 0x63, 0x68, - 0x28, 0x22, 0x28, 0x2e, 0x2d, 0x29, 0x2f, 0x25, 0x2e, 0x24, 0x22, 0x29, 0x20, 0x6f, 0x72, 0x20, 0x66, 0x75, - 0x6c, 0x6c, 0x0a, - 0x65, 0x6e, 0x64, 0x0a, - 0x0a, - 0x2d, 0x2d, 0x20, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6c, 0x65, 0x61, - 0x66, 0x20, 0x6f, 0x66, 0x20, 0x61, 0x20, 0x66, 0x75, 0x6c, 0x6c, 0x20, 0x70, 0x61, 0x74, 0x68, 0x2e, 0x0a, - 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x70, 0x61, 0x74, 0x68, - 0x2e, 0x6c, 0x65, 0x61, 0x66, 0x28, 0x70, 0x29, 0x0a, - 0x09, 0x70, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x70, 0x61, 0x74, 0x68, 0x2e, 0x6e, 0x6f, 0x72, - 0x6d, 0x61, 0x6c, 0x73, 0x6c, 0x61, 0x73, 0x68, 0x65, 0x73, 0x28, 0x70, 0x29, 0x0a, - 0x0a, - 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x61, 0x20, 0x3d, 0x20, 0x31, 0x0a, - 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6c, 0x61, 0x73, 0x74, 0x20, 0x3d, 0x20, 0x70, 0x0a, - 0x0a, - 0x09, 0x77, 0x68, 0x69, 0x6c, 0x65, 0x20, 0x61, 0x20, 0x64, 0x6f, 0x0a, - 0x09, 0x09, 0x61, 0x20, 0x3d, 0x20, 0x70, 0x3a, 0x66, 0x69, 0x6e, 0x64, 0x28, 0x22, 0x2f, 0x22, 0x2c, 0x20, - 0x61, 0x2b, 0x31, 0x29, 0x0a, - 0x0a, - 0x09, 0x09, 0x69, 0x66, 0x20, 0x61, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, - 0x09, 0x09, 0x09, 0x6c, 0x61, 0x73, 0x74, 0x20, 0x3d, 0x20, 0x70, 0x3a, 0x73, 0x75, 0x62, 0x28, 0x61, 0x2b, - 0x31, 0x29, 0x0a, - 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, - 0x09, 0x65, 0x6e, 0x64, 0x0a, - 0x0a, - 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6c, 0x61, 0x73, 0x74, 0x0a, - 0x65, 0x6e, 0x64, 0x0a, - 0x0a, - 0x2d, 0x2d, 0x20, 0x46, 0x69, 0x6e, 0x64, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6b, 0x65, 0x79, 0x20, 0x69, - 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x74, - 0x68, 0x65, 0x20, 0x6c, 0x6f, 0x77, 0x65, 0x73, 0x74, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x6c, - 0x20, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x20, 0x54, 0x68, 0x65, 0x20, 0x6c, 0x6f, 0x77, 0x65, 0x73, 0x74, 0x0a, - 0x2d, 0x2d, 0x20, 0x77, 0x69, 0x6c, 0x6c, 0x20, 0x74, 0x79, 0x70, 0x69, 0x63, 0x61, 0x6c, 0x6c, 0x79, 0x20, - 0x74, 0x68, 0x65, 0x20, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x2c, 0x20, 0x66, 0x6f, - 0x72, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x20, 0x22, 0x6c, 0x75, 0x61, 0x35, 0x2e, 0x31, - 0x2e, 0x65, 0x78, 0x65, 0x22, 0x2e, 0x0a, - 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x61, 0x72, 0x67, 0x2e, - 0x67, 0x65, 0x74, 0x4c, 0x6f, 0x77, 0x28, 0x61, 0x29, 0x0a, - 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6d, 0x20, 0x3d, 0x20, 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x68, 0x75, - 0x67, 0x65, 0x0a, - 0x09, 0x66, 0x6f, 0x72, 0x20, 0x6b, 0x2c, 0x76, 0x20, 0x69, 0x6e, 0x20, 0x70, 0x61, 0x69, 0x72, 0x73, 0x28, - 0x61, 0x29, 0x20, 0x64, 0x6f, 0x0a, - 0x09, 0x09, 0x69, 0x66, 0x20, 0x6b, 0x20, 0x3c, 0x20, 0x6d, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, - 0x09, 0x09, 0x09, 0x6d, 0x20, 0x3d, 0x20, 0x6b, 0x0a, - 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, - 0x09, 0x65, 0x6e, 0x64, 0x0a, - 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x61, 0x5b, 0x6d, 0x5d, 0x2c, 0x20, 0x6d, 0x0a, - 0x65, 0x6e, 0x64, 0x0a, - 0x0a, - 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x61, 0x72, 0x67, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x3d, - 0x20, 0x7b, 0x0a, - 0x09, 0x63, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, 0x20, 0x3d, 0x20, 0x7b, 0x20, 0x61, 0x20, 0x3d, 0x20, 0x30, - 0x20, 0x7d, 0x2c, 0x0a, - 0x09, 0x66, 0x75, 0x73, 0x65, 0x64, 0x20, 0x3d, 0x20, 0x7b, 0x61, 0x20, 0x3d, 0x20, 0x30, 0x20, 0x7d, 0x2c, 0x0a, - 0x09, 0x67, 0x61, 0x6d, 0x65, 0x20, 0x3d, 0x20, 0x7b, 0x20, 0x61, 0x20, 0x3d, 0x20, 0x31, 0x20, 0x7d, 0x0a, - 0x7d, 0x0a, - 0x0a, - 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x61, 0x72, 0x67, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x64, - 0x69, 0x63, 0x65, 0x73, 0x20, 0x3d, 0x20, 0x7b, 0x7d, 0x0a, - 0x0a, - 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x61, 0x72, 0x67, 0x2e, - 0x70, 0x61, 0x72, 0x73, 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6d, 0x2c, 0x20, 0x69, 0x29, 0x0a, - 0x09, 0x6d, 0x2e, 0x73, 0x65, 0x74, 0x20, 0x3d, 0x20, 0x74, 0x72, 0x75, 0x65, 0x0a, - 0x0a, - 0x09, 0x69, 0x66, 0x20, 0x6d, 0x2e, 0x61, 0x20, 0x3e, 0x20, 0x30, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, - 0x09, 0x09, 0x6d, 0x2e, 0x61, 0x72, 0x67, 0x20, 0x3d, 0x20, 0x7b, 0x7d, 0x0a, - 0x09, 0x09, 0x66, 0x6f, 0x72, 0x20, 0x6a, 0x3d, 0x69, 0x2c, 0x69, 0x2b, 0x6d, 0x2e, 0x61, 0x2d, 0x31, 0x20, - 0x64, 0x6f, 0x0a, - 0x09, 0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x61, 0x72, 0x67, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, - 0x49, 0x6e, 0x64, 0x69, 0x63, 0x65, 0x73, 0x5b, 0x6a, 0x5d, 0x20, 0x3d, 0x20, 0x74, 0x72, 0x75, 0x65, 0x0a, - 0x09, 0x09, 0x09, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x2e, 0x69, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x28, 0x6d, 0x2e, - 0x61, 0x72, 0x67, 0x2c, 0x20, 0x61, 0x72, 0x67, 0x5b, 0x6a, 0x5d, 0x29, 0x0a, - 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, - 0x09, 0x65, 0x6e, 0x64, 0x0a, - 0x0a, - 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6d, 0x2e, 0x61, 0x0a, - 0x65, 0x6e, 0x64, 0x0a, - 0x0a, - 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x61, 0x72, 0x67, 0x2e, - 0x70, 0x61, 0x72, 0x73, 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x28, 0x29, 0x0a, - 0x0a, - 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x67, 0x61, 0x6d, 0x65, 0x0a, - 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x61, 0x72, 0x67, 0x63, 0x20, 0x3d, 0x20, 0x23, 0x61, 0x72, 0x67, 0x0a, - 0x0a, - 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x69, 0x20, 0x3d, 0x20, 0x31, 0x0a, - 0x09, 0x77, 0x68, 0x69, 0x6c, 0x65, 0x20, 0x69, 0x20, 0x3c, 0x3d, 0x20, 0x61, 0x72, 0x67, 0x63, 0x20, 0x64, - 0x6f, 0x0a, - 0x09, 0x09, 0x2d, 0x2d, 0x20, 0x4c, 0x6f, 0x6f, 0x6b, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x6f, 0x70, 0x74, 0x69, - 0x6f, 0x6e, 0x73, 0x2e, 0x0a, - 0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6d, 0x20, 0x3d, 0x20, 0x61, 0x72, 0x67, 0x5b, 0x69, 0x5d, - 0x3a, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x28, 0x22, 0x5e, 0x25, 0x2d, 0x25, 0x2d, 0x28, 0x2e, 0x2a, 0x29, 0x22, - 0x29, 0x0a, - 0x0a, - 0x09, 0x09, 0x69, 0x66, 0x20, 0x6d, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x6d, 0x20, 0x7e, 0x3d, 0x20, 0x22, 0x22, - 0x20, 0x61, 0x6e, 0x64, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x61, 0x72, 0x67, 0x2e, 0x6f, 0x70, 0x74, 0x69, - 0x6f, 0x6e, 0x73, 0x5b, 0x6d, 0x5d, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x6c, 0x6f, 0x76, - 0x65, 0x2e, 0x61, 0x72, 0x67, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x5b, 0x6d, 0x5d, 0x2e, 0x73, - 0x65, 0x74, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, - 0x09, 0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x61, 0x72, 0x67, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, - 0x49, 0x6e, 0x64, 0x69, 0x63, 0x65, 0x73, 0x5b, 0x69, 0x5d, 0x20, 0x3d, 0x20, 0x74, 0x72, 0x75, 0x65, 0x0a, - 0x09, 0x09, 0x09, 0x69, 0x20, 0x3d, 0x20, 0x69, 0x20, 0x2b, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x61, 0x72, - 0x67, 0x2e, 0x70, 0x61, 0x72, 0x73, 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6c, 0x6f, 0x76, 0x65, - 0x2e, 0x61, 0x72, 0x67, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x5b, 0x6d, 0x5d, 0x2c, 0x20, 0x69, - 0x2b, 0x31, 0x29, 0x0a, - 0x09, 0x09, 0x65, 0x6c, 0x73, 0x65, 0x69, 0x66, 0x20, 0x6d, 0x20, 0x3d, 0x3d, 0x20, 0x22, 0x22, 0x20, 0x74, - 0x68, 0x65, 0x6e, 0x20, 0x2d, 0x2d, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x20, 0x27, 0x2d, 0x2d, 0x27, - 0x20, 0x61, 0x73, 0x20, 0x61, 0x6e, 0x20, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x0a, - 0x09, 0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x61, 0x72, 0x67, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, - 0x49, 0x6e, 0x64, 0x69, 0x63, 0x65, 0x73, 0x5b, 0x69, 0x5d, 0x20, 0x3d, 0x20, 0x74, 0x72, 0x75, 0x65, 0x0a, - 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x67, 0x61, 0x6d, 0x65, 0x20, 0x74, 0x68, 0x65, - 0x6e, 0x20, 0x2d, 0x2d, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x20, 0x27, 0x2d, 0x2d, 0x27, 0x20, 0x66, - 0x6f, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x67, 0x61, 0x6d, 0x65, 0x20, 0x6e, 0x61, - 0x6d, 0x65, 0x0a, - 0x09, 0x09, 0x09, 0x09, 0x67, 0x61, 0x6d, 0x65, 0x20, 0x3d, 0x20, 0x69, 0x20, 0x2b, 0x20, 0x31, 0x0a, - 0x09, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, - 0x09, 0x09, 0x09, 0x62, 0x72, 0x65, 0x61, 0x6b, 0x0a, - 0x09, 0x09, 0x65, 0x6c, 0x73, 0x65, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x67, 0x61, 0x6d, 0x65, 0x20, - 0x74, 0x68, 0x65, 0x6e, 0x0a, - 0x09, 0x09, 0x09, 0x67, 0x61, 0x6d, 0x65, 0x20, 0x3d, 0x20, 0x69, 0x0a, - 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, - 0x09, 0x09, 0x69, 0x20, 0x3d, 0x20, 0x69, 0x20, 0x2b, 0x20, 0x31, 0x0a, - 0x09, 0x65, 0x6e, 0x64, 0x0a, - 0x0a, - 0x09, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x61, 0x72, 0x67, 0x2e, 0x6f, - 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x67, 0x61, 0x6d, 0x65, 0x2e, 0x73, 0x65, 0x74, 0x20, 0x74, 0x68, - 0x65, 0x6e, 0x0a, - 0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x61, 0x72, 0x67, 0x2e, 0x70, 0x61, 0x72, 0x73, 0x65, 0x4f, 0x70, - 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x61, 0x72, 0x67, 0x2e, 0x6f, 0x70, 0x74, 0x69, - 0x6f, 0x6e, 0x73, 0x2e, 0x67, 0x61, 0x6d, 0x65, 0x2c, 0x20, 0x67, 0x61, 0x6d, 0x65, 0x20, 0x6f, 0x72, 0x20, - 0x30, 0x29, 0x0a, - 0x09, 0x65, 0x6e, 0x64, 0x0a, - 0x65, 0x6e, 0x64, 0x0a, - 0x0a, - 0x2d, 0x2d, 0x20, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, 0x72, 0x67, - 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x61, 0x72, 0x65, 0x20, 0x70, 0x61, - 0x73, 0x73, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x79, 0x6f, 0x75, 0x72, 0x20, 0x67, 0x61, 0x6d, 0x65, 0x20, - 0x76, 0x69, 0x61, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x6c, 0x6f, 0x61, 0x64, 0x28, 0x29, 0x0a, - 0x2d, 0x2d, 0x20, 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, - 0x77, 0x65, 0x72, 0x65, 0x20, 0x70, 0x61, 0x72, 0x73, 0x65, 0x64, 0x20, 0x61, 0x73, 0x20, 0x6f, 0x70, 0x74, - 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x61, 0x72, 0x65, 0x20, 0x73, 0x6b, 0x69, 0x70, 0x70, 0x65, 0x64, 0x2e, 0x0a, - 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x61, 0x72, 0x67, 0x2e, - 0x70, 0x61, 0x72, 0x73, 0x65, 0x47, 0x61, 0x6d, 0x65, 0x41, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, - 0x28, 0x61, 0x29, 0x0a, - 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6f, 0x75, 0x74, 0x20, 0x3d, 0x20, 0x7b, 0x7d, 0x0a, - 0x0a, - 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x5f, 0x2c, 0x20, 0x6c, 0x6f, 0x77, 0x69, 0x6e, 0x64, 0x65, 0x78, - 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x61, 0x72, 0x67, 0x2e, 0x67, 0x65, 0x74, 0x4c, 0x6f, 0x77, - 0x28, 0x61, 0x29, 0x0a, - 0x0a, - 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6f, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x77, 0x69, 0x6e, 0x64, 0x65, - 0x78, 0x0a, - 0x09, 0x66, 0x6f, 0x72, 0x20, 0x69, 0x3d, 0x6c, 0x6f, 0x77, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2c, 0x20, 0x23, - 0x61, 0x20, 0x64, 0x6f, 0x0a, - 0x09, 0x09, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x61, 0x72, 0x67, 0x2e, - 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x64, 0x69, 0x63, 0x65, 0x73, 0x5b, 0x69, 0x5d, 0x20, 0x74, - 0x68, 0x65, 0x6e, 0x0a, - 0x09, 0x09, 0x09, 0x6f, 0x75, 0x74, 0x5b, 0x6f, 0x5d, 0x20, 0x3d, 0x20, 0x61, 0x5b, 0x69, 0x5d, 0x0a, - 0x09, 0x09, 0x09, 0x6f, 0x20, 0x3d, 0x20, 0x6f, 0x20, 0x2b, 0x20, 0x31, 0x0a, - 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, - 0x09, 0x65, 0x6e, 0x64, 0x0a, - 0x0a, - 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6f, 0x75, 0x74, 0x0a, - 0x65, 0x6e, 0x64, 0x0a, - 0x0a, - 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x63, 0x72, 0x65, 0x61, - 0x74, 0x65, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x73, 0x28, 0x29, 0x0a, - 0x0a, - 0x09, 0x2d, 0x2d, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x63, 0x61, 0x6c, 0x6c, 0x62, - 0x61, 0x63, 0x6b, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x73, 0x2e, 0x0a, - 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x73, 0x20, 0x3d, 0x20, 0x73, - 0x65, 0x74, 0x6d, 0x65, 0x74, 0x61, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x28, 0x7b, 0x0a, - 0x09, 0x09, 0x6b, 0x65, 0x79, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x62, 0x2c, 0x73, 0x2c, 0x72, 0x29, 0x0a, - 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x6b, 0x65, 0x79, 0x70, 0x72, 0x65, 0x73, - 0x73, 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6c, 0x6f, - 0x76, 0x65, 0x2e, 0x6b, 0x65, 0x79, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x28, 0x62, 0x2c, 0x73, 0x2c, - 0x72, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a, - 0x09, 0x09, 0x65, 0x6e, 0x64, 0x2c, 0x0a, - 0x09, 0x09, 0x6b, 0x65, 0x79, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x64, 0x20, 0x3d, 0x20, 0x66, 0x75, - 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x62, 0x2c, 0x73, 0x29, 0x0a, - 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x6b, 0x65, 0x79, 0x72, 0x65, 0x6c, 0x65, - 0x61, 0x73, 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6c, - 0x6f, 0x76, 0x65, 0x2e, 0x6b, 0x65, 0x79, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x64, 0x28, 0x62, 0x2c, - 0x73, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a, - 0x09, 0x09, 0x65, 0x6e, 0x64, 0x2c, 0x0a, - 0x09, 0x09, 0x74, 0x65, 0x78, 0x74, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x74, 0x29, 0x0a, - 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x74, 0x65, 0x78, 0x74, 0x69, 0x6e, 0x70, - 0x75, 0x74, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6c, 0x6f, 0x76, - 0x65, 0x2e, 0x74, 0x65, 0x78, 0x74, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x28, 0x74, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a, - 0x09, 0x09, 0x65, 0x6e, 0x64, 0x2c, 0x0a, - 0x09, 0x09, 0x74, 0x65, 0x78, 0x74, 0x65, 0x64, 0x69, 0x74, 0x65, 0x64, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x74, 0x2c, 0x73, 0x2c, 0x6c, 0x29, 0x0a, - 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x74, 0x65, 0x78, 0x74, 0x65, 0x64, 0x69, - 0x74, 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6c, 0x6f, - 0x76, 0x65, 0x2e, 0x74, 0x65, 0x78, 0x74, 0x65, 0x64, 0x69, 0x74, 0x65, 0x64, 0x28, 0x74, 0x2c, 0x73, 0x2c, - 0x6c, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a, - 0x09, 0x09, 0x65, 0x6e, 0x64, 0x2c, 0x0a, - 0x09, 0x09, 0x6d, 0x6f, 0x75, 0x73, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x78, 0x2c, 0x79, 0x2c, 0x64, 0x78, 0x2c, 0x64, 0x79, 0x2c, 0x74, - 0x29, 0x0a, - 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x6d, 0x6f, 0x75, 0x73, 0x65, 0x6d, 0x6f, - 0x76, 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6c, 0x6f, - 0x76, 0x65, 0x2e, 0x6d, 0x6f, 0x75, 0x73, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x28, 0x78, 0x2c, 0x79, 0x2c, - 0x64, 0x78, 0x2c, 0x64, 0x79, 0x2c, 0x74, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a, - 0x09, 0x09, 0x65, 0x6e, 0x64, 0x2c, 0x0a, - 0x09, 0x09, 0x6d, 0x6f, 0x75, 0x73, 0x65, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x20, 0x3d, 0x20, 0x66, - 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x78, 0x2c, 0x79, 0x2c, 0x62, 0x2c, 0x74, 0x2c, 0x63, - 0x29, 0x0a, - 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x6d, 0x6f, 0x75, 0x73, 0x65, 0x70, 0x72, - 0x65, 0x73, 0x73, 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, - 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x6d, 0x6f, 0x75, 0x73, 0x65, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x28, - 0x78, 0x2c, 0x79, 0x2c, 0x62, 0x2c, 0x74, 0x2c, 0x63, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a, - 0x09, 0x09, 0x65, 0x6e, 0x64, 0x2c, 0x0a, - 0x09, 0x09, 0x6d, 0x6f, 0x75, 0x73, 0x65, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x64, 0x20, 0x3d, 0x20, - 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x78, 0x2c, 0x79, 0x2c, 0x62, 0x2c, 0x74, 0x2c, - 0x63, 0x29, 0x0a, - 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x6d, 0x6f, 0x75, 0x73, 0x65, 0x72, 0x65, - 0x6c, 0x65, 0x61, 0x73, 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, - 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x6d, 0x6f, 0x75, 0x73, 0x65, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, - 0x64, 0x28, 0x78, 0x2c, 0x79, 0x2c, 0x62, 0x2c, 0x74, 0x2c, 0x63, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a, - 0x09, 0x09, 0x65, 0x6e, 0x64, 0x2c, 0x0a, - 0x09, 0x09, 0x77, 0x68, 0x65, 0x65, 0x6c, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x78, 0x2c, 0x79, 0x29, 0x0a, - 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x77, 0x68, 0x65, 0x65, 0x6c, 0x6d, 0x6f, - 0x76, 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6c, 0x6f, - 0x76, 0x65, 0x2e, 0x77, 0x68, 0x65, 0x65, 0x6c, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x28, 0x78, 0x2c, 0x79, 0x29, - 0x20, 0x65, 0x6e, 0x64, 0x0a, - 0x09, 0x09, 0x65, 0x6e, 0x64, 0x2c, 0x0a, - 0x09, 0x09, 0x74, 0x6f, 0x75, 0x63, 0x68, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x20, 0x3d, 0x20, 0x66, - 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x69, 0x64, 0x2c, 0x78, 0x2c, 0x79, 0x2c, 0x64, 0x78, - 0x2c, 0x64, 0x79, 0x2c, 0x70, 0x29, 0x0a, - 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x74, 0x6f, 0x75, 0x63, 0x68, 0x70, 0x72, - 0x65, 0x73, 0x73, 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, - 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x74, 0x6f, 0x75, 0x63, 0x68, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x28, - 0x69, 0x64, 0x2c, 0x78, 0x2c, 0x79, 0x2c, 0x64, 0x78, 0x2c, 0x64, 0x79, 0x2c, 0x70, 0x29, 0x20, 0x65, 0x6e, - 0x64, 0x0a, - 0x09, 0x09, 0x65, 0x6e, 0x64, 0x2c, 0x0a, - 0x09, 0x09, 0x74, 0x6f, 0x75, 0x63, 0x68, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x64, 0x20, 0x3d, 0x20, - 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x69, 0x64, 0x2c, 0x78, 0x2c, 0x79, 0x2c, 0x64, - 0x78, 0x2c, 0x64, 0x79, 0x2c, 0x70, 0x29, 0x0a, - 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x74, 0x6f, 0x75, 0x63, 0x68, 0x72, 0x65, - 0x6c, 0x65, 0x61, 0x73, 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, - 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x74, 0x6f, 0x75, 0x63, 0x68, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, - 0x64, 0x28, 0x69, 0x64, 0x2c, 0x78, 0x2c, 0x79, 0x2c, 0x64, 0x78, 0x2c, 0x64, 0x79, 0x2c, 0x70, 0x29, 0x20, - 0x65, 0x6e, 0x64, 0x0a, - 0x09, 0x09, 0x65, 0x6e, 0x64, 0x2c, 0x0a, - 0x09, 0x09, 0x74, 0x6f, 0x75, 0x63, 0x68, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x69, 0x64, 0x2c, 0x78, 0x2c, 0x79, 0x2c, 0x64, 0x78, 0x2c, 0x64, - 0x79, 0x2c, 0x70, 0x29, 0x0a, - 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x74, 0x6f, 0x75, 0x63, 0x68, 0x6d, 0x6f, - 0x76, 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6c, 0x6f, - 0x76, 0x65, 0x2e, 0x74, 0x6f, 0x75, 0x63, 0x68, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x28, 0x69, 0x64, 0x2c, 0x78, - 0x2c, 0x79, 0x2c, 0x64, 0x78, 0x2c, 0x64, 0x79, 0x2c, 0x70, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a, - 0x09, 0x09, 0x65, 0x6e, 0x64, 0x2c, 0x0a, - 0x09, 0x09, 0x6a, 0x6f, 0x79, 0x73, 0x74, 0x69, 0x63, 0x6b, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x20, - 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x6a, 0x2c, 0x62, 0x29, 0x0a, - 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x6a, 0x6f, 0x79, 0x73, 0x74, 0x69, 0x63, - 0x6b, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x72, 0x65, 0x74, 0x75, - 0x72, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x6a, 0x6f, 0x79, 0x73, 0x74, 0x69, 0x63, 0x6b, 0x70, 0x72, - 0x65, 0x73, 0x73, 0x65, 0x64, 0x28, 0x6a, 0x2c, 0x62, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a, - 0x09, 0x09, 0x65, 0x6e, 0x64, 0x2c, 0x0a, - 0x09, 0x09, 0x6a, 0x6f, 0x79, 0x73, 0x74, 0x69, 0x63, 0x6b, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x64, - 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x6a, 0x2c, 0x62, 0x29, 0x0a, - 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x6a, 0x6f, 0x79, 0x73, 0x74, 0x69, 0x63, - 0x6b, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x72, 0x65, 0x74, - 0x75, 0x72, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x6a, 0x6f, 0x79, 0x73, 0x74, 0x69, 0x63, 0x6b, 0x72, - 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x64, 0x28, 0x6a, 0x2c, 0x62, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a, - 0x09, 0x09, 0x65, 0x6e, 0x64, 0x2c, 0x0a, - 0x09, 0x09, 0x6a, 0x6f, 0x79, 0x73, 0x74, 0x69, 0x63, 0x6b, 0x61, 0x78, 0x69, 0x73, 0x20, 0x3d, 0x20, 0x66, - 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x6a, 0x2c, 0x61, 0x2c, 0x76, 0x29, 0x0a, - 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x6a, 0x6f, 0x79, 0x73, 0x74, 0x69, 0x63, - 0x6b, 0x61, 0x78, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, - 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x6a, 0x6f, 0x79, 0x73, 0x74, 0x69, 0x63, 0x6b, 0x61, 0x78, 0x69, 0x73, 0x28, - 0x6a, 0x2c, 0x61, 0x2c, 0x76, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a, - 0x09, 0x09, 0x65, 0x6e, 0x64, 0x2c, 0x0a, - 0x09, 0x09, 0x6a, 0x6f, 0x79, 0x73, 0x74, 0x69, 0x63, 0x6b, 0x68, 0x61, 0x74, 0x20, 0x3d, 0x20, 0x66, 0x75, - 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x6a, 0x2c, 0x68, 0x2c, 0x76, 0x29, 0x0a, - 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x6a, 0x6f, 0x79, 0x73, 0x74, 0x69, 0x63, - 0x6b, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6c, - 0x6f, 0x76, 0x65, 0x2e, 0x6a, 0x6f, 0x79, 0x73, 0x74, 0x69, 0x63, 0x6b, 0x68, 0x61, 0x74, 0x28, 0x6a, 0x2c, - 0x68, 0x2c, 0x76, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a, - 0x09, 0x09, 0x65, 0x6e, 0x64, 0x2c, 0x0a, - 0x09, 0x09, 0x67, 0x61, 0x6d, 0x65, 0x70, 0x61, 0x64, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x20, 0x3d, - 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x6a, 0x2c, 0x62, 0x29, 0x0a, - 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x61, 0x6d, 0x65, 0x70, 0x61, 0x64, - 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, - 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x61, 0x6d, 0x65, 0x70, 0x61, 0x64, 0x70, 0x72, 0x65, 0x73, - 0x73, 0x65, 0x64, 0x28, 0x6a, 0x2c, 0x62, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a, - 0x09, 0x09, 0x65, 0x6e, 0x64, 0x2c, 0x0a, - 0x09, 0x09, 0x67, 0x61, 0x6d, 0x65, 0x70, 0x61, 0x64, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x64, 0x20, - 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x6a, 0x2c, 0x62, 0x29, 0x0a, - 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x61, 0x6d, 0x65, 0x70, 0x61, 0x64, - 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x72, 0x65, 0x74, 0x75, - 0x72, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x61, 0x6d, 0x65, 0x70, 0x61, 0x64, 0x72, 0x65, 0x6c, - 0x65, 0x61, 0x73, 0x65, 0x64, 0x28, 0x6a, 0x2c, 0x62, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a, - 0x09, 0x09, 0x65, 0x6e, 0x64, 0x2c, 0x0a, - 0x09, 0x09, 0x67, 0x61, 0x6d, 0x65, 0x70, 0x61, 0x64, 0x61, 0x78, 0x69, 0x73, 0x20, 0x3d, 0x20, 0x66, 0x75, - 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x6a, 0x2c, 0x61, 0x2c, 0x76, 0x29, 0x0a, - 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x61, 0x6d, 0x65, 0x70, 0x61, 0x64, - 0x61, 0x78, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6c, - 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x61, 0x6d, 0x65, 0x70, 0x61, 0x64, 0x61, 0x78, 0x69, 0x73, 0x28, 0x6a, 0x2c, - 0x61, 0x2c, 0x76, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a, - 0x09, 0x09, 0x65, 0x6e, 0x64, 0x2c, 0x0a, - 0x09, 0x09, 0x6a, 0x6f, 0x79, 0x73, 0x74, 0x69, 0x63, 0x6b, 0x61, 0x64, 0x64, 0x65, 0x64, 0x20, 0x3d, 0x20, - 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x6a, 0x29, 0x0a, - 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x6a, 0x6f, 0x79, 0x73, 0x74, 0x69, 0x63, - 0x6b, 0x61, 0x64, 0x64, 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, - 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x6a, 0x6f, 0x79, 0x73, 0x74, 0x69, 0x63, 0x6b, 0x61, 0x64, 0x64, 0x65, - 0x64, 0x28, 0x6a, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a, - 0x09, 0x09, 0x65, 0x6e, 0x64, 0x2c, 0x0a, - 0x09, 0x09, 0x6a, 0x6f, 0x79, 0x73, 0x74, 0x69, 0x63, 0x6b, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x20, - 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x6a, 0x29, 0x0a, - 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x6a, 0x6f, 0x79, 0x73, 0x74, 0x69, 0x63, - 0x6b, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x72, 0x65, 0x74, 0x75, - 0x72, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x6a, 0x6f, 0x79, 0x73, 0x74, 0x69, 0x63, 0x6b, 0x72, 0x65, - 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x28, 0x6a, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a, - 0x09, 0x09, 0x65, 0x6e, 0x64, 0x2c, 0x0a, - 0x09, 0x09, 0x66, 0x6f, 0x63, 0x75, 0x73, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x20, 0x28, 0x66, 0x29, 0x0a, - 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x66, 0x6f, 0x63, 0x75, 0x73, 0x20, 0x74, - 0x68, 0x65, 0x6e, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x66, 0x6f, - 0x63, 0x75, 0x73, 0x28, 0x66, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a, - 0x09, 0x09, 0x65, 0x6e, 0x64, 0x2c, 0x0a, - 0x09, 0x09, 0x6d, 0x6f, 0x75, 0x73, 0x65, 0x66, 0x6f, 0x63, 0x75, 0x73, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x66, 0x29, 0x0a, - 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x6d, 0x6f, 0x75, 0x73, 0x65, 0x66, 0x6f, - 0x63, 0x75, 0x73, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6c, 0x6f, - 0x76, 0x65, 0x2e, 0x6d, 0x6f, 0x75, 0x73, 0x65, 0x66, 0x6f, 0x63, 0x75, 0x73, 0x28, 0x66, 0x29, 0x20, 0x65, - 0x6e, 0x64, 0x0a, - 0x09, 0x09, 0x65, 0x6e, 0x64, 0x2c, 0x0a, - 0x09, 0x09, 0x76, 0x69, 0x73, 0x69, 0x62, 0x6c, 0x65, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x20, 0x28, 0x76, 0x29, 0x0a, - 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x76, 0x69, 0x73, 0x69, 0x62, 0x6c, 0x65, - 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, - 0x76, 0x69, 0x73, 0x69, 0x62, 0x6c, 0x65, 0x28, 0x76, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a, - 0x09, 0x09, 0x65, 0x6e, 0x64, 0x2c, 0x0a, - 0x09, 0x09, 0x71, 0x75, 0x69, 0x74, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, - 0x28, 0x29, 0x0a, - 0x09, 0x09, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x0a, - 0x09, 0x09, 0x65, 0x6e, 0x64, 0x2c, 0x0a, - 0x09, 0x09, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x20, 0x3d, 0x20, 0x66, 0x75, - 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x74, 0x2c, 0x20, 0x65, 0x72, 0x72, 0x29, 0x0a, - 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x65, - 0x72, 0x72, 0x6f, 0x72, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6c, - 0x6f, 0x76, 0x65, 0x2e, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x28, 0x74, 0x2c, - 0x20, 0x65, 0x72, 0x72, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a, - 0x09, 0x09, 0x65, 0x6e, 0x64, 0x2c, 0x0a, - 0x09, 0x09, 0x72, 0x65, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x20, 0x28, 0x77, 0x2c, 0x20, 0x68, 0x29, 0x0a, - 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x72, 0x65, 0x73, 0x69, 0x7a, 0x65, 0x20, - 0x74, 0x68, 0x65, 0x6e, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x72, - 0x65, 0x73, 0x69, 0x7a, 0x65, 0x28, 0x77, 0x2c, 0x20, 0x68, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a, - 0x09, 0x09, 0x65, 0x6e, 0x64, 0x2c, 0x0a, - 0x09, 0x09, 0x66, 0x69, 0x6c, 0x65, 0x64, 0x72, 0x6f, 0x70, 0x70, 0x65, 0x64, 0x20, 0x3d, 0x20, 0x66, 0x75, - 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x66, 0x29, 0x0a, - 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x64, 0x72, 0x6f, - 0x70, 0x70, 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6c, - 0x6f, 0x76, 0x65, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x64, 0x72, 0x6f, 0x70, 0x70, 0x65, 0x64, 0x28, 0x66, 0x29, - 0x20, 0x65, 0x6e, 0x64, 0x0a, - 0x09, 0x09, 0x65, 0x6e, 0x64, 0x2c, 0x0a, - 0x09, 0x09, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x64, 0x72, 0x6f, 0x70, 0x70, 0x65, 0x64, - 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x64, 0x69, 0x72, 0x29, 0x0a, - 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, - 0x72, 0x79, 0x64, 0x72, 0x6f, 0x70, 0x70, 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x72, 0x65, 0x74, - 0x75, 0x72, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, - 0x64, 0x72, 0x6f, 0x70, 0x70, 0x65, 0x64, 0x28, 0x64, 0x69, 0x72, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a, - 0x09, 0x09, 0x65, 0x6e, 0x64, 0x2c, 0x0a, - 0x09, 0x09, 0x6c, 0x6f, 0x77, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x29, 0x0a, - 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x6c, 0x6f, 0x77, 0x6d, 0x65, 0x6d, 0x6f, - 0x72, 0x79, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x6c, 0x6f, 0x77, 0x6d, 0x65, - 0x6d, 0x6f, 0x72, 0x79, 0x28, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a, - 0x09, 0x09, 0x09, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x67, 0x61, 0x72, 0x62, 0x61, 0x67, 0x65, 0x28, - 0x29, 0x0a, - 0x09, 0x09, 0x09, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x67, 0x61, 0x72, 0x62, 0x61, 0x67, 0x65, 0x28, - 0x29, 0x0a, - 0x09, 0x09, 0x65, 0x6e, 0x64, 0x2c, 0x0a, - 0x09, 0x09, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x72, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x64, 0x20, 0x3d, - 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, - 0x2c, 0x20, 0x6f, 0x72, 0x69, 0x65, 0x6e, 0x74, 0x29, 0x0a, - 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, - 0x72, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, - 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x72, 0x6f, 0x74, 0x61, - 0x74, 0x65, 0x64, 0x28, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x2c, 0x20, 0x6f, 0x72, 0x69, 0x65, 0x6e, - 0x74, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a, - 0x09, 0x09, 0x65, 0x6e, 0x64, 0x2c, 0x0a, - 0x09, 0x7d, 0x2c, 0x20, 0x7b, 0x0a, - 0x09, 0x09, 0x5f, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2c, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x29, 0x0a, - 0x09, 0x09, 0x09, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x28, 0x22, 0x55, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x20, - 0x65, 0x76, 0x65, 0x6e, 0x74, 0x3a, 0x20, 0x22, 0x20, 0x2e, 0x2e, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x29, 0x0a, - 0x09, 0x09, 0x65, 0x6e, 0x64, 0x2c, 0x0a, - 0x09, 0x7d, 0x29, 0x0a, - 0x0a, - 0x65, 0x6e, 0x64, 0x0a, - 0x0a, - 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x75, 0x72, 0x69, - 0x64, 0x65, 0x63, 0x6f, 0x64, 0x65, 0x28, 0x73, 0x29, 0x0a, - 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x73, 0x3a, 0x67, 0x73, 0x75, 0x62, 0x28, 0x22, 0x25, 0x25, - 0x25, 0x78, 0x25, 0x78, 0x22, 0x2c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x73, 0x74, - 0x72, 0x29, 0x0a, - 0x09, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x63, 0x68, - 0x61, 0x72, 0x28, 0x74, 0x6f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x28, 0x73, 0x74, 0x72, 0x3a, 0x73, 0x75, - 0x62, 0x28, 0x32, 0x29, 0x2c, 0x20, 0x31, 0x36, 0x29, 0x29, 0x0a, - 0x09, 0x65, 0x6e, 0x64, 0x29, 0x0a, - 0x65, 0x6e, 0x64, 0x0a, - 0x0a, - 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6e, 0x6f, 0x5f, 0x67, 0x61, 0x6d, 0x65, 0x5f, 0x63, 0x6f, 0x64, 0x65, - 0x20, 0x3d, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x0a, - 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x69, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x5f, 0x67, 0x61, 0x6d, 0x65, - 0x5f, 0x70, 0x61, 0x74, 0x68, 0x20, 0x3d, 0x20, 0x6e, 0x69, 0x6c, 0x0a, - 0x0a, - 0x2d, 0x2d, 0x20, 0x54, 0x68, 0x69, 0x73, 0x20, 0x63, 0x61, 0x6e, 0x27, 0x74, 0x20, 0x62, 0x65, 0x20, 0x6f, - 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x2e, 0x0a, - 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x62, 0x6f, 0x6f, 0x74, - 0x28, 0x29, 0x0a, - 0x0a, - 0x09, 0x2d, 0x2d, 0x20, 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x61, 0x62, 0x73, 0x6f, 0x6c, 0x75, - 0x74, 0x65, 0x6c, 0x79, 0x20, 0x6e, 0x65, 0x65, 0x64, 0x65, 0x64, 0x2e, 0x0a, - 0x09, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x28, 0x22, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x66, 0x69, 0x6c, - 0x65, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x22, 0x29, 0x0a, - 0x0a, - 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x61, 0x72, 0x67, 0x30, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x76, 0x65, - 0x2e, 0x61, 0x72, 0x67, 0x2e, 0x67, 0x65, 0x74, 0x4c, 0x6f, 0x77, 0x28, 0x61, 0x72, 0x67, 0x29, 0x0a, - 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x2e, 0x69, - 0x6e, 0x69, 0x74, 0x28, 0x61, 0x72, 0x67, 0x30, 0x29, 0x0a, - 0x0a, - 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x65, 0x78, 0x65, 0x70, 0x61, 0x74, 0x68, 0x20, 0x3d, 0x20, 0x6c, - 0x6f, 0x76, 0x65, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x2e, 0x67, 0x65, 0x74, - 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x50, 0x61, 0x74, 0x68, 0x28, 0x29, 0x0a, - 0x09, 0x69, 0x66, 0x20, 0x23, 0x65, 0x78, 0x65, 0x70, 0x61, 0x74, 0x68, 0x20, 0x3d, 0x3d, 0x20, 0x30, 0x20, - 0x74, 0x68, 0x65, 0x6e, 0x0a, - 0x09, 0x09, 0x2d, 0x2d, 0x20, 0x54, 0x68, 0x69, 0x73, 0x20, 0x73, 0x68, 0x6f, 0x75, 0x6c, 0x64, 0x6e, 0x27, - 0x74, 0x20, 0x68, 0x61, 0x70, 0x70, 0x65, 0x6e, 0x2c, 0x20, 0x62, 0x75, 0x74, 0x20, 0x6a, 0x75, 0x73, 0x74, - 0x20, 0x69, 0x6e, 0x20, 0x63, 0x61, 0x73, 0x65, 0x20, 0x77, 0x65, 0x27, 0x6c, 0x6c, 0x20, 0x66, 0x61, 0x6c, - 0x6c, 0x20, 0x62, 0x61, 0x63, 0x6b, 0x20, 0x74, 0x6f, 0x20, 0x61, 0x72, 0x67, 0x30, 0x2e, 0x0a, - 0x09, 0x09, 0x65, 0x78, 0x65, 0x70, 0x61, 0x74, 0x68, 0x20, 0x3d, 0x20, 0x61, 0x72, 0x67, 0x30, 0x0a, - 0x09, 0x65, 0x6e, 0x64, 0x0a, - 0x0a, - 0x09, 0x6e, 0x6f, 0x5f, 0x67, 0x61, 0x6d, 0x65, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x3d, 0x20, 0x66, 0x61, - 0x6c, 0x73, 0x65, 0x0a, - 0x09, 0x69, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x5f, 0x67, 0x61, 0x6d, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, - 0x20, 0x3d, 0x20, 0x6e, 0x69, 0x6c, 0x0a, - 0x0a, - 0x09, 0x2d, 0x2d, 0x20, 0x49, 0x73, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x6f, 0x6e, 0x65, 0x20, 0x6f, 0x66, - 0x20, 0x74, 0x68, 0x6f, 0x73, 0x65, 0x20, 0x66, 0x61, 0x6e, 0x63, 0x79, 0x20, 0x22, 0x66, 0x75, 0x73, 0x65, - 0x64, 0x22, 0x20, 0x67, 0x61, 0x6d, 0x65, 0x73, 0x3f, 0x0a, - 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x63, 0x61, 0x6e, 0x5f, 0x68, 0x61, 0x73, 0x5f, 0x67, 0x61, 0x6d, - 0x65, 0x20, 0x3d, 0x20, 0x70, 0x63, 0x61, 0x6c, 0x6c, 0x28, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x66, 0x69, 0x6c, - 0x65, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x2e, 0x73, 0x65, 0x74, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2c, - 0x20, 0x65, 0x78, 0x65, 0x70, 0x61, 0x74, 0x68, 0x29, 0x0a, - 0x0a, - 0x09, 0x2d, 0x2d, 0x20, 0x49, 0x74, 0x27, 0x73, 0x20, 0x61, 0x20, 0x66, 0x75, 0x73, 0x65, 0x64, 0x20, 0x67, - 0x61, 0x6d, 0x65, 0x2c, 0x20, 0x64, 0x6f, 0x6e, 0x27, 0x74, 0x20, 0x70, 0x61, 0x72, 0x73, 0x65, 0x20, 0x2d, - 0x2d, 0x67, 0x61, 0x6d, 0x65, 0x20, 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x0a, - 0x09, 0x69, 0x66, 0x20, 0x63, 0x61, 0x6e, 0x5f, 0x68, 0x61, 0x73, 0x5f, 0x67, 0x61, 0x6d, 0x65, 0x20, 0x74, - 0x68, 0x65, 0x6e, 0x0a, - 0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x61, 0x72, 0x67, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, - 0x2e, 0x67, 0x61, 0x6d, 0x65, 0x2e, 0x73, 0x65, 0x74, 0x20, 0x3d, 0x20, 0x74, 0x72, 0x75, 0x65, 0x0a, - 0x09, 0x65, 0x6e, 0x64, 0x0a, - 0x0a, - 0x09, 0x2d, 0x2d, 0x20, 0x50, 0x61, 0x72, 0x73, 0x65, 0x20, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, - 0x6e, 0x6f, 0x77, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x77, 0x65, 0x20, 0x6b, 0x6e, 0x6f, 0x77, 0x20, 0x77, - 0x68, 0x69, 0x63, 0x68, 0x20, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x77, 0x65, 0x27, 0x72, 0x65, - 0x20, 0x6c, 0x6f, 0x6f, 0x6b, 0x69, 0x6e, 0x67, 0x20, 0x66, 0x6f, 0x72, 0x2e, 0x0a, - 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x61, 0x72, 0x67, 0x2e, 0x70, 0x61, 0x72, 0x73, 0x65, 0x4f, 0x70, 0x74, - 0x69, 0x6f, 0x6e, 0x73, 0x28, 0x29, 0x0a, - 0x0a, - 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6f, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x61, 0x72, - 0x67, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x0a, - 0x0a, - 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x69, 0x73, 0x5f, 0x66, 0x75, 0x73, 0x65, 0x64, 0x5f, 0x67, 0x61, - 0x6d, 0x65, 0x20, 0x3d, 0x20, 0x63, 0x61, 0x6e, 0x5f, 0x68, 0x61, 0x73, 0x5f, 0x67, 0x61, 0x6d, 0x65, 0x20, - 0x6f, 0x72, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x61, 0x72, 0x67, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, - 0x73, 0x2e, 0x66, 0x75, 0x73, 0x65, 0x64, 0x2e, 0x73, 0x65, 0x74, 0x0a, - 0x0a, - 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x2e, 0x73, - 0x65, 0x74, 0x46, 0x75, 0x73, 0x65, 0x64, 0x28, 0x69, 0x73, 0x5f, 0x66, 0x75, 0x73, 0x65, 0x64, 0x5f, 0x67, - 0x61, 0x6d, 0x65, 0x29, 0x0a, - 0x0a, - 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x73, 0x65, 0x74, 0x44, 0x65, 0x70, 0x72, 0x65, 0x63, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x28, 0x6e, 0x6f, 0x74, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, - 0x66, 0x69, 0x6c, 0x65, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x2e, 0x69, 0x73, 0x46, 0x75, 0x73, 0x65, 0x64, - 0x28, 0x29, 0x29, 0x0a, - 0x0a, - 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x20, 0x3d, 0x20, - 0x22, 0x22, 0x0a, - 0x09, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x63, 0x61, 0x6e, 0x5f, 0x68, 0x61, 0x73, 0x5f, 0x67, 0x61, - 0x6d, 0x65, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x6f, 0x2e, 0x67, 0x61, 0x6d, 0x65, 0x2e, 0x73, 0x65, 0x74, 0x20, - 0x61, 0x6e, 0x64, 0x20, 0x6f, 0x2e, 0x67, 0x61, 0x6d, 0x65, 0x2e, 0x61, 0x72, 0x67, 0x5b, 0x31, 0x5d, 0x20, - 0x74, 0x68, 0x65, 0x6e, 0x0a, - 0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6e, 0x6f, 0x75, 0x72, 0x69, 0x20, 0x3d, 0x20, 0x6f, 0x2e, - 0x67, 0x61, 0x6d, 0x65, 0x2e, 0x61, 0x72, 0x67, 0x5b, 0x31, 0x5d, 0x0a, - 0x0a, - 0x09, 0x09, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x75, 0x72, 0x69, 0x3a, 0x73, 0x75, 0x62, 0x28, 0x31, 0x2c, 0x20, - 0x37, 0x29, 0x20, 0x3d, 0x3d, 0x20, 0x22, 0x66, 0x69, 0x6c, 0x65, 0x3a, 0x2f, 0x2f, 0x22, 0x20, 0x74, 0x68, - 0x65, 0x6e, 0x0a, - 0x09, 0x09, 0x09, 0x6e, 0x6f, 0x75, 0x72, 0x69, 0x20, 0x3d, 0x20, 0x75, 0x72, 0x69, 0x64, 0x65, 0x63, 0x6f, - 0x64, 0x65, 0x28, 0x6e, 0x6f, 0x75, 0x72, 0x69, 0x3a, 0x73, 0x75, 0x62, 0x28, 0x38, 0x29, 0x29, 0x0a, - 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, - 0x0a, - 0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x75, 0x6c, 0x6c, 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x70, 0x61, 0x74, 0x68, 0x2e, 0x67, 0x65, 0x74, 0x46, - 0x75, 0x6c, 0x6c, 0x28, 0x6e, 0x6f, 0x75, 0x72, 0x69, 0x29, 0x0a, - 0x09, 0x09, 0x63, 0x61, 0x6e, 0x5f, 0x68, 0x61, 0x73, 0x5f, 0x67, 0x61, 0x6d, 0x65, 0x20, 0x3d, 0x20, 0x70, - 0x63, 0x61, 0x6c, 0x6c, 0x28, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x79, 0x73, 0x74, - 0x65, 0x6d, 0x2e, 0x73, 0x65, 0x74, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2c, 0x20, 0x66, 0x75, 0x6c, 0x6c, - 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x29, 0x0a, - 0x0a, - 0x09, 0x09, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x63, 0x61, 0x6e, 0x5f, 0x68, 0x61, 0x73, 0x5f, 0x67, - 0x61, 0x6d, 0x65, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, - 0x09, 0x09, 0x09, 0x69, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x5f, 0x67, 0x61, 0x6d, 0x65, 0x5f, 0x70, 0x61, - 0x74, 0x68, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6c, 0x6c, 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x0a, - 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, - 0x0a, - 0x09, 0x09, 0x2d, 0x2d, 0x20, 0x55, 0x73, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x20, - 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x20, 0x2e, 0x6c, 0x6f, 0x76, - 0x65, 0x20, 0x61, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x20, - 0x66, 0x6f, 0x72, 0x20, 0x6e, 0x6f, 0x77, 0x2e, 0x0a, - 0x09, 0x09, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, - 0x70, 0x61, 0x74, 0x68, 0x2e, 0x6c, 0x65, 0x61, 0x66, 0x28, 0x66, 0x75, 0x6c, 0x6c, 0x5f, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x29, 0x0a, - 0x09, 0x65, 0x6c, 0x73, 0x65, 0x0a, - 0x09, 0x09, 0x2d, 0x2d, 0x20, 0x55, 0x73, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x20, - 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x65, 0x78, 0x65, 0x20, 0x61, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, - 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x6e, 0x6f, 0x77, 0x2e, 0x0a, - 0x09, 0x09, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, - 0x70, 0x61, 0x74, 0x68, 0x2e, 0x6c, 0x65, 0x61, 0x66, 0x28, 0x65, 0x78, 0x65, 0x70, 0x61, 0x74, 0x68, 0x29, 0x0a, - 0x09, 0x65, 0x6e, 0x64, 0x0a, - 0x0a, - 0x09, 0x2d, 0x2d, 0x20, 0x54, 0x72, 0x79, 0x20, 0x74, 0x6f, 0x20, 0x75, 0x73, 0x65, 0x20, 0x74, 0x68, 0x65, - 0x20, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x69, 0x6e, - 0x67, 0x20, 0x6d, 0x61, 0x69, 0x6e, 0x2e, 0x6c, 0x75, 0x61, 0x20, 0x61, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, - 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x2e, 0x20, 0x49, 0x74, 0x0a, - 0x09, 0x2d, 0x2d, 0x20, 0x6d, 0x69, 0x67, 0x68, 0x74, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x62, 0x65, 0x20, 0x61, - 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x2c, 0x20, 0x69, 0x6e, 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, - 0x20, 0x63, 0x61, 0x73, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x66, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, - 0x73, 0x20, 0x61, 0x62, 0x6f, 0x76, 0x65, 0x20, 0x61, 0x72, 0x65, 0x20, 0x75, 0x73, 0x65, 0x64, 0x2e, 0x0a, - 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x72, 0x65, 0x61, 0x6c, 0x64, 0x69, 0x72, 0x20, 0x3d, 0x20, 0x6c, - 0x6f, 0x76, 0x65, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x2e, 0x67, 0x65, 0x74, - 0x52, 0x65, 0x61, 0x6c, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x28, 0x22, 0x6d, 0x61, 0x69, - 0x6e, 0x2e, 0x6c, 0x75, 0x61, 0x22, 0x29, 0x0a, - 0x09, 0x69, 0x66, 0x20, 0x72, 0x65, 0x61, 0x6c, 0x64, 0x69, 0x72, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, - 0x09, 0x09, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, - 0x70, 0x61, 0x74, 0x68, 0x2e, 0x6c, 0x65, 0x61, 0x66, 0x28, 0x72, 0x65, 0x61, 0x6c, 0x64, 0x69, 0x72, 0x29, 0x0a, - 0x09, 0x65, 0x6e, 0x64, 0x0a, - 0x0a, - 0x09, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x20, 0x3d, 0x20, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, - 0x74, 0x79, 0x3a, 0x67, 0x73, 0x75, 0x62, 0x28, 0x22, 0x5e, 0x28, 0x5b, 0x25, 0x2e, 0x5d, 0x2b, 0x29, 0x22, - 0x2c, 0x20, 0x22, 0x22, 0x29, 0x20, 0x2d, 0x2d, 0x20, 0x73, 0x74, 0x72, 0x69, 0x70, 0x20, 0x6c, 0x65, 0x61, - 0x64, 0x69, 0x6e, 0x67, 0x20, 0x22, 0x2e, 0x22, 0x27, 0x73, 0x0a, - 0x09, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x20, 0x3d, 0x20, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, - 0x74, 0x79, 0x3a, 0x67, 0x73, 0x75, 0x62, 0x28, 0x22, 0x25, 0x2e, 0x28, 0x5b, 0x5e, 0x25, 0x2e, 0x5d, 0x2b, - 0x29, 0x24, 0x22, 0x2c, 0x20, 0x22, 0x22, 0x29, 0x20, 0x2d, 0x2d, 0x20, 0x73, 0x74, 0x72, 0x69, 0x70, 0x20, - 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x0a, - 0x09, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x20, 0x3d, 0x20, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, - 0x74, 0x79, 0x3a, 0x67, 0x73, 0x75, 0x62, 0x28, 0x22, 0x25, 0x2e, 0x22, 0x2c, 0x20, 0x22, 0x5f, 0x22, 0x29, - 0x20, 0x2d, 0x2d, 0x20, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x20, 0x72, 0x65, 0x6d, 0x61, 0x69, 0x6e, - 0x69, 0x6e, 0x67, 0x20, 0x22, 0x2e, 0x22, 0x27, 0x73, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x22, 0x5f, 0x22, 0x0a, - 0x09, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x20, 0x3d, 0x20, 0x23, 0x69, 0x64, 0x65, 0x6e, 0x74, - 0x69, 0x74, 0x79, 0x20, 0x3e, 0x20, 0x30, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, - 0x74, 0x79, 0x20, 0x6f, 0x72, 0x20, 0x22, 0x6c, 0x6f, 0x76, 0x65, 0x67, 0x61, 0x6d, 0x65, 0x22, 0x0a, - 0x0a, - 0x09, 0x2d, 0x2d, 0x20, 0x57, 0x68, 0x65, 0x6e, 0x20, 0x63, 0x6f, 0x6e, 0x66, 0x2e, 0x6c, 0x75, 0x61, 0x20, - 0x69, 0x73, 0x20, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x6c, 0x79, 0x20, 0x6c, 0x6f, 0x61, 0x64, 0x65, - 0x64, 0x2c, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6d, 0x61, 0x69, 0x6e, 0x20, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x20, 0x73, 0x68, 0x6f, 0x75, 0x6c, 0x64, 0x20, 0x62, 0x65, 0x20, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x65, 0x64, 0x0a, - 0x09, 0x2d, 0x2d, 0x20, 0x62, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x61, 0x76, - 0x65, 0x20, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x20, 0x28, 0x74, 0x68, 0x65, 0x20, 0x69, - 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x20, 0x73, 0x68, 0x6f, 0x75, 0x6c, 0x64, 0x20, 0x62, 0x65, 0x20, - 0x61, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x64, 0x2e, 0x29, 0x0a, - 0x09, 0x70, 0x63, 0x61, 0x6c, 0x6c, 0x28, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x79, - 0x73, 0x74, 0x65, 0x6d, 0x2e, 0x73, 0x65, 0x74, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2c, 0x20, - 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2c, 0x20, 0x74, 0x72, 0x75, 0x65, 0x29, 0x0a, - 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, 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, - 0x0a, - 0x09, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x63, 0x61, 0x6e, 0x5f, 0x68, 0x61, 0x73, 0x5f, 0x67, 0x61, - 0x6d, 0x65, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, - 0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6e, 0x6f, 0x67, 0x61, 0x6d, 0x65, 0x20, 0x3d, 0x20, 0x72, - 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x28, 0x22, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x6e, 0x6f, 0x67, 0x61, 0x6d, - 0x65, 0x22, 0x29, 0x0a, - 0x09, 0x09, 0x6e, 0x6f, 0x67, 0x61, 0x6d, 0x65, 0x28, 0x29, 0x0a, - 0x09, 0x65, 0x6e, 0x64, 0x0a, - 0x65, 0x6e, 0x64, 0x0a, - 0x0a, - 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x69, 0x6e, 0x69, 0x74, - 0x28, 0x29, 0x0a, - 0x0a, - 0x09, 0x2d, 0x2d, 0x20, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x20, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, - 0x20, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x73, 0x65, 0x74, - 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x0a, - 0x09, 0x2d, 0x2d, 0x20, 0x4e, 0x4f, 0x54, 0x45, 0x3a, 0x20, 0x41, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x61, - 0x20, 0x6e, 0x65, 0x77, 0x20, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x68, 0x65, - 0x20, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x0a, - 0x09, 0x2d, 0x2d, 0x20, 0x77, 0x69, 0x6c, 0x6c, 0x20, 0x4e, 0x4f, 0x54, 0x20, 0x6d, 0x61, 0x6b, 0x65, 0x20, - 0x69, 0x74, 0x20, 0x6c, 0x6f, 0x61, 0x64, 0x2c, 0x20, 0x73, 0x65, 0x65, 0x20, 0x62, 0x65, 0x6c, 0x6f, 0x77, - 0x2e, 0x0a, - 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x63, 0x20, 0x3d, 0x20, 0x7b, 0x0a, - 0x09, 0x09, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x20, 0x3d, 0x20, 0x22, 0x55, 0x6e, 0x74, 0x69, 0x74, 0x6c, 0x65, - 0x64, 0x22, 0x2c, 0x0a, - 0x09, 0x09, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x5f, - 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x2c, 0x0a, - 0x09, 0x09, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x20, 0x3d, 0x20, 0x7b, 0x0a, - 0x09, 0x09, 0x09, 0x77, 0x69, 0x64, 0x74, 0x68, 0x20, 0x3d, 0x20, 0x38, 0x30, 0x30, 0x2c, 0x0a, - 0x09, 0x09, 0x09, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x20, 0x3d, 0x20, 0x36, 0x30, 0x30, 0x2c, 0x0a, - 0x09, 0x09, 0x09, 0x78, 0x20, 0x3d, 0x20, 0x6e, 0x69, 0x6c, 0x2c, 0x0a, - 0x09, 0x09, 0x09, 0x79, 0x20, 0x3d, 0x20, 0x6e, 0x69, 0x6c, 0x2c, 0x0a, - 0x09, 0x09, 0x09, 0x6d, 0x69, 0x6e, 0x77, 0x69, 0x64, 0x74, 0x68, 0x20, 0x3d, 0x20, 0x31, 0x2c, 0x0a, - 0x09, 0x09, 0x09, 0x6d, 0x69, 0x6e, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x20, 0x3d, 0x20, 0x31, 0x2c, 0x0a, - 0x09, 0x09, 0x09, 0x66, 0x75, 0x6c, 0x6c, 0x73, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x20, 0x3d, 0x20, 0x66, 0x61, - 0x6c, 0x73, 0x65, 0x2c, 0x0a, - 0x09, 0x09, 0x09, 0x66, 0x75, 0x6c, 0x6c, 0x73, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x74, 0x79, 0x70, 0x65, 0x20, - 0x3d, 0x20, 0x22, 0x64, 0x65, 0x73, 0x6b, 0x74, 0x6f, 0x70, 0x22, 0x2c, 0x0a, - 0x09, 0x09, 0x09, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x20, 0x3d, 0x20, 0x31, 0x2c, 0x0a, - 0x09, 0x09, 0x09, 0x76, 0x73, 0x79, 0x6e, 0x63, 0x20, 0x3d, 0x20, 0x31, 0x2c, 0x0a, - 0x09, 0x09, 0x09, 0x6d, 0x73, 0x61, 0x61, 0x20, 0x3d, 0x20, 0x30, 0x2c, 0x0a, - 0x09, 0x09, 0x09, 0x62, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x6c, 0x65, 0x73, 0x73, 0x20, 0x3d, 0x20, 0x66, 0x61, - 0x6c, 0x73, 0x65, 0x2c, 0x0a, - 0x09, 0x09, 0x09, 0x72, 0x65, 0x73, 0x69, 0x7a, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x3d, 0x20, 0x66, 0x61, 0x6c, - 0x73, 0x65, 0x2c, 0x0a, - 0x09, 0x09, 0x09, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x65, 0x64, 0x20, 0x3d, 0x20, 0x74, 0x72, 0x75, 0x65, - 0x2c, 0x0a, - 0x09, 0x09, 0x09, 0x68, 0x69, 0x67, 0x68, 0x64, 0x70, 0x69, 0x20, 0x3d, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, - 0x2c, 0x0a, - 0x09, 0x09, 0x09, 0x75, 0x73, 0x65, 0x64, 0x70, 0x69, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x20, 0x3d, 0x20, 0x74, - 0x72, 0x75, 0x65, 0x2c, 0x0a, - 0x09, 0x09, 0x7d, 0x2c, 0x0a, - 0x09, 0x09, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x20, 0x3d, 0x20, 0x7b, 0x0a, - 0x09, 0x09, 0x09, 0x64, 0x61, 0x74, 0x61, 0x20, 0x3d, 0x20, 0x74, 0x72, 0x75, 0x65, 0x2c, 0x0a, - 0x09, 0x09, 0x09, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x20, 0x3d, 0x20, 0x74, 0x72, 0x75, 0x65, 0x2c, 0x0a, - 0x09, 0x09, 0x09, 0x6b, 0x65, 0x79, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x20, 0x3d, 0x20, 0x74, 0x72, 0x75, 0x65, - 0x2c, 0x0a, - 0x09, 0x09, 0x09, 0x6d, 0x6f, 0x75, 0x73, 0x65, 0x20, 0x3d, 0x20, 0x74, 0x72, 0x75, 0x65, 0x2c, 0x0a, - 0x09, 0x09, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x72, 0x20, 0x3d, 0x20, 0x74, 0x72, 0x75, 0x65, 0x2c, 0x0a, - 0x09, 0x09, 0x09, 0x6a, 0x6f, 0x79, 0x73, 0x74, 0x69, 0x63, 0x6b, 0x20, 0x3d, 0x20, 0x74, 0x72, 0x75, 0x65, - 0x2c, 0x0a, - 0x09, 0x09, 0x09, 0x74, 0x6f, 0x75, 0x63, 0x68, 0x20, 0x3d, 0x20, 0x74, 0x72, 0x75, 0x65, 0x2c, 0x0a, - 0x09, 0x09, 0x09, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x20, 0x3d, 0x20, 0x74, 0x72, 0x75, 0x65, 0x2c, 0x0a, - 0x09, 0x09, 0x09, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x20, 0x3d, 0x20, 0x74, 0x72, 0x75, 0x65, - 0x2c, 0x0a, - 0x09, 0x09, 0x09, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x20, 0x3d, 0x20, 0x74, 0x72, 0x75, 0x65, 0x2c, 0x0a, - 0x09, 0x09, 0x09, 0x6d, 0x61, 0x74, 0x68, 0x20, 0x3d, 0x20, 0x74, 0x72, 0x75, 0x65, 0x2c, 0x0a, - 0x09, 0x09, 0x09, 0x70, 0x68, 0x79, 0x73, 0x69, 0x63, 0x73, 0x20, 0x3d, 0x20, 0x74, 0x72, 0x75, 0x65, 0x2c, 0x0a, - 0x09, 0x09, 0x09, 0x73, 0x6f, 0x75, 0x6e, 0x64, 0x20, 0x3d, 0x20, 0x74, 0x72, 0x75, 0x65, 0x2c, 0x0a, - 0x09, 0x09, 0x09, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x20, 0x3d, 0x20, 0x74, 0x72, 0x75, 0x65, 0x2c, 0x0a, - 0x09, 0x09, 0x09, 0x66, 0x6f, 0x6e, 0x74, 0x20, 0x3d, 0x20, 0x74, 0x72, 0x75, 0x65, 0x2c, 0x0a, - 0x09, 0x09, 0x09, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x20, 0x3d, 0x20, 0x74, 0x72, 0x75, 0x65, 0x2c, 0x0a, - 0x09, 0x09, 0x09, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x20, 0x3d, 0x20, 0x74, 0x72, 0x75, 0x65, 0x2c, 0x0a, - 0x09, 0x09, 0x09, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x20, 0x3d, 0x20, 0x74, 0x72, 0x75, 0x65, 0x2c, 0x0a, - 0x09, 0x09, 0x7d, 0x2c, 0x0a, - 0x09, 0x09, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x20, 0x3d, 0x20, 0x7b, 0x0a, - 0x09, 0x09, 0x09, 0x6d, 0x69, 0x78, 0x77, 0x69, 0x74, 0x68, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x20, 0x3d, - 0x20, 0x74, 0x72, 0x75, 0x65, 0x2c, 0x20, 0x2d, 0x2d, 0x20, 0x4f, 0x6e, 0x6c, 0x79, 0x20, 0x72, 0x65, 0x6c, - 0x65, 0x76, 0x61, 0x6e, 0x74, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x41, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x20, - 0x2f, 0x20, 0x69, 0x4f, 0x53, 0x2e, 0x0a, - 0x09, 0x09, 0x09, 0x6d, 0x69, 0x63, 0x20, 0x3d, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x2c, 0x20, 0x2d, 0x2d, - 0x20, 0x4f, 0x6e, 0x6c, 0x79, 0x20, 0x72, 0x65, 0x6c, 0x65, 0x76, 0x61, 0x6e, 0x74, 0x20, 0x66, 0x6f, 0x72, - 0x20, 0x41, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2e, 0x0a, - 0x09, 0x09, 0x7d, 0x2c, 0x0a, - 0x09, 0x09, 0x63, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, 0x20, 0x3d, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x2c, - 0x20, 0x2d, 0x2d, 0x20, 0x4f, 0x6e, 0x6c, 0x79, 0x20, 0x72, 0x65, 0x6c, 0x65, 0x76, 0x61, 0x6e, 0x74, 0x20, - 0x66, 0x6f, 0x72, 0x20, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x73, 0x2e, 0x0a, - 0x09, 0x09, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x20, 0x3d, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, - 0x2c, 0x0a, - 0x09, 0x09, 0x61, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x20, 0x3d, - 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x2c, 0x0a, - 0x09, 0x09, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x20, - 0x3d, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x2c, 0x20, 0x2d, 0x2d, 0x20, 0x4f, 0x6e, 0x6c, 0x79, 0x20, 0x72, - 0x65, 0x6c, 0x65, 0x76, 0x61, 0x6e, 0x74, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x41, 0x6e, 0x64, 0x72, 0x6f, 0x69, - 0x64, 0x2e, 0x0a, - 0x09, 0x09, 0x61, 0x63, 0x63, 0x65, 0x6c, 0x65, 0x72, 0x6f, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x6a, 0x6f, 0x79, - 0x73, 0x74, 0x69, 0x63, 0x6b, 0x20, 0x3d, 0x20, 0x74, 0x72, 0x75, 0x65, 0x2c, 0x20, 0x2d, 0x2d, 0x20, 0x4f, - 0x6e, 0x6c, 0x79, 0x20, 0x72, 0x65, 0x6c, 0x65, 0x76, 0x61, 0x6e, 0x74, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x41, - 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x20, 0x2f, 0x20, 0x69, 0x4f, 0x53, 0x2e, 0x0a, - 0x09, 0x09, 0x67, 0x61, 0x6d, 0x6d, 0x61, 0x63, 0x6f, 0x72, 0x72, 0x65, 0x63, 0x74, 0x20, 0x3d, 0x20, 0x66, - 0x61, 0x6c, 0x73, 0x65, 0x2c, 0x0a, - 0x09, 0x7d, 0x0a, - 0x0a, - 0x09, 0x2d, 0x2d, 0x20, 0x43, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, 0x20, 0x68, 0x61, 0x63, 0x6b, 0x2c, 0x20, - 0x70, 0x61, 0x72, 0x74, 0x20, 0x31, 0x2e, 0x0a, - 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6f, 0x70, 0x65, 0x6e, 0x65, 0x64, 0x63, 0x6f, 0x6e, 0x73, 0x6f, - 0x6c, 0x65, 0x20, 0x3d, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x0a, - 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x61, 0x72, 0x67, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, - 0x6e, 0x73, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, 0x2e, 0x73, 0x65, 0x74, 0x20, 0x61, 0x6e, 0x64, - 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x43, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, - 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, - 0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x43, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, - 0x65, 0x28, 0x29, 0x0a, - 0x09, 0x09, 0x6f, 0x70, 0x65, 0x6e, 0x65, 0x64, 0x63, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, 0x20, 0x3d, 0x20, - 0x74, 0x72, 0x75, 0x65, 0x0a, - 0x09, 0x65, 0x6e, 0x64, 0x0a, - 0x0a, - 0x09, 0x2d, 0x2d, 0x20, 0x49, 0x66, 0x20, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x20, 0x66, 0x69, 0x6c, 0x65, - 0x20, 0x65, 0x78, 0x69, 0x73, 0x74, 0x73, 0x2c, 0x20, 0x6c, 0x6f, 0x61, 0x64, 0x20, 0x69, 0x74, 0x20, 0x61, - 0x6e, 0x64, 0x20, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x20, 0x69, 0x74, 0x20, 0x74, 0x6f, 0x20, 0x75, 0x70, 0x64, - 0x61, 0x74, 0x65, 0x20, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x20, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x2e, 0x0a, - 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x63, 0x6f, 0x6e, 0x66, 0x6f, 0x6b, 0x2c, 0x20, 0x63, 0x6f, 0x6e, - 0x66, 0x65, 0x72, 0x72, 0x0a, - 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, 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, - 0x09, 0x65, 0x6e, 0x64, 0x0a, - 0x0a, - 0x09, 0x2d, 0x2d, 0x20, 0x59, 0x65, 0x73, 0x2c, 0x20, 0x63, 0x6f, 0x6e, 0x66, 0x2e, 0x6c, 0x75, 0x61, 0x20, - 0x6d, 0x69, 0x67, 0x68, 0x74, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x65, 0x78, 0x69, 0x73, 0x74, 0x2c, 0x20, 0x62, - 0x75, 0x74, 0x20, 0x74, 0x68, 0x65, 0x72, 0x65, 0x20, 0x61, 0x72, 0x65, 0x20, 0x6f, 0x74, 0x68, 0x65, 0x72, - 0x20, 0x77, 0x61, 0x79, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x6d, 0x61, 0x6b, 0x69, 0x6e, 0x67, 0x0a, - 0x09, 0x2d, 0x2d, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x20, 0x61, 0x70, 0x70, 0x65, - 0x61, 0x72, 0x2c, 0x20, 0x73, 0x6f, 0x20, 0x77, 0x65, 0x20, 0x73, 0x68, 0x6f, 0x75, 0x6c, 0x64, 0x20, 0x63, - 0x68, 0x65, 0x63, 0x6b, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x69, 0x74, 0x20, 0x61, 0x6e, 0x79, 0x77, 0x61, 0x79, - 0x2e, 0x0a, - 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 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, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x2c, - 0x20, 0x63, 0x29, 0x0a, - 0x09, 0x09, 0x2d, 0x2d, 0x20, 0x49, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x20, - 0x65, 0x72, 0x72, 0x6f, 0x72, 0x73, 0x2c, 0x20, 0x77, 0x65, 0x27, 0x6c, 0x6c, 0x20, 0x74, 0x72, 0x69, 0x67, - 0x67, 0x65, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x20, 0x61, 0x66, 0x74, 0x65, - 0x72, 0x20, 0x6c, 0x6f, 0x61, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x20, - 0x73, 0x6f, 0x0a, - 0x09, 0x09, 0x2d, 0x2d, 0x20, 0x74, 0x68, 0x65, 0x20, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x20, 0x6d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x20, 0x63, 0x61, 0x6e, 0x20, 0x62, 0x65, 0x20, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, - 0x79, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x0a, - 0x09, 0x65, 0x6e, 0x64, 0x0a, - 0x0a, - 0x09, 0x2d, 0x2d, 0x20, 0x43, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, 0x20, 0x68, 0x61, 0x63, 0x6b, 0x2c, 0x20, - 0x70, 0x61, 0x72, 0x74, 0x20, 0x32, 0x2e, 0x0a, - 0x09, 0x69, 0x66, 0x20, 0x63, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, 0x20, 0x61, 0x6e, 0x64, 0x20, - 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x43, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, 0x20, - 0x61, 0x6e, 0x64, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x6f, 0x70, 0x65, 0x6e, 0x65, 0x64, 0x63, 0x6f, 0x6e, 0x73, - 0x6f, 0x6c, 0x65, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, - 0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x43, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, - 0x65, 0x28, 0x29, 0x0a, - 0x09, 0x65, 0x6e, 0x64, 0x0a, - 0x0a, - 0x09, 0x2d, 0x2d, 0x20, 0x48, 0x61, 0x63, 0x6b, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x64, 0x69, 0x73, 0x61, 0x62, - 0x6c, 0x69, 0x6e, 0x67, 0x20, 0x61, 0x63, 0x63, 0x65, 0x6c, 0x65, 0x72, 0x6f, 0x6d, 0x65, 0x74, 0x65, 0x72, - 0x2d, 0x61, 0x73, 0x2d, 0x6a, 0x6f, 0x79, 0x73, 0x74, 0x69, 0x63, 0x6b, 0x20, 0x6f, 0x6e, 0x20, 0x41, 0x6e, - 0x64, 0x72, 0x6f, 0x69, 0x64, 0x20, 0x2f, 0x20, 0x69, 0x4f, 0x53, 0x2e, 0x0a, - 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x5f, 0x73, 0x65, 0x74, 0x41, 0x63, 0x63, 0x65, 0x6c, - 0x65, 0x72, 0x6f, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x41, 0x73, 0x4a, 0x6f, 0x79, 0x73, 0x74, 0x69, 0x63, 0x6b, - 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, - 0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x5f, 0x73, 0x65, 0x74, 0x41, 0x63, 0x63, 0x65, 0x6c, 0x65, 0x72, - 0x6f, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x41, 0x73, 0x4a, 0x6f, 0x79, 0x73, 0x74, 0x69, 0x63, 0x6b, 0x28, 0x63, - 0x2e, 0x61, 0x63, 0x63, 0x65, 0x6c, 0x65, 0x72, 0x6f, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x6a, 0x6f, 0x79, 0x73, - 0x74, 0x69, 0x63, 0x6b, 0x29, 0x0a, - 0x09, 0x65, 0x6e, 0x64, 0x0a, - 0x0a, - 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x5f, 0x73, 0x65, 0x74, 0x47, 0x61, 0x6d, 0x6d, 0x61, - 0x43, 0x6f, 0x72, 0x72, 0x65, 0x63, 0x74, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, - 0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x5f, 0x73, 0x65, 0x74, 0x47, 0x61, 0x6d, 0x6d, 0x61, 0x43, 0x6f, - 0x72, 0x72, 0x65, 0x63, 0x74, 0x28, 0x63, 0x2e, 0x67, 0x61, 0x6d, 0x6d, 0x61, 0x63, 0x6f, 0x72, 0x72, 0x65, - 0x63, 0x74, 0x29, 0x0a, - 0x09, 0x65, 0x6e, 0x64, 0x0a, - 0x0a, - 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x5f, 0x73, 0x65, 0x74, 0x41, 0x75, 0x64, 0x69, 0x6f, - 0x4d, 0x69, 0x78, 0x57, 0x69, 0x74, 0x68, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, - 0x09, 0x09, 0x69, 0x66, 0x20, 0x63, 0x2e, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x63, - 0x2e, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2e, 0x6d, 0x69, 0x78, 0x77, 0x69, 0x74, 0x68, 0x73, 0x79, 0x73, 0x74, - 0x65, 0x6d, 0x20, 0x7e, 0x3d, 0x20, 0x6e, 0x69, 0x6c, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, - 0x09, 0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x5f, 0x73, 0x65, 0x74, 0x41, 0x75, 0x64, 0x69, 0x6f, 0x4d, - 0x69, 0x78, 0x57, 0x69, 0x74, 0x68, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x28, 0x63, 0x2e, 0x61, 0x75, 0x64, - 0x69, 0x6f, 0x2e, 0x6d, 0x69, 0x78, 0x77, 0x69, 0x74, 0x68, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x29, 0x0a, - 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, - 0x09, 0x65, 0x6e, 0x64, 0x0a, - 0x0a, - 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, - 0x65, 0x63, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, - 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, - 0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x63, - 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x28, 0x63, - 0x2e, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x63, 0x2e, 0x61, 0x75, 0x64, 0x69, 0x6f, - 0x2e, 0x6d, 0x69, 0x63, 0x29, 0x0a, - 0x09, 0x65, 0x6e, 0x64, 0x0a, - 0x0a, - 0x09, 0x2d, 0x2d, 0x20, 0x47, 0x65, 0x74, 0x73, 0x20, 0x64, 0x65, 0x73, 0x69, 0x72, 0x65, 0x64, 0x20, 0x6d, - 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x2e, 0x0a, - 0x09, 0x66, 0x6f, 0x72, 0x20, 0x6b, 0x2c, 0x76, 0x20, 0x69, 0x6e, 0x20, 0x69, 0x70, 0x61, 0x69, 0x72, 0x73, - 0x7b, 0x0a, - 0x09, 0x09, 0x22, 0x64, 0x61, 0x74, 0x61, 0x22, 0x2c, 0x0a, - 0x09, 0x09, 0x22, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x22, 0x2c, 0x0a, - 0x09, 0x09, 0x22, 0x74, 0x69, 0x6d, 0x65, 0x72, 0x22, 0x2c, 0x0a, - 0x09, 0x09, 0x22, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x22, 0x2c, 0x0a, - 0x09, 0x09, 0x22, 0x6b, 0x65, 0x79, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x22, 0x2c, 0x0a, - 0x09, 0x09, 0x22, 0x6a, 0x6f, 0x79, 0x73, 0x74, 0x69, 0x63, 0x6b, 0x22, 0x2c, 0x0a, - 0x09, 0x09, 0x22, 0x6d, 0x6f, 0x75, 0x73, 0x65, 0x22, 0x2c, 0x0a, - 0x09, 0x09, 0x22, 0x74, 0x6f, 0x75, 0x63, 0x68, 0x22, 0x2c, 0x0a, - 0x09, 0x09, 0x22, 0x73, 0x6f, 0x75, 0x6e, 0x64, 0x22, 0x2c, 0x0a, - 0x09, 0x09, 0x22, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x22, 0x2c, 0x0a, - 0x09, 0x09, 0x22, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x22, 0x2c, 0x0a, - 0x09, 0x09, 0x22, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x22, 0x2c, 0x0a, - 0x09, 0x09, 0x22, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x22, 0x2c, 0x0a, - 0x09, 0x09, 0x22, 0x66, 0x6f, 0x6e, 0x74, 0x22, 0x2c, 0x0a, - 0x09, 0x09, 0x22, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x22, 0x2c, 0x0a, - 0x09, 0x09, 0x22, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x22, 0x2c, 0x0a, - 0x09, 0x09, 0x22, 0x6d, 0x61, 0x74, 0x68, 0x22, 0x2c, 0x0a, - 0x09, 0x09, 0x22, 0x70, 0x68, 0x79, 0x73, 0x69, 0x63, 0x73, 0x22, 0x2c, 0x0a, - 0x09, 0x7d, 0x20, 0x64, 0x6f, 0x0a, - 0x09, 0x09, 0x69, 0x66, 0x20, 0x63, 0x2e, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x5b, 0x76, 0x5d, 0x20, - 0x74, 0x68, 0x65, 0x6e, 0x0a, - 0x09, 0x09, 0x09, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x28, 0x22, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x22, - 0x20, 0x2e, 0x2e, 0x20, 0x76, 0x29, 0x0a, - 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, - 0x09, 0x65, 0x6e, 0x64, 0x0a, - 0x0a, - 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x20, 0x74, 0x68, 0x65, - 0x6e, 0x0a, - 0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x68, 0x61, 0x6e, 0x64, 0x6c, - 0x65, 0x72, 0x73, 0x28, 0x29, 0x0a, - 0x09, 0x65, 0x6e, 0x64, 0x0a, - 0x0a, - 0x09, 0x2d, 0x2d, 0x20, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x20, 0x74, 0x68, 0x65, 0x20, 0x76, 0x65, 0x72, 0x73, - 0x69, 0x6f, 0x6e, 0x0a, - 0x09, 0x63, 0x2e, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x3d, 0x20, 0x74, 0x6f, 0x73, 0x74, 0x72, - 0x69, 0x6e, 0x67, 0x28, 0x63, 0x2e, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x29, 0x0a, - 0x09, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x69, 0x73, 0x56, 0x65, 0x72, - 0x73, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x74, 0x69, 0x62, 0x6c, 0x65, 0x28, 0x63, 0x2e, 0x76, - 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x29, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, - 0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6d, 0x61, 0x6a, 0x6f, 0x72, 0x2c, 0x20, 0x6d, 0x69, 0x6e, - 0x6f, 0x72, 0x2c, 0x20, 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x3d, 0x20, 0x63, 0x2e, 0x76, - 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x3a, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x28, 0x22, 0x5e, 0x28, 0x25, 0x64, - 0x2b, 0x29, 0x25, 0x2e, 0x28, 0x25, 0x64, 0x2b, 0x29, 0x25, 0x2e, 0x28, 0x25, 0x64, 0x2b, 0x29, 0x24, 0x22, - 0x29, 0x0a, - 0x09, 0x09, 0x69, 0x66, 0x20, 0x28, 0x6e, 0x6f, 0x74, 0x20, 0x6d, 0x61, 0x6a, 0x6f, 0x72, 0x20, 0x6f, 0x72, - 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x6d, 0x69, 0x6e, 0x6f, 0x72, 0x20, 0x6f, 0x72, 0x20, 0x6e, 0x6f, 0x74, 0x20, - 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x29, 0x20, 0x6f, 0x72, 0x20, 0x28, 0x6d, 0x61, 0x6a, 0x6f, - 0x72, 0x20, 0x7e, 0x3d, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, - 0x5f, 0x6d, 0x61, 0x6a, 0x6f, 0x72, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x6d, 0x69, 0x6e, 0x6f, 0x72, 0x20, 0x7e, - 0x3d, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x69, - 0x6e, 0x6f, 0x72, 0x29, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, - 0x09, 0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6d, 0x73, 0x67, 0x20, 0x3d, 0x20, 0x28, 0x22, 0x54, - 0x68, 0x69, 0x73, 0x20, 0x67, 0x61, 0x6d, 0x65, 0x20, 0x69, 0x6e, 0x64, 0x69, 0x63, 0x61, 0x74, 0x65, 0x73, - 0x20, 0x69, 0x74, 0x20, 0x77, 0x61, 0x73, 0x20, 0x6d, 0x61, 0x64, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x76, - 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x27, 0x25, 0x73, 0x27, 0x20, 0x6f, 0x66, 0x20, 0x4c, 0x4f, 0x56, - 0x45, 0x2e, 0x5c, 0x6e, 0x22, 0x2e, 0x2e, 0x0a, - 0x09, 0x09, 0x09, 0x09, 0x22, 0x49, 0x74, 0x20, 0x6d, 0x61, 0x79, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x62, 0x65, - 0x20, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x74, 0x69, 0x62, 0x6c, 0x65, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x74, - 0x68, 0x65, 0x20, 0x72, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, - 0x20, 0x28, 0x25, 0x73, 0x29, 0x2e, 0x22, 0x29, 0x3a, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x28, 0x63, 0x2e, - 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x2c, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x5f, 0x76, 0x65, 0x72, - 0x73, 0x69, 0x6f, 0x6e, 0x29, 0x0a, - 0x0a, - 0x09, 0x09, 0x09, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x28, 0x6d, 0x73, 0x67, 0x29, 0x0a, - 0x0a, - 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x20, - 0x74, 0x68, 0x65, 0x6e, 0x0a, - 0x09, 0x09, 0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x73, 0x68, - 0x6f, 0x77, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x42, 0x6f, 0x78, 0x28, 0x22, 0x43, 0x6f, 0x6d, 0x70, - 0x61, 0x74, 0x69, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x20, 0x57, 0x61, 0x72, 0x6e, 0x69, 0x6e, 0x67, 0x22, - 0x2c, 0x20, 0x6d, 0x73, 0x67, 0x2c, 0x20, 0x22, 0x77, 0x61, 0x72, 0x6e, 0x69, 0x6e, 0x67, 0x22, 0x29, 0x0a, - 0x09, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, - 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, - 0x09, 0x65, 0x6e, 0x64, 0x0a, - 0x0a, - 0x09, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x63, 0x6f, 0x6e, 0x66, 0x6f, 0x6b, 0x20, 0x61, 0x6e, 0x64, - 0x20, 0x63, 0x6f, 0x6e, 0x66, 0x65, 0x72, 0x72, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, - 0x09, 0x09, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x28, 0x63, 0x6f, 0x6e, 0x66, 0x65, 0x72, 0x72, 0x29, 0x0a, - 0x09, 0x65, 0x6e, 0x64, 0x0a, - 0x0a, - 0x09, 0x2d, 0x2d, 0x20, 0x53, 0x65, 0x74, 0x75, 0x70, 0x20, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x20, 0x68, - 0x65, 0x72, 0x65, 0x2e, 0x0a, - 0x09, 0x69, 0x66, 0x20, 0x63, 0x2e, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x63, - 0x2e, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x2e, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x20, 0x74, 0x68, - 0x65, 0x6e, 0x0a, - 0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x73, 0x65, 0x74, 0x54, - 0x69, 0x74, 0x6c, 0x65, 0x28, 0x63, 0x2e, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x74, 0x69, 0x74, 0x6c, - 0x65, 0x20, 0x6f, 0x72, 0x20, 0x63, 0x2e, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x29, 0x0a, - 0x09, 0x09, 0x61, 0x73, 0x73, 0x65, 0x72, 0x74, 0x28, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x77, 0x69, 0x6e, 0x64, - 0x6f, 0x77, 0x2e, 0x73, 0x65, 0x74, 0x4d, 0x6f, 0x64, 0x65, 0x28, 0x63, 0x2e, 0x77, 0x69, 0x6e, 0x64, 0x6f, - 0x77, 0x2e, 0x77, 0x69, 0x64, 0x74, 0x68, 0x2c, 0x20, 0x63, 0x2e, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, - 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x2c, 0x0a, - 0x09, 0x09, 0x7b, 0x0a, - 0x09, 0x09, 0x09, 0x66, 0x75, 0x6c, 0x6c, 0x73, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x20, 0x3d, 0x20, 0x63, 0x2e, - 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x66, 0x75, 0x6c, 0x6c, 0x73, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x2c, 0x0a, - 0x09, 0x09, 0x09, 0x66, 0x75, 0x6c, 0x6c, 0x73, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x74, 0x79, 0x70, 0x65, 0x20, - 0x3d, 0x20, 0x63, 0x2e, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x66, 0x75, 0x6c, 0x6c, 0x73, 0x63, 0x72, - 0x65, 0x65, 0x6e, 0x74, 0x79, 0x70, 0x65, 0x2c, 0x0a, - 0x09, 0x09, 0x09, 0x76, 0x73, 0x79, 0x6e, 0x63, 0x20, 0x3d, 0x20, 0x63, 0x2e, 0x77, 0x69, 0x6e, 0x64, 0x6f, - 0x77, 0x2e, 0x76, 0x73, 0x79, 0x6e, 0x63, 0x2c, 0x0a, - 0x09, 0x09, 0x09, 0x6d, 0x73, 0x61, 0x61, 0x20, 0x3d, 0x20, 0x63, 0x2e, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, - 0x2e, 0x6d, 0x73, 0x61, 0x61, 0x2c, 0x0a, - 0x09, 0x09, 0x09, 0x73, 0x74, 0x65, 0x6e, 0x63, 0x69, 0x6c, 0x20, 0x3d, 0x20, 0x63, 0x2e, 0x77, 0x69, 0x6e, - 0x64, 0x6f, 0x77, 0x2e, 0x73, 0x74, 0x65, 0x6e, 0x63, 0x69, 0x6c, 0x2c, 0x0a, - 0x09, 0x09, 0x09, 0x64, 0x65, 0x70, 0x74, 0x68, 0x20, 0x3d, 0x20, 0x63, 0x2e, 0x77, 0x69, 0x6e, 0x64, 0x6f, - 0x77, 0x2e, 0x64, 0x65, 0x70, 0x74, 0x68, 0x2c, 0x0a, - 0x09, 0x09, 0x09, 0x72, 0x65, 0x73, 0x69, 0x7a, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x3d, 0x20, 0x63, 0x2e, 0x77, - 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x72, 0x65, 0x73, 0x69, 0x7a, 0x61, 0x62, 0x6c, 0x65, 0x2c, 0x0a, - 0x09, 0x09, 0x09, 0x6d, 0x69, 0x6e, 0x77, 0x69, 0x64, 0x74, 0x68, 0x20, 0x3d, 0x20, 0x63, 0x2e, 0x77, 0x69, - 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x6d, 0x69, 0x6e, 0x77, 0x69, 0x64, 0x74, 0x68, 0x2c, 0x0a, - 0x09, 0x09, 0x09, 0x6d, 0x69, 0x6e, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x20, 0x3d, 0x20, 0x63, 0x2e, 0x77, - 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x6d, 0x69, 0x6e, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x2c, 0x0a, - 0x09, 0x09, 0x09, 0x62, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x6c, 0x65, 0x73, 0x73, 0x20, 0x3d, 0x20, 0x63, 0x2e, - 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x62, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x6c, 0x65, 0x73, 0x73, 0x2c, 0x0a, - 0x09, 0x09, 0x09, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x65, 0x64, 0x20, 0x3d, 0x20, 0x63, 0x2e, 0x77, 0x69, - 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x65, 0x64, 0x2c, 0x0a, - 0x09, 0x09, 0x09, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x20, 0x3d, 0x20, 0x63, 0x2e, 0x77, 0x69, 0x6e, - 0x64, 0x6f, 0x77, 0x2e, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x2c, 0x0a, - 0x09, 0x09, 0x09, 0x68, 0x69, 0x67, 0x68, 0x64, 0x70, 0x69, 0x20, 0x3d, 0x20, 0x63, 0x2e, 0x77, 0x69, 0x6e, - 0x64, 0x6f, 0x77, 0x2e, 0x68, 0x69, 0x67, 0x68, 0x64, 0x70, 0x69, 0x2c, 0x0a, - 0x09, 0x09, 0x09, 0x75, 0x73, 0x65, 0x64, 0x70, 0x69, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x20, 0x3d, 0x20, 0x63, - 0x2e, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x75, 0x73, 0x65, 0x64, 0x70, 0x69, 0x73, 0x63, 0x61, 0x6c, - 0x65, 0x2c, 0x0a, - 0x09, 0x09, 0x09, 0x78, 0x20, 0x3d, 0x20, 0x63, 0x2e, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x78, 0x2c, 0x0a, - 0x09, 0x09, 0x09, 0x79, 0x20, 0x3d, 0x20, 0x63, 0x2e, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x79, 0x2c, 0x0a, - 0x09, 0x09, 0x7d, 0x29, 0x2c, 0x20, 0x22, 0x43, 0x6f, 0x75, 0x6c, 0x64, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x73, - 0x65, 0x74, 0x20, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x20, 0x6d, 0x6f, 0x64, 0x65, 0x22, 0x29, 0x0a, - 0x09, 0x09, 0x69, 0x66, 0x20, 0x63, 0x2e, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x69, 0x63, 0x6f, 0x6e, - 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, - 0x09, 0x09, 0x09, 0x61, 0x73, 0x73, 0x65, 0x72, 0x74, 0x28, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x69, 0x6d, 0x61, - 0x67, 0x65, 0x2c, 0x20, 0x22, 0x49, 0x66, 0x20, 0x61, 0x6e, 0x20, 0x69, 0x63, 0x6f, 0x6e, 0x20, 0x69, 0x73, - 0x20, 0x73, 0x65, 0x74, 0x20, 0x69, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x2c, - 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62, - 0x65, 0x20, 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x64, 0x21, 0x22, 0x29, 0x0a, - 0x09, 0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x73, 0x65, 0x74, - 0x49, 0x63, 0x6f, 0x6e, 0x28, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2e, 0x6e, 0x65, - 0x77, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x44, 0x61, 0x74, 0x61, 0x28, 0x63, 0x2e, 0x77, 0x69, 0x6e, 0x64, 0x6f, - 0x77, 0x2e, 0x69, 0x63, 0x6f, 0x6e, 0x29, 0x29, 0x0a, - 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, - 0x09, 0x65, 0x6e, 0x64, 0x0a, - 0x0a, - 0x09, 0x2d, 0x2d, 0x20, 0x4f, 0x75, 0x72, 0x20, 0x66, 0x69, 0x72, 0x73, 0x74, 0x20, 0x74, 0x69, 0x6d, 0x65, - 0x73, 0x74, 0x65, 0x70, 0x2c, 0x20, 0x62, 0x65, 0x63, 0x61, 0x75, 0x73, 0x65, 0x20, 0x77, 0x69, 0x6e, 0x64, - 0x6f, 0x77, 0x20, 0x63, 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x63, 0x61, 0x6e, 0x20, 0x74, 0x61, - 0x6b, 0x65, 0x20, 0x73, 0x6f, 0x6d, 0x65, 0x20, 0x74, 0x69, 0x6d, 0x65, 0x0a, - 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x74, 0x69, 0x6d, 0x65, 0x72, 0x20, 0x74, 0x68, 0x65, - 0x6e, 0x0a, - 0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x74, 0x69, 0x6d, 0x65, 0x72, 0x2e, 0x73, 0x74, 0x65, 0x70, 0x28, - 0x29, 0x0a, - 0x09, 0x65, 0x6e, 0x64, 0x0a, - 0x0a, - 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x79, 0x73, 0x74, 0x65, - 0x6d, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, - 0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x2e, - 0x5f, 0x73, 0x65, 0x74, 0x41, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x53, 0x61, 0x76, 0x65, 0x45, 0x78, 0x74, - 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x28, 0x63, 0x2e, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x73, 0x74, - 0x6f, 0x72, 0x61, 0x67, 0x65, 0x29, 0x0a, - 0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x2e, - 0x73, 0x65, 0x74, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x28, 0x63, 0x2e, 0x69, 0x64, 0x65, 0x6e, - 0x74, 0x69, 0x74, 0x79, 0x20, 0x6f, 0x72, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73, - 0x79, 0x73, 0x74, 0x65, 0x6d, 0x2e, 0x67, 0x65, 0x74, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x28, - 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, 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, - 0x0a, - 0x09, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x5f, 0x67, 0x61, 0x6d, 0x65, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x74, - 0x68, 0x65, 0x6e, 0x0a, - 0x09, 0x09, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x28, 0x22, 0x4e, 0x6f, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x74, - 0x6f, 0x20, 0x72, 0x75, 0x6e, 0x5c, 0x6e, 0x59, 0x6f, 0x75, 0x72, 0x20, 0x67, 0x61, 0x6d, 0x65, 0x20, 0x6d, - 0x69, 0x67, 0x68, 0x74, 0x20, 0x62, 0x65, 0x20, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x64, 0x20, 0x69, - 0x6e, 0x63, 0x6f, 0x72, 0x72, 0x65, 0x63, 0x74, 0x6c, 0x79, 0x2e, 0x5c, 0x6e, 0x4d, 0x61, 0x6b, 0x65, 0x20, - 0x73, 0x75, 0x72, 0x65, 0x20, 0x6d, 0x61, 0x69, 0x6e, 0x2e, 0x6c, 0x75, 0x61, 0x20, 0x69, 0x73, 0x20, 0x61, - 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x6f, 0x70, 0x20, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x20, 0x6f, 0x66, - 0x20, 0x74, 0x68, 0x65, 0x20, 0x7a, 0x69, 0x70, 0x2e, 0x22, 0x29, 0x0a, - 0x09, 0x65, 0x6c, 0x73, 0x65, 0x69, 0x66, 0x20, 0x69, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x5f, 0x67, 0x61, - 0x6d, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, - 0x09, 0x09, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x28, 0x22, 0x43, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x20, 0x6c, 0x6f, - 0x61, 0x64, 0x20, 0x67, 0x61, 0x6d, 0x65, 0x20, 0x61, 0x74, 0x20, 0x70, 0x61, 0x74, 0x68, 0x20, 0x27, 0x22, - 0x20, 0x2e, 0x2e, 0x20, 0x69, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x5f, 0x67, 0x61, 0x6d, 0x65, 0x5f, 0x70, - 0x61, 0x74, 0x68, 0x20, 0x2e, 0x2e, 0x20, 0x22, 0x27, 0x2e, 0x5c, 0x6e, 0x4d, 0x61, 0x6b, 0x65, 0x20, 0x73, - 0x75, 0x72, 0x65, 0x20, 0x61, 0x20, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x20, 0x65, 0x78, 0x69, 0x73, 0x74, - 0x73, 0x20, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, 0x64, - 0x20, 0x70, 0x61, 0x74, 0x68, 0x2e, 0x22, 0x29, 0x0a, - 0x09, 0x65, 0x6e, 0x64, 0x0a, - 0x65, 0x6e, 0x64, 0x0a, - 0x0a, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, - 0x2d, 0x2d, 0x20, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x20, 0x63, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, - 0x6b, 0x73, 0x2e, 0x0a, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, - 0x0a, - 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x72, 0x75, 0x6e, 0x28, - 0x29, 0x0a, - 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x6c, 0x6f, 0x61, 0x64, 0x20, 0x74, 0x68, 0x65, 0x6e, - 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x6c, 0x6f, 0x61, 0x64, 0x28, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x61, 0x72, - 0x67, 0x2e, 0x70, 0x61, 0x72, 0x73, 0x65, 0x47, 0x61, 0x6d, 0x65, 0x41, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, - 0x74, 0x73, 0x28, 0x61, 0x72, 0x67, 0x29, 0x2c, 0x20, 0x61, 0x72, 0x67, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a, - 0x0a, - 0x09, 0x2d, 0x2d, 0x20, 0x57, 0x65, 0x20, 0x64, 0x6f, 0x6e, 0x27, 0x74, 0x20, 0x77, 0x61, 0x6e, 0x74, 0x20, - 0x74, 0x68, 0x65, 0x20, 0x66, 0x69, 0x72, 0x73, 0x74, 0x20, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x27, 0x73, 0x20, - 0x64, 0x74, 0x20, 0x74, 0x6f, 0x20, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x20, 0x74, 0x69, 0x6d, 0x65, - 0x20, 0x74, 0x61, 0x6b, 0x65, 0x6e, 0x20, 0x62, 0x79, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x6c, 0x6f, 0x61, - 0x64, 0x2e, 0x0a, - 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x74, 0x69, 0x6d, 0x65, 0x72, 0x20, 0x74, 0x68, 0x65, - 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x74, 0x69, 0x6d, 0x65, 0x72, 0x2e, 0x73, 0x74, 0x65, 0x70, 0x28, - 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a, - 0x0a, - 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x64, 0x74, 0x20, 0x3d, 0x20, 0x30, 0x0a, - 0x0a, - 0x09, 0x2d, 0x2d, 0x20, 0x4d, 0x61, 0x69, 0x6e, 0x20, 0x6c, 0x6f, 0x6f, 0x70, 0x20, 0x74, 0x69, 0x6d, 0x65, - 0x2e, 0x0a, - 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x0a, - 0x09, 0x09, 0x2d, 0x2d, 0x20, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x20, 0x65, 0x76, 0x65, 0x6e, 0x74, - 0x73, 0x2e, 0x0a, - 0x09, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x20, 0x74, 0x68, - 0x65, 0x6e, 0x0a, - 0x09, 0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x70, 0x75, 0x6d, 0x70, - 0x28, 0x29, 0x0a, - 0x09, 0x09, 0x09, 0x66, 0x6f, 0x72, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x20, 0x61, 0x2c, 0x62, 0x2c, 0x63, - 0x2c, 0x64, 0x2c, 0x65, 0x2c, 0x66, 0x20, 0x69, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x65, 0x76, 0x65, - 0x6e, 0x74, 0x2e, 0x70, 0x6f, 0x6c, 0x6c, 0x28, 0x29, 0x20, 0x64, 0x6f, 0x0a, - 0x09, 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x20, 0x3d, 0x3d, 0x20, 0x22, 0x71, 0x75, - 0x69, 0x74, 0x22, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x71, - 0x75, 0x69, 0x74, 0x20, 0x6f, 0x72, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x71, 0x75, - 0x69, 0x74, 0x28, 0x29, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x61, 0x20, 0x6f, 0x72, 0x20, - 0x30, 0x0a, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, - 0x09, 0x09, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, - 0x09, 0x09, 0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x73, 0x5b, - 0x6e, 0x61, 0x6d, 0x65, 0x5d, 0x28, 0x61, 0x2c, 0x62, 0x2c, 0x63, 0x2c, 0x64, 0x2c, 0x65, 0x2c, 0x66, 0x29, 0x0a, - 0x09, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, - 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, - 0x0a, - 0x09, 0x09, 0x2d, 0x2d, 0x20, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x20, 0x64, 0x74, 0x2c, 0x20, 0x61, 0x73, - 0x20, 0x77, 0x65, 0x27, 0x6c, 0x6c, 0x20, 0x62, 0x65, 0x20, 0x70, 0x61, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x20, - 0x69, 0x74, 0x20, 0x74, 0x6f, 0x20, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x0a, - 0x09, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x74, 0x69, 0x6d, 0x65, 0x72, 0x20, 0x74, 0x68, - 0x65, 0x6e, 0x20, 0x64, 0x74, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x74, 0x69, 0x6d, 0x65, 0x72, - 0x2e, 0x73, 0x74, 0x65, 0x70, 0x28, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a, - 0x0a, - 0x09, 0x09, 0x2d, 0x2d, 0x20, 0x43, 0x61, 0x6c, 0x6c, 0x20, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x20, 0x61, - 0x6e, 0x64, 0x20, 0x64, 0x72, 0x61, 0x77, 0x0a, - 0x09, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x20, 0x74, - 0x68, 0x65, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x28, 0x64, 0x74, - 0x29, 0x20, 0x65, 0x6e, 0x64, 0x20, 0x2d, 0x2d, 0x20, 0x77, 0x69, 0x6c, 0x6c, 0x20, 0x70, 0x61, 0x73, 0x73, - 0x20, 0x30, 0x20, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x74, 0x69, 0x6d, 0x65, 0x72, 0x20, 0x69, - 0x73, 0x20, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x0a, - 0x0a, - 0x09, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, - 0x20, 0x61, 0x6e, 0x64, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, - 0x2e, 0x69, 0x73, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x28, 0x29, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, - 0x09, 0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x6f, - 0x72, 0x69, 0x67, 0x69, 0x6e, 0x28, 0x29, 0x0a, - 0x09, 0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x63, - 0x6c, 0x65, 0x61, 0x72, 0x28, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, - 0x2e, 0x67, 0x65, 0x74, 0x42, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x43, 0x6f, 0x6c, 0x6f, - 0x72, 0x28, 0x29, 0x29, 0x0a, - 0x0a, - 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x64, 0x72, 0x61, 0x77, 0x20, 0x74, 0x68, - 0x65, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x64, 0x72, 0x61, 0x77, 0x28, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a, - 0x0a, - 0x09, 0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x70, - 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x28, 0x29, 0x0a, - 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, - 0x0a, - 0x09, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x74, 0x69, 0x6d, 0x65, 0x72, 0x20, 0x74, 0x68, - 0x65, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x74, 0x69, 0x6d, 0x65, 0x72, 0x2e, 0x73, 0x6c, 0x65, 0x65, - 0x70, 0x28, 0x30, 0x2e, 0x30, 0x30, 0x31, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a, - 0x09, 0x65, 0x6e, 0x64, 0x0a, - 0x0a, - 0x65, 0x6e, 0x64, 0x0a, - 0x0a, - 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x64, 0x65, 0x62, 0x75, 0x67, 0x2c, 0x20, 0x70, 0x72, 0x69, 0x6e, 0x74, - 0x2c, 0x20, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x20, 0x3d, 0x20, 0x64, 0x65, 0x62, 0x75, 0x67, 0x2c, 0x20, 0x70, - 0x72, 0x69, 0x6e, 0x74, 0x2c, 0x20, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x0a, - 0x0a, - 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x74, 0x68, 0x72, 0x65, - 0x61, 0x64, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x28, 0x74, 0x2c, 0x20, 0x65, 0x72, 0x72, 0x29, 0x0a, - 0x09, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x28, 0x22, 0x54, 0x68, 0x72, 0x65, 0x61, 0x64, 0x20, 0x65, 0x72, 0x72, - 0x6f, 0x72, 0x20, 0x28, 0x22, 0x2e, 0x2e, 0x74, 0x6f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x28, 0x74, 0x29, - 0x2e, 0x2e, 0x22, 0x29, 0x5c, 0x6e, 0x5c, 0x6e, 0x22, 0x2e, 0x2e, 0x65, 0x72, 0x72, 0x2c, 0x20, 0x30, 0x29, 0x0a, - 0x65, 0x6e, 0x64, 0x0a, - 0x0a, - 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x75, 0x74, 0x66, 0x38, 0x20, 0x3d, 0x20, 0x72, 0x65, 0x71, 0x75, 0x69, - 0x72, 0x65, 0x28, 0x22, 0x75, 0x74, 0x66, 0x38, 0x22, 0x29, 0x0a, - 0x0a, - 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x65, 0x72, 0x72, - 0x6f, 0x72, 0x5f, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x28, 0x6d, 0x73, 0x67, 0x2c, 0x20, 0x6c, 0x61, - 0x79, 0x65, 0x72, 0x29, 0x0a, - 0x09, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x28, 0x28, 0x64, 0x65, 0x62, 0x75, 0x67, 0x2e, 0x74, 0x72, 0x61, 0x63, - 0x65, 0x62, 0x61, 0x63, 0x6b, 0x28, 0x22, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x3a, 0x20, 0x22, 0x20, 0x2e, 0x2e, - 0x20, 0x74, 0x6f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x28, 0x6d, 0x73, 0x67, 0x29, 0x2c, 0x20, 0x31, 0x2b, - 0x28, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x20, 0x6f, 0x72, 0x20, 0x31, 0x29, 0x29, 0x3a, 0x67, 0x73, 0x75, 0x62, - 0x28, 0x22, 0x5c, 0x6e, 0x5b, 0x5e, 0x5c, 0x6e, 0x5d, 0x2b, 0x24, 0x22, 0x2c, 0x20, 0x22, 0x22, 0x29, 0x29, - 0x29, 0x0a, - 0x65, 0x6e, 0x64, 0x0a, - 0x0a, - 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x65, 0x72, 0x72, 0x68, - 0x61, 0x6e, 0x64, 0x28, 0x6d, 0x73, 0x67, 0x29, 0x0a, - 0x09, 0x6d, 0x73, 0x67, 0x20, 0x3d, 0x20, 0x74, 0x6f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x28, 0x6d, 0x73, - 0x67, 0x29, 0x0a, - 0x0a, - 0x09, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x28, 0x6d, 0x73, 0x67, - 0x2c, 0x20, 0x32, 0x29, 0x0a, - 0x0a, - 0x09, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x77, 0x69, 0x6e, 0x64, 0x6f, - 0x77, 0x20, 0x6f, 0x72, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, - 0x68, 0x69, 0x63, 0x73, 0x20, 0x6f, 0x72, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x65, - 0x76, 0x65, 0x6e, 0x74, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, - 0x09, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x0a, - 0x09, 0x65, 0x6e, 0x64, 0x0a, - 0x0a, - 0x09, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, - 0x69, 0x63, 0x73, 0x2e, 0x69, 0x73, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x28, 0x29, 0x20, 0x6f, 0x72, - 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x69, - 0x73, 0x4f, 0x70, 0x65, 0x6e, 0x28, 0x29, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, - 0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x2c, 0x20, 0x73, - 0x74, 0x61, 0x74, 0x75, 0x73, 0x20, 0x3d, 0x20, 0x70, 0x63, 0x61, 0x6c, 0x6c, 0x28, 0x6c, 0x6f, 0x76, 0x65, - 0x2e, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x73, 0x65, 0x74, 0x4d, 0x6f, 0x64, 0x65, 0x2c, 0x20, 0x38, - 0x30, 0x30, 0x2c, 0x20, 0x36, 0x30, 0x30, 0x29, 0x0a, - 0x09, 0x09, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x20, 0x6f, - 0x72, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, - 0x09, 0x09, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x0a, - 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, - 0x09, 0x65, 0x6e, 0x64, 0x0a, - 0x0a, - 0x09, 0x2d, 0x2d, 0x20, 0x52, 0x65, 0x73, 0x65, 0x74, 0x20, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x0a, - 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x6d, 0x6f, 0x75, 0x73, 0x65, 0x20, 0x74, 0x68, 0x65, - 0x6e, 0x0a, - 0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x6d, 0x6f, 0x75, 0x73, 0x65, 0x2e, 0x73, 0x65, 0x74, 0x56, 0x69, - 0x73, 0x69, 0x62, 0x6c, 0x65, 0x28, 0x74, 0x72, 0x75, 0x65, 0x29, 0x0a, - 0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x6d, 0x6f, 0x75, 0x73, 0x65, 0x2e, 0x73, 0x65, 0x74, 0x47, 0x72, - 0x61, 0x62, 0x62, 0x65, 0x64, 0x28, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x29, 0x0a, - 0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x6d, 0x6f, 0x75, 0x73, 0x65, 0x2e, 0x73, 0x65, 0x74, 0x52, 0x65, - 0x6c, 0x61, 0x74, 0x69, 0x76, 0x65, 0x4d, 0x6f, 0x64, 0x65, 0x28, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x29, 0x0a, - 0x09, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x6d, 0x6f, 0x75, 0x73, 0x65, 0x2e, 0x69, 0x73, - 0x43, 0x75, 0x72, 0x73, 0x6f, 0x72, 0x53, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x28, 0x29, 0x20, - 0x74, 0x68, 0x65, 0x6e, 0x0a, - 0x09, 0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x6d, 0x6f, 0x75, 0x73, 0x65, 0x2e, 0x73, 0x65, 0x74, 0x43, - 0x75, 0x72, 0x73, 0x6f, 0x72, 0x28, 0x29, 0x0a, - 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, - 0x09, 0x65, 0x6e, 0x64, 0x0a, - 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x6a, 0x6f, 0x79, 0x73, 0x74, 0x69, 0x63, 0x6b, 0x20, - 0x74, 0x68, 0x65, 0x6e, 0x0a, - 0x09, 0x09, 0x2d, 0x2d, 0x20, 0x53, 0x74, 0x6f, 0x70, 0x20, 0x61, 0x6c, 0x6c, 0x20, 0x6a, 0x6f, 0x79, 0x73, - 0x74, 0x69, 0x63, 0x6b, 0x20, 0x76, 0x69, 0x62, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x0a, - 0x09, 0x09, 0x66, 0x6f, 0x72, 0x20, 0x69, 0x2c, 0x76, 0x20, 0x69, 0x6e, 0x20, 0x69, 0x70, 0x61, 0x69, 0x72, - 0x73, 0x28, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x6a, 0x6f, 0x79, 0x73, 0x74, 0x69, 0x63, 0x6b, 0x2e, 0x67, 0x65, - 0x74, 0x4a, 0x6f, 0x79, 0x73, 0x74, 0x69, 0x63, 0x6b, 0x73, 0x28, 0x29, 0x29, 0x20, 0x64, 0x6f, 0x0a, - 0x09, 0x09, 0x09, 0x76, 0x3a, 0x73, 0x65, 0x74, 0x56, 0x69, 0x62, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x28, - 0x29, 0x0a, - 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, - 0x09, 0x65, 0x6e, 0x64, 0x0a, - 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x20, 0x74, 0x68, 0x65, - 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2e, 0x73, 0x74, 0x6f, 0x70, 0x28, - 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a, - 0x0a, - 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x72, 0x65, 0x73, - 0x65, 0x74, 0x28, 0x29, 0x0a, - 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x6f, 0x6e, 0x74, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x76, 0x65, - 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x73, 0x65, 0x74, 0x4e, 0x65, 0x77, 0x46, 0x6f, - 0x6e, 0x74, 0x28, 0x31, 0x34, 0x29, 0x0a, - 0x0a, - 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x73, 0x65, 0x74, - 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x28, 0x31, 0x2c, 0x20, 0x31, 0x2c, 0x20, 0x31, 0x29, 0x0a, - 0x0a, - 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x74, 0x72, 0x61, 0x63, 0x65, 0x20, 0x3d, 0x20, 0x64, 0x65, 0x62, - 0x75, 0x67, 0x2e, 0x74, 0x72, 0x61, 0x63, 0x65, 0x62, 0x61, 0x63, 0x6b, 0x28, 0x29, 0x0a, - 0x0a, - 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x6f, 0x72, 0x69, - 0x67, 0x69, 0x6e, 0x28, 0x29, 0x0a, - 0x0a, - 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x73, 0x61, 0x6e, 0x69, 0x74, 0x69, 0x7a, 0x65, 0x64, 0x6d, 0x73, - 0x67, 0x20, 0x3d, 0x20, 0x7b, 0x7d, 0x0a, - 0x09, 0x66, 0x6f, 0x72, 0x20, 0x63, 0x68, 0x61, 0x72, 0x20, 0x69, 0x6e, 0x20, 0x6d, 0x73, 0x67, 0x3a, 0x67, - 0x6d, 0x61, 0x74, 0x63, 0x68, 0x28, 0x75, 0x74, 0x66, 0x38, 0x2e, 0x63, 0x68, 0x61, 0x72, 0x70, 0x61, 0x74, - 0x74, 0x65, 0x72, 0x6e, 0x29, 0x20, 0x64, 0x6f, 0x0a, - 0x09, 0x09, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x2e, 0x69, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x28, 0x73, 0x61, 0x6e, - 0x69, 0x74, 0x69, 0x7a, 0x65, 0x64, 0x6d, 0x73, 0x67, 0x2c, 0x20, 0x63, 0x68, 0x61, 0x72, 0x29, 0x0a, - 0x09, 0x65, 0x6e, 0x64, 0x0a, - 0x09, 0x73, 0x61, 0x6e, 0x69, 0x74, 0x69, 0x7a, 0x65, 0x64, 0x6d, 0x73, 0x67, 0x20, 0x3d, 0x20, 0x74, 0x61, - 0x62, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6e, 0x63, 0x61, 0x74, 0x28, 0x73, 0x61, 0x6e, 0x69, 0x74, 0x69, 0x7a, - 0x65, 0x64, 0x6d, 0x73, 0x67, 0x29, 0x0a, - 0x0a, - 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x65, 0x72, 0x72, 0x20, 0x3d, 0x20, 0x7b, 0x7d, 0x0a, - 0x0a, - 0x09, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x2e, 0x69, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x28, 0x65, 0x72, 0x72, 0x2c, - 0x20, 0x22, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x5c, 0x6e, 0x22, 0x29, 0x0a, - 0x09, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x2e, 0x69, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x28, 0x65, 0x72, 0x72, 0x2c, - 0x20, 0x73, 0x61, 0x6e, 0x69, 0x74, 0x69, 0x7a, 0x65, 0x64, 0x6d, 0x73, 0x67, 0x29, 0x0a, - 0x0a, - 0x09, 0x69, 0x66, 0x20, 0x23, 0x73, 0x61, 0x6e, 0x69, 0x74, 0x69, 0x7a, 0x65, 0x64, 0x6d, 0x73, 0x67, 0x20, - 0x7e, 0x3d, 0x20, 0x23, 0x6d, 0x73, 0x67, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, - 0x09, 0x09, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x2e, 0x69, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x28, 0x65, 0x72, 0x72, - 0x2c, 0x20, 0x22, 0x49, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x20, 0x55, 0x54, 0x46, 0x2d, 0x38, 0x20, 0x73, - 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x69, 0x6e, 0x20, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x20, 0x6d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x2e, 0x22, 0x29, 0x0a, - 0x09, 0x65, 0x6e, 0x64, 0x0a, - 0x0a, - 0x09, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x2e, 0x69, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x28, 0x65, 0x72, 0x72, 0x2c, - 0x20, 0x22, 0x5c, 0x6e, 0x22, 0x29, 0x0a, - 0x0a, - 0x09, 0x66, 0x6f, 0x72, 0x20, 0x6c, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x72, 0x61, 0x63, 0x65, 0x3a, 0x67, 0x6d, - 0x61, 0x74, 0x63, 0x68, 0x28, 0x22, 0x28, 0x2e, 0x2d, 0x29, 0x5c, 0x6e, 0x22, 0x29, 0x20, 0x64, 0x6f, 0x0a, - 0x09, 0x09, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x6c, 0x3a, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x28, 0x22, - 0x62, 0x6f, 0x6f, 0x74, 0x2e, 0x6c, 0x75, 0x61, 0x22, 0x29, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, - 0x09, 0x09, 0x09, 0x6c, 0x20, 0x3d, 0x20, 0x6c, 0x3a, 0x67, 0x73, 0x75, 0x62, 0x28, 0x22, 0x73, 0x74, 0x61, - 0x63, 0x6b, 0x20, 0x74, 0x72, 0x61, 0x63, 0x65, 0x62, 0x61, 0x63, 0x6b, 0x3a, 0x22, 0x2c, 0x20, 0x22, 0x54, - 0x72, 0x61, 0x63, 0x65, 0x62, 0x61, 0x63, 0x6b, 0x5c, 0x6e, 0x22, 0x29, 0x0a, - 0x09, 0x09, 0x09, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x2e, 0x69, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x28, 0x65, 0x72, - 0x72, 0x2c, 0x20, 0x6c, 0x29, 0x0a, - 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, - 0x09, 0x65, 0x6e, 0x64, 0x0a, - 0x0a, - 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x70, 0x20, 0x3d, 0x20, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x2e, 0x63, - 0x6f, 0x6e, 0x63, 0x61, 0x74, 0x28, 0x65, 0x72, 0x72, 0x2c, 0x20, 0x22, 0x5c, 0x6e, 0x22, 0x29, 0x0a, - 0x0a, - 0x09, 0x70, 0x20, 0x3d, 0x20, 0x70, 0x3a, 0x67, 0x73, 0x75, 0x62, 0x28, 0x22, 0x5c, 0x74, 0x22, 0x2c, 0x20, - 0x22, 0x22, 0x29, 0x0a, - 0x09, 0x70, 0x20, 0x3d, 0x20, 0x70, 0x3a, 0x67, 0x73, 0x75, 0x62, 0x28, 0x22, 0x25, 0x5b, 0x73, 0x74, 0x72, - 0x69, 0x6e, 0x67, 0x20, 0x5c, 0x22, 0x28, 0x2e, 0x2d, 0x29, 0x5c, 0x22, 0x25, 0x5d, 0x22, 0x2c, 0x20, 0x22, - 0x25, 0x31, 0x22, 0x29, 0x0a, - 0x0a, - 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x64, 0x72, - 0x61, 0x77, 0x28, 0x29, 0x0a, - 0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x70, 0x6f, 0x73, 0x20, 0x3d, 0x20, 0x37, 0x30, 0x0a, - 0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x63, 0x6c, - 0x65, 0x61, 0x72, 0x28, 0x38, 0x39, 0x2f, 0x32, 0x35, 0x35, 0x2c, 0x20, 0x31, 0x35, 0x37, 0x2f, 0x32, 0x35, - 0x35, 0x2c, 0x20, 0x32, 0x32, 0x30, 0x2f, 0x32, 0x35, 0x35, 0x29, 0x0a, - 0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x70, 0x72, - 0x69, 0x6e, 0x74, 0x66, 0x28, 0x70, 0x2c, 0x20, 0x70, 0x6f, 0x73, 0x2c, 0x20, 0x70, 0x6f, 0x73, 0x2c, 0x20, - 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x67, 0x65, 0x74, 0x57, - 0x69, 0x64, 0x74, 0x68, 0x28, 0x29, 0x20, 0x2d, 0x20, 0x70, 0x6f, 0x73, 0x29, 0x0a, - 0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x70, 0x72, - 0x65, 0x73, 0x65, 0x6e, 0x74, 0x28, 0x29, 0x0a, - 0x09, 0x65, 0x6e, 0x64, 0x0a, - 0x0a, - 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x75, 0x6c, 0x6c, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x54, 0x65, - 0x78, 0x74, 0x20, 0x3d, 0x20, 0x70, 0x0a, - 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x63, 0x6f, - 0x70, 0x79, 0x54, 0x6f, 0x43, 0x6c, 0x69, 0x70, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x28, 0x29, 0x0a, - 0x09, 0x09, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x73, 0x79, 0x73, 0x74, - 0x65, 0x6d, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x65, 0x6e, 0x64, 0x0a, - 0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x2e, 0x73, 0x65, 0x74, 0x43, - 0x6c, 0x69, 0x70, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x54, 0x65, 0x78, 0x74, 0x28, 0x66, 0x75, 0x6c, 0x6c, 0x45, - 0x72, 0x72, 0x6f, 0x72, 0x54, 0x65, 0x78, 0x74, 0x29, 0x0a, - 0x09, 0x09, 0x70, 0x20, 0x3d, 0x20, 0x70, 0x20, 0x2e, 0x2e, 0x20, 0x22, 0x5c, 0x6e, 0x43, 0x6f, 0x70, 0x69, - 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x63, 0x6c, 0x69, 0x70, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x21, 0x22, 0x0a, - 0x09, 0x09, 0x64, 0x72, 0x61, 0x77, 0x28, 0x29, 0x0a, - 0x09, 0x65, 0x6e, 0x64, 0x0a, - 0x0a, - 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x20, 0x74, 0x68, - 0x65, 0x6e, 0x0a, - 0x09, 0x09, 0x70, 0x20, 0x3d, 0x20, 0x70, 0x20, 0x2e, 0x2e, 0x20, 0x22, 0x5c, 0x6e, 0x5c, 0x6e, 0x50, 0x72, - 0x65, 0x73, 0x73, 0x20, 0x43, 0x74, 0x72, 0x6c, 0x2b, 0x43, 0x20, 0x6f, 0x72, 0x20, 0x74, 0x61, 0x70, 0x20, - 0x74, 0x6f, 0x20, 0x63, 0x6f, 0x70, 0x79, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x65, 0x72, 0x72, 0x6f, 0x72, - 0x22, 0x0a, - 0x09, 0x65, 0x6e, 0x64, 0x0a, - 0x0a, - 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x0a, - 0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x70, 0x75, 0x6d, 0x70, 0x28, - 0x29, 0x0a, - 0x0a, - 0x09, 0x09, 0x66, 0x6f, 0x72, 0x20, 0x65, 0x2c, 0x20, 0x61, 0x2c, 0x20, 0x62, 0x2c, 0x20, 0x63, 0x20, 0x69, - 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x70, 0x6f, 0x6c, 0x6c, 0x28, - 0x29, 0x20, 0x64, 0x6f, 0x0a, - 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x65, 0x20, 0x3d, 0x3d, 0x20, 0x22, 0x71, 0x75, 0x69, 0x74, 0x22, 0x20, - 0x74, 0x68, 0x65, 0x6e, 0x0a, - 0x09, 0x09, 0x09, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x31, 0x0a, - 0x09, 0x09, 0x09, 0x65, 0x6c, 0x73, 0x65, 0x69, 0x66, 0x20, 0x65, 0x20, 0x3d, 0x3d, 0x20, 0x22, 0x6b, 0x65, - 0x79, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x22, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x61, 0x20, 0x3d, 0x3d, - 0x20, 0x22, 0x65, 0x73, 0x63, 0x61, 0x70, 0x65, 0x22, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, - 0x09, 0x09, 0x09, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x31, 0x0a, - 0x09, 0x09, 0x09, 0x65, 0x6c, 0x73, 0x65, 0x69, 0x66, 0x20, 0x65, 0x20, 0x3d, 0x3d, 0x20, 0x22, 0x6b, 0x65, - 0x79, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x22, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x61, 0x20, 0x3d, 0x3d, - 0x20, 0x22, 0x63, 0x22, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x6b, 0x65, 0x79, 0x62, - 0x6f, 0x61, 0x72, 0x64, 0x2e, 0x69, 0x73, 0x44, 0x6f, 0x77, 0x6e, 0x28, 0x22, 0x6c, 0x63, 0x74, 0x72, 0x6c, - 0x22, 0x2c, 0x20, 0x22, 0x72, 0x63, 0x74, 0x72, 0x6c, 0x22, 0x29, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, - 0x09, 0x09, 0x09, 0x09, 0x63, 0x6f, 0x70, 0x79, 0x54, 0x6f, 0x43, 0x6c, 0x69, 0x70, 0x62, 0x6f, 0x61, 0x72, - 0x64, 0x28, 0x29, 0x0a, - 0x09, 0x09, 0x09, 0x65, 0x6c, 0x73, 0x65, 0x69, 0x66, 0x20, 0x65, 0x20, 0x3d, 0x3d, 0x20, 0x22, 0x74, 0x6f, - 0x75, 0x63, 0x68, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x22, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, - 0x09, 0x09, 0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x20, 0x3d, 0x20, 0x6c, - 0x6f, 0x76, 0x65, 0x2e, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x67, 0x65, 0x74, 0x54, 0x69, 0x74, 0x6c, - 0x65, 0x28, 0x29, 0x0a, - 0x09, 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x23, 0x6e, 0x61, 0x6d, 0x65, 0x20, 0x3d, 0x3d, 0x20, 0x30, 0x20, - 0x6f, 0x72, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x20, 0x3d, 0x3d, 0x20, 0x22, 0x55, 0x6e, 0x74, 0x69, 0x74, 0x6c, - 0x65, 0x64, 0x22, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x20, 0x3d, 0x20, 0x22, 0x47, - 0x61, 0x6d, 0x65, 0x22, 0x20, 0x65, 0x6e, 0x64, 0x0a, - 0x09, 0x09, 0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x62, 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x73, 0x20, - 0x3d, 0x20, 0x7b, 0x22, 0x4f, 0x4b, 0x22, 0x2c, 0x20, 0x22, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x22, 0x7d, 0x0a, - 0x09, 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, - 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x62, 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x73, 0x5b, 0x33, 0x5d, 0x20, 0x3d, 0x20, - 0x22, 0x43, 0x6f, 0x70, 0x79, 0x20, 0x74, 0x6f, 0x20, 0x63, 0x6c, 0x69, 0x70, 0x62, 0x6f, 0x61, 0x72, 0x64, - 0x22, 0x0a, - 0x09, 0x09, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, - 0x09, 0x09, 0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x20, - 0x3d, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x73, 0x68, 0x6f, 0x77, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x42, 0x6f, 0x78, 0x28, 0x22, 0x51, 0x75, 0x69, 0x74, 0x20, 0x22, - 0x2e, 0x2e, 0x6e, 0x61, 0x6d, 0x65, 0x2e, 0x2e, 0x22, 0x3f, 0x22, 0x2c, 0x20, 0x22, 0x22, 0x2c, 0x20, 0x62, - 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x73, 0x29, 0x0a, - 0x09, 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x20, 0x3d, 0x3d, 0x20, - 0x31, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x31, 0x0a, - 0x09, 0x09, 0x09, 0x09, 0x65, 0x6c, 0x73, 0x65, 0x69, 0x66, 0x20, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, - 0x20, 0x3d, 0x3d, 0x20, 0x33, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x63, 0x6f, 0x70, 0x79, 0x54, 0x6f, 0x43, 0x6c, 0x69, 0x70, 0x62, 0x6f, 0x61, - 0x72, 0x64, 0x28, 0x29, 0x0a, - 0x09, 0x09, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, - 0x09, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, - 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, - 0x0a, - 0x09, 0x09, 0x64, 0x72, 0x61, 0x77, 0x28, 0x29, 0x0a, - 0x0a, - 0x09, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x74, 0x69, 0x6d, 0x65, 0x72, 0x20, 0x74, 0x68, - 0x65, 0x6e, 0x0a, - 0x09, 0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x74, 0x69, 0x6d, 0x65, 0x72, 0x2e, 0x73, 0x6c, 0x65, 0x65, - 0x70, 0x28, 0x30, 0x2e, 0x31, 0x29, 0x0a, - 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, - 0x09, 0x65, 0x6e, 0x64, 0x0a, - 0x0a, - 0x65, 0x6e, 0x64, 0x0a, - 0x0a, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, - 0x2d, 0x2d, 0x20, 0x54, 0x68, 0x65, 0x20, 0x72, 0x6f, 0x6f, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x61, 0x6c, 0x6c, - 0x20, 0x63, 0x61, 0x6c, 0x6c, 0x73, 0x2e, 0x0a, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, - 0x0a, - 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x0a, - 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x0a, - 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x69, 0x6e, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x20, 0x3d, 0x20, 0x66, - 0x61, 0x6c, 0x73, 0x65, 0x0a, - 0x0a, - 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x64, 0x65, - 0x66, 0x65, 0x72, 0x45, 0x72, 0x72, 0x68, 0x61, 0x6e, 0x64, 0x28, 0x2e, 0x2e, 0x2e, 0x29, 0x0a, - 0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x65, 0x72, 0x72, 0x68, 0x61, 0x6e, 0x64, 0x20, 0x3d, 0x20, - 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x20, - 0x6f, 0x72, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x65, 0x72, 0x72, 0x68, 0x61, 0x6e, 0x64, 0x0a, - 0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x20, 0x3d, 0x20, - 0x28, 0x6e, 0x6f, 0x74, 0x20, 0x69, 0x6e, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x65, - 0x72, 0x72, 0x68, 0x61, 0x6e, 0x64, 0x29, 0x20, 0x6f, 0x72, 0x20, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x70, - 0x72, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x0a, - 0x09, 0x09, 0x69, 0x6e, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x20, 0x3d, 0x20, 0x74, 0x72, 0x75, 0x65, 0x0a, - 0x09, 0x09, 0x66, 0x75, 0x6e, 0x63, 0x20, 0x3d, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x28, 0x2e, - 0x2e, 0x2e, 0x29, 0x0a, - 0x09, 0x65, 0x6e, 0x64, 0x0a, - 0x0a, - 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x65, 0x61, - 0x72, 0x6c, 0x79, 0x69, 0x6e, 0x69, 0x74, 0x28, 0x29, 0x0a, - 0x09, 0x09, 0x2d, 0x2d, 0x20, 0x49, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x62, 0x6f, 0x6f, 0x74, 0x20, - 0x66, 0x61, 0x69, 0x6c, 0x73, 0x2c, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x31, 0x20, 0x61, 0x6e, - 0x64, 0x20, 0x66, 0x69, 0x6e, 0x69, 0x73, 0x68, 0x20, 0x69, 0x6d, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x74, 0x65, - 0x6c, 0x79, 0x0a, - 0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x20, 0x3d, 0x20, 0x78, - 0x70, 0x63, 0x61, 0x6c, 0x6c, 0x28, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x62, 0x6f, 0x6f, 0x74, 0x2c, 0x20, 0x65, - 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x29, 0x0a, - 0x09, 0x09, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x20, 0x74, 0x68, - 0x65, 0x6e, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x31, 0x20, 0x65, 0x6e, 0x64, 0x0a, - 0x0a, - 0x09, 0x09, 0x2d, 0x2d, 0x20, 0x49, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x69, 0x6e, 0x69, 0x74, 0x20, - 0x6f, 0x72, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x72, 0x75, 0x6e, 0x20, 0x66, 0x61, 0x69, 0x6c, 0x73, 0x2c, - 0x20, 0x64, 0x6f, 0x6e, 0x27, 0x74, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x61, 0x20, 0x76, 0x61, - 0x6c, 0x75, 0x65, 0x2c, 0x0a, - 0x09, 0x09, 0x2d, 0x2d, 0x20, 0x61, 0x73, 0x20, 0x77, 0x65, 0x20, 0x77, 0x61, 0x6e, 0x74, 0x20, 0x74, 0x68, - 0x65, 0x20, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x20, 0x74, 0x6f, - 0x20, 0x74, 0x61, 0x6b, 0x65, 0x20, 0x6f, 0x76, 0x65, 0x72, 0x0a, - 0x09, 0x09, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x20, 0x3d, 0x20, 0x78, 0x70, 0x63, 0x61, 0x6c, 0x6c, 0x28, - 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x69, 0x6e, 0x69, 0x74, 0x2c, 0x20, 0x64, 0x65, 0x66, 0x65, 0x72, 0x45, 0x72, - 0x72, 0x68, 0x61, 0x6e, 0x64, 0x29, 0x0a, - 0x09, 0x09, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x20, 0x74, 0x68, - 0x65, 0x6e, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x65, 0x6e, 0x64, 0x0a, - 0x0a, - 0x09, 0x09, 0x2d, 0x2d, 0x20, 0x4e, 0x4f, 0x54, 0x45, 0x3a, 0x20, 0x57, 0x65, 0x20, 0x63, 0x61, 0x6e, 0x27, - 0x74, 0x20, 0x61, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x20, 0x74, 0x6f, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x20, 0x64, - 0x69, 0x72, 0x65, 0x63, 0x74, 0x6c, 0x79, 0x2c, 0x20, 0x61, 0x73, 0x20, 0x77, 0x65, 0x27, 0x64, 0x0a, - 0x09, 0x09, 0x2d, 0x2d, 0x20, 0x6f, 0x76, 0x65, 0x72, 0x77, 0x72, 0x69, 0x74, 0x65, 0x20, 0x74, 0x68, 0x65, - 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x64, 0x65, 0x66, 0x65, 0x72, 0x45, 0x72, - 0x72, 0x68, 0x61, 0x6e, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x6e, 0x69, 0x6c, 0x20, 0x6f, 0x6e, 0x20, - 0x65, 0x72, 0x72, 0x6f, 0x72, 0x0a, - 0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6d, 0x61, 0x69, 0x6e, 0x0a, - 0x09, 0x09, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x2c, 0x20, 0x6d, 0x61, 0x69, 0x6e, 0x20, 0x3d, 0x20, 0x78, - 0x70, 0x63, 0x61, 0x6c, 0x6c, 0x28, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x72, 0x75, 0x6e, 0x2c, 0x20, 0x64, 0x65, - 0x66, 0x65, 0x72, 0x45, 0x72, 0x72, 0x68, 0x61, 0x6e, 0x64, 0x29, 0x0a, - 0x09, 0x09, 0x69, 0x66, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, - 0x09, 0x09, 0x09, 0x66, 0x75, 0x6e, 0x63, 0x20, 0x3d, 0x20, 0x6d, 0x61, 0x69, 0x6e, 0x0a, - 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, - 0x09, 0x65, 0x6e, 0x64, 0x0a, - 0x0a, - 0x09, 0x66, 0x75, 0x6e, 0x63, 0x20, 0x3d, 0x20, 0x65, 0x61, 0x72, 0x6c, 0x79, 0x69, 0x6e, 0x69, 0x74, 0x0a, - 0x0a, - 0x09, 0x77, 0x68, 0x69, 0x6c, 0x65, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x20, 0x64, 0x6f, 0x0a, - 0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x5f, 0x2c, 0x20, 0x72, 0x65, 0x74, 0x76, 0x61, 0x6c, 0x20, - 0x3d, 0x20, 0x78, 0x70, 0x63, 0x61, 0x6c, 0x6c, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x2c, 0x20, 0x64, 0x65, 0x66, - 0x65, 0x72, 0x45, 0x72, 0x72, 0x68, 0x61, 0x6e, 0x64, 0x29, 0x0a, - 0x09, 0x09, 0x69, 0x66, 0x20, 0x72, 0x65, 0x74, 0x76, 0x61, 0x6c, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x72, - 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x72, 0x65, 0x74, 0x76, 0x61, 0x6c, 0x20, 0x65, 0x6e, 0x64, 0x0a, - 0x09, 0x09, 0x63, 0x6f, 0x72, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x65, 0x2e, 0x79, 0x69, 0x65, 0x6c, 0x64, 0x28, - 0x29, 0x0a, - 0x09, 0x65, 0x6e, 0x64, 0x0a, - 0x0a, - 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x31, 0x0a, - 0x65, 0x6e, 0x64, 0x0a, -}; // [boot.lua] -} // love From e258601bb59385f11e7cbfb59cf452867002c5a6 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Thu, 21 Oct 2021 13:46:42 -0300 Subject: [PATCH 13/43] Fix the save dir not being created if appdata/LOVE/ doesn't exist. --- src/modules/filesystem/Filesystem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/filesystem/Filesystem.cpp b/src/modules/filesystem/Filesystem.cpp index fcdc3f79a..bccd35a03 100644 --- a/src/modules/filesystem/Filesystem.cpp +++ b/src/modules/filesystem/Filesystem.cpp @@ -122,7 +122,7 @@ static bool getContainingDirectory(const std::string &path, std::string &newpath newpath = path.substr(0, index); // Bail if the root has been stripped out. - return newpath.find("/\\") != std::string::npos; + return newpath.find_first_of("/\\") != std::string::npos; } static bool createDirectoryRaw(const std::string &path) From a57d207a57ac199b9a1c061081b97607131b86c8 Mon Sep 17 00:00:00 2001 From: Semyon Yentsov Date: Mon, 1 Nov 2021 01:37:18 +0300 Subject: [PATCH 14/43] Fix bug #1707 --- src/modules/graphics/Font.cpp | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/modules/graphics/Font.cpp b/src/modules/graphics/Font.cpp index 967fe78f2..5d3304904 100644 --- a/src/modules/graphics/Font.cpp +++ b/src/modules/graphics/Font.cpp @@ -896,14 +896,11 @@ void Font::getWrap(const ColoredCodepoints &codepoints, float wraplimit, std::ve } // Push the last line. - if (!wline.cps.empty()) - { - lines.push_back(wline); + lines.push_back(wline); - // Ignore the width of any trailing spaces, for individual lines. - if (linewidths) - linewidths->push_back(width - widthoftrailingspace); - } + // Ignore the width of any trailing spaces, for individual lines. + if (linewidths) + linewidths->push_back(width - widthoftrailingspace); } void Font::getWrap(const std::vector &text, float wraplimit, std::vector &lines, std::vector *linewidths) From b79b99bbaa60fb283d160782e5b31f953b43760c Mon Sep 17 00:00:00 2001 From: Miku AuahDark Date: Tue, 2 Nov 2021 17:54:13 +0800 Subject: [PATCH 15/43] Use specialized logic when loading C modules in Android. --- src/common/android.cpp | 42 ++++++++++++++++++++++ src/common/android.h | 2 ++ src/modules/filesystem/wrap_Filesystem.cpp | 25 +++++++++++++ 3 files changed, 69 insertions(+) diff --git a/src/common/android.cpp b/src/common/android.cpp index 075b6b7d9..e926737a5 100644 --- a/src/common/android.cpp +++ b/src/common/android.cpp @@ -724,6 +724,48 @@ bool checkFusedGame(void **physfsIO_Out) return false; } +const char *getCRequirePath() +{ + static bool initialized = false; + static const char *path = nullptr; + + if (!initialized) + { + JNIEnv *env = (JNIEnv*) SDL_AndroidGetJNIEnv(); + jobject activity = (jobject) SDL_AndroidGetActivity(); + + jclass clazz(env->GetObjectClass(activity)); + jmethodID method_id = env->GetMethodID(clazz, "getCRequirePath", "()Ljava/lang/String;"); + + path = ""; + initialized = true; + + if (method_id) + { + jstring cpath = (jstring) env->CallObjectMethod(activity, method_id); + const char *utf = env->GetStringUTFChars(cpath, nullptr); + if (utf) + { + path = SDL_strdup(utf); + env->ReleaseStringUTFChars(cpath, utf); + } + + env->DeleteLocalRef(cpath); + } + else + { + // NoSuchMethodException is thrown in case methodID is null + env->ExceptionClear(); + return ""; + } + + env->DeleteLocalRef(activity); + env->DeleteLocalRef(clazz); + } + + return path; +} + } // android } // love diff --git a/src/common/android.h b/src/common/android.h index 68b2259bf..3c0c5a35f 100644 --- a/src/common/android.h +++ b/src/common/android.h @@ -101,6 +101,8 @@ void deinitializeVirtualArchive(); */ bool checkFusedGame(void **physfsIO_Out); +const char *getCRequirePath(); + } // android } // love diff --git a/src/modules/filesystem/wrap_Filesystem.cpp b/src/modules/filesystem/wrap_Filesystem.cpp index 62f356f0f..41db59725 100644 --- a/src/modules/filesystem/wrap_Filesystem.cpp +++ b/src/modules/filesystem/wrap_Filesystem.cpp @@ -29,6 +29,10 @@ #include "physfs/Filesystem.h" +#ifdef LOVE_ANDROID +#include "common/android.h" +#endif + // SDL #include @@ -782,6 +786,23 @@ int extloader(lua_State *L) void *handle = nullptr; auto *inst = instance(); +#ifdef LOVE_ANDROID + // Specifically Android, look the library path based on getCRequirePath first + std::string androidPath(love::android::getCRequirePath()); + + if (!androidPath.empty()) + { + // Replace ? with just the dotted filename (not tokenized_name) + replaceAll(androidPath, "?", filename); + + // Load directly, don't check for existence. + handle = SDL_LoadObject(androidPath.c_str()); + } + + if (!handle) + { +#endif // LOVE_ANDROID + for (const std::string &el : inst->getCRequirePath()) { for (const char *ext : library_extensions) @@ -811,6 +832,10 @@ int extloader(lua_State *L) break; } +#ifdef LOVE_ANDROID + } // if (!handle) +#endif + if (!handle) { lua_pushfstring(L, "\n\tno file '%s' in LOVE paths.", tokenized_name.c_str()); From 3a18a2ab0d40a13e986d6032b0cb2c53b8283094 Mon Sep 17 00:00:00 2001 From: Miku AuahDark Date: Fri, 5 Nov 2021 13:55:14 +0800 Subject: [PATCH 16/43] Use GameActivity.buildFileLookup via JNI to build file tree. Turns out AAssetDir_getNextFilename() intentionally excludes directories, thus the custom archive backend only sees the top-level files. --- src/common/android.cpp | 167 +++++++++++++++++++++++++++-------------- 1 file changed, 112 insertions(+), 55 deletions(-) diff --git a/src/common/android.cpp b/src/common/android.cpp index e926737a5..8f4c2cf84 100644 --- a/src/common/android.cpp +++ b/src/common/android.cpp @@ -333,24 +333,59 @@ void showRecordingPermissionMissingDialog() env->DeleteLocalRef(activity); } +/* A container for AssetManager Java object */ +class AssetManagerObject +{ +public: + AssetManagerObject() + { + JNIEnv *env = (JNIEnv *) SDL_AndroidGetJNIEnv(); + jobject am = getLocalAssetManager(env); + + assetManager = env->NewGlobalRef(am); + env->DeleteLocalRef(am); + } + + ~AssetManagerObject() + { + JNIEnv *env = (JNIEnv *) SDL_AndroidGetJNIEnv(); + env->DeleteGlobalRef(assetManager); + } + + static jobject getLocalAssetManager(JNIEnv *env) { + jobject self = (jobject) SDL_AndroidGetActivity(); + jclass activity = env->GetObjectClass(self); + jmethodID method = env->GetMethodID(activity, "getAssets", "()Landroid/content/res/AssetManager;"); + jobject am = env->CallObjectMethod(self, method); + + env->DeleteLocalRef(self); + env->DeleteLocalRef(activity); + return am; + } + + explicit operator jobject() + { + return assetManager; + }; +private: + jobject assetManager; +}; + /* * Helper functions to aid new fusing method */ + +// This returns *global* reference, no need to free it. +static jobject getJavaAssetManager() +{ + static AssetManagerObject assetManager; + return (jobject) assetManager; +} + static AAssetManager *getAssetManager() { JNIEnv *env = (JNIEnv*) SDL_AndroidGetJNIEnv(); - jobject self = (jobject) SDL_AndroidGetActivity(); - jclass activity = env->GetObjectClass(self); - jmethodID method = env->GetMethodID(activity, "getAssetManager", "()Landroid/content/res/AssetManager;"); - - jobject assetManager = env->CallObjectMethod(self, method); - AAssetManager *assetManagerObject = AAssetManager_fromJava(env, assetManager); - - env->DeleteLocalRef(assetManager); - env->DeleteLocalRef(activity); - env->DeleteLocalRef(self); - - return assetManagerObject; + return AAssetManager_fromJava(env, (jobject) getJavaAssetManager()); } namespace aasset @@ -368,35 +403,6 @@ struct AssetInfo static std::unordered_map fileTree; -// Workaround AAsset can't detect whetever something is a directory or doesn't exist -static void buildFileLookup( - AAssetManager *assetManager, - std::unordered_map &out, - const std::string &path = "" -) -{ - if (!path.empty()) - { - AAsset *test = AAssetManager_open(assetManager, path.c_str(), AASSET_MODE_STREAMING); - if (test) - { - AAsset_close(test); - out[path] = PHYSFS_FILETYPE_REGULAR; - return; - } - - out[path] = PHYSFS_FILETYPE_DIRECTORY; - } - - AAssetDir *dir = AAssetManager_openDir(assetManager, path.c_str()); - const char *file; - - while ((file = AAssetDir_getNextFileName(dir)) != nullptr) - buildFileLookup(assetManager, out, file); - - AAssetDir_close(dir); -} - PHYSFS_sint64 read(PHYSFS_Io *io, void *buf, PHYSFS_uint64 len) { AAsset *asset = ((AssetInfo *) io->opaque)->asset; @@ -505,7 +511,31 @@ void *openArchive(PHYSFS_Io *io, const char *name, int forWrite, int *claimed) AAssetManager *assetManager = getAssetManager(); if (io::fileTree.empty()) - io::buildFileLookup(assetManager, io::fileTree); + { + // AAssetDir_getNextFileName intentionally excludes directories, so + // we have to use JNI that calls AssetManager.list() recursively. + JNIEnv *env = (JNIEnv *) SDL_AndroidGetJNIEnv(); + jobject activity = (jobject) SDL_AndroidGetActivity(); + jclass clazz = env->GetObjectClass(activity); + + jmethodID method = env->GetMethodID(clazz, "buildFileTree", "()[Ljava/lang/String;"); + jobjectArray list = (jobjectArray) env->CallObjectMethod(activity, method); + + for (jsize i = 0; i < env->GetArrayLength(list); i++) + { + jstring jstr = (jstring) env->GetObjectArrayElement(list, i); + const char *str = env->GetStringUTFChars(jstr, nullptr); + + io::fileTree[str + 1] = str[0] == 'd' ? PHYSFS_FILETYPE_DIRECTORY : PHYSFS_FILETYPE_REGULAR; + + env->ReleaseStringUTFChars(jstr, str); + env->DeleteLocalRef(jstr); + } + + env->DeleteLocalRef(list); + env->DeleteLocalRef(clazz); + env->DeleteLocalRef(activity); + } return assetManager; } @@ -518,33 +548,60 @@ PHYSFS_EnumerateCallbackResult enumerate( void *callbackdata ) { + using FileTreeIterator = std::unordered_map::iterator; + LOVE_UNUSED(opaque); + const char *path = dirname; if (path == nullptr || (path[0] == '/' && path[1] == 0)) path = ""; - AAssetManager *assetManager = (AAssetManager *) opaque; - AAssetDir *dir = AAssetManager_openDir(assetManager, path); - - if (dir == nullptr) + if (path[0] != 0) { - PHYSFS_setErrorCode(PHYSFS_ERR_NOT_FOUND); - return PHYSFS_ENUM_ERROR; + FileTreeIterator result = io::fileTree.find(path); + + if (result == io::fileTree.end() || result->second != PHYSFS_FILETYPE_DIRECTORY) + { + PHYSFS_setErrorCode(PHYSFS_ERR_NOT_FOUND); + return PHYSFS_ENUM_ERROR; + } } + JNIEnv *env = (JNIEnv *) SDL_AndroidGetJNIEnv(); + jobject assetManager = getJavaAssetManager(); + jclass clazz = env->GetObjectClass(assetManager); + jmethodID method = env->GetMethodID(clazz, "list", "(Ljava/lang/String;)[Ljava/lang/String"); + + jstring jstringDir = env->NewStringUTF(path); + jobjectArray dir = (jobjectArray) env->CallObjectMethod(assetManager, method, jstringDir); + PHYSFS_EnumerateCallbackResult ret = PHYSFS_ENUM_OK; - while (ret == PHYSFS_ENUM_OK) + if (env->ExceptionCheck()) { - const char *name = AAssetDir_getNextFileName(dir); + // IOException occured + ret = PHYSFS_ENUM_ERROR; + env->ExceptionClear(); + } + else + { + jsize i = 0; + jsize len = env->GetArrayLength(dir); - // No more files? - if (name == nullptr) - break; + while (ret == PHYSFS_ENUM_OK && i < len) { + jstring jstr = (jstring) env->GetObjectArrayElement(dir, i++); + const char *name = env->GetStringUTFChars(jstr, nullptr); - ret = cb(callbackdata, origdir, name); + ret = cb(callbackdata, origdir, name); + + env->ReleaseStringUTFChars(jstr, name); + env->DeleteLocalRef(jstr); + } + + env->DeleteLocalRef(dir); } - AAssetDir_close(dir); + env->DeleteLocalRef(jstringDir); + env->DeleteLocalRef(clazz); return ret; } From 1bb22d2e90eb43146b4e577055064260b4649c2d Mon Sep 17 00:00:00 2001 From: Miku AuahDark Date: Fri, 5 Nov 2021 15:22:03 +0800 Subject: [PATCH 17/43] Set game source path when using virtual archive in Android. This will also prevent double `love.filesystem.setSource()` call in that case. --- src/modules/filesystem/physfs/Filesystem.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/modules/filesystem/physfs/Filesystem.cpp b/src/modules/filesystem/physfs/Filesystem.cpp index 62504780e..12ce395dd 100644 --- a/src/modules/filesystem/physfs/Filesystem.cpp +++ b/src/modules/filesystem/physfs/Filesystem.cpp @@ -232,15 +232,13 @@ bool Filesystem::setSource(const char *source) PHYSFS_Io *gameLoveIO; bool hasFusedGame = love::android::checkFusedGame((void **) &gameLoveIO); + bool isAAssetMounted = false; if (hasFusedGame) { if (gameLoveIO) - { // Actually we should just be able to mount gameLoveIO, but that's experimental. gameLoveIO->destroy(gameLoveIO); - goto oldschool; - } else { if (!love::android::initializeVirtualArchive()) @@ -248,11 +246,15 @@ bool Filesystem::setSource(const char *source) SDL_Log("Unable to mount AAsset: %s", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode())); return false; } + + // See love::android::initializeVirtualArchive() + new_search_path = "ASET.AASSET"; + isAAssetMounted = true; } } - else + + if (!isAAssetMounted) { - oldschool: new_search_path = love::android::getSelectedGameFile(); // try mounting first, if that fails, load to memory and mount From b916c0ad92645474b0eb6a6e976f6acc161b1ab3 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Sat, 6 Nov 2021 10:41:30 -0300 Subject: [PATCH 18/43] Fix error message when sending buffers to unused variables --- src/modules/graphics/opengl/Shader.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/modules/graphics/opengl/Shader.cpp b/src/modules/graphics/opengl/Shader.cpp index 7abd4e2d1..9bacf446e 100644 --- a/src/modules/graphics/opengl/Shader.cpp +++ b/src/modules/graphics/opengl/Shader.cpp @@ -166,6 +166,12 @@ void Shader::mapActiveUniforms() u.storageTextureFormat = reflectionit->second.format; u.access = reflectionit->second.access; } + else + { + // No reflection info - maybe glslang was better at detecting + // dead code than the driver's compiler? + continue; + } StorageTextureBinding binding = {}; binding.gltexture = gl.getDefaultTexture(u.textureType, u.dataBaseType); @@ -372,6 +378,12 @@ void Shader::mapActiveUniforms() u.bufferMemberCount = reflectionit->second.memberCount; u.access = reflectionit->second.access; } + else + { + // No reflection info - maybe glslang was better at detecting + // dead code than the driver's compiler? + continue; + } // Make sure previously set uniform data is preserved, and shader- // initialized values are retrieved. From 041aa2fc238ab0bf01d274dd7b1710c91e5c8dc5 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Sat, 6 Nov 2021 10:43:43 -0300 Subject: [PATCH 19/43] Revert Shader:send to cause a Lua error instead of returning false, if the given variable doesn't exist or is optimized out in the shader. --- src/modules/graphics/wrap_Shader.cpp | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/modules/graphics/wrap_Shader.cpp b/src/modules/graphics/wrap_Shader.cpp index 706c77de3..bd3ad5bb7 100644 --- a/src/modules/graphics/wrap_Shader.cpp +++ b/src/modules/graphics/wrap_Shader.cpp @@ -447,18 +447,12 @@ int w_Shader_send(lua_State *L) const Shader::UniformInfo *info = shader->getUniformInfo(name); if (info == nullptr) - { - luax_pushboolean(L, false); - return 1; - } + return luaL_error(L, "Shader uniform '%s' does not exist.\nA common error is to define but not use the variable.", name); if (luax_istype(L, 3, Data::type) || (info->baseType == Shader::UNIFORM_MATRIX && luax_istype(L, 4, Data::type))) - w_Shader_sendData(L, 3, shader, info, false); + return w_Shader_sendData(L, 3, shader, info, false); else - w_Shader_sendLuaValues(L, 3, shader, info, name); - - luax_pushboolean(L, true); - return 1; + return w_Shader_sendLuaValues(L, 3, shader, info, name); } int w_Shader_sendColors(lua_State *L) From 68977ec31186119686858244a447f3c069a30a40 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Sat, 6 Nov 2021 11:17:23 -0300 Subject: [PATCH 20/43] Fix alignment of storage buffers with vec3 or mat3 components. --- src/modules/graphics/Buffer.cpp | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/modules/graphics/Buffer.cpp b/src/modules/graphics/Buffer.cpp index f040cbd51..a64e9654a 100644 --- a/src/modules/graphics/Buffer.cpp +++ b/src/modules/graphics/Buffer.cpp @@ -147,11 +147,22 @@ Buffer::Buffer(Graphics *gfx, const Settings &settings, const std::vector Date: Sat, 6 Nov 2021 16:42:41 -0300 Subject: [PATCH 21/43] Allow plain arrays of a base type as shader buffer block declarations. --- src/modules/graphics/Shader.cpp | 8 ++++---- src/modules/graphics/opengl/Shader.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/modules/graphics/Shader.cpp b/src/modules/graphics/Shader.cpp index 71ffac2df..728e372ab 100644 --- a/src/modules/graphics/Shader.cpp +++ b/src/modules/graphics/Shader.cpp @@ -891,14 +891,14 @@ bool Shader::validateInternal(StrongRef stages[], std::string &err, const glslang::TTypeList *structure = type->getStruct(); if (structure == nullptr || structure->size() != 1) { - err = "Shader validation error:\nStorage Buffer block '" + info.name + "' must contain a single unsized array of structs."; + err = "Shader validation error:\nStorage Buffer block '" + info.name + "' must contain a single unsized array of base types or structs."; return false; } - const glslang::TType* structtype = (*structure)[0].type; - if (structtype == nullptr || structtype->getBasicType() != glslang::EbtStruct || !structtype->isUnsizedArray()) + const glslang::TType* elementtype = (*structure)[0].type; + if (elementtype == nullptr || !elementtype->isUnsizedArray()) { - err = "Shader validation error:\nStorage Buffer block '" + info.name + "' must contain a single unsized array of structs."; + err = "Shader validation error:\nStorage Buffer block '" + info.name + "' must contain a single unsized array of base types or structs."; return false; } diff --git a/src/modules/graphics/opengl/Shader.h b/src/modules/graphics/opengl/Shader.h index efab5ab59..13ded3566 100644 --- a/src/modules/graphics/opengl/Shader.h +++ b/src/modules/graphics/opengl/Shader.h @@ -45,7 +45,7 @@ public: struct StorageTextureBinding { - Texture *texture = nullptr; + love::graphics::Texture *texture = nullptr; GLuint gltexture = 0; TextureType type = TEXTURE_2D; GLenum access = GL_READ_ONLY; From 5c98cbdabdbe0555fa89ca6833b4fee47115d636 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Sat, 6 Nov 2021 17:03:54 -0300 Subject: [PATCH 22/43] Fix Shader:send with storage buffers when the shader uses more than 1. --- src/modules/graphics/opengl/Shader.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/modules/graphics/opengl/Shader.cpp b/src/modules/graphics/opengl/Shader.cpp index 9bacf446e..63c1845e0 100644 --- a/src/modules/graphics/opengl/Shader.cpp +++ b/src/modules/graphics/opengl/Shader.cpp @@ -358,6 +358,7 @@ void Shader::mapActiveUniforms() glGetProgramInterfaceiv(program, GL_SHADER_STORAGE_BLOCK, GL_ACTIVE_RESOURCES, &numstoragebuffers); char namebuffer[2048] = { '\0' }; + int nextstoragebufferbinding = 0; for (int sindex = 0; sindex < numstoragebuffers; sindex++) { @@ -405,8 +406,11 @@ void Shader::mapActiveUniforms() memset(u.buffers, 0, sizeof(Buffer*)* u.count); } - GLenum props[] = { GL_BUFFER_BINDING }; - glGetProgramResourceiv(program, GL_SHADER_STORAGE_BLOCK, sindex, 1, props, 1, nullptr, u.ints); + // Unlike local uniforms and attributes, OpenGL doesn't auto-assign storage + // block bindings if they're unspecified in the shader. So we overwrite them + // regardless, here. + u.ints[0] = nextstoragebufferbinding++; + glShaderStorageBlockBinding(program, sindex, u.ints[0]); BufferBinding binding; binding.bindingindex = u.ints[0]; @@ -1198,6 +1202,9 @@ Shader::MatrixSize Shader::getMatrixSize(GLenum type) const m.columns = 4; m.rows = 3; break; + default: + m.columns = m.rows = 0; + break; } return m; From a3ff9999d1a70e0152ac15910795774066a1a17c Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Sat, 6 Nov 2021 18:30:08 -0300 Subject: [PATCH 23/43] Disallow mat3 formats in shader storage buffers. GLSL's std430 layout rules make it really unintuitive for users to deal with. --- src/modules/graphics/Buffer.cpp | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/modules/graphics/Buffer.cpp b/src/modules/graphics/Buffer.cpp index a64e9654a..569bb1e8a 100644 --- a/src/modules/graphics/Buffer.cpp +++ b/src/modules/graphics/Buffer.cpp @@ -154,11 +154,19 @@ Buffer::Buffer(Graphics *gfx, const Settings &settings, const std::vector 0 || info.isMatrix)) + { + const char *fstr = "unknown"; + getConstant(decl.format, fstr); + throw love::Exception("Data format %s%s is not currently supported in shader storage buffers.", fstr, decl.arrayLength > 0 ? " array" : ""); + } // "If the member is a structure, the base alignment of the structure // is N, where N is the largest base alignment value of any of its From 888051d01eb9108174d9a3baa385e17bdec097f5 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Fri, 12 Nov 2021 21:58:49 -0400 Subject: [PATCH 24/43] Potential very hacky workaround for arm64 JIT allocation issues. Try to reserve blocks of executable memory before external library code claims the address space. LuaJIT on arm64 currently has a very limited range of memory it can use for JIT code. --- .../xcode/liblove.xcodeproj/project.pbxproj | 2 + src/love.cpp | 24 ++++--- src/modules/love/jitsetup.lua | 71 +++++++++++++++++++ src/modules/love/love.cpp | 27 +++++-- src/modules/love/love.h | 3 + 5 files changed, 115 insertions(+), 12 deletions(-) create mode 100644 src/modules/love/jitsetup.lua diff --git a/platform/xcode/liblove.xcodeproj/project.pbxproj b/platform/xcode/liblove.xcodeproj/project.pbxproj index 3e3226bc0..113fd36ff 100644 --- a/platform/xcode/liblove.xcodeproj/project.pbxproj +++ b/platform/xcode/liblove.xcodeproj/project.pbxproj @@ -1849,6 +1849,7 @@ FA620A311AA2F8DB005DB4C2 /* wrap_Texture.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wrap_Texture.h; sourceTree = ""; }; FA620A391AA305F6005DB4C2 /* types.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = types.cpp; sourceTree = ""; }; FA665DC321C34C900074BBD6 /* wrap_GraphicsShader.lua */ = {isa = PBXFileReference; lastKnownFileType = text; path = wrap_GraphicsShader.lua; sourceTree = ""; }; + FA69B918273828DD00CDC2E7 /* jitsetup.lua */ = {isa = PBXFileReference; lastKnownFileType = text; path = jitsetup.lua; sourceTree = ""; }; FA6A2B641F5F7B6B0074C308 /* wrap_Data.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wrap_Data.h; sourceTree = ""; }; FA6A2B651F5F7B6B0074C308 /* wrap_Data.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = wrap_Data.cpp; sourceTree = ""; }; FA6A2B681F5F7F560074C308 /* DataView.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = DataView.cpp; sourceTree = ""; }; @@ -2966,6 +2967,7 @@ FA1E95B4271F932B0044CF08 /* arg.lua */, FA577A8D16C71D3600860150 /* boot.lua */, FA1E95B5271F932B0044CF08 /* callbacks.lua */, + FA69B918273828DD00CDC2E7 /* jitsetup.lua */, FA0B7BFE1A95902C000E1D17 /* love.cpp */, FA0B7BFF1A95902C000E1D17 /* love.h */, ); diff --git a/src/love.cpp b/src/love.cpp index 089440a47..3245d73f6 100644 --- a/src/love.cpp +++ b/src/love.cpp @@ -142,14 +142,6 @@ enum DoneAction static DoneAction runlove(int argc, char **argv, int &retval) { -#ifdef LOVE_LEGENDARY_APP_ARGV_HACK - int hack_argc = 0; - char **hack_argv = 0; - get_app_arguments(argc, argv, hack_argc, hack_argv); - argc = hack_argc; - argv = hack_argv; -#endif // LOVE_LEGENDARY_APP_ARGV_HACK - // Oh, you just want the version? Okay! if (argc > 1 && strcmp(argv[1], "--version") == 0) { @@ -166,6 +158,22 @@ static DoneAction runlove(int argc, char **argv, int &retval) lua_State *L = luaL_newstate(); luaL_openlibs(L); + // LuaJIT-specific setup needs to be done as early as possible - before + // get_app_arguments because that loads external library code. This is also + // loaded inside require("love"). Note that it doesn't use the love table. + love_preload(L, luaopen_love_jitsetup, "love.jitsetup"); + lua_getglobal(L, "require"); + lua_pushstring(L, "love.jitsetup"); + lua_call(L, 1, 0); + +#ifdef LOVE_LEGENDARY_APP_ARGV_HACK + int hack_argc = 0; + char **hack_argv = nullptr; + get_app_arguments(argc, argv, hack_argc, hack_argv); + argc = hack_argc; + argv = hack_argv; +#endif // LOVE_LEGENDARY_APP_ARGV_HACK + // Add love to package.preload for easy requiring. love_preload(L, luaopen_love, "love"); diff --git a/src/modules/love/jitsetup.lua b/src/modules/love/jitsetup.lua new file mode 100644 index 000000000..d87afa3ce --- /dev/null +++ b/src/modules/love/jitsetup.lua @@ -0,0 +1,71 @@ +R"luastring"--( +-- DO NOT REMOVE THE ABOVE LINE. It is used to load this file as a C++ string. +-- There is a matching delimiter at the bottom of the file. + +--[[ +Copyright (c) 2006-2021 LOVE Development Team + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +--]] + +if type(jit) ~= "table" or not jit.status() then + return +end + +-- Double the defaults. +jit.opt.start("maxtrace=2000", "maxrecord=8000") + +-- Somewhat arbitrary value. Needs to be higher than the combined sizes below, +-- and higher than the default (512) because that's already too low. +jit.opt.start("maxmcode=16384") + +if jit.arch == "arm64" then + -- https://github.com/LuaJIT/LuaJIT/issues/285 + -- LuaJIT 2.1 on arm64 currently (as of commit b4b2dce) can only use memory + -- for JIT compilation within a certain short range. Other libraries such as + -- SDL can take all the usable space in that range and cause attempts at JIT + -- compilation to both fail and take a long time. + -- This is a very hacky attempt at a workaround. LuaJIT allocates executable + -- code in pools. We'll try "reserving" pools before any external code is + -- executed, by causing JIT compilation via a small loop. We can't easily + -- tell if JIT compilation succeeded, so we do several successively smaller + -- pool allocations in case previous ones fail. + -- This is a really hacky hack and by no means foolproof - there are a lot of + -- potential situations (especially when threads are used) where previously + -- executed external code will still take up space that LuaJIT needed for itself. + + jit.opt.start("sizemcode=2048") + for i=1, 100 do end + + jit.opt.start("sizemcode=1024") + for i=1, 100 do end + + jit.opt.start("sizemcode=512") + for i=1, 100 do end + + jit.opt.start("sizemcode=256") + for i=1, 100 do end + + jit.opt.start("sizemcode=128") + for i=1, 100 do end +else + -- Somewhat arbitrary value (>= the default). + jit.opt.start("sizemcode=128") +end + +-- DO NOT REMOVE THE NEXT LINE. It is used to load this file as a C++ string. +--)luastring"--" diff --git a/src/modules/love/love.cpp b/src/modules/love/love.cpp index 5728514ad..a70125f91 100644 --- a/src/modules/love/love.cpp +++ b/src/modules/love/love.cpp @@ -97,6 +97,10 @@ static const char boot_lua[] = #include "boot.lua" ; +static const char jit_setup_lua[] = +#include "jitsetup.lua" +; + // All modules define a c-accessible luaopen // so let's make use of those, instead // of addressing implementations directly. @@ -160,6 +164,7 @@ extern "C" extern int luaopen_love_window(lua_State*); #endif extern int luaopen_love_nogame(lua_State*); + extern int luaopen_love_jitsetup(lua_State*); extern int luaopen_love_arg(lua_State*); extern int luaopen_love_callbacks(lua_State*); extern int luaopen_love_boot(lua_State*); @@ -224,6 +229,7 @@ static const luaL_Reg modules[] = { { "love.window", luaopen_love_window }, #endif { "love.nogame", luaopen_love_nogame }, + { "love.jitsetup", luaopen_love_jitsetup }, { "love.arg", luaopen_love_arg }, { "love.callbacks", luaopen_love_callbacks }, { "love.boot", luaopen_love_boot }, @@ -404,6 +410,15 @@ static void luax_addcompatibilityalias(lua_State *L, const char *module, const c int luaopen_love(lua_State *L) { + // Preload module loaders. + for (int i = 0; modules[i].name != nullptr; i++) + love::luax_preload(L, modules[i].func, modules[i].name); + + // jitsetup is also loaded in the love executable runlove function. It's + // needed here too for threads. Note that it doesn't use the love table. + love::luax_require(L, "love.jitsetup"); + lua_pop(L, 1); + love::luax_insistpinnedthread(L); love::luax_insistglobal(L, "love"); @@ -501,10 +516,6 @@ int luaopen_love(lua_State *L) lua_setfield(L, -2, "hasDeprecationOutput"); } - // Preload module loaders. - for (int i = 0; modules[i].name != nullptr; i++) - love::luax_preload(L, modules[i].func, modules[i].name); - // Necessary for Data-creating methods to work properly in Data subclasses. love::luax_require(L, "love.data"); lua_pop(L, 1); @@ -657,6 +668,14 @@ int luaopen_love_nogame(lua_State *L) return 1; } +int luaopen_love_jitsetup(lua_State *L) +{ + if (luaL_loadbuffer(L, jit_setup_lua, sizeof(jit_setup_lua), "jitsetup.lua") == 0) + lua_call(L, 0, 1); + + return 1; +} + int luaopen_love_arg(lua_State *L) { if (luaL_loadbuffer(L, arg_lua, sizeof(arg_lua), "arg.lua") == 0) diff --git a/src/modules/love/love.h b/src/modules/love/love.h index ee057f5b4..149bb3eb7 100644 --- a/src/modules/love/love.h +++ b/src/modules/love/love.h @@ -36,6 +36,9 @@ LOVE_EXPORT const char *love_version(); LOVE_EXPORT const char *love_codename(); LOVE_EXPORT int luaopen_love(lua_State *L); LOVE_EXPORT int luaopen_love_nogame(lua_State *L); +LOVE_EXPORT int luaopen_love_jitsetup(lua_State *L); +LOVE_EXPORT int luaopen_love_arg(lua_State *L); +LOVE_EXPORT int luaopen_love_callbacks(lua_State *L); LOVE_EXPORT int luaopen_love_boot(lua_State *L); #ifdef LOVE_LEGENDARY_CONSOLE_IO_HACK From 0f9e598ebb5f77a38124ab7ac8c4a92a1403ee47 Mon Sep 17 00:00:00 2001 From: Miku AuahDark Date: Sat, 13 Nov 2021 14:34:54 +0800 Subject: [PATCH 25/43] Fixed love.filesystem.getDirectoryItems() in Android with new fusing mehod. --- src/common/android.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/android.cpp b/src/common/android.cpp index 8f4c2cf84..1c3cdf11b 100644 --- a/src/common/android.cpp +++ b/src/common/android.cpp @@ -569,7 +569,7 @@ PHYSFS_EnumerateCallbackResult enumerate( JNIEnv *env = (JNIEnv *) SDL_AndroidGetJNIEnv(); jobject assetManager = getJavaAssetManager(); jclass clazz = env->GetObjectClass(assetManager); - jmethodID method = env->GetMethodID(clazz, "list", "(Ljava/lang/String;)[Ljava/lang/String"); + jmethodID method = env->GetMethodID(clazz, "list", "(Ljava/lang/String;)[Ljava/lang/String;"); jstring jstringDir = env->NewStringUTF(path); jobjectArray dir = (jobjectArray) env->CallObjectMethod(assetManager, method, jstringDir); From bd741a8c780aaf7795499be1b2f8883109749f06 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Fri, 19 Nov 2021 21:44:04 -0400 Subject: [PATCH 26/43] Fix incorrect particle offsets when Quads are used without setOffset. Fixes #1741. --- src/modules/graphics/ParticleSystem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/graphics/ParticleSystem.cpp b/src/modules/graphics/ParticleSystem.cpp index 800da3aca..304b0edb0 100644 --- a/src/modules/graphics/ParticleSystem.cpp +++ b/src/modules/graphics/ParticleSystem.cpp @@ -177,7 +177,7 @@ void ParticleSystem::resetOffset() else { Quad::Viewport v = quads[0]->getViewport(); - offset = love::Vector2(v.x*0.5f, v.y*0.5f); + offset = love::Vector2(v.w*0.5f, v.h*0.5f); } } From 7b6012891d0495fa38fba451fddfe67a07b28690 Mon Sep 17 00:00:00 2001 From: Miku AuahDark Date: Sat, 20 Nov 2021 11:42:33 +0800 Subject: [PATCH 27/43] Replace AppImage packaging method. The new AppImage packaging method compiles all the dependencies from source instead of using system-provided libraries, which can be problematic in certain situations (see #1710). Fixes #1710 and closes #1700 --- .github/workflows/main.yml | 45 ++++++++++++++++---------------------- 1 file changed, 19 insertions(+), 26 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 65f5b4a63..e601f3b64 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -9,37 +9,30 @@ jobs: run: sudo apt-get update - name: Install Dependencies run: | - sudo apt-get install --assume-yes build-essential autotools-dev automake libtool pkg-config \ - libfreetype6-dev libluajit-5.1-dev libsdl2-dev libopenal-dev \ - libogg-dev libvorbis-dev libmodplug-dev libmpg123-dev libtheora-dev - - name: Checkout - uses: actions/checkout@v2 - - name: Pre-Configure - run: $PWD/platform/unix/automagic - - name: Configure - run: mkdir build && cd build && ../configure - - name: Build - run: cd build && make -j2 - - name: Prepare appimagetool - run: | - cd build && - wget https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage -O appimagetool && - chmod +x appimagetool && - sudo apt install -y appstream - - name: Clone love-appimages + sudo apt-get install --assume-yes build-essential git make cmake autoconf automake \ + libtool pkg-config libasound2-dev libpulse-dev libaudio-dev \ + libjack-dev libx11-dev libxext-dev libxrandr-dev libxcursor-dev \ + libxfixes-dev libxi-dev libxinerama-dev libxxf86vm-dev libxss-dev \ + libgl1-mesa-dev libdbus-1-dev libudev-dev libgles2-mesa-dev \ + libegl1-mesa-dev libibus-1.0-dev fcitx-libs-dev libsamplerate0-dev \ + libsndio-dev libwayland-dev libxkbcommon-dev libdrm-dev libgbm-dev + - name: Checkout love-appimage-source uses: actions/checkout@v2 with: - path: build/love-appimages - repository: pfirsich/love-appimages + repository: MikuAuahDark/love-appimage-source + - name: Checkout LÖVE + uses: actions/checkout@v2 + with: + path: love2d-${{ github.sha }} - name: Build AppImage - run: | - cd build && - python3 love-appimages/build.py .. AppDir --builddir build --appimage love.AppImage + run: make LOVE_BRANCH=${{ github.sha }} + - name: Print LuaJIT branch + run: git -C LuaJIT-v2.1 branch -v - name: Artifact - uses: actions/upload-artifact@v2-preview + uses: actions/upload-artifact@v2 with: - name: love.AppImage - path: build/love.AppImage + name: love-x86_64.AppImage + path: love-${{ github.sha }}.AppImage windows-os: runs-on: windows-latest strategy: From 85894ad5e493253b2ab02979b74fa4ad1f5af1aa Mon Sep 17 00:00:00 2001 From: megagrump Date: Sun, 21 Nov 2021 01:04:48 +0100 Subject: [PATCH 28/43] use dt instead of inv_dt in RevoluteJoint::getMotorTorque --- src/modules/physics/box2d/RevoluteJoint.cpp | 3 ++- src/modules/physics/box2d/RevoluteJoint.h | 4 ++-- src/modules/physics/box2d/wrap_RevoluteJoint.cpp | 4 ++-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/modules/physics/box2d/RevoluteJoint.cpp b/src/modules/physics/box2d/RevoluteJoint.cpp index 9e580a326..4175389e7 100644 --- a/src/modules/physics/box2d/RevoluteJoint.cpp +++ b/src/modules/physics/box2d/RevoluteJoint.cpp @@ -101,8 +101,9 @@ float RevoluteJoint::getMotorSpeed() const return joint->GetMotorSpeed(); } -float RevoluteJoint::getMotorTorque(float inv_dt) const +float RevoluteJoint::getMotorTorque(float dt) const { + float inv_dt = 1.0f / dt; return Physics::scaleUp(Physics::scaleUp(joint->GetMotorTorque(inv_dt))); } diff --git a/src/modules/physics/box2d/RevoluteJoint.h b/src/modules/physics/box2d/RevoluteJoint.h index e69430c3c..12fdf041b 100644 --- a/src/modules/physics/box2d/RevoluteJoint.h +++ b/src/modules/physics/box2d/RevoluteJoint.h @@ -87,9 +87,9 @@ public: /** * Get the current motor torque, usually in N-m. - * @param inv_dt The inverse timestep. + * @param dt The timestep. **/ - float getMotorTorque(float inv_dt) const; + float getMotorTorque(float dt) const; /** * Get the maximum motor torque, usually in N-m. diff --git a/src/modules/physics/box2d/wrap_RevoluteJoint.cpp b/src/modules/physics/box2d/wrap_RevoluteJoint.cpp index 91e66345f..6d98de6e7 100644 --- a/src/modules/physics/box2d/wrap_RevoluteJoint.cpp +++ b/src/modules/physics/box2d/wrap_RevoluteJoint.cpp @@ -91,8 +91,8 @@ int w_RevoluteJoint_getMotorSpeed(lua_State *L) int w_RevoluteJoint_getMotorTorque(lua_State *L) { RevoluteJoint *t = luax_checkrevolutejoint(L, 1); - float inv_dt = (float)luaL_checknumber(L, 2); - lua_pushnumber(L, t->getMotorTorque(inv_dt)); + float dt = (float)luaL_checknumber(L, 2); + lua_pushnumber(L, t->getMotorTorque(dt)); return 1; } From 136c3cd2770125c694aa424338ffbf732bffe479 Mon Sep 17 00:00:00 2001 From: megagrump Date: Mon, 22 Nov 2021 14:57:05 +0100 Subject: [PATCH 29/43] use double precision numbers in love.math.noise --- src/libraries/noise1234/noise1234.cpp | 164 +++++++++---------- src/libraries/noise1234/noise1234.h | 28 ++-- src/libraries/noise1234/simplexnoise1234.cpp | 70 ++++---- src/libraries/noise1234/simplexnoise1234.h | 13 +- src/modules/math/MathModule.h | 8 +- src/modules/math/wrap_Math.cpp | 12 +- src/modules/math/wrap_Math.lua | 8 +- 7 files changed, 146 insertions(+), 157 deletions(-) diff --git a/src/libraries/noise1234/noise1234.cpp b/src/libraries/noise1234/noise1234.cpp index bb84642d9..a62bb08c8 100644 --- a/src/libraries/noise1234/noise1234.cpp +++ b/src/libraries/noise1234/noise1234.cpp @@ -106,47 +106,47 @@ unsigned char Noise1234::perm[] = {151,160,137,91,90,15, * float SLnoise = (Noise1234::noise(x,y,z) + 1.0) * 0.5; */ -float Noise1234::grad( int hash, float x ) { +double Noise1234::grad( int hash, double x ) { int h = hash & 15; - float grad = 1.0 + (h & 7); // Gradient value 1.0, 2.0, ..., 8.0 + double grad = 1.0 + (h & 7); // Gradient value 1.0, 2.0, ..., 8.0 if (h&8) grad = -grad; // and a random sign for the gradient return ( grad * x ); // Multiply the gradient with the distance } -float Noise1234::grad( int hash, float x, float y ) { - int h = hash & 7; // Convert low 3 bits of hash code - float u = h<4 ? x : y; // into 8 simple gradient directions, - float v = h<4 ? y : x; // and compute the dot product with (x,y). +double Noise1234::grad( int hash, double x, double y ) { + int h = hash & 7; // Convert low 3 bits of hash code + double u = h<4 ? x : y; // into 8 simple gradient directions, + double v = h<4 ? y : x; // and compute the dot product with (x,y). return ((h&1)? -u : u) + ((h&2)? -2.0*v : 2.0*v); } -float Noise1234::grad( int hash, float x, float y , float z ) { - int h = hash & 15; // Convert low 4 bits of hash code into 12 simple - float u = h<8 ? x : y; // gradient directions, and compute dot product. - float v = h<4 ? y : h==12||h==14 ? x : z; // Fix repeats at h = 12 to 15 +double Noise1234::grad( int hash, double x, double y , double z ) { + int h = hash & 15; // Convert low 4 bits of hash code into 12 simple + double u = h<8 ? x : y; // gradient directions, and compute dot product. + double v = h<4 ? y : h==12||h==14 ? x : z; // Fix repeats at h = 12 to 15 return ((h&1)? -u : u) + ((h&2)? -v : v); } -float Noise1234::grad( int hash, float x, float y, float z, float t ) { - int h = hash & 31; // Convert low 5 bits of hash code into 32 simple - float u = h<24 ? x : y; // gradient directions, and compute dot product. - float v = h<16 ? y : z; - float w = h<8 ? z : t; +double Noise1234::grad( int hash, double x, double y, double z, double t ) { + int h = hash & 31; // Convert low 5 bits of hash code into 32 simple + double u = h<24 ? x : y; // gradient directions, and compute dot product. + double v = h<16 ? y : z; + double w = h<8 ? z : t; return ((h&1)? -u : u) + ((h&2)? -v : v) + ((h&4)? -w : w); } //--------------------------------------------------------------------- /** 1D float Perlin noise, SL "noise()" */ -float Noise1234::noise( float x ) +float Noise1234::noise( double x ) { int ix0, ix1; - float fx0, fx1; - float s, n0, n1; + double fx0, fx1; + double s, n0, n1; ix0 = FASTFLOOR( x ); // Integer part of x - fx0 = x - ix0; // Fractional part of x - fx1 = fx0 - 1.0f; + fx0 = x - ix0; // Fractional part of x + fx1 = fx0 - 1.0; ix1 = ( ix0+1 ) & 0xff; ix0 = ix0 & 0xff; // Wrap to 0..255 @@ -160,17 +160,17 @@ float Noise1234::noise( float x ) //--------------------------------------------------------------------- /** 1D float Perlin periodic noise, SL "pnoise()" */ -float Noise1234::pnoise( float x, int px ) +float Noise1234::pnoise( double x, int px ) { int ix0, ix1; - float fx0, fx1; - float s, n0, n1; + double fx0, fx1; + double s, n0, n1; ix0 = FASTFLOOR( x ); // Integer part of x - fx0 = x - ix0; // Fractional part of x - fx1 = fx0 - 1.0f; + fx0 = x - ix0; // Fractional part of x + fx1 = fx0 - 1.0; ix1 = (( ix0 + 1 ) % px) & 0xff; // Wrap to 0..px-1 *and* wrap to 0..255 - ix0 = ( ix0 % px ) & 0xff; // (because px might be greater than 256) + ix0 = ( ix0 % px ) & 0xff; // (because px might be greater than 256) s = FADE( fx0 ); @@ -183,23 +183,23 @@ float Noise1234::pnoise( float x, int px ) //--------------------------------------------------------------------- /** 2D float Perlin noise. */ -float Noise1234::noise( float x, float y ) +float Noise1234::noise( double x, double y ) { int ix0, iy0, ix1, iy1; - float fx0, fy0, fx1, fy1; - float s, t, nx0, nx1, n0, n1; + double fx0, fy0, fx1, fy1; + double s, t, nx0, nx1, n0, n1; ix0 = FASTFLOOR( x ); // Integer part of x iy0 = FASTFLOOR( y ); // Integer part of y fx0 = x - ix0; // Fractional part of x fy0 = y - iy0; // Fractional part of y - fx1 = fx0 - 1.0f; - fy1 = fy0 - 1.0f; + fx1 = fx0 - 1.0; + fy1 = fy0 - 1.0; ix1 = (ix0 + 1) & 0xff; // Wrap to 0..255 iy1 = (iy0 + 1) & 0xff; ix0 = ix0 & 0xff; iy0 = iy0 & 0xff; - + t = FADE( fy0 ); s = FADE( fx0 ); @@ -217,23 +217,23 @@ float Noise1234::noise( float x, float y ) //--------------------------------------------------------------------- /** 2D float Perlin periodic noise. */ -float Noise1234::pnoise( float x, float y, int px, int py ) +float Noise1234::pnoise( double x, double y, int px, int py ) { int ix0, iy0, ix1, iy1; - float fx0, fy0, fx1, fy1; - float s, t, nx0, nx1, n0, n1; + double fx0, fy0, fx1, fy1; + double s, t, nx0, nx1, n0, n1; ix0 = FASTFLOOR( x ); // Integer part of x iy0 = FASTFLOOR( y ); // Integer part of y fx0 = x - ix0; // Fractional part of x fy0 = y - iy0; // Fractional part of y - fx1 = fx0 - 1.0f; - fy1 = fy0 - 1.0f; + fx1 = fx0 - 1.0; + fy1 = fy0 - 1.0; ix1 = (( ix0 + 1 ) % px) & 0xff; // Wrap to 0..px-1 and wrap to 0..255 iy1 = (( iy0 + 1 ) % py) & 0xff; // Wrap to 0..py-1 and wrap to 0..255 ix0 = ( ix0 % px ) & 0xff; iy0 = ( iy0 % py ) & 0xff; - + t = FADE( fy0 ); s = FADE( fx0 ); @@ -252,12 +252,12 @@ float Noise1234::pnoise( float x, float y, int px, int py ) //--------------------------------------------------------------------- /** 3D float Perlin noise. */ -float Noise1234::noise( float x, float y, float z ) +float Noise1234::noise( double x, double y, double z ) { int ix0, iy0, ix1, iy1, iz0, iz1; - float fx0, fy0, fz0, fx1, fy1, fz1; - float s, t, r; - float nxy0, nxy1, nx0, nx1, n0, n1; + double fx0, fy0, fz0, fx1, fy1, fz1; + double s, t, r; + double nxy0, nxy1, nx0, nx1, n0, n1; ix0 = FASTFLOOR( x ); // Integer part of x iy0 = FASTFLOOR( y ); // Integer part of y @@ -265,16 +265,16 @@ float Noise1234::noise( float x, float y, float z ) fx0 = x - ix0; // Fractional part of x fy0 = y - iy0; // Fractional part of y fz0 = z - iz0; // Fractional part of z - fx1 = fx0 - 1.0f; - fy1 = fy0 - 1.0f; - fz1 = fz0 - 1.0f; + fx1 = fx0 - 1.0; + fy1 = fy0 - 1.0; + fz1 = fz0 - 1.0; ix1 = ( ix0 + 1 ) & 0xff; // Wrap to 0..255 iy1 = ( iy0 + 1 ) & 0xff; iz1 = ( iz0 + 1 ) & 0xff; ix0 = ix0 & 0xff; iy0 = iy0 & 0xff; iz0 = iz0 & 0xff; - + r = FADE( fz0 ); t = FADE( fy0 ); s = FADE( fx0 ); @@ -298,19 +298,19 @@ float Noise1234::noise( float x, float y, float z ) nx1 = LERP( r, nxy0, nxy1 ); n1 = LERP( t, nx0, nx1 ); - + return 0.936f * ( LERP( s, n0, n1 ) ); } //--------------------------------------------------------------------- /** 3D float Perlin periodic noise. */ -float Noise1234::pnoise( float x, float y, float z, int px, int py, int pz ) +float Noise1234::pnoise( double x, double y, double z, int px, int py, int pz ) { int ix0, iy0, ix1, iy1, iz0, iz1; - float fx0, fy0, fz0, fx1, fy1, fz1; - float s, t, r; - float nxy0, nxy1, nx0, nx1, n0, n1; + double fx0, fy0, fz0, fx1, fy1, fz1; + double s, t, r; + double nxy0, nxy1, nx0, nx1, n0, n1; ix0 = FASTFLOOR( x ); // Integer part of x iy0 = FASTFLOOR( y ); // Integer part of y @@ -318,16 +318,16 @@ float Noise1234::pnoise( float x, float y, float z, int px, int py, int pz ) fx0 = x - ix0; // Fractional part of x fy0 = y - iy0; // Fractional part of y fz0 = z - iz0; // Fractional part of z - fx1 = fx0 - 1.0f; - fy1 = fy0 - 1.0f; - fz1 = fz0 - 1.0f; + fx1 = fx0 - 1.0; + fy1 = fy0 - 1.0; + fz1 = fz0 - 1.0; ix1 = (( ix0 + 1 ) % px ) & 0xff; // Wrap to 0..px-1 and wrap to 0..255 iy1 = (( iy0 + 1 ) % py ) & 0xff; // Wrap to 0..py-1 and wrap to 0..255 iz1 = (( iz0 + 1 ) % pz ) & 0xff; // Wrap to 0..pz-1 and wrap to 0..255 ix0 = ( ix0 % px ) & 0xff; iy0 = ( iy0 % py ) & 0xff; iz0 = ( iz0 % pz ) & 0xff; - + r = FADE( fz0 ); t = FADE( fy0 ); s = FADE( fx0 ); @@ -351,7 +351,7 @@ float Noise1234::pnoise( float x, float y, float z, int px, int py, int pz ) nx1 = LERP( r, nxy0, nxy1 ); n1 = LERP( t, nx0, nx1 ); - + return 0.936f * ( LERP( s, n0, n1 ) ); } @@ -360,12 +360,12 @@ float Noise1234::pnoise( float x, float y, float z, int px, int py, int pz ) /** 4D float Perlin noise. */ -float Noise1234::noise( float x, float y, float z, float w ) +float Noise1234::noise( double x, double y, double z, double w ) { int ix0, iy0, iz0, iw0, ix1, iy1, iz1, iw1; - float fx0, fy0, fz0, fw0, fx1, fy1, fz1, fw1; - float s, t, r, q; - float nxyz0, nxyz1, nxy0, nxy1, nx0, nx1, n0, n1; + double fx0, fy0, fz0, fw0, fx1, fy1, fz1, fw1; + double s, t, r, q; + double nxyz0, nxyz1, nxy0, nxy1, nx0, nx1, n0, n1; ix0 = FASTFLOOR( x ); // Integer part of x iy0 = FASTFLOOR( y ); // Integer part of y @@ -375,10 +375,10 @@ float Noise1234::noise( float x, float y, float z, float w ) fy0 = y - iy0; // Fractional part of y fz0 = z - iz0; // Fractional part of z fw0 = w - iw0; // Fractional part of w - fx1 = fx0 - 1.0f; - fy1 = fy0 - 1.0f; - fz1 = fz0 - 1.0f; - fw1 = fw0 - 1.0f; + fx1 = fx0 - 1.0; + fy1 = fy0 - 1.0; + fz1 = fz0 - 1.0; + fw1 = fw0 - 1.0; ix1 = ( ix0 + 1 ) & 0xff; // Wrap to 0..255 iy1 = ( iy0 + 1 ) & 0xff; iz1 = ( iz0 + 1 ) & 0xff; @@ -396,17 +396,17 @@ float Noise1234::noise( float x, float y, float z, float w ) nxyz0 = grad(perm[ix0 + perm[iy0 + perm[iz0 + perm[iw0]]]], fx0, fy0, fz0, fw0); nxyz1 = grad(perm[ix0 + perm[iy0 + perm[iz0 + perm[iw1]]]], fx0, fy0, fz0, fw1); nxy0 = LERP( q, nxyz0, nxyz1 ); - + nxyz0 = grad(perm[ix0 + perm[iy0 + perm[iz1 + perm[iw0]]]], fx0, fy0, fz1, fw0); nxyz1 = grad(perm[ix0 + perm[iy0 + perm[iz1 + perm[iw1]]]], fx0, fy0, fz1, fw1); nxy1 = LERP( q, nxyz0, nxyz1 ); - + nx0 = LERP ( r, nxy0, nxy1 ); nxyz0 = grad(perm[ix0 + perm[iy1 + perm[iz0 + perm[iw0]]]], fx0, fy1, fz0, fw0); nxyz1 = grad(perm[ix0 + perm[iy1 + perm[iz0 + perm[iw1]]]], fx0, fy1, fz0, fw1); nxy0 = LERP( q, nxyz0, nxyz1 ); - + nxyz0 = grad(perm[ix0 + perm[iy1 + perm[iz1 + perm[iw0]]]], fx0, fy1, fz1, fw0); nxyz1 = grad(perm[ix0 + perm[iy1 + perm[iz1 + perm[iw1]]]], fx0, fy1, fz1, fw1); nxy1 = LERP( q, nxyz0, nxyz1 ); @@ -418,7 +418,7 @@ float Noise1234::noise( float x, float y, float z, float w ) nxyz0 = grad(perm[ix1 + perm[iy0 + perm[iz0 + perm[iw0]]]], fx1, fy0, fz0, fw0); nxyz1 = grad(perm[ix1 + perm[iy0 + perm[iz0 + perm[iw1]]]], fx1, fy0, fz0, fw1); nxy0 = LERP( q, nxyz0, nxyz1 ); - + nxyz0 = grad(perm[ix1 + perm[iy0 + perm[iz1 + perm[iw0]]]], fx1, fy0, fz1, fw0); nxyz1 = grad(perm[ix1 + perm[iy0 + perm[iz1 + perm[iw1]]]], fx1, fy0, fz1, fw1); nxy1 = LERP( q, nxyz0, nxyz1 ); @@ -428,7 +428,7 @@ float Noise1234::noise( float x, float y, float z, float w ) nxyz0 = grad(perm[ix1 + perm[iy1 + perm[iz0 + perm[iw0]]]], fx1, fy1, fz0, fw0); nxyz1 = grad(perm[ix1 + perm[iy1 + perm[iz0 + perm[iw1]]]], fx1, fy1, fz0, fw1); nxy0 = LERP( q, nxyz0, nxyz1 ); - + nxyz0 = grad(perm[ix1 + perm[iy1 + perm[iz1 + perm[iw0]]]], fx1, fy1, fz1, fw0); nxyz1 = grad(perm[ix1 + perm[iy1 + perm[iz1 + perm[iw1]]]], fx1, fy1, fz1, fw1); nxy1 = LERP( q, nxyz0, nxyz1 ); @@ -444,13 +444,13 @@ float Noise1234::noise( float x, float y, float z, float w ) /** 4D float Perlin periodic noise. */ -float Noise1234::pnoise( float x, float y, float z, float w, +float Noise1234::pnoise( double x, double y, double z, double w, int px, int py, int pz, int pw ) { int ix0, iy0, iz0, iw0, ix1, iy1, iz1, iw1; - float fx0, fy0, fz0, fw0, fx1, fy1, fz1, fw1; - float s, t, r, q; - float nxyz0, nxyz1, nxy0, nxy1, nx0, nx1, n0, n1; + double fx0, fy0, fz0, fw0, fx1, fy1, fz1, fw1; + double s, t, r, q; + double nxyz0, nxyz1, nxy0, nxy1, nx0, nx1, n0, n1; ix0 = FASTFLOOR( x ); // Integer part of x iy0 = FASTFLOOR( y ); // Integer part of y @@ -460,10 +460,10 @@ float Noise1234::pnoise( float x, float y, float z, float w, fy0 = y - iy0; // Fractional part of y fz0 = z - iz0; // Fractional part of z fw0 = w - iw0; // Fractional part of w - fx1 = fx0 - 1.0f; - fy1 = fy0 - 1.0f; - fz1 = fz0 - 1.0f; - fw1 = fw0 - 1.0f; + fx1 = fx0 - 1.0; + fy1 = fy0 - 1.0; + fz1 = fz0 - 1.0; + fw1 = fw0 - 1.0; ix1 = (( ix0 + 1 ) % px ) & 0xff; // Wrap to 0..px-1 and wrap to 0..255 iy1 = (( iy0 + 1 ) % py ) & 0xff; // Wrap to 0..py-1 and wrap to 0..255 iz1 = (( iz0 + 1 ) % pz ) & 0xff; // Wrap to 0..pz-1 and wrap to 0..255 @@ -481,17 +481,17 @@ float Noise1234::pnoise( float x, float y, float z, float w, nxyz0 = grad(perm[ix0 + perm[iy0 + perm[iz0 + perm[iw0]]]], fx0, fy0, fz0, fw0); nxyz1 = grad(perm[ix0 + perm[iy0 + perm[iz0 + perm[iw1]]]], fx0, fy0, fz0, fw1); nxy0 = LERP( q, nxyz0, nxyz1 ); - + nxyz0 = grad(perm[ix0 + perm[iy0 + perm[iz1 + perm[iw0]]]], fx0, fy0, fz1, fw0); nxyz1 = grad(perm[ix0 + perm[iy0 + perm[iz1 + perm[iw1]]]], fx0, fy0, fz1, fw1); nxy1 = LERP( q, nxyz0, nxyz1 ); - + nx0 = LERP ( r, nxy0, nxy1 ); nxyz0 = grad(perm[ix0 + perm[iy1 + perm[iz0 + perm[iw0]]]], fx0, fy1, fz0, fw0); nxyz1 = grad(perm[ix0 + perm[iy1 + perm[iz0 + perm[iw1]]]], fx0, fy1, fz0, fw1); nxy0 = LERP( q, nxyz0, nxyz1 ); - + nxyz0 = grad(perm[ix0 + perm[iy1 + perm[iz1 + perm[iw0]]]], fx0, fy1, fz1, fw0); nxyz1 = grad(perm[ix0 + perm[iy1 + perm[iz1 + perm[iw1]]]], fx0, fy1, fz1, fw1); nxy1 = LERP( q, nxyz0, nxyz1 ); @@ -503,7 +503,7 @@ float Noise1234::pnoise( float x, float y, float z, float w, nxyz0 = grad(perm[ix1 + perm[iy0 + perm[iz0 + perm[iw0]]]], fx1, fy0, fz0, fw0); nxyz1 = grad(perm[ix1 + perm[iy0 + perm[iz0 + perm[iw1]]]], fx1, fy0, fz0, fw1); nxy0 = LERP( q, nxyz0, nxyz1 ); - + nxyz0 = grad(perm[ix1 + perm[iy0 + perm[iz1 + perm[iw0]]]], fx1, fy0, fz1, fw0); nxyz1 = grad(perm[ix1 + perm[iy0 + perm[iz1 + perm[iw1]]]], fx1, fy0, fz1, fw1); nxy1 = LERP( q, nxyz0, nxyz1 ); @@ -513,7 +513,7 @@ float Noise1234::pnoise( float x, float y, float z, float w, nxyz0 = grad(perm[ix1 + perm[iy1 + perm[iz0 + perm[iw0]]]], fx1, fy1, fz0, fw0); nxyz1 = grad(perm[ix1 + perm[iy1 + perm[iz0 + perm[iw1]]]], fx1, fy1, fz0, fw1); nxy0 = LERP( q, nxyz0, nxyz1 ); - + nxyz0 = grad(perm[ix1 + perm[iy1 + perm[iz1 + perm[iw0]]]], fx1, fy1, fz1, fw0); nxyz1 = grad(perm[ix1 + perm[iy1 + perm[iz1 + perm[iw1]]]], fx1, fy1, fz1, fw1); nxy1 = LERP( q, nxyz0, nxyz1 ); diff --git a/src/libraries/noise1234/noise1234.h b/src/libraries/noise1234/noise1234.h index 928572a55..dbc867e13 100644 --- a/src/libraries/noise1234/noise1234.h +++ b/src/libraries/noise1234/noise1234.h @@ -20,10 +20,6 @@ * This is a clean, fast, modern and free Perlin noise class in C++. * Being a stand-alone class with no external dependencies, it is * highly reusable without source code modifications. - * - * Note: - * Replacing the "float" type with "double" can actually make this run faster - * on some platforms. A templatized version of Noise1234 could be useful. */ class Noise1234 { @@ -34,24 +30,24 @@ class Noise1234 { /** 1D, 2D, 3D and 4D float Perlin noise, SL "noise()" */ - static float noise( float x ); - static float noise( float x, float y ); - static float noise( float x, float y, float z ); - static float noise( float x, float y, float z, float w ); + static float noise( double x ); + static float noise( double x, double y ); + static float noise( double x, double y, double z ); + static float noise( double x, double y, double z, double w ); /** 1D, 2D, 3D and 4D float Perlin periodic noise, SL "pnoise()" */ - static float pnoise( float x, int px ); - static float pnoise( float x, float y, int px, int py ); - static float pnoise( float x, float y, float z, int px, int py, int pz ); - static float pnoise( float x, float y, float z, float w, + static float pnoise( double x, int px ); + static float pnoise( double x, double y, int px, int py ); + static float pnoise( double x, double y, double z, int px, int py, int pz ); + static float pnoise( double x, double y, double z, double w, int px, int py, int pz, int pw ); private: static unsigned char perm[]; - static float grad( int hash, float x ); - static float grad( int hash, float x, float y ); - static float grad( int hash, float x, float y , float z ); - static float grad( int hash, float x, float y, float z, float t ); + static double grad( int hash, double x ); + static double grad( int hash, double x, double y ); + static double grad( int hash, double x, double y , double z ); + static double grad( int hash, double x, double y, double z, double t ); }; diff --git a/src/libraries/noise1234/simplexnoise1234.cpp b/src/libraries/noise1234/simplexnoise1234.cpp index 2765f38e1..b2caec4ad 100644 --- a/src/libraries/noise1234/simplexnoise1234.cpp +++ b/src/libraries/noise1234/simplexnoise1234.cpp @@ -85,7 +85,7 @@ unsigned char SimplexNoise1234::perm[512] = {151,160,137,91,90,15, 129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,97,228, 251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,107, 49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254, - 138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180 + 138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180 }; //--------------------------------------------------------------------- @@ -103,37 +103,35 @@ unsigned char SimplexNoise1234::perm[512] = {151,160,137,91,90,15, * float SLnoise = (SimplexNoise1234::noise(x,y,z) + 1.0) * 0.5; */ -float SimplexNoise1234::grad( int hash, float x ) { +double SimplexNoise1234::grad( int hash, double x ) { int h = hash & 15; - float grad = 1.0f + (h & 7); // Gradient value 1.0, 2.0, ..., 8.0 + double grad = 1.0 + (h & 7); // Gradient value 1.0, 2.0, ..., 8.0 if (h&8) grad = -grad; // Set a random sign for the gradient return ( grad * x ); // Multiply the gradient with the distance } -float SimplexNoise1234::grad( int hash, float x, float y ) { +double SimplexNoise1234::grad( int hash, double x, double y ) { int h = hash & 7; // Convert low 3 bits of hash code - float u = h<4 ? x : y; // into 8 simple gradient directions, - float v = h<4 ? y : x; // and compute the dot product with (x,y). - return ((h&1)? -u : u) + ((h&2)? -2.0f*v : 2.0f*v); + double u = h<4 ? x : y; // into 8 simple gradient directions, + double v = h<4 ? y : x; // and compute the dot product with (x,y). + return ((h&1)? -u : u) + ((h&2)? -2.0*v : 2.0*v); } // 1D simplex noise -float SimplexNoise1234::noise(float x) { +float SimplexNoise1234::noise(double x) { int i0 = FASTFLOOR(x); int i1 = i0 + 1; - float x0 = x - i0; - float x1 = x0 - 1.0f; + double x0 = x - i0; + double x1 = x0 - 1.0; - float n0, n1; + double n0, n1; - float t0 = 1.0f - x0*x0; -// if(t0 < 0.0f) t0 = 0.0f; + double t0 = 1.0 - x0*x0; t0 *= t0; n0 = t0 * t0 * grad(perm[i0 & 0xff], x0); - float t1 = 1.0f - x1*x1; -// if(t1 < 0.0f) t1 = 0.0f; + double t1 = 1.0 - x1*x1; t1 *= t1; n1 = t1 * t1 * grad(perm[i1 & 0xff], x1); // The maximum value of this noise is 8*(3/4)^4 = 2.53125 @@ -143,25 +141,25 @@ float SimplexNoise1234::noise(float x) { } // 2D simplex noise -float SimplexNoise1234::noise(float x, float y) { +float SimplexNoise1234::noise(double x, double y) { #define F2 0.366025403 // F2 = 0.5*(sqrt(3.0)-1.0) #define G2 0.211324865 // G2 = (3.0-Math.sqrt(3.0))/6.0 - float n0, n1, n2; // Noise contributions from the three corners + double n0, n1, n2; // Noise contributions from the three corners // Skew the input space to determine which simplex cell we're in - float s = (x+y)*F2; // Hairy factor for 2D - float xs = x + s; - float ys = y + s; + double s = (x+y)*F2; // Hairy factor for 2D + double xs = x + s; + double ys = y + s; int i = FASTFLOOR(xs); int j = FASTFLOOR(ys); - float t = (float)(i+j)*G2; - float X0 = i-t; // Unskew the cell origin back to (x,y) space - float Y0 = j-t; - float x0 = x-X0; // The x,y distances from the cell origin - float y0 = y-Y0; + double t = (i+j)*G2; + double X0 = i-t; // Unskew the cell origin back to (x,y) space + double Y0 = j-t; + double x0 = x-X0; // The x,y distances from the cell origin + double y0 = y-Y0; // For the 2D case, the simplex shape is an equilateral triangle. // Determine which simplex we are in. @@ -173,32 +171,32 @@ float SimplexNoise1234::noise(float x, float y) { // a step of (0,1) in (i,j) means a step of (-c,1-c) in (x,y), where // c = (3-sqrt(3))/6 - float x1 = x0 - i1 + G2; // Offsets for middle corner in (x,y) unskewed coords - float y1 = y0 - j1 + G2; - float x2 = x0 - 1.0f + 2.0f * G2; // Offsets for last corner in (x,y) unskewed coords - float y2 = y0 - 1.0f + 2.0f * G2; + double x1 = x0 - i1 + G2; // Offsets for middle corner in (x,y) unskewed coords + double y1 = y0 - j1 + G2; + double x2 = x0 - 1.0 + 2.0 * G2; // Offsets for last corner in (x,y) unskewed coords + double y2 = y0 - 1.0 + 2.0 * G2; // Wrap the integer indices at 256, to avoid indexing perm[] out of bounds int ii = i & 0xff; int jj = j & 0xff; // Calculate the contribution from the three corners - float t0 = 0.5f - x0*x0-y0*y0; - if(t0 < 0.0f) n0 = 0.0f; + double t0 = 0.5 - x0*x0-y0*y0; + if(t0 < 0.0) n0 = 0.0; else { t0 *= t0; - n0 = t0 * t0 * grad(perm[ii+perm[jj]], x0, y0); + n0 = t0 * t0 * grad(perm[ii+perm[jj]], x0, y0); } - float t1 = 0.5f - x1*x1-y1*y1; - if(t1 < 0.0f) n1 = 0.0f; + double t1 = 0.5 - x1*x1-y1*y1; + if(t1 < 0.0) n1 = 0.0; else { t1 *= t1; n1 = t1 * t1 * grad(perm[ii+i1+perm[jj+j1]], x1, y1); } - float t2 = 0.5f - x2*x2-y2*y2; - if(t2 < 0.0f) n2 = 0.0f; + double t2 = 0.5 - x2*x2-y2*y2; + if(t2 < 0.0) n2 = 0.0; else { t2 *= t2; n2 = t2 * t2 * grad(perm[ii+1+perm[jj+1]], x2, y2); diff --git a/src/libraries/noise1234/simplexnoise1234.h b/src/libraries/noise1234/simplexnoise1234.h index 6aceb6b61..137edf5dc 100644 --- a/src/libraries/noise1234/simplexnoise1234.h +++ b/src/libraries/noise1234/simplexnoise1234.h @@ -25,11 +25,6 @@ * This is a clean, fast, modern and free Perlin Simplex noise class in C++. * Being a stand-alone class with no external dependencies, it is * highly reusable without source code modifications. - * - * - * Note: - * Replacing the "float" type with "double" can actually make this run faster - * on some platforms. A templatized version of SimplexNoise1234 could be useful. */ class SimplexNoise1234 { @@ -40,12 +35,12 @@ class SimplexNoise1234 { /** 1D and 2D float Perlin noise */ - static float noise( float x ); - static float noise( float x, float y ); + static float noise( double x ); + static float noise( double x, double y ); private: static unsigned char perm[]; - static float grad( int hash, float x ); - static float grad( int hash, float x, float y ); + static double grad( int hash, double x ); + static double grad( int hash, double x, double y ); }; diff --git a/src/modules/math/MathModule.h b/src/modules/math/MathModule.h index 9fb1795cf..bce3de5a9 100644 --- a/src/modules/math/MathModule.h +++ b/src/modules/math/MathModule.h @@ -132,12 +132,12 @@ private: }; // Math -static inline float noise1(float x) +static inline float noise1(double x) { return SimplexNoise1234::noise(x) * 0.5f + 0.5f; } -static inline float noise2(float x, float y) +static inline float noise2(double x, double y) { return SimplexNoise1234::noise(x, y) * 0.5f + 0.5f; } @@ -145,12 +145,12 @@ static inline float noise2(float x, float y) // Perlin noise is used instead of Simplex noise in the 3D and 4D cases to avoid // patent issues. -static inline float noise3(float x, float y, float z) +static inline float noise3(double x, double y, double z) { return Noise1234::noise(x, y, z) * 0.5f + 0.5f; } -static inline float noise4(float x, float y, float z, float w) +static inline float noise4(double x, double y, double z, double w) { return Noise1234::noise(x, y, z, w) * 0.5f + 0.5f; } diff --git a/src/modules/math/wrap_Math.cpp b/src/modules/math/wrap_Math.cpp index b7be334d6..cb9933513 100644 --- a/src/modules/math/wrap_Math.cpp +++ b/src/modules/math/wrap_Math.cpp @@ -319,10 +319,10 @@ int w_linearToGamma(lua_State *L) int w_noise(lua_State *L) { int nargs = std::min(std::max(lua_gettop(L), 1), 4); - float args[4]; + double args[4]; for (int i = 0; i < nargs; i++) - args[i] = (float) luaL_checknumber(L, i + 1); + args[i] = luaL_checknumber(L, i + 1); float val = 0.0f; @@ -349,10 +349,10 @@ int w_noise(lua_State *L) // C functions in a struct, necessary for the FFI versions of math functions. struct FFI_Math { - float (*noise1)(float x); - float (*noise2)(float x, float y); - float (*noise3)(float x, float y, float z); - float (*noise4)(float x, float y, float z, float w); + float (*noise1)(double x); + float (*noise2)(double x, double y); + float (*noise3)(double x, double y, double z); + float (*noise4)(double x, double y, double z, double w); float (*gammaToLinear)(float c); float (*linearToGamma)(float c); diff --git a/src/modules/math/wrap_Math.lua b/src/modules/math/wrap_Math.lua index 8aedbb924..7ad612ce9 100644 --- a/src/modules/math/wrap_Math.lua +++ b/src/modules/math/wrap_Math.lua @@ -93,10 +93,10 @@ if not status then return end pcall(ffi.cdef, [[ typedef struct FFI_Math { - float (*noise1)(float x); - float (*noise2)(float x, float y); - float (*noise3)(float x, float y, float z); - float (*noise4)(float x, float y, float z, float w); + float (*noise1)(double x); + float (*noise2)(double x, double y); + float (*noise3)(double x, double y, double z); + float (*noise4)(double x, double y, double z, double w); float (*gammaToLinear)(float c); float (*linearToGamma)(float c); From b87034404e7e165489175e85c58d53d489d25960 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Wed, 24 Nov 2021 21:15:51 -0400 Subject: [PATCH 30/43] newVideo: slightly more descriptive error when given an invalid file --- src/modules/video/theora/OggDemuxer.cpp | 12 ++++++++---- src/modules/video/theora/OggDemuxer.h | 2 +- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/modules/video/theora/OggDemuxer.cpp b/src/modules/video/theora/OggDemuxer.cpp index acc6f9849..31136c897 100644 --- a/src/modules/video/theora/OggDemuxer.cpp +++ b/src/modules/video/theora/OggDemuxer.cpp @@ -43,7 +43,7 @@ OggDemuxer::~OggDemuxer() ogg_sync_clear(&sync); } -void OggDemuxer::readPage(bool throweof) +bool OggDemuxer::readPage(bool erroreof) { char *syncBuffer = nullptr; while (ogg_sync_pageout(&sync, &page) != 1) @@ -53,11 +53,13 @@ void OggDemuxer::readPage(bool throweof) syncBuffer = ogg_sync_buffer(&sync, 8192); size_t read = file->read(syncBuffer, 8192); - if (read == 0 && throweof) - throw love::Exception("Invalid stream"); + if (read == 0 && erroreof) + return false; ogg_sync_wrote(&sync, read); } + + return true; } bool OggDemuxer::readPacket(ogg_packet &packet, bool mustSucceed) @@ -129,8 +131,10 @@ OggDemuxer::StreamType OggDemuxer::findStream() while (true) { + if (!readPage(true)) + return TYPE_UNKNOWN; + // If this page isn't at the start of a stream, we've seen all streams - readPage(true); if (!ogg_page_bos(&page)) break; diff --git a/src/modules/video/theora/OggDemuxer.h b/src/modules/video/theora/OggDemuxer.h index f55a352d2..242f73717 100644 --- a/src/modules/video/theora/OggDemuxer.h +++ b/src/modules/video/theora/OggDemuxer.h @@ -67,7 +67,7 @@ private: int videoSerial; bool eos; - void readPage(bool throweof = false); + bool readPage(bool erroreof = false); StreamType determineType(); }; // OggDemuxer From 8f9d1d7f82f860e93baaef1ea0872605740d30fb Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Wed, 24 Nov 2021 21:18:45 -0400 Subject: [PATCH 31/43] xcode: address setting recommendations added in 13.1 --- platform/xcode/liblove.xcodeproj/project.pbxproj | 2 +- platform/xcode/love.xcodeproj/project.pbxproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/platform/xcode/liblove.xcodeproj/project.pbxproj b/platform/xcode/liblove.xcodeproj/project.pbxproj index 113fd36ff..9a405300a 100644 --- a/platform/xcode/liblove.xcodeproj/project.pbxproj +++ b/platform/xcode/liblove.xcodeproj/project.pbxproj @@ -4141,7 +4141,7 @@ 08FB7793FE84155DC02AAC07 /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 1250; + LastUpgradeCheck = 1310; TargetAttributes = { FA0B78DC1A958B90000E1D17 = { CreatedOnToolsVersion = 6.1.1; diff --git a/platform/xcode/love.xcodeproj/project.pbxproj b/platform/xcode/love.xcodeproj/project.pbxproj index babecde81..d03d1b52e 100644 --- a/platform/xcode/love.xcodeproj/project.pbxproj +++ b/platform/xcode/love.xcodeproj/project.pbxproj @@ -328,7 +328,7 @@ 29B97313FDCFA39411CA2CEA /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 1250; + LastUpgradeCheck = 1310; TargetAttributes = { FA0B7F051A95AAF3000E1D17 = { CreatedOnToolsVersion = 6.1.1; From c5b8930a751377f5e69d6cf6166f7ffed895aefd Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Wed, 24 Nov 2021 21:30:18 -0400 Subject: [PATCH 32/43] Updated changelog --- changes.txt | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/changes.txt b/changes.txt index 2bbb7c89e..c46ccde82 100644 --- a/changes.txt +++ b/changes.txt @@ -3,12 +3,14 @@ LOVE 11.4 [Mysterious Mysteries] Released: N/A +* Added native arm64 support on macOS. * Added Body:getLocalPoints. * Added Font:getKerning. * Added support for r16, rg16, and rgba16 pixel formats in Canvases. * Added Shader:send(name, matrixlayout, data, ...) variant, whose argument order is more consistent than Shader:send(name, data, matrixlayout, ...). * Changed love.timer.getTime to start at 0 when the module is first loaded. +* Changed certain out-of-Lua-memory situations to show a message box instead of instantly crashing. * Fixed build-time compatibility with Lua 5.4. * Fixed code compatibility with math.mod and string.gfind when LuaJIT 2.1 is used. @@ -19,21 +21,28 @@ Released: N/A * Fixed support for > 2GB dropped files on desktops. * Fixed love.physics meter scale value persisting after love.event.quit("restart"). * Fixed audio to resume properly after interruption on iOS. +* Fixed love.graphics.newVideo to error instead of crash when an invalid video file is given. * Fixed initial window creation to set the window's title during creation instead of after. * Fixed the window's screen position when exiting fullscreen via love.window.setFullscreen. +* Fixed love.displayrotated being given a boolean instead of an enum string. * Fixed memory corruption and a crash when drawing smooth lines. * Fixed a crash in Canvas:newImageData when the pixel format's pixel byte size multiplied by its width isn't a multiple of 4. * Fixed love.graphics.newVolumeImage when explicit mipmaps are provided. * Fixed freezes and crashes in automatic batching when an AMD GPU is used. * Fixed love.graphics.print and Image:replacePixels on more AMD/ATI GPUs. * Fixed Font:setFallbacks to account for different DPI scales in each fallback font. +* Fixed Font:getWrap to not remove trailing newlines. * Fixed Text:getWidth when the Text's string only contains spaces. * Fixed a crash with some Intel graphics drivers on Linux. * Fixed a hang with some Intel graphics drivers on Windows, by preventing gamma correct rendering on affected systems. * Fixed a crash with some Intel graphics drivers on Windows when mipmapped Canvases are used. * Fixed texture memory reported by love.graphics.getStats when a volume or array Canvas is created. +* Fixed DXT1 textures which use 1 bit alpha-cutout. * Fixed rare issues where textures were not sent to shaders correctly. * Fixed Shader:send(name, data, matrixlayout, ...). +* Fixed quad offsets in ParticleSystems when ParticleSystem:setOffset is not used. +* Fixed rounded rectangles breaking if the rx or ry parameters are negative. +* Fixed rounded rectangle automatic points calculation when rx or ry are more than half the rectangle's size. * Fixed source code compilation on Xcode 12+. * Fixed source code compilation on Linux systems that don't provide posix_spawn APIs. From 9a480d77527d29027b1ceaf4b975e5ed2c90debb Mon Sep 17 00:00:00 2001 From: Kai Date: Sun, 28 Nov 2021 18:36:00 +0100 Subject: [PATCH 33/43] README.md: HTTP => HTTPS --- readme.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/readme.md b/readme.md index da777de6b..ceba05852 100644 --- a/readme.md +++ b/readme.md @@ -84,16 +84,16 @@ Dependencies - Vorbisfile - Theora -[site]: http://love2d.org -[wiki]: http://love2d.org/wiki -[forums]: http://love2d.org/forums +[site]: https://love2d.org +[wiki]: https://love2d.org/wiki +[forums]: https://love2d.org/forums [discord]: https://discord.gg/rhUets9 [irc]: irc://irc.oftc.net/love [dependencies-macos]: https://github.com/slime73/love-apple-dependencies [dependencies-ios]: https://github.com/love2d/love/releases [megasource]: https://github.com/love2d/megasource [unstableppa]: https://launchpad.net/~bartbes/+archive/love-unstable -[aur]: http://aur.archlinux.org/packages/love-git +[aur]: https://aur.archlinux.org/packages/love-git [love-experiments]: https://github.com/slime73/love-experiments [codestyle]: https://love2d.org/wiki/Code_Style [android-repository]: https://github.com/love2d/love-android From b54aaf65ca5063e99d7a14913b29ab8c6d46abcf Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Sat, 4 Dec 2021 11:58:00 -0400 Subject: [PATCH 34/43] Fix the default error handler drawing when love.graphics is inactive. love.graphics.isActive() is false on mobile devices when the app isn't in the foreground. On iOS there can be a few frames between when the app is backgrounded and when the OS pauses it, where it's not valid to call OpenGL functions or present the screen. --- src/modules/love/callbacks.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/love/callbacks.lua b/src/modules/love/callbacks.lua index 38ee277ac..320b380e7 100644 --- a/src/modules/love/callbacks.lua +++ b/src/modules/love/callbacks.lua @@ -259,6 +259,7 @@ function love.errhand(msg) p = p:gsub("%[string \"(.-)\"%]", "%1") local function draw() + if not love.graphics.isActive() then return end local pos = 70 love.graphics.clear(89/255, 157/255, 220/255) love.graphics.printf(p, pos, pos, love.graphics.getWidth() - pos) @@ -270,7 +271,6 @@ function love.errhand(msg) if not love.system then return end love.system.setClipboardText(fullErrorText) p = p .. "\nCopied to clipboard!" - draw() end if love.system then From 7310fde7b90ce4d7cb5ae05fd54efaa8af27a6a8 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Sat, 4 Dec 2021 13:11:01 -0400 Subject: [PATCH 35/43] glslang: fix compilation on certain newer compilers This is already fixed in the latest glslang source code, but updating may be too risky for love 11.x. --- src/libraries/glslang/glslang/Include/PoolAlloc.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libraries/glslang/glslang/Include/PoolAlloc.h b/src/libraries/glslang/glslang/Include/PoolAlloc.h index 0e237a6a2..b8eccb883 100644 --- a/src/libraries/glslang/glslang/Include/PoolAlloc.h +++ b/src/libraries/glslang/glslang/Include/PoolAlloc.h @@ -304,7 +304,6 @@ public: size_type max_size() const { return static_cast(-1) / sizeof(T); } size_type max_size(int size) const { return static_cast(-1) / size; } - void setAllocator(TPoolAllocator* a) { allocator = *a; } TPoolAllocator& getAllocator() const { return allocator; } protected: From ebd5f13456729be97e42f03ad26bf683effe17df Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Tue, 7 Dec 2021 19:51:40 -0400 Subject: [PATCH 36/43] Fix missing ByteData:clone and DataView:clone implementations. Fixes #1754 --- src/modules/data/wrap_ByteData.cpp | 11 +++++++++++ src/modules/data/wrap_DataView.cpp | 13 ++++++++++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/modules/data/wrap_ByteData.cpp b/src/modules/data/wrap_ByteData.cpp index 446f62214..ed0c0d35c 100644 --- a/src/modules/data/wrap_ByteData.cpp +++ b/src/modules/data/wrap_ByteData.cpp @@ -31,8 +31,19 @@ ByteData *luax_checkbytedata(lua_State *L, int idx) return luax_checktype(L, idx); } +int w_ByteData_clone(lua_State *L) +{ + ByteData *t = luax_checkbytedata(L, 1); + ByteData *c = nullptr; + luax_catchexcept(L, [&](){ c = t->clone(); }); + luax_pushtype(L, c); + c->release(); + return 1; +} + static const luaL_Reg w_ByteData_functions[] = { + { "clone", w_ByteData_clone }, { 0, 0 } }; diff --git a/src/modules/data/wrap_DataView.cpp b/src/modules/data/wrap_DataView.cpp index 9aec29d7c..e41826b38 100644 --- a/src/modules/data/wrap_DataView.cpp +++ b/src/modules/data/wrap_DataView.cpp @@ -26,13 +26,24 @@ namespace love namespace data { -DataView *luax_checkdataView(lua_State *L, int idx) +DataView *luax_checkdataview(lua_State *L, int idx) { return luax_checktype(L, idx); } +int w_DataView_clone(lua_State *L) +{ + DataView *t = luax_checkdataview(L, 1); + DataView *c = nullptr; + luax_catchexcept(L, [&](){ c = t->clone(); }); + luax_pushtype(L, c); + c->release(); + return 1; +} + static const luaL_Reg w_DataView_functions[] = { + { "clone", w_DataView_clone }, { 0, 0 } }; From 7e271fc53ebb9710ecc31343aef5bcaffb5cd8d8 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Sat, 11 Dec 2021 11:52:42 -0400 Subject: [PATCH 37/43] Use SDL's rumble APIs for Joystick:setVibration, when available. Fixes #1756 --- src/modules/joystick/sdl/Joystick.cpp | 31 +++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/src/modules/joystick/sdl/Joystick.cpp b/src/modules/joystick/sdl/Joystick.cpp index 2a8a85519..3c8b69067 100644 --- a/src/modules/joystick/sdl/Joystick.cpp +++ b/src/modules/joystick/sdl/Joystick.cpp @@ -392,6 +392,11 @@ bool Joystick::checkCreateHaptic() bool Joystick::isVibrationSupported() { +#if SDL_VERSION_ATLEAST(2, 0, 18) + if (isConnected() && SDL_JoystickHasRumble(joyhandle) == SDL_TRUE) + return true; +#endif + if (!checkCreateHaptic()) return false; @@ -442,8 +447,12 @@ bool Joystick::setVibration(float left, float right, float duration) if (left == 0.0f && right == 0.0f) return setVibration(); - if (!checkCreateHaptic()) + if (!isConnected()) + { + vibration.left = vibration.right = 0.0f; + vibration.endtime = SDL_HAPTIC_INFINITY; return false; + } Uint32 length = SDL_HAPTIC_INFINITY; if (duration >= 0.0f) @@ -453,10 +462,19 @@ bool Joystick::setVibration(float left, float right, float duration) } bool success = false; + +#if SDL_VERSION_ATLEAST(2, 0, 9) + if (SDL_JoystickRumble(joyhandle, (Uint16)(left * LOVE_UINT16_MAX), (Uint16)(right * LOVE_UINT16_MAX), length) == 0) + success = true; +#endif + + if (!success && !checkCreateHaptic()) + return false; + unsigned int features = SDL_HapticQuery(haptic); int axes = SDL_HapticNumAxes(haptic); - if ((features & SDL_HAPTIC_LEFTRIGHT) != 0) + if (!success && (features & SDL_HAPTIC_LEFTRIGHT) != 0) { memset(&vibration.effect, 0, sizeof(SDL_HapticEffect)); vibration.effect.type = SDL_HAPTIC_LEFTRIGHT; @@ -528,9 +546,14 @@ bool Joystick::setVibration(float left, float right, float duration) bool Joystick::setVibration() { - bool success = true; + bool success = false; - if (SDL_WasInit(SDL_INIT_HAPTIC) && haptic && SDL_HapticIndex(haptic) != -1) +#if SDL_VERSION_ATLEAST(2, 0, 9) + if (!success) + success = isConnected() && SDL_JoystickRumble(joyhandle, 0, 0, 0) == 0; +#endif + + if (!success && SDL_WasInit(SDL_INIT_HAPTIC) && haptic && SDL_HapticIndex(haptic) != -1) success = (SDL_HapticStopEffect(haptic, vibration.id) == 0); if (success) From fb815edc282f05e7b37a588d65064725939b9401 Mon Sep 17 00:00:00 2001 From: Miku AuahDark Date: Sun, 12 Dec 2021 01:26:20 +0800 Subject: [PATCH 38/43] Change luaL_loadbuffer chunkname with prefixes. --- src/libraries/luasocket/libluasocket/ftp.lua.h | 2 +- src/libraries/luasocket/libluasocket/headers.lua.h | 2 +- src/libraries/luasocket/libluasocket/http.lua.h | 2 +- src/libraries/luasocket/libluasocket/ltn12.lua.h | 2 +- src/libraries/luasocket/libluasocket/mbox.lua.h | 2 +- src/libraries/luasocket/libluasocket/mime.lua.h | 2 +- src/libraries/luasocket/libluasocket/smtp.lua.h | 2 +- src/libraries/luasocket/libluasocket/socket.lua.h | 2 +- src/libraries/luasocket/libluasocket/tp.lua.h | 2 +- src/libraries/luasocket/libluasocket/url.lua.h | 2 +- src/modules/event/wrap_Event.cpp | 2 +- src/modules/graphics/wrap_Graphics.cpp | 4 ++-- src/modules/graphics/wrap_Video.cpp | 2 +- src/modules/love/love.cpp | 10 +++++----- src/modules/math/wrap_Math.cpp | 2 +- 15 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/libraries/luasocket/libluasocket/ftp.lua.h b/src/libraries/luasocket/libluasocket/ftp.lua.h index fcb0d403a..857390980 100644 --- a/src/libraries/luasocket/libluasocket/ftp.lua.h +++ b/src/libraries/luasocket/libluasocket/ftp.lua.h @@ -540,5 +540,5 @@ static const unsigned char B1[]={ }; - if (luaL_loadbuffer(L,(const char*)B1,sizeof(B1),"ftp.lua")==0) lua_call(L, 0, LUA_MULTRET); + if (luaL_loadbuffer(L,(const char*)B1,sizeof(B1),"=[socket \"ftp.lua\"]")==0) lua_call(L, 0, LUA_MULTRET); } diff --git a/src/libraries/luasocket/libluasocket/headers.lua.h b/src/libraries/luasocket/libluasocket/headers.lua.h index 0d8d891a2..f7958973f 100644 --- a/src/libraries/luasocket/libluasocket/headers.lua.h +++ b/src/libraries/luasocket/libluasocket/headers.lua.h @@ -192,5 +192,5 @@ static const unsigned char B1[]={ 108,101,114, 34, 44, 10,125, 10, 10,114,101,116,117,114,110, 32, 95, 77, }; - if (luaL_loadbuffer(L,(const char*)B1,sizeof(B1),"headers.lua")==0) lua_call(L, 0, LUA_MULTRET); + if (luaL_loadbuffer(L,(const char*)B1,sizeof(B1),"=[socket \"headers.lua\"]")==0) lua_call(L, 0, LUA_MULTRET); } diff --git a/src/libraries/luasocket/libluasocket/http.lua.h b/src/libraries/luasocket/libluasocket/http.lua.h index 840cd85ca..0ecd8892e 100644 --- a/src/libraries/luasocket/libluasocket/http.lua.h +++ b/src/libraries/luasocket/libluasocket/http.lua.h @@ -668,5 +668,5 @@ static const unsigned char B1[]={ 101,110,100, 41, 10, 10,114,101,116,117,114,110, 32, 95, 77, 10, }; - if (luaL_loadbuffer(L,(const char*)B1,sizeof(B1),"http.lua")==0) lua_call(L, 0, LUA_MULTRET); + if (luaL_loadbuffer(L,(const char*)B1,sizeof(B1),"=[socket \"http.lua\"]")==0) lua_call(L, 0, LUA_MULTRET); } diff --git a/src/libraries/luasocket/libluasocket/ltn12.lua.h b/src/libraries/luasocket/libluasocket/ltn12.lua.h index 6fcfed99a..59ac8a445 100644 --- a/src/libraries/luasocket/libluasocket/ltn12.lua.h +++ b/src/libraries/luasocket/libluasocket/ltn12.lua.h @@ -442,5 +442,5 @@ static const unsigned char B1[]={ 110,100, 10,101,110,100, 10, 10,114,101,116,117,114,110, 32, 95, 77, 10, }; - if (luaL_loadbuffer(L,(const char*)B1,sizeof(B1),"ltn12.lua")==0) lua_call(L, 0, LUA_MULTRET); + if (luaL_loadbuffer(L,(const char*)B1,sizeof(B1),"=[socket \"ltn12.lua\"]")==0) lua_call(L, 0, LUA_MULTRET); } diff --git a/src/libraries/luasocket/libluasocket/mbox.lua.h b/src/libraries/luasocket/libluasocket/mbox.lua.h index f3edca978..2033abfc2 100644 --- a/src/libraries/luasocket/libluasocket/mbox.lua.h +++ b/src/libraries/luasocket/libluasocket/mbox.lua.h @@ -140,5 +140,5 @@ static const unsigned char B1[]={ 110,100, 10, 10,114,101,116,117,114,110, 32, 95, 77, 10, }; - if (luaL_loadbuffer(L,(const char*)B1,sizeof(B1),"mbox.lua")==0) lua_call(L, 0, LUA_MULTRET); + if (luaL_loadbuffer(L,(const char*)B1,sizeof(B1),"=[socket \"mbox.lua\"]")==0) lua_call(L, 0, LUA_MULTRET); } diff --git a/src/libraries/luasocket/libluasocket/mime.lua.h b/src/libraries/luasocket/libluasocket/mime.lua.h index 78a14cb27..7c648b0f2 100644 --- a/src/libraries/luasocket/libluasocket/mime.lua.h +++ b/src/libraries/luasocket/libluasocket/mime.lua.h @@ -132,5 +132,5 @@ static const unsigned char B1[]={ 116,117,114,110, 32, 95, 77, }; - if (luaL_loadbuffer(L,(const char*)B1,sizeof(B1),"mime.lua")==0) lua_call(L, 0, LUA_MULTRET); + if (luaL_loadbuffer(L,(const char*)B1,sizeof(B1),"=[socket \"mime.lua\"]")==0) lua_call(L, 0, LUA_MULTRET); } diff --git a/src/libraries/luasocket/libluasocket/smtp.lua.h b/src/libraries/luasocket/libluasocket/smtp.lua.h index 2faf479cf..212945257 100644 --- a/src/libraries/luasocket/libluasocket/smtp.lua.h +++ b/src/libraries/luasocket/libluasocket/smtp.lua.h @@ -411,5 +411,5 @@ static const unsigned char B1[]={ 110,100, 41, 10, 10,114,101,116,117,114,110, 32, 95, 77, }; - if (luaL_loadbuffer(L,(const char*)B1,sizeof(B1),"smtp.lua")==0) lua_call(L, 0, LUA_MULTRET); + if (luaL_loadbuffer(L,(const char*)B1,sizeof(B1),"=[socket \"smtp.lua\"]")==0) lua_call(L, 0, LUA_MULTRET); } diff --git a/src/libraries/luasocket/libluasocket/socket.lua.h b/src/libraries/luasocket/libluasocket/socket.lua.h index f99e58ec9..8b2de82cf 100644 --- a/src/libraries/luasocket/libluasocket/socket.lua.h +++ b/src/libraries/luasocket/libluasocket/socket.lua.h @@ -230,5 +230,5 @@ static const unsigned char B1[]={ 116,117,114,110, 32, 95, 77, 10, }; - if (luaL_loadbuffer(L,(const char*)B1,sizeof(B1),"socket.lua")==0) lua_call(L, 0, LUA_MULTRET); + if (luaL_loadbuffer(L,(const char*)B1,sizeof(B1),"=[socket \"socket.lua\"]")==0) lua_call(L, 0, LUA_MULTRET); } diff --git a/src/libraries/luasocket/libluasocket/tp.lua.h b/src/libraries/luasocket/libluasocket/tp.lua.h index cde8b6480..313ce92a3 100644 --- a/src/libraries/luasocket/libluasocket/tp.lua.h +++ b/src/libraries/luasocket/libluasocket/tp.lua.h @@ -196,5 +196,5 @@ static const unsigned char B1[]={ 114,110, 32, 95, 77, 10, }; - if (luaL_loadbuffer(L,(const char*)B1,sizeof(B1),"tp.lua")==0) lua_call(L, 0, LUA_MULTRET); + if (luaL_loadbuffer(L,(const char*)B1,sizeof(B1),"=[socket \"tp.lua\"]")==0) lua_call(L, 0, LUA_MULTRET); } diff --git a/src/libraries/luasocket/libluasocket/url.lua.h b/src/libraries/luasocket/libluasocket/url.lua.h index 251472148..283b79796 100644 --- a/src/libraries/luasocket/libluasocket/url.lua.h +++ b/src/libraries/luasocket/libluasocket/url.lua.h @@ -563,5 +563,5 @@ static const unsigned char B1[]={ 110, 32, 95, 77, 10, }; - if (luaL_loadbuffer(L,(const char*)B1,sizeof(B1),"url.lua")==0) lua_call(L, 0, LUA_MULTRET); + if (luaL_loadbuffer(L,(const char*)B1,sizeof(B1),"=[socket \"url.lua\"]")==0) lua_call(L, 0, LUA_MULTRET); } diff --git a/src/modules/event/wrap_Event.cpp b/src/modules/event/wrap_Event.cpp index ff18075dc..bf1d8075e 100644 --- a/src/modules/event/wrap_Event.cpp +++ b/src/modules/event/wrap_Event.cpp @@ -136,7 +136,7 @@ extern "C" int luaopen_love_event(lua_State *L) int ret = luax_register_module(L, w); - if (luaL_loadbuffer(L, (const char *)event_lua, sizeof(event_lua), "wrap_Event.lua") == 0) + if (luaL_loadbuffer(L, (const char *)event_lua, sizeof(event_lua), "=[love \"wrap_Event.lua\"]") == 0) lua_call(L, 0, 0); else lua_error(L); diff --git a/src/modules/graphics/wrap_Graphics.cpp b/src/modules/graphics/wrap_Graphics.cpp index f6596062a..ad96f8fb7 100644 --- a/src/modules/graphics/wrap_Graphics.cpp +++ b/src/modules/graphics/wrap_Graphics.cpp @@ -3075,12 +3075,12 @@ extern "C" int luaopen_love_graphics(lua_State *L) int n = luax_register_module(L, w); - if (luaL_loadbuffer(L, (const char *)graphics_lua, sizeof(graphics_lua), "wrap_Graphics.lua") == 0) + if (luaL_loadbuffer(L, (const char *)graphics_lua, sizeof(graphics_lua), "=[love \"wrap_Graphics.lua\"]") == 0) lua_call(L, 0, 0); else lua_error(L); - if (luaL_loadbuffer(L, (const char *)graphics_shader_lua, sizeof(graphics_shader_lua), "wrap_GraphicsShader.lua") == 0) + if (luaL_loadbuffer(L, (const char *)graphics_shader_lua, sizeof(graphics_shader_lua), "=[love \"wrap_GraphicsShader.lua\"]") == 0) lua_call(L, 0, 0); else lua_error(L); diff --git a/src/modules/graphics/wrap_Video.cpp b/src/modules/graphics/wrap_Video.cpp index 712330dbe..387aab75e 100644 --- a/src/modules/graphics/wrap_Video.cpp +++ b/src/modules/graphics/wrap_Video.cpp @@ -168,7 +168,7 @@ int luaopen_video(lua_State *L) { int ret = luax_register_type(L, &Video::type, functions, nullptr); - luaL_loadbuffer(L, video_lua, sizeof(video_lua), "Video.lua"); + luaL_loadbuffer(L, video_lua, sizeof(video_lua), "=[love \"Video.lua\"]"); luax_gettypemetatable(L, Video::type); lua_call(L, 1, 0); diff --git a/src/modules/love/love.cpp b/src/modules/love/love.cpp index a70125f91..7330c0f2d 100644 --- a/src/modules/love/love.cpp +++ b/src/modules/love/love.cpp @@ -662,7 +662,7 @@ int w__setAccelerometerAsJoystick(lua_State *L) int luaopen_love_nogame(lua_State *L) { - if (luaL_loadbuffer(L, (const char *)love::nogame_lua, sizeof(love::nogame_lua), "nogame.lua") == 0) + if (luaL_loadbuffer(L, (const char *)love::nogame_lua, sizeof(love::nogame_lua), "=[love \"nogame.lua\"]") == 0) lua_call(L, 0, 1); return 1; @@ -670,7 +670,7 @@ int luaopen_love_nogame(lua_State *L) int luaopen_love_jitsetup(lua_State *L) { - if (luaL_loadbuffer(L, jit_setup_lua, sizeof(jit_setup_lua), "jitsetup.lua") == 0) + if (luaL_loadbuffer(L, jit_setup_lua, sizeof(jit_setup_lua), "=[love \"jitsetup.lua\"]") == 0) lua_call(L, 0, 1); return 1; @@ -678,7 +678,7 @@ int luaopen_love_jitsetup(lua_State *L) int luaopen_love_arg(lua_State *L) { - if (luaL_loadbuffer(L, arg_lua, sizeof(arg_lua), "arg.lua") == 0) + if (luaL_loadbuffer(L, arg_lua, sizeof(arg_lua), "=[love \"arg.lua\"]") == 0) lua_call(L, 0, 1); return 1; @@ -686,7 +686,7 @@ int luaopen_love_arg(lua_State *L) int luaopen_love_callbacks(lua_State *L) { - if (luaL_loadbuffer(L, callbacks_lua, sizeof(callbacks_lua), "callbacks.lua") == 0) + if (luaL_loadbuffer(L, callbacks_lua, sizeof(callbacks_lua), "=[love \"callbacks.lua\"]") == 0) lua_call(L, 0, 1); return 1; @@ -694,7 +694,7 @@ int luaopen_love_callbacks(lua_State *L) int luaopen_love_boot(lua_State *L) { - if (luaL_loadbuffer(L, boot_lua, sizeof(boot_lua), "boot.lua") == 0) + if (luaL_loadbuffer(L, boot_lua, sizeof(boot_lua), "=[love \"boot.lua\"]") == 0) lua_call(L, 0, 1); return 1; diff --git a/src/modules/math/wrap_Math.cpp b/src/modules/math/wrap_Math.cpp index 390aa9c72..e8af3b2ec 100644 --- a/src/modules/math/wrap_Math.cpp +++ b/src/modules/math/wrap_Math.cpp @@ -498,7 +498,7 @@ extern "C" int luaopen_love_math(lua_State *L) int n = luax_register_module(L, w); // Execute wrap_Math.lua, sending the math table and ffifuncs pointer as args. - luaL_loadbuffer(L, math_lua, sizeof(math_lua), "wrap_Math.lua"); + luaL_loadbuffer(L, math_lua, sizeof(math_lua), "=[love \"wrap_Math.lua\"]"); lua_pushvalue(L, -2); luax_pushpointerasstring(L, &ffifuncs); lua_call(L, 2, 0); From 380cc1033e6c62af2e54cd04c96dd959a24a73c8 Mon Sep 17 00:00:00 2001 From: Miku AuahDark Date: Sun, 12 Dec 2021 09:34:08 +0800 Subject: [PATCH 39/43] Change luax_runwrapper chunk name prefix. --- src/common/runtime.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/common/runtime.cpp b/src/common/runtime.cpp index 972b35753..34205b9dd 100644 --- a/src/common/runtime.cpp +++ b/src/common/runtime.cpp @@ -985,7 +985,9 @@ void luax_runwrapper(lua_State *L, const char *filedata, size_t datalen, const c // functions struct pointer as arguments. if (lua_istable(L, -1)) { - luaL_loadbuffer(L, filedata, datalen, filename); + std::string chunkname = std::string("=[love \"") + std::string(filename) + std::string("\"]"); + + luaL_loadbuffer(L, filedata, datalen, chunkname.c_str()); lua_pushvalue(L, -2); if (ffifuncs != nullptr) luax_pushpointerasstring(L, ffifuncs); From b3593118320115b2a1da12ebe38b6db9f7f3bbfb Mon Sep 17 00:00:00 2001 From: megagrump Date: Mon, 13 Dec 2021 09:20:17 +0100 Subject: [PATCH 40/43] accept Data objects in newFileData --- src/modules/filesystem/wrap_Filesystem.cpp | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/modules/filesystem/wrap_Filesystem.cpp b/src/modules/filesystem/wrap_Filesystem.cpp index 41db59725..a99f60c99 100644 --- a/src/modules/filesystem/wrap_Filesystem.cpp +++ b/src/modules/filesystem/wrap_Filesystem.cpp @@ -331,11 +331,22 @@ int w_newFileData(lua_State *L) } size_t length = 0; - const char *str = luaL_checklstring(L, 1, &length); + const void *ptr = nullptr; + if (luax_istype(L, 1, Data::type)) + { + Data *data = data::luax_checkdata(L, 1); + ptr = data->getData(); + length = data->getSize(); + } + else if (lua_isstring(L, 1)) + ptr = luaL_checklstring(L, 1, &length); + else + return luaL_argerror(L, 1, "string or Data expected"); + const char *filename = luaL_checkstring(L, 2); FileData *t = nullptr; - luax_catchexcept(L, [&](){ t = instance()->newFileData(str, length, filename); }); + luax_catchexcept(L, [&](){ t = instance()->newFileData(ptr, length, filename); }); luax_pushtype(L, t); t->release(); From ede0ad0a20a607353240f8477e5665234b84dffd Mon Sep 17 00:00:00 2001 From: Miku AuahDark Date: Sun, 19 Dec 2021 09:47:45 +0800 Subject: [PATCH 41/43] Fix ENet error on certain system with >48-bit pointers. Fixes love2d/love-android#222 --- src/libraries/enet/enet.cpp | 54 +++++++++++++++++++++++++++---------- 1 file changed, 40 insertions(+), 14 deletions(-) diff --git a/src/libraries/enet/enet.cpp b/src/libraries/enet/enet.cpp index 076fcb20d..bca527cd6 100644 --- a/src/libraries/enet/enet.cpp +++ b/src/libraries/enet/enet.cpp @@ -118,11 +118,30 @@ static size_t find_peer_index(lua_State *l, ENetHost *enet_host, ENetPeer *peer) #define ENET_ALIGNOF(x) alignof(x) #endif -// For use with the enet_peers registry. -// Using the pointer directly via lightuserdata would be ideal, but LuaJIT -// cannot use lightuserdata with more than 47 bits whereas some newer arm64 -// architectures allow pointers which use more than that. -static lua_Number compute_peer_key(lua_State *L, ENetPeer *peer) +static bool supports_full_lightuserdata(lua_State *L) +{ + static bool checked = false; + static bool supported = false; + + if (!checked) + { + lua_pushcclosure(L, [](lua_State* L) -> int + { + // Try to push pointer with all bits set. + lua_pushlightuserdata(L, (void*)(~((size_t)0))); + return 1; + }, 0); + + supported = lua_pcall(L, 0, 1, 0) == 0; + checked = true; + + lua_pop(L, 1); + } + + return supported; +} + +static uintptr_t compute_peer_key(lua_State *L, ENetPeer *peer) { // ENet peers are be allocated on the heap in an array. Lua numbers // (doubles) can store all possible integers up to 2^53. We can store @@ -140,21 +159,28 @@ static lua_Number compute_peer_key(lua_State *L, ENetPeer *peer) static const size_t shift = (size_t) log2((double) minalign); - key >>= shift; + return key >> shift; +} - // Make sure our key isn't larger than 2^53. - if (key > 0x20000000000000ULL) - luaL_error(L, "Cannot push enet peer to Lua: pointer value %p is too large", peer); - - return (lua_Number) key; +static void push_peer_key(lua_State *L, uintptr_t key) +{ + // If full 64-bit lightuserdata is supported, always use that. Otherwise, + // if the key is smaller than 2^53 (which is integer precision for double + // datatype), then push number. Otherwise, throw error. + if (supports_full_lightuserdata(L)) + lua_pushlightuserdata(L, (void*) key); + else if (key > 0x20000000000000ULL) // 2^53 + luaL_error(L, "Cannot push enet peer to Lua: pointer value %p is too large", key); + else + lua_pushnumber(L, (lua_Number) key); } static void push_peer(lua_State *l, ENetPeer *peer) { - lua_Number key = compute_peer_key(l, peer); + uintptr_t key = compute_peer_key(l, peer); // try to find in peer table lua_getfield(l, LUA_REGISTRYINDEX, "enet_peers"); - lua_pushnumber(l, key); + push_peer_key(l, key); lua_gettable(l, -2); if (lua_isnil(l, -1)) { @@ -165,7 +191,7 @@ static void push_peer(lua_State *l, ENetPeer *peer) { luaL_getmetatable(l, "enet_peer"); lua_setmetatable(l, -2); - lua_pushnumber(l, key); + push_peer_key(l, key); lua_pushvalue(l, -2); lua_settable(l, -4); From cee8f8ae4854f4a7f7067b7a4b200e991a05c66f Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Fri, 24 Dec 2021 11:26:11 -0400 Subject: [PATCH 42/43] Fix a compiler warning --- src/common/runtime.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/common/runtime.cpp b/src/common/runtime.cpp index 34205b9dd..71638302c 100644 --- a/src/common/runtime.cpp +++ b/src/common/runtime.cpp @@ -1010,8 +1010,10 @@ int luax_resume(lua_State *L, int nargs, int* nres) #if LUA_VERSION_NUM >= 504 return lua_resume(L, nullptr, nargs, nres); #elif LUA_VERSION_NUM >= 502 + LOVE_UNUSED(nres); return lua_resume(L, nullptr, nargs); #else + LOVE_UNUSED(nres); return lua_resume(L, nargs); #endif } From 185b53421ae451d4b5d101bd3803d8919de059db Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Fri, 24 Dec 2021 11:41:12 -0400 Subject: [PATCH 43/43] Fix function declaration type mismatch (didn't cause any errors). --- src/modules/math/MathModule.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/modules/math/MathModule.h b/src/modules/math/MathModule.h index bce3de5a9..4d4729071 100644 --- a/src/modules/math/MathModule.h +++ b/src/modules/math/MathModule.h @@ -83,10 +83,10 @@ float linearToGamma(float c); * * @return Noise value in the range of [0, 1]. **/ -static float noise1(float x); -static float noise2(float x, float y); -static float noise3(float x, float y, float z); -static float noise4(float x, float y, float z, float w); +static float noise1(double x); +static float noise2(double x, double y); +static float noise3(double x, double y, double z); +static float noise4(double x, double y, double z, double w); class Math : public Module