Commits

Alex Szpakowski committed 14b9b02

Added experimental optional LuaJIT FFI bindings for some functions in love.graphics. love.math, and love.timer, as well as for some methods for ImageData, SpriteBatches, Canvases, Geometry, Images, and RandomGenerators. Added t.ffi (boolean flag) to love.conf.

Comments (1)

  1. Alex Szpakowski author

    The bindings need a lot of real-world profiling - it is always preferable to not have the FFI bindings for a function if not much real-world performance will be gained from it, since there's a high maintainability and updatability cost to the binding functions.

    The bindings will always be optional alongside the regular Lua/C bindings, since Lua 5.1 is the main target for LÖVE and some platforms which support LuaJIT do not support the JIT/FFI (e.g. iOS.)

Files changed (36)

platform/macosx/love-framework.xcodeproj/project.pbxproj

 		FA08F67B16C754BA00F007B5 /* Window.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 351B09E51FDC338622F44624 /* Window.cpp */; };
 		FA08F67C16C754BA00F007B5 /* Window.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6CDD4F3320303D222C180CD0 /* Window.cpp */; };
 		FA0CDE3D1710F9A50056E8D7 /* FormatHandler.h in Headers */ = {isa = PBXBuildFile; fileRef = FA0CDE3B1710F9A50056E8D7 /* FormatHandler.h */; };
+		FA318A4E177EE0280050DBE3 /* LuaJIT.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA318A4D177EE0280050DBE3 /* LuaJIT.framework */; };
 		FA5454C216F1310000D30303 /* MathModule.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA5454C016F1310000D30303 /* MathModule.cpp */; };
 		FA5454C316F1310000D30303 /* MathModule.h in Headers */ = {isa = PBXBuildFile; fileRef = FA5454C116F1310000D30303 /* MathModule.h */; };
 		FA577AB016C7507900860150 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA577A7916C71A1700860150 /* Cocoa.framework */; };
 		FA577AC316C7512F00860150 /* Game_Music_Emu.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA577A6B16C719E400860150 /* Game_Music_Emu.framework */; };
 		FA577AC416C7513200860150 /* IL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA577A6916C719DE00860150 /* IL.framework */; };
 		FA577AC516C7513400860150 /* libmodplug.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA577A8216C71A5300860150 /* libmodplug.framework */; };
-		FA577AC616C7513800860150 /* Lua.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA577A6D16C719EA00860150 /* Lua.framework */; };
 		FA577AC716C7513A00860150 /* mpg123.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA577A6F16C719F000860150 /* mpg123.framework */; };
 		FA577AC816C7513C00860150 /* Ogg.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA577A7116C719F400860150 /* Ogg.framework */; };
 		FA577ACA16C7514100860150 /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA577A7C16C71A2600860150 /* OpenGL.framework */; };
 		FA636D8F171B72A70065623F /* wrap_RandomGenerator.h in Headers */ = {isa = PBXBuildFile; fileRef = FA636D8D171B72A70065623F /* wrap_RandomGenerator.h */; };
 		FA7C937A16DCC6C2006F2BEE /* wrap_Math.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA7C937516DCC6C2006F2BEE /* wrap_Math.cpp */; };
 		FA7C937B16DCC6C2006F2BEE /* wrap_Math.h in Headers */ = {isa = PBXBuildFile; fileRef = FA7C937616DCC6C2006F2BEE /* wrap_Math.h */; };
+		FA7FAE6A177FB9AF0059AB71 /* ffi_graphics.lua.h in Headers */ = {isa = PBXBuildFile; fileRef = FA7FAE69177FB9AF0059AB71 /* ffi_graphics.lua.h */; };
 		FA9FC0B0173D6E3E005027FF /* wrap_Window.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA9FC0AE173D6E3E005027FF /* wrap_Window.cpp */; };
 		FA9FC0B1173D6E3E005027FF /* wrap_Window.h in Headers */ = {isa = PBXBuildFile; fileRef = FA9FC0AF173D6E3E005027FF /* wrap_Window.h */; };
 		FAAC6B02170A373B008A61C5 /* CompressedData.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAAC6B00170A373A008A61C5 /* CompressedData.cpp */; };
 		FA03546B1731F3A700284828 /* simplexnoise1234.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = simplexnoise1234.h; sourceTree = "<group>"; };
 		FA08F5AE16C7525600F007B5 /* Info-Framework.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "Info-Framework.plist"; sourceTree = "<group>"; };
 		FA0CDE3B1710F9A50056E8D7 /* FormatHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FormatHandler.h; sourceTree = "<group>"; };
+		FA318A4D177EE0280050DBE3 /* LuaJIT.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = LuaJIT.framework; path = /Library/Frameworks/LuaJIT.framework; sourceTree = "<absolute>"; };
 		FA5454C016F1310000D30303 /* MathModule.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MathModule.cpp; sourceTree = "<group>"; };
 		FA5454C116F1310000D30303 /* MathModule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MathModule.h; sourceTree = "<group>"; };
 		FA577A6716C719D900860150 /* FreeType.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = FreeType.framework; path = /Library/Frameworks/FreeType.framework; sourceTree = "<absolute>"; };
 		FA577A6916C719DE00860150 /* IL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IL.framework; path = /Library/Frameworks/IL.framework; sourceTree = "<absolute>"; };
 		FA577A6B16C719E400860150 /* Game_Music_Emu.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Game_Music_Emu.framework; path = /Library/Frameworks/Game_Music_Emu.framework; sourceTree = "<absolute>"; };
-		FA577A6D16C719EA00860150 /* Lua.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Lua.framework; path = /Library/Frameworks/Lua.framework; sourceTree = "<absolute>"; };
 		FA577A6F16C719F000860150 /* mpg123.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = mpg123.framework; path = /Library/Frameworks/mpg123.framework; sourceTree = "<absolute>"; };
 		FA577A7116C719F400860150 /* Ogg.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Ogg.framework; path = /Library/Frameworks/Ogg.framework; sourceTree = "<absolute>"; };
 		FA577A7316C719F900860150 /* physfs.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = physfs.framework; path = /Library/Frameworks/physfs.framework; sourceTree = "<absolute>"; };
 		FA636D8D171B72A70065623F /* wrap_RandomGenerator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wrap_RandomGenerator.h; sourceTree = "<group>"; };
 		FA7C937516DCC6C2006F2BEE /* wrap_Math.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = wrap_Math.cpp; sourceTree = "<group>"; };
 		FA7C937616DCC6C2006F2BEE /* wrap_Math.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wrap_Math.h; sourceTree = "<group>"; };
+		FA7FAE69177FB9AF0059AB71 /* ffi_graphics.lua.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ffi_graphics.lua.h; sourceTree = "<group>"; };
 		FA9FC0AE173D6E3E005027FF /* wrap_Window.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = wrap_Window.cpp; sourceTree = "<group>"; };
 		FA9FC0AF173D6E3E005027FF /* wrap_Window.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wrap_Window.h; sourceTree = "<group>"; };
 		FAAC6B00170A373A008A61C5 /* CompressedData.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CompressedData.cpp; sourceTree = "<group>"; };
 			isa = PBXFrameworksBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
+				FA318A4E177EE0280050DBE3 /* LuaJIT.framework in Frameworks */,
 				FAAFF04416CB11C700CCDE45 /* OpenAL-Soft.framework in Frameworks */,
 				FA577AB016C7507900860150 /* Cocoa.framework in Frameworks */,
 				FA577AC216C7512D00860150 /* FreeType.framework in Frameworks */,
 				FA577AC316C7512F00860150 /* Game_Music_Emu.framework in Frameworks */,
 				FA577AC416C7513200860150 /* IL.framework in Frameworks */,
 				FA577AC516C7513400860150 /* libmodplug.framework in Frameworks */,
-				FA577AC616C7513800860150 /* Lua.framework in Frameworks */,
 				FA577AC716C7513A00860150 /* mpg123.framework in Frameworks */,
 				FA577AC816C7513C00860150 /* Ogg.framework in Frameworks */,
 				FA577ACA16C7514100860150 /* OpenGL.framework in Frameworks */,
 				FA577A8C16C71D3600860150 /* auto.lua */,
 				FA577A8D16C71D3600860150 /* boot.lua */,
 				503971A86B7167A91B670FBA /* boot.lua.h */,
+				FA7FAE69177FB9AF0059AB71 /* ffi_graphics.lua.h */,
 				FA577A8E16C71D3600860150 /* graphics.lua */,
 				104144AB73A974BC04A03131 /* graphics.lua.h */,
 			);
 		FA577A6616C7199700860150 /* Frameworks */ = {
 			isa = PBXGroup;
 			children = (
+				FA318A4D177EE0280050DBE3 /* LuaJIT.framework */,
 				FA577A7916C71A1700860150 /* Cocoa.framework */,
 				FA577A6716C719D900860150 /* FreeType.framework */,
 				FA577A6B16C719E400860150 /* Game_Music_Emu.framework */,
 				FA577A6916C719DE00860150 /* IL.framework */,
 				FA577A8216C71A5300860150 /* libmodplug.framework */,
-				FA577A6D16C719EA00860150 /* Lua.framework */,
 				FA577A6F16C719F000860150 /* mpg123.framework */,
 				FA577A7116C719F400860150 /* Ogg.framework */,
 				FAAFF04316CB11C700CCDE45 /* OpenAL-Soft.framework */,
 				FA9FC0B1173D6E3E005027FF /* wrap_Window.h in Headers */,
 				FAC5710117402D1100D147E4 /* BezierCurve.h in Headers */,
 				FAC5710317402D1100D147E4 /* wrap_BezierCurve.h in Headers */,
+				FA7FAE6A177FB9AF0059AB71 /* ffi_graphics.lua.h in Headers */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
 					"\"$(SRCROOT)/../../src/libraries\"",
 					"\"$(SRCROOT)/../../src/modules\"",
 					/Library/Frameworks/FreeType.framework/Headers,
-					/Library/Frameworks/Lua.framework/Headers,
+					/Library/Frameworks/LuaJIT.framework/Headers,
 					/Library/Frameworks/SDL.framework/Headers,
 				);
 				LIBRARY_SEARCH_PATHS = "";
 					"\"$(SRCROOT)/../../src/libraries\"",
 					"\"$(SRCROOT)/../../src/modules\"",
 					/Library/Frameworks/FreeType.framework/Headers,
-					/Library/Frameworks/Lua.framework/Headers,
+					/Library/Frameworks/LuaJIT.framework/Headers,
 					/Library/Frameworks/SDL.framework/Headers,
 				);
 				LIBRARY_SEARCH_PATHS = "";

platform/macosx/love.xcodeproj/project.pbxproj

 		A911D3C915DFF25D005B7EB8 /* Game_Music_Emu.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = A911D3C715DFF24D005B7EB8 /* Game_Music_Emu.framework */; };
 		A9255DD11043183600BA1496 /* FreeType.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = A93E6E4810420B4A007D418B /* FreeType.framework */; };
 		A9255DD21043183600BA1496 /* SDL.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = A93E6E5210420B57007D418B /* SDL.framework */; };
-		A9255DD31043183600BA1496 /* Lua.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = A93E6E5310420B57007D418B /* Lua.framework */; };
 		A9255DEC1043188D00BA1496 /* SDLMain.m in Sources */ = {isa = PBXBuildFile; fileRef = A9255DEA1043188D00BA1496 /* SDLMain.m */; };
 		A9255E031043195A00BA1496 /* Vorbis.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = A9255E021043195A00BA1496 /* Vorbis.framework */; };
 		A9255F431043240F00BA1496 /* IL.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = A9255F421043240F00BA1496 /* IL.framework */; };
 		A9255F58104324E100BA1496 /* Ogg.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = A9255F51104324D700BA1496 /* Ogg.framework */; };
 		A93E6E4A10420B4A007D418B /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A93E6E4710420B4A007D418B /* OpenGL.framework */; };
 		A93E6E5410420B57007D418B /* SDL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A93E6E5210420B57007D418B /* SDL.framework */; };
-		A93E6E5510420B57007D418B /* Lua.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A93E6E5310420B57007D418B /* Lua.framework */; };
 		A93E6EED10420BA8007D418B /* love.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A93E6A3410420AC0007D418B /* love.cpp */; };
 		A9D307F2106635D3004FEDF8 /* physfs.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = A9D307E9106635C3004FEDF8 /* physfs.framework */; };
 		A9DEC1C11046EFA70049C70C /* Love.icns in Resources */ = {isa = PBXBuildFile; fileRef = A9DEC1BF1046EFA60049C70C /* Love.icns */; };
 		A9F169AD109E825000FC83D1 /* libmodplug.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = A9F16926109E7BAD00FC83D1 /* libmodplug.framework */; };
 		FA08F69616C766E000F007B5 /* love.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA08F69116C765A200F007B5 /* love.framework */; };
 		FA08F69716C766E700F007B5 /* love.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = FA08F69116C765A200F007B5 /* love.framework */; };
+		FA318A50177EE04A0050DBE3 /* LuaJIT.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA318A4F177EE04A0050DBE3 /* LuaJIT.framework */; };
+		FA318A51177EE0530050DBE3 /* LuaJIT.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = FA318A4F177EE04A0050DBE3 /* LuaJIT.framework */; };
 		FAAFF04716CB120000CCDE45 /* OpenAL-Soft.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = FAAFF04616CB120000CCDE45 /* OpenAL-Soft.framework */; };
 /* End PBXBuildFile section */
 
 				A9F169AC109E825000FC83D1 /* mpg123.framework in Copy Frameworks */,
 				A9F169AD109E825000FC83D1 /* libmodplug.framework in Copy Frameworks */,
 				A9D307F2106635D3004FEDF8 /* physfs.framework in Copy Frameworks */,
+				FA318A51177EE0530050DBE3 /* LuaJIT.framework in Copy Frameworks */,
 				A9255F58104324E100BA1496 /* Ogg.framework in Copy Frameworks */,
 				A9255F431043240F00BA1496 /* IL.framework in Copy Frameworks */,
 				A9255E031043195A00BA1496 /* Vorbis.framework in Copy Frameworks */,
 				A9255DD11043183600BA1496 /* FreeType.framework in Copy Frameworks */,
 				A9255DD21043183600BA1496 /* SDL.framework in Copy Frameworks */,
-				A9255DD31043183600BA1496 /* Lua.framework in Copy Frameworks */,
 				A911D3C915DFF25D005B7EB8 /* Game_Music_Emu.framework in Copy Frameworks */,
 			);
 			name = "Copy Frameworks";
 		A93E6E4710420B4A007D418B /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = /System/Library/Frameworks/OpenGL.framework; sourceTree = "<absolute>"; };
 		A93E6E4810420B4A007D418B /* FreeType.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = FreeType.framework; path = /Library/Frameworks/FreeType.framework; sourceTree = "<absolute>"; };
 		A93E6E5210420B57007D418B /* SDL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SDL.framework; path = /Library/Frameworks/SDL.framework; sourceTree = "<absolute>"; };
-		A93E6E5310420B57007D418B /* Lua.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Lua.framework; path = /Library/Frameworks/Lua.framework; sourceTree = "<absolute>"; };
 		A97E3842132A9EDE00198A2F /* love-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "love-Info.plist"; sourceTree = "<group>"; };
 		A9B1AE451197293000D496EB /* love_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = love_Prefix.pch; sourceTree = "<group>"; };
 		A9D307E9106635C3004FEDF8 /* physfs.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = physfs.framework; path = /Library/Frameworks/physfs.framework; sourceTree = "<absolute>"; };
 		A9F16926109E7BAD00FC83D1 /* libmodplug.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = libmodplug.framework; path = /Library/Frameworks/libmodplug.framework; sourceTree = "<absolute>"; };
 		A9F169A6109E824900FC83D1 /* mpg123.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = mpg123.framework; path = /Library/Frameworks/mpg123.framework; sourceTree = "<absolute>"; };
 		FA08F69116C765A200F007B5 /* love.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = love.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+		FA318A4F177EE04A0050DBE3 /* LuaJIT.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = LuaJIT.framework; path = /Library/Frameworks/LuaJIT.framework; sourceTree = "<absolute>"; };
 		FA577A9316C7217800860150 /* love-framework.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; path = "love-framework.xcodeproj"; sourceTree = "<group>"; };
 		FAAFF04616CB120000CCDE45 /* OpenAL-Soft.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = "OpenAL-Soft.framework"; path = "/Library/Frameworks/OpenAL-Soft.framework"; sourceTree = "<absolute>"; };
 /* End PBXFileReference section */
 			isa = PBXFrameworksBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
+				FA318A50177EE04A0050DBE3 /* LuaJIT.framework in Frameworks */,
 				FA08F69616C766E000F007B5 /* love.framework in Frameworks */,
 				8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */,
 				A93E6E4A10420B4A007D418B /* OpenGL.framework in Frameworks */,
 				A93E6E5410420B57007D418B /* SDL.framework in Frameworks */,
-				A93E6E5510420B57007D418B /* Lua.framework in Frameworks */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
 		1058C7A0FEA54F0111CA2CBB /* Frameworks */ = {
 			isa = PBXGroup;
 			children = (
+				FA318A4F177EE04A0050DBE3 /* LuaJIT.framework */,
 				1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */,
 				A93E6E4810420B4A007D418B /* FreeType.framework */,
 				A911D3C715DFF24D005B7EB8 /* Game_Music_Emu.framework */,
 				A9255F421043240F00BA1496 /* IL.framework */,
 				A9F16926109E7BAD00FC83D1 /* libmodplug.framework */,
 				FA08F69116C765A200F007B5 /* love.framework */,
-				A93E6E5310420B57007D418B /* Lua.framework */,
 				A9F169A6109E824900FC83D1 /* mpg123.framework */,
 				A9255F51104324D700BA1496 /* Ogg.framework */,
 				FAAFF04616CB120000CCDE45 /* OpenAL-Soft.framework */,
 					"\"$(SRCROOT)/../../src\"",
 					"\"$(SRCROOT)/../../src/libraries\"",
 					"\"$(SRCROOT)/../../src/modules\"",
-					/Library/Frameworks/Lua.framework/Headers,
+					/Library/Frameworks/LuaJIT.framework/Headers,
 					/Library/Frameworks/FreeType.framework/Headers,
 					/Library/Frameworks/SDL.framework/Headers,
 				);
 					"\"$(SRCROOT)/../../src\"",
 					"\"$(SRCROOT)/../../src/libraries\"",
 					"\"$(SRCROOT)/../../src/modules\"",
-					/Library/Frameworks/Lua.framework/Headers,
+					/Library/Frameworks/LuaJIT.framework/Headers,
 					/Library/Frameworks/FreeType.framework/Headers,
 					/Library/Frameworks/SDL.framework/Headers,
 				);

src/common/runtime.cpp

  * 3. This notice may not be removed or altered from any source distribution.
  **/
 
+#include "config.h"
 #include "runtime.h"
 
 // LOVE
 #include "StringMap.h"
 #include <thread/threads.h>
 
-// STD
+// stdlib
 #include <iostream>
+#include <algorithm>
+#include <cstring>
+#include <cstdarg>
+#include <cstdio>
 
 namespace love
 {
 	lua_newtable(L);
 
 	// Register all the functions.
-	luaL_register(L, 0, m.functions);
+	if (m.functions != 0)
+		luaL_register(L, 0, m.functions);
 
 	// Register types.
 	if (m.types != 0)
 
 StringMap<Type, TYPE_MAX_ENUM> types(typeEntries, sizeof(typeEntries));
 
+
 Type luax_type(lua_State *L, int idx)
 {
 	Type t = INVALID_ID;
 	return t;
 }
 
+int w__gettypemetatable(lua_State *L)
+{
+	const char *tname = luaL_checkstring(L, 1);
+	love::Type type;
+	if (!types.find(tname, type))
+		return luaL_error(L, "Invalid object type: %s.", tname);
+
+	luaL_newmetatable(L, tname);
+	return 1;
+}
+
+void luax_ffi_error(WrapError *wraperror, const char *fmt, ...)
+{
+	if (!wraperror)
+		return;
+
+	// Zero out the outarg error string to start with a clean slate.
+	memset(wraperror->str, 0, WRAP_ERROR_MAX_LENGTH + 1);
+
+	va_list args;
+	va_start(args, fmt);
+
+	vsnprintf(wraperror->str, WRAP_ERROR_MAX_LENGTH + 1, fmt, args);
+
+	va_end(args);
+
+	wraperror->len = strlen(wraperror->str);
+	wraperror->diderror = 1;
+}
+
+bool luax_ffi_istype(Proxy *p, love::bits type)
+{
+	return (p->flags & type) == type;
+}
+
+bool luax_ffi_istype(Proxy *proxy, love::Type tid)
+{
+	return proxy != 0 && proxy->flags[tid] != 0;
+}
+
+bool luax_ffi_checktype(Proxy *proxy, love::Type tid, WrapError *werr)
+{
+	if (proxy == 0 || !luax_ffi_istype(proxy, tid))
+	{
+		const char *typestr;
+		if (types.find(tid, typestr))
+			luax_ffi_error(werr, "Incorrect parameter type: expected %s.", typestr);
+		else
+			luax_ffi_error(werr, "Incorrect parameter type.");
+		return false;
+	}
+
+	return true;
+}
+
 } // love

src/common/runtime.h

 #define LOVE_RUNTIME_H
 
 // LOVE
+#include "config.h"
 #include "types.h"
 
 // Lua
 };
 
 /**
+ * Structure for holding an error genererated within the LuaJIT FFI bindings.
+ * The actual structure will be Lua-side and get passed as a pointer to FFI
+ * functions which set the error, in order for it to be 'thread-local'.
+ * The calling lua function should check the diderror flag after every time a
+ * WrapError pointer is passed to a FFI function.
+ **/
+static const size_t WRAP_ERROR_MAX_LENGTH = 1024;
+struct WrapError
+{
+	char str[WRAP_ERROR_MAX_LENGTH + 1];
+	size_t len;
+	int diderror;
+};
+
+/**
  * Returns a reference to the top stack element (-1) if the value
  * is of the specified type. If the value is incorrect, zero is returned.
  *
 
 Type luax_type(lua_State *L, int idx);
 
+
+/**
+ * Gets the metatable for the specified love type. Necessary for the FFI
+ * bindings.
+ **/
+int w__gettypemetatable(lua_State *L);
+
+/**
+ * Triggers a Lua-side FFI error by putting the given error string into the
+ * WrapError object.
+ * Important: code will continue as normal after luax_ffi_error is called. It
+ * is the responsibility of the calling function to return as soon as possible
+ * once this function is called!
+ **/
+void luax_ffi_error(WrapError *wraperror, const char *fmt, ...);
+
+/**
+ * Gets whether a Proxy object is a certain type.
+ **/
+bool luax_ffi_istype(Proxy *proxy, love::Type tid);
+
+/**
+ * Checks whether a Proxy object is a certain type, and creates an FFI error
+ * if the type does not match.
+ * As with luax_ffi_error, it is the responsibility of the calling function
+ * to return as soon as possible if this function returns false!
+ **/
+bool luax_ffi_checktype(Proxy *proxy, love::Type tid, WrapError *werr);
+
+/**
+ * Checks whether a proxy object is a certain type, and returns the Object the
+ * proxy points to if the type matches. If not, an FFI error is created and
+ * NULL is returned.
+ * As above, it is the responsibility of the calling function to return ASAP
+ * if this function returns NULL.
+ **/
+template <typename T>
+T *luax_ffi_checktype(Proxy *proxy, love::Type tid, WrapError *werr)
+{
+	if (luax_ffi_checktype(proxy, tid, werr))
+		return (T *) proxy->data;
+
+	return NULL;
+}
+
 } // love
 
 #endif // LOVE_RUNTIME_H

src/modules/graphics/opengl/wrap_Canvas.cpp

 	return luax_register_type(L, "Canvas", functions);
 }
 
+
+// LuaJIT FFI bindings.
+
+static Canvas *luax_ffi_checkcanvas(Proxy *proxy, WrapError *werr)
+{
+	return luax_ffi_checktype<Canvas>(proxy, GRAPHICS_CANVAS_ID, werr);
+}
+
+extern "C"
+{
+
+int wf_Canvas_getWidth(WrapError *werr, Proxy *pc)
+{
+	Canvas *c = luax_ffi_checkcanvas(pc, werr);
+	if (!c)
+		return 0;
+
+	return c->getWidth();
+}
+
+int wf_Canvas_getHeight(WrapError *werr, Proxy *pc)
+{
+	Canvas *c = luax_ffi_checkcanvas(pc, werr);
+	if (!c)
+		return 0;
+
+	return c->getHeight();
+}
+
+} // extern "C"
+
 } // opengl
 } // graphics
 } // love

src/modules/graphics/opengl/wrap_Canvas.h

 int w_Canvas_getType(lua_State *L);
 extern "C" int luaopen_canvas(lua_State *L);
 
+
+// LuaJIT FFI bindings.
+extern "C"
+{
+
+LOVE_EXPORT int wf_Canvas_getWidth(WrapError *werr, Proxy *pc);
+LOVE_EXPORT int wf_Canvas_getHeight(WrapError *werr, Proxy *pc);
+
+} // extern "C"
+
 } // opengl
 } // graphics
 } // love

src/modules/graphics/opengl/wrap_Geometry.cpp

 	return luax_register_type(L, "Geometry", w_Geometry_functions);
 }
 
+
+// LuaJIT FFI bindings.
+
+static Geometry *luax_ffi_checkgeometry(Proxy *proxy, WrapError *werr)
+{
+	return luax_ffi_checktype<Geometry>(proxy, GRAPHICS_GEOMETRY_ID, werr);
+}
+
+extern "C"
+{
+
+size_t wf_Geometry_getVertexCount(WrapError *werr, Proxy *gp)
+{
+	Geometry *geom = luax_ffi_checkgeometry(gp, werr);
+	if (!geom)
+		return 0;
+
+	return geom->getVertexCount();
+}
+
+void wf_Geometry_getVertex(WrapError *werr, Proxy *gp, size_t i, float *xyuv, int *rgba)
+{
+	Geometry *geom = luax_ffi_checkgeometry(gp, werr);
+	if (!geom)
+		return;
+
+	try
+	{
+		vertex v = geom->getVertex(i-1);
+
+		xyuv[0] = v.x;
+		xyuv[1] = v.y;
+		xyuv[2] = v.s;
+		xyuv[3] = v.t;
+
+		rgba[0] = v.r;
+		rgba[1] = v.g;
+		rgba[2] = v.b;
+		rgba[3] = v.a;
+	}
+	catch (love::Exception &e)
+	{
+		luax_ffi_error(werr, "%s", e.what());
+	}
+}
+
+void wf_Geometry_setVertex(WrapError *werr, Proxy *gp, size_t i, float x, float y, float u, float v, int r, int g, int b, int a)
+{
+	Geometry *geom = luax_ffi_checkgeometry(gp, werr);
+	if (!geom)
+		return;
+
+	try
+	{
+		vertex vert(x, y, u, v, (unsigned char) r, (unsigned char) g, (unsigned char) b, (unsigned char) a);
+		geom->setVertex(i-1, vert);
+
+		if (vert.r != 255 && vert.g != 255 && vert.b != 255 && vert.a != 255)
+			geom->setVertexColors(true);
+	}
+	catch (love::Exception &e)
+	{
+		luax_ffi_error(werr, "%s", e.what());
+	}
+}
+
+} // extern "C"
+
 } // opengl
 } // graphics
 } // love

src/modules/graphics/opengl/wrap_Geometry.h

 int w_Geometry_hasVertexColors(lua_State *L);
 extern "C" int luaopen_geometry(lua_State *L);
 
+
+// LuaJIT FFI bindings.
+extern "C"
+{
+
+LOVE_EXPORT size_t wf_Geometry_getVertexCount(WrapError *werr, Proxy *gp);
+LOVE_EXPORT void wf_Geometry_getVertex(WrapError *werr, Proxy *gp, size_t i, float *xyuv, int *rgba);
+LOVE_EXPORT void wf_Geometry_setVertex(WrapError *werr, Proxy *gp, size_t i, float x, float y, float u, float v, int r, int g, int b, int a);
+
+} // extern "C"
+
 } // opengl
 } // graphics
 } // love

src/modules/graphics/opengl/wrap_Graphics.cpp

 #include "font/Rasterizer.h"
 
 #include "scripts/graphics.lua.h"
+#include "scripts/ffi_graphics.lua.h"
+
 #include <cassert>
 
 using love::window::WindowFlags;
 
 	int n = luax_register_module(L, w);
 
+	// FFI bindings.
+	if (luaL_loadbuffer(L, (const char *)ffi_graphics_lua, sizeof(ffi_graphics_lua), "wrap_graphics.lua") == 0)
+		lua_call(L, 0, 0);
+
 	if (luaL_loadbuffer(L, (const char *)graphics_lua, sizeof(graphics_lua), "graphics.lua") == 0)
 		lua_call(L, 0, 0);
 
 	return n;
 }
 
+// LuaJIT FFI bindings.
+extern "C"
+{
+
+int wf_graphics_getWidth()
+{
+	return instance->getWidth();
+}
+
+int wf_graphics_getHeight()
+{
+	return instance->getHeight();
+}
+
+void wf_graphics_setColor(int r, int g, int b, int a)
+{
+	instance->setColor(Color(r, g, b, a));
+}
+
+void wf_graphics_getColor(int *color)
+{
+	Color c = instance->getColor();
+	color[0] = c.r;
+	color[1] = c.g;
+	color[2] = c.b;
+	color[3] = c.a;
+}
+
+void wf_graphics_setBlendMode(WrapError *werr, const char *str)
+{
+	Graphics::BlendMode mode;
+	if (!Graphics::getConstant(str, mode))
+	{
+		luax_ffi_error(werr, "Invalid blend mode: %s", str);
+		return;
+	}
+
+	instance->setBlendMode(mode);
+}
+
+const char *wf_graphics_getBlendMode(WrapError *werr)
+{
+	Graphics::BlendMode mode = instance->getBlendMode();
+	const char *str;
+
+	if (!Graphics::getConstant(mode, str))
+	{
+		luax_ffi_error(werr, "Unknown blend mode.");
+		return NULL;
+	}
+
+	return str;
+}
+
+void wf_graphics_point(float x, float y)
+{
+	instance->point(x, y);
+}
+
+void wf_graphics_push(WrapError *werr)
+{
+	try
+	{
+		instance->push();
+	}
+	catch (love::Exception &e)
+	{
+		luax_ffi_error(werr, "%s", e.what());
+	}
+}
+
+void wf_graphics_pop(WrapError *werr)
+{
+	try
+	{
+		instance->pop();
+	}
+	catch (love::Exception &e)
+	{
+		luax_ffi_error(werr, "%s", e.what());
+	}
+}
+
+void wf_graphics_rotate(float angle)
+{
+	instance->rotate(angle);
+}
+
+void wf_graphics_scale(float sx, float sy)
+{
+	instance->scale(sx, sy);
+}
+
+void wf_graphics_translate(float x, float y)
+{
+	instance->translate(x, y);
+}
+
+void wf_graphics_shear(float kx, float ky)
+{
+	instance->shear(kx, ky);
+}
+
+void wf_graphics_origin()
+{
+	instance->origin();
+}
+
+} // extern "C"
+
 } // opengl
 } // graphics
 } // love

src/modules/graphics/opengl/wrap_Graphics.h

 int w_origin(lua_State *L);
 extern "C" LOVE_EXPORT int luaopen_love_graphics(lua_State *L);
 
+
+// LuaJIT FFI bindings.
+extern "C"
+{
+
+LOVE_EXPORT int wf_graphics_getWidth();
+LOVE_EXPORT int wf_graphics_getHeight();
+
+LOVE_EXPORT void wf_graphics_setColor(int r, int g, int b, int a);
+LOVE_EXPORT void wf_graphics_getColor(int *color); // 4-component array.
+
+LOVE_EXPORT void wf_graphics_setBlendMode(WrapError *werr, const char *str);
+LOVE_EXPORT const char *wf_graphics_getBlendMode(WrapError *werr);
+
+LOVE_EXPORT void wf_graphics_point(float x, float y);
+
+LOVE_EXPORT void wf_graphics_push(WrapError *werr);
+LOVE_EXPORT void wf_graphics_pop(WrapError *werr);
+LOVE_EXPORT void wf_graphics_rotate(float angle);
+LOVE_EXPORT void wf_graphics_scale(float sx, float sy);
+LOVE_EXPORT void wf_graphics_translate(float x, float y);
+LOVE_EXPORT void wf_graphics_shear(float kx, float ky);
+LOVE_EXPORT void wf_graphics_origin();
+
+} // extern "C"
+
 } // opengl
 } // graphics
 } // love

src/modules/graphics/opengl/wrap_Image.cpp

 	return luax_register_type(L, "Image", functions);
 }
 
+
+// LuaJIT FFI bindings.
+
+static Image *luax_ffi_checkimage(Proxy *proxy, WrapError *werr)
+{
+	return luax_ffi_checktype<Image>(proxy, GRAPHICS_IMAGE_ID, werr);
+}
+
+extern "C"
+{
+
+int wf_Image_getWidth(WrapError *werr, Proxy *pi)
+{
+	Image *i = luax_ffi_checkimage(pi, werr);
+	if (!i)
+		return 0;
+
+	return i->getWidth();
+}
+
+int wf_Image_getHeight(WrapError *werr, Proxy *pi)
+{
+	Image *i = luax_ffi_checkimage(pi, werr);
+	if (!i)
+		return 0;
+
+	return i->getHeight();
+}
+
+} // extern "C"
+
 } // opengl
 } // graphics
 } // love

src/modules/graphics/opengl/wrap_Image.h

 int w_Image_getData(lua_State *L);
 extern "C" int luaopen_image(lua_State *L);
 
+
+// LuaJIT FFI bindings.
+extern "C"
+{
+
+LOVE_EXPORT int wf_Image_getWidth(WrapError *werr, Proxy *pi);
+LOVE_EXPORT int wf_Image_getHeight(WrapError *werr, Proxy *pi);
+
+} // extern "C"
+
 } // opengl
 } // graphics
 } // love

src/modules/graphics/opengl/wrap_SpriteBatch.cpp

 	return luax_register_type(L, "SpriteBatch", functions);
 }
 
+
+// LuaJIT FFI bindings.
+
+static SpriteBatch *luax_ffi_checkspritebatch(Proxy *proxy, WrapError *werr)
+{
+	return luax_ffi_checktype<SpriteBatch>(proxy, GRAPHICS_SPRITE_BATCH_ID, werr);
+}
+
+extern "C"
+{
+
+int wf_SpriteBatch_add(WrapError *werr, Proxy *sb, float x, float y, float a, float sx, float sy, float ox, float oy, float kx, float ky)
+{
+	SpriteBatch *t = luax_ffi_checkspritebatch(sb, werr);
+	if (!t)
+		return 0;
+
+	return t->add(x, y, a, sx, sy, ox, oy, kx, ky);
+}
+
+int wf_SpriteBatch_addg(WrapError *werr, Proxy *sb, Proxy *g, float x, float y, float a, float sx, float sy, float ox, float oy, float kx, float ky)
+{
+	SpriteBatch *t = luax_ffi_checkspritebatch(sb, werr);
+	if (!t)
+		return 0;
+
+	if (!luax_ffi_checktype(g, GRAPHICS_GEOMETRY_ID, werr))
+		return 0;
+
+	Geometry *geom = (Geometry *) g->data;
+
+	int id = 0;
+	try
+	{
+		id = t->addg(geom, x, y, a, sx, sy, ox, oy, kx, ky);
+	}
+	catch (love::Exception &e)
+	{
+		luax_ffi_error(werr, "%s", e.what());
+		return 0;
+	}
+	return id;
+}
+
+void wf_SpriteBatch_set(WrapError *werr, Proxy *sb, int id, float x, float y, float a, float sx, float sy, float ox, float oy, float kx, float ky)
+{
+	SpriteBatch *t = luax_ffi_checkspritebatch(sb, werr);
+	if (!t)
+		return;
+
+	t->add(x, y, a, sx, sy, ox, oy, kx, ky, id);
+}
+	
+void wf_SpriteBatch_setg(WrapError *werr, Proxy *sb, int id, Proxy *g, float x, float y, float a, float sx, float sy, float ox, float oy, float kx, float ky)
+{
+	SpriteBatch *t = luax_ffi_checkspritebatch(sb, werr);
+	if (!t)
+		return;
+
+	if (!luax_ffi_checktype(g, GRAPHICS_GEOMETRY_ID, werr))
+		return;
+
+	Geometry *geom = (Geometry *) g->data;
+
+	try
+	{
+		t->addg(geom, x, y, a, sx, sy, ox, oy, kx, ky, id);
+	}
+	catch (love::Exception &e)
+	{
+		luax_ffi_error(werr, "%s", e.what());
+	}
+}
+
+void wf_SpriteBatch_bind(WrapError *werr, Proxy *sb)
+{
+	SpriteBatch *t = luax_ffi_checkspritebatch(sb, werr);
+	if (!t)
+		return;
+
+	try
+	{
+		t->lock();
+	}
+	catch (love::Exception &e)
+	{
+		luax_ffi_error(werr, "%s", e.what());
+	}
+}
+
+void wf_SpriteBatch_unbind(WrapError *werr, Proxy *sb)
+{
+	SpriteBatch *t = luax_ffi_checkspritebatch(sb, werr);
+	if (!t)
+		return;
+
+	t->unlock();
+}
+
+void wf_SpriteBatch_setColor(WrapError *werr, Proxy *sb, int r, int g, int b, int a)
+{
+	SpriteBatch *t = luax_ffi_checkspritebatch(sb, werr);
+	if (!t)
+		return;
+
+	t->setColor(Color(r, g, b, a));
+}
+
+void wf_SpriteBatch_disableColor(WrapError *werr, Proxy *sb)
+{
+	SpriteBatch *t = luax_ffi_checkspritebatch(sb, werr);
+	if (!t)
+		return;
+
+	t->setColor();
+}
+
+} // extern "C"
+
 } // opengl
 } // graphics
 } // love

src/modules/graphics/opengl/wrap_SpriteBatch.h

 
 extern "C" int luaopen_spritebatch(lua_State *L);
 
+
+// LuaJIT FFI bindings.
+extern "C"
+{
+
+LOVE_EXPORT int wf_SpriteBatch_add(WrapError *werr, Proxy *sb, float x, float y, float a, float sx, float sy, float ox, float oy, float kx, float ky);
+LOVE_EXPORT int wf_SpriteBatch_addg(WrapError *werr, Proxy *sb, Proxy *g, float x, float y, float a, float sx, float sy, float ox, float oy, float kx, float ky);
+LOVE_EXPORT void wf_SpriteBatch_set(WrapError *werr, Proxy *sb, int id, float x, float y, float a, float sx, float sy, float ox, float oy, float kx, float ky);
+LOVE_EXPORT void wf_SpriteBatch_setg(WrapError *werr, Proxy *sb, int id, Proxy *g, float x, float y, float a, float sx, float sy, float ox, float oy, float kx, float ky);
+
+LOVE_EXPORT void wf_SpriteBatch_bind(WrapError *werr, Proxy *sb);
+LOVE_EXPORT void wf_SpriteBatch_unbind(WrapError *werr, Proxy *sb);
+
+LOVE_EXPORT void wf_SpriteBatch_setColor(WrapError *werr, Proxy *sb, int r, int g, int b, int a);
+LOVE_EXPORT void wf_SpriteBatch_disableColor(WrapError *werr, Proxy *sb);
+
+} // extern "C"
+
 } // opengl
 } // graphics
 } // love

src/modules/image/wrap_Image.cpp

 #include "common/StringMap.h"
 
 #include "magpie/Image.h"
+#include "scripts/ffi_image.lua.h"
 
 namespace love
 {
 	w.functions = functions;
 	w.types = types;
 
-	return luax_register_module(L, w);
+	int n = luax_register_module(L, w);
+
+	if (luaL_loadbuffer(L, (const char *)ffi_image_lua, sizeof(ffi_image_lua), "wrap_image.lua") == 0)
+		lua_call(L, 0, 0);
+
+	return n;
 }
 
 } // image

src/modules/image/wrap_ImageData.cpp

 	return luax_register_type(L, "ImageData", functions);
 }
 
+
+static ImageData *luax_ffi_checkimagedata(Proxy *proxy, WrapError *werr)
+{
+	return luax_ffi_checktype<ImageData>(proxy, IMAGE_IMAGE_DATA_ID, werr);
+}
+
+// LuaJIT FFI bindings.
+extern "C"
+{
+
+int wf_ImageData_getWidth(WrapError *werr, Proxy *ip)
+{
+	ImageData *id = luax_ffi_checkimagedata(ip, werr);
+	if (!id)
+		return 0;
+
+	return id->getWidth();
+}
+
+int wf_ImageData_getHeight(WrapError *werr, Proxy *ip)
+{
+	ImageData *id = luax_ffi_checkimagedata(ip, werr);
+	if (!id)
+		return 0;
+
+	return id->getHeight();
+}
+
+void wf_ImageData_getPixel(WrapError *werr, Proxy *ip, int x, int y, int *pix)
+{
+	ImageData *id = luax_ffi_checkimagedata(ip, werr);
+	if (!id)
+		return;
+
+	try
+	{
+		pixel p = id->getPixel(x, y);
+		pix[0] = p.r;
+		pix[1] = p.g;
+		pix[2] = p.b;
+		pix[3] = p.a;
+	}
+	catch (love::Exception &e)
+	{
+		luax_ffi_error(werr, "%s", e.what());
+	}
+}
+
+void wf_ImageData_setPixel(WrapError *werr, Proxy *ip, int x, int y, int *pix)
+{
+	ImageData *id = luax_ffi_checkimagedata(ip, werr);
+	if (!id)
+		return;
+
+	pixel p = {pix[0], pix[1], pix[2], pix[3]};
+
+	try
+	{
+		id->setPixel(x, y, p);
+	}
+	catch (love::Exception &e)
+	{
+		luax_ffi_error(werr, "%s", e.what());
+	}
+}
+
+} // extern "C"
+
+
 } // image
 } // love

src/modules/image/wrap_ImageData.h

 int w_ImageData_encode(lua_State *L);
 extern "C" int luaopen_imagedata(lua_State *L);
 
+
+// LuaJIT FFI bindings.
+extern "C"
+{
+
+LOVE_EXPORT int wf_ImageData_getWidth(WrapError *werr, Proxy *ip);
+LOVE_EXPORT int wf_ImageData_getHeight(WrapError *werr, Proxy *ip);
+LOVE_EXPORT void wf_ImageData_getPixel(WrapError *werr, Proxy *ip, int x, int y, int *pix);
+LOVE_EXPORT void wf_ImageData_setPixel(WrapError *werr, Proxy *ip, int x, int y, int *pix);
+
+}
+
 } // image
 } // love
 

src/modules/love/love.cpp

 
 // Scripts
 #include "scripts/boot.lua.h"
+#include "scripts/ffi.lua.h"
 
 // All modules define a c-accessible luaopen
 // so let's make use of those, instead
 // of addressing implementations directly.
 extern "C"
 {
+	extern int luaopen_love_ffi(lua_State*);
 	extern int luaopen_love_audio(lua_State*);
 	extern int luaopen_love_event(lua_State*);
 	extern int luaopen_love_filesystem(lua_State*);
 }
 
 static const luaL_Reg modules[] = {
+	{ "love.ffi", luaopen_love_ffi },
 	{ "love.audio", luaopen_love_audio },
 	{ "love.event", luaopen_love_event },
 	{ "love.filesystem", luaopen_love_filesystem },
 };
 
 #ifdef LOVE_LEGENDARY_CONSOLE_IO_HACK
-int w__openConsole(lua_State * L);
+int w__openConsole(lua_State *L);
 #endif // LOVE_LEGENDARY_CONSOLE_IO_HACK
 
 const char *love_version()
 #endif
 	lua_setfield(L, -2, "_os");
 
+	// Required for the FFI bindings.
+	lua_pushcfunction(L, love::w__gettypemetatable);
+	lua_setfield(L, -2, "_gettypemetatable");
+
 	// Preload module loaders.
 	for (int i = 0; modules[i].name != 0; i++)
 	{
 	return 1;
 }
 
+int luaopen_love_ffi(lua_State *L)
+{
+	if (luaL_loadbuffer(L, (const char *)love::ffi_lua, sizeof(love::ffi_lua), "love_ffi.lua") == 0)
+		lua_call(L, 0, 1);
 
+	return 1;
+}
 
+
+

src/modules/math/wrap_Math.cpp

 #include "MathModule.h"
 #include "BezierCurve.h"
 
+#include "scripts/ffi_math.lua.h"
+
 #include <cmath>
 #include <iostream>
 
 
 	int n = luax_register_module(L, w);
 
+	if (luaL_loadbuffer(L, (const char *)ffi_math_lua, sizeof(ffi_math_lua), "wrap_math.lua") == 0)
+		lua_call(L, 0, 0);
+
 	return n;
 }
 
+
+extern "C"
+{
+
+double wf_math_random()
+{
+	return Math::instance.random();
+}
+
+double wf_math_randomLU(WrapError *werr, double l, double u)
+{
+	return luax_ffi_getrandom(werr, Math::instance.random(), l, u);
+}
+
+double wf_math_randomnormal(double mean, double stddev)
+{
+	return Math::instance.randomnormal(stddev) + mean;
+}
+
+float wf_math_noise1(float x)
+{
+	return Math::instance.noise(x);
+}
+float wf_math_noise2(float x, float y)
+{
+	return Math::instance.noise(x, y);
+}
+float wf_math_noise3(float x, float y, float z)
+{
+	return Math::instance.noise(x, y, z);
+}
+float wf_math_noise4(float x, float y, float z, float w)
+{
+	return Math::instance.noise(x, y, z, w);
+}
+
+} // extern "C"
+
 } // math
 } // love

src/modules/math/wrap_Math.h

 int w_noise(lua_State *L);
 extern "C" LOVE_EXPORT int luaopen_love_math(lua_State *L);
 
+
+extern "C"
+{
+
+LOVE_EXPORT double wf_math_random();
+LOVE_EXPORT double wf_math_randomLU(WrapError *werr, double l, double u);
+LOVE_EXPORT double wf_math_randomnormal(double mean, double stddev);
+LOVE_EXPORT float wf_math_noise1(float x);
+LOVE_EXPORT float wf_math_noise2(float x, float y);
+LOVE_EXPORT float wf_math_noise3(float x, float y, float z);
+LOVE_EXPORT float wf_math_noise4(float x, float y, float z, float w);
+
+} // extern "C"
+
 } // random
 } // love
 

src/modules/math/wrap_RandomGenerator.cpp

 	return luax_register_type(L, "RandomGenerator", functions);
 }
 
+
+double luax_ffi_getrandom(WrapError *werr, double r, double l, double u)
+{
+	if (l > u)
+	{
+		luax_ffi_error(werr, "Interval is empty");
+		return 0;
+	}
+
+	return floor(r * (u - l + 1.0)) + l;
+}
+
+static RandomGenerator *luax_ffi_checkrandomgenerator(Proxy *proxy, WrapError *werr)
+{
+	return luax_ffi_checktype<RandomGenerator>(proxy, MATH_RANDOM_GENERATOR_ID, werr);
+}
+
+// LuaJIT FFI bindings.
+extern "C"
+{
+
+double wf_RandomGenerator_random(WrapError *werr, Proxy *pr)
+{
+	RandomGenerator *rng = luax_ffi_checkrandomgenerator(pr, werr);
+	if (!rng)
+		return 0;
+
+	return rng->random();
+}
+
+double wf_RandomGenerator_randomLU(WrapError *werr, Proxy *pr, double l, double u)
+{
+	RandomGenerator *rng = luax_ffi_checkrandomgenerator(pr, werr);
+	if (!rng)
+		return 0;
+
+	return luax_ffi_getrandom(werr, rng->random(), l, u);
+}
+
+double wf_RandomGenerator_randomnormal(WrapError *werr, Proxy *pr, double mean, double stddev)
+{
+	RandomGenerator *rng = luax_ffi_checkrandomgenerator(pr, werr);
+	if (!rng)
+		return 0;
+
+	return rng->randomnormal(stddev) + mean;
+}
+
+} // extern "C"
+
 } // math
 } // love

src/modules/math/wrap_RandomGenerator.h

 int w_RandomGenerator_randomnormal(lua_State *L);
 extern "C" int luaopen_randomgenerator(lua_State *L);
 
+
+double luax_ffi_getrandom(WrapError *werr, double r, double l, double u);
+
+extern "C"
+{
+
+LOVE_EXPORT double wf_RandomGenerator_random(WrapError *werr, Proxy *pr);
+LOVE_EXPORT double wf_RandomGenerator_randomLU(WrapError *werr, Proxy *pr, double l, double u);
+LOVE_EXPORT double wf_RandomGenerator_randomnormal(WrapError *werr, Proxy *pr, double mean, double stddev);
+
+} // extern "C"
+
 } // math
 } // love
 

src/modules/timer/wrap_Timer.cpp

 
 // LOVE
 #include "wrap_Timer.h"
-
 #include "sdl/Timer.h"
+#include "scripts/ffi_timer.lua.h"
 
 namespace love
 {
 	w.functions = functions;
 	w.types = 0;
 
-	return luax_register_module(L, w);
+	int n = luax_register_module(L, w);
+
+	if (luaL_loadbuffer(L, (const char *)ffi_timer_lua, sizeof(ffi_timer_lua), "wrap_timer.lua") == 0)
+		lua_call(L, 0, 0);
+
+	return n;
+}
+
+
+// LuaJIT FFI bindings.
+extern "C"
+{
+
+double wf_timer_getDelta()
+{
+	return instance->getDelta();
+}
+
+int wf_timer_getFPS()
+{
+	return instance->getFPS();
+}
+
+double wf_timer_getAverageDelta()
+{
+	return instance->getAverageDelta();
+}
+
+double wf_timer_getTime()
+{
+	return instance->getTime();
+}
+
 }
 
 } // timer

src/modules/timer/wrap_Timer.h

 int w_getTime(lua_State *L);
 extern "C" LOVE_EXPORT int luaopen_love_timer(lua_State *L);
 
+
+// LuaJIT FFI bindings.
+extern "C"
+{
+
+LOVE_EXPORT double wf_timer_getDelta();
+LOVE_EXPORT int wf_timer_getFPS();
+LOVE_EXPORT double wf_timer_getAverageDelta();
+LOVE_EXPORT double wf_timer_getTime();
+
+}
+
 } // timer
 } // love
 

src/scripts/boot.lua

 		console = false, -- Only relevant for windows.
 		identity = false,
 		release = false,
+		ffi = true,
 	}
 
 	-- If config file exists, load it and allow it to update config table.
 	if love.arg.options.console.set then
 		c.console = true
 	end
+	
+	-- We need to use love.ffi before the rest are required.
+	local lovex = require("love.ffi")
+	if c.ffi and lovex.isSupported() then
+		lovex.enable()
+	end
 
 	-- Gets desired modules.
 	for k,v in ipairs{

src/scripts/boot.lua.h

 	0x09, 0x09, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x20, 0x3d, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 
 	0x2c, 0x0a,
 	0x09, 0x09, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x20, 0x3d, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x2c, 0x0a,
+	0x09, 0x09, 0x66, 0x66, 0x69, 0x20, 0x3d, 0x20, 0x74, 0x72, 0x75, 0x65, 0x2c, 0x0a,
 	0x09, 0x7d, 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, 0x0a,
 	0x09, 0x09, 0x63, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, 0x20, 0x3d, 0x20, 0x74, 0x72, 0x75, 0x65, 0x0a,
 	0x09, 0x65, 0x6e, 0x64, 0x0a,
+	0x09, 0x0a,
+	0x09, 0x2d, 0x2d, 0x20, 0x57, 0x65, 0x20, 0x6e, 0x65, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x75, 0x73, 0x65, 
+	0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x66, 0x66, 0x69, 0x20, 0x62, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x20, 0x74, 
+	0x68, 0x65, 0x20, 0x72, 0x65, 0x73, 0x74, 0x20, 0x61, 0x72, 0x65, 0x20, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 
+	0x65, 0x64, 0x2e, 0x0a,
+	0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x78, 0x20, 0x3d, 0x20, 0x72, 0x65, 0x71, 
+	0x75, 0x69, 0x72, 0x65, 0x28, 0x22, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x66, 0x66, 0x69, 0x22, 0x29, 0x0a,
+	0x09, 0x69, 0x66, 0x20, 0x63, 0x2e, 0x66, 0x66, 0x69, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x6c, 0x6f, 0x76, 0x65, 
+	0x78, 0x2e, 0x69, 0x73, 0x53, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x28, 0x29, 0x20, 0x74, 0x68, 
+	0x65, 0x6e, 0x0a,
+	0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x78, 0x2e, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x28, 0x29, 0x0a,
+	0x09, 0x65, 0x6e, 0x64, 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, 

src/scripts/ffi.lua

+--[[
+Copyright (c) 2006-2013 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.
+--]]
+
+
+--[[
+Some notes:
+
+- C++ exceptions cannot nicely be turned into Lua errors in a thread-safe
+  manner from within the C-side FFI wrapper code. So C functions which can
+  potentially error must have a WrapError* argument. Lua-side,
+  luax.errorptr() is passed into the function, and lovex.checkerror() is
+  called directly after.
+  
+- nil will be accepted as a const char* argument. Use lovex.checkstring.
+
+- String arguments and string return values can vastly reduce the
+  potential performance benefits of FFI functions.
+
+- All object methods *MUST* do error checking (via lovex.errorptr and
+  lovex.checkerror.) This is because the userdata/Proxy needs type checking
+  and it should be done C-side.
+
+- Profile! Having an FFI-bound function makes it much more time
+  consuming and bug-prone to change or update the C++ side function
+  in the future.
+  In many cases using FFI bindings will not increase performance
+  by a substantial amount, either because the function's bottleneck
+  is mostly C++side, the function uses strings, tables or a variable
+  amount of arguments, or any number of other reasons.
+  If the standard Lua bindings give similar performance, or if the
+  function will not likely be called many times per frame, *don't keep an
+  FFI version*.
+  
+- Use tonumber() on return value numbers.
+
+- You still have to switch between 0-based and 1-based indices! Do this C-side.
+
+]]
+
+local lovex = {}
+lovex.enabled = false
+
+local module_functions = {}
+
+function lovex.register_module_functions(modname, funcs)	
+	module_functions[modname] = module_functions[modname] or {new={}, old={}}
+	local modfuncs = module_functions[modname]
+	
+	for funcname, func in pairs(funcs) do
+		modfuncs.new[funcname] = func
+		if lovex.enabled and love[modname] and love[modname][funcname] then
+			if love[modname][funcname] ~= func then
+				modfuncs.old[funcname] = love[modname][funcname]
+			end
+			love[modname][funcname] = func
+		end
+	end
+end
+
+local type_functions = {}
+
+function lovex.register_type_methods(typename, funcs)
+	local type_metatable = love._gettypemetatable(typename)
+	assert(type(type_metatable) == "table" and type_metatable.typeOf ~= nil, "Invalid type: "..typename)
+	
+	type_functions[typename] = type_functions[typename] or {new={}, old={}}
+	local typefuncs = type_functions[typename]
+	
+	for funcname, func in pairs(funcs) do
+		typefuncs.new[funcname] = func
+		if lovex.enabled and type_metatable[funcname] then
+			if type_metatable[funcname] ~= func then
+				typefuncs.old[funcname] = type_metatable[funcname]
+			end
+			type_metatable[funcname] = func
+		end
+	end
+end
+
+function lovex.enable()
+	if lovex.enabled or not lovex.isSupported() then
+		return false
+	end
+	
+	-- Replace module functions with registered FFI variants.
+	for modname, mod in pairs(module_functions) do
+		if type(love[modname]) == "table" then
+			for funcname, func in pairs(mod.new) do
+				if love[modname][funcname] ~= func then
+					-- Store the old functions so we can restore them later.
+					mod.old[funcname] = love[modname][funcname]
+					love[modname][funcname] = func
+				end
+			end
+		end
+	end
+	
+	-- Replace type methods with registered FFI variants.
+	for typename, ttype in pairs(type_functions) do
+		local type_metatable = love._gettypemetatable(typename)
+		if type(type_metatable) == "table" and type_metatable.typeOf ~= nil then
+			for funcname, func in pairs(ttype.new) do
+				if type_metatable[funcname] ~= func then
+					-- Store the old methods so we can restore them later.
+					ttype.old[funcname] = type_metatable[funcname]
+					type_metatable[funcname] = func
+				end
+			end
+		end
+	end
+	
+	lovex.enabled = true
+	return true
+end
+
+function lovex.disable()
+	if not lovex.enabled or not lovex.isSupported() then
+		return false
+	end
+	
+	-- Restore old module functions.
+	for modname, mod in pairs(module_functions) do
+		if type(love[modname] == "table") then
+			for funcname, func in pairs(mod.new) do
+				if mod.old[funcname] and love[modname][funcname] == func then
+					love[modname][funcname] = mod.old[funcname]
+				end
+			end
+		end
+	end
+	
+	-- Restore old type methods.
+	for typename, ttype in pairs(type_functions) do
+		local type_metatable = love._gettypemetatable(typename)
+		if type(type_metatable) == "table" and type_metatable.typeOf ~= nil then
+			for funcname, func in pairs(ttype.new) do
+				if ttype.old[funcname] and type_metatable[funcname] == func then
+					type_metatable[funcname] = ttype.old[funcname]
+				end
+			end
+		end
+	end
+	
+	lovex.enabled = false
+end
+
+function lovex.isEnabled()
+	return lovex.enabled
+end
+
+local ffi
+
+-- Verify that we have LuaJIT, FFI support, and liblove.
+if jit and jit.status() then
+	ffi = require("ffi")
+	
+	local liblove_path = "love"
+	if ffi.os == "OSX" then
+		liblove_path = "love.framework/love"
+	end
+
+	local has_liblove, liblove = pcall(ffi.load, liblove_path)
+	if has_liblove then
+		
+		ffi.cdef[[ const char *love_version(); ]]
+		
+		if pcall(liblove.love_version) then
+			lovex.liblove = liblove
+		end
+	end
+end
+
+function lovex.isSupported()
+	return lovex.liblove ~= nil
+end
+
+function lovex.checktype(arg, ttype, level)
+	if type(arg) ~= "userdata" or not arg:typeOf(ttype) then
+		error("Incorrect parameter type: expected "..ttype, level or 3)
+	end
+end
+
+function lovex.checkstring(str, level)
+	if type(str) ~= "string" then
+		error("Incorrect parameter type: expected string", level or 3)
+	end
+end
+
+
+if lovex.isSupported() then
+
+	ffi.cdef[[
+// A proxy is a small wrapper for all Lua-exposed love objects.
+typedef struct Proxy Proxy;
+
+// Structure used to retrieve internal love errors.
+static const int WRAP_ERROR_MAX_LENGTH = 1024;
+typedef struct WrapError
+{
+	char str[WRAP_ERROR_MAX_LENGTH + 1];
+	size_t len;
+	int diderror;
+} WrapError;
+
+]]
+	
+	local new_wraperror_pointer = ffi.typeof("WrapError *")
+
+	-- The error structure is kept around permanently.
+	local ffi_error = ffi.new("WrapError")
+	local error_pointer = new_wraperror_pointer(ffi_error)
+
+	function lovex.errorptr()
+		return error_pointer
+	end
+
+	function lovex.checkerror(level)
+		if ffi_error.diderror ~= 0 then
+			local errstr = ffi.string(ffi_error.str, ffi_error.len)
+			
+			-- Clear the FFI error for re-use.
+			ffi_error.diderror = 0
+			ffi_error.len = 0
+			ffi.fill(ffi_error.str, ffi.sizeof(ffi_error.str), 0)
+			
+			error(errstr, level or 3)
+		end
+	end
+end
+
+-- Pseudo-module.
+love.ffi = lovex
+
+return lovex

src/scripts/ffi.lua.h

+/**
+ * Copyright (c) 2006-2013 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
+{
+
+// [ffi.lua]
+const unsigned char ffi_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, 0x31, 0x33, 0x20, 0x4c, 0x4f, 0x56, 0x45, 0x20, 0x44, 0x65, 0x76, 0x65, 0x6c, 0x6f, 0x70, 
+	0x6d, 0x65, 0x6e, 0x74, 0x20, 0x54, 0x65, 0x61, 0x6d, 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,
+	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,
+	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,
+	0x2d, 0x2d, 0x5b, 0x5b, 0x0a,
+	0x53, 0x6f, 0x6d, 0x65, 0x20, 0x6e, 0x6f, 0x74, 0x65, 0x73, 0x3a, 0x0a,
+	0x2d, 0x20, 0x43, 0x2b, 0x2b, 0x20, 0x65, 0x78, 0x63, 0x65, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x63, 
+	0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x20, 0x6e, 0x69, 0x63, 0x65, 0x6c, 0x79, 0x20, 0x62, 0x65, 0x20, 0x74, 0x75, 
+	0x72, 0x6e, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x74, 0x6f, 0x20, 0x4c, 0x75, 0x61, 0x20, 0x65, 0x72, 0x72, 0x6f, 
+	0x72, 0x73, 0x20, 0x69, 0x6e, 0x20, 0x61, 0x20, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x2d, 0x73, 0x61, 0x66, 
+	0x65, 0x0a,
+	0x20, 0x20, 0x6d, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x77, 0x69, 0x74, 0x68, 
+	0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x43, 0x2d, 0x73, 0x69, 0x64, 0x65, 0x20, 0x46, 0x46, 0x49, 0x20, 
+	0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x2e, 0x20, 0x53, 0x6f, 0x20, 0x43, 
+	0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, 0x63, 
+	0x61, 0x6e, 0x0a,
+	0x20, 0x20, 0x70, 0x6f, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x6c, 0x79, 0x20, 0x65, 0x72, 0x72, 0x6f, 
+	0x72, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x68, 0x61, 0x76, 0x65, 0x20, 0x61, 0x20, 0x57, 0x72, 0x61, 0x70, 
+	0x45, 0x72, 0x72, 0x6f, 0x72, 0x2a, 0x20, 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x20, 0x4c, 
+	0x75, 0x61, 0x2d, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x0a,
+	0x20, 0x20, 0x6c, 0x75, 0x61, 0x78, 0x2e, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x70, 0x74, 0x72, 0x28, 0x29, 0x20, 
+	0x69, 0x73, 0x20, 0x70, 0x61, 0x73, 0x73, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x74, 0x6f, 0x20, 0x74, 0x68, 0x65, 
+	0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2c, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x6c, 0x6f, 0x76, 
+	0x65, 0x78, 0x2e, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x28, 0x29, 0x20, 0x69, 0x73, 0x0a,
+	0x20, 0x20, 0x63, 0x61, 0x6c, 0x6c, 0x65, 0x64, 0x20, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6c, 0x79, 0x20, 
+	0x61, 0x66, 0x74, 0x65, 0x72, 0x2e, 0x0a,
+	0x20, 0x20, 0x0a,
+	0x2d, 0x20, 0x6e, 0x69, 0x6c, 0x20, 0x77, 0x69, 0x6c, 0x6c, 0x20, 0x62, 0x65, 0x20, 0x61, 0x63, 0x63, 0x65, 
+	0x70, 0x74, 0x65, 0x64, 0x20, 0x61, 0x73, 0x20, 0x61, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x20, 0x63, 0x68, 
+	0x61, 0x72, 0x2a, 0x20, 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x20, 0x55, 0x73, 0x65, 0x20, 
+	0x6c, 0x6f, 0x76, 0x65, 0x78, 0x2e, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x0a,
+	0x2d, 0x20, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 
+	0x20, 0x61, 0x6e, 0x64, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 
+	0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x20, 0x63, 0x61, 0x6e, 0x20, 0x76, 0x61, 0x73, 0x74, 0x6c, 0x79, 
+	0x20, 0x72, 0x65, 0x64, 0x75, 0x63, 0x65, 0x20, 0x74, 0x68, 0x65, 0x0a,
+	0x20, 0x20, 0x70, 0x6f, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x20, 0x70, 0x65, 0x72, 0x66, 0x6f, 0x72, 
+	0x6d, 0x61, 0x6e, 0x63, 0x65, 0x20, 0x62, 0x65, 0x6e, 0x65, 0x66, 0x69, 0x74, 0x73, 0x20, 0x6f, 0x66, 0x20, 
+	0x46, 0x46, 0x49, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x0a,
+	0x2d, 0x20, 0x41, 0x6c, 0x6c, 0x20, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x20, 0x6d, 0x65, 0x74, 0x68, 0x6f, 
+	0x64, 0x73, 0x20, 0x2a, 0x4d, 0x55, 0x53, 0x54, 0x2a, 0x20, 0x64, 0x6f, 0x20, 0x65, 0x72, 0x72, 0x6f, 0x72, 
+	0x20, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x69, 0x6e, 0x67, 0x20, 0x28, 0x76, 0x69, 0x61, 0x20, 0x6c, 0x6f, 0x76, 
+	0x65, 0x78, 0x2e, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x70, 0x74, 0x72, 0x20, 0x61, 0x6e, 0x64, 0x0a,
+	0x20, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x78, 0x2e, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x65, 0x72, 0x72, 0x6f, 0x72, 
+	0x2e, 0x29, 0x20, 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x62, 0x65, 0x63, 0x61, 0x75, 0x73, 0x65, 
+	0x20, 0x74, 0x68, 0x65, 0x20, 0x75, 0x73, 0x65, 0x72, 0x64, 0x61, 0x74, 0x61, 0x2f, 0x50, 0x72, 0x6f, 0x78, 
+	0x79, 0x20, 0x6e, 0x65, 0x65, 0x64, 0x73, 0x20, 0x74, 0x79, 0x70, 0x65, 0x20, 0x63, 0x68, 0x65, 0x63, 0x6b, 
+	0x69, 0x6e, 0x67, 0x0a,
+	0x20, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x69, 0x74, 0x20, 0x73, 0x68, 0x6f, 0x75, 0x6c, 0x64, 0x20, 0x62, 0x65, 
+	0x20, 0x64, 0x6f, 0x6e, 0x65, 0x20, 0x43, 0x2d, 0x73, 0x69, 0x64, 0x65, 0x2e, 0x0a,
+	0x2d, 0x20, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x21, 0x20, 0x48, 0x61, 0x76, 0x69, 0x6e, 0x67, 0x20, 
+	0x61, 0x6e, 0x20, 0x46, 0x46, 0x49, 0x2d, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 
+	0x69, 0x6f, 0x6e, 0x20, 0x6d, 0x61, 0x6b, 0x65, 0x73, 0x20, 0x69, 0x74, 0x20, 0x6d, 0x75, 0x63, 0x68, 0x20, 
+	0x6d, 0x6f, 0x72, 0x65, 0x20, 0x74, 0x69, 0x6d, 0x65, 0x0a,
+	0x20, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x69, 0x6e, 0x67, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x62, 0x75, 
+	0x67, 0x2d, 0x70, 0x72, 0x6f, 0x6e, 0x65, 0x20, 0x74, 0x6f, 0x20, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x20, 
+	0x6f, 0x72, 0x20, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x43, 0x2b, 0x2b, 0x20, 
+	0x73, 0x69, 0x64, 0x65, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x0a,
+	0x20, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x66, 0x75, 0x74, 0x75, 0x72, 0x65, 0x2e, 0x0a,
+	0x20, 0x20, 0x49, 0x6e, 0x20, 0x6d, 0x61, 0x6e, 0x79, 0x20, 0x63, 0x61, 0x73, 0x65, 0x73, 0x20, 0x75, 0x73, 
+	0x69, 0x6e, 0x67, 0x20, 0x46, 0x46, 0x49, 0x20, 0x62, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x73, 0x20, 0x77, 
+	0x69, 0x6c, 0x6c, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x69, 0x6e, 0x63, 0x72, 0x65, 0x61, 0x73, 0x65, 0x20, 0x70, 
+	0x65, 0x72, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x6e, 0x63, 0x65, 0x0a,
+	0x20, 0x20, 0x62, 0x79, 0x20, 0x61, 0x20, 0x73, 0x75, 0x62, 0x73, 0x74, 0x61, 0x6e, 0x74, 0x69, 0x61, 0x6c, 
+	0x20, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x2c, 0x20, 0x65, 0x69, 0x74, 0x68, 0x65, 0x72, 0x20, 0x62, 0x65, 
+	0x63, 0x61, 0x75, 0x73, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 
+	0x27, 0x73, 0x20, 0x62, 0x6f, 0x74, 0x74, 0x6c, 0x65, 0x6e, 0x65, 0x63, 0x6b, 0x0a,
+	0x20, 0x20, 0x69, 0x73, 0x20, 0x6d, 0x6f, 0x73, 0x74, 0x6c, 0x79, 0x20, 0x43, 0x2b, 0x2b, 0x73, 0x69, 0x64, 
+	0x65, 0x2c, 0x20, 0x74, 0x68, 0x65, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x75, 0x73, 
+	0x65, 0x73, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x73, 0x2c, 0x20, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x73, 
+	0x20, 0x6f, 0x72, 0x20, 0x61, 0x20, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x0a,
+	0x20, 0x20, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65, 
+	0x6e, 0x74, 0x73, 0x2c, 0x20, 0x6f, 0x72, 0x20, 0x61, 0x6e, 0x79, 0x20, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 
+	0x20, 0x6f, 0x66, 0x20, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x20, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x73, 0x2e, 0x0a,
+	0x20, 0x20, 0x49, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 
+	0x4c, 0x75, 0x61, 0x20, 0x62, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x73, 0x20, 0x67, 0x69, 0x76, 0x65, 0x20, 
+	0x73, 0x69, 0x6d, 0x69, 0x6c, 0x61, 0x72, 0x20, 0x70, 0x65, 0x72, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x6e, 0x63, 
+	0x65, 0x2c, 0x20, 0x6f, 0x72, 0x20, 0x69, 0x66, 0x20, 0x74, 0x68, 0x65, 0x0a,
+	0x20, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x77, 0x69, 0x6c, 0x6c, 0x20, 0x6e, 0x6f, 
+	0x74, 0x20, 0x6c, 0x69, 0x6b, 0x65, 0x6c, 0x79, 0x20, 0x62, 0x65, 0x20, 0x63, 0x61, 0x6c, 0x6c, 0x65, 0x64, 
+	0x20, 0x6d, 0x61, 0x6e, 0x79, 0x20, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x20, 0x70, 0x65, 0x72, 0x20, 0x66, 0x72, 
+	0x61, 0x6d, 0x65, 0x2c, 0x20, 0x2a, 0x64, 0x6f, 0x6e, 0x27, 0x74, 0x20, 0x6b, 0x65, 0x65, 0x70, 0x20, 0x61, 
+	0x6e, 0x0a,
+	0x20, 0x20, 0x46, 0x46, 0x49, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x2a, 0x2e, 0x0a,
+	0x20, 0x20, 0x0a,
+	0x2d, 0x20, 0x55, 0x73, 0x65, 0x20, 0x74, 0x6f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x28, 0x29, 0x20, 0x6f, 
+	0x6e, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x20, 0x6e, 0x75, 0x6d, 
+	0x62, 0x65, 0x72, 0x73, 0x2e, 0x0a,
+	0x2d, 0x20, 0x59, 0x6f, 0x75, 0x20, 0x73, 0x74, 0x69, 0x6c, 0x6c, 0x20, 0x68, 0x61, 0x76, 0x65, 0x20, 0x74, 
+	0x6f, 0x20, 0x73, 0x77, 0x69, 0x74, 0x63, 0x68, 0x20, 0x62, 0x65, 0x74, 0x77, 0x65, 0x65, 0x6e, 0x20, 0x30, 
+	0x2d, 0x62, 0x61, 0x73, 0x65, 0x64, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x31, 0x2d, 0x62, 0x61, 0x73, 0x65, 0x64, 
+	0x20, 0x69, 0x6e, 0x64, 0x69, 0x63, 0x65, 0x73, 0x21, 0x20, 0x44, 0x6f, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 
+	0x43, 0x2d, 0x73, 0x69, 0x64, 0x65, 0x2e, 0x0a,
+	0x5d, 0x5d, 0x0a,
+	0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x78, 0x20, 0x3d, 0x20, 0x7b, 0x7d, 0x0a,
+	0x6c, 0x6f, 0x76, 0x65, 0x78, 0x2e, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x20, 0x3d, 0x20, 0x66, 0x61, 
+	0x6c, 0x73, 0x65, 0x0a,
+	0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x74, 
+	0x69, 0x6f, 0x6e, 0x73, 0x20, 0x3d, 0x20, 0x7b, 0x7d, 0x0a,
+	0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x78, 0x2e, 0x72, 0x65, 0x67, 
+	0x69, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x74, 
+	0x69, 0x6f, 0x6e, 0x73, 0x28, 0x6d, 0x6f, 0x64, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x20, 0x66, 0x75, 0x6e, 0x63, 
+	0x73, 0x29, 0x09, 0x0a,
+	0x09, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x5b, 
+	0x6d, 0x6f, 0x64, 0x6e, 0x61, 0x6d, 0x65, 0x5d, 0x20, 0x3d, 0x20, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5f, 
+	0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x5b, 0x6d, 0x6f, 0x64, 0x6e, 0x61, 0x6d, 0x65, 0x5d, 
+	0x20, 0x6f, 0x72, 0x20, 0x7b, 0x6e, 0x65, 0x77, 0x3d, 0x7b, 0x7d, 0x2c, 0x20, 0x6f, 0x6c, 0x64, 0x3d, 0x7b, 
+	0x7d, 0x7d, 0x0a,
+	0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6d, 0x6f, 0x64, 0x66, 0x75, 0x6e, 0x63, 0x73, 0x20, 0x3d, 0x20, 
+	0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x5b, 0x6d, 
+	0x6f, 0x64, 0x6e, 0x61, 0x6d, 0x65, 0x5d, 0x0a,
+	0x09, 0x0a,
+	0x09, 0x66, 0x6f, 0x72, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x20, 0x66, 0x75, 0x6e, 
+	0x63, 0x20, 0x69, 0x6e, 0x20, 0x70, 0x61, 0x69, 0x72, 0x73, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x73, 0x29, 0x20, 
+	0x64, 0x6f, 0x0a,
+	0x09, 0x09, 0x6d, 0x6f, 0x64, 0x66, 0x75, 0x6e, 0x63, 0x73, 0x2e, 0x6e, 0x65, 0x77, 0x5b, 0x66, 0x75, 0x6e, 
+	0x63, 0x6e, 0x61, 0x6d, 0x65, 0x5d, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x0a,
+	0x09, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x78, 0x2e, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 
+	0x20, 0x61, 0x6e, 0x64, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x5b, 0x6d, 0x6f, 0x64, 0x6e, 0x61, 0x6d, 0x65, 0x5d, 
+	0x20, 0x61, 0x6e, 0x64, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x5b, 0x6d, 0x6f, 0x64, 0x6e, 0x61, 0x6d, 0x65, 0x5d, 
+	0x5b, 0x66, 0x75, 0x6e, 0x63, 0x6e, 0x61, 0x6d, 0x65, 0x5d, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a,
+	0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x5b, 0x6d, 0x6f, 0x64, 0x6e, 0x61, 0x6d, 0x65, 
+	0x5d, 0x5b, 0x66, 0x75, 0x6e, 0x63, 0x6e, 0x61, 0x6d, 0x65, 0x5d, 0x20, 0x7e, 0x3d, 0x20, 0x66, 0x75, 0x6e, 
+	0x63, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a,
+	0x09, 0x09, 0x09, 0x09, 0x6d, 0x6f, 0x64, 0x66, 0x75, 0x6e, 0x63, 0x73, 0x2e, 0x6f, 0x6c, 0x64, 0x5b, 0x66, 
+	0x75, 0x6e, 0x63, 0x6e, 0x61, 0x6d, 0x65, 0x5d, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x5b, 0x6d, 0x6f, 
+	0x64, 0x6e, 0x61, 0x6d, 0x65, 0x5d, 0x5b, 0x66, 0x75, 0x6e, 0x63, 0x6e, 0x61, 0x6d, 0x65, 0x5d, 0x0a,
+	0x09, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a,
+	0x09, 0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x5b, 0x6d, 0x6f, 0x64, 0x6e, 0x61, 0x6d, 0x65, 0x5d, 0x5b, 0x66, 
+	0x75, 0x6e, 0x63, 0x6e, 0x61, 0x6d, 0x65, 0x5d, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x0a,
+	0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a,
+	0x09, 0x65, 0x6e, 0x64, 0x0a,
+	0x65, 0x6e, 0x64, 0x0a,
+	0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x74, 0x79, 0x70, 0x65, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 
+	0x6e, 0x73, 0x20, 0x3d, 0x20, 0x7b, 0x7d, 0x0a,
+	0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x78, 0x2e, 0x72, 0x65, 0x67, 
+	0x69, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x73, 
+	0x28, 0x74, 0x79, 0x70, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x73, 0x29, 0x0a,
+	0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x74, 0x79, 0x70, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x74, 0x61, 
+	0x62, 0x6c, 0x65, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x5f, 0x67, 0x65, 0x74, 0x74, 0x79, 0x70, 
+	0x65, 0x6d, 0x65, 0x74, 0x61, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x28, 0x74, 0x79, 0x70, 0x65, 0x6e, 0x61, 0x6d, 
+	0x65, 0x29, 0x0a,
+	0x09, 0x61, 0x73, 0x73, 0x65, 0x72, 0x74, 0x28, 0x74, 0x79, 0x70, 0x65, 0x28, 0x74, 0x79, 0x70, 0x65, 0x5f, 
+	0x6d, 0x65, 0x74, 0x61, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x29, 0x20, 0x3d, 0x3d, 0x20, 0x22, 0x74, 0x61, 0x62, 
+	0x6c, 0x65, 0x22, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x74, 0x79, 0x70, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x74, 
+	0x61, 0x62, 0x6c, 0x65, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x4f, 0x66, 0x20, 0x7e, 0x3d, 0x20, 0x6e, 0x69, 0x6c, 
+	0x2c, 0x20, 0x22, 0x49, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x20, 0x74, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x22, 
+	0x2e, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x29, 0x0a,
+	0x09, 0x0a,
+	0x09, 0x74, 0x79, 0x70, 0x65, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x5b, 0x74, 0x79, 
+	0x70, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x5d, 0x20, 0x3d, 0x20, 0x74, 0x79, 0x70, 0x65, 0x5f, 0x66, 0x75, 0x6e, 
+	0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x5b, 0x74, 0x79, 0x70, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x5d, 0x20, 0x6f, 
+	0x72, 0x20, 0x7b, 0x6e, 0x65, 0x77, 0x3d, 0x7b, 0x7d, 0x2c, 0x20, 0x6f, 0x6c, 0x64, 0x3d, 0x7b, 0x7d, 0x7d, 0x0a,
+	0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x74, 0x79, 0x70, 0x65, 0x66, 0x75, 0x6e, 0x63, 0x73, 0x20, 0x3d, 
+	0x20, 0x74, 0x79, 0x70, 0x65, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x5b, 0x74, 0x79, 
+	0x70, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x5d, 0x0a,
+	0x09, 0x0a,
+	0x09, 0x66, 0x6f, 0x72, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x20, 0x66, 0x75, 0x6e, 
+	0x63, 0x20, 0x69, 0x6e, 0x20, 0x70, 0x61, 0x69, 0x72, 0x73, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x73, 0x29, 0x20, 
+	0x64, 0x6f, 0x0a,
+	0x09, 0x09, 0x74, 0x79, 0x70, 0x65, 0x66, 0x75, 0x6e, 0x63, 0x73, 0x2e, 0x6e, 0x65, 0x77, 0x5b, 0x66, 0x75, 
+	0x6e, 0x63, 0x6e, 0x61, 0x6d, 0x65, 0x5d, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x0a,
+	0x09, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x78, 0x2e, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 
+	0x20, 0x61, 0x6e, 0x64, 0x20, 0x74, 0x79, 0x70, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x74, 0x61, 0x62, 0x6c, 
+	0x65, 0x5b, 0x66, 0x75, 0x6e, 0x63, 0x6e, 0x61, 0x6d, 0x65, 0x5d, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a,
+	0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x74, 0x79, 0x70, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x74, 0x61, 0x62, 
+	0x6c, 0x65, 0x5b, 0x66, 0x75, 0x6e, 0x63, 0x6e, 0x61, 0x6d, 0x65, 0x5d, 0x20, 0x7e, 0x3d, 0x20, 0x66, 0x75, 
+	0x6e, 0x63, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a,
+	0x09, 0x09, 0x09, 0x09, 0x74, 0x79, 0x70, 0x65, 0x66, 0x75, 0x6e, 0x63, 0x73, 0x2e, 0x6f, 0x6c, 0x64, 0x5b, 
+	0x66, 0x75, 0x6e, 0x63, 0x6e, 0x61, 0x6d, 0x65, 0x5d, 0x20, 0x3d, 0x20, 0x74, 0x79, 0x70, 0x65, 0x5f, 0x6d, 
+	0x65, 0x74, 0x61, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5b, 0x66, 0x75, 0x6e, 0x63, 0x6e, 0x61, 0x6d, 0x65, 0x5d, 0x0a,
+	0x09, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a,
+	0x09, 0x09, 0x09, 0x74, 0x79, 0x70, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5b, 
+	0x66, 0x75, 0x6e, 0x63, 0x6e, 0x61, 0x6d, 0x65, 0x5d, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x0a,
+	0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a,
+	0x09, 0x65, 0x6e, 0x64, 0x0a,
+	0x65, 0x6e, 0x64, 0x0a,
+	0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x78, 0x2e, 0x65, 0x6e, 0x61, 
+	0x62, 0x6c, 0x65, 0x28, 0x29, 0x0a,
+	0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x78, 0x2e, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x20, 
+	0x6f, 0x72, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x78, 0x2e, 0x69, 0x73, 0x53, 0x75, 0x70, 
+	0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x28, 0x29, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a,
+	0x09, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x0a,
+	0x09, 0x65, 0x6e, 0x64, 0x0a,
+	0x09, 0x0a,
+	0x09, 0x2d, 0x2d, 0x20, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x20, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 
+	0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x72, 0x65, 
+	0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x65, 0x64, 0x20, 0x46, 0x46, 0x49, 0x20, 0x76, 0x61, 0x72, 0x69, 0x61, 
+	0x6e, 0x74, 0x73, 0x2e, 0x0a,
+	0x09, 0x66, 0x6f, 0x72, 0x20, 0x6d, 0x6f, 0x64, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x20, 0x6d, 0x6f, 0x64, 0x20, 
+	0x69, 0x6e, 0x20, 0x70, 0x61, 0x69, 0x72, 0x73, 0x28, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x66, 0x75, 
+	0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x29, 0x20, 0x64, 0x6f, 0x0a,
+	0x09, 0x09, 0x69, 0x66, 0x20, 0x74, 0x79, 0x70, 0x65, 0x28, 0x6c, 0x6f, 0x76, 0x65, 0x5b, 0x6d, 0x6f, 0x64, 
+	0x6e, 0x61, 0x6d, 0x65, 0x5d, 0x29, 0x20, 0x3d, 0x3d, 0x20, 0x22, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x22, 0x20, 
+	0x74, 0x68, 0x65, 0x6e, 0x0a,
+	0x09, 0x09, 0x09, 0x66, 0x6f, 0x72, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x20, 0x66, 
+	0x75, 0x6e, 0x63, 0x20, 0x69, 0x6e, 0x20, 0x70, 0x61, 0x69, 0x72, 0x73, 0x28, 0x6d, 0x6f, 0x64, 0x2e, 0x6e, 
+	0x65, 0x77, 0x29, 0x20, 0x64, 0x6f, 0x0a,
+	0x09, 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x5b, 0x6d, 0x6f, 0x64, 0x6e, 0x61, 0x6d, 
+	0x65, 0x5d, 0x5b, 0x66, 0x75, 0x6e, 0x63, 0x6e, 0x61, 0x6d, 0x65, 0x5d, 0x20, 0x7e, 0x3d, 0x20, 0x66, 0x75, 
+	0x6e, 0x63, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a,
+	0x09, 0x09, 0x09, 0x09, 0x09, 0x2d, 0x2d, 0x20, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 
+	0x6f, 0x6c, 0x64, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x73, 0x6f, 0x20, 0x77, 
+	0x65, 0x20, 0x63, 0x61, 0x6e, 0x20, 0x72, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x20, 0x74, 0x68, 0x65, 0x6d, 
+	0x20, 0x6c, 0x61, 0x74, 0x65, 0x72, 0x2e, 0x0a,
+	0x09, 0x09, 0x09, 0x09, 0x09, 0x6d, 0x6f, 0x64, 0x2e, 0x6f, 0x6c, 0x64, 0x5b, 0x66, 0x75, 0x6e, 0x63, 0x6e, 
+	0x61, 0x6d, 0x65, 0x5d, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x5b, 0x6d, 0x6f, 0x64, 0x6e, 0x61, 0x6d, 
+	0x65, 0x5d, 0x5b, 0x66, 0x75, 0x6e, 0x63, 0x6e, 0x61, 0x6d, 0x65, 0x5d, 0x0a,
+	0x09, 0x09, 0x09, 0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x5b, 0x6d, 0x6f, 0x64, 0x6e, 0x61, 0x6d, 0x65, 0x5d, 
+	0x5b, 0x66, 0x75, 0x6e, 0x63, 0x6e, 0x61, 0x6d, 0x65, 0x5d, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x0a,
+	0x09, 0x09, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a,
+	0x09, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a,
+	0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a,
+	0x09, 0x65, 0x6e, 0x64, 0x0a,
+	0x09, 0x0a,
+	0x09, 0x2d, 0x2d, 0x20, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x20, 0x74, 0x79, 0x70, 0x65, 0x20, 0x6d, 
+	0x65, 0x74, 0x68, 0x6f, 0x64, 0x73, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 
+	0x65, 0x72, 0x65, 0x64, 0x20, 0x46, 0x46, 0x49, 0x20, 0x76, 0x61, 0x72, 0x69, 0x61, 0x6e, 0x74, 0x73, 0x2e, 0x0a,
+	0x09, 0x66, 0x6f, 0x72, 0x20, 0x74, 0x79, 0x70, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x20, 0x74, 0x74, 0x79, 
+	0x70, 0x65, 0x20, 0x69, 0x6e, 0x20, 0x70, 0x61, 0x69, 0x72, 0x73, 0x28, 0x74, 0x79, 0x70, 0x65, 0x5f, 0x66, 
+	0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x29, 0x20, 0x64, 0x6f, 0x0a,
+	0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x74, 0x79, 0x70, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x74, 
+	0x61, 0x62, 0x6c, 0x65, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x5f, 0x67, 0x65, 0x74, 0x74, 0x79, 
+	0x70, 0x65, 0x6d, 0x65, 0x74, 0x61, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x28, 0x74, 0x79, 0x70, 0x65, 0x6e, 0x61, 
+	0x6d, 0x65, 0x29, 0x0a,
+	0x09, 0x09, 0x69, 0x66, 0x20, 0x74, 0x79, 0x70, 0x65, 0x28, 0x74, 0x79, 0x70, 0x65, 0x5f, 0x6d, 0x65, 0x74, 
+	0x61, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x29, 0x20, 0x3d, 0x3d, 0x20, 0x22, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x22, 
+	0x20, 0x61, 0x6e, 0x64, 0x20, 0x74, 0x79, 0x70, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x74, 0x61, 0x62, 0x6c, 
+	0x65, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x4f, 0x66, 0x20, 0x7e, 0x3d, 0x20, 0x6e, 0x69, 0x6c, 0x20, 0x74, 0x68, 
+	0x65, 0x6e, 0x0a,
+	0x09, 0x09, 0x09, 0x66, 0x6f, 0x72, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x20, 0x66, 
+	0x75, 0x6e, 0x63, 0x20, 0x69, 0x6e, 0x20, 0x70, 0x61, 0x69, 0x72, 0x73, 0x28, 0x74, 0x74, 0x79, 0x70, 0x65, 
+	0x2e, 0x6e, 0x65, 0x77, 0x29, 0x20, 0x64, 0x6f, 0x0a,
+	0x09, 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x74, 0x79, 0x70, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x74, 0x61, 
+	0x62, 0x6c, 0x65, 0x5b, 0x66, 0x75, 0x6e, 0x63, 0x6e, 0x61, 0x6d, 0x65, 0x5d, 0x20, 0x7e, 0x3d, 0x20, 0x66, 
+	0x75, 0x6e, 0x63, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a,
+	0x09, 0x09, 0x09, 0x09, 0x09, 0x2d, 0x2d, 0x20, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 
+	0x6f, 0x6c, 0x64, 0x20, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x73, 0x20, 0x73, 0x6f, 0x20, 0x77, 0x65, 0x20, 
+	0x63, 0x61, 0x6e, 0x20, 0x72, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x20, 0x74, 0x68, 0x65, 0x6d, 0x20, 0x6c, 
+	0x61, 0x74, 0x65, 0x72, 0x2e, 0x0a,
+	0x09, 0x09, 0x09, 0x09, 0x09, 0x74, 0x74, 0x79, 0x70, 0x65, 0x2e, 0x6f, 0x6c, 0x64, 0x5b, 0x66, 0x75, 0x6e, 
+	0x63, 0x6e, 0x61, 0x6d, 0x65, 0x5d, 0x20, 0x3d, 0x20, 0x74, 0x79, 0x70, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 
+	0x74, 0x61, 0x62, 0x6c, 0x65, 0x5b, 0x66, 0x75, 0x6e, 0x63, 0x6e, 0x61, 0x6d, 0x65, 0x5d, 0x0a,
+	0x09, 0x09, 0x09, 0x09, 0x09, 0x74, 0x79, 0x70, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x74, 0x61, 0x62, 0x6c, 
+	0x65, 0x5b, 0x66, 0x75, 0x6e, 0x63, 0x6e, 0x61, 0x6d, 0x65, 0x5d, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x0a,
+	0x09, 0x09, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a,
+	0x09, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a,
+	0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a,