- make sure all log messages get displayed, even when the console is not
authorMatthias Braun <matze@braunis.de>
Thu, 20 Apr 2006 18:44:10 +0000 (18:44 +0000)
committerMatthias Braun <matze@braunis.de>
Thu, 20 Apr 2006 18:44:10 +0000 (18:44 +0000)
  completely intiailized yet
- first attempt to include sqdbg into supertux (commented out again for now)
- some work on worldmap switching
- new editor images for ghostparticels and scripttrigger

SVN-Revision: 3379

28 files changed:
configure.ac
data/images/engine/editor/ghostparticles.png [new file with mode: 0644]
data/images/engine/editor/ghostparticles.xcf [new file with mode: 0644]
data/images/engine/editor/scripttrigger.png [new file with mode: 0644]
data/images/engine/editor/scripttrigger.xcf [new file with mode: 0644]
data/levels/world1/world.nut
data/levels/world1/worldmap.stwm
data/scripts/console.nut
data/scripts/default.nut
mk/jam/objects.jam
src/Jamfile
src/console.cpp
src/console.hpp
src/main.cpp
src/mainloop.cpp
src/mainloop.hpp
src/script_manager.cpp
src/script_manager.hpp
src/scripting/functions.cpp
src/scripting/functions.hpp
src/scripting/wrapper.cpp
src/squirrel/Jamfile
src/squirrel/README
src/squirrel/sqdbg/serialize_state.inl [new file with mode: 0644]
src/squirrel/sqdbg/sqdbgserver.cpp [new file with mode: 0644]
src/squirrel/sqdbg/sqdbgserver.h [new file with mode: 0644]
src/squirrel/sqdbg/sqrdbg.cpp [new file with mode: 0644]
src/squirrel/sqdbg/sqrdbg.h [new file with mode: 0644]

index 21cc765..be44942 100644 (file)
@@ -59,38 +59,40 @@ AC_CHECK_HEADERS(unistd.h)
 
 dnl Checks for typedefs, structures, and compiler characteristics.
 AC_C_CONST
+AC_C_BIGENDIAN
 
 dnl ===========================================================================
 dnl Give advanced users some options to play with
 
 VARIANT=optimize
-AC_MSG_CHECKING(for gprof mode)
+AC_MSG_CHECKING([for build variant])
+
 AC_ARG_ENABLE(gprof,
               AC_HELP_STRING([--enable-gprof], [enable GNU profiling support]),
               [enable_gprof=$enableval], [enable_gprof=no])
 if test "$enable_gprof" = "yes"; then
-    #CXXFLAGS="$CXXFLAGS -pg"
     VARIANT=profile
-    AC_MSG_RESULT([enabled])
-else
-    AC_MSG_RESULT([disabled])
 fi
 
-AC_MSG_CHECKING(for debug mode)
 AC_ARG_ENABLE(debug,
               AC_HELP_STRING([--enable-debug], [enable debugging mode]),
               [enable_debug=$enableval], [enable_debug=no])
 if test "$enable_debug" = "yes"; then
     AC_DEFINE([DEBUG], 1, [define to compile in debug checks])
     VARIANT=debug
-    AC_MSG_RESULT([enabled])
 else
     VARIANT=optimize
-    AC_MSG_RESULT([disabled])
 fi
 AC_SUBST([VARIANT])
-
-AC_C_BIGENDIAN()
+AC_MSG_RESULT([$VARIANT])
+
+AC_ARG_ENABLE(sqdbg,
+              AC_HELP_STRING([--enable-sqdbg], [enable squirrel remote debugger]),
+              [enable_sqdbg=$enableval], [enable_sqdbg=no])
+if test "$enable_sqdbg" = "yes"; then
+    AC_DEFINE([ENABLE_SQDBG], 1, [define if sqdbg should be enabled])
+    AC_SUBST([enable_sqdbg])
+fi
 
 AM_ICONV
 AC_SUBST([ICONV_LIBS], [$LIBICONV])
@@ -145,12 +147,6 @@ AC_CONFIG_FILES([Jamconfig])
 AC_OUTPUT
 
 echo ""
-echo "Features:"
-echo "========="
-echo " Profile Mode:   $enable_gprof"
-echo " Debug Mode:     $enable_debug"
-echo ""
-echo ""
 echo "       NOTE: This project uses jam (and not make) as build tool"
 echo ""
 
diff --git a/data/images/engine/editor/ghostparticles.png b/data/images/engine/editor/ghostparticles.png
new file mode 100644 (file)
index 0000000..4f1afed
Binary files /dev/null and b/data/images/engine/editor/ghostparticles.png differ
diff --git a/data/images/engine/editor/ghostparticles.xcf b/data/images/engine/editor/ghostparticles.xcf
new file mode 100644 (file)
index 0000000..1ced9d3
Binary files /dev/null and b/data/images/engine/editor/ghostparticles.xcf differ
diff --git a/data/images/engine/editor/scripttrigger.png b/data/images/engine/editor/scripttrigger.png
new file mode 100644 (file)
index 0000000..b6bdabd
Binary files /dev/null and b/data/images/engine/editor/scripttrigger.png differ
diff --git a/data/images/engine/editor/scripttrigger.xcf b/data/images/engine/editor/scripttrigger.xcf
new file mode 100644 (file)
index 0000000..841f50b
Binary files /dev/null and b/data/images/engine/editor/scripttrigger.xcf differ
index c9e608b..c83bcc3 100644 (file)
@@ -10,7 +10,19 @@ if(! ("world" in state)) {
        state.world <- "levels/world1/worldmap.stwm";
        save_state();
 }
+
+// load worldmap and wait till it is displayed
 load_worldmap(state.world);
 fadeout_screen(0.5);
 wait_for_screenswitch();
 save_state();
+
+worldthread <- get_current_thread();
+// wait for worldchanges
+while(true) {
+       ::suspend();
+       exit_screen();
+       load_worldmap(state.world);
+       save_state();
+}
+
index 647b7f2..7062bce 100644 (file)
     )
     (special-tile
       (invisible-tile #t)
-      (script "state.world <- \"levels/world2/worldmap.stwm\";
-save_state();
-
-exit_screen();
-fadeout_screen(2.5);
+      (script "
+state.world <- \"levels/world2/worldmap.stwm\";
+fadeout_screen(2);
+wait(2);
+worldthread.wakeup();
 ")
       (x 38)
       (y 21)
index 9170e45..ff411c0 100644 (file)
@@ -14,12 +14,6 @@ function finish()
        Level.finish(true);
 }
 
-function println(val)
-{
-       print(val);
-       print("\n");
-}
-
 /**
  * Display a list of functions in the roottable (or in the table specified)
  */
@@ -40,4 +34,3 @@ function functions(...)
        }
 }
 
-
index fbfc8a8..f3a262e 100644 (file)
@@ -2,7 +2,6 @@
  * This script gets loaded into the squirrel root vm in supertux. So functions
  * and variables you define here can be used in all threads
  */
-
 function end_level()
 {
   Sound.play_music("music/leveldone.ogg");
@@ -21,3 +20,9 @@ function levelflip()
   Effect.fade_in(1);
 }
 
+function println(val)
+{
+       print(val);
+       print("\n");
+}
+
index 03b006b..0449b43 100644 (file)
@@ -148,8 +148,8 @@ rule UseHeaderFile
 {
     return ;
 }
-RegisterFileType UseHeaderFile : .h .hpp ;
-RegisterHeaderRule HeaderRule : $(HDRPATTERN) : .h .hpp .inc ;
+RegisterFileType UseHeaderFile : .h .hpp .inc .inl ;
+RegisterHeaderRule HeaderRule : $(HDRPATTERN) : .h .hpp .inc .inl ;
 
 ##  SearchSource
 ##    Sets search path of the sourcefiles to the current SUBDIR and sets a
index b1ca0c4..69f7b26 100644 (file)
@@ -27,5 +27,5 @@ C++Flags supertux : -DAPPDATADIR='\"$(appdatadir)\"' ;
 LinkWith supertux : squirrel ;
 ExternalLibs supertux : SDL SDLIMAGE GL OPENAL VORBIS VORBISFILE OGG ICONV PHYSFS BINRELOC ;
 Help supertux : "Build the supertux executable" ;
-IncludeDir supertux : squirrel/include ;
+IncludeDir supertux : squirrel/include squirrel ;
 
index 7e7b38f..9ac545c 100644 (file)
@@ -38,10 +38,7 @@ Console::Console()
   : vm(NULL), backgroundOffset(0), height(0), alpha(1.0), offset(0),
     focused(false), stayOpen(0)
 {
-  font.reset(new Font("images/engine/fonts/white-small.png",
-                      "images/engine/fonts/shadow-small.png", 8, 9, 1));
-  background.reset(new Surface("images/engine/console.png"));
-  background2.reset(new Surface("images/engine/console2.png"));
+  fontheight = 8;
 }
 
 Console::~Console() 
@@ -51,6 +48,16 @@ Console::~Console()
   }
 }
 
+void
+Console::init_graphics()
+{
+  font.reset(new Font("images/engine/fonts/white-small.png",
+                      "images/engine/fonts/shadow-small.png", 8, 9, 1));
+  fontheight = font->get_height();
+  background.reset(new Surface("images/engine/console.png"));
+  background2.reset(new Surface("images/engine/console2.png"));
+}
+
 void 
 Console::flush(ConsoleStreamBuffer* buffer) 
 {
@@ -192,7 +199,7 @@ Console::addLine(std::string s)
   if (height < 64) {
     if(height < 4)
       height = 4;
-    height += font->get_height();
+    height += fontheight;
   }
 
   alpha = 1.0;
index ff93571..1194a7f 100644 (file)
@@ -46,6 +46,8 @@ public:
   static std::ostream input; /**< stream of keyboard input to send to the console. Do not forget to send std::endl or to flush the stream. */
   static std::ostream output; /**< stream of characters to output to the console. Do not forget to send std::endl or to flush the stream. */
 
+  void init_graphics();
+
   void backspace(); /**< delete last character sent to the input stream */
   void scroll(int offset); /**< scroll console text up or down by @c offset lines */
   void autocomplete(); /**< autocomplete current command */
@@ -98,6 +100,7 @@ private:
   int offset; /**< decrease to scroll text up */
   bool focused; /**< true if console has input focus */
   std::auto_ptr<Font> font;
+  float fontheight; /**< height of the font (this is a separate var, because the font could not be initialized yet but is needed in the addLine message */
 
   float stayOpen;
 
index 8f4569e..5543ea3 100644 (file)
@@ -483,12 +483,11 @@ int main(int argc, char** argv)
   int result = 0;
     
   try {
+    Console::instance = new Console();
     srand(time(0));
     init_physfs(argv[0]);
     init_sdl();
     
-    log_fatal << "Test" << std::endl;
-    
     timelog("controller");
     main_controller = new JoystickKeyboardController();    
     timelog("config");
@@ -502,7 +501,7 @@ int main(int argc, char** argv)
     init_audio();
     timelog("video");
     init_video();
-    Console::instance = new Console(); 
+    Console::instance->init_graphics(); 
     timelog("scripting");
     init_scripting();
 
index 4e7199d..65da30b 100644 (file)
@@ -60,6 +60,10 @@ MainLoop::push_screen(Screen* screen, ScreenFade* screen_fade)
 {
   this->next_screen.reset(screen);
   this->screen_fade.reset(screen_fade);
+  if(nextpop)
+    nextpush = false;
+  else
+    nextpush = true;
   nextpop = false;
   speed = 1.0;
 }
@@ -70,6 +74,7 @@ MainLoop::exit_screen(ScreenFade* screen_fade)
   next_screen.reset(NULL);
   this->screen_fade.reset(screen_fade);
   nextpop = true;
+  nextpush = false;
 }
 
 void
@@ -134,7 +139,8 @@ MainLoop::run()
         screen_stack.pop_back();
         nextpop = false;
         speed = 1.0;
-      } else if(current_screen.get() != NULL) {
+      }
+      if(nextpush && current_screen.get() != NULL) {
         screen_stack.push_back(current_screen.release());
       }
       
index 5e51d2d..db961e0 100644 (file)
@@ -48,6 +48,7 @@ private:
   bool running;
   float speed;
   bool nextpop;
+  bool nextpush;
   std::auto_ptr<Screen> next_screen;
   std::auto_ptr<Screen> current_screen;
   std::auto_ptr<Console> console;
index 14e6599..da3f606 100644 (file)
@@ -60,6 +60,22 @@ ScriptManager::ScriptManager()
     throw std::runtime_error("Couldn't initialize squirrel vm");
   sq_setforeignptr(vm, (SQUserPointer) this);
 
+#ifdef ENABLE_SQDBG
+  debugger = NULL;
+  /*
+  debugger = sq_rdbg_init(vm, 1234, SQFalse);
+  if(debugger == NULL)
+    throw SquirrelError(vm, "Couldn't initialize suirrel remote debugger");
+
+  sq_enabledebuginfo(vm, SQTrue);
+  log_info << "Waiting for debug client..." << std::endl;
+  if(!SQ_SUCCEEDED(sq_rdbg_waitforconnections(debugger))) {
+    throw SquirrelError(vm, "Waiting for debug clients failed");
+  }
+  log_info << "debug client connected." << std::endl;
+  */
+#endif
+
   // register squirrel libs
   sq_pushroottable(vm);
   if(sqstd_register_bloblib(vm) < 0)
@@ -89,6 +105,9 @@ ScriptManager::ScriptManager()
 
 ScriptManager::ScriptManager(ScriptManager* parent)
 {
+#ifdef ENABLE_SQDBG
+  debugger = NULL;
+#endif
   this->parent = parent;
   vm = parent->vm;
   parent->childs.push_back(this);
@@ -105,6 +124,9 @@ ScriptManager::~ScriptManager()
         std::remove(parent->childs.begin(), parent->childs.end(), this),
         parent->childs.end());
   } else {
+#ifdef ENABLE_SQDBG
+    sq_rdbg_shutdown(debugger);
+#endif
     sq_close(vm);
   }
 }
@@ -136,12 +158,21 @@ ScriptManager::create_thread(bool leave_thread_on_stack)
 void
 ScriptManager::update()
 {
+#ifdef ENABLE_SQDBG
+  if(debugger != NULL)
+    sq_rdbg_update(debugger);
+#endif
+
   for(SquirrelVMs::iterator i = squirrel_vms.begin(); i != squirrel_vms.end(); ) {
     SquirrelVM& squirrel_vm = *i;
     int vm_state = sq_getvmstate(squirrel_vm.vm);
     
-    if(vm_state == SQ_VMSTATE_SUSPENDED && squirrel_vm.wakeup_time > 0 && game_time >= squirrel_vm.wakeup_time) {
+    if(vm_state == SQ_VMSTATE_SUSPENDED 
+            && squirrel_vm.wakeup_time > 0 
+            && game_time >= squirrel_vm.wakeup_time) {
       squirrel_vm.waiting_for_events = WakeupData(NO_EVENT);
+      squirrel_vm.wakeup_time = 0;
+      
       try {
         if(SQ_FAILED(sq_wakeupvm(squirrel_vm.vm, false, false))) {
           throw SquirrelError(squirrel_vm.vm, "Couldn't resume script");
index 77d74d2..e0f2978 100644 (file)
@@ -25,6 +25,9 @@
 #include <squirrel.h>
 #include <iostream>
 #include "timer.hpp"
+#ifdef ENABLE_SQDBG
+#include <sqdbg/sqrdbg.h>
+#endif
 
 class GameObject;
 
@@ -98,6 +101,9 @@ private:
   HSQUIRRELVM vm;
   ScriptManager* parent;
   std::vector<ScriptManager*> childs;
+#ifdef ENABLE_SQDBG
+  HSQREMOTEDBG debugger;
+#endif
 };
 
 #endif
index f1a3715..fc946db 100644 (file)
@@ -58,6 +58,22 @@ int display(HSQUIRRELVM vm)
   return 0;
 }
 
+void print_stacktrace(HSQUIRRELVM vm)
+{
+  print_squirrel_stack(vm);
+}
+
+int get_current_thread(HSQUIRRELVM vm)
+{
+  SQObject object;
+  sq_resetobject(&object);
+  object._unVal.pThread = vm;
+  object._type = OT_THREAD;
+  sq_pushobject(vm, object);
+
+  return 1;
+}
+
 void wait(HSQUIRRELVM vm, float seconds)
 {
   SQUserPointer ptr = sq_getforeignptr(vm);
index 9222c0e..2b69063 100644 (file)
@@ -43,6 +43,16 @@ static const int KEY_GOLD   = 0x010;
 int display(HSQUIRRELVM vm) __custom;
 
 /**
+ * Displays contents of the current stack
+ */
+void print_stacktrace(HSQUIRRELVM vm);
+
+/**
+ * returns the currently running thread
+ */
+int get_current_thread(HSQUIRRELVM vm) __custom;
+
+/**
  * Display a text file and scrolls it over the screen (on next screenswitch)
  */
 void display_text_file(const std::string& filename);
index 4f2592e..910d6bc 100644 (file)
@@ -1481,6 +1481,30 @@ static int display_wrapper(HSQUIRRELVM vm)
   return Scripting::display(vm);
 }
 
+static int print_stacktrace_wrapper(HSQUIRRELVM vm)
+{
+  HSQUIRRELVM arg0 = vm;
+  
+  try {
+    Scripting::print_stacktrace(arg0);
+  
+    return 0;
+  
+  } catch(std::exception& e) {
+    sq_throwerror(vm, e.what());
+    return SQ_ERROR;
+  } catch(...) {
+    sq_throwerror(vm, _SC("Unexpected exception while executing function 'print_stacktrace'"));
+    return SQ_ERROR;
+  }
+  
+}
+
+static int get_current_thread_wrapper(HSQUIRRELVM vm)
+{
+  return Scripting::get_current_thread(vm);
+}
+
 static int display_text_file_wrapper(HSQUIRRELVM vm)
 {
   const char* arg0;
@@ -2321,6 +2345,18 @@ void register_supertux_wrapper(HSQUIRRELVM v)
     throw SquirrelError(v, "Couldn't register function 'display'");
   }
 
+  sq_pushstring(v, "print_stacktrace", -1);
+  sq_newclosure(v, &print_stacktrace_wrapper, 0);
+  if(SQ_FAILED(sq_createslot(v, -3))) {
+    throw SquirrelError(v, "Couldn't register function 'print_stacktrace'");
+  }
+
+  sq_pushstring(v, "get_current_thread", -1);
+  sq_newclosure(v, &get_current_thread_wrapper, 0);
+  if(SQ_FAILED(sq_createslot(v, -3))) {
+    throw SquirrelError(v, "Couldn't register function 'get_current_thread'");
+  }
+
   sq_pushstring(v, "display_text_file", -1);
   sq_newclosure(v, &display_text_file_wrapper, 0);
   if(SQ_FAILED(sq_createslot(v, -3))) {
index 9db2502..3a3c36f 100644 (file)
@@ -1,14 +1,21 @@
 SubDir TOP src squirrel ;
 
+SQDBG_SOURCES = [ Wildcard sqdbg : *.cpp *.h *.inl ] ;
+if $(enable_sqdbg) = "yes" {
+    EXTRA_SOURCES = $(SQDBG_SOURCES) ;
+} else {
+    Package $(SQDBG_SOURCES) ;
+}
+
 Library squirrel
     : [ Wildcard squirrel : *.cpp *.h ]
       [ Wildcard sqstdlib : *.cpp *.c *.h ]
+      $(EXTRA_SOURCES)
     : noinstall
 ;
 
-for i in $(squirrel_OBJECTS)
-{
-  CXXFLAGS on $(i) = [ Filter [ on $(i) GetVar CXXFLAGS ] : -Wall -W -Werror ] ;
-  CFLAGS on $(i) = [ Filter [ on $(i) GetVar CFLAGS ] : -Wall -W -Werror ] ;
+for i in $(squirrel_OBJECTS) {
+    CXXFLAGS on $(i) = [ Filter [ on $(i) GetVar CXXFLAGS ] : -Wall -W -Werror ] ;
+    CFLAGS on $(i) = [ Filter [ on $(i) GetVar CFLAGS ] : -Wall -W -Werror ] ;
 }
 IncludeDir squirrel : include ;
index a0776e9..d6c0471 100644 (file)
@@ -1,3 +1,66 @@
-This directory contains the SQUIRREL programming language version 2.0.1 from
-http://squirrel.sourceforge.net
-Originally on zlib/png license.
+~~~~~~~~
+Squirrel
+~~~~~~~~
+
+This directory contains the SQUIRREL programming language as found on 
+http://www.squirrel-lang.org with some minor fixes to make it compile warning
+free on 64bit architectures.
+
+Squirrel Copyright:
+Copyright (c) 2003-2006 Alberto Demichelis
+
+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.
+-----------------------------------------------------
+END OF COPYRIGHT
+
+
+~~~~~~~~~~~~~~~~~~~~~~~~
+Squirrel Remote Debugger
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+The subdirectory sqdbg contains the sqdbg library by Alberto Demichelis.
+
+SQDBG License:
+
+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.
+
diff --git a/src/squirrel/sqdbg/serialize_state.inl b/src/squirrel/sqdbg/serialize_state.inl
new file mode 100644 (file)
index 0000000..347ee63
--- /dev/null
@@ -0,0 +1,416 @@
+static const SQChar serialize_state_nut[] = {
+0x74, 0x72, 0x79, 0x20, 0x7b, 0x0d, 0x0a, 0x09, 0x0d, 0x0a, 0x6c, 0x6f, 
+0x63, 0x61, 0x6c, 0x20, 0x6f, 0x62, 0x6a, 0x73, 0x5f, 0x72, 0x65, 0x67, 
+0x3d, 0x7b, 0x6d, 0x61, 0x78, 0x69, 0x64, 0x3d, 0x30, 0x2c, 0x72, 0x65, 
+0x66, 0x73, 0x3d, 0x7b, 0x7d, 0x7d, 0x0d, 0x0a, 0x0d, 0x0a, 0x63, 0x6f, 
+0x6d, 0x70, 0x6c, 0x65, 0x78, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x20, 
+0x3c, 0x2d, 0x20, 0x7b, 0x0d, 0x0a, 0x09, 0x5b, 0x22, 0x74, 0x61, 0x62, 
+0x6c, 0x65, 0x22, 0x5d, 0x20, 0x3d, 0x20, 0x6e, 0x75, 0x6c, 0x6c, 0x2c, 
+0x0d, 0x0a, 0x09, 0x5b, 0x22, 0x61, 0x72, 0x72, 0x61, 0x79, 0x22, 0x5d, 
+0x20, 0x3d, 0x20, 0x6e, 0x75, 0x6c, 0x6c, 0x2c, 0x0d, 0x0a, 0x09, 0x5b, 
+0x22, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x22, 0x5d, 0x20, 0x3d, 0x20, 0x6e, 
+0x75, 0x6c, 0x6c, 0x2c, 0x0d, 0x0a, 0x09, 0x5b, 0x22, 0x69, 0x6e, 0x73, 
+0x74, 0x61, 0x6e, 0x63, 0x65, 0x22, 0x5d, 0x20, 0x3d, 0x20, 0x6e, 0x75, 
+0x6c, 0x6c, 0x2c, 0x0d, 0x0a, 0x09, 0x5b, 0x22, 0x77, 0x65, 0x61, 0x6b, 
+0x72, 0x65, 0x66, 0x22, 0x5d, 0x20, 0x3d, 0x20, 0x6e, 0x75, 0x6c, 0x6c, 
+0x2c, 0x0d, 0x0a, 0x7d, 0x0d, 0x0a, 0x0d, 0x0a, 0x66, 0x75, 0x6e, 0x63, 
+0x74, 0x69, 0x6f, 0x6e, 0x20, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x72, 
+0x65, 0x66, 0x73, 0x28, 0x74, 0x29, 0x3a, 0x28, 0x6f, 0x62, 0x6a, 0x73, 
+0x5f, 0x72, 0x65, 0x67, 0x29, 0x0d, 0x0a, 0x7b, 0x0d, 0x0a, 0x09, 0x69, 
+0x66, 0x28, 0x74, 0x20, 0x3d, 0x3d, 0x20, 0x3a, 0x3a, 0x67, 0x65, 0x74, 
+0x72, 0x6f, 0x6f, 0x74, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x28, 0x29, 0x29, 
+0x0d, 0x0a, 0x09, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x3b, 0x0d, 
+0x0a, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6f, 0x74, 0x79, 0x70, 
+0x65, 0x20, 0x3d, 0x20, 0x3a, 0x3a, 0x74, 0x79, 0x70, 0x65, 0x28, 0x74, 
+0x29, 0x3b, 0x0d, 0x0a, 0x09, 0x69, 0x66, 0x28, 0x6f, 0x74, 0x79, 0x70, 
+0x65, 0x20, 0x69, 0x6e, 0x20, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x78, 
+0x5f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x29, 0x0d, 0x0a, 0x09, 0x7b, 0x0d, 
+0x0a, 0x09, 0x09, 0x69, 0x66, 0x28, 0x21, 0x28, 0x74, 0x20, 0x69, 0x6e, 
+0x20, 0x6f, 0x62, 0x6a, 0x73, 0x5f, 0x72, 0x65, 0x67, 0x2e, 0x72, 0x65, 
+0x66, 0x73, 0x29, 0x29, 0x20, 0x7b, 0x0d, 0x0a, 0x09, 0x09, 0x09, 0x6f, 
+0x62, 0x6a, 0x73, 0x5f, 0x72, 0x65, 0x67, 0x2e, 0x72, 0x65, 0x66, 0x73, 
+0x5b, 0x74, 0x5d, 0x20, 0x3c, 0x2d, 0x20, 0x6f, 0x62, 0x6a, 0x73, 0x5f, 
+0x72, 0x65, 0x67, 0x2e, 0x6d, 0x61, 0x78, 0x69, 0x64, 0x2b, 0x2b, 0x3b, 
+0x0d, 0x0a, 0x09, 0x09, 0x0d, 0x0a, 0x09, 0x09, 0x20, 0x20, 0x20, 0x20, 
+0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x65, 0x6f, 0x62, 0x6a, 0x65, 0x63, 
+0x74, 0x28, 0x74, 0x2c, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 
+0x28, 0x6f, 0x2c, 0x69, 0x2c, 0x76, 0x61, 0x6c, 0x29, 0x3a, 0x28, 0x6f, 
+0x62, 0x6a, 0x73, 0x5f, 0x72, 0x65, 0x67, 0x29, 0x0d, 0x0a, 0x09, 0x09, 
+0x20, 0x20, 0x20, 0x20, 0x7b, 0x0d, 0x0a, 0x09, 0x09, 0x09, 0x20, 0x20, 
+0x20, 0x20, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x72, 0x65, 0x66, 0x73, 
+0x28, 0x76, 0x61, 0x6c, 0x29, 0x3b, 0x0d, 0x0a, 0x09, 0x09, 0x09, 0x20, 
+0x20, 0x20, 0x20, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x72, 0x65, 0x66, 
+0x73, 0x28, 0x69, 0x29, 0x3b, 0x0d, 0x0a, 0x09, 0x09, 0x20, 0x20, 0x20, 
+0x20, 0x7d, 0x29, 0x0d, 0x0a, 0x09, 0x09, 0x7d, 0x0d, 0x0a, 0x09, 0x09, 
+0x0d, 0x0a, 0x09, 0x7d, 0x0d, 0x0a, 0x7d, 0x0d, 0x0a, 0x0d, 0x0a, 0x66, 
+0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x67, 0x65, 0x74, 0x76, 
+0x61, 0x6c, 0x75, 0x65, 0x28, 0x76, 0x29, 0x3a, 0x28, 0x6f, 0x62, 0x6a, 
+0x73, 0x5f, 0x72, 0x65, 0x67, 0x29, 0x0d, 0x0a, 0x7b, 0x0d, 0x0a, 0x09, 
+0x73, 0x77, 0x69, 0x74, 0x63, 0x68, 0x28, 0x3a, 0x3a, 0x74, 0x79, 0x70, 
+0x65, 0x28, 0x76, 0x29, 0x29, 0x0d, 0x0a, 0x09, 0x7b, 0x0d, 0x0a, 0x09, 
+0x09, 0x63, 0x61, 0x73, 0x65, 0x20, 0x22, 0x74, 0x61, 0x62, 0x6c, 0x65, 
+0x22, 0x3a, 0x0d, 0x0a, 0x09, 0x09, 0x63, 0x61, 0x73, 0x65, 0x20, 0x22, 
+0x61, 0x72, 0x72, 0x61, 0x79, 0x22, 0x3a, 0x0d, 0x0a, 0x09, 0x09, 0x63, 
+0x61, 0x73, 0x65, 0x20, 0x22, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x22, 0x3a, 
+0x0d, 0x0a, 0x09, 0x09, 0x63, 0x61, 0x73, 0x65, 0x20, 0x22, 0x69, 0x6e, 
+0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x22, 0x3a, 0x0d, 0x0a, 0x09, 0x09, 
+0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6f, 0x62, 0x6a, 0x73, 
+0x5f, 0x72, 0x65, 0x67, 0x2e, 0x72, 0x65, 0x66, 0x73, 0x5b, 0x76, 0x5d, 
+0x2e, 0x74, 0x6f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x28, 0x29, 0x3b, 
+0x0d, 0x0a, 0x09, 0x09, 0x63, 0x61, 0x73, 0x65, 0x20, 0x22, 0x69, 0x6e, 
+0x74, 0x65, 0x67, 0x65, 0x72, 0x22, 0x3a, 0x0d, 0x0a, 0x09, 0x09, 0x63, 
+0x61, 0x73, 0x65, 0x20, 0x22, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x22, 0x3a, 
+0x0d, 0x0a, 0x09, 0x09, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 
+0x72, 0x6e, 0x20, 0x76, 0x3b, 0x0d, 0x0a, 0x09, 0x09, 0x63, 0x61, 0x73, 
+0x65, 0x20, 0x22, 0x62, 0x6f, 0x6f, 0x6c, 0x22, 0x3a, 0x0d, 0x0a, 0x09, 
+0x09, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 
+0x76, 0x2e, 0x74, 0x6f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x28, 0x29, 
+0x3b, 0x0d, 0x0a, 0x09, 0x09, 0x63, 0x61, 0x73, 0x65, 0x20, 0x22, 0x73, 
+0x74, 0x72, 0x69, 0x6e, 0x67, 0x22, 0x3a, 0x0d, 0x0a, 0x09, 0x09, 0x09, 
+0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x76, 0x3b, 0x0d, 0x0a, 0x09, 
+0x09, 0x63, 0x61, 0x73, 0x65, 0x20, 0x22, 0x6e, 0x75, 0x6c, 0x6c, 0x22, 
+0x3a, 0x0d, 0x0a, 0x09, 0x09, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 
+0x75, 0x72, 0x6e, 0x20, 0x22, 0x6e, 0x75, 0x6c, 0x6c, 0x22, 0x3b, 0x0d, 
+0x0a, 0x09, 0x09, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x3a, 0x0d, 
+0x0a, 0x09, 0x09, 0x09, 0x0d, 0x0a, 0x09, 0x09, 0x09, 0x72, 0x65, 0x74, 
+0x75, 0x72, 0x6e, 0x20, 0x70, 0x61, 0x63, 0x6b, 0x5f, 0x74, 0x79, 0x70, 
+0x65, 0x28, 0x3a, 0x3a, 0x74, 0x79, 0x70, 0x65, 0x28, 0x76, 0x29, 0x29, 
+0x3b, 0x0d, 0x0a, 0x09, 0x7d, 0x0d, 0x0a, 0x7d, 0x0d, 0x0a, 0x0d, 0x0a, 
+0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x64, 
+0x5f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x3d, 0x7b, 0x0d, 0x0a, 0x09, 0x5b, 
+0x22, 0x6e, 0x75, 0x6c, 0x6c, 0x22, 0x5d, 0x3d, 0x22, 0x6e, 0x22, 0x2c, 
+0x0d, 0x0a, 0x09, 0x5b, 0x22, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x22, 
+0x5d, 0x3d, 0x22, 0x73, 0x22, 0x2c, 0x0d, 0x0a, 0x09, 0x5b, 0x22, 0x69, 
+0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x22, 0x5d, 0x3d, 0x22, 0x69, 0x22, 
+0x2c, 0x0d, 0x0a, 0x09, 0x5b, 0x22, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x22, 
+0x5d, 0x3d, 0x22, 0x66, 0x22, 0x2c, 0x0d, 0x0a, 0x09, 0x5b, 0x22, 0x75, 
+0x73, 0x65, 0x72, 0x64, 0x61, 0x74, 0x61, 0x22, 0x5d, 0x3d, 0x22, 0x75, 
+0x22, 0x2c, 0x0d, 0x0a, 0x09, 0x5b, 0x22, 0x66, 0x75, 0x6e, 0x63, 0x74, 
+0x69, 0x6f, 0x6e, 0x22, 0x5d, 0x3d, 0x22, 0x66, 0x6e, 0x22, 0x2c, 0x0d, 
+0x0a, 0x09, 0x5b, 0x22, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x22, 0x5d, 0x3d, 
+0x22, 0x74, 0x22, 0x2c, 0x0d, 0x0a, 0x09, 0x5b, 0x22, 0x61, 0x72, 0x72, 
+0x61, 0x79, 0x22, 0x5d, 0x3d, 0x22, 0x61, 0x22, 0x2c, 0x0d, 0x0a, 0x09, 
+0x5b, 0x22, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x22, 
+0x5d, 0x3d, 0x22, 0x67, 0x22, 0x2c, 0x0d, 0x0a, 0x09, 0x5b, 0x22, 0x74, 
+0x68, 0x72, 0x65, 0x61, 0x64, 0x22, 0x5d, 0x3d, 0x22, 0x68, 0x22, 0x2c, 
+0x0d, 0x0a, 0x09, 0x5b, 0x22, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 
+0x65, 0x22, 0x5d, 0x3d, 0x22, 0x78, 0x22, 0x2c, 0x20, 0x0d, 0x0a, 0x09, 
+0x5b, 0x22, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x22, 0x5d, 0x3d, 0x22, 0x79, 
+0x22, 0x2c, 0x20, 0x20, 0x0d, 0x0a, 0x09, 0x5b, 0x22, 0x62, 0x6f, 0x6f, 
+0x6c, 0x22, 0x5d, 0x3d, 0x22, 0x62, 0x22, 0x2c, 0x0d, 0x0a, 0x09, 0x5b, 
+0x22, 0x77, 0x65, 0x61, 0x6b, 0x72, 0x65, 0x66, 0x22, 0x5d, 0x3d, 0x22, 
+0x77, 0x22, 0x20, 0x20, 0x0d, 0x0a, 0x7d, 0x0d, 0x0a, 0x0d, 0x0a, 0x66, 
+0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x70, 0x61, 0x63, 0x6b, 
+0x5f, 0x74, 0x79, 0x70, 0x65, 0x28, 0x74, 0x79, 0x70, 0x65, 0x29, 0x3a, 
+0x28, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x64, 0x5f, 0x74, 0x79, 0x70, 0x65, 
+0x73, 0x29, 0x0d, 0x0a, 0x7b, 0x0d, 0x0a, 0x09, 0x69, 0x66, 0x28, 0x74, 
+0x79, 0x70, 0x65, 0x20, 0x69, 0x6e, 0x20, 0x70, 0x61, 0x63, 0x6b, 0x65, 
+0x64, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x29, 0x72, 0x65, 0x74, 0x75, 
+0x72, 0x6e, 0x20, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x64, 0x5f, 0x74, 0x79, 
+0x70, 0x65, 0x73, 0x5b, 0x74, 0x79, 0x70, 0x65, 0x5d, 0x0d, 0x0a, 0x09, 
+0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x74, 0x79, 0x70, 0x65, 0x0d, 
+0x0a, 0x7d, 0x20, 0x0d, 0x0a, 0x0d, 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74, 
+0x69, 0x6f, 0x6e, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x65, 0x6f, 
+0x62, 0x6a, 0x65, 0x63, 0x74, 0x28, 0x6f, 0x62, 0x6a, 0x2c, 0x66, 0x75, 
+0x6e, 0x63, 0x29, 0x0d, 0x0a, 0x7b, 0x0d, 0x0a, 0x09, 0x6c, 0x6f, 0x63, 
+0x61, 0x6c, 0x20, 0x74, 0x79, 0x20, 0x3d, 0x20, 0x3a, 0x3a, 0x74, 0x79, 
+0x70, 0x65, 0x28, 0x6f, 0x62, 0x6a, 0x29, 0x3b, 0x0d, 0x0a, 0x09, 0x69, 
+0x66, 0x28, 0x74, 0x79, 0x20, 0x3d, 0x3d, 0x20, 0x22, 0x69, 0x6e, 0x73, 
+0x74, 0x61, 0x6e, 0x63, 0x65, 0x22, 0x29, 0x20, 0x7b, 0x0d, 0x0a, 0x09, 
+0x09, 0x74, 0x72, 0x79, 0x20, 0x7b, 0x20, 0x2f, 0x2f, 0x54, 0x52, 0x59, 
+0x20, 0x54, 0x4f, 0x20, 0x55, 0x53, 0x45, 0x20, 0x5f, 0x6e, 0x65, 0x78, 
+0x74, 0x69, 0x0d, 0x0a, 0x09, 0x09, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6f, 
+0x72, 0x65, 0x61, 0x63, 0x68, 0x28, 0x69, 0x64, 0x78, 0x2c, 0x76, 0x61, 
+0x6c, 0x20, 0x69, 0x6e, 0x20, 0x6f, 0x62, 0x6a, 0x29, 0x0d, 0x0a, 0x09, 
+0x09, 0x20, 0x20, 0x20, 0x20, 0x7b, 0x0d, 0x0a, 0x09, 0x09, 0x09, 0x09, 
+0x66, 0x75, 0x6e, 0x63, 0x28, 0x6f, 0x62, 0x6a, 0x2c, 0x69, 0x64, 0x78, 
+0x2c, 0x76, 0x61, 0x6c, 0x29, 0x3b, 0x0d, 0x0a, 0x09, 0x09, 0x20, 0x20, 
+0x20, 0x20, 0x7d, 0x0d, 0x0a, 0x09, 0x09, 0x7d, 0x0d, 0x0a, 0x09, 0x09, 
+0x63, 0x61, 0x74, 0x63, 0x68, 0x28, 0x65, 0x29, 0x20, 0x7b, 0x0d, 0x0a, 
+0x09, 0x09, 0x20, 0x20, 0x20, 0x66, 0x6f, 0x72, 0x65, 0x61, 0x63, 0x68, 
+0x28, 0x69, 0x64, 0x78, 0x2c, 0x76, 0x61, 0x6c, 0x20, 0x69, 0x6e, 0x20, 
+0x6f, 0x62, 0x6a, 0x2e, 0x67, 0x65, 0x74, 0x63, 0x6c, 0x61, 0x73, 0x73, 
+0x28, 0x29, 0x29, 0x0d, 0x0a, 0x09, 0x09, 0x20, 0x20, 0x20, 0x7b, 0x0d, 
+0x0a, 0x09, 0x09, 0x09, 0x66, 0x75, 0x6e, 0x63, 0x28, 0x6f, 0x62, 0x6a, 
+0x2c, 0x69, 0x64, 0x78, 0x2c, 0x6f, 0x62, 0x6a, 0x5b, 0x69, 0x64, 0x78, 
+0x5d, 0x29, 0x3b, 0x0d, 0x0a, 0x09, 0x09, 0x20, 0x20, 0x20, 0x7d, 0x0d, 
+0x0a, 0x09, 0x09, 0x7d, 0x0d, 0x0a, 0x09, 0x7d, 0x0d, 0x0a, 0x09, 0x65, 
+0x6c, 0x73, 0x65, 0x20, 0x69, 0x66, 0x28, 0x74, 0x79, 0x20, 0x3d, 0x3d, 
+0x20, 0x22, 0x77, 0x65, 0x61, 0x6b, 0x72, 0x65, 0x66, 0x22, 0x29, 0x20, 
+0x7b, 0x0d, 0x0a, 0x09, 0x09, 0x66, 0x75, 0x6e, 0x63, 0x28, 0x6f, 0x62, 
+0x6a, 0x2c, 0x22, 0x40, 0x72, 0x65, 0x66, 0x22, 0x2c, 0x6f, 0x62, 0x6a, 
+0x2e, 0x72, 0x65, 0x66, 0x28, 0x29, 0x29, 0x3b, 0x0d, 0x0a, 0x09, 0x7d, 
+0x0d, 0x0a, 0x09, 0x65, 0x6c, 0x73, 0x65, 0x20, 0x7b, 0x0d, 0x0a, 0x09, 
+0x09, 0x66, 0x6f, 0x72, 0x65, 0x61, 0x63, 0x68, 0x28, 0x69, 0x64, 0x78, 
+0x2c, 0x76, 0x61, 0x6c, 0x20, 0x69, 0x6e, 0x20, 0x6f, 0x62, 0x6a, 0x29, 
+0x0d, 0x0a, 0x09, 0x09, 0x7b, 0x0d, 0x0a, 0x09, 0x09, 0x20, 0x20, 0x20, 
+0x20, 0x66, 0x75, 0x6e, 0x63, 0x28, 0x6f, 0x62, 0x6a, 0x2c, 0x69, 0x64, 
+0x78, 0x2c, 0x76, 0x61, 0x6c, 0x29, 0x3b, 0x0d, 0x0a, 0x09, 0x09, 0x7d, 
+0x0d, 0x0a, 0x09, 0x7d, 0x0d, 0x0a, 0x09, 0x09, 0x09, 0x0d, 0x0a, 0x7d, 
+0x0d, 0x0a, 0x0d, 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 
+0x20, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x74, 0x72, 0x65, 0x65, 0x28, 
+0x29, 0x3a, 0x28, 0x6f, 0x62, 0x6a, 0x73, 0x5f, 0x72, 0x65, 0x67, 0x29, 
+0x0d, 0x0a, 0x7b, 0x0d, 0x0a, 0x09, 0x66, 0x6f, 0x72, 0x65, 0x61, 0x63, 
+0x68, 0x28, 0x69, 0x2c, 0x6f, 0x20, 0x69, 0x6e, 0x20, 0x6f, 0x62, 0x6a, 
+0x73, 0x5f, 0x72, 0x65, 0x67, 0x2e, 0x72, 0x65, 0x66, 0x73, 0x29, 0x0d, 
+0x0a, 0x09, 0x7b, 0x0d, 0x0a, 0x09, 0x09, 0x62, 0x65, 0x67, 0x69, 0x6e, 
+0x65, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x28, 0x22, 0x6f, 0x22, 0x29, 
+0x3b, 0x0d, 0x0a, 0x09, 0x09, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 
+0x74, 0x65, 0x28, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x2c, 0x28, 0x69, 
+0x3d, 0x3d, 0x3a, 0x3a, 0x67, 0x65, 0x74, 0x72, 0x6f, 0x6f, 0x74, 0x74, 
+0x61, 0x62, 0x6c, 0x65, 0x28, 0x29, 0x3f, 0x22, 0x72, 0x22, 0x3a, 0x70, 
+0x61, 0x63, 0x6b, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x28, 0x3a, 0x3a, 0x74, 
+0x79, 0x70, 0x65, 0x28, 0x69, 0x29, 0x29, 0x29, 0x29, 0x3b, 0x0d, 0x0a, 
+0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x5f, 0x74, 0x79, 0x70, 
+0x65, 0x6f, 0x66, 0x20, 0x3d, 0x20, 0x74, 0x79, 0x70, 0x65, 0x6f, 0x66, 
+0x20, 0x69, 0x3b, 0x0d, 0x0a, 0x09, 0x09, 0x69, 0x66, 0x28, 0x5f, 0x74, 
+0x79, 0x70, 0x65, 0x6f, 0x66, 0x20, 0x21, 0x3d, 0x20, 0x3a, 0x3a, 0x74, 
+0x79, 0x70, 0x65, 0x28, 0x69, 0x29, 0x29, 0x20, 0x7b, 0x0d, 0x0a, 0x09, 
+0x09, 0x09, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x28, 
+0x22, 0x74, 0x79, 0x70, 0x65, 0x6f, 0x66, 0x22, 0x2c, 0x5f, 0x74, 0x79, 
+0x70, 0x65, 0x6f, 0x66, 0x29, 0x3b, 0x0d, 0x0a, 0x09, 0x09, 0x7d, 0x0d, 
+0x0a, 0x09, 0x09, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 
+0x28, 0x22, 0x72, 0x65, 0x66, 0x22, 0x2c, 0x6f, 0x2e, 0x74, 0x6f, 0x73, 
+0x74, 0x72, 0x69, 0x6e, 0x67, 0x28, 0x29, 0x29, 0x3b, 0x0d, 0x0a, 0x09, 
+0x09, 0x69, 0x66, 0x28, 0x69, 0x20, 0x21, 0x3d, 0x20, 0x3a, 0x3a, 0x67, 
+0x65, 0x74, 0x72, 0x6f, 0x6f, 0x74, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x28, 
+0x29, 0x29, 0x7b, 0x0d, 0x0a, 0x09, 0x09, 0x09, 0x69, 0x74, 0x65, 0x72, 
+0x61, 0x74, 0x65, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x28, 0x69, 0x2c, 
+0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x6f, 0x62, 
+0x6a, 0x2c, 0x69, 0x64, 0x78, 0x2c, 0x76, 0x61, 0x6c, 0x29, 0x20, 0x7b, 
+0x0d, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x69, 0x66, 0x28, 0x3a, 0x3a, 0x74, 
+0x79, 0x70, 0x65, 0x28, 0x76, 0x61, 0x6c, 0x29, 0x20, 0x3d, 0x3d, 0x20, 
+0x22, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x29, 0x0d, 
+0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 
+0x3b, 0x0d, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x0d, 0x0a, 0x09, 0x09, 
+0x09, 0x09, 0x62, 0x65, 0x67, 0x69, 0x6e, 0x65, 0x6c, 0x65, 0x6d, 0x65, 
+0x6e, 0x74, 0x28, 0x22, 0x65, 0x22, 0x29, 0x3b, 0x09, 0x0d, 0x0a, 0x09, 
+0x09, 0x09, 0x09, 0x09, 0x65, 0x6d, 0x69, 0x74, 0x76, 0x61, 0x6c, 0x75, 
+0x65, 0x28, 0x22, 0x6b, 0x74, 0x22, 0x2c, 0x22, 0x6b, 0x76, 0x22, 0x2c, 
+0x69, 0x64, 0x78, 0x29, 0x3b, 0x0d, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 
+0x65, 0x6d, 0x69, 0x74, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x28, 0x22, 0x76, 
+0x74, 0x22, 0x2c, 0x22, 0x76, 0x22, 0x2c, 0x6f, 0x62, 0x6a, 0x5b, 0x69, 
+0x64, 0x78, 0x5d, 0x29, 0x3b, 0x0d, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x65, 
+0x6e, 0x64, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x28, 0x22, 0x65, 
+0x22, 0x29, 0x3b, 0x09, 0x0d, 0x0a, 0x0d, 0x0a, 0x09, 0x09, 0x09, 0x7d, 
+0x29, 0x0d, 0x0a, 0x09, 0x09, 0x7d, 0x0d, 0x0a, 0x09, 0x09, 0x65, 0x6e, 
+0x64, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x28, 0x22, 0x6f, 0x22, 
+0x29, 0x3b, 0x0d, 0x0a, 0x09, 0x7d, 0x0d, 0x0a, 0x7d, 0x0d, 0x0a, 0x0d, 
+0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x65, 0x76, 
+0x61, 0x6c, 0x75, 0x61, 0x74, 0x65, 0x5f, 0x77, 0x61, 0x74, 0x63, 0x68, 
+0x28, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x73, 0x2c, 0x69, 0x64, 0x2c, 0x65, 
+0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x29, 0x0d, 0x0a, 
+0x7b, 0x0d, 0x0a, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x75, 
+0x6e, 0x63, 0x5f, 0x73, 0x72, 0x63, 0x3d, 0x22, 0x72, 0x65, 0x74, 0x75, 
+0x72, 0x6e, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 
+0x28, 0x22, 0x0d, 0x0a, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x70, 
+0x61, 0x72, 0x61, 0x6d, 0x73, 0x3d, 0x5b, 0x5d, 0x3b, 0x0d, 0x0a, 0x09, 
+0x0d, 0x0a, 0x09, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x2e, 0x61, 0x70, 
+0x70, 0x65, 0x6e, 0x64, 0x28, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x73, 0x5b, 
+0x22, 0x74, 0x68, 0x69, 0x73, 0x22, 0x5d, 0x29, 0x0d, 0x0a, 0x09, 0x6c, 
+0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x69, 0x72, 0x73, 0x74, 0x3d, 0x31, 
+0x3b, 0x0d, 0x0a, 0x09, 0x66, 0x6f, 0x72, 0x65, 0x61, 0x63, 0x68, 0x28, 
+0x69, 0x2c, 0x76, 0x20, 0x69, 0x6e, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 
+0x73, 0x29, 0x7b, 0x0d, 0x0a, 0x09, 0x09, 0x69, 0x66, 0x28, 0x69, 0x21, 
+0x3d, 0x22, 0x74, 0x68, 0x69, 0x73, 0x22, 0x20, 0x26, 0x26, 0x20, 0x69, 
+0x5b, 0x30, 0x5d, 0x20, 0x21, 0x3d, 0x20, 0x27, 0x40, 0x27, 0x29, 0x7b, 
+0x20, 0x2f, 0x2f, 0x66, 0x6f, 0x72, 0x65, 0x61, 0x63, 0x68, 0x20, 0x69, 
+0x74, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x20, 0x73, 0x74, 0x61, 
+0x72, 0x74, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x40, 0x0d, 0x0a, 0x09, 
+0x09, 0x09, 0x69, 0x66, 0x28, 0x21, 0x66, 0x69, 0x72, 0x73, 0x74, 0x29, 
+0x7b, 0x0d, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x66, 0x75, 0x6e, 0x63, 0x5f, 
+0x73, 0x72, 0x63, 0x3d, 0x66, 0x75, 0x6e, 0x63, 0x5f, 0x73, 0x72, 0x63, 
+0x2b, 0x22, 0x2c, 0x22, 0x0d, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x0d, 0x0a, 
+0x09, 0x09, 0x09, 0x7d, 0x0d, 0x0a, 0x09, 0x09, 0x09, 0x66, 0x69, 0x72, 
+0x73, 0x74, 0x3d, 0x6e, 0x75, 0x6c, 0x6c, 0x0d, 0x0a, 0x09, 0x09, 0x09, 
+0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x2e, 0x61, 0x70, 0x70, 0x65, 0x6e, 
+0x64, 0x28, 0x76, 0x29, 0x0d, 0x0a, 0x09, 0x09, 0x09, 0x66, 0x75, 0x6e, 
+0x63, 0x5f, 0x73, 0x72, 0x63, 0x3d, 0x66, 0x75, 0x6e, 0x63, 0x5f, 0x73, 
+0x72, 0x63, 0x2b, 0x69, 0x0d, 0x0a, 0x09, 0x09, 0x7d, 0x0d, 0x0a, 0x09, 
+0x7d, 0x0d, 0x0a, 0x09, 0x66, 0x75, 0x6e, 0x63, 0x5f, 0x73, 0x72, 0x63, 
+0x3d, 0x66, 0x75, 0x6e, 0x63, 0x5f, 0x73, 0x72, 0x63, 0x2b, 0x22, 0x29, 
+0x7b, 0x5c, 0x6e, 0x22, 0x0d, 0x0a, 0x09, 0x66, 0x75, 0x6e, 0x63, 0x5f, 
+0x73, 0x72, 0x63, 0x3d, 0x66, 0x75, 0x6e, 0x63, 0x5f, 0x73, 0x72, 0x63, 
+0x2b, 0x22, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x28, 0x22, 0x2b, 
+0x65, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x2b, 0x22, 
+0x29, 0x5c, 0x6e, 0x7d, 0x22, 0x0d, 0x0a, 0x09, 0x0d, 0x0a, 0x09, 0x74, 
+0x72, 0x79, 0x20, 0x7b, 0x0d, 0x0a, 0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 
+0x6c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x3d, 0x3a, 0x3a, 0x63, 0x6f, 0x6d, 
+0x70, 0x69, 0x6c, 0x65, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x28, 0x66, 
+0x75, 0x6e, 0x63, 0x5f, 0x73, 0x72, 0x63, 0x29, 0x3b, 0x0d, 0x0a, 0x09, 
+0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x7b, 0x73, 0x74, 0x61, 
+0x74, 0x75, 0x73, 0x3d, 0x22, 0x6f, 0x6b, 0x22, 0x20, 0x2c, 0x20, 0x76, 
+0x61, 0x6c, 0x3d, 0x66, 0x75, 0x6e, 0x63, 0x28, 0x29, 0x2e, 0x61, 0x63, 
+0x61, 0x6c, 0x6c, 0x28, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x29, 0x7d, 
+0x3b, 0x0d, 0x0a, 0x09, 0x7d, 0x0d, 0x0a, 0x09, 0x63, 0x61, 0x74, 0x63, 
+0x68, 0x28, 0x65, 0x29, 0x0d, 0x0a, 0x09, 0x7b, 0x0d, 0x0a, 0x09, 0x09, 
+0x0d, 0x0a, 0x09, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x7b, 
+0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x3d, 0x22, 0x65, 0x72, 0x72, 0x6f, 
+0x72, 0x22, 0x7d, 0x0d, 0x0a, 0x09, 0x7d, 0x0d, 0x0a, 0x7d, 0x0d, 0x0a, 
+0x0d, 0x0a, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 
+0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 
+0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 
+0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 
+0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 
+0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 
+0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x0d, 0x0a, 0x2f, 0x2f, 0x2f, 
+0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 
+0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 
+0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 
+0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 
+0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 
+0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 
+0x2f, 0x2f, 0x0d, 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 
+0x20, 0x65, 0x6d, 0x69, 0x74, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x28, 0x74, 
+0x79, 0x70, 0x65, 0x5f, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x2c, 0x76, 
+0x61, 0x6c, 0x75, 0x65, 0x5f, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x2c, 
+0x76, 0x61, 0x6c, 0x29, 0x0d, 0x0a, 0x7b, 0x0d, 0x0a, 0x09, 0x61, 0x74, 
+0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x28, 0x74, 0x79, 0x70, 0x65, 
+0x5f, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x2c, 0x70, 0x61, 0x63, 0x6b, 
+0x5f, 0x74, 0x79, 0x70, 0x65, 0x28, 0x3a, 0x3a, 0x74, 0x79, 0x70, 0x65, 
+0x28, 0x76, 0x61, 0x6c, 0x29, 0x29, 0x29, 0x3b, 0x0d, 0x0a, 0x09, 0x61, 
+0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x28, 0x76, 0x61, 0x6c, 
+0x75, 0x65, 0x5f, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x2c, 0x67, 0x65, 
+0x74, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x28, 0x76, 0x61, 0x6c, 0x29, 0x2e, 
+0x74, 0x6f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x28, 0x29, 0x29, 0x3b, 
+0x0d, 0x0a, 0x7d, 0x0d, 0x0a, 0x0d, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 
+0x20, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x3d, 0x5b, 0x5d, 0x0d, 0x0a, 0x6c, 
+0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x3d, 0x33, 
+0x3b, 0x0d, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x73, 0x69, 0x3b, 
+0x0d, 0x0a, 0x0d, 0x0a, 0x2f, 0x2f, 0x74, 0x72, 0x79, 0x20, 0x7b, 0x0d, 
+0x0a, 0x09, 0x2f, 0x2f, 0x45, 0x4e, 0x55, 0x4d, 0x45, 0x52, 0x41, 0x54, 
+0x45, 0x20, 0x54, 0x48, 0x45, 0x20, 0x53, 0x54, 0x41, 0x43, 0x4b, 0x20, 
+0x57, 0x41, 0x54, 0x43, 0x48, 0x45, 0x53, 0x0d, 0x0a, 0x09, 0x77, 0x68, 
+0x69, 0x6c, 0x65, 0x28, 0x73, 0x69, 0x3d, 0x3a, 0x3a, 0x67, 0x65, 0x74, 
+0x73, 0x74, 0x61, 0x63, 0x6b, 0x69, 0x6e, 0x66, 0x6f, 0x73, 0x28, 0x6c, 
+0x65, 0x76, 0x65, 0x6c, 0x29, 0x29, 0x0d, 0x0a, 0x09, 0x7b, 0x0d, 0x0a, 
+0x09, 0x09, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x2e, 0x61, 0x70, 0x70, 0x65, 
+0x6e, 0x64, 0x28, 0x73, 0x69, 0x29, 0x3b, 0x0d, 0x0a, 0x09, 0x09, 0x6c, 
+0x65, 0x76, 0x65, 0x6c, 0x2b, 0x2b, 0x3b, 0x0d, 0x0a, 0x09, 0x7d, 0x0d, 
+0x0a, 0x0d, 0x0a, 0x09, 0x2f, 0x2f, 0x45, 0x56, 0x41, 0x4c, 0x55, 0x41, 
+0x54, 0x45, 0x20, 0x41, 0x4c, 0x4c, 0x20, 0x57, 0x41, 0x54, 0x43, 0x48, 
+0x45, 0x53, 0x0d, 0x0a, 0x09, 0x6f, 0x62, 0x6a, 0x73, 0x5f, 0x72, 0x65, 
+0x67, 0x2e, 0x72, 0x65, 0x66, 0x73, 0x5b, 0x3a, 0x3a, 0x67, 0x65, 0x74, 
+0x72, 0x6f, 0x6f, 0x74, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x28, 0x29, 0x5d, 
+0x20, 0x3c, 0x2d, 0x20, 0x6f, 0x62, 0x6a, 0x73, 0x5f, 0x72, 0x65, 0x67, 
+0x2e, 0x6d, 0x61, 0x78, 0x69, 0x64, 0x2b, 0x2b, 0x3b, 0x0d, 0x0a, 0x09, 
+0x66, 0x6f, 0x72, 0x65, 0x61, 0x63, 0x68, 0x28, 0x69, 0x2c, 0x76, 0x61, 
+0x6c, 0x20, 0x69, 0x6e, 0x20, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x29, 0x0d, 
+0x0a, 0x09, 0x7b, 0x0d, 0x0a, 0x09, 0x09, 0x69, 0x66, 0x28, 0x76, 0x61, 
+0x6c, 0x2e, 0x73, 0x72, 0x63, 0x21, 0x3d, 0x22, 0x4e, 0x41, 0x54, 0x49, 
+0x56, 0x45, 0x22, 0x29, 0x20, 0x7b, 0x0d, 0x0a, 0x09, 0x09, 0x09, 0x69, 
+0x66, 0x28, 0x22, 0x77, 0x61, 0x74, 0x63, 0x68, 0x65, 0x73, 0x22, 0x20, 
+0x69, 0x6e, 0x20, 0x74, 0x68, 0x69, 0x73, 0x29, 0x20, 0x7b, 0x0d, 0x0a, 
+0x09, 0x09, 0x09, 0x09, 0x76, 0x61, 0x6c, 0x2e, 0x77, 0x61, 0x74, 0x63, 
+0x68, 0x65, 0x73, 0x20, 0x3c, 0x2d, 0x20, 0x7b, 0x7d, 0x0d, 0x0a, 0x09, 
+0x09, 0x09, 0x09, 0x66, 0x6f, 0x72, 0x65, 0x61, 0x63, 0x68, 0x28, 0x69, 
+0x2c, 0x77, 0x61, 0x74, 0x63, 0x68, 0x20, 0x69, 0x6e, 0x20, 0x77, 0x61, 
+0x74, 0x63, 0x68, 0x65, 0x73, 0x29, 0x0d, 0x0a, 0x09, 0x09, 0x09, 0x09, 
+0x7b, 0x0d, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x69, 0x66, 0x28, 0x76, 
+0x61, 0x6c, 0x2e, 0x73, 0x72, 0x63, 0x21, 0x3d, 0x22, 0x4e, 0x41, 0x54, 
+0x49, 0x56, 0x45, 0x22, 0x29, 0x7b, 0x0d, 0x0a, 0x09, 0x09, 0x09, 0x09, 
+0x09, 0x09, 0x76, 0x61, 0x6c, 0x2e, 0x77, 0x61, 0x74, 0x63, 0x68, 0x65, 
+0x73, 0x5b, 0x69, 0x5d, 0x20, 0x3c, 0x2d, 0x20, 0x65, 0x76, 0x61, 0x6c, 
+0x75, 0x61, 0x74, 0x65, 0x5f, 0x77, 0x61, 0x74, 0x63, 0x68, 0x28, 0x76, 
+0x61, 0x6c, 0x2e, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x73, 0x2c, 0x69, 0x2c, 
+0x77, 0x61, 0x74, 0x63, 0x68, 0x29, 0x3b, 0x0d, 0x0a, 0x09, 0x09, 0x09, 
+0x09, 0x09, 0x09, 0x69, 0x66, 0x28, 0x76, 0x61, 0x6c, 0x2e, 0x77, 0x61, 
+0x74, 0x63, 0x68, 0x65, 0x73, 0x5b, 0x69, 0x5d, 0x2e, 0x73, 0x74, 0x61, 
+0x74, 0x75, 0x73, 0x21, 0x3d, 0x22, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 
+0x29, 0x0d, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x62, 0x75, 
+0x69, 0x6c, 0x64, 0x5f, 0x72, 0x65, 0x66, 0x73, 0x28, 0x76, 0x61, 0x6c, 
+0x2e, 0x77, 0x61, 0x74, 0x63, 0x68, 0x65, 0x73, 0x5b, 0x69, 0x5d, 0x2e, 
+0x76, 0x61, 0x6c, 0x29, 0x3b, 0x0d, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 
+0x7d, 0x0d, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x65, 0x6c, 0x73, 0x65, 
+0x7b, 0x0d, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x76, 0x61, 0x6c, 
+0x2e, 0x77, 0x61, 0x74, 0x63, 0x68, 0x65, 0x73, 0x5b, 0x69, 0x5d, 0x20, 
+0x3c, 0x2d, 0x20, 0x7b, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x3d, 0x22, 
+0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x7d, 0x0d, 0x0a, 0x09, 0x09, 0x09, 
+0x09, 0x09, 0x7d, 0x0d, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x76, 0x61, 
+0x6c, 0x2e, 0x77, 0x61, 0x74, 0x63, 0x68, 0x65, 0x73, 0x5b, 0x69, 0x5d, 
+0x2e, 0x65, 0x78, 0x70, 0x20, 0x3c, 0x2d, 0x20, 0x77, 0x61, 0x74, 0x63, 
+0x68, 0x3b, 0x0d, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x7d, 0x0d, 0x0a, 0x09, 
+0x09, 0x09, 0x09, 0x0d, 0x0a, 0x09, 0x09, 0x09, 0x7d, 0x0d, 0x0a, 0x09, 
+0x09, 0x7d, 0x0d, 0x0a, 0x09, 0x09, 0x66, 0x6f, 0x72, 0x65, 0x61, 0x63, 
+0x68, 0x28, 0x69, 0x2c, 0x6c, 0x20, 0x69, 0x6e, 0x20, 0x76, 0x61, 0x6c, 
+0x2e, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x73, 0x29, 0x0d, 0x0a, 0x09, 0x09, 
+0x09, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x72, 0x65, 0x66, 0x73, 0x28, 
+0x6c, 0x29, 0x3b, 0x0d, 0x0a, 0x09, 0x7d, 0x0d, 0x0a, 0x0d, 0x0a, 0x0d, 
+0x0a, 0x09, 0x62, 0x65, 0x67, 0x69, 0x6e, 0x65, 0x6c, 0x65, 0x6d, 0x65, 
+0x6e, 0x74, 0x28, 0x22, 0x6f, 0x62, 0x6a, 0x73, 0x22, 0x29, 0x3b, 0x0d, 
+0x0a, 0x09, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x74, 0x72, 0x65, 0x65, 
+0x28, 0x29, 0x3b, 0x0d, 0x0a, 0x09, 0x65, 0x6e, 0x64, 0x65, 0x6c, 0x65, 
+0x6d, 0x65, 0x6e, 0x74, 0x28, 0x22, 0x6f, 0x62, 0x6a, 0x73, 0x22, 0x29, 
+0x3b, 0x0d, 0x0a, 0x0d, 0x0a, 0x09, 0x62, 0x65, 0x67, 0x69, 0x6e, 0x65, 
+0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x28, 0x22, 0x63, 0x61, 0x6c, 0x6c, 
+0x73, 0x22, 0x29, 0x3b, 0x0d, 0x0a, 0x0d, 0x0a, 0x09, 0x66, 0x6f, 0x72, 
+0x65, 0x61, 0x63, 0x68, 0x28, 0x69, 0x2c, 0x76, 0x61, 0x6c, 0x20, 0x69, 
+0x6e, 0x20, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x29, 0x0d, 0x0a, 0x09, 0x7b, 
+0x0d, 0x0a, 0x0d, 0x0a, 0x09, 0x09, 0x62, 0x65, 0x67, 0x69, 0x6e, 0x65, 
+0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x28, 0x22, 0x63, 0x61, 0x6c, 0x6c, 
+0x22, 0x29, 0x3b, 0x0d, 0x0a, 0x09, 0x09, 0x61, 0x74, 0x74, 0x72, 0x69, 
+0x62, 0x75, 0x74, 0x65, 0x28, 0x22, 0x66, 0x6e, 0x63, 0x22, 0x2c, 0x76, 
+0x61, 0x6c, 0x2e, 0x66, 0x75, 0x6e, 0x63, 0x29, 0x3b, 0x0d, 0x0a, 0x09, 
+0x09, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x28, 0x22, 
+0x73, 0x72, 0x63, 0x22, 0x2c, 0x76, 0x61, 0x6c, 0x2e, 0x73, 0x72, 0x63, 
+0x29, 0x3b, 0x0d, 0x0a, 0x09, 0x09, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 
+0x75, 0x74, 0x65, 0x28, 0x22, 0x6c, 0x69, 0x6e, 0x65, 0x22, 0x2c, 0x76, 
+0x61, 0x6c, 0x2e, 0x6c, 0x69, 0x6e, 0x65, 0x2e, 0x74, 0x6f, 0x73, 0x74, 
+0x72, 0x69, 0x6e, 0x67, 0x28, 0x29, 0x29, 0x3b, 0x0d, 0x0a, 0x09, 0x09, 
+0x66, 0x6f, 0x72, 0x65, 0x61, 0x63, 0x68, 0x28, 0x69, 0x2c, 0x76, 0x20, 
+0x69, 0x6e, 0x20, 0x76, 0x61, 0x6c, 0x2e, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 
+0x73, 0x29, 0x0d, 0x0a, 0x09, 0x09, 0x7b, 0x0d, 0x0a, 0x09, 0x09, 0x09, 
+0x62, 0x65, 0x67, 0x69, 0x6e, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 
+0x28, 0x22, 0x6c, 0x22, 0x29, 0x3b, 0x0d, 0x0a, 0x09, 0x09, 0x09, 0x09, 
+0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x28, 0x22, 0x6e, 
+0x61, 0x6d, 0x65, 0x22, 0x2c, 0x67, 0x65, 0x74, 0x76, 0x61, 0x6c, 0x75, 
+0x65, 0x28, 0x69, 0x29, 0x2e, 0x74, 0x6f, 0x73, 0x74, 0x72, 0x69, 0x6e, 
+0x67, 0x28, 0x29, 0x29, 0x3b, 0x0d, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x65, 
+0x6d, 0x69, 0x74, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x28, 0x22, 0x74, 0x79, 
+0x70, 0x65, 0x22, 0x2c, 0x22, 0x76, 0x61, 0x6c, 0x22, 0x2c, 0x76, 0x29, 
+0x3b, 0x0d, 0x0a, 0x09, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x65, 0x6c, 0x65, 
+0x6d, 0x65, 0x6e, 0x74, 0x28, 0x22, 0x6c, 0x22, 0x29, 0x3b, 0x0d, 0x0a, 
+0x09, 0x09, 0x7d, 0x0d, 0x0a, 0x09, 0x09, 0x69, 0x66, 0x28, 0x22, 0x77, 
+0x61, 0x74, 0x63, 0x68, 0x65, 0x73, 0x22, 0x20, 0x69, 0x6e, 0x20, 0x76, 
+0x61, 0x6c, 0x29, 0x20, 0x7b, 0x0d, 0x0a, 0x09, 0x09, 0x09, 0x66, 0x6f, 
+0x72, 0x65, 0x61, 0x63, 0x68, 0x28, 0x69, 0x2c, 0x76, 0x20, 0x69, 0x6e, 
+0x20, 0x76, 0x61, 0x6c, 0x2e, 0x77, 0x61, 0x74, 0x63, 0x68, 0x65, 0x73, 
+0x29, 0x0d, 0x0a, 0x09, 0x09, 0x09, 0x7b, 0x0d, 0x0a, 0x09, 0x09, 0x09, 
+0x09, 0x62, 0x65, 0x67, 0x69, 0x6e, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 
+0x74, 0x28, 0x22, 0x77, 0x22, 0x29, 0x3b, 0x0d, 0x0a, 0x09, 0x09, 0x09, 
+0x09, 0x09, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x28, 
+0x22, 0x69, 0x64, 0x22, 0x2c, 0x69, 0x2e, 0x74, 0x6f, 0x73, 0x74, 0x72, 
+0x69, 0x6e, 0x67, 0x28, 0x29, 0x29, 0x3b, 0x0d, 0x0a, 0x09, 0x09, 0x09, 
+0x09, 0x09, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x28, 
+0x22, 0x65, 0x78, 0x70, 0x22, 0x2c, 0x76, 0x2e, 0x65, 0x78, 0x70, 0x29, 
+0x3b, 0x0d, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x61, 0x74, 0x74, 0x72, 
+0x69, 0x62, 0x75, 0x74, 0x65, 0x28, 0x22, 0x73, 0x74, 0x61, 0x74, 0x75, 
+0x73, 0x22, 0x2c, 0x76, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x29, 
+0x3b, 0x0d, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x69, 0x66, 0x28, 0x76, 
+0x2e, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x21, 0x3d, 0x22, 0x65, 0x72, 
+0x72, 0x6f, 0x72, 0x22, 0x29, 0x20, 0x7b, 0x0d, 0x0a, 0x09, 0x09, 0x09, 
+0x09, 0x09, 0x09, 0x65, 0x6d, 0x69, 0x74, 0x76, 0x61, 0x6c, 0x75, 0x65, 
+0x28, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x2c, 0x22, 0x76, 0x61, 0x6c, 
+0x22, 0x2c, 0x76, 0x2e, 0x76, 0x61, 0x6c, 0x29, 0x3b, 0x0d, 0x0a, 0x09, 
+0x09, 0x09, 0x09, 0x09, 0x7d, 0x0d, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x65, 
+0x6e, 0x64, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x28, 0x22, 0x77, 
+0x22, 0x29, 0x3b, 0x0d, 0x0a, 0x09, 0x09, 0x09, 0x7d, 0x0d, 0x0a, 0x09, 
+0x09, 0x7d, 0x0d, 0x0a, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x65, 0x6c, 0x65, 
+0x6d, 0x65, 0x6e, 0x74, 0x28, 0x22, 0x63, 0x61, 0x6c, 0x6c, 0x22, 0x29, 
+0x3b, 0x0d, 0x0a, 0x09, 0x09, 0x20, 0x0d, 0x0a, 0x09, 0x7d, 0x0d, 0x0a, 
+0x09, 0x65, 0x6e, 0x64, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x28, 
+0x22, 0x63, 0x61, 0x6c, 0x6c, 0x73, 0x22, 0x29, 0x3b, 0x0d, 0x0a, 0x0d, 
+0x0a, 0x0d, 0x0a, 0x09, 0x6f, 0x62, 0x6a, 0x73, 0x5f, 0x72, 0x65, 0x67, 
+0x20, 0x3d, 0x20, 0x6e, 0x75, 0x6c, 0x6c, 0x3b, 0x0d, 0x0a, 0x09, 0x73, 
+0x74, 0x61, 0x63, 0x6b, 0x20, 0x3d, 0x20, 0x6e, 0x75, 0x6c, 0x6c, 0x3b, 
+0x0d, 0x0a, 0x09, 0x0d, 0x0a, 0x09, 0x69, 0x66, 0x28, 0x22, 0x63, 0x6f, 
+0x6c, 0x6c, 0x65, 0x63, 0x74, 0x67, 0x61, 0x72, 0x62, 0x61, 0x67, 0x65, 
+0x22, 0x20, 0x69, 0x6e, 0x20, 0x3a, 0x3a, 0x67, 0x65, 0x74, 0x72, 0x6f, 
+0x6f, 0x74, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x28, 0x29, 0x29, 0x20, 0x3a, 
+0x3a, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x67, 0x61, 0x72, 0x62, 
+0x61, 0x67, 0x65, 0x28, 0x29, 0x3b, 0x0d, 0x0a, 0x7d, 0x63, 0x61, 0x74, 
+0x63, 0x68, 0x28, 0x65, 0x29, 0x0d, 0x0a, 0x7b, 0x0d, 0x0a, 0x09, 0x3a, 
+0x3a, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x28, 0x22, 0x45, 0x52, 0x52, 0x4f, 
+0x52, 0x22, 0x2b, 0x65, 0x2b, 0x22, 0x5c, 0x6e, 0x22, 0x29, 0x3b, 0x0d, 
+0x0a, 0x7d, 0x0d, 0x0a, 0x0d, 0x0a, 0x00, 
+};
diff --git a/src/squirrel/sqdbg/sqdbgserver.cpp b/src/squirrel/sqdbg/sqdbgserver.cpp
new file mode 100644 (file)
index 0000000..7cdbe99
--- /dev/null
@@ -0,0 +1,634 @@
+#include <squirrel.h>\r
+#include <assert.h>\r
+#include <sqstdblob.h>\r
+#include "sqrdbg.h"\r
+#include "sqdbgserver.h"\r
+\r
+\r
+#ifndef _UNICODE\r
+#define scstrcpy strcpy\r
+#else\r
+#define scstrcpy wcscpy\r
+#endif\r
+struct XMLEscape{\r
+       const SQChar c;\r
+       const SQChar *esc;\r
+};\r
+\r
+#define SQDBG_DEBUG_HOOK _SC("_sqdbg_debug_hook_")\r
+#define SQDBG_ERROR_HANDLER _SC("_sqdbg_error_handler_")\r
+\r
+XMLEscape g_escapes[]={\r
+       {_SC('<'),_SC("&lt;")},{'>',_SC("&gt;")},{_SC('&'),_SC("&amp;")},{_SC('\''),_SC("&apos;")},{_SC('\"'),_SC("&quot;")},{_SC('\n'),_SC("&quot;n")},{_SC('\r'),_SC("&quot;r")},{0, NULL}\r
+};\r
+\r
+const SQChar *IntToString(int n)\r
+{\r
+       static SQChar temp[256];\r
+       scsprintf(temp,_SC("%d"),n);\r
+       return temp;\r
+}\r
+\r
+int debug_hook(HSQUIRRELVM v);\r
+int error_handler(HSQUIRRELVM v);\r
+\r
+int beginelement(HSQUIRRELVM v)\r
+{\r
+       SQUserPointer up;\r
+       const SQChar *name;\r
+       sq_getuserpointer(v,-1,&up);\r
+       SQDbgServer *self = (SQDbgServer*)up;\r
+       sq_getuserpointer(v,-1,&up);\r
+       sq_getstring(v,2,&name);\r
+       self->BeginElement(name);\r
+       return 0;\r
+}\r
+\r
+int endelement(HSQUIRRELVM v)\r
+{\r
+       SQUserPointer up;\r
+       const SQChar *name;\r
+       sq_getuserpointer(v,-1,&up);\r
+       SQDbgServer *self = (SQDbgServer*)up;\r
+       sq_getuserpointer(v,-1,&up);\r
+       sq_getstring(v,2,&name);\r
+       self->EndElement(name);\r
+       return 0;\r
+}\r
+\r
+int attribute(HSQUIRRELVM v)\r
+{\r
+       SQUserPointer up;\r
+       const SQChar *name,*value;\r
+       sq_getuserpointer(v,-1,&up);\r
+       SQDbgServer *self = (SQDbgServer*)up;\r
+       sq_getuserpointer(v,-1,&up);\r
+       sq_getstring(v,2,&name);\r
+       sq_getstring(v,3,&value);\r
+       self->Attribute(name,value);\r
+       return 0;\r
+}\r
+\r
+const SQChar *EscapeXMLString(HSQUIRRELVM v,const SQChar *s)\r
+{\r
+       \r
+       SQChar *temp=sq_getscratchpad(v,((int)scstrlen(s)*6) + sizeof(SQChar));\r
+       SQChar *dest=temp;\r
+       while(*s!=_SC('\0')){\r
+               int i=0;\r
+               bool escaped=false;\r
+               while(g_escapes[i].esc!=NULL){\r
+                       if(*s==g_escapes[i].c){\r
+                               scstrcpy(dest,g_escapes[i].esc);\r
+                               dest+=scstrlen(g_escapes[i].esc);\r
+                               escaped=true;\r
+                               break;\r
+                       }\r
+                       i++;\r
+               }\r
+               if(!escaped){*dest=*s;*dest++;}\r
+               *s++;\r
+       }\r
+       *dest=_SC('\0');\r
+       return temp;\r
+}\r
+\r
+SQDbgServer::SQDbgServer(HSQUIRRELVM v)\r
+{\r
+       _ready = false;\r
+       _nestedcalls = 0;\r
+       _autoupdate = false;\r
+       _v = v;\r
+       _state = eDBG_Running;\r
+       _accept = INVALID_SOCKET;\r
+       _endpoint = INVALID_SOCKET;\r
+       _maxrecursion = 10;\r
+       sq_resetobject(&_debugroot);\r
+}\r
+\r
+SQDbgServer::~SQDbgServer()\r
+{\r
+       sq_release(_v,&_debugroot);\r
+       if(_accept != INVALID_SOCKET)\r
+               sqdbg_closesocket(_accept);\r
+       if(_endpoint != INVALID_SOCKET)\r
+               sqdbg_closesocket(_endpoint);\r
+}\r
+\r
+bool SQDbgServer::Init()\r
+{\r
+       //creates  an environment table for the debugger\r
+       \r
+       sq_newtable(_v);\r
+       sq_getstackobj(_v,-1,&_debugroot);\r
+       sq_addref(_v,&_debugroot);\r
+\r
+       //creates a emptyslot to store the watches\r
+       sq_pushstring(_v,_SC("watches"),-1);\r
+       sq_pushnull(_v);\r
+       sq_createslot(_v,-3);\r
+\r
+       sq_pushstring(_v,_SC("beginelement"),-1);\r
+       sq_pushuserpointer(_v,this);\r
+       sq_newclosure(_v,beginelement,1);\r
+       sq_setparamscheck(_v,2,_SC(".s"));\r
+       sq_createslot(_v,-3);\r
+\r
+       sq_pushstring(_v,_SC("endelement"),-1);\r
+       sq_pushuserpointer(_v,this);\r
+       sq_newclosure(_v,endelement,1);\r
+       sq_setparamscheck(_v,2,_SC(".s"));\r
+       sq_createslot(_v,-3);\r
+\r
+       sq_pushstring(_v,_SC("attribute"),-1);\r
+       sq_pushuserpointer(_v,this);\r
+       sq_newclosure(_v,attribute,1);\r
+       sq_setparamscheck(_v,3,_SC(".ss"));\r
+       sq_createslot(_v,-3);\r
+\r
+       sq_pop(_v,1);\r
+\r
+       //stores debug hook and error handler in the registry\r
+       sq_pushregistrytable(_v);\r
+\r
+       sq_pushstring(_v,SQDBG_DEBUG_HOOK,-1);\r
+       sq_pushuserpointer(_v,this);\r
+       sq_newclosure(_v,debug_hook,1);\r
+       sq_createslot(_v,-3);\r
+       \r
+       sq_pushstring(_v,SQDBG_ERROR_HANDLER,-1);\r
+       sq_pushuserpointer(_v,this);\r
+       sq_newclosure(_v,error_handler,1);\r
+       sq_createslot(_v,-3);\r
+\r
+       \r
+       sq_pop(_v,1);\r
+\r
+       //sets the error handlers\r
+       SetErrorHandlers();\r
+       return true;\r
+}\r
+\r
+bool SQDbgServer::ReadMsg()\r
+{\r
+       return false;\r
+}\r
+\r
+void SQDbgServer::BusyWait()\r
+{\r
+       while( !ReadMsg() )\r
+               sleep(0);\r
+}\r
+\r
+void SQDbgServer::SendChunk(const SQChar *chunk)\r
+{\r
+       char *buf=NULL;\r
+       int buf_len=0;\r
+#ifdef _UNICODE\r
+       buf_len=(int)scstrlen(chunk)+1;\r
+       buf=(char *)sq_getscratchpad(_v,(buf_len)*3);\r
+       wcstombs((char *)buf,chunk,buf_len);\r
+#else\r
+       buf_len=(int)scstrlen(chunk);\r
+       buf=(char *)chunk;\r
+#endif\r
+       send(_endpoint,(const char*)buf,(int)strlen((const char *)buf),0);\r
+}\r
+\r
+\r
+void SQDbgServer::Terminated()\r
+{\r
+       BeginElement(_SC("terminated"));\r
+       EndElement(_SC("terminated"));\r
+       ::usleep(200);\r
+}\r
+\r
+void SQDbgServer::Hook(int type,int line,const SQChar *src,const SQChar *func)\r
+{\r
+       switch(_state){\r
+       case eDBG_Running:\r
+               if(type==_SC('l') && _breakpoints.size()) {\r
+                       BreakPointSetItor itr = _breakpoints.find(BreakPoint(line,src));\r
+                       if(itr != _breakpoints.end()) {\r
+                               Break(line,src,_SC("breakpoint"));\r
+                               BreakExecution();\r
+                       }\r
+               }\r
+               break;\r
+       case eDBG_Suspended:\r
+               _nestedcalls=0;\r
+       case eDBG_StepOver:\r
+               switch(type){\r
+               case _SC('l'):\r
+                       if(_nestedcalls==0) {\r
+                               Break(line,src,_SC("step"));\r
+                               BreakExecution();\r
+                       }\r
+                       break;\r
+               case _SC('c'):\r
+                       _nestedcalls++;\r
+                       break;\r
+               case _SC('r'):\r
+                       if(_nestedcalls==0){\r
+                               _nestedcalls=0;\r
+                               \r
+                       }else{\r
+                               _nestedcalls--;\r
+                       }\r
+                       break;\r
+               }\r
+               break;\r
+       case eDBG_StepInto:\r
+               switch(type){\r
+               case _SC('l'):\r
+                       _nestedcalls=0;\r
+                       Break(line,src,_SC("step"));\r
+                       BreakExecution();\r
+                       break;\r
+               \r
+               }\r
+               break;\r
+       case eDBG_StepReturn:\r
+               switch(type){\r
+               case _SC('l'):\r
+                       break;\r
+               case _SC('c'):\r
+                       _nestedcalls++;\r
+                       break;\r
+               case _SC('r'):\r
+                       if(_nestedcalls==0){\r
+                               _nestedcalls=0;\r
+                               _state=eDBG_StepOver;\r
+                       }else{\r
+                               _nestedcalls--;\r
+                       }\r
+                       \r
+                       break;\r
+               }\r
+               break;\r
+       case eDBG_Disabled:\r
+               break;\r
+       }\r
+}\r
+\r
+\r
+#define MSG_ID(x,y) ((y<<8)|x)\r
+//ab Add Breakpoint\r
+//rb Remove Breakpoint\r
+//sp Suspend\r
+void SQDbgServer::ParseMsg(const char *msg)\r
+{\r
+       \r
+       switch(*((unsigned short *)msg)){\r
+               case MSG_ID('a','b'): {\r
+                       BreakPoint bp;\r
+                       if(ParseBreakpoint(msg+3,bp)){\r
+                               AddBreakpoint(bp);\r
+                               scprintf(_SC("added bp %d %s\n"),bp._line,bp._src.c_str());\r
+                       }\r
+                       else\r
+                               scprintf(_SC("error parsing add breakpoint"));\r
+                                                        }\r
+                       break;\r
+               case MSG_ID('r','b'): {\r
+                       BreakPoint bp;\r
+                       if(ParseBreakpoint(msg+3,bp)){\r
+                               RemoveBreakpoint(bp);\r
+                               scprintf(_SC("removed bp %d %s\n"),bp._line,bp._src.c_str());\r
+                       }else\r
+                               scprintf(_SC("error parsing remove breakpoint"));\r
+                                                       }\r
+                       break;\r
+               case MSG_ID('g','o'):\r
+                       if(_state!=eDBG_Running){\r
+                               _state=eDBG_Running;\r
+                               BeginDocument();\r
+                                       BeginElement(_SC("resumed"));\r
+                                       EndElement(_SC("resumed"));\r
+                               EndDocument();\r
+//                             Send(_SC("<resumed/>\r\n"));\r
+                               scprintf(_SC("go (execution resumed)\n"));\r
+                       }\r
+                       break;\r
+               case MSG_ID('s','p'):\r
+                       if(_state!=eDBG_Suspended){\r
+                               _state=eDBG_Suspended;\r
+                               scprintf(_SC("suspend\n"));\r
+                       }\r
+                       break;\r
+               case MSG_ID('s','o'):\r
+                       if(_state==eDBG_Suspended){\r
+                               _state=eDBG_StepOver;\r
+                       }\r
+                       break;\r
+               case MSG_ID('s','i'):\r
+                       if(_state==eDBG_Suspended){\r
+                               _state=eDBG_StepInto;\r
+                               scprintf(_SC("step into\n"));\r
+                       }\r
+                       break;\r
+               case MSG_ID('s','r'):\r
+                       if(_state==eDBG_Suspended){\r
+                               _state=eDBG_StepReturn;\r
+                               scprintf(_SC("step return\n"));\r
+                       }\r
+                       break;\r
+               case MSG_ID('d','i'):\r
+                       if(_state!=eDBG_Disabled){\r
+                               _state=eDBG_Disabled;\r
+                               scprintf(_SC("disabled\n"));\r
+                       }\r
+                       break;\r
+               case MSG_ID('a','w'): {\r
+                       Watch w;\r
+                       if(ParseWatch(msg+3,w))\r
+                       {\r
+                               AddWatch(w);\r
+                               scprintf(_SC("added watch %d %s\n"),w._id,w._exp.c_str());\r
+                       }\r
+                       else\r
+                               scprintf(_SC("error parsing add watch"));\r
+                                                               }\r
+                       break;\r
+               case MSG_ID('r','w'): {\r
+                       int id;\r
+                       if(ParseRemoveWatch(msg+3,id))\r
+                       {\r
+                               RemoveWatch(id);\r
+                               scprintf(_SC("added watch %d\n"),id);\r
+                       }\r
+                       else\r
+                               scprintf(_SC("error parsing remove watch"));\r
+                                                               }\r
+                       break;\r
+               case MSG_ID('t','r'):\r
+                       scprintf(_SC("terminate from user\n"));\r
+                       break;\r
+               case MSG_ID('r','d'):\r
+                       scprintf(_SC("ready\n"));\r
+                       _ready=true;\r
+                       break;\r
+               default:\r
+                       scprintf(_SC("unknown packet"));\r
+\r
+       }\r
+}\r
+\r
+/*\r
+       see copyright notice in sqrdbg.h\r
+*/\r
+bool SQDbgServer::ParseBreakpoint(const char *msg,BreakPoint &out)\r
+{\r
+       static char stemp[MAX_BP_PATH];\r
+       char *ep=NULL;\r
+       out._line=strtoul(msg,&ep,16);\r
+       if(ep==msg || (*ep)!=':')return false;\r
+       \r
+       char *dest=stemp;\r
+       ep++;\r
+       while((*ep)!='\n' && (*ep)!='\0')\r
+       {\r
+               *dest=*ep;\r
+               *dest++;*ep++;\r
+       }\r
+       *dest='\0';\r
+       *dest++;\r
+       *dest='\0';\r
+#ifdef _UNICODE\r
+       int len=(int)strlen(stemp);\r
+       SQChar *p=sq_getscratchpad(_v,(SQInteger)(mbstowcs(NULL,stemp,len)+2)*sizeof(SQChar));\r
+       size_t destlen=mbstowcs(p,stemp,len);\r
+       p[destlen]=_SC('\0');\r
+       out._src=p;\r
+#else\r
+       out._src=stemp;\r
+#endif\r
+       return true;\r
+}\r
+\r
+bool SQDbgServer::ParseWatch(const char *msg,Watch &out)\r
+{\r
+       char *ep=NULL;\r
+       out._id=strtoul(msg,&ep,16);\r
+       if(ep==msg || (*ep)!=':')return false;\r
+\r
+       //char *dest=out._src;\r
+       ep++;\r
+       while((*ep)!='\n' && (*ep)!='\0')\r
+       {\r
+               out._exp.append(1,*ep);\r
+               *ep++;\r
+       }\r
+       return true;\r
+}\r
+\r
+bool SQDbgServer::ParseRemoveWatch(const char *msg,int &id)\r
+{\r
+       char *ep=NULL;\r
+       id=strtoul(msg,&ep,16);\r
+       if(ep==msg)return false;\r
+       return true;\r
+}\r
+\r
+\r
+void SQDbgServer::BreakExecution()\r
+{\r
+       _state=eDBG_Suspended;\r
+       while(_state==eDBG_Suspended){\r
+               if(SQ_FAILED(sq_rdbg_update(this)))\r
+                       exit(0);\r
+               usleep(10);\r
+       }\r
+}\r
+\r
+//COMMANDS\r
+void SQDbgServer::AddBreakpoint(BreakPoint &bp)\r
+{\r
+       _breakpoints.insert(bp);\r
+       BeginDocument();\r
+               BeginElement(_SC("addbreakpoint"));\r
+                       Attribute(_SC("line"),IntToString(bp._line));\r
+                       Attribute(_SC("src"),bp._src.c_str());\r
+               EndElement(_SC("addbreakpoint"));\r
+       EndDocument();\r
+}\r
+\r
+void SQDbgServer::AddWatch(Watch &w)\r
+{\r
+       _watches.insert(w);\r
+}\r
+\r
+void SQDbgServer::RemoveWatch(int id)\r
+{\r
+       WatchSetItor itor=_watches.find(Watch(id,_SC("")));\r
+       if(itor==_watches.end()){\r
+               BeginDocument();\r
+               BeginElement(_SC("error"));\r
+                       Attribute(_SC("desc"),_SC("the watch does not exists"));\r
+               EndElement(_SC("error"));\r
+       EndDocument();\r
+       }\r
+       else{\r
+               _watches.erase(itor);\r
+               scprintf(_SC("removed watch %d\n"),id);\r
+       }\r
+}\r
+\r
+void SQDbgServer::RemoveBreakpoint(BreakPoint &bp)\r
+{\r
+       BreakPointSetItor itor=_breakpoints.find(bp);\r
+       if(itor==_breakpoints.end()){\r
+               BeginDocument();\r
+                       BeginElement(_SC("break"));\r
+                               Attribute(_SC("desc"),_SC("the breakpoint doesn't exists"));\r
+                       EndElement(_SC("break"));\r
+               EndDocument();\r
+       }\r
+       else{\r
+               BeginDocument();\r
+                       BeginElement(_SC("removebreakpoint"));\r
+                               Attribute(_SC("line"),IntToString(bp._line));\r
+                               Attribute(_SC("src"),bp._src.c_str());\r
+                       EndElement(_SC("removebreakpoint"));\r
+               EndDocument();\r
+               _breakpoints.erase(itor);\r
+       }\r
+}\r
+\r
+void SQDbgServer::Break(int line,const SQChar *src,const SQChar *type,const SQChar *error)\r
+{\r
+       if(!error){\r
+               BeginDocument();\r
+                       BeginElement(_SC("break"));\r
+                               Attribute(_SC("line"),IntToString(line));\r
+                               Attribute(_SC("src"),src);\r
+                               Attribute(_SC("type"),type);\r
+                               SerializeState();\r
+                       EndElement(_SC("break"));\r
+               EndDocument();\r
+       }else{\r
+               BeginDocument();\r
+                       BeginElement(_SC("break"));\r
+                               Attribute(_SC("line"),IntToString(line));\r
+                               Attribute(_SC("src"),src);\r
+                               Attribute(_SC("type"),type);\r
+                               Attribute(_SC("error"),error);\r
+                               SerializeState();\r
+                       EndElement(_SC("break"));\r
+               EndDocument();\r
+       }\r
+}\r
+\r
+void SQDbgServer::SerializeState()\r
+{\r
+       sq_pushnull(_v);\r
+       sq_setdebughook(_v);\r
+       sq_pushnull(_v);\r
+       sq_seterrorhandler(_v);\r
+       const SQChar *sz;\r
+       sq_pushobject(_v,_serializefunc);\r
+       sq_pushobject(_v,_debugroot);\r
+       sq_pushstring(_v,_SC("watches"),-1);\r
+       sq_newtable(_v);\r
+       for(WatchSetItor i=_watches.begin(); i!=_watches.end(); ++i)\r
+       {\r
+               sq_pushinteger(_v,i->_id);\r
+               sq_pushstring(_v,i->_exp.c_str(),(int)i->_exp.length());\r
+               sq_createslot(_v,-3);\r
+       }\r
+       sq_rawset(_v,-3);\r
+       if(SQ_SUCCEEDED(sq_call(_v,1,SQTrue))){\r
+               if(SQ_SUCCEEDED(sqstd_getblob(_v,-1,(SQUserPointer*)&sz)))\r
+                       SendChunk(sz);\r
+       }\r
+       sq_pop(_v,2);\r
+       \r
+       SetErrorHandlers();\r
+}\r
+\r
+\r
+void SQDbgServer::SetErrorHandlers()\r
+{\r
+       sq_pushregistrytable(_v);\r
+       sq_pushstring(_v,SQDBG_DEBUG_HOOK,-1);\r
+       sq_rawget(_v,-2);\r
+       sq_setdebughook(_v);\r
+       sq_pushstring(_v,SQDBG_ERROR_HANDLER,-1);\r
+       sq_rawget(_v,-2);\r
+       sq_seterrorhandler(_v);\r
+       sq_pop(_v,1);\r
+}\r
+\r
+void SQDbgServer::BeginElement(const SQChar *name)\r
+{\r
+       _xmlcurrentement++;\r
+       XMLElementState *self = &xmlstate[_xmlcurrentement];\r
+       scstrcpy(self->name,name);\r
+       self->haschildren = false;\r
+       if(_xmlcurrentement > 0) {\r
+               XMLElementState *parent = &xmlstate[_xmlcurrentement-1];\r
+               if(!parent->haschildren) {\r
+                       SendChunk(_SC(">")); // closes the parent tag\r
+                       parent->haschildren = true;\r
+               }\r
+       }\r
+       _scratchstring.resize(2+scstrlen(name));\r
+       scsprintf(&_scratchstring[0],_SC("<%s"),name);\r
+       SendChunk(&_scratchstring[0]);\r
+}\r
+\r
+void SQDbgServer::Attribute(const SQChar *name,const SQChar *value)\r
+{\r
+       XMLElementState *self = &xmlstate[_xmlcurrentement];\r
+       assert(!self->haschildren); //cannot have attributes if already has children\r
+       const SQChar *escval = escape_xml(value);\r
+       _scratchstring.resize(5+scstrlen(name)+scstrlen(escval));\r
+       scsprintf(&_scratchstring[0],_SC(" %s=\"%s\""),name,escval);\r
+       SendChunk(&_scratchstring[0]);\r
+}\r
+\r
+void SQDbgServer::EndElement(const SQChar *name)\r
+{\r
+       XMLElementState *self = &xmlstate[_xmlcurrentement];\r
+       assert(scstrcmp(self->name,name) == 0);\r
+       if(self->haschildren) {\r
+               _scratchstring.resize(4+scstrlen(name));\r
+               scsprintf(&_scratchstring[0],_SC("</%s>"),name);\r
+               SendChunk(&_scratchstring[0]);\r
+               \r
+       }\r
+       else {\r
+               SendChunk(_SC("/>"));\r
+       }\r
+       _xmlcurrentement--;\r
+}\r
+\r
+void SQDbgServer::EndDocument()\r
+{\r
+       SendChunk(_SC("\r\n"));\r
+}\r
+\r
+//this can be done much better/faster(do we need that?)\r
+const SQChar *SQDbgServer::escape_xml(const SQChar *s)\r
+{\r
+       SQChar *temp=sq_getscratchpad(_v,((int)scstrlen(s)*6) + sizeof(SQChar));\r
+       SQChar *dest=temp;\r
+       while(*s!=_SC('\0')){\r
+               int i=0;\r
+               bool escaped=false;\r
+               while(g_escapes[i].esc!=NULL){\r
+                       if(*s==g_escapes[i].c){\r
+                               scstrcpy(dest,g_escapes[i].esc);\r
+                               dest+=scstrlen(g_escapes[i].esc);\r
+                               escaped=true;\r
+                               break;\r
+                       }\r
+                       i++;\r
+               }\r
+               if(!escaped){*dest=*s;*dest++;}\r
+               *s++;\r
+       }\r
+       *dest=_SC('\0');\r
+       return temp;\r
+       \r
+}\r
diff --git a/src/squirrel/sqdbg/sqdbgserver.h b/src/squirrel/sqdbg/sqdbgserver.h
new file mode 100644 (file)
index 0000000..dcfa7cf
--- /dev/null
@@ -0,0 +1,159 @@
+#ifndef _SQ_DBGSERVER_H_\r
+#define _SQ_DBGSERVER_H_\r
+\r
+#define MAX_BP_PATH 512\r
+#define MAX_MSG_LEN 2049\r
+\r
+#include <set>\r
+#include <string>\r
+#include <vector>\r
+\r
+#ifdef _WIN32\r
+#include <winsock.h>\r
+#define sqdbg_closesocket(x) closesocket((x))\r
+typedef socklen_t int;\r
+#else\r
+#include <unistd.h>\r
+#include <errno.h>\r
+#include <sys/socket.h>\r
+#include <sys/types.h>\r
+#include <netinet/in.h>\r
+#include <arpa/inet.h>\r
+#include <netdb.h>\r
+#include <fcntl.h>\r
+\r
+#define sqdbg_closesocket(x) close((x))\r
+typedef int SOCKET;\r
+typedef struct timeval TIMEVAL;\r
+#define SOCKET_ERROR -1\r
+#define INVALID_SOCKET -1\r
+#endif\r
+\r
+typedef std::basic_string<SQChar> SQDBGString;\r
+\r
+inline bool dbg_less(const SQChar *x,const SQChar *y)\r
+{\r
+       int n = 0;\r
+       do {\r
+               int xl = *x == '\\' ? '/' : tolower(*x);\r
+               int yl = *y == '\\' ? '/' : tolower(*y);\r
+               int diff = xl - yl;\r
+               if(diff != 0)\r
+                       return diff > 0?true:false;\r
+               x++; y++;\r
+       }while(*x != 0 && *y != 0);\r
+       return false;\r
+}\r
+\r
+struct BreakPoint{\r
+       BreakPoint(){_line=0;}\r
+       BreakPoint(int line, const SQChar *src){ _line = line; _src = src; }\r
+       BreakPoint(const BreakPoint& bp){ _line = bp._line; _src=bp._src; }\r
+       inline bool operator<(const BreakPoint& bp) const\r
+       {\r
+               if(_line<bp._line)\r
+                       return true;\r
+               if(_line==bp._line){\r
+                       return dbg_less(_src.c_str(),bp._src.c_str());\r
+               }\r
+               return false;\r
+       }\r
+       \r
+       int _line;\r
+       SQDBGString _src;\r
+};\r
+\r
+struct Watch{\r
+       Watch() { _id = 0; }\r
+       Watch(int id,const SQChar *exp) { _id = id; _exp = exp; }\r
+       Watch(const Watch &w) { _id = w._id; _exp = w._exp; }\r
+       bool operator<(const Watch& w) const { return _id<w._id; }\r
+       bool operator==(const Watch& w) const { return _id == w._id; }\r
+       int _id;\r
+       SQDBGString _exp;\r
+};\r
+\r
+typedef std::set<BreakPoint> BreakPointSet;\r
+typedef BreakPointSet::iterator BreakPointSetItor;\r
+\r
+typedef std::set<Watch> WatchSet;\r
+typedef WatchSet::iterator WatchSetItor;\r
+\r
+typedef std::vector<SQChar> SQCharVec;\r
+struct SQDbgServer{\r
+public:\r
+       enum eDbgState{\r
+               eDBG_Running,\r
+               eDBG_StepOver,\r
+               eDBG_StepInto,\r
+               eDBG_StepReturn,\r
+               eDBG_Suspended,\r
+               eDBG_Disabled,\r
+       };\r
+\r
+       SQDbgServer(HSQUIRRELVM v);\r
+       ~SQDbgServer();\r
+       bool Init();\r
+       //returns true if a message has been received\r
+       bool WaitForClient();\r
+       bool ReadMsg();\r
+       void BusyWait();\r
+       void Hook(int type,int line,const SQChar *src,const SQChar *func);\r
+       void ParseMsg(const char *msg);\r
+       bool ParseBreakpoint(const char *msg,BreakPoint &out);\r
+       bool ParseWatch(const char *msg,Watch &out);\r
+       bool ParseRemoveWatch(const char *msg,int &id);\r
+       void Terminated();\r
+       //\r
+       void BreakExecution();\r
+       void Send(const SQChar *s,...);\r
+       void SendChunk(const SQChar *chunk);\r
+       void Break(int line,const SQChar *src,const SQChar *type,const SQChar *error=NULL);\r
+       \r
+\r
+       void SerializeState();\r
+       //COMMANDS\r
+       void AddBreakpoint(BreakPoint &bp);\r
+       void AddWatch(Watch &w);\r
+       void RemoveWatch(int id);\r
+       void RemoveBreakpoint(BreakPoint &bp);\r
+\r
+       //\r
+       void SetErrorHandlers();\r
+\r
+       //XML RELATED STUFF///////////////////////\r
+       #define MAX_NESTING 10\r
+       struct XMLElementState {\r
+               SQChar name[256];\r
+               bool haschildren;\r
+       };\r
+\r
+       XMLElementState xmlstate[MAX_NESTING];\r
+       int _xmlcurrentement;\r
+\r
+       void BeginDocument() { _xmlcurrentement = -1; }\r
+       void BeginElement(const SQChar *name);\r
+       void Attribute(const SQChar *name, const SQChar *value);\r
+       void EndElement(const SQChar *name);\r
+       void EndDocument();\r
+\r
+       const SQChar *escape_xml(const SQChar *x);\r
+       //////////////////////////////////////////////\r
+       HSQUIRRELVM _v;\r
+       HSQOBJECT _debugroot;\r
+       eDbgState _state;\r
+       SOCKET _accept;\r
+       SOCKET _endpoint;\r
+       BreakPointSet _breakpoints;\r
+       WatchSet _watches;\r
+       int _recursionlevel; \r
+       int _maxrecursion;\r
+       int _nestedcalls;\r
+       bool _ready;\r
+       bool _autoupdate;\r
+       HSQOBJECT _serializefunc;\r
+       SQCharVec _scratchstring;\r
+               \r
+};\r
+\r
+#endif //_SQ_DBGSERVER_H_ \r
diff --git a/src/squirrel/sqdbg/sqrdbg.cpp b/src/squirrel/sqdbg/sqrdbg.cpp
new file mode 100644 (file)
index 0000000..b58a41d
--- /dev/null
@@ -0,0 +1,166 @@
+/*\r
+       see copyright notice in sqrdbg.h\r
+*/\r
+#include <squirrel.h>\r
+#include "sqrdbg.h"\r
+#include "sqdbgserver.h"\r
+int debug_hook(HSQUIRRELVM v);\r
+int error_handler(HSQUIRRELVM v);\r
+\r
+#include "serialize_state.inl"\r
+\r
+HSQREMOTEDBG sq_rdbg_init(HSQUIRRELVM v,unsigned short port,SQBool autoupdate)\r
+{\r
+       sockaddr_in bindaddr;\r
+#ifdef _WIN32\r
+       WSADATA wsadata;        \r
+       if (WSAStartup (MAKEWORD(1,1), &wsadata) != 0){\r
+               return NULL;\r
+       }       \r
+#endif \r
+        \r
+       SQDbgServer *rdbg = new SQDbgServer(v);\r
+       rdbg->_autoupdate = autoupdate?true:false;\r
+       rdbg->_accept = socket(AF_INET,SOCK_STREAM,0);\r
+       bindaddr.sin_family = AF_INET;\r
+       bindaddr.sin_port = htons(port);\r
+       bindaddr.sin_addr.s_addr = htonl (INADDR_ANY);\r
+       if(bind(rdbg->_accept,(sockaddr*)&bindaddr,sizeof(bindaddr))==SOCKET_ERROR){\r
+               delete rdbg;\r
+               sq_throwerror(v,_SC("failed to bind the socket"));\r
+               return NULL;\r
+       }\r
+       if(!rdbg->Init()) {\r
+               delete rdbg;\r
+               sq_throwerror(v,_SC("failed to initialize the debugger"));\r
+               return NULL;\r
+       }\r
+       \r
+    return rdbg;\r
+}\r
+\r
+SQRESULT sq_rdbg_waitforconnections(HSQREMOTEDBG rdbg)\r
+{\r
+       if(SQ_FAILED(sq_compilebuffer(rdbg->_v,serialize_state_nut,(SQInteger)scstrlen(serialize_state_nut),_SC("SERIALIZE_STATE"),SQFalse))) {\r
+               sq_throwerror(rdbg->_v,_SC("error compiling the serialization function"));\r
+       }\r
+       sq_getstackobj(rdbg->_v,-1,&rdbg->_serializefunc);\r
+       sq_addref(rdbg->_v,&rdbg->_serializefunc);\r
+       sq_pop(rdbg->_v,1);\r
+\r
+       sockaddr_in cliaddr;\r
+       socklen_t addrlen=sizeof(cliaddr);\r
+       if(listen(rdbg->_accept,0)==SOCKET_ERROR)\r
+               return sq_throwerror(rdbg->_v,_SC("error on listen(socket)"));\r
+       rdbg->_endpoint = accept(rdbg->_accept,(sockaddr*)&cliaddr,&addrlen);\r
+       //do not accept any other connection\r
+       sqdbg_closesocket(rdbg->_accept);\r
+       rdbg->_accept = INVALID_SOCKET;\r
+       if(rdbg->_endpoint==INVALID_SOCKET){\r
+               return sq_throwerror(rdbg->_v,_SC("error accept(socket)"));\r
+       }\r
+       while(!rdbg->_ready){\r
+               sq_rdbg_update(rdbg);\r
+       }\r
+       return SQ_OK;\r
+}\r
+\r
+SQRESULT sq_rdbg_update(HSQREMOTEDBG rdbg)\r
+{\r
+       TIMEVAL time;\r
+       time.tv_sec=0;\r
+       time.tv_usec=0;\r
+       fd_set read_flags;\r
+    FD_ZERO(&read_flags);\r
+       FD_SET(rdbg->_endpoint, &read_flags);\r
+       select(FD_SETSIZE, &read_flags, NULL, NULL, &time);\r
+\r
+       if(FD_ISSET(rdbg->_endpoint,&read_flags)){\r
+               char temp[1024];\r
+               int size=0;\r
+               char c,prev=0;\r
+               memset(&temp,0,sizeof(temp));\r
+               int res;\r
+               FD_CLR(rdbg->_endpoint, &read_flags);\r
+               while((res = recv(rdbg->_endpoint,&c,1,0))>0){\r
+                       \r
+                       if(c=='\n')break;\r
+                       if(c!='\r'){\r
+                               temp[size]=c;\r
+                               prev=c;\r
+                               size++;\r
+                       }\r
+               }\r
+               switch(res){\r
+               case 0:\r
+                       return sq_throwerror(rdbg->_v,_SC("disconnected"));\r
+               case SOCKET_ERROR:\r
+                       return sq_throwerror(rdbg->_v,_SC("socket error"));\r
+        }\r
+               \r
+               temp[size]=0;\r
+               temp[size+1]=0;\r
+               rdbg->ParseMsg(temp);\r
+       }\r
+       return SQ_OK;\r
+}\r
+\r
+int debug_hook(HSQUIRRELVM v)\r
+{\r
+       SQUserPointer up;\r
+       int event_type,line;\r
+       const SQChar *src,*func;\r
+       sq_getinteger(v,2,&event_type);\r
+       sq_getstring(v,3,&src);\r
+       sq_getinteger(v,4,&line);\r
+       sq_getstring(v,5,&func);\r
+       sq_getuserpointer(v,-1,&up);\r
+       HSQREMOTEDBG rdbg = (HSQREMOTEDBG)up;\r
+       rdbg->Hook(event_type,line,src,func);\r
+       if(rdbg->_autoupdate) {\r
+               if(SQ_FAILED(sq_rdbg_update(rdbg)))\r
+                       return sq_throwerror(v,_SC("socket failed"));\r
+       }\r
+       return 0;\r
+}\r
+\r
+int error_handler(HSQUIRRELVM v)\r
+{\r
+       SQUserPointer up;\r
+       const SQChar *sErr=NULL;\r
+       const SQChar *fn=_SC("unknown");\r
+       const SQChar *src=_SC("unknown");\r
+       int line=-1;\r
+       SQStackInfos si;\r
+       sq_getuserpointer(v,-1,&up);\r
+       HSQREMOTEDBG rdbg=(HSQREMOTEDBG)up;\r
+       if(SQ_SUCCEEDED(sq_stackinfos(v,1,&si)))\r
+       {\r
+               if(si.funcname)fn=si.funcname;\r
+               if(si.source)src=si.source;\r
+               line=si.line;\r
+               scprintf(_SC("*FUNCTION [%s] %s line [%d]\n"),fn,src,si.line);\r
+       }\r
+       if(sq_gettop(v)>=1){\r
+               if(SQ_SUCCEEDED(sq_getstring(v,2,&sErr)))       {\r
+                       scprintf(_SC("\nAN ERROR HAS OCCURED [%s]\n"),sErr);\r
+                       rdbg->Break(si.line,src,_SC("error"),sErr);\r
+               }\r
+               else{\r
+                       scprintf(_SC("\nAN ERROR HAS OCCURED [unknown]\n"));\r
+                       rdbg->Break(si.line,src,_SC("error"),_SC("unknown"));\r
+               }\r
+       }\r
+       rdbg->BreakExecution();\r
+       return 0;\r
+}\r
+\r
+\r
+SQRESULT sq_rdbg_shutdown(HSQREMOTEDBG rdbg)\r
+{\r
+       delete rdbg;\r
+#ifdef _WIN32\r
+       WSACleanup();\r
+#endif\r
+       return SQ_OK;\r
+}\r
diff --git a/src/squirrel/sqdbg/sqrdbg.h b/src/squirrel/sqdbg/sqrdbg.h
new file mode 100644 (file)
index 0000000..3d15e74
--- /dev/null
@@ -0,0 +1,51 @@
+/*\r
+Copyright (c) 2003-2005 Alberto Demichelis\r
+\r
+This software is provided 'as-is', without any \r
+express or implied warranty. In no event will the \r
+authors be held liable for any damages arising from \r
+the use of this software.\r
+\r
+Permission is granted to anyone to use this software \r
+for any purpose, including commercial applications, \r
+and to alter it and redistribute it freely, subject \r
+to the following restrictions:\r
+\r
+               1. The origin of this software must not be \r
+               misrepresented; you must not claim that \r
+               you wrote the original software. If you \r
+               use this software in a product, an \r
+               acknowledgment in the product \r
+               documentation would be appreciated but is \r
+               not required.\r
+\r
+               2. Altered source versions must be plainly \r
+               marked as such, and must not be \r
+               misrepresented as being the original \r
+               software.\r
+\r
+               3. This notice may not be removed or \r
+               altered from any source distribution.\r
+\r
+*/\r
+#ifndef _SQ_RDBG_H_\r
+#define _SQ_RDBG_H_\r
+\r
+#ifdef __cplusplus\r
+extern "C" {\r
+#endif\r
+\r
+struct SQDbgServer;\r
+typedef SQDbgServer* HSQREMOTEDBG;\r
+\r
+HSQREMOTEDBG sq_rdbg_init(HSQUIRRELVM v,unsigned short port,SQBool autoupdate);\r
+SQRESULT sq_rdbg_waitforconnections(HSQREMOTEDBG rdbg);\r
+SQRESULT sq_rdbg_shutdown(HSQREMOTEDBG rdbg);\r
+SQRESULT sq_rdbg_update(HSQREMOTEDBG rdbg);\r
\r
+#ifdef __cplusplus\r
+} /*extern "C"*/\r
+#endif\r
+\r
+#endif //_SQ_RDBG_H_\r
+\r